From e6adb283672c00dbaaeeb70d28f73eb74d1dfadf Mon Sep 17 00:00:00 2001 From: Sam Spilsbury 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 09:46:56.000000000 +0100 +++ compiz-0.9.4git20110322/CMakeLists.txt 2011-04-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -0,0 +1,29 @@ +compiz and the standard set of plugins are designed and written by + +David Reveman + +with additional functionality by + +Radek Doulik IO multiplexing +Mirco Müller Skydome support in cube plugin +Søren Sandmann plane plugin +Dan Winship gconf-dump plugin +Brian Paul Matrix functions + +and other contributions by + +Mike Cook +Mike Dransfield +Diogo Ferreira +gandalfn +Guillaume +Kristian Høgsberg +Dennis Kasprzyk +Gerd Kohlberger +Volker Krause +moppsy +Jeremy C. Reed +Thierry Reding +Julian Sikorski +Quinn Storm +Erkin Bahceci 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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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. + + + Copyright (C) + + 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. + + , 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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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@novell.com 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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -0,0 +1,870 @@ +#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); + + decor_context_t *context = &window_context_no_shadow; + + + 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 = _win_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)); + + if (d.active) + { + d.context = &window_active_context; + d.shadow = border_active_shadow; + } + else + { + 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; + + extents.top += titlebar_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); + + fprintf (stderr, "extents are %i %i %i %i %i\n", extents.left, extents.right, extents.top, extents.bottom); + + decor_quads_to_property (data, GDK_PIXMAP_XID (d.pixmap), + &extents, &extents, &extents, &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)); + + 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), + &extents, &extents, &extents, &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-01 12:29:28.000000000 +0200 @@ -0,0 +1,135 @@ +#include "gtk-window-decorator.h" + +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-01 12:29:28.000000000 +0200 @@ -0,0 +1,1173 @@ +#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 = gdk_window_foreign_new_for_display (gdkdisplay, + 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 (p), "decor"); + + if (g_slist_find (d->transient_windows, p)) + 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-01 12:29:28.000000000 +0200 @@ -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, + "%s\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-01 12:29:28.000000000 +0200 @@ -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 = gdk_window_foreign_new (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); +} \ No newline at end of file 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-01 12:29:28.000000000 +0200 @@ -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 + */ + +#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; + +#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; + } + } +#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 = gdk_window_foreign_new_for_display (gdkdisplay, + 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 = gdk_window_foreign_new_for_display (gdkdisplay, + 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-01 12:29:28.000000000 +0200 @@ -0,0 +1,980 @@ +#ifndef _GTK_WINDOW_DECORATOR_H +#define _GTK_WINDOW_DECORATOR_H +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#ifndef GDK_DISABLE_DEPRECATED +#define GDK_DISABLE_DEPRECATED +#endif + +#ifndef GTK_DISABLE_DEPRECATED +#define GTK_DISABLE_DEPRECATED +#endif + +#include +#include +#include + +#ifdef USE_GCONF_UNITY_WINDOW_DECORATOR +#include +#endif + +#ifdef USE_DBUS_GLIB +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include +#endif + +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include +#include + +#ifndef HAVE_LIBWNCK_2_19_4 +#define wnck_window_get_client_window_geometry wnck_window_get_geometry +#endif + +#include +#include + +#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 1, 0) +#define CAIRO_EXTEND_PAD CAIRO_EXTEND_NONE +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#define _(x) gettext (x) +#define N_(x) x + +#ifdef USE_METACITY +#include +#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); + +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); + +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_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-01 12:29:28.000000000 +0200 @@ -0,0 +1,81 @@ + + + + /schemas/apps/gwd/blur_type + /apps/gwd/blur_type + gwd + string + none + + Blur type + Type of blur used for window decorations + + + + /schemas/apps/gwd/use_metacity_theme + /apps/gwd/use_metacity_theme + gwd + bool + true + + Use metacity theme + Use metacity theme when drawing window decorations + + + + /schemas/apps/gwd/mouse_wheel_action + /apps/gwd/mouse_wheel_action + gwd + string + none + + Title bar mouse wheel action + Action to take when scrolling the mouse wheel on a window title bar. + + + + /schemas/apps/gwd/metacity_theme_opacity + /apps/gwd/metacity_theme_opacity + gwd + float + 0.75 + + Metacity theme opacity + Opacity to use for metacity theme decorations + + + + /schemas/apps/gwd/metacity_theme_shade_opacity + /apps/gwd/metacity_theme_shade_opacity + gwd + bool + true + + Metacity theme opacity shade + Shade windows with metacity theme decorations from opaque to translucent + + + + /schemas/apps/gwd/metacity_theme_active_opacity + /apps/gwd/metacity_theme_active_opacity + gwd + float + 1.0 + + Metacity theme active window opacity + Opacity to use for active windows with metacity theme decorations + + + + /schemas/apps/gwd/metacity_theme_active_shade_opacity + /apps/gwd/metacity_theme_active_shade_opacity + gwd + bool + true + + Metacity theme active window opacity shade + Shade active windows with metacity theme decorations from opaque to translucent + + + + 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-01 12:29:28.000000000 +0200 @@ -0,0 +1,1923 @@ +#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; + +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-01 12:29:28.000000000 +0200 @@ -0,0 +1,564 @@ +#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; + } + 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; + } + + 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; + + 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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:29:28.000000000 +0200 @@ -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-01 12:36:36.000000000 +0200 @@ -0,0 +1,789 @@ +#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 (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 (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 = NULL; + GSList *list = NULL; + + if (!screen || !win) + return; + + d = g_object_get_data (G_OBJECT (win), "decor"); + if (!d) + return; + + for (list = d->transient_windows; list; list = list->next) + { + WnckWindow *wnck_win = NULL; + decor_t *d_transient = NULL; + + wnck_win = (WnckWindow *) list->data; + if (wnck_win) + { + d_transient = g_object_get_data (G_OBJECT (wnck_win), "decor"); + if (d_transient) + d_transient->transient_parent = NULL; + } + } + + g_slist_free (d->transient_windows); + d->transient_windows = NULL; + + if (d->transient_parent) + { + decor_t *d_parent = NULL; + + d_parent = g_object_get_data (G_OBJECT (d->transient_parent), "decor"); + if (d_parent) + { + 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; + } +}