diff options
Diffstat (limited to 'src/pop-window-view.c')
-rw-r--r-- | src/pop-window-view.c | 934 |
1 files changed, 934 insertions, 0 deletions
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; +} |