diff --git a/gdk/Makefile.am b/gdk/Makefile.am index 3f188ad..10aa985 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -92,6 +92,7 @@ gdk_public_h_sources = \ gdktestutils.h \ gdktypes.h \ gdkvisual.h \ + gdkwindowimpl.h \ gdkwindow.h gdk_built_public_sources = \ @@ -108,6 +109,7 @@ gdk_c_sources = \ gdkcolor.c \ gdkcursor.c \ gdkdisplay.c \ + gdkdisplaymanager.c \ gdkdnd.c \ gdkdraw.c \ gdkevents.c \ @@ -119,7 +121,7 @@ gdk_c_sources = \ gdkimage.c \ gdkinternals.h \ gdkintl.h \ - gdkdisplaymanager.c \ + gdkoffscreenwindow.c \ gdkpango.c \ gdkpixbuf-drawable.c \ gdkpixbuf-render.c \ @@ -133,7 +135,8 @@ gdk_c_sources = \ gdkscreen.c \ gdkselection.c \ gdkvisual.c \ - gdkwindow.c + gdkwindow.c \ + gdkwindowimpl.c gdk_built_sources = \ gdkaliasdef.c \ diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index ec121c8..2bb4415 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -252,12 +252,6 @@ gdk_visual_type_get_type G_GNUC_CONST #endif #endif -#if IN_HEADER(__GDK_PIXMAP_H__) -#if IN_FILE(__GDK_PIXMAP_X11_C__) -gdk_bitmap_create_from_data -#endif -#endif - #if IN_HEADER(__GDK_FONT_H__) #if IN_FILE(__GDK_FONT_C__) #ifndef GDK_DISABLE_DEPRECATED @@ -647,6 +641,29 @@ gdk_window_impl_x11_get_type G_GNUC_CONST #if IN_FILE(__GDK_WINDOW_C__) gdk_get_default_root_window gdk_window_new +gdk_window_show_unraised +gdk_window_show +gdk_window_hide +gdk_window_withdraw +gdk_window_get_events +gdk_window_set_events +gdk_window_raise +gdk_window_lower +gdk_window_move +gdk_window_resize +gdk_window_move_resize +gdk_window_scroll +gdk_window_move_region +gdk_window_set_background +gdk_window_set_back_pixmap +gdk_window_set_cursor +gdk_window_get_geometry +gdk_window_get_origin +gdk_window_shape_combine_mask +gdk_window_shape_combine_region +gdk_window_set_child_shapes +gdk_window_merge_child_shapes +gdk_window_set_static_gravities gdk_window_reparent gdk_window_add_filter gdk_window_at_pointer @@ -699,27 +716,11 @@ gdk_window_register_dnd #endif #if IN_HEADER(__GDK_WINDOW_H__) -#if IN_FILE(__GDK_GEOMETRY_X11_C__) -gdk_window_scroll -gdk_window_move_region -#endif -#endif - -#if IN_HEADER(__GDK_WINDOW_H__) #if IN_FILE(__GDK_WINDOW_X11_C__) gdk_window_foreign_new_for_display +gdk_window_focus gdk_window_lookup gdk_window_lookup_for_display -gdk_window_show_unraised -gdk_window_show -gdk_window_hide -gdk_window_withdraw -gdk_window_move -gdk_window_resize -gdk_window_move_resize -gdk_window_raise -gdk_window_lower -gdk_window_focus #ifndef GDK_DISABLE_DEPRECATED gdk_window_set_hints gdk_window_get_deskrelative_origin @@ -735,17 +736,8 @@ gdk_window_set_title gdk_window_set_role gdk_window_set_startup_id gdk_window_set_transient_for -gdk_window_set_background -gdk_window_set_back_pixmap -gdk_window_set_cursor -gdk_window_get_geometry -gdk_window_get_origin gdk_window_get_root_origin gdk_window_get_frame_extents -gdk_window_get_events -gdk_window_set_events -gdk_window_shape_combine_mask -gdk_window_shape_combine_region gdk_window_input_shape_combine_mask gdk_window_input_shape_combine_region gdk_window_set_override_redirect @@ -771,11 +763,8 @@ gdk_window_set_group gdk_window_get_decorations gdk_window_set_decorations gdk_window_set_functions -gdk_window_set_child_shapes -gdk_window_merge_child_shapes gdk_window_set_child_input_shapes gdk_window_merge_child_input_shapes -gdk_window_set_static_gravities gdk_window_begin_move_drag gdk_window_begin_resize_drag gdk_window_enable_synchronized_configure @@ -924,23 +913,24 @@ gdk_pixbuf_render_to_drawable_alpha #if IN_HEADER(__GDK_PIXMAP_H__) #if IN_FILE(__GDK_PIXMAP_C__) +gdk_bitmap_create_from_data gdk_pixmap_colormap_create_from_xpm +gdk_pixmap_create_from_data gdk_pixmap_create_from_xpm gdk_pixmap_colormap_create_from_xpm_d gdk_pixmap_create_from_xpm_d gdk_pixmap_get_type G_GNUC_CONST +gdk_pixmap_new #endif #endif #if IN_HEADER(__GDK_PIXMAP_H__) #if IN_FILE(__GDK_PIXMAP_X11_C__) -gdk_pixmap_create_from_data gdk_pixmap_foreign_new gdk_pixmap_foreign_new_for_display gdk_pixmap_foreign_new_for_screen gdk_pixmap_lookup gdk_pixmap_lookup_for_display -gdk_pixmap_new #endif #endif diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 2a5b92c..0a7777e 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -22,9 +22,11 @@ */ #include "config.h" +#include #include #include "gdk.h" /* gdk_event_send_client_message() */ #include "gdkdisplay.h" +#include "gdkwindowimpl.h" #include "gdkinternals.h" #include "gdkmarshalers.h" #include "gdkscreen.h" @@ -60,6 +62,14 @@ static GdkWindow* singlehead_default_window_get_pointer (GdkWindow *window static GdkWindow* singlehead_default_window_at_pointer (GdkScreen *screen, gint *win_x, gint *win_y); +static GdkWindow *gdk_window_real_window_get_pointer (GdkDisplay *display, + GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask); +static GdkWindow *gdk_display_real_get_window_at_pointer (GdkDisplay *display, + gint *win_x, + gint *win_y); static guint signals[LAST_SIGNAL] = { 0 }; @@ -67,8 +77,8 @@ static char *gdk_sm_client_id; static const GdkDisplayPointerHooks default_pointer_hooks = { _gdk_windowing_get_pointer, - _gdk_windowing_window_get_pointer, - _gdk_windowing_window_at_pointer + gdk_window_real_window_get_pointer, + gdk_display_real_get_window_at_pointer }; static const GdkDisplayPointerHooks singlehead_pointer_hooks = { @@ -471,6 +481,73 @@ gdk_display_get_pointer (GdkDisplay *display, *mask = tmp_mask; } +static GdkWindow* +gdk_display_real_get_window_at_pointer (GdkDisplay *display, + gint *win_x, + gint *win_y) +{ + GdkWindow *window; + + window =_gdk_windowing_window_at_pointer (display, win_x, win_y); + + if (window && GDK_WINDOW_OBJECT (window)->offscreen_children) + { + GdkWindow *child; + gdouble child_x, child_y; + + child = _gdk_window_get_offscreen_window_child_at (window, + *win_x, *win_y, + &child_x, &child_y); + *win_x = floor (child_x + 0.5); + *win_y = floor (child_y + 0.5); + + return child; + } + + return window; +} + +static GdkWindow * +gdk_window_real_window_get_pointer (GdkDisplay *display, + GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowObject *private; + GdkWindow *event_window; + GdkWindow *pointer_window; + gint tmpx, tmpy; + + private = (GdkWindowObject *) window; + + event_window = _gdk_window_get_offscreen_event_window (window); + + pointer_window = _gdk_windowing_window_get_pointer (display, + event_window, + &tmpx, &tmpy, + mask); + + /* Convert to offscreen if needed */ + _gdk_offscreen_window_transform_coords (event_window, + window, + &tmpx, &tmpy); + if (x) + *x = tmpx; + if (y) + *y = tmpy; + + /* If the pointer is in a window with offscreen children, recalculate pointer + * window, as the pointer it might be in an offscreen child. + */ + if (pointer_window != NULL && + GDK_WINDOW_OBJECT (pointer_window)->offscreen_children) + pointer_window = gdk_display_real_get_window_at_pointer (display, + &tmpx, &tmpy); + + return pointer_window; +} + /** * gdk_display_get_window_at_pointer: * @display: a #GdkDisplay @@ -582,8 +659,8 @@ singlehead_default_window_get_pointer (GdkWindow *window, gint *y, GdkModifierType *mask) { - return _gdk_windowing_window_get_pointer (gdk_drawable_get_display (window), - window, x, y, mask); + return gdk_window_real_window_get_pointer (gdk_drawable_get_display (window), + window, x, y, mask); } static GdkWindow* @@ -591,8 +668,8 @@ singlehead_default_window_at_pointer (GdkScreen *screen, gint *win_x, gint *win_y) { - return _gdk_windowing_window_at_pointer (gdk_screen_get_display (screen), - win_x, win_y); + return gdk_display_real_get_window_at_pointer (gdk_screen_get_display (screen), + win_x, win_y); } /** diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c index 0876695..13efed9 100644 --- a/gdk/gdkdraw.c +++ b/gdk/gdkdraw.c @@ -48,6 +48,7 @@ static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable *draw gint height, gint *composite_x_offset, gint *composite_y_offset); +static GdkDrawable *gdk_drawable_real_get_source_drawable (GdkDrawable *drawable); static GdkRegion * gdk_drawable_real_get_visible_region (GdkDrawable *drawable); static void gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable, GdkGC *gc, @@ -70,6 +71,7 @@ gdk_drawable_class_init (GdkDrawableClass *klass) { klass->get_image = gdk_drawable_real_get_image; klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable; + klass->get_source_drawable = gdk_drawable_real_get_source_drawable; /* Default implementation for clip and visible region is the same */ klass->get_clip_region = gdk_drawable_real_get_visible_region; klass->get_visible_region = gdk_drawable_real_get_visible_region; @@ -1187,7 +1189,13 @@ gdk_drawable_real_get_image (GdkDrawable *drawable, return gdk_drawable_copy_to_image (drawable, NULL, x, y, 0, 0, width, height); } -static GdkDrawable* +static GdkDrawable * +gdk_drawable_real_get_source_drawable (GdkDrawable *drawable) +{ + return drawable; +} + +static GdkDrawable * gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable, gint x, gint y, @@ -1773,5 +1781,22 @@ _gdk_drawable_get_scratch_gc (GdkDrawable *drawable, } } +/** + * _gdk_drawable_get_source_drawable: + * @drawable: a #GdkDrawable + * + * Returns a drawable for the passed @drawable that is guaranteed to be + * usable to create a pixmap (e.g.: not an offscreen window). + * + * Since: 2.16 + */ +GdkDrawable * +_gdk_drawable_get_source_drawable (GdkDrawable *drawable) +{ + g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL); + + return GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable (drawable); +} + #define __GDK_DRAW_C__ #include "gdkaliasdef.c" diff --git a/gdk/gdkdrawable.h b/gdk/gdkdrawable.h index 508bf86..6cb0fc0 100644 --- a/gdk/gdkdrawable.h +++ b/gdk/gdkdrawable.h @@ -200,8 +200,9 @@ struct _GdkDrawableClass cairo_surface_t *(*ref_cairo_surface) (GdkDrawable *drawable); + GdkDrawable *(*get_source_drawable) (GdkDrawable *drawable); + /* Padding for future expansion */ - void (*_gdk_reserved4) (void); void (*_gdk_reserved5) (void); void (*_gdk_reserved6) (void); void (*_gdk_reserved7) (void); diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 2cb3238..c6e882f 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -121,6 +121,46 @@ _gdk_event_queue_append (GdkDisplay *display, } /** + * _gdk_event_queue_append_after: + * @display: a #GdkDisplay + * @after_event: Append after this event. + * @event: Event to append. + * + * Appends an event after the specified event, or if it isn't in + * the queue, onto the tail of the event queue. + * + * Returns: the newly appended list node. + * + * Since: 2.16 + */ +GList * +_gdk_event_queue_append_after (GdkDisplay *display, + GdkEvent *after_event, + GdkEvent *event) +{ + GList *tmp_list = display->queued_events; + + while (tmp_list) + { + GdkEvent *list_event = tmp_list->data; + + if (list_event == after_event) + { + tmp_list->next = g_list_prepend (tmp_list->next, event); + + if (display->queued_tail == tmp_list) + display->queued_tail = tmp_list->next; + + return tmp_list->next; + } + + tmp_list = g_list_next (tmp_list); + } + + return _gdk_event_queue_append (display, event); +} + +/** * _gdk_event_queue_remove_link: * @display: a #GdkDisplay * @node: node to remove @@ -1069,13 +1109,18 @@ gdk_synthesize_click (GdkDisplay *display, gint nclicks) { GdkEvent temp_event; + GdkEvent *event_copy; + GList *link; g_return_if_fail (event != NULL); temp_event = *event; temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; - - gdk_display_put_event (display, &temp_event); + + event_copy = gdk_event_copy (&temp_event); + link = _gdk_event_queue_append (display, event_copy); + + _gdk_event_rewrite_for_offscreen (display, link, event_copy); } void diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index b5ce96e..c3a9b77 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -181,15 +181,18 @@ extern gchar *_gdk_display_arg_name; void _gdk_events_queue (GdkDisplay *display); GdkEvent* _gdk_event_unqueue (GdkDisplay *display); -GList* _gdk_event_queue_find_first (GdkDisplay *display); -void _gdk_event_queue_remove_link (GdkDisplay *display, - GList *node); -GList* _gdk_event_queue_prepend (GdkDisplay *display, - GdkEvent *event); -GList* _gdk_event_queue_append (GdkDisplay *display, - GdkEvent *event); -void _gdk_event_button_generate (GdkDisplay *display, - GdkEvent *event); +GList* _gdk_event_queue_find_first (GdkDisplay *display); +void _gdk_event_queue_remove_link (GdkDisplay *display, + GList *node); +GList* _gdk_event_queue_prepend (GdkDisplay *display, + GdkEvent *event); +GList* _gdk_event_queue_append (GdkDisplay *display, + GdkEvent *event); +GList* _gdk_event_queue_append_after (GdkDisplay *display, + GdkEvent *after_event, + GdkEvent *event); +void _gdk_event_button_generate (GdkDisplay *display, + GdkEvent *event); void _gdk_windowing_event_data_copy (const GdkEvent *src, GdkEvent *dst); @@ -226,6 +229,8 @@ GdkImage *_gdk_drawable_copy_to_image (GdkDrawable *drawable, cairo_surface_t *_gdk_drawable_ref_cairo_surface (GdkDrawable *drawable); +GdkDrawable *_gdk_drawable_get_source_drawable (GdkDrawable *drawable); + /* GC caching */ GdkGC *_gdk_drawable_get_scratch_gc (GdkDrawable *drawable, gboolean graphics_exposures); @@ -240,11 +245,30 @@ void _gdk_gc_update_context (GdkGC *gc, * Interfaces used by windowing code * *************************************/ -void _gdk_window_destroy (GdkWindow *window, - gboolean foreign_destroy); -void _gdk_window_clear_update_area (GdkWindow *window); - -void _gdk_screen_close (GdkScreen *screen); +GdkPixmap *_gdk_pixmap_new (GdkDrawable *drawable, + gint width, + gint height, + gint depth); +GdkPixmap *_gdk_pixmap_create_from_data (GdkDrawable *drawable, + const gchar *data, + gint width, + gint height, + gint depth, + const GdkColor *fg, + const GdkColor *bg); +GdkPixmap *_gdk_bitmap_create_from_data (GdkDrawable *drawable, + const gchar *data, + gint width, + gint height); + +GdkWindow *_gdk_window_new (GdkWindow *window, + GdkWindowAttr *attributes, + gint attributes_mask); +void _gdk_window_destroy (GdkWindow *window, + gboolean foreign_destroy); +void _gdk_window_clear_update_area (GdkWindow *window); + +void _gdk_screen_close (GdkScreen *screen); const char *_gdk_get_sm_client_id (void); @@ -283,16 +307,6 @@ gchar *_gdk_windowing_substitute_screen_number (const gchar *display_name, void _gdk_windowing_window_get_offsets (GdkWindow *window, gint *x_offset, gint *y_offset); -void _gdk_windowing_window_clear_area (GdkWindow *window, - gint x, - gint y, - gint width, - gint height); -void _gdk_windowing_window_clear_area_e (GdkWindow *window, - gint x, - gint y, - gint width, - gint height); void _gdk_windowing_get_pointer (GdkDisplay *display, GdkScreen **screen, @@ -315,10 +329,6 @@ gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display, GdkWindow* _gdk_window_new (GdkWindow *parent, GdkWindowAttr *attributes, gint attributes_mask); -void _gdk_window_reparent (GdkWindow *window, - GdkWindow *new_parent, - gint x, - gint y); #define GDK_WINDOW_IS_MAPPED(window) ((((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_WITHDRAWN) == 0) @@ -444,6 +454,55 @@ char *_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context, void _gdk_windowing_launch_failed (GAppLaunchContext *context, const char *startup_notify_id); +void _gdk_windowing_grab_broken (GdkDisplay *display); +void _gdk_windowing_update_implicit_grab (GdkWindow *old_grab, + GdkWindow *new_grab, + guint event_mask, + guint32 time_); + +/***************************** + * offscreen window routines * + *****************************/ + +GdkWindow* _gdk_window_new_offscreen (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask, + gboolean toplevel); +void _gdk_offscreen_window_destroy (GdkWindow *window, + gboolean recursing); +void _gdk_offscreen_window_set_pointer_grab (GdkWindow *old_grab_window, + GdkWindow *old_native_grab_window, + GdkWindow *grab_window, + gboolean owner_events, + guint event_mask, + guint32 time_); +void _gdk_offscreen_window_unset_pointer_grab (GdkWindow *window, + gboolean regrab, + gboolean grab_one_button_release, + guint32 time_); +GdkRegion *_gdk_window_calculate_full_clip_region (GdkWindow *window, + GdkWindow *base_window, + GdkGC *gc, + gboolean do_children, + gint *base_x_offset, + gint *base_y_offset); +void _gdk_event_rewrite_for_offscreen (GdkDisplay *display, + GList *event_node, + GdkEvent *event); +void _gdk_window_add_offscreen_child (GdkWindow *window); +void _gdk_window_remove_offscreen_child (GdkWindow *window); +GdkWindow *_gdk_window_get_offscreen_window_child_at (GdkWindow *parent, + gdouble x, + gdouble y, + gdouble *win_x_out, + gdouble *win_y_out); +GdkWindow *_gdk_window_get_offscreen_event_window (GdkWindow *window); +void _gdk_offscreen_window_transform_coords (GdkWindow *event_window, + GdkWindow *relative_window, + gint *x, + gint *y); +gboolean _gdk_window_is_toplevel_offscreen (GdkWindow *child); + /************************************ * Initialization and exit routines * diff --git a/gdk/gdkoffscreenwindow.c b/gdk/gdkoffscreenwindow.c new file mode 100644 index 0000000..698c1b9 --- /dev/null +++ b/gdk/gdkoffscreenwindow.c @@ -0,0 +1,2646 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2005. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include +#include +#include "gdk.h" +#include "gdkwindow.h" +#include "gdkinternals.h" +#include "gdkwindowimpl.h" +#include "gdkpixmap.h" +#include "gdkdrawable.h" +#include "gdktypes.h" +#include "gdkscreen.h" +#include "gdkgc.h" +#include "gdkcolor.h" +#include "gdkcursor.h" +#include "gdkalias.h" + +/* LIMITATIONS: + * + * Offscreen windows must be child windows + * Offscreen windows can't be the child of a foreign window, + * nor contain foreign windows + * All drawing must be within begin/end_paint + * The confine_window argument of pointer grabs doesn't work + * GDK_POINTER_MOTION_HINT_MASK isn't effective + * You can't reparent between offscreen windows and normal windows + */ + +/* TODO: + + * change expose order so that children are exposed before parent, to + avoid double drawing due to damage from children coming after parent expose. + Event with the right order we will expose twice, although both with an + uptodate pixmap. + Not sure how to fix this. Perhaps with a get_and_clear_damage() call? + + * gtk_widget_reparent should unrealize/realize if the new parent GdkWindow is + offscreen and widget is not, or if the new parent is not offscreen and the + widget is. The problem is, how do you know what the new parent GdkWindow is + before gtk_container_add()? + + * Unite the API for all 3 kinds of redirection? how? + + * support cursors in offscreen windows + + * XIM support (is this possible?) + + * Introduce generic "this point in the window in root/other window coords" + operation in gtk + + * dnd drop positions wrong with transformed windows. Needs above point + transformation. + + * various menu popup positions wrong with transformed widgets. Needs above + point transformation. + + */ + +typedef struct _GdkOffscreenWindow GdkOffscreenWindow; +typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass; + +struct _GdkOffscreenWindow +{ + GdkDrawable parent_instance; + + GdkWindow *wrapper; + gint width, height; + GdkCursor *cursor; + GdkColormap *colormap; + GdkScreen *screen; + + /* same window if this is the toplevel */ + GdkOffscreenWindow *toplevel_offscreen; + + /* computed position in pixmap: + * abs: position of top left corner of window in pixmap + * llim: lower limit of visible part of window + * this can be != abs if the window is outside its parent + * lim: upper limit of visible part of window + */ + gint abs_x, abs_y; + gint lim_x, lim_y; + gint llim_x, llim_y; +}; + +struct _GdkOffscreenWindowClass +{ + GdkDrawableClass parent_class; +}; + +#define GDK_TYPE_OFFSCREEN_WINDOW (gdk_offscreen_window_get_type()) +#define GDK_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindow)) +#define GDK_IS_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_OFFSCREEN_WINDOW)) +#define GDK_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass)) +#define GDK_IS_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_OFFSCREEN_WINDOW)) +#define GDK_OFFSCREEN_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass)) + +static void gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface); +static void send_crossing_events (GdkWindowOffscreenChildren *offscreen_children, + GdkWindow *event_window, + GdkWindow *src, + GdkWindow *dest, + GdkCrossingMode mode, + int event_x, + int event_y, + GdkModifierType mask, + guint32 time_, + gboolean do_first, + gboolean do_last); +static GdkWindow *gdk_offscreen_window_get_window_at (GdkWindow *window, + gdouble x, + gdouble y, + gdouble *win_x, + gdouble *win_y); +static void gdk_offscreen_window_hide (GdkWindow *window); +static void gdk_offscreen_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height, + gboolean send_expose); +static GdkRegion *gdk_offscreen_window_get_visible_region (GdkDrawable *drawable); + +static void convert_event_coords_to_window (GdkWindow *event_window, + GdkWindow *window, + gdouble event_x, + gdouble event_y, + gdouble *window_x, + gdouble *window_y); + +G_DEFINE_TYPE_WITH_CODE (GdkOffscreenWindow, + gdk_offscreen_window, + GDK_TYPE_DRAWABLE, + G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL, + gdk_offscreen_window_impl_iface_init)); + + +static void +gdk_offscreen_window_finalize (GObject *object) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object); + + if (offscreen->cursor) + gdk_cursor_unref (offscreen->cursor); + + offscreen->cursor = NULL; + + G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object); +} + +static void +gdk_offscreen_window_init (GdkOffscreenWindow *window) +{ +} + +void +_gdk_offscreen_window_destroy (GdkWindow *window, + gboolean recursing) +{ + GdkWindowObject *private = GDK_WINDOW_OBJECT (window); + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + if (offscreen->toplevel_offscreen == offscreen && private->parent) + _gdk_window_remove_offscreen_child (GDK_WINDOW (private->parent)); + + if (!recursing) + gdk_offscreen_window_hide (window); + + g_object_unref (offscreen->colormap); + offscreen->colormap = NULL; +} + +static gboolean +is_parent_of (GdkWindow *parent, + GdkWindow *child) +{ + GdkWindow *w; + + w = child; + while (w != NULL) + { + if (w == parent) + return TRUE; + + w = gdk_window_get_parent (w); + } + + return FALSE; +} + +static GdkGC * +gdk_offscreen_window_create_gc (GdkDrawable *drawable, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkWindowObject *private; + + private = GDK_WINDOW_OBJECT (offscreen->wrapper); + + return gdk_gc_new_with_values (private->redirect->pixmap, values, values_mask); +} + +static GdkImage* +gdk_offscreen_window_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkWindowObject *private; + gint x_offset, y_offset; + + private = GDK_WINDOW_OBJECT (offscreen->wrapper); + + GDK_WINDOW_IMPL_GET_IFACE (offscreen)->get_offsets (drawable, + &x_offset, + &y_offset); + + return gdk_drawable_copy_to_image (private->redirect->pixmap, + image, + src_x - x_offset, + src_y - y_offset, + dest_x, dest_y, + width, height); +} + +static cairo_surface_t * +gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable) +{ + g_error ("Attempt to get a cairo surface directly for an offscreen " + "window. This is not supported, you must use " + "gdk_window_begin_paint_region()."); + + return NULL; +} + + + +static void +gdk_offscreen_window_empty_draw_op (GdkDrawable *drawable) +{ + /* All actual rendering is done in gdkwindow.c */ +} + +static GdkWindow * +find_offscreen_child (GdkWindow *window, + gdouble x, + gdouble y) +{ + GdkWindowObject *private = (GdkWindowObject *) window; + GdkWindow *hit_window; + + hit_window = NULL; + + if (private->offscreen_hooks && + private->offscreen_hooks->find_offscreen_child) + hit_window = private->offscreen_hooks->find_offscreen_child (window, x, y); + + return hit_window; +} + + +static void +window_to_parent (GdkWindow *window, + gdouble x, + gdouble y, + gdouble *parent_x, + gdouble *parent_y) +{ + GdkWindowObject *private = (GdkWindowObject *) window; + + /* Default value if no handler */ + *parent_x = x + private->x; + *parent_y = y + private->y; + + if (private->offscreen_hooks && + private->offscreen_hooks->window_to_parent) + private->offscreen_hooks->window_to_parent (window, + x, y, + parent_x, parent_y); +} + +static void +parent_to_window (GdkWindow *window, + gdouble x, + gdouble y, + gdouble *window_x, + gdouble *window_y) +{ + GdkWindowObject *private = (GdkWindowObject *) window; + + /* Default value if no handler */ + *window_x = x - private->x; + *window_y = y - private->y; + + if (private->offscreen_hooks && + private->offscreen_hooks->parent_to_window) + private->offscreen_hooks->parent_to_window (window, + x, y, + window_x, window_y); +} + + +static GdkColormap* +gdk_offscreen_window_get_colormap (GdkDrawable *drawable) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + return offscreen->colormap; +} + +static void +gdk_offscreen_window_set_colormap (GdkDrawable *drawable, + GdkColormap*colormap) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + if (colormap && GDK_WINDOW_DESTROYED (offscreen->wrapper)) + return; + + if (offscreen->colormap == colormap) + return; + + if (offscreen->colormap) + g_object_unref (offscreen->colormap); + + offscreen->colormap = colormap; + if (offscreen->colormap) + g_object_ref (offscreen->colormap); +} + + +static gint +gdk_offscreen_window_get_depth (GdkDrawable *drawable) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + return gdk_drawable_get_depth (offscreen->wrapper); +} + +static void +gdk_offscreen_window_get_size (GdkDrawable *drawable, + gint *width, + gint *height) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + if (width) + *width = offscreen->width; + if (height) + *height = offscreen->height; +} + +static GdkScreen* +gdk_offscreen_window_get_screen (GdkDrawable *drawable) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + return offscreen->screen; +} + +static GdkVisual* +gdk_offscreen_window_get_visual (GdkDrawable *drawable) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + return gdk_drawable_get_visual (offscreen->wrapper); +} + +static void +gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass) +{ + GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gdk_offscreen_window_finalize; + + drawable_class->create_gc = gdk_offscreen_window_create_gc; + drawable_class->_copy_to_image = gdk_offscreen_window_copy_to_image; + drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface; + drawable_class->set_colormap = gdk_offscreen_window_set_colormap; + drawable_class->get_colormap = gdk_offscreen_window_get_colormap; + drawable_class->get_depth = gdk_offscreen_window_get_depth; + drawable_class->get_size = gdk_offscreen_window_get_size; + drawable_class->get_screen = gdk_offscreen_window_get_screen; + drawable_class->get_visual = gdk_offscreen_window_get_visual; + drawable_class->get_clip_region = gdk_offscreen_window_get_visible_region; + drawable_class->get_visible_region = gdk_offscreen_window_get_visible_region; + + /* All actual rendering is done in gdkwindow.c with the redirect */ + drawable_class->draw_drawable = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_rectangle = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_points = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_arc = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_polygon = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_text = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_text_wc = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_segments = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_lines = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_image = (gpointer)gdk_offscreen_window_empty_draw_op; + drawable_class->draw_pixbuf = (gpointer)gdk_offscreen_window_empty_draw_op; +} + +static void +recompute_abs_positions (GdkWindow *window, + gint parent_x, + gint parent_y, + gint parent_llim_x, + gint parent_llim_y, + gint parent_lim_x, + gint parent_lim_y) +{ + GdkWindowObject *private = (GdkWindowObject *) window; + GdkOffscreenWindow *offscreen; + GList *l; + gint x, y; + + if (!GDK_WINDOW_IS_MAPPED (window)) + return; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + offscreen->abs_x = parent_x + private->x; + offscreen->abs_y = parent_y + private->y; + + x = MAX (parent_llim_x, offscreen->abs_x); + x = MIN (x, parent_lim_x); + offscreen->llim_x = x; + + y = MAX (parent_llim_y, offscreen->abs_y); + y = MIN (y, parent_lim_y); + offscreen->llim_y = y; + + x = MIN (parent_lim_x, offscreen->abs_x + offscreen->width); + x = MAX (x, offscreen->llim_x); + offscreen->lim_x = x; + + y = MIN (parent_lim_y, offscreen->abs_y + offscreen->height); + y = MAX (y, offscreen->llim_y); + offscreen->lim_y = y; + + g_assert (offscreen->llim_x <= offscreen->lim_x); + g_assert (offscreen->llim_y <= offscreen->lim_y); + + for (l = private->children; l; l = l->next) + recompute_abs_positions (l->data, + offscreen->abs_x, offscreen->abs_y, + offscreen->llim_x, offscreen->llim_y, + offscreen->lim_x, offscreen->lim_y); +} + + +static void +recompute_window (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen, *parent_offscreen; + GdkWindowObject *parent_private; + GList *l; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + if (offscreen->toplevel_offscreen == offscreen) + { + offscreen->abs_x = 0; + offscreen->abs_y = 0; + offscreen->llim_x = 0; + offscreen->llim_y = 0; + offscreen->lim_x = offscreen->width; + offscreen->lim_y = offscreen->height; + + for (l = private->children; l; l = l->next) + recompute_abs_positions (l->data, + offscreen->abs_x, offscreen->abs_y, + offscreen->llim_x, offscreen->llim_y, + offscreen->lim_x, offscreen->lim_y); + } + else + { + parent_private = private->parent; + parent_offscreen = GDK_OFFSCREEN_WINDOW (parent_private->impl); + recompute_abs_positions (window, + parent_offscreen->abs_x, + parent_offscreen->abs_y, + parent_offscreen->llim_x, + parent_offscreen->llim_y, + parent_offscreen->lim_x, + parent_offscreen->lim_y); + } +} + + +/** + * gdk_offscreen_window_new: + * @parent: a #GdkWindow + * @attributes: attributes of the new window + * @attributes_mask: mask indicating which fields in @attributes are valid + * + * Creates a new offscreen #GdkWindow child using the attributes from + * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for + * more details. + + * Being offscreen means that the window will not automatically + * rendered to the parent window, instead it is drawn to a pixmap that + * is availible with gdk_window_get_offscreen_pixmap(). You can use + * this pixmap to render the window however you want. When the + * offscreen pixmap is drawn into, damage events are sent to the + * window, so the GtkWidget::damage_event signal handler can be used + * to make sure the parent window is updated. + * + * All children of an offscreen window are automatically turned into + * offscreen windows that share the offscreen pixmap with the window + * created using gdk_window_new_offscreen(). You can nest offscreen + * windows, but at least one ancestor must be a non-offscreen window. + * + * To correctly support offscreen children a parent window should + * catch the GdkWindow::find-offscreen-child signal on the parent + * window. Additionally, if you render the child transformed you need + * to implement GdkWindow::parent-to-window-coordinate and + * GdkWindow::window-to-parent-coordinate to get coordinates correct + * in e.g. pointer events. + * + * Offscreen windows have some limitations: + * + * + * They can't be toplevel windows. + * They can't contain foreign windows, nor be children + * of foreign windows. This means #GtkPlug/#GtkSocket do not work + * with them. + * X specific features like XVideo and GLX doesn't + * work. + * All rendering must be done inside + * gdk_window_begin_paint_region() and gdk_window_end_paint() + * calls. + * The confine_window argument of pointer grabs + * does not work + * The %GDK_POINTER_MOTION_HINT_MASK mask is not + * effective + * You can't reparent between offscreen windows and + * normal windows + * + * + * Return value: the new #GdkWindow + * + * Since: 2.14 + */ +GdkWindow* +gdk_offscreen_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + return _gdk_window_new_offscreen (parent, attributes, attributes_mask, TRUE); +} + +GdkWindow * +_gdk_window_new_offscreen (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask, + gboolean toplevel) +{ + GdkWindow *window; + GdkWindowObject *parent_private; + GdkWindowObject *private; + GdkOffscreenWindow *offscreen; + int x, y; + GdkScreen *screen; + GdkVisual *visual; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (parent == NULL || + (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT) || + (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN) || + (attributes->window_type != GDK_WINDOW_CHILD) ) + { + g_warning ("Only child offscreen windows allowed"); + return NULL; + } + + if (GDK_WINDOW_DESTROYED (parent)) + return NULL; + + parent_private = (GdkWindowObject*) parent; + + window = g_object_new (GDK_TYPE_WINDOW, NULL); + private = (GdkWindowObject *)window; + private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL); + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + offscreen->wrapper = window; + + private->parent = (GdkWindowObject *)parent; + + screen = gdk_drawable_get_screen (parent); + + offscreen->screen = screen; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + offscreen->width = (attributes->width > 1) ? (attributes->width) : (1); + offscreen->height = (attributes->height > 1) ? (attributes->height) : (1); + + private->window_type = GDK_WINDOW_CHILD; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_screen_get_system_visual (screen); + + private->event_mask = attributes->event_mask; + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + private->input_only = FALSE; + private->depth = visual->depth; + + if (attributes_mask & GDK_WA_COLORMAP) + offscreen->colormap = g_object_ref (attributes->colormap); + else + { + if (gdk_screen_get_system_visual (screen) == visual) + { + offscreen->colormap = gdk_screen_get_system_colormap (screen); + g_object_ref (offscreen->colormap); + } + else + offscreen->colormap = gdk_colormap_new (visual, FALSE); + } + + private->bg_color.red = private->bg_color.green = private->bg_color.blue = 0; + private->bg_color.pixel = 0; + private->bg_pixmap = NULL; + } + else + { + private->depth = 0; + private->input_only = TRUE; + offscreen->colormap = gdk_screen_get_system_colormap (screen); + g_object_ref (offscreen->colormap); + } + + if (private->parent) + { + private->parent->children = g_list_prepend (private->parent->children, window); + + if (toplevel) + _gdk_window_add_offscreen_child (GDK_WINDOW (private->parent)); + } + + /* Inherit redirection from parent */ + private->redirect = private->parent->redirect; + + if (toplevel) + { + GdkPixmap *pixmap; + + offscreen->toplevel_offscreen = offscreen; + offscreen->abs_x = 0; + offscreen->abs_y = 0; + offscreen->llim_x = 0; + offscreen->llim_y = 0; + offscreen->lim_x = offscreen->width; + offscreen->lim_y = offscreen->height; + + pixmap = gdk_pixmap_new (parent, + offscreen->width, + offscreen->height, + private->depth); + gdk_window_redirect_to_drawable (window, + pixmap, 0, 0, 0, 0, + offscreen->width, + offscreen->height); + g_object_unref (pixmap); + } + else + { + GdkOffscreenWindow *parent_offscreen = GDK_OFFSCREEN_WINDOW (parent_private->impl); + + offscreen->toplevel_offscreen = parent_offscreen->toplevel_offscreen; + recompute_abs_positions (window, + parent_offscreen->abs_x, parent_offscreen->abs_y, + parent_offscreen->llim_x, parent_offscreen->llim_y, + parent_offscreen->lim_x, parent_offscreen->lim_y); + } + + + return window; +} + +static gboolean +gdk_offscreen_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent; + GdkOffscreenWindow *offscreen; + gboolean was_mapped; + + /* Can't reparent offscreen window to toplevel */ + if (!new_parent) + return FALSE; + + if (!gdk_window_is_offscreen (new_parent)) + { + g_warning ("Can't reparent offscreen window to native parent"); + return FALSE; + } + + /* No input-output children of input-only windows */ + if (new_parent_private->input_only && !private->input_only) + return FALSE; + + /* Don't create loops in hierarchy */ + if (is_parent_of (window, new_parent)) + return FALSE; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + was_mapped = GDK_WINDOW_IS_MAPPED (window); + + gdk_window_hide (window); + + if (private->parent) + { + private->parent->children = g_list_remove (private->parent->children, window); + if (offscreen->toplevel_offscreen == offscreen) + _gdk_window_remove_offscreen_child (GDK_WINDOW (private->parent)); + } + + private->parent = new_parent_private; + private->x = x; + private->y = y; + + private->parent->children = g_list_prepend (private->parent->children, window); + if (offscreen->toplevel_offscreen == offscreen) + _gdk_window_add_offscreen_child (GDK_WINDOW (private->parent)); + else + { + GdkOffscreenWindow *parent_offscreen = GDK_OFFSCREEN_WINDOW (new_parent_private->impl); + + offscreen->toplevel_offscreen = parent_offscreen->toplevel_offscreen; + recompute_abs_positions (window, + parent_offscreen->abs_x, parent_offscreen->abs_y, + parent_offscreen->llim_x, parent_offscreen->llim_y, + parent_offscreen->lim_x, parent_offscreen->lim_y); + } + + return was_mapped; +} + +/** + * gdk_window_is_offscreen: + * @window: a #GdkWindow + * + * Returns: %TRUE if the window is an offscreen window + **/ +gboolean +gdk_window_is_offscreen (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + return GDK_IS_OFFSCREEN_WINDOW (private->impl); +} + +gboolean +_gdk_window_is_toplevel_offscreen (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + if (!GDK_IS_OFFSCREEN_WINDOW (private->impl)) + return FALSE; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + return offscreen->toplevel_offscreen == offscreen; +} + + +/** + * gdk_window_get_offscreen_pixmap: + * @window: a #GdkWindow + * + * Gets the offscreen pixmap that an offscreen window renders into. If + * you need to keep this around over window resizes, you need to add a + * reference to it. + * + * Returns: The offscreen pixmap, or NULL if not offscreen + **/ +GdkPixmap * +gdk_window_get_offscreen_pixmap (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + if (!GDK_IS_OFFSCREEN_WINDOW (private->impl)) + return NULL; + + return private->redirect->pixmap; +} + +static void +offscreen_visible_rect (GdkOffscreenWindow *offscreen, + GdkRectangle *rect) +{ + rect->x = offscreen->llim_x - offscreen->abs_x; + rect->y = offscreen->llim_y - offscreen->abs_y; + rect->width = offscreen->lim_x - offscreen->llim_x; + rect->height = offscreen->lim_y - offscreen->llim_y; +} + +static GdkRegion * +gdk_offscreen_window_get_visible_region (GdkDrawable *drawable) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkRectangle rect; + + offscreen_visible_rect (offscreen, &rect); + + return gdk_region_rectangle (&rect); +} + +static void +gdk_offscreen_window_invalidate_visible (GdkWindow *window) +{ + GdkRectangle r; + + offscreen_visible_rect (GDK_OFFSCREEN_WINDOW (window), &r); + gdk_window_invalidate_rect (window, &r, TRUE); +} + +static void +gdk_offscreen_window_raise (GdkWindow *window) +{ + /* gdk_window_raise already changed the stacking order */ + gdk_offscreen_window_invalidate_visible (window); +} + +static void +gdk_offscreen_window_invalidate_in_parent (GdkWindowObject *private) +{ + GdkRectangle r, child; + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + /* get the visible rectangle of the parent */ + r.x = r.y = 0; + gdk_drawable_get_size (GDK_DRAWABLE (private->parent), &r.width, &r.height); + + child.x = private->x; + child.y = private->y; + child.width = offscreen->width; + child.height = offscreen->height; + + gdk_rectangle_intersect (&r, &child, &r); + + gdk_window_invalidate_rect (GDK_WINDOW (private->parent), &r, TRUE); +} + + +static void +gdk_offscreen_window_lower (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + /* gdk_window_lower already changed the stacking order */ + + /* Invalidate the rect */ + if (offscreen->toplevel_offscreen != offscreen) + gdk_offscreen_window_invalidate_in_parent (private); +} + +static void +send_pointer_events_for_geometry_change (GdkWindow *window) +{ + GdkWindow *mousewin, *event_window; + GdkWindowOffscreenChildren *offscreen_children; + + event_window = _gdk_window_get_offscreen_event_window (window); + offscreen_children = GDK_WINDOW_OBJECT (event_window)->offscreen_children; + /* The window the pointer is in might have changed */ + if (offscreen_children->window_under_pointer != NULL) + { + mousewin = _gdk_window_get_offscreen_window_child_at (event_window, + offscreen_children->last_mouse_x, + offscreen_children->last_mouse_y, + NULL, NULL); + send_crossing_events (offscreen_children, + event_window, + offscreen_children->window_under_pointer, mousewin, + GDK_CROSSING_NORMAL, + offscreen_children->last_mouse_x, offscreen_children->last_mouse_y, + offscreen_children->last_state, GDK_CURRENT_TIME, + TRUE, TRUE); + } +} + +static void +gdk_offscreen_window_move_region (GdkWindow *window, + const GdkRegion *region, + gint dx, + gint dy) +{ + GdkRegion *dest_region; + + dest_region = gdk_region_copy (region); + gdk_region_offset (dest_region, dx, dy); + + /* Really cheesy implementation that just exposes both regions */ + gdk_window_invalidate_region (window, region, FALSE); + gdk_window_invalidate_region (window, dest_region, FALSE); + +} + +static void +gdk_offscreen_window_scroll (GdkWindow *window, + gint dx, + gint dy) +{ + GdkWindowObject *obj = GDK_WINDOW_OBJECT (window); + GList *tmp_list; + + /* Move the current invalid region */ + if (obj->update_area) + gdk_region_offset (obj->update_area, dx, dy); + +/* We currently scroll in a pretty lame way, we move all + the subwindows, then re-expose the whole window */ + + tmp_list = obj->children; + while (tmp_list) + { + GdkWindow *child = GDK_WINDOW (tmp_list->data); + GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child); + + child_obj->x += dx; + child_obj->y += dx; + recompute_window (child); + + tmp_list = tmp_list->next; + } + + gdk_window_invalidate_rect (window, NULL, TRUE); + send_pointer_events_for_geometry_change (window); +} + +static void +gdk_offscreen_window_move_resize_internal (GdkWindow *window, + gint x, + gint y, + gint width, + gint height, + gboolean send_expose_events) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen, *toplevel; + gint dx, dy, dw, dh; + GdkRegion *old_region; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + toplevel = offscreen->toplevel_offscreen; + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + if (private->destroyed) + return; + + if (private->input_only) + send_expose_events = FALSE; + + old_region = NULL; + if (GDK_WINDOW_IS_MAPPED (private) && send_expose_events) + { + old_region = _gdk_window_calculate_full_clip_region (window, + toplevel->wrapper, + NULL, FALSE, + NULL, NULL); + /* Adjust region to parent window coords */ + gdk_region_offset (old_region, private->x, private->y); + } + + dx = x - private->x; + dy = y - private->y; + dw = width - offscreen->width; + dh = height - offscreen->height; + + private->x = x; + private->y = y; + offscreen->width = width; + offscreen->height = height; + + if (GDK_WINDOW_IS_MAPPED (private)) + { + recompute_window (window); + + if (send_expose_events) + { + if (offscreen == toplevel) + { + if (dw != 0 || dh != 0) + { + GdkGC *gc; + GdkPixmap *old_pixmap; + + old_pixmap = private->redirect->pixmap; + private->redirect->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap), + offscreen->width, + offscreen->height, + private->depth); + private->redirect->width = offscreen->width; + private->redirect->height = offscreen->height; + + gc = _gdk_drawable_get_scratch_gc (private->redirect->pixmap, FALSE); + gdk_draw_drawable (private->redirect->pixmap, + gc, + old_pixmap, + 0,0, 0, 0, + -1, -1); + g_object_unref (old_pixmap); + + } + gdk_window_invalidate_rect (window, NULL, TRUE); + } + else + { + GdkRegion *new_region; + + new_region = _gdk_window_calculate_full_clip_region (window, + toplevel->wrapper, + NULL, FALSE, + NULL, NULL); + /* Adjust region to parent window coords */ + gdk_region_offset (new_region, private->x, private->y); + gdk_region_union (new_region, old_region); + + /* Here we could optimize by copying areas that overlaps both + * new_region and old_region, but we just expose everything instead */ + + /* Invalidate regions in new_region */ + gdk_window_invalidate_region (GDK_WINDOW (private->parent), new_region, TRUE); + + gdk_region_destroy (new_region); + } + } + + send_pointer_events_for_geometry_change (window); + } + + if (old_region != NULL) + gdk_region_destroy (old_region); +} + +static void +gdk_offscreen_window_move (GdkWindow *window, + gint x, gint y) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + gdk_offscreen_window_move_resize_internal (window, x, y, + offscreen->width, + offscreen->height, + TRUE); +} + +static void +gdk_offscreen_window_resize (GdkWindow *window, + gint width, gint height) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + gdk_offscreen_window_move_resize_internal (window, + private->x, private->y, + width, + height, + TRUE); +} + +static void +gdk_offscreen_window_move_resize (GdkWindow *window, + gint x, gint y, + gint width, gint height) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + gdk_offscreen_window_move_resize_internal (window, x, y, + width, height, + TRUE); +} + +static gboolean +all_parents_shown (GdkWindowObject *private) +{ + private = (GdkWindowObject *)private->parent; + + while (private != NULL && + GDK_WINDOW_IS_MAPPED (private) && + GDK_IS_OFFSCREEN_WINDOW (private->impl)) + { + private = (GdkWindowObject *)private->parent; + } + + return private == NULL || !GDK_IS_OFFSCREEN_WINDOW (private->impl); +} + +static const guint type_masks[] = { + GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE = 0 */ + GDK_STRUCTURE_MASK, /* GDK_DESTROY = 1 */ + GDK_EXPOSURE_MASK, /* GDK_EXPOSE = 2 */ + GDK_POINTER_MOTION_MASK, /* GDK_MOTION_NOTIFY = 3 */ + GDK_BUTTON_PRESS_MASK, /* GDK_BUTTON_PRESS = 4 */ + GDK_BUTTON_PRESS_MASK, /* GDK_2BUTTON_PRESS = 5 */ + GDK_BUTTON_PRESS_MASK, /* GDK_3BUTTON_PRESS = 6 */ + GDK_BUTTON_RELEASE_MASK, /* GDK_BUTTON_RELEASE = 7 */ + GDK_KEY_PRESS_MASK, /* GDK_KEY_PRESS = 8 */ + GDK_KEY_RELEASE_MASK, /* GDK_KEY_RELEASE = 9 */ + GDK_ENTER_NOTIFY_MASK, /* GDK_ENTER_NOTIFY = 10 */ + GDK_LEAVE_NOTIFY_MASK, /* GDK_LEAVE_NOTIFY = 11 */ + GDK_FOCUS_CHANGE_MASK, /* GDK_FOCUS_CHANGE = 12 */ + GDK_STRUCTURE_MASK, /* GDK_CONFIGURE = 13 */ + GDK_VISIBILITY_NOTIFY_MASK, /* GDK_MAP = 14 */ + GDK_VISIBILITY_NOTIFY_MASK, /* GDK_UNMAP = 15 */ + GDK_PROPERTY_CHANGE_MASK, /* GDK_PROPERTY_NOTIFY = 16 */ + GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_CLEAR = 17 */ + GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_REQUEST = 18 */ + GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_NOTIFY = 19 */ + GDK_PROXIMITY_IN_MASK, /* GDK_PROXIMITY_IN = 20 */ + GDK_PROXIMITY_OUT_MASK, /* GDK_PROXIMITY_OUT = 21 */ + GDK_ALL_EVENTS_MASK, /* GDK_DRAG_ENTER = 22 */ + GDK_ALL_EVENTS_MASK, /* GDK_DRAG_LEAVE = 23 */ + GDK_ALL_EVENTS_MASK, /* GDK_DRAG_MOTION = 24 */ + GDK_ALL_EVENTS_MASK, /* GDK_DRAG_STATUS = 25 */ + GDK_ALL_EVENTS_MASK, /* GDK_DROP_START = 26 */ + GDK_ALL_EVENTS_MASK, /* GDK_DROP_FINISHED = 27 */ + GDK_ALL_EVENTS_MASK, /* GDK_CLIENT_EVENT = 28 */ + GDK_VISIBILITY_NOTIFY_MASK, /* GDK_VISIBILITY_NOTIFY = 29 */ + GDK_EXPOSURE_MASK, /* GDK_NO_EXPOSE = 30 */ + GDK_SCROLL_MASK /* GDK_SCROLL = 31 */ + /* Later additions: */ + /* GDK_WINDOW_STATE = 32 */ + /* GDK_SETTING = 33 */ + /* GDK_OWNER_CHANGE = 34 */ + /* GDK_GRAB_BROKEN = 35 */ +}; + +static GdkWindow * +get_target_window_for_event (GdkWindow *window, + GdkEventType type, + gboolean recurse) +{ + guint32 evmask; + GdkWindow *w; + gboolean was_offscreen; + + w = window; + while (w != NULL && GDK_WINDOW_OBJECT (w)->window_type != GDK_WINDOW_ROOT) + { + evmask = GDK_WINDOW_OBJECT (w)->event_mask; + + if (evmask & type_masks[type]) + return w; + + if (!recurse) + break; + + /* skip over parent of toplevel, to avoid event recursion */ + was_offscreen = gdk_window_is_offscreen (w); + w = gdk_window_get_parent (w); + if (was_offscreen && !gdk_window_is_offscreen (w)) + w = gdk_window_get_parent (w); + } + + return NULL; +} + +/* send motion events if the right buttons are down */ +static guint +update_evmask_for_button_motion (guint evmask, + GdkModifierType mask) +{ + if ((evmask & GDK_BUTTON_MOTION_MASK) && + (mask & (GDK_BUTTON1_MASK | + GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | + GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK))) + evmask |= GDK_POINTER_MOTION_MASK; + + if (((evmask & GDK_BUTTON1_MOTION_MASK) && (mask & GDK_BUTTON1_MASK)) || + ((evmask & GDK_BUTTON2_MOTION_MASK) && (mask & GDK_BUTTON2_MASK)) || + ((evmask & GDK_BUTTON3_MOTION_MASK) && (mask & GDK_BUTTON3_MASK))) + evmask |= GDK_POINTER_MOTION_MASK; + + return evmask; +} + +static GdkWindow * +get_target_window_for_pointer_event (GdkWindowOffscreenChildren *offscreen_children, + GdkWindow *window, + GdkEventType type, + GdkModifierType mask) +{ + guint evmask; + gboolean crossing_event; + GdkWindow *w, *grab_window; + + /* crossing events don't propagate up like other types of events */ + crossing_event = (type == GDK_ENTER_NOTIFY || type == GDK_LEAVE_NOTIFY); + + if ((offscreen_children->pointer_grab_window != NULL && + !offscreen_children->pointer_grab_owner_events) || + (type == GDK_BUTTON_RELEASE && + offscreen_children->grab_one_pointer_release_event)) + { + evmask = offscreen_children->pointer_grab_event_mask; + evmask = update_evmask_for_button_motion (evmask, mask); + + if (type == GDK_BUTTON_RELEASE && + offscreen_children->grab_one_pointer_release_event) + { + grab_window = offscreen_children->grab_one_pointer_release_event; + offscreen_children->grab_one_pointer_release_event = NULL; + } + else + grab_window = offscreen_children->pointer_grab_window; + + if ((evmask & type_masks[type]) && + (!crossing_event || window == grab_window)) + return grab_window; + else + return NULL; + } + + w = window; + while (w != NULL) + { + evmask = GDK_WINDOW_OBJECT(window)->event_mask; + evmask = update_evmask_for_button_motion (evmask, mask); + + if (evmask & type_masks[type]) + return w; + + if (crossing_event) + break; + + w = gdk_window_get_parent (w); + } + + if (offscreen_children->pointer_grab_window != NULL && + offscreen_children->pointer_grab_owner_events) + { + evmask = offscreen_children->pointer_grab_event_mask; + evmask = update_evmask_for_button_motion (evmask, mask); + + if ((evmask & type_masks[type]) && + (!crossing_event || window == offscreen_children->pointer_grab_window)) + return offscreen_children->pointer_grab_window; + else + return NULL; + } + + return NULL; +} + +static GdkEvent * +make_gdk_event (GdkWindow *window, + GdkEventType type, + GdkEvent *append_after) +{ + GdkEvent *event = gdk_event_new (type); + guint32 the_time; + GdkModifierType the_state; + + the_time = gdk_event_get_time (append_after); + gdk_event_get_state (append_after, &the_state); + + event->any.window = g_object_ref (window); + event->any.send_event = FALSE; + + switch (type) + { + case GDK_MOTION_NOTIFY: + event->motion.time = the_time; + event->motion.axes = NULL; + event->motion.state = the_state; + break; + + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + event->button.time = the_time; + event->button.axes = NULL; + event->button.state = the_state; + break; + + case GDK_SCROLL: + event->scroll.time = the_time; + event->scroll.state = the_state; + break; + + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + event->key.time = the_time; + event->key.state = the_state; + break; + + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + event->crossing.time = the_time; + event->crossing.state = the_state; + break; + + case GDK_PROPERTY_NOTIFY: + event->property.time = the_time; + event->property.state = the_state; + break; + + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + event->selection.time = the_time; + break; + + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + event->proximity.time = the_time; + break; + + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + event->dnd.time = the_time; + break; + + case GDK_FOCUS_CHANGE: + case GDK_CONFIGURE: + case GDK_MAP: + case GDK_UNMAP: + case GDK_CLIENT_EVENT: + case GDK_VISIBILITY_NOTIFY: + case GDK_NO_EXPOSE: + case GDK_DELETE: + case GDK_DESTROY: + case GDK_EXPOSE: + default: + break; + } + + if (append_after) + _gdk_event_queue_append_after (gdk_drawable_get_display (window), append_after, event); + else + _gdk_event_queue_append (gdk_drawable_get_display (window), event); + + return event; +} + +static void +send_map_events (GdkWindowObject *private) +{ + GList *l; + GdkWindowObject *parent_private = private->parent; + GdkWindow *event_win; + GdkOffscreenWindow *offscreen, *parent_offscreen; + + if (!GDK_WINDOW_IS_MAPPED (private)) + return; + + event_win = get_target_window_for_event ((GdkWindow *)private, GDK_MAP, FALSE); + if (event_win) + make_gdk_event (event_win, GDK_MAP, NULL); + + if (private->input_only) + return; + + if (!parent_private) + parent_private = private; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + if (GDK_IS_OFFSCREEN_WINDOW (parent_private->impl)) + { + parent_offscreen = GDK_OFFSCREEN_WINDOW (parent_private->impl); + + if (((offscreen->abs_x > parent_offscreen->lim_x) || + (offscreen->abs_y > parent_offscreen->lim_y) || + (offscreen->lim_x < parent_offscreen->llim_x) || + (offscreen->lim_y < parent_offscreen->llim_y))) + return; + } + + gdk_window_clear ((GdkWindow *)private); + + for (l = private->children; l; l = l->next) + send_map_events (l->data); +} + +static void +gdk_offscreen_window_show (GdkWindow *window, gboolean raise) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + if (GDK_WINDOW_IS_MAPPED (window)) + return; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + private->state = 0; + + /* gdk_window_show already changed the stacking order if needed */ + + if (all_parents_shown (private)) + { + recompute_window (window); + + send_map_events (private); + send_pointer_events_for_geometry_change (window); + + if (private->input_only) + return; + + gdk_window_clear_area_e (window, 0, 0, + offscreen->width, offscreen->height); + } +} + + +static void +gdk_offscreen_window_hide (GdkWindow *window) +{ + GdkWindowObject *private; + GdkWindow *event_win; + GdkOffscreenWindow *offscreen; + GdkWindow *grab_window; + + g_return_if_fail (window != NULL); + + private = (GdkWindowObject*) window; + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + if (GDK_WINDOW_IS_MAPPED (private)) + { + GdkEvent *event; + GdkRectangle r; + GdkDisplay *display; + + /* May need to break grabs on children */ + display = gdk_drawable_get_display (window); + if (gdk_pointer_grab_info_libgtk_only (display, &grab_window, NULL)) + { + if (is_parent_of (window, grab_window)) + { + _gdk_offscreen_window_unset_pointer_grab (grab_window, + FALSE, FALSE, + GDK_CURRENT_TIME); + gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); + _gdk_windowing_grab_broken (display); + } + } + + event_win = get_target_window_for_event (window, GDK_UNMAP, FALSE); + if (event_win) + event = make_gdk_event (event_win, GDK_UNMAP, NULL); + + r.x = offscreen->llim_x; + r.y = offscreen->llim_y; + r.width = offscreen->lim_x - r.x; + r.height = offscreen->lim_y - r.y; + + private->state = GDK_WINDOW_STATE_WITHDRAWN; + + send_pointer_events_for_geometry_change (window); + + /* Invalidate the rect */ + if (offscreen->toplevel_offscreen != offscreen) + gdk_offscreen_window_invalidate_in_parent (private); + } +} + +static void +gdk_offscreen_window_withdraw (GdkWindow *window) +{ +} + +static GdkEventMask +gdk_offscreen_window_get_events (GdkWindow *window) +{ + return GDK_WINDOW_OBJECT (window)->event_mask; +} + +static void +gdk_offscreen_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + GDK_WINDOW_OBJECT (window)->event_mask = event_mask; +} + + +static void +gdk_offscreen_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height, + gboolean send_expose) +{ + if (GDK_WINDOW_DESTROYED (window)) + return; + + /* Actual drawing is done by gdkwindow.c */ + + if (send_expose) + { + GdkRectangle visible, rect; + + visible.x = visible.y = 0; + gdk_drawable_get_size (GDK_DRAWABLE (window), &visible.width, &visible.height); + + rect.x = x; + rect.y = x; + rect.width = width; + rect.height = height; + + gdk_rectangle_intersect (&rect, &visible, &rect); + + gdk_window_invalidate_rect (window, &rect, TRUE); + } +} + +static void +gdk_offscreen_window_set_background (GdkWindow *window, + const GdkColor *color) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkColormap *colormap = gdk_drawable_get_colormap (window); + + private->bg_color = *color; + gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color); + + if (private->bg_pixmap && + private->bg_pixmap != GDK_PARENT_RELATIVE_BG && + private->bg_pixmap != GDK_NO_BG) + g_object_unref (private->bg_pixmap); + + private->bg_pixmap = NULL; +} + +static void +gdk_offscreen_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gboolean parent_relative) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (pixmap == NULL || !parent_relative); + g_return_if_fail (pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap)); + + if (pixmap && !gdk_drawable_get_colormap (pixmap)) + { + g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap"); + return; + } + + if (private->bg_pixmap && + private->bg_pixmap != GDK_PARENT_RELATIVE_BG && + private->bg_pixmap != GDK_NO_BG) + g_object_unref (private->bg_pixmap); + + if (parent_relative) + private->bg_pixmap = GDK_PARENT_RELATIVE_BG; + else + { + if (pixmap) + { + g_object_ref (pixmap); + private->bg_pixmap = pixmap; + } + else + private->bg_pixmap = GDK_NO_BG; + } +} + +static void +gdk_offscreen_window_get_offsets (GdkWindow *window, + gint *x_offset, + gint *y_offset) +{ + *x_offset = 0; + *y_offset = 0; +} + +static GdkWindow * +gdk_offscreen_window_get_window_at (GdkWindow *window, + gdouble x, + gdouble y, + gdouble *win_x, + gdouble *win_y) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + GdkWindow *return_val; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + return_val = NULL; + + if ((x >= 0) && (x < offscreen->width) && + (y >= 0) && (y < offscreen->height)) + { + GdkWindowObject *sub; + GdkOffscreenWindow *sub_offscreen; + gdouble subx = x, suby = y; + + for (sub = private; sub; private = sub) + { + GList *ltmp; + + /* This assumes children is ordered in reverse stack order */ + for (ltmp = private->children; ltmp; ltmp = ltmp->next) + { + sub = ltmp->data; + + if (!GDK_WINDOW_IS_MAPPED (sub)) + continue; + + sub_offscreen = GDK_OFFSCREEN_WINDOW (sub->impl); + + if (subx >= sub->x && + (subx < (sub_offscreen->width + sub->x)) && + (suby >= sub->y) && + (suby < (sub_offscreen->height + sub->y))) + { + subx -= sub->x; + suby -= sub->y; + break; + } + } + + if (!ltmp) + { + sub = NULL; + break; + } + } + + if (win_x) + *win_x = subx; + if (win_y) + *win_y = suby; + + return_val = (GdkWindow *)private; + } + + return return_val; +} + +GdkWindow * +_gdk_window_get_offscreen_window_child_at (GdkWindow *parent, + gdouble x, + gdouble y, + gdouble *win_x_out, + gdouble *win_y_out) +{ + GdkWindow *target; + GdkWindow *child; + GdkWindowObject *parent_private; + gdouble win_x, win_y; + + parent_private = GDK_WINDOW_OBJECT (parent); + if (parent_private && parent_private->offscreen_children) + { + child = find_offscreen_child (parent, x, y); + if (child) + { + parent_to_window (child, x, y, &win_x, &win_y); + target = gdk_offscreen_window_get_window_at (child, + win_x, win_y, + &win_x, &win_y); + return _gdk_window_get_offscreen_window_child_at (target, + win_x, win_y, + win_x_out, win_y_out); + } + } + + if (win_x_out) + *win_x_out = x; + if (win_y_out) + *win_y_out = y; + + return parent; +} + +static GdkWindow * +find_common_ancestor (GdkWindow *win1, + GdkWindow *win2) +{ + GdkWindowObject *tmp; + GList *path1 = NULL, *path2 = NULL; + GList *list1, *list2; + + tmp = GDK_WINDOW_OBJECT (win1); + while (tmp) + { + path1 = g_list_prepend (path1, tmp); + tmp = tmp->parent; + } + + tmp = GDK_WINDOW_OBJECT (win2); + while (tmp) + { + path2 = g_list_prepend (path2, tmp); + tmp = tmp->parent; + } + + list1 = path1; + list2 = path2; + tmp = NULL; + while (list1 && list2 && (list1->data == list2->data)) + { + tmp = (GdkWindowObject *)list1->data; + list1 = g_list_next (list1); + list2 = g_list_next (list2); + } + g_list_free (path1); + g_list_free (path2); + + return GDK_WINDOW (tmp); +} + + +/* x, y are in toplevel coords */ +static void +send_crossing_events (GdkWindowOffscreenChildren *offscreen_children, + GdkWindow *event_window, + GdkWindow *src, + GdkWindow *dest, + GdkCrossingMode mode, + int event_x, int event_y, + GdkModifierType mask, + guint32 time_, + gboolean do_first, + gboolean do_last) +{ + GdkWindow *c; + GdkWindow *win, *last, *next; + GdkEvent *event; + GList *path, *list; + gboolean non_linear; + GdkWindow *a; + GdkWindow *b; + GdkWindow *event_win; + + if ((mode == GDK_CROSSING_NORMAL) && + (dest == offscreen_children->window_under_pointer)) + return; + + if (src) + a = src; + else + a = event_window; + + if (dest) + b = dest; + else + b = event_window; + + if (a == b) + return; + + c = find_common_ancestor (a, b); + if (c == NULL) + return; + + non_linear = (c != a) && (c != b); + + event_win = get_target_window_for_pointer_event (offscreen_children, a, GDK_LEAVE_NOTIFY, mask); + if (do_first && event_win) + { + event = make_gdk_event (event_win, GDK_LEAVE_NOTIFY, NULL); + event->crossing.time = time_; + event->crossing.subwindow = NULL; + convert_event_coords_to_window (event_window, + event_win, event_x, event_y, + &event->crossing.x, &event->crossing.y); + event->crossing.x_root = event_x; + event->crossing.y_root = event_y; + event->crossing.mode = mode; + if (non_linear) + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + else if (c == a) + event->crossing.detail = GDK_NOTIFY_INFERIOR; + else + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + event->crossing.focus = FALSE; + event->crossing.state = mask; + } + + /* Traverse up from a to (excluding) c */ + if (c != a) + { + last = a; + win = GDK_WINDOW (GDK_WINDOW_OBJECT (a)->parent); + while (win != c) + { + event_win = get_target_window_for_pointer_event (offscreen_children, win, GDK_LEAVE_NOTIFY, mask); + if (event_win) + { + event = make_gdk_event (event_win, GDK_LEAVE_NOTIFY, NULL); + event->crossing.time = time_; + event->crossing.subwindow = g_object_ref (last); + convert_event_coords_to_window (event_window, + event_win, event_x, event_y, + &event->crossing.x, &event->crossing.y); + event->crossing.x_root = event_x; + event->crossing.y_root = event_y; + event->crossing.mode = mode; + if (non_linear) + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + else + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + event->crossing.focus = FALSE; + event->crossing.state = mask; + } + last = win; + win = GDK_WINDOW (GDK_WINDOW_OBJECT (win)->parent); + } + } + + /* Traverse down from c to b */ + if (c != b) + { + path = NULL; + win = GDK_WINDOW (GDK_WINDOW_OBJECT (b)->parent); + while (win != c) + { + path = g_list_prepend (path, win); + win = GDK_WINDOW( GDK_WINDOW_OBJECT (win)->parent); + } + + list = path; + while (list) + { + win = (GdkWindow *)list->data; + list = g_list_next (list); + if (list) + next = (GdkWindow *)list->data; + else + next = b; + + event_win = get_target_window_for_pointer_event (offscreen_children, win, GDK_ENTER_NOTIFY, mask); + if (event_win) + { + event = make_gdk_event (event_win, GDK_ENTER_NOTIFY, NULL); + event->crossing.time = time_; + event->crossing.subwindow = g_object_ref (next); + convert_event_coords_to_window (event_window, + event_win, event_x, event_y, + &event->crossing.x, &event->crossing.y); + event->crossing.x_root = event_x; + event->crossing.y_root = event_y; + event->crossing.mode = mode; + if (non_linear) + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + else + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + event->crossing.focus = FALSE; + event->crossing.state = mask; + } + } + g_list_free (path); + } + + event_win = get_target_window_for_pointer_event (offscreen_children, b, GDK_ENTER_NOTIFY, mask); + if (do_last && event_win) + { + event = make_gdk_event (event_win, GDK_ENTER_NOTIFY, NULL); + event->crossing.time = time_; + event->crossing.subwindow = NULL; + convert_event_coords_to_window (event_window, + event_win, event_x, event_y, + &event->crossing.x, &event->crossing.y); + event->crossing.x_root = event_x; + event->crossing.y_root = event_y; + event->crossing.mode = mode; + if (non_linear) + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + else if (c == a) + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + else + event->crossing.detail = GDK_NOTIFY_INFERIOR; + event->crossing.focus = FALSE; + event->crossing.state = mask; + } + + if (mode != GDK_CROSSING_GRAB && + mode != GDK_CROSSING_UNGRAB && + dest != offscreen_children->window_under_pointer) + { + if (offscreen_children->window_under_pointer) + g_object_unref (offscreen_children->window_under_pointer); + offscreen_children->window_under_pointer = NULL; + if (dest) + offscreen_children->window_under_pointer = g_object_ref (dest); + } +} + +/* Find the first enclosing non-offscreen window. + * This window is the one used to get events to the + * offscreen windows + */ +GdkWindow * +_gdk_window_get_offscreen_event_window (GdkWindow *window) +{ + GdkWindowObject *private; + GdkOffscreenWindow *offscreen; + GdkWindow *toplevel; + + while (window != NULL && gdk_window_is_offscreen (window)) + { + private = (GdkWindowObject *)window; + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + toplevel = offscreen->toplevel_offscreen->wrapper; + window = GDK_WINDOW (GDK_WINDOW_OBJECT (toplevel)->parent); + } + + return window; +} + +static void +convert_event_coords_to_window (GdkWindow *event_window, + GdkWindow *window, + gdouble event_x, + gdouble event_y, + gdouble *window_x, + gdouble *window_y) +{ + GdkOffscreenWindow *offscreen, *toplevel_offscreen; + GdkWindow *toplevel_parent; + + if (event_window == window) + { + *window_x = event_x; + *window_y = event_y; + return; + } + + offscreen = GDK_OFFSCREEN_WINDOW (GDK_WINDOW_OBJECT (window)->impl); + + toplevel_offscreen = offscreen->toplevel_offscreen; + toplevel_parent = GDK_WINDOW (GDK_WINDOW_OBJECT (toplevel_offscreen->wrapper)->parent); + if (toplevel_parent != event_window) + convert_event_coords_to_window (event_window, + toplevel_parent, + event_x, event_y, + &event_x, &event_y); + + /* Convert to toplevel coords */ + parent_to_window (toplevel_offscreen->wrapper, + event_x, event_y, + &event_x, &event_y); + + /* Convert to window coords */ + *window_x = event_x - offscreen->abs_x; + *window_y = event_y - offscreen->abs_y; +} + +static void +convert_window_coords_to_event (GdkWindow *event_window, + GdkWindow *window, + gdouble window_x, + gdouble window_y, + gdouble *event_x, + gdouble *event_y) +{ + GdkOffscreenWindow *offscreen, *toplevel_offscreen; + GdkWindow *toplevel_parent; + + offscreen = GDK_OFFSCREEN_WINDOW (GDK_WINDOW_OBJECT (window)->impl); + toplevel_offscreen = offscreen->toplevel_offscreen; + toplevel_parent = GDK_WINDOW (GDK_WINDOW_OBJECT (toplevel_offscreen->wrapper)->parent); + + /* Convert to toplevel coords */ + window_x += offscreen->abs_x; + window_y += offscreen->abs_y; + + /* Convert to parent toplevel coords */ + window_to_parent (toplevel_offscreen->wrapper, + window_x, window_y, + &window_x, &window_y); + if (toplevel_parent != event_window) + convert_window_coords_to_event (event_window, + toplevel_parent, + window_x, window_y, + &window_x, &window_y); + *event_x = window_x; + *event_y = window_y; +} + + +static gboolean +proxy_pointer_event (GdkWindow *pointer_window, + gdouble event_x, + gdouble event_y, + GdkEvent *source_event, + GdkWindowOffscreenChildren *offscreen_children) +{ + GdkWindow *event_win, *cursor_window; + gboolean crossing_event; + gboolean sent_motion; + GdkEvent *event; + guint state; + guint32 time_; + + gdk_event_get_state (source_event, &state); + time_ = gdk_event_get_time (source_event); + + crossing_event = + source_event->type == GDK_ENTER_NOTIFY || + source_event->type == GDK_LEAVE_NOTIFY; + + if (crossing_event) + { + GdkEventCrossing *crossing = &source_event->crossing; + + if (crossing->mode == GDK_CROSSING_GRAB) + { + if (crossing->type == GDK_LEAVE_NOTIFY && + offscreen_children->window_under_pointer != NULL) + { + send_crossing_events (offscreen_children, source_event->any.window, + offscreen_children->window_under_pointer, + NULL, + GDK_CROSSING_GRAB, + event_x, event_y, state, time_, + TRUE, FALSE); + } + + if (crossing->type == GDK_ENTER_NOTIFY && + offscreen_children->pointer_grab_window != NULL) + { + send_crossing_events (offscreen_children, source_event->any.window, + NULL, offscreen_children->pointer_grab_window, + GDK_CROSSING_GRAB, + event_x, event_y, state, time_, + FALSE, TRUE); + } + } + + if (crossing->mode == GDK_CROSSING_UNGRAB) + { + if (crossing->type == GDK_LEAVE_NOTIFY && + offscreen_children->pointer_grab_window != NULL) + { + send_crossing_events (offscreen_children, source_event->any.window, + offscreen_children->pointer_grab_window, + NULL, + GDK_CROSSING_UNGRAB, + event_x, event_y, state, time_, + TRUE, FALSE); + } + + if (crossing->type == GDK_ENTER_NOTIFY && + offscreen_children->window_under_pointer != NULL) + { + send_crossing_events (offscreen_children, source_event->any.window, + NULL, + offscreen_children->window_under_pointer, + GDK_CROSSING_UNGRAB, + event_x, event_y, state, time_, + FALSE, TRUE); + } + } + } + + cursor_window = pointer_window; + if (offscreen_children->pointer_grab_window && + (pointer_window == NULL || + !is_parent_of (offscreen_children->pointer_grab_window, pointer_window))) + cursor_window = offscreen_children->pointer_grab_window; + + /* TODO: set cursor from cursor_window, or grab cursor */ + + sent_motion = FALSE; + if (!crossing_event && + (offscreen_children->window_under_pointer == pointer_window || + (offscreen_children->pointer_grab_window != NULL && + !offscreen_children->pointer_grab_owner_events))) + { + /* send motion events */ + event_win = get_target_window_for_pointer_event (offscreen_children, pointer_window, GDK_MOTION_NOTIFY, state); + + if (event_win) + { + sent_motion = TRUE; + event = make_gdk_event (event_win, GDK_MOTION_NOTIFY, source_event); + event->motion.time = time_; + convert_event_coords_to_window (source_event->any.window, + event_win, event_x, event_y, + &event->motion.x, &event->motion.y); + event->motion.x_root = event_x; /* TODO: right? */ + event->motion.y_root = event_y; + event->motion.state = state; + event->motion.is_hint = FALSE; + event->motion.device = NULL; + if (source_event && source_event->type == GDK_MOTION_NOTIFY) + event->motion.device = source_event->motion.device; + } + } + + send_crossing_events (offscreen_children, + source_event->any.window, + offscreen_children->window_under_pointer, + pointer_window, + GDK_CROSSING_NORMAL, + event_x, event_y, + state, time_, + TRUE, TRUE); + + + /* unlink move event from parent if we sent a motion event */ + return source_event->type == GDK_MOTION_NOTIFY && sent_motion; +} + +static gboolean +is_button_type (GdkEventType type) +{ + return type == GDK_BUTTON_PRESS || + type == GDK_2BUTTON_PRESS || + type == GDK_3BUTTON_PRESS || + type == GDK_BUTTON_RELEASE; +} + +static gboolean +is_scroll_type (GdkEventType type) +{ + return type == GDK_SCROLL; +} + +static gboolean +is_motion_type (GdkEventType type) +{ + return type == GDK_MOTION_NOTIFY || + type == GDK_ENTER_NOTIFY || + type == GDK_LEAVE_NOTIFY; +} + +static gboolean +proxy_button_event (GdkWindow *pointer_window, + gdouble event_x, gint event_y, + GdkEvent *source_event, + GdkWindowOffscreenChildren *offscreen_children) +{ + GdkWindow *event_win; + GdkEvent *event; + guint state; + guint32 time_; + GdkEventType type; + + type = source_event->any.type; + gdk_event_get_state (source_event, &state); + time_ = gdk_event_get_time (source_event); + + if (type == GDK_BUTTON_PRESS && pointer_window != NULL) + _gdk_windowing_update_implicit_grab (source_event->any.window, + pointer_window, + gdk_window_get_events (pointer_window), + time_); + + event_win = get_target_window_for_pointer_event (offscreen_children, + pointer_window, + type, + state); + + if (event_win && event_win != source_event->any.window) + { + event = make_gdk_event (event_win, type, source_event); + + switch (type) + { + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + event->button.time = time_; + event->button.button = source_event->button.button; + convert_event_coords_to_window (source_event->any.window, + event_win, + event_x, event_y, + &event->button.x, &event->button.y); + event->button.x_root = event_x; + event->button.y_root = event_y; + event->button.state = state; + event->button.device = NULL; + if (source_event && is_button_type (type)) + event->button.device = source_event->button.device; + return TRUE; + + case GDK_SCROLL: + event->scroll.time = time_; + event->scroll.direction = source_event->scroll.direction; + convert_event_coords_to_window (source_event->any.window, + event_win, + event_x, event_y, + &event->scroll.x, &event->scroll.y); + event->scroll.x_root = event_x; + event->scroll.y_root = event_y; + event->scroll.state = state; + event->scroll.device = NULL; + if (source_event && is_scroll_type (type)) + event->scroll.device = source_event->scroll.device; + return TRUE; + + default: + return FALSE; + } + } + return FALSE; +} + +static gint +gdk_offscreen_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindow *event_window; + int parent_x, parent_y; + gdouble event_x, event_y; + + event_window = _gdk_window_get_offscreen_event_window (window); + + convert_window_coords_to_event (event_window, window, + 0.0, 0.0, + &event_x, &event_y); + + gdk_window_get_origin (event_window, &parent_x, &parent_y); + + if (x) + *x = floor (event_x + 0.5) + parent_x; + if (y) + *y = floor (event_y + 0.5) + parent_y; + + return TRUE; +} + +static void +gdk_offscreen_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y) +{ +} + +static void +gdk_offscreen_window_shape_combine_region (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y) +{ +} + +static void +gdk_offscreen_window_set_child_shapes (GdkWindow *window) +{ +} + +static void +gdk_offscreen_window_merge_child_shapes (GdkWindow *window) +{ +} + +static gboolean +gdk_offscreen_window_set_static_gravities (GdkWindow *window, + gboolean use_static) +{ + return TRUE; +} + +static void +gdk_offscreen_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + if (offscreen->cursor) + { + gdk_cursor_unref (offscreen->cursor); + offscreen->cursor = NULL; + } + + if (cursor) + offscreen->cursor = gdk_cursor_ref (cursor); + + /* TODO: The cursor is never actually used... */ +} + +static void +gdk_offscreen_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + g_return_if_fail (window == NULL || GDK_IS_WINDOW (window)); + + if (!GDK_WINDOW_DESTROYED (window)) + { + if (x) + *x = private->x; + if (y) + *y = private->y; + if (width) + *width = offscreen->width; + if (height) + *height = offscreen->width; + if (depth) + *depth = private->depth; + } +} + +void +_gdk_offscreen_window_transform_coords (GdkWindow *event_window, + GdkWindow *relative_window, + gint *x, + gint *y) +{ + gdouble window_x, window_y; + + if (relative_window != event_window) + { + /* The relative window is an offscreen window */ + convert_event_coords_to_window (event_window, relative_window, + *x, *y, + &window_x, &window_y); + *x = floor (window_x + 0.5); + *y = floor (window_y + 0.5); + } +} + +void +_gdk_offscreen_window_set_pointer_grab (GdkWindow *old_grab_window, + GdkWindow *old_native_grab_window, + GdkWindow *grab_window, + gboolean owner_events, + guint event_mask, + guint32 time_) +{ + GdkDisplay *display; + GdkWindow *crossing_start, *event_window; + GdkWindowOffscreenChildren *offscreen_children; + gint wx, wy; + + display = gdk_drawable_get_display (grab_window); + event_window = _gdk_window_get_offscreen_event_window (grab_window); + offscreen_children = GDK_WINDOW_OBJECT (event_window)->offscreen_children; + + /* Normal GRAB events are sent by listening for enter and leave + * events on the parent of the toplevel, which is then proxied + * into the offscreen where we create them. However, there are two + * cases where X will not send these events: + * * When there is already a grab on the parent of the toplevel + * offscreen grab window + * * When there is no grab, but the pointer is already in the + * parent of the toplevel offscreen grab window + * In these cases we need to generate our own grab crossing events. + */ + crossing_start = NULL; + if (old_grab_window != NULL && old_native_grab_window == event_window) + crossing_start = old_grab_window; + + if (old_grab_window == NULL && + _gdk_windowing_window_at_pointer (display, &wx, &wy) == event_window) + crossing_start = offscreen_children->window_under_pointer; + + if (crossing_start != NULL) + { + /* TODO: Hmmm, is this totally right if start is in another toplevel? */ + send_crossing_events (offscreen_children, + event_window, + crossing_start, + grab_window, + GDK_CROSSING_GRAB, + /* These may be stale... */ + offscreen_children->last_mouse_x, + offscreen_children->last_mouse_y, + offscreen_children->last_state, + time_, TRUE, TRUE); + } + + + /* TODO: What about the case of grabbing the toplevel parent, when + an offscreen child of it is grabbed or has the pointer? */ + + if (offscreen_children->pointer_grab_window != NULL) + g_object_unref (offscreen_children->pointer_grab_window); + + offscreen_children->pointer_grab_window = g_object_ref (grab_window); + offscreen_children->pointer_grab_owner_events = owner_events; + offscreen_children->pointer_grab_event_mask = event_mask; +} + +void +_gdk_offscreen_window_unset_pointer_grab (GdkWindow *window, + gboolean regrab, + gboolean grab_one_pointer_release_event, + guint32 time_) +{ + GdkWindow *event_window; + GdkWindowOffscreenChildren *offscreen_children; + GdkDisplay *display; + gint wx, wy; + + display = gdk_drawable_get_display (window); + event_window = _gdk_window_get_offscreen_event_window (window); + offscreen_children = GDK_WINDOW_OBJECT (event_window)->offscreen_children; + + g_assert (offscreen_children->pointer_grab_window != NULL); + + if (grab_one_pointer_release_event) + offscreen_children->grab_one_pointer_release_event = offscreen_children->pointer_grab_window; + + g_object_unref (offscreen_children->pointer_grab_window); + offscreen_children->pointer_grab_window = NULL; + + /* Normal UNGRAB events are sent by listening for enter and leave + * events on the parent of the toplevel, which is then proxied + * into the offscreen where we create them. However, there are two + * cases where X will not send these events: + * * When this ungrab is due to a new grab on the parent of the toplevel + * offscreen grab window. + * * When there is no new grab, and the pointer is already in the + * parent of the toplevel offscreen grab window + * In the first case we send the right GRAB events from the grab, but + * in the second case we need to generate our own UNGRAB crossing events. + */ + if (!regrab && + _gdk_windowing_window_at_pointer (display, &wx, &wy) == event_window) + { + GdkWindow *crossing_end = offscreen_children->window_under_pointer; + + send_crossing_events (offscreen_children, event_window, + window, + crossing_end, + GDK_CROSSING_UNGRAB, + /* These may be stale... */ + offscreen_children->last_mouse_x, + offscreen_children->last_mouse_y, + offscreen_children->last_state, + time_, TRUE, TRUE); + } +} + +void +_gdk_event_rewrite_for_offscreen (GdkDisplay *display, + GList *event_link, + GdkEvent *event) +{ + GdkWindow *event_window; + GdkWindow *pointer_window; + GdkWindowObject *event_private; + GdkWindowOffscreenChildren *offscreen_children; + gboolean is_grab; + gdouble x,y; + gboolean unlink_event; + + event_window = event->any.window; + event_private = GDK_WINDOW_OBJECT (event_window); + if (!event_window || !event_private->offscreen_children) + return; + + if (!(is_button_type (event->type) || is_motion_type (event->type))) + return; + + offscreen_children = event_private->offscreen_children; + + gdk_event_get_coords (event, &x, &y); + offscreen_children->last_mouse_x = x; + offscreen_children->last_mouse_y = y; + + gdk_event_get_state (event, &offscreen_children->last_state); + + pointer_window = _gdk_window_get_offscreen_window_child_at (event_window, + x, y, + NULL, NULL); + if (pointer_window == event_window) + pointer_window = NULL; + + is_grab = FALSE; + if (offscreen_children->pointer_grab_window) + is_grab = TRUE; + + unlink_event = FALSE; + if (is_motion_type (event->type)) + unlink_event = proxy_pointer_event (pointer_window, x, y, + event, + offscreen_children); + + if (is_button_type (event->type)) + unlink_event = proxy_button_event (pointer_window, x, y, + event, + offscreen_children); + + if (is_scroll_type (event->type)) + unlink_event = proxy_button_event (pointer_window, x, y, + event, + offscreen_children); + + if (unlink_event) + { + _gdk_event_queue_remove_link (display, event_link); + g_list_free_1 (event_link); + gdk_event_free (event); + } +} + +/** + * gdk_window_set_offscreen_hooks: + * @window: a #GdkWindow + * @hooks: a table of pointers to functions for handling offscreen + * window coordinates translations + * + * Sets the parent-to-window and window-to-parent coordinates + * translation functions for offscreen windows. + * + * This function is useful for complex widgets employing + * offscreen windows. + * + * Since: 2.16 + */ +void +gdk_window_set_offscreen_hooks (GdkWindow *window, + const GdkOffscreenHooks *hooks) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (hooks != NULL); + + private = (GdkWindowObject *) window; + + private->offscreen_hooks = hooks; +} + +static void +gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface) +{ + iface->show = gdk_offscreen_window_show; + iface->hide = gdk_offscreen_window_hide; + iface->withdraw = gdk_offscreen_window_withdraw; + iface->raise = gdk_offscreen_window_raise; + iface->lower = gdk_offscreen_window_lower; + iface->move = gdk_offscreen_window_move; + iface->resize = gdk_offscreen_window_resize; + iface->move_resize = gdk_offscreen_window_move_resize; + iface->scroll = gdk_offscreen_window_scroll; + iface->move_region = gdk_offscreen_window_move_region; + iface->set_background = gdk_offscreen_window_set_background; + iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap; + iface->get_events = gdk_offscreen_window_get_events; + iface->set_events = gdk_offscreen_window_set_events; + iface->clear_area = gdk_offscreen_window_clear_area; + iface->reparent = gdk_offscreen_window_reparent; + iface->set_cursor = gdk_offscreen_window_set_cursor; + iface->get_geometry = gdk_offscreen_window_get_geometry; + iface->get_origin = gdk_offscreen_window_get_origin; + iface->shape_combine_mask = gdk_offscreen_window_shape_combine_mask; + iface->shape_combine_region = gdk_offscreen_window_shape_combine_region; + iface->set_child_shapes = gdk_offscreen_window_set_child_shapes; + iface->merge_child_shapes = gdk_offscreen_window_merge_child_shapes; + iface->set_static_gravities = gdk_offscreen_window_set_static_gravities; + iface->get_offsets = gdk_offscreen_window_get_offsets; +} diff --git a/gdk/gdkpixmap.c b/gdk/gdkpixmap.c index c717b9a..806a5ca 100644 --- a/gdk/gdkpixmap.c +++ b/gdk/gdkpixmap.c @@ -229,6 +229,48 @@ gdk_pixmap_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } +GdkPixmap * +gdk_pixmap_new (GdkDrawable *drawable, + gint width, + gint height, + gint depth) +{ + GdkDrawable *source_drawable; + + source_drawable = _gdk_drawable_get_source_drawable (drawable); + return _gdk_pixmap_new (source_drawable, width, height, depth); +} + +GdkPixmap * +gdk_bitmap_create_from_data (GdkDrawable *drawable, + const gchar *data, + gint width, + gint height) +{ + GdkDrawable *source_drawable; + + source_drawable = _gdk_drawable_get_source_drawable (drawable); + return _gdk_bitmap_create_from_data (source_drawable, data, width, height); +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkDrawable *drawable, + const gchar *data, + gint width, + gint height, + gint depth, + const GdkColor *fg, + const GdkColor *bg) +{ + GdkDrawable *source_drawable; + + source_drawable = _gdk_drawable_get_source_drawable (drawable); + return _gdk_pixmap_create_from_data (source_drawable, + data, width, height, + depth, fg,bg); +} + + static GdkGC * gdk_pixmap_create_gc (GdkDrawable *drawable, GdkGCValues *values, diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 28064ae..16e5b9b 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -27,6 +27,7 @@ #include "config.h" #include "gdkwindow.h" +#include "gdkwindowimpl.h" #include "gdkinternals.h" #include "gdk.h" /* For gdk_rectangle_union() */ #include "gdkpixmap.h" @@ -55,18 +56,6 @@ typedef struct { gint y_offset; } GdkWindowClipData; -struct _GdkWindowRedirect -{ - GdkWindowObject *redirected; - GdkDrawable *pixmap; - gint src_x; - gint src_y; - gint dest_x; - gint dest_y; - gint width; - gint height; -}; - static GdkGC *gdk_window_create_gc (GdkDrawable *drawable, GdkGCValues *values, GdkGCValuesMask mask); @@ -191,6 +180,7 @@ static void gdk_window_real_set_colormap (GdkDrawable *drawable, GdkColormap *cmap); static GdkColormap* gdk_window_real_get_colormap (GdkDrawable *drawable); +static GdkDrawable* gdk_window_get_source_drawable (GdkDrawable *drawable); static GdkDrawable* gdk_window_get_composite_drawable (GdkDrawable *drawable, gint x, gint y, @@ -202,6 +192,7 @@ static GdkRegion* gdk_window_get_clip_region (GdkDrawable *drawable); static GdkRegion* gdk_window_get_visible_region (GdkDrawable *drawable); static void gdk_window_free_paint_stack (GdkWindow *window); +static void gdk_window_raise_internal (GdkWindow *window); static void gdk_window_init (GdkWindowObject *window); static void gdk_window_class_init (GdkWindowObjectClass *klass); @@ -222,12 +213,6 @@ static void apply_redirect_to_children (GdkWindowObject *private, GdkWindowRedirect *redirect); static void remove_redirect_from_children (GdkWindowObject *private, GdkWindowRedirect *redirect); -static GdkRegion *_gdk_window_calculate_full_clip_region (GdkWindow *window, - GdkWindow *base_window, - GdkGC *gc, - gboolean do_children, - gint *base_x_offset, - gint *base_y_offset); static gpointer parent_class = NULL; @@ -280,8 +265,6 @@ gdk_window_init (GdkWindowObject *window) window->window_type = GDK_WINDOW_CHILD; window->state = GDK_WINDOW_STATE_WITHDRAWN; - - window->impl = g_object_new (_gdk_window_impl_get_type (), NULL); } static void @@ -320,6 +303,7 @@ gdk_window_class_init (GdkWindowObjectClass *klass) drawable_class->get_clip_region = gdk_window_get_clip_region; drawable_class->get_visible_region = gdk_window_get_visible_region; drawable_class->get_composite_drawable = gdk_window_get_composite_drawable; + drawable_class->get_source_drawable = gdk_window_get_source_drawable; } static void @@ -372,7 +356,10 @@ gdk_window_new (GdkWindow *parent, g_return_val_if_fail (attributes != NULL, NULL); - window = _gdk_window_new (parent, attributes, attributes_mask); + if (parent && gdk_window_is_offscreen (parent)) + window = _gdk_window_new_offscreen (parent, attributes, attributes_mask, FALSE); + else + window = _gdk_window_new (parent, attributes, attributes_mask); /* Inherit redirection from parent */ if (parent != NULL) @@ -403,6 +390,7 @@ gdk_window_reparent (GdkWindow *window, gint y) { GdkWindowObject *private; + gboolean show; g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent)); @@ -410,9 +398,7 @@ gdk_window_reparent (GdkWindow *window, if (GDK_WINDOW_DESTROYED (window) || (new_parent && GDK_WINDOW_DESTROYED (new_parent))) - { - return; - } + return; private = (GdkWindowObject *) window; @@ -423,7 +409,7 @@ gdk_window_reparent (GdkWindow *window, private->redirect = NULL; } - _gdk_window_reparent (window, new_parent, x, y); + show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent (window, new_parent, x, y); /* Inherit parent redirect if we don't have our own */ if (private->parent && private->redirect == NULL) @@ -431,6 +417,9 @@ gdk_window_reparent (GdkWindow *window, private->redirect = private->parent->redirect; apply_redirect_to_children (private, private->redirect); } + + if (show) + gdk_window_show (window); } static void @@ -560,8 +549,12 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, g_list_free (children); } - - _gdk_windowing_window_destroy (window, recursing, foreign_destroy); + + if (gdk_window_is_offscreen (window)) + _gdk_offscreen_window_destroy (window, recursing); + else + _gdk_windowing_window_destroy (window, recursing, foreign_destroy); + private->parent = NULL; private->destroyed = TRUE; @@ -1205,7 +1198,7 @@ gdk_window_end_paint (GdkWindow *window) tmp_gc = _gdk_drawable_get_scratch_gc (window, FALSE); - _gdk_windowing_window_get_offsets (window, &x_offset, &y_offset); + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, &x_offset, &y_offset); gdk_gc_set_clip_region (tmp_gc, paint->region); gdk_gc_set_clip_origin (tmp_gc, - x_offset, - y_offset); @@ -1309,7 +1302,7 @@ gdk_window_get_offsets (GdkWindow *window, *y_offset = paint->y_offset; } else - _gdk_windowing_window_get_offsets (window, x_offset, y_offset); + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, x_offset, y_offset); } /** @@ -1423,7 +1416,7 @@ gdk_window_draw_rectangle (GdkDrawable *drawable, { GdkWindowPaint *paint = private->paint_stack->data; gdk_draw_rectangle (paint->pixmap, gc, filled, - x - x_offset, y - y_offset, width, height); + x - x_offset, y - y_offset, width, height); } else gdk_draw_rectangle (private->impl, gc, filled, @@ -1564,7 +1557,18 @@ gdk_window_draw_text_wc (GdkDrawable *drawable, RESTORE_GC (gc); } -static GdkDrawable* +static GdkDrawable * +gdk_window_get_source_drawable (GdkDrawable *drawable) +{ + GdkWindow *window = GDK_WINDOW (drawable); + + if (gdk_window_is_offscreen (window)) + return gdk_window_get_offscreen_pixmap (window); + + return drawable; +} + +static GdkDrawable * gdk_window_get_composite_drawable (GdkDrawable *drawable, gint x, gint y, @@ -1579,13 +1583,16 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable, GdkRectangle rect; GdkGC *tmp_gc; gboolean overlap_buffer; + gboolean is_offscreen; - _gdk_windowing_window_get_offsets (drawable, - composite_x_offset, - composite_y_offset); - - if ((GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable)) - || private->paint_stack == NULL) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (GDK_WINDOW (drawable), + composite_x_offset, + composite_y_offset); + + is_offscreen = gdk_window_is_offscreen (GDK_WINDOW (drawable)); + + if ((GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable)) || + (!is_offscreen && private->paint_stack == NULL)) { /* No backing store */ return g_object_ref (drawable); @@ -1622,7 +1629,7 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable, } } - if (!overlap_buffer) + if (!overlap_buffer && !is_offscreen) return g_object_ref (drawable); tmp_pixmap = gdk_pixmap_new (drawable, width, height, -1); @@ -2188,15 +2195,18 @@ gdk_window_clear_area (GdkWindow *window, g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); - + if (private->paint_stack) gdk_window_clear_backing_rect (window, x, y, width, height); else { if (private->redirect) gdk_window_clear_backing_rect_redirect (window, x, y, width, height); - - _gdk_windowing_window_clear_area (window, x, y, width, height); + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window, + x, y, + width, height, + FALSE); } } @@ -2232,8 +2242,11 @@ gdk_window_clear_area_e (GdkWindow *window, if (private->redirect) gdk_window_clear_backing_rect_redirect (window, x, y, width, height); - - _gdk_windowing_window_clear_area_e (window, x, y, width, height); + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window, + x, y, + width, height, + TRUE); } static void @@ -2444,6 +2457,7 @@ gdk_window_copy_to_image (GdkDrawable *drawable, gint width, gint height) { + GdkWindowObject *private = (GdkWindowObject *) drawable; gint x_offset, y_offset; g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL); @@ -2455,9 +2469,10 @@ gdk_window_copy_to_image (GdkDrawable *drawable, * we can ignore the paint stack. */ - _gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset); + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (drawable, + &x_offset, &y_offset); - return gdk_drawable_copy_to_image (((GdkWindowObject*)drawable)->impl, + return gdk_drawable_copy_to_image (private->impl, image, src_x - x_offset, src_y - y_offset, @@ -2551,8 +2566,9 @@ gdk_window_process_updates_internal (GdkWindow *window) gdk_display_sync (gdk_drawable_get_display (window)); g_usleep (70000); } - - save_region = _gdk_windowing_window_queue_antiexpose (window, update_area); + + if (!gdk_window_is_offscreen (window)) + save_region = _gdk_windowing_window_queue_antiexpose (window, update_area); if (save_region) expose_region = gdk_region_copy (update_area); @@ -2870,7 +2886,8 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window, /* remove child area from the invalid area of the parent */ if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped && - !child->composited) + !child->composited && + !_gdk_window_is_toplevel_offscreen (GDK_WINDOW (child))) gdk_region_subtract (visible_region, child_region); if (child_func && (*child_func) ((GdkWindow *)child, user_data)) @@ -3383,6 +3400,741 @@ gdk_window_foreign_new (GdkNativeWindow anid) } /** + * gdk_window_show_unraised: + * @window: a #GdkWindow + * + * Shows a #GdkWindow onscreen, but does not modify its stacking + * order. In contrast, gdk_window_show() will raise the window + * to the top of the window stack. + * + * On the X11 platform, in Xlib terms, this function calls + * XMapWindow() (it also updates some internal GDK state, which means + * that you can't really use XMapWindow() directly on a GDK window). + */ +void +gdk_window_show_unraised (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, FALSE); +} + +static inline void +gdk_window_raise_internal (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *parent; + + parent = private->parent; + + if (parent) + { + parent->children = g_list_remove (parent->children, window); + parent->children = g_list_prepend (parent->children, window); + } +} + +/** + * gdk_window_show: + * @window: a #GdkWindow + * + * Like gdk_window_show_unraised(), but also raises the window to the + * top of the window stack (moves the window to the front of the + * Z-order). + * + * This function maps a window so it's visible onscreen. Its opposite + * is gdk_window_hide(). + * + * When implementing a #GtkWidget, you should call this function on the widget's + * #GdkWindow as part of the "map" method. + */ +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + /* Keep children in (reverse) stacking order */ + gdk_window_raise_internal (window); + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, TRUE); +} + +/** + * gdk_window_hide: + * @window: a #GdkWindow + * + * For toplevel windows, withdraws them, so they will no longer be + * known to the window manager; for all windows, unmaps them, so + * they won't be displayed. Normally done automatically as + * part of gtk_widget_hide(). + */ +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide (window); +} + +/** + * gdk_window_withdraw: + * @window: a toplevel #GdkWindow + * + * Withdraws a window (unmaps it and asks the window manager to forget about it). + * This function is not really useful as gdk_window_hide() automatically + * withdraws toplevel windows before hiding them. + **/ +void +gdk_window_withdraw (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->withdraw (window); +} + +/** + * gdk_window_set_events: + * @window: a #GdkWindow + * @event_mask: event mask for @window + * + * The event mask for a window determines which events will be reported + * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK + * means the window should report button press events. The event mask + * is the bitwise OR of values from the #GdkEventMask enumeration. + **/ +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, event_mask); +} + +/** + * gdk_window_get_events: + * @window: a #GdkWindow + * + * Gets the event mask for @window. See gdk_window_set_events(). + * + * Return value: event mask for @window + **/ +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return 0; + + return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_events (window); +} + +/** + * gdk_window_raise: + * @window: a #GdkWindow + * + * Raises @window to the top of the Z-order (stacking order), so that + * other windows with the same parent window appear below @window. + * This is true whether or not the windows are visible. + * + * If @window is a toplevel, the window manager may choose to deny the + * request to move the window in the Z-order, gdk_window_raise() only + * requests the restack, does not guarantee it. + */ +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + /* Keep children in (reverse) stacking order */ + gdk_window_raise_internal (window); + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window); +} + +static void +gdk_window_lower_internal (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *parent; + + parent = private->parent; + if (parent) + { + parent->children = g_list_remove (parent->children, window); + parent->children = g_list_append (parent->children, window); + } +} + +/** + * gdk_window_lower: + * @window: a #GdkWindow + * + * Lowers @window to the bottom of the Z-order (stacking order), so that + * other windows with the same parent window appear above @window. + * This is true whether or not the other windows are visible. + * + * If @window is a toplevel, the window manager may choose to deny the + * request to move the window in the Z-order, gdk_window_lower() only + * requests the restack, does not guarantee it. + * + * Note that gdk_window_show() raises the window again, so don't call this + * function before gdk_window_show(). (Try gdk_window_show_unraised().) + */ +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + /* Keep children in (reverse) stacking order */ + gdk_window_lower_internal (window); + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->lower (window); +} + +/** + * gdk_window_move: + * @window: a #GdkWindow + * @x: X coordinate relative to window's parent + * @y: Y coordinate relative to window's parent + * + * Repositions a window relative to its parent window. + * For toplevel windows, window managers may ignore or modify the move; + * you should probably use gtk_window_move() on a #GtkWindow widget + * anyway, instead of using GDK functions. For child windows, + * the move will reliably succeed. + * + * If you're also planning to resize the window, use gdk_window_move_resize() + * to both move and resize simultaneously, for a nicer visual effect. + **/ +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move (window, x, y); +} + +/** + * gdk_window_resize: + * @window: a #GdkWindow + * @width: new width of the window + * @height: new height of the window + * + * Resizes @window; for toplevel windows, asks the window manager to resize + * the window. The window manager may not allow the resize. When using GTK+, + * use gtk_window_resize() instead of this low-level GDK function. + * + * Windows may not be resized below 1x1. + * + * If you're also planning to move the window, use gdk_window_move_resize() + * to both move and resize simultaneously, for a nicer visual effect. + **/ +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->resize (window, width, height); +} + + +/** + * gdk_window_move_resize: + * @window: a #GdkWindow + * @x: new X position relative to window's parent + * @y: new Y position relative to window's parent + * @width: new width + * @height: new height + * + * Equivalent to calling gdk_window_move() and gdk_window_resize(), + * except that both operations are performed at once, avoiding strange + * visual effects. (i.e. the user may be able to see the window first + * move, then resize, if you don't use gdk_window_move_resize().) + **/ +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, x, y, width, height); +} + + +/** + * gdk_window_scroll: + * @window: a #GdkWindow + * @dx: Amount to scroll in the X direction + * @dy: Amount to scroll in the Y direction + * + * Scroll the contents of @window, both pixels and children, by the + * given amount. @window itself does not move. Portions of the window + * that the scroll operation brings in from offscreen areas are + * invalidated. The invalidated region may be bigger than what would + * strictly be necessary. + * + * For X11, a minimum area will be invalidated if the window has no + * subwindows, or if the edges of the window's parent do not extend + * beyond the edges of the window. In other cases, a multi-step process + * is used to scroll the window which may produce temporary visual + * artifacts and unnecessary invalidations. + **/ +void +gdk_window_scroll (GdkWindow *window, + gint dx, + gint dy) +{ + GdkWindowObject *private = (GdkWindowObject *) window; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (dx == 0 && dy == 0) + return; + + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->scroll (window, dx, dy); +} + +/** + * gdk_window_move_region: + * @window: a #GdkWindow + * @region: The #GdkRegion to move + * @dx: Amount to move in the X direction + * @dy: Amount to move in the Y direction + * + * Move the part of @window indicated by @region by @dy pixels in the Y + * direction and @dx pixels in the X direction. The portions of @region + * that not covered by the new position of @region are invalidated. + * + * Child windows are not moved. + * + * Since: 2.8 + */ +void +gdk_window_move_region (GdkWindow *window, + const GdkRegion *region, + gint dx, + gint dy) +{ + GdkWindowObject *private = (GdkWindowObject *) window; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (region != NULL); + + if (dx == 0 && dy == 0) + return; + + if (private->destroyed) + return; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_region (window, region, dx, dy); +} + +/** + * gdk_window_set_background: + * @window: a #GdkWindow + * @color: an allocated #GdkColor + * + * Sets the background color of @window. (However, when using GTK+, + * set the background of a widget with gtk_widget_modify_bg() - if + * you're an application - or gtk_style_set_background() - if you're + * implementing a custom widget.) + * + * The @color must be allocated; gdk_rgb_find_color() is the best way + * to allocate a color. + * + * See also gdk_window_set_back_pixmap(). + */ +void +gdk_window_set_background (GdkWindow *window, + const GdkColor *color) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, color); +} + +/** + * gdk_window_set_back_pixmap: + * @window: a #GdkWindow + * @pixmap: a #GdkPixmap, or %NULL + * @parent_relative: whether the tiling origin is at the origin of + * @window's parent + * + * Sets the background pixmap of @window. May also be used to set a + * background of "None" on @window, by setting a background pixmap + * of %NULL. + * + * A background pixmap will be tiled, positioning the first tile at + * the origin of @window, or if @parent_relative is %TRUE, the tiling + * will be done based on the origin of the parent window (useful to + * align tiles in a parent with tiles in a child). + * + * A background pixmap of %NULL means that the window will have no + * background. A window with no background will never have its + * background filled by the windowing system, instead the window will + * contain whatever pixels were already in the corresponding area of + * the display. + * + * The windowing system will normally fill a window with its background + * when the window is obscured then exposed, and when you call + * gdk_window_clear(). + */ +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gboolean parent_relative) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, pixmap, parent_relative); +} + +/** + * gdk_window_set_cursor: + * @window: a #GdkWindow + * @cursor: a cursor + * + * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or + * gdk_cursor_new_from_pixmap() to create the cursor. + * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create + * a cursor with no pixels in it. Passing %NULL for the @cursor argument + * to gdk_window_set_cursor() means that @window will use the cursor of + * its parent window. Most windows should use this default. + */ +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_cursor (window, cursor); +} + +/** + * gdk_window_get_geometry: + * @window: a #GdkWindow + * @x: return location for X coordinate of window (relative to its parent) + * @y: return location for Y coordinate of window (relative to its parent) + * @width: return location for width of window + * @height: return location for height of window + * @depth: return location for bit depth of window + * + * Any of the return location arguments to this function may be %NULL, + * if you aren't interested in getting the value of that field. + * + * The X and Y coordinates returned are relative to the parent window + * of @window, which for toplevels usually means relative to the + * window decorations (titlebar, etc.) rather than relative to the + * root window (screen-size background window). + * + * On the X11 platform, the geometry is obtained from the X server, + * so reflects the latest position of @window; this may be out-of-sync + * with the position of @window delivered in the most-recently-processed + * #GdkEventConfigure. gdk_window_get_position() in contrast gets the + * position from the most recent configure event. + * + * + * If @window is not a toplevel, it is much better + * to call gdk_window_get_position() and gdk_drawable_get_size() instead, + * because it avoids the roundtrip to the X server and because + * gdk_drawable_get_size() supports the full 32-bit coordinate space, + * whereas gdk_window_get_geometry() is restricted to the 16-bit + * coordinates of X11. + * + **/ +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + GdkWindowObject *private; + + if (!window) + { + GDK_NOTE (MULTIHEAD, + g_message ("gdk_window_get_geometry(): Window needs " + "to be non-NULL to be multi head safe")); + window = gdk_screen_get_root_window ((gdk_screen_get_default ())); + } + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + if (!GDK_WINDOW_DESTROYED (window)) + { + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y, + width, height, + depth); + } +} + +/** + * gdk_window_get_origin: + * @window: a #GdkWindow + * @x: return location for X coordinate + * @y: return location for Y coordinate + * + * Obtains the position of a window in root window coordinates. + * (Compare with gdk_window_get_position() and + * gdk_window_get_geometry() which return the position of a window + * relative to its parent window.) + * + * Return value: not meaningful, ignore + */ +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowObject *private; + + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + + private = (GdkWindowObject *) window; + + return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_origin (window, x, y); +} + +/** + * gdk_window_shape_combine_mask: + * @window: a #GdkWindow + * @mask: shape mask + * @x: X position of shape mask with respect to @window + * @y: Y position of shape mask with respect to @window + * + * Applies a shape mask to @window. Pixels in @window corresponding to + * set bits in the @mask will be visible; pixels in @window + * corresponding to unset bits in the @mask will be transparent. This + * gives a non-rectangular window. + * + * If @mask is %NULL, the shape mask will be unset, and the @x/@y + * parameters are not used. + * + * On the X11 platform, this uses an X server extension which is + * widely available on most common platforms, but not available on + * very old X servers, and occasionally the implementation will be + * buggy. On servers without the shape extension, this function + * will do nothing. + * + * This function works on both toplevel and child windows. + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_mask (window, mask, x, y); +} + +/** + * gdk_window_shape_combine_region: + * @window: a #GdkWindow + * @shape_region: region of window to be non-transparent + * @offset_x: X position of @shape_region in @window coordinates + * @offset_y: Y position of @shape_region in @window coordinates + * + * Makes pixels in @window outside @shape_region be transparent, + * so that the window may be nonrectangular. See also + * gdk_window_shape_combine_mask() to use a bitmap as the mask. + * + * If @shape_region is %NULL, the shape will be unset, so the whole + * window will be opaque again. @offset_x and @offset_y are ignored + * if @shape_region is %NULL. + * + * On the X11 platform, this uses an X server extension which is + * widely available on most common platforms, but not available on + * very old X servers, and occasionally the implementation will be + * buggy. On servers without the shape extension, this function + * will do nothing. + * + * This function works on both toplevel and child windows. + */ +void +gdk_window_shape_combine_region (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region (window, shape_region, offset_x, offset_y); +} + +/** + * gdk_window_set_child_shapes: + * @window: a #GdkWindow + * + * Sets the shape mask of @window to the union of shape masks + * for all children of @window, ignoring the shape mask of @window + * itself. Contrast with gdk_window_merge_child_shapes() which includes + * the shape mask of @window in the masks to be merged. + **/ +void +gdk_window_set_child_shapes (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_child_shapes (window); +} + +/** + * gdk_window_merge_child_shapes: + * @window: a #GdkWindow + * + * Merges the shape masks for any child windows into the + * shape mask for @window. i.e. the union of all masks + * for @window and its children will become the new mask + * for @window. See gdk_window_shape_combine_mask(). + * + * This function is distinct from gdk_window_set_child_shapes() + * because it includes @window's shape mask in the set of shapes to + * be merged. + */ +void +gdk_window_merge_child_shapes (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->merge_child_shapes (window); +} + + +/** + * gdk_window_set_static_gravities: + * @window: a #GdkWindow + * @use_static: %TRUE to turn on static gravity + * + * Set the bit gravity of the given window to static, and flag it so + * all children get static subwindow gravity. This is used if you are + * implementing scary features that involve deep knowledge of the + * windowing system. Don't worry about it unless you have to. + * + * Return value: %TRUE if the server supports static gravity + */ +gboolean +gdk_window_set_static_gravities (GdkWindow *window, + gboolean use_static) +{ + GdkWindowObject *private; + + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + private = (GdkWindowObject *) window; + + return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_static_gravities (window, use_static); +} + +/** * gdk_window_set_composited: * @window: a #GdkWindow * @composited: %TRUE to set the window as composited @@ -3468,7 +4220,9 @@ remove_redirect_from_children (GdkWindowObject *private, GdkWindowRedirect *redi * * Removes and active redirection started by * gdk_window_redirect_to_drawable(). - **/ + * + * Since: 2.14 + */ void gdk_window_remove_redirection (GdkWindow *window) { @@ -3522,8 +4276,9 @@ apply_redirect_to_children (GdkWindowObject *private, GdkWindowRedirect *redirec * @width and @height is also drawn into @drawable at * @dest_x, @dest_y. * - * Only drawing between gdk_window_begin_paint_region() and - * gdk_window_end_paint() is redirected. + * Only drawing between gdk_window_begin_paint_region() or + * gdk_window_begin_paint_rect() and gdk_window_end_paint() is + * redirected. * * Redirection is active until gdk_window_remove_redirection() * is called. @@ -3531,13 +4286,18 @@ apply_redirect_to_children (GdkWindowObject *private, GdkWindowRedirect *redirec * This function should not be used on windows created by * gdk_window_new_offscreen(), as that is implemented using * redirection. - **/ + * + * Since: 2.14. + */ void -gdk_window_redirect_to_drawable (GdkWindow *window, +gdk_window_redirect_to_drawable (GdkWindow *window, GdkDrawable *drawable, - gint src_x, gint src_y, - gint dest_x, gint dest_y, - gint width, gint height) + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height) { GdkWindowObject *private; @@ -3584,13 +4344,13 @@ window_get_size_rectangle (GdkWindow *window, /* Calculates the real clipping region for a window, in window coordinates, * taking into account other windows, gc clip region and gc clip mask. */ -static GdkRegion * +GdkRegion * _gdk_window_calculate_full_clip_region (GdkWindow *window, GdkWindow *base_window, - GdkGC *gc, - gboolean do_children, - gint *base_x_offset, - gint *base_y_offset) + GdkGC *gc, + gboolean do_children, + gint *base_x_offset, + gint *base_y_offset) { GdkWindowObject *private = GDK_WINDOW_OBJECT (window); GdkRectangle visible_rect; @@ -3632,24 +4392,33 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window, { GList *cur; GdkRectangle real_clip_rect; - + gboolean is_offscreen; + if (parentwin != private) { x_offset += GDK_WINDOW_OBJECT (lastwin)->x; y_offset += GDK_WINDOW_OBJECT (lastwin)->y; } - + + is_offscreen = gdk_window_is_offscreen (GDK_WINDOW (parentwin)); + /* children is ordered in reverse stack order */ - for (cur = GDK_WINDOW_OBJECT (parentwin)->children; cur && cur->data != lastwin; cur = cur->next) + for (cur = GDK_WINDOW_OBJECT (parentwin)->children; + cur && cur->data != lastwin; + cur = cur->next) { GdkWindow *child = cur->data; GdkWindowObject *child_private = (GdkWindowObject *)child; - + if (!GDK_WINDOW_IS_MAPPED (child) || child_private->input_only) continue; + /* Ignore toplevel offscreen children */ + if (_gdk_window_is_toplevel_offscreen (child)) + continue; + window_get_size_rectangle (child, &visible_rect); - + /* Convert rect to "window" coords */ visible_rect.x += child_private->x - x_offset; visible_rect.y += child_private->y - y_offset; @@ -3766,7 +4535,9 @@ setup_redirect_clip (GdkWindow *window, } static void -reset_redirect_clip (GdkWindow *offscreen, GdkGC *gc, GdkWindowClipData *data) +reset_redirect_clip (GdkWindow *offscreen, + GdkGC *gc, + GdkWindowClipData *data) { /* offset back */ gdk_gc_offset (gc, data->x_offset, data->y_offset); @@ -3785,5 +4556,39 @@ gdk_window_redirect_free (GdkWindowRedirect *redirect) g_free (redirect); } +void +_gdk_window_add_offscreen_child (GdkWindow *window) +{ + GdkWindowObject *obj = (GdkWindowObject*) window; + + if (obj->offscreen_children) + obj->offscreen_children->n_offscreen_children++; + else + { + obj->offscreen_children = g_slice_new0 (GdkWindowOffscreenChildren); + obj->offscreen_children->n_offscreen_children = 1; + } +} + +void +_gdk_window_remove_offscreen_child (GdkWindow *window) +{ + GdkWindowObject *obj = (GdkWindowObject*) window; + + g_return_if_fail (obj->offscreen_children != NULL); + + if (obj->offscreen_children) + { + g_return_if_fail (obj->offscreen_children->n_offscreen_children > 0); + + obj->offscreen_children->n_offscreen_children--; + if (obj->offscreen_children->n_offscreen_children == 0) + { + g_slice_free (GdkWindowOffscreenChildren, obj->offscreen_children); + obj->offscreen_children = NULL; + } + } +} + #define __GDK_WINDOW_C__ #include "gdkaliasdef.c" diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index 06ee018..22199e3 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -37,10 +37,12 @@ G_BEGIN_DECLS -typedef struct _GdkGeometry GdkGeometry; -typedef struct _GdkWindowAttr GdkWindowAttr; -typedef struct _GdkPointerHooks GdkPointerHooks; -typedef struct _GdkWindowRedirect GdkWindowRedirect; +typedef struct _GdkGeometry GdkGeometry; +typedef struct _GdkWindowAttr GdkWindowAttr; +typedef struct _GdkPointerHooks GdkPointerHooks; +typedef struct _GdkOffscreenHooks GdkOffscreenHooks; +typedef struct _GdkWindowRedirect GdkWindowRedirect; +typedef struct _GdkWindowOffscreenChildren GdkWindowOffscreenChildren; /* Classes of windows. * InputOutput: Almost every window should be of this type. Such windows @@ -248,9 +250,62 @@ struct _GdkPointerHooks gint *win_y); }; +struct _GdkOffscreenHooks +{ + void (*parent_to_window) (GdkWindow *window, + gdouble parent_x, + gdouble parent_y, + gdouble *win_x, + gdouble *win_y); + void (*window_to_parent) (GdkWindow *window, + gdouble win_x, + gdouble win_y, + gdouble *parent_x, + gdouble *parent_y); + GdkWindow* (*find_offscreen_child) (GdkWindow *window, + gdouble x, + gdouble y); +}; + +struct _GdkWindowOffscreenChildren +{ + gint n_offscreen_children; + + /* The window with the mouse in it, or NULL if the pointer is not inside + * an offscreen child. A pointer grab doesn't affect this. + */ + GdkWindow *window_under_pointer; + + gdouble last_mouse_x, last_mouse_y; + guint32 last_state; + + GdkWindow *pointer_grab_window; + gboolean pointer_grab_owner_events; + + GdkWindow *grab_one_pointer_release_event; + guint pointer_grab_event_mask; +}; + typedef struct _GdkWindowObject GdkWindowObject; typedef struct _GdkWindowObjectClass GdkWindowObjectClass; +struct _GdkWindowRedirect +{ + GdkWindowObject *redirected; + GdkDrawable *pixmap; + + gint src_x; + gint src_y; + gint dest_x; + gint dest_y; + gint width; + gint height; + + GdkRegion *damage; + guint damage_idle; +}; + + #define GDK_TYPE_WINDOW (gdk_window_object_get_type ()) #define GDK_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WINDOW, GdkWindow)) #define GDK_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW, GdkWindowObjectClass)) @@ -307,6 +362,8 @@ struct _GdkWindowObject guint update_and_descendants_freeze_count; GdkWindowRedirect *redirect; + GdkWindowOffscreenChildren *offscreen_children; + const GdkOffscreenHooks *offscreen_hooks; }; struct _GdkWindowObjectClass @@ -645,12 +702,26 @@ GdkPointerHooks *gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks); GdkWindow *gdk_get_default_root_window (void); -void gdk_window_redirect_to_drawable (GdkWindow *window, - GdkDrawable *drawable, - gint src_x, gint src_y, - gint dest_x, gint dest_y, - gint width, gint height); -void gdk_window_remove_redirection (GdkWindow *window); +/* Offscreen redirection */ +GdkWindow *gdk_offscreen_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask); + +gboolean gdk_window_is_offscreen (GdkWindow *window); +GdkPixmap *gdk_window_get_offscreen_pixmap (GdkWindow *window); + +void gdk_window_redirect_to_drawable (GdkWindow *window, + GdkDrawable *drawable, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height); +void gdk_window_remove_redirection (GdkWindow *window); + +void gdk_window_set_offscreen_hooks (GdkWindow *window, + const GdkOffscreenHooks *hooks); #ifndef GDK_DISABLE_DEPRECATED #define GDK_ROOT_PARENT() (gdk_get_default_root_window ()) diff --git a/gdk/gdkwindowimpl.c b/gdk/gdkwindowimpl.c new file mode 100644 index 0000000..32923d1 --- /dev/null +++ b/gdk/gdkwindowimpl.c @@ -0,0 +1,57 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include +#include "gdkwindowimpl.h" +#include "gdkinternals.h" + +static void +gdk_window_impl_base_init (gpointer g_class) +{ +} + +GType +gdk_window_impl_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo info = { + sizeof (GdkWindowImplIface), + gdk_window_impl_base_init, + NULL, + NULL, + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + g_intern_static_string ("GdkWindowImpl"), + &info, 0); + g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + } + + return type; +} diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h new file mode 100644 index 0000000..65b6fac --- /dev/null +++ b/gdk/gdkwindowimpl.h @@ -0,0 +1,129 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GDK_WINDOW_IMPL_H__ +#define __GDK_WINDOW_IMPL_H__ + +#include + +G_BEGIN_DECLS + +#define GDK_TYPE_WINDOW_IMPL (gdk_window_impl_get_type ()) +#define GDK_WINDOW_IMPL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WINDOW_IMPL, GdkWindowImpl)) +#define GDK_IS_WINDOW_IMPL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WINDOW_IMPL)) +#define GDK_WINDOW_IMPL_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GDK_TYPE_WINDOW_IMPL, GdkWindowImplIface)) + +typedef struct _GdkWindowImpl GdkWindowImpl; +typedef struct _GdkWindowImplIface GdkWindowImplIface; + +struct _GdkWindowImplIface +{ + GTypeInterface g_iface; + + void (* show) (GdkWindow *window, + gboolean raise); + void (* hide) (GdkWindow *window); + void (* withdraw) (GdkWindow *window); + void (* raise) (GdkWindow *window); + void (* lower) (GdkWindow *window); + + void (* move) (GdkWindow *window, + gint x, + gint y); + void (* resize) (GdkWindow *window, + gint width, + gint height); + void (* move_resize) (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); + void (* move_region) (GdkWindow *window, + const GdkRegion *region, + gint dx, + gint dy); + void (* scroll) (GdkWindow *window, + gint dx, + gint dy); + + void (* clear_area) (GdkWindow *window, + gint x, + gint y, + gint width, + gint height, + gboolean send_expose); + void (* set_background) (GdkWindow *window, + const GdkColor *color); + void (* set_back_pixmap) (GdkWindow *window, + GdkPixmap *pixmap, + gboolean parent_relative); + + GdkEventMask (* get_events) (GdkWindow *window); + void (* set_events) (GdkWindow *window, + GdkEventMask event_mask); + + gboolean (* reparent) (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y); + + void (* set_cursor) (GdkWindow *window, + GdkCursor *cursor); + + void (* get_geometry) (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth); + gint (* get_origin) (GdkWindow *window, + gint *x, + gint *y); + void (* get_offsets) (GdkWindow *window, + gint *x_offset, + gint *y_offset); + + void (* shape_combine_mask) (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y); + void (* shape_combine_region) (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y); + void (* set_child_shapes) (GdkWindow *window); + void (* merge_child_shapes) (GdkWindow *window); + + gboolean (* set_static_gravities) (GdkWindow *window, + gboolean use_static); +}; + +/* Interface Functions */ +GType gdk_window_impl_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __GDK_WINDOW_IMPL_H__ */ diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 08b77da..e4bb5c4 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -576,7 +576,7 @@ _gdk_x11_display_is_root_window (GdkDisplay *display, */ void gdk_display_pointer_ungrab (GdkDisplay *display, - guint32 time) + guint32 time_) { Display *xdisplay; GdkDisplayX11 *display_x11; @@ -586,14 +586,21 @@ gdk_display_pointer_ungrab (GdkDisplay *display, display_x11 = GDK_DISPLAY_X11 (display); xdisplay = GDK_DISPLAY_XDISPLAY (display); - _gdk_input_ungrab_pointer (display, time); - XUngrabPointer (xdisplay, time); + _gdk_input_ungrab_pointer (display, time_); + XUngrabPointer (xdisplay, time_); XFlush (xdisplay); - if (time == GDK_CURRENT_TIME || + if (time_ == GDK_CURRENT_TIME || display_x11->pointer_xgrab_time == GDK_CURRENT_TIME || - !XSERVER_TIME_IS_LATER (display_x11->pointer_xgrab_time, time)) - display_x11->pointer_xgrab_window = NULL; + !XSERVER_TIME_IS_LATER (display_x11->pointer_xgrab_time, time_)) + { + GdkWindow *xgrab_window = GDK_WINDOW (display_x11->pointer_xgrab_window); + + if (gdk_window_is_offscreen (xgrab_window)) + _gdk_offscreen_window_unset_pointer_grab (xgrab_window, FALSE, FALSE, time_); + + display_x11->pointer_xgrab_window = NULL; + } } /** @@ -1308,7 +1315,9 @@ gdk_display_store_clipboard (GdkDisplay *display, { GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display); Atom clipboard_manager, save_targets; - + + g_return_if_fail (!gdk_window_is_offscreen (clipboard_window)); + clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER"); save_targets = gdk_x11_get_xatom_by_name_for_display (display, "SAVE_TARGETS"); diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index ffd0461..d515a74 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -98,12 +98,14 @@ struct _GdkDisplayX11 * window is NULL, then the other associated fields are ignored */ GdkWindowObject *pointer_xgrab_window; + GdkWindowObject *pointer_xgrab_native_window; gulong pointer_xgrab_serial; gboolean pointer_xgrab_owner_events; gboolean pointer_xgrab_implicit; guint32 pointer_xgrab_time; GdkWindowObject *keyboard_xgrab_window; + GdkWindowObject *keyboard_xgrab_native_window; gulong keyboard_xgrab_serial; gboolean keyboard_xgrab_owner_events; guint32 keyboard_xgrab_time; @@ -169,6 +171,9 @@ struct _GdkDisplayX11 /* Alpha mask picture format */ XRenderPictFormat *mask_format; + + /* The offscreen window that has the pointer in it (if any) */ + GdkWindow *active_offscreen_window; }; struct _GdkDisplayX11Class diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c index 62a2d8c..65bf8ba 100644 --- a/gdk/x11/gdkdnd-x11.c +++ b/gdk/x11/gdkdnd-x11.c @@ -2987,6 +2987,7 @@ gdk_drag_begin (GdkWindow *window, GdkDragContext *new_context; g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (!gdk_window_is_offscreen (window), NULL); new_context = gdk_drag_context_new (); new_context->is_source = TRUE; @@ -3186,6 +3187,12 @@ gdk_drag_find_window_for_screen (GdkDragContext *context, g_return_if_fail (context != NULL); + if (gdk_window_is_offscreen (drag_window)) + { + *dest_window = NULL; + return; + } + display = GDK_WINDOW_DISPLAY (context->source_window); window_cache = drag_context_find_window_cache (context, screen); @@ -3261,6 +3268,7 @@ gdk_drag_motion (GdkDragContext *context, GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); g_return_val_if_fail (context != NULL, FALSE); + g_return_val_if_fail (dest_window == NULL || !gdk_window_is_offscreen (dest_window), FALSE); private->old_actions = context->actions; context->actions = possible_actions; diff --git a/gdk/x11/gdkdrawable-x11.c b/gdk/x11/gdkdrawable-x11.c index a19c7a2..6ec0c97 100644 --- a/gdk/x11/gdkdrawable-x11.c +++ b/gdk/x11/gdkdrawable-x11.c @@ -870,7 +870,15 @@ gdk_x11_drawable_get_xid (GdkDrawable *drawable) GdkDrawable *impl; if (GDK_IS_WINDOW (drawable)) - impl = ((GdkPixmapObject *)drawable)->impl; + { + if (gdk_window_is_offscreen (GDK_WINDOW (drawable))) + { + g_warning (G_STRLOC " drawable is an offscreen window"); + return None; + } + + impl = ((GdkPixmapObject *)drawable)->impl; + } else if (GDK_IS_PIXMAP (drawable)) impl = ((GdkPixmapObject *)drawable)->impl; else diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index 3e4eb1e..f9ada01 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -313,7 +313,9 @@ gdk_event_get_graphics_expose (GdkWindow *window) GdkEvent *event; g_return_val_if_fail (window != NULL, NULL); - + + window = _gdk_window_get_offscreen_event_window (window); + XIfEvent (GDK_WINDOW_XDISPLAY (window), &xevent, graphics_expose_predicate, (XPointer) window); @@ -942,6 +944,14 @@ gdk_event_translate (GdkDisplay *display, if (window != NULL) { + /* Rewrite keyboard grabs to offscreen windows */ + if ((xevent->type == KeyPress || xevent->type == KeyRelease) && + window_private == display_x11->keyboard_xgrab_native_window) + { + window_private = display_x11->keyboard_xgrab_window; + window = (GdkWindow *) window_private; + } + window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl); /* Move key events on focus window to the real toplevel, and @@ -1042,9 +1052,7 @@ gdk_event_translate (GdkDisplay *display, return_val = TRUE; if (window) - { - _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); - } + _gdk_x11_window_get_offsets (window, &xoffset, &yoffset); else { xoffset = 0; @@ -2299,6 +2307,7 @@ _gdk_events_queue (GdkDisplay *display) if (gdk_event_translate (display, event, &xevent, FALSE)) { ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING; + _gdk_event_rewrite_for_offscreen (display, node, event); } else { diff --git a/gdk/x11/gdkgeometry-x11.c b/gdk/x11/gdkgeometry-x11.c index dcd5627..f986e30 100644 --- a/gdk/x11/gdkgeometry-x11.c +++ b/gdk/x11/gdkgeometry-x11.c @@ -192,9 +192,9 @@ static void gdk_window_clip_changed (GdkWindow *window, GdkRectangle *new_clip); void -_gdk_windowing_window_get_offsets (GdkWindow *window, - gint *x_offset, - gint *y_offset) +_gdk_x11_window_get_offsets (GdkWindow *window, + gint *x_offset, + gint *y_offset) { GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl); @@ -395,25 +395,10 @@ gdk_window_guffaw_scroll (GdkWindow *window, g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos); } -/** - * gdk_window_scroll: - * @window: a #GdkWindow - * @dx: Amount to scroll in the X direction - * @dy: Amount to scroll in the Y direction - * - * Scroll the contents of @window, both pixels and children, by the given - * amount. @window itself does not move. Portions of the window that the scroll - * operation brings in from offscreen areas are invalidated. The invalidated - * region may be bigger than what would strictly be necessary. (For X11, a - * minimum area will be invalidated if the window has no subwindows, or if the - * edges of the window's parent do not extend beyond the edges of the window. In - * other cases, a multi-step process is used to scroll the window which may - * produce temporary visual artifacts and unnecessary invalidations.) - **/ void -gdk_window_scroll (GdkWindow *window, - gint dx, - gint dy) +_gdk_x11_window_scroll (GdkWindow *window, + gint dx, + gint dy) { gboolean can_guffaw_scroll = FALSE; GdkRegion *invalidate_region; @@ -421,17 +406,9 @@ gdk_window_scroll (GdkWindow *window, GdkWindowObject *obj; GdkRectangle src_rect, dest_rect; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) - return; - obj = GDK_WINDOW_OBJECT (window); impl = GDK_WINDOW_IMPL_X11 (obj->impl); - if (dx == 0 && dy == 0) - return; - /* Move the current invalid region */ if (obj->update_area) gdk_region_offset (obj->update_area, dx, dy); @@ -483,26 +460,11 @@ gdk_window_scroll (GdkWindow *window, gdk_window_guffaw_scroll (window, dx, dy); } -/** - * gdk_window_move_region: - * @window: a #GdkWindow - * @region: The #GdkRegion to move - * @dx: Amount to move in the X direction - * @dy: Amount to move in the Y direction - * - * Move the part of @window indicated by @region by @dy pixels in the Y - * direction and @dx pixels in the X direction. The portions of @region - * that not covered by the new position of @region are invalidated. - * - * Child windows are not moved. - * - * Since: 2.8 - **/ void -gdk_window_move_region (GdkWindow *window, - const GdkRegion *region, - gint dx, - gint dy) +_gdk_x11_window_move_region (GdkWindow *window, + const GdkRegion *region, + gint dx, + gint dy) { GdkWindowImplX11 *impl; GdkWindowObject *private; @@ -514,18 +476,9 @@ gdk_window_move_region (GdkWindow *window, GdkRectangle dest_extents; GdkGC *gc; - g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (region != NULL); - - if (GDK_WINDOW_DESTROYED (window)) - return; - private = GDK_WINDOW_OBJECT (window); impl = GDK_WINDOW_IMPL_X11 (private->impl); - if (dx == 0 && dy == 0) - return; - window_clip = gdk_region_rectangle (&impl->position_info.clip_rect); /* compute source regions */ @@ -902,6 +855,9 @@ gdk_window_premove (GdkWindow *window, gint d_xoffset, d_yoffset; GdkWindowParentPos this_pos; + if (gdk_window_is_offscreen (window)) + return; + obj = (GdkWindowObject *) window; impl = GDK_WINDOW_IMPL_X11 (obj->impl); @@ -942,6 +898,9 @@ gdk_window_postmove (GdkWindow *window, gint d_xoffset, d_yoffset; GdkWindowParentPos this_pos; + if (gdk_window_is_offscreen (window)) + return; + obj = (GdkWindowObject *) window; impl = GDK_WINDOW_IMPL_X11 (obj->impl); diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c index 98840bb..b4a7ba4 100644 --- a/gdk/x11/gdkinput.c +++ b/gdk/x11/gdkinput.c @@ -207,7 +207,7 @@ gdk_device_get_history (GdkDevice *device, int tmp_n_events = 0; int i; - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (window), FALSE); if (GDK_WINDOW_DESTROYED (window)) /* Nothing */ ; @@ -303,7 +303,7 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask, GdkDisplayX11 *display_x11; g_return_if_fail (window != NULL); - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); window_private = (GdkWindowObject*) window; display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c index 7bede22..37eb385 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -191,6 +191,7 @@ gdk_pointer_grab (GdkWindow * window, { gint return_val; GdkCursorPrivate *cursor_private; + GdkWindow *native; GdkDisplayX11 *display_x11; guint xevent_mask; Window xwindow; @@ -202,13 +203,18 @@ gdk_pointer_grab (GdkWindow * window, g_return_val_if_fail (window != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (window), 0); g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0); - - display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); + + native = _gdk_window_get_offscreen_event_window (window); + + if (confine_to) + confine_to = _gdk_window_get_offscreen_event_window (confine_to); + + display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native)); cursor_private = (GdkCursorPrivate*) cursor; - xwindow = GDK_WINDOW_XID (window); - serial = NextRequest (GDK_WINDOW_XDISPLAY (window)); + xwindow = GDK_WINDOW_XID (native); + serial = NextRequest (GDK_WINDOW_XDISPLAY (native)); if (!confine_to || GDK_WINDOW_DESTROYED (confine_to)) xconfine_to = None; @@ -230,7 +236,7 @@ gdk_pointer_grab (GdkWindow * window, xevent_mask |= _gdk_event_mask_table[i]; } - return_val = _gdk_input_grab_pointer (window, + return_val = _gdk_input_grab_pointer (native, owner_events, event_mask, confine_to, @@ -239,14 +245,14 @@ gdk_pointer_grab (GdkWindow * window, if (return_val == GrabSuccess || G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed)) { - if (!GDK_WINDOW_DESTROYED (window)) + if (!GDK_WINDOW_DESTROYED (native)) { #ifdef G_ENABLE_DEBUG if (_gdk_debug_flags & GDK_DEBUG_NOGRABS) return_val = GrabSuccess; else #endif - return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (window), + return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (native), xwindow, owner_events, xevent_mask, @@ -263,11 +269,25 @@ gdk_pointer_grab (GdkWindow * window, { if (display_x11->pointer_xgrab_window != NULL && display_x11->pointer_xgrab_window != (GdkWindowObject *)window) - generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), - FALSE, display_x11->pointer_xgrab_implicit, - window); + { + if (gdk_window_is_offscreen (GDK_WINDOW (display_x11->pointer_xgrab_window))) + _gdk_offscreen_window_unset_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window), + TRUE, FALSE, time); + + generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), + FALSE, display_x11->pointer_xgrab_implicit, + window); + } + + if (gdk_window_is_offscreen (window)) + _gdk_offscreen_window_set_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window), + GDK_WINDOW (display_x11->pointer_xgrab_native_window), + window, + owner_events, event_mask, + time); display_x11->pointer_xgrab_window = (GdkWindowObject *)window; + display_x11->pointer_xgrab_native_window = (GdkWindowObject *)native; display_x11->pointer_xgrab_serial = serial; display_x11->pointer_xgrab_owner_events = owner_events; display_x11->pointer_xgrab_time = time; @@ -342,23 +362,26 @@ gdk_keyboard_grab (GdkWindow * window, gint return_val; unsigned long serial; GdkDisplayX11 *display_x11; - + GdkWindow *native; + g_return_val_if_fail (window != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (window), 0); - - display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); - serial = NextRequest (GDK_WINDOW_XDISPLAY (window)); + native = _gdk_window_get_offscreen_event_window (window); - if (!GDK_WINDOW_DESTROYED (window)) + display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native)); + + serial = NextRequest (GDK_WINDOW_XDISPLAY (native)); + + if (!GDK_WINDOW_DESTROYED (native)) { #ifdef G_ENABLE_DEBUG if (_gdk_debug_flags & GDK_DEBUG_NOGRABS) return_val = GrabSuccess; else #endif - return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), + return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (native), + GDK_WINDOW_XID (native), owner_events, GrabModeAsync, GrabModeAsync, time); @@ -378,6 +401,7 @@ gdk_keyboard_grab (GdkWindow * window, TRUE, FALSE, window); display_x11->keyboard_xgrab_window = (GdkWindowObject *)window; + display_x11->keyboard_xgrab_native_window = (GdkWindowObject *)native; display_x11->keyboard_xgrab_serial = serial; display_x11->keyboard_xgrab_owner_events = owner_events; display_x11->keyboard_xgrab_time = time; @@ -386,6 +410,19 @@ gdk_keyboard_grab (GdkWindow * window, return gdk_x11_convert_grab_status (return_val); } +void +_gdk_windowing_grab_broken (GdkDisplay *display) +{ + GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display); + + generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), + FALSE, + display_x11->pointer_xgrab_implicit, + NULL); + + display_x11->pointer_xgrab_window = NULL; +} + /** * gdk_keyboard_grab_info_libgtk_only: * @display: the display for which to get the grab information @@ -443,13 +480,18 @@ _gdk_xgrab_check_unmap (GdkWindow *window, serial >= display_x11->pointer_xgrab_serial) { GdkWindowObject *private = GDK_WINDOW_OBJECT (window); - GdkWindowObject *tmp = display_x11->pointer_xgrab_window; + GdkWindowObject *tmp = display_x11->pointer_xgrab_native_window; while (tmp && tmp != private) tmp = tmp->parent; if (tmp) - { + { + if (gdk_window_is_offscreen (GDK_WINDOW (display_x11->pointer_xgrab_window))) + _gdk_offscreen_window_unset_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window), + FALSE, FALSE, + GDK_CURRENT_TIME); + generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), FALSE, display_x11->pointer_xgrab_implicit, NULL); @@ -488,15 +530,22 @@ _gdk_xgrab_check_destroy (GdkWindow *window) { GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window)); - if ((GdkWindowObject *)window == display_x11->pointer_xgrab_window) + if ((GdkWindowObject *)window == display_x11->pointer_xgrab_native_window && + display_x11->pointer_xgrab_window != NULL) { + if (gdk_window_is_offscreen (GDK_WINDOW (display_x11->pointer_xgrab_window))) + _gdk_offscreen_window_unset_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window), + FALSE, FALSE, + GDK_CURRENT_TIME); + generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), FALSE, display_x11->pointer_xgrab_implicit, NULL); display_x11->pointer_xgrab_window = NULL; } - if ((GdkWindowObject *)window == display_x11->keyboard_xgrab_window) + if ((GdkWindowObject *)window == display_x11->keyboard_xgrab_native_window && + display_x11->keyboard_xgrab_window != NULL) { generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), TRUE, FALSE, NULL); @@ -530,6 +579,7 @@ _gdk_xgrab_check_button_event (GdkWindow *window, if (!display_x11->pointer_xgrab_window) { display_x11->pointer_xgrab_window = (GdkWindowObject *)window; + display_x11->pointer_xgrab_native_window = (GdkWindowObject *)window; display_x11->pointer_xgrab_serial = xevent->xany.serial; display_x11->pointer_xgrab_owner_events = FALSE; display_x11->pointer_xgrab_time = xevent->xbutton.time; @@ -541,6 +591,11 @@ _gdk_xgrab_check_button_event (GdkWindow *window, display_x11->pointer_xgrab_implicit && (xevent->xbutton.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0) { + if (gdk_window_is_offscreen (GDK_WINDOW (display_x11->pointer_xgrab_window))) + _gdk_offscreen_window_unset_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window), + FALSE, TRUE, + xevent->xbutton.time); + display_x11->pointer_xgrab_window = NULL; } break; @@ -550,6 +605,27 @@ _gdk_xgrab_check_button_event (GdkWindow *window, } void +_gdk_windowing_update_implicit_grab (GdkWindow *old_grab, + GdkWindow *new_grab, + guint event_mask, + guint32 time) +{ + GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (old_grab)); + + if (display_x11->pointer_xgrab_window == GDK_WINDOW_OBJECT (old_grab) && + display_x11->pointer_xgrab_implicit) + { + if (gdk_window_is_offscreen (new_grab)) + _gdk_offscreen_window_set_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window), + GDK_WINDOW (display_x11->pointer_xgrab_native_window), + new_grab, FALSE, + event_mask, time); + + display_x11->pointer_xgrab_window = GDK_WINDOW_OBJECT (new_grab); + } +} + +void _gdk_windowing_display_set_sm_client_id (GdkDisplay *display, const gchar *sm_client_id) { diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c index 81d2b1d..ad8f3ab 100644 --- a/gdk/x11/gdkpixmap-x11.c +++ b/gdk/x11/gdkpixmap-x11.c @@ -137,10 +137,10 @@ gdk_pixmap_impl_x11_get_size (GdkDrawable *drawable, } GdkPixmap* -gdk_pixmap_new (GdkDrawable *drawable, - gint width, - gint height, - gint depth) +_gdk_pixmap_new (GdkDrawable *drawable, + gint width, + gint height, + gint depth) { GdkPixmap *pixmap; GdkDrawableImplX11 *draw_impl; @@ -194,10 +194,10 @@ gdk_pixmap_new (GdkDrawable *drawable, } GdkPixmap * -gdk_bitmap_create_from_data (GdkDrawable *drawable, - const gchar *data, - gint width, - gint height) +_gdk_bitmap_create_from_data (GdkDrawable *drawable, + const gchar *data, + gint width, + gint height) { GdkPixmap *pixmap; GdkDrawableImplX11 *draw_impl; @@ -238,13 +238,13 @@ gdk_bitmap_create_from_data (GdkDrawable *drawable, } GdkPixmap* -gdk_pixmap_create_from_data (GdkDrawable *drawable, - const gchar *data, - gint width, - gint height, - gint depth, - const GdkColor *fg, - const GdkColor *bg) +_gdk_pixmap_create_from_data (GdkDrawable *drawable, + const gchar *data, + gint width, + gint height, + gint depth, + const GdkColor *fg, + const GdkColor *bg) { GdkPixmap *pixmap; GdkDrawableImplX11 *draw_impl; diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h index e0948b3..f79a1e8 100644 --- a/gdk/x11/gdkprivate-x11.h +++ b/gdk/x11/gdkprivate-x11.h @@ -128,6 +128,14 @@ void _gdk_window_process_expose (GdkWindow *window, gulong serial, GdkRectangle *area); +void _gdk_x11_window_scroll (GdkWindow *window, + gint dx, + gint dy); +void _gdk_x11_window_move_region (GdkWindow *window, + const GdkRegion *region, + gint dx, + gint dy); + void _gdk_selection_window_destroyed (GdkWindow *window); gboolean _gdk_selection_filter_clear_event (XSelectionClearEvent *event); @@ -207,5 +215,6 @@ extern gboolean _gdk_synchronize; #define GDK_WINDOW_DISPLAY(win) (GDK_SCREEN_X11 (GDK_WINDOW_SCREEN (win))->display) #define GDK_WINDOW_XROOTWIN(win) (GDK_SCREEN_X11 (GDK_WINDOW_SCREEN (win))->xroot_window) #define GDK_GC_DISPLAY(gc) (GDK_SCREEN_DISPLAY (GDK_GC_X11(gc)->screen)) +#define GDK_IS_ONSCREEN_WINDOW(win) (GDK_IS_WINDOW (win) && !gdk_window_is_offscreen ((win))) #endif /* __GDK_PRIVATE_X11_H__ */ diff --git a/gdk/x11/gdkproperty-x11.c b/gdk/x11/gdkproperty-x11.c index 36b8e9f..05f934b 100644 --- a/gdk/x11/gdkproperty-x11.c +++ b/gdk/x11/gdkproperty-x11.c @@ -541,7 +541,7 @@ gdk_property_get (GdkWindow *window, Atom xtype; int res; - g_return_val_if_fail (!window || GDK_IS_WINDOW (window), FALSE); + g_return_val_if_fail (!window || GDK_IS_ONSCREEN_WINDOW (window), FALSE); if (!window) { @@ -550,6 +550,8 @@ gdk_property_get (GdkWindow *window, GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n")); } + else if (gdk_window_is_offscreen (window)) + return FALSE; if (GDK_WINDOW_DESTROYED (window)) return FALSE; @@ -675,7 +677,7 @@ gdk_property_change (GdkWindow *window, Atom xproperty; Atom xtype; - g_return_if_fail (!window || GDK_IS_WINDOW (window)); + g_return_if_fail (!window || GDK_IS_ONSCREEN_WINDOW (window)); if (!window) { @@ -686,7 +688,8 @@ gdk_property_change (GdkWindow *window, GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n")); } - + else if (gdk_window_is_offscreen (window)) + return; if (GDK_WINDOW_DESTROYED (window)) return; @@ -726,7 +729,7 @@ void gdk_property_delete (GdkWindow *window, GdkAtom property) { - g_return_if_fail (!window || GDK_IS_WINDOW (window)); + g_return_if_fail (!window || GDK_IS_ONSCREEN_WINDOW (window)); if (!window) { @@ -736,6 +739,8 @@ gdk_property_delete (GdkWindow *window, GDK_NOTE (MULTIHEAD, g_message ("gdk_property_delete(): window is NULL\n")); } + else if (gdk_window_is_offscreen (window)) + return; if (GDK_WINDOW_DESTROYED (window)) return; diff --git a/gdk/x11/gdkselection-x11.c b/gdk/x11/gdkselection-x11.c index f56ab43..5f930cc 100644 --- a/gdk/x11/gdkselection-x11.c +++ b/gdk/x11/gdkselection-x11.c @@ -141,7 +141,7 @@ gdk_selection_owner_set_for_display (GdkDisplay *display, if (owner) { - if (GDK_WINDOW_DESTROYED (owner)) + if (GDK_WINDOW_DESTROYED (owner) || gdk_window_is_offscreen (owner)) return FALSE; xdisplay = GDK_WINDOW_XDISPLAY (owner); @@ -231,7 +231,7 @@ gdk_selection_convert (GdkWindow *requestor, g_return_if_fail (selection != GDK_NONE); - if (GDK_WINDOW_DESTROYED (requestor)) + if (GDK_WINDOW_DESTROYED (requestor) || gdk_window_is_offscreen (requestor)) return; display = GDK_WINDOW_DISPLAY (requestor); @@ -279,10 +279,11 @@ gdk_selection_property_get (GdkWindow *requestor, g_return_val_if_fail (requestor != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0); + g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (requestor), 0); display = GDK_WINDOW_DISPLAY (requestor); - if (GDK_WINDOW_DESTROYED (requestor)) + if (GDK_WINDOW_DESTROYED (requestor) || gdk_window_is_offscreen (requestor)) goto err; t = NULL; diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index a54eb0a..b542fb0 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -41,6 +41,7 @@ #include "gdk.h" #include "gdkwindow.h" +#include "gdkwindowimpl.h" #include "gdkasync.h" #include "gdkinputprivate.h" #include "gdkdisplay-x11.h" @@ -115,7 +116,8 @@ static void gdk_window_impl_x11_get_size (GdkDrawable *drawable, gint *width, gint *height); static GdkRegion* gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable); -static void gdk_window_impl_x11_finalize (GObject *object); +static void gdk_window_impl_x11_finalize (GObject *object); +static void gdk_window_impl_iface_init (GdkWindowImplIface *iface); #define WINDOW_IS_TOPLEVEL(window) \ (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ @@ -129,7 +131,11 @@ static void gdk_window_impl_x11_finalize (GObject *object); (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 )) \ ) -G_DEFINE_TYPE (GdkWindowImplX11, gdk_window_impl_x11, GDK_TYPE_DRAWABLE_IMPL_X11) +G_DEFINE_TYPE_WITH_CODE (GdkWindowImplX11, + gdk_window_impl_x11, + GDK_TYPE_DRAWABLE_IMPL_X11, + G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL, + gdk_window_impl_iface_init)); GType _gdk_window_impl_get_type (void) @@ -294,7 +300,8 @@ _gdk_x11_window_tmp_unset_bg (GdkWindow *window, if (private->input_only || private->destroyed || (private->window_type != GDK_WINDOW_ROOT && - !GDK_WINDOW_IS_MAPPED (window))) + !GDK_WINDOW_IS_MAPPED (window)) || + gdk_window_is_offscreen (window)) { return; } @@ -326,7 +333,8 @@ _gdk_x11_window_tmp_reset_bg (GdkWindow *window, if (private->input_only || private->destroyed || (private->window_type != GDK_WINDOW_ROOT && - !GDK_WINDOW_IS_MAPPED (window))) + !GDK_WINDOW_IS_MAPPED (window)) || + gdk_window_is_offscreen (window)) { return; } @@ -448,7 +456,10 @@ _gdk_windowing_window_init (GdkScreen * screen) gdk_screen_get_system_colormap (screen)); screen_x11->root_window = g_object_new (GDK_TYPE_WINDOW, NULL); - private = (GdkWindowObject *)screen_x11->root_window; + + private = (GdkWindowObject *) screen_x11->root_window; + private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); + impl = GDK_WINDOW_IMPL_X11 (private->impl); draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl); @@ -647,7 +658,7 @@ setup_toplevel_window (GdkWindow *window, ensure_sync_counter (window); } -GdkWindow* +GdkWindow * _gdk_window_new (GdkWindow *parent, GdkWindowAttr *attributes, gint attributes_mask) @@ -697,7 +708,10 @@ _gdk_window_new (GdkWindow *parent, xparent = GDK_WINDOW_XID (parent); window = g_object_new (GDK_TYPE_WINDOW, NULL); - private = (GdkWindowObject *)window; + + private = (GdkWindowObject *) window; + private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); + impl = GDK_WINDOW_IMPL_X11 (private->impl); draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl); draw_impl->wrapper = GDK_DRAWABLE (window); @@ -1012,7 +1026,10 @@ gdk_window_foreign_new_for_display (GdkDisplay *display, XFree (children); window = g_object_new (GDK_TYPE_WINDOW, NULL); - private = (GdkWindowObject *)window; + + private = (GdkWindowObject *) window; + private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); + impl = GDK_WINDOW_IMPL_X11 (private->impl); draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl); draw_impl->wrapper = GDK_DRAWABLE (window); @@ -1200,7 +1217,7 @@ gdk_window_destroy_notify (GdkWindow *window) { GdkWindowImplX11 *window_impl; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); window_impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl); @@ -1404,16 +1421,14 @@ set_initial_hints (GdkWindow *window) } static void -show_window_internal (GdkWindow *window, - gboolean raise) +gdk_window_x11_show (GdkWindow *window, + gboolean raise) { GdkWindowObject *private; GdkDisplay *display; GdkDisplayX11 *display_x11; GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject*) window; if (!private->destroyed) { @@ -1468,50 +1483,6 @@ show_window_internal (GdkWindow *window, } } -/** - * gdk_window_show_unraised: - * @window: a #GdkWindow - * - * Shows a #GdkWindow onscreen, but does not modify its stacking - * order. In contrast, gdk_window_show() will raise the window - * to the top of the window stack. - * - * On the X11 platform, in Xlib terms, this function calls - * XMapWindow() (it also updates some internal GDK state, which means - * that you can't really use XMapWindow() directly on a GDK window). - * - **/ -void -gdk_window_show_unraised (GdkWindow *window) -{ - g_return_if_fail (GDK_IS_WINDOW (window)); - - show_window_internal (window, FALSE); -} - -/** - * gdk_window_show: - * @window: a #GdkWindow - * - * Like gdk_window_show_unraised(), but also raises the window to the - * top of the window stack (moves the window to the front of the - * Z-order). - * - * This function maps a window so it's visible onscreen. Its opposite - * is gdk_window_hide(). - * - * When implementing a #GtkWidget, you should call this function on the widget's - * #GdkWindow as part of the "map" method. - * - **/ -void -gdk_window_show (GdkWindow *window) -{ - g_return_if_fail (GDK_IS_WINDOW (window)); - - show_window_internal (window, TRUE); -} - static void pre_unmap (GdkWindow *window) { @@ -1561,23 +1532,11 @@ post_unmap (GdkWindow *window) } } -/** - * gdk_window_hide: - * @window: a #GdkWindow - * - * For toplevel windows, withdraws them, so they will no longer be - * known to the window manager; for all windows, unmaps them, so - * they won't be displayed. Normally done automatically as - * part of gtk_widget_hide(). - * - **/ -void -gdk_window_hide (GdkWindow *window) +static void +gdk_window_x11_hide (GdkWindow *window) { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject*) window; /* We'll get the unmap notify eventually, and handle it then, @@ -1622,22 +1581,11 @@ gdk_window_hide (GdkWindow *window) } } -/** - * gdk_window_withdraw: - * @window: a toplevel #GdkWindow - * - * Withdraws a window (unmaps it and asks the window manager to forget about it). - * This function is not really useful as gdk_window_hide() automatically - * withdraws toplevel windows before hiding them. - * - **/ -void -gdk_window_withdraw (GdkWindow *window) +static void +gdk_window_x11_withdraw (GdkWindow *window) { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject*) window; if (!private->destroyed) { @@ -1657,33 +1605,16 @@ gdk_window_withdraw (GdkWindow *window) } } -/** - * gdk_window_move: - * @window: a #GdkWindow - * @x: X coordinate relative to window's parent - * @y: Y coordinate relative to window's parent - * - * Repositions a window relative to its parent window. - * For toplevel windows, window managers may ignore or modify the move; - * you should probably use gtk_window_move() on a #GtkWindow widget - * anyway, instead of using GDK functions. For child windows, - * the move will reliably succeed. - * - * If you're also planning to resize the window, use gdk_window_move_resize() - * to both move and resize simultaneously, for a nicer visual effect. - **/ -void -gdk_window_move (GdkWindow *window, - gint x, - gint y) +static void +gdk_window_x11_move (GdkWindow *window, + gint x, + gint y) { GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplX11 *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - impl = GDK_WINDOW_IMPL_X11 (private->impl); - + if (!GDK_WINDOW_DESTROYED (window)) { if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD) @@ -1706,37 +1637,20 @@ gdk_window_move (GdkWindow *window, } } -/** - * gdk_window_resize: - * @window: a #GdkWindow - * @width: new width of the window - * @height: new height of the window - * - * Resizes @window; for toplevel windows, asks the window manager to resize - * the window. The window manager may not allow the resize. When using GTK+, - * use gtk_window_resize() instead of this low-level GDK function. - * - * Windows may not be resized below 1x1. - * - * If you're also planning to move the window, use gdk_window_move_resize() - * to both move and resize simultaneously, for a nicer visual effect. - **/ -void -gdk_window_resize (GdkWindow *window, - gint width, - gint height) +static void +gdk_window_x11_resize (GdkWindow *window, + gint width, + gint height) { GdkWindowObject *private; - - g_return_if_fail (GDK_IS_WINDOW (window)); - + if (width < 1) width = 1; if (height < 1) height = 1; private = (GdkWindowObject*) window; - + if (!GDK_WINDOW_DESTROYED (window)) { if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD) @@ -1770,35 +1684,21 @@ gdk_window_resize (GdkWindow *window, } } -/** - * gdk_window_move_resize: - * @window: a #GdkWindow - * @x: new X position relative to window's parent - * @y: new Y position relative to window's parent - * @width: new width - * @height: new height - * - * Equivalent to calling gdk_window_move() and gdk_window_resize(), - * except that both operations are performed at once, avoiding strange - * visual effects. (i.e. the user may be able to see the window first - * move, then resize, if you don't use gdk_window_move_resize().) - **/ -void -gdk_window_move_resize (GdkWindow *window, - gint x, - gint y, - gint width, - gint height) +static void +gdk_window_x11_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); - if (width < 1) width = 1; + if (height < 1) height = 1; - + private = (GdkWindowObject*) window; if (!GDK_WINDOW_DESTROYED (window)) @@ -1833,18 +1733,24 @@ gdk_window_move_resize (GdkWindow *window, } } -void -_gdk_window_reparent (GdkWindow *window, - GdkWindow *new_parent, - gint x, - gint y) +static gboolean +gdk_window_x11_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) { GdkWindowObject *window_private; GdkWindowObject *parent_private; GdkWindowObject *old_parent_private; GdkWindowImplX11 *impl; gboolean was_toplevel; - + + if (new_parent && gdk_window_is_offscreen (new_parent)) + { + g_warning ("Can't reparent a X11 window to an offscreen parent"); + return FALSE; + } + if (!new_parent) new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window)); @@ -1852,7 +1758,7 @@ _gdk_window_reparent (GdkWindow *window, old_parent_private = (GdkWindowObject*)window_private->parent; parent_private = (GdkWindowObject*) new_parent; impl = GDK_WINDOW_IMPL_X11 (window_private->impl); - + XReparentWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), GDK_WINDOW_XID (new_parent), @@ -1860,13 +1766,13 @@ _gdk_window_reparent (GdkWindow *window, window_private->x = x; window_private->y = y; - + /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like * the root window */ if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN) new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window)); - + window_private->parent = (GdkWindowObject *)new_parent; /* Switch the window type as appropriate */ @@ -1876,7 +1782,7 @@ _gdk_window_reparent (GdkWindow *window, case GDK_WINDOW_ROOT: case GDK_WINDOW_FOREIGN: was_toplevel = WINDOW_IS_TOPLEVEL (window); - + if (impl->toplevel_window_type != -1) GDK_WINDOW_TYPE (window) = impl->toplevel_window_type; else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD) @@ -1903,7 +1809,7 @@ _gdk_window_reparent (GdkWindow *window, XDestroyWindow (GDK_WINDOW_XDISPLAY (window), impl->toplevel->focus_window); _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), impl->toplevel->focus_window); } - + gdk_toplevel_x11_free_contents (GDK_WINDOW_DISPLAY (window), impl->toplevel); g_free (impl->toplevel); @@ -1914,88 +1820,42 @@ _gdk_window_reparent (GdkWindow *window, if (old_parent_private) old_parent_private->children = g_list_remove (old_parent_private->children, window); - + if ((old_parent_private && (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) || (!old_parent_private && parent_private->guffaw_gravity)) gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity); - + parent_private->children = g_list_prepend (parent_private->children, window); _gdk_window_init_position (GDK_WINDOW (window_private)); -} -void -_gdk_windowing_window_clear_area (GdkWindow *window, - gint x, - gint y, - gint width, - gint height) -{ - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (!GDK_WINDOW_DESTROYED (window)) - XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), - x, y, width, height, False); + return TRUE; } -void -_gdk_windowing_window_clear_area_e (GdkWindow *window, - gint x, - gint y, - gint width, - gint height) +static void +gdk_window_x11_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height, + gboolean send_expose) { - g_return_if_fail (GDK_IS_WINDOW (window)); - if (!GDK_WINDOW_DESTROYED (window)) XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), - x, y, width, height, True); + x, y, width, height, + send_expose); } - -/** - * gdk_window_raise: - * @window: a #GdkWindow - * - * Raises @window to the top of the Z-order (stacking order), so that - * other windows with the same parent window appear below @window. - * This is true whether or not the windows are visible. - * - * If @window is a toplevel, the window manager may choose to deny the - * request to move the window in the Z-order, gdk_window_raise() only - * requests the restack, does not guarantee it. - * - **/ -void -gdk_window_raise (GdkWindow *window) +static void +gdk_window_x11_raise (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - if (!GDK_WINDOW_DESTROYED (window)) XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); } -/** - * gdk_window_lower: - * @window: a #GdkWindow - * - * Lowers @window to the bottom of the Z-order (stacking order), so that - * other windows with the same parent window appear above @window. - * This is true whether or not the other windows are visible. - * - * If @window is a toplevel, the window manager may choose to deny the - * request to move the window in the Z-order, gdk_window_lower() only - * requests the restack, does not guarantee it. - * - * Note that gdk_window_show() raises the window again, so don't call this - * function before gdk_window_show(). (Try gdk_window_show_unraised().) - * - **/ -void -gdk_window_lower (GdkWindow *window) +static void +gdk_window_x11_lower (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - if (!GDK_WINDOW_DESTROYED (window)) XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); } @@ -2099,9 +1959,9 @@ gdk_window_focus (GdkWindow *window, { GdkDisplay *display; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; display = GDK_WINDOW_DISPLAY (window); @@ -2171,9 +2031,9 @@ gdk_window_set_hints (GdkWindow *window, { XSizeHints size_hints; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; size_hints.flags = 0; @@ -2226,9 +2086,9 @@ gdk_window_set_type_hint (GdkWindow *window, GdkDisplay *display; Atom atom; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; display = gdk_drawable_get_display (window); @@ -2412,9 +2272,9 @@ gdk_window_set_modal_hint (GdkWindow *window, { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; private = (GdkWindowObject*) window; @@ -2447,10 +2307,10 @@ gdk_window_set_skip_taskbar_hint (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -2484,10 +2344,10 @@ gdk_window_set_skip_pager_hint (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -2515,10 +2375,10 @@ gdk_window_set_urgency_hint (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -2563,9 +2423,9 @@ gdk_window_set_geometry_hints (GdkWindow *window, { XSizeHints size_hints; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; size_hints.flags = 0; @@ -2827,10 +2687,10 @@ gdk_window_set_title (GdkWindow *window, Display *xdisplay; Window xwindow; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); g_return_if_fail (title != NULL); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; display = gdk_drawable_get_display (window); @@ -2877,7 +2737,7 @@ gdk_window_set_role (GdkWindow *window, { GdkDisplay *display; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); display = gdk_drawable_get_display (window); @@ -2945,7 +2805,7 @@ void gdk_window_set_transient_for (GdkWindow *window, GdkWindow *parent) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent)) XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), @@ -2953,31 +2813,13 @@ gdk_window_set_transient_for (GdkWindow *window, GDK_WINDOW_XID (parent)); } -/** - * gdk_window_set_background: - * @window: a #GdkWindow - * @color: an allocated #GdkColor - * - * Sets the background color of @window. (However, when using GTK+, - * set the background of a widget with gtk_widget_modify_bg() - if - * you're an application - or gtk_style_set_background() - if you're - * implementing a custom widget.) - * - * The @color must be allocated; gdk_rgb_find_color() is the best way - * to allocate a color. - * - * See also gdk_window_set_back_pixmap(). - * - **/ -void -gdk_window_set_background (GdkWindow *window, - const GdkColor *color) +static void +gdk_window_x11_set_background (GdkWindow *window, + const GdkColor *color) { GdkWindowObject *private = (GdkWindowObject *)window; GdkColormap *colormap = gdk_drawable_get_colormap (window); - g_return_if_fail (GDK_IS_WINDOW (window)); - if (!GDK_WINDOW_DESTROYED (window)) XSetWindowBackground (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), color->pixel); @@ -2993,42 +2835,14 @@ gdk_window_set_background (GdkWindow *window, private->bg_pixmap = NULL; } -/** - * gdk_window_set_back_pixmap: - * @window: a #GdkWindow - * @pixmap: a #GdkPixmap, or %NULL - * @parent_relative: whether the tiling origin is at the origin of @window's parent - * - * Sets the background pixmap of @window. May also be used to set a background of - * "None" on @window, by setting a background pixmap of %NULL. - * A background pixmap will be tiled, positioning the first tile at the origin of - * @window, or if @parent_relative is %TRUE, the tiling will be done based on the - * origin of the parent window (useful to align tiles in a parent with tiles - * in a child). - * - * A background pixmap of %NULL means that the window will have no - * background. A window with no background will never have its - * background filled by the windowing system, instead the window will - * contain whatever pixels were already in the corresponding area of - * the display. - * - * The windowing system will normally fill a window with its background - * when the window is obscured then exposed, and when you call - * gdk_window_clear(). - * - **/ -void -gdk_window_set_back_pixmap (GdkWindow *window, - GdkPixmap *pixmap, - gboolean parent_relative) +static void +gdk_window_x11_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gboolean parent_relative) { GdkWindowObject *private = (GdkWindowObject *)window; Pixmap xpixmap; - g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (pixmap == NULL || !parent_relative); - g_return_if_fail (pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap)); - if (pixmap && !gdk_drawable_get_colormap (pixmap)) { g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap"); @@ -3065,30 +2879,15 @@ gdk_window_set_back_pixmap (GdkWindow *window, GDK_WINDOW_XID (window), xpixmap); } -/** - * gdk_window_set_cursor: - * @window: a #GdkWindow - * @cursor: a cursor - * - * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or - * gdk_cursor_new_from_pixmap() to create the cursor. - * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create - * a cursor with no pixels in it. Passing %NULL for the @cursor argument - * to gdk_window_set_cursor() means that @window will use the cursor of - * its parent window. Most windows should use this default. - * - **/ -void -gdk_window_set_cursor (GdkWindow *window, - GdkCursor *cursor) +static void +gdk_window_x11_set_cursor (GdkWindow *window, + GdkCursor *cursor) { GdkWindowObject *private; GdkWindowImplX11 *impl; GdkCursorPrivate *cursor_private; Cursor xcursor; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject *)window; impl = GDK_WINDOW_IMPL_X11 (private->impl); cursor_private = (GdkCursorPrivate*) cursor; @@ -3132,45 +2931,13 @@ _gdk_x11_window_get_cursor (GdkWindow *window) return impl->cursor; } -/** - * gdk_window_get_geometry: - * @window: a #GdkWindow - * @x: return location for X coordinate of window (relative to its parent) - * @y: return location for Y coordinate of window (relative to its parent) - * @width: return location for width of window - * @height: return location for height of window - * @depth: return location for bit depth of window - * - * Any of the return location arguments to this function may be %NULL, - * if you aren't interested in getting the value of that field. - * - * The X and Y coordinates returned are relative to the parent window - * of @window, which for toplevels usually means relative to the - * window decorations (titlebar, etc.) rather than relative to the - * root window (screen-size background window). - * - * On the X11 platform, the geometry is obtained from the X server, - * so reflects the latest position of @window; this may be out-of-sync - * with the position of @window delivered in the most-recently-processed - * #GdkEventConfigure. gdk_window_get_position() in contrast gets the - * position from the most recent configure event. - * - * - * If @window is not a toplevel, it is much better - * to call gdk_window_get_position() and gdk_drawable_get_size() instead, - * because it avoids the roundtrip to the X server and because - * gdk_drawable_get_size() supports the full 32-bit coordinate space, - * whereas gdk_window_get_geometry() is restricted to the 16-bit - * coordinates of X11. - * - **/ -void -gdk_window_get_geometry (GdkWindow *window, - gint *x, - gint *y, - gint *width, - gint *height, - gint *depth) +static void +gdk_window_x11_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) { Window root; gint tx; @@ -3180,15 +2947,6 @@ gdk_window_get_geometry (GdkWindow *window, guint tborder_width; guint tdepth; - g_return_if_fail (window == NULL || GDK_IS_WINDOW (window)); - - if (!window) - { - GDK_NOTE (MULTIHEAD, - g_message ("gdk_window_get_geometry(): Window needs to be non-NULL to be multi head safe")); - window = gdk_screen_get_root_window ((gdk_screen_get_default ())); - } - if (!GDK_WINDOW_DESTROYED (window)) { XGetGeometry (GDK_WINDOW_XDISPLAY (window), @@ -3208,31 +2966,16 @@ gdk_window_get_geometry (GdkWindow *window, } } -/** - * gdk_window_get_origin: - * @window: a #GdkWindow - * @x: return location for X coordinate - * @y: return location for Y coordinate - * - * Obtains the position of a window in root window coordinates. - * (Compare with gdk_window_get_position() and - * gdk_window_get_geometry() which return the position of a window - * relative to its parent window.) - * - * Return value: not meaningful, ignore - **/ -gint -gdk_window_get_origin (GdkWindow *window, - gint *x, - gint *y) +static gint +gdk_window_x11_get_origin (GdkWindow *window, + gint *x, + gint *y) { gint return_val; Window child; gint tx = 0; gint ty = 0; - g_return_val_if_fail (GDK_IS_WINDOW (window), 0); - if (!GDK_WINDOW_DESTROYED (window)) { return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window), @@ -3282,7 +3025,7 @@ gdk_window_get_deskrelative_origin (GdkWindow *window, gulong number_return, bytes_after_return; guchar *data_return; - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (window), FALSE); if (!GDK_WINDOW_DESTROYED (window)) { @@ -3348,7 +3091,7 @@ gdk_window_get_root_origin (GdkWindow *window, { GdkRectangle rect; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); gdk_window_get_frame_extents (window, &rect); @@ -3394,7 +3137,7 @@ gdk_window_get_frame_extents (GdkWindow *window, gint wx, wy; gboolean got_frame_extents = FALSE; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); g_return_if_fail (rect != NULL); private = (GdkWindowObject*) window; @@ -3404,7 +3147,7 @@ gdk_window_get_frame_extents (GdkWindow *window, rect->width = 1; rect->height = 1; - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; while (private->parent && ((GdkWindowObject*) private->parent)->parent) @@ -3603,7 +3346,7 @@ _gdk_windowing_window_get_pointer (GdkDisplay *display, g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); - _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); + _gdk_x11_window_get_offsets (window, &xoffset, &yoffset); return_val = NULL; if (!GDK_WINDOW_DESTROYED (window)) @@ -3789,21 +3532,11 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display, return window; } -/** - * gdk_window_get_events: - * @window: a #GdkWindow - * - * Gets the event mask for @window. See gdk_window_set_events(). - * - * Return value: event mask for @window - **/ -GdkEventMask -gdk_window_get_events (GdkWindow *window) +static GdkEventMask +gdk_window_x11_get_events (GdkWindow *window) { XWindowAttributes attrs; GdkEventMask event_mask; - - g_return_val_if_fail (GDK_IS_WINDOW (window), 0); if (GDK_WINDOW_DESTROYED (window)) return 0; @@ -3819,27 +3552,13 @@ gdk_window_get_events (GdkWindow *window) return event_mask; } } - -/** - * gdk_window_set_events: - * @window: a #GdkWindow - * @event_mask: event mask for @window - * - * The event mask for a window determines which events will be reported - * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK - * means the window should report button press events. The event mask - * is the bitwise OR of values from the #GdkEventMask enumeration. - * - **/ -void -gdk_window_set_events (GdkWindow *window, - GdkEventMask event_mask) +static void +gdk_window_x11_set_events (GdkWindow *window, + GdkEventMask event_mask) { long xevent_mask; int i; - g_return_if_fail (GDK_IS_WINDOW (window)); - if (!GDK_WINDOW_DESTROYED (window)) { GDK_WINDOW_OBJECT (window)->event_mask = event_mask; @@ -3908,10 +3627,10 @@ gdk_window_add_colormap_windows (GdkWindow *window) * If not available, shaped windows will look * ugly, but programs still work. Stefan Wille */ -static void +static inline void do_shape_combine_mask (GdkWindow *window, GdkBitmap *mask, - gint x, + gint x, gint y, gint shape) { @@ -3919,13 +3638,11 @@ do_shape_combine_mask (GdkWindow *window, Pixmap pixmap; gint xoffset, yoffset; - g_return_if_fail (GDK_IS_WINDOW (window)); - #ifdef HAVE_SHAPE_EXT if (GDK_WINDOW_DESTROYED (window)) return; - _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); + _gdk_x11_window_get_offsets (window, &xoffset, &yoffset); if (xoffset != 0 || yoffset != 0) { @@ -3962,37 +3679,11 @@ do_shape_combine_mask (GdkWindow *window, #endif /* HAVE_SHAPE_EXT */ } -/** - * gdk_window_shape_combine_mask: - * @window: a #GdkWindow - * @mask: shape mask - * @x: X position of shape mask with respect to @window - * @y: Y position of shape mask with respect to @window - * - * Applies a shape mask to @window. Pixels in @window corresponding to - * set bits in the @mask will be visible; pixels in @window - * corresponding to unset bits in the @mask will be transparent. This - * gives a non-rectangular window. - * - * If @mask is %NULL, the shape mask will be unset, and the @x/@y - * parameters are not used. - * - * On the X11 platform, this uses an X server extension which is - * widely available on most common platforms, but not available on - * very old X servers, and occasionally the implementation will be - * buggy. On servers without the shape extension, this function - * will do nothing. - * - * On the Win32 platform the functionality is always present. - * - * This function works on both toplevel and child windows. - * - **/ -void -gdk_window_shape_combine_mask (GdkWindow *window, - GdkBitmap *mask, - gint x, - gint y) +static void +gdk_window_x11_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y) { do_shape_combine_mask (window, mask, x, y, ShapeBounding); } @@ -4035,7 +3726,7 @@ gdk_window_input_shape_combine_mask (GdkWindow *window, } -static void +static inline void do_shape_combine_region (GdkWindow *window, const GdkRegion *shape_region, gint offset_x, @@ -4045,13 +3736,11 @@ do_shape_combine_region (GdkWindow *window, GdkWindowObject *private = (GdkWindowObject *)window; gint xoffset, yoffset; - g_return_if_fail (GDK_IS_WINDOW (window)); - #ifdef HAVE_SHAPE_EXT if (GDK_WINDOW_DESTROYED (window)) return; - _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); + _gdk_x11_window_get_offsets (window, &xoffset, &yoffset); if (xoffset != 0 || yoffset != 0) { @@ -4091,38 +3780,11 @@ do_shape_combine_region (GdkWindow *window, } #endif /* HAVE_SHAPE_EXT */ } - -/** - * gdk_window_shape_combine_region: - * @window: a #GdkWindow - * @shape_region: region of window to be non-transparent - * @offset_x: X position of @shape_region in @window coordinates - * @offset_y: Y position of @shape_region in @window coordinates - * - * Makes pixels in @window outside @shape_region be transparent, - * so that the window may be nonrectangular. See also - * gdk_window_shape_combine_mask() to use a bitmap as the mask. - * - * If @shape_region is %NULL, the shape will be unset, so the whole - * window will be opaque again. @offset_x and @offset_y are ignored - * if @shape_region is %NULL. - * - * On the X11 platform, this uses an X server extension which is - * widely available on most common platforms, but not available on - * very old X servers, and occasionally the implementation will be - * buggy. On servers without the shape extension, this function - * will do nothing. - * - * On the Win32 platform, this functionality is always present. - * - * This function works on both toplevel and child windows. - * - **/ -void -gdk_window_shape_combine_region (GdkWindow *window, - const GdkRegion *shape_region, - gint offset_x, - gint offset_y) +static void +gdk_window_x11_shape_combine_region (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y) { do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding); } @@ -4186,7 +3848,7 @@ gdk_window_set_override_redirect (GdkWindow *window, { XSetWindowAttributes attr; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); if (!GDK_WINDOW_DESTROYED (window)) { @@ -4222,7 +3884,7 @@ gdk_window_set_accept_focus (GdkWindow *window, { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); private = (GdkWindowObject *)window; @@ -4259,7 +3921,7 @@ gdk_window_set_focus_on_map (GdkWindow *window, { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); private = (GdkWindowObject *)window; @@ -4304,9 +3966,9 @@ gdk_x11_window_set_user_time (GdkWindow *window, glong timestamp_long = (glong)timestamp; Window xid; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; display = gdk_drawable_get_display (window); @@ -4374,9 +4036,9 @@ gdk_window_set_icon_list (GdkWindow *window, GdkDisplay *display; gint n; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; display = gdk_drawable_get_display (window); @@ -4486,10 +4148,10 @@ gdk_window_set_icon (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -4546,9 +4208,9 @@ gdk_window_set_icon_name (GdkWindow *window, { GdkDisplay *display; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; display = gdk_drawable_get_display (window); @@ -4581,9 +4243,9 @@ gdk_window_set_icon_name (GdkWindow *window, void gdk_window_iconify (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4615,9 +4277,9 @@ gdk_window_iconify (GdkWindow *window) void gdk_window_deiconify (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4651,9 +4313,9 @@ gdk_window_deiconify (GdkWindow *window) void gdk_window_stick (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4708,9 +4370,9 @@ gdk_window_stick (GdkWindow *window) void gdk_window_unstick (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4752,9 +4414,9 @@ gdk_window_unstick (GdkWindow *window) void gdk_window_maximize (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4787,9 +4449,9 @@ gdk_window_maximize (GdkWindow *window) void gdk_window_unmaximize (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4825,9 +4487,9 @@ gdk_window_unmaximize (GdkWindow *window) void gdk_window_fullscreen (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4861,9 +4523,9 @@ gdk_window_fullscreen (GdkWindow *window) void gdk_window_unfullscreen (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4895,7 +4557,8 @@ gdk_window_unfullscreen (GdkWindow *window) * Since: 2.4 **/ void -gdk_window_set_keep_above (GdkWindow *window, gboolean setting) +gdk_window_set_keep_above (GdkWindow *window, + gboolean setting) { g_return_if_fail (GDK_IS_WINDOW (window)); @@ -4974,10 +4637,10 @@ gdk_window_get_group (GdkWindow *window) { GdkToplevelX11 *toplevel; - g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (window), NULL); g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return NULL; toplevel = _gdk_x11_window_get_toplevel (window); @@ -5007,9 +4670,9 @@ gdk_window_set_group (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader)); + g_return_if_fail (leader == NULL || GDK_IS_ONSCREEN_WINDOW (leader)); if (GDK_WINDOW_DESTROYED (window) || (leader != NULL && GDK_WINDOW_DESTROYED (leader))) return; @@ -5137,7 +4800,7 @@ gdk_window_set_decorations (GdkWindow *window, { MotifWmHints hints; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); /* initialize to zero to avoid writing uninitialized data to socket */ memset(&hints, 0, sizeof(hints)); @@ -5162,7 +4825,7 @@ gdk_window_get_decorations(GdkWindow *window, MotifWmHints *hints; gboolean result = FALSE; - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (window), FALSE); hints = gdk_window_get_mwm_hints (window); @@ -5534,53 +5197,48 @@ gdk_propagate_shapes (Display *disp, #endif /* HAVE_SHAPE_EXT */ -/** - * gdk_window_set_child_shapes: - * @window: a #GdkWindow - * - * Sets the shape mask of @window to the union of shape masks - * for all children of @window, ignoring the shape mask of @window - * itself. Contrast with gdk_window_merge_child_shapes() which includes - * the shape mask of @window in the masks to be merged. - **/ -void -gdk_window_set_child_shapes (GdkWindow *window) +static inline void +do_child_shapes (GdkWindow *window, + gboolean merge) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - -#ifdef HAVE_SHAPE_EXT if (!GDK_WINDOW_DESTROYED (window) && gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))) - gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), FALSE, ShapeBounding); -#endif + { + gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + merge, + ShapeBounding); + } } -/** - * gdk_window_merge_child_shapes: - * @window: a #GdkWindow - * - * Merges the shape masks for any child windows into the - * shape mask for @window. i.e. the union of all masks - * for @window and its children will become the new mask - * for @window. See gdk_window_shape_combine_mask(). - * - * This function is distinct from gdk_window_set_child_shapes() - * because it includes @window's shape mask in the set of shapes to - * be merged. - **/ -void -gdk_window_merge_child_shapes (GdkWindow *window) +static void +gdk_window_x11_set_child_shapes (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - #ifdef HAVE_SHAPE_EXT + do_child_shapes (window, FALSE); +#endif +} + +static void +gdk_window_x11_merge_child_shapes (GdkWindow *window) +{ +#ifdef HAVE_SHAPE_EXT + do_child_shapes (window, TRUE); +#endif +} + +static inline void +do_child_input_shapes (GdkWindow *window, + gboolean merge) +{ if (!GDK_WINDOW_DESTROYED (window) && gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))) - gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), TRUE, ShapeBounding); -#endif + { + gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + merge, + ShapeInput); + } } /** @@ -5601,10 +5259,7 @@ gdk_window_set_child_input_shapes (GdkWindow *window) #ifdef HAVE_SHAPE_EXT #ifdef ShapeInput - if (!GDK_WINDOW_DESTROYED (window) && - gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window))) - gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), FALSE, ShapeInput); + do_child_input_shapes (window, FALSE); #endif #endif } @@ -5631,10 +5286,7 @@ gdk_window_merge_child_input_shapes (GdkWindow *window) #ifdef HAVE_SHAPE_EXT #ifdef ShapeInput - if (!GDK_WINDOW_DESTROYED (window) && - gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window))) - gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), TRUE, ShapeInput); + do_child_input_shapes (window, TRUE); #endif #endif } @@ -5675,27 +5327,13 @@ gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on) CWWinGravity, &xattributes); } -/** - * gdk_window_set_static_gravities: - * @window: a #GdkWindow - * @use_static: %TRUE to turn on static gravity - * - * Set the bit gravity of the given window to static, and flag it so - * all children get static subwindow gravity. This is used if you are - * implementing scary features that involve deep knowledge of the - * windowing system. Don't worry about it unless you have to. - * - * Return value: %TRUE if the server supports static gravity - **/ -gboolean -gdk_window_set_static_gravities (GdkWindow *window, - gboolean use_static) +static gboolean +gdk_window_x11_set_static_gravities (GdkWindow *window, + gboolean use_static) { GdkWindowObject *private = (GdkWindowObject *)window; GList *tmp_list; - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); - if (!use_static == !private->guffaw_gravity) return TRUE; @@ -5708,7 +5346,8 @@ gdk_window_set_static_gravities (GdkWindow *window, tmp_list = private->children; while (tmp_list) { - gdk_window_set_static_win_gravity (tmp_list->data, use_static); + if (!gdk_window_is_offscreen (tmp_list->data)) + gdk_window_set_static_win_gravity (tmp_list->data, use_static); tmp_list = tmp_list->next; } @@ -6283,9 +5922,9 @@ gdk_window_begin_resize_drag (GdkWindow *window, gint root_y, guint32 timestamp) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), @@ -6318,9 +5957,9 @@ gdk_window_begin_move_drag (GdkWindow *window, gint root_y, guint32 timestamp) { - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) return; if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), @@ -6354,7 +5993,7 @@ gdk_window_enable_synchronized_configure (GdkWindow *window) GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplX11 *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); impl = GDK_WINDOW_IMPL_X11 (private->impl); @@ -6385,7 +6024,7 @@ gdk_window_configure_finished (GdkWindow *window) { GdkWindowImplX11 *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window)); impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl); if (!impl->use_synchronized_configure) @@ -6426,6 +6065,11 @@ gdk_window_beep (GdkWindow *window) { GdkDisplay *display; + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window)) + return; + display = GDK_WINDOW_DISPLAY (window); #ifdef HAVE_XKB @@ -6525,6 +6169,35 @@ _gdk_windowing_window_set_composited (GdkWindow *window, #endif } +static void +gdk_window_impl_iface_init (GdkWindowImplIface *iface) +{ + iface->show = gdk_window_x11_show; + iface->hide = gdk_window_x11_hide; + iface->withdraw = gdk_window_x11_withdraw; + iface->set_events = gdk_window_x11_set_events; + iface->get_events = gdk_window_x11_get_events; + iface->clear_area = gdk_window_x11_clear_area; + iface->raise = gdk_window_x11_raise; + iface->lower = gdk_window_x11_lower; + iface->move = gdk_window_x11_move; + iface->resize = gdk_window_x11_resize; + iface->move_resize = gdk_window_x11_move_resize; + iface->scroll = _gdk_x11_window_scroll; + iface->move_region = _gdk_x11_window_move_region; + iface->set_background = gdk_window_x11_set_background; + iface->set_back_pixmap = gdk_window_x11_set_back_pixmap; + iface->reparent = gdk_window_x11_reparent; + iface->set_cursor = gdk_window_x11_set_cursor; + iface->get_geometry = gdk_window_x11_get_geometry; + iface->get_origin = gdk_window_x11_get_origin; + iface->shape_combine_mask = gdk_window_x11_shape_combine_mask; + iface->shape_combine_region = gdk_window_x11_shape_combine_region; + iface->set_child_shapes = gdk_window_x11_set_child_shapes; + iface->merge_child_shapes = gdk_window_x11_merge_child_shapes; + iface->set_static_gravities = gdk_window_x11_set_static_gravities; + iface->get_offsets = _gdk_x11_window_get_offsets; +} #define __GDK_WINDOW_X11_C__ #include "gdkaliasdef.c" diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h index 3ab23d6..2a2799b 100644 --- a/gdk/x11/gdkwindow-x11.h +++ b/gdk/x11/gdkwindow-x11.h @@ -169,6 +169,9 @@ void _gdk_x11_window_tmp_reset_bg (GdkWindow *window, GdkCursor *_gdk_x11_window_get_cursor (GdkWindow *window); +void _gdk_x11_window_get_offsets (GdkWindow *window, + gint *x_offset, + gint *y_offset); G_END_DECLS diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c index a2f63e9..3685811 100644 --- a/gtk/gtkspinbutton.c +++ b/gtk/gtkspinbutton.c @@ -744,12 +744,7 @@ static gint gtk_spin_button_expose (GtkWidget *widget, GdkEventExpose *event) { - GtkSpinButton *spin; - - g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - spin = GTK_SPIN_BUTTON (widget); + GtkSpinButton *spin = GTK_SPIN_BUTTON (widget); if (GTK_WIDGET_DRAWABLE (widget)) { diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 7c6d983..c356e9c 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -2025,9 +2025,10 @@ gtk_widget_class_init (GtkWidgetClass *klass) * Since: 2.14 */ widget_signals[DAMAGE_EVENT] = - g_signal_new ("damage_event", + g_signal_new (I_("damage-event"), G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, 0, + G_SIGNAL_RUN_LAST, + 0, _gtk_boolean_handled_accumulator, NULL, _gtk_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, diff --git a/tests/Makefile.am b/tests/Makefile.am index edd18b0..223988e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -54,6 +54,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \ testmultiscreen \ testnotebookdnd \ testnouiprint \ + testoffscreen \ testprint \ testrgb \ testrecentchooser \ @@ -128,6 +129,7 @@ testmultidisplay_DEPENDENCIES = $(TEST_DEPS) testmultiscreen_DEPENDENCIES = $(TEST_DEPS) testnotebookdnd_DEPENDENCIES = $(TEST_DEPS) testnouiprint_DEPENDENCIES = $(TEST_DEPS) +testoffscreen_DEPENDENCIES = $(TEST_DEPS) testprint_DEPENDENCIES = $(TEST_DEPS) testrecentchooser_DEPENDENCIES = $(TEST_DEPS) testrecentchoosermenu_DEPENDENCIES = $(TEST_DEPS) @@ -182,6 +184,7 @@ testmultidisplay_LDADD = $(LDADDS) testmultiscreen_LDADD = $(LDADDS) testnotebookdnd_LDADD = $(LDADDS) testnouiprint_LDADD = $(LDADDS) +testoffscreen_LDADD = $(LDADDS) testprint_LDADD = $(LDADDS) testrecentchooser_LDADD = $(LDADDS) testrecentchoosermenu_LDADD = $(LDADDS) @@ -302,6 +305,11 @@ testrecentchoosermenu_SOURCES = \ testvolumebutton_SOURCES = \ testvolumebutton.c +testoffscreen_SOURCES = \ + gtkoffscreenbox.c \ + gtkoffscreenbox.h \ + testoffscreen.c + EXTRA_DIST += \ prop-editor.h \ testgtk.1 \ diff --git a/tests/gtkoffscreenbox.c b/tests/gtkoffscreenbox.c new file mode 100644 index 0000000..cdff2ea --- /dev/null +++ b/tests/gtkoffscreenbox.c @@ -0,0 +1,697 @@ +#include +#include +#include +#include +#include + +#include "gtkoffscreenbox.h" + +static void gtk_offscreen_box_class_init (GtkOffscreenBoxClass *klass); +static void gtk_offscreen_box_init (GtkOffscreenBox *offscreen_box); +static void gtk_offscreen_box_realize (GtkWidget *widget); +static void gtk_offscreen_box_unrealize (GtkWidget *widget); +static void gtk_offscreen_box_map (GtkWidget *widget); +static void gtk_offscreen_box_unmap (GtkWidget *widget); +static void gtk_offscreen_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_offscreen_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_offscreen_box_expose (GtkWidget *widget, + GdkEventExpose *offscreen); +static void gtk_offscreen_box_add (GtkContainer *container, + GtkWidget *child); +static void gtk_offscreen_box_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_offscreen_box_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GType gtk_offscreen_box_child_type (GtkContainer *container); +static gboolean gtk_offscreen_box_damage_event (GtkWidget *widget, + GdkEventExpose *event); +static void window_to_parent_coordinate (GdkWindow *window, + double x, + double y, + double *parent_x, + double *parent_y); +static void parent_to_window_coordinate (GdkWindow *window, + double x, + double y, + double *win_x, + double *win_y); +static GdkWindow *find_offscreen_child (GdkWindow *window, + double x, + double y); + +static const GdkOffscreenHooks offscreen_hooks = { + window_to_parent_coordinate, + parent_to_window_coordinate, + find_offscreen_child +}; + +#define CHILD1_SIZE_SCALE 1.0 +#define CHILD2_SIZE_SCALE 1.0 + +G_DEFINE_TYPE (GtkOffscreenBox, gtk_offscreen_box, GTK_TYPE_CONTAINER); + +static void +gtk_offscreen_box_class_init (GtkOffscreenBoxClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + widget_class->realize = gtk_offscreen_box_realize; + widget_class->unrealize = gtk_offscreen_box_unrealize; + widget_class->map = gtk_offscreen_box_map; + widget_class->unmap = gtk_offscreen_box_unmap; + widget_class->size_request = gtk_offscreen_box_size_request; + widget_class->size_allocate = gtk_offscreen_box_size_allocate; + widget_class->expose_event = gtk_offscreen_box_expose; + + g_signal_override_class_closure (g_signal_lookup ("damage-event", GTK_TYPE_WIDGET), + GTK_TYPE_OFFSCREEN_BOX, + g_cclosure_new (G_CALLBACK (gtk_offscreen_box_damage_event), + NULL, NULL)); + + container_class->add = gtk_offscreen_box_add; + container_class->remove = gtk_offscreen_box_remove; + container_class->forall = gtk_offscreen_box_forall; + container_class->child_type = gtk_offscreen_box_child_type; +} + +static void +gtk_offscreen_box_init (GtkOffscreenBox *offscreen_box) +{ + GTK_WIDGET_UNSET_FLAGS (offscreen_box, GTK_NO_WINDOW); +} + +GtkWidget* +gtk_offscreen_box_new (void) +{ + return g_object_new (GTK_TYPE_OFFSCREEN_BOX, NULL); +} + +static void +gtk_offscreen_box_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + gint border_width; + GtkOffscreenBox *offscreen_box; + GtkRequisition child_requisition; + int start_y; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + offscreen_box = GTK_OFFSCREEN_BOX (widget); + border_width = GTK_CONTAINER (widget)->border_width; + + attributes.x = widget->allocation.x + border_width; + attributes.y = widget->allocation.y + border_width; + attributes.width = widget->allocation.width - 2 * border_width; + attributes.height = widget->allocation.height - 2 * border_width; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) + | GDK_EXPOSURE_MASK + | GDK_POINTER_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_SCROLL_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK; + + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.wclass = GDK_INPUT_OUTPUT; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + gdk_window_set_offscreen_hooks (widget->window, &offscreen_hooks); + + start_y = 0; + + /* Child 1 */ + child_requisition.width = child_requisition.height = 0; + if (offscreen_box->child1 && GTK_WIDGET_VISIBLE (offscreen_box->child1)) + gtk_widget_get_child_requisition (offscreen_box->child1, &child_requisition); + + attributes.x = child_requisition.width * (CHILD1_SIZE_SCALE - 1.0) / 2; + attributes.y = start_y + child_requisition.height * (CHILD1_SIZE_SCALE - 1.0) / 2; + attributes.width = child_requisition.width; + attributes.height = child_requisition.height; + + start_y += CHILD1_SIZE_SCALE * child_requisition.height; + + offscreen_box->offscreen_window1 = gdk_offscreen_window_new (widget->window, + &attributes, attributes_mask); + gdk_window_set_user_data (offscreen_box->offscreen_window1, widget); + + if (offscreen_box->child1) + gtk_widget_set_parent_window (offscreen_box->child1, + offscreen_box->offscreen_window1); + + /* Child 2 */ + child_requisition.width = child_requisition.height = 0; + if (offscreen_box->child2 && GTK_WIDGET_VISIBLE (offscreen_box->child2)) + gtk_widget_get_child_requisition (offscreen_box->child2, &child_requisition); + + attributes.x = child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2; + attributes.y = start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2; + attributes.width = child_requisition.width; + attributes.height = child_requisition.height; + + start_y += CHILD2_SIZE_SCALE * child_requisition.height; + + offscreen_box->offscreen_window2 = gdk_offscreen_window_new (widget->window, + &attributes, attributes_mask); + gdk_window_set_user_data (offscreen_box->offscreen_window2, widget); + + if (offscreen_box->child2) + gtk_widget_set_parent_window (offscreen_box->child2, + offscreen_box->offscreen_window2); + + + widget->style = gtk_style_attach (widget->style, widget->window); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, offscreen_box->offscreen_window1, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, offscreen_box->offscreen_window2, GTK_STATE_NORMAL); + + gdk_window_show (offscreen_box->offscreen_window1); + gdk_window_show (offscreen_box->offscreen_window2); +} + +static void +gtk_offscreen_box_unrealize (GtkWidget *widget) +{ + GtkOffscreenBox *offscreen_box; + + offscreen_box = GTK_OFFSCREEN_BOX (widget); + + gdk_window_set_user_data (offscreen_box->offscreen_window1, NULL); + gdk_window_destroy (offscreen_box->offscreen_window1); + offscreen_box->offscreen_window1 = NULL; + + gdk_window_set_user_data (offscreen_box->offscreen_window2, NULL); + gdk_window_destroy (offscreen_box->offscreen_window2); + offscreen_box->offscreen_window2 = NULL; + + GTK_WIDGET_CLASS (gtk_offscreen_box_parent_class)->unrealize (widget); +} + +static GType +gtk_offscreen_box_child_type (GtkContainer *container) +{ + if (!GTK_OFFSCREEN_BOX (container)->child1 || !GTK_OFFSCREEN_BOX (container)->child2) + return GTK_TYPE_WIDGET; + else + return G_TYPE_NONE; +} + +static void +gtk_offscreen_box_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkOffscreenBox *offscreen_box; + + g_return_if_fail (GTK_IS_OFFSCREEN_BOX (container)); + + offscreen_box = GTK_OFFSCREEN_BOX (container); + + if (!offscreen_box->child1) + gtk_offscreen_box_add1 (offscreen_box, widget); + else if (!offscreen_box->child2) + gtk_offscreen_box_add2 (offscreen_box, widget); + else + g_warning ("GtkOffscreenBox cannot have more than 2 children\n"); +} + +void +gtk_offscreen_box_add1 (GtkOffscreenBox *offscreen_box, + GtkWidget *child) +{ + g_return_if_fail (GTK_IS_WIDGET (child)); + + if (offscreen_box->child1 == NULL) + { + gtk_widget_set_parent_window (child, offscreen_box->offscreen_window1); + gtk_widget_set_parent (child, GTK_WIDGET (offscreen_box)); + offscreen_box->child1 = child; + } +} + +void +gtk_offscreen_box_add2 (GtkOffscreenBox *offscreen_box, + GtkWidget *child) +{ + g_return_if_fail (GTK_IS_WIDGET (child)); + + if (offscreen_box->child2 == NULL) + { + gtk_widget_set_parent_window (child, offscreen_box->offscreen_window2); + gtk_widget_set_parent (child, GTK_WIDGET (offscreen_box)); + offscreen_box->child2 = child; + } +} + +static void +gtk_offscreen_box_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkOffscreenBox *offscreen_box; + gboolean was_visible; + + + offscreen_box = GTK_OFFSCREEN_BOX (container); + was_visible = GTK_WIDGET_VISIBLE (widget); + + if (offscreen_box->child1 == widget) + { + gtk_widget_unparent (widget); + + offscreen_box->child1 = NULL; + + if (was_visible && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } + else if (offscreen_box->child2 == widget) + { + gtk_widget_unparent (widget); + + offscreen_box->child2 = NULL; + + if (was_visible && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +gtk_offscreen_box_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkOffscreenBox *offscreen_box; + + g_return_if_fail (callback != NULL); + + offscreen_box = GTK_OFFSCREEN_BOX (container); + + if (offscreen_box->child1) + (*callback) (offscreen_box->child1, callback_data); + if (offscreen_box->child2) + (*callback) (offscreen_box->child2, callback_data); +} + +static void +gtk_offscreen_box_map (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (gtk_offscreen_box_parent_class)->map (widget); +} + +static void +gtk_offscreen_box_unmap (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (gtk_offscreen_box_parent_class)->unmap (widget); +} + +void +gtk_offscreen_box_set_angle (GtkOffscreenBox *offscreen_box, + gdouble angle) +{ + g_return_if_fail (GTK_IS_OFFSCREEN_BOX (offscreen_box)); + + offscreen_box->angle = angle; + gtk_widget_queue_draw (GTK_WIDGET (offscreen_box)); + + /* TODO: Really needs to resent pointer events if over the rotated window */ +} + + +static void +gtk_offscreen_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkOffscreenBox *offscreen_box = GTK_OFFSCREEN_BOX (widget); + int w, h; + + w = 0; + h = 0; + + if (offscreen_box->child1 && + GTK_WIDGET_VISIBLE (offscreen_box->child1)) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (offscreen_box->child1, &child_requisition); + + w = MAX (w, CHILD1_SIZE_SCALE * child_requisition.width); + h += CHILD1_SIZE_SCALE * child_requisition.height; + } + + if (offscreen_box->child2 && + GTK_WIDGET_VISIBLE (offscreen_box->child2)) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (offscreen_box->child2, &child_requisition); + + w = MAX (w, CHILD2_SIZE_SCALE * child_requisition.width); + h += CHILD2_SIZE_SCALE * child_requisition.height; + } + + requisition->width = GTK_CONTAINER (widget)->border_width * 2 + w; + requisition->height = GTK_CONTAINER (widget)->border_width * 2 + h; +} + +static void +gtk_offscreen_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkOffscreenBox *offscreen_box; + GtkAllocation child_allocation; + GtkRequisition child_requisition; + gint border_width; + gint start_y; + + widget->allocation = *allocation; + offscreen_box = GTK_OFFSCREEN_BOX (widget); + + border_width = GTK_CONTAINER (widget)->border_width; + + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x + border_width, + allocation->y + border_width, + allocation->width - border_width * 2, + allocation->height - border_width * 2); + + } + + start_y = 0; + + if (offscreen_box->child1 && GTK_WIDGET_VISIBLE (offscreen_box->child1)) + { + gtk_widget_get_child_requisition (offscreen_box->child1, &child_requisition); + + child_allocation.x = child_requisition.width * (CHILD1_SIZE_SCALE - 1.0) / 2; + child_allocation.y = start_y + child_requisition.height * (CHILD1_SIZE_SCALE - 1.0) / 2; + child_allocation.width = child_requisition.width; + child_allocation.height = child_requisition.height; + + start_y += CHILD1_SIZE_SCALE * child_requisition.height; + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (offscreen_box->offscreen_window1, + child_allocation.x, + child_allocation.y, + child_allocation.width, + child_allocation.height); + + child_allocation.x = child_allocation.y = 0; + gtk_widget_size_allocate (offscreen_box->child1, &child_allocation); + } + + if (offscreen_box->child2 && GTK_WIDGET_VISIBLE (offscreen_box->child2)) + { + gtk_widget_get_child_requisition (offscreen_box->child2, &child_requisition); + + child_allocation.x = child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2; + child_allocation.y = start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2; + child_allocation.width = child_requisition.width; + child_allocation.height = child_requisition.height; + + start_y += CHILD2_SIZE_SCALE * child_requisition.height; + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (offscreen_box->offscreen_window2, + child_allocation.x, + child_allocation.y, + child_allocation.width, + child_allocation.height); + + child_allocation.x = child_allocation.y = 0; + gtk_widget_size_allocate (offscreen_box->child2, &child_allocation); + } +} + +static gboolean +gtk_offscreen_box_damage_event (GtkWidget *widget, + GdkEventExpose *event) +{ + gdk_window_invalidate_rect (widget->window, NULL, TRUE); + + return TRUE; +} + +static gint +gtk_offscreen_box_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkOffscreenBox *offscreen_box = GTK_OFFSCREEN_BOX (widget); + GtkRequisition child_requisition; + + + if (GTK_WIDGET_DRAWABLE (widget)) + { + if (event->window == widget->window) + { + GdkPixmap *pixmap; + cairo_t *cr; + int x, y, width, height, start_y; + + start_y = 0; + + if (offscreen_box->child1 && GTK_WIDGET_VISIBLE (offscreen_box->child1)) + { + gtk_widget_get_child_requisition (offscreen_box->child1, &child_requisition); + + x = child_requisition.width * (CHILD1_SIZE_SCALE - 1.0) / 2; + y = start_y + child_requisition.height * (CHILD1_SIZE_SCALE - 1.0) / 2; + width = child_requisition.width; + height = child_requisition.height; + + start_y += CHILD1_SIZE_SCALE * child_requisition.height; + + pixmap = gdk_window_get_offscreen_pixmap (offscreen_box->offscreen_window1); + + cr = gdk_cairo_create (widget->window); + gdk_cairo_set_source_pixmap (cr, pixmap, 0, 0); + cairo_paint (cr); + } + + if (offscreen_box->child2 && GTK_WIDGET_VISIBLE (offscreen_box->child2)) + { + + gtk_widget_get_child_requisition (offscreen_box->child2, &child_requisition); + + x = child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2; + y = start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2; + width = child_requisition.width; + height = child_requisition.height; + + start_y += CHILD2_SIZE_SCALE * child_requisition.height; + + pixmap = gdk_window_get_offscreen_pixmap (offscreen_box->offscreen_window2); + + cr = gdk_cairo_create (widget->window); + cairo_translate (cr, x, y); + cairo_translate (cr, width / 2, height / 2); + cairo_rotate (cr, offscreen_box->angle); + cairo_translate (cr, -width / 2, -height / 2); + gdk_cairo_set_source_pixmap (cr, pixmap, 0, 0); + cairo_paint (cr); + } + } + else if (event->window == offscreen_box->offscreen_window1) + { + gtk_paint_flat_box (widget->style, event->window, + GTK_STATE_NORMAL, GTK_SHADOW_NONE, + &event->area, widget, "blah", + 0, 0, -1, -1); + + if (offscreen_box->child1) + gtk_container_propagate_expose (GTK_CONTAINER (widget), + offscreen_box->child1, + event); + } + else if (event->window == offscreen_box->offscreen_window2) + { + gtk_paint_flat_box (widget->style, event->window, + GTK_STATE_NORMAL, GTK_SHADOW_NONE, + &event->area, widget, "blah", + 0, 0, -1, -1); + + if (offscreen_box->child2) + gtk_container_propagate_expose (GTK_CONTAINER (widget), + offscreen_box->child2, + event); + } + } + + return FALSE; +} + +static gboolean +parent_to_child1 (GtkOffscreenBox *offscreen_box, + gdouble x, + gdouble y, + gdouble *child_x, + gdouble *child_y) +{ + GtkRequisition child_requisition; + + gtk_widget_size_request (offscreen_box->child1, &child_requisition); + + *child_x = x + (child_requisition.width * (CHILD1_SIZE_SCALE - 1.0) / 2); + *child_y = y + (child_requisition.height * (CHILD1_SIZE_SCALE - 1.0) / 2); + + return (*child_x >= 0 && *child_x <= child_requisition.width && + *child_y >= 0 && *child_y <= child_requisition.height); +} + +static void +parent_to_window_coordinate (GdkWindow *window, + gdouble x, + gdouble y, + gdouble *win_x, + gdouble *win_y) +{ + GtkOffscreenBox *offscreen_box = NULL; + gpointer window_data; + GtkRequisition child_requisition; + double pos_x, pos_y, rot_x, rot_y, start_y; + double angle; + + gdk_window_get_user_data (window, &window_data); + offscreen_box = window_data; + if (!offscreen_box) + return; + + start_y = 0; + + if (offscreen_box->child1) + { + gtk_widget_size_request (offscreen_box->child1, &child_requisition); + start_y = child_requisition.height * CHILD1_SIZE_SCALE; + } + + gtk_widget_size_request (offscreen_box->child2, &child_requisition); + + pos_x = x - (child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2); + pos_y = y - (start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2); + + pos_x -= child_requisition.width / 2; + pos_y -= child_requisition.height / 2; + + angle = -offscreen_box->angle; + rot_x = pos_x*cos (angle) - pos_y * sin(angle); + rot_y = pos_x*sin (angle) + pos_y * cos(angle); + + *win_x = rot_x + child_requisition.width / 2; + *win_y = rot_y + child_requisition.height / 2; +} + +static void +window_to_parent_coordinate (GdkWindow *window, + gdouble x, + gdouble y, + gdouble *parent_x, + gdouble *parent_y) +{ + GtkOffscreenBox *offscreen_box = NULL; + gpointer window_data; + GtkRequisition child_requisition; + gdouble pos_x, pos_y, rot_x, rot_y, start_y; + gdouble angle; + + gdk_window_get_user_data (window, &window_data); + offscreen_box = window_data; + if (!offscreen_box) + return; + + gtk_widget_size_request (offscreen_box->child1, &child_requisition); + start_y = child_requisition.height * CHILD1_SIZE_SCALE; + + gtk_widget_size_request (offscreen_box->child2, &child_requisition); + + pos_x = x + child_requisition.width / 2; + pos_y = y + child_requisition.height / 2; + + angle = offscreen_box->angle; + rot_x = pos_x * cos (angle) - pos_y * sin(angle); + rot_y = pos_x * sin (angle) + pos_y * cos(angle); + + rot_x += child_requisition.width / 2; + rot_y += child_requisition.height / 2; + + *parent_x = rot_x + (child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2); + *parent_y = rot_y + (start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2); +} + +static gboolean +parent_to_child2 (GtkOffscreenBox *offscreen_box, + gdouble x, + gdouble y, + gdouble *child_x, + gdouble *child_y) +{ + GtkRequisition child_requisition; + double pos_x, pos_y, rot_x, rot_y, start_y; + double angle; + + start_y = 0; + if (offscreen_box->child1) + { + gtk_widget_size_request (offscreen_box->child1, &child_requisition); + start_y += child_requisition.height * CHILD1_SIZE_SCALE; + } + + gtk_widget_size_request (offscreen_box->child2, &child_requisition); + + pos_x = x - (child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2); + pos_y = y - (start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2); + + pos_x -= child_requisition.width / 2; + pos_y -= child_requisition.height / 2; + + angle = -offscreen_box->angle; + rot_x = pos_x * cos (angle) - pos_y * sin (angle); + rot_y = pos_x * sin (angle) + pos_y * cos (angle); + + *child_x = rot_x + child_requisition.width / 2; + *child_y = rot_y + child_requisition.height / 2; + + return (*child_x >= 0 && *child_x < child_requisition.width && + *child_y >= 0 && *child_y < child_requisition.height); +} + +static GdkWindow * +find_offscreen_child (GdkWindow *window, + gdouble x, + gdouble y) +{ + GtkOffscreenBox *offscreen_box = NULL; + gpointer window_data; + gdouble ox, oy; + + gdk_window_get_user_data (window, &window_data); + offscreen_box = window_data; + g_assert (offscreen_box != NULL); + + /* Child2 is drawn last, pick first */ + if (offscreen_box->child2 && + parent_to_child2 (offscreen_box, x, y, &ox, &oy)) + return offscreen_box->offscreen_window2; + + if (offscreen_box->child1 && + parent_to_child1 (offscreen_box, x, y, &ox, &oy)) + return offscreen_box->offscreen_window1; + + return NULL; +} diff --git a/tests/gtkoffscreenbox.h b/tests/gtkoffscreenbox.h new file mode 100644 index 0000000..8e459b8 --- /dev/null +++ b/tests/gtkoffscreenbox.h @@ -0,0 +1,53 @@ +#ifndef __GTK_OFFSCREEN_BOX_H__ +#define __GTK_OFFSCREEN_BOX_H__ + + +#include +#include + + +G_BEGIN_DECLS + +#define GTK_TYPE_OFFSCREEN_BOX (gtk_offscreen_box_get_type ()) +#define GTK_OFFSCREEN_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_OFFSCREEN_BOX, GtkOffscreenBox)) +#define GTK_OFFSCREEN_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_OFFSCREEN_BOX, GtkOffscreenBoxClass)) +#define GTK_IS_OFFSCREEN_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_OFFSCREEN_BOX)) +#define GTK_IS_OFFSCREEN_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_OFFSCREEN_BOX)) +#define GTK_OFFSCREEN_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_OFFSCREEN_BOX, GtkOffscreenBoxClass)) + +typedef struct _GtkOffscreenBox GtkOffscreenBox; +typedef struct _GtkOffscreenBoxClass GtkOffscreenBoxClass; + +struct _GtkOffscreenBox +{ + GtkContainer container; + + GtkWidget *child1; + GtkWidget *child2; + + GdkWindow *offscreen_window1; + GdkWindow *offscreen_window2; + + GdkWindow *last_pointer_event_window; + gdouble angle; +}; + +struct _GtkOffscreenBoxClass +{ + GtkBinClass parent_class; +}; + +GType gtk_offscreen_box_get_type (void) G_GNUC_CONST; +GtkWidget* gtk_offscreen_box_new (void); +void gtk_offscreen_box_add1 (GtkOffscreenBox *offscreen, + GtkWidget *child); +void gtk_offscreen_box_add2 (GtkOffscreenBox *offscreen, + GtkWidget *child); +void gtk_offscreen_box_set_angle (GtkOffscreenBox *offscreen, + double angle); + + + +G_END_DECLS + +#endif /* __GTK_OFFSCREEN_BOX_H__ */ diff --git a/tests/testoffscreen.c b/tests/testoffscreen.c new file mode 100644 index 0000000..f40741a --- /dev/null +++ b/tests/testoffscreen.c @@ -0,0 +1,291 @@ +#undef GTK_DISABLE_DEPRECATED + +#include +#include +#include "gtkoffscreenbox.h" + + +static void +combo_changed_cb (GtkWidget *combo, + gpointer data) +{ + GtkWidget *label = GTK_WIDGET (data); + gint active; + + active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); + + gtk_label_set_ellipsize (GTK_LABEL (label), (PangoEllipsizeMode)active); +} + +gboolean +layout_expose_handler (GtkWidget *widget, GdkEventExpose *event) +{ + GtkLayout *layout; + + gint i,j; + gint imin, imax, jmin, jmax; + + layout = GTK_LAYOUT (widget); + + if (event->window != layout->bin_window) + return FALSE; + + imin = (event->area.x) / 10; + imax = (event->area.x + event->area.width + 9) / 10; + + jmin = (event->area.y) / 10; + jmax = (event->area.y + event->area.height + 9) / 10; + + for (i=imin; ibin_window, + widget->style->black_gc, + TRUE, + 10*i, 10*j, + 1+i%10, 1+j%10); + + return FALSE; +} + +static gboolean +scroll_layout (gpointer data) +{ + GtkWidget *layout = data; + GtkAdjustment *adj; + + adj = gtk_layout_get_hadjustment (GTK_LAYOUT (layout)); + gtk_adjustment_set_value (adj, + gtk_adjustment_get_value (adj) + 5.0); + return TRUE; +} + +static guint layout_timeout; + +void create_layout (GtkWidget *vbox) +{ + GtkWidget *layout; + GtkWidget *scrolledwindow; + GtkWidget *button; + gchar buf[16]; + gint i, j; + + + scrolledwindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), + GTK_SHADOW_IN); + gtk_scrolled_window_set_placement (GTK_SCROLLED_WINDOW (scrolledwindow), + GTK_CORNER_TOP_RIGHT); + + gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0); + + layout = gtk_layout_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolledwindow), layout); + + /* We set step sizes here since GtkLayout does not set + * them itself. + */ + GTK_LAYOUT (layout)->hadjustment->step_increment = 10.0; + GTK_LAYOUT (layout)->vadjustment->step_increment = 10.0; + + gtk_widget_set_events (layout, GDK_EXPOSURE_MASK); + g_signal_connect (layout, "expose_event", + G_CALLBACK (layout_expose_handler), NULL); + + gtk_layout_set_size (GTK_LAYOUT (layout), 1600, 128000); + + for (i=0 ; i < 16 ; i++) + for (j=0 ; j < 16 ; j++) + { + sprintf(buf, "Button %d, %d", i, j); + if ((i + j) % 2) + button = gtk_button_new_with_label (buf); + else + button = gtk_label_new (buf); + + gtk_layout_put (GTK_LAYOUT (layout), button, + j*100, i*100); + } + + for (i=16; i < 1280; i++) + { + sprintf(buf, "Button %d, %d", i, 0); + if (i % 2) + button = gtk_button_new_with_label (buf); + else + button = gtk_label_new (buf); + + gtk_layout_put (GTK_LAYOUT (layout), button, + 0, i*100); + } + + layout_timeout = g_timeout_add (1000, scroll_layout, layout); +} + +GtkWidget * +create_widgets (void) +{ + GtkWidget *vbox, *hbox, *label, *combo, *entry, *button, *cb; + GtkWidget *sw, *text_view; + GList *cbitems = NULL; + + vbox = gtk_vbox_new (0, FALSE); + + hbox = gtk_hbox_new (0, FALSE); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new ("This label may be ellipsized\nto make it fit."); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + + combo = gtk_combo_box_new_text (); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "NONE"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "START"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "MIDDLE"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "END"); + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0); + gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0); + g_signal_connect (combo, "changed", G_CALLBACK (combo_changed_cb), label); + + entry = gtk_entry_new (); + gtk_entry_set_text (GTK_ENTRY (entry), "an entry - lots of text.... lots of text.... lots of text.... lots of text.... "); + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + + label = gtk_label_new ("Label after entry."); + gtk_label_set_selectable (GTK_LABEL (label), TRUE); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("Button"); + gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0); + + button = gtk_check_button_new_with_mnemonic ("_Check button"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + cb = gtk_combo_new (); + cbitems = g_list_append(cbitems, "item0"); + cbitems = g_list_append(cbitems, "item1 item1"); + cbitems = g_list_append(cbitems, "item2 item2 item2"); + gtk_combo_set_popdown_strings (GTK_COMBO (cb), cbitems); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO(cb)->entry), "hello world ♥ foo"); + gtk_editable_select_region (GTK_EDITABLE (GTK_COMBO(cb)->entry), + 0, -1); + gtk_box_pack_start (GTK_BOX (vbox), cb, TRUE, TRUE, 0); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + text_view = gtk_text_view_new (); + gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (sw), text_view); + + create_layout (vbox); + + return vbox; +} + + +static void +scale_changed (GtkRange *range, + GtkOffscreenBox *offscreen_box) +{ + gtk_offscreen_box_set_angle (offscreen_box, gtk_range_get_value (range)); +} + +static GtkWidget *scale = NULL; + +static void +remove_clicked (GtkButton *button, GtkWidget *widget) +{ + gtk_widget_destroy (widget); + g_source_remove (layout_timeout); + + gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE); + gtk_widget_set_sensitive (scale, FALSE); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window, *widget, *vbox, *button, *widget2, *entry; + GtkWidget *offscreen = NULL, *offscreen2; + gboolean use_offscreen; + + gtk_init (&argc, &argv); + + use_offscreen = argc == 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 300,300); + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + + vbox = gtk_vbox_new (0, FALSE); + gtk_container_add (GTK_CONTAINER (window), vbox); + + scale = gtk_hscale_new_with_range (0, + M_PI * 2, + 0.01); + gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Remove child 2"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + if (use_offscreen) + { + offscreen = gtk_offscreen_box_new (); + + g_signal_connect (scale, "value_changed", + G_CALLBACK (scale_changed), + offscreen); + } + else + offscreen = gtk_vpaned_new (); + + gtk_box_pack_start (GTK_BOX (vbox), offscreen, TRUE, TRUE, 0); + + widget = create_widgets (); + if (use_offscreen) + gtk_offscreen_box_add1 (GTK_OFFSCREEN_BOX (offscreen), + widget); + else + gtk_paned_add1 (GTK_PANED (offscreen), widget); + + widget = create_widgets (); + if (1) + { + widget2 = gtk_button_new_with_label ("Offscreen in offscreen"); + offscreen2 = gtk_offscreen_box_new (); + gtk_offscreen_box_add2 (GTK_OFFSCREEN_BOX (offscreen2), + widget2); + g_signal_connect (scale, "value_changed", G_CALLBACK (scale_changed), offscreen2); + gtk_box_pack_start (GTK_BOX (widget), offscreen2, FALSE, FALSE, 0); + } + + if (use_offscreen) + gtk_offscreen_box_add2 (GTK_OFFSCREEN_BOX (offscreen), + widget); + else + gtk_paned_add2 (GTK_PANED (offscreen), widget); + + gtk_widget_show_all (window); + + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (remove_clicked), widget); + + /* redirect */ + if (0) + { + GtkWidget *redirect_win; + + redirect_win = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (redirect_win), 400,400); + gtk_widget_show (redirect_win); + gtk_widget_realize (redirect_win); + gtk_widget_realize (window); + gdk_window_redirect_to_drawable (window->window, + GDK_DRAWABLE (redirect_win->window), + 0, 0, 0, 0, -1, -1); + } + + gtk_main (); + + return 0; +}