summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2007-04-08 22:00:20 -0400
committerRay Strode <rstrode@redhat.com>2007-04-08 22:00:20 -0400
commitcb0925c5702c5fe76fe02cddf399fc7b9fec3416 (patch)
tree80abb2d54ec154b3cb0395a8c511ebbf0c31d0c0
parentbb78615a633823720139d7a62e1e1b9c8f5364e1 (diff)
parent6896d3d790755ef7d0972c64254378eb13481efe (diff)
Merge branch 'event-rewrite'master
Conflicts: pop-window.c
-rw-r--r--AUTHORS1
-rw-r--r--COPYING340
-rw-r--r--ChangeLog0
-rw-r--r--FIGURING-OUT-WHAT-TO-REDRAW41
-rw-r--r--INSTALL0
-rw-r--r--Makefile3
-rw-r--r--Makefile.am27
-rw-r--r--NEWS0
-rw-r--r--README0
-rw-r--r--TODO11
-rwxr-xr-xautogen.sh6
-rw-r--r--configure.ac44
-rw-r--r--po/ChangeLog0
-rw-r--r--po/POTFILES.in7
-rw-r--r--po/POTFILES.skip0
-rw-r--r--pop-demo.c301
-rw-r--r--pop-window.c723
-rw-r--r--pop-window.h79
-rwxr-xr-xscripts/new-object.sh387
-rw-r--r--src/Makefile.am29
-rw-r--r--src/pop-demo.c437
-rw-r--r--src/pop-event-listener.c1165
-rw-r--r--src/pop-event-listener.h88
-rw-r--r--src/pop-marshal.list2
-rw-r--r--src/pop-overlay-window.c (renamed from pop-overlay-window.c)4
-rw-r--r--src/pop-overlay-window.h (renamed from pop-overlay-window.h)0
-rw-r--r--src/pop-window-stack.c492
-rw-r--r--src/pop-window-stack.h83
-rw-r--r--src/pop-window-view.c1061
-rw-r--r--src/pop-window-view.h83
30 files changed, 4306 insertions, 1108 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..6b4438d
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Ray Strode <rstrode@redhat.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/FIGURING-OUT-WHAT-TO-REDRAW b/FIGURING-OUT-WHAT-TO-REDRAW
new file mode 100644
index 0000000..d8d32cf
--- /dev/null
+++ b/FIGURING-OUT-WHAT-TO-REDRAW
@@ -0,0 +1,41 @@
+Right now every toplevel (direct descendent of a root window) window is
+given an associated "view". The view is responsible for translating the
+various offscreen window events to some on screen representation. In
+it's current form that means just showing the window exactly as it was
+before, verbatim. Eventually it will also mean doing translucency and
+animations.
+
+One interesting property of the views is that they track window
+"damage". That means that they know when parts of their windows get
+drawn off screen. The views should take advantage of this to only
+update the on screen area that corresponds to the offscreen area that
+got redrawn (the damaged areas).
+
+Also, in order to facilitate a reasonable amount of large-sized windows,
+we need to make sure that views that are completely occluded are
+properly culled and not drawn. Figuring out the proper culling logic is
+a bit tricky, because only the view knows its geometry at any given
+instant, and each view doesn't know the geometry or relative stacking
+order and opacity of its siblings.
+
+One possible way to solve the problem is to institute a sort comparison
+function that returns the difference of two views. This function would
+return an area that encompasses the part of the first view that doesn't
+overlap with the second view. In addition, the area would need to
+account for (I mean, include) overlapping areas where the second view isn't
+fully opaque. To figure out which part of a given view needs to be
+redrawn, the application would call the comparison function for that
+view against all of the views that are higher in the stack than it. The
+view's initial bounding area would be intersected with each run of the
+comparison function, and the remaining area is the area that isn't
+occluded. This area should get passed to the view when requesting it
+render itself. It would then only redraw damaged areas within the
+passed in area.
+
+It's important that the application keep a list of views with windows
+that have been recently damaged and only do the comparison on those views
+and on views that been recently exposed because of a higher stacked view
+moving.
+
+Also, the final rendered output of any given run should be
+cached and redrawn initially next time around.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/INSTALL
diff --git a/Makefile b/Makefile
deleted file mode 100644
index a2d8a44..0000000
--- a/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-all:
- gcc pop-overlay-window.c pop-window.c pop-demo.c -o pop-demo `pkg-config --cflags --libs glib-2.0 gtk+-2.0 cairo cairo-xlib xcomposite xdamage ` -ggdb3 -O0
-
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e1babde
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,27 @@
+SUBDIRS = src po
+
+EXTRA_DIST = ChangeLog \
+ README \
+ intltool-extract.in \
+ intltool-merge.in \
+ intltool-update.in
+
+DISTCLEANFILES = intltool-extract \
+ intltool-merge \
+ intltool-update
+
+MAINTAINERCLEANFILES = aclocal.m4 \
+ compile \
+ config.guess \
+ config.h.in \
+ config.h.in~ \
+ config.sub \
+ configure \
+ depcomp \
+ install-sh \
+ intltool-extract.in \
+ intltool-merge.in \
+ intltool-update.in \
+ ltmain.sh \
+ Makefile.in \
+ missing
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..e1ec5eb
--- /dev/null
+++ b/TODO
@@ -0,0 +1,11 @@
+- make event listener support multiple screens
+- fix window stack to only XQueryTree the root once and then
+ update the list from X events
+- get rid of the junk test pop-demo.c file and come up with a real
+ program
+- remove some of the commented out boilerplate created from the
+ object generator script
+- don't repaint every window on every damage event
+- advertise the _NET_WM_CM selection
+- add some of the common effects found in compositing managers (drop shadows,
+animations (?), support for tranlucency)
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..2c5bd8a
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+(cd $(dirname $0);
+ autoreconf --install --symlink;
+ intltoolize --force;
+ ./configure --enable-maintainer-mode $@)
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..5912c18
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,44 @@
+# the versioning scheme is 0.0.1-unstable
+# followed by 0.1.0 for initial release
+# followed by 0.1.0-stable and 0.1.0-unstable
+# followed by 0.1.1 and 0.2.0
+# followed by 0.1.1-stable and 0.2.0-unstable
+# etc., etc.
+AC_INIT(pop, 0.0.1-unstable, "rstrode@redhat.com")
+AC_CONFIG_SRCDIR(src/pop-demo.c)
+AC_CONFIG_HEADER(config.h)
+
+AC_PROG_AWK
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_HEADER_STDC
+AC_C_CONST
+
+AM_INIT_AUTOMAKE([dist-bzip2])
+AM_MAINTAINER_MODE
+
+GETTEXT_PACKAGE=pop
+AC_DEFINE([GETTEXT_PACKAGE], [], "a toy compositing manager")
+AC_SUBST(GETTEXT_PACKAGE)
+AM_GLIB_GNU_GETTEXT
+ALL_LINGUAS=""
+
+IT_PROG_INTLTOOL
+PKG_PROG_PKG_CONFIG
+
+PKG_CHECK_MODULES(POP, [glib-2.0 >= 2.12.11
+ gtk+-2.0 >= 2.10.11
+ cairo >= 1.4.2
+ cairo-xlib >= 1.4.2
+ xcomposite >= 0.3.1
+ xdamage >= 1.1.1
+])
+AC_SUBST(POP_CFLAGS)
+AC_SUBST(POP_LIBS)
+
+AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
+
+AC_OUTPUT([Makefile
+ src/Makefile
+ po/Makefile.in
+])
diff --git a/po/ChangeLog b/po/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/po/ChangeLog
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..a608b0b
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,7 @@
+[encoding: UTF-8]
+src/pop-event-listener.c
+src/pop-window-view.c
+src/pop-overlay-window.c
+src/pop-marshal.c
+src/pop-window-stack.c
+src/pop-demo.c
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/po/POTFILES.skip
diff --git a/pop-demo.c b/pop-demo.c
deleted file mode 100644
index 3286034..0000000
--- a/pop-demo.c
+++ /dev/null
@@ -1,301 +0,0 @@
-#include <unistd.h>
-
-#include <glib.h>
-
-#include <X11/extensions/Xcomposite.h>
-#include <X11/extensions/Xdamage.h>
-#include <X11/extensions/Xfixes.h>
-
-#include <cairo.h>
-#include <cairo-xlib.h>
-
-#include <gdk/gdk.h>
-#include <gdk/gdkcairo.h>
-#include <gdk/gdkx.h>
-
-#include "pop-overlay-window.h"
-#include "pop-window.h"
-
-static GList *window_list = NULL;
-
-static int damage_extension_event_base,
- damage_extension_error_base;
-
-static int shape_extension_event_base,
- shape_extension_error_base;
-
-static gboolean
-composite_is_available (void)
-{
- int event_base, error_base;
-
- event_base = 0;
- error_base = 0;
- if (XCompositeQueryExtension (GDK_DISPLAY (), &event_base, &error_base))
- return TRUE;
- return FALSE;
-}
-
-static gboolean
-initialize_damage_extension (void)
-{
- if (XDamageQueryExtension (GDK_DISPLAY (), &damage_extension_event_base,
- &damage_extension_error_base))
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean
-initialize_shape_extension (void)
-{
- if (XShapeQueryExtension (GDK_DISPLAY (), &shape_extension_event_base,
- &shape_extension_error_base))
- return TRUE;
-
- return FALSE;
-}
-
-static void
-draw_windows (cairo_t *cairo_context)
-{
- GList *tmp;
-
- for (tmp = window_list; tmp != NULL; tmp = tmp->next)
- pop_window_draw (POP_WINDOW (tmp->data), cairo_context);
-}
-
-gint
-window_compare (PopWindow *window_1,
- Window *x_window_id)
-{
- if (!POP_IS_WINDOW (window_1))
- {
- g_warning ("passed invalid data to compare func: %p\n", window_1);
- return -1;
- }
- return ((gulong) pop_window_get_x_window_id (window_1))
- - *x_window_id;
-}
-
-static PopWindow *
-find_window_from_x_window_id (Window x_window_id)
-{
-
- GList *node;
-
- node = g_list_find_custom (window_list, &x_window_id,
- (GCompareFunc) window_compare);
-
- if (node == NULL)
- return NULL;
-
- return (PopWindow *) node->data;
-}
-
-static void
-add_window_to_list (Window x_window_id)
-{
- PopWindow *window;
- XWindowAttributes attributes;
-
- if (!XGetWindowAttributes (GDK_DISPLAY (), x_window_id, &attributes))
- return;
-
- if (attributes.class == InputOnly)
- return;
-
- window = pop_window_new (x_window_id);
- gtk_widget_realize (GTK_WIDGET (window));
- window_list = g_list_append (window_list, window);
-}
-
-static void
-remove_window_from_list (Window x_window_id)
-{
- PopWindow *window;
-
- window = find_window_from_x_window_id (x_window_id);
-
- if (window == NULL)
- return;
-
- g_assert (POP_IS_WINDOW (window));
-
- window_list = g_list_remove (window_list, window);
- gtk_widget_destroy (GTK_WIDGET (window));
-}
-
-static void
-get_initial_window_list (void)
-{
- Window root, parent;
- Window *x_window_ids;
- guint number_of_windows, i;
-
- gdk_x11_grab_server ();
- if (!XQueryTree (GDK_DISPLAY (),
- GDK_ROOT_WINDOW (), &root, &parent,
- &x_window_ids, &number_of_windows))
- {
- gdk_x11_ungrab_server ();
- return;
- }
-
- for (i = 0; i < number_of_windows; i++)
- {
- if (!find_window_from_x_window_id (x_window_ids[i]))
- add_window_to_list (x_window_ids[i]);
- }
-
- XFree (x_window_ids);
- gdk_x11_ungrab_server ();
-}
-
-static gboolean
-on_expose_event (GtkWidget *widget,
- GdkEventExpose *event)
-{
- cairo_t *cairo_context;
-
- cairo_context = gdk_cairo_create (widget->window);
- cairo_set_source_rgb (cairo_context, 0.5, 0.5, 0.6);
- cairo_paint (cairo_context);
- draw_windows (cairo_context);
- cairo_destroy (cairo_context);
-
- return FALSE;
-}
-
-static void
-on_map (GtkWidget *widget)
-{
- /* redirect the direct descendents of root window (all toplevels)
- * I think that the overlay window is automatically excluded even
- * though it is a toplevel (which makes sense). It's the window we
- * are going to be outputing the redirecting windows to, so it shouldn't
- * be redirected itself.
- */
- XCompositeRedirectSubwindows (GDK_DISPLAY (),
- GDK_ROOT_WINDOW (),
- CompositeRedirectManual);
- get_initial_window_list ();
-}
-
-static void
-on_damage_event (XDamageNotifyEvent *damage_event,
- PopOverlayWindow *overlay_window)
-{
- GdkDisplay *display;
- PopWindow *window;
- Window x_window_id;
-
- x_window_id = (Window) damage_event->drawable;
- window = find_window_from_x_window_id (x_window_id);
-
- gdk_error_trap_push ();
-
- XDamageSubtract (GDK_DISPLAY (),
- damage_event->damage,
- None, None);
-
- gdk_flush ();
- gdk_error_trap_pop ();
-
- if (window == NULL)
- return;
-
- gtk_widget_queue_draw (GTK_WIDGET (overlay_window));
-}
-
-static void
-on_create_window_event (XCreateWindowEvent *window_event,
- PopOverlayWindow *overlay_window)
-{
- g_assert (window_event->parent == GDK_ROOT_WINDOW ());
- add_window_to_list (window_event->window);
-}
-
-static void
-on_destroy_window_event (XDestroyWindowEvent *window_event,
- PopOverlayWindow *overlay_window)
-{
- remove_window_from_list (window_event->window);
- gtk_widget_queue_draw (GTK_WIDGET (overlay_window));
-}
-
-static gboolean
-x_event_is_damage_event (XEvent *x_event)
-{
- return x_event->type == damage_extension_event_base + XDamageNotify;
-}
-
-static gboolean
-x_event_is_create_window_event (XEvent *x_event)
-{
- return x_event->type == CreateNotify;
-}
-
-static gboolean
-x_event_is_destroy_window_event (XEvent *x_event)
-{
- return x_event->type == DestroyNotify;
-}
-
-static GdkFilterReturn
-on_event (XEvent *x_event,
- GdkEvent *event,
- PopOverlayWindow *overlay_window)
-{
- if (x_event_is_damage_event (x_event))
- on_damage_event ((XDamageNotifyEvent *) x_event, overlay_window);
- else if (x_event_is_create_window_event (x_event))
- on_create_window_event ((XCreateWindowEvent *) x_event, overlay_window);
- else if (x_event_is_destroy_window_event (x_event))
- on_destroy_window_event ((XDestroyWindowEvent *) x_event, overlay_window);
-
-
- return GDK_FILTER_CONTINUE;
-}
-
-int
-main (int argc,
- char **argv)
-{
- GtkWidget *overlay_window;
- GdkWindow *root_window;
-
- gtk_init (&argc, &argv);
-
- if (!composite_is_available ())
- {
- g_printerr ("composite extension not found\n");
- return 1;
- }
-
- if (!initialize_damage_extension ())
- {
- g_printerr ("damage extension not found\n");
- return 2;
- }
-
- initialize_shape_extension ();
-
- overlay_window = pop_overlay_window_new ();
- gtk_container_set_border_width (GTK_CONTAINER (overlay_window), 200);
-
- g_signal_connect (G_OBJECT (overlay_window), "expose-event",
- G_CALLBACK (on_expose_event), NULL);
- g_signal_connect (G_OBJECT (overlay_window), "map",
- G_CALLBACK (on_map), NULL);
-
- root_window = gdk_get_default_root_window ();
- gdk_window_set_events (root_window, GDK_SUBSTRUCTURE_MASK);
- gdk_window_add_filter (NULL, (GdkFilterFunc) on_event, overlay_window);
-
- gtk_widget_show (overlay_window);
-
- gtk_main();
-
- return 0;
-}
diff --git a/pop-window.c b/pop-window.c
deleted file mode 100644
index f35adc2..0000000
--- a/pop-window.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/* pop-window.c -
- *
- * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
- *
- * 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-#include "pop-window.h"
-
-#include <errno.h>
-#include <string.h>
-
-#include <glib.h>
-#include <glib-object.h>
-#include <glib/gi18n.h>
-
-#include <cairo.h>
-
-#include <X11/extensions/Xcomposite.h>
-#include <X11/extensions/Xdamage.h>
-#include <X11/extensions/shape.h>
-
-#include <cairo-xlib.h>
-#include <gdk/gdkx.h>
-
-#include <gdk/gdk.h>
-
-#include <gtk/gtk.h>
-
-struct _PopWindowPrivate
-{
- Window x_window_id;
- Damage x_damage_id;
- cairo_pattern_t *cairo_pattern;
- cairo_path_t *cairo_clip_path;
-};
-
-#if 0
-static void pop_window_class_install_signals (PopWindowClass * window_class);
-#endif
-static void pop_window_class_install_properties (PopWindowClass *
- window_class);
-
-static void pop_window_set_property (GObject * object,
- guint prop_id,
- const GValue * value,
- GParamSpec * pspec);
-static void pop_window_get_property (GObject * object,
- guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void pop_window_set_x_window_id (PopWindow *window,
- Window x_window_id);
-
-static void pop_window_do_finalize (GObject *object);
-static void pop_window_do_realize (GtkWidget *widget);
-static void pop_window_do_unrealize (GtkWidget *widget);
-static gboolean pop_window_do_configure_event (GtkWidget *widget,
- GdkEventConfigure *configure_event);
-static gboolean pop_window_do_map_event (GtkWidget *widget,
- GdkEventAny *event);
-static gboolean pop_window_do_unmap_event (GtkWidget *widget,
- GdkEventAny *event);
-
-enum
-{
- PROP_0 = 0,
- PROP_X_WINDOW_ID
-};
-
-#define POP_WINDOW_INVALID_X_WINDOW_ID (Window) 0
-#define POP_WINDOW_INVALID_X_PIXMAP_ID (Pixmap) 0
-#define POP_WINDOW_INVALID_X_DAMAGE_ID (Damage) 0
-
-#if 0
-enum
-{
- FOO = 0,
- NUMBER_OF_SIGNALS
-};
-
-static guint pop_window_signals[NUMBER_OF_SIGNALS];
-#endif
-
-G_DEFINE_TYPE (PopWindow, pop_window, GTK_TYPE_INVISIBLE);
-
-static void
-pop_window_class_init (PopWindowClass *window_class)
-{
- GObjectClass *object_class;
- GtkWidgetClass *widget_class;
-
- object_class = G_OBJECT_CLASS (window_class);
- widget_class = GTK_WIDGET_CLASS (window_class);
-
- object_class->finalize = pop_window_do_finalize;
-
- widget_class->configure_event = pop_window_do_configure_event;
- widget_class->map_event = pop_window_do_map_event;
- widget_class->unmap_event = pop_window_do_unmap_event;
- widget_class->realize = pop_window_do_realize;
-
- pop_window_class_install_properties (window_class);
-#if 0
- pop_window_class_install_signals (window_class);
-#endif
-
- g_type_class_add_private (window_class, sizeof (PopWindowPrivate));
-}
-
-#if 0
-static void
-pop_window_class_install_signals (PopWindowClass * window_class)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (window_class);
-
- pop_window_signals[FOO] =
- g_signal_new ("foo", G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PopWindowClass, foo),
- NULL, NULL, g_cclosure_marshal_VOID__NONE; G_TYPE_NONE, 0);
- window_class->foo = NULL;
-}
-#endif
-
-static void
-pop_window_class_install_properties (PopWindowClass *window_class)
-{
- GObjectClass *object_class;
- GParamSpec *param_spec;
-
- object_class = G_OBJECT_CLASS (window_class);
- object_class->set_property = pop_window_set_property;
- object_class->get_property = pop_window_get_property;
-
- param_spec = g_param_spec_ulong ("x-window-id", _("X Window ID"),
- _("A client-side identifier representing a "
- "server-side window"), 0, G_MAXULONG,
- (gulong) POP_WINDOW_INVALID_X_WINDOW_ID,
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
- g_object_class_install_property (object_class, PROP_X_WINDOW_ID, param_spec);
-}
-
-static gboolean
-pop_window_enable_damage_reporting (PopWindow *window)
-{
- GtkWidget *widget;
-
- g_assert (POP_IS_WINDOW (window));
-
- widget = GTK_WIDGET (window);
-
- gdk_error_trap_push ();
- window->priv->x_damage_id =
- XDamageCreate (GDK_WINDOW_XDISPLAY (widget->window),
- window->priv->x_window_id,
- XDamageReportNonEmpty);
- gdk_flush ();
- if (gdk_error_trap_pop ())
- return FALSE;
-
- return TRUE;
-}
-
-static void
-pop_window_disable_damage_reporting (PopWindow *window)
-{
- GtkWidget *widget;
-
- g_assert (POP_IS_WINDOW (window));
-
- widget = GTK_WIDGET (window);
-
- gdk_error_trap_push ();
- XDamageDestroy (GDK_WINDOW_XDISPLAY (widget->window),
- window->priv->x_damage_id);
- window->priv->x_damage_id = POP_WINDOW_INVALID_X_DAMAGE_ID;
-
- gdk_flush ();
- gdk_error_trap_pop ();
-}
-
-static void
-pop_window_init (PopWindow *window)
-{
- g_assert (POP_IS_WINDOW (window));
-
- window->priv = G_TYPE_INSTANCE_GET_PRIVATE (window,
- POP_TYPE_WINDOW,
- PopWindowPrivate);
-}
-
-static void
-pop_window_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- PopWindow *window = POP_WINDOW (object);
-
- switch (prop_id)
- {
- case PROP_X_WINDOW_ID:
- pop_window_set_x_window_id (window, (Window) g_value_get_ulong (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-pop_window_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PopWindow *window = POP_WINDOW (object);
-
- switch (prop_id)
- {
- case PROP_X_WINDOW_ID:
- g_value_set_ulong (value, (gulong) pop_window_get_x_window_id (window));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-pop_window_do_finalize (GObject *object)
-{
- PopWindow *window;
- GObjectClass *parent_class;
-
- window = POP_WINDOW (object);
-
- parent_class = G_OBJECT_CLASS (pop_window_parent_class);
-
- if (parent_class->finalize != NULL)
- parent_class->finalize (object);
-}
-
-static Pixmap
-pop_window_fetch_x_pixmap_id (PopWindow *window)
-{
- GtkWidget *widget;
- Pixmap x_pixmap_id;
-
- g_assert (POP_IS_WINDOW (window));
- g_assert (GTK_WIDGET (window)->window != NULL);
-
- widget = GTK_WIDGET (window);
-
- gdk_error_trap_push ();
- x_pixmap_id =
- XCompositeNameWindowPixmap (GDK_WINDOW_XDISPLAY (widget->window),
- window->priv->x_window_id);
- gdk_flush();
- if (gdk_error_trap_pop ())
- return POP_WINDOW_INVALID_X_PIXMAP_ID;
-
- return x_pixmap_id;
-}
-
-static cairo_surface_t *
-pop_window_get_cairo_surface (PopWindow *window)
-{
- cairo_surface_t *surface;
- cairo_status_t status;
-
- g_assert (POP_IS_WINDOW (window));
- g_assert (window->priv->cairo_pattern != NULL);
-
- surface = NULL;
- status = cairo_pattern_get_surface (window->priv->cairo_pattern, &surface);
- g_assert (status != CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
-
- return surface;
-}
-
-static void
-pop_window_free_x_pixmap (PopWindow *window)
-{
- GtkWidget *widget;
- cairo_surface_t *surface;
- Pixmap x_pixmap_id;
-
- g_assert (POP_IS_WINDOW (window));
-
- widget = GTK_WIDGET (window);
-
- if (widget->window == NULL)
- return;
-
- surface = pop_window_get_cairo_surface (window);
-
- g_assert (surface != NULL);
- x_pixmap_id = (Pixmap) cairo_xlib_surface_get_drawable (surface);
- XFreePixmap (GDK_WINDOW_XDISPLAY (widget->window), x_pixmap_id);
-}
-
-static void
-pop_window_create_cairo_pattern_from_x_pixmap_id (PopWindow *window,
- Pixmap x_pixmap_id)
-{
- GtkWidget *widget;
- GdkVisual *visual;
- cairo_surface_t *surface;
- int width, height;
-
- g_assert (POP_IS_WINDOW (window));
- g_assert (GTK_WIDGET (window)->window != NULL);
- g_assert (window->priv->cairo_pattern == NULL);
-
- widget = GTK_WIDGET (window);
- visual = gtk_widget_get_visual (widget);
-
- gdk_drawable_get_size (GDK_DRAWABLE (widget->window),
- &width, &height);
-
- surface = cairo_xlib_surface_create (GDK_WINDOW_XDISPLAY (widget->window),
- (Drawable) x_pixmap_id,
- GDK_VISUAL_XVISUAL (visual),
- width, height);
- window->priv->cairo_pattern = cairo_pattern_create_for_surface (surface);
- cairo_surface_destroy (surface);
-}
-
-static void
-pop_window_set_cairo_clip_path_from_x_rectangles (PopWindow *window,
- XRectangle *x_rectangles,
- int number_of_x_rectangles)
-{
- GtkWidget *widget;
- cairo_t *cairo_context;
- cairo_surface_t *surface;
- int width, height, i;
- int x, y;
-
- g_assert (POP_IS_WINDOW (window));
- g_assert (GTK_WIDGET (window) != NULL);
- g_assert (x_rectangles != NULL);
- g_assert (number_of_x_rectangles > 0);
-
- widget = GTK_WIDGET (window);
-
- if (window->priv->cairo_clip_path != NULL)
- cairo_path_destroy (window->priv->cairo_clip_path);
-
- gdk_drawable_get_size (GDK_DRAWABLE (widget->window),
- &width, &height);
- gdk_window_get_position (GTK_WIDGET (window)->window,
- &x, &y);
-
- surface = cairo_image_surface_create (CAIRO_FORMAT_A1,
- width, height);
- cairo_context = cairo_create (surface);
-
- for (i = 0; i < number_of_x_rectangles; i++)
- {
- cairo_rectangle (cairo_context,
- x + x_rectangles[i].x,
- y + x_rectangles[i].y,
- x_rectangles[i].width,
- x_rectangles[i].height);
- }
-
- window->priv->cairo_clip_path = cairo_copy_path_flat (cairo_context);
- cairo_destroy (cairo_context);
-}
-
-static void
-pop_window_create_cairo_pattern (PopWindow *window)
-{
- GtkWidget *widget;
- GdkVisual *visual;
- Pixmap x_pixmap_id;
- g_assert (POP_IS_WINDOW (window));
- g_assert (GTK_WIDGET (window)->window != NULL);
- g_assert (window->priv->cairo_pattern == NULL);
-
- widget = GTK_WIDGET (window);
-
- x_pixmap_id = pop_window_fetch_x_pixmap_id (window);
-
- if (x_pixmap_id == POP_WINDOW_INVALID_X_PIXMAP_ID)
- return;
-
- pop_window_create_cairo_pattern_from_x_pixmap_id (window, x_pixmap_id);
-}
-
-static gboolean
-pop_window_size_is_different (PopWindow *window)
-{
- GtkWidget *widget;
- cairo_surface_t *surface;
- gint old_window_width, old_window_height;
- gint window_width, window_height;
-
- g_assert (POP_IS_WINDOW (window));
- g_assert (window->priv->cairo_pattern != NULL);
-
- widget = GTK_WIDGET (window);
- surface = pop_window_get_cairo_surface (window);
-
- g_assert (surface != NULL);
- old_window_width = cairo_xlib_surface_get_width (surface);
- old_window_height = cairo_xlib_surface_get_height (surface);
-
- gdk_drawable_get_size (GDK_DRAWABLE (widget->window),
- &window_width, &window_height);
-
- if ((window_width != old_window_width)
- || (window_height != old_window_height))
- return TRUE;
-
- return FALSE;
-}
-
-static void
-pop_window_destroy_pattern (PopWindow *window)
-{
- g_assert (POP_IS_WINDOW (window));
- g_assert (window->priv->cairo_pattern != NULL);
-
- pop_window_free_x_pixmap (window);
- cairo_pattern_destroy (window->priv->cairo_pattern);
- window->priv->cairo_pattern = NULL;
-}
-
-static void
-pop_window_update_pattern_size (PopWindow *window)
-{
- GtkWidget *widget;
- Pixmap old_x_pixmap_id, x_pixmap_id;
- cairo_surface_t *surface;
- gint window_width, window_height;
-
- g_assert (POP_IS_WINDOW (window));
- g_assert (window->priv->cairo_pattern != NULL);
-
- widget = GTK_WIDGET (window);
- pop_window_free_x_pixmap (window);
- x_pixmap_id = pop_window_fetch_x_pixmap_id (window);
-
- if (x_pixmap_id == POP_WINDOW_INVALID_X_PIXMAP_ID)
- {
- pop_window_destroy_pattern (window);
- return;
- }
-
- gdk_drawable_get_size (GDK_DRAWABLE (widget->window),
- &window_width, &window_height);
-
- surface = pop_window_get_cairo_surface (window);
- g_assert (surface != NULL);
- cairo_xlib_surface_set_drawable (surface, (Drawable) x_pixmap_id,
- window_width, window_height);
-}
-
-static void
-pop_window_sync_pattern_with_server (PopWindow *window)
-{
- GtkWidget *widget;
- cairo_surface_t *surface;
- cairo_matrix_t matrix;
- gint x, y;
- XRectangle *x_rectangles;
- int ordering, number_of_x_rectangles;
-
- g_assert (POP_IS_WINDOW (window));
- g_assert (GTK_WIDGET (window)->window != NULL);
-
- widget = GTK_WIDGET (window);
-
- if (window->priv->cairo_pattern == NULL)
- pop_window_create_cairo_pattern (window);
- else if (pop_window_size_is_different (window))
- pop_window_update_pattern_size (window);
-
- if (window->priv->cairo_pattern == NULL)
- return;
-
- number_of_x_rectangles = 0;
- x_rectangles = XShapeGetRectangles (GDK_WINDOW_XDISPLAY (widget->window),
- window->priv->x_window_id,
- ShapeBounding, &number_of_x_rectangles,
- &ordering);
-
- if (number_of_x_rectangles > 0)
- pop_window_set_cairo_clip_path_from_x_rectangles (window,
- x_rectangles,
- number_of_x_rectangles);
- XFree (x_rectangles);
-
- gdk_window_get_position (GDK_WINDOW (widget->window), &x, &y);
- cairo_matrix_init_identity (&matrix);
- cairo_matrix_translate (&matrix, -x, -y);
- cairo_pattern_set_matrix (window->priv->cairo_pattern, &matrix);
-}
-
-static void
-pop_window_setup_gdk_window (PopWindow *window)
-{
- GtkWidget *widget;
-
- g_assert (POP_IS_WINDOW (window));
-
- widget = GTK_WIDGET (window);
-
- widget->window =
- gdk_window_foreign_new ((GdkNativeWindow) window->priv->x_window_id);
-
- if (widget->window == NULL)
- return;
-
- gdk_window_set_events (widget->window,
- GDK_STRUCTURE_MASK);
-
- XShapeInputSelected (GDK_WINDOW_XDISPLAY (widget->window),
- window->priv->x_window_id);
-
- gdk_window_set_user_data (widget->window, window);
-
- pop_window_sync_pattern_with_server (POP_WINDOW (widget));
- if (!pop_window_enable_damage_reporting (window))
- {
- gdk_window_destroy (widget->window);
- widget->window = NULL;
- }
-}
-
-static void
-pop_window_do_realize (GtkWidget *widget)
-{
- PopWindow *window;
-
- window = POP_WINDOW (widget);
-
- pop_window_setup_gdk_window (POP_WINDOW (widget));
-
- widget->style = gtk_style_attach (widget->style, widget->window);
- GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-}
-
-static void
-pop_window_do_unrealize (GtkWidget *widget)
-{
- PopWindow *window;
-
- window = POP_WINDOW (widget);
-
- if (widget->window == NULL)
- {
- gdk_window_destroy (widget->window);
- widget->window = NULL;
- }
-
- if (window->priv->cairo_pattern != NULL)
- pop_window_destroy_pattern (window);
-
- pop_window_disable_damage_reporting (window);
-
- GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
-}
-
-GQuark
-pop_window_error_quark (void)
-{
- static GQuark error_quark = 0;
-
- if (error_quark == 0)
- error_quark = g_quark_from_static_string ("pop-window");
-
- return error_quark;
-}
-
-PopWindow *
-pop_window_new (Window x_window_id)
-{
- PopWindow *window;
-
- window = g_object_new (POP_TYPE_WINDOW,
- "x-window-id", x_window_id, NULL);
-
- return window;
-}
-
-static void
-pop_window_disable_content_tracking (PopWindow *window)
-{
- GtkWidget *widget;
-
- g_assert (POP_IS_WINDOW (window));
-
- widget = GTK_WIDGET (window);
-
- if (window->priv->cairo_pattern != NULL)
- {
- gdk_error_trap_push ();
- pop_window_destroy_pattern (window);
- gdk_flush ();
- if (gdk_error_trap_pop ())
- {
- pop_window_disable_damage_reporting (window);
- gdk_window_destroy (widget->window);
- widget->window = NULL;
- }
- }
-}
-
-static gboolean
-pop_window_do_configure_event (GtkWidget *widget,
- GdkEventConfigure *configure_event)
-{
- PopWindow *window;
-
- g_assert (POP_IS_WINDOW (widget));
-
- window = POP_WINDOW (widget);
-
- gdk_error_trap_push ();
- pop_window_sync_pattern_with_server (window);
- gdk_flush ();
- if (gdk_error_trap_pop ())
- pop_window_disable_content_tracking (window);
-
- return FALSE;
-}
-
-static gboolean
-pop_window_do_map_event (GtkWidget *widget,
- GdkEventAny *event)
-{
- PopWindow *window;
-
- g_assert (POP_IS_WINDOW (widget));
-
- window = POP_WINDOW (widget);
-
- gdk_error_trap_push ();
- pop_window_sync_pattern_with_server (POP_WINDOW (widget));
- gdk_flush ();
- if (gdk_error_trap_pop ())
- pop_window_disable_content_tracking (window);
-}
-
-static gboolean
-pop_window_do_unmap_event (GtkWidget *widget,
- GdkEventAny *event)
-{
- PopWindow *window;
-
- g_assert (POP_IS_WINDOW (widget));
-
- window = POP_WINDOW (widget);
-
- if (window->priv->cairo_pattern != NULL)
- {
- gdk_error_trap_push ();
- pop_window_destroy_pattern (window);
- gdk_flush ();
- if (gdk_error_trap_pop ())
- pop_window_disable_content_tracking (window);
- }
- return FALSE;
-}
-
-static void
-pop_window_set_x_window_id (PopWindow *window,
- Window x_window_id)
-{
- g_assert (POP_IS_WINDOW (window));
- g_assert (x_window_id != POP_WINDOW_INVALID_X_WINDOW_ID);
- g_assert (window->priv->x_window_id == POP_WINDOW_INVALID_X_WINDOW_ID);
-
- window->priv->x_window_id = x_window_id;
-}
-
-Window
-pop_window_get_x_window_id (PopWindow *window)
-{
- g_return_val_if_fail (POP_IS_WINDOW (window), POP_WINDOW_INVALID_X_WINDOW_ID);
-
- return window->priv->x_window_id;
-}
-
-void
-pop_window_draw (PopWindow *window,
- cairo_t *cairo_context)
-{
- cairo_surface_t *surface;
-
- if (window->priv->cairo_pattern == NULL)
- return;
-
- cairo_set_source (cairo_context, window->priv->cairo_pattern);
- if (window->priv->cairo_clip_path != NULL)
- {
- cairo_save (cairo_context);
- cairo_append_path (cairo_context, window->priv->cairo_clip_path);
- cairo_clip (cairo_context);
- cairo_paint_with_alpha (cairo_context, .9);
- cairo_restore (cairo_context);
- }
- else
- cairo_paint (cairo_context);
-}
diff --git a/pop-window.h b/pop-window.h
deleted file mode 100644
index 99d41cf..0000000
--- a/pop-window.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* pop-window.h -
- *
- * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
- *
- * 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-#ifndef POP_WINDOW_H
-#define POP_WINDOW_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <X11/X.h>
-
-#include <cairo.h>
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-#define POP_TYPE_WINDOW (pop_window_get_type ())
-#define POP_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POP_TYPE_WINDOW, PopWindow))
-#define POP_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POP_TYPE_WINDOW, PopWindowClass))
-#define POP_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), POP_TYPE_WINDOW))
-#define POP_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POP_TYPE_WINDOW))
-#define POP_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), POP_TYPE_WINDOW, PopWindowClass))
-#define POP_WINDOW_ERROR (pop_window_error_quark ())
-typedef struct _PopWindow PopWindow;
-typedef struct _PopWindowClass PopWindowClass;
-typedef struct _PopWindowPrivate PopWindowPrivate;
-typedef enum _PopWindowError PopWindowError;
-
-struct _PopWindow
-{
- GtkInvisible parent;
-
- /*< private > */
- PopWindowPrivate *priv;
-};
-
-struct _PopWindowClass
-{
- GtkInvisibleClass parent_class;
-
- /* signals */
-#if 0
- void (*foo) (PopWindow * window);
-#endif
-};
-
-enum _PopWindowError
-{
- POP_WINDOW_ERROR_GENERIC = 0,
-};
-
-#ifndef POP_HIDE_FUNCTION_DECLARATIONS
-GType pop_window_get_type (void);
-GQuark pop_window_error_quark (void);
-
-PopWindow *pop_window_new (Window x_window_id) G_GNUC_MALLOC;
-Window pop_window_get_x_window_id (PopWindow *window);
-void pop_window_draw (PopWindow *window, cairo_t *cairo_context);
-
-#endif
-
-G_END_DECLS
-#endif /* POP_WINDOW_H */
diff --git a/scripts/new-object.sh b/scripts/new-object.sh
new file mode 100755
index 0000000..b5f31dc
--- /dev/null
+++ b/scripts/new-object.sh
@@ -0,0 +1,387 @@
+#!/bin/bash
+
+NAMESPACE="Pop"
+AUTHOR="Ray Strode <rstrode@redhat.com>"
+#-----------------------------------------------------------------------------
+uppercase ()
+{
+ echo "${1}" | tr 'a-z' 'A-Z'
+}
+
+lowercase ()
+{
+ echo "${1}" | tr 'A-Z' 'a-z'
+}
+
+change_character ()
+{
+ echo "${1}" | tr "${2}" "${3}"
+}
+
+delete_character ()
+{
+ echo "${1}" | tr -d "${2}"
+}
+
+#-----------------------------------------------------------------------------
+MACRO_NAMESPACE="$(change_character $(uppercase ${NAMESPACE}) '-' '_')"
+METHOD_NAMESPACE="$(change_character $(lowercase ${NAMESPACE}) '-' '_')"
+
+OBJECT_NAME="$(delete_character ${1} '-')"
+MACRO_OBJECT_NAME="$(change_character $(uppercase ${1}) '-' '_')"
+METHOD_OBJECT_NAME="$(change_character $(lowercase ${1}) '-' '_')"
+FULL_OBJECT_NAME="$(delete_character ${NAMESPACE} '-')${OBJECT_NAME}"
+SHORT_OBJECT_NAME="$(lowercase $(echo ${1} | awk -F- '{print $NF}'))"
+
+HEADER_FILENAME="$(lowercase ${NAMESPACE}-${1}).h"
+HEADER_GUARD="$(change_character $(change_character $(uppercase ${HEADER_FILENAME}) '-' '_') '.' '_')"
+
+SOURCE_FILENAME="$(lowercase ${NAMESPACE}-${1}).c"
+
+MACRO_PREFIX="${MACRO_NAMESPACE}_${MACRO_OBJECT_NAME}"
+METHOD_PREFIX="${METHOD_NAMESPACE}_${METHOD_OBJECT_NAME}"
+
+ERROR_QUARK="${METHOD_NAMESPACE}-$(lowercase ${1})"
+HUMAN_READABLE_NAME=$(change_character $(lowercase ${1}) '-' ' ')
+
+#-----------------------------------------------------------------------------
+cat <<  > ${HEADER_FILENAME}
+/* ${HEADER_FILENAME} - ${2}
+ *
+ * Copyright (C) $(date +%Y) ${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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef ${HEADER_GUARD}
+#define ${HEADER_GUARD}
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define ${MACRO_NAMESPACE}_TYPE_${MACRO_OBJECT_NAME} (${METHOD_PREFIX}_get_type ())
+#define ${MACRO_PREFIX}(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ${MACRO_NAMESPACE}_TYPE_${MACRO_OBJECT_NAME}, ${FULL_OBJECT_NAME}))
+#define ${MACRO_PREFIX}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ${MACRO_NAMESPACE}_TYPE_${MACRO_OBJECT_NAME}, ${FULL_OBJECT_NAME}Class))
+#define ${MACRO_NAMESPACE}_IS_${MACRO_OBJECT_NAME}(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ${MACRO_NAMESPACE}_TYPE_${MACRO_OBJECT_NAME}))
+#define ${MACRO_NAMESPACE}_IS_${MACRO_OBJECT_NAME}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ${MACRO_NAMESPACE}_TYPE_${MACRO_OBJECT_NAME}))
+#define ${MACRO_PREFIX}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), ${MACRO_NAMESPACE}_TYPE_${MACRO_OBJECT_NAME}, ${FULL_OBJECT_NAME}Class))
+#define ${MACRO_PREFIX}_ERROR (${METHOD_PREFIX}_error_quark ())
+
+typedef struct _${FULL_OBJECT_NAME} ${FULL_OBJECT_NAME};
+typedef struct _${FULL_OBJECT_NAME}Class ${FULL_OBJECT_NAME}Class;
+typedef struct _${FULL_OBJECT_NAME}Private ${FULL_OBJECT_NAME}Private;
+typedef enum _${FULL_OBJECT_NAME}Error ${FULL_OBJECT_NAME}Error;
+
+struct _${FULL_OBJECT_NAME}
+{
+ GObject parent;
+
+ /*< private >*/
+ ${FULL_OBJECT_NAME}Private *priv;
+};
+
+struct _${FULL_OBJECT_NAME}Class
+{
+ GObjectClass parent_class;
+
+ /* signals */
+#if 0
+ void (* foo) (${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME});
+#endif
+};
+
+enum _${FULL_OBJECT_NAME}Error
+{
+ ${MACRO_PREFIX}_ERROR_GENERIC = 0,
+};
+
+#ifndef ${MACRO_NAMESPACE}_HIDE_FUNCTION_DECLARATIONS
+GType ${METHOD_PREFIX}_get_type (void);
+GQuark ${METHOD_PREFIX}_error_quark (void);
+
+${FULL_OBJECT_NAME} *${METHOD_PREFIX}_new (void) G_GNUC_MALLOC;
+#endif
+
+G_END_DECLS
+#endif /* ${HEADER_GUARD} */
+
+#-----------------------------------------------------------------------------
+cat <<  > ${SOURCE_FILENAME}
+/* ${SOURCE_FILENAME} - ${2}
+ *
+ * Copyright (C) $(date +%Y) ${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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "config.h"
+#include "${HEADER_FILENAME}"
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+struct _${FULL_OBJECT_NAME}Private
+{
+ int bar;
+};
+
+static void ${METHOD_PREFIX}_finalize (GObject *object);
+#if 0
+static void ${METHOD_PREFIX}_class_install_signals (${FULL_OBJECT_NAME}Class *${SHORT_OBJECT_NAME}_class);
+static void ${METHOD_PREFIX}_class_install_properties (${FULL_OBJECT_NAME}Class *${SHORT_OBJECT_NAME}_class);
+
+static void ${METHOD_PREFIX}_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ${METHOD_PREFIX}_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+enum
+{
+ PROP_0 = 0,
+ PROP_BAR
+};
+
+#define ${MACRO_PREFIX}_DEFAULT_BAR 1
+
+enum
+{
+ FOO = 0,
+ NUMBER_OF_SIGNALS
+};
+
+static guint ${METHOD_PREFIX}_signals[NUMBER_OF_SIGNALS];
+#endif
+
+G_DEFINE_TYPE (${FULL_OBJECT_NAME}, ${METHOD_PREFIX}, G_TYPE_OBJECT);
+
+static void
+${METHOD_PREFIX}_class_init (${FULL_OBJECT_NAME}Class *${SHORT_OBJECT_NAME}_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (${SHORT_OBJECT_NAME}_class);
+
+ object_class->finalize = ${METHOD_PREFIX}_finalize;
+
+#if 0
+ ${METHOD_PREFIX}_class_install_properties (${SHORT_OBJECT_NAME}_class);
+ ${METHOD_PREFIX}_class_install_signals (${SHORT_OBJECT_NAME}_class);
+#endif
+
+ g_type_class_add_private (${SHORT_OBJECT_NAME}_class, sizeof (${FULL_OBJECT_NAME}Private));
+}
+
+#if 0
+static void
+${METHOD_PREFIX}_class_install_signals (${FULL_OBJECT_NAME}Class *${SHORT_OBJECT_NAME}_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (${SHORT_OBJECT_NAME}_class);
+
+ ${METHOD_PREFIX}_signals[FOO] =
+ g_signal_new ("foo", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (${FULL_OBJECT_NAME}Class, foo),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ ${SHORT_OBJECT_NAME}_class->foo = NULL;
+}
+
+static void
+${METHOD_PREFIX}_class_install_properties (${FULL_OBJECT_NAME}Class *${SHORT_OBJECT_NAME}_class)
+{
+ GObjectClass *object_class;
+ GParamSpec *param_spec;
+
+ object_class = G_OBJECT_CLASS (${SHORT_OBJECT_NAME}_class);
+ object_class->set_property = ${METHOD_PREFIX}_set_property;
+ object_class->get_property = ${METHOD_PREFIX}_get_property;
+
+ param_spec = g_param_spec_int ("bar", _("Bar"),
+ _("The amount of bar"),
+ 0, G_MAXINT,
+ ${MACRO_PREFIX}_DEFAULT_BAR,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+ g_object_class_install_property (object_class, PROP_BAR, param_spec);
+}
+#endif
+
+static void
+${METHOD_PREFIX}_init (${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME})
+{
+ ${SHORT_OBJECT_NAME}->priv = G_TYPE_INSTANCE_GET_PRIVATE (${SHORT_OBJECT_NAME},
+ ${MACRO_NAMESPACE}_TYPE_${MACRO_OBJECT_NAME},
+ ${FULL_OBJECT_NAME}Private);
+
+}
+
+static void
+${METHOD_PREFIX}_finalize (GObject *object)
+{
+ ${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME};
+ GObjectClass *parent_class;
+
+ ${SHORT_OBJECT_NAME} = ${MACRO_PREFIX} (object);
+
+ parent_class = G_OBJECT_CLASS (${METHOD_PREFIX}_parent_class);
+
+
+
+ if (parent_class->finalize != NULL)
+ parent_class->finalize (object);
+}
+
+#if 0
+static void
+${METHOD_PREFIX}_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME} = ${MACRO_PREFIX} (object);
+
+ switch (prop_id)
+ {
+ case PROP_BAR:
+ ${METHOD_PREFIX}_set_bar (${SHORT_OBJECT_NAME},
+ g_value_get_int (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+${METHOD_PREFIX}_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME} = ${MACRO_PREFIX} (object);
+
+ switch (prop_id)
+ {
+ case PROP_BAR:
+ g_value_set_int (value,
+ ${METHOD_PREFIX}_get_bar (${SHORT_OBJECT_NAME}));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+#endif
+
+GQuark
+${METHOD_PREFIX}_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (error_quark == 0)
+ error_quark = g_quark_from_static_string ("${ERROR_QUARK}");
+
+ return error_quark;
+}
+
+${FULL_OBJECT_NAME} *
+${METHOD_PREFIX}_new (void)
+{
+ ${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME};
+
+ ${SHORT_OBJECT_NAME} = g_object_new (${MACRO_NAMESPACE}_TYPE_${MACRO_OBJECT_NAME}, NULL);
+
+ return ${SHORT_OBJECT_NAME};
+}
+
+#if 0
+void
+${METHOD_PREFIX}_set_bar (${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME},
+ int bar)
+{
+ if (${SHORT_OBJECT_NAME}->priv->bar != bar)
+ {
+ ${SHORT_OBJECT_NAME}->priv->bar = bar;
+ g_object_notify (G_OBJECT (${SHORT_OBJECT_NAME}), "bar");
+ }
+}
+
+int
+${METHOD_PREFIX}_get_bar (${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME})
+{
+ return ${SHORT_OBJECT_NAME}->priv->bar;
+}
+#endif
+
+#ifdef ${MACRO_PREFIX}_ENABLE_TEST
+
+#include <stdio.h>
+#include <glib.h>
+
+int
+main (int argc,
+ char **argv)
+{
+ ${FULL_OBJECT_NAME} *${SHORT_OBJECT_NAME};
+ int exit_code;
+
+ g_log_set_always_fatal (G_LOG_LEVEL_ERROR
+ | G_LOG_LEVEL_CRITICAL
+ | G_LOG_LEVEL_WARNING);
+
+ g_type_init ();
+
+ g_message ("creating instance of '${HUMAN_READABLE_NAME}' object...");
+ ${SHORT_OBJECT_NAME} = ${METHOD_PREFIX}_new ();
+ g_message ("'${HUMAN_READABLE_NAME}' object created successfully");
+
+ g_message ("destroying previously created '${HUMAN_READABLE_NAME}' object...");
+ g_object_unref (${SHORT_OBJECT_NAME});
+ g_message ("'${HUMAN_READABLE_NAME}' object destroyed successfully");
+
+ exit_code = 0;
+
+ return exit_code;
+}
+#endif /* ${MACRO_PREFIX}_ENABLE_TEST */
+
+
+indent -gnu ${HEADER_FILENAME}
+rm -f ${HEADER_FILENAME}~
+indent -gnu ${SOURCE_FILENAME}
+rm -f ${SOURCE_FILENAME}~
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..f401637
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,29 @@
+INCLUDES = -I$(top_srcdir) \
+ -I$(srcdir)
+
+BUILT_SOURCES = pop-marshal.c \
+ pop-marshal.h
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = pop-marshal.list
+
+pop-marshal.c: pop-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --body --prefix=pop_marshal > $@
+
+pop-marshal.h: pop-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=pop_marshal > $@
+
+pop_demo_CFLAGS = $(POP_CFLAGS)
+pop_demo_LDADD = $(POP_LIBS)
+pop_demo_SOURCES = pop-window-stack.c \
+ pop-window-stack.h \
+ pop-window-view.c \
+ pop-window-view.h \
+ pop-event-listener.c \
+ pop-event-listener.h \
+ pop-overlay-window.c \
+ pop-overlay-window.h \
+ $(BUILT_SOURCES) \
+ pop-demo.c
+
+noinst_PROGRAMS = pop-demo
diff --git a/src/pop-demo.c b/src/pop-demo.c
new file mode 100644
index 0000000..e035d2f
--- /dev/null
+++ b/src/pop-demo.c
@@ -0,0 +1,437 @@
+#include "config.h"
+
+#include <unistd.h>
+
+#include <glib.h>
+
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xfixes.h>
+
+#include <cairo.h>
+#include <cairo-xlib.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkcairo.h>
+#include <gdk/gdkx.h>
+
+#include "pop-overlay-window.h"
+#include "pop-window-stack.h"
+#include "pop-event-listener.h"
+#include "pop-window-view.h"
+
+static PopWindowStack *stack = NULL;
+static PopEventListener *listener = NULL;
+GtkWidget *overlay_window;
+static int damage_extension_event_base,
+ damage_extension_error_base;
+
+static int shape_extension_event_base,
+ shape_extension_error_base;
+
+static gboolean
+composite_is_available (void)
+{
+ int event_base, error_base;
+
+ event_base = 0;
+ error_base = 0;
+ if (XCompositeQueryExtension (GDK_DISPLAY (), &event_base, &error_base))
+ return TRUE;
+ return FALSE;
+}
+
+static gboolean
+initialize_damage_extension (void)
+{
+ if (XDamageQueryExtension (GDK_DISPLAY (), &damage_extension_event_base,
+ &damage_extension_error_base))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+initialize_shape_extension (void)
+{
+ if (XShapeQueryExtension (GDK_DISPLAY (), &shape_extension_event_base,
+ &shape_extension_error_base))
+ return TRUE;
+
+ return FALSE;
+}
+
+gint
+window_compare (PopWindowView *view,
+ Window *x_window_id)
+{
+ GdkWindow *window;
+ if (!POP_IS_WINDOW_VIEW (view))
+ {
+ g_warning ("passed invalid data to compare func: %p\n", view);
+ return -1;
+ }
+
+ window = pop_window_view_get_window (view);
+ return ((gulong) GDK_WINDOW_XWINDOW (window)) - *x_window_id;
+}
+
+static void
+remove_window_from_list (GdkWindow *window)
+{
+ PopWindowView *view;
+
+ view = g_object_get_data (G_OBJECT (window), "pop-window-view");
+
+ if (view == NULL)
+ return;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ pop_window_view_unset_window (view);
+ g_object_unref (view);
+
+ g_object_set_data (G_OBJECT (window), "pop-window-view", NULL);
+ g_object_unref (G_OBJECT (window));
+}
+
+static void
+add_window_to_list (GdkWindow *window)
+{
+ PopWindowView *view;
+
+ if (window == GTK_WIDGET (overlay_window)->window)
+ return;
+ {
+ Window parent, root, *children;
+ guint number_of_children, i;
+
+ gdk_error_trap_push ();
+ if (!XQueryTree (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (window),
+ &root, &parent, &children, &number_of_children))
+ return;
+ if (gdk_error_trap_pop ())
+ return;
+
+ for (i = 0; i < number_of_children; i++)
+ {
+ if (children[i] == GDK_WINDOW_XWINDOW (GTK_WIDGET (overlay_window)->window))
+ break;
+ }
+ XFree (children);
+ if (i != number_of_children)
+ return;
+ }
+
+ view = pop_window_view_new ();
+ if (!pop_window_view_set_window (view, window))
+ {
+ g_print ("couldn't redirect 0x%lx to overlay window\n",
+ GDK_WINDOW_XWINDOW (window));
+ return;
+ }
+
+ g_object_ref (G_OBJECT (window));
+ g_object_set_data (G_OBJECT (window), "pop-window-view", g_object_ref (view));
+}
+
+static void
+view_subtract_overlapping_region (PopWindowStack *stack,
+ GdkWindow *window,
+ GdkWindow *above_window,
+ GdkRegion **visible_region)
+{
+ PopWindowView *view, *above_view;
+ GdkRegion *difference;
+
+ g_assert (POP_IS_WINDOW_STACK (stack));
+ g_assert (GDK_IS_WINDOW (window));
+ g_assert (GDK_IS_WINDOW (above_window));
+ g_assert (visible_region != NULL);
+
+ above_view = g_object_get_data (G_OBJECT (above_window), "pop-window-view");
+
+ if (!POP_IS_WINDOW_VIEW (above_view))
+ return;
+
+ view = g_object_get_data (G_OBJECT (window), "pop-window-view");
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ difference = pop_window_view_get_difference (view, above_view);
+
+ g_assert (difference != NULL);
+
+ if (*visible_region == NULL)
+ *visible_region = difference;
+ else
+ {
+ gdk_region_intersect (*visible_region, difference);
+ gdk_region_destroy (difference);
+ }
+
+}
+
+static GdkRegion *
+get_view_visible_region (PopWindowStack *stack,
+ PopWindowView *view)
+{
+ GdkWindow *window;
+ GdkRegion *visible_region;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ window = pop_window_view_get_window (view);
+
+ g_assert (GDK_IS_WINDOW (window));
+
+ visible_region = NULL;
+ pop_window_stack_above_window_foreach (stack, window,
+ (PopWindowStackAboveWindowForeachFunc)
+ view_subtract_overlapping_region,
+ &visible_region);
+ if (visible_region == NULL)
+ visible_region = gdk_region_new ();
+
+ return visible_region;
+}
+
+static void
+draw_window_from_stack (PopWindowStack *stack,
+ GdkWindow *window,
+ cairo_t *cairo_context)
+{
+ PopWindowView *view;
+ GdkRegion *visible_region;
+
+ view = g_object_get_data (G_OBJECT (window), "pop-window-view");
+
+ if (view == NULL)
+ return;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+#if 0
+ visible_region = get_view_visible_region (stack, view);
+
+ if (!gdk_region_empty (visible_region))
+ {
+#endif
+ cairo_save (cairo_context);
+ pop_window_view_render_to_context (view, cairo_context);
+ cairo_restore (cairo_context);
+#if 0
+ }
+
+ gdk_region_destroy (visible_region);
+#endif
+}
+
+static void
+draw_windows (cairo_t *cairo_context)
+{
+ pop_window_stack_foreach (stack,
+ (PopWindowStackForeachFunc)
+ draw_window_from_stack, cairo_context);
+}
+
+void
+add_window_from_stack_to_list (PopWindowStack *stack,
+ GdkWindow *window)
+{
+ add_window_to_list (g_object_ref (window));
+}
+
+static void
+get_initial_view_list (void)
+{
+
+ stack = pop_window_stack_get_for_screen (NULL);
+
+ pop_window_stack_foreach (stack,
+ (PopWindowStackForeachFunc)
+ add_window_from_stack_to_list, NULL);
+}
+
+static gboolean
+on_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ cairo_t *cairo_context;
+ GdkRectangle monitor_area;
+ GdkScreen *screen;
+ double x_scale_factor, y_scale_factor;
+
+ screen = gtk_widget_get_screen (widget);
+ gdk_screen_get_monitor_geometry (screen,
+ gdk_screen_get_monitor_at_window (screen, widget->window), &monitor_area);
+
+ x_scale_factor = widget->allocation.width / ((double) monitor_area.width);
+ y_scale_factor = widget->allocation.height / ((double) monitor_area.height);
+
+ cairo_context = gdk_cairo_create (widget->window);
+ //cairo_scale (cairo_context, x_scale_factor, y_scale_factor);
+ //cairo_set_source_rgb (cairo_context, 0.5, 0.5, 0.6);
+ //cairo_paint (cairo_context);
+ draw_windows (cairo_context);
+ cairo_destroy (cairo_context);
+
+ return FALSE;
+}
+
+static void
+on_map (GtkWidget *widget)
+{
+ get_initial_view_list ();
+}
+
+static void
+remove_window_from_stack_from_list (PopWindowStack *stack,
+ GdkWindow *window)
+{
+ remove_window_from_list (window);
+}
+
+static gboolean
+on_close (GtkWidget *widget)
+{
+ pop_window_stack_foreach (stack,
+ (PopWindowStackForeachFunc)
+ remove_window_from_stack_from_list,
+ NULL);
+ g_object_unref (stack);
+ stack = NULL;
+
+ gtk_main_quit ();
+
+ return FALSE;
+}
+
+static void
+on_damage_event (XDamageNotifyEvent *damage_event,
+ PopOverlayWindow *overlay_window)
+{
+ gtk_widget_queue_draw (GTK_WIDGET (overlay_window));
+}
+
+static void
+on_create_window_event (XCreateWindowEvent *window_event,
+ PopOverlayWindow *overlay_window)
+{
+ GdkWindow *window;
+
+ if (window_event->parent != GDK_ROOT_WINDOW ())
+ return;
+
+ window = gdk_window_foreign_new (window_event->window);
+
+ if (window != NULL)
+ add_window_to_list (window);
+ else
+ g_print ("recently created window 0x%lx has already been destroyed\n",
+ window_event->window);
+}
+
+static void
+on_destroy_window_event (XDestroyWindowEvent *window_event,
+ PopOverlayWindow *overlay_window)
+{
+ GdkWindow *window;
+
+ window = gdk_window_lookup (window_event->window);
+ if (window == NULL)
+ return;
+ remove_window_from_list (window);
+ gtk_widget_queue_draw (GTK_WIDGET (overlay_window));
+}
+
+static gboolean
+x_event_is_damage_event (XEvent *x_event)
+{
+ return x_event->type == damage_extension_event_base + XDamageNotify;
+}
+
+static gboolean
+x_event_is_create_window_event (XEvent *x_event)
+{
+ return /* x_event->type == CreateNotify || */ x_event->type == MapNotify;
+}
+
+static gboolean
+x_event_is_destroy_window_event (XEvent *x_event)
+{
+ return /* x_event->type == DestroyNotify || */ x_event->type == UnmapNotify;
+}
+
+static GdkFilterReturn
+on_event (XEvent *x_event,
+ GdkEvent *event,
+ PopOverlayWindow *overlay_window)
+{
+
+ if (((GdkEventAny *) event)->window == GTK_WIDGET (overlay_window)->window)
+ return GDK_FILTER_CONTINUE;
+ if (x_event_is_damage_event (x_event))
+ on_damage_event ((XDamageNotifyEvent *) x_event, overlay_window);
+ else if (x_event_is_create_window_event (x_event))
+ on_create_window_event ((XCreateWindowEvent *) x_event, overlay_window);
+ else if (x_event_is_destroy_window_event (x_event))
+ on_destroy_window_event ((XDestroyWindowEvent *) x_event, overlay_window);
+
+ gtk_widget_queue_draw (GTK_WIDGET (overlay_window));
+
+ return GDK_FILTER_CONTINUE;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GdkWindow *root_window;
+
+ gtk_init (&argc, &argv);
+
+ if (!composite_is_available ())
+ {
+ g_printerr ("composite extension not found\n");
+ return 1;
+ }
+
+ if (!initialize_damage_extension ())
+ {
+ g_printerr ("damage extension not found\n");
+ return 2;
+ }
+
+ initialize_shape_extension ();
+
+ overlay_window = pop_overlay_window_new ();
+ overlay_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_app_paintable (GTK_WIDGET (overlay_window), TRUE);
+ gtk_window_set_default_size (GTK_WINDOW (overlay_window), 640, 480);
+#if 0
+ gtk_widget_realize (GTK_WIDGET (overlay_window));
+#endif
+
+ g_signal_connect (G_OBJECT (overlay_window), "expose-event",
+ G_CALLBACK (on_expose_event), NULL);
+ g_signal_connect (G_OBJECT (overlay_window), "map",
+ G_CALLBACK (on_map), NULL);
+ g_signal_connect (G_OBJECT (overlay_window), "delete-event",
+ G_CALLBACK (on_close), NULL);
+
+ root_window = gdk_get_default_root_window ();
+ gdk_window_set_events (root_window, GDK_SUBSTRUCTURE_MASK);
+ gdk_window_add_filter (NULL, (GdkFilterFunc) on_event, overlay_window);
+
+ listener = pop_event_listener_get_default ();
+
+ gtk_widget_show (overlay_window);
+
+ g_print ("overlay window is 0x%lx\n", GDK_WINDOW_XWINDOW (overlay_window->window));
+
+ gtk_main();
+
+ return 0;
+}
diff --git a/src/pop-event-listener.c b/src/pop-event-listener.c
new file mode 100644
index 0000000..9667b98
--- /dev/null
+++ b/src/pop-event-listener.c
@@ -0,0 +1,1165 @@
+/* pop-event-listener.c - emits signals based on display events
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "config.h"
+#include "pop-event-listener.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xdamage.h>
+
+#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
+
+#include <gtk/gtk.h>
+
+#include "pop-marshal.h"
+
+static void pop_event_listener_do_finalize (GObject *object);
+static void pop_event_listener_destroy_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+static void pop_event_listener_configure_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+static void pop_event_listener_map_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+static void pop_event_listener_unmap_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+static void pop_event_listener_damage_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+static void pop_event_listener_shape_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+
+static void pop_event_listener_reparent_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+static void pop_event_listener_circulate_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+
+static void pop_event_listener_stop (PopEventListener *listener);
+
+
+static int pop_event_listener_damage_notify_event_type,
+ pop_event_listener_shape_notify_event_type;
+
+struct _PopEventListenerPrivate
+{
+ GHashTable *event_handlers;
+};
+
+
+/* XXX: This is a bit of a hack. gdk doesn't have
+ * events for some of X extensions we need, so we
+ * are rolling our own using an event filter.
+ *
+ * The event types are given high negative values so they
+ * less likely to conflict with gdk in the future, and all
+ * the event structures are less than sizeof (GdkEvent) and
+ * have the same first few members as GdkEventAny
+ */
+typedef enum
+{
+ POP_DAMAGE = -1000,
+ POP_SHAPE = -1001,
+ POP_REPARENT = -1002,
+ POP_CIRCULATE = -1003,
+} PopEventType;
+
+typedef struct _PopEventDamage PopEventDamage;
+struct _PopEventDamage
+{
+ PopEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+ GdkRectangle area;
+};
+
+typedef struct _PopEventShape PopEventShape;
+struct _PopEventShape
+{
+ PopEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+};
+
+typedef struct _PopEventReparent PopEventReparent;
+struct _PopEventReparent
+{
+ PopEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+ GdkWindow *parent;
+ gint x;
+ gint y;
+};
+
+typedef enum _PopEventCirculatePlacement PopEventCirculatePlacement;
+enum _PopEventCirculatePlacement
+{
+ POP_EVENT_CIRCULATE_PLACEMENT_TOP,
+ POP_EVENT_CIRCULATE_PLACEMENT_BOTTOM
+};
+
+typedef struct _PopEventCirculate PopEventCirculate;
+struct _PopEventCirculate
+{
+ PopEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+ PopEventCirculatePlacement placement;
+};
+
+typedef void (* PopEventListenerEventHandler) (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window);
+
+static void
+pop_event_listener_class_install_signals (PopEventListenerClass *listener_class);
+
+#if 0
+static void
+pop_event_listener_class_install_properties
+(PopEventListenerClass * listener_class);
+
+static void pop_event_listener_set_property (GObject * object,
+ guint prop_id,
+ const GValue * value,
+ GParamSpec * pspec);
+static void pop_event_listener_get_property (GObject * object,
+ guint prop_id,
+ GValue * value,
+ GParamSpec * pspec);
+
+enum
+{
+ PROP_0 = 0,
+ PROP_BAR
+};
+
+#define POP_EVENT_LISTENER_DEFAULT_BAR 1
+
+#endif
+
+enum
+{
+ WINDOW_CREATED = 0,
+ WINDOW_DESTROYED,
+ WINDOW_SHOWN,
+ WINDOW_HIDDEN,
+ WINDOW_MOVED,
+ WINDOW_RESIZED,
+ WINDOW_RESHAPED,
+ WINDOW_REPARENTED,
+ WINDOW_REDRAWN,
+ WINDOW_LAYERED_UNDER,
+ WINDOW_LAYERED_ON_TOP,
+ WINDOW_LAYERED_ON_BOTTOM,
+ NUMBER_OF_SIGNALS
+};
+
+static guint pop_event_listener_signals[NUMBER_OF_SIGNALS];
+
+G_DEFINE_TYPE (PopEventListener, pop_event_listener, G_TYPE_OBJECT);
+
+static void
+pop_event_listener_class_init (PopEventListenerClass *listener_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (listener_class);
+
+ object_class->finalize = pop_event_listener_do_finalize;
+
+#if 0
+ pop_event_listener_class_install_properties (listener_class);
+#endif
+ pop_event_listener_class_install_signals (listener_class);
+
+ g_type_class_add_private (listener_class,
+ sizeof (PopEventListenerPrivate));
+}
+
+static void
+created (PopEventListener *listener,
+ GdkWindow *window)
+{
+ g_print ("created 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+}
+
+static void
+destroyed (PopEventListener *listener,
+ GdkWindow *window)
+{
+ g_print ("destroyed 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+}
+
+static void
+moved (PopEventListener *listener,
+ GdkWindow *window)
+{
+ g_print ("moved 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+}
+
+static void
+resized (PopEventListener *listener,
+ GdkWindow *window)
+{
+ g_print ("resized 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+}
+
+static void
+redrawn (PopEventListener *listener,
+ GdkWindow *window,
+ GdkRectangle *area)
+{
+#if 0
+ g_print ("redrawn 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+#endif
+}
+
+static void
+reparented (PopEventListener *listener,
+ GdkWindow *window,
+ GdkWindow *parent)
+{
+ g_print ("reparented 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+}
+
+static void
+shown (PopEventListener *listener,
+ GdkWindow *window)
+{
+ g_print ("shown 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+}
+
+static void
+hidden (PopEventListener *listener,
+ GdkWindow *window)
+{
+ g_print ("hidden 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+}
+
+static void
+pop_event_listener_class_install_signals (PopEventListenerClass *listener_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (listener_class);
+
+ pop_event_listener_signals[WINDOW_CREATED] =
+ g_signal_new ("window-created", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_created),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_created = created;
+
+ pop_event_listener_signals[WINDOW_DESTROYED] =
+ g_signal_new ("window-destroyed", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_destroyed),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_destroyed = destroyed;
+
+ pop_event_listener_signals[WINDOW_SHOWN] =
+ g_signal_new ("window-shown", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_shown),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_shown = shown;
+
+ pop_event_listener_signals[WINDOW_HIDDEN] =
+ g_signal_new ("window-hidden", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_hidden),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_hidden = hidden;
+
+ pop_event_listener_signals[WINDOW_MOVED] =
+ g_signal_new ("window-moved", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_moved),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_moved = moved;
+
+ pop_event_listener_signals[WINDOW_RESIZED] =
+ g_signal_new ("window-resized", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_resized),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_resized = resized;
+
+ pop_event_listener_signals[WINDOW_RESHAPED] =
+ g_signal_new ("window-reshaped", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_reshaped),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_reshaped = NULL;
+
+ pop_event_listener_signals[WINDOW_REPARENTED] =
+ g_signal_new ("window-reparented", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_reparented),
+ NULL, NULL, pop_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2,
+ G_TYPE_OBJECT, G_TYPE_OBJECT);
+ listener_class->window_reparented = reparented;
+
+ pop_event_listener_signals[WINDOW_REDRAWN] =
+ g_signal_new ("window-redrawn", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_redrawn),
+ NULL, NULL, pop_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2,
+ G_TYPE_OBJECT, G_TYPE_POINTER);
+ listener_class->window_redrawn = redrawn;
+
+ pop_event_listener_signals[WINDOW_LAYERED_UNDER] =
+ g_signal_new ("window-layered-under", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_layered_under),
+ NULL, NULL, pop_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2,
+ G_TYPE_OBJECT, G_TYPE_OBJECT);
+ listener_class->window_layered_under = NULL;
+
+ pop_event_listener_signals[WINDOW_LAYERED_ON_TOP] =
+ g_signal_new ("window-layered-on-top", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_layered_on_top),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_layered_on_top = NULL;
+
+ pop_event_listener_signals[WINDOW_LAYERED_ON_BOTTOM] =
+ g_signal_new ("window-layered-on-bottom", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (PopEventListenerClass, window_layered_on_bottom),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ listener_class->window_layered_on_bottom = NULL;
+}
+
+#if 0
+static void
+pop_event_listener_class_install_properties (PopEventListenerClass *listener_class)
+{
+ GObjectClass *object_class;
+ GParamSpec *bar_spec;
+
+ object_class = G_OBJECT_CLASS (listener_class);
+ object_class->set_property = pop_event_listener_set_property;
+ object_class->get_property = pop_event_listener_get_property;
+
+ bar_spec = g_param_spec_int ("bar", _("Bar"),
+ _("The amount of bar"),
+ 0, G_MAXINT,
+ POP_EVENT_LISTENER_DEFAULT_BAR,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+ g_object_class_install_property (object_class, PROP_BAR, bar_spec);
+}
+#endif
+
+static void
+pop_event_listener_initialize_damage_extension (PopEventListener *listener)
+{
+ int event_base, error_base;
+ XDamageQueryExtension (GDK_DISPLAY (), &event_base, &error_base);
+
+ pop_event_listener_damage_notify_event_type = event_base + XDamageNotify;
+}
+
+static void
+pop_event_listener_initialize_shape_extension (PopEventListener *listener)
+{
+ int event_base, error_base;
+ XShapeQueryExtension (GDK_DISPLAY (), &event_base, &error_base);
+
+ pop_event_listener_shape_notify_event_type = event_base + ShapeNotify;
+}
+
+static void
+pop_event_listener_register_event_handlers (PopEventListener *listener)
+{
+ listener->priv->event_handlers = g_hash_table_new (NULL, NULL);
+
+ g_hash_table_insert (listener->priv->event_handlers,
+ GINT_TO_POINTER (GDK_DESTROY),
+ pop_event_listener_destroy_handler);
+
+ g_hash_table_insert (listener->priv->event_handlers,
+ GINT_TO_POINTER (GDK_CONFIGURE),
+ pop_event_listener_configure_handler);
+
+ g_hash_table_insert (listener->priv->event_handlers,
+ GINT_TO_POINTER (GDK_MAP),
+ pop_event_listener_map_handler);
+
+ g_hash_table_insert (listener->priv->event_handlers,
+ GINT_TO_POINTER (GDK_UNMAP),
+ pop_event_listener_unmap_handler);
+
+ g_hash_table_insert (listener->priv->event_handlers,
+ GINT_TO_POINTER (POP_DAMAGE),
+ pop_event_listener_damage_handler);
+
+ g_hash_table_insert (listener->priv->event_handlers,
+ GINT_TO_POINTER (POP_SHAPE),
+ pop_event_listener_shape_handler);
+
+ g_hash_table_insert (listener->priv->event_handlers,
+ GINT_TO_POINTER (POP_REPARENT),
+ pop_event_listener_reparent_handler);
+
+ g_hash_table_insert (listener->priv->event_handlers,
+ GINT_TO_POINTER (POP_CIRCULATE),
+ pop_event_listener_circulate_handler);
+
+}
+
+static void
+pop_event_listener_init (PopEventListener *listener)
+{
+ listener->priv = G_TYPE_INSTANCE_GET_PRIVATE (listener,
+ POP_TYPE_EVENT_LISTENER,
+ PopEventListenerPrivate);
+ pop_event_listener_initialize_damage_extension (listener);
+ pop_event_listener_initialize_shape_extension (listener);
+ pop_event_listener_register_event_handlers (listener);
+}
+
+static void
+pop_event_listener_do_finalize (GObject *object)
+{
+ PopEventListener *listener;
+ GObjectClass *parent_class;
+
+ listener = POP_EVENT_LISTENER (object);
+
+ g_hash_table_destroy (listener->priv->event_handlers);
+
+ parent_class = G_OBJECT_CLASS (pop_event_listener_parent_class);
+
+ pop_event_listener_stop (listener);
+
+ if (parent_class->finalize != NULL)
+ parent_class->finalize (object);
+}
+
+#if 0
+static void
+pop_event_listener_set_property (GObject * object,
+ guint prop_id,
+ const GValue * value,
+ GParamSpec * pspec)
+{
+ PopEventListener *listener = POP_EVENT_LISTENER (object);
+
+ switch (prop_id)
+ {
+ case PROP_BAR:
+ pop_event_listener_set_bar (listener, g_value_get_int (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+pop_event_listener_get_property (GObject * object,
+ guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ PopEventListener *listener = POP_EVENT_LISTENER (object);
+
+ switch (prop_id)
+ {
+ case PROP_BAR:
+ g_value_set_int (value, pop_event_listener_get_bar (listener));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+#endif
+
+GQuark
+pop_event_listener_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (error_quark == 0)
+ error_quark = g_quark_from_static_string ("pop-event-listener");
+
+ return error_quark;
+}
+
+static PopEventListener *
+pop_event_listener_new (GdkDisplay *display)
+{
+ PopEventListener *listener;
+
+ listener = g_object_new (POP_TYPE_EVENT_LISTENER, NULL);
+
+ return listener;
+}
+
+#if 0
+void
+pop_event_listener_set_bar (PopEventListener * listener, int bar)
+{
+ if (listener->priv->bar != bar)
+ {
+ listener->priv->bar = bar;
+ g_object_notify (G_OBJECT (listener), "bar");
+ }
+}
+
+int
+pop_event_listener_get_bar (PopEventListener * listener)
+{
+ return listener->priv->bar;
+}
+#endif
+
+static GQuark
+pop_event_listener_get_signal_detail_for_window (PopEventListener *listener,
+ GdkWindow *window)
+{
+ gchar window_id[sizeof ("ffffffff")];
+ g_snprintf (window_id, sizeof (window_id),
+ "%lx", GDK_WINDOW_XWINDOW (window));
+
+ return g_quark_from_string (window_id);
+}
+
+static void
+pop_event_listener_destroy_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_CREATED],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+}
+
+static gboolean
+pop_event_listener_get_cached_window_geometry (PopEventListener *listener,
+ GdkWindow *window,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ gboolean has_cached_geometry;
+
+ has_cached_geometry = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-"
+ "has-cached-"
+ "window-geometry"));
+
+ if (!has_cached_geometry)
+ return FALSE;
+
+ if (x)
+ *x = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-x"));
+
+ if (y)
+ *y = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-y"));
+
+ if (width)
+ *width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-width"));
+
+ if (height)
+ *height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-height"));
+
+ return TRUE;
+}
+
+static void
+pop_event_listener_cache_window_geometry (PopEventListener *listener,
+ GdkWindow *window,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-x",
+ GINT_TO_POINTER (x));
+
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-y",
+ GINT_TO_POINTER (y));
+
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-width",
+ GINT_TO_POINTER (width));
+
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-height",
+ GINT_TO_POINTER (height));
+
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-has-cached-window-geometry",
+ GINT_TO_POINTER (TRUE));
+}
+
+static gboolean
+pop_event_listener_get_cached_window_layer (PopEventListener *listener,
+ GdkWindow *window,
+ GdkWindow **window_above)
+{
+ gboolean has_cached_layer;
+ GdkWindow *cached_window_above, *cached_window_below;
+
+ has_cached_layer = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-"
+ "has-cached-"
+ "window-layer"));
+
+ if (!has_cached_layer)
+ return FALSE;
+
+ cached_window_above = g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-"
+ "layer-window-above");
+
+ if (cached_window_above)
+ {
+ cached_window_below = g_object_get_data (G_OBJECT (cached_window_above),
+ "pop-event-listener-cached-window-"
+ "layer-window-below");
+
+ /* referential integrity is broken, assume it's stale
+ */
+ if (cached_window_below != window)
+ {
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-"
+ "layer-window-above", NULL);
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-has-cached-window-layer",
+ GINT_TO_POINTER (FALSE));
+ g_object_unref (cached_window_above);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+pop_event_listener_cache_window_layer (PopEventListener *listener,
+ GdkWindow *window,
+ GdkWindow *window_above)
+{
+ GdkWindow *old_window_above;
+
+ old_window_above = g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-layer-window-above");
+ if (old_window_above != NULL)
+ g_object_unref (old_window_above);
+
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-layer-window-above",
+ window_above);
+ if (window_above != NULL)
+ {
+ g_object_ref (window_above);
+
+ g_object_set_data (G_OBJECT (window_above),
+ "pop-event-listener-cached-window-layer-window-below",
+ g_object_ref (window));
+ }
+
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-has-cached-window-layer",
+ GINT_TO_POINTER (TRUE));
+}
+
+static void
+pop_event_listener_configure_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+ GdkEventConfigure *configure_event;
+ GdkWindow *new_window_above, *window_above;
+ gint x, y, width, height;
+ gboolean changed_position, changed_size, changed_layer;
+
+ configure_event = (GdkEventConfigure *) event;
+
+ new_window_above = g_object_get_data (G_OBJECT (window),
+ "pop-event-listener-window-above");
+ g_assert ((new_window_above == NULL) || (G_IS_OBJECT (new_window_above)));
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-window-above",
+ NULL);
+
+ if (pop_event_listener_get_cached_window_geometry (listener, window,
+ &x, &y, &width, &height))
+ {
+ changed_position = (x != configure_event->x) || (y != configure_event->y);
+ changed_size = (width != configure_event->width)
+ || (height != configure_event->height);
+ }
+ else
+ {
+ changed_position = TRUE;
+ changed_size = TRUE;
+ }
+
+ if (pop_event_listener_get_cached_window_layer (listener, window, &window_above))
+ changed_layer = window_above != new_window_above;
+ else
+ changed_layer = TRUE;
+
+ PopWindowView *view;
+ view = g_object_get_data (G_OBJECT (window), "pop-window-view");
+ if (changed_position)
+ {
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_MOVED],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+ }
+
+ if (changed_size)
+ {
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_RESIZED],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+ }
+
+ if (changed_layer)
+ {
+ g_print ("window 0x%lx changed layers\n", GDK_WINDOW_XWINDOW (window));
+ if (new_window_above != NULL)
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_LAYERED_UNDER],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window,
+ new_window_above);
+ else
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_LAYERED_ON_BOTTOM],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+ pop_event_listener_cache_window_layer (listener, window, new_window_above);
+ }
+
+ if (new_window_above != NULL)
+ g_object_unref (new_window_above);
+
+ pop_event_listener_cache_window_geometry (listener, window,
+ configure_event->x,
+ configure_event->y,
+ configure_event->width,
+ configure_event->height);
+}
+
+static void
+pop_event_listener_map_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_SHOWN],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+}
+
+static void
+pop_event_listener_unmap_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_HIDDEN],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+}
+
+static void
+pop_event_listener_damage_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+ PopEventDamage *damage_event;
+
+ g_assert (POP_IS_EVENT_LISTENER (listener));
+ g_assert (event->type == POP_DAMAGE);
+
+ damage_event = (PopEventDamage *) event;
+
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_REDRAWN],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window, &damage_event->area);
+}
+
+static void
+pop_event_listener_shape_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+ PopEventShape *shape_event;
+
+ g_assert (POP_IS_EVENT_LISTENER (listener));
+ g_assert (event->type == POP_SHAPE);
+
+ shape_event = (PopEventShape *) event;
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_RESHAPED],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+}
+
+static void
+pop_event_listener_reparent_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+ PopEventReparent *reparent_event;
+
+ g_assert (POP_IS_EVENT_LISTENER (listener));
+ g_assert (event->type == POP_REPARENT);
+
+ reparent_event = (PopEventReparent *) event;
+
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_REPARENTED],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window, reparent_event->parent);
+}
+
+static void
+pop_event_listener_circulate_handler (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+ PopEventCirculate *circulate_event;
+
+ g_assert (POP_IS_EVENT_LISTENER (listener));
+ g_assert (event->type == POP_CIRCULATE);
+
+ circulate_event = (PopEventCirculate *) event;
+
+ if (circulate_event->placement == POP_EVENT_CIRCULATE_PLACEMENT_TOP)
+ {
+ g_print ("window 0x%lx moved to top of stack\n", GDK_WINDOW_XWINDOW (window));
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_LAYERED_ON_TOP],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+ }
+ else if (circulate_event->placement == POP_EVENT_CIRCULATE_PLACEMENT_BOTTOM)
+ {
+ g_print ("window 0x%lx moved to bottom of stack\n", GDK_WINDOW_XWINDOW (window));
+ g_signal_emit (G_OBJECT (listener),
+ pop_event_listener_signals[WINDOW_LAYERED_ON_BOTTOM],
+ pop_event_listener_get_signal_detail_for_window (listener,
+ window),
+ window);
+ }
+}
+
+static void
+pop_event_listener_process_event_for_window (PopEventListener *listener,
+ GdkEvent *event,
+ GdkWindow *window)
+{
+ PopEventListenerEventHandler event_handler;
+
+ event_handler = (PopEventListenerEventHandler)
+ g_hash_table_lookup (listener->priv->event_handlers,
+ GINT_TO_POINTER (event->type));
+
+ if (event_handler == NULL)
+ return;
+
+ event_handler (listener, event, window);
+}
+
+static void
+pop_event_listener_event_handler (GdkEvent *event,
+ gpointer data)
+{
+ PopEventListener *listener;
+
+ g_assert (event != NULL);
+ g_assert (POP_IS_EVENT_LISTENER (data));
+
+ listener = POP_EVENT_LISTENER (data);
+
+ if (event->any.window != NULL)
+ pop_event_listener_process_event_for_window (listener, event,
+ event->any.window);
+
+ /* chain up to the default handler if it's not one of our custom
+ * events
+ */
+ if (event->type >= GDK_NOTHING)
+ gtk_main_do_event (event);
+}
+
+GdkFilterReturn
+pop_event_listener_filter_damage_event (XDamageNotifyEvent *x_damage_event,
+ PopEventDamage *damage_event,
+ GdkWindow *window)
+{
+ damage_event->window = g_object_ref (window);
+ damage_event->type = POP_DAMAGE;
+ damage_event->send_event = FALSE;
+ damage_event->area.x = x_damage_event->area.x;
+ damage_event->area.y = x_damage_event->area.y;
+ damage_event->area.width = x_damage_event->area.width;
+ damage_event->area.height = x_damage_event->area.height;
+
+ return GDK_FILTER_TRANSLATE;
+}
+
+GdkFilterReturn
+pop_event_listener_filter_shape_event (XShapeEvent *x_shape_event,
+ PopEventShape *shape_event,
+ GdkWindow *window)
+{
+ shape_event->window = g_object_ref (window);
+ shape_event->type = POP_SHAPE;
+ shape_event->send_event = FALSE;
+
+ return GDK_FILTER_TRANSLATE;
+}
+
+GdkFilterReturn
+pop_event_listener_filter_reparent_event (XReparentEvent *x_reparent_event,
+ PopEventReparent *reparent_event,
+ GdkWindow *window)
+{
+ GdkWindow *parent;
+
+ reparent_event->window = g_object_ref (window);
+ reparent_event->type = POP_REPARENT;
+ reparent_event->send_event = FALSE;
+
+ parent = gdk_window_lookup (x_reparent_event->parent);
+
+ if (parent == NULL)
+ parent = gdk_window_foreign_new (x_reparent_event->parent);
+
+ reparent_event->parent = parent;
+
+ return GDK_FILTER_TRANSLATE;
+}
+
+GdkFilterReturn
+pop_event_listener_filter_circulate_event (XCirculateEvent *x_circulate_event,
+ PopEventCirculate *circulate_event,
+ GdkWindow *window)
+{
+ circulate_event->window = g_object_ref (window);
+ circulate_event->type = POP_CIRCULATE;
+ circulate_event->send_event = FALSE;
+
+ g_assert ((x_circulate_event->place == PlaceOnTop) ||
+ (x_circulate_event->place == PlaceOnBottom));
+
+ if (x_circulate_event->place == PlaceOnTop)
+ circulate_event->placement = POP_EVENT_CIRCULATE_PLACEMENT_TOP;
+ else if (x_circulate_event->place == PlaceOnBottom)
+ circulate_event->placement = POP_EVENT_CIRCULATE_PLACEMENT_BOTTOM;
+
+ return GDK_FILTER_TRANSLATE;
+}
+
+GdkFilterReturn
+pop_event_listener_filter_configure_event (XConfigureEvent *x_configure_event,
+ GdkEventConfigure *configure_event,
+ GdkWindow *window)
+{
+ GdkWindow *window_above;
+
+ /* Unfortunately, GdkEventConfigure doesn't have the same "above" member that
+ * the XConfigureEvent has, and we need it to report some stacking events.
+ */
+
+ if (x_configure_event->above == None)
+ window_above = NULL;
+ else
+ window_above = gdk_window_foreign_new (x_configure_event->above);
+
+ g_object_set_data (G_OBJECT (window), "pop-event-listener-window-above",
+ window_above);
+
+ if (window_above != NULL)
+ g_object_ref (window_above);
+
+ return GDK_FILTER_CONTINUE;
+}
+
+GdkFilterReturn
+pop_event_listener_filter (XEvent *x_event,
+ GdkEvent *event,
+ PopEventListener *listener)
+{
+ GdkWindow *window;
+
+ window = gdk_window_lookup (x_event->xany.window);
+
+ if (window == NULL)
+ return GDK_FILTER_CONTINUE;
+
+ if (x_event->type == pop_event_listener_damage_notify_event_type)
+ {
+ g_assert (sizeof (PopEventDamage) <= sizeof (*event));
+ return pop_event_listener_filter_damage_event ((XDamageNotifyEvent *) x_event,
+ (PopEventDamage *) event,
+ window);
+ }
+ else if (x_event->type == pop_event_listener_shape_notify_event_type)
+ {
+ g_assert (sizeof (PopEventShape) <= sizeof (*event));
+ return pop_event_listener_filter_shape_event ((XShapeEvent *) x_event,
+ (PopEventShape *) event,
+ window);
+ }
+ else if (x_event->type == ReparentNotify)
+ {
+ g_assert (sizeof (PopEventReparent) <= sizeof (*event));
+ return pop_event_listener_filter_reparent_event ((XReparentEvent *) x_event,
+ (PopEventReparent *) event,
+ window);
+ }
+ else if (x_event->type == CirculateNotify)
+ {
+ g_assert (sizeof (PopEventCirculate) <= sizeof (*event));
+ return pop_event_listener_filter_circulate_event ((XCirculateEvent *) x_event,
+ (PopEventCirculate *) event,
+ window);
+ }
+ else if (x_event->type == ConfigureNotify)
+ {
+ return pop_event_listener_filter_configure_event ((XConfigureEvent *) x_event,
+ (GdkEventConfigure *) event,
+ window);
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+pop_event_listener_start (PopEventListener *listener)
+{
+ /* used for questionable hack to get damage and shape events reported
+ */
+ gdk_window_add_filter (NULL, (GdkFilterFunc) pop_event_listener_filter,
+ listener);
+
+ /* translates gdk events to signals on the listener object
+ */
+ gdk_event_handler_set (pop_event_listener_event_handler,
+ listener, NULL);
+}
+
+static void
+pop_event_listener_stop (PopEventListener *listener)
+{
+ gdk_event_handler_set ((GdkEventFunc) gtk_main_do_event, NULL, NULL);
+}
+
+PopEventListener *
+pop_event_listener_get_default (void)
+{
+ static PopEventListener *listener = NULL;
+
+ if (listener == NULL)
+ {
+ listener = pop_event_listener_new (gdk_display_get_default ());
+ pop_event_listener_start (listener);
+ }
+
+ return g_object_ref (listener);
+}
+
+#ifdef POP_EVENT_LISTENER_ENABLE_TEST
+
+#include <stdio.h>
+#include <glib.h>
+
+int
+main (int argc, char **argv)
+{
+ PopEventListener *listener;
+ int exit_code;
+
+ g_log_set_always_fatal (G_LOG_LEVEL_ERROR
+ | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
+
+ g_type_init ();
+
+ g_message ("creating instance of 'event listener' object...");
+ listener = pop_event_listener_new (gdk_display_get_default ());
+ g_message ("'event listener' object created successfully");
+
+ g_message
+ ("destroying previously created 'event listener' object...");
+ g_object_unref (listener);
+ g_message ("'event listener' object destroyed successfully");
+
+ exit_code = 0;
+
+ return exit_code;
+}
+#endif /* POP_EVENT_LISTENER_ENABLE_TEST */
diff --git a/src/pop-event-listener.h b/src/pop-event-listener.h
new file mode 100644
index 0000000..fce4fcc
--- /dev/null
+++ b/src/pop-event-listener.h
@@ -0,0 +1,88 @@
+/* pop-event-listener.h - Listens for events on toplevel window and
+ * passes them to the appropriate window model
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef POP_EVENT_LISTENER_H
+#define POP_EVENT_LISTENER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdk/gdk.h>
+
+#include "pop-window-view.h"
+
+G_BEGIN_DECLS
+#define POP_TYPE_EVENT_LISTENER (pop_event_listener_get_type ())
+#define POP_EVENT_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POP_TYPE_EVENT_LISTENER, PopEventListener))
+#define POP_EVENT_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POP_TYPE_EVENT_LISTENER, PopEventListenerClass))
+#define POP_IS_EVENT_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), POP_TYPE_EVENT_LISTENER))
+#define POP_IS_EVENT_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POP_TYPE_EVENT_LISTENER))
+#define POP_EVENT_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), POP_TYPE_EVENT_LISTENER, PopEventListenerClass))
+#define POP_EVENT_LISTENER_ERROR (pop_event_listener_error_quark ())
+typedef struct _PopEventListener PopEventListener;
+typedef struct _PopEventListenerClass PopEventListenerClass;
+typedef struct _PopEventListenerPrivate PopEventListenerPrivate;
+typedef enum _PopEventListenerError PopEventListenerError;
+
+struct _PopEventListener
+{
+ GObject parent;
+
+ /*< private > */
+ PopEventListenerPrivate *priv;
+};
+
+struct _PopEventListenerClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (* window_created) (PopEventListener *listener, GdkWindow *window);
+ void (* window_destroyed) (PopEventListener *listener, GdkWindow *window);
+ void (* window_shown) (PopEventListener *listener, GdkWindow *window);
+ void (* window_hidden) (PopEventListener *listener, GdkWindow *window);
+ void (* window_resized) (PopEventListener *listener, GdkWindow *window);
+ void (* window_reshaped) (PopEventListener *listener, GdkWindow *window);
+ void (* window_reparented) (PopEventListener *listener, GdkWindow *window,
+ GdkWindow *new_parent);
+ void (* window_moved) (PopEventListener *listener, GdkWindow *window);
+ void (* window_redrawn) (PopEventListener *listener, GdkWindow *window,
+ GdkRectangle *redrawn_area);
+ void (* window_layered_under) (PopEventListener *listener, GdkWindow *window,
+ GdkWindow *above_window);
+ void (* window_layered_on_top) (PopEventListener *listener, GdkWindow *window);
+ void (* window_layered_on_bottom) (PopEventListener *listener, GdkWindow *window);
+};
+
+enum _PopEventListenerError
+{
+ POP_EVENT_LISTENER_ERROR_GENERIC = 0,
+};
+
+#ifndef POP_HIDE_FUNCTION_DECLARATIONS
+GType pop_event_listener_get_type (void);
+GQuark pop_event_listener_error_quark (void);
+
+PopEventListener *pop_event_listener_get_default (void);
+
+#endif
+
+G_END_DECLS
+#endif /* POP_EVENT_LISTENER_H */
diff --git a/src/pop-marshal.list b/src/pop-marshal.list
new file mode 100644
index 0000000..cc41355
--- /dev/null
+++ b/src/pop-marshal.list
@@ -0,0 +1,2 @@
+VOID:OBJECT,OBJECT
+VOID:OBJECT,POINTER
diff --git a/pop-overlay-window.c b/src/pop-overlay-window.c
index a64507a..955eccb 100644
--- a/pop-overlay-window.c
+++ b/src/pop-overlay-window.c
@@ -20,6 +20,7 @@
*
* Originally written by: Ray Strode <rstrode@redhat.com>
*/
+#include "config.h"
#include "pop-overlay-window.h"
#include <errno.h>
@@ -89,7 +90,7 @@ static void
pop_overlay_window_setup_parent_window (PopOverlayWindow *overlay_window)
{
GdkDisplay *display;
- GdkWindow *root_window, *parent_window;
+ GdkWindow *root_window;
Window parent_xwindow;
g_assert (POP_IS_OVERLAY_WINDOW (overlay_window));
@@ -265,7 +266,6 @@ static GdkRegion *
pop_overlay_window_create_region_from_allocation (PopOverlayWindow *overlay_window,
GtkAllocation *allocation)
{
- GdkDisplay *display;
GdkRectangle rectangle;
GdkRegion *region;
diff --git a/pop-overlay-window.h b/src/pop-overlay-window.h
index 9f3f832..9f3f832 100644
--- a/pop-overlay-window.h
+++ b/src/pop-overlay-window.h
diff --git a/src/pop-window-stack.c b/src/pop-window-stack.c
new file mode 100644
index 0000000..8ad0320
--- /dev/null
+++ b/src/pop-window-stack.c
@@ -0,0 +1,492 @@
+/* pop-window-stack.c - tracks the stacking order of toplevel windows
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "config.h"
+#include "pop-window-stack.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
+
+#include "pop-event-listener.h"
+
+struct _PopWindowStackPrivate
+{
+ GdkScreen *screen;
+ PopEventListener *event_listener;
+ GQueue *windows;
+};
+
+typedef struct
+{
+ PopWindowStack *stack;
+ PopWindowStackForeachFunc func;
+ gpointer user_data;
+} PopWindowStackForeachClosure;
+
+typedef struct
+{
+ PopWindowStack *stack;
+ GdkWindow *window;
+ PopWindowStackAboveWindowForeachFunc func;
+ gpointer user_data;
+} PopWindowStackAboveWindowForeachClosure;
+
+static void pop_window_stack_finalize (GObject * object);
+#if 0
+static void pop_window_stack_class_install_signals (PopWindowStackClass *
+ stack_class);
+#endif
+static void pop_window_stack_class_install_properties (PopWindowStackClass *
+ stack_class);
+
+static void pop_window_stack_set_property (GObject * object,
+ guint prop_id,
+ const GValue * value,
+ GParamSpec * pspec);
+static void pop_window_stack_get_property (GObject * object,
+ guint prop_id,
+ GValue * value,
+ GParamSpec * pspec);
+
+static void pop_window_stack_set_screen (PopWindowStack *stack,
+ GdkScreen *screen);
+static void pop_window_stack_clear_window_list (PopWindowStack *stack);
+static void pop_window_stack_get_initial_window_list (PopWindowStack *stack);
+
+
+enum
+{
+ PROP_0 = 0,
+ PROP_SCREEN
+};
+
+#if 0
+enum
+{
+ FOO = 0,
+ NUMBER_OF_SIGNALS
+};
+
+static guint pop_window_stack_signals[NUMBER_OF_SIGNALS];
+#endif
+
+G_DEFINE_TYPE (PopWindowStack, pop_window_stack, G_TYPE_OBJECT);
+
+static void
+pop_window_stack_class_init (PopWindowStackClass * stack_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (stack_class);
+
+ object_class->finalize = pop_window_stack_finalize;
+
+ pop_window_stack_class_install_properties (stack_class);
+#if 0
+ pop_window_stack_class_install_signals (stack_class);
+#endif
+
+ g_type_class_add_private (stack_class, sizeof (PopWindowStackPrivate));
+}
+
+#if 0
+static void
+pop_window_stack_class_install_signals (PopWindowStackClass * stack_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (stack_class);
+
+ pop_window_stack_signals[FOO] =
+ g_signal_new ("foo", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PopWindowStackClass, foo),
+ NULL, NULL, g_cclosure_marshal_VOID__NONE; G_TYPE_NONE, 0);
+ stack_class->foo = NULL;
+}
+#endif
+
+static void
+pop_window_stack_class_install_properties (PopWindowStackClass * stack_class)
+{
+ GObjectClass *object_class;
+ GParamSpec *param_spec;
+
+ object_class = G_OBJECT_CLASS (stack_class);
+ object_class->set_property = pop_window_stack_set_property;
+ object_class->get_property = pop_window_stack_get_property;
+
+ param_spec = g_param_spec_pointer ("screen", _("Screen"),
+ _("Which screen to user for tracking window stack"),
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_SCREEN, param_spec);
+}
+
+static void
+pop_window_stack_init (PopWindowStack *stack)
+{
+ stack->priv = G_TYPE_INSTANCE_GET_PRIVATE (stack,
+ POP_TYPE_WINDOW_STACK,
+ PopWindowStackPrivate);
+
+ stack->priv->event_listener = pop_event_listener_get_default ();
+ g_signal_connect_swapped (G_OBJECT (stack->priv->event_listener),
+ "window-layered-under",
+ G_CALLBACK (pop_window_stack_get_initial_window_list),
+ stack);
+ g_signal_connect_swapped (G_OBJECT (stack->priv->event_listener),
+ "window-layered-on-top",
+ G_CALLBACK (pop_window_stack_get_initial_window_list),
+ stack);
+ g_signal_connect_swapped (G_OBJECT (stack->priv->event_listener),
+ "window-layered-on-bottom",
+ G_CALLBACK (pop_window_stack_get_initial_window_list),
+ stack);
+
+ stack->priv->windows = g_queue_new ();
+}
+
+static void
+pop_window_stack_finalize (GObject * object)
+{
+ PopWindowStack *stack;
+ GObjectClass *parent_class;
+
+ stack = POP_WINDOW_STACK (object);
+
+ parent_class = G_OBJECT_CLASS (pop_window_stack_parent_class);
+
+ g_object_unref (stack->priv->event_listener);
+
+ pop_window_stack_clear_window_list (stack);
+ g_queue_free (stack->priv->windows);
+
+ if (parent_class->finalize != NULL)
+ parent_class->finalize (object);
+}
+
+static void
+pop_window_stack_set_property (GObject * object,
+ guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ PopWindowStack *stack = POP_WINDOW_STACK (object);
+
+ switch (prop_id)
+ {
+ case PROP_SCREEN:
+ pop_window_stack_set_screen (stack, g_value_get_pointer (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+pop_window_stack_get_property (GObject * object,
+ guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ PopWindowStack *stack = POP_WINDOW_STACK (object);
+
+ switch (prop_id)
+ {
+ case PROP_SCREEN:
+ g_value_set_pointer (value, stack->priv->screen);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+GQuark
+pop_window_stack_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (error_quark == 0)
+ error_quark = g_quark_from_static_string ("pop-window-stack");
+
+ return error_quark;
+}
+
+static PopWindowStack *
+pop_window_stack_new (GdkScreen *screen)
+{
+ PopWindowStack *stack;
+
+ if (screen == NULL)
+ screen = gdk_screen_get_default ();
+
+ stack = g_object_new (POP_TYPE_WINDOW_STACK,
+ "screen", screen, NULL);
+
+ return stack;
+}
+
+PopWindowStack *
+pop_window_stack_get_for_screen (GdkScreen *screen)
+{
+ static GList *stack_list = NULL, *tmp;
+ PopWindowStack *stack;
+
+ if (screen == NULL)
+ screen = gdk_screen_get_default ();
+
+ for (tmp = stack_list; tmp != NULL; tmp = tmp->next)
+ {
+ g_assert (POP_IS_WINDOW_STACK (tmp->data));
+
+ stack = POP_WINDOW_STACK (tmp->data);
+
+ if (gdk_screen_get_number (stack->priv->screen) ==
+ gdk_screen_get_number (screen))
+ return g_object_ref (screen);
+ }
+
+ stack = pop_window_stack_new (screen);
+ stack_list = g_list_prepend (stack_list, stack);
+
+ return g_object_ref (stack);
+}
+
+guint
+pop_window_stack_get_length (PopWindowStack *stack)
+{
+ g_return_val_if_fail (POP_IS_WINDOW_STACK (stack), 0);
+
+ return g_queue_get_length (stack->priv->windows);
+}
+
+static void
+pop_window_stack_foreach_func (gpointer data,
+ gpointer user_data)
+{
+ GdkWindow *window;
+ PopWindowStackForeachClosure *closure;
+
+ window = (GdkWindow *) data;
+ closure = (PopWindowStackForeachClosure *) user_data;
+
+ closure->func (closure->stack, window, closure->user_data);
+}
+
+void
+pop_window_stack_foreach (PopWindowStack *stack,
+ PopWindowStackForeachFunc func,
+ gpointer user_data)
+{
+ PopWindowStackForeachClosure closure;
+
+ g_return_if_fail (POP_IS_WINDOW_STACK (stack));
+ g_return_if_fail (func != NULL);
+
+ closure.stack = stack;
+ closure.func = func;
+ closure.user_data = user_data;
+
+ g_queue_foreach (stack->priv->windows, pop_window_stack_foreach_func, &closure);
+}
+
+static void
+pop_window_stack_above_window_foreach_func (gpointer data,
+ gpointer user_data)
+{
+ GdkWindow *above_window;
+ PopWindowStackAboveWindowForeachClosure *closure;
+
+ above_window = (GdkWindow *) data;
+ closure = (PopWindowStackAboveWindowForeachClosure *) user_data;
+
+ closure->func (closure->stack, closure->window, above_window, closure->user_data);
+}
+
+void
+pop_window_stack_above_window_foreach (PopWindowStack *stack,
+ GdkWindow *window,
+ PopWindowStackAboveWindowForeachFunc func,
+ gpointer user_data)
+{
+ PopWindowStackAboveWindowForeachClosure closure;
+ GList *window_link;
+
+ g_return_if_fail (POP_IS_WINDOW_STACK (stack));
+ g_return_if_fail (func != NULL);
+ g_return_if_fail (window != NULL);
+
+ window_link = g_queue_find (stack->priv->windows, window);
+
+ if (window_link == NULL)
+ {
+ g_warning ("window with id 0x%lx is not in window stack\n",
+ GDK_WINDOW_XWINDOW (window));
+ return;
+ }
+
+ closure.stack = stack;
+ closure.window = g_object_ref (window); closure.func = func;
+ closure.user_data = user_data;
+
+ g_list_foreach (window_link->next, pop_window_stack_above_window_foreach_func, &closure);
+
+ g_object_unref (window);
+}
+
+static void
+pop_window_stack_clear_window_list (PopWindowStack *stack)
+{
+ if (g_queue_is_empty (stack->priv->windows))
+ return;
+
+ g_queue_foreach (stack->priv->windows, (GFunc) g_object_unref, NULL);
+
+ g_queue_free (stack->priv->windows);
+ stack->priv->windows = g_queue_new ();
+}
+
+static gboolean
+window_can_output (GdkWindow *window)
+{
+ XWindowAttributes attrs;
+ gboolean received_attrs;
+
+ /* FIXME: this sucks because it requires a server round trip.
+ */
+
+ gdk_error_trap_push ();
+ received_attrs = XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XWINDOW (window),
+ &attrs);
+
+ if (gdk_error_trap_pop () || !received_attrs)
+ return FALSE;
+
+ return attrs.class == InputOutput;
+}
+
+static void
+pop_window_stack_get_initial_window_list (PopWindowStack *stack)
+{
+ GdkScreen *screen;
+ GdkDisplay *display;
+ Window root, parent, *children;
+ guint number_of_children, i;
+ gboolean query_was_successful;
+
+ pop_window_stack_clear_window_list (stack);
+
+ screen = stack->priv->screen;
+
+ if (screen == NULL)
+ screen = gdk_screen_get_default ();
+
+ display = gdk_screen_get_display (screen);
+
+ gdk_x11_display_grab (display);
+ query_was_successful =
+ XQueryTree (GDK_DISPLAY_XDISPLAY (display),
+ GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)),
+ &root, &parent, &children, &number_of_children);
+
+ if (query_was_successful)
+ {
+ for (i = 0; i < number_of_children; i++)
+ {
+ GdkWindow *window;
+
+ window = gdk_window_foreign_new_for_display (display, children[i]);
+
+ if (window == NULL)
+ continue;
+
+ if (!window_can_output (window))
+ {
+ g_print ("excluding window 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+ g_object_unref (window);
+ continue;
+ }
+
+ g_queue_push_tail (stack->priv->windows, window);
+ }
+ XFree (children);
+ }
+ gdk_x11_display_ungrab (display);
+}
+
+static void
+pop_window_stack_set_screen (PopWindowStack *stack,
+ GdkScreen *screen)
+{
+ if (screen != stack->priv->screen)
+ {
+ stack->priv->screen = screen;
+ pop_window_stack_get_initial_window_list (stack);
+ g_object_notify (G_OBJECT (stack), "screen");
+ }
+}
+
+#ifdef POP_WINDOW_STACK_ENABLE_TEST
+
+#include <stdio.h>
+#include <glib.h>
+
+static void
+print_toplevel (PopWindowStack *stack,
+ GdkWindow *window,
+ gpointer data)
+{
+ g_print ("0x%lx\n", GDK_WINDOW_XWINDOW (window));
+}
+
+int
+main (int argc, char **argv)
+{
+ PopWindowStack *stack;
+ int exit_code;
+
+ g_log_set_always_fatal (G_LOG_LEVEL_ERROR
+ | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
+
+ g_type_init ();
+ gtk_init (&argc, &argv);
+
+ g_message ("creating instance of 'window stack' object...");
+ stack = pop_window_stack_new (gdk_screen_get_default ());
+ g_message ("'window stack' object created successfully");
+
+ pop_window_stack_foreach (stack, print_toplevel, NULL);
+
+ g_message ("destroying previously created 'window stack' object...");
+ g_object_unref (stack);
+ g_message ("'window stack' object destroyed successfully");
+
+ exit_code = 0;
+
+ return exit_code;
+}
+#endif /* POP_WINDOW_STACK_ENABLE_TEST */
diff --git a/src/pop-window-stack.h b/src/pop-window-stack.h
new file mode 100644
index 0000000..d8e7803
--- /dev/null
+++ b/src/pop-window-stack.h
@@ -0,0 +1,83 @@
+/* pop-window-stack.h - tracks the stacking order of toplevel windows
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef POP_WINDOW_STACK_H
+#define POP_WINDOW_STACK_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+#define POP_TYPE_WINDOW_STACK (pop_window_stack_get_type ())
+#define POP_WINDOW_STACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POP_TYPE_WINDOW_STACK, PopWindowStack))
+#define POP_WINDOW_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POP_TYPE_WINDOW_STACK, PopWindowStackClass))
+#define POP_IS_WINDOW_STACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), POP_TYPE_WINDOW_STACK))
+#define POP_IS_WINDOW_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POP_TYPE_WINDOW_STACK))
+#define POP_WINDOW_STACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), POP_TYPE_WINDOW_STACK, PopWindowStackClass))
+#define POP_WINDOW_STACK_ERROR (pop_window_stack_error_quark ())
+typedef struct _PopWindowStack PopWindowStack;
+typedef struct _PopWindowStackClass PopWindowStackClass;
+typedef struct _PopWindowStackPrivate PopWindowStackPrivate;
+typedef enum _PopWindowStackError PopWindowStackError;
+typedef void (* PopWindowStackForeachFunc) (PopWindowStack *stack, GdkWindow *window, gpointer user_data);
+typedef void (* PopWindowStackAboveWindowForeachFunc) (PopWindowStack *stack, GdkWindow *window, GdkWindow *above_window, gpointer user_data);
+
+struct _PopWindowStack
+{
+ GObject parent;
+
+ /*< private > */
+ PopWindowStackPrivate *priv;
+};
+
+struct _PopWindowStackClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+#if 0
+ void (*foo) (PopWindowStack * stack);
+#endif
+};
+
+enum _PopWindowStackError
+{
+ POP_WINDOW_STACK_ERROR_GENERIC = 0,
+};
+
+#ifndef POP_HIDE_FUNCTION_DECLARATIONS
+GType pop_window_stack_get_type (void);
+GQuark pop_window_stack_error_quark (void);
+
+PopWindowStack *pop_window_stack_get_for_screen (GdkScreen *screen);
+guint pop_window_stack_get_length (PopWindowStack *stack);
+void pop_window_stack_foreach (PopWindowStack *stack,
+ PopWindowStackForeachFunc func,
+ gpointer user_data);
+void pop_window_stack_above_window_foreach (PopWindowStack *stack,
+ GdkWindow *window,
+ PopWindowStackAboveWindowForeachFunc func,
+ gpointer user_data);
+
+#endif
+
+G_END_DECLS
+#endif /* POP_WINDOW_STACK_H */
diff --git a/src/pop-window-view.c b/src/pop-window-view.c
new file mode 100644
index 0000000..9e7f3dd
--- /dev/null
+++ b/src/pop-window-view.c
@@ -0,0 +1,1061 @@
+/* pop-window-view.c - view of redirected offscreen windows
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "config.h"
+#include "pop-window-view.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include <cairo.h>
+
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/shape.h>
+
+#include <cairo-xlib.h>
+#include <gdk/gdkx.h>
+
+#include <gdk/gdk.h>
+
+#include "pop-event-listener.h"
+
+struct _PopWindowViewPrivate
+{
+ GdkWindow *window;
+ PopEventListener *event_listener;
+
+ Damage damage;
+ cairo_pattern_t *pattern;
+ cairo_path_t *clip_path;
+
+ GdkRectangle damaged_area;
+
+ guint is_mapped : 1;
+ guint is_damaged : 1;
+
+ gint x, y;
+ gint width, height;
+};
+
+static void pop_window_view_class_install_signals (PopWindowViewClass *view_class);
+static void pop_window_view_class_install_properties (PopWindowViewClass *view_class);
+
+static void pop_window_view_set_property (GObject * object,
+ guint prop_id,
+ const GValue * value,
+ GParamSpec * pspec);
+static void pop_window_view_get_property (GObject * object,
+ guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void pop_window_view_do_finalize (GObject *object);
+
+enum
+{
+ PROP_0 = 0,
+ PROP_WINDOW
+};
+
+#define POP_WINDOW_VIEW_INVALID_WINDOW (Window) 0
+#define POP_WINDOW_VIEW_INVALID_PIXMAP (Pixmap) 0
+#define POP_WINDOW_VIEW_INVALID_DAMAGE (Damage) 0
+
+#if 0
+enum
+{
+ FOO = 0,
+ NUMBER_OF_SIGNALS
+};
+
+static guint pop_window_view_signals[NUMBER_OF_SIGNALS];
+#endif
+
+G_DEFINE_TYPE (PopWindowView, pop_window_view, G_TYPE_OBJECT);
+
+static void
+pop_window_view_class_init (PopWindowViewClass *view_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (view_class);
+
+ object_class->finalize = pop_window_view_do_finalize;
+
+ pop_window_view_class_install_properties (view_class);
+#if 0
+ pop_window_view_class_install_signals (view_class);
+#endif
+
+ g_type_class_add_private (view_class, sizeof (PopWindowViewPrivate));
+}
+
+#if 0
+static void
+pop_window_view_class_install_signals (PopWindowViewClass * view_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (view_class);
+
+ pop_window_view_signals[FOO] =
+ g_signal_new ("foo", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PopWindowViewClass, foo),
+ NULL, NULL, g_cclosure_marshal_VOID__NONE; G_TYPE_NONE, 0);
+ view_class->foo = NULL;
+}
+#endif
+
+static void
+pop_window_view_class_install_properties (PopWindowViewClass *view_class)
+{
+ GObjectClass *object_class;
+ GParamSpec *param_spec;
+
+ object_class = G_OBJECT_CLASS (view_class);
+ object_class->set_property = pop_window_view_set_property;
+ object_class->get_property = pop_window_view_get_property;
+
+ param_spec = NULL;
+#if 0
+ param_spec = g_param_spec_ulong ("x-window-id", _("X Window ID"),
+ _("A client-side identifier representing a "
+ "server-side window"), 0, G_MAXULONG,
+ (gulong) POP_WINDOW_VIEW_INVALID_WINDOW,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_WINDOW, param_spec);
+#endif
+}
+
+static void
+pop_window_view_init (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view,
+ POP_TYPE_WINDOW_VIEW,
+ PopWindowViewPrivate);
+
+ view->priv->event_listener = pop_event_listener_get_default ();
+}
+
+static void
+pop_window_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PopWindowView *view = POP_WINDOW_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_WINDOW:
+ view = NULL;
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+pop_window_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PopWindowView *view = POP_WINDOW_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_WINDOW:
+ view = NULL;
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+pop_window_view_do_finalize (GObject *object)
+{
+ PopWindowView *view;
+ GObjectClass *parent_class;
+
+ view = POP_WINDOW_VIEW (object);
+
+ if (view->priv->window != NULL)
+ pop_window_view_unset_window (view);
+
+ parent_class = G_OBJECT_CLASS (pop_window_view_parent_class);
+
+ if (parent_class->finalize != NULL)
+ parent_class->finalize (object);
+}
+
+static gboolean
+pop_window_get_initial_geometry (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+ g_assert (view->priv->window != NULL);
+
+ gdk_window_get_geometry (view->priv->window,
+ &view->priv->x,
+ &view->priv->y,
+ &view->priv->width,
+ &view->priv->height,
+ NULL);
+ return TRUE;
+}
+
+static cairo_surface_t *
+pop_window_view_get_surface (PopWindowView *view)
+{
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+ g_assert (view->priv->pattern != NULL);
+
+ surface = NULL;
+ status = cairo_pattern_get_surface (view->priv->pattern, &surface);
+ g_assert (status != CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
+
+ return surface;
+}
+
+static void
+pop_window_view_free_x_pixmap (PopWindowView *view)
+{
+ cairo_surface_t *surface;
+ Pixmap pixmap;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ surface = pop_window_view_get_surface (view);
+
+ g_assert (surface != NULL);
+ pixmap = (Pixmap) cairo_xlib_surface_get_drawable (surface);
+ XFreePixmap (GDK_WINDOW_XDISPLAY (view->priv->window), pixmap);
+}
+
+static void
+pop_window_view_destroy_pattern (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ if (view->priv->pattern == NULL)
+ return;
+
+ pop_window_view_free_x_pixmap (view);
+ cairo_pattern_destroy (view->priv->pattern);
+ view->priv->pattern = NULL;
+}
+
+static void
+pop_window_view_destroy_clip_path (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ if (view->priv->clip_path == NULL)
+ return;
+
+ cairo_path_destroy (view->priv->clip_path);
+ view->priv->clip_path = NULL;
+}
+
+GQuark
+pop_window_view_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (error_quark == 0)
+ error_quark = g_quark_from_static_string ("pop-window");
+
+ return error_quark;
+}
+
+PopWindowView *
+pop_window_view_new (void)
+{
+ PopWindowView *view;
+
+ view = g_object_new (POP_TYPE_WINDOW_VIEW, NULL);
+
+ return view;
+}
+
+static gboolean
+pop_window_view_redirect_window_off_screen (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ gdk_error_trap_push ();
+ XCompositeRedirectWindow (GDK_WINDOW_XDISPLAY (view->priv->window),
+ GDK_WINDOW_XWINDOW (view->priv->window),
+ CompositeRedirectAutomatic);
+ gdk_flush ();
+ if (gdk_error_trap_pop ())
+ return FALSE;
+
+ return TRUE;
+}
+
+static Pixmap
+pop_window_view_fetch_window_pixmap (PopWindowView *view)
+{
+ Pixmap pixmap;
+ gint status;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ gdk_error_trap_push ();
+ pixmap =
+ XCompositeNameWindowPixmap (GDK_WINDOW_XDISPLAY (view->priv->window),
+ GDK_WINDOW_XWINDOW (view->priv->window));
+ gdk_flush ();
+ status = gdk_error_trap_pop ();
+
+ if (status != Success)
+ {
+ char error_message[64];
+
+ XGetErrorText (GDK_WINDOW_XDISPLAY (view->priv->window),
+ status, error_message, sizeof (error_message) - 1);
+ g_print ("could not name pixmap for window 0x%lx: %s\n",
+ GDK_WINDOW_XWINDOW (view->priv->window),
+ error_message);
+
+ return POP_WINDOW_VIEW_INVALID_PIXMAP;
+ }
+
+ return pixmap;
+}
+
+static gboolean
+pop_window_view_create_pattern_from_window (PopWindowView *view)
+{
+ GdkVisual *visual;
+ Pixmap pixmap;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ int width, height;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+ g_assert (view->priv->window != NULL);
+ g_assert (view->priv->pattern == NULL);
+
+ pixmap = pop_window_view_fetch_window_pixmap (view);
+
+ if (pixmap == POP_WINDOW_VIEW_INVALID_PIXMAP)
+ {
+ g_print ("couldn't fetch pixmap for window\n");
+ return FALSE;
+ }
+
+ gdk_drawable_get_size (GDK_DRAWABLE (view->priv->window),
+ &width, &height);
+
+ visual = gdk_drawable_get_visual (GDK_DRAWABLE (view->priv->window));
+ surface = cairo_xlib_surface_create (GDK_WINDOW_XDISPLAY (view->priv->window),
+ (Drawable) pixmap,
+ GDK_VISUAL_XVISUAL (visual),
+ width, height);
+ status = cairo_surface_status (surface);
+ if (status != CAIRO_STATUS_SUCCESS)
+ {
+ g_print ("could create xlib surface for window: %s\n", cairo_status_to_string (status));
+ goto failed;
+ }
+
+ view->priv->pattern = cairo_pattern_create_for_surface (surface);
+ cairo_surface_destroy (surface);
+
+ status = cairo_pattern_status (view->priv->pattern);
+ if (status != CAIRO_STATUS_SUCCESS)
+ {
+ g_print ("couldn't create cairo pattern: %s\n", cairo_status_to_string (status));
+ goto failed;
+ }
+
+ return TRUE;
+
+failed:
+ if (view->priv->pattern != NULL)
+ {
+ cairo_pattern_destroy (view->priv->pattern);
+ view->priv->pattern = NULL;
+ }
+
+ XFreePixmap (GDK_WINDOW_XDISPLAY (view->priv->window),
+ pixmap);
+
+ return FALSE;
+}
+
+static XRectangle *
+pop_window_view_get_tesselated_window_shape (PopWindowView *view,
+ gint *number_of_rectangles)
+{
+ XRectangle *rectangles;
+ gint ordering;
+ gint status;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+ g_assert (number_of_rectangles != NULL);
+
+ *number_of_rectangles = 0;
+
+ gdk_error_trap_push ();
+ rectangles = XShapeGetRectangles (GDK_WINDOW_XDISPLAY (view->priv->window),
+ GDK_WINDOW_XWINDOW (view->priv->window),
+ ShapeBounding, number_of_rectangles,
+ &ordering);
+ gdk_flush ();
+ status = gdk_error_trap_pop ();
+
+ if (status != Success)
+ return NULL;
+
+ return rectangles;
+}
+
+
+static gboolean
+pop_window_view_set_clip_path_from_window (PopWindowView *view)
+{
+ XRectangle *rectangles;
+ gint number_of_rectangles;
+ cairo_t *cairo_context;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ gint i;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+ g_assert (view->priv->clip_path == NULL);
+
+ rectangles = pop_window_view_get_tesselated_window_shape (view,
+ &number_of_rectangles);
+
+ if (rectangles == NULL)
+ return FALSE;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_A1,
+ view->priv->width, view->priv->height);
+
+ status = cairo_surface_status (surface);
+
+ if (status != CAIRO_STATUS_SUCCESS)
+ {
+ cairo_surface_destroy (surface);
+ XFree (rectangles);
+ return FALSE;
+ }
+
+ cairo_context = cairo_create (surface);
+
+ for (i = 0; i < number_of_rectangles; i++)
+ {
+ cairo_rectangle (cairo_context,
+ rectangles[i].x,
+ rectangles[i].y,
+ rectangles[i].width,
+ rectangles[i].height);
+ }
+ XFree (rectangles);
+
+ view->priv->clip_path = cairo_copy_path_flat (cairo_context);
+ cairo_destroy (cairo_context);
+ cairo_surface_destroy (surface);
+
+ return TRUE;
+}
+
+static gboolean
+pop_window_view_set_clip_path_for_placeholder (PopWindowView *view)
+{
+ cairo_t *cairo_context;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+ g_assert (view->priv->clip_path == NULL);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_A1,
+ view->priv->width, view->priv->height);
+
+ status = cairo_surface_status (surface);
+
+ if (status != CAIRO_STATUS_SUCCESS)
+ {
+ cairo_surface_destroy (surface);
+ return FALSE;
+ }
+
+ cairo_context = cairo_create (surface);
+
+ cairo_rectangle (cairo_context,
+ view->priv->x, view->priv->y,
+ view->priv->width, view->priv->height);
+
+ view->priv->clip_path = cairo_copy_path_flat (cairo_context);
+ cairo_destroy (cairo_context);
+ cairo_surface_destroy (surface);
+
+ return TRUE;
+}
+
+static void
+pop_window_view_enable_window_geometry_reporting (PopWindowView *view)
+{
+ GdkEventMask event_mask;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ event_mask = gdk_window_get_events (view->priv->window);
+
+ gdk_window_set_events (view->priv->window, event_mask | GDK_STRUCTURE_MASK | GDK_EXPOSURE_MASK);
+}
+
+static void
+pop_window_view_disable_window_geometry_reporting (PopWindowView *view)
+{
+ GdkEventMask event_mask;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ event_mask = gdk_window_get_events (view->priv->window);
+
+ gdk_window_set_events (view->priv->window, event_mask & ~GDK_STRUCTURE_MASK);
+}
+
+static void
+pop_window_view_enable_window_shape_reporting (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ XShapeSelectInput (GDK_WINDOW_XDISPLAY (view->priv->window),
+ GDK_WINDOW_XWINDOW (view->priv->window),
+ ShapeNotifyMask);
+}
+
+static void
+pop_window_view_disable_window_shape_reporting (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ XShapeSelectInput (GDK_WINDOW_XDISPLAY (view->priv->window),
+ GDK_WINDOW_XWINDOW (view->priv->window),
+ 0);
+}
+
+static void
+pop_window_view_enable_window_damage_reporting (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ view->priv->damage =
+ XDamageCreate (GDK_WINDOW_XDISPLAY (view->priv->window),
+ GDK_WINDOW_XWINDOW (view->priv->window),
+ XDamageReportBoundingBox);
+}
+
+static void
+pop_window_view_disable_window_damage_reporting (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ gdk_error_trap_push ();
+ XDamageDestroy (GDK_WINDOW_XDISPLAY (view->priv->window),
+ view->priv->damage);
+ gdk_flush ();
+ gdk_error_trap_pop ();
+ view->priv->damage = POP_WINDOW_VIEW_INVALID_DAMAGE;
+}
+
+static void
+pop_window_view_window_redrawn (PopWindowView *view,
+ GdkWindow *window,
+ GdkRectangle *rectangle)
+{
+ g_print ("window 0x%lx redrawn (area: %dx%d+%d+%d)\n", GDK_WINDOW_XWINDOW (view->priv->window), rectangle->x, rectangle->y, rectangle->width, rectangle->height);
+ if (view->priv->pattern == NULL)
+ pop_window_view_create_pattern_from_window (view);
+
+ if (view->priv->clip_path == NULL)
+ pop_window_view_set_clip_path_from_window (view);
+
+ gdk_rectangle_union (&view->priv->damaged_area,
+ rectangle,
+ &view->priv->damaged_area);
+
+ view->priv->is_damaged = TRUE;
+}
+
+void
+pop_window_view_window_resized (PopWindowView *view)
+{
+ gint old_width, old_height;
+
+ g_print ("window 0x%lx resized\n", GDK_WINDOW_XWINDOW (view->priv->window));
+
+ old_width = view->priv->width;
+ old_height = view->priv->height;
+
+ gdk_drawable_get_size (GDK_DRAWABLE (view->priv->window),
+ &view->priv->width,
+ &view->priv->height);
+ if (view->priv->pattern != NULL)
+ {
+ pop_window_view_destroy_pattern (view);
+ pop_window_view_create_pattern_from_window (view);
+ }
+
+ if (view->priv->clip_path != NULL)
+ {
+ pop_window_view_destroy_clip_path (view);
+ pop_window_view_set_clip_path_from_window (view);
+ }
+
+ g_print ("window 0x%lx resized from (%dx%d) to (%dx%d)\n",
+ GDK_WINDOW_XWINDOW (view->priv->window),
+ old_width, old_height,
+ view->priv->width, view->priv->height);
+}
+
+void
+pop_window_view_window_moved (PopWindowView *view)
+{
+ gint old_x, old_y;
+
+ old_x = view->priv->x;
+ old_y = view->priv->y;
+
+ gdk_window_get_position (GDK_DRAWABLE (view->priv->window),
+ &view->priv->x,
+ &view->priv->y);
+
+ g_print ("window 0x%lx moved from (%d, %d) to (%d, %d)\n",
+ GDK_WINDOW_XWINDOW (view->priv->window),
+ old_x, old_y, view->priv->x, view->priv->y);
+}
+
+static void
+pop_window_view_window_shown (PopWindowView *view)
+{
+ g_print ("window 0x%lx is now visible\n",
+ GDK_WINDOW_XWINDOW (view->priv->window));
+
+ view->priv->is_mapped = TRUE;
+
+#if 0
+ if (view->priv->pattern == NULL)
+ pop_window_view_create_pattern_from_window (view);
+
+ if (view->priv->clip_path == NULL)
+ pop_window_view_set_clip_path_from_window (view);
+#endif
+}
+
+static void
+pop_window_view_window_hidden (PopWindowView *view)
+{
+
+ view->priv->is_mapped = FALSE;
+ g_print ("window 0x%lx hidden\n", GDK_WINDOW_XWINDOW (view->priv->window));
+ pop_window_view_destroy_pattern (view);
+}
+
+static void
+pop_window_view_window_destroyed (PopWindowView *view)
+{
+ g_print ("window 0x%lx destroyed\n", GDK_WINDOW_XWINDOW (view->priv->window));
+ pop_window_view_unset_window (view);
+}
+
+static void
+pop_window_view_window_reshaped (PopWindowView *view)
+{
+ gint old_width, old_height;
+
+ g_print ("window 0x%lx reshaped\n", GDK_WINDOW_XWINDOW (view->priv->window));
+ old_width = view->priv->width;
+ old_height = view->priv->height;
+
+ gdk_drawable_get_size (GDK_DRAWABLE (view->priv->window),
+ &view->priv->width,
+ &view->priv->height);
+ if (view->priv->pattern != NULL)
+ {
+ pop_window_view_destroy_pattern (view);
+ pop_window_view_create_pattern_from_window (view);
+ }
+
+ if (view->priv->clip_path != NULL)
+ {
+ pop_window_view_destroy_clip_path (view);
+ pop_window_view_set_clip_path_from_window (view);
+ }
+}
+
+static void
+pop_window_view_window_reparented (PopWindowView *view)
+{
+ g_print ("window 0x%lx reparented\n", GDK_WINDOW_XWINDOW (view->priv->window));
+ pop_window_view_unset_window (view);
+}
+
+static void
+pop_window_view_listen_to_window (PopWindowView *view)
+{
+ gchar detailed_signal[sizeof ("window-XXXXXXXXXX::ffffffff")];
+
+ g_print ("listening to window 0x%lx\n", GDK_WINDOW_XWINDOW (view->priv->window));
+
+ snprintf (detailed_signal, sizeof (detailed_signal),
+ "window-destroyed::%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ g_signal_connect_swapped (G_OBJECT (view->priv->event_listener),
+ detailed_signal,
+ G_CALLBACK (pop_window_view_window_destroyed),
+ view);
+ snprintf (detailed_signal, sizeof (detailed_signal),
+ "window-shown::%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ g_signal_connect_swapped (G_OBJECT (view->priv->event_listener),
+ detailed_signal,
+ G_CALLBACK (pop_window_view_window_shown),
+ view);
+ snprintf (detailed_signal, sizeof (detailed_signal),
+ "window-hidden::%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ g_signal_connect_swapped (G_OBJECT (view->priv->event_listener),
+ detailed_signal,
+ G_CALLBACK (pop_window_view_window_hidden),
+ view);
+ snprintf (detailed_signal, sizeof (detailed_signal),
+ "window-resized::%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ g_signal_connect_swapped (G_OBJECT (view->priv->event_listener),
+ detailed_signal,
+ G_CALLBACK (pop_window_view_window_resized),
+ view);
+ snprintf (detailed_signal, sizeof (detailed_signal),
+ "window-reshaped::%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ g_signal_connect_swapped (G_OBJECT (view->priv->event_listener),
+ detailed_signal,
+ G_CALLBACK (pop_window_view_window_reshaped),
+ view);
+ snprintf (detailed_signal, sizeof (detailed_signal),
+ "window-reparented::%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ g_signal_connect_swapped (G_OBJECT (view->priv->event_listener),
+ detailed_signal,
+ G_CALLBACK (pop_window_view_window_reparented),
+ view);
+ snprintf (detailed_signal, sizeof (detailed_signal),
+ "window-moved::%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ g_signal_connect_swapped (G_OBJECT (view->priv->event_listener),
+ detailed_signal,
+ G_CALLBACK (pop_window_view_window_moved),
+ view);
+ snprintf (detailed_signal, sizeof (detailed_signal),
+ "window-redrawn::%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ g_signal_connect_swapped (G_OBJECT (view->priv->event_listener),
+ detailed_signal,
+ G_CALLBACK (pop_window_view_window_redrawn),
+ view);
+}
+
+static void
+pop_window_view_ignore_window (PopWindowView *view)
+{
+ g_print ("ignoring window 0x%lx\n", GDK_WINDOW_XWINDOW (view->priv->window));
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->event_listener),
+ G_CALLBACK (pop_window_view_window_destroyed),
+ view);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->event_listener),
+ G_CALLBACK (pop_window_view_window_shown),
+ view);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->event_listener),
+ G_CALLBACK (pop_window_view_window_hidden),
+ view);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->event_listener),
+ G_CALLBACK (pop_window_view_window_resized),
+ view);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->event_listener),
+ G_CALLBACK (pop_window_view_window_reshaped),
+ view);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->event_listener),
+ G_CALLBACK (pop_window_view_window_reparented),
+ view);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->event_listener),
+ G_CALLBACK (pop_window_view_window_moved),
+ view);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->event_listener),
+ G_CALLBACK (pop_window_view_window_redrawn),
+ view);
+}
+
+static gboolean
+pop_window_view_enable_window_status_reporting (PopWindowView *view)
+{
+ gint status;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ gdk_error_trap_push ();
+ pop_window_view_enable_window_geometry_reporting (view);
+ pop_window_view_enable_window_shape_reporting (view);
+ pop_window_view_enable_window_damage_reporting (view);
+ pop_window_view_listen_to_window (view);
+ gdk_flush ();
+ status = gdk_error_trap_pop ();
+
+ return status == Success;
+}
+
+static void
+pop_window_view_disable_window_status_reporting (PopWindowView *view)
+{
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ if ((view->priv->window == NULL) || GDK_WINDOW_DESTROYED (view->priv->window))
+ return;
+
+ pop_window_view_disable_window_damage_reporting (view);
+
+ gdk_error_trap_push ();
+ pop_window_view_disable_window_geometry_reporting (view);
+ pop_window_view_disable_window_shape_reporting (view);
+ pop_window_view_ignore_window (view);
+ gdk_flush ();
+ gdk_error_trap_pop ();
+}
+
+gboolean
+pop_window_view_set_window (PopWindowView *view,
+ GdkWindow *window)
+{
+ g_return_val_if_fail (POP_IS_WINDOW_VIEW (view), FALSE);
+ g_return_val_if_fail (window != NULL, FALSE);
+
+ g_return_val_if_fail (view->priv->window == NULL, FALSE);
+ view->priv->window = window;
+
+ if (!pop_window_get_initial_geometry (view))
+ {
+ g_print ("couldn't get initial geometry\n");
+ view->priv->window = NULL;
+ return FALSE;
+ }
+
+ if (!pop_window_view_enable_window_status_reporting (view))
+ {
+ g_print ("couldn't enable damage for window\n");
+ pop_window_view_disable_window_status_reporting (view);
+ view->priv->window = NULL;
+ return FALSE;
+ }
+
+ if (!pop_window_view_redirect_window_off_screen (view))
+ {
+ g_print ("couldn't redirect window off screen\n");
+ view->priv->window = NULL;
+ return FALSE;
+ }
+
+ if (gdk_window_is_visible (view->priv->window))
+ view->priv->is_mapped = TRUE;
+
+ g_object_ref (window);
+
+ return TRUE;
+}
+
+void
+pop_window_view_unset_window (PopWindowView *view)
+{
+ g_return_if_fail (POP_IS_WINDOW_VIEW (view));
+ g_return_if_fail (view->priv->window != NULL);
+
+ pop_window_view_disable_window_status_reporting (view);
+ pop_window_view_destroy_clip_path (view);
+ pop_window_view_destroy_pattern (view);
+
+ g_object_unref (view->priv->window);
+ view->priv->window = NULL;
+
+ g_object_unref (view->priv->event_listener);
+ view->priv->event_listener = NULL;
+}
+
+GdkWindow *
+pop_window_view_get_window (PopWindowView *view)
+{
+ g_return_val_if_fail (POP_IS_WINDOW_VIEW (view), NULL);
+
+ return view->priv->window;
+}
+
+void
+pop_window_view_report_fixed_damage (PopWindowView *view)
+{
+ gdk_error_trap_push ();
+ XDamageSubtract (GDK_WINDOW_XDISPLAY (view->priv->window),
+ view->priv->damage, None, None);
+ gdk_flush ();
+ gdk_error_trap_pop ();
+
+ view->priv->is_damaged = FALSE;
+ view->priv->damaged_area.x = 0;
+ view->priv->damaged_area.y = 0;
+ view->priv->damaged_area.width = 0;
+ view->priv->damaged_area.height = 0;
+}
+
+static GdkRegion *
+pop_window_view_get_bounding_region (PopWindowView *view)
+{
+ GdkRectangle bounding_area;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ bounding_area.x = view->priv->x;
+ bounding_area.y = view->priv->y;
+ bounding_area.width = view->priv->width;
+ bounding_area.height = view->priv->height;
+
+ return gdk_region_rectangle (&bounding_area);
+}
+
+GdkRegion *
+pop_window_view_get_difference (PopWindowView *view,
+ PopWindowView *other_view)
+{
+ GdkRegion *view_bounding_region, *other_view_bounding_region;
+
+ g_return_val_if_fail (POP_IS_WINDOW_VIEW (view), NULL);
+ g_return_val_if_fail (POP_IS_WINDOW_VIEW (other_view), NULL);
+
+ if (!gdk_window_is_visible (view->priv->window))
+ return gdk_region_new ();
+
+ view_bounding_region = pop_window_view_get_bounding_region (view);
+
+ if (!gdk_window_is_visible (other_view->priv->window))
+ return view_bounding_region;
+ other_view_bounding_region = pop_window_view_get_bounding_region (other_view);
+
+ /* This is the part of the view that isn't overlapped by the
+ * other view
+ */
+ gdk_region_subtract (view_bounding_region, other_view_bounding_region);
+ gdk_region_destroy (other_view_bounding_region);
+ other_view_bounding_region = NULL;
+
+ /* FIXME: need to also add in overlapping areas where the other view isn't
+ * fully opaque.
+ */
+ return view_bounding_region;
+}
+
+static void
+pop_window_view_render_placeholder_to_context (PopWindowView *view,
+ cairo_t *cairo_context)
+{
+
+ cairo_translate (cairo_context, view->priv->x, view->priv->y);
+
+ cairo_set_source_rgba (cairo_context, 1.0, 1.0, 1.0, .75);
+ cairo_rectangle (cairo_context, 0.0, 0.0,
+ view->priv->width, view->priv->height);
+ cairo_clip (cairo_context);
+ cairo_paint (cairo_context);
+
+ cairo_set_source_rgb (cairo_context, 0.0, 0.0, 0.0);
+ cairo_rectangle (cairo_context, 0.0, 0.0,
+ view->priv->width, view->priv->height);
+ cairo_stroke (cairo_context);
+}
+
+void
+pop_window_view_render_to_context (PopWindowView *view,
+ cairo_t *cairo_context)
+{
+ g_return_if_fail (POP_IS_WINDOW_VIEW (view));
+ g_return_if_fail (cairo_context != NULL);
+
+ if (view->priv->pattern == NULL)
+ {
+ if (gdk_window_is_visible (view->priv->window))
+ pop_window_view_render_placeholder_to_context (view, cairo_context);
+ return;
+ }
+
+ if (!view->priv->is_damaged && FALSE)
+ return;
+
+ g_assert (view->priv->clip_path != NULL);
+
+ pop_window_view_report_fixed_damage (view);
+
+ cairo_translate (cairo_context, view->priv->x, view->priv->y);
+#if 0
+ char *text;
+ text = g_strdup_printf ("0x%lx", GDK_WINDOW_XWINDOW (view->priv->window));
+ cairo_move_to (cairo_context, view->priv->width, view->priv->height);
+ cairo_set_source_rgb (cairo_context, 1.0, 0.0, 1.0);
+ cairo_show_text (cairo_context, text);
+ g_free (text);
+#endif
+
+ cairo_set_source (cairo_context, view->priv->pattern);
+ cairo_move_to (cairo_context, 0.0, 0.0);
+ cairo_append_path (cairo_context, view->priv->clip_path);
+ cairo_clip (cairo_context);
+ cairo_paint (cairo_context);
+}
+
+void
+pop_window_view_get_size (PopWindowView *view,
+ int *width,
+ int *height)
+{
+
+ if (width)
+ *width = view->priv->width;
+
+ if (height)
+ *height = view->priv->height;
+}
+
+void
+pop_window_view_get_position (PopWindowView *view,
+ int *x,
+ int *y)
+{
+ if (x)
+ *x = view->priv->x;
+
+ if (y)
+ *y = view->priv->y;
+}
diff --git a/src/pop-window-view.h b/src/pop-window-view.h
new file mode 100644
index 0000000..3e3bb5b
--- /dev/null
+++ b/src/pop-window-view.h
@@ -0,0 +1,83 @@
+/* pop-window-view.h - view of redirected offscreen windows
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef POP_WINDOW_VIEW_H
+#define POP_WINDOW_VIEW_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <X11/X.h>
+
+#include <cairo.h>
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+#define POP_TYPE_WINDOW_VIEW (pop_window_view_get_type ())
+#define POP_WINDOW_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POP_TYPE_WINDOW_VIEW, PopWindowView))
+#define POP_WINDOW_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POP_TYPE_WINDOW_VIEW, PopWindowViewClass))
+#define POP_IS_WINDOW_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), POP_TYPE_WINDOW_VIEW))
+#define POP_IS_WINDOW_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POP_TYPE_WINDOW_VIEW))
+#define POP_WINDOW_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), POP_TYPE_WINDOW_VIEW, PopWindowViewClass))
+#define POP_WINDOW_VIEW_ERROR (pop_window_view_error_quark ())
+typedef struct _PopWindowView PopWindowView;
+typedef struct _PopWindowViewClass PopWindowViewClass;
+typedef struct _PopWindowViewPrivate PopWindowViewPrivate;
+typedef enum _PopWindowViewError PopWindowViewError;
+
+struct _PopWindowView
+{
+ GObject parent;
+
+ /*< private > */
+ PopWindowViewPrivate *priv;
+};
+
+struct _PopWindowViewClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (* foo) (PopWindowView * window);
+};
+
+enum _PopWindowViewError
+{
+ POP_WINDOW_VIEW_ERROR_GENERIC = 0,
+};
+
+#ifndef POP_HIDE_FUNCTION_DECLARATIONS
+GType pop_window_view_get_type (void);
+GQuark pop_window_view_error_quark (void);
+
+PopWindowView *pop_window_view_new (void) G_GNUC_MALLOC;
+gboolean pop_window_view_set_window (PopWindowView *view, GdkWindow *window);
+void pop_window_view_unset_window (PopWindowView *view);
+GdkWindow *pop_window_view_get_window (PopWindowView *view);
+void pop_window_view_get_size (PopWindowView *view, gint *width, gint *height);
+void pop_window_view_get_position (PopWindowView *view, int *x, int *y);
+GdkRegion *pop_window_view_get_difference (PopWindowView *view,
+ PopWindowView *other_view);
+void pop_window_view_render_to_context (PopWindowView *view,
+ cairo_t *cairo_context);
+#endif
+
+G_END_DECLS
+#endif /* POP_WINDOW_VIEW_H */