summaryrefslogtreecommitdiff
path: root/heliodor
diff options
context:
space:
mode:
authorquinn <quinn@d7aaf104-2d23-0410-ae22-9d23157bf5a3>2006-11-03 06:09:11 +0000
committerquinn <quinn@d7aaf104-2d23-0410-ae22-9d23157bf5a3>2006-11-03 06:09:11 +0000
commit3391cd0812e2ae57e03aa843d728db7c0dba8e5b (patch)
tree8f277fefa5c91f526fefdabb16cd0ede05adcb4f /heliodor
parentbdb9faadec80b039787bc53fa374c48b55088312 (diff)
downloadmarex-dev-3391cd0812e2ae57e03aa843d728db7c0dba8e5b.tar.gz
marex-dev-3391cd0812e2ae57e03aa843d728db7c0dba8e5b.tar.bz2
Initial import of heliodor, it of course can be renamed, and its in need of some work to really polish it (like that minimize-button-bug)
git-svn-id: file:///beryl/trunk@981 d7aaf104-2d23-0410-ae22-9d23157bf5a3
Diffstat (limited to 'heliodor')
-rw-r--r--heliodor/AUTHORS1
-rw-r--r--heliodor/COPYING340
-rw-r--r--heliodor/ChangeLog0
-rw-r--r--heliodor/INSTALL236
-rw-r--r--heliodor/Makefile.am1
-rw-r--r--heliodor/NEWS0
-rw-r--r--heliodor/README1
-rw-r--r--heliodor/VERSION2
-rwxr-xr-xheliodor/autogen.sh14
-rw-r--r--heliodor/configure.ac42
-rw-r--r--heliodor/lib/Makefile.am44
-rw-r--r--heliodor/lib/beryl-window-manager.c505
-rw-r--r--heliodor/lib/beryl-window-manager.h39
-rw-r--r--heliodor/lib/beryl.desktop13
-rw-r--r--heliodor/src/Makefile.am4
-rw-r--r--heliodor/src/main.c5846
16 files changed, 7088 insertions, 0 deletions
diff --git a/heliodor/AUTHORS b/heliodor/AUTHORS
new file mode 100644
index 0000000..9d6cf4b
--- /dev/null
+++ b/heliodor/AUTHORS
@@ -0,0 +1 @@
+FIXME
diff --git a/heliodor/COPYING b/heliodor/COPYING
new file mode 100644
index 0000000..623b625
--- /dev/null
+++ b/heliodor/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/heliodor/ChangeLog b/heliodor/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/heliodor/ChangeLog
diff --git a/heliodor/INSTALL b/heliodor/INSTALL
new file mode 100644
index 0000000..23e5f25
--- /dev/null
+++ b/heliodor/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script). Here is a another example:
+
+ /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/heliodor/Makefile.am b/heliodor/Makefile.am
new file mode 100644
index 0000000..77b7418
--- /dev/null
+++ b/heliodor/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=src lib
diff --git a/heliodor/NEWS b/heliodor/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/heliodor/NEWS
diff --git a/heliodor/README b/heliodor/README
new file mode 100644
index 0000000..9d6cf4b
--- /dev/null
+++ b/heliodor/README
@@ -0,0 +1 @@
+FIXME
diff --git a/heliodor/VERSION b/heliodor/VERSION
new file mode 100644
index 0000000..f7f469a
--- /dev/null
+++ b/heliodor/VERSION
@@ -0,0 +1,2 @@
+#beryl version header
+VERSION=0.1.2
diff --git a/heliodor/autogen.sh b/heliodor/autogen.sh
new file mode 100755
index 0000000..3c023f6
--- /dev/null
+++ b/heliodor/autogen.sh
@@ -0,0 +1,14 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+
+cd $ORIGDIR || exit $?
+
+$srcdir/configure "$@"
+
diff --git a/heliodor/configure.ac b/heliodor/configure.ac
new file mode 100644
index 0000000..dbcdc1c
--- /dev/null
+++ b/heliodor/configure.ac
@@ -0,0 +1,42 @@
+AC_PREREQ(2.57)
+
+AC_INIT([heliodor],esyscmd(. ./VERSION;echo -n $VERSION), [livinglatexkali@gmail.com])
+
+AC_DEFINE_UNQUOTED(VERSION,"$VERSION",[Version])
+
+AM_INIT_AUTOMAKE([dist-bzip2])
+AC_CONFIG_HEADER([config.h])
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_LIBTOOL
+AC_HEADER_STDC
+AC_CHECK_HEADERS([stdlib.h sys/time.h unistd.h])
+
+AC_C_BIGENDIAN
+HELIODOR_REQUIRES=" xrender >= 0.8.4 \
+ gtk+-2.0 >= 2.8.0 \
+ libwnck-1.0 \
+ beryl \
+ gconf-2.0 \
+ pangocairo \
+ libmetacity-private >= 2.15.21"
+PKG_CHECK_MODULES(HELIODOR, $HELIODOR_REQUIRES)
+AC_SUBST(HELIODOR_REQUIRES)
+CFLAGS="$CFLAGS $HELIODOR_CFLAGS"
+LIBS="$LIBS $HELIODOR_LIBS"
+AC_CHECK_FUNCS(wnck_window_has_name)
+PKG_CHECK_MODULES(GNOME_WINDOW_SETTINGS,
+ gnome-window-settings-2.0 \
+ gnome-desktop-2.0)
+windowsettingsdatadir=`pkg-config --variable=prefix gnome-window-settings-2.0`/share
+windowsettingslibdir=`pkg-config --variable=libdir gnome-window-settings-2.0`
+AC_SUBST(windowsettingsdatadir)
+AC_SUBST(windowsettingslibdir)
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+lib/Makefile
+])
diff --git a/heliodor/lib/Makefile.am b/heliodor/lib/Makefile.am
new file mode 100644
index 0000000..2aa3c11
--- /dev/null
+++ b/heliodor/lib/Makefile.am
@@ -0,0 +1,44 @@
+moduledir = $(DESTDIR)$(windowsettingslibdir)/window-manager-settings
+
+libberyl_la_LDFLAGS = -export-dynamic -avoid-version -rpath $(moduledir)
+libberyl_la_LIBADD = @GNOME_WINDOW_SETTINGS_LIBS@
+libberyl_la_SOURCES = \
+ beryl-window-manager.c \
+ beryl-window-manager.h
+libberyl_module = libberyl.la
+
+desktopfilesdir = $(DESTDIR)$(windowsettingsdatadir)/gnome/wm-properties
+desktopfiles_in_files = beryl.desktop.in
+desktopfiles_files = $(desktopfiles_in_files:.desktop.in=.desktop)
+noinst_DATA = $(desktopfiles_files)
+
+install-exec-local:
+ if mkdir -p $(moduledir) && test -w $(moduledir); then ( \
+ $(LIBTOOL) --mode=install $(INSTALL) $(libberyl_module) \
+ $(moduledir) \
+ ); \
+ fi
+
+install-data-local:
+ if mkdir -p $(desktopfilesdir) && test -w $(desktopfilesdir); then ( \
+ $(INSTALL) -m 644 $(desktopfiles_files) \
+ $(desktopfilesdir) \
+ ); \
+ fi
+
+uninstall-local:
+ if test -w $(moduledir); then ( \
+ rm -f $(moduledir)/libberyl.* \
+ ); \
+ fi
+ if test -w $(desktopfilesdir); then ( \
+ rm -f $(desktopfilesdir)/beryl.desktop \
+ ); \
+ fi
+
+
+INCLUDES = @GNOME_WINDOW_SETTINGS_CFLAGS@ \
+ -DMETACITY_THEME_DIR=\""$(windowsettingsdatadir)/themes"\"
+
+noinst_LTLIBRARIES = \
+ $(libberyl_module)
diff --git a/heliodor/lib/beryl-window-manager.c b/heliodor/lib/beryl-window-manager.c
new file mode 100644
index 0000000..3f6bc20
--- /dev/null
+++ b/heliodor/lib/beryl-window-manager.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <config.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <gconf/gconf-client.h>
+
+#include "beryl-window-manager.h"
+
+#define COMPIZ_CLICK_TO_FOCUS_KEY \
+ "/apps/compiz/general/allscreens/options/click_to_focus"
+
+#define COMPIZ_AUTORAISE_KEY \
+ "/apps/compiz/general/allscreens/options/autoraise"
+
+#define COMPIZ_AUTORAISE_DELAY_KEY \
+ "/apps/compiz/general/allscreens/options/autoraise_delay"
+
+#define COMPIZ_MOUSE_MOVE_KEY \
+ "/apps/compiz/plugins/move/screen0/options/initiate"
+
+#define GCONF_DIR "/apps/metacity/general"
+
+#define COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY \
+ GCONF_DIR "/action_double_click_titlebar"
+
+#define COMPIZ_USE_SYSTEM_FONT_KEY \
+ GCONF_DIR "/titlebar_uses_system_font"
+
+#define COMPIZ_TITLEBAR_FONT_KEY \
+ GCONF_DIR "/titlebar_font"
+
+#define COMPIZ_THEME_KEY \
+ GCONF_DIR "/theme"
+
+enum {
+ DOUBLE_CLICK_SHADE,
+ DOUBLE_CLICK_MAXIMIZE
+};
+
+static GnomeWindowManagerClass *parent_class;
+
+struct _CompizWindowManagerPrivate {
+ GConfClient *gconf;
+ gchar *font;
+ gchar *theme;
+ gchar *mouse_modifier;
+};
+
+static void
+value_changed (GConfClient *client,
+ const gchar *key,
+ GConfValue *value,
+ void *data)
+{
+ CompizWindowManager *wm;
+
+ wm = COMPIZ_WINDOW_MANAGER (data);
+
+ gnome_window_manager_settings_changed (GNOME_WINDOW_MANAGER (wm));
+}
+
+/* this function is called when the shared lib is loaded */
+GObject *
+window_manager_new (int expected_interface_version)
+{
+ GObject *wm;
+
+ if (expected_interface_version != GNOME_WINDOW_MANAGER_INTERFACE_VERSION)
+ {
+ g_warning ("Compiz window manager module wasn't compiled with the "
+ "current version of gnome-control-center");
+ return NULL;
+ }
+
+ wm = g_object_new (compiz_window_manager_get_type (), NULL);
+
+ return wm;
+}
+
+static void
+compiz_change_settings (GnomeWindowManager *wm,
+ const GnomeWMSettings *settings)
+{
+ CompizWindowManager *cwm;
+
+ cwm = COMPIZ_WINDOW_MANAGER (wm);
+
+ if (settings->flags & GNOME_WM_SETTING_FONT)
+ gconf_client_set_string (cwm->p->gconf,
+ COMPIZ_TITLEBAR_FONT_KEY,
+ settings->font, NULL);
+
+ if (settings->flags & GNOME_WM_SETTING_MOUSE_FOCUS)
+ gconf_client_set_bool (cwm->p->gconf,
+ COMPIZ_CLICK_TO_FOCUS_KEY,
+ settings->focus_follows_mouse == FALSE,
+ NULL);
+
+ if (settings->flags & GNOME_WM_SETTING_AUTORAISE)
+ gconf_client_set_bool (cwm->p->gconf,
+ COMPIZ_AUTORAISE_KEY,
+ settings->autoraise, NULL);
+
+ if (settings->flags & GNOME_WM_SETTING_AUTORAISE_DELAY)
+ gconf_client_set_int (cwm->p->gconf,
+ COMPIZ_AUTORAISE_DELAY_KEY,
+ settings->autoraise_delay, NULL);
+
+ if (settings->flags & GNOME_WM_SETTING_MOUSE_MOVE_MODIFIER)
+ {
+ char *value;
+
+ value = g_strdup_printf ("<%s>Button1", settings->mouse_move_modifier);
+ gconf_client_set_string (cwm->p->gconf,
+ COMPIZ_MOUSE_MOVE_KEY,
+ value, NULL);
+ g_free (value);
+ }
+
+ if (settings->flags & GNOME_WM_SETTING_THEME)
+ gconf_client_set_string (cwm->p->gconf,
+ COMPIZ_THEME_KEY,
+ settings->theme, NULL);
+
+ if (settings->flags & GNOME_WM_SETTING_DOUBLE_CLICK_ACTION)
+ {
+ const char *action = NULL;
+
+ switch (settings->double_click_action) {
+ case DOUBLE_CLICK_SHADE:
+ action = "toggle_shade";
+ break;
+ case DOUBLE_CLICK_MAXIMIZE:
+ action = "toggle_maximize";
+ break;
+ }
+
+ if (action)
+ gconf_client_set_string (cwm->p->gconf,
+ COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY,
+ action, NULL);
+ }
+}
+
+static void
+compiz_get_settings (GnomeWindowManager *wm,
+ GnomeWMSettings *settings)
+{
+ CompizWindowManager *cwm;
+ int to_get;
+
+ cwm = COMPIZ_WINDOW_MANAGER (wm);
+
+ to_get = settings->flags;
+ settings->flags = 0;
+
+ if (to_get & GNOME_WM_SETTING_FONT)
+ {
+ char *str;
+
+ str = gconf_client_get_string (cwm->p->gconf,
+ COMPIZ_TITLEBAR_FONT_KEY,
+ NULL);
+
+ if (!str)
+ str = g_strdup ("Sans Bold 12");
+
+ if (cwm->p->font)
+ g_free (cwm->p->font);
+
+ cwm->p->font = str;
+
+ settings->font = cwm->p->font;
+
+ settings->flags |= GNOME_WM_SETTING_FONT;
+ }
+
+ if (to_get & GNOME_WM_SETTING_MOUSE_FOCUS)
+ {
+ settings->focus_follows_mouse =
+ gconf_client_get_bool (cwm->p->gconf,
+ COMPIZ_CLICK_TO_FOCUS_KEY, NULL) == FALSE;
+
+ settings->flags |= GNOME_WM_SETTING_MOUSE_FOCUS;
+ }
+
+ if (to_get & GNOME_WM_SETTING_AUTORAISE)
+ {
+ settings->autoraise = gconf_client_get_bool (cwm->p->gconf,
+ COMPIZ_AUTORAISE_KEY,
+ NULL);
+
+ settings->flags |= GNOME_WM_SETTING_AUTORAISE;
+ }
+
+ if (to_get & GNOME_WM_SETTING_AUTORAISE_DELAY)
+ {
+ settings->autoraise_delay =
+ gconf_client_get_int (cwm->p->gconf,
+ COMPIZ_AUTORAISE_DELAY_KEY,
+ NULL);
+
+ settings->flags |= GNOME_WM_SETTING_AUTORAISE_DELAY;
+ }
+
+ if (to_get & GNOME_WM_SETTING_MOUSE_MOVE_MODIFIER)
+ {
+ const char *new;
+ char *str;
+
+ str = gconf_client_get_string (cwm->p->gconf,
+ COMPIZ_MOUSE_MOVE_KEY,
+ NULL);
+
+ if (str == NULL)
+ str = g_strdup ("<Super>");
+
+ if (strncmp (str, "<Super>", 7) == 0)
+ new = "Super";
+ else if (strncmp (str, "<Alt>", 5) == 0)
+ new = "Alt";
+ else if (strncmp (str, "<Meta>", 6) == 0)
+ new = "Meta";
+ else if (strncmp (str, "<Hyper>", 7) == 0)
+ new = "Hyper";
+ else if (strncmp (str, "<Control>", 9) == 0)
+ new = "Control";
+ else
+ new = NULL;
+
+ if (cwm->p->mouse_modifier)
+ g_free (cwm->p->mouse_modifier);
+
+ cwm->p->mouse_modifier = g_strdup (new ? new : "");
+
+ g_free (str);
+
+ settings->mouse_move_modifier = cwm->p->mouse_modifier;
+
+ settings->flags |= GNOME_WM_SETTING_MOUSE_MOVE_MODIFIER;
+ }
+
+ if (to_get & GNOME_WM_SETTING_THEME)
+ {
+ char *str;
+
+ str = gconf_client_get_string (cwm->p->gconf,
+ COMPIZ_THEME_KEY,
+ NULL);
+
+ if (str == NULL)
+ str = g_strdup ("Atlanta");
+
+ g_free (cwm->p->theme);
+ cwm->p->theme = str;
+ settings->theme = cwm->p->theme;
+
+ settings->flags |= GNOME_WM_SETTING_THEME;
+ }
+
+ if (to_get & GNOME_WM_SETTING_DOUBLE_CLICK_ACTION)
+ {
+ char *str;
+
+ settings->double_click_action = DOUBLE_CLICK_MAXIMIZE;
+
+ str = gconf_client_get_string (cwm->p->gconf,
+ COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY,
+ NULL);
+
+ if (str)
+ {
+ if (strcmp (str, "toggle_shade") == 0)
+ settings->double_click_action = DOUBLE_CLICK_SHADE;
+ else if (strcmp (str, "toggle_maximize") == 0)
+ settings->double_click_action = DOUBLE_CLICK_MAXIMIZE;
+ }
+
+ settings->flags |= GNOME_WM_SETTING_DOUBLE_CLICK_ACTION;
+ }
+}
+
+static int
+compiz_get_settings_mask (GnomeWindowManager *wm)
+{
+ return GNOME_WM_SETTING_MASK;
+}
+
+static GList *
+add_themes_from_dir (GList *current_list,
+ const char *path)
+{
+ DIR *theme_dir;
+ struct dirent *entry;
+ char *theme_file_path;
+ GList *node;
+ gboolean found = FALSE;
+
+ if (!(g_file_test (path, G_FILE_TEST_EXISTS) &&
+ g_file_test (path, G_FILE_TEST_IS_DIR)))
+ {
+ return current_list;
+ }
+
+ theme_dir = opendir (path);
+
+ /* If this is NULL, then we couldn't open ~/.themes. The test above
+ * only checks existence, not wether we can really read it.*/
+ if (theme_dir == NULL)
+ return current_list;
+
+ for (entry = readdir (theme_dir); entry; entry = readdir (theme_dir))
+ {
+ theme_file_path =
+ g_build_filename (path, entry->d_name,
+ "metacity-1/metacity-theme-1.xml", NULL);
+
+ if (g_file_test (theme_file_path, G_FILE_TEST_EXISTS))
+ {
+
+ for (node = current_list; node && !found; node = node->next)
+ found = strcmp (node->data, entry->d_name) == 0;
+
+ if (!found)
+ current_list = g_list_prepend (current_list,
+ g_strdup (entry->d_name));
+ }
+
+ found = FALSE;
+
+ g_free (theme_file_path);
+ }
+
+ closedir (theme_dir);
+
+ return current_list;
+}
+
+static GList *
+compiz_get_theme_list (GnomeWindowManager *wm)
+{
+ GList *themes = NULL;
+ char *home_dir_themes;
+
+ home_dir_themes = g_build_filename (g_get_home_dir (), ".themes", NULL);
+
+ themes = add_themes_from_dir (themes, METACITY_THEME_DIR);
+ themes = add_themes_from_dir (themes, "/usr/share/themes");
+ themes = add_themes_from_dir (themes, home_dir_themes);
+
+ g_free (home_dir_themes);
+
+ return themes;
+}
+
+static char *
+compiz_get_user_theme_folder (GnomeWindowManager *wm)
+{
+ return g_build_filename (g_get_home_dir (), ".themes", NULL);
+}
+
+static void
+compiz_get_double_click_actions (GnomeWindowManager *wm,
+ const GnomeWMDoubleClickAction **actions_p,
+ int *n_actions_p)
+{
+ static GnomeWMDoubleClickAction actions[] = {
+ { DOUBLE_CLICK_SHADE, "Shade" },
+ { DOUBLE_CLICK_MAXIMIZE, "Maximize" }
+ };
+
+ *actions_p = actions;
+ *n_actions_p = (int) G_N_ELEMENTS (actions);
+}
+
+static void
+compiz_window_manager_init (CompizWindowManager *cwm,
+ CompizWindowManagerClass *class)
+{
+ cwm->p = g_new0 (CompizWindowManagerPrivate, 1);
+ cwm->p->gconf = gconf_client_get_default ();
+ cwm->p->mouse_modifier = NULL;
+ cwm->p->font = NULL;
+ cwm->p->theme = NULL;
+
+ gconf_client_add_dir (cwm->p->gconf,
+ "/apps/compiz",
+ GCONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ gconf_client_add_dir (cwm->p->gconf,
+ GCONF_DIR,
+ GCONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+
+ g_signal_connect (G_OBJECT (cwm->p->gconf),
+ "value_changed",
+ G_CALLBACK (value_changed),
+ cwm);
+}
+
+static void
+compiz_window_manager_finalize (GObject *object)
+{
+ CompizWindowManager *cwm;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_COMPIZ_WINDOW_MANAGER (object));
+
+ cwm = COMPIZ_WINDOW_MANAGER (object);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (cwm->p->gconf),
+ G_CALLBACK (value_changed),
+ cwm);
+
+ if (cwm->p->mouse_modifier)
+ g_free (cwm->p->mouse_modifier);
+
+ if (cwm->p->font)
+ g_free (cwm->p->font);
+
+ if (cwm->p->theme)
+ g_free (cwm->p->theme);
+
+ g_object_unref (G_OBJECT (cwm->p->gconf));
+ g_free (cwm->p);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+compiz_window_manager_class_init (CompizWindowManagerClass *class)
+{
+ GObjectClass *object_class;
+ GnomeWindowManagerClass *wm_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ wm_class = GNOME_WINDOW_MANAGER_CLASS (class);
+
+ object_class->finalize = compiz_window_manager_finalize;
+
+ wm_class->change_settings = compiz_change_settings;
+ wm_class->get_settings = compiz_get_settings;
+ wm_class->get_settings_mask = compiz_get_settings_mask;
+ wm_class->get_user_theme_folder = compiz_get_user_theme_folder;
+ wm_class->get_theme_list = compiz_get_theme_list;
+ wm_class->get_double_click_actions = compiz_get_double_click_actions;
+
+ parent_class = g_type_class_peek_parent (class);
+}
+
+GType
+compiz_window_manager_get_type (void)
+{
+ static GType compiz_window_manager_type = 0;
+
+ if (!compiz_window_manager_type)
+ {
+ static GTypeInfo compiz_window_manager_info = {
+ sizeof (CompizWindowManagerClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) compiz_window_manager_class_init,
+ NULL,
+ NULL,
+ sizeof (CompizWindowManager),
+ 0,
+ (GInstanceInitFunc) compiz_window_manager_init,
+ NULL
+ };
+
+ compiz_window_manager_type =
+ g_type_register_static (gnome_window_manager_get_type (),
+ "CompizWindowManager",
+ &compiz_window_manager_info, 0);
+ }
+
+ return compiz_window_manager_type;
+}
diff --git a/heliodor/lib/beryl-window-manager.h b/heliodor/lib/beryl-window-manager.h
new file mode 100644
index 0000000..5506e63
--- /dev/null
+++ b/heliodor/lib/beryl-window-manager.h
@@ -0,0 +1,39 @@
+#ifndef COMPIZ_WINDOW_MANAGER_H
+#define COMPIZ_WINDOW_MANAGER_H
+
+#include <glib-object.h>
+
+#include "gnome-window-manager.h"
+
+#define COMPIZ_WINDOW_MANAGER(obj) \
+ G_TYPE_CHECK_INSTANCE_CAST (obj, compiz_window_manager_get_type (), \
+ CompizWindowManager)
+
+#define COMPIZ_WINDOW_MANAGER_CLASS(klass) \
+ G_TYPE_CHECK_CLASS_CAST (klass, compiz_window_manager_get_type (), \
+ MetacityWindowManagerClass)
+
+#define IS_COMPIZ_WINDOW_MANAGER(obj) \
+ G_TYPE_CHECK_INSTANCE_TYPE (obj, compiz_window_manager_get_type ())
+
+
+typedef struct _CompizWindowManager CompizWindowManager;
+typedef struct _CompizWindowManagerClass CompizWindowManagerClass;
+typedef struct _CompizWindowManagerPrivate CompizWindowManagerPrivate;
+
+struct _CompizWindowManager {
+ GnomeWindowManager parent;
+ CompizWindowManagerPrivate *p;
+};
+
+struct _CompizWindowManagerClass {
+ GnomeWindowManagerClass klass;
+};
+
+GType
+compiz_window_manager_get_type (void);
+
+GObject *
+window_manager_new (int expected_interface_version);
+
+#endif
diff --git a/heliodor/lib/beryl.desktop b/heliodor/lib/beryl.desktop
new file mode 100644
index 0000000..0bfcd8d
--- /dev/null
+++ b/heliodor/lib/beryl.desktop
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Beryl
+Exec=beryl
+# name of loadable control center module
+X-GNOME-WMSettingsModule=beryl
+# name we put on the WM spec check window
+X-GNOME-WMName=beryl
+# back compat only
+X-GnomeWMSettingsLibrary=beryl
+
+[Window Manager]
+SessionManaged=false
diff --git a/heliodor/src/Makefile.am b/heliodor/src/Makefile.am
new file mode 100644
index 0000000..028ebf9
--- /dev/null
+++ b/heliodor/src/Makefile.am
@@ -0,0 +1,4 @@
+INCLUDES=@HELIODOR_CFLAGS@ -DUSE_METACITY
+heliodor_LDFLAGS=@HELIODOR_LIBS@
+heliodor_SOURCES=main.c
+bin_PROGRAMS=heliodor
diff --git a/heliodor/src/main.c b/heliodor/src/main.c
new file mode 100644
index 0000000..0af40bc
--- /dev/null
+++ b/heliodor/src/main.c
@@ -0,0 +1,5846 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define DECOR_INTERFACE_VERSION 0 // for beryl
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/Xregion.h>
+
+#ifndef GTK_DISABLE_DEPRECATED
+#define GTK_DISABLE_DEPRECATED
+#endif
+
+#include <gtk/gtk.h>
+#include <gtk/gtkwindow.h>
+#include <gdk/gdkx.h>
+
+#include <gconf/gconf-client.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+#include <libwnck/window-action-menu.h>
+
+#include <cairo.h>
+#include <cairo-xlib.h>
+
+#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 1, 0)
+#define CAIRO_EXTEND_PAD CAIRO_EXTEND_NONE
+#endif
+
+#include <pango/pango-context.h>
+#include <pango/pangocairo.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#ifdef USE_METACITY
+#include <metacity-private/theme.h>
+#endif
+
+#define METACITY_GCONF_DIR "/apps/metacity/general"
+
+#define COMPIZ_USE_SYSTEM_FONT_KEY \
+ METACITY_GCONF_DIR "/titlebar_uses_system_font"
+
+#define COMPIZ_TITLEBAR_FONT_KEY \
+ METACITY_GCONF_DIR "/titlebar_font"
+
+#define COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY \
+ METACITY_GCONF_DIR "/action_double_click_titlebar"
+
+#define COMPIZ_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_OFFSET_X_KEY \
+ COMPIZ_GCONF_DIR1 "/shadow_offset_x"
+
+#define COMPIZ_SHADOW_OFFSET_Y_KEY \
+ COMPIZ_GCONF_DIR1 "/shadow_offset_y"
+
+#define META_AUDIBLE_BELL_KEY \
+ METACITY_GCONF_DIR "/audible_bell"
+
+#define META_VISUAL_BELL_KEY \
+ METACITY_GCONF_DIR "/visual_bell"
+
+#define META_VISUAL_BELL_TYPE_KEY \
+ METACITY_GCONF_DIR "/visual_bell_type"
+
+#define META_THEME_KEY \
+ METACITY_GCONF_DIR "/theme"
+
+#define COMPIZ_GCONF_DIR2 "/apps/compiz/general/allscreens/options"
+
+#define COMPIZ_AUDIBLE_BELL_KEY \
+ COMPIZ_GCONF_DIR2 "/audible_bell"
+
+#define COMPIZ_GCONF_DIR3 "/apps/compiz/plugins/fade/screen0/options"
+
+#define COMPIZ_VISUAL_BELL_KEY \
+ COMPIZ_GCONF_DIR3 "/visual_bell"
+
+#define COMPIZ_FULLSCREEN_VISUAL_BELL_KEY \
+ COMPIZ_GCONF_DIR3 "/fullscreen_visual_bell"
+
+#define GCONF_DIR "/apps/heliodor"
+
+#define META_THEME_OPACITY_KEY \
+ GCONF_DIR "/theme_opacity"
+
+#define META_THEME_SHADE_OPACITY_KEY \
+ GCONF_DIR "/theme_shade_opacity"
+
+#define META_THEME_ACTIVE_OPACITY_KEY \
+ GCONF_DIR "/theme_active_opacity"
+
+#define META_THEME_ACTIVE_SHADE_OPACITY_KEY \
+ GCONF_DIR "/theme_active_shade_opacity"
+
+
+#define STROKE_ALPHA 0.6
+
+#define ICON_SPACE 20
+
+#define DOUBLE_CLICK_DISTANCE 8.0
+
+typedef struct _extents {
+ gint left;
+ gint right;
+ gint top;
+ gint bottom;
+} extents;
+
+#define GRAVITY_WEST (1 << 0)
+#define GRAVITY_EAST (1 << 1)
+#define GRAVITY_NORTH (1 << 2)
+#define GRAVITY_SOUTH (1 << 3)
+
+#define ALIGN_LEFT (0)
+#define ALIGN_RIGHT (1 << 0)
+#define ALIGN_TOP (0)
+#define ALIGN_BOTTOM (1 << 1)
+
+#define CLAMP_HORZ (1 << 0)
+#define CLAMP_VERT (1 << 1)
+
+#define XX_MASK (1 << 12)
+#define XY_MASK (1 << 13)
+#define YX_MASK (1 << 14)
+#define YY_MASK (1 << 15)
+
+#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 META_OPACITY 0.75
+#define META_SHADE_OPACITY TRUE
+#define META_ACTIVE_OPACITY 1.0
+#define META_ACTIVE_SHADE_OPACITY TRUE
+
+#define N_QUADS_MAX 24
+
+typedef struct _point {
+ gint x;
+ gint y;
+ gint gravity;
+} point;
+
+typedef struct _quad {
+ point p1;
+ point p2;
+ gint max_width;
+ gint max_height;
+ gint align;
+ gint clamp;
+ cairo_matrix_t m;
+} quad;
+
+#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
+
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+} MwmHints;
+
+enum {
+ DOUBLE_CLICK_SHADE,
+ DOUBLE_CLICK_MAXIMIZE
+};
+
+int double_click_action = DOUBLE_CLICK_SHADE;
+
+static gboolean minimal = FALSE;
+
+static double decoration_alpha = 0.5;
+
+static extents _shadow_extents = { 0, 0, 0, 0 };
+static extents _win_extents = { 6, 6, 4, 6 };
+static extents _switcher_extents = { 0, 0, 0, 0 };
+
+#define SWITCHER_SPACE 40
+#define SWITCHER_TOP_EXTRA 4
+
+static gint left_space = 6;
+static gint right_space = 6;
+static gint top_space = 4;
+static gint bottom_space = 6;
+
+static gint left_corner_space = 0;
+static gint right_corner_space = 0;
+static gint top_corner_space = 0;
+static gint bottom_corner_space = 0;
+
+static gint titlebar_height = 17;
+
+static gint normal_top_corner_space = 0;
+static gint switcher_top_corner_space = 0;
+static gint switcher_bottom_corner_space = 0;
+
+static gint shadow_left_space = 0;
+static gint shadow_right_space = 0;
+static gint shadow_top_space = 0;
+static gint shadow_bottom_space = 0;
+
+static gint shadow_left_corner_space = 0;
+static gint shadow_right_corner_space = 0;
+static gint shadow_top_corner_space = 0;
+static gint shadow_bottom_corner_space = 0;
+
+static gdouble shadow_radius = SHADOW_RADIUS;
+static gdouble shadow_opacity = SHADOW_OPACITY;
+static gint shadow_offset_x = SHADOW_OFFSET_X;
+static gint shadow_offset_y = SHADOW_OFFSET_Y;
+
+#ifdef USE_METACITY
+static double meta_opacity = META_OPACITY;
+static gboolean meta_shade_opacity = META_SHADE_OPACITY;
+static double meta_active_opacity = META_ACTIVE_OPACITY;
+static gboolean meta_active_shade_opacity = META_ACTIVE_SHADE_OPACITY;
+#endif
+
+static GdkPixmap *shadow_pixmap = NULL;
+static GdkPixmap *large_shadow_pixmap = NULL;
+static GdkPixmap *decor_normal_pixmap = NULL;
+static GdkPixmap *decor_active_pixmap = NULL;
+
+static cairo_pattern_t *shadow_pattern = NULL;
+
+static Atom frame_window_atom;
+static Atom win_decor_atom;
+static Atom wm_move_resize_atom;
+static Atom restack_window_atom;
+static Atom select_window_atom;
+static Atom mwm_hints_atom;
+
+static Atom toolkit_action_atom;
+static Atom toolkit_action_main_menu_atom;
+static Atom toolkit_action_run_dialog_atom;
+static Atom toolkit_action_window_menu_atom;
+static Atom toolkit_action_force_quit_dialog_atom;
+
+static Atom panel_action_atom;
+static Atom panel_action_main_menu_atom;
+static Atom panel_action_run_dialog_atom;
+
+static Atom manager_atom;
+static Atom targets_atom;
+static Atom multiple_atom;
+static Atom timestamp_atom;
+static Atom version_atom;
+static Atom atom_pair_atom;
+
+static Atom utf8_string_atom;
+
+static Atom dm_name_atom;
+static Atom dm_sn_atom;
+
+static Time dm_sn_timestamp;
+
+#define C(name) { 0, XC_ ## name }
+
+static struct _cursor {
+ Cursor cursor;
+ unsigned int shape;
+} 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) }
+};
+
+static struct _pos {
+ int x, y, w, h;
+ int xw, yh, ww, hh, yth, hth;
+} 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 }
+ }
+};
+
+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 {
+ Window event_windows[3][3];
+ Window button_windows[3];
+ guint button_states[3];
+ GdkPixmap *pixmap;
+ GdkPixmap *buffer_pixmap;
+ GdkGC *gc;
+ gint button_width;
+ gint width;
+ gint 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;
+ 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);
+gint (*theme_calc_titlebar_height) (gint text_height);
+void (*theme_get_button_position) (decor_t *d,
+ gint i,
+ gint width,
+ gint height,
+ gint *x,
+ gint *y,
+ gint *w,
+ gint *h);
+
+typedef void (*event_callback) (WnckWindow *win, XEvent *event);
+
+static char *program_name;
+
+static GtkWidget *style_window;
+
+static GHashTable *frame_table;
+static GtkWidget *action_menu = NULL;
+static gboolean action_menu_mapped = FALSE;
+static decor_color_t _title_color[2];
+static PangoContext *pango_context;
+static gint double_click_timeout = 250;
+
+static GtkWidget *tip_window;
+static GtkWidget *tip_label;
+static GTimeVal tooltip_last_popdown = { -1, -1 };
+static gint tooltip_timer_tag = 0;
+
+static GSList *draw_list = NULL;
+static guint draw_idle_id = 0;
+
+static PangoFontDescription *titlebar_font = NULL;
+static gboolean use_system_font = FALSE;
+static gint text_height;
+
+static GdkPixmap *switcher_pixmap = NULL;
+static GdkPixmap *switcher_buffer_pixmap = NULL;
+static gint switcher_width;
+static gint switcher_height;
+
+#define BASE_PROP_SIZE 12
+#define QUAD_PROP_SIZE 9
+
+/*
+ decoration property
+ -------------------
+
+ data[0] = version
+
+ data[1] = pixmap
+
+ data[2] = input left
+ data[3] = input right
+ data[4] = input top
+ data[5] = input bottom
+
+ data[6] = input left when maximized
+ data[7] = input right when maximized
+ data[8] = input top when maximized
+ data[9] = input bottom when maximized
+
+ data[10] = min width
+ data[11] = min height
+
+ flags
+
+ 1st to 4nd bit p1 gravity, 5rd to 8th bit p2 gravity,
+ 9rd and 10th bit alignment, 11rd and 12th bit clamp,
+ 13th bit XX, 14th bit XY, 15th bit YX, 16th bit YY.
+
+ data[11 + n * 9 + 1] = flags
+ data[11 + n * 9 + 2] = p1 x
+ data[11 + n * 9 + 3] = p1 y
+ data[11 + n * 9 + 4] = p2 x
+ data[11 + n * 9 + 5] = p2 y
+ data[11 + n * 9 + 6] = widthMax
+ data[11 + n * 9 + 7] = heightMax
+ data[11 + n * 9 + 8] = x0
+ data[11 + n * 9 + 9] = y0
+ */
+static void
+decoration_to_property (long *data,
+ Pixmap pixmap,
+ extents *input,
+ extents *max_input,
+ int min_width,
+ int min_height,
+ quad *quad,
+ int nQuad)
+{
+ *data++ = DECOR_INTERFACE_VERSION;
+
+ memcpy (data++, &pixmap, sizeof (Pixmap));
+
+ *data++ = input->left;
+ *data++ = input->right;
+ *data++ = input->top;
+ *data++ = input->bottom;
+
+ *data++ = max_input->left;
+ *data++ = max_input->right;
+ *data++ = max_input->top;
+ *data++ = max_input->bottom;
+
+ *data++ = min_width;
+ *data++ = min_height;
+
+ while (nQuad--)
+ {
+ *data++ =
+ (quad->p1.gravity << 0) |
+ (quad->p2.gravity << 4) |
+ (quad->align << 8) |
+ (quad->clamp << 10) |
+ (quad->m.xx ? XX_MASK : 0) |
+ (quad->m.xy ? XY_MASK : 0) |
+ (quad->m.yx ? YX_MASK : 0) |
+ (quad->m.yy ? YY_MASK : 0);
+
+ *data++ = quad->p1.x;
+ *data++ = quad->p1.y;
+ *data++ = quad->p2.x;
+ *data++ = quad->p2.y;
+ *data++ = quad->max_width;
+ *data++ = quad->max_height;
+ *data++ = quad->m.x0;
+ *data++ = quad->m.y0;
+
+ quad++;
+ }
+}
+
+static gint
+set_horz_quad_line (quad *q,
+ int left,
+ int left_corner,
+ int right,
+ int right_corner,
+ int top,
+ int bottom,
+ int gravity,
+ int width,
+ double x0,
+ double y0)
+{
+ gint dx, nQuad = 0;
+
+ dx = (left_corner - right_corner) >> 1;
+
+ q->p1.x = -left;
+ q->p1.y = top;
+ q->p1.gravity = gravity | GRAVITY_WEST;
+ q->p2.x = dx;
+ q->p2.y = bottom;
+ q->p2.gravity = gravity;
+ q->max_width = left + left_corner;
+ q->max_height = SHRT_MAX;
+ q->align = ALIGN_LEFT;
+ q->clamp = 0;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = x0;
+ q->m.y0 = y0;
+
+ q++; nQuad++;
+
+ q->p1.x = left_corner;
+ q->p1.y = top;
+ q->p1.gravity = gravity | GRAVITY_WEST;
+ q->p2.x = -right_corner;
+ q->p2.y = bottom;
+ q->p2.gravity = gravity | GRAVITY_EAST;
+ q->max_width = SHRT_MAX;
+ q->max_height = SHRT_MAX;
+ q->align = 0;
+ q->clamp = 0;
+ q->m.xx = 0.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = x0 + left + left_corner;
+ q->m.y0 = y0;
+
+ q++; nQuad++;
+
+ q->p1.x = dx;
+ q->p1.y = top;
+ q->p1.gravity = gravity;
+ q->p2.x = right;
+ q->p2.y = bottom;
+ q->p2.gravity = gravity | GRAVITY_EAST;
+ q->max_width = right_corner + right;
+ q->max_height = SHRT_MAX;
+ q->align = ALIGN_RIGHT;
+ q->clamp = 0;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = x0 + width;
+ q->m.y0 = y0;
+
+ nQuad++;
+
+ return nQuad;
+}
+
+static gint
+set_vert_quad_row (quad *q,
+ int top,
+ int top_corner,
+ int bottom,
+ int bottom_corner,
+ int left,
+ int right,
+ int gravity,
+ int height,
+ double x0,
+ double y0)
+{
+ gint dy, nQuad = 0;
+
+ dy = (top_corner - bottom_corner) >> 1;
+
+ q->p1.x = left;
+ q->p1.y = -top;
+ q->p1.gravity = gravity | GRAVITY_NORTH;
+ q->p2.x = right;
+ q->p2.y = dy;
+ q->p2.gravity = gravity;
+ q->max_width = SHRT_MAX;
+ q->max_height = top + top_corner;
+ q->align = ALIGN_TOP;
+ q->clamp = CLAMP_VERT;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = x0;
+ q->m.y0 = y0;
+
+ q++; nQuad++;
+
+ q->p1.x = left;
+ q->p1.y = top_corner;
+ q->p1.gravity = gravity | GRAVITY_NORTH;
+ q->p2.x = right;
+ q->p2.y = -bottom_corner;
+ q->p2.gravity = gravity | GRAVITY_SOUTH;
+ q->max_width = SHRT_MAX;
+ q->max_height = SHRT_MAX;
+ q->align = 0;
+ q->clamp = CLAMP_VERT;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 0.0;
+ q->m.x0 = x0;
+ q->m.y0 = y0 + top + top_corner;
+
+ q++; nQuad++;
+
+ q->p1.x = left;
+ q->p1.y = dy;
+ q->p1.gravity = gravity;
+ q->p2.x = right;
+ q->p2.y = bottom;
+ q->p2.gravity = gravity | GRAVITY_SOUTH;
+ q->max_width = SHRT_MAX;
+ q->max_height = bottom_corner + bottom;
+ q->align = ALIGN_BOTTOM;
+ q->clamp = CLAMP_VERT;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = x0;
+ q->m.y0 = y0 + height;
+
+ nQuad++;
+
+ return nQuad;
+}
+
+static int
+set_common_window_quads (quad *q,
+ int width,
+ int height)
+{
+ gint n, nQuad = 0;
+
+ /* left quads */
+ n = set_vert_quad_row (q,
+ 0,
+ normal_top_corner_space,
+ 0,
+ bottom_corner_space,
+ -left_space,
+ 0,
+ GRAVITY_WEST,
+ height - top_space - titlebar_height - bottom_space,
+ 0.0,
+ top_space + titlebar_height + 1.0);
+
+ q += n; nQuad += n;
+
+ /* right quads */
+ n = set_vert_quad_row (q,
+ 0,
+ normal_top_corner_space,
+ 0,
+ bottom_corner_space,
+ 0,
+ right_space,
+ GRAVITY_EAST,
+ height - top_space - titlebar_height - bottom_space,
+ width - right_space,
+ top_space + titlebar_height + 1.0);
+
+ q += n; nQuad += n;
+
+ /* bottom quads */
+ n = set_horz_quad_line (q,
+ left_space,
+ left_corner_space,
+ right_space,
+ right_corner_space,
+ 0,
+ bottom_space,
+ GRAVITY_SOUTH,
+ width,
+ 0.0,
+ top_space + titlebar_height +
+ normal_top_corner_space +
+ bottom_corner_space + 2.0);
+
+ nQuad += n;
+
+ return nQuad;
+}
+
+static int
+set_window_quads (quad *q,
+ int width,
+ int height,
+ int button_width)
+{
+ gint n, nQuad = 0;
+ int top_left, top_right, y;
+ double y0;
+
+ top_right = button_width;
+ top_left = width - left_space - right_space - top_right - 1;
+
+ /* special case which can happen with large shadows */
+ if (right_corner_space > top_right || left_corner_space > top_left)
+ {
+ y = -titlebar_height;
+ y0 = top_space;
+
+ /* top quads */
+ n = set_horz_quad_line (q,
+ left_space,
+ left_corner_space,
+ right_space,
+ right_corner_space,
+ -top_space - titlebar_height,
+ y,
+ GRAVITY_NORTH,
+ width,
+ 0.0,
+ 0.0);
+
+ q += n; nQuad += n;
+ }
+ else
+ {
+ y = -top_space - titlebar_height;
+ y0 = 0.0;
+ }
+
+ /* 3 top/titlebar quads */
+ q->p1.x = -left_space;
+ q->p1.y = y;
+ q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
+ q->p2.x = -top_right;
+ q->p2.y = 0;
+ q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
+ q->max_width = left_space + top_left;
+ q->max_height = SHRT_MAX;
+ q->align = ALIGN_LEFT;
+ q->clamp = 0;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = 0.0;
+ q->m.y0 = y0;
+
+ q++; nQuad++;
+
+ q->p1.x = top_left;
+ q->p1.y = y;
+ q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
+ q->p2.x = -top_right;
+ q->p2.y = 0;
+ q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
+ q->max_width = SHRT_MAX;
+ q->max_height = SHRT_MAX;
+ q->align = 0;
+ q->clamp = 0;
+ q->m.xx = 0.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = left_space + top_left;
+ q->m.y0 = y0;
+
+ q++; nQuad++;
+
+ q->p1.x = 0;
+ q->p1.y = y;
+ q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
+ q->p2.x = right_space;
+ q->p2.y = 0;
+ q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
+ q->max_width = right_space + top_right;
+ q->max_height = SHRT_MAX;
+ q->align = ALIGN_RIGHT;
+ q->clamp = 0;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = width;
+ q->m.y0 = y0;
+
+ q++; nQuad++;
+
+ n = set_common_window_quads (q, width, height);
+
+ nQuad += n;
+
+ return nQuad;
+}
+
+static int
+set_no_title_window_quads (quad *q,
+ int width,
+ int height)
+{
+ gint n, nQuad = 0;
+
+ /* top quads */
+ n = set_horz_quad_line (q,
+ left_space,
+ left_corner_space,
+ right_space,
+ right_corner_space,
+ -top_space - titlebar_height,
+ 0,
+ GRAVITY_NORTH,
+ width,
+ 0.0,
+ 0.0);
+
+ q += n; nQuad += n;
+
+ n = set_common_window_quads (q, width, height);
+
+ nQuad += n;
+
+ return nQuad;
+}
+
+static int
+set_switcher_quads (quad *q,
+ int width,
+ int height)
+{
+ gint n, nQuad = 0;
+
+ /* 1 top quads */
+ q->p1.x = -left_space;
+ q->p1.y = -top_space - SWITCHER_TOP_EXTRA;
+ q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
+ q->p2.x = right_space;
+ q->p2.y = 0;
+ q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
+ q->max_width = SHRT_MAX;
+ q->max_height = SHRT_MAX;
+ q->align = 0;
+ q->clamp = 0;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = 0.0;
+ q->m.y0 = 0.0;
+
+ q++; nQuad++;
+
+ /* left quads */
+ n = set_vert_quad_row (q,
+ 0,
+ switcher_top_corner_space,
+ 0,
+ bottom_corner_space,
+ -left_space,
+ 0,
+ GRAVITY_WEST,
+ height - top_space - titlebar_height - bottom_space,
+ 0.0,
+ top_space + SWITCHER_TOP_EXTRA);
+
+ q += n; nQuad += n;
+
+ /* right quads */
+ n = set_vert_quad_row (q,
+ 0,
+ switcher_top_corner_space,
+ 0,
+ switcher_bottom_corner_space,
+ 0,
+ right_space,
+ GRAVITY_EAST,
+ height - top_space - titlebar_height - bottom_space,
+ width - right_space,
+ top_space + SWITCHER_TOP_EXTRA);
+
+ q += n; nQuad += n;
+
+ /* 1 bottom quad */
+ q->p1.x = -left_space;
+ q->p1.y = 0;
+ q->p1.gravity = GRAVITY_SOUTH | GRAVITY_WEST;
+ q->p2.x = right_space;
+ q->p2.y = bottom_space + SWITCHER_SPACE;
+ q->p2.gravity = GRAVITY_SOUTH | GRAVITY_EAST;
+ q->max_width = SHRT_MAX;
+ q->max_height = SHRT_MAX;
+ q->align = 0;
+ q->clamp = 0;
+ q->m.xx = 1.0;
+ q->m.xy = 0.0;
+ q->m.yx = 0.0;
+ q->m.yy = 1.0;
+ q->m.x0 = 0.0;
+ q->m.y0 = height - bottom_space - SWITCHER_SPACE;
+
+ nQuad++;
+
+ return nQuad;
+}
+
+static void
+decor_update_switcher_property (decor_t *d)
+{
+ long data[256];
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ gint nQuad;
+ quad quads[N_QUADS_MAX];
+ extents extents = _switcher_extents;
+
+ nQuad = set_switcher_quads (quads, d->width, d->height);
+
+ decoration_to_property (data, GDK_PIXMAP_XID (d->pixmap),
+ &extents, &extents, 0, 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);
+ XSync (xdisplay, FALSE);
+ gdk_error_trap_pop ();
+}
+
+static int
+set_shadow_quads (quad *q,
+ gint width,
+ gint height)
+{
+ gint n, nQuad = 0;
+
+ /* top quads */
+ n = set_horz_quad_line (q,
+ shadow_left_space,
+ shadow_left_corner_space,
+ shadow_right_space,
+ shadow_right_corner_space,
+ -shadow_top_space,
+ 0,
+ GRAVITY_NORTH,
+ width,
+ 0.0,
+ 0.0);
+
+ q += n; nQuad += n;
+
+ /* left quads */
+ n = set_vert_quad_row (q,
+ 0,
+ shadow_top_corner_space,
+ 0,
+ shadow_bottom_corner_space,
+ -shadow_left_space,
+ 0,
+ GRAVITY_WEST,
+ height - shadow_top_space - shadow_bottom_space,
+ 0.0,
+ shadow_top_space);
+
+ q += n; nQuad += n;
+
+ /* right quads */
+ n = set_vert_quad_row (q,
+ 0,
+ shadow_top_corner_space,
+ 0,
+ shadow_bottom_corner_space,
+ 0,
+ shadow_right_space,
+ GRAVITY_EAST,
+ height - shadow_top_space - shadow_bottom_space,
+ width - shadow_right_space,
+ shadow_top_space);
+
+ q += n; nQuad += n;
+
+ /* bottom quads */
+ n = set_horz_quad_line (q,
+ shadow_left_space,
+ shadow_left_corner_space,
+ shadow_right_space,
+ shadow_right_corner_space,
+ 0,
+ shadow_bottom_space,
+ GRAVITY_SOUTH,
+ width,
+ 0.0,
+ shadow_top_space + shadow_top_corner_space +
+ shadow_bottom_corner_space + 1.0);
+
+ nQuad += n;
+
+ return nQuad;
+}
+
+static 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);
+}
+
+static GdkPixmap *
+create_pixmap (int w,
+ int h)
+{
+ GdkPixmap *pixmap;
+ GdkVisual *visual;
+ GdkColormap *colormap;
+
+ visual = gdk_visual_get_best_with_depth (32);
+ if (!visual)
+ return NULL;
+
+ pixmap = gdk_pixmap_new (NULL, w, h, 32);
+ if (!pixmap)
+ return NULL;
+
+ colormap = gdk_colormap_new (visual, FALSE);
+ if (!colormap)
+ {
+ gdk_pixmap_unref (pixmap);
+ return NULL;
+ }
+
+ gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), colormap);
+ gdk_colormap_unref (colormap);
+
+ return pixmap;
+}
+
+#define CORNER_TOPLEFT (1 << 0)
+#define CORNER_TOPRIGHT (1 << 1)
+#define CORNER_BOTTOMRIGHT (1 << 2)
+#define CORNER_BOTTOMLEFT (1 << 3)
+
+static 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);
+}
+
+#define SHADE_LEFT (1 << 0)
+#define SHADE_RIGHT (1 << 1)
+#define SHADE_TOP (1 << 2)
+#define SHADE_BOTTOM (1 << 3)
+
+static 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);
+}
+
+static void
+draw_shadow_background (decor_t *d,
+ cairo_t *cr)
+{
+ cairo_matrix_t matrix;
+ double w, h, x2, y2;
+ gint width, height;
+ gint left, right, top, bottom;
+
+ if (!large_shadow_pixmap)
+ {
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
+ cairo_paint (cr);
+
+ return;
+ }
+
+ gdk_drawable_get_size (large_shadow_pixmap, &width, &height);
+
+ left = left_space + left_corner_space;
+ right = right_space + right_corner_space;
+ top = top_space + top_corner_space;
+ bottom = bottom_space + bottom_corner_space;
+
+ if (d->width - left - right < 0)
+ {
+ left = d->width / 2;
+ right = d->width - left;
+ }
+
+ if (d->height - top - bottom < 0)
+ {
+ top = d->height / 2;
+ bottom = d->height - top;
+ }
+
+ w = d->width - left - right;
+ h = d->height - top - bottom;
+
+ x2 = d->width - right;
+ y2 = d->height - bottom;
+
+ /* top left */
+ cairo_matrix_init_identity (&matrix);
+ cairo_pattern_set_matrix (shadow_pattern, &matrix);
+ cairo_set_source (cr, shadow_pattern);
+ cairo_rectangle (cr, 0.0, 0.0, left, top);
+ cairo_fill (cr);
+
+ /* top */
+ if (w > 0)
+ {
+ cairo_matrix_init_translate (&matrix, left, 0.0);
+ cairo_matrix_scale (&matrix, 1.0 / w, 1.0);
+ cairo_matrix_translate (&matrix, -left, 0.0);
+ cairo_pattern_set_matrix (shadow_pattern, &matrix);
+ cairo_set_source (cr, shadow_pattern);
+ cairo_rectangle (cr, left, 0.0, w, top);
+ cairo_fill (cr);
+ }
+
+ /* top right */
+ cairo_matrix_init_translate (&matrix, width - right - x2, 0.0);
+ cairo_pattern_set_matrix (shadow_pattern, &matrix);
+ cairo_set_source (cr, shadow_pattern);
+ cairo_rectangle (cr, x2, 0.0, right, top);
+ cairo_fill (cr);
+
+ /* left */
+ if (h > 0)
+ {
+ cairo_matrix_init_translate (&matrix, 0.0, top);
+ cairo_matrix_scale (&matrix, 1.0, 1.0 / h);
+ cairo_matrix_translate (&matrix, 0.0, -top);
+ cairo_pattern_set_matrix (shadow_pattern, &matrix);
+ cairo_set_source (cr, shadow_pattern);
+ cairo_rectangle (cr, 0.0, top, left, h);
+ cairo_fill (cr);
+ }
+
+ /* right */
+ if (h > 0)
+ {
+ cairo_matrix_init_translate (&matrix, width - right - x2, top);
+ cairo_matrix_scale (&matrix, 1.0, 1.0 / h);
+ cairo_matrix_translate (&matrix, 0.0, -top);
+ cairo_pattern_set_matrix (shadow_pattern, &matrix);
+ cairo_set_source (cr, shadow_pattern);
+ cairo_rectangle (cr, x2, top, right, h);
+ cairo_fill (cr);
+ }
+
+ /* bottom left */
+ cairo_matrix_init_translate (&matrix, 0.0, height - bottom - y2);
+ cairo_pattern_set_matrix (shadow_pattern, &matrix);
+ cairo_set_source (cr, shadow_pattern);
+ cairo_rectangle (cr, 0.0, y2, left, bottom);
+ cairo_fill (cr);
+
+ /* bottom */
+ if (w > 0)
+ {
+ cairo_matrix_init_translate (&matrix, left,
+ height - bottom - y2);
+ cairo_matrix_scale (&matrix, 1.0 / w, 1.0);
+ cairo_matrix_translate (&matrix, -left, 0.0);
+ cairo_pattern_set_matrix (shadow_pattern, &matrix);
+ cairo_set_source (cr, shadow_pattern);
+ cairo_rectangle (cr, left, y2, w, bottom);
+ cairo_fill (cr);
+ }
+
+ /* bottom right */
+ cairo_matrix_init_translate (&matrix, width - right - x2,
+ height - bottom - y2);
+ cairo_pattern_set_matrix (shadow_pattern, &matrix);
+ cairo_set_source (cr, shadow_pattern);
+ cairo_rectangle (cr, x2, y2, right, bottom);
+ cairo_fill (cr);
+}
+
+typedef void (*draw_proc) (cairo_t *cr);
+
+#ifdef USE_METACITY
+static void
+decor_update_meta_window_property (decor_t *d,
+ MetaTheme *theme,
+ MetaFrameFlags flags)
+{
+ long data[256];
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ extents extents, max_extents;
+ gint nQuad;
+ quad quads[N_QUADS_MAX];
+ gint left_width, right_width, top_height, bottom_height;
+
+ nQuad = set_window_quads (quads, d->width, d->height, d->button_width);
+
+ meta_theme_get_frame_borders (theme,
+ META_FRAME_TYPE_NORMAL,
+ text_height,
+ flags & ~META_FRAME_MAXIMIZED,
+ &top_height,
+ &bottom_height,
+ &left_width,
+ &right_width);
+
+ extents.top = top_height;
+ extents.bottom = bottom_height;
+ extents.left = left_width;
+ extents.right = right_width;
+
+ meta_theme_get_frame_borders (theme,
+ META_FRAME_TYPE_NORMAL,
+ text_height,
+ flags | META_FRAME_MAXIMIZED,
+ &top_height,
+ &bottom_height,
+ &left_width,
+ &right_width);
+
+ max_extents.top = top_height;
+ max_extents.bottom = bottom_height;
+ max_extents.left = left_width;
+ max_extents.right = right_width;
+
+ decoration_to_property (data, GDK_PIXMAP_XID (d->pixmap),
+ &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);
+ XSync (xdisplay, FALSE);
+ gdk_error_trap_pop ();
+}
+
+static Region
+meta_get_window_region (const MetaFrameGeometry *fgeom,
+ int width,
+ int height)
+{
+ Region corners_xregion, window_xregion;
+ XRectangle xrect;
+
+ corners_xregion = XCreateRegion ();
+
+ if (fgeom->top_left_corner_rounded)
+ {
+ xrect.x = 0;
+ xrect.y = 0;
+ xrect.width = 5;
+ xrect.height = 1;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = 1;
+ xrect.width = 3;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = 2;
+ xrect.width = 2;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = 3;
+ xrect.width = 1;
+ xrect.height = 2;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+ }
+
+ if (fgeom->top_right_corner_rounded)
+ {
+ xrect.x = width - 5;
+ xrect.y = 0;
+ xrect.width = 5;
+ xrect.height = 1;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = 1;
+ xrect.x = width - 3;
+ xrect.width = 3;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = 2;
+ xrect.x = width - 2;
+ xrect.width = 2;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = 3;
+ xrect.x = width - 1;
+ xrect.width = 1;
+ xrect.height = 2;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+ }
+
+ if (fgeom->bottom_left_corner_rounded)
+ {
+ xrect.x = 0;
+ xrect.y = height - 1;
+ xrect.width = 5;
+ xrect.height = 1;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = height - 2;
+ xrect.width = 3;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = height - 3;
+ xrect.width = 2;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = height - 5;
+ xrect.width = 1;
+ xrect.height = 2;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+ }
+
+ if (fgeom->bottom_right_corner_rounded)
+ {
+ xrect.x = width - 5;
+ xrect.y = height - 1;
+ xrect.width = 5;
+ xrect.height = 1;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = height - 2;
+ xrect.x = width - 3;
+ xrect.width = 3;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = height - 3;
+ xrect.x = width - 2;
+ xrect.width = 2;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+
+ xrect.y = height - 5;
+ xrect.x = width - 1;
+ xrect.width = 1;
+ xrect.height = 2;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+ }
+
+ window_xregion = XCreateRegion ();
+
+ xrect.x = 0;
+ xrect.y = 0;
+ xrect.width = width;
+ xrect.height = height;
+
+ XUnionRectWithRegion (&xrect, window_xregion, window_xregion);
+
+ XSubtractRegion (window_xregion, corners_xregion, window_xregion);
+
+ XDestroyRegion (corners_xregion);
+
+ return window_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 MetaButtonState
+meta_button_state_for_button_type (decor_t *d,
+ MetaButtonType type)
+{
+ switch (type) {
+ case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
+ case META_BUTTON_TYPE_MINIMIZE:
+ return meta_button_state (d->button_states[2]);
+ case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
+ case META_BUTTON_TYPE_MAXIMIZE:
+ return meta_button_state (d->button_states[1]);
+ case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
+ case META_BUTTON_TYPE_CLOSE:
+ return meta_button_state (d->button_states[0]);
+ case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
+ case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
+ case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
+ case META_BUTTON_TYPE_MENU:
+ default:
+ break;
+ }
+
+ return META_BUTTON_STATE_NORMAL;
+}
+
+static 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;
+
+ button_layout->left_buttons[0] = META_BUTTON_FUNCTION_MENU;
+ button_layout->left_buttons[1] = META_BUTTON_FUNCTION_LAST;
+ button_layout->left_buttons[2] = META_BUTTON_FUNCTION_LAST;
+ button_layout->left_buttons[3] = 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;
+ button_layout->right_buttons[3] = META_BUTTON_FUNCTION_LAST;
+
+ *flags = 0;
+
+ if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
+ *flags |= META_FRAME_ALLOWS_DELETE;
+
+ if (d->actions & WNCK_WINDOW_ACTION_MINIMIZE)
+ *flags |= META_FRAME_ALLOWS_MINIMIZE;
+
+ if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
+ *flags |= META_FRAME_ALLOWS_MAXIMIZE;
+
+ *flags |= META_FRAME_ALLOWS_MENU;
+ *flags |= META_FRAME_ALLOWS_VERTICAL_RESIZE;
+ *flags |= META_FRAME_ALLOWS_HORIZONTAL_RESIZE;
+ *flags |= META_FRAME_ALLOWS_MOVE;
+
+ if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
+ *flags |= META_FRAME_ALLOWS_MAXIMIZE;
+
+ if (d->active)
+ *flags |= META_FRAME_HAS_FOCUS;
+
+#define META_MAXIMIZED (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY | \
+ WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY)
+
+ if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
+ *flags |= META_FRAME_MAXIMIZED;
+
+ meta_theme_get_frame_borders (theme,
+ META_FRAME_TYPE_NORMAL,
+ text_height,
+ *flags,
+ &top_height,
+ &bottom_height,
+ &left_width,
+ &right_width);
+
+ clip->x = left_space - left_width;
+ clip->y = top_space + titlebar_height - top_height;
+ clip->width = d->width - right_space + right_width - clip->x;
+ clip->height = d->height - bottom_space + bottom_height - clip->y;
+
+ meta_theme_calc_geometry (theme,
+ META_FRAME_TYPE_NORMAL,
+ text_height,
+ *flags,
+ clip->width - left_width - right_width,
+ clip->height - top_height - bottom_height,
+ button_layout,
+ fgeom);
+}
+
+static void
+meta_draw_window_decoration (decor_t *d)
+{
+ MetaButtonState button_states[META_BUTTON_TYPE_LAST];
+ MetaButtonLayout button_layout;
+ MetaFrameGeometry fgeom;
+ MetaFrameFlags flags;
+ MetaTheme *theme;
+ GtkStyle *style;
+ cairo_t *cr;
+ gint i;
+ GdkRectangle clip, rect;
+ GdkDrawable *drawable;
+ Region region;
+ double alpha = (d->active) ? meta_active_opacity : meta_opacity;
+
+ if (!d->pixmap)
+ return;
+
+ style = gtk_widget_get_style (style_window);
+
+ drawable = d->buffer_pixmap ? d->buffer_pixmap : d->pixmap;
+
+ cr = gdk_cairo_create (GDK_DRAWABLE (drawable));
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+
+ draw_shadow_background (d, cr);
+
+ theme = meta_theme_get_current ();
+
+ meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout,
+ &clip);
+
+ for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
+ button_states[i] = meta_button_state_for_button_type (d, i);
+
+ region = meta_get_window_region (&fgeom, clip.width, clip.height);
+
+ if (alpha != 1.0)
+ {
+ GdkPixmap *pixmap;
+ cairo_t *pcr;
+ gboolean shade_alpha = (d->active) ? meta_active_shade_opacity :
+ meta_shade_opacity;
+
+ pixmap = create_pixmap (clip.width, clip.height);
+
+ pcr = gdk_cairo_create (GDK_DRAWABLE (pixmap));
+
+ gdk_cairo_set_source_color (pcr, &style->bg[GTK_STATE_NORMAL]);
+ cairo_paint (pcr);
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = clip.width;
+ rect.height = clip.height;
+
+ 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);
+
+ cairo_save (cr);
+
+ for (i = 0; i < region->numRects; i++)
+ cairo_rectangle (cr,
+ clip.x + region->rects[i].x1,
+ clip.y + region->rects[i].y1,
+ region->rects[i].x2 - region->rects[i].x1,
+ region->rects[i].y2 - region->rects[i].y1);
+
+ cairo_clip (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha);
+ cairo_paint (cr);
+
+ if (shade_alpha)
+ {
+ static decor_color_t color = { 0.0, 0.0, 0.0 };
+ int corners = 0;
+
+ if (fgeom.top_left_corner_rounded)
+ corners |= CORNER_TOPLEFT;
+
+ if (fgeom.top_right_corner_rounded)
+ corners |= CORNER_TOPRIGHT;
+
+ if (fgeom.bottom_left_corner_rounded)
+ corners |= CORNER_BOTTOMLEFT;
+
+ if (fgeom.bottom_right_corner_rounded)
+ corners |= CORNER_BOTTOMRIGHT;
+
+ if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
+ WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
+ corners = 0;
+
+ fill_rounded_rectangle (cr,
+ clip.x,
+ clip.y,
+ fgeom.left_width,
+ fgeom.top_height,
+ 5.0, CORNER_TOPLEFT & corners,
+ &color, 1.0,
+ &color, alpha,
+ SHADE_TOP | SHADE_LEFT);
+
+ fill_rounded_rectangle (cr,
+ clip.x + fgeom.left_width,
+ clip.y,
+ clip.width - fgeom.left_width -
+ fgeom.right_width,
+ fgeom.top_height,
+ 5.0, 0,
+ &color, 1.0, &color, alpha,
+ SHADE_TOP);
+
+ fill_rounded_rectangle (cr,
+ clip.x + clip.width - fgeom.right_width,
+ clip.y,
+ fgeom.right_width,
+ fgeom.top_height,
+ 5.0, CORNER_TOPRIGHT & corners,
+ &color, 1.0, &color, alpha,
+ SHADE_TOP | SHADE_RIGHT);
+
+ fill_rounded_rectangle (cr,
+ clip.x,
+ clip.y + fgeom.top_height,
+ fgeom.left_width,
+ clip.height - fgeom.top_height -
+ fgeom.bottom_height,
+ 5.0, 0,
+ &color, 1.0, &color, alpha,
+ SHADE_LEFT);
+
+ fill_rounded_rectangle (cr,
+ clip.x + clip.width - fgeom.right_width,
+ clip.y + fgeom.top_height,
+ fgeom.right_width,
+ clip.height - fgeom.top_height -
+ fgeom.bottom_height,
+ 5.0, 0,
+ &color, 1.0, &color, alpha,
+ SHADE_RIGHT);
+
+ fill_rounded_rectangle (cr,
+ clip.x,
+ clip.y + clip.height - fgeom.bottom_height,
+ fgeom.left_width,
+ fgeom.bottom_height,
+ 5.0, CORNER_BOTTOMLEFT & corners,
+ &color, 1.0, &color, alpha,
+ SHADE_BOTTOM | SHADE_LEFT);
+
+ fill_rounded_rectangle (cr,
+ clip.x + fgeom.left_width,
+ clip.y + clip.height - fgeom.bottom_height,
+ clip.width - fgeom.left_width -
+ fgeom.right_width,
+ fgeom.bottom_height,
+ 5.0, 0,
+ &color, 1.0, &color, alpha,
+ SHADE_BOTTOM);
+
+ fill_rounded_rectangle (cr,
+ clip.x + clip.width - fgeom.right_width,
+ clip.y + clip.height - fgeom.bottom_height,
+ fgeom.right_width,
+ fgeom.bottom_height,
+ 5.0, CORNER_BOTTOMRIGHT & corners,
+ &color, 1.0, &color, alpha,
+ SHADE_BOTTOM | SHADE_RIGHT);
+ }
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_IN);
+ cairo_set_source_surface (cr, cairo_get_target (pcr), clip.x, clip.y);
+ cairo_paint (cr);
+
+ cairo_restore (cr);
+
+ cairo_destroy (pcr);
+ gdk_pixmap_unref (pixmap);
+ }
+ else
+ {
+ gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
+
+ for (i = 0; i < region->numRects; i++)
+ {
+ rect.x = clip.x + region->rects[i].x1;
+ rect.y = clip.y + region->rects[i].y1;
+ rect.width = region->rects[i].x2 - region->rects[i].x1;
+ rect.height = region->rects[i].y2 - region->rects[i].y1;
+
+ cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
+ cairo_fill (cr);
+
+ meta_theme_draw_frame (theme,
+ style_window,
+ drawable,
+ &rect,
+ clip.x,
+ clip.y,
+ 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);
+ }
+ }
+
+ cairo_destroy (cr);
+
+ XDestroyRegion (region);
+
+ if (d->buffer_pixmap)
+ gdk_draw_drawable (d->pixmap,
+ d->gc,
+ d->buffer_pixmap,
+ 0,
+ 0,
+ 0,
+ 0,
+ d->width,
+ d->height);
+
+ if (d->prop_xid)
+ {
+ decor_update_meta_window_property (d, theme, flags);
+ d->prop_xid = 0;
+ }
+}
+#endif
+
+#define SWITCHER_ALPHA 0xa0a0
+
+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);
+
+ 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 = _win_extents.bottom;
+
+ x1 = left_space - _win_extents.left;
+ y1 = top_space - _win_extents.top;
+ x2 = d->width - right_space + _win_extents.right;
+ y2 = d->height - bottom_space + _win_extents.bottom;
+
+ h = y2 - y1 - _win_extents.bottom - _win_extents.bottom;
+
+ cairo_set_line_width (cr, 1.0);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+
+ draw_shadow_background (d, cr);
+
+ fill_rounded_rectangle (cr,
+ x1 + 0.5,
+ y1 + 0.5,
+ _win_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 + _win_extents.left,
+ y1 + 0.5,
+ x2 - x1 - _win_extents.left -
+ _win_extents.right,
+ top - 0.5,
+ 5.0, 0,
+ &color, alpha, &color, alpha * 0.75,
+ 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,
+ &color, alpha, &color, alpha * 0.75,
+ SHADE_TOP | SHADE_RIGHT);
+
+ fill_rounded_rectangle (cr,
+ x1 + 0.5,
+ y1 + top,
+ _win_extents.left - 0.5,
+ h,
+ 5.0, 0,
+ &color, alpha, &color, alpha * 0.75,
+ SHADE_LEFT);
+
+ fill_rounded_rectangle (cr,
+ x2 - _win_extents.right,
+ y1 + top,
+ _win_extents.right - 0.5,
+ h,
+ 5.0, 0,
+ &color, alpha, &color, alpha * 0.75,
+ 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,
+ &color, alpha, &color, alpha * 0.75,
+ 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, alpha, &color, alpha * 0.75,
+ 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,
+ &color, alpha, &color, alpha * 0.75,
+ SHADE_BOTTOM | SHADE_RIGHT);
+
+ cairo_rectangle (cr, x1 + _win_extents.left,
+ y1 + top,
+ x2 - x1 - _win_extents.left - _win_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);
+
+ gdk_draw_drawable (d->pixmap,
+ d->gc,
+ d->buffer_pixmap,
+ 0,
+ 0,
+ 0,
+ 0,
+ d->width,
+ d->height);
+
+ pixel = ((((a * style->bg[GTK_STATE_NORMAL].red ) >> 24) & 0x0000ff) |
+ (((a * style->bg[GTK_STATE_NORMAL].green) >> 16) & 0x00ff00) |
+ (((a * style->bg[GTK_STATE_NORMAL].blue ) >> 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);
+ XSync (xdisplay, FALSE);
+ gdk_error_trap_pop ();
+
+ d->prop_xid = 0;
+}
+
+static void
+draw_switcher_foreground (decor_t *d)
+{
+ cairo_t *cr;
+ GtkStyle *style;
+ decor_color_t color;
+ double alpha = SWITCHER_ALPHA / 65535.0;
+ double x1, y1, x2;
+ int top;
+
+ if (!d->pixmap || !d->buffer_pixmap)
+ return;
+
+ style = gtk_widget_get_style (style_window);
+
+ 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;
+
+ top = _win_extents.bottom;
+
+ x1 = left_space - _win_extents.left;
+ y1 = top_space - _win_extents.top;
+ x2 = d->width - right_space + _win_extents.right;
+
+ cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+
+ cairo_rectangle (cr, x1 + _win_extents.left,
+ y1 + top + switcher_top_corner_space,
+ x2 - x1 - _win_extents.left - _win_extents.right,
+ 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,
+ y1 + top + switcher_top_corner_space +
+ SWITCHER_SPACE / 2 - text_height / 2);
+
+ pango_cairo_show_layout (cr, d->layout);
+ }
+
+ cairo_destroy (cr);
+
+ gdk_draw_drawable (d->pixmap,
+ d->gc,
+ d->buffer_pixmap,
+ 0,
+ 0,
+ 0,
+ 0,
+ d->width,
+ d->height);
+}
+
+static void
+draw_switcher_decoration (decor_t *d)
+{
+ if (d->prop_xid)
+ draw_switcher_background (d);
+
+ draw_switcher_foreground (d);
+}
+
+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;
+}
+
+static 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);
+}
+
+static GdkPixmap *
+pixmap_new_from_pixbuf (GdkPixbuf *pixbuf)
+{
+ 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);
+ 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;
+}
+
+static 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;
+ quad quads[N_QUADS_MAX];
+ extents extents = _win_extents;
+
+ xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
+
+ bareAtom = XInternAtom (xdisplay, "_NET_WINDOW_DECOR_BARE", FALSE);
+ normalAtom = XInternAtom (xdisplay, "_NET_WINDOW_DECOR_NORMAL", FALSE);
+ activeAtom = XInternAtom (xdisplay, "_NET_WINDOW_DECOR_ACTIVE", FALSE);
+
+ if (shadow_pixmap)
+ {
+ int width, height;
+
+ gdk_drawable_get_size (shadow_pixmap, &width, &height);
+
+ nQuad = set_shadow_quads (quads, width, height);
+
+ decoration_to_property (data, GDK_PIXMAP_XID (shadow_pixmap),
+ &_shadow_extents, &_shadow_extents,
+ 0, 0, quads, nQuad);
+
+ XChangeProperty (xdisplay, xroot,
+ bareAtom,
+ XA_INTEGER,
+ 32, PropModeReplace, (guchar *) data,
+ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
+
+ if (minimal)
+ {
+ XChangeProperty (xdisplay, xroot,
+ normalAtom,
+ XA_INTEGER,
+ 32, PropModeReplace, (guchar *) data,
+ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
+ XChangeProperty (xdisplay, xroot,
+ activeAtom,
+ XA_INTEGER,
+ 32, PropModeReplace, (guchar *) data,
+ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
+ }
+ }
+ else
+ {
+ XDeleteProperty (xdisplay, xroot, bareAtom);
+
+ if (minimal)
+ {
+ XDeleteProperty (xdisplay, xroot, normalAtom);
+ XDeleteProperty (xdisplay, xroot, activeAtom);
+ }
+ }
+
+ if (minimal)
+ return;
+
+ memset (&d, 0, sizeof (d));
+
+ d.width = left_space + left_corner_space + 1 + right_corner_space +
+ right_space;
+ d.height = top_space + titlebar_height + normal_top_corner_space + 2 +
+ bottom_corner_space + bottom_space;
+
+ extents.top += titlebar_height;
+
+ d.draw = theme_draw_window_decoration;
+
+ if (decor_normal_pixmap)
+ gdk_pixmap_unref (decor_normal_pixmap);
+
+ nQuad = set_no_title_window_quads (quads, d.width, d.height);
+
+ decor_normal_pixmap = create_pixmap (d.width, d.height);
+ if (decor_normal_pixmap)
+ {
+ d.pixmap = decor_normal_pixmap;
+ d.active = FALSE;
+
+ (*d.draw) (&d);
+
+ decoration_to_property (data, GDK_PIXMAP_XID (d.pixmap),
+ &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)
+ gdk_pixmap_unref (decor_active_pixmap);
+
+ decor_active_pixmap = create_pixmap (d.width, d.height);
+ if (decor_active_pixmap)
+ {
+ d.pixmap = decor_active_pixmap;
+ d.active = TRUE;
+
+ (*d.draw) (&d);
+
+ decoration_to_property (data, GDK_PIXMAP_XID (d.pixmap),
+ &extents, &extents, 0, 0, quads, nQuad);
+
+ XChangeProperty (xdisplay, xroot,
+ activeAtom,
+ XA_INTEGER,
+ 32, PropModeReplace, (guchar *) data,
+ BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
+ }
+}
+
+static void
+set_dm_check_hint (GdkScreen *screen)
+{
+ XSetWindowAttributes attrs;
+ unsigned long data[1];
+ Window xroot;
+ GdkDisplay *gdkdisplay = gdk_display_get_default ();
+ Display *xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
+ Atom atom;
+
+ attrs.override_redirect = TRUE;
+ attrs.event_mask = PropertyChangeMask;
+
+ xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
+
+ data[0] = XCreateWindow (xdisplay,
+ xroot,
+ -100, -100, 1, 1,
+ 0,
+ CopyFromParent,
+ CopyFromParent,
+ (Visual *) CopyFromParent,
+ CWOverrideRedirect | CWEventMask,
+ &attrs);
+
+ atom = XInternAtom (xdisplay, "_NET_SUPPORTING_DM_CHECK", FALSE);
+
+ XChangeProperty (xdisplay, xroot,
+ atom,
+ XA_WINDOW,
+ 32, PropModeReplace, (guchar *) data, 1);
+}
+
+static 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,
+ 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;
+}
+
+static unsigned int
+get_mwm_prop (Window xwindow)
+{
+ Display *xdisplay;
+ Atom actual;
+ int err, result, format;
+ unsigned long n, left;
+ MwmHints *mwm_hints;
+ 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,
+ (unsigned char **) &mwm_hints);
+
+ err = gdk_error_trap_pop ();
+ if (err != Success || result != Success)
+ return decor;
+
+ if (n && mwm_hints)
+ {
+ if (n >= PROP_MOTIF_WM_HINT_ELEMENTS)
+ {
+ if (mwm_hints->flags & MWM_HINTS_DECORATIONS)
+ decor = mwm_hints->decorations;
+ }
+
+ XFree (mwm_hints);
+ }
+
+ return decor;
+}
+
+#ifdef USE_METACITY
+static void
+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;
+ GdkRectangle clip;
+ MetaButtonSpace *space;
+
+ theme = meta_theme_get_current ();
+
+ meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout,
+ &clip);
+
+ switch (i) {
+ case 2:
+ space = &fgeom.min_rect;
+ break;
+ case 1:
+ space = &fgeom.max_rect;
+ break;
+ case 0:
+ default:
+ space = &fgeom.close_rect;
+ break;
+ }
+
+ *x = space->clickable.x;
+ *y = space->clickable.y;
+ *w = space->clickable.width;
+ *h = space->clickable.height;
+}
+#endif
+
+static 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;
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+
+ wnck_window_get_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++)
+ {
+ if (d->actions & event_window_actions[i][j] && i >= k && i <= l)
+ {
+ 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);
+ w = pos[i][j].w + pos[i][j].ww * width;
+ h = pos[i][j].h + pos[i][j].hh * height + pos[i][j].hth * (titlebar_height - 17);
+
+ XMapWindow (xdisplay, d->event_windows[i][j]);
+ XMoveResizeWindow (xdisplay, d->event_windows[i][j],
+ x, y, w, h);
+ }
+ else
+ {
+ XUnmapWindow (xdisplay, d->event_windows[i][j]);
+ }
+ }
+ }
+
+ 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])
+ {
+ (*theme_get_button_position) (d, i, width, height, &x, &y, &w, &h);
+
+ XMapWindow (xdisplay, d->button_windows[i]);
+ XMoveResizeWindow (xdisplay, d->button_windows[i], x, y, w, h);
+ }
+ else
+ XUnmapWindow (xdisplay, d->button_windows[i]);
+ }
+
+ XSync (xdisplay, FALSE);
+ gdk_error_trap_pop ();
+}
+
+#if 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
+
+static gint
+max_window_name_width (WnckWindow *win)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+ const gchar *name;
+ gint w;
+
+ name = wnck_window_get_name (win);
+ if (!name)
+ return 0;
+
+ if (!d->layout)
+ {
+ d->layout = pango_layout_new (pango_context);
+ if (!d->layout)
+ return 0;
+
+ pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
+ }
+
+ 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;
+}
+
+static 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, n_line;
+
+ w = d->width - left_space - right_space - ICON_SPACE - 4;
+ w -= d->button_width;
+ if (w < 1)
+ w = 1;
+
+ pango_layout_set_width (d->layout, w * PANGO_SCALE);
+ pango_layout_set_text (d->layout, name, name_length);
+
+ n_line = pango_layout_get_line_count (d->layout);
+
+ 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;
+ 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);
+ }
+ else if (d->layout)
+ {
+ g_object_unref (G_OBJECT (d->layout));
+ d->layout = NULL;
+ }
+}
+
+static 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)
+ {
+ gdk_pixmap_unref (d->icon_pixmap);
+ d->icon_pixmap = NULL;
+ }
+
+ if (d->icon_pixbuf)
+ gdk_pixbuf_unref (d->icon_pixbuf);
+
+ d->icon_pixbuf = wnck_window_get_mini_icon (win);
+ if (d->icon_pixbuf)
+ {
+ cairo_t *cr;
+
+ gdk_pixbuf_ref (d->icon_pixbuf);
+
+ d->icon_pixmap = pixmap_new_from_pixbuf (d->icon_pixbuf);
+ cr = gdk_cairo_create (GDK_DRAWABLE (d->icon_pixmap));
+ d->icon = cairo_pattern_create_for_surface (cairo_get_target (cr));
+ cairo_destroy (cr);
+ }
+}
+
+static 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);
+}
+
+static 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
+update_window_button_size (WnckWindow *win)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+ 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++;
+
+ if (button_width != d->button_width)
+ {
+ d->button_width = button_width;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#ifdef USE_METACITY
+static gboolean
+meta_calc_decoration_size (decor_t *d,
+ gint w,
+ gint h,
+ gint name_width,
+ gint *width,
+ gint *height)
+{
+ *width = MAX (w, left_corner_space + right_corner_space);
+ *width += left_space + 1 + right_space;
+
+ *height = titlebar_height + normal_top_corner_space + bottom_corner_space;
+ *height += top_space + 2 + bottom_space;
+
+ return (*width != d->width || *height != d->height);
+}
+#endif
+
+static gboolean
+update_window_decoration_size (WnckWindow *win)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+ GdkPixmap *pixmap, *buffer_pixmap = NULL;
+ gint width, height;
+ gint w, h, name_width;
+
+ wnck_window_get_geometry (win, NULL, NULL, &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;
+ }
+
+ pixmap = create_pixmap (width, height);
+ if (!pixmap)
+ return FALSE;
+
+ buffer_pixmap = create_pixmap (width, height);
+ if (!buffer_pixmap)
+ {
+ gdk_pixmap_unref (pixmap);
+ return FALSE;
+ }
+
+ if (d->pixmap)
+ gdk_pixmap_unref (d->pixmap);
+
+ if (d->buffer_pixmap)
+ gdk_pixmap_unref (d->buffer_pixmap);
+
+ if (d->gc)
+ gdk_gc_unref (d->gc);
+
+ d->pixmap = pixmap;
+ d->buffer_pixmap = buffer_pixmap;
+ d->gc = gdk_gc_new (pixmap);
+
+ 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;
+}
+
+static void
+add_frame_window (WnckWindow *win,
+ Window frame)
+{
+ 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 ());
+
+ attr.event_mask = ButtonPressMask | EnterWindowMask | LeaveWindowMask;
+ attr.override_redirect = TRUE;
+
+ gdk_error_trap_push ();
+
+ for (i = 0; i < 3; i++)
+ {
+ for (j = 0; j < 3; j++)
+ {
+ d->event_windows[i][j] =
+ 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],
+ cursor[i][j].cursor);
+ }
+ }
+
+ attr.event_mask |= ButtonReleaseMask;
+
+ for (i = 0; i < 3; i++)
+ {
+ d->button_windows[i] =
+ XCreateWindow (xdisplay,
+ frame,
+ 0, 0, 1, 1, 0,
+ CopyFromParent, CopyFromParent, CopyFromParent,
+ CWOverrideRedirect | CWEventMask, &attr);
+
+ d->button_states[i] = 0;
+ }
+
+ XSync (xdisplay, FALSE);
+ 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++)
+ g_hash_table_insert (frame_table,
+ GINT_TO_POINTER (d->event_windows[i][j]),
+ GINT_TO_POINTER (xid));
+
+ for (i = 0; i < 3; i++)
+ g_hash_table_insert (frame_table,
+ GINT_TO_POINTER (d->button_windows[i]),
+ GINT_TO_POINTER (xid));
+
+
+ update_window_decoration_state (win);
+ update_window_decoration_actions (win);
+ update_window_decoration_icon (win);
+ update_window_button_size (win);
+ update_window_decoration_size (win);
+
+ update_event_windows (win);
+ }
+ else
+ {
+ memset (d->event_windows, 0, sizeof (d->event_windows));
+ }
+}
+
+static gboolean
+update_switcher_window (WnckWindow *win,
+ Window selected)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+ GdkPixmap *pixmap, *buffer_pixmap = NULL;
+ gint height, width = 0;
+ WnckWindow *selected_win;
+
+ wnck_window_get_geometry (win, NULL, NULL, &width, NULL);
+
+ width += left_space + right_space;
+ height = top_space + SWITCHER_TOP_EXTRA + switcher_top_corner_space +
+ SWITCHER_SPACE + switcher_bottom_corner_space + bottom_space;
+
+ d->decorated = FALSE;
+ d->draw = draw_switcher_decoration;
+
+ if (!d->pixmap && switcher_pixmap)
+ {
+ gdk_pixmap_ref (switcher_pixmap);
+ d->pixmap = switcher_pixmap;
+ }
+
+ if (!d->buffer_pixmap && switcher_buffer_pixmap)
+ {
+ gdk_pixmap_ref (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)))
+ {
+ gint n_line;
+
+ 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 - left_space - right_space - 64;
+ pango_layout_set_width (d->layout, tw * PANGO_SCALE);
+ pango_layout_set_text (d->layout, name, name_length);
+
+ n_line = pango_layout_get_line_count (d->layout);
+
+ 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 (width == d->width && height == d->height)
+ {
+ if (!d->gc)
+ d->gc = gdk_gc_new (d->pixmap);
+
+ queue_decor_draw (d);
+ return FALSE;
+ }
+
+ pixmap = create_pixmap (width, height);
+ if (!pixmap)
+ return FALSE;
+
+ buffer_pixmap = create_pixmap (width, height);
+ if (!buffer_pixmap)
+ {
+ gdk_pixmap_unref (pixmap);
+ return FALSE;
+ }
+
+ if (switcher_pixmap)
+ gdk_pixmap_unref (switcher_pixmap);
+
+ if (switcher_buffer_pixmap)
+ gdk_pixmap_unref (switcher_buffer_pixmap);
+
+ if (d->pixmap)
+ gdk_pixmap_unref (d->pixmap);
+
+ if (d->buffer_pixmap)
+ gdk_pixmap_unref (d->buffer_pixmap);
+
+ if (d->gc)
+ gdk_gc_unref (d->gc);
+
+ switcher_pixmap = pixmap;
+ switcher_buffer_pixmap = buffer_pixmap;
+
+ switcher_width = width;
+ switcher_height = height;
+
+ gdk_pixmap_ref (pixmap);
+ gdk_pixmap_ref (buffer_pixmap);
+
+ d->pixmap = pixmap;
+ d->buffer_pixmap = buffer_pixmap;
+ d->gc = gdk_gc_new (pixmap);
+
+ d->width = width;
+ d->height = height;
+
+ d->prop_xid = wnck_window_get_xid (win);
+
+ queue_decor_draw (d);
+
+ return TRUE;
+}
+
+static void
+remove_frame_window (WnckWindow *win)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+
+ if (d->pixmap)
+ {
+ gdk_pixmap_unref (d->pixmap);
+ d->pixmap = NULL;
+ }
+
+ if (d->buffer_pixmap)
+ {
+ gdk_pixmap_unref (d->buffer_pixmap);
+ d->buffer_pixmap = NULL;
+ }
+
+ if (d->gc)
+ {
+ gdk_gc_unref (d->gc);
+ d->gc = NULL;
+ }
+
+ 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)
+ {
+ gdk_pixmap_unref (d->icon_pixmap);
+ d->icon_pixmap = NULL;
+ }
+
+ if (d->icon_pixbuf)
+ {
+ gdk_pixbuf_unref (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);
+ }
+
+ d->width = 0;
+ d->height = 0;
+
+ d->decorated = FALSE;
+
+ d->state = 0;
+ d->actions = 0;
+
+ draw_list = g_slist_remove (draw_list, d);
+}
+
+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)
+ {
+ 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);
+ 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_button_size (win))
+ {
+ update_window_decoration_size (win);
+ update_event_windows (win);
+ }
+ else
+ {
+ queue_decor_draw (d);
+ }
+ }
+}
+
+static 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->pixmap)
+ {
+ d->active = wnck_window_is_active (win);
+ queue_decor_draw (d);
+ }
+ }
+
+ win = wnck_screen_get_active_window (screen);
+ if (win)
+ {
+ d = g_object_get_data (G_OBJECT (win), "decor");
+ if (d->pixmap)
+ {
+ d->active = wnck_window_is_active (win);
+ queue_decor_draw (d);
+ }
+ }
+}
+
+static void
+window_opened (WnckScreen *screen,
+ WnckWindow *win)
+{
+ decor_t *d;
+ Window window;
+ gulong xid;
+
+ d = g_malloc (sizeof (decor_t));
+ if (!d)
+ return;
+
+ d->pixmap = NULL;
+ d->buffer_pixmap = NULL;
+ d->gc = NULL;
+
+ d->icon = NULL;
+ d->icon_pixmap = NULL;
+ d->icon_pixbuf = NULL;
+
+ d->button_width = 0;
+
+ d->width = 0;
+ d->height = 0;
+
+ d->active = wnck_window_is_active (win);
+
+ d->layout = NULL;
+ d->name = NULL;
+
+ d->state = 0;
+ d->actions = 0;
+
+ d->prop_xid = 0;
+
+ d->decorated = FALSE;
+
+ d->force_quit_dialog = NULL;
+
+ d->draw = theme_draw_window_decoration;
+
+ g_object_set_data (G_OBJECT (win), "decor", d);
+
+ connect_window (win);
+
+ xid = wnck_window_get_xid (win);
+
+ if (get_window_prop (xid, frame_window_atom, &window))
+ {
+ add_frame_window (win, window);
+ }
+ else if (get_window_prop (xid, select_window_atom, &window))
+ {
+ d->prop_xid = wnck_window_get_xid (win);
+ update_switcher_window (win, window);
+ }
+}
+
+static void
+window_closed (WnckScreen *screen,
+ WnckWindow *win)
+{
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+
+ remove_frame_window (win);
+
+ gdk_error_trap_push ();
+ XDeleteProperty (xdisplay, wnck_window_get_xid (win), win_decor_atom);
+ XSync (xdisplay, FALSE);
+ gdk_error_trap_pop ();
+
+ g_free (d);
+}
+
+static 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;
+ }
+}
+
+static void
+move_resize_window (WnckWindow *win,
+ int direction,
+ XEvent *xevent)
+{
+ 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] = xevent->xbutton.x_root;
+ ev.xclient.data.l[1] = xevent->xbutton.y_root;
+ ev.xclient.data.l[2] = direction;
+ ev.xclient.data.l[3] = xevent->xbutton.button;
+ ev.xclient.data.l[4] = 1;
+
+ XUngrabPointer (xdisplay, xevent->xbutton.time);
+ XUngrabKeyboard (xdisplay, xevent->xbutton.time);
+
+ XSendEvent (xdisplay, xroot, FALSE,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &ev);
+
+ XSync (xdisplay, FALSE);
+}
+
+static 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);
+}
+
+/* stolen from gtktooltip.c */
+
+#define DEFAULT_DELAY 500 /* Default delay in ms */
+#define STICKY_DELAY 0 /* Delay before popping up next tip
+ * if we're sticky
+ */
+#define STICKY_REVERT_DELAY 1000 /* Delay before sticky tooltips revert
+ * to normal
+ */
+
+static void
+show_tooltip (const char *text)
+{
+ GdkDisplay *gdkdisplay;
+ GtkRequisition requisition;
+ gint x, y, w, h;
+ GdkScreen *screen;
+ gint monitor_num;
+ GdkRectangle monitor;
+
+ gdkdisplay = gdk_display_get_default ();
+
+ gtk_label_set_text (GTK_LABEL (tip_label), text);
+
+ gtk_widget_size_request (tip_window, &requisition);
+
+ w = requisition.width;
+ h = requisition.height;
+
+ gdk_display_get_pointer (gdkdisplay, &screen, &x, &y, NULL);
+
+ x -= (w / 2 + 4);
+
+ monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ if ((x + w) > monitor.x + monitor.width)
+ x -= (x + w) - (monitor.x + monitor.width);
+ else if (x < monitor.x)
+ x = monitor.x;
+
+ if ((y + h + 16) > monitor.y + monitor.height)
+ y = y - h - 16;
+ else
+ y = y + 16;
+
+ gtk_window_move (GTK_WINDOW (tip_window), x, y);
+ gtk_widget_show (tip_window);
+}
+
+static void
+hide_tooltip (void)
+{
+ if (GTK_WIDGET_VISIBLE (tip_window))
+ g_get_current_time (&tooltip_last_popdown);
+
+ gtk_widget_hide (tip_window);
+
+ if (tooltip_timer_tag)
+ {
+ g_source_remove (tooltip_timer_tag);
+ tooltip_timer_tag = 0;
+ }
+}
+
+static gboolean
+tooltip_recently_shown (void)
+{
+ GTimeVal now;
+ glong msec;
+
+ g_get_current_time (&now);
+
+ msec = (now.tv_sec - tooltip_last_popdown.tv_sec) * 1000 +
+ (now.tv_usec - tooltip_last_popdown.tv_usec) / 1000;
+
+ return (msec < STICKY_REVERT_DELAY);
+}
+
+static gint
+tooltip_timeout (gpointer data)
+{
+ tooltip_timer_tag = 0;
+
+ show_tooltip ((const char *) data);
+
+ return FALSE;
+}
+
+static void
+tooltip_start_delay (const char *text)
+{
+ guint delay = DEFAULT_DELAY;
+
+ if (tooltip_timer_tag)
+ return;
+
+ if (tooltip_recently_shown ())
+ delay = STICKY_DELAY;
+
+ tooltip_timer_tag = g_timeout_add (delay,
+ tooltip_timeout,
+ (gpointer) text);
+}
+
+static gint
+tooltip_paint_window (GtkWidget *tooltip)
+{
+ GtkRequisition req;
+
+ gtk_widget_size_request (tip_window, &req);
+ gtk_paint_flat_box (tip_window->style, tip_window->window,
+ GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+ NULL, GTK_WIDGET (tip_window), "tooltip",
+ 0, 0, req.width, req.height);
+
+ return FALSE;
+}
+
+static gboolean
+create_tooltip_window (void)
+{
+ tip_window = gtk_window_new (GTK_WINDOW_POPUP);
+
+ gtk_widget_set_app_paintable (tip_window, TRUE);
+ gtk_window_set_resizable (GTK_WINDOW (tip_window), FALSE);
+ gtk_widget_set_name (tip_window, "gtk-tooltips");
+ gtk_container_set_border_width (GTK_CONTAINER (tip_window), 4);
+
+#if GTK_CHECK_VERSION (2, 10, 0)
+ if (!gtk_check_version (2, 10, 0))
+ gtk_window_set_type_hint (GTK_WINDOW (tip_window),
+ GDK_WINDOW_TYPE_HINT_TOOLTIP);
+#endif
+
+ g_signal_connect_swapped (tip_window,
+ "expose_event",
+ G_CALLBACK (tooltip_paint_window),
+ 0);
+
+ tip_label = gtk_label_new (NULL);
+ gtk_label_set_line_wrap (GTK_LABEL (tip_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (tip_label), 0.5, 0.5);
+ gtk_widget_show (tip_label);
+
+ gtk_container_add (GTK_CONTAINER (tip_window), tip_label);
+
+ gtk_widget_ensure_style (tip_window);
+
+ return TRUE;
+}
+
+static void
+handle_tooltip_event (WnckWindow *win,
+ XEvent *xevent,
+ guint state,
+ const char *tip)
+{
+ switch (xevent->type) {
+ case ButtonPress:
+ hide_tooltip ();
+ break;
+ case ButtonRelease:
+ break;
+ case EnterNotify:
+ if (!(state & PRESSED_EVENT_WINDOW))
+ {
+ if (wnck_window_is_active (win))
+ tooltip_start_delay (tip);
+ }
+ break;
+ case LeaveNotify:
+ hide_tooltip ();
+ break;
+ }
+}
+
+static void
+close_button_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+ guint state = d->button_states[0];
+
+ handle_tooltip_event (win, xevent, state, "Close Window");
+
+ switch (xevent->type) {
+ case ButtonPress:
+ if (xevent->xbutton.button == 1)
+ d->button_states[0] |= PRESSED_EVENT_WINDOW;
+ break;
+ case ButtonRelease:
+ if (xevent->xbutton.button == 1)
+ {
+ if (d->button_states[0] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
+ wnck_window_close (win, xevent->xbutton.time);
+
+ d->button_states[0] &= ~PRESSED_EVENT_WINDOW;
+ }
+ break;
+ case EnterNotify:
+ d->button_states[0] |= IN_EVENT_WINDOW;
+ break;
+ case LeaveNotify:
+ d->button_states[0] &= ~IN_EVENT_WINDOW;
+ break;
+ }
+
+ if (state != d->button_states[0])
+ queue_decor_draw (d);
+}
+
+static void
+max_button_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+ guint state = d->button_states[1];
+
+ if (wnck_window_is_maximized (win))
+ handle_tooltip_event (win, xevent, state, "Unmaximize Window");
+ else
+ handle_tooltip_event (win, xevent, state, "Maximize Window");
+
+ switch (xevent->type) {
+ case ButtonPress:
+ if (xevent->xbutton.button == 1)
+ d->button_states[1] |= PRESSED_EVENT_WINDOW;
+ break;
+ case ButtonRelease:
+ if (xevent->xbutton.button == 1)
+ {
+ if (d->button_states[1] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
+ {
+ if (wnck_window_is_maximized (win))
+ wnck_window_unmaximize (win);
+ else
+ wnck_window_maximize (win);
+ }
+
+ d->button_states[1] &= ~PRESSED_EVENT_WINDOW;
+ }
+ break;
+ case EnterNotify:
+ d->button_states[1] |= IN_EVENT_WINDOW;
+ break;
+ case LeaveNotify:
+ d->button_states[1] &= ~IN_EVENT_WINDOW;
+ break;
+ }
+
+ if (state != d->button_states[1])
+ queue_decor_draw (d);
+}
+
+static void
+min_button_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+ guint state = d->button_states[2];
+
+ handle_tooltip_event (win, xevent, state, "Minimize Window");
+
+ switch (xevent->type) {
+ case ButtonPress:
+ if (xevent->xbutton.button == 1)
+ d->button_states[2] |= PRESSED_EVENT_WINDOW;
+ break;
+ case ButtonRelease:
+ if (xevent->xbutton.button == 1)
+ {
+ if (d->button_states[2] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
+ wnck_window_minimize (win);
+
+ d->button_states[2] &= ~PRESSED_EVENT_WINDOW;
+ }
+ break;
+ case EnterNotify:
+ d->button_states[2] |= IN_EVENT_WINDOW;
+ if (wnck_window_is_active (win))
+ tooltip_start_delay ("Minimize Window");
+ break;
+ case LeaveNotify:
+ d->button_states[2] &= ~IN_EVENT_WINDOW;
+ break;
+ }
+
+ if (state != d->button_states[2])
+ queue_decor_draw (d);
+}
+
+static void
+top_left_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ if (xevent->xbutton.button == 1)
+ move_resize_window (win, WM_MOVERESIZE_SIZE_TOPLEFT, xevent);
+}
+
+static void
+top_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ if (xevent->xbutton.button == 1)
+ move_resize_window (win, WM_MOVERESIZE_SIZE_TOP, xevent);
+}
+
+static void
+top_right_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ if (xevent->xbutton.button == 1)
+ move_resize_window (win, WM_MOVERESIZE_SIZE_TOPRIGHT, xevent);
+}
+
+static void
+left_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ if (xevent->xbutton.button == 1)
+ move_resize_window (win, WM_MOVERESIZE_SIZE_LEFT, xevent);
+}
+
+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;
+
+ wnck_window_get_geometry (win, x, y, NULL, NULL);
+
+ *push_in = TRUE;
+}
+
+static 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:
+ case WNCK_WINDOW_MODAL_DIALOG:
+ 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)
+ gtk_menu_popup (GTK_MENU (action_menu),
+ NULL, NULL,
+ NULL, NULL,
+ button,
+ time);
+ else
+ gtk_menu_popup (GTK_MENU (action_menu),
+ NULL, NULL,
+ position_action_menu, (gpointer) win,
+ button,
+ time);
+
+ action_menu_mapped = TRUE;
+}
+
+static double
+square (double x)
+{
+ return x * x;
+}
+
+static double
+dist (double x1, double y1,
+ double x2, double y2)
+{
+ return sqrt (square (x1 - x2) + square (y1 - y2));
+}
+
+static void
+title_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ 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;
+
+ if (xevent->type != ButtonPress)
+ return;
+
+ if (xevent->xbutton.button == 1)
+ {
+ if (xevent->xbutton.button == last_button_num &&
+ xevent->xbutton.window == last_button_xwindow &&
+ xevent->xbutton.time < last_button_time + double_click_timeout &&
+ dist (xevent->xbutton.x, xevent->xbutton.y,
+ last_button_x, last_button_y) < DOUBLE_CLICK_DISTANCE)
+ {
+ switch (double_click_action) {
+ case DOUBLE_CLICK_SHADE:
+ if (wnck_window_is_shaded (win))
+ wnck_window_unshade (win);
+ else
+ wnck_window_shade (win);
+ break;
+ case DOUBLE_CLICK_MAXIMIZE:
+ if (wnck_window_is_maximized (win))
+ wnck_window_unmaximize (win);
+ else
+ wnck_window_maximize (win);
+ default:
+ break;
+ }
+
+ last_button_num = 0;
+ last_button_xwindow = None;
+ last_button_time = 0;
+ last_button_x = 0;
+ last_button_y = 0;
+ }
+ else
+ {
+ last_button_num = xevent->xbutton.button;
+ last_button_xwindow = xevent->xbutton.window;
+ last_button_time = xevent->xbutton.time;
+ last_button_x = xevent->xbutton.x;
+ last_button_y = xevent->xbutton.y;
+
+ restack_window (win, Above);
+
+ move_resize_window (win, WM_MOVERESIZE_MOVE, xevent);
+ }
+ }
+ else if (xevent->xbutton.button == 2)
+ {
+ restack_window (win, Below);
+ }
+ else if (xevent->xbutton.button == 3)
+ {
+ action_menu_map (win,
+ xevent->xbutton.button,
+ xevent->xbutton.time);
+ }
+}
+
+static void
+right_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ if (xevent->xbutton.button == 1)
+ move_resize_window (win, WM_MOVERESIZE_SIZE_RIGHT, xevent);
+}
+
+static void
+bottom_left_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ if (xevent->xbutton.button == 1)
+ move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOMLEFT, xevent);
+}
+
+static void
+bottom_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ if (xevent->xbutton.button == 1)
+ move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOM, xevent);
+}
+
+static void
+bottom_right_event (WnckWindow *win,
+ XEvent *xevent)
+{
+ if (xevent->xbutton.button == 1)
+ move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOMRIGHT, xevent);
+}
+
+static void
+panel_action (Display *xdisplay,
+ Window root,
+ Atom panel_action,
+ Time event_time)
+{
+ XEvent ev;
+
+ ev.type = ClientMessage;
+ ev.xclient.window = root;
+ ev.xclient.message_type = panel_action_atom;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = panel_action;
+ ev.xclient.data.l[1] = event_time;
+ ev.xclient.data.l[2] = 0;
+ ev.xclient.data.l[3] = 0;
+ ev.xclient.data.l[4] = 0;
+
+ XSendEvent (xdisplay, root, FALSE, StructureNotifyMask, &ev);
+}
+
+static void
+force_quit_dialog_realize (GtkWidget *dialog,
+ void *data)
+{
+ WnckWindow *win = data;
+
+ gdk_error_trap_push ();
+ XSetTransientForHint (gdk_display,
+ GDK_WINDOW_XID (dialog->window),
+ wnck_window_get_xid (win));
+ XSync (gdk_display, FALSE);
+ gdk_error_trap_pop ();
+}
+
+static char *
+get_client_machine (Window xwindow)
+{
+ Atom atom, type;
+ gulong nitems, bytes_after;
+ gchar *str = NULL;
+ int format, result;
+ char *retval;
+
+ atom = XInternAtom (gdk_display, "WM_CLIENT_MACHINE", FALSE);
+
+ gdk_error_trap_push ();
+
+ result = XGetWindowProperty (gdk_display,
+ xwindow, atom,
+ 0, G_MAXLONG,
+ FALSE, XA_STRING, &type, &format, &nitems,
+ &bytes_after, (guchar **) &str);
+
+ gdk_error_trap_pop ();
+
+ if (result != Success)
+ return NULL;
+
+ if (type != XA_STRING)
+ {
+ XFree (str);
+ return NULL;
+ }
+
+ retval = g_strdup (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, wnck_window_get_xid (win));
+ XSync (gdk_display, FALSE);
+ 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);
+ }
+}
+
+static void
+show_force_quit_dialog (WnckWindow *win,
+ Time timestamp)
+{
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+ GtkWidget *dialog;
+ gchar *str, *tmp;
+
+ if (d->force_quit_dialog)
+ return;
+
+ tmp = g_markup_escape_text (wnck_window_get_name (win), -1);
+ str = g_strdup_printf ("The window \"%s\" is not responding.", tmp);
+
+ g_free (tmp);
+
+ dialog = gtk_message_dialog_new (NULL, 0,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ "<b>%s</b>\n\n%s",
+ str,
+ "Forcing this application to "
+ "quit will cause you to lose any "
+ "unsaved changes.");
+ g_free (str);
+
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), "force-quit");
+
+ gtk_label_set_use_markup (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label),
+ TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label),
+ TRUE);
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT,
+ "_Force Quit",
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
+
+ g_signal_connect (G_OBJECT (dialog), "realize",
+ G_CALLBACK (force_quit_dialog_realize),
+ win);
+
+ g_signal_connect (G_OBJECT (dialog), "response",
+ G_CALLBACK (force_quit_dialog_response),
+ win);
+
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+
+ gtk_widget_realize (dialog);
+
+ gdk_x11_window_set_user_time (dialog->window, timestamp);
+
+ gtk_widget_show (dialog);
+
+ d->force_quit_dialog = dialog;
+}
+
+static 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;
+ }
+}
+
+/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
+static gboolean
+convert_property (Display *xdisplay,
+ Window w,
+ Atom target,
+ Atom property)
+{
+
+#define N_TARGETS 4
+
+ Atom conversion_targets[N_TARGETS];
+ long icccm_version[] = { 2, 0 };
+
+ conversion_targets[0] = targets_atom;
+ conversion_targets[1] = multiple_atom;
+ conversion_targets[2] = timestamp_atom;
+ conversion_targets[3] = version_atom;
+
+ if (target == targets_atom)
+ XChangeProperty (xdisplay, w, property,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) conversion_targets, N_TARGETS);
+ else if (target == timestamp_atom)
+ XChangeProperty (xdisplay, w, property,
+ XA_INTEGER, 32, PropModeReplace,
+ (unsigned char *) &dm_sn_timestamp, 1);
+ else if (target == version_atom)
+ XChangeProperty (xdisplay, w, property,
+ XA_INTEGER, 32, PropModeReplace,
+ (unsigned char *) icccm_version, 2);
+ else
+ return FALSE;
+
+ /* Be sure the PropertyNotify has arrived so we
+ * can send SelectionNotify
+ */
+ XSync (xdisplay, FALSE);
+
+ return TRUE;
+}
+
+static void
+handle_selection_request (Display *xdisplay,
+ XEvent *event)
+{
+ XSelectionEvent reply;
+
+ reply.type = SelectionNotify;
+ reply.display = xdisplay;
+ reply.requestor = event->xselectionrequest.requestor;
+ reply.selection = event->xselectionrequest.selection;
+ reply.target = event->xselectionrequest.target;
+ reply.property = None;
+ reply.time = event->xselectionrequest.time;
+
+ if (event->xselectionrequest.target == multiple_atom)
+ {
+ if (event->xselectionrequest.property != None)
+ {
+ Atom type, *adata;
+ int i, format;
+ unsigned long num, rest;
+ unsigned char *data;
+
+ if (XGetWindowProperty (xdisplay,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.property,
+ 0, 256, FALSE,
+ atom_pair_atom,
+ &type, &format, &num, &rest,
+ &data) != Success)
+ return;
+
+ /* FIXME: to be 100% correct, should deal with rest > 0,
+ * but since we have 4 possible targets, we will hardly ever
+ * meet multiple requests with a length > 8
+ */
+ adata = (Atom *) data;
+ i = 0;
+ while (i < (int) num)
+ {
+ if (!convert_property (xdisplay,
+ event->xselectionrequest.requestor,
+ adata[i], adata[i + 1]))
+ adata[i + 1] = None;
+
+ i += 2;
+ }
+
+ XChangeProperty (xdisplay,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.property,
+ atom_pair_atom,
+ 32, PropModeReplace, data, num);
+ }
+ }
+ else
+ {
+ if (event->xselectionrequest.property == None)
+ event->xselectionrequest.property = event->xselectionrequest.target;
+
+ if (convert_property (xdisplay,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.target,
+ event->xselectionrequest.property))
+ reply.property = event->xselectionrequest.property;
+ }
+
+ XSendEvent (xdisplay,
+ event->xselectionrequest.requestor,
+ FALSE, 0L, (XEvent *) &reply);
+}
+
+static void
+handle_selection_clear (Display *xdisplay,
+ XEvent *xevent)
+{
+ if (xevent->xselectionclear.selection == dm_sn_atom)
+ exit (0);
+}
+
+static gboolean
+acquire_dm_session (Display *xdisplay,
+ int screen,
+ gboolean replace_current_dm)
+{
+ XEvent event;
+ XSetWindowAttributes attr;
+ Window current_dm_sn_owner, new_dm_sn_owner;
+ char buf[128];
+
+ sprintf (buf, "DM_S%d", screen);
+ dm_sn_atom = XInternAtom (xdisplay, buf, 0);
+
+ current_dm_sn_owner = XGetSelectionOwner (xdisplay, dm_sn_atom);
+
+ if (current_dm_sn_owner != None)
+ {
+ if (!replace_current_dm)
+ {
+ 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, screen, DisplayString (xdisplay));
+
+ return FALSE;
+ }
+
+ XSelectInput (xdisplay, current_dm_sn_owner, StructureNotifyMask);
+ }
+
+ attr.override_redirect = TRUE;
+ attr.event_mask = PropertyChangeMask;
+
+ new_dm_sn_owner =
+ XCreateWindow (xdisplay, XRootWindow (xdisplay, screen),
+ -100, -100, 1, 1, 0,
+ CopyFromParent, CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect | CWEventMask,
+ &attr);
+
+ XChangeProperty (xdisplay,
+ new_dm_sn_owner,
+ dm_name_atom,
+ utf8_string_atom, 8,
+ PropModeReplace,
+ (unsigned char *) "gwd",
+ strlen ("gwd"));
+
+ XWindowEvent (xdisplay,
+ new_dm_sn_owner,
+ PropertyChangeMask,
+ &event);
+
+ dm_sn_timestamp = event.xproperty.time;
+
+ XSetSelectionOwner (xdisplay, dm_sn_atom, new_dm_sn_owner,
+ dm_sn_timestamp);
+
+ if (XGetSelectionOwner (xdisplay, dm_sn_atom) != new_dm_sn_owner)
+ {
+ fprintf (stderr,
+ "%s: Could not acquire decoration manager "
+ "selection on screen %d display \"%s\"\n",
+ program_name, screen, DisplayString (xdisplay));
+
+ XDestroyWindow (xdisplay, new_dm_sn_owner);
+
+ return FALSE;
+ }
+
+ /* Send client message indicating that we are now the DM */
+ event.xclient.type = ClientMessage;
+ event.xclient.window = XRootWindow (xdisplay, screen);
+ event.xclient.message_type = manager_atom;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = dm_sn_timestamp;
+ event.xclient.data.l[1] = dm_sn_atom;
+ event.xclient.data.l[2] = 0;
+ event.xclient.data.l[3] = 0;
+ event.xclient.data.l[4] = 0;
+
+ XSendEvent (xdisplay, XRootWindow (xdisplay, screen), FALSE,
+ StructureNotifyMask, &event);
+
+ /* Wait for old decoration manager to go away */
+ if (current_dm_sn_owner != None)
+ {
+ do {
+ XWindowEvent (xdisplay, current_dm_sn_owner,
+ StructureNotifyMask, &event);
+ } while (event.type != DestroyNotify);
+ }
+
+ return TRUE;
+}
+
+static GdkFilterReturn
+event_filter_func (GdkXEvent *gdkxevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ Display *xdisplay;
+ GdkDisplay *gdkdisplay;
+ XEvent *xevent = gdkxevent;
+ gulong xid = 0;
+
+ gdkdisplay = gdk_display_get_default ();
+ xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
+
+ switch (xevent->type) {
+ 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_window_atom)
+ {
+ WnckWindow *win;
+
+ xid = xevent->xproperty.window;
+
+ win = wnck_window_get (xid);
+ if (win)
+ {
+ Window frame;
+
+ if (get_window_prop (xid, frame_window_atom, &frame))
+ add_frame_window (win, frame);
+ else
+ remove_frame_window (win);
+ }
+ }
+ 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->width = d->height = 0;
+
+ update_window_decoration_size (win);
+ update_event_windows (win);
+ }
+ else
+ {
+ gdk_error_trap_push ();
+ XDeleteProperty (xdisplay, xid, win_decor_atom);
+ XSync (xdisplay, FALSE);
+ gdk_error_trap_pop ();
+ }
+ }
+ }
+ }
+ else if (xevent->xproperty.atom == select_window_atom)
+ {
+ WnckWindow *win;
+
+ xid = xevent->xproperty.window;
+
+ win = wnck_window_get (xid);
+ if (win)
+ {
+ Window select;
+
+ if (get_window_prop (xid, select_window_atom, &select))
+ update_switcher_window (win, select);
+ }
+ }
+ 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_main_menu_atom)
+ {
+ panel_action (xdisplay, xevent->xclient.window,
+ panel_action_main_menu_atom,
+ xevent->xclient.data.l[1]);
+ }
+ else if (action == toolkit_action_run_dialog_atom)
+ {
+ panel_action (xdisplay, xevent->xclient.window,
+ panel_action_run_dialog_atom,
+ xevent->xclient.data.l[1]);
+ }
+ else 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)
+ {
+ 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[3] = {
+ close_button_event,
+ max_button_event,
+ min_button_event
+ };
+ decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
+
+ if (d->decorated)
+ {
+ gint i, j;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ if (d->event_windows[i][j] == xevent->xany.window)
+ (*callback[i][j]) (win, xevent);
+
+ for (i = 0; i < 3; i++)
+ if (d->button_windows[i] == xevent->xany.window)
+ (*button_callback[i]) (win, xevent);
+ }
+ }
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static GdkFilterReturn
+selection_event_filter_func (GdkXEvent *gdkxevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ Display *xdisplay;
+ GdkDisplay *gdkdisplay;
+ XEvent *xevent = gdkxevent;
+
+ gdkdisplay = gdk_display_get_default ();
+ xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
+
+ switch (xevent->type) {
+ case SelectionRequest:
+ handle_selection_request (xdisplay, xevent);
+ break;
+ case SelectionClear:
+ handle_selection_clear (xdisplay, xevent);
+ default:
+ break;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+
+/* 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;
+ }
+}
+
+static 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;
+}
+
+static void
+update_style (GtkWidget *widget)
+{
+ GtkStyle *style;
+ decor_color_t spot_color;
+
+ style = gtk_widget_get_style (widget);
+ 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;
+
+ shade (&spot_color, &_title_color[0], 1.05);
+ shade (&_title_color[0], &_title_color[1], 0.85);
+}
+
+#if G_MAXINT != G_MAXLONG
+/* XRenderSetPictureFilter used to be broken on LP64. This
+ * works with either the broken or fixed version.
+ */
+static void
+XRenderSetPictureFilter_wrapper (Display *dpy,
+ Picture picture,
+ char *filter,
+ XFixed *params,
+ int nparams)
+{
+ gdk_error_trap_push ();
+ XRenderSetPictureFilter (dpy, picture, filter, params, nparams);
+ XSync (dpy, False);
+ if (gdk_error_trap_pop ())
+ {
+ long *long_params = g_new (long, nparams);
+ int i;
+
+ for (i = 0; i < nparams; i++)
+ long_params[i] = params[i];
+
+ XRenderSetPictureFilter (dpy, picture, filter,
+ (XFixed *) long_params, nparams);
+ g_free (long_params);
+ }
+}
+
+#define XRenderSetPictureFilter XRenderSetPictureFilter_wrapper
+#endif
+
+static void
+set_picture_transform (Display *xdisplay,
+ Picture p,
+ int dx,
+ int dy)
+{
+ XTransform transform = {
+ {
+ { 1 << 16, 0, -dx << 16 },
+ { 0, 1 << 16, -dy << 16 },
+ { 0, 0, 1 << 16 },
+ }
+ };
+
+ XRenderSetPictureTransform (xdisplay, p, &transform);
+}
+
+static XFixed *
+create_gaussian_kernel (double radius,
+ double sigma,
+ double alpha,
+ double opacity,
+ int *r_size)
+{
+ XFixed *params;
+ double *amp, scale, x_scale, fx, sum;
+ int size, half_size, x, i, n;
+
+ scale = 1.0f / (2.0f * M_PI * sigma * sigma);
+ half_size = alpha + 0.5f;
+
+ if (half_size == 0)
+ half_size = 1;
+
+ size = half_size * 2 + 1;
+ x_scale = 2.0f * radius / size;
+
+ if (size < 3)
+ return NULL;
+
+ n = size;
+
+ amp = g_malloc (sizeof (double) * n);
+ if (!amp)
+ return NULL;
+
+ n += 2;
+
+ params = g_malloc (sizeof (XFixed) * n);
+ if (!params)
+ return NULL;
+
+ i = 0;
+ sum = 0.0f;
+
+ for (x = 0; x < size; x++)
+ {
+ fx = x_scale * (x - half_size);
+
+ amp[i] = scale * exp ((-1.0f * (fx * fx)) / (2.0f * sigma * sigma));
+
+ sum += amp[i];
+
+ i++;
+ }
+
+ /* normalize */
+ if (sum != 0.0)
+ sum = 1.0 / sum;
+
+ params[0] = params[1] = 0;
+
+ for (i = 2; i < n; i++)
+ params[i] = XDoubleToFixed (amp[i - 2] * sum * opacity * 1.2);
+
+ g_free (amp);
+
+ *r_size = size;
+
+ return params;
+}
+
+/* to save some memory, value is specific to current decorations */
+#define CORNER_REDUCTION 3
+
+#define SIGMA(r) ((r) / 2.0)
+#define ALPHA(r) (r)
+
+static int
+update_shadow (void)
+{
+ Display *xdisplay = gdk_display;
+ XRenderPictFormat *format;
+ GdkPixmap *pixmap;
+ Picture src, dst, tmp;
+ XFixed *params;
+ XFilters *filters;
+ char *filter = NULL;
+ int size, n_params = 0;
+ cairo_t *cr;
+ decor_t d;
+ double save_decoration_alpha;
+ static XRenderColor color = { 0x0000, 0x0000, 0x0000, 0xffff };
+ static XRenderColor clear = { 0x0000, 0x0000, 0x0000, 0x0000 };
+ static XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
+
+ /* compute a gaussian convolution kernel */
+ params = create_gaussian_kernel (shadow_radius,
+ SIGMA (shadow_radius),
+ ALPHA (shadow_radius),
+ shadow_opacity,
+ &size);
+ if (!params)
+ shadow_offset_x = shadow_offset_y = size = 0;
+
+ if (shadow_radius <= 0.0 && shadow_offset_x == 0 && shadow_offset_y == 0)
+ size = 0;
+
+ n_params = size + 2;
+ size = size / 2;
+
+ left_space = _win_extents.left + size - shadow_offset_x;
+ right_space = _win_extents.right + size + shadow_offset_x;
+ top_space = _win_extents.top + size - shadow_offset_y;
+ bottom_space = _win_extents.bottom + size + shadow_offset_y;
+
+ left_space = MAX (_win_extents.left, left_space);
+ right_space = MAX (_win_extents.right, right_space);
+ top_space = MAX (_win_extents.top, top_space);
+ bottom_space = MAX (_win_extents.bottom, bottom_space);
+
+ shadow_left_space = MAX (0, size - shadow_offset_x);
+ shadow_right_space = MAX (0, size + shadow_offset_x);
+ shadow_top_space = MAX (0, size - shadow_offset_y);
+ shadow_bottom_space = MAX (0, size + shadow_offset_y);
+
+ shadow_left_corner_space = MAX (0, size + shadow_offset_x);
+ shadow_right_corner_space = MAX (0, size - shadow_offset_x);
+ shadow_top_corner_space = MAX (0, size + shadow_offset_y);
+ shadow_bottom_corner_space = MAX (0, size - shadow_offset_y);
+
+ left_corner_space = MAX (0, shadow_left_corner_space - CORNER_REDUCTION);
+ right_corner_space = MAX (0, shadow_right_corner_space - CORNER_REDUCTION);
+ top_corner_space = MAX (0, shadow_top_corner_space - CORNER_REDUCTION);
+ bottom_corner_space =
+ MAX (0, shadow_bottom_corner_space - CORNER_REDUCTION);
+
+ normal_top_corner_space = MAX (0, top_corner_space - titlebar_height);
+ switcher_top_corner_space = MAX (0, top_corner_space - SWITCHER_TOP_EXTRA);
+ switcher_bottom_corner_space =
+ MAX (0, bottom_corner_space - SWITCHER_SPACE);
+
+ memset (&d, 0, sizeof (d));
+
+ d.draw = theme_draw_window_decoration;
+ d.active = TRUE;
+
+ d.width = left_space + left_corner_space + 1 + right_corner_space +
+ right_space;
+ d.height = top_space + titlebar_height + normal_top_corner_space + 2 +
+ bottom_corner_space + bottom_space;
+
+ /* all pixmaps are ARGB32 */
+ format = XRenderFindStandardFormat (xdisplay, PictStandardARGB32);
+
+ /* shadow color */
+ src = XRenderCreateSolidFill (xdisplay, &color);
+
+ if (large_shadow_pixmap)
+ {
+ gdk_pixmap_unref (large_shadow_pixmap);
+ large_shadow_pixmap = NULL;
+ }
+
+ if (shadow_pattern)
+ {
+ cairo_pattern_destroy (shadow_pattern);
+ shadow_pattern = NULL;
+ }
+
+ if (shadow_pixmap)
+ {
+ gdk_pixmap_unref (shadow_pixmap);
+ shadow_pixmap = NULL;
+ }
+
+ /* no shadow */
+ if (size <= 0)
+ {
+ if (params)
+ g_free (params);
+
+ return 1;
+ }
+
+ pixmap = create_pixmap (d.width, d.height);
+ if (!pixmap)
+ {
+ g_free (params);
+ return 0;
+ }
+
+ /* query server for convolution filter */
+ filters = XRenderQueryFilters (xdisplay, GDK_PIXMAP_XID (pixmap));
+ if (filters)
+ {
+ int i;
+
+ for (i = 0; i < filters->nfilter; i++)
+ {
+ if (strcmp (filters->filter[i], FilterConvolution) == 0)
+ {
+ filter = FilterConvolution;
+ break;
+ }
+ }
+
+ XFree (filters);
+ }
+
+ if (!filter)
+ {
+ fprintf (stderr, "can't generate shadows, X server doesn't support "
+ "convolution filters\n");
+
+ g_free (params);
+ gdk_pixmap_unref (pixmap);
+ return 1;
+ }
+
+
+ /* WINDOWS WITH DECORATION */
+
+ d.pixmap = create_pixmap (d.width, d.height);
+ if (!d.pixmap)
+ {
+ g_free (params);
+ gdk_pixmap_unref (pixmap);
+ return 0;
+ }
+
+ /* create shadow from opaque decoration */
+ save_decoration_alpha = decoration_alpha;
+ decoration_alpha = 1.0;
+
+ /* draw decorations */
+ (*d.draw) (&d);
+
+ decoration_alpha = save_decoration_alpha;
+
+ dst = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (d.pixmap),
+ format, 0, NULL);
+ tmp = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (pixmap),
+ format, 0, NULL);
+
+ /* first pass */
+ params[0] = (n_params - 2) << 16;
+ params[1] = 1 << 16;
+
+ set_picture_transform (xdisplay, dst, shadow_offset_x, 0);
+ XRenderSetPictureFilter (xdisplay, dst, filter, params, n_params);
+ XRenderComposite (xdisplay,
+ PictOpSrc,
+ src,
+ dst,
+ tmp,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ d.width, d.height);
+
+ /* second pass */
+ params[0] = 1 << 16;
+ params[1] = (n_params - 2) << 16;
+
+ set_picture_transform (xdisplay, tmp, 0, shadow_offset_y);
+ XRenderSetPictureFilter (xdisplay, tmp, filter, params, n_params);
+ XRenderComposite (xdisplay,
+ PictOpSrc,
+ src,
+ tmp,
+ dst,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ d.width, d.height);
+
+ XRenderFreePicture (xdisplay, tmp);
+ XRenderFreePicture (xdisplay, dst);
+
+ gdk_pixmap_unref (pixmap);
+
+ large_shadow_pixmap = d.pixmap;
+
+ cr = gdk_cairo_create (GDK_DRAWABLE (large_shadow_pixmap));
+ shadow_pattern = cairo_pattern_create_for_surface (cairo_get_target (cr));
+ cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_NEAREST);
+ cairo_destroy (cr);
+
+
+ /* WINDOWS WITHOUT DECORATIONS */
+
+ d.width = shadow_left_space + shadow_left_corner_space + 1 +
+ shadow_right_space + shadow_right_corner_space;
+ d.height = shadow_top_space + shadow_top_corner_space + 1 +
+ shadow_bottom_space + shadow_bottom_corner_space;
+
+ pixmap = create_pixmap (d.width, d.height);
+ if (!pixmap)
+ {
+ g_free (params);
+ return 0;
+ }
+
+ d.pixmap = create_pixmap (d.width, d.height);
+ if (!d.pixmap)
+ {
+ gdk_pixmap_unref (pixmap);
+ g_free (params);
+ return 0;
+ }
+
+ dst = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (d.pixmap),
+ format, 0, NULL);
+
+ /* draw rectangle */
+ XRenderFillRectangle (xdisplay, PictOpSrc, dst, &clear,
+ 0,
+ 0,
+ d.width,
+ d.height);
+ XRenderFillRectangle (xdisplay, PictOpSrc, dst, &white,
+ shadow_left_space,
+ shadow_top_space,
+ d.width - shadow_left_space - shadow_right_space,
+ d.height - shadow_top_space - shadow_bottom_space);
+
+ tmp = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (pixmap),
+ format, 0, NULL);
+
+ /* first pass */
+ params[0] = (n_params - 2) << 16;
+ params[1] = 1 << 16;
+
+ set_picture_transform (xdisplay, dst, shadow_offset_x, 0);
+ XRenderSetPictureFilter (xdisplay, dst, filter, params, n_params);
+ XRenderComposite (xdisplay,
+ PictOpSrc,
+ src,
+ dst,
+ tmp,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ d.width, d.height);
+
+ /* second pass */
+ params[0] = 1 << 16;
+ params[1] = (n_params - 2) << 16;
+
+ set_picture_transform (xdisplay, tmp, 0, shadow_offset_y);
+ XRenderSetPictureFilter (xdisplay, tmp, filter, params, n_params);
+ XRenderComposite (xdisplay,
+ PictOpSrc,
+ src,
+ tmp,
+ dst,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ d.width, d.height);
+
+ XRenderFreePicture (xdisplay, tmp);
+ XRenderFreePicture (xdisplay, dst);
+ XRenderFreePicture (xdisplay, src);
+
+ gdk_pixmap_unref (pixmap);
+
+ g_free (params);
+
+ shadow_pixmap = d.pixmap;
+
+ return 1;
+}
+
+static void
+style_changed (GtkWidget *widget)
+{
+ GdkDisplay *gdkdisplay;
+ GdkScreen *gdkscreen;
+ WnckScreen *screen;
+ GList *windows;
+
+ gdkdisplay = gdk_display_get_default ();
+ gdkscreen = gdk_display_get_default_screen (gdkdisplay);
+ screen = wnck_screen_get_default ();
+
+ update_style (widget);
+
+ update_default_decorations (gdkscreen);
+
+ if (minimal)
+ return;
+
+ windows = wnck_screen_get_windows (screen);
+ while (windows != NULL)
+ {
+ decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
+
+ if (d->decorated)
+ {
+ /* force size update */
+ d->width = d->height = 0;
+
+ update_window_decoration_size (WNCK_WINDOW (windows->data));
+ update_event_windows (WNCK_WINDOW (windows->data));
+ }
+ windows = windows->next;
+ }
+}
+
+static const PangoFontDescription *
+get_titlebar_font (void)
+{
+ if (use_system_font)
+ {
+ return NULL;
+ }
+ else
+ return titlebar_font;
+}
+
+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
+double_click_titlebar_changed (GConfClient *client)
+{
+ gchar *action;
+
+ double_click_action = DOUBLE_CLICK_MAXIMIZE;
+
+ action = gconf_client_get_string (client,
+ COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY,
+ NULL);
+ if (action)
+ {
+ if (strcmp (action, "toggle_shade") == 0)
+ double_click_action = DOUBLE_CLICK_SHADE;
+ else if (strcmp (action, "toggle_maximize") == 0)
+ double_click_action = DOUBLE_CLICK_MAXIMIZE;
+
+ g_free (action);
+ }
+}
+
+#ifdef USE_METACITY
+static gint
+meta_calc_titlebar_height (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);
+
+ return top_height - _win_extents.top;
+}
+#endif
+
+static 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));
+
+ titlebar_height = (*theme_calc_titlebar_height) (text_height);
+
+ pango_font_metrics_unref (metrics);
+}
+
+static gboolean
+shadow_settings_changed (GConfClient *client)
+{
+ double radius, opacity;
+ int offset;
+ gboolean changed = FALSE;
+
+ radius = gconf_client_get_float (client,
+ COMPIZ_SHADOW_RADIUS_KEY,
+ NULL);
+ radius = MAX (0.0, MIN (radius, 48.0));
+ if (shadow_radius != radius)
+ {
+ shadow_radius = radius;
+ changed = TRUE;
+ }
+
+ opacity = gconf_client_get_float (client,
+ COMPIZ_SHADOW_OPACITY_KEY,
+ NULL);
+ opacity = MAX (0.0, MIN (opacity, 6.0));
+ if (shadow_opacity != opacity)
+ {
+ shadow_opacity = opacity;
+ changed = TRUE;
+ }
+
+ offset = gconf_client_get_int (client,
+ COMPIZ_SHADOW_OFFSET_X_KEY,
+ NULL);
+ offset = MAX (-16, MIN (offset, 16));
+ if (shadow_offset_x != offset)
+ {
+ shadow_offset_x = offset;
+ changed = TRUE;
+ }
+
+ offset = gconf_client_get_int (client,
+ COMPIZ_SHADOW_OFFSET_Y_KEY,
+ NULL);
+ offset = MAX (-16, MIN (offset, 16));
+ if (shadow_offset_y != offset)
+ {
+ shadow_offset_y = offset;
+ changed = TRUE;
+ }
+
+ return changed;
+}
+
+static void
+bell_settings_changed (GConfClient *client)
+{
+ gboolean audible, visual, fullscreen;
+ gchar *type;
+
+ audible = gconf_client_get_bool (client,
+ META_AUDIBLE_BELL_KEY,
+ NULL);
+
+ visual = gconf_client_get_bool (client,
+ META_VISUAL_BELL_KEY,
+ NULL);
+
+ type = gconf_client_get_string (client,
+ META_VISUAL_BELL_TYPE_KEY,
+ NULL);
+
+ if (type && strcmp (type, "fullscreen") == 0)
+ fullscreen = TRUE;
+ else
+ fullscreen = FALSE;
+
+ g_free (type);
+
+ gconf_client_set_bool (client,
+ COMPIZ_AUDIBLE_BELL_KEY,
+ audible,
+ NULL);
+
+ gconf_client_set_bool (client,
+ COMPIZ_VISUAL_BELL_KEY,
+ visual,
+ NULL);
+
+ gconf_client_set_bool (client,
+ COMPIZ_FULLSCREEN_VISUAL_BELL_KEY,
+ fullscreen,
+ NULL);
+}
+
+static gboolean
+theme_changed (GConfClient *client)
+{
+ 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 ())
+ g_warning("Couldn't set metacity theme?");
+
+ g_free (theme);
+ }
+ else
+ {
+ g_warning("No metacity theme set?");
+ }
+ theme_draw_window_decoration = meta_draw_window_decoration;
+ theme_calc_decoration_size = meta_calc_decoration_size;
+ theme_calc_titlebar_height = meta_calc_titlebar_height;
+ theme_get_button_position = meta_get_button_position;
+ return TRUE;
+}
+
+static gboolean
+theme_opacity_changed (GConfClient *client)
+{
+
+#ifdef USE_METACITY
+ gboolean shade_opacity, changed = FALSE;
+ gdouble opacity;
+
+ opacity =1.0;
+ /*= gconf_client_get_float (client,
+ META_THEME_OPACITY_KEY,
+ NULL);*/
+
+ if (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 (shade_opacity != meta_shade_opacity)
+ {
+ meta_shade_opacity = shade_opacity;
+ changed = TRUE;
+ }
+ }
+
+ opacity = 1.0;
+ /*gconf_client_get_float (client,
+ META_THEME_ACTIVE_OPACITY_KEY,
+ NULL);*/
+
+ if (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 (shade_opacity != meta_active_shade_opacity)
+ {
+ meta_active_shade_opacity = shade_opacity;
+ changed = TRUE;
+ }
+ }
+
+ return changed;
+#else
+ return FALSE;
+#endif
+
+}
+
+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)
+ {
+ double_click_titlebar_changed (client);
+ }
+ else if (strcmp (key, COMPIZ_SHADOW_RADIUS_KEY) == 0 ||
+ strcmp (key, COMPIZ_SHADOW_OPACITY_KEY) == 0 ||
+ strcmp (key, COMPIZ_SHADOW_OFFSET_X_KEY) == 0 ||
+ strcmp (key, COMPIZ_SHADOW_OFFSET_Y_KEY) == 0)
+ {
+ if (shadow_settings_changed (client))
+ changed = TRUE;
+ }
+ else if (strcmp (key, META_AUDIBLE_BELL_KEY) == 0 ||
+ strcmp (key, META_VISUAL_BELL_KEY) == 0 ||
+ strcmp (key, META_VISUAL_BELL_TYPE_KEY) == 0)
+ {
+ bell_settings_changed (client);
+ }
+ else if (
+ strcmp (key, META_THEME_KEY) == 0)
+ {
+ if (theme_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)
+ {
+ GdkDisplay *gdkdisplay;
+ GdkScreen *gdkscreen;
+ WnckScreen *screen = data;
+ GList *windows;
+
+ gdkdisplay = gdk_display_get_default ();
+ gdkscreen = gdk_display_get_default_screen (gdkdisplay);
+
+ update_titlebar_font ();
+ update_shadow ();
+
+ update_default_decorations (gdkscreen);
+
+ if (minimal)
+ return;
+
+ windows = wnck_screen_get_windows (screen);
+ while (windows != NULL)
+ {
+ decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
+
+ if (d->decorated)
+ {
+ d->width = d->height = 0;
+
+#ifdef USE_METACITY
+ if (
+ d->draw == meta_draw_window_decoration)
+ d->draw = theme_draw_window_decoration;
+#endif
+
+ update_window_decoration_size (WNCK_WINDOW (windows->data));
+ update_event_windows (WNCK_WINDOW (windows->data));
+ }
+ windows = windows->next;
+ }
+ }
+}
+
+static gboolean
+init_settings (WnckScreen *screen)
+{
+ GtkSettings *settings;
+ GConfClient *gconf;
+ GdkScreen *gdkscreen;
+ GdkColormap *colormap;
+
+ 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);
+
+ gconf_client_add_dir (gconf,
+ COMPIZ_GCONF_DIR1,
+ GCONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ gconf_client_add_dir (gconf,
+ COMPIZ_GCONF_DIR2,
+ GCONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ gconf_client_add_dir (gconf,
+ COMPIZ_GCONF_DIR3,
+ GCONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ g_signal_connect (G_OBJECT (gconf),
+ "value_changed",
+ G_CALLBACK (value_changed),
+ screen);
+
+ style_window = 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, colormap);
+
+ gtk_widget_realize (style_window);
+
+ g_signal_connect_object (style_window, "style-set",
+ G_CALLBACK (style_changed),
+ 0, 0);
+
+ settings = gtk_widget_get_settings (style_window);
+
+ g_object_get (G_OBJECT (settings), "gtk-double-click-time",
+ &double_click_timeout, NULL);
+
+ pango_context = gtk_widget_create_pango_context (style_window);
+
+ use_system_font = gconf_client_get_bool (gconf,
+ COMPIZ_USE_SYSTEM_FONT_KEY,
+ NULL);
+
+ theme_changed (gconf);
+ theme_opacity_changed (gconf);
+ update_style (style_window);
+ titlebar_font_changed (gconf);
+ update_titlebar_font ();
+ double_click_titlebar_changed (gconf);
+ shadow_settings_changed (gconf);
+ bell_settings_changed (gconf);
+ update_shadow ();
+
+ return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GdkDisplay *gdkdisplay;
+ Display *xdisplay;
+ GdkScreen *gdkscreen;
+ WnckScreen *screen;
+ gint i, j;
+ gboolean replace = FALSE;
+
+ program_name = argv[0];
+
+ gtk_init (&argc, &argv);
+
+ 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], "--help") == 0)
+ {
+ fprintf (stderr, "%s [--minimal] [--replace] [--help]\n",
+ program_name);
+ return 0;
+ }
+ }
+
+ gdkdisplay = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
+ gdkscreen = gdk_display_get_default_screen (gdkdisplay);
+
+ frame_window_atom = XInternAtom (xdisplay, "_NET_FRAME_WINDOW", FALSE);
+ win_decor_atom = XInternAtom (xdisplay, "_NET_WINDOW_DECOR", 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, "_SWITCH_SELECT_WINDOW",
+ FALSE);
+ mwm_hints_atom = XInternAtom (xdisplay, "_MOTIF_WM_HINTS", FALSE);
+
+ toolkit_action_atom =
+ XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION", FALSE);
+ toolkit_action_main_menu_atom =
+ XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION_MAIN_MENU", FALSE);
+ toolkit_action_run_dialog_atom =
+ XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION_RUN_DIALOG", 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);
+
+ panel_action_atom =
+ XInternAtom (xdisplay, "_GNOME_PANEL_ACTION", FALSE);
+ panel_action_main_menu_atom =
+ XInternAtom (xdisplay, "_GNOME_PANEL_ACTION_MAIN_MENU", FALSE);
+ panel_action_run_dialog_atom =
+ XInternAtom (xdisplay, "_GNOME_PANEL_ACTION_RUN_DIALOG", FALSE);
+
+ manager_atom = XInternAtom (xdisplay, "MANAGER", FALSE);
+ targets_atom = XInternAtom (xdisplay, "TARGETS", FALSE);
+ multiple_atom = XInternAtom (xdisplay, "MULTIPLE", FALSE);
+ timestamp_atom = XInternAtom (xdisplay, "TIMESTAMP", FALSE);
+ version_atom = XInternAtom (xdisplay, "VERSION", FALSE);
+ atom_pair_atom = XInternAtom (xdisplay, "ATOM_PAIR", FALSE);
+
+ utf8_string_atom = XInternAtom (xdisplay, "UTF8_STRING", FALSE);
+
+ dm_name_atom = XInternAtom (xdisplay, "_NET_DM_NAME", FALSE);
+
+ if (!acquire_dm_session (xdisplay, 0, replace))
+ 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);
+ }
+ }
+
+ frame_table = g_hash_table_new (NULL, NULL);
+
+ if (!create_tooltip_window ())
+ {
+ fprintf (stderr, "%s, Couldn't create tooltip window\n", argv[0]);
+ return 1;
+ }
+
+ screen = wnck_screen_get_default ();
+
+ gdk_window_add_filter (NULL,
+ selection_event_filter_func,
+ NULL);
+
+ if (!minimal)
+ {
+ gdk_window_add_filter (NULL,
+ event_filter_func,
+ NULL);
+
+ connect_screen (screen);
+ }
+
+ if (!init_settings (screen))
+ {
+ fprintf (stderr, "%s: Failed to get necessary gtk settings\n", argv[0]);
+ return 1;
+ }
+
+ set_dm_check_hint (gdk_display_get_default_screen (gdkdisplay));
+
+ update_default_decorations (gdkscreen);
+
+ gtk_main ();
+
+ return 0;
+}