diff options
author | Ray Strode <rstrode@redhat.com> | 2007-03-29 21:56:35 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2007-03-29 21:56:35 -0400 |
commit | 31f7f32d2484413e5ac799c957daa1a37d4cf822 (patch) | |
tree | b620cd0e0c068b9da02fc80a05a2b6a5f335b424 /src | |
parent | fbaecaf279e9450c126e6f21e9f03fb08fa1dd92 (diff) |
move files to src/ directory
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 3 | ||||
-rw-r--r-- | src/pop-demo.c | 335 | ||||
-rw-r--r-- | src/pop-event-listener.c | 877 | ||||
-rw-r--r-- | src/pop-event-listener.h | 88 | ||||
-rw-r--r-- | src/pop-overlay-window.c | 368 | ||||
-rw-r--r-- | src/pop-overlay-window.h | 69 | ||||
-rw-r--r-- | src/pop-window-stack.c | 396 | ||||
-rw-r--r-- | src/pop-window-stack.h | 77 | ||||
-rw-r--r-- | src/pop-window-view.c | 934 | ||||
-rw-r--r-- | src/pop-window-view.h | 94 |
10 files changed, 3241 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..c30c56e --- /dev/null +++ b/src/Makefile @@ -0,0 +1,3 @@ +all: + gcc pop-window-stack.c pop-window-view.c pop-event-listener.c pop-demo.c pop-overlay-window.c pop-marshal.c -o pop-demo `pkg-config --cflags --libs glib-2.0 gtk+-2.0 cairo cairo-xlib xcomposite xdamage ` -ggdb3 -O0 -Wall + diff --git a/src/pop-demo.c b/src/pop-demo.c new file mode 100644 index 0000000..3aa71df --- /dev/null +++ b/src/pop-demo.c @@ -0,0 +1,335 @@ +#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 +draw_window_from_stack (PopWindowStack *stack, + GdkWindow *window, + cairo_t *cairo_context) +{ + 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_render_to_context (view, cairo_context); +} + +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 +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 (); +#if 0 + 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); +#endif + gtk_widget_realize (GTK_WIDGET (overlay_window)); + + 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); + + listener = pop_event_listener_new (gtk_widget_get_display (overlay_window)); + pop_event_listener_start (listener); + + gtk_main(); + + return 0; +} diff --git a/src/pop-event-listener.c b/src/pop-event-listener.c new file mode 100644 index 0000000..c934c9a --- /dev/null +++ b/src/pop-event-listener.c @@ -0,0 +1,877 @@ +/* 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 "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 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 +} 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 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, + 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) +{ + g_print ("redrawn 0x%lx\n", GDK_WINDOW_XWINDOW (window)); +} + +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; +} + +#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); +} + +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); + + 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; +} + +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 void +pop_event_listener_get_cached_window_geometry (PopEventListener *listener, + GdkWindow *window, + int *x, + int *y, + int *width, + int *height) +{ + 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")); +} + +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)); +} + +static void +pop_event_listener_configure_handler (PopEventListener *listener, + GdkEvent *event, + GdkWindow *window) +{ + GdkEventConfigure *configure_event; + gint x, y, width, height; + gboolean changed_position, changed_size; + + configure_event = (GdkEventConfigure *) event; + + 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); + + 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); + } + + 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_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 (XEvent *x_event, + GdkEvent *event, + PopEventListener *listener) +{ + if (x_event->type == pop_event_listener_damage_notify_event_type) + { + XDamageNotifyEvent *x_damage_event; + PopEventDamage *damage_event; + GdkWindow *window; + + window = gdk_window_lookup (x_event->xany.window); + + if (window != NULL) + { + x_damage_event = (XDamageNotifyEvent *) x_event; + g_assert (sizeof (*damage_event) <= sizeof (*event)); + damage_event = (PopEventDamage *) event; + 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; + } + } + else if (x_event->type == pop_event_listener_shape_notify_event_type) + { + XShapeEvent *x_shape_event; + PopEventShape *shape_event; + GdkWindow *window; + + window = gdk_window_lookup (x_event->xany.window); + + if (window != NULL) + { + x_shape_event = (XShapeEvent *) x_event; + g_assert (sizeof (*shape_event) <= sizeof (*event)); + shape_event = (PopEventShape *) event; + shape_event->window = g_object_ref (window); + shape_event->type = POP_SHAPE; + shape_event->send_event = FALSE; + + return GDK_FILTER_TRANSLATE; + } + } + else if (x_event->type == ReparentNotify) + { + XReparentEvent *x_reparent_event; + PopEventReparent *reparent_event; + GdkWindow *window, *parent; + + window = gdk_window_lookup (x_event->xany.window); + + if (window != NULL) + { + x_reparent_event = (XReparentEvent *) x_event; + g_assert (sizeof (*reparent_event) <= sizeof (*event)); + reparent_event = (PopEventReparent *) event; + 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; + } + } + + return GDK_FILTER_CONTINUE; +} + +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); +} + +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..d302f44 --- /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); +}; + +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_new (GdkDisplay *display) G_GNUC_MALLOC; +void pop_event_listener_start (PopEventListener *listener); +void pop_event_listener_stop (PopEventListener *listener); + +PopEventListener *pop_event_listener_get_default (void); + +#endif + +G_END_DECLS +#endif /* POP_EVENT_LISTENER_H */ diff --git a/src/pop-overlay-window.c b/src/pop-overlay-window.c new file mode 100644 index 0000000..5e7c48a --- /dev/null +++ b/src/pop-overlay-window.c @@ -0,0 +1,368 @@ +/* pop-overlay-window.c - special toplevel overlay window + * + * Copyright (C) 200y Ray Strode <rstrode@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2, 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 Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser 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. + * + * Originally written by: Ray Strode <rstrode@redhat.com> + */ +#include "pop-overlay-window.h" + +#include <errno.h> +#include <stdlib.h> + +#include <glib.h> +#include <glib-object.h> + +#include <X11/extensions/Xcomposite.h> +#include <X11/extensions/Xfixes.h> + +#include <gdk/gdkx.h> +#include <gtk/gtkwindow.h> + +static void pop_overlay_window_do_finalize (GObject *object); +static void pop_overlay_window_do_realize (GtkWidget *widget); +static void pop_overlay_window_do_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +struct _PopOverlayWindowPrivate +{ + GdkWindow *parent_window; +}; + +G_DEFINE_TYPE (PopOverlayWindow, pop_overlay_window, GTK_TYPE_WINDOW); + +static void +pop_overlay_window_class_init (PopOverlayWindowClass *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_overlay_window_do_finalize; + widget_class->realize = pop_overlay_window_do_realize; + widget_class->size_allocate = pop_overlay_window_do_size_allocate; + + g_type_class_add_private (object_class, sizeof (PopOverlayWindowPrivate)); +} + +static void +pop_overlay_window_init (PopOverlayWindow *overlay_window) +{ + overlay_window->priv = G_TYPE_INSTANCE_GET_PRIVATE (overlay_window, + POP_TYPE_OVERLAY_WINDOW, + PopOverlayWindowPrivate); +} + +static void +pop_overlay_window_do_finalize (GObject *object) +{ + PopOverlayWindow *window; + GObjectClass *parent_class; + + window = POP_OVERLAY_WINDOW (object); + + parent_class = G_OBJECT_CLASS (pop_overlay_window_parent_class); + + if (parent_class->finalize != NULL) + parent_class->finalize (object); +} + +static void +pop_overlay_window_setup_parent_window (PopOverlayWindow *overlay_window) +{ + GdkDisplay *display; + GdkWindow *root_window; + Window parent_xwindow; + + g_assert (POP_IS_OVERLAY_WINDOW (overlay_window)); + g_assert (overlay_window->priv->parent_window == NULL); + + display = gtk_widget_get_display (GTK_WIDGET (overlay_window)); + root_window = gtk_widget_get_root_window (GTK_WIDGET (overlay_window)); + + parent_xwindow = XCompositeGetOverlayWindow (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XWINDOW (root_window)); + overlay_window->priv->parent_window = gdk_window_foreign_new (parent_xwindow); + + gdk_window_set_events (overlay_window->priv->parent_window, + GDK_EXPOSURE_MASK + | GDK_KEY_PRESS_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_FOCUS_CHANGE_MASK + | GDK_STRUCTURE_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK); +} + +static void +pop_overlay_window_get_initial_display_window_attributes (PopOverlayWindow *overlay_window, + GdkWindowAttr *attributes, + gint *attributes_mask) +{ + GtkWidget *widget; + static gint new_attributes_mask = GDK_WA_COLORMAP + | GDK_WA_VISUAL + | GDK_WA_X + | GDK_WA_Y; + static GdkEventMask new_event_mask = GDK_EXPOSURE_MASK + | GDK_KEY_PRESS_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_FOCUS_CHANGE_MASK + | GDK_STRUCTURE_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK; + gint x, y, width, height; + GdkWindowAttr new_attributes; + + g_assert (POP_IS_OVERLAY_WINDOW (overlay_window)); + g_assert (overlay_window->priv->parent_window != NULL); + g_assert (attributes != NULL); + g_assert (attributes_mask != NULL); + + widget = GTK_WIDGET (overlay_window); + + gdk_window_get_geometry (overlay_window->priv->parent_window, + &x, &y, &width, &height, NULL); + new_attributes.window_type = GDK_WINDOW_TOPLEVEL; + new_attributes.wclass = GDK_INPUT_OUTPUT; + new_attributes.colormap = gtk_widget_get_colormap (widget); + new_attributes.visual = gtk_widget_get_visual (widget); + new_attributes.x = x; + new_attributes.y = y; + new_attributes.width = width; + new_attributes.height = height; + new_attributes.event_mask = new_event_mask; + + *attributes = new_attributes; + *attributes_mask = new_attributes_mask; +} + +static void +pop_overlay_window_setup_display_window (PopOverlayWindow *overlay_window) +{ + GdkWindowAttr attributes; + gint attributes_mask; + GtkWidget *widget; + GdkScreen *screen; + + g_assert (POP_IS_OVERLAY_WINDOW (overlay_window)); + g_assert (overlay_window->priv->parent_window != NULL); + g_assert (GTK_WIDGET (overlay_window)->window == NULL); + + widget = GTK_WIDGET (overlay_window); + screen = gtk_widget_get_screen (widget); + + pop_overlay_window_get_initial_display_window_attributes (POP_OVERLAY_WINDOW (widget), + &attributes, + &attributes_mask); + widget->window = gdk_window_new (overlay_window->priv->parent_window, + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + gdk_window_set_decorations (widget->window, (GdkWMDecoration) 0); +} + +static void +pop_overlay_window_setup_initial_geometry (PopOverlayWindow *overlay_window) +{ + GtkRequisition requisition; + GtkAllocation allocation; + int x, y, width, height; + GtkWidget *widget; + + g_assert (POP_IS_OVERLAY_WINDOW (overlay_window)); + g_assert (GTK_WIDGET (overlay_window)->window != NULL); + + widget = GTK_WIDGET (overlay_window); + + gdk_window_get_position (widget->window, &x, &y); + gdk_drawable_get_size (GDK_DRAWABLE (widget->window), &width, &height); + gtk_widget_size_request (widget, &requisition); + allocation.x = x; + allocation.y = y; + allocation.width = width; + allocation.height = height; + gtk_widget_size_allocate (widget, &allocation); + gtk_window_resize (GTK_WINDOW (widget), width, height); +} + +static void +pop_overlay_window_do_realize (GtkWidget *widget) +{ + PopOverlayWindow *overlay_window; + + overlay_window = POP_OVERLAY_WINDOW (widget); + + /* we make the widget's display window a child of X's + * composite overlay window instead of using the composite + * overlay window directly, so that we have some flexibility + * over what visual to use. + */ + pop_overlay_window_setup_parent_window (overlay_window); + pop_overlay_window_setup_display_window (overlay_window); + + /* at this point widget->window is filled in with a valid window, + * so we're realized, let's make it official + */ + g_assert (widget->window != NULL); + widget->style = gtk_style_attach (widget->style, widget->window); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + gdk_window_set_back_pixmap (widget->window, NULL, FALSE); + pop_overlay_window_setup_initial_geometry (overlay_window); +} + +static void +pop_overlay_window_compute_child_allocation (PopOverlayWindow *overlay_window, + GtkAllocation *child_allocation) +{ + GtkWidget *widget; + guint border_width; + + g_assert (POP_IS_OVERLAY_WINDOW (overlay_window)); + g_assert (child_allocation != NULL); + + widget = GTK_WIDGET (overlay_window); + border_width = gtk_container_get_border_width (GTK_CONTAINER (overlay_window)); + + child_allocation->x = border_width; + child_allocation->y = border_width; + child_allocation->width = widget->allocation.width - 2 * border_width; + child_allocation->height = widget->allocation.height - 2 * border_width; + + if (child_allocation->width < 1) + child_allocation->width = 1; + + if (child_allocation->height < 1) + child_allocation->height = 1; +} + +static GdkRegion * +pop_overlay_window_create_region_from_allocation (PopOverlayWindow *overlay_window, + GtkAllocation *allocation) +{ + GdkRectangle rectangle; + GdkRegion *region; + + g_assert (POP_IS_OVERLAY_WINDOW (overlay_window)); + g_assert (allocation != NULL); + + region = gdk_region_new (); + + rectangle.x = allocation->x; + rectangle.y = allocation->y; + rectangle.width = allocation->width; + rectangle.height = allocation->height; + + gdk_region_union_with_rect (region, &rectangle); + + return region; +} + +static void +pop_overlay_window_set_input_region_from_allocation (PopOverlayWindow *overlay_window, + GtkAllocation *allocation) +{ + GtkWidget *widget; + GdkRegion *input_region; + + g_assert (POP_IS_OVERLAY_WINDOW (overlay_window)); + g_assert (allocation != NULL); + g_assert (gdk_display_supports_input_shapes (gtk_widget_get_display (GTK_WIDGET (overlay_window)))); + + /* either the child allocation is empty or present, it shouldn't + * ever be negative or only filled on one dimension + */ + g_assert (((allocation->width > 0) && (allocation->height > 0)) + || ((allocation->width == 0) && (allocation->height == 0))); + + widget = GTK_WIDGET (overlay_window); + input_region = + pop_overlay_window_create_region_from_allocation (overlay_window, + allocation); + + g_assert (input_region != NULL); + + gdk_window_input_shape_combine_region (overlay_window->priv->parent_window, + input_region, 0, 0); + gdk_region_destroy (input_region); +} + +static void +pop_overlay_window_do_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + PopOverlayWindow *overlay_window; + GtkWidget *child_widget; + GtkAllocation child_allocation = { 0 }; + + g_assert (POP_IS_OVERLAY_WINDOW (widget)); + g_assert (allocation != NULL); + + overlay_window = POP_OVERLAY_WINDOW (widget); + + widget->allocation = *allocation; + + child_widget = gtk_bin_get_child (GTK_BIN (widget)); + + if ((child_widget != NULL) && GTK_WIDGET_VISIBLE (child_widget)) + { + /* first figure out how much the space our children should get. + * Normally the answer is "all of it", but I guess to be a good + * GtkContainer subclass we should respect border width and exclude + * it from the outside of the child allocation. + */ + pop_overlay_window_compute_child_allocation (overlay_window, + &child_allocation); + + /* now that we have the child allocation, tell our child about it, so + * it can divvy it up to its children + */ + gtk_widget_size_allocate (child_widget, &child_allocation); + } + + /* we want our children to be able to receive input events, but all space + * not allocated to a child should just pass through to windows under the + * overlay, so we set the input region to the area occupied by our children + */ + if (GTK_WIDGET_REALIZED (overlay_window)) + pop_overlay_window_set_input_region_from_allocation (overlay_window, + &child_allocation); +} + +GtkWidget * +pop_overlay_window_new (void) +{ + PopOverlayWindow *overlay_window; + + overlay_window = g_object_new (POP_TYPE_OVERLAY_WINDOW, + "type", GTK_WINDOW_TOPLEVEL, + "app-paintable", TRUE, + NULL); + + return GTK_WIDGET (overlay_window); +} diff --git a/src/pop-overlay-window.h b/src/pop-overlay-window.h new file mode 100644 index 0000000..9f3f832 --- /dev/null +++ b/src/pop-overlay-window.h @@ -0,0 +1,69 @@ +/* pop-overlay-window.h - special toplevel overlay window + * + * 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 Lesser 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 Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser 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. + * + * Originally written by: Ray Strode <rstrode@redhat.com> + */ +#ifndef POP_OVERLAY_WINDOW_H +#define POP_OVERLAY_WINDOW_H + +#include <glib.h> +#include <glib-object.h> + +#include <gtk/gtk.h> + +G_BEGIN_DECLS +#define POP_TYPE_OVERLAY_WINDOW (pop_overlay_window_get_type ()) +#define POP_OVERLAY_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POP_TYPE_OVERLAY_WINDOW, PopOverlayWindow)) +#define POP_OVERLAY_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POP_TYPE_OVERLAY_WINDOW, PopOverlayWindowClass)) +#define POP_IS_OVERLAY_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), POP_TYPE_OVERLAY_WINDOW)) +#define POP_IS_OVERLAY_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POP_TYPE_OVERLAY_WINDOW)) +#define POP_OVERLAY_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), POP_TYPE_OVERLAY_WINDOW, PopOverlayWindowClass)) + +typedef struct _PopOverlayWindow PopOverlayWindow; +typedef struct _PopOverlayWindowClass PopOverlayWindowClass; +typedef struct _PopOverlayWindowPrivate PopOverlayWindowPrivate; + +struct _PopOverlayWindow +{ + GtkWindow parent; + + /*< private >*/ + /* reserved for priv pointer */ + PopOverlayWindowPrivate *priv; +}; + +struct _PopOverlayWindowClass +{ + GtkWindowClass parent_class; + + /* for signals later if needed */ + gpointer reserved_1; + gpointer reserved_2; + gpointer reserved_3; + gpointer reserved_4; +}; + +#ifndef POP_HIDE_FUNCTION_DECLARATIONS +GType pop_overlay_window_get_type (void); +GtkWidget *pop_overlay_window_new (void); +#endif + +G_END_DECLS +#endif /* POP_OVERLAY_WINDOW_H */ diff --git a/src/pop-window-stack.c b/src/pop-window-stack.c new file mode 100644 index 0000000..f547342 --- /dev/null +++ b/src/pop-window-stack.c @@ -0,0 +1,396 @@ +/* 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 "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> + +struct _PopWindowStackPrivate +{ + GdkScreen *screen; + GQueue *windows; +}; + +typedef struct +{ + PopWindowStack *stack; + PopWindowStackForeachFunc func; + gpointer user_data; +} PopWindowStackForeachClosure; + +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->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); + + 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_queue_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); + + /* need to listen for display events and keep the list up to date + * that way instead of constantly rebuilding it + */ + pop_window_stack_get_initial_window_list (stack); + + closure.stack = stack; + closure.func = func; + closure.user_data = user_data; + + g_queue_foreach (stack->priv->windows, pop_window_stack_queue_foreach_func, &closure); +} + +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 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; + + /* FIXME: check that it's not INPUT_ONLY */ + 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"); + } +} + +#if 0 +int +pop_window_stack_get_bar (PopWindowStack * stack) +{ + return stack->priv->bar; +} +#endif + +#ifdef POP_WINDOW_STACK_ENABLE_TEST + +#include <stdio.h> +#include <glib.h> + +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 (); + + g_message ("creating instance of 'window stack' object..."); + stack = pop_window_stack_new (); + g_message ("'window stack' object created successfully"); + + 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..b54a450 --- /dev/null +++ b/src/pop-window-stack.h @@ -0,0 +1,77 @@ +/* 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); + +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); +#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..117d4bb --- /dev/null +++ b/src/pop-window-view.c @@ -0,0 +1,934 @@ +/* pop-window-view.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-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_damaged : 1; + + gint x, y; + gint width, height; +}; + +#if 0 +static void pop_window_view_class_install_signals (PopWindowViewClass * window_class); +#endif +static void pop_window_view_class_install_properties (PopWindowViewClass * + window_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 *window_class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (window_class); + + object_class->finalize = pop_window_view_do_finalize; + + pop_window_view_class_install_properties (window_class); +#if 0 + pop_window_view_class_install_signals (window_class); +#endif + + g_type_class_add_private (window_class, sizeof (PopWindowViewPrivate)); +} + +#if 0 +static void +pop_window_view_class_install_signals (PopWindowViewClass * window_class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (window_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); + window_class->foo = NULL; +} +#endif + +static void +pop_window_view_class_install_properties (PopWindowViewClass *window_class) +{ + GObjectClass *object_class; + GParamSpec *param_spec; + + object_class = G_OBJECT_CLASS (window_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 (); + pop_event_listener_start (view->priv->event_listener); +} + +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) + { + 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); + } + + view->priv->clip_path = cairo_copy_path_flat (cairo_context); + cairo_destroy (cairo_context); + + 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), + XDamageReportNonEmpty); +} + +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; +} + +static 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); + pop_window_view_destroy_pattern (view); + pop_window_view_create_pattern_from_window (view); + + 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); +} + +static 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)); + 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); +} + +static void +pop_window_view_window_hidden (PopWindowView *view) +{ + 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); + pop_window_view_destroy_pattern (view); + pop_window_view_create_pattern_from_window (view); + + 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)) + pop_window_view_window_shown (view); + + 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; +} + +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) + return; + + pop_window_view_report_fixed_damage (view); + + cairo_save (cairo_context); + 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_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); + + cairo_restore (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..bcc3fa1 --- /dev/null +++ b/src/pop-window-view.h @@ -0,0 +1,94 @@ +/* pop-window-view.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_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 */ +#if 0 + void (*foo) (PopWindowView * window); +#endif +}; + +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); +void pop_window_view_queue_damage (PopWindowView *view); +void pop_window_view_render_to_context (PopWindowView *view, + cairo_t *cairo_context); + +void _pop_window_view_window_damaged (PopWindowView *view, + GdkRectangle *rectangle); +void _pop_window_view_window_resized (PopWindowView *view); +void _pop_window_view_window_moved (PopWindowView *view); +void _pop_window_view_window_shown (PopWindowView *view); +void _pop_window_view_window_hidden (PopWindowView *view); +void _pop_window_view_window_destroyed (PopWindowView *view); +void _pop_window_view_window_reshaped (PopWindowView *view); +void _pop_window_view_window_reparented (PopWindowView *view); +#endif + +G_END_DECLS +#endif /* POP_WINDOW_VIEW_H */ |