compiz team mailing list archive
-
compiz team
-
Mailing list archive
-
Message #14349
[Merge] lp:~smspillaz/compiz/compiz.fix_crashes_for_good into lp:compiz
Sam "SmSpillaz" Spilsbury has proposed merging lp:~smspillaz/compiz/compiz.fix_crashes_for_good into lp:compiz.
Requested reviews:
compiz packagers (compiz)
For more details, see:
https://code.launchpad.net/~smspillaz/compiz/compiz.fix_crashes_for_good/+merge/56609
fix all the crashers. EVERY ONE
--
https://code.launchpad.net/~smspillaz/compiz/compiz.fix_crashes_for_good/+merge/56609
Your team compiz packagers is requested to review the proposed merge of lp:~smspillaz/compiz/compiz.fix_crashes_for_good into lp:compiz.
=== added file 'debian/patches/01_unity_window_decorator.patch.OTHER'
--- debian/patches/01_unity_window_decorator.patch.OTHER 1970-01-01 00:00:00 +0000
+++ debian/patches/01_unity_window_decorator.patch.OTHER 2011-04-06 16:20:52 +0000
@@ -0,0 +1,10093 @@
+From e6adb283672c00dbaaeeb70d28f73eb74d1dfadf Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <smspillaz@xxxxxxxxx>
+Date: Thu, 13 Jan 2011 12:05:32 +0800
+Subject: [PATCH] Add UXD unity window decorator with improved borders and shadows
+
+---
+ CMakeLists.txt | 1 +
+ unity/unity_window_decorator/.gitignore | 1 +
+ unity/unity_window_decorator/AUTHORS | 29 +
+ unity/unity_window_decorator/CMakeLists.txt | 38 +
+ unity/unity_window_decorator/COPYING | 6 +
+ unity/unity_window_decorator/COPYING.GPL | 340 ++++
+ unity/unity_window_decorator/INSTALL | 14 +
+ unity/unity_window_decorator/README | 8 +
+ unity/unity_window_decorator/src/CMakeLists.txt | 161 ++
+ unity/unity_window_decorator/src/TODO | 6 +
+ unity/unity_window_decorator/src/actionmenu.c | 109 ++
+ unity/unity_window_decorator/src/blurprops.c | 68 +
+ unity/unity_window_decorator/src/cairo.c | 1001 +++++++++++
+ unity/unity_window_decorator/src/config.h.gtk.in | 25 +
+ unity/unity_window_decorator/src/decorator.c | 882 +++++++++
+ unity/unity_window_decorator/src/decorprops.c | 134 ++
+ unity/unity_window_decorator/src/events.c | 1130 ++++++++++++
+ unity/unity_window_decorator/src/forcequit.c | 176 ++
+ unity/unity_window_decorator/src/gdk.c | 87 +
+ .../src/gtk-window-decorator.c | 414 +++++
+ .../src/gtk-window-decorator.h | 969 ++++++++++
+ unity/unity_window_decorator/src/gwd.schemas.in | 81 +
+ unity/unity_window_decorator/src/metacity.c | 1898 ++++++++++++++++++++
+ unity/unity_window_decorator/src/settings.c | 564 ++++++
+ unity/unity_window_decorator/src/style.c | 42 +
+ unity/unity_window_decorator/src/switcher.c | 427 +++++
+ unity/unity_window_decorator/src/util.c | 278 +++
+ unity/unity_window_decorator/src/wnck.c | 687 +++++++
+ 28 files changed, 9576 insertions(+), 0 deletions(-)
+ create mode 100644 unity/unity_window_decorator/.gitignore
+ create mode 100644 unity/unity_window_decorator/AUTHORS
+ create mode 100644 unity/unity_window_decorator/CMakeLists.txt
+ create mode 100644 unity/unity_window_decorator/COPYING
+ create mode 100644 unity/unity_window_decorator/COPYING.GPL
+ create mode 100644 unity/unity_window_decorator/INSTALL
+ create mode 100644 unity/unity_window_decorator/NEWS
+ create mode 100644 unity/unity_window_decorator/README
+ create mode 100644 unity/unity_window_decorator/src/CMakeLists.txt
+ create mode 100644 unity/unity_window_decorator/src/TODO
+ create mode 100644 unity/unity_window_decorator/src/actionmenu.c
+ create mode 100644 unity/unity_window_decorator/src/blurprops.c
+ create mode 100644 unity/unity_window_decorator/src/cairo.c
+ create mode 100644 unity/unity_window_decorator/src/config.h.gtk.in
+ create mode 100644 unity/unity_window_decorator/src/decorator.c
+ create mode 100644 unity/unity_window_decorator/src/decorprops.c
+ create mode 100644 unity/unity_window_decorator/src/events.c
+ create mode 100644 unity/unity_window_decorator/src/forcequit.c
+ create mode 100644 unity/unity_window_decorator/src/gdk.c
+ create mode 100644 unity/unity_window_decorator/src/gtk-window-decorator.c
+ create mode 100644 unity/unity_window_decorator/src/gtk-window-decorator.h
+ create mode 100644 unity/unity_window_decorator/src/gwd.schemas.in
+ create mode 100644 unity/unity_window_decorator/src/metacity.c
+ create mode 100644 unity/unity_window_decorator/src/settings.c
+ create mode 100644 unity/unity_window_decorator/src/style.c
+ create mode 100644 unity/unity_window_decorator/src/switcher.c
+ create mode 100644 unity/unity_window_decorator/src/util.c
+ create mode 100644 unity/unity_window_decorator/src/wnck.c
+
+Index: compiz-0.9.4git20110322/CMakeLists.txt
+===================================================================
+--- compiz-0.9.4git20110322.orig/CMakeLists.txt 2011-03-22 16:46:56.000000000 +0800
++++ compiz-0.9.4git20110322/CMakeLists.txt 2011-04-06 22:06:48.519070563 +0800
+@@ -112,6 +112,7 @@
+ add_subdirectory (libdecoration)
+ add_subdirectory (gtk)
+ add_subdirectory (kde)
++add_subdirectory (unity/unity_window_decorator)
+ add_subdirectory (po)
+ add_subdirectory (metadata)
+ add_subdirectory (src)
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/.gitignore
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/.gitignore 2011-04-06 22:06:48.519070563 +0800
+@@ -0,0 +1 @@
++po/compiz.pot
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/AUTHORS
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/AUTHORS 2011-04-06 22:06:48.519070563 +0800
+@@ -0,0 +1,29 @@
++compiz and the standard set of plugins are designed and written by
++
++David Reveman <davidr@xxxxxxxxxx>
++
++with additional functionality by
++
++Radek Doulik <rodo@xxxxxxxxxx> IO multiplexing
++Mirco Müller <macslow@xxxxxxxxxx> Skydome support in cube plugin
++Søren Sandmann <sandmann@xxxxxxxxxx> plane plugin
++Dan Winship <danw@xxxxxxxxxx> gconf-dump plugin
++Brian Paul <brian.paul@xxxxxxxxxxxxxxxxxxxx> Matrix functions
++
++and other contributions by
++
++Mike Cook <mcook@xxxxxxxxxx>
++Mike Dransfield <mike@xxxxxxxxxxxxxx>
++Diogo Ferreira <diogo@xxxxxxxxxxxx>
++gandalfn <gandalfn@xxxxxxxxxxxxxxxx>
++Guillaume <ixcemix@xxxxxxxxx>
++Kristian Høgsberg <krh@xxxxxxxxxx>
++Dennis Kasprzyk <onestone@xxxxxxxxxxxxxxxxx>
++Gerd Kohlberger <lowfi@xxxxxxxxx>
++Volker Krause <vkrause@xxxxxxx>
++moppsy <moppsy@xxxxxxxxxxx>
++Jeremy C. Reed <reed@xxxxxxxxxxxxx>
++Thierry Reding <thierry@xxxxxxxx>
++Julian Sikorski <lordzanon@xxxxxxxxxxxxxx>
++Quinn Storm <livinglatexkali@xxxxxxxxx>
++Erkin Bahceci <erkinbah@xxxxxxxxx>
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/CMakeLists.txt
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/CMakeLists.txt 2011-04-06 22:06:48.519070563 +0800
+@@ -0,0 +1,38 @@
++project (unity-window-decorator)
++
++find_package (Compiz REQUIRED)
++
++include (CompizCommon)
++include (CompizPackage)
++
++set (CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRe" CACHE INTERNAL "" FORCE)
++if (NOT CMAKE_BUILD_TYPE)
++ set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type (Debug/Release/RelWithDebInfo/MinSizeRe)" FORCE)
++endif (NOT CMAKE_BUILD_TYPE)
++
++# compiz package version number
++# An odd micro number indicates in-progress development.
++# An even micro number indicates a released version.
++set (COMPIZ_VERSION_MAJOR 0)
++set (COMPIZ_VERSION_MINOR 9)
++set (COMPIZ_VERSION_MICRO 2)
++set (COMPIZ_VERSION_MACRO 1)
++set (VERSION ${COMPIZ_VERSION_MAJOR}.${COMPIZ_VERSION_MINOR}.${COMPIZ_VERSION_MICRO}.${COMPIZ_VERSION_MACRO})
++
++option (BUILD_UNITY "Build Unity window decorator" 1)
++option (BUILD_METACITY "Unity-window-decorator metacity theme support" 1)
++
++compiz_set (USE_METACITY ${BUILD_METACITY})
++
++add_subdirectory (src)
++
++compiz_print_configure_header ("Compiz Unity Window Decorator")
++compiz_color_message ("\n${_escape}[4mFeatures:${_escape}[0m\n")
++
++compiz_print_result_message ("Metacity Theme Support" USE_METACITY)
++compiz_print_configure_footer ()
++
++compiz_add_uninstall ()
++compiz_package_generation ("Compiz Unity Window Decorator")
++
++
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/COPYING
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/COPYING 2011-04-06 22:06:48.519070563 +0800
+@@ -0,0 +1,6 @@
++Most of the code is MIT licensed, some code is instead licensed
++under the LGPL and some under the GPL. Each source code file
++contain a header that describes the license for the code in that
++specific file.
++
++For More information see COPYING.GPL, COPYING.LGPL and COPYING.MIT.
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/COPYING.GPL
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/COPYING.GPL 2011-04-06 22:06:48.523070576 +0800
+@@ -0,0 +1,340 @@
++ GNU GENERAL PUBLIC LICENSE
++ Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++ Preamble
++
++ The licenses for most software are designed to take away your
++freedom to share and change it. By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users. This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it. (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.) You can apply it to
++your programs, too.
++
++ When we speak of free software, we are referring to freedom, not
++price. Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++ To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++ For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have. You must make sure that they, too, receive or can get the
++source code. And you must show them these terms so they know their
++rights.
++
++ We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++ Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software. If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++ Finally, any free program is threatened constantly by software
++patents. We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary. To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++ The precise terms and conditions for copying, distribution and
++modification follow.
++
++ GNU GENERAL PUBLIC LICENSE
++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++ 0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License. The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language. (Hereinafter, translation is included without limitation in
++the term "modification".) Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope. The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++ 1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++ 2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++ a) You must cause the modified files to carry prominent notices
++ stating that you changed the files and the date of any change.
++
++ b) You must cause any work that you distribute or publish, that in
++ whole or in part contains or is derived from the Program or any
++ part thereof, to be licensed as a whole at no charge to all third
++ parties under the terms of this License.
++
++ c) If the modified program normally reads commands interactively
++ when run, you must cause it, when started running for such
++ interactive use in the most ordinary way, to print or display an
++ announcement including an appropriate copyright notice and a
++ notice that there is no warranty (or else, saying that you provide
++ a warranty) and that users may redistribute the program under
++ these conditions, and telling the user how to view a copy of this
++ License. (Exception: if the Program itself is interactive but
++ does not normally print such an announcement, your work based on
++ the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole. If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works. But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++ 3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++ a) Accompany it with the complete corresponding machine-readable
++ source code, which must be distributed under the terms of Sections
++ 1 and 2 above on a medium customarily used for software interchange; or,
++
++ b) Accompany it with a written offer, valid for at least three
++ years, to give any third party, for a charge no more than your
++ cost of physically performing source distribution, a complete
++ machine-readable copy of the corresponding source code, to be
++ distributed under the terms of Sections 1 and 2 above on a medium
++ customarily used for software interchange; or,
++
++ c) Accompany it with the information you received as to the offer
++ to distribute corresponding source code. (This alternative is
++ allowed only for noncommercial distribution and only if you
++ received the program in object code or executable form with such
++ an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it. For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable. However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++ 4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License. Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++ 5. You are not required to accept this License, since you have not
++signed it. However, nothing else grants you permission to modify or
++distribute the Program or its derivative works. These actions are
++prohibited by law if you do not accept this License. Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++ 6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions. You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++ 7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License. If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all. For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices. Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++ 8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded. In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++ 9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time. Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number. If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation. If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++ 10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission. For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this. Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++ NO WARRANTY
++
++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++ END OF TERMS AND CONDITIONS
++
++ How to Apply These Terms to Your New Programs
++
++ If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++ To do so, attach the following notices to the program. It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++ <one line to give the program's name and a brief idea of what it does.>
++ Copyright (C) <year> <name of author>
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++ Gnomovision version 69, Copyright (C) year name of author
++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++ This is free software, and you are welcome to redistribute it
++ under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License. Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a "copyright disclaimer" for the program, if
++necessary. Here is a sample; alter the names:
++
++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++ `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++ <signature of Ty Coon>, 1 April 1989
++ Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs. If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library. If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/INSTALL
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/INSTALL 2011-04-06 22:06:48.523070576 +0800
+@@ -0,0 +1,14 @@
++compiz uses libstartup-notification which is available at
++ftp://ftp.gnome.org/pub/GNOME/sources/startup-notification/
++
++compiz uses out-of-tree builds with cmake, in order to generate the Makefiles for compiz use:
++
++ $ mkdir build
++ $ cd build
++ $ cmake ..
++
++After that, standard build procedures apply:
++
++ $ make
++ # make install
++
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/README
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/README 2011-04-06 22:06:48.523070576 +0800
+@@ -0,0 +1,8 @@
++compiz - OpenGL window and compositing manager
++
++Compiz is an OpenGL compositing manager that use GLX_EXT_texture_from_pixmap
++for binding redirected top-level windows to texture objects. It has a flexible
++plug-in system and it is designed to run well on most graphics hardware.
++
++David Reveman
++davidr@xxxxxxxxxx
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/CMakeLists.txt
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/CMakeLists.txt 2011-04-06 22:06:48.527070597 +0800
+@@ -0,0 +1,161 @@
++function (compiz_install_gconf_schema _src _dst)
++ pkg_check_modules (GCONF gconf-2.0)
++ find_program (GCONFTOOL_EXECUTABLE gconftool-2)
++ mark_as_advanced (FORCE GCONFTOOL_EXECUTABLE)
++
++ if (GCONFTOOL_EXECUTABLE AND NOT COMPIZ_DISABLE_SCHEMAS_INSTALL)
++ install (CODE "
++ if (\"\$ENV{USER}\" STREQUAL \"root\")
++ exec_program (${GCONFTOOL_EXECUTABLE}
++ ARGS \"--get-default-source\"
++ OUTPUT_VARIABLE ENV{GCONF_CONFIG_SOURCE})
++ exec_program (${GCONFTOOL_EXECUTABLE}
++ ARGS \"--makefile-install-rule ${_src} > /dev/null\")
++ else (\"\$ENV{USER}\" STREQUAL \"root\")
++ exec_program (${GCONFTOOL_EXECUTABLE}
++ ARGS \"--install-schema-file=${_src} > /dev/null\")
++ endif (\"\$ENV{USER}\" STREQUAL \"root\")
++ ")
++ endif ()
++ install (
++ FILES "${_src}"
++ DESTINATION "${COMPIZ_DESTDIR}${_dst}"
++ )
++endfunction ()
++
++set (USE_GCONF_UNITY_WINDOW_DECORATOR 1 CACHE BOOL "Install GConf schemas for Unity Window Decorator")
++
++if (BUILD_UNITY)
++
++ pkg_check_modules (UNITY_WINDOW_DECORATOR
++ gconf-2.0
++ xrender>=0.8.4
++ gtk+-2.0>=2.18.0
++ libwnck-1.0
++ pangocairo
++ )
++ if (UNITY_WINDOW_DECORATOR_FOUND)
++ include (CheckFunctionExists)
++ set (CMAKE_REQUIRED_FLAGS ${UNITY_WINDOW_DECORATOR_CFLAGS})
++ set (CMAKE_REQUIRED_LIBRARIES ${UNITY_WINDOW_DECORATOR_LIBRARIES})
++ list (FIND CMAKE_REQUIRED_FLAGS "-D_REENTRANT" REENTRANT_INDEX)
++ if (REENTRANT_INDEX)
++ list (REMOVE_AT CMAKE_REQUIRED_FLAGS REENTRANT_INDEX)
++ list (APPEND CMAKE_REQUIRED_FLAGS "-D_REENTRANT=1")
++ endif (REENTRANT_INDEX)
++ check_function_exists (wnck_window_has_name HAVE_WNCK_WINDOW_HAS_NAME)
++ set (CMAKE_REQUIRED_FLAGS "")
++ set (CMAKE_REQUIRED_LIBRARIES "")
++
++ compiz_pkg_check_modules (HAVE_LIBWNCK_2_18_1 libwnck-1.0>=2.18.1)
++ compiz_pkg_check_modules (HAVE_LIBWNCK_2_19_4 libwnck-1.0>=2.19.4)
++
++ if (BUILD_METACITY)
++ pkg_check_modules (METACITY libmetacity-private)
++ if (METACITY_FOUND)
++ compiz_pkg_check_modules (HAVE_METACITY_2_15_21 libmetacity-private>=2.15.21)
++ compiz_pkg_check_modules (HAVE_METACITY_2_17_0 libmetacity-private>=2.17.0)
++ compiz_pkg_check_modules (HAVE_METACITY_2_23_2 libmetacity-private>=2.23.2)
++ else (METACITY_FOUND)
++ compiz_set (USE_METACITY 0)
++ endif (METACITY_FOUND)
++ endif (BUILD_METACITY)
++
++ if (COMPIZ_BUILD_WITH_RPATH)
++ set (CMAKE_INSTALL_RPATH ${libdir})
++ endif (COMPIZ_BUILD_WITH_RPATH)
++
++ configure_file (
++ ${CMAKE_CURRENT_SOURCE_DIR}/config.h.gtk.in
++ ${CMAKE_CURRENT_BINARY_DIR}/config.h
++ )
++
++ include_directories (
++ ${compiz_SOURCE_DIR}/include
++ ${CMAKE_CURRENT_BINARY_DIR}
++ ${UNITY_WINDOW_DECORATOR_INCLUDE_DIRS}
++ ${METACITY_INCLUDE_DIRS}
++ ${GCONF_INCLUDE_DIRS}
++ ${DBUS_GLIB_INCLUDE_DIRS}
++ )
++
++ add_definitions (
++ -DHAVE_CONFIG_H
++ -DALL_LINGUAS=\"${ALL_LINGUAS}\"
++ -DLOCALEDIR=\\\"${datadir}/locale\\\"
++ )
++
++ link_directories (
++ ${UNITY_WINDOW_DECORATOR_LIBRARY_DIRS}
++ ${COMPIZ_LINK_DIRS}
++ )
++
++ if (USE_GCONF_UNITY_WINDOW_DECORATOR)
++
++ if (NOT COMPIZ_INSTALL_GCONF_SCHEMA_DIR)
++ set (SCHEMADIR "${CMAKE_INSTALL_PREFIX}/share/gconf/schemas")
++ else (NOT COMPIZ_INSTALL_GCONF_SCHEMA_DIR)
++ set (SCHEMADIR "${COMPIZ_INSTALL_GCONF_SCHEMA_DIR}")
++ endif (NOT COMPIZ_INSTALL_GCONF_SCHEMA_DIR)
++
++ set (gwd_schema ${CMAKE_CURRENT_BINARY_DIR}/gwd.schemas)
++
++ compiz_translate_xml (
++ ${CMAKE_CURRENT_SOURCE_DIR}/gwd.schemas.in
++ ${gwd_schema}
++ )
++
++ compiz_install_gconf_schema (${CMAKE_CURRENT_BINARY_DIR}/gwd.schemas ${SCHEMADIR})
++
++ endif (USE_GCONF_UNITY_WINDOW_DECORATOR)
++
++ add_executable (unity-window-decorator
++ gtk-window-decorator.c
++ blurprops.c
++ decorprops.c
++ cairo.c
++ gdk.c
++ switcher.c
++ metacity.c
++ events.c
++ forcequit.c
++ actionmenu.c
++ settings.c
++ util.c
++ style.c
++ wnck.c
++ decorator.c
++ ${gwd_schema}
++ )
++
++ if (USE_METACITY)
++ set (metacitylibs ${METACITY_LIBRARIES})
++ endif (USE_METACITY)
++
++ set_target_properties (
++ unity-window-decorator PROPERTIES
++ INSTALL_RPATH_USE_LINK_PATH 0
++ )
++
++ target_link_libraries (unity-window-decorator
++ decoration
++ ${UNITY_WINDOW_DECORATOR_LIBRARIES}
++ ${GCONF_LIBRARIES}
++ ${DBUS_GLIB_LIBRARIES}
++ ${metacitylibs}
++ )
++
++ install (
++ TARGETS unity-window-decorator
++ DESTINATION ${COMPIZ_DESTDIR}${exec_prefix}
++ RUNTIME DESTINATION bin
++ )
++
++ else (UNITY_WINDOW_DECORATOR_FOUND)
++ set (USE_UNITY 0)
++ endif (UNITY_WINDOW_DECORATOR_FOUND)
++
++endif (BUILD_UNITY)
++
++
++
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/TODO
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/TODO 2011-04-06 22:06:48.527070597 +0800
+@@ -0,0 +1,6 @@
++
++* Plugin interface
++
++* Plugin with SVG-based theme support
++
++* Plugin that supports old metacity themes
+\ No newline at end of file
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/actionmenu.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/actionmenu.c 2011-04-06 22:06:48.527070597 +0800
+@@ -0,0 +1,109 @@
++#include "gtk-window-decorator.h"
++
++static void
++action_menu_unmap (GObject *object)
++{
++ action_menu_mapped = FALSE;
++}
++
++static void
++position_action_menu (GtkMenu *menu,
++ gint *x,
++ gint *y,
++ gboolean *push_in,
++ gpointer user_data)
++{
++ WnckWindow *win = (WnckWindow *) user_data;
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ gint bx, by, width, height;
++
++ wnck_window_get_client_window_geometry (win, x, y, &width, &height);
++
++ if ((*theme_get_button_position) (d, BUTTON_MENU, width, height,
++ &bx, &by, &width, &height))
++ *x = *x - _win_extents.left + bx;
++
++ if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
++ {
++ GtkRequisition req;
++
++ gtk_widget_size_request (GTK_WIDGET (menu), &req);
++ *x = MAX (0, *x - req.width + width);
++ }
++
++ *push_in = TRUE;
++}
++
++void
++action_menu_map (WnckWindow *win,
++ long button,
++ Time time)
++{
++ GdkDisplay *gdkdisplay;
++ GdkScreen *screen;
++
++ gdkdisplay = gdk_display_get_default ();
++ screen = gdk_display_get_default_screen (gdkdisplay);
++
++ if (action_menu)
++ {
++ if (action_menu_mapped)
++ {
++ gtk_widget_destroy (action_menu);
++ action_menu_mapped = FALSE;
++ action_menu = NULL;
++ return;
++ }
++ else
++ gtk_widget_destroy (action_menu);
++ }
++
++ switch (wnck_window_get_window_type (win)) {
++ case WNCK_WINDOW_DESKTOP:
++ case WNCK_WINDOW_DOCK:
++ /* don't allow window action */
++ return;
++ case WNCK_WINDOW_NORMAL:
++ case WNCK_WINDOW_DIALOG:
++
++#ifndef HAVE_LIBWNCK_2_19_4
++ case WNCK_WINDOW_MODAL_DIALOG:
++#endif
++
++ case WNCK_WINDOW_TOOLBAR:
++ case WNCK_WINDOW_MENU:
++ case WNCK_WINDOW_UTILITY:
++ case WNCK_WINDOW_SPLASHSCREEN:
++ /* allow window action menu */
++ break;
++ }
++
++ action_menu = wnck_create_window_action_menu (win);
++
++ gtk_menu_set_screen (GTK_MENU (action_menu), screen);
++
++ g_signal_connect_object (G_OBJECT (action_menu), "unmap",
++ G_CALLBACK (action_menu_unmap),
++ 0, 0);
++
++ gtk_widget_show (action_menu);
++
++ if (!button || button == 1)
++ {
++ gtk_menu_popup (GTK_MENU (action_menu),
++ NULL, NULL,
++ position_action_menu, (gpointer) win,
++ button,
++ time);
++ }
++ else
++ {
++ gtk_menu_popup (GTK_MENU (action_menu),
++ NULL, NULL,
++ NULL, NULL,
++ button,
++ time);
++ }
++
++ action_menu_mapped = TRUE;
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/blurprops.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/blurprops.c 2011-04-06 22:06:48.527070597 +0800
+@@ -0,0 +1,68 @@
++#include "gtk-window-decorator.h"
++
++void
++decor_update_blur_property (decor_t *d,
++ int width,
++ int height,
++ Region top_region,
++ int top_offset,
++ Region bottom_region,
++ int bottom_offset,
++ Region left_region,
++ int left_offset,
++ Region right_region,
++ int right_offset)
++{
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ long *data = NULL;
++ int size = 0;
++
++ if (blur_type != BLUR_TYPE_ALL)
++ {
++ bottom_region = NULL;
++ left_region = NULL;
++ right_region = NULL;
++
++ if (blur_type != BLUR_TYPE_TITLEBAR)
++ top_region = NULL;
++ }
++
++ if (top_region)
++ size += top_region->numRects;
++ if (bottom_region)
++ size += bottom_region->numRects;
++ if (left_region)
++ size += left_region->numRects;
++ if (right_region)
++ size += right_region->numRects;
++
++ if (size)
++ data = (long *) malloc (sizeof (long) * (2 + size * 6));
++
++ if (data)
++ {
++ decor_region_to_blur_property (data, 4, 0, width, height,
++ top_region, top_offset,
++ bottom_region, bottom_offset,
++ left_region, left_offset,
++ right_region, right_offset);
++
++ gdk_error_trap_push ();
++ XChangeProperty (xdisplay, d->prop_xid,
++ win_blur_decor_atom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ 2 + size * 6);
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++
++ free (data);
++ }
++ else
++ {
++ gdk_error_trap_push ();
++ XDeleteProperty (xdisplay, d->prop_xid, win_blur_decor_atom);
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++ }
++}
+\ No newline at end of file
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/cairo.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/cairo.c 2011-04-06 22:06:48.531070622 +0800
+@@ -0,0 +1,1001 @@
++#include "gtk-window-decorator.h"
++
++void
++rounded_rectangle (cairo_t *cr,
++ double x,
++ double y,
++ double w,
++ double h,
++ double radius,
++ int corner)
++{
++ if (corner & CORNER_TOPLEFT)
++ cairo_move_to (cr, x + radius, y);
++ else
++ cairo_move_to (cr, x, y);
++
++ if (corner & CORNER_TOPRIGHT)
++ cairo_arc (cr, x + w - radius, y + radius, radius,
++ M_PI * 1.5, M_PI * 2.0);
++ else
++ cairo_line_to (cr, x + w, y);
++
++ if (corner & CORNER_BOTTOMRIGHT)
++ cairo_arc (cr, x + w - radius, y + h - radius, radius,
++ 0.0, M_PI * 0.5);
++ else
++ cairo_line_to (cr, x + w, y + h);
++
++ if (corner & CORNER_BOTTOMLEFT)
++ cairo_arc (cr, x + radius, y + h - radius, radius,
++ M_PI * 0.5, M_PI);
++ else
++ cairo_line_to (cr, x, y + h);
++
++ if (corner & CORNER_TOPLEFT)
++ cairo_arc (cr, x + radius, y + radius, radius, M_PI, M_PI * 1.5);
++ else
++ cairo_line_to (cr, x, y);
++}
++
++void
++fill_rounded_rectangle (cairo_t *cr,
++ double x,
++ double y,
++ double w,
++ double h,
++ double radius,
++ int corner,
++ decor_color_t *c0,
++ double alpha0,
++ decor_color_t *c1,
++ double alpha1,
++ int gravity)
++{
++ cairo_pattern_t *pattern;
++
++ rounded_rectangle (cr, x, y, w, h, radius, corner);
++
++ if (gravity & SHADE_RIGHT)
++ {
++ x = x + w;
++ w = -w;
++ }
++ else if (!(gravity & SHADE_LEFT))
++ {
++ x = w = 0;
++ }
++
++ if (gravity & SHADE_BOTTOM)
++ {
++ y = y + h;
++ h = -h;
++ }
++ else if (!(gravity & SHADE_TOP))
++ {
++ y = h = 0;
++ }
++
++ if (w && h)
++ {
++ cairo_matrix_t matrix;
++
++ pattern = cairo_pattern_create_radial (0.0, 0.0, 0.0, 0.0, 0.0, w);
++
++ cairo_matrix_init_scale (&matrix, 1.0, w / h);
++ cairo_matrix_translate (&matrix, -(x + w), -(y + h));
++
++ cairo_pattern_set_matrix (pattern, &matrix);
++ }
++ else
++ {
++ pattern = cairo_pattern_create_linear (x + w, y + h, x, y);
++ }
++
++ cairo_pattern_add_color_stop_rgba (pattern, 0.0, c0->r, c0->g, c0->b,
++ alpha0);
++
++ cairo_pattern_add_color_stop_rgba (pattern, 1.0, c1->r, c1->g, c1->b,
++ alpha1);
++
++ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
++
++ cairo_set_source (cr, pattern);
++ cairo_fill (cr);
++ cairo_pattern_destroy (pattern);
++}
++
++void
++draw_shadow_background (decor_t *d,
++ cairo_t *cr,
++ decor_shadow_t *s,
++ decor_context_t *c)
++{
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++
++ if (!s || !s->picture ||!d->picture)
++ {
++ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
++ cairo_paint (cr);
++ }
++ else
++ {
++ decor_fill_picture_extents_with_shadow (xdisplay,
++ s, c,
++ d->picture,
++ &d->border_layout);
++ }
++}
++
++static void
++draw_close_button (decor_t *d,
++ cairo_t *cr,
++ double s)
++{
++ cairo_rel_move_to (cr, 0.0, s);
++
++ cairo_rel_line_to (cr, s, -s);
++ cairo_rel_line_to (cr, s, s);
++ cairo_rel_line_to (cr, s, -s);
++ cairo_rel_line_to (cr, s, s);
++
++ cairo_rel_line_to (cr, -s, s);
++ cairo_rel_line_to (cr, s, s);
++ cairo_rel_line_to (cr, -s, s);
++ cairo_rel_line_to (cr, -s, -s);
++
++ cairo_rel_line_to (cr, -s, s);
++ cairo_rel_line_to (cr, -s, -s);
++ cairo_rel_line_to (cr, s, -s);
++
++ cairo_close_path (cr);
++}
++
++static void
++draw_max_button (decor_t *d,
++ cairo_t *cr,
++ double s)
++{
++ cairo_rel_line_to (cr, 12.0, 0.0);
++ cairo_rel_line_to (cr, 0.0, 12.0);
++ cairo_rel_line_to (cr, -12.0, 0.0);
++
++ cairo_close_path (cr);
++
++ cairo_rel_move_to (cr, 2.0, s);
++
++ cairo_rel_line_to (cr, 12.0 - 4.0, 0.0);
++ cairo_rel_line_to (cr, 0.0, 12.0 - s - 2.0);
++ cairo_rel_line_to (cr, -(12.0 - 4.0), 0.0);
++
++ cairo_close_path (cr);
++}
++
++static void
++draw_unmax_button (decor_t *d,
++ cairo_t *cr,
++ double s)
++{
++ cairo_rel_move_to (cr, 1.0, 1.0);
++
++ cairo_rel_line_to (cr, 10.0, 0.0);
++ cairo_rel_line_to (cr, 0.0, 10.0);
++ cairo_rel_line_to (cr, -10.0, 0.0);
++
++ cairo_close_path (cr);
++
++ cairo_rel_move_to (cr, 2.0, s);
++
++ cairo_rel_line_to (cr, 10.0 - 4.0, 0.0);
++ cairo_rel_line_to (cr, 0.0, 10.0 - s - 2.0);
++ cairo_rel_line_to (cr, -(10.0 - 4.0), 0.0);
++
++ cairo_close_path (cr);
++}
++
++static void
++draw_min_button (decor_t *d,
++ cairo_t *cr,
++ double s)
++{
++ cairo_rel_move_to (cr, 0.0, 8.0);
++
++ cairo_rel_line_to (cr, 12.0, 0.0);
++ cairo_rel_line_to (cr, 0.0, s);
++ cairo_rel_line_to (cr, -12.0, 0.0);
++
++ cairo_close_path (cr);
++}
++
++typedef void (*draw_proc) (cairo_t *cr);
++
++static void
++button_state_offsets (gdouble x,
++ gdouble y,
++ guint state,
++ gdouble *return_x,
++ gdouble *return_y)
++{
++ static double off[] = { 0.0, 0.0, 0.0, 0.5 };
++
++ *return_x = x + off[state];
++ *return_y = y + off[state];
++}
++
++static void
++button_state_paint (cairo_t *cr,
++ GtkStyle *style,
++ decor_color_t *color,
++ guint state)
++{
++
++#define IN_STATE (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW)
++
++ if ((state & IN_STATE) == IN_STATE)
++ {
++ if (state & IN_EVENT_WINDOW)
++ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
++ else
++ cairo_set_source_rgba (cr, color->r, color->g, color->b, 0.95);
++
++ cairo_fill_preserve (cr);
++
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ STROKE_ALPHA);
++
++ cairo_set_line_width (cr, 1.0);
++ cairo_stroke (cr);
++ cairo_set_line_width (cr, 2.0);
++ }
++ else
++ {
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ STROKE_ALPHA);
++ cairo_stroke_preserve (cr);
++
++ if (state & IN_EVENT_WINDOW)
++ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
++ else
++ cairo_set_source_rgba (cr, color->r, color->g, color->b, 0.95);
++
++ cairo_fill (cr);
++ }
++}
++
++void
++draw_window_decoration (decor_t *d)
++{
++ cairo_t *cr;
++ GtkStyle *style;
++ GdkDrawable *drawable;
++ decor_color_t color;
++ double alpha;
++ double x1, y1, x2, y2, x, y, h;
++ int corners = SHADE_LEFT | SHADE_RIGHT | SHADE_TOP | SHADE_BOTTOM;
++ int top;
++ int button_x;
++
++ if (!d->pixmap)
++ return;
++
++ style = gtk_widget_get_style (style_window_rgba);
++
++ if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
++ WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
++ corners = 0;
++
++ color.r = style->bg[GTK_STATE_NORMAL].red / 65535.0;
++ color.g = style->bg[GTK_STATE_NORMAL].green / 65535.0;
++ color.b = style->bg[GTK_STATE_NORMAL].blue / 65535.0;
++
++ if (d->frame_window)
++ {
++ GdkColormap *cmap;
++
++ cmap = get_colormap_for_drawable (GDK_DRAWABLE (d->pixmap));
++ gdk_drawable_set_colormap (GDK_DRAWABLE (d->pixmap), cmap);
++ gdk_drawable_set_colormap (GDK_DRAWABLE (d->buffer_pixmap), cmap);
++ drawable = GDK_DRAWABLE (d->buffer_pixmap);
++ }
++ else if (d->buffer_pixmap)
++ drawable = GDK_DRAWABLE (d->buffer_pixmap);
++ else
++ drawable = GDK_DRAWABLE (d->pixmap);
++
++ cr = gdk_cairo_create (GDK_DRAWABLE (drawable));
++ if (!cr)
++ return;
++
++ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++
++ top = _win_extents.top + titlebar_height;
++
++ x1 = d->context->left_space - _win_extents.left;
++ y1 = d->context->top_space - _win_extents.top - titlebar_height;
++ x2 = d->width - d->context->right_space + _win_extents.right;
++ y2 = d->height - d->context->bottom_space + _win_extents.bottom;
++
++ h = d->height - d->context->top_space - d->context->bottom_space;
++
++ cairo_set_line_width (cr, 1.0);
++
++ if (!d->frame_window)
++ draw_shadow_background (d, cr, d->shadow, d->context);
++
++ if (d->active)
++ {
++ decor_color_t *title_color = _title_color;
++
++ alpha = decoration_alpha + 0.3;
++
++ fill_rounded_rectangle (cr,
++ x1 + 0.5,
++ y1 + 0.5,
++ _win_extents.left - 0.5,
++ top - 0.5,
++ 5.0, CORNER_TOPLEFT & corners,
++ &title_color[0], 1.0, &title_color[1], alpha,
++ SHADE_TOP | SHADE_LEFT);
++
++ fill_rounded_rectangle (cr,
++ x1 + _win_extents.left,
++ y1 + 0.5,
++ x2 - x1 - _win_extents.left -
++ _win_extents.right,
++ top - 0.5,
++ 5.0, 0,
++ &title_color[0], 1.0, &title_color[1], alpha,
++ SHADE_TOP);
++
++ fill_rounded_rectangle (cr,
++ x2 - _win_extents.right,
++ y1 + 0.5,
++ _win_extents.right - 0.5,
++ top - 0.5,
++ 5.0, CORNER_TOPRIGHT & corners,
++ &title_color[0], 1.0, &title_color[1], alpha,
++ SHADE_TOP | SHADE_RIGHT);
++ }
++ else
++ {
++ alpha = decoration_alpha;
++
++ fill_rounded_rectangle (cr,
++ x1 + 0.5,
++ y1 + 0.5,
++ _win_extents.left - 0.5,
++ top - 0.5,
++ 5.0, CORNER_TOPLEFT & corners,
++ &color, 1.0, &color, alpha,
++ SHADE_TOP | SHADE_LEFT);
++
++ fill_rounded_rectangle (cr,
++ x1 + _win_extents.left,
++ y1 + 0.5,
++ x2 - x1 - _win_extents.left -
++ _win_extents.right,
++ top - 0.5,
++ 5.0, 0,
++ &color, 1.0, &color, alpha,
++ SHADE_TOP);
++
++ fill_rounded_rectangle (cr,
++ x2 - _win_extents.right,
++ y1 + 0.5,
++ _win_extents.right - 0.5,
++ top - 0.5,
++ 5.0, CORNER_TOPRIGHT & corners,
++ &color, 1.0, &color, alpha,
++ SHADE_TOP | SHADE_RIGHT);
++ }
++
++ fill_rounded_rectangle (cr,
++ x1 + 0.5,
++ y1 + top,
++ _win_extents.left - 0.5,
++ h,
++ 5.0, 0,
++ &color, 1.0, &color, alpha,
++ SHADE_LEFT);
++
++ fill_rounded_rectangle (cr,
++ x2 - _win_extents.right,
++ y1 + top,
++ _win_extents.right - 0.5,
++ h,
++ 5.0, 0,
++ &color, 1.0, &color, alpha,
++ SHADE_RIGHT);
++
++
++ fill_rounded_rectangle (cr,
++ x1 + 0.5,
++ y2 - _win_extents.bottom,
++ _win_extents.left - 0.5,
++ _win_extents.bottom - 0.5,
++ 5.0, CORNER_BOTTOMLEFT & corners,
++ &color, 1.0, &color, alpha,
++ SHADE_BOTTOM | SHADE_LEFT);
++
++ fill_rounded_rectangle (cr,
++ x1 + _win_extents.left,
++ y2 - _win_extents.bottom,
++ x2 - x1 - _win_extents.left -
++ _win_extents.right,
++ _win_extents.bottom - 0.5,
++ 5.0, 0,
++ &color, 1.0, &color, alpha,
++ SHADE_BOTTOM);
++
++ fill_rounded_rectangle (cr,
++ x2 - _win_extents.right,
++ y2 - _win_extents.bottom,
++ _win_extents.right - 0.5,
++ _win_extents.bottom - 0.5,
++ 5.0, CORNER_BOTTOMRIGHT & corners,
++ &color, 1.0, &color, alpha,
++ SHADE_BOTTOM | SHADE_RIGHT);
++
++ cairo_rectangle (cr,
++ d->context->left_space,
++ d->context->top_space,
++ d->width - d->context->left_space -
++ d->context->right_space,
++ h);
++ gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
++ cairo_fill (cr);
++
++ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
++
++ if (d->active)
++ {
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ 0.7);
++
++ cairo_move_to (cr, x1 + 0.5, y1 + top - 0.5);
++ cairo_rel_line_to (cr, x2 - x1 - 1.0, 0.0);
++
++ cairo_stroke (cr);
++ }
++
++ rounded_rectangle (cr,
++ x1 + 0.5, y1 + 0.5,
++ x2 - x1 - 1.0, y2 - y1 - 1.0,
++ 5.0,
++ (CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
++ CORNER_BOTTOMRIGHT) & corners);
++
++ cairo_clip (cr);
++
++ cairo_translate (cr, 1.0, 1.0);
++
++ rounded_rectangle (cr,
++ x1 + 0.5, y1 + 0.5,
++ x2 - x1 - 1.0, y2 - y1 - 1.0,
++ 5.0,
++ (CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
++ CORNER_BOTTOMRIGHT) & corners);
++
++ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.4);
++
++ cairo_stroke (cr);
++
++ cairo_translate (cr, -2.0, -2.0);
++
++ rounded_rectangle (cr,
++ x1 + 0.5, y1 + 0.5,
++ x2 - x1 - 1.0, y2 - y1 - 1.0,
++ 5.0,
++ (CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
++ CORNER_BOTTOMRIGHT) & corners);
++
++ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.1);
++
++ cairo_stroke (cr);
++
++ cairo_translate (cr, 1.0, 1.0);
++
++ cairo_reset_clip (cr);
++
++ rounded_rectangle (cr,
++ x1 + 0.5, y1 + 0.5,
++ x2 - x1 - 1.0, y2 - y1 - 1.0,
++ 5.0,
++ (CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
++ CORNER_BOTTOMRIGHT) & corners);
++
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ alpha);
++
++ cairo_stroke (cr);
++
++ cairo_set_line_width (cr, 2.0);
++
++ button_x = d->width - d->context->right_space - 13;
++
++ if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
++ {
++ button_state_offsets (button_x,
++ y1 - 3.0 + titlebar_height / 2,
++ d->button_states[BUTTON_CLOSE], &x, &y);
++
++ button_x -= 17;
++
++ if (d->active)
++ {
++ cairo_move_to (cr, x, y);
++ draw_close_button (d, cr, 3.0);
++ button_state_paint (cr, style, &color,
++ d->button_states[BUTTON_CLOSE]);
++ }
++ else
++ {
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ alpha * 0.75);
++
++ cairo_move_to (cr, x, y);
++ draw_close_button (d, cr, 3.0);
++ cairo_fill (cr);
++ }
++ }
++
++ if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
++ {
++ button_state_offsets (button_x,
++ y1 - 3.0 + titlebar_height / 2,
++ d->button_states[BUTTON_MAX], &x, &y);
++
++ button_x -= 17;
++
++ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
++
++ if (d->active)
++ {
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ STROKE_ALPHA);
++
++ cairo_move_to (cr, x, y);
++
++ if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
++ WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
++ draw_unmax_button (d, cr, 4.0);
++ else
++ draw_max_button (d, cr, 4.0);
++
++ button_state_paint (cr, style, &color,
++ d->button_states[BUTTON_MAX]);
++ }
++ else
++ {
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ alpha * 0.75);
++
++ cairo_move_to (cr, x, y);
++
++ if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
++ WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
++ draw_unmax_button (d, cr, 4.0);
++ else
++ draw_max_button (d, cr, 4.0);
++
++ cairo_fill (cr);
++ }
++ }
++
++ if (d->actions & WNCK_WINDOW_ACTION_MINIMIZE)
++ {
++ button_state_offsets (button_x,
++ y1 - 3.0 + titlebar_height / 2,
++ d->button_states[BUTTON_MIN], &x, &y);
++
++ button_x -= 17;
++
++ if (d->active)
++ {
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ STROKE_ALPHA);
++
++
++ cairo_move_to (cr, x, y);
++ draw_min_button (d, cr, 4.0);
++ button_state_paint (cr, style, &color,
++ d->button_states[BUTTON_MIN]);
++ }
++ else
++ {
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ alpha * 0.75);
++
++ cairo_move_to (cr, x, y);
++ draw_min_button (d, cr, 4.0);
++ cairo_fill (cr);
++ }
++ }
++
++ if (d->layout)
++ {
++ if (d->active)
++ {
++ cairo_move_to (cr,
++ d->context->left_space + 21.0,
++ y1 + 2.0 + (titlebar_height - text_height) / 2.0);
++
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ STROKE_ALPHA);
++
++ pango_cairo_layout_path (cr, d->layout);
++ cairo_stroke (cr);
++
++ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
++ }
++ else
++ {
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ alpha);
++ }
++
++ cairo_move_to (cr,
++ d->context->left_space + 21.0,
++ y1 + 2.0 + (titlebar_height - text_height) / 2.0);
++
++ pango_cairo_show_layout (cr, d->layout);
++ }
++
++ if (d->icon)
++ {
++ cairo_translate (cr, d->context->left_space + 1,
++ y1 - 5.0 + titlebar_height / 2);
++ cairo_set_source (cr, d->icon);
++ cairo_rectangle (cr, 0.0, 0.0, 16.0, 16.0);
++ cairo_clip (cr);
++
++ if (d->active)
++ cairo_paint (cr);
++ else
++ cairo_paint_with_alpha (cr, alpha);
++ }
++
++ cairo_destroy (cr);
++
++ copy_to_front_buffer (d);
++
++ if (d->frame_window)
++ {
++ GdkWindow *gdk_frame_window = gtk_widget_get_window (d->decor_window);
++
++ gtk_image_set_from_pixmap (GTK_IMAGE (d->decor_image), d->pixmap, NULL);
++ gtk_window_resize (GTK_WINDOW (d->decor_window), d->width, d->height);
++ gdk_window_move (gdk_frame_window, 0, 0);
++ gdk_window_lower (gdk_frame_window);
++ }
++
++ if (d->prop_xid)
++ {
++ decor_update_window_property (d);
++ d->prop_xid = 0;
++ }
++}
++
++static void
++calc_button_size (decor_t *d)
++{
++ gint button_width;
++
++ button_width = 0;
++
++ if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
++ button_width += 17;
++
++ if (d->actions & (WNCK_WINDOW_ACTION_MAXIMIZE_HORIZONTALLY |
++ WNCK_WINDOW_ACTION_MAXIMIZE_VERTICALLY |
++ WNCK_WINDOW_ACTION_UNMAXIMIZE_HORIZONTALLY |
++ WNCK_WINDOW_ACTION_UNMAXIMIZE_VERTICALLY))
++ button_width += 17;
++
++ if (d->actions & (WNCK_WINDOW_ACTION_MINIMIZE |
++ WNCK_WINDOW_ACTION_MINIMIZE))
++ button_width += 17;
++
++ if (button_width)
++ button_width++;
++
++ d->button_width = button_width;
++}
++
++gboolean
++calc_decoration_size (decor_t *d,
++ gint w,
++ gint h,
++ gint name_width,
++ gint *width,
++ gint *height)
++{
++ decor_layout_t layout;
++ int top_width;
++
++ /* To avoid wasting texture memory, we only calculate the minimal
++ * required decoration size then clip and stretch the texture where
++ * appropriate
++ */
++
++ if (!d->frame_window)
++ {
++ calc_button_size (d);
++
++ if (w < ICON_SPACE + d->button_width)
++ return FALSE;
++
++ top_width = name_width + d->button_width + ICON_SPACE;
++ if (w < top_width)
++ top_width = MAX (ICON_SPACE + d->button_width, w);
++
++ if (d->active)
++ decor_get_default_layout (&window_active_context, top_width, 1, &layout);
++ else
++ decor_get_default_layout (&window_inactive_context, top_width, 1, &layout);
++
++ if (!d->context || memcmp (&layout, &d->border_layout, sizeof (layout)))
++ {
++ *width = layout.width;
++ *height = layout.height;
++
++ d->border_layout = layout;
++ if (d->active)
++ {
++ d->context = &window_active_context;
++ d->shadow = border_active_shadow;
++ }
++ else
++ {
++ d->context = &window_inactive_context;
++ d->shadow = border_inactive_shadow;
++ }
++
++ return TRUE;
++ }
++ }
++ else
++ {
++ calc_button_size (d);
++
++ /* _default_win_extents + top height */
++
++ top_width = name_width + d->button_width + ICON_SPACE;
++ if (w < top_width)
++ top_width = MAX (ICON_SPACE + d->button_width, w);
++
++ decor_get_default_layout (&window_context_no_shadow,
++ d->client_width, d->client_height, &layout);
++
++ *width = layout.width;
++ *height = layout.height;
++
++ d->border_layout = layout;
++ d->context = &window_context_no_shadow;
++ d->shadow = border_no_shadow;
++
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++gboolean
++get_button_position (decor_t *d,
++ gint i,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h)
++{
++ if (i > BUTTON_MENU)
++ return FALSE;
++
++ if (d->frame_window)
++ {
++ *x = bpos[i].x + bpos[i].xw * width + _win_extents.left + 4;
++ *y = bpos[i].y + bpos[i].yh * height + bpos[i].yth *
++ (titlebar_height - 17) + _win_extents.top + 2;
++ }
++ else
++ {
++ *x = bpos[i].x + bpos[i].xw * width;
++ *y = bpos[i].y + bpos[i].yh * height + bpos[i].yth *
++ (titlebar_height - 17);
++ }
++
++ *w = bpos[i].w + bpos[i].ww * width;
++ *h = bpos[i].h + bpos[i].hh * height + bpos[i].hth +
++ (titlebar_height - 17);
++
++ /* hack to position multiple buttons on the right */
++ if (i != BUTTON_MENU)
++ *x -= 10 + 16 * i;
++
++ return TRUE;
++}
++
++void
++get_event_window_position (decor_t *d,
++ gint i,
++ gint j,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h)
++{
++ if (d->frame_window)
++ {
++ *x = pos[i][j].x + pos[i][j].xw * width + _win_extents.left;
++ *y = pos[i][j].y + _win_extents.top +
++ pos[i][j].yh * height + pos[i][j].yth * (titlebar_height - 17);
++
++ if (i == 0 && (j == 0 || j == 2))
++ *y -= titlebar_height;
++ }
++ else
++ {
++ *x = pos[i][j].x + pos[i][j].xw * width;
++ *y = pos[i][j].y +
++ pos[i][j].yh * height + pos[i][j].yth * (titlebar_height - 17);
++ }
++
++ if ((d->state & WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY) &&
++ (j == 0 || j == 2))
++ {
++ *w = 0;
++ }
++ else
++ {
++ *w = pos[i][j].w + pos[i][j].ww * width;
++ }
++
++ if ((d->state & WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY) &&
++ (i == 0 || i == 2))
++ {
++ *h = 0;
++ }
++ else
++ {
++ *h = pos[i][j].h +
++ pos[i][j].hh * height + pos[i][j].hth * (titlebar_height - 17);
++ }
++}
++
++void
++update_border_extents (gint text_height)
++{
++ _win_extents = _default_win_extents;
++ _max_win_extents = _default_win_extents;
++ max_titlebar_height = titlebar_height =
++ (text_height < 17) ? 17 : text_height;
++}
++
++decor_shadow_t *
++cairo_update_shadow (gint shadow_type)
++{
++ decor_shadow_options_t opt_active_shadow;
++ decor_shadow_options_t opt_inactive_shadow;
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ GdkDisplay *display = gdk_display_get_default ();
++ GdkScreen *screen = gdk_display_get_default_screen (display);
++
++ opt_active_shadow.shadow_radius = shadow_radius;
++ opt_active_shadow.shadow_opacity = shadow_opacity;
++
++ memcpy (opt_active_shadow.shadow_color, shadow_color, sizeof (shadow_color));
++
++ opt_active_shadow.shadow_offset_x = shadow_offset_x;
++ opt_active_shadow.shadow_offset_y = shadow_offset_y;
++
++ opt_inactive_shadow.shadow_radius = shadow_radius;
++ opt_inactive_shadow.shadow_opacity = shadow_opacity;
++
++ opt_inactive_shadow.shadow_offset_x = shadow_offset_x;
++ opt_inactive_shadow.shadow_offset_y = shadow_offset_y;
++
++ memcpy (opt_inactive_shadow.shadow_color, shadow_color, sizeof (shadow_color));
++
++ switch (shadow_type)
++ {
++ case SHADOW_TYPE_ACTIVE_NORMAL:
++ return decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _win_extents.left,
++ _win_extents.right,
++ _win_extents.top + titlebar_height,
++ _win_extents.bottom,
++ _win_extents.left -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.right -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.top + titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.bottom -
++ TRANSLUCENT_CORNER_SIZE,
++ &opt_active_shadow,
++ &window_active_context,
++ draw_border_shape,
++ 0);
++ break;
++ case SHADOW_TYPE_INACTIVE_NORMAL:
++ return decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _win_extents.left,
++ _win_extents.right,
++ _win_extents.top + titlebar_height,
++ _win_extents.bottom,
++ _win_extents.left -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.right -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.top + titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.bottom -
++ TRANSLUCENT_CORNER_SIZE,
++ &opt_inactive_shadow,
++ &window_inactive_context,
++ draw_border_shape,
++ 0);
++ case SHADOW_TYPE_ACTIVE_MAX:
++ return decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _max_win_extents.left,
++ _max_win_extents.right,
++ _max_win_extents.top + max_titlebar_height,
++ _max_win_extents.bottom,
++ _max_win_extents.left - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.right - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.top + max_titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.bottom - TRANSLUCENT_CORNER_SIZE,
++ &opt_active_shadow,
++ &max_window_active_context,
++ draw_border_shape,
++ (void *) 1);
++ case SHADOW_TYPE_INACTIVE_MAX:
++ return decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _max_win_extents.left,
++ _max_win_extents.right,
++ _max_win_extents.top + max_titlebar_height,
++ _max_win_extents.bottom,
++ _max_win_extents.left - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.right - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.top + max_titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.bottom - TRANSLUCENT_CORNER_SIZE,
++ &opt_inactive_shadow,
++ &max_window_inactive_context,
++ draw_border_shape,
++ (void *) 1);
++ default:
++ return NULL;
++ }
++
++ return NULL;
++}
++
++void
++get_shadow (decor_t *d, gint shadow_type)
++{
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/config.h.gtk.in
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/config.h.gtk.in 2011-04-06 22:06:48.531070622 +0800
+@@ -0,0 +1,25 @@
++/* Define to 1 if Metacity support is enabled */
++#cmakedefine USE_METACITY 1
++
++/* Define to 1 if Gconf support is enabled */
++#cmakedefine USE_GCONF_UNITY_WINDOW_DECORATOR 1
++
++/* Define to 1 if you have the `wnck_window_has_name' function. */
++#cmakedefine HAVE_WNCK_WINDOW_HAS_NAME 1
++
++/* Define to 1 if libwnck version >= 2_18_1 */
++#cmakedefine HAVE_LIBWNCK_2_18_1 1
++
++/* Define to 1 if libwnck version >= 2_19_4 */
++#cmakedefine HAVE_LIBWNCK_2_19_4 1
++
++/* Define to 1 if metacity version >= 2.15.21 */
++#cmakedefine HAVE_METACITY_2_15_21 1
++
++/* Define to 1 if metacity version >= 2.17.0 */
++#cmakedefine HAVE_METACITY_2_17_0 1
++
++/* Define to 1 if metacity version >= 2.23.2 */
++#cmakedefine HAVE_METACITY_2_23_2 1
++
++#define GETTEXT_PACKAGE "${GETTEXT_PACKAGE}"
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/decorator.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/decorator.c 2011-04-06 22:06:48.535070637 +0800
+@@ -0,0 +1,874 @@
++#include "gtk-window-decorator.h"
++
++static const PangoFontDescription *
++get_titlebar_font (void)
++{
++ if (use_system_font)
++ {
++ return NULL;
++ }
++ else
++ return titlebar_font;
++}
++
++void
++update_titlebar_font (void)
++{
++ const PangoFontDescription *font_desc;
++ PangoFontMetrics *metrics;
++ PangoLanguage *lang;
++
++ font_desc = get_titlebar_font ();
++ if (!font_desc)
++ {
++ GtkStyle *default_style;
++
++ default_style = gtk_widget_get_default_style ();
++ font_desc = default_style->font_desc;
++ }
++
++ pango_context_set_font_description (pango_context, font_desc);
++
++ lang = pango_context_get_language (pango_context);
++ metrics = pango_context_get_metrics (pango_context, font_desc, lang);
++
++ text_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
++ pango_font_metrics_get_descent (metrics));
++
++ pango_font_metrics_unref (metrics);
++}
++
++void
++update_event_windows (WnckWindow *win)
++{
++ Display *xdisplay;
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ gint x0, y0, width, height, x, y, w, h;
++ gint i, j, k, l;
++ gint actions = d->actions;
++
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++
++ wnck_window_get_client_window_geometry (win, &x0, &y0, &width, &height);
++
++ if (d->state & WNCK_WINDOW_STATE_SHADED)
++ {
++ height = 0;
++ k = l = 1;
++ }
++ else
++ {
++ k = 0;
++ l = 2;
++ }
++
++ gdk_error_trap_push ();
++
++ for (i = 0; i < 3; i++)
++ {
++ static guint event_window_actions[3][3] = {
++ {
++ WNCK_WINDOW_ACTION_RESIZE,
++ WNCK_WINDOW_ACTION_RESIZE,
++ WNCK_WINDOW_ACTION_RESIZE
++ }, {
++ WNCK_WINDOW_ACTION_RESIZE,
++ WNCK_WINDOW_ACTION_MOVE,
++ WNCK_WINDOW_ACTION_RESIZE
++ }, {
++ WNCK_WINDOW_ACTION_RESIZE,
++ WNCK_WINDOW_ACTION_RESIZE,
++ WNCK_WINDOW_ACTION_RESIZE
++ }
++ };
++
++ for (j = 0; j < 3; j++)
++ {
++ w = 0;
++ h = 0;
++
++ if (actions & event_window_actions[i][j] && i >= k && i <= l)
++ (*theme_get_event_window_position) (d, i, j, width, height,
++ &x, &y, &w, &h);
++
++ if (d->frame_window)
++ {
++ BoxPtr box = &d->event_windows[i][j].pos;
++ box->x1 = x;
++ box->x2 = x + w;
++ box->y1 = y;
++ box->y2 = y + h;
++ }
++ else if (!d->frame_window && w != 0 && h != 0)
++ {
++ XMapWindow (xdisplay, d->event_windows[i][j].window);
++ XMoveResizeWindow (xdisplay, d->event_windows[i][j].window,
++ x, y, w, h);
++ }
++ else if (!d->frame_window)
++ {
++ XUnmapWindow (xdisplay, d->event_windows[i][j].window);
++ }
++ }
++ }
++
++ /* no button event windows if width is less than minimum width */
++ if (width < ICON_SPACE + d->button_width)
++ actions = 0;
++
++ for (i = 0; i < BUTTON_NUM; i++)
++ {
++ static guint button_actions[BUTTON_NUM] = {
++ WNCK_WINDOW_ACTION_CLOSE,
++ WNCK_WINDOW_ACTION_MAXIMIZE,
++ WNCK_WINDOW_ACTION_MINIMIZE,
++ 0,
++ WNCK_WINDOW_ACTION_SHADE,
++
++#ifdef HAVE_LIBWNCK_2_18_1
++ WNCK_WINDOW_ACTION_ABOVE,
++ WNCK_WINDOW_ACTION_STICK,
++ WNCK_WINDOW_ACTION_UNSHADE,
++ WNCK_WINDOW_ACTION_ABOVE,
++ WNCK_WINDOW_ACTION_UNSTICK
++#else
++ 0,
++ 0,
++ 0,
++ 0,
++ 0
++#endif
++
++ };
++
++ if (d->frame_window &&
++ button_actions[i] && !(actions & button_actions[i]))
++ {
++ memset (&d->button_windows[i].pos, 0, sizeof (Box));
++ }
++ else if (!d->frame_window &&
++ button_actions[i] && !(actions & button_actions[i]))
++ {
++ XUnmapWindow (xdisplay, d->button_windows[i].window);
++ continue;
++ }
++
++ if (d->frame_window &&
++ (*theme_get_button_position) (d, i, width, height, &x, &y, &w, &h))
++ {
++ BoxPtr box = &d->button_windows[i].pos;
++ box->x1 = x;
++ box->y1 = y;
++ box->x2 = x + w;
++ box->y2 = y + h;
++ }
++ else if (!d->frame_window &&
++ (*theme_get_button_position) (d, i, width, height,
++ &x, &y, &w, &h))
++ {
++ Window win = d->button_windows[i].window;
++ XMapWindow (xdisplay, win);
++ XMoveResizeWindow (xdisplay, win, x, y, w, h);
++ }
++ else if (!d->frame_window)
++ {
++ XUnmapWindow (xdisplay, d->button_windows[i].window);
++ }
++ }
++
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++}
++
++#ifdef HAVE_WNCK_WINDOW_HAS_NAME
++static const char *
++wnck_window_get_real_name (WnckWindow *win)
++{
++ return wnck_window_has_name (win) ? wnck_window_get_name (win) : NULL;
++}
++#define wnck_window_get_name wnck_window_get_real_name
++#endif
++
++gint
++max_window_name_width (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ const gchar *name;
++ gint w;
++
++ if (!d->layout)
++ {
++ d->layout = pango_layout_new (pango_context);
++ if (!d->layout)
++ return 0;
++
++ pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
++ }
++
++ name = wnck_window_get_name (win);
++ if (!name)
++ return 0;
++
++ pango_layout_set_auto_dir (d->layout, FALSE);
++ pango_layout_set_width (d->layout, -1);
++ pango_layout_set_text (d->layout, name, strlen (name));
++ pango_layout_get_pixel_size (d->layout, &w, NULL);
++
++ if (d->name)
++ pango_layout_set_text (d->layout, d->name, strlen (d->name));
++
++ return w + 6;
++}
++
++void
++update_window_decoration_name (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ const gchar *name;
++ glong name_length;
++ PangoLayoutLine *line;
++
++ if (d->name)
++ {
++ g_free (d->name);
++ d->name = NULL;
++ }
++
++ name = wnck_window_get_name (win);
++ if (name && (name_length = strlen (name)))
++ {
++ gint w;
++
++ if (theme_draw_window_decoration != draw_window_decoration)
++ {
++ w = SHRT_MAX;
++ }
++ else
++ {
++ gint width;
++
++ wnck_window_get_client_window_geometry (win, NULL, NULL,
++ &width, NULL);
++
++ w = width - ICON_SPACE - 2 - d->button_width;
++ if (w < 1)
++ w = 1;
++ }
++
++ pango_layout_set_auto_dir (d->layout, FALSE);
++ pango_layout_set_width (d->layout, w * PANGO_SCALE);
++ pango_layout_set_text (d->layout, name, name_length);
++
++ line = pango_layout_get_line (d->layout, 0);
++
++ name_length = line->length;
++ if (pango_layout_get_line_count (d->layout) > 1)
++ {
++ if (name_length < 4)
++ {
++ pango_layout_set_text (d->layout, NULL, 0);
++ return;
++ }
++
++ d->name = g_strndup (name, name_length);
++ strcpy (d->name + name_length - 3, "...");
++ }
++ else
++ d->name = g_strndup (name, name_length);
++
++ pango_layout_set_text (d->layout, d->name, name_length);
++ }
++}
++
++void
++update_window_decoration_icon (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->icon)
++ {
++ cairo_pattern_destroy (d->icon);
++ d->icon = NULL;
++ }
++
++ if (d->icon_pixmap)
++ {
++ g_object_unref (G_OBJECT (d->icon_pixmap));
++ d->icon_pixmap = NULL;
++ }
++
++ if (d->icon_pixbuf)
++ g_object_unref (G_OBJECT (d->icon_pixbuf));
++
++ d->icon_pixbuf = wnck_window_get_mini_icon (win);
++ if (d->icon_pixbuf)
++ {
++ cairo_t *cr;
++
++ g_object_ref (G_OBJECT (d->icon_pixbuf));
++
++ if (d->frame_window)
++ d->icon_pixmap = pixmap_new_from_pixbuf (d->icon_pixbuf,
++ 24);
++ else
++ d->icon_pixmap = pixmap_new_from_pixbuf (d->icon_pixbuf,
++ 32);
++ cr = gdk_cairo_create (GDK_DRAWABLE (d->icon_pixmap));
++ d->icon = cairo_pattern_create_for_surface (cairo_get_target (cr));
++ cairo_destroy (cr);
++ }
++}
++
++gboolean
++update_window_decoration_size (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ GdkPixmap *pixmap, *buffer_pixmap = NULL;
++ Picture picture;
++ gint width, height;
++ gint x, y, w, h, name_width;
++ Display *xdisplay;
++ XRenderPictFormat *format;
++ int depth;
++
++ if (!d)
++ return FALSE;
++
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++
++ wnck_window_get_client_window_geometry (win, &x, &y, &w, &h);
++
++ name_width = max_window_name_width (win);
++
++ if (!(*theme_calc_decoration_size) (d, w, h, name_width, &width, &height))
++ {
++ update_window_decoration_name (win);
++ return FALSE;
++ }
++
++ gdk_error_trap_push ();
++
++ if (d->frame_window)
++ depth = gdk_drawable_get_depth (GDK_DRAWABLE (d->frame_window));
++ else
++ depth = 32;
++
++ pixmap = create_pixmap (width, height, depth);
++
++ gdk_flush ();
++
++ if (!pixmap || gdk_error_trap_pop ())
++ {
++ memset (pixmap, 0, sizeof (pixmap));
++ return FALSE;
++ }
++
++ gdk_error_trap_push ();
++
++ buffer_pixmap = create_pixmap (width, height, depth);
++
++ gdk_flush ();
++
++ if (!buffer_pixmap || gdk_error_trap_pop ())
++ {
++ memset (buffer_pixmap, 0, sizeof (buffer_pixmap));
++ g_object_unref (G_OBJECT (pixmap));
++ return FALSE;
++ }
++
++ format = get_format_for_drawable (d, GDK_DRAWABLE (buffer_pixmap));
++ picture = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (buffer_pixmap),
++ format, 0, NULL);
++
++ if (d->pixmap)
++ g_object_unref (G_OBJECT (d->pixmap));
++
++ if (d->buffer_pixmap)
++ g_object_unref (G_OBJECT (d->buffer_pixmap));
++
++ if (d->picture)
++ XRenderFreePicture (xdisplay, d->picture);
++
++ if (d->cr)
++ cairo_destroy (d->cr);
++
++ d->pixmap = pixmap;
++ d->buffer_pixmap = buffer_pixmap;
++ d->cr = gdk_cairo_create (pixmap);
++
++ d->picture = picture;
++
++ d->width = width;
++ d->height = height;
++
++ d->prop_xid = wnck_window_get_xid (win);
++
++ update_window_decoration_name (win);
++
++ queue_decor_draw (d);
++
++ return TRUE;
++}
++
++void
++draw_border_shape (Display *xdisplay,
++ Pixmap pixmap,
++ Picture picture,
++ int width,
++ int height,
++ decor_context_t *c,
++ void *closure)
++{
++ static XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
++ GdkColormap *colormap;
++ decor_t d;
++ double save_decoration_alpha;
++
++ memset (&d, 0, sizeof (d));
++
++ d.pixmap = gdk_pixmap_foreign_new_for_display (gdk_display_get_default (),
++ pixmap);
++ d.width = width;
++ d.height = height;
++ d.active = TRUE;
++ d.draw = theme_draw_window_decoration;
++ d.picture = picture;
++ d.context = c;
++
++ /* we use closure argument if maximized */
++ if (closure)
++ d.state |=
++ WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
++ WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY;
++
++ decor_get_default_layout (c, 1, 1, &d.border_layout);
++
++ colormap = get_colormap_for_drawable (GDK_DRAWABLE (d.pixmap));
++ gdk_drawable_set_colormap (d.pixmap, colormap);
++
++ /* create shadow from opaque decoration */
++ save_decoration_alpha = decoration_alpha;
++ decoration_alpha = 1.0;
++
++ (*d.draw) (&d);
++
++ decoration_alpha = save_decoration_alpha;
++
++ XRenderFillRectangle (xdisplay, PictOpSrc, picture, &white,
++ c->left_space,
++ c->top_space,
++ width - c->left_space - c->right_space,
++ height - c->top_space - c->bottom_space);
++
++ g_object_unref (G_OBJECT (d.pixmap));
++}
++
++int
++update_shadow (void)
++{
++ decor_shadow_options_t opt_active_shadow;
++ decor_shadow_options_t opt_inactive_shadow;
++ decor_shadow_options_t opt_no_shadow;
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ GdkDisplay *display = gdk_display_get_default ();
++ GdkScreen *screen = gdk_display_get_default_screen (display);
++
++ opt_active_shadow.shadow_radius = shadow_radius;
++ opt_active_shadow.shadow_opacity = shadow_opacity;
++
++ memcpy (opt_active_shadow.shadow_color, shadow_color, sizeof (shadow_color));
++
++ opt_active_shadow.shadow_offset_x = shadow_offset_x;
++ opt_active_shadow.shadow_offset_y = shadow_offset_y;
++
++ opt_inactive_shadow.shadow_radius = shadow_radius;
++ opt_inactive_shadow.shadow_opacity = shadow_opacity;
++
++ memcpy (opt_inactive_shadow.shadow_color, shadow_color, sizeof (shadow_color));
++
++ opt_inactive_shadow.shadow_offset_x = shadow_offset_x;
++ opt_inactive_shadow.shadow_offset_y = shadow_offset_y;
++
++ opt_no_shadow.shadow_radius = 0;
++ opt_no_shadow.shadow_opacity = 0;
++
++ opt_no_shadow.shadow_offset_x = 0;
++ opt_no_shadow.shadow_offset_y = 0;
++
++ if (no_border_shadow)
++ {
++ decor_shadow_destroy (xdisplay, no_border_shadow);
++ no_border_shadow = NULL;
++ }
++
++ no_border_shadow = decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ 0,
++ 0,
++ 0,
++ 0,
++ 0, 0, 0, 0,
++ &opt_inactive_shadow,
++ &shadow_context,
++ decor_draw_simple,
++ 0);
++
++ if (border_active_shadow)
++ {
++ decor_shadow_destroy (xdisplay, border_active_shadow);
++ border_active_shadow = NULL;
++ }
++
++ border_active_shadow = (*theme_update_shadow) (SHADOW_TYPE_ACTIVE_NORMAL);
++
++ if (!border_active_shadow)
++ border_active_shadow = cairo_update_shadow (SHADOW_TYPE_ACTIVE_NORMAL);
++
++ if (border_inactive_shadow)
++ {
++ decor_shadow_destroy (xdisplay, border_inactive_shadow);
++ border_inactive_shadow = NULL;
++ }
++
++ border_inactive_shadow = (*theme_update_shadow) (SHADOW_TYPE_INACTIVE_NORMAL);
++
++ if (!border_inactive_shadow)
++ border_inactive_shadow = cairo_update_shadow (SHADOW_TYPE_INACTIVE_NORMAL);
++
++ if (border_no_shadow)
++ {
++ decor_shadow_destroy (xdisplay, border_no_shadow);
++ border_no_shadow = NULL;
++ }
++
++ border_no_shadow = decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _win_extents.left,
++ _win_extents.right,
++ _win_extents.top + titlebar_height,
++ _win_extents.bottom,
++ _win_extents.left -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.right -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.top + titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.bottom -
++ TRANSLUCENT_CORNER_SIZE,
++ &opt_no_shadow,
++ &window_context_no_shadow,
++ draw_border_shape,
++ 0);
++
++
++ if (max_border_active_shadow)
++ {
++ decor_shadow_destroy (xdisplay, max_border_active_shadow);
++ max_border_active_shadow = NULL;
++ }
++
++ max_border_active_shadow = (*theme_update_shadow) (SHADOW_TYPE_ACTIVE_MAX);
++
++ if (!max_border_active_shadow)
++ max_border_active_shadow = cairo_update_shadow (SHADOW_TYPE_ACTIVE_MAX);
++
++ if (max_border_inactive_shadow)
++ {
++ decor_shadow_destroy (xdisplay, max_border_inactive_shadow);
++ max_border_inactive_shadow = NULL;
++ }
++
++ max_border_inactive_shadow = (*theme_update_shadow) (SHADOW_TYPE_INACTIVE_MAX);
++
++ if (!max_border_inactive_shadow)
++ max_border_inactive_shadow = cairo_update_shadow (SHADOW_TYPE_INACTIVE_MAX);
++
++ if (max_border_no_shadow)
++ {
++ decor_shadow_destroy (xdisplay, max_border_active_shadow);
++ max_border_active_shadow = NULL;
++ }
++
++ max_border_no_shadow =
++ decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _max_win_extents.left,
++ _max_win_extents.right,
++ _max_win_extents.top + max_titlebar_height,
++ _max_win_extents.bottom,
++ _max_win_extents.left - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.right - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.top + max_titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.bottom - TRANSLUCENT_CORNER_SIZE,
++ &opt_no_shadow,
++ &max_window_context_no_shadow,
++ draw_border_shape,
++ (void *) 1);
++
++ if (switcher_shadow)
++ {
++ decor_shadow_destroy (xdisplay, switcher_shadow);
++ switcher_shadow = NULL;
++ }
++
++ switcher_shadow = decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _switcher_extents.left,
++ _switcher_extents.right,
++ _switcher_extents.top,
++ _switcher_extents.bottom,
++ _switcher_extents.left -
++ TRANSLUCENT_CORNER_SIZE,
++ _switcher_extents.right -
++ TRANSLUCENT_CORNER_SIZE,
++ _switcher_extents.top -
++ TRANSLUCENT_CORNER_SIZE,
++ _switcher_extents.bottom -
++ TRANSLUCENT_CORNER_SIZE,
++ &opt_inactive_shadow,
++ &switcher_context,
++ decor_draw_simple,
++ 0);
++
++ return 1;
++}
++
++void
++update_window_decoration (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->decorated)
++ {
++ /* force size update */
++ d->context = NULL;
++ d->width = d->height = 0;
++
++ update_window_decoration_size (win);
++ update_event_windows (win);
++ }
++}
++
++void
++update_window_decoration_state (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ d->state = wnck_window_get_state (win);
++}
++
++void
++update_window_decoration_actions (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ d->actions = wnck_window_get_actions (win);
++}
++
++static gboolean
++draw_decor_list (void *data)
++{
++ GSList *list;
++ decor_t *d;
++
++ draw_idle_id = 0;
++
++ for (list = draw_list; list; list = list->next)
++ {
++ d = (decor_t *) list->data;
++ (*d->draw) (d);
++ }
++
++ g_slist_free (draw_list);
++ draw_list = NULL;
++
++ return FALSE;
++}
++
++void
++queue_decor_draw (decor_t *d)
++{
++ if (g_slist_find (draw_list, d))
++ return;
++
++ draw_list = g_slist_append (draw_list, d);
++
++ if (!draw_idle_id)
++ draw_idle_id = g_idle_add (draw_decor_list, NULL);
++}
++
++void
++update_default_decorations (GdkScreen *screen)
++{
++ long data[256];
++ Window xroot;
++ GdkDisplay *gdkdisplay = gdk_display_get_default ();
++ Display *xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
++ Atom bareAtom, normalAtom, activeAtom;
++ decor_t d;
++ gint nQuad;
++ decor_quad_t quads[N_QUADS_MAX];
++ decor_extents_t extents = extents, frame_extents, max_extents, frame_max_extents;
++
++ (*theme_get_border_extents) (&extents, &frame_extents, &max_extents, &frame_max_extents);
++
++ xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
++
++ bareAtom = XInternAtom (xdisplay, DECOR_BARE_ATOM_NAME, FALSE);
++ normalAtom = XInternAtom (xdisplay, DECOR_NORMAL_ATOM_NAME, FALSE);
++ activeAtom = XInternAtom (xdisplay, DECOR_ACTIVE_ATOM_NAME, FALSE);
++
++ if (no_border_shadow)
++ {
++ decor_layout_t layout;
++
++ decor_get_default_layout (&shadow_context, 1, 1, &layout);
++
++ nQuad = decor_set_lSrStSbS_window_quads (quads, &shadow_context,
++ &layout);
++
++ decor_quads_to_property (data, no_border_shadow->pixmap,
++ &_shadow_extents, &_shadow_extents,
++ &_shadow_extents, &_shadow_extents,
++ 0, 0, quads, nQuad);
++
++ XChangeProperty (xdisplay, xroot,
++ bareAtom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
++
++ if (minimal)
++ {
++ XChangeProperty (xdisplay, xroot,
++ normalAtom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
++ XChangeProperty (xdisplay, xroot,
++ activeAtom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
++ }
++ }
++ else
++ {
++ XDeleteProperty (xdisplay, xroot, bareAtom);
++
++ if (minimal)
++ {
++ XDeleteProperty (xdisplay, xroot, normalAtom);
++ XDeleteProperty (xdisplay, xroot, activeAtom);
++ }
++ }
++
++ if (minimal)
++ return;
++
++ memset (&d, 0, sizeof (d));
++
++ d.context = &window_inactive_context;
++ d.shadow = border_inactive_shadow;
++
++ d.layout = pango_layout_new (pango_context);
++
++ decor_get_default_layout (d.context, 1, 1, &d.border_layout);
++
++ d.width = d.border_layout.width;
++ d.height = d.border_layout.height;
++
++ d.draw = theme_draw_window_decoration;
++
++ if (decor_normal_pixmap)
++ g_object_unref (G_OBJECT (decor_normal_pixmap));
++
++ nQuad = decor_set_lSrStSbS_window_quads (quads, d.context,
++ &d.border_layout);
++
++ decor_normal_pixmap = create_pixmap (d.width, d.height, 32);
++
++ if (decor_normal_pixmap)
++ {
++ d.pixmap = decor_normal_pixmap;
++ d.active = FALSE;
++ d.picture = XRenderCreatePicture (xdisplay,
++ GDK_PIXMAP_XID (d.pixmap),
++ xformat_rgba, 0, NULL);
++
++ (*d.draw) (&d);
++
++ XRenderFreePicture (xdisplay, d.picture);
++
++ decor_quads_to_property (data, GDK_PIXMAP_XID (d.pixmap),
++ &frame_extents, &extents, &frame_max_extents, &max_extents, 0, 0, quads, nQuad);
++
++ XChangeProperty (xdisplay, xroot,
++ normalAtom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
++ }
++
++ if (decor_active_pixmap)
++ g_object_unref (G_OBJECT (decor_active_pixmap));
++
++ if (d.layout)
++ g_object_unref (G_OBJECT (d.layout));
++
++ d.context = &window_active_context;
++ d.shadow = border_active_shadow;
++
++ d.layout = pango_layout_new (pango_context);
++
++ decor_get_default_layout (d.context, 1, 1, &d.border_layout);
++
++ d.width = d.border_layout.width;
++ d.height = d.border_layout.height;
++
++ nQuad = decor_set_lSrStSbS_window_quads (quads, d.context,
++ &d.border_layout);
++
++ decor_active_pixmap = create_pixmap (d.width, d.height, 32);
++
++ if (decor_active_pixmap)
++ {
++ d.pixmap = decor_active_pixmap;
++ d.active = TRUE;
++ d.picture = XRenderCreatePicture (xdisplay,
++ GDK_PIXMAP_XID (d.pixmap),
++ xformat_rgba, 0, NULL);
++
++ (*d.draw) (&d);
++
++ XRenderFreePicture (xdisplay, d.picture);
++
++ decor_quads_to_property (data, GDK_PIXMAP_XID (d.pixmap),
++ &frame_extents, &extents, &frame_max_extents, &max_extents, 0, 0, quads, nQuad);
++
++ XChangeProperty (xdisplay, xroot,
++ activeAtom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
++ }
++
++ if (d.layout)
++ g_object_unref (G_OBJECT (d.layout));
++}
++
++void
++copy_to_front_buffer (decor_t *d)
++{
++ if (!d->buffer_pixmap)
++ return;
++
++ cairo_set_operator (d->cr, CAIRO_OPERATOR_SOURCE);
++ gdk_cairo_set_source_pixmap (d->cr, d->buffer_pixmap, 0, 0);
++ cairo_paint (d->cr);
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/decorprops.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/decorprops.c 2011-04-06 22:06:48.539070662 +0800
+@@ -0,0 +1,150 @@
++#include "gtk-window-decorator.h"
++
++void
++get_border_extents (decor_extents_t *extents,
++ decor_extents_t *frame_extents,
++ decor_extents_t *max_extents,
++ decor_extents_t *frame_max_extents)
++{
++ *extents = *frame_extents = _win_extents;
++ *max_extents = *frame_max_extents = _max_win_extents;
++
++ extents->top += titlebar_height;
++ frame_extents->top += titlebar_height;
++ max_extents->top += max_titlebar_height;
++ frame_max_extents->top += max_titlebar_height;
++}
++
++void
++decor_update_window_property (decor_t *d)
++{
++ long data[256];
++ Display *xdisplay =
++ GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ decor_extents_t extents = _win_extents;
++ gint nQuad;
++ decor_quad_t quads[N_QUADS_MAX];
++ int w, h;
++ gint stretch_offset;
++ REGION top, bottom, left, right;
++
++ w = d->border_layout.top.x2 - d->border_layout.top.x1 -
++ d->context->left_space - d->context->right_space;
++
++ if (d->border_layout.rotation)
++ h = d->border_layout.left.x2 - d->border_layout.left.x1;
++ else
++ h = d->border_layout.left.y2 - d->border_layout.left.y1;
++
++ stretch_offset = w - d->button_width - 1;
++
++ nQuad = decor_set_lSrStXbS_window_quads (quads, d->context,
++ &d->border_layout,
++ stretch_offset);
++
++ extents.top += titlebar_height;
++
++ if (d->frame_window)
++ {
++ decor_gen_window_property (data, &extents, &extents, 20, 20);
++ }
++ else
++ {
++ decor_quads_to_property (data, GDK_PIXMAP_XID (d->pixmap),
++ &extents, &extents, &extents, &extents,
++ ICON_SPACE + d->button_width,
++ 0,
++ quads, nQuad);
++ }
++
++ gdk_error_trap_push ();
++ XChangeProperty (xdisplay, d->prop_xid,
++ win_decor_atom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++
++ top.rects = &top.extents;
++ top.numRects = top.size = 1;
++
++ top.extents.x1 = -extents.left;
++ top.extents.y1 = -extents.top;
++ top.extents.x2 = w + extents.right;
++ top.extents.y2 = 0;
++
++ bottom.rects = &bottom.extents;
++ bottom.numRects = bottom.size = 1;
++
++ bottom.extents.x1 = -extents.left;
++ bottom.extents.y1 = 0;
++ bottom.extents.x2 = w + extents.right;
++ bottom.extents.y2 = extents.bottom;
++
++ left.rects = &left.extents;
++ left.numRects = left.size = 1;
++
++ left.extents.x1 = -extents.left;
++ left.extents.y1 = 0;
++ left.extents.x2 = 0;
++ left.extents.y2 = h;
++
++ right.rects = &right.extents;
++ right.numRects = right.size = 1;
++
++ right.extents.x1 = 0;
++ right.extents.y1 = 0;
++ right.extents.x2 = extents.right;
++ right.extents.y2 = h;
++
++ decor_update_blur_property (d,
++ w, h,
++ &top, stretch_offset,
++ &bottom, w / 2,
++ &left, h / 2,
++ &right, h / 2);
++}
++
++void
++decor_update_switcher_property (decor_t *d)
++{
++ long data[256];
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ gint nQuad;
++ decor_quad_t quads[N_QUADS_MAX];
++ GtkStyle *style;
++ long fgColor[4];
++
++ nQuad = decor_set_lSrStSbX_window_quads (quads, &switcher_context,
++ &d->border_layout,
++ d->border_layout.top.x2 -
++ d->border_layout.top.x1 -
++ switcher_context.extents.left -
++ switcher_context.extents.right -
++ 32);
++
++ decor_quads_to_property (data, GDK_PIXMAP_XID (d->pixmap),
++ &_switcher_extents, &_switcher_extents,
++ &_switcher_extents, &_switcher_extents,
++ 0, 0, quads, nQuad);
++
++ style = gtk_widget_get_style (style_window_rgba);
++
++ fgColor[0] = style->fg[GTK_STATE_NORMAL].red;
++ fgColor[1] = style->fg[GTK_STATE_NORMAL].green;
++ fgColor[2] = style->fg[GTK_STATE_NORMAL].blue;
++ fgColor[3] = SWITCHER_ALPHA;
++
++ gdk_error_trap_push ();
++ XChangeProperty (xdisplay, d->prop_xid,
++ win_decor_atom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
++ XChangeProperty (xdisplay, d->prop_xid, switcher_fg_atom,
++ XA_INTEGER, 32, PropModeReplace, (guchar *) fgColor, 4);
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/events.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/events.c 2011-04-06 22:08:44.707646711 +0800
+@@ -0,0 +1,1175 @@
++#include "gtk-window-decorator.h"
++
++void
++move_resize_window (WnckWindow *win,
++ int direction,
++ decor_event *gtkwd_event)
++{
++ Display *xdisplay;
++ GdkDisplay *gdkdisplay;
++ GdkScreen *screen;
++ Window xroot;
++ XEvent ev;
++
++ gdkdisplay = gdk_display_get_default ();
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
++ screen = gdk_display_get_default_screen (gdkdisplay);
++ xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
++
++ if (action_menu_mapped)
++ {
++ gtk_object_destroy (GTK_OBJECT (action_menu));
++ action_menu_mapped = FALSE;
++ action_menu = NULL;
++ return;
++ }
++
++ ev.xclient.type = ClientMessage;
++ ev.xclient.display = xdisplay;
++
++ ev.xclient.serial = 0;
++ ev.xclient.send_event = TRUE;
++
++ ev.xclient.window = wnck_window_get_xid (win);
++ ev.xclient.message_type = wm_move_resize_atom;
++ ev.xclient.format = 32;
++
++ ev.xclient.data.l[0] = gtkwd_event->x_root;
++ ev.xclient.data.l[1] = gtkwd_event->y_root;
++ ev.xclient.data.l[2] = direction;
++ ev.xclient.data.l[3] = gtkwd_event->button;
++ ev.xclient.data.l[4] = 1;
++
++ XUngrabPointer (xdisplay, gtkwd_event->time);
++ XUngrabKeyboard (xdisplay, gtkwd_event->time);
++
++ XSendEvent (xdisplay, xroot, FALSE,
++ SubstructureRedirectMask | SubstructureNotifyMask,
++ &ev);
++
++ XSync (xdisplay, FALSE);
++}
++
++void
++common_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type,
++ int button,
++ int max)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[button];
++
++ if (d->frame_window && gtkwd_type == GEnterNotify)
++ {
++ GdkCursor* cursor;
++ cursor = gdk_cursor_new (GDK_LEFT_PTR);
++ gdk_window_set_cursor (d->frame_window, cursor);
++ gdk_cursor_unref (cursor);
++ }
++
++ switch (gtkwd_type) {
++ case GButtonPress:
++ if (gtkwd_event->button <= max)
++ d->button_states[button] |= PRESSED_EVENT_WINDOW;
++ break;
++ case GButtonRelease:
++ if (gtkwd_event->button <= max)
++ d->button_states[button] &= ~PRESSED_EVENT_WINDOW;
++ break;
++ case GEnterNotify:
++ d->button_states[button] |= IN_EVENT_WINDOW;
++ break;
++ case GLeaveNotify:
++ d->button_states[button] &= ~IN_EVENT_WINDOW;
++ break;
++ default:
++ break;
++ }
++
++ if (state != d->button_states[button])
++ queue_decor_draw (d);
++}
++
++#define BUTTON_EVENT_ACTION_STATE (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW)
++
++void
++close_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_CLOSE];
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_CLOSE, 1);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button == 1)
++ if (state == BUTTON_EVENT_ACTION_STATE)
++ wnck_window_close (win, gtkwd_event->time);
++ break;
++ default:
++ break;
++ }
++}
++
++void
++max_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_MAX];
++
++ if (wnck_window_is_maximized (win))
++ common_button_event (win, gtkwd_event, gtkwd_type, BUTTON_MAX,
++ 3);
++ else
++ common_button_event (win, gtkwd_event, gtkwd_type, BUTTON_MAX,
++ 3);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button <= 3)
++ {
++ if (state == BUTTON_EVENT_ACTION_STATE)
++ {
++ if (gtkwd_event->button == 2)
++ {
++ if (wnck_window_is_maximized_vertically (win))
++ wnck_window_unmaximize_vertically (win);
++ else
++ wnck_window_maximize_vertically (win);
++ }
++ else if (gtkwd_event->button == 3)
++ {
++ if (wnck_window_is_maximized_horizontally (win))
++ wnck_window_unmaximize_horizontally (win);
++ else
++ wnck_window_maximize_horizontally (win);
++ }
++ else
++ {
++ if (wnck_window_is_maximized (win))
++ wnck_window_unmaximize (win);
++ else
++ wnck_window_maximize (win);
++ }
++ }
++ }
++ break;
++ default:
++ break;
++ }
++}
++
++void
++min_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_MIN];
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_MIN, 1);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button == 1)
++ if (state == BUTTON_EVENT_ACTION_STATE)
++ wnck_window_minimize (win);
++ break;
++ default:
++ break;
++ }
++}
++
++void
++menu_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_MENU, 1);
++
++ switch (gtkwd_type) {
++ case GButtonPress:
++ if (gtkwd_event->button == 1)
++ action_menu_map (win,
++ gtkwd_event->button,
++ gtkwd_event->time);
++ break;
++ default:
++ break;
++ }
++}
++
++void
++shade_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_SHADE];
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_SHADE, 1);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button == 1)
++ {
++ if (state == BUTTON_EVENT_ACTION_STATE)
++ wnck_window_shade (win);
++ }
++ break;
++ default:
++ break;
++ }
++}
++
++void
++above_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_ABOVE];
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_ABOVE, 1);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button == 1)
++ if (state == BUTTON_EVENT_ACTION_STATE)
++#ifdef HAVE_LIBWNCK_2_18_1
++ wnck_window_make_above (win);
++#endif
++ break;
++ default:
++ break;
++ }
++}
++
++void
++stick_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_STICK];
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_STICK, 1);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button == 1)
++ if (state == BUTTON_EVENT_ACTION_STATE)
++ wnck_window_stick (win);
++ break;
++ default:
++ break;
++ }
++}
++
++void
++unshade_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_UNSHADE];
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_UNSHADE, 1);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button == 1)
++ if (state == BUTTON_EVENT_ACTION_STATE)
++ wnck_window_unshade (win);
++ break;
++ default:
++ break;
++ }
++}
++
++void
++unabove_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_UNABOVE];
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_UNABOVE, 1);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button == 1)
++ if (state == BUTTON_EVENT_ACTION_STATE)
++#ifdef HAVE_LIBWNCK_2_18_1
++ wnck_window_unmake_above (win);
++#endif
++ break;
++ default:
++ break;
++ }
++}
++
++void
++unstick_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ guint state = d->button_states[BUTTON_UNSTICK];
++
++ common_button_event (win, gtkwd_event, gtkwd_type,
++ BUTTON_UNSTICK, 1);
++
++ switch (gtkwd_type) {
++ case GButtonRelease:
++ if (gtkwd_event->button == 1)
++ if (state == BUTTON_EVENT_ACTION_STATE)
++ wnck_window_unstick (win);
++ break;
++ default:
++ break;
++ }
++}
++
++void
++handle_title_button_event (WnckWindow *win,
++ int action,
++ decor_event *gtkwd_event)
++{
++ switch (action) {
++ case CLICK_ACTION_SHADE:
++ if (wnck_window_is_shaded (win))
++ wnck_window_unshade (win);
++ else
++ wnck_window_shade (win);
++ break;
++ case CLICK_ACTION_MAXIMIZE:
++ if (wnck_window_is_maximized (win))
++ wnck_window_unmaximize (win);
++ else
++ wnck_window_maximize (win);
++ break;
++ case CLICK_ACTION_MINIMIZE:
++ if (!wnck_window_is_minimized (win))
++ wnck_window_minimize (win);
++ break;
++ case CLICK_ACTION_RAISE:
++ restack_window (win, Above);
++ break;
++ case CLICK_ACTION_LOWER:
++ restack_window (win, Below);
++ break;
++ case CLICK_ACTION_MENU:
++ action_menu_map (win, gtkwd_event->button, gtkwd_event->time);
++ break;
++ }
++}
++
++void
++handle_mouse_wheel_title_event (WnckWindow *win,
++ unsigned int button)
++{
++ switch (wheel_action) {
++ case WHEEL_ACTION_SHADE:
++ if (button == 4)
++ {
++ if (!wnck_window_is_shaded (win))
++ wnck_window_shade (win);
++ }
++ else if (button == 5)
++ {
++ if (wnck_window_is_shaded (win))
++ wnck_window_unshade (win);
++ }
++ break;
++ default:
++ break;
++ }
++}
++
++void
++title_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ static int last_button_num = 0;
++ static Window last_button_xwindow = None;
++ static Time last_button_time = 0;
++ static int last_button_x = 0;
++ static int last_button_y = 0;
++
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->frame_window && gtkwd_type == GEnterNotify)
++ {
++ GdkCursor* cursor = gdk_cursor_new (GDK_LEFT_PTR);
++ gdk_window_set_cursor (d->frame_window, cursor);
++ gdk_cursor_unref (cursor);
++ }
++
++ if (gtkwd_type != GButtonPress)
++ return;
++
++ if (gtkwd_event->button == 1)
++ {
++ if (gtkwd_event->button == last_button_num &&
++ gtkwd_event->window == last_button_xwindow &&
++ gtkwd_event->time < last_button_time + double_click_timeout &&
++ dist (gtkwd_event->x, gtkwd_event->y,
++ last_button_x, last_button_y) < DOUBLE_CLICK_DISTANCE)
++ {
++ handle_title_button_event (win, double_click_action,
++ gtkwd_event);
++
++ last_button_num = 0;
++ last_button_xwindow = None;
++ last_button_time = 0;
++ last_button_x = 0;
++ last_button_y = 0;
++ }
++ else
++ {
++ last_button_num = gtkwd_event->button;
++ last_button_xwindow = gtkwd_event->window;
++ last_button_time = gtkwd_event->time;
++ last_button_x = gtkwd_event->x;
++ last_button_y = gtkwd_event->y;
++
++ restack_window (win, Above);
++
++ move_resize_window (win, WM_MOVERESIZE_MOVE, gtkwd_event);
++ }
++ }
++ else if (gtkwd_event->button == 2)
++ {
++ handle_title_button_event (win, middle_click_action,
++ gtkwd_event);
++ }
++ else if (gtkwd_event->button == 3)
++ {
++ handle_title_button_event (win, right_click_action,
++ gtkwd_event);
++ }
++ else if (gtkwd_event->button == 4 ||
++ gtkwd_event->button == 5)
++ {
++ handle_mouse_wheel_title_event (win, gtkwd_event->button);
++ }
++}
++
++void
++frame_common_event (WnckWindow *win,
++ int direction,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->frame_window && gtkwd_type == GEnterNotify)
++ {
++ GdkCursor *cursor = NULL;
++
++ switch (direction)
++ {
++ case WM_MOVERESIZE_SIZE_TOPLEFT:
++ cursor = gdk_cursor_new (GDK_TOP_LEFT_CORNER);
++ break;
++ case WM_MOVERESIZE_SIZE_LEFT:
++ cursor = gdk_cursor_new (GDK_LEFT_SIDE);
++ break;
++ case WM_MOVERESIZE_SIZE_BOTTOMLEFT:
++ cursor = gdk_cursor_new (GDK_BOTTOM_LEFT_CORNER);
++ break;
++ case WM_MOVERESIZE_SIZE_BOTTOM:
++ cursor = gdk_cursor_new (GDK_BOTTOM_SIDE);
++ break;
++ case WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
++ cursor = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER);
++ break;
++ case WM_MOVERESIZE_SIZE_RIGHT:
++ cursor = gdk_cursor_new (GDK_RIGHT_SIDE);
++ break;
++ case WM_MOVERESIZE_SIZE_TOPRIGHT:
++ cursor = gdk_cursor_new (GDK_TOP_RIGHT_CORNER);
++ break;
++ case WM_MOVERESIZE_SIZE_TOP:
++ cursor = gdk_cursor_new (GDK_TOP_SIDE);
++ break;
++ default:
++ break;
++ }
++
++ if (cursor)
++ {
++ gdk_window_set_cursor (d->frame_window, cursor);
++ gdk_cursor_unref (cursor);
++ }
++ }
++
++ if (gtkwd_type != GButtonPress)
++ return;
++
++ switch (gtkwd_event->button) {
++ case 1:
++ move_resize_window (win, direction, gtkwd_event);
++ restack_window (win, Above);
++ break;
++ case 2:
++ handle_title_button_event (win, middle_click_action,
++ gtkwd_event);
++ break;
++ case 3:
++ handle_title_button_event (win, right_click_action,
++ gtkwd_event);
++ break;
++ }
++}
++
++void
++top_left_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ frame_common_event (win, WM_MOVERESIZE_SIZE_TOPLEFT,
++ gtkwd_event, gtkwd_type);
++}
++
++void
++top_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ frame_common_event (win, WM_MOVERESIZE_SIZE_TOP,
++ gtkwd_event, gtkwd_type);
++}
++
++void
++top_right_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ frame_common_event (win, WM_MOVERESIZE_SIZE_TOPRIGHT,
++ gtkwd_event, gtkwd_type);
++}
++
++void
++left_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ frame_common_event (win, WM_MOVERESIZE_SIZE_LEFT,
++ gtkwd_event, gtkwd_type);
++}
++
++void
++right_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ frame_common_event (win, WM_MOVERESIZE_SIZE_RIGHT,
++ gtkwd_event, gtkwd_type);
++}
++
++void
++bottom_left_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ frame_common_event (win, WM_MOVERESIZE_SIZE_BOTTOMLEFT,
++ gtkwd_event, gtkwd_type);
++}
++
++void
++bottom_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ frame_common_event (win, WM_MOVERESIZE_SIZE_BOTTOM,
++ gtkwd_event, gtkwd_type);
++}
++
++void
++bottom_right_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type)
++{
++ frame_common_event (win, WM_MOVERESIZE_SIZE_BOTTOMRIGHT,
++ gtkwd_event, gtkwd_type);
++}
++
++void
++frame_window_realized (GtkWidget *widget,
++ gpointer data)
++{
++ decor_t *d = (decor_t *) data;
++
++ if (d)
++ {
++ GdkWindow *gdk_frame_window = gtk_widget_get_window (d->decor_window);
++ gdk_window_reparent (gdk_frame_window, d->frame_window, 0, 0);
++ gdk_window_lower (gdk_frame_window);
++
++ }
++}
++
++event_callback
++find_event_callback_for_point (decor_t *d,
++ int x,
++ int y,
++ Bool *enter,
++ Bool *leave,
++ BoxPtr *entered_box)
++{
++ int i, j;
++ BoxPtr box;
++
++ for (i = 0; i < BUTTON_NUM; i++)
++ {
++ box = &d->button_windows[i].pos;
++ if (x >= box->x1 && x <= box->x2 &&
++ y >= box->y1 && y <= box->y2)
++ {
++ if (d->last_pos_entered != box)
++ {
++ if (enter)
++ *enter = TRUE;
++ if (leave && d->last_pos_entered)
++ *leave = TRUE;
++ if (entered_box)
++ *entered_box = box;
++ }
++ return d->button_windows[i].callback;
++ }
++ }
++
++ for (i = 0; i < 3; i++)
++ {
++ for (j = 0; j < 3; j++)
++ {
++ box = &d->event_windows[i][j].pos;
++ if (x >= box->x1 && x <= box->x2 &&
++ y >= box->y1 && y <= box->y2)
++ {
++ if (d->last_pos_entered != box)
++ {
++ if (enter)
++ *enter = TRUE;
++ if (leave && d->last_pos_entered)
++ *leave = TRUE;
++ if (entered_box)
++ *entered_box = box;
++ }
++ return d->event_windows[i][j].callback;
++ }
++ }
++ }
++
++ return NULL;
++}
++
++event_callback
++find_leave_event_callback (decor_t *d)
++{
++ int i, j;
++
++ for (i = 0; i < BUTTON_NUM; i++)
++ {
++ if (d->last_pos_entered == &d->button_windows[i].pos)
++ return d->button_windows[i].callback;
++ }
++
++ for (i = 0; i < 3; i++)
++ {
++ for (j = 0; j < 3; j++)
++ {
++ if (d->last_pos_entered == &d->event_windows[i][j].pos)
++ return d->event_windows[i][j].callback;
++ }
++ }
++
++ return NULL;
++}
++
++void
++frame_handle_button_press (GtkWidget *widget,
++ GdkEventButton *event,
++ gpointer user_data)
++{
++ decor_t *d = (decor_t *) user_data;
++
++ if (d)
++ {
++ /* Check to see where the event happened and fill out an appropriate
++ * struct
++ */
++ event_callback cb;
++
++ cb = find_event_callback_for_point (d, event->x, event->y,
++ NULL, NULL, NULL);
++
++ if (cb && d->decorated)
++ {
++ decor_event gtkwd_event;
++
++ gtkwd_event.window = GDK_WINDOW_XID (d->frame_window);
++ gtkwd_event.button = event->button;
++ gtkwd_event.x = event->x;
++ gtkwd_event.y = event->y;
++ gtkwd_event.x_root = event->x_root;
++ gtkwd_event.y_root = event->y_root;
++ gtkwd_event.time = event->time;
++
++ (*cb) (d->win, >kwd_event, GButtonPress);
++ }
++ }
++}
++
++void
++frame_handle_button_release (GtkWidget *widget,
++ GdkEventButton *event,
++ gpointer user_data)
++{
++ decor_t *d = (decor_t *) user_data;
++
++ if (d)
++ {
++ event_callback cb;
++
++ cb = find_event_callback_for_point (d, event->x, event->y,
++ NULL, NULL, NULL);
++
++ if (cb && d->decorated)
++ {
++ decor_event gtkwd_event;
++
++ gtkwd_event.window = GDK_WINDOW_XID (d->frame_window);
++ gtkwd_event.button = event->button;
++ gtkwd_event.x = event->x;
++ gtkwd_event.y = event->y;
++ gtkwd_event.x_root = event->x_root;
++ gtkwd_event.y_root = event->y_root;
++ gtkwd_event.time = event->time;
++
++ (*cb) (d->win, >kwd_event, GButtonRelease);
++ }
++ }
++}
++
++void
++frame_handle_motion (GtkWidget *widget,
++ GdkEventMotion *event,
++ gpointer user_data)
++{
++ decor_t *d = (decor_t *) user_data;
++
++ if (d)
++ {
++ event_callback cb = NULL;
++ Bool send_enter = FALSE;
++ Bool send_leave = FALSE;
++ BoxPtr entered_box;
++
++ cb = find_event_callback_for_point (d, event->x, event->y,
++ &send_enter, &send_leave,
++ &entered_box);
++
++ if (cb && d->decorated)
++ {
++ decor_event gtkwd_event;
++
++ gtkwd_event.window = GDK_WINDOW_XID (d->frame_window);
++ gtkwd_event.x = event->x;
++ gtkwd_event.y = event->y;
++ gtkwd_event.x_root = event->x_root;
++ gtkwd_event.y_root = event->y_root;
++ gtkwd_event.time = event->time;
++
++ if (send_enter)
++ (*cb) (d->win, >kwd_event, GEnterNotify);
++
++ if (send_leave)
++ {
++ event_callback leave_cb;
++
++ leave_cb = find_leave_event_callback (d);
++
++ if (leave_cb)
++ (*leave_cb) (d->win, >kwd_event, GLeaveNotify);
++
++ }
++
++ if (send_enter)
++ d->last_pos_entered = entered_box;
++ }
++ else if (d->last_pos_entered && d->decorated)
++ {
++ /* We are not in an event / button window but last_pos_entered
++ * is still set, so send a GLeaveNotify to last_pos_entered
++ * and set it to NULL
++ */
++
++ event_callback leave_cb;
++
++ leave_cb = find_leave_event_callback (d);
++
++ if (leave_cb)
++ {
++ decor_event gtkwd_event;
++
++ gtkwd_event.window = GDK_WINDOW_XID (d->frame_window);
++ gtkwd_event.x = event->x;
++ gtkwd_event.y = event->y;
++ gtkwd_event.x_root = event->x_root;
++ gtkwd_event.y_root = event->y_root;
++ gtkwd_event.time = event->time;
++
++ (*leave_cb) (d->win, >kwd_event, GLeaveNotify);
++ }
++
++ d->last_pos_entered = NULL;
++ }
++ }
++}
++
++GdkFilterReturn
++event_filter_func (GdkXEvent *gdkxevent,
++ GdkEvent *event,
++ gpointer data)
++{
++ Display *xdisplay;
++ GdkDisplay *gdkdisplay;
++ XEvent *xevent = gdkxevent;
++ gulong xid = 0;
++ Window select = 0;
++
++ gdkdisplay = gdk_display_get_default ();
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
++
++ switch (xevent->type) {
++ case CreateNotify:
++ {
++ if (!wnck_window_get (xevent->xcreatewindow.window))
++ {
++ GdkWindow *toplevel = create_foreign_window (xevent->xcreatewindow.window);
++
++ if (toplevel)
++ {
++ gdk_window_set_events (toplevel,
++ gdk_window_get_events (toplevel) |
++ GDK_PROPERTY_CHANGE_MASK);
++
++ /* check if the window is a switcher and update accordingly */
++
++ if (get_window_prop (xevent->xcreatewindow.window, select_window_atom, &select))
++ update_switcher_window (xevent->xcreatewindow.window, select);
++ }
++ }
++ }
++ break;
++ case ButtonPress:
++ case ButtonRelease:
++ xid = (gulong)
++ g_hash_table_lookup (frame_table,
++ GINT_TO_POINTER (xevent->xbutton.window));
++ break;
++ case EnterNotify:
++ case LeaveNotify:
++ xid = (gulong)
++ g_hash_table_lookup (frame_table,
++ GINT_TO_POINTER (xevent->xcrossing.window));
++ break;
++ case MotionNotify:
++ xid = (gulong)
++ g_hash_table_lookup (frame_table,
++ GINT_TO_POINTER (xevent->xmotion.window));
++ break;
++ case PropertyNotify:
++ if (xevent->xproperty.atom == frame_input_window_atom)
++ {
++ WnckWindow *win;
++
++ xid = xevent->xproperty.window;
++
++ win = wnck_window_get (xid);
++ if (win)
++ {
++ Window frame;
++
++ if (!get_window_prop (xid, select_window_atom, &select))
++ {
++ if (get_window_prop (xid, frame_input_window_atom, &frame))
++ add_frame_window (win, frame, FALSE);
++ else
++ remove_frame_window (win);
++ }
++ }
++ }
++ if (xevent->xproperty.atom == frame_output_window_atom)
++ {
++ WnckWindow *win;
++
++ xid = xevent->xproperty.window;
++
++ win = wnck_window_get (xid);
++ if (win)
++ {
++ Window frame;
++
++ if (!get_window_prop (xid, select_window_atom, &select))
++ {
++ if (get_window_prop (xid, frame_output_window_atom, &frame))
++ add_frame_window (win, frame, TRUE);
++ else
++ remove_frame_window (win);
++ }
++ }
++ }
++ else if (xevent->xproperty.atom == compiz_shadow_info_atom ||
++ xevent->xproperty.atom == compiz_shadow_color_atom)
++ {
++ GdkScreen *g_screen = gdk_display_get_default_screen (gdkdisplay);
++ Window root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (g_screen));
++ WnckScreen *screen;
++
++ screen = wnck_screen_get_for_root (root);
++
++ if (screen)
++ {
++ shadow_property_changed (screen);
++ }
++ }
++ else if (xevent->xproperty.atom == mwm_hints_atom)
++ {
++ WnckWindow *win;
++
++ xid = xevent->xproperty.window;
++
++ win = wnck_window_get (xid);
++ if (win)
++ {
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ gboolean decorated = FALSE;
++
++ if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
++ decorated = TRUE;
++
++ if (decorated != d->decorated)
++ {
++ d->decorated = decorated;
++ if (decorated)
++ {
++ d->context = NULL;
++ d->width = d->height = 0;
++
++ update_window_decoration_size (win);
++ update_event_windows (win);
++ }
++ else
++ {
++ gdk_error_trap_push ();
++ XDeleteProperty (xdisplay, xid, win_decor_atom);
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++ }
++ }
++ }
++ }
++ else if (xevent->xproperty.atom == select_window_atom)
++ {
++ Window select;
++
++ if (get_window_prop (xevent->xproperty.window, select_window_atom, &select))
++ update_switcher_window (xevent->xproperty.window, select);
++ }
++ else if (xevent->xproperty.atom == XA_WM_TRANSIENT_FOR)
++ {
++ WnckWindow *win = wnck_window_get (xevent->xproperty.window);
++
++ if (win &&
++ wnck_window_get_window_type (win) == WNCK_WINDOW_DIALOG)
++ {
++ Window parent;
++
++ if (get_window_prop (xevent->xproperty.window, XA_WM_TRANSIENT_FOR, &parent))
++ {
++ WnckWindow *p = wnck_window_get (parent);
++ decor_t *d = g_object_get_data (G_OBJECT (p), "decor");
++ decor_t *d_transient = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (p)
++ {
++ if (g_slist_find (d->transient_windows, win))
++ break;
++
++ if (d)
++ {
++ d->transient_windows = g_slist_append (d->transient_windows, win);
++ d_transient->transient_parent = p;
++ }
++ }
++ }
++ }
++ }
++ break;
++ case DestroyNotify:
++ {
++ g_hash_table_remove (frame_table,
++ GINT_TO_POINTER (xevent->xproperty.window));
++
++ break;
++ }
++ case ClientMessage:
++ if (xevent->xclient.message_type == toolkit_action_atom)
++ {
++ long action;
++
++ action = xevent->xclient.data.l[0];
++ if (action == toolkit_action_window_menu_atom)
++ {
++ WnckWindow *win;
++
++ win = wnck_window_get (xevent->xclient.window);
++ if (win)
++ {
++ action_menu_map (win,
++ xevent->xclient.data.l[2],
++ xevent->xclient.data.l[1]);
++ }
++ }
++ else if (action == toolkit_action_force_quit_dialog_atom)
++ {
++ WnckWindow *win;
++
++ win = wnck_window_get (xevent->xclient.window);
++ if (win)
++ {
++ if (xevent->xclient.data.l[2])
++ show_force_quit_dialog (win,
++ xevent->xclient.data.l[1]);
++ else
++ hide_force_quit_dialog (win);
++ }
++ }
++ }
++ default:
++ break;
++ }
++
++ if (xid)
++ {
++ WnckWindow *win;
++
++ win = wnck_window_get (xid);
++ if (win)
++ {
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->decorated)
++ {
++ gint i, j;
++ event_callback cb = NULL;
++ Window w = xevent->xany.window;
++
++ for (i = 0; i < 3; i++)
++ for (j = 0; j < 3; j++)
++ if (d->event_windows[i][j].window == w)
++ cb = d->event_windows[i][j].callback;
++
++ if (!cb)
++ {
++ for (i = 0; i < BUTTON_NUM; i++)
++ if (d->button_windows[i].window == w)
++ cb = d->button_windows[i].callback;
++ }
++
++ if (cb)
++ {
++ decor_event gtkwd_event;
++ decor_event_type gtkwd_type;
++
++ gtkwd_event.window = w;
++
++ switch (xevent->type)
++ {
++ case ButtonPress:
++ case ButtonRelease:
++ if (xevent->type == ButtonPress)
++ gtkwd_type = GButtonPress;
++ else
++ gtkwd_type = GButtonRelease;
++ gtkwd_event.button = xevent->xbutton.button;
++ gtkwd_event.x = xevent->xbutton.x;
++ gtkwd_event.y = xevent->xbutton.y;
++ gtkwd_event.x_root = xevent->xbutton.x_root;
++ gtkwd_event.y_root = xevent->xbutton.y_root;
++ gtkwd_event.time = xevent->xbutton.time;
++ break;
++ case EnterNotify:
++ case LeaveNotify:
++ if (xevent->type == EnterNotify)
++ gtkwd_type = GEnterNotify;
++ else
++ gtkwd_type = GLeaveNotify;
++ gtkwd_event.x = xevent->xcrossing.x;
++ gtkwd_event.y = xevent->xcrossing.y;
++ gtkwd_event.x_root = xevent->xcrossing.x_root;
++ gtkwd_event.y_root = xevent->xcrossing.y_root;
++ gtkwd_event.time = xevent->xcrossing.time;
++ break;
++ default:
++ cb = NULL;
++ break;
++ }
++ if (cb)
++ (*cb) (win, >kwd_event, gtkwd_type);
++ }
++ }
++ }
++ }
++
++ return GDK_FILTER_CONTINUE;
++}
++
++GdkFilterReturn
++selection_event_filter_func (GdkXEvent *gdkxevent,
++ GdkEvent *event,
++ gpointer data)
++{
++ Display *xdisplay;
++ GdkDisplay *gdkdisplay;
++ XEvent *xevent = gdkxevent;
++ int status;
++
++ gdkdisplay = gdk_display_get_default ();
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
++
++ switch (xevent->type) {
++ case SelectionRequest:
++ decor_handle_selection_request (xdisplay, xevent, dm_sn_timestamp);
++ break;
++ case SelectionClear:
++ status = decor_handle_selection_clear (xdisplay, xevent, 0);
++ if (status == DECOR_SELECTION_GIVE_UP)
++ exit (0);
++ default:
++ break;
++ }
++
++ return GDK_FILTER_CONTINUE;
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/forcequit.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/forcequit.c 2011-04-06 22:06:48.543070677 +0800
+@@ -0,0 +1,176 @@
++#include "gtk-window-decorator.h"
++
++static char *
++get_client_machine (Window xwindow)
++{
++ Atom atom, type;
++ gulong nitems, bytes_after;
++ guchar *str = NULL;
++ int format, result;
++ char *retval;
++
++ atom = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "WM_CLIENT_MACHINE", FALSE);
++
++ gdk_error_trap_push ();
++
++ result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++ xwindow, atom,
++ 0, G_MAXLONG,
++ FALSE, XA_STRING, &type, &format, &nitems,
++ &bytes_after, &str);
++
++ gdk_error_trap_pop ();
++
++ if (result != Success)
++ return NULL;
++
++ if (type != XA_STRING)
++ {
++ XFree (str);
++ return NULL;
++ }
++
++ retval = g_strdup ((gchar *) str);
++
++ XFree (str);
++
++ return retval;
++}
++
++static void
++kill_window (WnckWindow *win)
++{
++ WnckApplication *app;
++
++ app = wnck_window_get_application (win);
++ if (app)
++ {
++ gchar buf[257], *client_machine;
++ int pid;
++
++ pid = wnck_application_get_pid (app);
++ client_machine = get_client_machine (wnck_application_get_xid (app));
++
++ if (client_machine && pid > 0)
++ {
++ if (gethostname (buf, sizeof (buf) - 1) == 0)
++ {
++ if (strcmp (buf, client_machine) == 0)
++ kill (pid, 9);
++ }
++ }
++
++ if (client_machine)
++ g_free (client_machine);
++ }
++
++ gdk_error_trap_push ();
++ XKillClient (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), wnck_window_get_xid (win));
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++}
++
++static void
++force_quit_dialog_realize (GtkWidget *dialog,
++ void *data)
++{
++ WnckWindow *win = data;
++
++ gdk_error_trap_push ();
++ XSetTransientForHint (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++ GDK_WINDOW_XID (dialog->window),
++ wnck_window_get_xid (win));
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++}
++
++static void
++force_quit_dialog_response (GtkWidget *dialog,
++ gint response,
++ void *data)
++{
++ WnckWindow *win = data;
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (response == GTK_RESPONSE_ACCEPT)
++ kill_window (win);
++
++ if (d->force_quit_dialog)
++ {
++ d->force_quit_dialog = NULL;
++ gtk_widget_destroy (dialog);
++ }
++}
++
++void
++show_force_quit_dialog (WnckWindow *win,
++ Time timestamp)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ GtkWidget *dialog;
++ gchar *str, *tmp;
++
++ if (d->force_quit_dialog)
++ return;
++
++ tmp = g_markup_escape_text (wnck_window_get_name (win), -1);
++ str = g_strdup_printf (_("The window \"%s\" is not responding."), tmp);
++
++ g_free (tmp);
++
++ dialog = gtk_message_dialog_new (NULL, 0,
++ GTK_MESSAGE_WARNING,
++ GTK_BUTTONS_NONE,
++ "<b>%s</b>\n\n%s",
++ str,
++ _("Forcing this application to "
++ "quit will cause you to lose any "
++ "unsaved changes."));
++ g_free (str);
++
++ gtk_window_set_icon_name (GTK_WINDOW (dialog), "force-quit");
++
++ gtk_label_set_use_markup (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label),
++ TRUE);
++ gtk_label_set_line_wrap (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label),
++ TRUE);
++
++ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
++ GTK_STOCK_CANCEL,
++ GTK_RESPONSE_REJECT,
++ _("_Force Quit"),
++ GTK_RESPONSE_ACCEPT,
++ NULL);
++
++ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
++
++ g_signal_connect (G_OBJECT (dialog), "realize",
++ G_CALLBACK (force_quit_dialog_realize),
++ win);
++
++ g_signal_connect (G_OBJECT (dialog), "response",
++ G_CALLBACK (force_quit_dialog_response),
++ win);
++
++ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
++
++ gtk_widget_realize (dialog);
++
++ gdk_x11_window_set_user_time (dialog->window, timestamp);
++
++ gtk_widget_show (dialog);
++
++ d->force_quit_dialog = dialog;
++}
++
++void
++hide_force_quit_dialog (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->force_quit_dialog)
++ {
++ gtk_widget_destroy (d->force_quit_dialog);
++ d->force_quit_dialog = NULL;
++ }
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/gdk.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/gdk.c 2011-04-06 22:06:48.543070677 +0800
+@@ -0,0 +1,87 @@
++#include "gtk-window-decorator.h"
++
++GdkPixmap *
++pixmap_new_from_pixbuf (GdkPixbuf *pixbuf, int depth)
++{
++ GdkPixmap *pixmap;
++ guint width, height;
++ cairo_t *cr;
++
++ width = gdk_pixbuf_get_width (pixbuf);
++ height = gdk_pixbuf_get_height (pixbuf);
++
++ pixmap = create_pixmap (width, height, depth);
++ if (!pixmap)
++ return NULL;
++
++ cr = (cairo_t *) gdk_cairo_create (GDK_DRAWABLE (pixmap));
++ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
++ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++ cairo_paint (cr);
++ cairo_destroy (cr);
++
++ return pixmap;
++}
++
++
++void
++gdk_cairo_set_source_color_alpha (cairo_t *cr,
++ GdkColor *color,
++ double alpha)
++{
++ cairo_set_source_rgba (cr,
++ color->red / 65535.0,
++ color->green / 65535.0,
++ color->blue / 65535.0,
++ alpha);
++}
++
++inline GdkWindow *
++create_gdk_window (Window xframe)
++{
++ GdkDisplay *display = gdk_display_get_default ();
++ GdkScreen *screen = gdk_display_get_default_screen (display);
++ GdkWindow *window = create_foreign_window (xframe);
++ GdkColormap *cmap = gdk_screen_get_rgb_colormap (screen);
++
++ gdk_drawable_set_colormap (GDK_DRAWABLE (window), cmap);
++
++ return window;
++}
++
++GdkColormap *
++get_colormap_for_drawable (GdkDrawable *d)
++{
++ GdkDisplay *display = gdk_display_get_default ();
++ GdkScreen *screen = gdk_display_get_default_screen (display);
++
++ if (gdk_drawable_get_depth (d) == 32)
++ return gdk_screen_get_rgba_colormap (screen);
++
++ return gdk_screen_get_rgb_colormap (screen);
++}
++
++XRenderPictFormat *
++get_format_for_drawable (decor_t *d, GdkDrawable *drawable)
++{
++ if (!d->frame_window || gdk_drawable_get_depth (drawable) == 32)
++ return xformat_rgba;
++
++ return xformat_rgb;
++}
++
++GdkPixmap *
++create_pixmap (int w,
++ int h,
++ int depth)
++{
++ GtkWidget *widget;
++ GdkWindow *window;
++
++ if (w == 0 || h == 0)
++ abort ();
++
++ widget = (depth > 24) ? style_window_rgba : style_window_rgb;
++ window = gtk_widget_get_window (widget);
++ return gdk_pixmap_new (GDK_DRAWABLE (window), w, h, depth);
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/gtk-window-decorator.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/gtk-window-decorator.c 2011-04-06 22:06:48.547070702 +0800
+@@ -0,0 +1,443 @@
++/*
++ * Copyright © 2006 Novell, Inc.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ *
++ * Author: David Reveman <davidr@xxxxxxxxxx>
++ */
++
++#include "gtk-window-decorator.h"
++
++gboolean minimal = FALSE;
++
++double decoration_alpha = 0.5;
++
++#define SWITCHER_SPACE 40
++
++decor_extents_t _shadow_extents = { 0, 0, 0, 0 };
++decor_extents_t _win_extents = { 6, 6, 6, 6 };
++decor_extents_t _max_win_extents = { 6, 6, 4, 6 };
++decor_extents_t _default_win_extents = { 6, 6, 6, 6 };
++decor_extents_t _switcher_extents = { 6, 6, 6, 6 + SWITCHER_SPACE };
++
++int titlebar_height = 17;
++int max_titlebar_height = 17;
++
++decor_context_t window_active_context = {
++ { 0, 0, 0, 0 },
++ 6, 6, 4, 6,
++ 0, 0, 0, 0
++};
++
++decor_context_t max_window_active_context = {
++ { 0, 0, 0, 0 },
++ 6, 6, 4, 6,
++ 0, 0, 0, 0
++};
++
++decor_context_t window_inactive_context = {
++ { 0, 0, 0, 0 },
++ 6, 6, 4, 6,
++ 0, 0, 0, 0
++};
++
++decor_context_t max_window_inactive_context = {
++ { 0, 0, 0, 0 },
++ 6, 6, 4, 6,
++ 0, 0, 0, 0
++};
++
++decor_context_t window_context_no_shadow = {
++ { 0, 0, 0, 0 },
++ 6, 6, 4, 6,
++ 0, 0, 0, 0
++};
++
++decor_context_t max_window_context_no_shadow = {
++ { 0, 0, 0, 0 },
++ 6, 6, 4, 6,
++ 0, 0, 0, 0
++};
++
++decor_context_t switcher_context = {
++ { 0, 0, 0, 0 },
++ 6, 6, 6, 6 + SWITCHER_SPACE,
++ 0, 0, 0, 0
++};
++
++decor_context_t shadow_context = {
++ { 0, 0, 0, 0 },
++ 0, 0, 0, 0,
++ 0, 0, 0, 0,
++};
++
++gdouble shadow_radius = SHADOW_RADIUS;
++gdouble shadow_opacity = SHADOW_OPACITY;
++gushort shadow_color[3] = {
++ SHADOW_COLOR_RED,
++ SHADOW_COLOR_GREEN,
++ SHADOW_COLOR_BLUE
++};
++gint shadow_offset_x = SHADOW_OFFSET_X;
++gint shadow_offset_y = SHADOW_OFFSET_Y;
++
++guint cmdline_options = 0;
++
++decor_shadow_t *no_border_shadow = NULL;
++decor_shadow_t *border_active_shadow = NULL;
++decor_shadow_t *border_inactive_shadow = NULL;
++decor_shadow_t *max_border_active_shadow = NULL;
++decor_shadow_t *max_border_inactive_shadow = NULL;
++decor_shadow_t *border_no_shadow = NULL;
++decor_shadow_t *max_border_no_shadow = NULL;
++decor_shadow_t *switcher_shadow = NULL;
++
++GdkPixmap *decor_normal_pixmap = NULL;
++GdkPixmap *decor_active_pixmap = NULL;
++
++Atom frame_input_window_atom;
++Atom frame_output_window_atom;
++Atom win_decor_atom;
++Atom win_blur_decor_atom;
++Atom wm_move_resize_atom;
++Atom restack_window_atom;
++Atom select_window_atom;
++Atom mwm_hints_atom;
++Atom switcher_fg_atom;
++
++Atom compiz_shadow_info_atom;
++Atom compiz_shadow_color_atom;
++
++Atom toolkit_action_atom;
++Atom toolkit_action_window_menu_atom;
++Atom toolkit_action_force_quit_dialog_atom;
++
++Time dm_sn_timestamp;
++
++struct _cursor cursor[3][3] = {
++ { C (top_left_corner), C (top_side), C (top_right_corner) },
++ { C (left_side), C (left_ptr), C (right_side) },
++ { C (bottom_left_corner), C (bottom_side), C (bottom_right_corner) }
++};
++
++struct _pos pos[3][3] = {
++ {
++ { 0, 0, 10, 21, 0, 0, 0, 0, 0, 1 },
++ { 10, 0, -8, 6, 0, 0, 1, 0, 0, 1 },
++ { 2, 0, 10, 21, 1, 0, 0, 0, 0, 1 }
++ }, {
++ { 0, 10, 6, 11, 0, 0, 0, 1, 1, 0 },
++ { 6, 6, 0, 15, 0, 0, 1, 0, 0, 1 },
++ { 6, 10, 6, 11, 1, 0, 0, 1, 1, 0 }
++ }, {
++ { 0, 17, 10, 10, 0, 1, 0, 0, 1, 0 },
++ { 10, 21, -8, 6, 0, 1, 1, 0, 1, 0 },
++ { 2, 17, 10, 10, 1, 1, 0, 0, 1, 0 }
++ }
++}, bpos[] = {
++ { 0, 6, 16, 16, 1, 0, 0, 0, 0, 0 },
++ { 0, 6, 16, 16, 1, 0, 0, 0, 0, 0 },
++ { 0, 6, 16, 16, 1, 0, 0, 0, 0, 0 },
++ { 6, 2, 16, 16, 0, 0, 0, 0, 0, 0 }
++};
++
++char *program_name;
++
++GtkWidget *style_window_rgba;
++GtkWidget *style_window_rgb;
++GtkWidget *switcher_label;
++
++GHashTable *frame_table;
++GtkWidget *action_menu = NULL;
++gboolean action_menu_mapped = FALSE;
++decor_color_t _title_color[2];
++PangoContext *pango_context;
++gint double_click_timeout = 250;
++
++GSList *draw_list = NULL;
++guint draw_idle_id = 0;
++
++PangoFontDescription *titlebar_font = NULL;
++gboolean use_system_font = FALSE;
++gint text_height;
++
++gint blur_type = BLUR_TYPE_NONE;
++
++GdkPixmap *switcher_pixmap = NULL;
++GdkPixmap *switcher_buffer_pixmap = NULL;
++gint switcher_width;
++gint switcher_height;
++Window switcher_selected_window = None;
++decor_t *switcher_window = NULL;
++
++XRenderPictFormat *xformat_rgba;
++XRenderPictFormat *xformat_rgb;
++
++int
++main (int argc, char *argv[])
++{
++ GdkDisplay *gdkdisplay;
++ Display *xdisplay;
++ GdkScreen *gdkscreen;
++ WnckScreen *screen;
++ gint i, j, status;
++ unsigned int nchildren;
++ Window root_ret, parent_ret;
++ Window *children = NULL;
++ gboolean replace = FALSE;
++
++#ifdef USE_METACITY
++ char *meta_theme = NULL;
++#endif
++
++ program_name = argv[0];
++
++ gtk_init (&argc, &argv);
++
++ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
++ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
++ textdomain (GETTEXT_PACKAGE);
++
++ for (i = 0; i < argc; i++)
++ {
++ if (strcmp (argv[i], "--minimal") == 0)
++ {
++ minimal = TRUE;
++ }
++ else if (strcmp (argv[i], "--replace") == 0)
++ {
++ replace = TRUE;
++ }
++ else if (strcmp (argv[i], "--blur") == 0)
++ {
++ if (argc > ++i)
++ {
++ if (strcmp (argv[i], "titlebar") == 0)
++ blur_type = BLUR_TYPE_TITLEBAR;
++ else if (strcmp (argv[i], "all") == 0)
++ blur_type = BLUR_TYPE_ALL;
++ }
++ cmdline_options |= CMDLINE_BLUR;
++ }
++
++#ifdef USE_METACITY
++ else if (strcmp (argv[i], "--opacity") == 0)
++ {
++ if (argc > ++i)
++ meta_opacity = atof (argv[i]);
++ cmdline_options |= CMDLINE_OPACITY;
++ }
++ else if (strcmp (argv[i], "--no-opacity-shade") == 0)
++ {
++ meta_shade_opacity = FALSE;
++ cmdline_options |= CMDLINE_OPACITY_SHADE;
++ }
++ else if (strcmp (argv[i], "--active-opacity") == 0)
++ {
++ if (argc > ++i)
++ meta_active_opacity = atof (argv[i]);
++ cmdline_options |= CMDLINE_ACTIVE_OPACITY;
++ }
++ else if (strcmp (argv[i], "--no-active-opacity-shade") == 0)
++ {
++ meta_active_shade_opacity = FALSE;
++ cmdline_options |= CMDLINE_ACTIVE_OPACITY_SHADE;
++ }
++ else if (strcmp (argv[i], "--metacity-theme") == 0)
++ {
++ if (argc > ++i)
++ meta_theme = argv[i];
++ cmdline_options |= CMDLINE_THEME;
++ }
++#endif
++
++ else if (strcmp (argv[i], "--help") == 0)
++ {
++ fprintf (stderr, "%s "
++ "[--minimal] "
++ "[--replace] "
++ "[--blur none|titlebar|all] "
++
++#ifdef USE_METACITY
++ "[--opacity OPACITY] "
++ "[--no-opacity-shade] "
++ "[--active-opacity OPACITY] "
++ "[--no-active-opacity-shade] "
++ "[--metacity-theme THEME] "
++#endif
++
++ "[--help]"
++
++ "\n", program_name);
++ return 0;
++ }
++ }
++
++ theme_draw_window_decoration = draw_window_decoration;
++ theme_calc_decoration_size = calc_decoration_size;
++ theme_update_border_extents = update_border_extents;
++ theme_get_event_window_position = get_event_window_position;
++ theme_get_button_position = get_button_position;
++ theme_update_shadow = cairo_update_shadow;
++ theme_get_shadow = get_shadow;
++ theme_get_border_extents = get_border_extents;
++
++#ifdef USE_METACITY
++ if (meta_theme)
++ {
++ meta_theme_set_current (meta_theme, TRUE);
++ if (meta_theme_get_current ())
++ {
++ theme_draw_window_decoration = meta_draw_window_decoration;
++ theme_calc_decoration_size = meta_calc_decoration_size;
++ theme_update_border_extents = meta_update_border_extents;
++ theme_get_event_window_position = meta_get_event_window_position;
++ theme_get_button_position = meta_get_button_position;
++ theme_update_shadow = meta_update_shadow;
++ theme_get_shadow = meta_get_shadow;
++ theme_get_border_extents = meta_get_border_extents;
++ }
++ }
++#endif
++
++ gdkdisplay = gdk_display_get_default ();
++ xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
++ gdkscreen = gdk_display_get_default_screen (gdkdisplay);
++
++ frame_input_window_atom = XInternAtom (xdisplay,
++ DECOR_INPUT_FRAME_ATOM_NAME, FALSE);
++ frame_output_window_atom = XInternAtom (xdisplay,
++ DECOR_OUTPUT_FRAME_ATOM_NAME, FALSE);
++
++ win_decor_atom = XInternAtom (xdisplay, DECOR_WINDOW_ATOM_NAME, FALSE);
++ win_blur_decor_atom = XInternAtom (xdisplay, DECOR_BLUR_ATOM_NAME, FALSE);
++ wm_move_resize_atom = XInternAtom (xdisplay, "_NET_WM_MOVERESIZE", FALSE);
++ restack_window_atom = XInternAtom (xdisplay, "_NET_RESTACK_WINDOW", FALSE);
++ select_window_atom = XInternAtom (xdisplay, DECOR_SWITCH_WINDOW_ATOM_NAME,
++ FALSE);
++ mwm_hints_atom = XInternAtom (xdisplay, "_MOTIF_WM_HINTS", FALSE);
++ switcher_fg_atom = XInternAtom (xdisplay,
++ DECOR_SWITCH_FOREGROUND_COLOR_ATOM_NAME,
++ FALSE);
++
++ compiz_shadow_info_atom = XInternAtom (xdisplay, "_COMPIZ_NET_CM_SHADOW_PROPERTIES", FALSE);
++ compiz_shadow_color_atom = XInternAtom (xdisplay, "_COMPIZ_NET_CM_SHADOW_COLOR", FALSE);
++
++ toolkit_action_atom =
++ XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION", FALSE);
++ toolkit_action_window_menu_atom =
++ XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION_WINDOW_MENU", FALSE);
++ toolkit_action_force_quit_dialog_atom =
++ XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION_FORCE_QUIT_DIALOG",
++ FALSE);
++
++ status = decor_acquire_dm_session (xdisplay,
++ gdk_screen_get_number (gdkscreen),
++ "gwd", replace, &dm_sn_timestamp);
++ if (status != DECOR_ACQUIRE_STATUS_SUCCESS)
++ {
++ if (status == DECOR_ACQUIRE_STATUS_FAILED)
++ {
++ fprintf (stderr,
++ "%s: Could not acquire decoration manager "
++ "selection on screen %d display \"%s\"\n",
++ program_name, gdk_screen_get_number (gdkscreen),
++ DisplayString (xdisplay));
++ }
++ else if (status == DECOR_ACQUIRE_STATUS_OTHER_DM_RUNNING)
++ {
++ fprintf (stderr,
++ "%s: Screen %d on display \"%s\" already "
++ "has a decoration manager; try using the "
++ "--replace option to replace the current "
++ "decoration manager.\n",
++ program_name, gdk_screen_get_number (gdkscreen),
++ DisplayString (xdisplay));
++ }
++
++ return 1;
++ }
++
++ for (i = 0; i < 3; i++)
++ {
++ for (j = 0; j < 3; j++)
++ {
++ if (cursor[i][j].shape != XC_left_ptr)
++ cursor[i][j].cursor =
++ XCreateFontCursor (xdisplay, cursor[i][j].shape);
++ }
++ }
++
++ xformat_rgba = XRenderFindStandardFormat (xdisplay, PictStandardARGB32);
++ xformat_rgb = XRenderFindStandardFormat (xdisplay, PictStandardRGB24);
++
++ frame_table = g_hash_table_new (NULL, NULL);
++
++ screen = wnck_screen_get_default ();
++ wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
++
++ gdk_window_add_filter (NULL,
++ selection_event_filter_func,
++ NULL);
++
++ if (!minimal)
++ {
++ GdkWindow *root = create_foreign_window (gdk_x11_get_default_root_xwindow ());
++
++ gdk_window_add_filter (NULL,
++ event_filter_func,
++ NULL);
++
++ XQueryTree (xdisplay, gdk_x11_get_default_root_xwindow (),
++ &root_ret, &parent_ret, &children, &nchildren);
++
++ for (i = 0; i < nchildren; i++)
++ {
++ GdkWindow *toplevel = create_foreign_window (children[i]);
++
++ /* Need property notify on all windows */
++
++ gdk_window_set_events (toplevel,
++ gdk_window_get_events (toplevel) |
++ GDK_PROPERTY_CHANGE_MASK);
++ }
++
++ /* Need MapNotify on new windows */
++ gdk_window_set_events (root, gdk_window_get_events (root) |
++ GDK_STRUCTURE_MASK |
++ GDK_PROPERTY_CHANGE_MASK |
++ GDK_VISIBILITY_NOTIFY_MASK |
++ GDK_SUBSTRUCTURE_MASK);
++
++ connect_screen (screen);
++ }
++
++ if (!init_settings (screen))
++ {
++ fprintf (stderr, "%s: Failed to get necessary gtk settings\n", argv[0]);
++ return 1;
++ }
++
++ decor_set_dm_check_hint (xdisplay, gdk_screen_get_number (gdkscreen),
++ WINDOW_DECORATION_TYPE_PIXMAP |
++ WINDOW_DECORATION_TYPE_WINDOW);
++
++ update_default_decorations (gdkscreen);
++
++ gtk_main ();
++
++ return 0;
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/gtk-window-decorator.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/gtk-window-decorator.h 2011-04-06 22:06:48.547070702 +0800
+@@ -0,0 +1,1009 @@
++#ifndef _GTK_WINDOW_DECORATOR_H
++#define _GTK_WINDOW_DECORATOR_H
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <decoration.h>
++
++#include <X11/Xlib.h>
++#include <X11/Xatom.h>
++#include <X11/cursorfont.h>
++#include <X11/extensions/Xrender.h>
++#include <X11/Xregion.h>
++
++#ifdef HAVE_GTK_2_24
++
++#ifndef GDK_DISABLE_DEPRECATED
++#define GDK_DISABLE_DEPRECATED
++#endif
++
++#define create_foreign_window(xid) \
++ gdk_x11_foreign_new_for_display (gdk_display_get_default (), \
++ xid);
++#else
++
++#define create_foreign_window(xid) \
++ gdk_window_foreign_new (xid)
++
++#ifdef GTK_DISABLE_DEPRECATED
++#undef GTK_DISABLE_DEPRECATED
++#endif
++
++#endif
++
++#include <gtk/gtk.h>
++#include <gdk/gdkx.h>
++#include <gdk/gdk.h>
++
++#ifdef USE_GCONF_UNITY_WINDOW_DECORATOR
++#include <gconf/gconf-client.h>
++#endif
++
++#ifdef USE_DBUS_GLIB
++#define DBUS_API_SUBJECT_TO_CHANGE
++#include <dbus/dbus.h>
++#include <dbus/dbus-glib-lowlevel.h>
++#endif
++
++#define WNCK_I_KNOW_THIS_IS_UNSTABLE
++#include <libwnck/libwnck.h>
++#include <libwnck/window-action-menu.h>
++
++#ifndef HAVE_LIBWNCK_2_19_4
++#define wnck_window_get_client_window_geometry wnck_window_get_geometry
++#endif
++
++#include <cairo.h>
++#include <cairo-xlib.h>
++
++#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 1, 0)
++#define CAIRO_EXTEND_PAD CAIRO_EXTEND_NONE
++#endif
++
++#include <pango/pango-context.h>
++#include <pango/pangocairo.h>
++
++#include <string.h>
++#include <stdlib.h>
++#include <math.h>
++#include <limits.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <signal.h>
++
++#include <libintl.h>
++#define _(x) gettext (x)
++#define N_(x) x
++
++#ifdef USE_METACITY
++#include <metacity-private/theme.h>
++#endif
++
++#define METACITY_GCONF_DIR "/apps/metacity/general"
++
++#define COMPIZ_USE_SYSTEM_FONT_KEY \
++METACITY_GCONF_DIR "/titlebar_uses_system_font"
++
++#define COMPIZ_TITLEBAR_FONT_KEY \
++METACITY_GCONF_DIR "/titlebar_font"
++
++#define COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY \
++METACITY_GCONF_DIR "/action_double_click_titlebar"
++
++#define COMPIZ_MIDDLE_CLICK_TITLEBAR_KEY \
++METACITY_GCONF_DIR "/action_middle_click_titlebar"
++
++#define COMPIZ_RIGHT_CLICK_TITLEBAR_KEY \
++METACITY_GCONF_DIR "/action_right_click_titlebar"
++
++#define COMPIZ_GCONF_DIR1 "/apps/compiz/plugins/decoration/allscreens/options"
++
++#define COMPIZ_SHADOW_RADIUS_KEY \
++COMPIZ_GCONF_DIR1 "/shadow_radius"
++
++#define COMPIZ_SHADOW_OPACITY_KEY \
++COMPIZ_GCONF_DIR1 "/shadow_opacity"
++
++#define COMPIZ_SHADOW_COLOR_KEY \
++COMPIZ_GCONF_DIR1 "/shadow_color"
++
++#define COMPIZ_SHADOW_OFFSET_X_KEY \
++COMPIZ_GCONF_DIR1 "/shadow_x_offset"
++
++#define COMPIZ_SHADOW_OFFSET_Y_KEY \
++COMPIZ_GCONF_DIR1 "/shadow_y_offset"
++
++#define META_THEME_KEY \
++METACITY_GCONF_DIR "/theme"
++
++#define META_BUTTON_LAYOUT_KEY \
++METACITY_GCONF_DIR "/button_layout"
++
++#define GCONF_DIR "/apps/gwd"
++
++#define USE_META_THEME_KEY \
++GCONF_DIR "/use_metacity_theme"
++
++#define META_THEME_OPACITY_KEY \
++GCONF_DIR "/metacity_theme_opacity"
++
++#define META_THEME_SHADE_OPACITY_KEY \
++GCONF_DIR "/metacity_theme_shade_opacity"
++
++#define META_THEME_ACTIVE_OPACITY_KEY \
++GCONF_DIR "/metacity_theme_active_opacity"
++
++#define META_THEME_ACTIVE_SHADE_OPACITY_KEY \
++GCONF_DIR "/metacity_theme_active_shade_opacity"
++
++#define BLUR_TYPE_KEY \
++GCONF_DIR "/blur_type"
++
++#define WHEEL_ACTION_KEY \
++GCONF_DIR "/mouse_wheel_action"
++
++#define DBUS_DEST "org.freedesktop.compiz"
++#define DBUS_PATH "/org/freedesktop/compiz/decor/screen0"
++#define DBUS_INTERFACE "org.freedesktop.compiz"
++#define DBUS_METHOD_GET "get"
++
++#define STROKE_ALPHA 0.6
++
++#define ICON_SPACE 20
++
++#define DOUBLE_CLICK_DISTANCE 8.0
++
++#define WM_MOVERESIZE_SIZE_TOPLEFT 0
++#define WM_MOVERESIZE_SIZE_TOP 1
++#define WM_MOVERESIZE_SIZE_TOPRIGHT 2
++#define WM_MOVERESIZE_SIZE_RIGHT 3
++#define WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
++#define WM_MOVERESIZE_SIZE_BOTTOM 5
++#define WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
++#define WM_MOVERESIZE_SIZE_LEFT 7
++#define WM_MOVERESIZE_MOVE 8
++#define WM_MOVERESIZE_SIZE_KEYBOARD 9
++#define WM_MOVERESIZE_MOVE_KEYBOARD 10
++
++#define SHADOW_RADIUS 8.0
++#define SHADOW_OPACITY 0.5
++#define SHADOW_OFFSET_X 1
++#define SHADOW_OFFSET_Y 1
++#define SHADOW_COLOR_RED 0x0000
++#define SHADOW_COLOR_GREEN 0x0000
++#define SHADOW_COLOR_BLUE 0x0000
++
++#define SHADOW_TYPE_ACTIVE_NORMAL 1
++#define SHADOW_TYPE_ACTIVE_MAX 2
++#define SHADOW_TYPE_INACTIVE_NORMAL 3
++#define SHADOW_TYPE_INACTIVE_MAX 4
++
++#define META_OPACITY 0.75
++#define META_SHADE_OPACITY TRUE
++#define META_ACTIVE_OPACITY 1.0
++#define META_ACTIVE_SHADE_OPACITY TRUE
++
++#define META_MAXIMIZED (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY | \
++WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY)
++
++#define CMDLINE_OPACITY (1 << 0)
++#define CMDLINE_OPACITY_SHADE (1 << 1)
++#define CMDLINE_ACTIVE_OPACITY (1 << 2)
++#define CMDLINE_ACTIVE_OPACITY_SHADE (1 << 3)
++#define CMDLINE_BLUR (1 << 4)
++#define CMDLINE_THEME (1 << 5)
++
++#define MWM_HINTS_DECORATIONS (1L << 1)
++
++#define MWM_DECOR_ALL (1L << 0)
++#define MWM_DECOR_BORDER (1L << 1)
++#define MWM_DECOR_HANDLE (1L << 2)
++#define MWM_DECOR_TITLE (1L << 3)
++#define MWM_DECOR_MENU (1L << 4)
++#define MWM_DECOR_MINIMIZE (1L << 5)
++#define MWM_DECOR_MAXIMIZE (1L << 6)
++
++#define PROP_MOTIF_WM_HINT_ELEMENTS 3
++
++/* to save some memory, value is specific to current decorations */
++#define TRANSLUCENT_CORNER_SIZE 3
++
++typedef struct {
++unsigned long flags;
++unsigned long functions;
++unsigned long decorations;
++} MwmHints;
++
++enum {
++ CLICK_ACTION_NONE,
++ CLICK_ACTION_SHADE,
++ CLICK_ACTION_MAXIMIZE,
++ CLICK_ACTION_MINIMIZE,
++ CLICK_ACTION_RAISE,
++ CLICK_ACTION_LOWER,
++ CLICK_ACTION_MENU
++};
++
++enum {
++ WHEEL_ACTION_NONE,
++ WHEEL_ACTION_SHADE
++};
++
++#define DOUBLE_CLICK_ACTION_DEFAULT CLICK_ACTION_MAXIMIZE
++#define MIDDLE_CLICK_ACTION_DEFAULT CLICK_ACTION_LOWER
++#define RIGHT_CLICK_ACTION_DEFAULT CLICK_ACTION_MENU
++#define WHEEL_ACTION_DEFAULT WHEEL_ACTION_NONE
++
++int double_click_action;
++int middle_click_action;
++int right_click_action;
++int wheel_action;
++
++extern gboolean minimal;
++extern double decoration_alpha;
++
++#define SWITCHER_SPACE 40
++
++extern decor_extents_t _shadow_extents;
++extern decor_extents_t _win_extents;
++extern decor_extents_t _max_win_extents;
++extern decor_extents_t _default_win_extents;
++extern decor_extents_t _switcher_extents;
++
++extern int titlebar_height;
++extern int max_titlebar_height;
++
++extern decor_context_t window_active_context;
++extern decor_context_t window_inactive_context;
++extern decor_context_t window_context_no_shadow;
++extern decor_context_t max_window_active_context;
++extern decor_context_t max_window_inactive_context;
++extern decor_context_t max_window_context_no_shadow;
++extern decor_context_t switcher_context;
++extern decor_context_t shadow_context;
++
++extern gdouble shadow_radius;
++extern gdouble shadow_opacity;
++extern gushort shadow_color[3];
++extern gint shadow_offset_x;
++extern gint shadow_offset_y;
++
++#ifdef USE_METACITY
++extern double meta_opacity;
++extern gboolean meta_shade_opacity;
++extern double meta_active_opacity;
++extern gboolean meta_active_shade_opacity;
++
++extern gboolean meta_button_layout_set;
++extern MetaButtonLayout meta_button_layout;
++#endif
++
++extern guint cmdline_options;
++
++extern decor_shadow_t *no_border_shadow;
++extern decor_shadow_t *border_active_shadow;
++extern decor_shadow_t *border_inactive_shadow;
++extern decor_shadow_t *border_no_shadow;
++extern decor_shadow_t *max_border_active_shadow;
++extern decor_shadow_t *max_border_inactive_shadow;
++extern decor_shadow_t *max_border_no_shadow;
++extern decor_shadow_t *switcher_shadow;
++
++extern GdkPixmap *decor_normal_pixmap;
++extern GdkPixmap *decor_active_pixmap;
++
++extern Atom frame_input_window_atom;
++extern Atom frame_output_window_atom;
++extern Atom win_decor_atom;
++extern Atom win_blur_decor_atom;
++extern Atom wm_move_resize_atom;
++extern Atom restack_window_atom;
++extern Atom select_window_atom;
++extern Atom mwm_hints_atom;
++extern Atom switcher_fg_atom;
++
++extern Atom toolkit_action_atom;
++extern Atom toolkit_action_window_menu_atom;
++extern Atom toolkit_action_force_quit_dialog_atom;
++
++extern Time dm_sn_timestamp;
++
++#define C(name) { 0, XC_ ## name }
++
++struct _cursor {
++ Cursor cursor;
++ unsigned int shape;
++};
++
++extern struct _cursor cursor[3][3];
++
++#define BUTTON_CLOSE 0
++#define BUTTON_MAX 1
++#define BUTTON_MIN 2
++#define BUTTON_MENU 3
++#define BUTTON_SHADE 4
++#define BUTTON_ABOVE 5
++#define BUTTON_STICK 6
++#define BUTTON_UNSHADE 7
++#define BUTTON_UNABOVE 8
++#define BUTTON_UNSTICK 9
++#define BUTTON_NUM 10
++
++struct _pos {
++ int x, y, w, h;
++ int xw, yh, ww, hh, yth, hth;
++};
++
++extern struct _pos pos[3][3], bpos[];
++
++typedef struct _decor_color {
++ double r;
++ double g;
++ double b;
++} decor_color_t;
++
++
++#define IN_EVENT_WINDOW (1 << 0)
++#define PRESSED_EVENT_WINDOW (1 << 1)
++
++typedef struct _decor_event {
++ guint time;
++ guint window;
++ guint x;
++ guint y;
++ guint x_root;
++ guint y_root;
++ guint button;
++} decor_event;
++
++typedef enum _decor_event_type {
++ GButtonPress = 1,
++ GButtonRelease,
++ GEnterNotify,
++ GLeaveNotify,
++ GMotionNotify
++} decor_event_type;
++
++typedef void (*event_callback) (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++typedef struct {
++ Window window;
++ Box pos;
++ event_callback callback;
++} event_window;
++
++typedef struct _decor {
++ WnckWindow *win;
++ event_window event_windows[3][3];
++ event_window button_windows[BUTTON_NUM];
++ Box *last_pos_entered;
++ guint button_states[BUTTON_NUM];
++ GdkPixmap *pixmap;
++ GdkPixmap *buffer_pixmap;
++ GdkWindow *frame_window;
++ GtkWidget *decor_window;
++ GtkWidget *decor_event_box;
++ GtkWidget *decor_image;
++ cairo_t *cr;
++ decor_layout_t border_layout;
++ decor_context_t *context;
++ decor_shadow_t *shadow;
++ Picture picture;
++ gint button_width;
++ gint width;
++ gint height;
++ gint client_width;
++ gint client_height;
++ gboolean decorated;
++ gboolean active;
++ PangoLayout *layout;
++ gchar *name;
++ cairo_pattern_t *icon;
++ GdkPixmap *icon_pixmap;
++ GdkPixbuf *icon_pixbuf;
++ WnckWindowState state;
++ WnckWindowActions actions;
++ XID prop_xid;
++ GtkWidget *force_quit_dialog;
++ GSList *transient_windows;
++ WnckWindow *transient_parent;
++ Bool created;
++ void (*draw) (struct _decor *d);
++} decor_t;
++
++void (*theme_draw_window_decoration) (decor_t *d);
++gboolean (*theme_calc_decoration_size) (decor_t *d,
++ int client_width,
++ int client_height,
++ int text_width,
++ int *width,
++ int *height);
++void (*theme_update_border_extents) (gint text_height);
++void (*theme_get_event_window_position) (decor_t *d,
++ gint i,
++ gint j,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h);
++gboolean (*theme_get_button_position) (decor_t *d,
++ gint i,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h);
++
++decor_shadow_t * (*theme_update_shadow) (gint shadow_type);
++
++void (*theme_get_shadow) (decor_t *d,
++ gint shadow_type);
++
++void (*theme_get_border_extents) (decor_extents_t *extents,
++ decor_extents_t *frame_extents,
++ decor_extents_t *extents_max,
++ decor_extents_t *frame_extents_max);
++
++extern char *program_name;
++
++extern GtkWidget *style_window_rgba;
++extern GtkWidget *style_window_rgb;
++extern GtkWidget *switcher_label;
++
++extern GHashTable *frame_table;
++extern GtkWidget *action_menu;
++extern gboolean action_menu_mapped;
++extern decor_color_t _title_color[2];
++extern PangoContext *pango_context;
++extern gint double_click_timeout;
++
++extern GSList *draw_list;
++extern guint draw_idle_id;
++
++extern PangoFontDescription *titlebar_font;
++extern gboolean use_system_font;
++extern gint text_height;
++
++#define BLUR_TYPE_NONE 0
++#define BLUR_TYPE_TITLEBAR 1
++#define BLUR_TYPE_ALL 2
++
++extern gint blur_type;
++
++extern GdkPixmap *switcher_pixmap;
++extern GdkPixmap *switcher_buffer_pixmap;
++extern gint switcher_width;
++extern gint switcher_height;
++extern Window switcher_selected_window;
++extern decor_t *switcher_window;
++
++extern XRenderPictFormat *xformat_rgba;
++extern XRenderPictFormat *xformat_rgb;
++
++extern Atom compiz_shadow_info_atom;
++extern Atom compiz_shadow_color_atom;
++
++/* gtk-window-decorator.c */
++
++double
++dist (double x1, double y1,
++ double x2, double y2);
++
++/* decorator.c */
++
++gboolean
++update_window_decoration_size (WnckWindow *win);
++
++void
++update_window_decoration_name (WnckWindow *win);
++
++gint
++max_window_name_width (WnckWindow *win);
++
++void
++update_default_decorations (GdkScreen *screen);
++
++void
++update_window_decoration_state (WnckWindow *win);
++
++void
++update_window_decoration_actions (WnckWindow *win);
++
++void
++update_window_decoration_icon (WnckWindow *win);
++
++void
++update_event_windows (WnckWindow *win);
++
++int
++update_shadow (void);
++
++void
++shadow_property_changed (WnckScreen *screen);
++
++void
++update_titlebar_font (void);
++
++void
++update_window_decoration_name (WnckWindow *win);
++
++void
++update_window_decoration (WnckWindow *win);
++
++void
++queue_decor_draw (decor_t *d);
++
++void
++copy_to_front_buffer (decor_t *d);
++
++void
++draw_border_shape (Display *xdisplay,
++ Pixmap pixmap,
++ Picture picture,
++ int width,
++ int height,
++ decor_context_t *c,
++ void *closure);
++
++
++/* wnck.c*/
++
++void
++decorations_changed (WnckScreen *screen);
++
++void
++connect_screen (WnckScreen *screen);
++
++void
++add_frame_window (WnckWindow *win,
++ Window frame,
++ Bool mode);
++
++void
++remove_frame_window (WnckWindow *win);
++
++void
++restack_window (WnckWindow *win,
++ int stack_mode);
++
++void connect_window (WnckWindow *win);
++
++/* blur.c */
++
++void
++decor_update_blur_property (decor_t *d,
++ int width,
++ int height,
++ Region top_region,
++ int top_offset,
++ Region bottom_region,
++ int bottom_offset,
++ Region left_region,
++ int left_offset,
++ Region right_region,
++ int right_offset);
++
++/* decorprops.c */
++
++void
++decor_update_window_property (decor_t *d);
++
++void
++decor_update_switcher_property (decor_t *d);
++
++/* cairo.c */
++
++#define CORNER_TOPLEFT (1 << 0)
++#define CORNER_TOPRIGHT (1 << 1)
++#define CORNER_BOTTOMRIGHT (1 << 2)
++#define CORNER_BOTTOMLEFT (1 << 3)
++
++#define SHADE_LEFT (1 << 0)
++#define SHADE_RIGHT (1 << 1)
++#define SHADE_TOP (1 << 2)
++#define SHADE_BOTTOM (1 << 3)
++
++void
++draw_shadow_background (decor_t *d,
++ cairo_t *cr,
++ decor_shadow_t *s,
++ decor_context_t *c);
++
++void
++draw_window_decoration (decor_t *d);
++
++void
++fill_rounded_rectangle (cairo_t *cr,
++ double x,
++ double y,
++ double w,
++ double h,
++ double radius,
++ int corner,
++ decor_color_t *c0,
++ double alpha0,
++ decor_color_t *c1,
++ double alpha1,
++ int gravity);
++
++void
++rounded_rectangle (cairo_t *cr,
++ double x,
++ double y,
++ double w,
++ double h,
++ double radius,
++ int corner);
++
++gboolean
++calc_decoration_size (decor_t *d,
++ gint w,
++ gint h,
++ gint name_width,
++ gint *width,
++ gint *height);
++
++void
++update_border_extents (gint text_height);
++
++void
++get_border_extents (decor_extents_t *extents,
++ decor_extents_t *frame_extents,
++ decor_extents_t *extents_max,
++ decor_extents_t *frame_extents_max);
++
++gboolean
++get_button_position (decor_t *d,
++ gint i,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h);
++
++void
++get_event_window_position (decor_t *d,
++ gint i,
++ gint j,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h);
++
++decor_shadow_t *
++cairo_update_shadow (gint shadow_type);
++
++void
++get_shadow (decor_t *, gint shadow_type);
++
++/* gdk.c */
++
++void
++gdk_cairo_set_source_color_alpha (cairo_t *cr,
++ GdkColor *color,
++ double alpha);
++
++inline GdkWindow *
++create_gdk_window (Window xframe);
++
++GdkColormap *
++get_colormap_for_drawable (GdkDrawable *d);
++
++XRenderPictFormat *
++get_format_for_drawable (decor_t *d, GdkDrawable *drawable);
++
++GdkPixmap *
++create_pixmap (int w,
++ int h,
++ int depth);
++
++GdkPixmap *
++pixmap_new_from_pixbuf (GdkPixbuf *pixbuf, int depth);
++
++/* metacity.c */
++#ifdef USE_METACITY
++void
++meta_draw_window_decoration (decor_t *d);
++
++void
++meta_get_decoration_geometry (decor_t *d,
++ MetaTheme *theme,
++ MetaFrameFlags *flags,
++ MetaFrameGeometry *fgeom,
++ MetaButtonLayout *button_layout,
++ GdkRectangle *clip);
++
++void
++meta_calc_button_size (decor_t *d);
++
++gboolean
++meta_calc_decoration_size (decor_t *d,
++ gint w,
++ gint h,
++ gint name_width,
++ gint *width,
++ gint *height);
++
++gboolean
++meta_get_button_position (decor_t *d,
++ gint i,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h);
++
++gboolean
++meta_button_present (MetaButtonLayout *button_layout,
++ MetaButtonFunction function);
++
++void
++meta_get_event_window_position (decor_t *d,
++ gint i,
++ gint j,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h);
++void
++meta_update_border_extents (gint text_height);
++
++void
++meta_get_border_extents (decor_extents_t *extents,
++ decor_extents_t *frame_extents,
++ decor_extents_t *extents_max,
++ decor_extents_t *frame_extents_max);
++
++void
++meta_update_button_layout (const char *value);
++
++decor_shadow_t *
++meta_update_shadow (gint shadow_type);
++
++void
++meta_get_shadow (decor_t *, gint shadow_type);
++
++#endif
++/* switcher.c */
++
++#define SWITCHER_ALPHA 0xa0a0
++
++void
++draw_switcher_decoration (decor_t *d);
++
++gboolean
++update_switcher_window (Window popup,
++ Window selected);
++
++decor_t *
++switcher_window_opened (Window popup, Window selected);
++
++void
++switcher_window_closed ();
++
++/* events.c */
++
++void
++move_resize_window (WnckWindow *win,
++ int direction,
++ decor_event *gtkwd_event);
++
++void
++common_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type,
++ int button,
++ int max);
++
++void
++close_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++max_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++min_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++menu_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++shade_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++above_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++stick_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++void
++unshade_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++unabove_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++unstick_button_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++handle_title_button_event (WnckWindow *win,
++ int action,
++ decor_event *gtkwd_event);
++
++void
++handle_mouse_wheel_title_event (WnckWindow *win,
++ unsigned int button);
++
++void
++title_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++frame_common_event (WnckWindow *win,
++ int direction,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++top_left_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++top_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++top_right_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++left_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++void
++right_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++bottom_left_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++bottom_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++void
++bottom_right_event (WnckWindow *win,
++ decor_event *gtkwd_event,
++ decor_event_type gtkwd_type);
++
++void
++frame_window_realized (GtkWidget *widget,
++ gpointer data);
++
++event_callback
++find_event_callback_for_point (decor_t *d,
++ int x,
++ int y,
++ Bool *enter,
++ Bool *leave,
++ BoxPtr *entered_box);
++
++event_callback
++find_leave_event_callback (decor_t *d);
++
++void
++frame_handle_button_press (GtkWidget *widget,
++ GdkEventButton *event,
++ gpointer user_data);
++
++void
++frame_handle_button_release (GtkWidget *widget,
++ GdkEventButton *event,
++ gpointer user_data);
++
++void
++frame_handle_motion (GtkWidget *widget,
++ GdkEventMotion *event,
++ gpointer user_data);
++
++GdkFilterReturn
++selection_event_filter_func (GdkXEvent *gdkxevent,
++ GdkEvent *event,
++ gpointer data);
++
++GdkFilterReturn
++event_filter_func (GdkXEvent *gdkxevent,
++ GdkEvent *event,
++ gpointer data);
++
++/* forcequit.c */
++
++void
++show_force_quit_dialog (WnckWindow *win,
++ Time timestamp);
++
++void
++hide_force_quit_dialog (WnckWindow *win);
++
++/* actionmenu.c */
++
++void
++action_menu_map (WnckWindow *win,
++ long button,
++ Time time);
++
++/* util.c */
++
++double
++square (double x);
++
++double
++dist (double x1, double y1,
++ double x2, double y2);
++
++void
++shade (const decor_color_t *a,
++ decor_color_t *b,
++ float k);
++
++gboolean
++get_window_prop (Window xwindow,
++ Atom atom,
++ Window *val);
++
++unsigned int
++get_mwm_prop (Window xwindow);
++
++
++/* style.c */
++
++void
++update_style (GtkWidget *widget);
++
++void
++style_changed (GtkWidget *widget);
++
++/* settings.c */
++
++gboolean
++init_settings (WnckScreen *screen);
++
++#endif
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/gwd.schemas.in
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/gwd.schemas.in 2011-04-06 22:06:48.551070718 +0800
+@@ -0,0 +1,81 @@
++<gconfschemafile>
++ <schemalist>
++ <schema>
++ <key>/schemas/apps/gwd/blur_type</key>
++ <applyto>/apps/gwd/blur_type</applyto>
++ <owner>gwd</owner>
++ <type>string</type>
++ <default>none</default>
++ <locale name="C">
++ <short>Blur type</short>
++ <long>Type of blur used for window decorations</long>
++ </locale>
++ </schema>
++ <schema>
++ <key>/schemas/apps/gwd/use_metacity_theme</key>
++ <applyto>/apps/gwd/use_metacity_theme</applyto>
++ <owner>gwd</owner>
++ <type>bool</type>
++ <default>true</default>
++ <locale name="C">
++ <short>Use metacity theme</short>
++ <long>Use metacity theme when drawing window decorations</long>
++ </locale>
++ </schema>
++ <schema>
++ <key>/schemas/apps/gwd/mouse_wheel_action</key>
++ <applyto>/apps/gwd/mouse_wheel_action</applyto>
++ <owner>gwd</owner>
++ <type>string</type>
++ <default>none</default>
++ <locale name="C">
++ <short>Title bar mouse wheel action</short>
++ <long>Action to take when scrolling the mouse wheel on a window title bar.</long>
++ </locale>
++ </schema>
++ <schema>
++ <key>/schemas/apps/gwd/metacity_theme_opacity</key>
++ <applyto>/apps/gwd/metacity_theme_opacity</applyto>
++ <owner>gwd</owner>
++ <type>float</type>
++ <default>0.75</default>
++ <locale name="C">
++ <short>Metacity theme opacity</short>
++ <long>Opacity to use for metacity theme decorations</long>
++ </locale>
++ </schema>
++ <schema>
++ <key>/schemas/apps/gwd/metacity_theme_shade_opacity</key>
++ <applyto>/apps/gwd/metacity_theme_shade_opacity</applyto>
++ <owner>gwd</owner>
++ <type>bool</type>
++ <default>true</default>
++ <locale name="C">
++ <short>Metacity theme opacity shade</short>
++ <long>Shade windows with metacity theme decorations from opaque to translucent</long>
++ </locale>
++ </schema>
++ <schema>
++ <key>/schemas/apps/gwd/metacity_theme_active_opacity</key>
++ <applyto>/apps/gwd/metacity_theme_active_opacity</applyto>
++ <owner>gwd</owner>
++ <type>float</type>
++ <default>1.0</default>
++ <locale name="C">
++ <short>Metacity theme active window opacity</short>
++ <long>Opacity to use for active windows with metacity theme decorations</long>
++ </locale>
++ </schema>
++ <schema>
++ <key>/schemas/apps/gwd/metacity_theme_active_shade_opacity</key>
++ <applyto>/apps/gwd/metacity_theme_active_shade_opacity</applyto>
++ <owner>gwd</owner>
++ <type>bool</type>
++ <default>true</default>
++ <locale name="C">
++ <short>Metacity theme active window opacity shade</short>
++ <long>Shade active windows with metacity theme decorations from opaque to translucent</long>
++ </locale>
++ </schema>
++ </schemalist>
++</gconfschemafile>
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/metacity.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/metacity.c 2011-04-06 22:06:48.555070737 +0800
+@@ -0,0 +1,1965 @@
++#include "gtk-window-decorator.h"
++
++#ifdef USE_METACITY
++
++double meta_opacity = META_OPACITY;
++gboolean meta_shade_opacity = META_SHADE_OPACITY;
++double meta_active_opacity = META_ACTIVE_OPACITY;
++gboolean meta_active_shade_opacity = META_ACTIVE_SHADE_OPACITY;
++
++gboolean meta_button_layout_set = FALSE;
++MetaButtonLayout meta_button_layout;
++
++void
++meta_get_border_extents (decor_extents_t *extents,
++ decor_extents_t *frame_extents,
++ decor_extents_t *max_extents,
++ decor_extents_t *frame_max_extents)
++{
++ MetaTheme *theme;
++ MetaFrameStyle *frame_style;
++ MetaFrameFlags flags;
++ MetaInvisibleGrabAreaProperties *invisible_grab_area_properties;
++
++ theme = meta_theme_get_current ();
++
++ if (!theme)
++ return;
++
++ memset (&flags, 0, sizeof (flags));
++
++ frame_style = meta_theme_get_frame_style (theme, META_FRAME_TYPE_NORMAL, flags);
++
++ if (!frame_style)
++ return;
++
++ *extents = *frame_extents = _win_extents;
++ *max_extents = *frame_max_extents = _max_win_extents;
++
++ invisible_grab_area_properties =
++ meta_frame_style_get_invisible_grab_area_properties (frame_style);
++
++ if (invisible_grab_area_properties)
++ {
++ frame_extents->left += invisible_grab_area_properties->left;
++ frame_extents->right += invisible_grab_area_properties->right;
++ frame_extents->bottom += invisible_grab_area_properties->bottom;
++ }
++
++ extents->top += titlebar_height;
++ frame_extents->top += titlebar_height;
++ max_extents->top += max_titlebar_height;
++ frame_max_extents->top += max_titlebar_height;
++}
++
++static void
++decor_update_meta_window_property (decor_t *d,
++ MetaTheme *theme,
++ MetaFrameFlags flags,
++ Region top,
++ Region bottom,
++ Region left,
++ Region right)
++{
++ long data[256];
++ Display *xdisplay =
++ GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ gint nQuad;
++ decor_extents_t extents, max_extents, frame_extents, frame_max_extents;
++ decor_quad_t quads[N_QUADS_MAX];
++ gint w, lh, rh;
++ gint top_stretch_offset;
++ gint bottom_stretch_offset;
++ gint left_stretch_offset;
++ gint right_stretch_offset;
++ MetaFrameStyle *frame_style;
++ MetaInvisibleGrabAreaProperties *invisible_grab_area_properties;
++
++ w = d->border_layout.top.x2 - d->border_layout.top.x1 -
++ d->context->left_space - d->context->right_space;
++
++ if (d->border_layout.rotation)
++ lh = d->border_layout.left.x2 - d->border_layout.left.x1;
++ else
++ lh = d->border_layout.left.y2 - d->border_layout.left.y1;
++
++ if (d->border_layout.rotation)
++ rh = d->border_layout.right.x2 - d->border_layout.right.x1;
++ else
++ rh = d->border_layout.right.y2 - d->border_layout.right.y1;
++
++ left_stretch_offset = lh / 2;
++ right_stretch_offset = rh / 2;
++ top_stretch_offset = w - d->button_width - 1;
++ bottom_stretch_offset = (d->border_layout.bottom.x2 -
++ d->border_layout.bottom.x1 -
++ d->context->left_space -
++ d->context->right_space) / 2;
++
++ nQuad = decor_set_lXrXtXbX_window_quads (quads, d->context,
++ &d->border_layout,
++ left_stretch_offset,
++ right_stretch_offset,
++ top_stretch_offset,
++ bottom_stretch_offset);
++
++ extents = frame_extents = _win_extents;
++ max_extents = frame_max_extents = _max_win_extents;
++
++ /* Add the invisible grab area padding, but only for
++ * pixmap type decorations */
++ frame_style = meta_theme_get_frame_style (theme, META_FRAME_TYPE_NORMAL, flags);
++
++ if (!frame_style)
++ return;
++
++ invisible_grab_area_properties =
++ meta_frame_style_get_invisible_grab_area_properties (frame_style);
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ frame_extents.left += invisible_grab_area_properties->left;
++ frame_extents.right += invisible_grab_area_properties->right;
++ frame_extents.bottom += invisible_grab_area_properties->bottom;
++ }
++
++ extents.top += titlebar_height;
++ frame_extents.top += titlebar_height;
++ max_extents.top += max_titlebar_height;
++ frame_max_extents.top += max_titlebar_height;
++
++ if (d->frame_window)
++ decor_gen_window_property (data, &extents, &max_extents, 20, 20);
++ else
++ decor_quads_to_property (data, GDK_PIXMAP_XID (d->pixmap),
++ &frame_extents, &extents, &frame_max_extents, &max_extents,
++ ICON_SPACE + d->button_width,
++ 0,
++ quads, nQuad);
++
++ gdk_error_trap_push ();
++ XChangeProperty (xdisplay, d->prop_xid,
++ win_decor_atom,
++ XA_INTEGER,
++ 32, PropModeReplace, (guchar *) data,
++ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++
++ decor_update_blur_property (d,
++ w, lh,
++ top, top_stretch_offset,
++ bottom, bottom_stretch_offset,
++ left, left_stretch_offset,
++ right, right_stretch_offset);
++}
++
++static void
++meta_get_corner_radius (const MetaFrameGeometry *fgeom,
++ int *top_left_radius,
++ int *top_right_radius,
++ int *bottom_left_radius,
++ int *bottom_right_radius)
++{
++
++#ifdef HAVE_METACITY_2_17_0
++ *top_left_radius = fgeom->top_left_corner_rounded_radius;
++ *top_right_radius = fgeom->top_right_corner_rounded_radius;
++ *bottom_left_radius = fgeom->bottom_left_corner_rounded_radius;
++ *bottom_right_radius = fgeom->bottom_right_corner_rounded_radius;
++#else
++ *top_left_radius = fgeom->top_left_corner_rounded ? 5 : 0;
++ *top_right_radius = fgeom->top_right_corner_rounded ? 5 : 0;
++ *bottom_left_radius = fgeom->bottom_left_corner_rounded ? 5 : 0;
++ *bottom_right_radius = fgeom->bottom_right_corner_rounded ? 5 : 0;
++#endif
++
++}
++
++static int
++radius_to_width (int radius,
++ int i)
++{
++ float r1 = sqrt (radius) + radius;
++ float r2 = r1 * r1 - (r1 - (i + 0.5)) * (r1 - (i + 0.5));
++
++ return floor (0.5f + r1 - sqrt (r2));
++}
++
++static Region
++meta_get_top_border_region (const MetaFrameGeometry *fgeom,
++ int width)
++{
++ Region corners_xregion, border_xregion;
++ XRectangle xrect;
++ int top_left_radius;
++ int top_right_radius;
++ int bottom_left_radius;
++ int bottom_right_radius;
++ int w, i;
++
++ corners_xregion = XCreateRegion ();
++
++ meta_get_corner_radius (fgeom,
++ &top_left_radius,
++ &top_right_radius,
++ &bottom_left_radius,
++ &bottom_right_radius);
++
++ if (top_left_radius)
++ {
++ for (i = 0; i < top_left_radius; i++)
++ {
++ w = radius_to_width (top_left_radius, i);
++
++ xrect.x = 0;
++ xrect.y = i;
++ xrect.width = w;
++ xrect.height = 1;
++
++ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
++ }
++ }
++
++ if (top_right_radius)
++ {
++ for (i = 0; i < top_right_radius; i++)
++ {
++ w = radius_to_width (top_right_radius, i);
++
++ xrect.x = width - w;
++ xrect.y = i;
++ xrect.width = w;
++ xrect.height = 1;
++
++ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
++ }
++ }
++
++ border_xregion = XCreateRegion ();
++
++ xrect.x = 0;
++ xrect.y = 0;
++ xrect.width = width;
++ xrect.height = fgeom->top_height;
++
++ XUnionRectWithRegion (&xrect, border_xregion, border_xregion);
++
++ XSubtractRegion (border_xregion, corners_xregion, border_xregion);
++
++ XDestroyRegion (corners_xregion);
++
++ return border_xregion;
++}
++
++static Region
++meta_get_bottom_border_region (const MetaFrameGeometry *fgeom,
++ int width)
++{
++ Region corners_xregion, border_xregion;
++ XRectangle xrect;
++ int top_left_radius;
++ int top_right_radius;
++ int bottom_left_radius;
++ int bottom_right_radius;
++ int w, i;
++
++ corners_xregion = XCreateRegion ();
++
++ meta_get_corner_radius (fgeom,
++ &top_left_radius,
++ &top_right_radius,
++ &bottom_left_radius,
++ &bottom_right_radius);
++
++ if (bottom_left_radius)
++ {
++ for (i = 0; i < bottom_left_radius; i++)
++ {
++ w = radius_to_width (bottom_left_radius, i);
++
++ xrect.x = 0;
++ xrect.y = fgeom->bottom_height - i - 1;
++ xrect.width = w;
++ xrect.height = 1;
++
++ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
++ }
++ }
++
++ if (bottom_right_radius)
++ {
++ for (i = 0; i < bottom_right_radius; i++)
++ {
++ w = radius_to_width (bottom_right_radius, i);
++
++ xrect.x = width - w;
++ xrect.y = fgeom->bottom_height - i - 1;
++ xrect.width = w;
++ xrect.height = 1;
++
++ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
++ }
++ }
++
++ border_xregion = XCreateRegion ();
++
++ xrect.x = 0;
++ xrect.y = 0;
++ xrect.width = width;
++ xrect.height = fgeom->bottom_height;
++
++ XUnionRectWithRegion (&xrect, border_xregion, border_xregion);
++
++ XSubtractRegion (border_xregion, corners_xregion, border_xregion);
++
++ XDestroyRegion (corners_xregion);
++
++ return border_xregion;
++}
++
++static Region
++meta_get_left_border_region (const MetaFrameGeometry *fgeom,
++ int height)
++{
++ Region border_xregion;
++ XRectangle xrect;
++
++ border_xregion = XCreateRegion ();
++
++ xrect.x = 0;
++ xrect.y = 0;
++ xrect.width = fgeom->left_width;
++ xrect.height = height - fgeom->top_height - fgeom->bottom_height;
++
++ XUnionRectWithRegion (&xrect, border_xregion, border_xregion);
++
++ return border_xregion;
++}
++
++static Region
++meta_get_right_border_region (const MetaFrameGeometry *fgeom,
++ int height)
++{
++ Region border_xregion;
++ XRectangle xrect;
++
++ border_xregion = XCreateRegion ();
++
++ xrect.x = 0;
++ xrect.y = 0;
++ xrect.width = fgeom->right_width;
++ xrect.height = height - fgeom->top_height - fgeom->bottom_height;
++
++ XUnionRectWithRegion (&xrect, border_xregion, border_xregion);
++
++ return border_xregion;
++}
++
++static MetaButtonState
++meta_button_state (int state)
++{
++ if (state & IN_EVENT_WINDOW)
++ {
++ if (state & PRESSED_EVENT_WINDOW)
++ return META_BUTTON_STATE_PRESSED;
++
++ return META_BUTTON_STATE_PRELIGHT;
++ }
++
++ return META_BUTTON_STATE_NORMAL;
++}
++
++static MetaButtonType
++meta_function_to_type (MetaButtonFunction function)
++{
++ switch (function) {
++ case META_BUTTON_FUNCTION_MENU:
++ return META_BUTTON_TYPE_MENU;
++ case META_BUTTON_FUNCTION_MINIMIZE:
++ return META_BUTTON_TYPE_MINIMIZE;
++ case META_BUTTON_FUNCTION_MAXIMIZE:
++ return META_BUTTON_TYPE_MAXIMIZE;
++ case META_BUTTON_FUNCTION_CLOSE:
++ return META_BUTTON_TYPE_CLOSE;
++
++#ifdef HAVE_METACITY_2_17_0
++ case META_BUTTON_FUNCTION_SHADE:
++ return META_BUTTON_TYPE_SHADE;
++ case META_BUTTON_FUNCTION_ABOVE:
++ return META_BUTTON_TYPE_ABOVE;
++ case META_BUTTON_FUNCTION_STICK:
++ return META_BUTTON_TYPE_STICK;
++ case META_BUTTON_FUNCTION_UNSHADE:
++ return META_BUTTON_TYPE_UNSHADE;
++ case META_BUTTON_FUNCTION_UNABOVE:
++ return META_BUTTON_TYPE_UNABOVE;
++ case META_BUTTON_FUNCTION_UNSTICK:
++ return META_BUTTON_TYPE_UNSTICK;
++#endif
++
++ default:
++ break;
++ }
++
++ return META_BUTTON_TYPE_LAST;
++}
++
++static MetaButtonState
++meta_button_state_for_button_type (decor_t *d,
++ MetaButtonType type)
++{
++ switch (type) {
++ case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
++ type = meta_function_to_type (meta_button_layout.left_buttons[0]);
++ break;
++ case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
++ type = meta_function_to_type (meta_button_layout.left_buttons[1]);
++ break;
++ case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
++ type = meta_function_to_type (meta_button_layout.left_buttons[2]);
++ break;
++ case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
++ type = meta_function_to_type (meta_button_layout.right_buttons[0]);
++ break;
++ case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
++ type = meta_function_to_type (meta_button_layout.right_buttons[1]);
++ break;
++ case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
++ type = meta_function_to_type (meta_button_layout.right_buttons[2]);
++ default:
++ break;
++ }
++
++ switch (type) {
++ case META_BUTTON_TYPE_CLOSE:
++ return meta_button_state (d->button_states[BUTTON_CLOSE]);
++ case META_BUTTON_TYPE_MAXIMIZE:
++ return meta_button_state (d->button_states[BUTTON_MAX]);
++ case META_BUTTON_TYPE_MINIMIZE:
++ return meta_button_state (d->button_states[BUTTON_MIN]);
++ case META_BUTTON_TYPE_MENU:
++ return meta_button_state (d->button_states[BUTTON_MENU]);
++
++#ifdef HAVE_METACITY_2_17_0
++ case META_BUTTON_TYPE_SHADE:
++ return meta_button_state (d->button_states[BUTTON_SHADE]);
++ case META_BUTTON_TYPE_ABOVE:
++ return meta_button_state (d->button_states[BUTTON_ABOVE]);
++ case META_BUTTON_TYPE_STICK:
++ return meta_button_state (d->button_states[BUTTON_STICK]);
++ case META_BUTTON_TYPE_UNSHADE:
++ return meta_button_state (d->button_states[BUTTON_UNSHADE]);
++ case META_BUTTON_TYPE_UNABOVE:
++ return meta_button_state (d->button_states[BUTTON_UNABOVE]);
++ case META_BUTTON_TYPE_UNSTICK:
++ return meta_button_state (d->button_states[BUTTON_UNSTICK]);
++#endif
++
++ default:
++ break;
++ }
++
++ return META_BUTTON_STATE_NORMAL;
++}
++
++void
++meta_get_decoration_geometry (decor_t *d,
++ MetaTheme *theme,
++ MetaFrameFlags *flags,
++ MetaFrameGeometry *fgeom,
++ MetaButtonLayout *button_layout,
++ GdkRectangle *clip)
++{
++ gint left_width, right_width, top_height, bottom_height;
++
++ if (meta_button_layout_set)
++ {
++ *button_layout = meta_button_layout;
++ }
++ else
++ {
++ gint i;
++
++ button_layout->left_buttons[0] = META_BUTTON_FUNCTION_MENU;
++
++ for (i = 1; i < MAX_BUTTONS_PER_CORNER; i++)
++ button_layout->left_buttons[i] = META_BUTTON_FUNCTION_LAST;
++
++ button_layout->right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
++ button_layout->right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
++ button_layout->right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
++
++ for (i = 3; i < MAX_BUTTONS_PER_CORNER; i++)
++ button_layout->right_buttons[i] = META_BUTTON_FUNCTION_LAST;
++ }
++
++ *flags = 0;
++
++ if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_DELETE;
++
++ if (d->actions & WNCK_WINDOW_ACTION_MINIMIZE)
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_MINIMIZE;
++
++ if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_MAXIMIZE;
++
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_MENU;
++
++ if (d->actions & WNCK_WINDOW_ACTION_RESIZE)
++ {
++ if (!(d->state & WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_VERTICAL_RESIZE;
++ if (!(d->state & WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY))
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_HORIZONTAL_RESIZE;
++ }
++
++ if (d->actions & WNCK_WINDOW_ACTION_MOVE)
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_MOVE;
++
++ if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_MAXIMIZE;
++
++ if (d->actions & WNCK_WINDOW_ACTION_SHADE)
++ *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_SHADE;
++
++ if (d->active)
++ *flags |= (MetaFrameFlags ) META_FRAME_HAS_FOCUS;
++ else if (d->transient_windows)
++ {
++ GSList *transient_windows = d->transient_windows;
++
++ for (; transient_windows;
++ transient_windows = transient_windows->next)
++ {
++ if (!transient_windows->data)
++ continue;
++
++ decor_t *d_transient = g_object_get_data (transient_windows->data, "decor");
++
++ if (d_transient)
++ {
++ if (d_transient->active)
++ {
++ *flags |= (MetaFrameFlags ) META_FRAME_HAS_FOCUS;
++ break;
++ }
++ }
++ }
++ }
++
++ if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
++ *flags |= (MetaFrameFlags ) META_FRAME_MAXIMIZED;
++
++ if (d->state & WNCK_WINDOW_STATE_STICKY)
++ *flags |= (MetaFrameFlags ) META_FRAME_STUCK;
++
++ if (d->state & WNCK_WINDOW_STATE_FULLSCREEN)
++ *flags |= (MetaFrameFlags ) META_FRAME_FULLSCREEN;
++
++ if (d->state & WNCK_WINDOW_STATE_SHADED)
++ *flags |= (MetaFrameFlags ) META_FRAME_SHADED;
++
++#ifdef HAVE_METACITY_2_17_0
++ if (d->state & WNCK_WINDOW_STATE_ABOVE)
++ *flags |= (MetaFrameFlags ) META_FRAME_ABOVE;
++#endif
++
++ meta_theme_get_frame_borders (theme,
++ META_FRAME_TYPE_NORMAL,
++ text_height,
++ *flags,
++ &top_height,
++ &bottom_height,
++ &left_width,
++ &right_width);
++
++ clip->x = d->context->left_space - left_width;
++ clip->y = d->context->top_space - top_height;
++
++ clip->width = d->border_layout.top.x2 - d->border_layout.top.x1;
++ clip->width -= d->context->right_space + d->context->left_space;
++
++ if (d->border_layout.rotation)
++ clip->height = d->border_layout.left.x2 - d->border_layout.left.x1;
++ else
++ clip->height = d->border_layout.left.y2 - d->border_layout.left.y1;
++
++ meta_theme_calc_geometry (theme,
++ META_FRAME_TYPE_NORMAL,
++ text_height,
++ *flags,
++ clip->width,
++ clip->height,
++ button_layout,
++ fgeom);
++
++ clip->width += left_width + right_width;
++ clip->height += top_height + bottom_height;
++}
++
++void
++meta_draw_window_decoration (decor_t *d)
++{
++ Display *xdisplay =
++ GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ GdkPixmap *pixmap;
++ Picture src;
++ MetaButtonState button_states[META_BUTTON_TYPE_LAST];
++ MetaButtonLayout button_layout;
++ MetaFrameGeometry fgeom;
++ MetaFrameFlags flags;
++ MetaTheme *theme;
++ GtkStyle *style;
++ cairo_t *cr;
++ gint size, i;
++ GdkRectangle clip, rect;
++ GdkDrawable *drawable;
++ Region top_region = NULL;
++ Region bottom_region = NULL;
++ Region left_region = NULL;
++ Region right_region = NULL;
++ double alpha = (d->active) ? meta_active_opacity : meta_opacity;
++ gboolean shade_alpha = (d->active) ? meta_active_shade_opacity :
++ meta_shade_opacity;
++ MetaFrameStyle *frame_style;
++ GtkWidget *style_window;
++ GdkColor bg_color;
++ double bg_alpha;
++
++ if (!d->pixmap || !d->picture)
++ return;
++
++ if (d->frame_window)
++ {
++ GdkColormap *cmap;
++
++ cmap = get_colormap_for_drawable (GDK_DRAWABLE (d->pixmap));
++ gdk_drawable_set_colormap (GDK_DRAWABLE (d->pixmap), cmap);
++ gdk_drawable_set_colormap (GDK_DRAWABLE (d->buffer_pixmap), cmap);
++ }
++
++ if (decoration_alpha == 1.0)
++ alpha = 1.0;
++
++ if (gdk_drawable_get_depth (GDK_DRAWABLE (d->pixmap)) == 32)
++ {
++ style = gtk_widget_get_style (style_window_rgba);
++ style_window = style_window_rgba;
++ }
++ else
++ {
++ style = gtk_widget_get_style (style_window_rgb);
++ style_window = style_window_rgb;
++ }
++
++ drawable = d->buffer_pixmap ? d->buffer_pixmap : d->pixmap;
++
++ cr = gdk_cairo_create (GDK_DRAWABLE (drawable));
++
++ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++
++ theme = meta_theme_get_current ();
++
++ meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout,
++ &clip);
++
++ /* we only have to redraw the shadow background when decoration
++ changed size */
++ if ((d->prop_xid || !d->buffer_pixmap) && !d->frame_window)
++ draw_shadow_background (d, cr, d->shadow, d->context);
++
++ for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
++ button_states[i] = meta_button_state_for_button_type (d, i);
++
++ frame_style = meta_theme_get_frame_style (theme,
++ META_FRAME_TYPE_NORMAL,
++ flags);
++
++ bg_color = style->bg[GTK_STATE_NORMAL];
++ bg_alpha = 1.0;
++
++#ifdef HAVE_METACITY_2_17_0
++ if (frame_style->window_background_color)
++ {
++ meta_color_spec_render (frame_style->window_background_color,
++ GTK_WIDGET (style_window),
++ &bg_color);
++
++ bg_alpha = frame_style->window_background_alpha / 255.0;
++ }
++#endif
++
++ cairo_destroy (cr);
++
++ rect.x = 0;
++ rect.y = 0;
++ rect.width = clip.width;
++
++ size = MAX (fgeom.top_height, fgeom.bottom_height);
++
++ if (rect.width && size)
++ {
++ XRenderPictFormat *format;
++
++ if (d->frame_window)
++ {
++ int depth;
++ GdkColormap *cmap;
++
++ cmap = get_colormap_for_drawable (GDK_DRAWABLE (d->pixmap));
++ depth = gdk_drawable_get_depth (GDK_DRAWABLE (d->frame_window));
++ pixmap = create_pixmap (rect.width, size, depth);
++ gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), cmap);
++ }
++ else
++ pixmap = create_pixmap (rect.width, size, 32);
++
++ cr = gdk_cairo_create (GDK_DRAWABLE (pixmap));
++ gdk_cairo_set_source_color_alpha (cr, &bg_color, bg_alpha);
++ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++
++ format = get_format_for_drawable (d, GDK_DRAWABLE (pixmap));
++ src = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (pixmap),
++ format, 0, NULL);
++
++ if (fgeom.top_height)
++ {
++ rect.height = fgeom.top_height;
++
++ cairo_paint (cr);
++
++ meta_theme_draw_frame (theme,
++ style_window,
++ pixmap,
++ &rect,
++ 0, 0,
++ META_FRAME_TYPE_NORMAL,
++ flags,
++ clip.width - fgeom.left_width -
++ fgeom.right_width,
++ clip.height - fgeom.top_height -
++ fgeom.bottom_height,
++ d->layout,
++ text_height,
++ &button_layout,
++ button_states,
++ d->icon_pixbuf,
++ NULL);
++
++ top_region = meta_get_top_border_region (&fgeom, clip.width);
++
++ decor_blend_border_picture (xdisplay,
++ d->context,
++ src,
++ 0, 0,
++ d->picture,
++ &d->border_layout,
++ BORDER_TOP,
++ top_region,
++ alpha * 0xffff,
++ shade_alpha,
++ 0);
++ }
++
++ if (fgeom.bottom_height)
++ {
++ rect.height = fgeom.bottom_height;
++
++ cairo_paint (cr);
++
++ meta_theme_draw_frame (theme,
++ style_window,
++ pixmap,
++ &rect,
++ 0,
++ -(clip.height - fgeom.bottom_height),
++ META_FRAME_TYPE_NORMAL,
++ flags,
++ clip.width - fgeom.left_width -
++ fgeom.right_width,
++ clip.height - fgeom.top_height -
++ fgeom.bottom_height,
++ d->layout,
++ text_height,
++ &button_layout,
++ button_states,
++ d->icon_pixbuf,
++ NULL);
++
++ bottom_region = meta_get_bottom_border_region (&fgeom, clip.width);
++
++ decor_blend_border_picture (xdisplay,
++ d->context,
++ src,
++ 0, 0,
++ d->picture,
++ &d->border_layout,
++ BORDER_BOTTOM,
++ bottom_region,
++ alpha * 0xffff,
++ shade_alpha,
++ 0);
++
++ }
++
++ cairo_destroy (cr);
++
++ g_object_unref (G_OBJECT (pixmap));
++
++ XRenderFreePicture (xdisplay, src);
++ }
++
++ rect.height = clip.height - fgeom.top_height - fgeom.bottom_height;
++
++ size = MAX (fgeom.left_width, fgeom.right_width);
++
++ if (size && rect.height)
++ {
++ XRenderPictFormat *format;
++
++ if (d->frame_window)
++ {
++ int depth;
++ GdkColormap *cmap;
++
++ cmap = get_colormap_for_drawable (GDK_DRAWABLE (d->pixmap));
++ depth = gdk_drawable_get_depth (GDK_DRAWABLE (d->frame_window));
++ pixmap = create_pixmap (size, rect.height, depth);
++ gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), cmap);
++ }
++ else
++ pixmap = create_pixmap (size, rect.height, 32);
++
++ cr = gdk_cairo_create (GDK_DRAWABLE (pixmap));
++ gdk_cairo_set_source_color_alpha (cr, &bg_color, bg_alpha);
++ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++
++ format = get_format_for_drawable (d, GDK_DRAWABLE (pixmap));
++ src = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (pixmap),
++ format, 0, NULL);
++
++ if (fgeom.left_width)
++ {
++ rect.width = fgeom.left_width;
++
++ cairo_paint (cr);
++
++ meta_theme_draw_frame (theme,
++ style_window,
++ pixmap,
++ &rect,
++ 0,
++ -fgeom.top_height,
++ META_FRAME_TYPE_NORMAL,
++ flags,
++ clip.width - fgeom.left_width -
++ fgeom.right_width,
++ clip.height - fgeom.top_height -
++ fgeom.bottom_height,
++ d->layout,
++ text_height,
++ &button_layout,
++ button_states,
++ d->icon_pixbuf,
++ NULL);
++
++ left_region = meta_get_left_border_region (&fgeom, clip.height);
++
++ decor_blend_border_picture (xdisplay,
++ d->context,
++ src,
++ 0, 0,
++ d->picture,
++ &d->border_layout,
++ BORDER_LEFT,
++ left_region,
++ alpha * 0xffff,
++ shade_alpha,
++ 0);
++ }
++
++ if (fgeom.right_width)
++ {
++ rect.width = fgeom.right_width;
++
++ cairo_paint (cr);
++
++ meta_theme_draw_frame (theme,
++ style_window,
++ pixmap,
++ &rect,
++ -(clip.width - fgeom.right_width),
++ -fgeom.top_height,
++ META_FRAME_TYPE_NORMAL,
++ flags,
++ clip.width - fgeom.left_width -
++ fgeom.right_width,
++ clip.height - fgeom.top_height -
++ fgeom.bottom_height,
++ d->layout,
++ text_height,
++ &button_layout,
++ button_states,
++ d->icon_pixbuf,
++ NULL);
++
++ right_region = meta_get_right_border_region (&fgeom, clip.height);
++
++ decor_blend_border_picture (xdisplay,
++ d->context,
++ src,
++ 0, 0,
++ d->picture,
++ &d->border_layout,
++ BORDER_RIGHT,
++ right_region,
++ alpha * 0xffff,
++ shade_alpha,
++ 0);
++ }
++
++ cairo_destroy (cr);
++
++ g_object_unref (G_OBJECT (pixmap));
++
++ XRenderFreePicture (xdisplay, src);
++ }
++
++ copy_to_front_buffer (d);
++
++ if (d->frame_window)
++ {
++ GdkWindow *gdk_frame_window = gtk_widget_get_window (d->decor_window);
++ decor_extents_t extents;
++
++ if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
++ WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
++ {
++ extents.left = 0;
++ extents.right = 0;
++ extents.top = 10;
++ extents.bottom = 0;
++ }
++ else
++ {
++ extents = _win_extents;
++ }
++
++ /*
++ * FIXME: What is '4' supposed to be for here...
++ */
++
++ gtk_image_set_from_pixmap (GTK_IMAGE (d->decor_image), d->pixmap, NULL);
++ gtk_window_resize (GTK_WINDOW (d->decor_window), d->width, d->height);
++ gdk_window_move (gdk_frame_window,
++ d->context->left_corner_space - 1,
++ d->context->top_corner_space - 1);
++ gdk_window_lower (gdk_frame_window);
++ }
++
++ if (d->prop_xid)
++ {
++ /* translate from frame to client window space */
++ if (top_region)
++ XOffsetRegion (top_region, -fgeom.left_width, -fgeom.top_height);
++ if (bottom_region)
++ XOffsetRegion (bottom_region, -fgeom.left_width, 0);
++ if (left_region)
++ XOffsetRegion (left_region, -fgeom.left_width, 0);
++
++ decor_update_meta_window_property (d, theme, flags,
++ top_region,
++ bottom_region,
++ left_region,
++ right_region);
++ d->prop_xid = 0;
++ }
++
++ if (top_region)
++ XDestroyRegion (top_region);
++ if (bottom_region)
++ XDestroyRegion (bottom_region);
++ if (left_region)
++ XDestroyRegion (left_region);
++ if (right_region)
++ XDestroyRegion (right_region);
++}
++
++void
++meta_calc_button_size (decor_t *d)
++{
++ gint i, min_x, x, y, w, h, width;
++
++ width = d->border_layout.top.x2 - d->border_layout.top.x1 -
++ d->context->left_space - d->context->right_space;
++ min_x = width;
++
++ for (i = 0; i < 3; i++)
++ {
++ static guint button_actions[3] = {
++ WNCK_WINDOW_ACTION_CLOSE,
++ WNCK_WINDOW_ACTION_MAXIMIZE,
++ WNCK_WINDOW_ACTION_MINIMIZE
++ };
++
++ if (d->actions & button_actions[i])
++ {
++ if (meta_get_button_position (d, i, width, 256,
++ &x, &y, &w, &h))
++ {
++ if (x > width / 2 && x < min_x)
++ min_x = x;
++ }
++ }
++ }
++
++ d->button_width = width - min_x + 6;
++}
++
++gboolean
++meta_get_button_position (decor_t *d,
++ gint i,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h)
++{
++ MetaButtonLayout button_layout;
++ MetaFrameGeometry fgeom;
++ MetaFrameFlags flags;
++ MetaTheme *theme;
++ MetaFrameStyle *frame_style;
++ MetaInvisibleGrabAreaProperties *invisible_grab_area_properties;
++ GdkRectangle clip;
++
++#ifdef HAVE_METACITY_2_15_21
++ MetaButtonSpace *space;
++#else
++ GdkRectangle *space;
++#endif
++
++ if (!d->context)
++ {
++ /* undecorated windows implicitly have no buttons */
++ return FALSE;
++ }
++
++ theme = meta_theme_get_current ();
++
++ meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout,
++ &clip);
++
++ frame_style = meta_theme_get_frame_style (theme, META_FRAME_TYPE_NORMAL, flags);
++
++ if (!frame_style)
++ return FALSE;
++
++ invisible_grab_area_properties =
++ meta_frame_style_get_invisible_grab_area_properties (frame_style);
++
++ switch (i) {
++ case BUTTON_MENU:
++ if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_MENU))
++ return FALSE;
++
++ space = &fgeom.menu_rect;
++ break;
++ case BUTTON_MIN:
++ if (!meta_button_present (&button_layout,
++ META_BUTTON_FUNCTION_MINIMIZE))
++ return FALSE;
++
++ space = &fgeom.min_rect;
++ break;
++ case BUTTON_MAX:
++ if (!meta_button_present (&button_layout,
++ META_BUTTON_FUNCTION_MAXIMIZE))
++ return FALSE;
++
++ space = &fgeom.max_rect;
++ break;
++ case BUTTON_CLOSE:
++ if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_CLOSE))
++ return FALSE;
++
++ space = &fgeom.close_rect;
++ break;
++
++#if defined (HAVE_METACITY_2_17_0) && defined (HAVE_LIBWNCK_2_18_1)
++ case BUTTON_SHADE:
++ if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_SHADE))
++ return FALSE;
++
++ space = &fgeom.shade_rect;
++ break;
++ case BUTTON_ABOVE:
++ if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_ABOVE))
++ return FALSE;
++
++ space = &fgeom.above_rect;
++ break;
++ case BUTTON_STICK:
++ if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_STICK))
++ return FALSE;
++
++ space = &fgeom.stick_rect;
++ break;
++ case BUTTON_UNSHADE:
++ if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_UNSHADE))
++ return FALSE;
++
++ space = &fgeom.unshade_rect;
++ break;
++ case BUTTON_UNABOVE:
++ if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_UNABOVE))
++ return FALSE;
++
++ space = &fgeom.unabove_rect;
++ break;
++ case BUTTON_UNSTICK:
++ if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_UNSTICK))
++ return FALSE;
++
++ space = &fgeom.unstick_rect;
++ break;
++#endif
++
++ default:
++ return FALSE;
++ }
++
++#ifdef HAVE_METACITY_2_15_21
++ if (!space->clickable.width && !space->clickable.height)
++ return FALSE;
++
++ *x = space->clickable.x;
++ *y = space->clickable.y;
++ *w = space->clickable.width;
++ *h = space->clickable.height;
++#else
++ if (!space->width && !space->height)
++ return FALSE;
++
++ *x = space->x;
++ *y = space->y;
++ *w = space->width;
++ *h = space->height;
++#endif
++
++ if (d->frame_window)
++ {
++ *x += _win_extents.left + 4;
++ *y += _win_extents.top + 2;
++ }
++ else if (invisible_grab_area_properties)
++ {
++ *x += invisible_grab_area_properties->left;
++ }
++
++ return TRUE;
++}
++
++gboolean
++meta_calc_decoration_size (decor_t *d,
++ gint w,
++ gint h,
++ gint name_width,
++ gint *width,
++ gint *height)
++{
++ decor_layout_t layout;
++ decor_context_t *context;
++ decor_shadow_t *shadow;
++
++ if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
++ {
++ if (!d->frame_window)
++ {
++ if (d->active)
++ {
++ context = &max_window_active_context;
++ shadow = max_border_active_shadow;
++ }
++ else
++ {
++ context = &max_window_inactive_context;
++ shadow = max_border_inactive_shadow;
++ }
++ }
++ else
++ {
++ context = &max_window_context_no_shadow;
++ shadow = max_border_no_shadow;
++ }
++ }
++ else
++ {
++ if (!d->frame_window)
++ {
++ if (d->active)
++ {
++ context = &window_active_context;
++ shadow = border_active_shadow;
++ }
++ else
++ {
++ context = &window_inactive_context;
++ shadow = border_inactive_shadow;
++ }
++ }
++ else
++ {
++ context = &window_context_no_shadow;
++ shadow = border_no_shadow;
++ }
++ }
++
++ if (!d->frame_window)
++ {
++ decor_get_best_layout (context, w, h, &layout);
++
++ if (context != d->context ||
++ memcmp (&layout, &d->border_layout, sizeof (layout)))
++ {
++ *width = layout.width;
++ *height = layout.height;
++
++ d->border_layout = layout;
++ d->context = context;
++ d->shadow = shadow;
++
++ meta_calc_button_size (d);
++
++ return TRUE;
++ }
++ }
++ else
++ {
++ if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
++ decor_get_default_layout (context, d->client_width,
++ d->client_height - titlebar_height,
++ &layout);
++ else
++ decor_get_default_layout (context, d->client_width,
++ d->client_height, &layout);
++
++ *width = layout.width;
++ *height = layout.height;
++
++ d->border_layout = layout;
++ d->shadow = no_border_shadow;
++ d->context = context;
++
++ meta_calc_button_size (d);
++
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++gboolean
++meta_button_present (MetaButtonLayout *button_layout,
++ MetaButtonFunction function)
++{
++ int i;
++
++ for (i = 0; i < MAX_BUTTONS_PER_CORNER; i++)
++ if (button_layout->left_buttons[i] == function)
++ return TRUE;
++
++ for (i = 0; i < MAX_BUTTONS_PER_CORNER; i++)
++ if (button_layout->right_buttons[i] == function)
++ return TRUE;
++
++ return FALSE;
++}
++
++#define TOP_RESIZE_HEIGHT 2
++#define RESIZE_EXTENDS 15
++
++void
++meta_get_event_window_position (decor_t *d,
++ gint i,
++ gint j,
++ gint width,
++ gint height,
++ gint *x,
++ gint *y,
++ gint *w,
++ gint *h)
++{
++ MetaButtonLayout button_layout;
++ MetaFrameGeometry fgeom;
++ MetaFrameFlags flags;
++ MetaFrameStyle *frame_style;
++ MetaInvisibleGrabAreaProperties *invisible_grab_area_properties;
++ MetaTheme *theme;
++ GdkRectangle clip;
++
++ theme = meta_theme_get_current ();
++
++ meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout,
++ &clip);
++
++ frame_style = meta_theme_get_frame_style (theme, META_FRAME_TYPE_NORMAL, flags);
++
++ if (!frame_style)
++ return;
++
++ invisible_grab_area_properties =
++ meta_frame_style_get_invisible_grab_area_properties (frame_style);
++
++ width += fgeom.right_width + fgeom.left_width;
++ height += fgeom.top_height + fgeom.bottom_height;
++
++ switch (i) {
++ case 2: /* bottom */
++ switch (j) {
++ case 2: /* bottom right */
++ if (d->frame_window)
++ {
++ *x = width - fgeom.right_width - RESIZE_EXTENDS +
++ _win_extents.left + 2;
++ *y = height - fgeom.bottom_height - RESIZE_EXTENDS +
++ _win_extents.top + 2;
++ }
++ else
++ {
++ *x = width - fgeom.right_width - RESIZE_EXTENDS;
++ *y = height - fgeom.bottom_height - RESIZE_EXTENDS;
++ }
++ *w = fgeom.right_width + RESIZE_EXTENDS;
++ *h = fgeom.bottom_height + RESIZE_EXTENDS;
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ *x += invisible_grab_area_properties->left;
++ *w += invisible_grab_area_properties->right;
++ *h += invisible_grab_area_properties->bottom;
++ }
++
++ break;
++ case 1: /* bottom */
++ *x = fgeom.left_width + RESIZE_EXTENDS;
++ *y = height - fgeom.bottom_height;
++ if (d->frame_window)
++ *y += _win_extents.top + 2;
++ *w = width - fgeom.left_width - fgeom.right_width -
++ (2 * RESIZE_EXTENDS);
++ *h = fgeom.bottom_height;
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ *x -= invisible_grab_area_properties->left;
++ *h += invisible_grab_area_properties->bottom;
++ *w += invisible_grab_area_properties->left +
++ invisible_grab_area_properties->right;
++ }
++
++
++ break;
++ case 0: /* bottom left */
++ default:
++ *x = 0;
++ *y = height - fgeom.bottom_height - RESIZE_EXTENDS;
++ if (d->frame_window)
++ {
++ *x += _win_extents.left + 4;
++ *y += _win_extents.bottom + 2;
++ }
++ *w = fgeom.left_width + RESIZE_EXTENDS;
++ *h = fgeom.bottom_height + RESIZE_EXTENDS;
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ *w += invisible_grab_area_properties->left;
++ *h += invisible_grab_area_properties->bottom;
++ }
++
++ break;
++ }
++ break;
++ case 1: /* middle */
++ switch (j) {
++ case 2: /* right */
++ *x = width - fgeom.right_width;
++ *y = fgeom.top_height + RESIZE_EXTENDS;
++ if (d->frame_window)
++ *x += _win_extents.left + 2;
++ *w = fgeom.right_width;
++ *h = height - fgeom.top_height - fgeom.bottom_height -
++ (2 * RESIZE_EXTENDS);
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ *x += invisible_grab_area_properties->left;
++ *w += invisible_grab_area_properties->right;
++ *h += invisible_grab_area_properties->bottom;
++ }
++
++ break;
++ case 1: /* middle */
++ *x = fgeom.left_width;
++ *y = fgeom.title_rect.y + TOP_RESIZE_HEIGHT;
++ *w = width - fgeom.left_width - fgeom.right_width;
++ *h = height - fgeom.top_titlebar_edge - fgeom.bottom_height;
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ *x += invisible_grab_area_properties->left;
++ }
++ break;
++ case 0: /* left */
++ default:
++ *x = 0;
++ if (d->frame_window)
++ *x += _win_extents.left + 4;
++ *y = fgeom.top_height + RESIZE_EXTENDS;
++ *w = fgeom.left_width;
++ *h = height - fgeom.top_height - fgeom.bottom_height -
++ (2 * RESIZE_EXTENDS);
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ *h += invisible_grab_area_properties->bottom;
++ *w += invisible_grab_area_properties->left;
++ }
++
++ break;
++ }
++ break;
++ case 0: /* top */
++ default:
++ switch (j) {
++ case 2: /* top right */
++ *x = width - fgeom.right_width - RESIZE_EXTENDS;
++ *y = 0;
++ if (d->frame_window)
++ {
++ *x += _win_extents.left + 2;
++ *y += _win_extents.top + 2 - fgeom.title_rect.height;
++ }
++ *w = fgeom.right_width + RESIZE_EXTENDS;
++ *h = fgeom.top_height + RESIZE_EXTENDS;
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ *x += invisible_grab_area_properties->left;
++ *w += invisible_grab_area_properties->right;
++ }
++ break;
++ case 1: /* top */
++ *x = fgeom.left_width + RESIZE_EXTENDS;
++ *y = 0;
++ if (d->frame_window)
++ *y += _win_extents.top + 2;
++ *w = width - fgeom.left_width - fgeom.right_width -
++ (2 * RESIZE_EXTENDS);
++ *h = fgeom.title_rect.y + TOP_RESIZE_HEIGHT;
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ {
++ *x -= invisible_grab_area_properties->left;
++ *w += invisible_grab_area_properties->right +
++ invisible_grab_area_properties->left;
++ }
++
++ break;
++ case 0: /* top left */
++ default:
++ *x = 0;
++ *y = 0;
++ if (d->frame_window)
++ {
++ *x += _win_extents.left + 4;
++ *y += _win_extents.top + 2 - fgeom.title_rect.height;
++ }
++ *w = fgeom.left_width + RESIZE_EXTENDS;
++ *h = fgeom.top_height + RESIZE_EXTENDS;
++
++ if (!d->frame_window && invisible_grab_area_properties)
++ *w += invisible_grab_area_properties->left;
++
++ break;
++ }
++ }
++
++ if (!(flags & META_FRAME_ALLOWS_VERTICAL_RESIZE))
++ {
++ /* turn off top and bottom event windows */
++ if (i == 0 || i == 2)
++ *w = *h = 0;
++ }
++
++ if (!(flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE))
++ {
++ /* turn off left and right event windows */
++ if (j == 0 || j == 2)
++ *w = *h = 0;
++ }
++}
++
++static MetaButtonFunction
++meta_button_function_from_string (const char *str)
++{
++ if (strcmp (str, "menu") == 0)
++ return META_BUTTON_FUNCTION_MENU;
++ else if (strcmp (str, "minimize") == 0)
++ return META_BUTTON_FUNCTION_MINIMIZE;
++ else if (strcmp (str, "maximize") == 0)
++ return META_BUTTON_FUNCTION_MAXIMIZE;
++ else if (strcmp (str, "close") == 0)
++ return META_BUTTON_FUNCTION_CLOSE;
++
++#ifdef HAVE_METACITY_2_17_0
++ else if (strcmp (str, "shade") == 0)
++ return META_BUTTON_FUNCTION_SHADE;
++ else if (strcmp (str, "above") == 0)
++ return META_BUTTON_FUNCTION_ABOVE;
++ else if (strcmp (str, "stick") == 0)
++ return META_BUTTON_FUNCTION_STICK;
++ else if (strcmp (str, "unshade") == 0)
++ return META_BUTTON_FUNCTION_UNSHADE;
++ else if (strcmp (str, "unabove") == 0)
++ return META_BUTTON_FUNCTION_UNABOVE;
++ else if (strcmp (str, "unstick") == 0)
++ return META_BUTTON_FUNCTION_UNSTICK;
++#endif
++
++ else
++ return META_BUTTON_FUNCTION_LAST;
++}
++
++static MetaButtonFunction
++meta_button_opposite_function (MetaButtonFunction ofwhat)
++{
++ switch (ofwhat)
++ {
++#ifdef HAVE_METACITY_2_17_0
++ case META_BUTTON_FUNCTION_SHADE:
++ return META_BUTTON_FUNCTION_UNSHADE;
++ case META_BUTTON_FUNCTION_UNSHADE:
++ return META_BUTTON_FUNCTION_SHADE;
++
++ case META_BUTTON_FUNCTION_ABOVE:
++ return META_BUTTON_FUNCTION_UNABOVE;
++ case META_BUTTON_FUNCTION_UNABOVE:
++ return META_BUTTON_FUNCTION_ABOVE;
++
++ case META_BUTTON_FUNCTION_STICK:
++ return META_BUTTON_FUNCTION_UNSTICK;
++ case META_BUTTON_FUNCTION_UNSTICK:
++ return META_BUTTON_FUNCTION_STICK;
++#endif
++
++ default:
++ return META_BUTTON_FUNCTION_LAST;
++ }
++}
++
++static void
++meta_initialize_button_layout (MetaButtonLayout *layout)
++{
++ int i;
++
++ for (i = 0; i < MAX_BUTTONS_PER_CORNER; i++)
++ {
++ layout->left_buttons[i] = META_BUTTON_FUNCTION_LAST;
++ layout->right_buttons[i] = META_BUTTON_FUNCTION_LAST;
++#ifdef HAVE_METACITY_2_23_2
++ layout->left_buttons_has_spacer[i] = FALSE;
++ layout->right_buttons_has_spacer[i] = FALSE;
++#endif
++ }
++}
++
++void
++meta_update_button_layout (const char *value)
++{
++ MetaButtonLayout new_layout;
++ MetaButtonFunction f;
++ char **sides;
++ int i;
++
++ meta_initialize_button_layout (&new_layout);
++
++ sides = g_strsplit (value, ":", 2);
++
++ if (sides[0] != NULL)
++ {
++ char **buttons;
++ int b;
++ gboolean used[META_BUTTON_FUNCTION_LAST];
++
++ for (i = 0; i < META_BUTTON_FUNCTION_LAST; i++)
++ used[i] = FALSE;
++
++ buttons = g_strsplit (sides[0], ",", -1);
++
++ i = b = 0;
++ while (buttons[b] != NULL)
++ {
++ f = meta_button_function_from_string (buttons[b]);
++#ifdef HAVE_METACITY_2_23_2
++ if (i > 0 && strcmp ("spacer", buttons[b]) == 0)
++ {
++ new_layout.left_buttons_has_spacer[i - 1] = TRUE;
++ f = meta_button_opposite_function (f);
++
++ if (f != META_BUTTON_FUNCTION_LAST)
++ new_layout.left_buttons_has_spacer[i - 2] = TRUE;
++ }
++ else
++#endif
++ {
++ if (f != META_BUTTON_FUNCTION_LAST && !used[f])
++ {
++ used[f] = TRUE;
++ new_layout.left_buttons[i++] = f;
++
++ f = meta_button_opposite_function (f);
++
++ if (f != META_BUTTON_FUNCTION_LAST)
++ new_layout.left_buttons[i++] = f;
++
++ }
++ else
++ {
++ fprintf (stderr, "%s: Ignoring unknown or already-used "
++ "button name \"%s\"\n", program_name, buttons[b]);
++ }
++ }
++ b++;
++ }
++
++ new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
++
++ g_strfreev (buttons);
++
++ if (sides[1] != NULL)
++ {
++ for (i = 0; i < META_BUTTON_FUNCTION_LAST; i++)
++ used[i] = FALSE;
++
++ buttons = g_strsplit (sides[1], ",", -1);
++
++ i = b = 0;
++ while (buttons[b] != NULL)
++ {
++ f = meta_button_function_from_string (buttons[b]);
++#ifdef HAVE_METACITY_2_23_2
++ if (i > 0 && strcmp ("spacer", buttons[b]) == 0)
++ {
++ new_layout.right_buttons_has_spacer[i - 1] = TRUE;
++ f = meta_button_opposite_function (f);
++ if (f != META_BUTTON_FUNCTION_LAST)
++ new_layout.right_buttons_has_spacer[i - 2] = TRUE;
++ }
++ else
++#endif
++ {
++ if (f != META_BUTTON_FUNCTION_LAST && !used[f])
++ {
++ used[f] = TRUE;
++ new_layout.right_buttons[i++] = f;
++
++ f = meta_button_opposite_function (f);
++
++ if (f != META_BUTTON_FUNCTION_LAST)
++ new_layout.right_buttons[i++] = f;
++ }
++ else
++ {
++ fprintf (stderr, "%s: Ignoring unknown or "
++ "already-used button name \"%s\"\n",
++ program_name, buttons[b]);
++ }
++ }
++ b++;
++ }
++ new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
++
++ g_strfreev (buttons);
++ }
++ }
++
++ g_strfreev (sides);
++
++ /* Invert the button layout for RTL languages */
++ if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
++ {
++ MetaButtonLayout rtl_layout;
++ int j;
++
++ meta_initialize_button_layout (&rtl_layout);
++
++ i = 0;
++ while (new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST)
++ i++;
++
++ for (j = 0; j < i; j++)
++ {
++ rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
++#ifdef HAVE_METACITY_2_23_2
++ if (j == 0)
++ rtl_layout.right_buttons_has_spacer[i - 1] =
++ new_layout.left_buttons_has_spacer[i - j - 1];
++ else
++ rtl_layout.right_buttons_has_spacer[j - 1] =
++ new_layout.left_buttons_has_spacer[i - j - 1];
++#endif
++ }
++
++ i = 0;
++ while (new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST)
++ i++;
++
++ for (j = 0; j < i; j++)
++ {
++ rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
++#ifdef HAVE_METACITY_2_23_2
++ if (j == 0)
++ rtl_layout.left_buttons_has_spacer[i - 1] =
++ new_layout.right_buttons_has_spacer[i - j - 1];
++ else
++ rtl_layout.left_buttons_has_spacer[j - 1] =
++ new_layout.right_buttons_has_spacer[i - j - 1];
++#endif
++ }
++
++ new_layout = rtl_layout;
++ }
++
++ meta_button_layout = new_layout;
++}
++
++void
++meta_update_border_extents (gint text_height)
++{
++ MetaTheme *theme;
++ gint top_height, bottom_height, left_width, right_width;
++
++ theme = meta_theme_get_current ();
++
++ meta_theme_get_frame_borders (theme,
++ META_FRAME_TYPE_NORMAL,
++ text_height, 0,
++ &top_height,
++ &bottom_height,
++ &left_width,
++ &right_width);
++
++ _win_extents.top = _default_win_extents.top;
++ _win_extents.bottom = bottom_height;
++ _win_extents.left = left_width;
++ _win_extents.right = right_width;
++
++ titlebar_height = top_height - _win_extents.top;
++
++ meta_theme_get_frame_borders (theme,
++ META_FRAME_TYPE_NORMAL,
++ text_height, META_FRAME_MAXIMIZED,
++ &top_height,
++ &bottom_height,
++ &left_width,
++ &right_width);
++
++ _max_win_extents.top = _default_win_extents.top;
++ _max_win_extents.bottom = bottom_height;
++ _max_win_extents.left = left_width;
++ _max_win_extents.right = right_width;
++
++ max_titlebar_height = top_height - _max_win_extents.top;
++}
++
++decor_shadow_t *
++meta_update_shadow (gint shadow_type)
++{
++
++ decor_shadow_options_t opt_shadow;
++ MetaTheme *theme;
++ MetaFrameStyle *frame_style;
++ MetaShadowProperties *shadow_properties;
++ MetaFrameFlags frame_flags;
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ GdkDisplay *display = gdk_display_get_default ();
++ GdkScreen *screen = gdk_display_get_default_screen (display);
++
++ memcpy (opt_shadow.shadow_color, shadow_color, sizeof (shadow_color));
++ memset (&frame_flags, 0, sizeof (MetaFrameFlags));
++
++
++ theme = meta_theme_get_current ();
++
++ switch (shadow_type)
++ {
++ case SHADOW_TYPE_ACTIVE_NORMAL:
++
++ frame_flags |= META_FRAME_HAS_FOCUS;
++ frame_style = meta_theme_get_frame_style (theme,
++ META_FRAME_TYPE_NORMAL,
++ frame_flags);
++
++ if (!frame_style)
++ return NULL;
++
++ shadow_properties = meta_frame_style_get_shadow_properties (frame_style);
++
++ if (!shadow_properties)
++ return NULL;
++
++ opt_shadow.shadow_radius = shadow_properties->unity_shadow_radius;
++ opt_shadow.shadow_offset_x = shadow_properties->unity_shadow_x_offset;
++ opt_shadow.shadow_offset_y = shadow_properties->unity_shadow_y_offset;
++ opt_shadow.shadow_opacity = shadow_properties->unity_shadow_opacity;
++
++ return decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _win_extents.left,
++ _win_extents.right,
++ _win_extents.top + titlebar_height,
++ _win_extents.bottom,
++ _win_extents.left -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.right -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.top + titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.bottom -
++ TRANSLUCENT_CORNER_SIZE,
++ &opt_shadow,
++ &window_active_context,
++ draw_border_shape,
++ 0);
++ break;
++ case SHADOW_TYPE_ACTIVE_MAX:
++
++ frame_flags |= META_FRAME_MAXIMIZED;
++ frame_flags |= META_FRAME_HAS_FOCUS;
++
++ frame_style = meta_theme_get_frame_style (theme,
++ META_FRAME_TYPE_NORMAL,
++ frame_flags);
++ if (!frame_style)
++ return NULL;
++
++ shadow_properties = meta_frame_style_get_shadow_properties (frame_style);
++
++ if (!shadow_properties)
++ return NULL;
++
++ opt_shadow.shadow_radius = shadow_properties->unity_shadow_radius;
++ opt_shadow.shadow_offset_x = shadow_properties->unity_shadow_x_offset;
++ opt_shadow.shadow_offset_y = shadow_properties->unity_shadow_y_offset;
++ opt_shadow.shadow_opacity = shadow_properties->unity_shadow_opacity;
++
++ return decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _max_win_extents.left,
++ _max_win_extents.right,
++ _max_win_extents.top + max_titlebar_height,
++ _max_win_extents.bottom,
++ _max_win_extents.left - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.right - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.top + max_titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.bottom - TRANSLUCENT_CORNER_SIZE,
++ &opt_shadow,
++ &max_window_active_context,
++ draw_border_shape,
++ (void *) 1);
++ case SHADOW_TYPE_INACTIVE_NORMAL:
++
++ frame_style = meta_theme_get_frame_style (theme,
++ META_FRAME_TYPE_NORMAL,
++ frame_flags);
++ if (!frame_style)
++ return NULL;
++
++ shadow_properties = meta_frame_style_get_shadow_properties (frame_style);
++
++ if (!shadow_properties)
++ return NULL;
++
++ opt_shadow.shadow_radius = shadow_properties->unity_shadow_radius;
++ opt_shadow.shadow_offset_x = shadow_properties->unity_shadow_x_offset;
++ opt_shadow.shadow_offset_y = shadow_properties->unity_shadow_y_offset;
++ opt_shadow.shadow_opacity = shadow_properties->unity_shadow_opacity;
++
++ return decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _win_extents.left,
++ _win_extents.right,
++ _win_extents.top + titlebar_height,
++ _win_extents.bottom,
++ _win_extents.left -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.right -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.top + titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _win_extents.bottom -
++ TRANSLUCENT_CORNER_SIZE,
++ &opt_shadow,
++ &window_inactive_context,
++ draw_border_shape,
++ 0);
++
++ case SHADOW_TYPE_INACTIVE_MAX:
++
++ frame_flags |= META_FRAME_MAXIMIZED;
++
++ frame_style = meta_theme_get_frame_style (theme,
++ META_FRAME_TYPE_NORMAL,
++ frame_flags);
++ if (!frame_style)
++ return NULL;
++
++ shadow_properties = meta_frame_style_get_shadow_properties (frame_style);
++
++ if (!shadow_properties)
++ return NULL;
++
++ opt_shadow.shadow_radius = shadow_properties->unity_shadow_radius;
++ opt_shadow.shadow_offset_x = shadow_properties->unity_shadow_x_offset;
++ opt_shadow.shadow_offset_y = shadow_properties->unity_shadow_y_offset;
++ opt_shadow.shadow_opacity = shadow_properties->unity_shadow_opacity;
++
++ return decor_shadow_create (xdisplay,
++ gdk_x11_screen_get_xscreen (screen),
++ 1, 1,
++ _max_win_extents.left,
++ _max_win_extents.right,
++ _max_win_extents.top + max_titlebar_height,
++ _max_win_extents.bottom,
++ _max_win_extents.left - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.right - TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.top + max_titlebar_height -
++ TRANSLUCENT_CORNER_SIZE,
++ _max_win_extents.bottom - TRANSLUCENT_CORNER_SIZE,
++ &opt_shadow,
++ &max_window_inactive_context,
++ draw_border_shape,
++ (void *) 1);
++ default:
++ return NULL;
++ }
++
++ return NULL;
++}
++
++void
++meta_get_shadow (decor_t *d, gint shadow_type)
++{
++}
++
++
++#endif
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/settings.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/settings.c 2011-04-06 22:06:48.559070762 +0800
+@@ -0,0 +1,567 @@
++#include "gtk-window-decorator.h"
++
++/* TODO: Trash all of this and use a window property
++ * instead - much much cleaner!
++ */
++
++void
++shadow_property_changed (WnckScreen *s)
++{
++ GdkDisplay *display = gdk_display_get_default ();
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
++ GdkScreen *screen = gdk_display_get_default_screen (display);
++ Window root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
++ Atom actual;
++ int result, format;
++ unsigned long n, left;
++ unsigned char *prop_data;
++ gboolean changed = FALSE;
++ XTextProperty shadow_color_xtp;
++
++ result = XGetWindowProperty (xdisplay, root, compiz_shadow_info_atom,
++ 0, 32768, 0, XA_INTEGER, &actual,
++ &format, &n, &left, &prop_data);
++
++ if (result != Success)
++ return;
++
++ if (n == 4)
++ {
++ long *data = (long *) prop_data;
++ gdouble radius = data[0];
++ gdouble opacity = data[1];
++ gint x_off = data[2];
++ gint y_off = data[3];
++
++ /* Radius and Opacity are multiplied by 1000 to keep precision,
++ * divide by that much to get our real radius and opacity
++ */
++ radius /= 1000;
++ opacity /= 1000;
++
++ changed = radius != shadow_radius ||
++ opacity != shadow_opacity ||
++ x_off != shadow_offset_x ||
++ y_off != shadow_offset_y;
++
++ shadow_radius = (gdouble) MAX (0.0, MIN (radius, 48.0));
++ shadow_opacity = (gdouble) MAX (0.0, MIN (opacity, 6.0));
++ shadow_offset_x = (gint) MAX (-16, MIN (x_off, 16));
++ shadow_offset_y = (gint) MAX (-16, MIN (y_off, 16));
++ }
++
++ XFree (prop_data);
++
++ result = XGetTextProperty (xdisplay, root, &shadow_color_xtp,
++ compiz_shadow_color_atom);
++
++ if (shadow_color_xtp.value)
++ {
++ int ret_count = 0;
++ char **t_data = NULL;
++
++ XTextPropertyToStringList (&shadow_color_xtp, &t_data, &ret_count);
++
++ if (ret_count == 1)
++ {
++ int c[4];
++
++ if (sscanf (t_data[0], "#%2x%2x%2x%2x",
++ &c[0], &c[1], &c[2], &c[3]) == 4)
++ {
++ shadow_color[0] = c[0] << 8 | c[0];
++ shadow_color[1] = c[1] << 8 | c[1];
++ shadow_color[2] = c[2] << 8 | c[2];
++ changed = TRUE;
++ }
++ }
++
++ XFree (shadow_color_xtp.value);
++ if (t_data)
++ XFreeStringList (t_data);
++ }
++
++ if (changed)
++ decorations_changed (s);
++}
++
++#ifdef USE_GCONF_UNITY_WINDOW_DECORATOR
++static gboolean
++blur_settings_changed (GConfClient *client)
++{
++ gchar *type;
++ int new_type = blur_type;
++
++ if (cmdline_options & CMDLINE_BLUR)
++ return FALSE;
++
++ type = gconf_client_get_string (client,
++ BLUR_TYPE_KEY,
++ NULL);
++
++ if (type)
++ {
++ if (strcmp (type, "titlebar") == 0)
++ new_type = BLUR_TYPE_TITLEBAR;
++ else if (strcmp (type, "all") == 0)
++ new_type = BLUR_TYPE_ALL;
++ else if (strcmp (type, "none") == 0)
++ new_type = BLUR_TYPE_NONE;
++
++ g_free (type);
++ }
++
++ if (new_type != blur_type)
++ {
++ blur_type = new_type;
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static gboolean
++theme_changed (GConfClient *client)
++{
++
++#ifdef USE_METACITY
++ gboolean use_meta_theme;
++
++ if (cmdline_options & CMDLINE_THEME)
++ return FALSE;
++
++ use_meta_theme = gconf_client_get_bool (client,
++ USE_META_THEME_KEY,
++ NULL);
++
++ if (use_meta_theme)
++ {
++ gchar *theme;
++
++ theme = gconf_client_get_string (client,
++ META_THEME_KEY,
++ NULL);
++
++ if (theme)
++ {
++ meta_theme_set_current (theme, TRUE);
++ if (!meta_theme_get_current ())
++ use_meta_theme = FALSE;
++
++ g_free (theme);
++ }
++ else
++ {
++ use_meta_theme = FALSE;
++ }
++ }
++
++ if (use_meta_theme)
++ {
++ theme_draw_window_decoration = meta_draw_window_decoration;
++ theme_calc_decoration_size = meta_calc_decoration_size;
++ theme_update_border_extents = meta_update_border_extents;
++ theme_get_event_window_position = meta_get_event_window_position;
++ theme_get_button_position = meta_get_button_position;
++ theme_update_shadow = meta_update_shadow;
++ theme_get_shadow = meta_get_shadow;
++ theme_get_border_extents = meta_get_border_extents;
++ }
++ else
++ {
++ theme_draw_window_decoration = draw_window_decoration;
++ theme_calc_decoration_size = calc_decoration_size;
++ theme_update_border_extents = update_border_extents;
++ theme_get_event_window_position = get_event_window_position;
++ theme_get_button_position = get_button_position;
++ theme_update_shadow = cairo_update_shadow;
++ theme_get_shadow = get_shadow;
++ theme_get_border_extents = get_border_extents;
++ }
++
++ return TRUE;
++#else
++ theme_draw_window_decoration = draw_window_decoration;
++ theme_calc_decoration_size = calc_decoration_size;
++ theme_update_border_extents = update_border_extents;
++ theme_get_event_window_position = get_event_window_position;
++ theme_get_button_position = get_button_position;
++ theme_get_border_extents = get_border_extents;
++
++ return FALSE;
++#endif
++
++}
++
++static gboolean
++theme_opacity_changed (GConfClient *client)
++{
++
++#ifdef USE_METACITY
++ gboolean shade_opacity, changed = FALSE;
++ gdouble opacity;
++
++ opacity = gconf_client_get_float (client,
++ META_THEME_OPACITY_KEY,
++ NULL);
++
++ if (!(cmdline_options & CMDLINE_OPACITY) &&
++ opacity != meta_opacity)
++ {
++ meta_opacity = opacity;
++ changed = TRUE;
++ }
++
++ if (opacity < 1.0)
++ {
++ shade_opacity = gconf_client_get_bool (client,
++ META_THEME_SHADE_OPACITY_KEY,
++ NULL);
++
++ if (!(cmdline_options & CMDLINE_OPACITY_SHADE) &&
++ shade_opacity != meta_shade_opacity)
++ {
++ meta_shade_opacity = shade_opacity;
++ changed = TRUE;
++ }
++ }
++
++ opacity = gconf_client_get_float (client,
++ META_THEME_ACTIVE_OPACITY_KEY,
++ NULL);
++
++ if (!(cmdline_options & CMDLINE_ACTIVE_OPACITY) &&
++ opacity != meta_active_opacity)
++ {
++ meta_active_opacity = opacity;
++ changed = TRUE;
++ }
++
++ if (opacity < 1.0)
++ {
++ shade_opacity =
++ gconf_client_get_bool (client,
++ META_THEME_ACTIVE_SHADE_OPACITY_KEY,
++ NULL);
++
++ if (!(cmdline_options & CMDLINE_ACTIVE_OPACITY_SHADE) &&
++ shade_opacity != meta_active_shade_opacity)
++ {
++ meta_active_shade_opacity = shade_opacity;
++ changed = TRUE;
++ }
++ }
++
++ return changed;
++#else
++ return FALSE;
++#endif
++
++}
++
++static gboolean
++button_layout_changed (GConfClient *client)
++{
++
++#ifdef USE_METACITY
++ gchar *button_layout;
++
++ button_layout = gconf_client_get_string (client,
++ META_BUTTON_LAYOUT_KEY,
++ NULL);
++
++ if (button_layout)
++ {
++ meta_update_button_layout (button_layout);
++
++ meta_button_layout_set = TRUE;
++
++ g_free (button_layout);
++
++ return TRUE;
++ }
++
++ if (meta_button_layout_set)
++ {
++ meta_button_layout_set = FALSE;
++ return TRUE;
++ }
++#endif
++
++ return FALSE;
++}
++
++static void
++titlebar_font_changed (GConfClient *client)
++{
++ gchar *str;
++
++ str = gconf_client_get_string (client,
++ COMPIZ_TITLEBAR_FONT_KEY,
++ NULL);
++ if (!str)
++ str = g_strdup ("Sans Bold 12");
++
++ if (titlebar_font)
++ pango_font_description_free (titlebar_font);
++
++ titlebar_font = pango_font_description_from_string (str);
++
++ g_free (str);
++}
++
++static void
++titlebar_click_action_changed (GConfClient *client,
++ const gchar *key,
++ int *action_value,
++ int default_value)
++{
++ gchar *action;
++
++ *action_value = default_value;
++
++ action = gconf_client_get_string (client, key, NULL);
++ if (action)
++ {
++ if (strcmp (action, "toggle_shade") == 0)
++ *action_value = CLICK_ACTION_SHADE;
++ else if (strcmp (action, "toggle_maximize") == 0)
++ *action_value = CLICK_ACTION_MAXIMIZE;
++ else if (strcmp (action, "minimize") == 0)
++ *action_value = CLICK_ACTION_MINIMIZE;
++ else if (strcmp (action, "raise") == 0)
++ *action_value = CLICK_ACTION_RAISE;
++ else if (strcmp (action, "lower") == 0)
++ *action_value = CLICK_ACTION_LOWER;
++ else if (strcmp (action, "menu") == 0)
++ *action_value = CLICK_ACTION_MENU;
++ else if (strcmp (action, "none") == 0)
++ *action_value = CLICK_ACTION_NONE;
++
++ g_free (action);
++ }
++}
++
++static void
++wheel_action_changed (GConfClient *client)
++{
++ gchar *action;
++
++ wheel_action = WHEEL_ACTION_DEFAULT;
++
++ action = gconf_client_get_string (client, WHEEL_ACTION_KEY, NULL);
++ if (action)
++ {
++ if (strcmp (action, "shade") == 0)
++ wheel_action = WHEEL_ACTION_SHADE;
++ else if (strcmp (action, "none") == 0)
++ wheel_action = WHEEL_ACTION_NONE;
++
++ g_free (action);
++ }
++}
++
++static void
++value_changed (GConfClient *client,
++ const gchar *key,
++ GConfValue *value,
++ void *data)
++{
++ gboolean changed = FALSE;
++
++ if (strcmp (key, COMPIZ_USE_SYSTEM_FONT_KEY) == 0)
++ {
++ if (gconf_client_get_bool (client,
++ COMPIZ_USE_SYSTEM_FONT_KEY,
++ NULL) != use_system_font)
++ {
++ use_system_font = !use_system_font;
++ changed = TRUE;
++ }
++ }
++ else if (strcmp (key, COMPIZ_TITLEBAR_FONT_KEY) == 0)
++ {
++ titlebar_font_changed (client);
++ changed = !use_system_font;
++ }
++ else if (strcmp (key, COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY) == 0)
++ {
++ titlebar_click_action_changed (client, key,
++ &double_click_action,
++ DOUBLE_CLICK_ACTION_DEFAULT);
++ }
++ else if (strcmp (key, COMPIZ_MIDDLE_CLICK_TITLEBAR_KEY) == 0)
++ {
++ titlebar_click_action_changed (client, key,
++ &middle_click_action,
++ MIDDLE_CLICK_ACTION_DEFAULT);
++ }
++ else if (strcmp (key, COMPIZ_RIGHT_CLICK_TITLEBAR_KEY) == 0)
++ {
++ titlebar_click_action_changed (client, key,
++ &right_click_action,
++ RIGHT_CLICK_ACTION_DEFAULT);
++ }
++ else if (strcmp (key, WHEEL_ACTION_KEY) == 0)
++ {
++ wheel_action_changed (client);
++ }
++ else if (strcmp (key, BLUR_TYPE_KEY) == 0)
++ {
++ if (blur_settings_changed (client))
++ changed = TRUE;
++ }
++ else if (strcmp (key, USE_META_THEME_KEY) == 0 ||
++ strcmp (key, META_THEME_KEY) == 0)
++ {
++ if (theme_changed (client))
++ changed = TRUE;
++ }
++ else if (strcmp (key, META_BUTTON_LAYOUT_KEY) == 0)
++ {
++ if (button_layout_changed (client))
++ changed = TRUE;
++ }
++ else if (strcmp (key, META_THEME_OPACITY_KEY) == 0 ||
++ strcmp (key, META_THEME_SHADE_OPACITY_KEY) == 0 ||
++ strcmp (key, META_THEME_ACTIVE_OPACITY_KEY) == 0 ||
++ strcmp (key, META_THEME_ACTIVE_SHADE_OPACITY_KEY) == 0)
++ {
++ if (theme_opacity_changed (client))
++ changed = TRUE;
++ }
++
++ if (changed)
++ decorations_changed (data);
++}
++#endif
++
++gboolean
++init_settings (WnckScreen *screen)
++{
++ GtkSettings *settings;
++ GdkScreen *gdkscreen;
++ GdkColormap *colormap;
++ AtkObject *switcher_label_obj;
++
++#ifdef USE_GCONF_UNITY_WINDOW_DECORATOR
++ GConfClient *gconf;
++
++ gconf = gconf_client_get_default ();
++
++ gconf_client_add_dir (gconf,
++ GCONF_DIR,
++ GCONF_CLIENT_PRELOAD_ONELEVEL,
++ NULL);
++
++ gconf_client_add_dir (gconf,
++ METACITY_GCONF_DIR,
++ GCONF_CLIENT_PRELOAD_ONELEVEL,
++ NULL);
++
++ g_signal_connect (G_OBJECT (gconf),
++ "value_changed",
++ G_CALLBACK (value_changed),
++ screen);
++#endif
++
++ style_window_rgba = gtk_window_new (GTK_WINDOW_POPUP);
++
++ gdkscreen = gdk_display_get_default_screen (gdk_display_get_default ());
++ colormap = gdk_screen_get_rgba_colormap (gdkscreen);
++ if (colormap)
++ gtk_widget_set_colormap (style_window_rgba, colormap);
++
++ gtk_widget_realize (style_window_rgba);
++
++ switcher_label = gtk_label_new ("");
++ switcher_label_obj = gtk_widget_get_accessible (switcher_label);
++ atk_object_set_role (switcher_label_obj, ATK_ROLE_STATUSBAR);
++ gtk_container_add (GTK_CONTAINER (style_window_rgba), switcher_label);
++
++ gtk_widget_set_size_request (style_window_rgba, 0, 0);
++ gtk_window_move (GTK_WINDOW (style_window_rgba), -100, -100);
++ gtk_widget_show_all (style_window_rgba);
++
++ g_signal_connect_object (style_window_rgba, "style-set",
++ G_CALLBACK (style_changed),
++ 0, 0);
++
++ settings = gtk_widget_get_settings (style_window_rgba);
++
++ g_object_get (G_OBJECT (settings), "gtk-double-click-time",
++ &double_click_timeout, NULL);
++
++ pango_context = gtk_widget_create_pango_context (style_window_rgba);
++
++ style_window_rgb = gtk_window_new (GTK_WINDOW_POPUP);
++
++ gdkscreen = gdk_display_get_default_screen (gdk_display_get_default ());
++ colormap = gdk_screen_get_rgb_colormap (gdkscreen);
++ if (colormap)
++ gtk_widget_set_colormap (style_window_rgb, colormap);
++
++ gtk_widget_realize (style_window_rgb);
++
++ switcher_label = gtk_label_new ("");
++ switcher_label_obj = gtk_widget_get_accessible (switcher_label);
++ atk_object_set_role (switcher_label_obj, ATK_ROLE_STATUSBAR);
++ gtk_container_add (GTK_CONTAINER (style_window_rgb), switcher_label);
++
++ gtk_widget_set_size_request (style_window_rgb, 0, 0);
++ gtk_window_move (GTK_WINDOW (style_window_rgb), -100, -100);
++ gtk_widget_show_all (style_window_rgb);
++
++ g_signal_connect_object (style_window_rgb, "style-set",
++ G_CALLBACK (style_changed),
++ 0, 0);
++
++ settings = gtk_widget_get_settings (style_window_rgb);
++
++ g_object_get (G_OBJECT (settings), "gtk-double-click-time",
++ &double_click_timeout, NULL);
++
++ pango_context = gtk_widget_create_pango_context (style_window_rgb);
++
++#ifdef USE_GCONF_UNITY_WINDOW_DECORATOR
++ use_system_font = gconf_client_get_bool (gconf,
++ COMPIZ_USE_SYSTEM_FONT_KEY,
++ NULL);
++ theme_changed (gconf);
++ theme_opacity_changed (gconf);
++ button_layout_changed (gconf);
++#endif
++
++ update_style (style_window_rgba);
++ update_style (style_window_rgb);
++#ifdef USE_GCONF_UNITY_WINDOW_DECORATOR
++ titlebar_font_changed (gconf);
++#endif
++
++ update_titlebar_font ();
++
++#ifdef USE_GCONF_UNITY_WINDOW_DECORATOR
++ titlebar_click_action_changed (gconf,
++ COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY,
++ &double_click_action,
++ DOUBLE_CLICK_ACTION_DEFAULT);
++ titlebar_click_action_changed (gconf,
++ COMPIZ_MIDDLE_CLICK_TITLEBAR_KEY,
++ &middle_click_action,
++ MIDDLE_CLICK_ACTION_DEFAULT);
++ titlebar_click_action_changed (gconf,
++ COMPIZ_RIGHT_CLICK_TITLEBAR_KEY,
++ &right_click_action,
++ RIGHT_CLICK_ACTION_DEFAULT);
++ wheel_action_changed (gconf);
++ blur_settings_changed (gconf);
++#endif
++
++ (*theme_update_border_extents) (text_height);
++
++ shadow_property_changed (screen);
++
++ update_shadow ();
++
++ return TRUE;
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/style.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/style.c 2011-04-06 22:06:48.559070762 +0800
+@@ -0,0 +1,42 @@
++#include "gtk-window-decorator.h"
++
++void
++update_style (GtkWidget *widget)
++{
++ GtkStyle *style;
++ decor_color_t spot_color;
++
++ style = gtk_widget_get_style (widget);
++ g_object_ref (G_OBJECT (style));
++
++ style = gtk_style_attach (style, widget->window);
++
++ spot_color.r = style->bg[GTK_STATE_SELECTED].red / 65535.0;
++ spot_color.g = style->bg[GTK_STATE_SELECTED].green / 65535.0;
++ spot_color.b = style->bg[GTK_STATE_SELECTED].blue / 65535.0;
++
++ g_object_unref (G_OBJECT (style));
++
++ shade (&spot_color, &_title_color[0], 1.05);
++ shade (&_title_color[0], &_title_color[1], 0.85);
++
++}
++
++void
++style_changed (GtkWidget *widget)
++{
++ GdkDisplay *gdkdisplay;
++ GdkScreen *gdkscreen;
++ WnckScreen *screen;
++
++ gdkdisplay = gdk_display_get_default ();
++ gdkscreen = gdk_display_get_default_screen (gdkdisplay);
++ screen = wnck_screen_get_default ();
++
++ update_style (widget);
++
++ pango_cairo_context_set_resolution (pango_context,
++ gdk_screen_get_resolution (gdkscreen));
++
++ decorations_changed (screen);
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/switcher.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/switcher.c 2011-04-06 22:06:48.559070762 +0800
+@@ -0,0 +1,455 @@
++#include "gtk-window-decorator.h"
++
++static void
++draw_switcher_background (decor_t *d)
++{
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ cairo_t *cr;
++ GtkStyle *style;
++ decor_color_t color;
++ double alpha = SWITCHER_ALPHA / 65535.0;
++ double x1, y1, x2, y2, h;
++ int top;
++ unsigned long pixel;
++ ushort a = SWITCHER_ALPHA;
++
++ if (!d->buffer_pixmap)
++ return;
++
++ style = gtk_widget_get_style (style_window_rgba);
++
++ color.r = style->bg[GTK_STATE_NORMAL].red / 65535.0;
++ color.g = style->bg[GTK_STATE_NORMAL].green / 65535.0;
++ color.b = style->bg[GTK_STATE_NORMAL].blue / 65535.0;
++
++ cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
++
++ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++
++ top = _switcher_extents.top;
++
++ x1 = switcher_context.left_space - _switcher_extents.left;
++ y1 = switcher_context.top_space - _switcher_extents.top;
++ x2 = d->width - switcher_context.right_space + _switcher_extents.right;
++ y2 = d->height - switcher_context.bottom_space + _switcher_extents.bottom;
++
++ h = y2 - y1 - _switcher_extents.top - _switcher_extents.top;
++
++ cairo_set_line_width (cr, 1.0);
++
++ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++
++ draw_shadow_background (d, cr, switcher_shadow, &switcher_context);
++
++ fill_rounded_rectangle (cr,
++ x1 + 0.5,
++ y1 + 0.5,
++ _switcher_extents.left - 0.5,
++ top - 0.5,
++ 5.0, CORNER_TOPLEFT,
++ &color, alpha, &color, alpha * 0.75,
++ SHADE_TOP | SHADE_LEFT);
++
++ fill_rounded_rectangle (cr,
++ x1 + _switcher_extents.left,
++ y1 + 0.5,
++ x2 - x1 - _switcher_extents.left -
++ _switcher_extents.right,
++ top - 0.5,
++ 5.0, 0,
++ &color, alpha, &color, alpha * 0.75,
++ SHADE_TOP);
++
++ fill_rounded_rectangle (cr,
++ x2 - _switcher_extents.right,
++ y1 + 0.5,
++ _switcher_extents.right - 0.5,
++ top - 0.5,
++ 5.0, CORNER_TOPRIGHT,
++ &color, alpha, &color, alpha * 0.75,
++ SHADE_TOP | SHADE_RIGHT);
++
++ fill_rounded_rectangle (cr,
++ x1 + 0.5,
++ y1 + top,
++ _switcher_extents.left - 0.5,
++ h,
++ 5.0, 0,
++ &color, alpha, &color, alpha * 0.75,
++ SHADE_LEFT);
++
++ fill_rounded_rectangle (cr,
++ x2 - _switcher_extents.right,
++ y1 + top,
++ _switcher_extents.right - 0.5,
++ h,
++ 5.0, 0,
++ &color, alpha, &color, alpha * 0.75,
++ SHADE_RIGHT);
++
++ fill_rounded_rectangle (cr,
++ x1 + 0.5,
++ y2 - _switcher_extents.top,
++ _switcher_extents.left - 0.5,
++ _switcher_extents.top - 0.5,
++ 5.0, CORNER_BOTTOMLEFT,
++ &color, alpha, &color, alpha * 0.75,
++ SHADE_BOTTOM | SHADE_LEFT);
++
++ fill_rounded_rectangle (cr,
++ x1 + _switcher_extents.left,
++ y2 - _switcher_extents.top,
++ x2 - x1 - _switcher_extents.left -
++ _switcher_extents.right,
++ _switcher_extents.top - 0.5,
++ 5.0, 0,
++ &color, alpha, &color, alpha * 0.75,
++ SHADE_BOTTOM);
++
++ fill_rounded_rectangle (cr,
++ x2 - _switcher_extents.right,
++ y2 - _switcher_extents.top,
++ _switcher_extents.right - 0.5,
++ _switcher_extents.top - 0.5,
++ 5.0, CORNER_BOTTOMRIGHT,
++ &color, alpha, &color, alpha * 0.75,
++ SHADE_BOTTOM | SHADE_RIGHT);
++
++ cairo_rectangle (cr, x1 + _switcher_extents.left,
++ y1 + top,
++ x2 - x1 - _switcher_extents.left - _switcher_extents.right,
++ h);
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->bg[GTK_STATE_NORMAL],
++ alpha);
++ cairo_fill (cr);
++
++ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
++
++ rounded_rectangle (cr,
++ x1 + 0.5, y1 + 0.5,
++ x2 - x1 - 1.0, y2 - y1 - 1.0,
++ 5.0,
++ CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
++ CORNER_BOTTOMRIGHT);
++
++ cairo_clip (cr);
++
++ cairo_translate (cr, 1.0, 1.0);
++
++ rounded_rectangle (cr,
++ x1 + 0.5, y1 + 0.5,
++ x2 - x1 - 1.0, y2 - y1 - 1.0,
++ 5.0,
++ CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
++ CORNER_BOTTOMRIGHT);
++
++ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.4);
++ cairo_stroke (cr);
++
++ cairo_translate (cr, -2.0, -2.0);
++
++ rounded_rectangle (cr,
++ x1 + 0.5, y1 + 0.5,
++ x2 - x1 - 1.0, y2 - y1 - 1.0,
++ 5.0,
++ CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
++ CORNER_BOTTOMRIGHT);
++
++ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.1);
++ cairo_stroke (cr);
++
++ cairo_translate (cr, 1.0, 1.0);
++
++ cairo_reset_clip (cr);
++
++ rounded_rectangle (cr,
++ x1 + 0.5, y1 + 0.5,
++ x2 - x1 - 1.0, y2 - y1 - 1.0,
++ 5.0,
++ CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
++ CORNER_BOTTOMRIGHT);
++
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ alpha);
++
++ cairo_stroke (cr);
++
++ cairo_destroy (cr);
++
++ copy_to_front_buffer (d);
++
++ pixel = ((((a * style->bg[GTK_STATE_NORMAL].blue ) >> 24) & 0x0000ff) |
++ (((a * style->bg[GTK_STATE_NORMAL].green) >> 16) & 0x00ff00) |
++ (((a * style->bg[GTK_STATE_NORMAL].red ) >> 8) & 0xff0000) |
++ (((a & 0xff00) << 16)));
++
++ decor_update_switcher_property (d);
++
++ gdk_error_trap_push ();
++ XSetWindowBackground (xdisplay, d->prop_xid, pixel);
++ XClearWindow (xdisplay, d->prop_xid);
++
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++
++ d->prop_xid = 0;
++}
++
++static void
++draw_switcher_foreground (decor_t *d)
++{
++ cairo_t *cr;
++ GtkStyle *style;
++ double alpha = SWITCHER_ALPHA / 65535.0;
++
++ if (!d->pixmap || !d->buffer_pixmap)
++ return;
++
++ style = gtk_widget_get_style (style_window_rgba);
++
++ cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
++
++ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++
++ cairo_rectangle (cr, switcher_context.left_space,
++ d->height - switcher_context.bottom_space,
++ d->width - switcher_context.left_space -
++ switcher_context.right_space,
++ SWITCHER_SPACE);
++
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->bg[GTK_STATE_NORMAL],
++ alpha);
++ cairo_fill (cr);
++
++ if (d->layout)
++ {
++ int w;
++
++ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
++
++ gdk_cairo_set_source_color_alpha (cr,
++ &style->fg[GTK_STATE_NORMAL],
++ 1.0);
++
++ pango_layout_get_pixel_size (d->layout, &w, NULL);
++
++ cairo_move_to (cr, d->width / 2 - w / 2,
++ d->height - switcher_context.bottom_space +
++ SWITCHER_SPACE / 2 - text_height / 2);
++
++ pango_cairo_show_layout (cr, d->layout);
++ }
++
++ cairo_destroy (cr);
++
++ copy_to_front_buffer (d);
++}
++
++void
++draw_switcher_decoration (decor_t *d)
++{
++ if (d->prop_xid)
++ draw_switcher_background (d);
++
++ draw_switcher_foreground (d);
++}
++
++void
++switcher_window_closed ()
++{
++ g_free (switcher_window);
++ switcher_window = NULL;
++}
++
++/* Switcher is override-redirect now, we need to track
++ * it separately */
++decor_t *
++switcher_window_opened (Window popup, Window window)
++{
++ decor_t *d;
++
++ d = switcher_window = calloc (1, sizeof (decor_t));
++ if (!d)
++ return NULL;
++
++ return d;
++}
++
++gboolean
++update_switcher_window (Window popup,
++ Window selected)
++{
++ decor_t *d = switcher_window;
++ GdkPixmap *pixmap, *buffer_pixmap = NULL;
++ unsigned int height, width = 0, border, depth;
++ int x, y;
++ Window root_return;
++ WnckWindow *selected_win;
++ Display *xdisplay;
++ XRenderPictFormat *format;
++
++ if (!d)
++ d = switcher_window_opened (popup, selected);
++
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++
++ /* Thats a round-trip */
++ XGetGeometry (gdk_x11_get_default_xdisplay (), popup, &root_return,
++ &x, &y, &width, &height, &border, &depth);
++
++ decor_get_default_layout (&switcher_context, width, 1, &d->border_layout);
++
++ width = d->border_layout.width;
++ height = d->border_layout.height;
++
++ d->decorated = FALSE;
++ d->draw = draw_switcher_decoration;
++
++ if (!d->pixmap && switcher_pixmap)
++ {
++ g_object_ref (G_OBJECT (switcher_pixmap));
++
++ d->pixmap = switcher_pixmap;
++ }
++
++ if (!d->buffer_pixmap && switcher_buffer_pixmap)
++ {
++ g_object_ref (G_OBJECT (switcher_buffer_pixmap));
++ d->buffer_pixmap = switcher_buffer_pixmap;
++ }
++
++ if (!d->width)
++ d->width = switcher_width;
++
++ if (!d->height)
++ d->height = switcher_height;
++
++ selected_win = wnck_window_get (selected);
++ if (selected_win)
++ {
++ glong name_length;
++ PangoLayoutLine *line;
++ const gchar *name;
++
++ if (d->name)
++ {
++ g_free (d->name);
++ d->name = NULL;
++ }
++
++ name = wnck_window_get_name (selected_win);
++ if (name && (name_length = strlen (name)))
++ {
++ if (!d->layout)
++ {
++ d->layout = pango_layout_new (pango_context);
++ if (d->layout)
++ pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
++ }
++
++ if (d->layout)
++ {
++ int tw;
++
++ tw = width - switcher_context.left_space -
++ switcher_context.right_space - 64;
++ pango_layout_set_auto_dir (d->layout, FALSE);
++ pango_layout_set_width (d->layout, tw * PANGO_SCALE);
++ pango_layout_set_text (d->layout, name, name_length);
++
++ line = pango_layout_get_line (d->layout, 0);
++
++ name_length = line->length;
++ if (pango_layout_get_line_count (d->layout) > 1)
++ {
++ if (name_length < 4)
++ {
++ g_object_unref (G_OBJECT (d->layout));
++ d->layout = NULL;
++ }
++ else
++ {
++ d->name = g_strndup (name, name_length);
++ strcpy (d->name + name_length - 3, "...");
++ }
++ }
++ else
++ d->name = g_strndup (name, name_length);
++
++ if (d->layout)
++ pango_layout_set_text (d->layout, d->name, name_length);
++ }
++ }
++ else if (d->layout)
++ {
++ g_object_unref (G_OBJECT (d->layout));
++ d->layout = NULL;
++ }
++ }
++
++ if (selected != switcher_selected_window)
++ {
++ gtk_label_set_text (GTK_LABEL (switcher_label), "");
++ if (selected_win && d->name)
++ gtk_label_set_text (GTK_LABEL (switcher_label), d->name);
++ switcher_selected_window = selected;
++ }
++
++ pixmap = create_pixmap (width, height, 32);
++ if (!pixmap)
++ return FALSE;
++
++ buffer_pixmap = create_pixmap (width, height, 32);
++ if (!buffer_pixmap)
++ {
++ g_object_unref (G_OBJECT (pixmap));
++ return FALSE;
++ }
++
++ if (switcher_pixmap)
++ g_object_unref (G_OBJECT (switcher_pixmap));
++
++ if (switcher_buffer_pixmap)
++ g_object_unref (G_OBJECT (switcher_buffer_pixmap));
++
++ if (d->pixmap)
++ g_object_unref (G_OBJECT (d->pixmap));
++
++ if (d->buffer_pixmap)
++ g_object_unref (G_OBJECT (d->buffer_pixmap));
++
++ if (d->cr)
++ cairo_destroy (d->cr);
++
++ if (d->picture)
++ XRenderFreePicture (xdisplay, d->picture);
++
++ switcher_pixmap = pixmap;
++ switcher_buffer_pixmap = buffer_pixmap;
++
++ switcher_width = width;
++ switcher_height = height;
++
++ g_object_ref (G_OBJECT (pixmap));
++ g_object_ref (G_OBJECT (buffer_pixmap));
++
++ d->pixmap = pixmap;
++ d->buffer_pixmap = buffer_pixmap;
++ d->cr = gdk_cairo_create (pixmap);
++
++ format = get_format_for_drawable (d, GDK_DRAWABLE (d->buffer_pixmap));
++ d->picture = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (buffer_pixmap),
++ format, 0, NULL);
++
++ d->width = width;
++ d->height = height;
++
++ d->prop_xid = popup;
++
++ queue_decor_draw (d);
++
++ return TRUE;
++}
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/util.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/util.c 2011-04-06 22:06:48.563070778 +0800
+@@ -0,0 +1,278 @@
++#include "gtk-window-decorator.h"
++
++double
++square (double x)
++{
++ return x * x;
++}
++
++double
++dist (double x1, double y1,
++ double x2, double y2)
++{
++ return sqrt (square (x1 - x2) + square (y1 - y2));
++}
++
++gboolean
++get_window_prop (Window xwindow,
++ Atom atom,
++ Window *val)
++{
++ Atom type;
++ int format;
++ gulong nitems;
++ gulong bytes_after;
++ Window *w;
++ int err, result;
++
++ *val = 0;
++
++ gdk_error_trap_push ();
++
++ type = None;
++ result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++ xwindow,
++ atom,
++ 0, G_MAXLONG,
++ False, XA_WINDOW, &type, &format, &nitems,
++ &bytes_after, (void*) &w);
++ err = gdk_error_trap_pop ();
++ if (err != Success || result != Success)
++ return FALSE;
++
++ if (type != XA_WINDOW)
++ {
++ XFree (w);
++ return FALSE;
++ }
++
++ *val = *w;
++ XFree (w);
++
++ return TRUE;
++}
++
++unsigned int
++get_mwm_prop (Window xwindow)
++{
++ Display *xdisplay;
++ Atom actual;
++ int err, result, format;
++ unsigned long n, left;
++ unsigned char *data;
++ unsigned int decor = MWM_DECOR_ALL;
++
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++
++ gdk_error_trap_push ();
++
++ result = XGetWindowProperty (xdisplay, xwindow, mwm_hints_atom,
++ 0L, 20L, FALSE, mwm_hints_atom,
++ &actual, &format, &n, &left, &data);
++
++ err = gdk_error_trap_pop ();
++ if (err != Success || result != Success)
++ return decor;
++
++ if (data)
++ {
++ MwmHints *mwm_hints = (MwmHints *) data;
++
++ if (n >= PROP_MOTIF_WM_HINT_ELEMENTS)
++ {
++ if (mwm_hints->flags & MWM_HINTS_DECORATIONS)
++ decor = mwm_hints->decorations;
++ }
++
++ XFree (data);
++ }
++
++ return decor;
++}
++
++/* from clearlooks theme */
++static void
++rgb_to_hls (gdouble *r,
++ gdouble *g,
++ gdouble *b)
++{
++ gdouble min;
++ gdouble max;
++ gdouble red;
++ gdouble green;
++ gdouble blue;
++ gdouble h, l, s;
++ gdouble delta;
++
++ red = *r;
++ green = *g;
++ blue = *b;
++
++ if (red > green)
++ {
++ if (red > blue)
++ max = red;
++ else
++ max = blue;
++
++ if (green < blue)
++ min = green;
++ else
++ min = blue;
++ }
++ else
++ {
++ if (green > blue)
++ max = green;
++ else
++ max = blue;
++
++ if (red < blue)
++ min = red;
++ else
++ min = blue;
++ }
++
++ l = (max + min) / 2;
++ s = 0;
++ h = 0;
++
++ if (max != min)
++ {
++ if (l <= 0.5)
++ s = (max - min) / (max + min);
++ else
++ s = (max - min) / (2 - max - min);
++
++ delta = max -min;
++ if (red == max)
++ h = (green - blue) / delta;
++ else if (green == max)
++ h = 2 + (blue - red) / delta;
++ else if (blue == max)
++ h = 4 + (red - green) / delta;
++
++ h *= 60;
++ if (h < 0.0)
++ h += 360;
++ }
++
++ *r = h;
++ *g = l;
++ *b = s;
++}
++
++static void
++hls_to_rgb (gdouble *h,
++ gdouble *l,
++ gdouble *s)
++{
++ gdouble hue;
++ gdouble lightness;
++ gdouble saturation;
++ gdouble m1, m2;
++ gdouble r, g, b;
++
++ lightness = *l;
++ saturation = *s;
++
++ if (lightness <= 0.5)
++ m2 = lightness * (1 + saturation);
++ else
++ m2 = lightness + saturation - lightness * saturation;
++
++ m1 = 2 * lightness - m2;
++
++ if (saturation == 0)
++ {
++ *h = lightness;
++ *l = lightness;
++ *s = lightness;
++ }
++ else
++ {
++ hue = *h + 120;
++ while (hue > 360)
++ hue -= 360;
++ while (hue < 0)
++ hue += 360;
++
++ if (hue < 60)
++ r = m1 + (m2 - m1) * hue / 60;
++ else if (hue < 180)
++ r = m2;
++ else if (hue < 240)
++ r = m1 + (m2 - m1) * (240 - hue) / 60;
++ else
++ r = m1;
++
++ hue = *h;
++ while (hue > 360)
++ hue -= 360;
++ while (hue < 0)
++ hue += 360;
++
++ if (hue < 60)
++ g = m1 + (m2 - m1) * hue / 60;
++ else if (hue < 180)
++ g = m2;
++ else if (hue < 240)
++ g = m1 + (m2 - m1) * (240 - hue) / 60;
++ else
++ g = m1;
++
++ hue = *h - 120;
++ while (hue > 360)
++ hue -= 360;
++ while (hue < 0)
++ hue += 360;
++
++ if (hue < 60)
++ b = m1 + (m2 - m1) * hue / 60;
++ else if (hue < 180)
++ b = m2;
++ else if (hue < 240)
++ b = m1 + (m2 - m1) * (240 - hue) / 60;
++ else
++ b = m1;
++
++ *h = r;
++ *l = g;
++ *s = b;
++ }
++}
++
++void
++shade (const decor_color_t *a,
++ decor_color_t *b,
++ float k)
++{
++ double red;
++ double green;
++ double blue;
++
++ red = a->r;
++ green = a->g;
++ blue = a->b;
++
++ rgb_to_hls (&red, &green, &blue);
++
++ green *= k;
++ if (green > 1.0)
++ green = 1.0;
++ else if (green < 0.0)
++ green = 0.0;
++
++ blue *= k;
++ if (blue > 1.0)
++ blue = 1.0;
++ else if (blue < 0.0)
++ blue = 0.0;
++
++ hls_to_rgb (&red, &green, &blue);
++
++ b->r = red;
++ b->g = green;
++ b->b = blue;
++}
++
+Index: compiz-0.9.4git20110322/unity/unity_window_decorator/src/wnck.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ compiz-0.9.4git20110322/unity/unity_window_decorator/src/wnck.c 2011-04-06 22:06:48.563070778 +0800
+@@ -0,0 +1,772 @@
++#include "gtk-window-decorator.h"
++
++static void
++window_name_changed (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->decorated)
++ {
++ if (!update_window_decoration_size (win))
++ queue_decor_draw (d);
++ }
++}
++
++static void
++window_geometry_changed (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->decorated)
++ {
++ int width, height;
++
++ wnck_window_get_client_window_geometry (win, NULL, NULL,
++ &width, &height);
++
++ if (width != d->client_width || height != d->client_height)
++ {
++ d->client_width = width;
++ d->client_height = height;
++
++ update_window_decoration_size (win);
++ update_event_windows (win);
++ }
++ }
++}
++
++static void
++window_icon_changed (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->decorated)
++ {
++ update_window_decoration_icon (win);
++ queue_decor_draw (d);
++ }
++}
++
++static void
++window_state_changed (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->decorated)
++ {
++ update_window_decoration_state (win);
++ if (!update_window_decoration_size (win))
++ queue_decor_draw (d);
++
++ update_event_windows (win);
++ }
++}
++
++static void
++window_actions_changed (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d->decorated)
++ {
++ update_window_decoration_actions (win);
++ if (!update_window_decoration_size (win))
++ queue_decor_draw (d);
++
++ update_event_windows (win);
++ }
++}
++
++void
++decorations_changed (WnckScreen *screen)
++{
++ GdkDisplay *gdkdisplay;
++ GdkScreen *gdkscreen;
++ GList *windows;
++ Window select;
++
++ gdkdisplay = gdk_display_get_default ();
++ gdkscreen = gdk_display_get_default_screen (gdkdisplay);
++
++ update_titlebar_font ();
++ (*theme_update_border_extents) (text_height);
++ update_shadow ();
++
++ update_default_decorations (gdkscreen);
++
++ if (minimal)
++ return;
++
++ /* Update all normal windows */
++
++ windows = wnck_screen_get_windows (screen);
++ while (windows != NULL)
++ {
++ decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
++
++ if (d->decorated)
++ {
++
++#ifdef USE_METACITY
++ if (d->draw == draw_window_decoration ||
++ d->draw == meta_draw_window_decoration)
++ d->draw = theme_draw_window_decoration;
++#endif
++
++ }
++
++ update_window_decoration (WNCK_WINDOW (windows->data));
++ windows = windows->next;
++ }
++
++ /* Update switcher window */
++
++ if (switcher_window &&
++ get_window_prop (switcher_window->prop_xid,
++ select_window_atom, &select))
++ {
++ decor_t *d = switcher_window;
++ /* force size update */
++ d->context = NULL;
++ d->width = d->height = 0;
++ switcher_width = switcher_height = 0;
++
++ update_switcher_window (d->prop_xid, select);
++ }
++}
++
++void
++restack_window (WnckWindow *win,
++ int stack_mode)
++{
++ Display *xdisplay;
++ GdkDisplay *gdkdisplay;
++ GdkScreen *screen;
++ Window xroot;
++ XEvent ev;
++
++ gdkdisplay = gdk_display_get_default ();
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
++ screen = gdk_display_get_default_screen (gdkdisplay);
++ xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
++
++ if (action_menu_mapped)
++ {
++ gtk_object_destroy (GTK_OBJECT (action_menu));
++ action_menu_mapped = FALSE;
++ action_menu = NULL;
++ return;
++ }
++
++ ev.xclient.type = ClientMessage;
++ ev.xclient.display = xdisplay;
++
++ ev.xclient.serial = 0;
++ ev.xclient.send_event = TRUE;
++
++ ev.xclient.window = wnck_window_get_xid (win);
++ ev.xclient.message_type = restack_window_atom;
++ ev.xclient.format = 32;
++
++ ev.xclient.data.l[0] = 2;
++ ev.xclient.data.l[1] = None;
++ ev.xclient.data.l[2] = stack_mode;
++ ev.xclient.data.l[3] = 0;
++ ev.xclient.data.l[4] = 0;
++
++ XSendEvent (xdisplay, xroot, FALSE,
++ SubstructureRedirectMask | SubstructureNotifyMask,
++ &ev);
++
++ XSync (xdisplay, FALSE);
++}
++
++
++void
++add_frame_window (WnckWindow *win,
++ Window frame,
++ Bool mode)
++{
++ Display *xdisplay;
++ XSetWindowAttributes attr;
++ gulong xid = wnck_window_get_xid (win);
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ gint i, j;
++
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++
++ /* If we have already done this, there is no need to do it again, except
++ * if the property changed.
++ *
++ * The reason this check is here is because sometimes the PropertyNotify X
++ * event can come a bit after the property on the window is actually set
++ * which might result in this function being called twice - once by
++ * wnck through window_opened and once through our X event handler
++ * event_filter_func
++ */
++
++ if (d->created && mode && d->frame_window)
++ return;
++
++ d->active = wnck_window_is_active (win);
++ d->win = win;
++ d->last_pos_entered = NULL;
++
++ attr.event_mask = ButtonPressMask | EnterWindowMask |
++ LeaveWindowMask | ExposureMask;
++ attr.override_redirect = TRUE;
++
++ gdk_error_trap_push ();
++
++ if (mode)
++ {
++ GdkColormap *colormap;
++
++ d->frame_window = create_gdk_window (frame);
++ d->decor_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++
++ colormap = get_colormap_for_drawable (GDK_DRAWABLE (d->frame_window));
++
++ d->decor_image = gtk_image_new ();
++
++ gtk_widget_set_colormap (d->decor_window, colormap);
++ gtk_widget_set_colormap (d->decor_image, colormap);
++
++ d->decor_event_box = gtk_event_box_new ();
++ gtk_event_box_set_visible_window (GTK_EVENT_BOX (d->decor_event_box),
++ FALSE);
++ gtk_widget_set_events (d->decor_event_box, GDK_BUTTON_PRESS_MASK |
++ GDK_BUTTON_RELEASE_MASK |
++ GDK_POINTER_MOTION_MASK);
++
++ g_signal_connect (G_OBJECT (d->decor_event_box), "button-press-event",
++ G_CALLBACK (frame_handle_button_press),
++ (gpointer) (d));
++
++ g_signal_connect (G_OBJECT (d->decor_event_box), "button-release-event",
++ G_CALLBACK (frame_handle_button_release),
++ (gpointer) (d));
++
++ g_signal_connect (G_OBJECT (d->decor_event_box), "motion-notify-event",
++ G_CALLBACK (frame_handle_motion),
++ (gpointer) (d));
++
++ gtk_container_add (GTK_CONTAINER (d->decor_event_box), d->decor_image);
++ gtk_event_box_set_above_child (GTK_EVENT_BOX (d->decor_event_box), TRUE);
++ gtk_widget_show_all (d->decor_event_box);
++ gtk_window_set_decorated (GTK_WINDOW (d->decor_window), FALSE);
++ gtk_window_set_default_size (GTK_WINDOW (d->decor_window), 1000, 1000);
++ gtk_container_add (GTK_CONTAINER (d->decor_window), d->decor_event_box);
++
++ /* Assumed realization happens here */
++
++ g_signal_connect (G_OBJECT (d->decor_window), "realize",
++ G_CALLBACK (frame_window_realized), (gpointer) d);
++
++ gtk_widget_show_all (d->decor_window);
++ gtk_widget_show (d->decor_window);
++
++ g_object_set_data (G_OBJECT (d->frame_window),
++ "client_wnck_window", win);
++ }
++ else
++ {
++ d->frame_window = NULL;
++
++ for (i = 0; i < 3; i++)
++ {
++ for (j = 0; j < 3; j++)
++ {
++ d->event_windows[i][j].window =
++ XCreateWindow (xdisplay,
++ frame,
++ 0, 0, 1, 1, 0,
++ CopyFromParent, CopyFromParent, CopyFromParent,
++ CWOverrideRedirect | CWEventMask, &attr);
++
++ if (cursor[i][j].cursor)
++ XDefineCursor (xdisplay, d->event_windows[i][j].window,
++ cursor[i][j].cursor);
++ }
++ }
++
++ attr.event_mask |= ButtonReleaseMask;
++
++ for (i = 0; i < BUTTON_NUM; i++)
++ {
++ d->button_windows[i].window =
++ XCreateWindow (xdisplay,
++ frame,
++ 0, 0, 1, 1, 0,
++ CopyFromParent, CopyFromParent, CopyFromParent,
++ CWOverrideRedirect | CWEventMask, &attr);
++
++ d->button_states[i] = 0;
++ }
++ }
++
++ gdk_display_sync (gdk_display_get_default ());
++ if (!gdk_error_trap_pop ())
++ {
++ if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
++ d->decorated = TRUE;
++
++ for (i = 0; i < 3; i++)
++ for (j = 0; j < 3; j++)
++ {
++ Window win = d->event_windows[i][j].window;
++ g_hash_table_insert (frame_table,
++ GINT_TO_POINTER (win),
++ GINT_TO_POINTER (xid));
++ }
++
++ for (i = 0; i < BUTTON_NUM; i++)
++ g_hash_table_insert (frame_table,
++ GINT_TO_POINTER (d->button_windows[i].window),
++ GINT_TO_POINTER (xid));
++
++ if (d->frame_window)
++ {
++ g_hash_table_insert (frame_table,
++ GINT_TO_POINTER (frame),
++ GINT_TO_POINTER (xid));
++ }
++ update_window_decoration_state (win);
++ update_window_decoration_actions (win);
++ update_window_decoration_icon (win);
++ update_window_decoration_size (win);
++
++ update_event_windows (win);
++ }
++ else
++ {
++ for (i = 0; i < 3; i++)
++ for (j = 0; j < 3; j++)
++ d->event_windows[i][j].window = None;
++ }
++
++ d->created = TRUE;
++}
++
++void
++remove_frame_window (WnckWindow *win)
++{
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ Display *xdisplay;
++
++ xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++
++ if (d->pixmap)
++ {
++ g_object_unref (G_OBJECT (d->pixmap));
++ d->pixmap = NULL;
++ }
++
++ if (d->buffer_pixmap)
++ {
++ g_object_unref (G_OBJECT (d->buffer_pixmap));
++ d->buffer_pixmap = NULL;
++ }
++
++ if (d->cr)
++ {
++ cairo_destroy (d->cr);
++ d->cr = NULL;
++ }
++
++ if (d->picture && !d->frame_window)
++ {
++ XRenderFreePicture (xdisplay, d->picture);
++ d->picture = 0;
++ }
++
++ if (d->name)
++ {
++ g_free (d->name);
++ d->name = NULL;
++ }
++
++ if (d->layout)
++ {
++ g_object_unref (G_OBJECT (d->layout));
++ d->layout = NULL;
++ }
++
++ if (d->icon)
++ {
++ cairo_pattern_destroy (d->icon);
++ d->icon = NULL;
++ }
++
++ if (d->icon_pixmap)
++ {
++ g_object_unref (G_OBJECT (d->icon_pixmap));
++ d->icon_pixmap = NULL;
++ }
++
++ if (d->icon_pixbuf)
++ {
++ g_object_unref (G_OBJECT (d->icon_pixbuf));
++ d->icon_pixbuf = NULL;
++ }
++
++ if (d->force_quit_dialog)
++ {
++ GtkWidget *dialog = d->force_quit_dialog;
++
++ d->force_quit_dialog = NULL;
++ gtk_widget_destroy (dialog);
++ }
++
++ if (d->frame_window)
++ {
++ gdk_window_destroy (d->frame_window);
++ d->frame_window = NULL;
++ }
++
++ if (d->decor_image)
++ {
++ g_object_unref (d->decor_image);
++ d->decor_image = NULL;
++ }
++
++ if (d->decor_event_box)
++ {
++ g_object_unref (d->decor_event_box);
++ d->decor_event_box = NULL;
++ }
++
++ if (d->decor_window)
++ {
++ g_object_unref (d->decor_window);
++ d->decor_window = NULL;
++ }
++
++ d->width = 0;
++ d->height = 0;
++
++ d->decorated = FALSE;
++
++ d->state = 0;
++ d->actions = 0;
++
++ d->context = NULL;
++ d->shadow = NULL;
++
++ draw_list = g_slist_remove (draw_list, d);
++}
++
++void
++connect_window (WnckWindow *win)
++{
++ g_signal_connect_object (win, "name_changed",
++ G_CALLBACK (window_name_changed),
++ 0, 0);
++ g_signal_connect_object (win, "geometry_changed",
++ G_CALLBACK (window_geometry_changed),
++ 0, 0);
++ g_signal_connect_object (win, "icon_changed",
++ G_CALLBACK (window_icon_changed),
++ 0, 0);
++ g_signal_connect_object (win, "state_changed",
++ G_CALLBACK (window_state_changed),
++ 0, 0);
++ g_signal_connect_object (win, "actions_changed",
++ G_CALLBACK (window_actions_changed),
++ 0, 0);
++}
++
++static void
++active_window_changed (WnckScreen *screen)
++{
++ WnckWindow *win;
++ decor_t *d;
++
++ win = wnck_screen_get_previously_active_window (screen);
++ if (win)
++ {
++ d = g_object_get_data (G_OBJECT (win), "decor");
++ if (d && d->pixmap)
++ {
++ d->active = wnck_window_is_active (win);
++
++ if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
++ {
++ if (!d->frame_window)
++ {
++ if (d->active)
++ {
++ d->context = &max_window_active_context;
++ d->shadow = max_border_active_shadow;
++ }
++ else
++ {
++ d->context = &max_window_inactive_context;
++ d->shadow = max_border_inactive_shadow;
++ }
++ }
++ else
++ {
++ d->shadow = max_border_no_shadow;
++ }
++ }
++ else
++ {
++ if (!d->frame_window)
++ {
++ if (d->active)
++ {
++ d->context = &window_active_context;
++ d->shadow = border_active_shadow;
++ }
++ else
++ {
++ d->context = &window_inactive_context;
++ d->shadow = border_inactive_shadow;
++ }
++ }
++ else
++ {
++ d->shadow = border_no_shadow;
++ }
++ }
++
++ /* We need to update the decoration size here
++ * since the shadow size might have changed and
++ * in that case the decoration will be redrawn,
++ * however if the shadow size doesn't change
++ * then we need to redraw the decoration anyways
++ * since the image would have changed */
++ if (!update_window_decoration_size (d->win))
++ queue_decor_draw (d);
++
++ /* Also update any parents of this window
++ * since they won't get a notification here
++ */
++ if (d->transient_parent)
++ {
++ decor_t *d_parent = g_object_get_data (G_OBJECT (d->transient_parent), "decor");
++ queue_decor_draw (d_parent);
++ }
++
++ }
++ }
++
++ win = wnck_screen_get_active_window (screen);
++ if (win)
++ {
++ d = g_object_get_data (G_OBJECT (win), "decor");
++ if (d && d->pixmap)
++ {
++ d->active = wnck_window_is_active (win);
++
++ if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
++ {
++ if (!d->frame_window)
++ {
++ if (d->active)
++ {
++ d->context = &max_window_active_context;
++ d->shadow = max_border_active_shadow;
++ }
++ else
++ {
++ d->context = &max_window_inactive_context;
++ d->shadow = max_border_inactive_shadow;
++ }
++ }
++ else
++ {
++ d->shadow = max_border_no_shadow;
++ }
++ }
++ else
++ {
++ if (!d->frame_window)
++ {
++ if (d->active)
++ {
++ d->context = &window_active_context;
++ d->shadow = border_active_shadow;
++ }
++ else
++ {
++ d->context = &window_inactive_context;
++ d->shadow = border_inactive_shadow;
++ }
++ }
++ else
++ {
++ d->shadow = border_no_shadow;
++ }
++ }
++
++ /* We need to update the decoration size here
++ * since the shadow size might have changed and
++ * in that case the decoration will be redrawn,
++ * however if the shadow size doesn't change
++ * then we need to redraw the decoration anyways
++ * since the image would have changed */
++ if (!update_window_decoration_size (d->win))
++ queue_decor_draw (d);
++
++ /* Also update any parents of this window
++ * since they won't get a notification here
++ */
++ if (d->transient_parent)
++ {
++ decor_t *d_parent = g_object_get_data (G_OBJECT (d->transient_parent), "decor");
++ queue_decor_draw (d_parent);
++ }
++ }
++ }
++}
++
++static void
++window_opened (WnckScreen *screen,
++ WnckWindow *win)
++{
++ decor_t *d;
++ Window window;
++ gulong xid;
++ unsigned int i, j;
++
++ static event_callback callback[3][3] = {
++ { top_left_event, top_event, top_right_event },
++ { left_event, title_event, right_event },
++ { bottom_left_event, bottom_event, bottom_right_event }
++ };
++ static event_callback button_callback[BUTTON_NUM] = {
++ close_button_event,
++ max_button_event,
++ min_button_event,
++ menu_button_event,
++ shade_button_event,
++ above_button_event,
++ stick_button_event,
++ unshade_button_event,
++ unabove_button_event,
++ unstick_button_event
++ };
++
++ d = calloc (1, sizeof (decor_t));
++ if (!d)
++ return;
++
++ for (i = 0; i < 3; i++)
++ for (j = 0; j < 3; j++)
++ d->event_windows[i][j].callback = callback[i][j];
++
++ for (i = 0; i < BUTTON_NUM; i++)
++ d->button_windows[i].callback = button_callback[i];
++
++ wnck_window_get_client_window_geometry (win, NULL, NULL,
++ &d->client_width,
++ &d->client_height);
++
++ d->draw = theme_draw_window_decoration;
++
++ d->created = FALSE;
++ d->pixmap = NULL;
++ d->cr = NULL;
++ d->buffer_pixmap = NULL;
++ d->picture = None;
++ d->transient_windows = NULL;
++
++ connect_window (win);
++
++ g_object_set_data (G_OBJECT (win), "decor", d);
++
++ xid = wnck_window_get_xid (win);
++
++ if (get_window_prop (xid, frame_input_window_atom, &window))
++ {
++ add_frame_window (win, window, FALSE);
++ }
++ else if (get_window_prop (xid, frame_output_window_atom, &window))
++ {
++ add_frame_window (win, window, TRUE);
++ }
++
++ if (wnck_window_get_window_type (win) == WNCK_WINDOW_DIALOG)
++ {
++ Window parent;
++
++ if (get_window_prop (xid, XA_WM_TRANSIENT_FOR, &parent))
++ {
++ WnckWindow *p = wnck_window_get (parent);
++ decor_t *d = g_object_get_data (G_OBJECT (p), "decor");
++ decor_t *d_transient = g_object_get_data (G_OBJECT (win), "decor");
++
++ if (d)
++ {
++ d->transient_windows = g_slist_append (d->transient_windows, win);
++ d_transient->transient_parent = p;
++ }
++ }
++ }
++}
++
++static void
++window_closed (WnckScreen *screen,
++ WnckWindow *win)
++{
++ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
++ GSList *list;
++
++ for (list = d->transient_windows; list; list = list->next)
++ {
++ WnckWindow *win = (WnckWindow *) list->data;
++ decor_t *d_transient = g_object_get_data (G_OBJECT (win), "decor");
++
++ d_transient->transient_parent = NULL;
++ }
++
++ g_slist_free (d->transient_windows);
++ d->transient_windows = NULL;
++
++ if (d->transient_parent)
++ {
++ decor_t *d_parent = g_object_get_data (G_OBJECT (d->transient_parent), "decor");
++
++ d_parent->transient_windows = g_slist_remove (d_parent->transient_windows, win);
++
++ if (!g_slist_length (d_parent->transient_windows))
++ d_parent->transient_windows = NULL;
++ }
++
++ remove_frame_window (win);
++
++ g_object_set_data (G_OBJECT (win), "decor", NULL);
++
++ gdk_error_trap_push ();
++ XDeleteProperty (xdisplay, wnck_window_get_xid (win), win_decor_atom);
++ gdk_display_sync (gdk_display_get_default ());
++ gdk_error_trap_pop ();
++
++ g_free (d);
++}
++
++void
++connect_screen (WnckScreen *screen)
++{
++ GList *windows;
++
++ g_signal_connect_object (G_OBJECT (screen), "active_window_changed",
++ G_CALLBACK (active_window_changed),
++ 0, 0);
++ g_signal_connect_object (G_OBJECT (screen), "window_opened",
++ G_CALLBACK (window_opened),
++ 0, 0);
++ g_signal_connect_object (G_OBJECT (screen), "window_closed",
++ G_CALLBACK (window_closed),
++ 0, 0);
++
++ windows = wnck_screen_get_windows (screen);
++ while (windows != NULL)
++ {
++ window_opened (screen, windows->data);
++ windows = windows->next;
++ }
++}