From: Alexander Larsson Date: Mon, 25 May 2009 12:30:01 +0000 (+0200) Subject: Merge branch 'master' into client-side-windows X-Git-Url: http://pileus.org/git/?a=commitdiff_plain;h=7698daf97aced5c22aeeb7bfbf02567b61cebaef;hp=d0f887ddb144a69a85371041d1ad3640ab379ee8;p=~andy%2Fgtk Merge branch 'master' into client-side-windows Conflicts: gdk/x11/gdkwindow-x11.c --- diff --git a/gdk/Makefile.am b/gdk/Makefile.am index 52a5bf046..1e962428b 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -120,6 +120,7 @@ gdk_c_sources = \ gdkintl.h \ gdkkeys.c \ gdkkeyuni.c \ + gdkoffscreenwindow.c \ gdkpango.c \ gdkpixbuf-drawable.c \ gdkpixbuf-render.c \ diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index cfb54c202..44cee62b4 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -69,9 +69,7 @@ gdk_get_use_xshm gdk_set_use_xshm #endif gdk_keyboard_grab -gdk_keyboard_grab_info_libgtk_only gdk_pointer_grab -gdk_pointer_grab_info_libgtk_only #endif #endif @@ -85,6 +83,9 @@ gdk_pointer_is_grabbed gdk_pointer_ungrab gdk_event_send_client_message gdk_event_send_clientmessage_toall +gdk_keyboard_grab_info_libgtk_only +gdk_pointer_grab_info_libgtk_only +gdk_display_pointer_is_grabbed #endif #endif @@ -254,12 +255,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 @@ -466,7 +461,6 @@ gdk_display_get_default_screen gdk_display_get_name gdk_display_get_n_screens gdk_display_get_screen -gdk_display_pointer_is_grabbed gdk_display_pointer_ungrab gdk_display_keyboard_ungrab gdk_display_open @@ -667,10 +661,15 @@ gdk_window_set_back_pixmap gdk_window_set_cursor gdk_window_get_geometry gdk_window_get_origin +gdk_window_get_deskrelative_origin gdk_window_shape_combine_mask gdk_window_shape_combine_region gdk_window_set_child_shapes gdk_window_merge_child_shapes +gdk_window_input_shape_combine_mask +gdk_window_input_shape_combine_region +gdk_window_set_child_input_shapes +gdk_window_merge_child_input_shapes gdk_window_set_static_gravities gdk_window_reparent gdk_window_add_filter @@ -719,6 +718,12 @@ gdk_window_set_composited #endif #endif +#if IN_HEADER(__GDK_WINDOW_H__) +#if IN_FILE(__GDK_OFFSCREEN_WINDOW_C__) +gdk_window_get_offscreen_pixmap +#endif +#endif + #if IN_HEADER(__GDK_WINDOW_H__) #if IN_FILE(__GDK_DND_X11_C__) gdk_window_register_dnd @@ -733,7 +738,6 @@ gdk_window_lookup gdk_window_lookup_for_display #ifndef GDK_DISABLE_DEPRECATED gdk_window_set_hints -gdk_window_get_deskrelative_origin #endif gdk_window_get_type_hint gdk_window_set_type_hint @@ -748,8 +752,6 @@ gdk_window_set_startup_id gdk_window_set_transient_for gdk_window_get_root_origin gdk_window_get_frame_extents -gdk_window_input_shape_combine_mask -gdk_window_input_shape_combine_region gdk_window_set_override_redirect gdk_window_set_accept_focus gdk_window_set_focus_on_map @@ -773,8 +775,6 @@ gdk_window_set_group gdk_window_get_decorations gdk_window_set_decorations gdk_window_set_functions -gdk_window_set_child_input_shapes -gdk_window_merge_child_input_shapes gdk_window_begin_move_drag gdk_window_begin_resize_drag gdk_window_enable_synchronized_configure @@ -925,23 +925,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/gdkcairo.c b/gdk/gdkcairo.c index 6e83f53a3..9d3ce2d64 100644 --- a/gdk/gdkcairo.c +++ b/gdk/gdkcairo.c @@ -50,6 +50,10 @@ gdk_cairo_create (GdkDrawable *drawable) surface = _gdk_drawable_ref_cairo_surface (drawable); cr = cairo_create (surface); + + if (GDK_DRAWABLE_GET_CLASS (drawable)->set_cairo_clip) + GDK_DRAWABLE_GET_CLASS (drawable)->set_cairo_clip (drawable, cr); + cairo_surface_destroy (surface); return cr; diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 9417c4e94..ae9c8f92d 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 = { @@ -434,6 +444,25 @@ _gdk_get_sm_client_id (void) return gdk_sm_client_id; } +void +_gdk_display_enable_motion_hints (GdkDisplay *display) +{ + gulong serial; + + if (display->pointer_info.motion_hint_serial != 0) + { + serial = _gdk_windowing_window_get_next_serial (display); + /* We might not actually generate the next request, so + make sure this triggers always, this may cause it to + trigger slightly to early, but this is just a hint + anyway. */ + if (serial > 0) + serial--; + if (serial < display->pointer_info.motion_hint_serial) + display->pointer_info.motion_hint_serial = serial; + } +} + /** * gdk_display_get_pointer: * @display: a #GdkDisplay @@ -473,6 +502,80 @@ 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; + gint x, y; + + window = _gdk_windowing_window_at_pointer (display, &x, &y, NULL); + + /* This might need corrections, as the native window returned + may contain client side children */ + if (window) + { + double xx, yy; + + window = _gdk_window_find_descendant_at (window, + x, y, + &xx, &yy); + x = floor (xx + 0.5); + y = floor (yy + 0.5); + } + + *win_x = x; + *win_y = y; + + return window; +} + +static GdkWindow * +gdk_window_real_window_get_pointer (GdkDisplay *display, + GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowObject *private; + GdkWindow *pointer_window; + gint tmpx, tmpy; + GdkModifierType tmp_mask; + + private = (GdkWindowObject *) window; + + pointer_window = _gdk_windowing_window_get_pointer (display, + window, + &tmpx, &tmpy, + mask); + /* We got the coords on the impl, conver to the window */ + tmpx -= private->abs_x; + tmpy -= private->abs_y; + + if (x) + *x = tmpx; + if (y) + *y = tmpy; + + /* We need to recalculate the true child window with the pointer in it + due to possible client side child windows */ + if (pointer_window != NULL) + { + /* First get the pointer coords relative to pointer_window */ + _gdk_windowing_window_get_pointer (display, + pointer_window, + &tmpx, &tmpy, + &tmp_mask); + /* Then convert that to a client side window */ + pointer_window = _gdk_window_find_descendant_at (pointer_window, + tmpx, tmpy, + NULL, NULL); + } + + return pointer_window; +} + /** * gdk_display_get_window_at_pointer: * @display: a #GdkDisplay @@ -586,8 +689,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* @@ -595,8 +698,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); } /** @@ -632,5 +735,568 @@ gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks) return (GdkPointerHooks *)result; } +static void +generate_grab_broken_event (GdkWindow *window, + gboolean keyboard, + gboolean implicit, + GdkWindow *grab_window) +{ + g_return_if_fail (window != NULL); + + if (!GDK_WINDOW_DESTROYED (window)) + { + GdkEvent event; + event.type = GDK_GRAB_BROKEN; + event.grab_broken.window = window; + event.grab_broken.send_event = 0; + event.grab_broken.keyboard = keyboard; + event.grab_broken.implicit = implicit; + event.grab_broken.grab_window = grab_window; + gdk_event_put (&event); + } +} + +GdkPointerGrabInfo * +_gdk_display_get_last_pointer_grab (GdkDisplay *display) +{ + GList *l; + + l = display->pointer_grabs; + + if (l == NULL) + return NULL; + + while (l->next != NULL) + l = l->next; + + return (GdkPointerGrabInfo *)l->data; +} + + +GdkPointerGrabInfo * +_gdk_display_add_pointer_grab (GdkDisplay *display, + GdkWindow *window, + GdkWindow *native_window, + gboolean owner_events, + GdkEventMask event_mask, + unsigned long serial_start, + guint32 time, + gboolean implicit) +{ + GdkPointerGrabInfo *info, *other_info; + GList *l; + + info = g_new0 (GdkPointerGrabInfo, 1); + + info->window = g_object_ref (window); + info->native_window = g_object_ref (native_window); + info->serial_start = serial_start; + info->serial_end = G_MAXULONG; + info->owner_events = owner_events; + info->event_mask = event_mask; + info->time = time; + info->implicit = implicit; + + /* Find the first grab that has a larger start time (if any) and insert + * before that. I.E we insert after already existing grabs with same + * start time */ + for (l = display->pointer_grabs; l != NULL; l = l->next) + { + other_info = l->data; + + if (info->serial_start < other_info->serial_start) + break; + } + display->pointer_grabs = + g_list_insert_before (display->pointer_grabs, l, info); + + /* Make sure the new grab end before next grab */ + if (l) + { + other_info = l->data; + info->serial_end = other_info->serial_start; + } + + /* Find any previous grab and update its end time */ + l = g_list_find (display->pointer_grabs, info); + l = l->prev; + if (l) + { + other_info = l->data; + other_info->serial_end = serial_start; + } + + return info; +} + +static void +free_pointer_grab (GdkPointerGrabInfo *info) +{ + g_object_unref (info->window); + g_object_unref (info->native_window); + g_free (info); +} + +/* _gdk_syntesize_crossing_events only works inside one toplevel. + This function splits things into two calls if needed, converting the + coordinates to the right toplevel */ +static void +synthesize_crossing_events (GdkDisplay *display, + GdkWindow *src_window, + GdkWindow *dest_window, + GdkCrossingMode crossing_mode, + guint32 time, + gulong serial) +{ + GdkWindow *src_toplevel, *dest_toplevel; + GdkModifierType state; + int x, y; + + if (src_window) + src_toplevel = gdk_window_get_toplevel (src_window); + else + src_toplevel = NULL; + if (dest_window) + dest_toplevel = gdk_window_get_toplevel (dest_window); + else + dest_toplevel = NULL; + + if (src_toplevel == NULL && dest_toplevel == NULL) + return; + + if (src_toplevel == NULL || + src_toplevel == dest_toplevel) + { + /* Same toplevels */ + _gdk_windowing_window_get_pointer (display, + dest_toplevel, + &x, &y, &state); + _gdk_syntesize_crossing_events (display, + src_window, + dest_window, + crossing_mode, + x, y, state, + time, + NULL, + serial); + } + else if (dest_toplevel == NULL) + { + _gdk_windowing_window_get_pointer (display, + src_toplevel, + &x, &y, &state); + _gdk_syntesize_crossing_events (display, + src_window, + NULL, + crossing_mode, + x, y, state, + time, + NULL, + serial); + } + else + { + /* Different toplevels */ + _gdk_windowing_window_get_pointer (display, + src_toplevel, + &x, &y, &state); + _gdk_syntesize_crossing_events (display, + src_window, + NULL, + crossing_mode, + x, y, state, + time, + NULL, + serial); + _gdk_windowing_window_get_pointer (display, + dest_toplevel, + &x, &y, &state); + _gdk_syntesize_crossing_events (display, + NULL, + dest_window, + crossing_mode, + x, y, state, + time, + NULL, + serial); + } +} + + +static void +switch_to_pointer_grab (GdkDisplay *display, + GdkPointerGrabInfo *grab, + GdkPointerGrabInfo *last_grab, + guint32 time, + gulong serial) +{ + GdkWindow *src_window, *pointer_window; + GdkWindowObject *w; + GList *old_grabs; + GdkModifierType state; + int x, y; + + /* Temporarily unset pointer to make sure we send the crossing events below */ + old_grabs = display->pointer_grabs; + display->pointer_grabs = NULL; + + if (grab) + { + /* New grab is in effect */ + + /* We need to generate crossing events for the grab. + * However, there are never any crossing events for implicit grabs + * TODO: ... Actually, this could happen if the pointer window + * doesn't have button mask so a parent gets the event... + */ + if (!grab->implicit) + { + /* We send GRAB crossing events from the window under the pointer to the + grab window. Except if there is an old grab then we start from that */ + if (last_grab) + src_window = last_grab->window; + else + src_window = display->pointer_info.window_under_pointer; + + if (src_window != grab->window) + { + synthesize_crossing_events (display, + src_window, grab->window, + GDK_CROSSING_GRAB, time, serial); + } + + /* !owner_event Grabbing a window that we're not inside, current status is + now NULL (i.e. outside grabbed window) */ + if (!grab->owner_events && display->pointer_info.window_under_pointer != grab->window) + _gdk_display_set_window_under_pointer (display, NULL); + } + + grab->activated = TRUE; + } + else if (last_grab) + { + pointer_window = _gdk_windowing_window_at_pointer (display, &x, &y, &state); + if (pointer_window != NULL && + (GDK_WINDOW_DESTROYED (pointer_window) || + GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT || + GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN)) + pointer_window = NULL; + + /* We force checked what window we're in, so we need to + * update the toplevel_under_pointer info, as that won't get told of + * this change. + */ + if (display->pointer_info.toplevel_under_pointer) + g_object_unref (display->pointer_info.toplevel_under_pointer); + display->pointer_info.toplevel_under_pointer = NULL; + + if (pointer_window) + { + /* Convert to toplevel */ + w = (GdkWindowObject *)pointer_window; + while (/*w->parent != NULL && */ + w->parent->window_type != GDK_WINDOW_ROOT) + { + x += w->x; + y += w->y; + w = w->parent; + } + + /* w is now toplevel and x,y in toplevel coords */ + display->pointer_info.toplevel_under_pointer = g_object_ref (w); + + /* Find (possibly virtual) child window */ + pointer_window = + _gdk_window_find_descendant_at ((GdkWindow *)w, + x, y, + NULL, NULL); + } + + if (pointer_window != last_grab->window) + synthesize_crossing_events (display, + last_grab->window, pointer_window, + GDK_CROSSING_UNGRAB, time, serial); + + /* We're now ungrabbed, update the window_under_pointer */ + _gdk_display_set_window_under_pointer (display, pointer_window); + + if (last_grab->implicit_ungrab) + generate_grab_broken_event (last_grab->window, + FALSE, TRUE, + NULL); + } + + display->pointer_grabs = old_grabs; + +} + +void +_gdk_display_pointer_grab_update (GdkDisplay *display, + gulong current_serial) +{ + GdkPointerGrabInfo *current_grab, *next_grab; + guint32 time; + + time = display->last_event_time; + + while (display->pointer_grabs != NULL) + { + current_grab = display->pointer_grabs->data; + + if (current_grab->serial_start > current_serial) + return; /* Hasn't started yet */ + + if (current_grab->serial_end > current_serial || + (current_grab->serial_end == current_serial && + current_grab->grab_one_pointer_release_event)) + { + /* This one hasn't ended yet. + its the currently active one or scheduled to be active */ + + if (!current_grab->activated) + switch_to_pointer_grab (display, current_grab, NULL, time, current_serial); + + break; + } + + + next_grab = NULL; + if (display->pointer_grabs->next) + { + /* This is the next active grab */ + next_grab = display->pointer_grabs->next->data; + + if (next_grab->serial_start > current_serial) + next_grab = NULL; /* Actually its not yet active */ + } + + if (next_grab == NULL || + current_grab->window != next_grab->window) + generate_grab_broken_event (GDK_WINDOW (current_grab->window), + FALSE, current_grab->implicit, + next_grab? next_grab->window : NULL); + + + /* Remove old grab */ + display->pointer_grabs = + g_list_delete_link (display->pointer_grabs, + display->pointer_grabs); + + switch_to_pointer_grab (display, + next_grab, current_grab, + time, current_serial); + + free_pointer_grab (current_grab); + } +} + +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 GList * +find_pointer_grab (GdkDisplay *display, + gulong serial) +{ + GdkPointerGrabInfo *grab; + GList *l; + + for (l = display->pointer_grabs; l != NULL; l = l->next) + { + grab = l->data; + + if (serial >= grab->serial_start && serial < grab->serial_end) + return l; + } + + return NULL; +} + + + +GdkPointerGrabInfo * +_gdk_display_has_pointer_grab (GdkDisplay *display, + gulong serial) +{ + GList *l; + + l = find_pointer_grab (display, serial); + if (l) + return l->data; + + return NULL; +} + +/* Returns true if last grab was ended */ +gboolean +_gdk_display_end_pointer_grab (GdkDisplay *display, + gulong serial, + GdkWindow *if_child, + gboolean implicit) +{ + GdkPointerGrabInfo *grab; + GList *l; + + l = find_pointer_grab (display, serial); + + if (l == NULL) + return FALSE; + + grab = l->data; + if (grab && + (if_child == NULL || + is_parent_of (grab->window, if_child))) + { + grab->serial_end = serial; + grab->implicit_ungrab = implicit; + return l->next == NULL; + } + + return FALSE; +} + +void +_gdk_display_set_has_keyboard_grab (GdkDisplay *display, + GdkWindow *window, + GdkWindow *native_window, + gboolean owner_events, + unsigned long serial, + guint32 time) +{ + if (display->keyboard_grab.window != NULL && + display->keyboard_grab.window != window) + generate_grab_broken_event (display->keyboard_grab.window, + TRUE, FALSE, window); + + display->keyboard_grab.window = window; + display->keyboard_grab.native_window = native_window; + display->keyboard_grab.owner_events = owner_events; + display->keyboard_grab.serial = serial; + display->keyboard_grab.time = time; +} + +void +_gdk_display_unset_has_keyboard_grab (GdkDisplay *display, + gboolean implicit) +{ + if (implicit) + generate_grab_broken_event (display->keyboard_grab.window, + TRUE, FALSE, NULL); + display->keyboard_grab.window = NULL; +} + +/** + * gdk_keyboard_grab_info_libgtk_only: + * @display: the display for which to get the grab information + * @grab_window: location to store current grab window + * @owner_events: location to store boolean indicating whether + * the @owner_events flag to gdk_keyboard_grab() was %TRUE. + * + * Determines information about the current keyboard grab. + * This is not public API and must not be used by applications. + * + * Return value: %TRUE if this application currently has the + * keyboard grabbed. + **/ +gboolean +gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display, + GdkWindow **grab_window, + gboolean *owner_events) +{ + g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE); + + if (display->keyboard_grab.window) + { + if (grab_window) + *grab_window = display->keyboard_grab.window; + if (owner_events) + *owner_events = display->keyboard_grab.owner_events; + + return TRUE; + } + else + return FALSE; +} + +/** + * gdk_pointer_grab_info_libgtk_only: + * @display: the #GdkDisplay for which to get the grab information + * @grab_window: location to store current grab window + * @owner_events: location to store boolean indicating whether + * the @owner_events flag to gdk_pointer_grab() was %TRUE. + * + * Determines information about the current pointer grab. + * This is not public API and must not be used by applications. + * + * Return value: %TRUE if this application currently has the + * pointer grabbed. + **/ +gboolean +gdk_pointer_grab_info_libgtk_only (GdkDisplay *display, + GdkWindow **grab_window, + gboolean *owner_events) +{ + GdkPointerGrabInfo *info; + + g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE); + + /* What we're interested in is the steady state (ie last grab), + because we're interested e.g. if we grabbed so that we + can ungrab, even if our grab is not active just yet. */ + info = _gdk_display_get_last_pointer_grab (display); + + if (info) + { + if (grab_window) + *grab_window = info->window; + if (owner_events) + *owner_events = info->owner_events; + + return TRUE; + } + else + return FALSE; +} + + +/** + * gdk_display_pointer_is_grabbed: + * @display: a #GdkDisplay + * + * Test if the pointer is grabbed. + * + * Returns: %TRUE if an active X pointer grab is in effect + * + * Since: 2.2 + */ +gboolean +gdk_display_pointer_is_grabbed (GdkDisplay *display) +{ + GdkPointerGrabInfo *info; + + g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE); + + /* What we're interested in is the steady state (ie last grab), + because we're interested e.g. if we grabbed so that we + can ungrab, even if our grab is not active just yet. */ + info = _gdk_display_get_last_pointer_grab (display); + + return (info && !info->implicit); +} + #define __GDK_DISPLAY_C__ #include "gdkaliasdef.c" diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h index 04bf1831b..3c7bde322 100644 --- a/gdk/gdkdisplay.h +++ b/gdk/gdkdisplay.h @@ -43,6 +43,33 @@ typedef struct _GdkDisplayPointerHooks GdkDisplayPointerHooks; #define GDK_IS_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DISPLAY)) #define GDK_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DISPLAY, GdkDisplayClass)) +/* Tracks information about the keyboard grab on this display */ +typedef struct +{ + GdkWindow *window; + GdkWindow *native_window; + gulong serial; + gboolean owner_events; + guint32 time; +} GdkKeyboardGrabInfo; + +/* Tracks information about which window and position the pointer last was in. + * This is useful when we need to synthesize events later. + * Note that we track toplevel_under_pointer using enter/leave events, + * so in the case of a grab, either with owner_events==FALSE or with the + * pointer in no clients window the x/y coordinates may actually be outside + * the window. + */ +typedef struct +{ + GdkWindow *toplevel_under_pointer; /* The toplevel window with mouse inside, tracked via native events */ + GdkWindow *window_under_pointer; /* The window that last got sent a normal enter event */ + gdouble toplevel_x, toplevel_y; + guint32 state; + guint32 button; + gulong motion_hint_serial; /* 0 == didn't deliver hinted motion event */ +} GdkPointerWindowInfo; + struct _GdkDisplay { GObject parent_instance; @@ -68,6 +95,13 @@ struct _GdkDisplay guint double_click_distance; /* Maximum distance between clicks in pixels */ gint button_x[2]; /* The last 2 button click positions. */ gint button_y[2]; + + GList *pointer_grabs; + GdkKeyboardGrabInfo keyboard_grab; + GdkPointerWindowInfo pointer_info; + + /* Last reported event time from server */ + guint32 last_event_time; }; struct _GdkDisplayClass diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c index 81e6e0839..8c5d4227a 100644 --- a/gdk/gdkdraw.c +++ b/gdk/gdkdraw.c @@ -150,7 +150,8 @@ gdk_drawable_get_size (GdkDrawable *drawable, { g_return_if_fail (GDK_IS_DRAWABLE (drawable)); - GDK_DRAWABLE_GET_CLASS (drawable)->get_size (drawable, width, height); + if (GDK_DRAWABLE_GET_CLASS (drawable)->get_size != NULL) + GDK_DRAWABLE_GET_CLASS (drawable)->get_size (drawable, width, height); } /** @@ -623,7 +624,7 @@ gdk_draw_drawable (GdkDrawable *drawable, gint width, gint height) { - GdkDrawable *composite; + GdkDrawable *composite, *composite_impl; gint composite_x_offset = 0; gint composite_y_offset = 0; @@ -652,8 +653,21 @@ gdk_draw_drawable (GdkDrawable *drawable, &composite_x_offset, &composite_y_offset); + /* The draw_drawable call below is will recurse into gdk_draw_drawable again, + * specifying the right impl for the destination. This means the composite + * we got here will be fed to get_composite_drawable again, which is a problem + * for window as that causes double the composite offset. Avoid this by passing + * in the impl directly. + */ + if (GDK_IS_WINDOW (composite)) + composite_impl = GDK_WINDOW_OBJECT (src)->impl; + else + composite_impl = composite; + + /* TODO: For non-native windows this may copy stuff from other overlapping + windows. We should clip that and clear that area in the destination instead. */ - GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable (drawable, gc, composite, + GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable (drawable, gc, composite_impl, xsrc - composite_x_offset, ysrc - composite_y_offset, xdest, ydest, @@ -871,7 +885,7 @@ real_draw_glyphs (GdkDrawable *drawable, cairo_t *cr; cr = gdk_cairo_create (drawable); - _gdk_gc_update_context (gc, cr, NULL, NULL, TRUE); + _gdk_gc_update_context (gc, cr, NULL, NULL, TRUE, drawable); if (matrix) { @@ -995,7 +1009,7 @@ gdk_draw_trapezoids (GdkDrawable *drawable, g_return_if_fail (n_trapezoids == 0 || trapezoids != NULL); cr = gdk_cairo_create (drawable); - _gdk_gc_update_context (gc, cr, NULL, NULL, TRUE); + _gdk_gc_update_context (gc, cr, NULL, NULL, TRUE, drawable); for (i = 0; i < n_trapezoids; i++) { @@ -1185,7 +1199,7 @@ 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_composite_drawable (GdkDrawable *drawable, gint x, gint y, @@ -1771,5 +1785,81 @@ _gdk_drawable_get_scratch_gc (GdkDrawable *drawable, } } +/** + * _gdk_drawable_get_subwindow_scratch_gc: + * @drawable: A #GdkDrawable + * + * Returns a #GdkGC suitable for drawing on @drawable. The #GdkGC has + * the standard values for @drawable, except for the graphics_exposures + * field which is %TRUE and the subwindow mode which is %GDK_INCLUDE_INFERIORS. + * + * The foreground color of the returned #GdkGC is undefined. The #GdkGC + * must not be altered in any way, except to change its foreground color. + * + * Return value: A #GdkGC suitable for drawing on @drawable + * + * Since: 2.18 + **/ +GdkGC * +_gdk_drawable_get_subwindow_scratch_gc (GdkDrawable *drawable) +{ + GdkScreen *screen; + gint depth; + + g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL); + + screen = gdk_drawable_get_screen (drawable); + + g_return_val_if_fail (!screen->closed, NULL); + + depth = gdk_drawable_get_depth (drawable) - 1; + + if (!screen->subwindow_gcs[depth]) + { + GdkGCValues values; + GdkGCValuesMask mask; + + values.graphics_exposures = TRUE; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + mask = GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW; + + screen->subwindow_gcs[depth] = + gdk_gc_new_with_values (drawable, &values, mask); + } + + return screen->subwindow_gcs[depth]; +} + + +/** + * _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); + + if (GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable) + return GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable (drawable); + + return drawable; +} + +cairo_surface_t * +_gdk_drawable_create_cairo_surface (GdkDrawable *drawable, + int width, + int height) +{ + return GDK_DRAWABLE_GET_CLASS (drawable)->create_cairo_surface (drawable, + width, height); +} + + #define __GDK_DRAW_C__ #include "gdkaliasdef.c" diff --git a/gdk/gdkdrawable.h b/gdk/gdkdrawable.h index 508bf86fc..50904fc2e 100644 --- a/gdk/gdkdrawable.h +++ b/gdk/gdkdrawable.h @@ -200,10 +200,16 @@ struct _GdkDrawableClass cairo_surface_t *(*ref_cairo_surface) (GdkDrawable *drawable); + GdkDrawable *(*get_source_drawable) (GdkDrawable *drawable); + + void (*set_cairo_clip) (GdkDrawable *drawable, + cairo_t *cr); + + cairo_surface_t * (*create_cairo_surface) (GdkDrawable *drawable, + int width, + int height); + /* Padding for future expansion */ - void (*_gdk_reserved4) (void); - void (*_gdk_reserved5) (void); - void (*_gdk_reserved6) (void); void (*_gdk_reserved7) (void); void (*_gdk_reserved9) (void); void (*_gdk_reserved10) (void); diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 24a29a1fd..3af4195cc 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -120,6 +120,63 @@ _gdk_event_queue_append (GdkDisplay *display, return display->queued_tail; } +/** + * _gdk_event_queue_insert_after: + * @display: a #GdkDisplay + * @sibling: 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_insert_after (GdkDisplay *display, + GdkEvent *sibling, + GdkEvent *event) +{ + GList *prev = g_list_find (display->queued_events, sibling); + if (prev && prev->next) + { + display->queued_events = g_list_insert_before (display->queued_events, prev->next, event); + return prev->next; + } + else + return _gdk_event_queue_append (display, event); +} + +/** + * _gdk_event_queue_insert_after: + * @display: a #GdkDisplay + * @sibling: Append after this event. + * @event: Event to append. + * + * Appends an event before 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_insert_before (GdkDisplay *display, + GdkEvent *sibling, + GdkEvent *event) +{ + GList *next = g_list_find (display->queued_events, sibling); + if (next) + { + display->queued_events = g_list_insert_before (display->queued_events, next, event); + return next->prev; + } + else + return _gdk_event_queue_append (display, event); +} + + /** * _gdk_event_queue_remove_link: * @display: a #GdkDisplay @@ -575,6 +632,7 @@ gdk_event_get_time (const GdkEvent *event) case GDK_SETTING: case GDK_OWNER_CHANGE: case GDK_GRAB_BROKEN: + case GDK_EVENT_LAST: /* return current time */ break; } @@ -653,6 +711,7 @@ gdk_event_get_state (const GdkEvent *event, case GDK_SETTING: case GDK_OWNER_CHANGE: case GDK_GRAB_BROKEN: + case GDK_EVENT_LAST: /* no state field */ break; } @@ -884,9 +943,17 @@ gdk_event_get_axis (const GdkEvent *event, void gdk_event_request_motions (const GdkEventMotion *event) { + GdkDisplay *display; + g_return_if_fail (event != NULL); + if (event->type == GDK_MOTION_NOTIFY && event->is_hint) - gdk_device_get_state (event->device, event->window, NULL, NULL); + { + gdk_device_get_state (event->device, event->window, NULL, NULL); + + display = gdk_drawable_get_display (event->window); + _gdk_display_enable_motion_hints (display); + } } /** @@ -1101,13 +1168,16 @@ 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); } void diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h index e64acb7b9..5d8e28915 100644 --- a/gdk/gdkevents.h +++ b/gdk/gdkevents.h @@ -151,7 +151,8 @@ typedef enum GDK_SETTING = 33, GDK_OWNER_CHANGE = 34, GDK_GRAB_BROKEN = 35, - GDK_DAMAGE = 36 + GDK_DAMAGE = 36, + GDK_EVENT_LAST /* helper variable for decls */ } GdkEventType; /* Event masks. (Used to select what types of events a window diff --git a/gdk/gdkgc.c b/gdk/gdkgc.c index f3389c70e..f3ac96820 100644 --- a/gdk/gdkgc.c +++ b/gdk/gdkgc.c @@ -43,9 +43,20 @@ struct _GdkGCPrivate { GdkRegion *clip_region; + guint32 region_tag_applied; + int region_tag_offset_x; + int region_tag_offset_y; + + GdkRegion *old_clip_region; + GdkPixmap *old_clip_mask; + + GdkSubwindowMode subwindow_mode; + GdkFill fill; GdkBitmap *stipple; GdkPixmap *tile; + + GdkPixmap *clip_mask; guint32 fg_pixel; guint32 bg_pixel; @@ -150,6 +161,8 @@ _gdk_gc_init (GdkGC *gc, gc->clip_x_origin = values->clip_x_origin; if (values_mask & GDK_GC_CLIP_Y_ORIGIN) gc->clip_y_origin = values->clip_y_origin; + if ((values_mask & GDK_GC_CLIP_MASK) && values->clip_mask) + priv->clip_mask = g_object_ref (values->clip_mask); if (values_mask & GDK_GC_TS_X_ORIGIN) gc->ts_x_origin = values->ts_x_origin; if (values_mask & GDK_GC_TS_Y_ORIGIN) @@ -172,6 +185,8 @@ _gdk_gc_init (GdkGC *gc, priv->fg_pixel = values->foreground.pixel; if (values_mask & GDK_GC_BACKGROUND) priv->bg_pixel = values->background.pixel; + if (values_mask & GDK_GC_SUBWINDOW) + priv->subwindow_mode = values->subwindow_mode; gc->colormap = gdk_drawable_get_colormap (drawable); if (gc->colormap) @@ -183,9 +198,15 @@ gdk_gc_finalize (GObject *object) { GdkGC *gc = GDK_GC (object); GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); - + if (priv->clip_region) gdk_region_destroy (priv->clip_region); + if (priv->old_clip_region) + gdk_region_destroy (priv->old_clip_region); + if (priv->clip_mask) + g_object_unref (priv->clip_mask); + if (priv->old_clip_mask) + g_object_unref (priv->old_clip_mask); if (gc->colormap) g_object_unref (gc->colormap); if (priv->tile) @@ -269,6 +290,12 @@ gdk_gc_set_values (GdkGC *gc, priv = GDK_GC_GET_PRIVATE (gc); + if ((values_mask & GDK_GC_CLIP_X_ORIGIN) || + (values_mask & GDK_GC_CLIP_Y_ORIGIN) || + (values_mask & GDK_GC_CLIP_MASK) || + (values_mask & GDK_GC_SUBWINDOW)) + _gdk_gc_remove_drawable_clip (gc); + if (values_mask & GDK_GC_CLIP_X_ORIGIN) gc->clip_x_origin = values->clip_x_origin; if (values_mask & GDK_GC_CLIP_Y_ORIGIN) @@ -279,6 +306,14 @@ gdk_gc_set_values (GdkGC *gc, gc->ts_y_origin = values->ts_y_origin; if (values_mask & GDK_GC_CLIP_MASK) { + if (priv->clip_mask) + { + g_object_unref (priv->clip_mask); + priv->clip_mask = NULL; + } + if (values->clip_mask) + priv->clip_mask = g_object_ref (values->clip_mask); + if (priv->clip_region) { gdk_region_destroy (priv->clip_region); @@ -313,6 +348,8 @@ gdk_gc_set_values (GdkGC *gc, priv->fg_pixel = values->foreground.pixel; if (values_mask & GDK_GC_BACKGROUND) priv->bg_pixel = values->background.pixel; + if (values_mask & GDK_GC_SUBWINDOW) + priv->subwindow_mode = values->subwindow_mode; GDK_GC_GET_CLASS (gc)->set_values (gc, values, values_mask); } @@ -542,18 +579,121 @@ gdk_gc_set_clip_mask (GdkGC *gc, gdk_gc_set_values (gc, &values, GDK_GC_CLIP_MASK); } +/* Takes ownership of passed in region */ static void -_gdk_gc_set_clip_region_internal (GdkGC *gc, - GdkRegion *region) +_gdk_gc_set_clip_region_real (GdkGC *gc, + GdkRegion *region, + gboolean reset_origin) { GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + if (priv->clip_mask) + { + g_object_unref (priv->clip_mask); + priv->clip_mask = NULL; + } + if (priv->clip_region) gdk_region_destroy (priv->clip_region); priv->clip_region = region; - _gdk_windowing_gc_set_clip_region (gc, region); + _gdk_windowing_gc_set_clip_region (gc, region, reset_origin); +} + +/* Doesn't copy region, allows not to reset origin */ +void +_gdk_gc_set_clip_region_internal (GdkGC *gc, + GdkRegion *region, + gboolean reset_origin) +{ + _gdk_gc_remove_drawable_clip (gc); + _gdk_gc_set_clip_region_real (gc, region, reset_origin); +} + + +/* returns old clip region */ +void +_gdk_gc_add_drawable_clip (GdkGC *gc, + guint32 region_tag, + GdkRegion *region, + int offset_x, + int offset_y) +{ + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + + if (priv->region_tag_applied == region_tag && + offset_x == priv->region_tag_offset_x && + offset_y == priv->region_tag_offset_y) + return; /* Already appied this drawable region */ + + if (priv->region_tag_applied) + _gdk_gc_remove_drawable_clip (gc); + + region = gdk_region_copy (region); + if (offset_x != 0 || offset_y != 0) + gdk_region_offset (region, offset_x, offset_y); + + if (priv->clip_mask) + { + int w, h; + GdkPixmap *new_mask; + GdkGC *tmp_gc; + GdkColor black = {0, 0, 0, 0}; + + priv->old_clip_mask = g_object_ref (priv->clip_mask); + gdk_drawable_get_size (priv->old_clip_mask, &w, &h); + + new_mask = gdk_pixmap_new (priv->old_clip_mask, w, h, -1); + tmp_gc = _gdk_drawable_get_scratch_gc ((GdkDrawable *)new_mask, FALSE); + + gdk_gc_set_foreground (tmp_gc, &black); + gdk_draw_rectangle (new_mask, tmp_gc, TRUE, 0, 0, -1, -1); + _gdk_gc_set_clip_region_internal (tmp_gc, region, TRUE); /* Takes ownership of region */ + gdk_draw_drawable (new_mask, + tmp_gc, + priv->old_clip_mask, + 0, 0, + 0, 0, + -1, -1); + gdk_gc_set_clip_region (tmp_gc, NULL); + gdk_gc_set_clip_mask (gc, new_mask); + } + else + { + priv->old_clip_region = priv->clip_region; + priv->clip_region = region; + if (priv->old_clip_region) + gdk_region_intersect (region, priv->old_clip_region); + + _gdk_windowing_gc_set_clip_region (gc, priv->clip_region, FALSE); + } + + priv->region_tag_applied = region_tag; + priv->region_tag_offset_x = offset_x; + priv->region_tag_offset_y = offset_y; +} + +void +_gdk_gc_remove_drawable_clip (GdkGC *gc) +{ + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + + if (priv->region_tag_applied) + { + priv->region_tag_applied = 0; + if (priv->old_clip_mask) + { + gdk_gc_set_clip_mask (gc, priv->old_clip_mask); + g_object_unref (priv->old_clip_mask); + priv->old_clip_mask = NULL; + } + else + { + _gdk_gc_set_clip_region_real (gc, priv->old_clip_region, FALSE); + priv->old_clip_region = NULL; + } + } } /** @@ -573,12 +713,14 @@ gdk_gc_set_clip_rectangle (GdkGC *gc, g_return_if_fail (GDK_IS_GC (gc)); + _gdk_gc_remove_drawable_clip (gc); + if (rectangle) region = gdk_region_rectangle (rectangle); else region = NULL; - _gdk_gc_set_clip_region_internal (gc, region); + _gdk_gc_set_clip_region_real (gc, region, TRUE); } /** @@ -598,12 +740,14 @@ gdk_gc_set_clip_region (GdkGC *gc, g_return_if_fail (GDK_IS_GC (gc)); + _gdk_gc_remove_drawable_clip (gc); + if (region) copy = gdk_region_copy (region); else copy = NULL; - _gdk_gc_set_clip_region_internal (gc, copy); + _gdk_gc_set_clip_region_real (gc, copy, TRUE); } /** @@ -723,13 +867,27 @@ gdk_gc_set_subwindow (GdkGC *gc, GdkSubwindowMode mode) { GdkGCValues values; + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); g_return_if_fail (GDK_IS_GC (gc)); + /* This could get called a lot to reset the subwindow mode in + the client side clipping, so bail out early */ + if (priv->subwindow_mode == mode) + return; + values.subwindow_mode = mode; gdk_gc_set_values (gc, &values, GDK_GC_SUBWINDOW); } +GdkSubwindowMode +_gdk_gc_get_subwindow (GdkGC *gc) +{ + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + + return priv->subwindow_mode; +} + /** * gdk_gc_set_exposures: * @gc: a #GdkGC. @@ -890,6 +1048,26 @@ gdk_gc_copy (GdkGC *dst_gc, dst_priv->clip_region = gdk_region_copy (src_priv->clip_region); else dst_priv->clip_region = NULL; + + dst_priv->region_tag_applied = src_priv->region_tag_applied; + + if (dst_priv->old_clip_region) + gdk_region_destroy (dst_priv->old_clip_region); + + if (src_priv->old_clip_region) + dst_priv->old_clip_region = gdk_region_copy (src_priv->old_clip_region); + else + dst_priv->old_clip_region = NULL; + + if (src_priv->clip_mask) + dst_priv->clip_mask = g_object_ref (src_priv->clip_mask); + else + dst_priv->clip_mask = NULL; + + if (src_priv->old_clip_mask) + dst_priv->old_clip_mask = g_object_ref (src_priv->old_clip_mask); + else + dst_priv->old_clip_mask = NULL; dst_priv->fill = src_priv->fill; @@ -907,6 +1085,7 @@ gdk_gc_copy (GdkGC *dst_gc, dst_priv->fg_pixel = src_priv->fg_pixel; dst_priv->bg_pixel = src_priv->bg_pixel; + dst_priv->subwindow_mode = src_priv->subwindow_mode; } /** @@ -1117,6 +1296,8 @@ gc_get_background (GdkGC *gc, * the fill mode will be forced to %GDK_STIPPLED * @gc_changed: pass %FALSE if the @gc has not changed since the * last call to this function + * @target_drawable: The drawable you're drawing in. If passed in + * this is used for client side window clip emulation. * * Set the attributes of a cairo context to match those of a #GdkGC * as far as possible. Some aspects of a #GdkGC, such as clip masks @@ -1127,7 +1308,8 @@ _gdk_gc_update_context (GdkGC *gc, cairo_t *cr, const GdkColor *override_foreground, GdkBitmap *override_stipple, - gboolean gc_changed) + gboolean gc_changed, + GdkDrawable *target_drawable) { GdkGCPrivate *priv; GdkFill fill; @@ -1246,6 +1428,10 @@ _gdk_gc_update_context (GdkGC *gc, cairo_clip (cr); } + + /* The reset above resets the window clip rect, so we want to re-set that */ + if (target_drawable && GDK_DRAWABLE_GET_CLASS (target_drawable)->set_cairo_clip) + GDK_DRAWABLE_GET_CLASS (target_drawable)->set_cairo_clip (target_drawable, cr); } diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 61a5433e2..a37f9e893 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -170,6 +170,103 @@ struct _GdkEventPrivate gpointer windowing_data; }; +/* Tracks information about the pointer grab on this display */ +typedef struct +{ + GdkWindow *window; + GdkWindow *native_window; + gulong serial_start; + gulong serial_end; /* exclusive, i.e. not active on serial_end */ + gboolean owner_events; + guint event_mask; + gboolean implicit; + guint32 time; + + gboolean activated; + gboolean implicit_ungrab; + gboolean grab_one_pointer_release_event; +} GdkPointerGrabInfo; + + +/* Private version of GdkWindowObject. The initial part of this strucuture + is public for historical reasons. Don't change that part */ +typedef struct _GdkWindowPaint GdkWindowPaint; + +struct _GdkWindowObject +{ + /* vvvvvvv THIS PART IS PUBLIC. DON'T CHANGE vvvvvvvvvvvvvv */ + GdkDrawable parent_instance; + + GdkDrawable *impl; /* window-system-specific delegate object */ + + GdkWindowObject *parent; + + gpointer user_data; + + gint x; + gint y; + + gint extension_events; + + GList *filters; + GList *children; + + GdkColor bg_color; + GdkPixmap *bg_pixmap; + + GSList *paint_stack; + + GdkRegion *update_area; + guint update_freeze_count; + + guint8 window_type; + guint8 depth; + guint8 resize_count; + + GdkWindowState state; + + guint guffaw_gravity : 1; + guint input_only : 1; + guint modal_hint : 1; + guint composited : 1; + + guint destroyed : 2; + + guint accept_focus : 1; + guint focus_on_map : 1; + guint shaped : 1; + + GdkEventMask event_mask; + + guint update_and_descendants_freeze_count; + + GdkWindowRedirect *redirect; + + /* ^^^^^^^^^^ THIS PART IS PUBLIC. DON'T CHANGE ^^^^^^^^^^ */ + + /* The GdkWindowObject that has the impl, ref:ed if another window. + * This ref is required to keep the wrapper of the impl window alive + * for as long as any GdkWindow references the impl. */ + GdkWindowObject *impl_window; + int abs_x, abs_y; /* Absolute offset in impl */ + gint width, height; + guint32 clip_tag; + GdkRegion *clip_region; /* Clip region (wrt toplevel) in window coords */ + GdkRegion *clip_region_with_children; /* Clip region in window coords */ + GdkCursor *cursor; + gint8 toplevel_window_type; + + GdkWindowPaint *implicit_paint; + + GList *outstanding_moves; + + GdkRegion *shape; + GdkRegion *input_shape; + + cairo_surface_t *cairo_surface; +}; + + extern GdkEventFunc _gdk_event_func; /* Callback for events */ extern gpointer _gdk_event_data; extern GDestroyNotify _gdk_event_notify; @@ -182,15 +279,21 @@ 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_insert_after (GdkDisplay *display, + GdkEvent *after_event, + GdkEvent *event); +GList* _gdk_event_queue_insert_before(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); @@ -227,28 +330,59 @@ 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); +cairo_surface_t * _gdk_drawable_create_cairo_surface (GdkDrawable *drawable, + int width, + int height); + /* GC caching */ GdkGC *_gdk_drawable_get_scratch_gc (GdkDrawable *drawable, gboolean graphics_exposures); +GdkGC *_gdk_drawable_get_subwindow_scratch_gc (GdkDrawable *drawable); void _gdk_gc_update_context (GdkGC *gc, cairo_t *cr, const GdkColor *override_foreground, GdkBitmap *override_stipple, - gboolean gc_changed); + gboolean gc_changed, + GdkDrawable *target_drawable); /************************************* * Interfaces used by windowing code * *************************************/ -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); +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); + +void _gdk_window_impl_new (GdkWindow *window, + GdkWindow *real_parent, + GdkScreen *screen, + GdkVisual *visual, + GdkEventMask event_mask, + GdkWindowAttr *attributes, + gint attributes_mask); +void _gdk_window_destroy (GdkWindow *window, + gboolean foreign_destroy); +void _gdk_window_clear_update_area (GdkWindow *window); +void _gdk_window_update_size (GdkWindow *window); + +void _gdk_window_process_updates_recurse (GdkWindow *window, + GdkRegion *expose_region); + +void _gdk_screen_close (GdkScreen *screen); const char *_gdk_get_sm_client_id (void); @@ -263,6 +397,16 @@ GdkPixmap *_gdk_gc_get_tile (GdkGC *gc); GdkBitmap *_gdk_gc_get_stipple (GdkGC *gc); guint32 _gdk_gc_get_fg_pixel (GdkGC *gc); guint32 _gdk_gc_get_bg_pixel (GdkGC *gc); +void _gdk_gc_add_drawable_clip (GdkGC *gc, + guint32 region_tag, + GdkRegion *region, + int offset_x, + int offset_y); +void _gdk_gc_remove_drawable_clip (GdkGC *gc); +void _gdk_gc_set_clip_region_internal (GdkGC *gc, + GdkRegion *region, + gboolean reset_origin); +GdkSubwindowMode _gdk_gc_get_subwindow (GdkGC *gc); /***************************************** * Interfaces provided by windowing code * @@ -284,9 +428,14 @@ void _gdk_windowing_set_default_display (GdkDisplay *display); gchar *_gdk_windowing_substitute_screen_number (const gchar *display_name, gint screen_number); +gulong _gdk_windowing_window_get_next_serial (GdkDisplay *display); void _gdk_windowing_window_get_offsets (GdkWindow *window, - gint *x_offset, - gint *y_offset); + gint *x_offset, + gint *y_offset); +GdkRegion *_gdk_windowing_window_get_shape (GdkWindow *window); +GdkRegion *_gdk_windowing_window_get_input_shape(GdkWindow *window); +GdkRegion *_gdk_windowing_get_shape_for_mask (GdkBitmap *mask); + void _gdk_windowing_get_pointer (GdkDisplay *display, GdkScreen **screen, @@ -300,44 +449,25 @@ GdkWindow* _gdk_windowing_window_get_pointer (GdkDisplay *display, GdkModifierType *mask); GdkWindow* _gdk_windowing_window_at_pointer (GdkDisplay *display, gint *win_x, - gint *win_y); + gint *win_y, + GdkModifierType *mask); +void _gdk_windowing_got_event (GdkDisplay *display, + GList *event_link, + GdkEvent *event, + gulong serial); + +void _gdk_windowing_window_process_updates_recurse (GdkWindow *window, + GdkRegion *expose_region); +void _gdk_windowing_before_process_all_updates (void); +void _gdk_windowing_after_process_all_updates (void); /* Return the number of bits-per-pixel for images of the specified depth. */ gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display, gint depth); -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) -/* Called before processing updates for a window. This gives the windowing - * layer a chance to save the region for later use in avoiding duplicate - * exposes. The return value indicates whether the function has a saved - * the region; if the result is TRUE, then the windowing layer is responsible - * for destroying the region later. - */ -gboolean _gdk_windowing_window_queue_antiexpose (GdkWindow *window, - GdkRegion *area); - -/* Called to do the windowing system specific part of gdk_window_destroy(), - * - * window: The window being destroyed - * recursing: If TRUE, then this is being called because a parent - * was destroyed. This generally means that the call to the windowing system - * to destroy the window can be omitted, since it will be destroyed as a result - * of the parent being destroyed. Unless @foreign_destroy - * - * foreign_destroy: If TRUE, the window or a parent was destroyed by some external - * agency. The window has already been destroyed and no windowing - * system calls should be made. (This may never happen for some - * windowing systems.) - */ -void _gdk_windowing_window_destroy (GdkWindow *window, - gboolean recursing, - gboolean foreign_destroy); /* Called when gdk_window_destroy() is called on a foreign window * or an ancestor of the foreign window. It should generally reparent @@ -365,15 +495,9 @@ struct _GdkPaintableIface GTypeInterface g_iface; void (* begin_paint_region) (GdkPaintable *paintable, + GdkWindow *window, const GdkRegion *region); void (* end_paint) (GdkPaintable *paintable); - - void (* invalidate_maybe_recurse) (GdkPaintable *paintable, - const GdkRegion *region, - gboolean (*child_func) (GdkWindow *, gpointer), - gpointer user_data); - void (* process_updates) (GdkPaintable *paintable, - gboolean update_children); }; GType _gdk_paintable_get_type (void) G_GNUC_CONST; @@ -387,6 +511,7 @@ GType _gdk_pixmap_impl_get_type (void) G_GNUC_CONST; * _gdk_windowing_gc_set_clip_region: * @gc: a #GdkGC * @region: the new clip region + * @reset_origin: if TRUE, reset the clip_x/y_origin values to 0 * * Do any window-system specific processing necessary * for a change in clip region. Since the clip origin @@ -398,7 +523,8 @@ GType _gdk_pixmap_impl_get_type (void) G_GNUC_CONST; * will already return the new region. **/ void _gdk_windowing_gc_set_clip_region (GdkGC *gc, - const GdkRegion *region); + const GdkRegion *region, + gboolean reset_origin); /** * _gdk_windowing_gc_copy: @@ -435,6 +561,93 @@ char *_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context, void _gdk_windowing_launch_failed (GAppLaunchContext *context, const char *startup_notify_id); +GdkPointerGrabInfo *_gdk_display_get_active_pointer_grab (GdkDisplay *display); +void _gdk_display_pointer_grab_update (GdkDisplay *display, + gulong current_serial); +GdkPointerGrabInfo *_gdk_display_get_last_pointer_grab (GdkDisplay *display); +GdkPointerGrabInfo *_gdk_display_add_pointer_grab (GdkDisplay *display, + GdkWindow *window, + GdkWindow *native_window, + gboolean owner_events, + GdkEventMask event_mask, + unsigned long serial_start, + guint32 time, + gboolean implicit); +GdkPointerGrabInfo * _gdk_display_has_pointer_grab (GdkDisplay *display, + gulong serial); +gboolean _gdk_display_end_pointer_grab (GdkDisplay *display, + gulong serial, + GdkWindow *if_child, + gboolean implicit); +void _gdk_display_set_has_keyboard_grab (GdkDisplay *display, + GdkWindow *window, + GdkWindow *native_window, + gboolean owner_events, + unsigned long serial, + guint32 time); +void _gdk_display_unset_has_keyboard_grab (GdkDisplay *display, + gboolean implicit); +void _gdk_display_enable_motion_hints (GdkDisplay *display); + + +void _gdk_window_invalidate_for_expose (GdkWindow *window, + const GdkRegion *region); + +void _gdk_windowing_set_cairo_surface_size (cairo_surface_t *surface, + int width, + int height); + +cairo_surface_t * _gdk_windowing_create_cairo_surface (GdkDrawable *drawable, + int width, + int height); +GdkWindow * _gdk_window_find_descendant_at (GdkWindow *toplevel, + double x, double y, + double *found_x, + double *found_y); + +void _gdk_window_add_damage (GdkWindow *toplevel, + GdkRegion *damaged_region); + +GdkEvent * _gdk_make_event (GdkWindow *window, + GdkEventType type, + GdkEvent *event_in_queue, + gboolean before_event); + +void _gdk_syntesize_crossing_events (GdkDisplay *display, + GdkWindow *src, + GdkWindow *dest, + GdkCrossingMode mode, + gint toplevel_x, + gint toplevel_y, + GdkModifierType mask, + guint32 time_, + GdkEvent *event_in_queue, + gulong serial); +void _gdk_display_set_window_under_pointer (GdkDisplay *display, + GdkWindow *window); + + +void _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window); + +GdkRegion *_gdk_window_calculate_full_clip_region (GdkWindow *window, + GdkWindow *base_window, + gboolean do_children, + gint *base_x_offset, + gint *base_y_offset); +gboolean _gdk_window_has_impl (GdkWindow *window); +GdkWindow * _gdk_window_get_impl_window (GdkWindow *window); +GdkRegion *_gdk_region_new_from_yxbanded_rects (GdkRectangle *rects, int n_rects); + +/***************************** + * offscreen window routines * + *****************************/ +GType gdk_offscreen_window_get_type (void); +void _gdk_offscreen_window_new (GdkWindow *window, + GdkScreen *screen, + GdkVisual *visual, + GdkWindowAttr *attributes, + gint attributes_mask); + /************************************ * Initialization and exit routines * diff --git a/gdk/gdkoffscreenwindow.c b/gdk/gdkoffscreenwindow.c new file mode 100644 index 000000000..5791eace5 --- /dev/null +++ b/gdk/gdkoffscreenwindow.c @@ -0,0 +1,1085 @@ +/* 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 can't be the child of a foreign window, + * nor contain foreign windows + * GDK_POINTER_MOTION_HINT_MASK isn't effective + */ + +typedef struct _GdkOffscreenWindow GdkOffscreenWindow; +typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass; + +struct _GdkOffscreenWindow +{ + GdkDrawable parent_instance; + + GdkWindow *wrapper; + GdkCursor *cursor; + GdkColormap *colormap; + GdkScreen *screen; + + GdkPixmap *pixmap; +}; + +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 gdk_offscreen_window_hide (GdkWindow *window); + +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; + + gdk_pixmap_unref (offscreen->pixmap); + + G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object); +} + +static void +gdk_offscreen_window_init (GdkOffscreenWindow *window) +{ +} + +static void +gdk_offscreen_window_destroy (GdkWindow *window, + gboolean recursing, + gboolean foreign_destroy) +{ + GdkWindowObject *private = GDK_WINDOW_OBJECT (window); + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + 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); + + return gdk_gc_new_with_values (offscreen->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); + + return gdk_drawable_copy_to_image (offscreen->pixmap, + image, + src_x, + src_y, + dest_x, dest_y, + width, height); +} + +static cairo_surface_t * +gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + return _gdk_drawable_ref_cairo_surface (offscreen->pixmap); +} + +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 GdkDrawable * +gdk_offscreen_window_get_source_drawable (GdkDrawable *drawable) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + return _gdk_drawable_get_source_drawable (offscreen->pixmap); +} + +static GdkDrawable * +gdk_offscreen_window_get_composite_drawable (GdkDrawable *drawable, + gint x, + gint y, + gint width, + gint height, + gint *composite_x_offset, + gint *composite_y_offset) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + + return g_object_ref (offscreen->pixmap); +} + +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 +add_damage (GdkOffscreenWindow *offscreen, + int x, int y, + int w, int h) +{ + GdkRectangle rect; + GdkRegion *damage; + + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + + damage = gdk_region_rectangle (&rect); + _gdk_window_add_damage (offscreen->wrapper, damage); + gdk_region_destroy (damage); +} + +static GdkDrawable * +get_real_drawable (GdkOffscreenWindow *offscreen) +{ + GdkPixmapObject *pixmap; + pixmap = (GdkPixmapObject *) offscreen->pixmap; + return GDK_DRAWABLE (pixmap->impl); +} + +static void +gdk_offscreen_window_draw_drawable (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + + gdk_draw_drawable (real_drawable, gc, + src, xsrc, ysrc, + xdest, ydest, + width, height); + + add_damage (offscreen, xdest, ydest, width, height); +} + +static void +gdk_offscreen_window_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gboolean filled, + gint x, + gint y, + gint width, + gint height) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + + gdk_draw_rectangle (real_drawable, + gc, filled, x, y, width, height); + + add_damage (offscreen, x, y, width, height); + +} + +static void +gdk_offscreen_window_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gboolean filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + + gdk_draw_arc (real_drawable, + gc, + filled, + x, + y, + width, + height, + angle1, + angle2); + add_damage (offscreen, x, y, width, height); +} + +static void +gdk_offscreen_window_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gboolean filled, + GdkPoint *points, + gint npoints) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + + gdk_draw_polygon (real_drawable, + gc, + filled, + points, + npoints); + + if (npoints > 0) + { + int min_x, min_y, max_x, max_y, i; + + min_x = max_x = points[0].x; + min_y = max_y = points[0].y; + + for (i = 1; i < npoints; i++) + { + min_x = MIN (min_x, points[i].x); + max_x = MAX (max_x, points[i].x); + min_y = MIN (min_y, points[i].y); + max_y = MAX (max_y, points[i].y); + } + + add_damage (offscreen, min_x, min_y, + max_x - min_x, + max_y - min_y); + } +} + +static void +gdk_offscreen_window_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + GdkWindowObject *private = GDK_WINDOW_OBJECT (offscreen->wrapper); + + gdk_draw_text (real_drawable, + font, + gc, + x, + y, + text, + text_length); + + /* Hard to compute the minimal size, not that often used anyway. */ + add_damage (offscreen, 0, 0, private->width, private->height); +} + +static void +gdk_offscreen_window_draw_text_wc (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const GdkWChar *text, + gint text_length) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + GdkWindowObject *private = GDK_WINDOW_OBJECT (offscreen->wrapper); + + gdk_draw_text_wc (real_drawable, + font, + gc, + x, + y, + text, + text_length); + + /* Hard to compute the minimal size, not that often used anyway. */ + add_damage (offscreen, 0, 0, private->width, private->height); +} + +static void +gdk_offscreen_window_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + + gdk_draw_points (real_drawable, + gc, + points, + npoints); + + + if (npoints > 0) + { + int min_x, min_y, max_x, max_y, i; + + min_x = max_x = points[0].x; + min_y = max_y = points[0].y; + + for (i = 1; i < npoints; i++) + { + min_x = MIN (min_x, points[i].x); + max_x = MAX (max_x, points[i].x); + min_y = MIN (min_y, points[i].y); + max_y = MAX (max_y, points[i].y); + } + + add_damage (offscreen, min_x, min_y, + max_x - min_x, + max_y - min_y); + } +} + +static void +gdk_offscreen_window_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + + gdk_draw_segments (real_drawable, + gc, + segs, + nsegs); + + if (nsegs > 0) + { + int min_x, min_y, max_x, max_y, i; + + min_x = max_x = segs[0].x1; + min_y = max_y = segs[0].y1; + + for (i = 1; i < nsegs; i++) + { + min_x = MIN (min_x, segs[i].x1); + max_x = MAX (max_x, segs[i].x1); + min_x = MIN (min_x, segs[i].x2); + max_x = MAX (max_x, segs[i].x2); + min_y = MIN (min_y, segs[i].y1); + max_y = MAX (max_y, segs[i].y1); + min_y = MIN (min_y, segs[i].y2); + max_y = MAX (max_y, segs[i].y2); + } + + add_damage (offscreen, min_x, min_y, + max_x - min_x, + max_y - min_y); + } + +} + +static void +gdk_offscreen_window_draw_lines (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + GdkWindowObject *private = GDK_WINDOW_OBJECT (offscreen->wrapper); + + gdk_draw_lines (real_drawable, + gc, + points, + npoints); + + /* Hard to compute the minimal size, as we don't know the line + width, and since joins are hard to calculate. + Its not that often used anyway, damage it all */ + add_damage (offscreen, 0, 0, private->width, private->height); +} + +static void +gdk_offscreen_window_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + + gdk_draw_image (real_drawable, + gc, + image, + xsrc, + ysrc, + xdest, + ydest, + width, + height); + + add_damage (offscreen, xdest, ydest, width, height); +} + + +static void +gdk_offscreen_window_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither) +{ + GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable); + GdkDrawable *real_drawable = get_real_drawable (offscreen); + + gdk_draw_pixbuf (real_drawable, + gc, + pixbuf, + src_x, + src_y, + dest_x, + dest_y, + width, + height, + dither, + x_dither, + y_dither); + + add_damage (offscreen, dest_x, dest_y, width, height); + +} + +void +_gdk_offscreen_window_new (GdkWindow *window, + GdkScreen *screen, + GdkVisual *visual, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindowObject *parent_private; + GdkWindowObject *private; + GdkOffscreenWindow *offscreen; + + g_return_if_fail (attributes != NULL); + + if (attributes->wclass != GDK_INPUT_OUTPUT) + return; /* Can't support input only offscreens */ + + private = (GdkWindowObject *)window; + + if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent)) + return; + + parent_private = (GdkWindowObject*) private->parent; + private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL); + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + offscreen->wrapper = window; + + offscreen->screen = screen; + + 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); + } + + offscreen->pixmap = gdk_pixmap_new ((GdkDrawable *)private->parent, + private->width, + private->height, + private->depth); +} + +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; + GdkWindowObject *old_parent; + GdkOffscreenWindow *offscreen; + gboolean was_mapped; + + if (new_parent) + { + /* 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); + + old_parent = private->parent; + private->parent = new_parent_private; + private->x = x; + private->y = y; + + if (new_parent_private) + private->parent->children = g_list_prepend (private->parent->children, window); + + _gdk_syntesize_crossing_events_for_geometry_change (window); + if (old_parent) + _gdk_syntesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent)); + + return was_mapped; +} + +static gint +gdk_offscreen_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + if (x) + *x = 0; + if (y) + *y = 0; + + return TRUE; +} + +/** + * 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; + GdkOffscreenWindow *offscreen; + + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + if (!GDK_IS_OFFSCREEN_WINDOW (private->impl)) + return NULL; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + return offscreen->pixmap; +} + +static void +gdk_offscreen_window_raise (GdkWindow *window) +{ + /* gdk_window_raise already changed the stacking order */ + _gdk_syntesize_crossing_events_for_geometry_change (window); +} + +static void +gdk_offscreen_window_lower (GdkWindow *window) +{ + /* gdk_window_lower already changed the stacking order */ + _gdk_syntesize_crossing_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; + gint dx, dy, dw, dh; + GdkGC *gc; + GdkPixmap *old_pixmap; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + if (private->destroyed) + return; + + dx = x - private->x; + dy = y - private->y; + dw = width - private->width; + dh = height - private->height; + + private->x = x; + private->y = y; + + if (private->width != width || + private->height != height) + { + private->width = width; + private->height = height; + + old_pixmap = offscreen->pixmap; + offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap), + width, + height, + private->depth); + + gc = _gdk_drawable_get_scratch_gc (offscreen->pixmap, FALSE); + gdk_draw_drawable (offscreen->pixmap, + gc, + old_pixmap, + 0,0, 0, 0, + -1, -1); + g_object_unref (old_pixmap); + } + + if (GDK_WINDOW_IS_MAPPED (private)) + { + // TODO: Only invalidate new area, i.e. for larger windows + gdk_window_invalidate_rect (window, NULL, TRUE); + _gdk_syntesize_crossing_events_for_geometry_change (window); + } +} + +static void +gdk_offscreen_window_move_resize (GdkWindow *window, + gboolean with_move, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkOffscreenWindow *offscreen; + + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + if (!with_move) + { + x = private->x; + y = private->y; + } + + if (width < 0) + width = private->width; + + if (height < 0) + height = private->height; + + gdk_offscreen_window_move_resize_internal (window, x, y, + width, height, + TRUE); +} + +static void +gdk_offscreen_window_show (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + gdk_window_clear_area_e (window, 0, 0, + private->width, private->height); +} + + +static void +gdk_offscreen_window_hide (GdkWindow *window) +{ + GdkWindowObject *private; + GdkOffscreenWindow *offscreen; + GdkDisplay *display; + + g_return_if_fail (window != NULL); + + private = (GdkWindowObject*) window; + offscreen = GDK_OFFSCREEN_WINDOW (private->impl); + + /* May need to break grabs on children */ + display = gdk_drawable_get_display (window); + + /* TODO: This needs updating to the new grab world */ +#if 0 + if (display->pointer_grab.window != NULL) + { + if (is_parent_of (window, display->pointer_grab.window)) + { + /* Call this ourselves, even though gdk_display_pointer_ungrab + does so too, since we want to pass implicit == TRUE so the + broken grab event is generated */ + _gdk_display_unset_has_pointer_grab (display, + TRUE, + FALSE, + GDK_CURRENT_TIME); + gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); + } + } +#endif +} + +static void +gdk_offscreen_window_withdraw (GdkWindow *window) +{ +} + +static GdkEventMask +gdk_offscreen_window_get_events (GdkWindow *window) +{ + return 0; +} + +static void +gdk_offscreen_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ +} + +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) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + if (pixmap && + private->bg_pixmap != GDK_PARENT_RELATIVE_BG && + private->bg_pixmap != GDK_NO_BG && + !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); + + private->bg_pixmap = pixmap; + + if (pixmap && + private->bg_pixmap != GDK_PARENT_RELATIVE_BG && + private->bg_pixmap != GDK_NO_BG) + g_object_ref (pixmap); +} + +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_input_shape_combine_region (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y) +{ +} + +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 = private->width; + if (height) + *height = private->height; + if (depth) + *depth = private->depth; + } +} + +static gboolean +gdk_offscreen_window_queue_antiexpose (GdkWindow *window, + GdkRegion *area) +{ + return FALSE; +} + +static void +gdk_offscreen_window_queue_translation (GdkWindow *window, + GdkRegion *area, + gint dx, + gint dy) +{ +} + + +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_screen = gdk_offscreen_window_get_screen; + drawable_class->get_visual = gdk_offscreen_window_get_visual; + drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable; + drawable_class->get_composite_drawable = gdk_offscreen_window_get_composite_drawable; + + drawable_class->draw_rectangle = gdk_offscreen_window_draw_rectangle; + drawable_class->draw_arc = gdk_offscreen_window_draw_arc; + drawable_class->draw_polygon = gdk_offscreen_window_draw_polygon; + drawable_class->draw_text = gdk_offscreen_window_draw_text; + drawable_class->draw_text_wc = gdk_offscreen_window_draw_text_wc; + drawable_class->draw_drawable = gdk_offscreen_window_draw_drawable; + drawable_class->draw_points = gdk_offscreen_window_draw_points; + drawable_class->draw_segments = gdk_offscreen_window_draw_segments; + drawable_class->draw_lines = gdk_offscreen_window_draw_lines; + drawable_class->draw_image = gdk_offscreen_window_draw_image; + drawable_class->draw_pixbuf = gdk_offscreen_window_draw_pixbuf; +} + +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_resize = gdk_offscreen_window_move_resize; + 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->reparent = gdk_offscreen_window_reparent; + iface->set_cursor = gdk_offscreen_window_set_cursor; + iface->get_geometry = gdk_offscreen_window_get_geometry; + iface->shape_combine_region = gdk_offscreen_window_shape_combine_region; + iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region; + iface->set_static_gravities = gdk_offscreen_window_set_static_gravities; + iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose; + iface->queue_translation = gdk_offscreen_window_queue_translation; + iface->get_origin = gdk_offscreen_window_get_origin; + iface->destroy = gdk_offscreen_window_destroy; +} + +#define __GDK_OFFSCREEN_WINDOW_C__ +#include "gdkaliasdef.c" diff --git a/gdk/gdkpango.c b/gdk/gdkpango.c index a38640374..24efca8b2 100644 --- a/gdk/gdkpango.c +++ b/gdk/gdkpango.c @@ -214,7 +214,8 @@ get_cairo_context (GdkPangoRenderer *gdk_renderer, priv->cr, color, priv->stipple[part], - priv->gc_changed); + priv->gc_changed, + priv->drawable); } priv->last_part = part; diff --git a/gdk/gdkpixmap.c b/gdk/gdkpixmap.c index c717b9afb..de735b91f 100644 --- a/gdk/gdkpixmap.c +++ b/gdk/gdkpixmap.c @@ -145,6 +145,9 @@ static GdkImage* gdk_pixmap_copy_to_image (GdkDrawable *drawable, gint height); static cairo_surface_t *gdk_pixmap_ref_cairo_surface (GdkDrawable *drawable); +static cairo_surface_t *gdk_pixmap_create_cairo_surface (GdkDrawable *drawable, + int width, + int height); static GdkVisual* gdk_pixmap_real_get_visual (GdkDrawable *drawable); static gint gdk_pixmap_real_get_depth (GdkDrawable *drawable); @@ -216,6 +219,7 @@ gdk_pixmap_class_init (GdkPixmapObjectClass *klass) drawable_class->get_visual = gdk_pixmap_real_get_visual; drawable_class->_copy_to_image = gdk_pixmap_copy_to_image; drawable_class->ref_cairo_surface = gdk_pixmap_ref_cairo_surface; + drawable_class->create_cairo_surface = gdk_pixmap_create_cairo_surface; } static void @@ -229,6 +233,54 @@ 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; + + if (drawable) + source_drawable = _gdk_drawable_get_source_drawable (drawable); + else + source_drawable = NULL; + 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; + + if (drawable) + source_drawable = _gdk_drawable_get_source_drawable (drawable); + else + source_drawable = NULL; + 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, @@ -249,6 +301,7 @@ gdk_pixmap_draw_rectangle (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_rectangle (private->impl, gc, filled, x, y, width, height); } @@ -266,6 +319,7 @@ gdk_pixmap_draw_arc (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_arc (private->impl, gc, filled, x, y, width, height, angle1, angle2); @@ -280,6 +334,7 @@ gdk_pixmap_draw_polygon (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_polygon (private->impl, gc, filled, points, npoints); } @@ -294,6 +349,7 @@ gdk_pixmap_draw_text (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_text (private->impl, font, gc, x, y, text, text_length); } @@ -309,6 +365,7 @@ gdk_pixmap_draw_text_wc (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_text_wc (private->impl, font, gc, x, y, text, text_length); } @@ -326,6 +383,7 @@ gdk_pixmap_draw_drawable (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_drawable (private->impl, gc, src, xsrc, ysrc, xdest, ydest, width, height); @@ -339,6 +397,7 @@ gdk_pixmap_draw_points (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_points (private->impl, gc, points, npoints); } @@ -350,6 +409,7 @@ gdk_pixmap_draw_segments (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_segments (private->impl, gc, segs, nsegs); } @@ -361,6 +421,7 @@ gdk_pixmap_draw_lines (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_lines (private->impl, gc, points, npoints); } @@ -374,6 +435,7 @@ gdk_pixmap_draw_glyphs (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_glyphs (private->impl, gc, font, x, y, glyphs); } @@ -388,6 +450,7 @@ gdk_pixmap_draw_glyphs_transformed (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_glyphs_transformed (private->impl, gc, matrix, font, x, y, glyphs); } @@ -404,6 +467,7 @@ gdk_pixmap_draw_image (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_image (private->impl, gc, image, xsrc, ysrc, xdest, ydest, width, height); } @@ -424,6 +488,8 @@ gdk_pixmap_draw_pixbuf (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + if (gc) + _gdk_gc_remove_drawable_clip (gc); gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y, dest_x, dest_y, width, height, dither, x_dither, y_dither); @@ -437,6 +503,7 @@ gdk_pixmap_draw_trapezoids (GdkDrawable *drawable, { GdkPixmapObject *private = (GdkPixmapObject *)drawable; + _gdk_gc_remove_drawable_clip (gc); gdk_draw_trapezoids (private->impl, gc, trapezoids, n_trapezoids); } @@ -515,6 +582,17 @@ gdk_pixmap_ref_cairo_surface (GdkDrawable *drawable) return _gdk_drawable_ref_cairo_surface (((GdkPixmapObject*)drawable)->impl); } +static cairo_surface_t * +gdk_pixmap_create_cairo_surface (GdkDrawable *drawable, + int width, + int height) +{ + return _gdk_windowing_create_cairo_surface (GDK_PIXMAP_OBJECT(drawable)->impl, + width, height); +} + + + static GdkBitmap * make_solid_mask (GdkScreen *screen, gint width, gint height) { diff --git a/gdk/gdkregion-generic.c b/gdk/gdkregion-generic.c index f835ab7d6..19e03e45c 100644 --- a/gdk/gdkregion-generic.c +++ b/gdk/gdkregion-generic.c @@ -96,6 +96,7 @@ static void miRegionOp (GdkRegion *newReg, overlapFunc overlapFn, nonOverlapFunc nonOverlap1Fn, nonOverlapFunc nonOverlap2Fn); +static void miSetExtents (GdkRegion *pReg); /** * gdk_region_new: @@ -122,6 +123,31 @@ gdk_region_new (void) return temp; } +GdkRegion * +_gdk_region_new_from_yxbanded_rects (GdkRectangle *rects, + int num_rects) +{ + GdkRegion *temp; + int i; + + temp = g_slice_new (GdkRegion); + + temp->rects = g_new (GdkRegionBox, num_rects); + temp->size = num_rects; + temp->numRects = num_rects; + for (i = 0; i < num_rects; i++) + { + temp->rects[i].x1 = rects[i].x; + temp->rects[i].y1 = rects[i].y; + temp->rects[i].x2 = rects[i].x + rects[i].width; + temp->rects[i].y2 = rects[i].y + rects[i].height; + } + miSetExtents (temp); + + return temp; +} + + /** * gdk_region_rectangle: * @rectangle: a #GdkRectangle diff --git a/gdk/gdkscreen.h b/gdk/gdkscreen.h index b1f3b8e8a..96ff8d44a 100644 --- a/gdk/gdkscreen.h +++ b/gdk/gdkscreen.h @@ -51,6 +51,7 @@ struct _GdkScreen GdkGC *normal_gcs[32]; GdkGC *exposure_gcs[32]; + GdkGC *subwindow_gcs[32]; cairo_font_options_t *font_options; double resolution; /* pixels/points scale factor for fonts */ diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 76a2ec618..d2798ba01 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -35,9 +35,33 @@ #include "gdkscreen.h" #include "gdkalias.h" -#define USE_BACKING_STORE /* Appears to work on Win32, too, now. */ +#undef DEBUG_WINDOW_PRINTING + +#ifdef GDK_WINDOWING_X11 +#include "x11/gdkx.h" /* For workaround */ +#endif -typedef struct _GdkWindowPaint GdkWindowPaint; +#include "math.h" + +/* Not all GdkWindows have a corresponding native window. + * Instead some draw into the nearest parent that has whatss + * called an "impl", i.e. the implementation window. + * For toplevel window system windows the impl is always native + * window, but child windows can also have native windows as + * this is sometimes necessary. Furthermore, offscreen windows + * (type GDK_WINDOW_OFFSCREEN) have an impl of type + * GdkOffscreenWindow rather than a backend implementation native + * window. Such windows draw into an offscreen pixmap instead + * of a window and collect damage that lets you paint it where + * you want. + * + * All GdkWindow track their position, size, clip region and + * absolute position in the impl window. For child window with + * native windows the clip region is set on the native window + * as a window shape to make it clip against other non-native windows. + */ + +#define USE_BACKING_STORE /* Appears to work on Win32, too, now. */ struct _GdkWindowPaint { @@ -46,27 +70,17 @@ struct _GdkWindowPaint gint x_offset; gint y_offset; cairo_surface_t *surface; + guint uses_implicit : 1; + guint32 region_tag; }; typedef struct { - GdkRegion *old_region; - gint old_clip_x_origin; - gint old_clip_y_origin; - gint x_offset; - 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; -}; + GdkRegion *dest_region; /* The destination region */ + int dx, dy; /* The amount that the source was moved to reach dest_region */ +} GdkWindowRegionMove; + + +/* Global info */ static GdkGC *gdk_window_create_gc (GdkDrawable *drawable, GdkGCValues *values, @@ -180,6 +194,11 @@ static GdkImage* gdk_window_copy_to_image (GdkDrawable *drawable, gint height); static cairo_surface_t *gdk_window_ref_cairo_surface (GdkDrawable *drawable); +static cairo_surface_t *gdk_window_create_cairo_surface (GdkDrawable *drawable, + int width, + int height); +static void gdk_window_set_cairo_clip (GdkDrawable *drawable, + cairo_t *cr); static void gdk_window_real_get_size (GdkDrawable *drawable, gint *width, @@ -192,6 +211,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, @@ -207,31 +227,38 @@ static void gdk_window_free_paint_stack (GdkWindow *window); static void gdk_window_init (GdkWindowObject *window); static void gdk_window_class_init (GdkWindowObjectClass *klass); static void gdk_window_finalize (GObject *object); -static void gdk_window_clear_backing_rect (GdkWindow *window, - gint x, - gint y, - gint width, - gint height); -static void setup_redirect_clip (GdkWindow *window, - GdkGC *gc, - GdkWindowClipData *data); -static void reset_redirect_clip (GdkWindow *offscreen, - GdkGC *gc, - GdkWindowClipData *data); +static void gdk_window_clear_backing_region (GdkWindow *window, + GdkRegion *region); static void gdk_window_redirect_free (GdkWindowRedirect *redirect); 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 void recompute_visible_regions (GdkWindowObject *private, + gboolean recalculate_siblings, + gboolean recalculate_children); +static void gdk_window_flush_outstanding_moves (GdkWindow *window); +static void gdk_window_flush (GdkWindow *window); +static void gdk_window_flush_recursive (GdkWindowObject *window); +static void do_move_region_bits_on_impl (GdkWindowObject *private, + GdkRegion *region, /* In impl window coords */ + int dx, int dy); +static void gdk_window_invalidate_in_parent (GdkWindowObject *private); +static void move_native_children (GdkWindowObject *private); + static gpointer parent_class = NULL; +static const cairo_user_data_key_t gdk_window_cairo_key; + +static guint32 +new_region_tag (void) +{ + static guint32 tag = 0; + + return ++tag; +} + GType gdk_window_object_get_type (void) { @@ -281,6 +308,9 @@ gdk_window_init (GdkWindowObject *window) window->window_type = GDK_WINDOW_CHILD; window->state = GDK_WINDOW_STATE_WITHDRAWN; + window->width = 1; + window->height = 1; + window->toplevel_window_type = -1; } static GQuark quark_pointer_window = 0; @@ -318,9 +348,12 @@ gdk_window_class_init (GdkWindowObjectClass *klass) drawable_class->get_visual = gdk_window_real_get_visual; drawable_class->_copy_to_image = gdk_window_copy_to_image; drawable_class->ref_cairo_surface = gdk_window_ref_cairo_surface; + drawable_class->create_cairo_surface = gdk_window_create_cairo_surface; + drawable_class->set_cairo_clip = gdk_window_set_cairo_clip; 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; quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window"); } @@ -345,12 +378,397 @@ gdk_window_finalize (GObject *object) _gdk_window_destroy (window, TRUE); } - g_object_unref (obj->impl); - obj->impl = NULL; + if (obj->impl) + { + g_object_unref (obj->impl); + obj->impl = NULL; + } + + if (obj->impl_window != obj) + { + g_object_unref (obj->impl_window); + obj->impl_window = NULL; + } + if (obj->shape) + gdk_region_destroy (obj->shape); + + if (obj->input_shape) + gdk_region_destroy (obj->input_shape); + + if (obj->cursor) + gdk_cursor_unref (obj->cursor); + G_OBJECT_CLASS (parent_class)->finalize (object); } +static gboolean +gdk_window_is_offscreen (GdkWindowObject *window) +{ + return GDK_WINDOW_TYPE (window) == GDK_WINDOW_OFFSCREEN; +} + +static GdkWindowObject * +gdk_window_get_impl_window (GdkWindowObject *window) +{ + return window->impl_window; +} + +GdkWindow * +_gdk_window_get_impl_window (GdkWindow *window) +{ + return (GdkWindow *)gdk_window_get_impl_window ((GdkWindowObject *)window); +} + +static gboolean +gdk_window_has_impl (GdkWindowObject *window) +{ + return window->impl_window == window; +} + +gboolean +_gdk_window_has_impl (GdkWindow *window) +{ + return gdk_window_has_impl ((GdkWindowObject *)window); +} + +static gboolean +gdk_window_has_no_impl (GdkWindowObject *window) +{ + return window->impl_window != window; +} + +static void +remove_child_area (GdkWindowObject *private, + GdkWindowObject *until, + gboolean for_input, + GdkRegion *region) +{ + GdkWindowObject *child; + GdkRegion *child_region; + GdkRectangle r; + GList *l; + GdkRegion *shape; + + for (l = private->children; l; l = l->next) + { + child = l->data; + + if (child == until) + break; + + if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited) + continue; + + /* Ignore offscreen children, as they don't draw in their parent and + * don't take part in the clipping */ + if (gdk_window_is_offscreen (child)) + continue; + + r.x = child->x; + r.y = child->y; + r.width = child->width; + r.height = child->height; + + child_region = gdk_region_rectangle (&r); + + if (child->shape) + gdk_region_intersect (child_region, child->shape); + else if (private->window_type == GDK_WINDOW_FOREIGN) + { + shape = _gdk_windowing_window_get_shape ((GdkWindow *)child); + if (shape) + { + gdk_region_intersect (child_region, shape); + gdk_region_destroy (shape); + } + } + + if (for_input) + { + if (child->input_shape) + gdk_region_intersect (child_region, child->input_shape); + else if (private->window_type == GDK_WINDOW_FOREIGN) + { + shape = _gdk_windowing_window_get_input_shape ((GdkWindow *)child); + if (shape) + { + gdk_region_intersect (child_region, shape); + gdk_region_destroy (shape); + } + } + } + + gdk_region_subtract (region, child_region); + gdk_region_destroy (child_region); + + } +} + +static void +recompute_visible_regions_internal (GdkWindowObject *private, + gboolean recalculate_clip, + gboolean recalculate_siblings, + gboolean recalculate_children) +{ + GdkRectangle r; + GList *l; + GdkWindowObject *child; + GdkRegion *new_clip, *old_clip_region_with_children; + gboolean clip_region_changed; + gboolean abs_pos_changed; + int old_abs_x, old_abs_y; + + old_abs_x = private->abs_x; + old_abs_y = private->abs_y; + + /* Update absolute position */ + if (gdk_window_has_impl (private)) + { + /* Native window starts here */ + private->abs_x = 0; + private->abs_y = 0; + } + else + { + private->abs_x = private->parent->abs_x + private->x; + private->abs_y = private->parent->abs_y + private->y; + } + + abs_pos_changed = + private->abs_x != old_abs_x || + private->abs_y != old_abs_y; + + /* Update clip region based on: + * parent clip + * window size + * siblings in parents above window + */ + clip_region_changed = FALSE; + if (recalculate_clip) + { + /* Calculate visible region (sans children) in parent window coords */ + r.x = private->x; + r.y = private->y; + r.width = private->width; + r.height = private->height; + new_clip = gdk_region_rectangle (&r); + + if (private->parent != NULL && GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT) + { + gdk_region_intersect (new_clip, private->parent->clip_region); + + /* Remove all overlapping children from parent */ + remove_child_area (private->parent, private, FALSE, new_clip); + } + + /* Convert from parent coords to window coords */ + gdk_region_offset (new_clip, -private->x, -private->y); + + if (private->shape) + gdk_region_intersect (new_clip, private->shape); + + if (private->clip_region == NULL || + !gdk_region_equal (private->clip_region, new_clip)) + clip_region_changed = TRUE; + + if (private->clip_region) + gdk_region_destroy (private->clip_region); + private->clip_region = new_clip; + + old_clip_region_with_children = private->clip_region_with_children; + private->clip_region_with_children = gdk_region_copy (private->clip_region); + remove_child_area (private, NULL, FALSE, private->clip_region_with_children); + + if (clip_region_changed || + !gdk_region_equal (private->clip_region_with_children, old_clip_region_with_children)) + private->clip_tag = new_region_tag (); + + if (old_clip_region_with_children) + gdk_region_destroy (old_clip_region_with_children); + } + + /* Update all children, recursively. */ + if (abs_pos_changed || clip_region_changed || recalculate_children) + { + for (l = private->children; l; l = l->next) + { + child = l->data; + /* Only recalculate clip if the the clip region changed, otherwise + * there is no way the child clip region could change (its has not e.g. moved) + * Except if recalculate_children is set to force child updates + */ + recompute_visible_regions_internal (child, recalculate_clip && (clip_region_changed || recalculate_children), FALSE, FALSE); + } + } + + if (clip_region_changed && + gdk_window_has_impl (private) && + /* Not for offscreens */ + private->window_type != GDK_WINDOW_OFFSCREEN && + /* or for non-shaped toplevels */ + (private->shaped || + (private->parent != NULL && + GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)) && + /* or for foreign windows */ + GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN + ) + { + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0); + } + + if (recalculate_siblings && + private->parent != NULL && + GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT) + { + /* If we moved a child window in parent or changed the stacking order, then we + * need to recompute the visible area of all the other children in the parent + */ + for (l = private->parent->children; l; l = l->next) + { + child = l->data; + + if (child != private) + recompute_visible_regions_internal (child, TRUE, FALSE, FALSE); + } + + /* We also need to recompute the _with_children clip for the parent */ + recompute_visible_regions_internal (private->parent, TRUE, FALSE, FALSE); + } + + if (private->cairo_surface) + { + int width, height; + + /* It would be nice if we had some cairo support here so we + could set the clip rect on the cairo surface */ + width = private->abs_x + private->width; + height = private->abs_y + private->height; + + _gdk_windowing_set_cairo_surface_size (private->cairo_surface, + width, height); + cairo_surface_set_device_offset (private->cairo_surface, + private->abs_x, + private->abs_y); + } +} + +/* Call this when private has changed in one or more of these ways: + * size changed + * window moved + * new window added + * stacking order of window changed + * child deleted + * + * It will recalculate abs_x/y and the clip regions + * + * Unless the window didn't change stacking order or size/pos, pass in TRUE + * for recalculate_siblings. (Mostly used internally for the recursion) + * + * If a child window was removed (and you can't use that child for + * recompute_visible_regions), pass in TRUE for recalculate_children on the parent + */ +static void +recompute_visible_regions (GdkWindowObject *private, + gboolean recalculate_siblings, + gboolean recalculate_children) +{ + recompute_visible_regions_internal (private, + TRUE, + recalculate_siblings, + recalculate_children); +} + +void +_gdk_window_update_size (GdkWindow *window) +{ + recompute_visible_regions ((GdkWindowObject *)window, TRUE, FALSE); +} + +/* Find the native window that would be just above "child" + * in the native stacking order if "child" was a native window + * (it doesn't have to be native). If there is no such native + * window inside this native parent then NULL is returned. + * If child is NULL, find lowest native window in parent. + */ +static GdkWindowObject * +find_native_sibling_above_helper (GdkWindowObject *parent, + GdkWindowObject *child) +{ + GdkWindowObject *w; + GList *l; + + if (child) + { + l = g_list_find (parent->children, child); + g_assert (l != NULL); /* Better be a child of its parent... */ + l = l->prev; /* Start looking at the one above the child */ + } + else + l = g_list_last (parent->children); + + for (; l != NULL; l = l->prev) + { + w = l->data; + + if (gdk_window_has_impl (w)) + return w; + + g_assert (parent != w); + w = find_native_sibling_above_helper (w, NULL); + if (w) + return w; + } + + return NULL; +} + + +static GdkWindowObject * +find_native_sibling_above (GdkWindowObject *parent, + GdkWindowObject *child) +{ + GdkWindowObject *w; + + w = find_native_sibling_above_helper (parent, child); + if (w) + return w; + + if (gdk_window_has_impl (parent)) + return NULL; + else + return find_native_sibling_above (parent->parent, parent); +} + +static GdkEventMask +get_native_event_mask (GdkWindowObject *private) +{ + if (private->window_type != GDK_WINDOW_ROOT && + private->window_type != GDK_WINDOW_FOREIGN) + { + return + /* We need thse for all native window so we can emulate + events on children: */ + GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | + GDK_SCROLL_MASK | + /* Then do whatever the app asks to, since the app + * may be asking for weird things for native windows, + * but filter out things that override the above + * requests somehow. */ + (private->event_mask & + ~(GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON2_MOTION_MASK | + GDK_BUTTON3_MOTION_MASK)); + } + else + return private->event_mask; +} + /** * gdk_window_new: * @parent: a #GdkWindow, or %NULL to create the window as a child of @@ -371,98 +789,580 @@ gdk_window_new (GdkWindow *parent, gint attributes_mask) { GdkWindow *window; - GdkWindowObject *private, *parent_private; - - g_return_val_if_fail (parent == NULL || GDK_IS_WINDOW (parent), NULL); + GdkWindowObject *private; + GdkScreen *screen; + GdkVisual *visual; + int x, y; + gboolean native; + GdkEventMask event_mask; + GdkWindow *real_parent; + g_return_val_if_fail (attributes != NULL, NULL); - - window = _gdk_window_new (parent, attributes, attributes_mask); - g_return_val_if_fail (window != NULL, window); - - /* Inherit redirection from parent */ - if (parent != NULL) + + if (!parent) { - parent_private = GDK_WINDOW_OBJECT (parent); - private = GDK_WINDOW_OBJECT (window); - private->redirect = parent_private->redirect; + GDK_NOTE (MULTIHEAD, + g_warning ("gdk_window_new(): no parent specified reverting to parent = default root window")); + + screen = gdk_screen_get_default (); + parent = gdk_screen_get_root_window (screen); } + else + screen = gdk_drawable_get_screen (parent); + + g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL); - return window; -} + if (GDK_WINDOW_DESTROYED (parent)) + return NULL; -/** - * gdk_window_reparent: - * @window: a #GdkWindow - * @new_parent: new parent to move @window into - * @x: X location inside the new parent - * @y: Y location inside the new parent - * - * Reparents @window into the given @new_parent. The window being - * reparented will be unmapped as a side effect. - * - **/ -void -gdk_window_reparent (GdkWindow *window, - GdkWindow *new_parent, - gint x, - gint y) -{ - GdkWindowObject *private; - gboolean show; + window = g_object_new (GDK_TYPE_WINDOW, NULL); + private = (GdkWindowObject *) window; - g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent)); - g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT); + /* Windows with a foreign parent are treated as if they are children + * of the root window, except for actual creation. + */ + real_parent = parent; + if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN) + parent = gdk_screen_get_root_window (screen); - if (GDK_WINDOW_DESTROYED (window) || - (new_parent && GDK_WINDOW_DESTROYED (new_parent))) - { - return; - } + private->parent = (GdkWindowObject *)parent; - private = (GdkWindowObject *) window; + private->accept_focus = TRUE; + private->focus_on_map = TRUE; - /* Break up redirection if inherited */ - if (private->redirect && private->redirect->redirected != private) + 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; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + +#ifdef GDK_WINDOWING_X11 + /* Work around a bug where Xorg refuses to map toplevel InputOnly windows + * from an untrusted client: http://bugs.freedesktop.org/show_bug.cgi?id=6988 + */ + if (attributes->wclass == GDK_INPUT_ONLY && + GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT && + !G_LIKELY (GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (parent))->trusted_client)) { - remove_redirect_from_children (private, private->redirect); - private->redirect = NULL; + g_warning ("Coercing GDK_INPUT_ONLY toplevel window to GDK_INPUT_OUTPUT to work around bug in Xorg server"); + attributes->wclass = GDK_INPUT_OUTPUT; } +#endif - show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent (window, new_parent, x, y); + if (attributes->wclass == GDK_INPUT_ONLY) + { + /* Backwards compatiblity - we've always ignored + * attributes->window_type for input-only windows + * before + */ + if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT) + private->window_type = GDK_WINDOW_TEMP; + else + private->window_type = GDK_WINDOW_CHILD; + } + else + private->window_type = attributes->window_type; - /* Inherit parent redirect if we don't have our own */ - if (private->parent && private->redirect == NULL) + /* Sanity checks */ + switch (private->window_type) { - private->redirect = private->parent->redirect; - apply_redirect_to_children (private, private->redirect); + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + case GDK_WINDOW_OFFSCREEN: + if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT) + g_warning (G_STRLOC "Toplevel windows must be created as children of\n" + "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN"); + case GDK_WINDOW_CHILD: + break; + break; + default: + g_warning (G_STRLOC "cannot make windows of type %d", private->window_type); + return NULL; } + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_screen_get_system_visual (screen); - if (show) - gdk_window_show (window); -} + private->event_mask = attributes->event_mask; -static void -window_remove_filters (GdkWindow *window) -{ - GdkWindowObject *obj = (GdkWindowObject*) window; + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + private->input_only = FALSE; + private->depth = visual->depth; + + private->bg_color.pixel = 0; // TODO: BlackPixel (xdisplay, screen_x11->screen_num); + private->bg_color.red = private->bg_color.green = private->bg_color.blue = 0; - if (obj->filters) + private->bg_pixmap = NULL; + } + else { - GList *tmp_list; - - for (tmp_list = obj->filters; tmp_list; tmp_list = tmp_list->next) - g_free (tmp_list->data); - - g_list_free (obj->filters); - obj->filters = NULL; + private->depth = 0; + private->input_only = TRUE; } -} -/** - * _gdk_window_destroy_hierarchy: - * @window: a #GdkWindow - * @recursing: If TRUE, then this is being called because a parent + if (private->parent) + private->parent->children = g_list_prepend (private->parent->children, window); + + native = FALSE; /* Default */ + if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + native = TRUE; /* Always use native windows for toplevels */ + else if (!private->input_only && + ((attributes_mask & GDK_WA_COLORMAP && + attributes->colormap != gdk_drawable_get_colormap ((GdkDrawable *)private->parent)) || + (attributes_mask & GDK_WA_VISUAL && + attributes->visual != gdk_drawable_get_visual ((GdkDrawable *)private->parent)))) + native = TRUE; /* InputOutput window with different colormap or visual than parent, needs native window */ + + if (private->window_type == GDK_WINDOW_OFFSCREEN) + { + _gdk_offscreen_window_new (window, screen, visual, attributes, attributes_mask); + private->impl_window = private; + } + else if (native) + { + GdkWindowObject *above; + GList listhead = {0}; + + event_mask = get_native_event_mask (private); + + /* Create the impl */ + _gdk_window_impl_new (window, real_parent, screen, visual, event_mask, attributes, attributes_mask); + private->impl_window = private; + + /* This will put the native window topmost in the native parent, which may + * be wrong wrt other native windows in the non-native hierarchy, so restack */ + above = find_native_sibling_above (private->parent, private); + if (above) + { + listhead.data = window; + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above, + &listhead); + } + + } + else + { + private->impl_window = g_object_ref (private->parent->impl_window); + private->impl = g_object_ref (private->impl_window->impl); + } + + recompute_visible_regions (private, TRUE, FALSE); + + if (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT) + { + /* Inherit redirection from parent */ + private->redirect = private->parent->redirect; + } + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +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 void +change_impl (GdkWindowObject *private, + GdkWindowObject *impl_window, + GdkDrawable *new) +{ + GList *l; + GdkWindowObject *child; + GdkDrawable *old_impl; + GdkWindowObject *old_impl_window; + + old_impl = private->impl; + old_impl_window = private->impl_window; + if (private != impl_window) + private->impl_window = g_object_ref (impl_window); + else + private->impl_window = private; + private->impl = g_object_ref (new); + if (old_impl_window != private) + g_object_unref (old_impl_window); + g_object_unref (old_impl); + + for (l = private->children; l != NULL; l = l->next) + { + child = l->data; + + if (child->impl == old_impl) + change_impl (child, impl_window, new); + } +} + +static void +reparent_to_impl (GdkWindowObject *private) +{ + GList *l; + GdkWindowObject *child; + gboolean show; + + /* Enumerate in reverse order so we get the right order for the native + windows (first in childrens list is topmost, and reparent places on top) */ + for (l = g_list_last (private->children); l != NULL; l = l->prev) + { + child = l->data; + + if (child->impl == private->impl) + reparent_to_impl (child); + else + { + show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent ((GdkWindow *)child, + (GdkWindow *)private, + child->x, child->y); + if (show) + gdk_window_show_unraised ((GdkWindow *)child); + } + } +} + + +/** + * gdk_window_reparent: + * @window: a #GdkWindow + * @new_parent: new parent to move @window into + * @x: X location inside the new parent + * @y: Y location inside the new parent + * + * Reparents @window into the given @new_parent. The window being + * reparented will be unmapped as a side effect. + * + **/ +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowObject *private; + GdkWindowObject *new_parent_private; + GdkWindowObject *old_parent; + gboolean show, was_toplevel, was_mapped; + gboolean do_reparent_to_impl; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent)); + g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT); + + if (GDK_WINDOW_DESTROYED (window) || + (new_parent && GDK_WINDOW_DESTROYED (new_parent))) + return; + + if (!new_parent) + new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window)); + + private = (GdkWindowObject *) window; + new_parent_private = (GdkWindowObject *)new_parent; + + /* No input-output children of input-only windows */ + if (new_parent_private->input_only && !private->input_only) + return; + + /* Don't create loops in hierarchy */ + if (is_parent_of (window, new_parent)) + return; + + if (private->cairo_surface) + { + /* This might be wrong in the new parent, e.g. for non-native surfaces. + To make sure we're ok, just wipe it. */ + cairo_surface_finish (private->cairo_surface); + cairo_surface_set_user_data (private->cairo_surface, &gdk_window_cairo_key, + NULL, NULL); + } + + old_parent = private->parent; + + /* Break up redirection if inherited */ + if (private->redirect && private->redirect->redirected != private) + { + remove_redirect_from_children (private, private->redirect); + private->redirect = NULL; + } + + was_toplevel = private->parent == NULL; + was_mapped = GDK_WINDOW_IS_MAPPED (window); + show = FALSE; + + /* Reparenting to toplevel. Ensure we have a native window so this can work */ + if (new_parent_private->window_type == GDK_WINDOW_ROOT || + new_parent_private->window_type == GDK_WINDOW_FOREIGN) + gdk_window_set_has_native (window, TRUE); + + do_reparent_to_impl = FALSE; + if (gdk_window_has_impl (private)) + { + /* Native window */ + show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent (window, new_parent, x, y); + } + else + { + /* This shouldn't happen, as we created a native in this case, check anyway to see if that ever fails */ + g_assert (new_parent_private->window_type != GDK_WINDOW_ROOT && + new_parent_private->window_type != GDK_WINDOW_FOREIGN); + + show = was_mapped; + gdk_window_hide (window); + + do_reparent_to_impl = TRUE; + change_impl (private, + new_parent_private->impl_window, + new_parent_private->impl); + } + + /* 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)); + new_parent_private = (GdkWindowObject *)new_parent; + } + + if (old_parent) + old_parent->children = g_list_remove (old_parent->children, window); + + private->parent = new_parent_private; + private->x = x; + private->y = y; + + new_parent_private->children = g_list_prepend (new_parent_private->children, window); + + /* Switch the window type as appropriate */ + + switch (GDK_WINDOW_TYPE (new_parent)) + { + case GDK_WINDOW_ROOT: + case GDK_WINDOW_FOREIGN: + if (private->toplevel_window_type != -1) + GDK_WINDOW_TYPE (window) = private->toplevel_window_type; + else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD) + GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL; + break; + case GDK_WINDOW_OFFSCREEN: + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ + GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN) + { + /* Save the original window type so we can restore it if the + * window is reparented back to be a toplevel + */ + private->toplevel_window_type = GDK_WINDOW_TYPE (window); + GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD; + } + } + + /* We might have changed window type for a native windows, so we + need to change the event mask too. */ + if (gdk_window_has_impl (private)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, get_native_event_mask (private)); + + /* Inherit parent redirect if we don't have our own */ + if (private->parent && private->redirect == NULL) + { + private->redirect = private->parent->redirect; + apply_redirect_to_children (private, private->redirect); + } + + recompute_visible_regions (private, TRUE, FALSE); + if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT) + recompute_visible_regions (old_parent, FALSE, TRUE); + + if (do_reparent_to_impl) + reparent_to_impl (private); + else + { + GdkWindowObject *above; + GList listhead = {0}; + + /* The reparent will have put the native window topmost in the native parent, + * which may be wrong wrt other native windows in the non-native hierarchy, + * so restack */ + above = find_native_sibling_above (private->parent, private); + if (above) + { + listhead.data = window; + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above, + &listhead); + } + } + + if (show) + gdk_window_show_unraised (window); + else + _gdk_syntesize_crossing_events_for_geometry_change (window); +} + +/** + * gdk_window_set_has_native: + * @window: a #GdkWindow + * @has_native: whethe the window should have a native window + * + * Tries to create or remove a window-system native window for this + * GdkWindow. This may fail in some situations. For instance: + * + * Toplevel and foreign windows must have a native window. + * Offscreen window and children of them can never have native windows. + * Some backends may not support native child windows. + * + **/ +void +gdk_window_set_has_native (GdkWindow *window, gboolean has_native) +{ + GdkWindowObject *private; + GdkWindowObject *impl_window; + GdkDrawable *new_impl, *old_impl; + GdkScreen *screen; + GdkVisual *visual; + GdkWindowAttr attributes; + GdkWindowObject *above; + GList listhead; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT || + GDK_WINDOW_DESTROYED (window)) + return; + + private = (GdkWindowObject *) window; + + if (has_native) + { + /* Create native window */ + + if (gdk_window_has_impl (private)) + /* Already has an impl, either native (ok) or + offscreen (not supported). Bail. */ + return; + + impl_window = gdk_window_get_impl_window (private); + if (impl_window->window_type == GDK_WINDOW_OFFSCREEN) + return; /* native in offscreens not supported */ + + screen = gdk_drawable_get_screen (window); + visual = gdk_drawable_get_visual (window); + + attributes.colormap = gdk_drawable_get_colormap (window); + + old_impl = private->impl; + _gdk_window_impl_new (window, (GdkWindow *)private->parent, screen, visual, + get_native_event_mask (private), &attributes, GDK_WA_COLORMAP); + new_impl = private->impl; + + private->impl = old_impl; + change_impl (private, private, new_impl); + + /* Native window creation will put the native window topmost in the + * native parent, which may be wrong wrt other native windows in the + * non-native hierarchy, so restack */ + above = find_native_sibling_above (private->parent, private); + if (above) + { + listhead.data = window; + listhead.prev = NULL; + listhead.next = NULL; + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above, + &listhead); + } + + recompute_visible_regions (private, FALSE, FALSE); + + /* The shape may not have been set, as the clip region doesn't actually + change, so do it here manually */ + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0); + + reparent_to_impl (private); + + if (!private->input_only) + { + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, &private->bg_color); + if (private->bg_pixmap != NULL) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap); + } + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0); + + if (gdk_window_is_viewable (window)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window); + } + else + { + /* Remove native window */ + + if (!gdk_window_has_impl (private)) + return; /* Not native, can't remove */ + + if (private->window_type == GDK_WINDOW_OFFSCREEN) + return; /* Not native, can't remove */ + + if (private->parent == NULL || + GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + return; /* toplevel, must be native */ + + g_warning ("Tried to turn native window to client side window, this is not supported yet."); + + /* TODO: remove native */ + } +} + +static void +window_remove_filters (GdkWindow *window) +{ + GdkWindowObject *obj = (GdkWindowObject*) window; + + if (obj->filters) + { + GList *tmp_list; + + for (tmp_list = obj->filters; tmp_list; tmp_list = tmp_list->next) + g_free (tmp_list->data); + + g_list_free (obj->filters); + obj->filters = NULL; + } +} + +/** + * _gdk_window_destroy_hierarchy: + * @window: a #GdkWindow + * @recursing: If TRUE, then this is being called because a parent + * was destroyed. + * @recursing_native: If TRUE, then this is being called because a native parent * was destroyed. This generally means that the call to the * windowing system to destroy the window can be omitted, since * it will be destroyed as a result of the parent being destroyed. @@ -478,12 +1378,14 @@ window_remove_filters (GdkWindow *window) static void _gdk_window_destroy_hierarchy (GdkWindow *window, gboolean recursing, + gboolean recursing_native, gboolean foreign_destroy) { GdkWindowObject *private; GdkWindowObject *temp_private; GdkWindow *temp_window; GdkScreen *screen; + GdkDisplay *display; GList *children; GList *tmp; @@ -494,11 +1396,13 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, if (GDK_WINDOW_DESTROYED (window)) return; + display = gdk_drawable_get_display (GDK_DRAWABLE (window)); screen = gdk_drawable_get_screen (GDK_DRAWABLE (window)); temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window); if (temp_window == window) g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL); + switch (GDK_WINDOW_TYPE (window)) { case GDK_WINDOW_ROOT: @@ -513,6 +1417,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, case GDK_WINDOW_DIALOG: case GDK_WINDOW_TEMP: case GDK_WINDOW_FOREIGN: + case GDK_WINDOW_OFFSCREEN: if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN && !foreign_destroy) { /* Logically, it probably makes more sense to send @@ -533,16 +1438,21 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, } else { - private->state |= GDK_WINDOW_STATE_WITHDRAWN; - if (private->parent) { GdkWindowObject *parent_private = (GdkWindowObject *)private->parent; + if (parent_private->children) parent_private->children = g_list_remove (parent_private->children, window); + + if (!recursing && + GDK_WINDOW_IS_MAPPED (window)) + { + recompute_visible_regions (private, TRUE, FALSE); + gdk_window_invalidate_in_parent (private); + } } - _gdk_window_clear_update_area (window); gdk_window_free_paint_stack (window); if (private->bg_pixmap && @@ -568,13 +1478,34 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, temp_private = (GdkWindowObject*) temp_window; if (temp_private) _gdk_window_destroy_hierarchy (temp_window, - TRUE, foreign_destroy); + TRUE, + recursing_native || gdk_window_has_impl (private), + foreign_destroy); } g_list_free (children); } + + _gdk_window_clear_update_area (window); - _gdk_windowing_window_destroy (window, recursing, foreign_destroy); + if (private->cairo_surface) + { + cairo_surface_finish (private->cairo_surface); + cairo_surface_set_user_data (private->cairo_surface, &gdk_window_cairo_key, + NULL, NULL); + } + + if (gdk_window_has_impl (private)) + { + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->destroy (window, recursing_native, foreign_destroy); + } + else + { + /* hide to make sure we repaint and break grabs */ + gdk_window_hide (window); + } + + private->state |= GDK_WINDOW_STATE_WITHDRAWN; private->parent = NULL; private->destroyed = TRUE; @@ -587,6 +1518,12 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, gdk_window_redirect_free (private->redirect); private->redirect = NULL; + + if (display->pointer_info.toplevel_under_pointer == window) + { + g_object_unref (display->pointer_info.toplevel_under_pointer); + display->pointer_info.toplevel_under_pointer = NULL; + } } break; } @@ -607,7 +1544,7 @@ void _gdk_window_destroy (GdkWindow *window, gboolean foreign_destroy) { - _gdk_window_destroy_hierarchy (window, FALSE, foreign_destroy); + _gdk_window_destroy_hierarchy (window, FALSE, FALSE, foreign_destroy); } /** @@ -625,7 +1562,7 @@ _gdk_window_destroy (GdkWindow *window, void gdk_window_destroy (GdkWindow *window) { - _gdk_window_destroy_hierarchy (window, FALSE, FALSE); + _gdk_window_destroy_hierarchy (window, FALSE, FALSE, FALSE); g_object_unref (window); } @@ -744,6 +1681,10 @@ gdk_window_get_parent (GdkWindow *window) * @window: a #GdkWindow * * Gets the toplevel window that's an ancestor of @window. + * + * Any window type but %GDK_WINDOW_CHILD is considered a + * toplevel window, as is a %GDK_WINDOW_CHILD window that + * has a root window as parent. * * Return value: the toplevel window containing @window **/ @@ -755,8 +1696,14 @@ gdk_window_get_toplevel (GdkWindow *window) g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); obj = (GdkWindowObject *)window; + while (GDK_WINDOW_TYPE (obj) == GDK_WINDOW_CHILD) - obj = (GdkWindowObject *)obj->parent; + { + if (obj->parent == NULL || + GDK_WINDOW_TYPE (obj->parent) == GDK_WINDOW_ROOT) + break; + obj = obj->parent; + } return GDK_WINDOW (obj); } @@ -835,6 +1782,11 @@ gdk_window_add_filter (GdkWindow *window, private = (GdkWindowObject*) window; if (private && GDK_WINDOW_DESTROYED (window)) return; + + /* Filters are for the native events on the native window, so + ensure there is a native window. */ + if (window) + gdk_window_set_has_native (window, TRUE); if (private) tmp_list = private->filters; @@ -1036,6 +1988,119 @@ gdk_window_get_state (GdkWindow *window) return private->state; } + +/* This creates an empty "implicit" paint region for the impl window. + * By itself this does nothing, but real paints to this window + * or children of it can use this pixmap as backing to avoid allocating + * multiple pixmaps for subwindow rendering. When doing so they + * add to the region of the implicit paint region, which will be + * pushed to the window when the implicit paint region is ended. + * Such paints should not copy anything to the window on paint end, but + * should rely on the implicit paint end. + * The implicit paint will be automatically ended if someone draws + * directly to the window or a child window. + */ +static gboolean +gdk_window_begin_implicit_paint (GdkWindow *window, GdkRectangle *rect) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowPaint *paint; + + g_assert (gdk_window_has_impl (private)); + + if (GDK_IS_PAINTABLE (private->impl)) + return FALSE; /* Implementation does double buffering */ + + if (private->paint_stack != NULL || + private->implicit_paint != NULL) + return FALSE; /* Don't stack implicit paints */ + + paint = g_new (GdkWindowPaint, 1); + paint->region = gdk_region_new (); /* Empty */ + paint->x_offset = rect->x; + paint->y_offset = rect->y; + paint->uses_implicit = FALSE; + paint->surface = NULL; + paint->pixmap = + gdk_pixmap_new (window, + MAX (rect->width, 1), MAX (rect->height, 1), -1); + + private->implicit_paint = paint; + + return TRUE; +} + +/* Ensure that all content related to this (sub)window is pushed to the + native region */ +static void +gdk_window_flush_implicit_paint (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *impl_window; + GdkWindowPaint *paint; + GdkRegion *region; + GdkGC *tmp_gc; + + /* Ensure that there is no explicit paint region. */ + g_assert (private->paint_stack == NULL); + + impl_window = gdk_window_get_impl_window (private); + if (impl_window->implicit_paint == NULL) + return; + + paint = impl_window->implicit_paint; + region = gdk_region_copy (private->clip_region_with_children); + gdk_region_offset (region, private->abs_x, private->abs_y); + gdk_region_intersect (region, paint->region); + + if (!gdk_region_empty (region)) + { + /* Some regions are valid, push these to window now */ + tmp_gc = _gdk_drawable_get_scratch_gc ((GdkDrawable *)window, FALSE); + _gdk_gc_set_clip_region_internal (tmp_gc, region, TRUE); + gdk_draw_drawable (private->impl, tmp_gc, paint->pixmap, + 0, 0, paint->x_offset, paint->y_offset, -1, -1); + /* Reset clip region of the cached GdkGC */ + gdk_gc_set_clip_region (tmp_gc, NULL); + + /* Remove flushed region from the implicit paint */ + gdk_region_subtract (paint->region, region); + } + else + gdk_region_destroy (region); +} + +/* Ends an implicit paint, paired with gdk_window_begin_implicit_paint returning TRUE */ +static void +gdk_window_end_implicit_paint (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowPaint *paint; + GdkGC *tmp_gc; + + g_assert (gdk_window_has_impl (private)); + + g_assert (private->implicit_paint != NULL); + + paint = private->implicit_paint; + + private->implicit_paint = NULL; + + if (!gdk_region_empty (paint->region)) + { + /* Some regions are valid, push these to window now */ + tmp_gc = _gdk_drawable_get_scratch_gc ((GdkDrawable *)window, FALSE); + _gdk_gc_set_clip_region_internal (tmp_gc, paint->region, TRUE); + gdk_draw_drawable (private->impl, tmp_gc, paint->pixmap, + 0, 0, paint->x_offset, paint->y_offset, -1, -1); + /* Reset clip region of the cached GdkGC */ + gdk_gc_set_clip_region (tmp_gc, NULL); + } + + g_object_unref (paint->pixmap); + g_free (paint); +} + /** * gdk_window_begin_paint_rect: * @window: a #GdkWindow @@ -1115,7 +2180,8 @@ gdk_window_begin_paint_region (GdkWindow *window, #ifdef USE_BACKING_STORE GdkWindowObject *private = (GdkWindowObject *)window; GdkRectangle clip_box; - GdkWindowPaint *paint; + GdkWindowPaint *paint, *implicit_paint; + GdkWindowObject *impl_window; GSList *list; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -1128,24 +2194,63 @@ gdk_window_begin_paint_region (GdkWindow *window, GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl); if (iface->begin_paint_region) - iface->begin_paint_region ((GdkPaintable*)private->impl, region); - + iface->begin_paint_region ((GdkPaintable*)private->impl, window, region); + return; } - gdk_region_get_clipbox (region, &clip_box); + impl_window = gdk_window_get_impl_window (private); + implicit_paint = impl_window->implicit_paint; paint = g_new (GdkWindowPaint, 1); paint->region = gdk_region_copy (region); - paint->x_offset = clip_box.x; - paint->y_offset = clip_box.y; - paint->pixmap = - gdk_pixmap_new (window, - MAX (clip_box.width, 1), MAX (clip_box.height, 1), -1); + paint->region_tag = new_region_tag (); + + gdk_region_intersect (paint->region, private->clip_region_with_children); + gdk_region_get_clipbox (paint->region, &clip_box); + + /* Convert to impl coords */ + gdk_region_offset (paint->region, private->abs_x, private->abs_y); + + /* Mark the region as valid on the implicit paint */ + + if (implicit_paint) + gdk_region_union (implicit_paint->region, paint->region); + + /* Convert back to normal coords */ + gdk_region_offset (paint->region, -private->abs_x, -private->abs_y); + + if (implicit_paint) + { + int width, height; + + paint->uses_implicit = TRUE; + paint->pixmap = g_object_ref (implicit_paint->pixmap); + paint->x_offset = -private->abs_x + implicit_paint->x_offset; + paint->y_offset = -private->abs_y + implicit_paint->y_offset; + + /* It would be nice if we had some cairo support here so we + could set the clip rect on the cairo surface */ + width = private->abs_x + private->width; + height = private->abs_y + private->height; + + paint->surface = _gdk_drawable_create_cairo_surface (paint->pixmap, width, height); - paint->surface = _gdk_drawable_ref_cairo_surface (paint->pixmap); - cairo_surface_set_device_offset (paint->surface, - - paint->x_offset, - paint->y_offset); + } + else + { + paint->uses_implicit = FALSE; + paint->x_offset = clip_box.x; + paint->y_offset = clip_box.y; + paint->pixmap = + gdk_pixmap_new (window, + MAX (clip_box.width, 1), MAX (clip_box.height, 1), -1); + paint->surface = _gdk_drawable_ref_cairo_surface (paint->pixmap); + } + + if (paint->surface) + cairo_surface_set_device_offset (paint->surface, + -paint->x_offset, -paint->y_offset); for (list = private->paint_stack; list != NULL; list = list->next) { @@ -1156,15 +2261,64 @@ gdk_window_begin_paint_region (GdkWindow *window, private->paint_stack = g_slist_prepend (private->paint_stack, paint); - if (!gdk_region_empty (region)) + if (!gdk_region_empty (paint->region)) { - gdk_window_clear_backing_rect (window, - clip_box.x, clip_box.y, - clip_box.width, clip_box.height); + gdk_window_clear_backing_region (window, + paint->region); } + #endif /* USE_BACKING_STORE */ } +static void +setup_redirect_clip (GdkWindow *window, + GdkGC *gc, + int *x_offset_out, + int *y_offset_out) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkRegion *visible_region; + GdkRectangle dest_rect; + GdkRegion *tmpreg; + GdkWindow *toplevel; + int x_offset, y_offset; + + toplevel = GDK_WINDOW (private->redirect->redirected); + + /* Get the clip region for gc clip rect + window hierarchy in + window relative coords */ + visible_region = + _gdk_window_calculate_full_clip_region (window, toplevel, + TRUE, + &x_offset, + &y_offset); + + /* Compensate for the source pos/size */ + x_offset -= private->redirect->src_x; + y_offset -= private->redirect->src_y; + dest_rect.x = -x_offset; + dest_rect.y = -y_offset; + dest_rect.width = private->redirect->width; + dest_rect.height = private->redirect->height; + tmpreg = gdk_region_rectangle (&dest_rect); + gdk_region_intersect (visible_region, tmpreg); + gdk_region_destroy (tmpreg); + + /* Compensate for the dest pos */ + x_offset += private->redirect->dest_x; + y_offset += private->redirect->dest_y; + + gdk_gc_set_clip_region (gc, visible_region); /* This resets clip origin! */ + + /* offset clip and tiles from window coords to pixmaps coords */ + gdk_gc_offset (gc, -x_offset, -y_offset); + + gdk_region_destroy (visible_region); + + *x_offset_out = x_offset; + *y_offset_out = y_offset; +} + /** * gdk_window_end_paint: * @window: a #GdkWindow @@ -1188,6 +2342,7 @@ gdk_window_end_paint (GdkWindow *window) GdkGC *tmp_gc; GdkRectangle clip_box; gint x_offset, y_offset; + GdkRegion *full_clip; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -1210,36 +2365,44 @@ gdk_window_end_paint (GdkWindow *window) } paint = private->paint_stack->data; + private->paint_stack = g_slist_delete_link (private->paint_stack, - private->paint_stack); + private->paint_stack); gdk_region_get_clipbox (paint->region, &clip_box); tmp_gc = _gdk_drawable_get_scratch_gc (window, FALSE); - 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); + x_offset = -private->abs_x; + y_offset = -private->abs_y; - gdk_draw_drawable (private->impl, tmp_gc, paint->pixmap, - clip_box.x - paint->x_offset, - clip_box.y - paint->y_offset, - clip_box.x - x_offset, clip_box.y - y_offset, - clip_box.width, clip_box.height); - - if (private->redirect) + if (!paint->uses_implicit) { - GdkWindowClipData data; + gdk_window_flush_outstanding_moves (window); - setup_redirect_clip (window, tmp_gc, &data); + full_clip = gdk_region_copy (private->clip_region_with_children); + gdk_region_intersect (full_clip, paint->region); + _gdk_gc_set_clip_region_internal (tmp_gc, full_clip, TRUE); /* Takes ownership of full_clip */ + gdk_gc_set_clip_origin (tmp_gc, - x_offset, - y_offset); + gdk_draw_drawable (private->impl, tmp_gc, paint->pixmap, + clip_box.x - paint->x_offset, + clip_box.y - paint->y_offset, + clip_box.x - x_offset, clip_box.y - y_offset, + clip_box.width, clip_box.height); + } + + if (private->redirect) + { + int x_offset, y_offset; + + /* TODO: Should also use paint->region for clipping */ + setup_redirect_clip (window, tmp_gc, &x_offset, &y_offset); gdk_draw_drawable (private->redirect->pixmap, tmp_gc, paint->pixmap, clip_box.x - paint->x_offset, clip_box.y - paint->y_offset, - clip_box.x + data.x_offset, - clip_box.y + data.y_offset, + clip_box.x + x_offset, + clip_box.y + y_offset, clip_box.width, clip_box.height); - reset_redirect_clip (window, tmp_gc, &data); } /* Reset clip region of the cached GdkGC */ @@ -1307,6 +2470,295 @@ gdk_window_free_paint_stack (GdkWindow *window) } } +static void +do_move_region_bits_on_impl (GdkWindowObject *impl_window, + GdkRegion *dest_region, /* In impl window coords */ + int dx, int dy) +{ + GdkGC *tmp_gc; + GdkRectangle copy_rect; + GdkWindowObject *private; + + /* We need to get data from subwindows here, because we might have + * shaped a native window over the moving region (with bg none, + * so the pixels are still there). In fact we might need to get data + * from overlapping native window that are not children of this window, + * so we copy from the toplevel with INCLUDE_INFERIORS. + */ + private = impl_window; + while (private->parent != NULL && + GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT) + { + dx -= private->parent->abs_x + private->x; + dy -= private->parent->abs_y + private->y; + private = gdk_window_get_impl_window (private->parent); + } + tmp_gc = _gdk_drawable_get_subwindow_scratch_gc ((GdkWindow *)private); + + /* The region area is moved and we queue translations for all expose events + to the source area that were sent prior to the copy */ + gdk_region_offset (dest_region, -dx, -dy); /* Temporarily move to source area */ + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_translation ((GdkWindow *)impl_window, + dest_region, dx, dy); + gdk_region_offset (dest_region, dx, dy); /* back to dest area */ + + gdk_region_get_clipbox (dest_region, ©_rect); + + gdk_gc_set_clip_region (tmp_gc, dest_region); + gdk_draw_drawable (impl_window->impl, + tmp_gc, + private->impl, + copy_rect.x-dx, copy_rect.y-dy, + copy_rect.x, copy_rect.y, + copy_rect.width, copy_rect.height); + gdk_gc_set_clip_region (tmp_gc, NULL); +} + +static GdkWindowRegionMove * +gdk_window_region_move_new (GdkRegion *region, + int dx, int dy) +{ + GdkWindowRegionMove *move; + + move = g_slice_new (GdkWindowRegionMove); + move->dest_region = gdk_region_copy (region); + move->dx = dx; + move->dy = dy; + + return move; +} + +static void +gdk_window_region_move_free (GdkWindowRegionMove *move) +{ + gdk_region_destroy (move->dest_region); + g_slice_free (GdkWindowRegionMove, move); +} + +static void +append_move_region (GdkWindowObject *impl_window, + GdkRegion *new_dest_region, + int dx, int dy) +{ + GdkWindowRegionMove *move, *old_move; + GdkRegion *new_total_region, *old_total_region; + GdkRegion *source_overlaps_destination; + GdkRegion *non_overwritten; + gboolean added_move; + GList *l, *prev; + + if (gdk_region_empty (new_dest_region)) + return; + + /* In principle this could just append the move to the list of outstanding + moves that will be replayed before drawing anything when we're handling + exposes. However, we'd like to do a bit better since its commonly the case + that we get multiple copies where A is copied to B and then B is copied + to C, and we'd like to express this as a simple copy A to C operation. */ + + /* We approach this by taking the new move and pushing it ahead of moves + starting at the end of the list and stopping when its not safe to do so. + Its not safe to push past a move is either the source of the new move + is in the destination of the old move, or if the destination of the new + move is in the source of the new move, or if the destination of the new + move overlaps the destination of the old move. We simplify this by + just comparing the total regions (src + dest) */ + new_total_region = gdk_region_copy (new_dest_region); + gdk_region_offset (new_total_region, -dx, -dy); + gdk_region_union (new_total_region, new_dest_region); + + added_move = FALSE; + for (l = g_list_last (impl_window->outstanding_moves); l != NULL; l = prev) + { + prev = l->prev; + old_move = l->data; + + old_total_region = gdk_region_copy (old_move->dest_region); + gdk_region_offset (old_total_region, -old_move->dx, -old_move->dy); + gdk_region_union (old_total_region, old_move->dest_region); + + gdk_region_intersect (old_total_region, new_total_region); + /* If these regions intersect then its not safe to push the + new region before the old one */ + if (!gdk_region_empty (old_total_region)) + { + /* The area where the new moves source overlaps the old ones + destination */ + source_overlaps_destination = gdk_region_copy (new_dest_region); + gdk_region_offset (source_overlaps_destination, -dx, -dy); + gdk_region_intersect (source_overlaps_destination, old_move->dest_region); + gdk_region_offset (source_overlaps_destination, dx, dy); + + /* We can do all sort of optimizations here, but to do things safely it becomes + quite complicated. However, a very common case is that you copy something first, + then copy all that or a subset of it to a new location (i.e. if you scroll twice + in the same direction). We'd like to detect this case and optimize it to one + copy. */ + if (gdk_region_equal (source_overlaps_destination, new_dest_region)) + { + /* This means we might be able to replace the old move and the new one + with the new one read from the old ones source, and a second copy of + the non-overwritten parts of the old move. However, such a split + is only valid if the source in the old move isn't overwritten + by the destination of the new one */ + + /* the new destination of old move if split is ok: */ + non_overwritten = gdk_region_copy (old_move->dest_region); + gdk_region_subtract (non_overwritten, new_dest_region); + /* move to source region */ + gdk_region_offset (non_overwritten, -old_move->dx, -old_move->dy); + + gdk_region_intersect (non_overwritten, new_dest_region); + if (gdk_region_empty (non_overwritten)) + { + added_move = TRUE; + move = gdk_window_region_move_new (new_dest_region, + dx + old_move->dx, + dy + old_move->dy); + + impl_window->outstanding_moves = + g_list_insert_before (impl_window->outstanding_moves, + l, move); + gdk_region_subtract (old_move->dest_region, new_dest_region); + } + gdk_region_destroy (non_overwritten); + } + + gdk_region_destroy (source_overlaps_destination); + gdk_region_destroy (old_total_region); + break; + } + gdk_region_destroy (old_total_region); + } + + gdk_region_destroy (new_total_region); + + if (!added_move) + { + move = gdk_window_region_move_new (new_dest_region, dx, dy); + + if (l == NULL) + impl_window->outstanding_moves = + g_list_prepend (impl_window->outstanding_moves, + move); + else + impl_window->outstanding_moves = + g_list_insert_before (impl_window->outstanding_moves, + l->next, move); + } +} + +/* Moves bits and update area by dx/dy in impl window, + takes ownership of region */ +static void +move_region_on_impl (GdkWindowObject *private, + GdkRegion *region, /* In impl window coords */ + int dx, int dy) +{ + GdkWindowObject *impl_window; + + if ((dx == 0 && dy == 0) || + gdk_region_empty (region)) + { + gdk_region_destroy (region); + return; + } + + impl_window = gdk_window_get_impl_window (private); + + /* Move any old invalid regions in the copy source area by dx/dy */ + if (impl_window->update_area) + { + GdkRegion *update_area; + update_area = gdk_region_copy (region); + + /* Convert from target to source */ + gdk_region_offset (update_area, -dx, -dy); + gdk_region_intersect (update_area, impl_window->update_area); + gdk_region_subtract (impl_window->update_area, update_area); + + /* Convert back */ + gdk_region_offset (update_area, dx, dy); + gdk_region_union (impl_window->update_area, update_area); + + /* This area of the destination is now invalid, + so no need to copy to it. */ + gdk_region_subtract (region, update_area); + + gdk_region_destroy (update_area); + } + + if (1) /* Enable flicker free handling of moves. */ + append_move_region (impl_window, region, dx, dy); + else + do_move_region_bits_on_impl (impl_window, + region, dx, dy); + + gdk_region_destroy (region); +} + +/* Flushes all outstanding changes to the window, call this + * before drawing directly to the window (i.e. outside a begin/end_paint pair). + */ +static void +gdk_window_flush_outstanding_moves (GdkWindow *window) +{ + GdkWindowObject *private; + GdkWindowObject *impl_window; + GList *l; + GdkWindowRegionMove *move; + + private = (GdkWindowObject *) window; + + impl_window = gdk_window_get_impl_window (private); + + for (l = impl_window->outstanding_moves; l != NULL; l = l->next) + { + move = l->data; + + do_move_region_bits_on_impl (impl_window, + move->dest_region, move->dx, move->dy); + + gdk_window_region_move_free (move); + } + + g_list_free (impl_window->outstanding_moves); + impl_window->outstanding_moves = NULL; +} + +static void +gdk_window_flush (GdkWindow *window) +{ + gdk_window_flush_outstanding_moves (window); + gdk_window_flush_implicit_paint (window); +} + +static void +gdk_window_flush_recursive_helper (GdkWindowObject *window, + GdkWindow *impl) +{ + GdkWindowObject *child; + GList *l; + + for (l = window->children; l != NULL; l = l->next) + { + child = l->data; + + if (child->impl == impl) + /* Same impl, ignore */ + gdk_window_flush_recursive_helper (child, impl); + else + gdk_window_flush_recursive (child); + } +} + +static void +gdk_window_flush_recursive (GdkWindowObject *window) +{ + gdk_window_flush ((GdkWindow *)window); + gdk_window_flush_recursive_helper (window, window->impl); +} + static void gdk_window_get_offsets (GdkWindow *window, gint *x_offset, @@ -1321,7 +2773,10 @@ gdk_window_get_offsets (GdkWindow *window, *y_offset = paint->y_offset; } else - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, x_offset, y_offset); + { + *x_offset = -private->abs_x; + *y_offset = -private->abs_y; + } } /** @@ -1369,7 +2824,12 @@ gdk_window_get_internal_paint_info (GdkWindow *window, *real_drawable = paint->pixmap; } else - *real_drawable = window; + { + /* This means you're probably gonna be doing some weird shit + directly to the window, so we flush all outstanding stuff */ + gdk_window_flush (window); + *real_drawable = window; + } } gdk_window_get_offsets (window, &x_off, &y_off); @@ -1380,6 +2840,46 @@ gdk_window_get_internal_paint_info (GdkWindow *window, *y_offset = y_off; } +static void +setup_clip_for_draw (GdkDrawable *drawable, + GdkGC *gc, + int old_clip_x, int old_clip_y) +{ + GdkWindowObject *private = (GdkWindowObject *)drawable; + GdkRegion *clip; + + if (private->window_type == GDK_WINDOW_ROOT) + return; + + if (_gdk_gc_get_subwindow (gc) == GDK_CLIP_BY_CHILDREN) + clip = private->clip_region_with_children; + else + clip = private->clip_region; + + _gdk_gc_add_drawable_clip (gc, + private->clip_tag, + clip, + /* If there was a clip origin set appart from the + * window offset, need to take that into consideration */ + -old_clip_x, -old_clip_y); +} + +static void +setup_clip_for_paint (GdkDrawable *drawable, + GdkWindowPaint *paint, + GdkGC *gc, + int old_clip_x, int old_clip_y) +{ + _gdk_gc_add_drawable_clip (gc, + paint->region_tag, + /* This includes the window clip */ + paint->region, + /* If there was a clip origin set appart from the + * window offset, need to take that into consideration */ + -old_clip_x, -old_clip_y); +} + + #define OFFSET_GC(gc) \ gint x_offset, y_offset; \ gint old_clip_x = gc->clip_x_origin; \ @@ -1402,6 +2902,20 @@ gdk_window_get_internal_paint_info (GdkWindow *window, gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y); \ } +#define SETUP_PAINT_GC_CLIP(gc) \ + if (paint->uses_implicit) \ + setup_clip_for_paint (drawable, paint, gc, old_clip_x, \ + old_clip_y); + +#define RESTORE_PAINT_GC_CLIP(gc) + + +#define SETUP_DIRECT_GC_CLIP(gc) \ + gdk_window_flush ((GdkWindow *)drawable);\ + setup_clip_for_draw (drawable, gc, old_clip_x, old_clip_y); + +#define RESTORE_DIRECT_GC_CLIP(gc) + static GdkGC * gdk_window_create_gc (GdkDrawable *drawable, GdkGCValues *values, @@ -1416,6 +2930,16 @@ gdk_window_create_gc (GdkDrawable *drawable, values, mask); } +/* After having set up the drawable clip rect on a GC we need + * to make sure that if we draw to a pixmap we draw to the impl, + * otherwise the pixmap code will reset the drawable clip. + */ +static GdkDrawable * +pixmap_impl (GdkPixmap *pixmap) +{ + return ((GdkPixmapObject *)pixmap)->impl; +} + static void gdk_window_draw_rectangle (GdkDrawable *drawable, GdkGC *gc, @@ -1434,12 +2958,18 @@ gdk_window_draw_rectangle (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_rectangle (paint->pixmap, gc, filled, + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_rectangle (pixmap_impl (paint->pixmap), gc, filled, x - x_offset, y - y_offset, width, height); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_rectangle (private->impl, gc, filled, - x - x_offset, y - y_offset, width, height); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_rectangle (private->impl, gc, filled, + x - x_offset, y - y_offset, width, height); + RESTORE_DIRECT_GC_CLIP(gc); + } RESTORE_GC (gc); } @@ -1464,14 +2994,20 @@ gdk_window_draw_arc (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_arc (paint->pixmap, gc, filled, + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_arc (pixmap_impl (paint->pixmap), gc, filled, x - x_offset, y - y_offset, width, height, angle1, angle2); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_arc (private->impl, gc, filled, - x - x_offset, y - y_offset, - width, height, angle1, angle2); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_arc (private->impl, gc, filled, + x - x_offset, y - y_offset, + width, height, angle1, angle2); + RESTORE_DIRECT_GC_CLIP(gc); + } RESTORE_GC (gc); } @@ -1507,11 +3043,16 @@ gdk_window_draw_polygon (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_polygon (paint->pixmap, gc, filled, new_points, npoints); - + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_polygon (pixmap_impl (paint->pixmap), gc, filled, new_points, npoints); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_polygon (private->impl, gc, filled, new_points, npoints); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_polygon (private->impl, gc, filled, new_points, npoints); + RESTORE_DIRECT_GC_CLIP(gc); + } if (new_points != points) g_free (new_points); @@ -1537,13 +3078,19 @@ gdk_window_draw_text (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_text (paint->pixmap, font, gc, + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_text (pixmap_impl (paint->pixmap), font, gc, x - x_offset, y - y_offset, text, text_length); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_text (private->impl, font, gc, - x - x_offset, y - y_offset, text, text_length); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_text (private->impl, font, gc, + x - x_offset, y - y_offset, text, text_length); + RESTORE_DIRECT_GC_CLIP(gc); + } RESTORE_GC (gc); } @@ -1566,17 +3113,36 @@ gdk_window_draw_text_wc (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_text_wc (paint->pixmap, font, gc, + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_text_wc (pixmap_impl (paint->pixmap), font, gc, x - x_offset, y - y_offset, text, text_length); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_text_wc (private->impl, font, gc, - x - x_offset, y - y_offset, text, text_length); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_text_wc (private->impl, font, gc, + x - x_offset, y - y_offset, text, text_length); + RESTORE_DIRECT_GC_CLIP(gc); + } RESTORE_GC (gc); } -static GdkDrawable* +static GdkDrawable * +gdk_window_get_source_drawable (GdkDrawable *drawable) +{ + GdkWindow *window = GDK_WINDOW (drawable); + GdkWindowObject *private; + + private = (GdkWindowObject *) window; + if (GDK_DRAWABLE_GET_CLASS (private->impl)->get_source_drawable) + return GDK_DRAWABLE_GET_CLASS (private->impl)->get_source_drawable (private->impl); + + return drawable; +} + +static GdkDrawable * gdk_window_get_composite_drawable (GdkDrawable *drawable, gint x, gint y, @@ -1591,19 +3157,17 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable, GdkRectangle rect; GdkGC *tmp_gc; gboolean overlap_buffer; + GdkDrawable *source; + GdkWindowObject *impl_window; + GdkWindowPaint *implicit_paint; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (GDK_WINDOW (drawable), - composite_x_offset, - composite_y_offset); - - if ((GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable)) - || private->paint_stack == NULL) - { - /* No backing store */ - return g_object_ref (drawable); - } + *composite_x_offset = -private->abs_x; + *composite_y_offset = -private->abs_y; - /* See if the buffered part is overlapping the part we want + if ((GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))) + return g_object_ref (_gdk_drawable_get_source_drawable (drawable)); + + /* See if any buffered part is overlapping the part we want * to get */ rect.x = x; @@ -1612,14 +3176,14 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable, rect.height = height; overlap_buffer = FALSE; - + for (list = private->paint_stack; list != NULL; list = list->next) { GdkWindowPaint *paint = list->data; GdkOverlapType overlap; - + overlap = gdk_region_rect_in (paint->region, &rect); - + if (overlap == GDK_OVERLAP_RECTANGLE_IN) { *composite_x_offset = paint->x_offset; @@ -1634,26 +3198,65 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable, } } - if (!overlap_buffer) - return g_object_ref (drawable); + impl_window = gdk_window_get_impl_window (private); + implicit_paint = impl_window->implicit_paint; + if (implicit_paint) + { + GdkOverlapType overlap; + + rect.x += private->abs_x; + rect.y += private->abs_y; + + overlap = gdk_region_rect_in (implicit_paint->region, &rect); + if (overlap == GDK_OVERLAP_RECTANGLE_IN) + { + *composite_x_offset = -private->abs_x + implicit_paint->x_offset; + *composite_y_offset = -private->abs_y + implicit_paint->y_offset; + + return g_object_ref (implicit_paint->pixmap); + } + else if (overlap == GDK_OVERLAP_RECTANGLE_PART) + overlap_buffer = TRUE; + } + if (!overlap_buffer) + return g_object_ref (_gdk_drawable_get_source_drawable (drawable)); + tmp_pixmap = gdk_pixmap_new (drawable, width, height, -1); tmp_gc = _gdk_drawable_get_scratch_gc (tmp_pixmap, FALSE); + source = _gdk_drawable_get_source_drawable (drawable); + /* Copy the current window contents */ gdk_draw_drawable (tmp_pixmap, tmp_gc, - private->impl, + GDK_WINDOW_OBJECT (source)->impl, x - *composite_x_offset, y - *composite_y_offset, 0, 0, width, height); /* paint the backing stores */ + if (implicit_paint) + { + GdkWindowPaint *paint = list->data; + + gdk_gc_set_clip_region (tmp_gc, paint->region); + gdk_gc_set_clip_origin (tmp_gc, -x - paint->x_offset, -y - paint->y_offset); + + gdk_draw_drawable (tmp_pixmap, tmp_gc, paint->pixmap, + x - paint->x_offset, + y - paint->y_offset, + 0, 0, width, height); + } + for (list = private->paint_stack; list != NULL; list = list->next) { GdkWindowPaint *paint = list->data; + if (paint->uses_implicit) + continue; /* We already copied this above */ + gdk_gc_set_clip_region (tmp_gc, paint->region); gdk_gc_set_clip_origin (tmp_gc, -x, -y); @@ -1662,7 +3265,7 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable, y - paint->y_offset, 0, 0, width, height); } - + /* Reset clip region of the cached GdkGC */ gdk_gc_set_clip_region (tmp_gc, NULL); @@ -1679,7 +3282,7 @@ gdk_window_get_clip_region (GdkDrawable *drawable) GdkWindowObject *private = (GdkWindowObject *)drawable; GdkRegion *result; - result = gdk_drawable_get_clip_region (private->impl); + result = gdk_region_copy (private->clip_region); if (private->paint_stack) { @@ -1706,8 +3309,8 @@ static GdkRegion* gdk_window_get_visible_region (GdkDrawable *drawable) { GdkWindowObject *private = (GdkWindowObject*) drawable; - - return gdk_drawable_get_visible_region (private->impl); + + return gdk_region_copy (private->clip_region); } static void @@ -1731,16 +3334,22 @@ gdk_window_draw_drawable (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_drawable (paint->pixmap, gc, + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_drawable (pixmap_impl (paint->pixmap), gc, src, xsrc, ysrc, xdest - x_offset, ydest - y_offset, width, height); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_drawable (private->impl, gc, - src, xsrc, ysrc, - xdest - x_offset, ydest - y_offset, - width, height); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_drawable (private->impl, gc, + src, xsrc, ysrc, + xdest - x_offset, ydest - y_offset, + width, height); + RESTORE_DIRECT_GC_CLIP(gc); + } RESTORE_GC (gc); } @@ -1776,10 +3385,16 @@ gdk_window_draw_points (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_points (paint->pixmap, gc, new_points, npoints); + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_points (pixmap_impl (paint->pixmap), gc, new_points, npoints); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_points (private->impl, gc, points, npoints); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_points (private->impl, gc, new_points, npoints); + RESTORE_DIRECT_GC_CLIP(gc); + } if (new_points != points) g_free (new_points); @@ -1820,10 +3435,16 @@ gdk_window_draw_segments (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_segments (paint->pixmap, gc, new_segs, nsegs); + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_segments (pixmap_impl (paint->pixmap), gc, new_segs, nsegs); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_segments (private->impl, gc, new_segs, nsegs); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_segments (private->impl, gc, new_segs, nsegs); + RESTORE_DIRECT_GC_CLIP(gc); + } if (new_segs != segs) g_free (new_segs); @@ -1862,10 +3483,16 @@ gdk_window_draw_lines (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_lines (paint->pixmap, gc, new_points, npoints); + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_lines (pixmap_impl (paint->pixmap), gc, new_points, npoints); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_lines (private->impl, gc, new_points, npoints); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_lines (private->impl, gc, new_points, npoints); + RESTORE_DIRECT_GC_CLIP(gc); + } if (new_points != points) g_free (new_points); @@ -1892,11 +3519,17 @@ gdk_window_draw_glyphs (GdkDrawable *drawable, { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_glyphs (paint->pixmap, gc, font, x - x_offset, y - y_offset, glyphs); + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_glyphs (pixmap_impl (paint->pixmap), gc, font, x - x_offset, y - y_offset, glyphs); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_glyphs (private->impl, gc, font, - x - x_offset, y - y_offset, glyphs); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_glyphs (private->impl, gc, font, + x - x_offset, y - y_offset, glyphs); + RESTORE_DIRECT_GC_CLIP(gc); + } RESTORE_GC (gc); } @@ -1947,10 +3580,16 @@ gdk_window_draw_glyphs_transformed (GdkDrawable *drawable, { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_glyphs_transformed (paint->pixmap, gc, matrix, font, x, y, glyphs); + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_glyphs_transformed (pixmap_impl (paint->pixmap), gc, matrix, font, x, y, glyphs); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_glyphs_transformed (private->impl, gc, matrix, font, x, y, glyphs); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_glyphs_transformed (private->impl, gc, matrix, font, x, y, glyphs); + RESTORE_DIRECT_GC_CLIP(gc); + } RESTORE_GC (gc); } @@ -2039,15 +3678,14 @@ setup_backing_rect_method (BackingRectMethod *method, GdkWindow *window, GdkWind } static void -gdk_window_clear_backing_rect (GdkWindow *window, - gint x, - gint y, - gint width, - gint height) +gdk_window_clear_backing_region (GdkWindow *window, + GdkRegion *region) { GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowPaint *paint = private->paint_stack->data; BackingRectMethod method; + GdkRegion *clip; + GdkRectangle clipbox; #if 0 GTimer *timer; double elapsed; @@ -2064,14 +3702,16 @@ gdk_window_clear_backing_rect (GdkWindow *window, method.gc = NULL; setup_backing_rect_method (&method, window, paint, 0, 0); + clip = gdk_region_copy (paint->region); + gdk_region_intersect (clip, region); + gdk_region_get_clipbox (clip, &clipbox); + + if (method.cr) { g_assert (method.gc == NULL); - cairo_rectangle (method.cr, x, y, width, height); - cairo_clip (method.cr); - - gdk_cairo_region (method.cr, paint->region); + gdk_cairo_region (method.cr, clip); cairo_fill (method.cr); cairo_destroy (method.cr); @@ -2084,8 +3724,10 @@ gdk_window_clear_backing_rect (GdkWindow *window, { g_assert (method.gc != NULL); - gdk_gc_set_clip_region (method.gc, paint->region); - gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height); + gdk_gc_set_clip_region (method.gc, clip); + gdk_draw_rectangle (window, method.gc, TRUE, + clipbox.x, clipbox.y, + clipbox.width, clipbox.height); g_object_unref (method.gc); #if 0 @@ -2094,21 +3736,21 @@ gdk_window_clear_backing_rect (GdkWindow *window, #endif } + gdk_region_destroy (clip); + #if 0 g_timer_destroy (timer); #endif } static void -gdk_window_clear_backing_rect_redirect (GdkWindow *window, - gint x, - gint y, - gint width, - gint height) +gdk_window_clear_backing_region_redirect (GdkWindow *window, + GdkRegion *region) { GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowRedirect *redirect = private->redirect; GdkRegion *clip_region; + GdkRectangle clipbox; gint x_offset, y_offset; BackingRectMethod method; GdkWindowPaint paint; @@ -2116,25 +3758,25 @@ gdk_window_clear_backing_rect_redirect (GdkWindow *window, if (GDK_WINDOW_DESTROYED (window)) return; - paint.x_offset = 0; - paint.y_offset = 0; - paint.pixmap = redirect->pixmap; - paint.surface = _gdk_drawable_ref_cairo_surface (redirect->pixmap); - clip_region = _gdk_window_calculate_full_clip_region (window, GDK_WINDOW (redirect->redirected), - NULL, TRUE, + TRUE, &x_offset, &y_offset); + gdk_region_intersect (clip_region, region); + /* offset is from redirected window origin to window origin, convert to the offset from the redirected pixmap origin to the window origin */ x_offset += redirect->dest_x - redirect->src_x; y_offset += redirect->dest_y - redirect->src_y; - /* Convert region and rect to pixmap coords */ + /* Convert region to pixmap coords */ gdk_region_offset (clip_region, x_offset, y_offset); - x += x_offset; - y += y_offset; - + + paint.x_offset = 0; + paint.y_offset = 0; + paint.pixmap = redirect->pixmap; + paint.surface = _gdk_drawable_ref_cairo_surface (redirect->pixmap); + method.cr = NULL; method.gc = NULL; setup_backing_rect_method (&method, window, &paint, -x_offset, -y_offset); @@ -2143,9 +3785,6 @@ gdk_window_clear_backing_rect_redirect (GdkWindow *window, { g_assert (method.gc == NULL); - cairo_rectangle (method.cr, x, y, width, height); - cairo_clip (method.cr); - gdk_cairo_region (method.cr, clip_region); cairo_fill (method.cr); @@ -2155,8 +3794,11 @@ gdk_window_clear_backing_rect_redirect (GdkWindow *window, { g_assert (method.gc != NULL); + gdk_region_get_clipbox (clip_region, &clipbox); gdk_gc_set_clip_region (method.gc, clip_region); - gdk_draw_rectangle (redirect->pixmap, method.gc, TRUE, x, y, width, height); + gdk_draw_rectangle (redirect->pixmap, method.gc, TRUE, + clipbox.x, clipbox.y, + clipbox.width, clipbox.height); g_object_unref (method.gc); } @@ -2165,6 +3807,57 @@ gdk_window_clear_backing_rect_redirect (GdkWindow *window, cairo_surface_destroy (paint.surface); } +static void +gdk_window_clear_backing_region_direct (GdkWindow *window, + GdkRegion *region) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + BackingRectMethod method; + GdkWindowPaint paint; + GdkRegion *clip; + GdkRectangle clipbox; + + if (GDK_WINDOW_DESTROYED (window)) + return; + + paint.x_offset = 0; + paint.y_offset = 0; + paint.pixmap = window; + paint.surface = _gdk_drawable_ref_cairo_surface (window); + + method.cr = NULL; + method.gc = NULL; + setup_backing_rect_method (&method, window, &paint, 0, 0); + + clip = gdk_region_copy (private->clip_region_with_children); + gdk_region_intersect (clip, region); + gdk_region_get_clipbox (clip, &clipbox); + + if (method.cr) + { + g_assert (method.gc == NULL); + + gdk_cairo_region (method.cr, clip); + cairo_fill (method.cr); + + cairo_destroy (method.cr); + } + else + { + g_assert (method.gc != NULL); + + gdk_gc_set_clip_region (method.gc, clip); + gdk_draw_rectangle (window, method.gc, TRUE, + clipbox.x, clipbox.y, + clipbox.width, clipbox.height); + g_object_unref (method.gc); + + } + + gdk_region_destroy (clip); + cairo_surface_destroy (paint.surface); +} + /** * gdk_window_clear: @@ -2185,6 +3878,60 @@ gdk_window_clear (GdkWindow *window) width, height); } +static void +gdk_window_clear_region_internal (GdkWindow *window, + GdkRegion *region, + gboolean send_expose) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + if (private->paint_stack) + gdk_window_clear_backing_region (window, region); + else + { + if (private->redirect) + gdk_window_clear_backing_region_redirect (window, region); + + gdk_window_clear_backing_region_direct (window, region); + if (send_expose) + gdk_window_invalidate_region (window, region, FALSE); + } +} + +static void +gdk_window_clear_area_internal (GdkWindow *window, + gint x, + gint y, + gint width, + gint height, + gboolean send_expose) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkRectangle rect; + GdkRegion *region; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + /* This is what XClearArea does, and e.g. GtkCList uses it, + so we need to duplicate that */ + if (width == 0) + width = private->width - x; + if (height == 0) + height = private->height - y; + + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + + region = gdk_region_rectangle (&rect); + gdk_window_clear_region_internal (window, + region, + FALSE); + gdk_region_destroy (region); + +} + /** * gdk_window_clear_area: * @window: a #GdkWindow @@ -2203,22 +3950,10 @@ gdk_window_clear_area (GdkWindow *window, gint width, gint height) { - GdkWindowObject *private = (GdkWindowObject *)window; - - 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_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window, - x, y, - width, height, - FALSE); - } + gdk_window_clear_area_internal (window, + x, y, + width, height, + FALSE); } /** @@ -2243,20 +3978,10 @@ gdk_window_clear_area_e (GdkWindow *window, gint width, gint height) { - GdkWindowObject *private = (GdkWindowObject *)window; - - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (private->paint_stack) - gdk_window_clear_backing_rect (window, x, y, width, height); - - if (private->redirect) - gdk_window_clear_backing_rect_redirect (window, x, y, width, height); - - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window, - x, y, - width, height, - TRUE); + gdk_window_clear_area_internal (window, + x, y, + width, height, + TRUE); } static void @@ -2280,15 +4005,21 @@ gdk_window_draw_image (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_image (paint->pixmap, gc, image, xsrc, ysrc, + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_image (pixmap_impl (paint->pixmap), gc, image, xsrc, ysrc, xdest - x_offset, ydest - y_offset, width, height); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_image (private->impl, gc, image, xsrc, ysrc, - xdest - x_offset, ydest - y_offset, - width, height); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_image (private->impl, gc, image, xsrc, ysrc, + xdest - x_offset, ydest - y_offset, + width, height); + RESTORE_DIRECT_GC_CLIP(gc); + } RESTORE_GC (gc); } @@ -2311,45 +4042,37 @@ gdk_window_draw_pixbuf (GdkDrawable *drawable, if (GDK_WINDOW_DESTROYED (drawable)) return; - - if (gc) + + /* If no gc => no user clipping, but we need clipping + for window emulation, so use a scratch gc */ + if (!gc) + gc = _gdk_drawable_get_scratch_gc (drawable, FALSE); + + /* Need block to make OFFSET_GC macro to work */ { OFFSET_GC (gc); if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_pixbuf (paint->pixmap, gc, pixbuf, src_x, src_y, + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_pixbuf (pixmap_impl (paint->pixmap), gc, pixbuf, src_x, src_y, dest_x - x_offset, dest_y - y_offset, width, height, dither, x_dither - x_offset, y_dither - y_offset); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y, - dest_x - x_offset, dest_y - y_offset, - width, height, - dither, x_dither, y_dither); - - RESTORE_GC (gc); - } - else - { - gint x_offset, y_offset; - gdk_window_get_offsets (drawable, &x_offset, &y_offset); - - if (private->paint_stack) { - GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_pixbuf (paint->pixmap, gc, pixbuf, src_x, src_y, + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y, dest_x - x_offset, dest_y - y_offset, width, height, - dither, x_dither - x_offset, y_dither - y_offset); + dither, x_dither, y_dither); + RESTORE_DIRECT_GC_CLIP(gc); } - else - gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y, - dest_x - x_offset, dest_y - y_offset, - width, height, - dither, x_dither, y_dither); + + RESTORE_GC (gc); } } @@ -2388,10 +4111,16 @@ gdk_window_draw_trapezoids (GdkDrawable *drawable, if (private->paint_stack) { GdkWindowPaint *paint = private->paint_stack->data; - gdk_draw_trapezoids (paint->pixmap, gc, trapezoids, n_trapezoids); + SETUP_PAINT_GC_CLIP (gc); + gdk_draw_trapezoids (pixmap_impl (paint->pixmap), gc, trapezoids, n_trapezoids); + RESTORE_PAINT_GC_CLIP (gc); } else - gdk_draw_trapezoids (private->impl, gc, trapezoids, n_trapezoids); + { + SETUP_DIRECT_GC_CLIP(gc); + gdk_draw_trapezoids (private->impl, gc, trapezoids, n_trapezoids); + RESTORE_DIRECT_GC_CLIP(gc); + } g_free (new_trapezoids); @@ -2403,10 +4132,12 @@ gdk_window_real_get_size (GdkDrawable *drawable, gint *width, gint *height) { - g_return_if_fail (GDK_IS_WINDOW (drawable)); + GdkWindowObject *private = (GdkWindowObject *)drawable; - gdk_drawable_get_size (GDK_WINDOW_OBJECT (drawable)->impl, - width, height); + if (width) + *width = private->width; + if (height) + *height = private->height; } static GdkVisual* @@ -2438,12 +4169,21 @@ static void gdk_window_real_set_colormap (GdkDrawable *drawable, GdkColormap *cmap) { + GdkWindowObject *private; + g_return_if_fail (GDK_IS_WINDOW (drawable)); if (GDK_WINDOW_DESTROYED (drawable)) return; + + private = (GdkWindowObject *)drawable; + + /* different colormap than parent, requires native window */ + if (!private->input_only && + cmap != gdk_drawable_get_colormap ((GdkDrawable *)(private->parent))) + gdk_window_set_has_native ((GdkWindow *)drawable, TRUE); - gdk_drawable_set_colormap (((GdkWindowObject*)drawable)->impl, cmap); + gdk_drawable_set_colormap (private->impl, cmap); } static GdkColormap* @@ -2478,9 +4218,10 @@ gdk_window_copy_to_image (GdkDrawable *drawable, /* If we're here, a composite image was not necessary, so * we can ignore the paint stack. */ - - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (drawable, - &x_offset, &y_offset); + + /* TODO: Is this right? */ + x_offset = 0; + y_offset = 0; return gdk_drawable_copy_to_image (private->impl, image, @@ -2490,6 +4231,24 @@ gdk_window_copy_to_image (GdkDrawable *drawable, width, height); } +static void +gdk_window_cairo_surface_destroy (void *data) +{ + GdkWindowObject *private = (GdkWindowObject*) data; + + private->cairo_surface = NULL; +} + +static cairo_surface_t * +gdk_window_create_cairo_surface (GdkDrawable *drawable, + int width, + int height) +{ + return _gdk_windowing_create_cairo_surface (GDK_WINDOW_OBJECT(drawable)->impl, + width, height); +} + + static cairo_surface_t * gdk_window_ref_cairo_surface (GdkDrawable *drawable) { @@ -2504,27 +4263,198 @@ gdk_window_ref_cairo_surface (GdkDrawable *drawable) cairo_surface_reference (surface); } else - surface = _gdk_drawable_ref_cairo_surface (private->impl); + { + + /* This will be drawing directly to the window, so flush implicit paint */ + gdk_window_flush ((GdkWindow *)drawable); + + if (!private->cairo_surface) + { + int width, height; + GdkDrawable *source; + + /* It would be nice if we had some cairo support here so we + could set the clip rect on the cairo surface */ + width = private->abs_x + private->width; + height = private->abs_y + private->height; + + source = _gdk_drawable_get_source_drawable (drawable); + + /* TODO: Avoid the typecheck crap by adding virtual call */ + private->cairo_surface = _gdk_drawable_create_cairo_surface (source, width, height); + + if (private->cairo_surface) + { + cairo_surface_set_device_offset (private->cairo_surface, + private->abs_x, + private->abs_y); + + cairo_surface_set_user_data (private->cairo_surface, &gdk_window_cairo_key, + drawable, gdk_window_cairo_surface_destroy); + } + } + else + cairo_surface_reference (private->cairo_surface); + + surface = private->cairo_surface; + } return surface; } +static void +gdk_window_set_cairo_clip (GdkDrawable *drawable, + cairo_t *cr) +{ + GdkWindowObject *private = (GdkWindowObject*) drawable; + + if (!private->paint_stack) + { + cairo_save (cr); + cairo_identity_matrix (cr); + + cairo_reset_clip (cr); + + cairo_new_path (cr); + gdk_cairo_region (cr, private->clip_region); + + cairo_restore (cr); + cairo_clip (cr); + } + else + { + GdkWindowPaint *paint = private->paint_stack->data; + + /* Only needs to clip to region if piggybacking + on an implicit paint pixmap */ + if (paint->uses_implicit) + { + cairo_save (cr); + cairo_identity_matrix (cr); + + cairo_reset_clip (cr); + + cairo_new_path (cr); + gdk_cairo_region (cr, paint->region); + cairo_restore (cr); + + cairo_clip (cr); + } + } +} + /* Code for dirty-region queueing */ static GSList *update_windows = NULL; static guint update_idle = 0; static gboolean debug_updates = FALSE; -static gboolean -gdk_window_update_idle (gpointer data) +static inline gboolean +gdk_window_is_ancestor (GdkWindow *window, + GdkWindow *ancestor) { - gdk_window_process_all_updates (); - + while (window) + { + GdkWindow *parent = (GdkWindow*) ((GdkWindowObject*) window)->parent; + + if (parent == ancestor) + return TRUE; + + window = parent; + } + return FALSE; } -static gboolean -gdk_window_is_toplevel_frozen (GdkWindow *window) +static void +gdk_window_add_update_window (GdkWindow *window) +{ + GSList *tmp; + GSList *prev = NULL; + gboolean has_ancestor_in_list = FALSE; + + for (tmp = update_windows; tmp; tmp = tmp->next) + { + GdkWindowObject *parent = GDK_WINDOW_OBJECT (window)->parent; + + /* check if tmp is an ancestor of "window"; if it is, set a + * flag indicating that all following windows are either + * children of "window" or from a differen hierarchy + */ + if (!has_ancestor_in_list && gdk_window_is_ancestor (window, tmp->data)) + has_ancestor_in_list = TRUE; + + /* insert in reverse stacking order when adding around siblings, + * so processing updates properly paints over lower stacked windows + */ + if (parent == GDK_WINDOW_OBJECT (tmp->data)->parent) + { + gint index = g_list_index (parent->children, window); + for (; tmp && parent == GDK_WINDOW_OBJECT (tmp->data)->parent; tmp = tmp->next) + { + gint sibling_index = g_list_index (parent->children, tmp->data); + if (index > sibling_index) + break; + prev = tmp; + } + /* here, tmp got advanced past all lower stacked siblings */ + tmp = g_slist_prepend (tmp, window); + if (prev) + prev->next = tmp; + else + update_windows = tmp; + return; + } + + /* if "window" has an ancestor in the list and tmp is one of + * "window's" children, insert "window" before tmp + */ + if (has_ancestor_in_list && gdk_window_is_ancestor (tmp->data, window)) + { + tmp = g_slist_prepend (tmp, window); + + if (prev) + prev->next = tmp; + else + update_windows = tmp; + return; + } + + /* if we're at the end of the list and had an ancestor it it, + * append to the list + */ + if (! tmp->next && has_ancestor_in_list) + { + tmp = g_slist_append (tmp, window); + return; + } + + prev = tmp; + } + + /* if all above checks failed ("window" is from a different + * hierarchy than what is already in the list) or the list is + * empty, prepend + */ + update_windows = g_slist_prepend (update_windows, window); +} + +static void +gdk_window_remove_update_window (GdkWindow *window) +{ + update_windows = g_slist_remove (update_windows, window); +} + +static gboolean +gdk_window_update_idle (gpointer data) +{ + gdk_window_process_all_updates (); + + return FALSE; +} + +static gboolean +gdk_window_is_toplevel_frozen (GdkWindow *window) { GdkWindowObject *toplevel; @@ -2548,11 +4478,96 @@ gdk_window_schedule_update (GdkWindow *window) } } +void +_gdk_window_process_updates_recurse (GdkWindow *window, + GdkRegion *expose_region) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *child; + GdkRegion *child_region; + GdkRectangle r; + GList *l; + + if (gdk_region_empty (expose_region)) + return; + + /* Iterate over children, starting at topmost */ + for (l = private->children; l != NULL; l = l->next) + { + child = l->data; + + if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited) + continue; + + /* Ignore offscreen children, as they don't draw in their parent and + * don't take part in the clipping */ + if (gdk_window_is_offscreen (child)) + continue; + + r.x = child->x; + r.y = child->y; + r.width = child->width; + r.height = child->height; + + child_region = gdk_region_rectangle (&r); + if (child->shape) + gdk_region_intersect (child_region, child->shape); + + if (child->impl == private->impl) + { + /* Client side child, expose */ + gdk_region_intersect (child_region, expose_region); + gdk_region_subtract (expose_region, child_region); + gdk_region_offset (child_region, -child->x, -child->y); + _gdk_window_process_updates_recurse ((GdkWindow *)child, child_region); + } + else + { + /* Native child, just remove area from expose region */ + gdk_region_subtract (expose_region, child_region); + } + gdk_region_destroy (child_region); + } + + if (!gdk_region_empty (expose_region)) + { + if (private->event_mask & GDK_EXPOSURE_MASK) + { + GdkEvent event; + + event.expose.type = GDK_EXPOSE; + event.expose.window = g_object_ref (window); + event.expose.send_event = FALSE; + event.expose.count = 0; + event.expose.region = expose_region; + gdk_region_get_clipbox (expose_region, &event.expose.area); + + (*_gdk_event_func) (&event, _gdk_event_data); + + g_object_unref (window); + } + else if (private->bg_pixmap != GDK_NO_BG) + { + /* No exposure mask set, so nothing will be drawn, the + * app relies on the background being what it specified + * for the window. So, we need to clear this manually. + * + * We use begin/end_paint around the clear so that we can + * piggyback on the implicit paint */ + + gdk_window_begin_paint_region (window, expose_region); + gdk_window_clear_region_internal (window, expose_region, FALSE); + gdk_window_end_paint (window); + } + } +} + static void gdk_window_process_updates_internal (GdkWindow *window) { GdkWindowObject *private = (GdkWindowObject *)window; gboolean save_region = FALSE; + GdkRectangle clip_box; /* If an update got queued during update processing, we can get a * window in the update queue that has an empty update_area. @@ -2563,62 +4578,99 @@ gdk_window_process_updates_internal (GdkWindow *window) GdkRegion *update_area = private->update_area; private->update_area = NULL; - if (_gdk_event_func && gdk_window_is_viewable (window)) + if (_gdk_event_func && gdk_window_is_viewable (window) && + private->window_type != GDK_WINDOW_FOREIGN) { GdkRectangle window_rect; GdkRegion *expose_region; GdkRegion *window_region; - gint width, height; + gboolean end_implicit; + /* Clip to part visible in toplevel */ + gdk_region_intersect (update_area, private->clip_region); + if (debug_updates) { /* Make sure we see the red invalid area before redrawing. */ gdk_display_sync (gdk_drawable_get_display (window)); g_usleep (70000); } - - save_region = _gdk_windowing_window_queue_antiexpose (window, update_area); + save_region = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_antiexpose (window, update_area); if (save_region) expose_region = gdk_region_copy (update_area); else expose_region = update_area; - gdk_drawable_get_size (GDK_DRAWABLE (private), &width, &height); - window_rect.x = 0; window_rect.y = 0; - window_rect.width = width; - window_rect.height = height; + window_rect.width = private->width; + window_rect.height = private->height; window_region = gdk_region_rectangle (&window_rect); gdk_region_intersect (expose_region, window_region); gdk_region_destroy (window_region); - - if (!gdk_region_empty (expose_region) && - (private->event_mask & GDK_EXPOSURE_MASK)) + + + /* No need to do any moves that will end up over the update area */ + if (private->outstanding_moves) { - GdkEvent event; - - event.expose.type = GDK_EXPOSE; - event.expose.window = g_object_ref (window); - event.expose.send_event = FALSE; - event.expose.count = 0; - event.expose.region = expose_region; - gdk_region_get_clipbox (expose_region, &event.expose.area); + GdkWindowRegionMove *move; + GdkRegion *remove; + GList *l, *prev; - (*_gdk_event_func) (&event, _gdk_event_data); - - g_object_unref (window); + remove = gdk_region_copy (update_area); + for (l = g_list_last (private->outstanding_moves); l != NULL; l = prev) + { + prev = l->prev; + move = l->data; + /* Don't need this area */ + gdk_region_subtract (move->dest_region, remove); + + /* However if any of the destination we do need has a source + in the updated region we do need that as a destination for + the earlier moves */ + gdk_region_offset (move->dest_region, -move->dx, -move->dy); + gdk_region_subtract (remove, move->dest_region); + + if (gdk_region_empty (move->dest_region)) + { + gdk_window_region_move_free (move); + private->outstanding_moves = + g_list_delete_link (private->outstanding_moves, l); + } + else + gdk_region_offset (move->dest_region, move->dx, move->dy); + } + gdk_region_destroy (remove); } - + + gdk_region_get_clipbox (expose_region, &clip_box); + end_implicit = gdk_window_begin_implicit_paint (window, &clip_box); + if (end_implicit) /* rendering is not double buffered, do moves now */ + gdk_window_flush_outstanding_moves (window); + _gdk_windowing_window_process_updates_recurse (window, expose_region); + if (end_implicit) + { + /* Do moves right before exposes are rendered */ + gdk_window_flush_outstanding_moves (window); + gdk_window_end_implicit_paint (window); + } + if (expose_region != update_area) gdk_region_destroy (expose_region); } if (!save_region) gdk_region_destroy (update_area); } + + if (private->outstanding_moves) + { + /* Flush any outstanding moves, may happen if we moved a window but got + no actual invalid area */ + gdk_window_flush_outstanding_moves (window); + } } static void @@ -2655,6 +4707,12 @@ gdk_window_process_all_updates (void) { GSList *old_update_windows = update_windows; GSList *tmp_list = update_windows; + static gboolean in_process_all_updates = FALSE; + + if (in_process_all_updates) + return; + + in_process_all_updates = TRUE; if (update_idle) g_source_remove (update_idle); @@ -2662,6 +4720,8 @@ gdk_window_process_all_updates (void) update_windows = NULL; update_idle = 0; + _gdk_windowing_before_process_all_updates (); + g_slist_foreach (old_update_windows, (GFunc)g_object_ref, NULL); while (tmp_list) @@ -2672,7 +4732,7 @@ gdk_window_process_all_updates (void) { if (private->update_freeze_count || gdk_window_is_toplevel_frozen (tmp_list->data)) - update_windows = g_slist_prepend (update_windows, private); + gdk_window_add_update_window ((GdkWindow *) private); else gdk_window_process_updates_internal (tmp_list->data); } @@ -2684,6 +4744,10 @@ gdk_window_process_all_updates (void) g_slist_free (old_update_windows); flush_all_displays (); + + _gdk_windowing_after_process_all_updates (); + + in_process_all_updates = FALSE; } /** @@ -2706,35 +4770,28 @@ gdk_window_process_updates (GdkWindow *window, gboolean update_children) { GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *impl_window; g_return_if_fail (GDK_IS_WINDOW (window)); - if (GDK_IS_PAINTABLE (private->impl)) - { - GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl); - - if (iface->process_updates) - iface->process_updates ((GdkPaintable*)private->impl, update_children); - - return; - } - - if (private->update_area && - !private->update_freeze_count && + impl_window = gdk_window_get_impl_window (private); + if ((impl_window->update_area || + impl_window->outstanding_moves) && + !impl_window->update_freeze_count && !gdk_window_is_toplevel_frozen (window)) { - gdk_window_process_updates_internal (window); - update_windows = g_slist_remove (update_windows, window); + gdk_window_process_updates_internal ((GdkWindow *)impl_window); + gdk_window_remove_update_window ((GdkWindow *)impl_window); } if (update_children) { - GList *tmp_list = private->children; - while (tmp_list) - { - gdk_window_process_updates (tmp_list->data, TRUE); - tmp_list = tmp_list->next; - } + /* process updates in reverse stacking order so composition or + * painting over achieves the desired effect for offscreen windows + */ + GList *node; + for (node = g_list_last (private->children); node; node = node->prev) + gdk_window_process_updates (node->data, TRUE); } } @@ -2838,6 +4895,7 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window, gpointer user_data) { GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *impl_window; GdkRegion *visible_region; GList *tmp_list; @@ -2849,28 +4907,7 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window, if (private->input_only || !GDK_WINDOW_IS_MAPPED (window)) return; - if (GDK_IS_PAINTABLE (private->impl)) - { - GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl); - - if (iface->invalidate_maybe_recurse) - iface->invalidate_maybe_recurse ((GdkPaintable*)private->impl, - region, child_func, user_data); - return; - } - - /* windows that a redirection has ben setup for need to be considered - * fully visible, in order to avoid missing redirected paint ops - * anywhere in the window area. - */ - if (private->redirect && private->redirect->redirected == private) - { - GdkRectangle visible_rect = { 0, 0, 0, 0 }; - gdk_drawable_get_size (GDK_DRAWABLE (window), &visible_rect.width, &visible_rect.height); - visible_region = gdk_region_rectangle (&visible_rect); - } - else - visible_region = gdk_drawable_get_visible_region (window); + visible_region = gdk_drawable_get_visible_region (window); gdk_region_intersect (visible_region, region); tmp_list = private->children; @@ -2882,17 +4919,17 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window, { GdkRegion *child_region; GdkRectangle child_rect; - - gdk_window_get_position ((GdkWindow *)child, - &child_rect.x, &child_rect.y); - gdk_drawable_get_size ((GdkDrawable *)child, - &child_rect.width, &child_rect.height); + child_rect.x = child->x; + child_rect.y = child->y; + child_rect.width = child->width; + child_rect.height = child->height; child_region = gdk_region_rectangle (&child_rect); /* 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_offscreen (child)) gdk_region_subtract (visible_region, child_region); if (child_func && (*child_func) ((GdkWindow *)child, user_data)) @@ -2914,22 +4951,30 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window, tmp_list = tmp_list->next; } + + impl_window = gdk_window_get_impl_window (private); - if (!gdk_region_empty (visible_region)) + if (!gdk_region_empty (visible_region) || + /* Even if we're not exposing anything, make sure we process + idles for windows with outstanding moves */ + (impl_window->outstanding_moves != NULL && + impl_window->update_area == NULL)) { if (debug_updates) draw_ugly_color (window, region); - - if (private->update_area) + + /* Convert to impl coords */ + gdk_region_offset (visible_region, private->abs_x, private->abs_y); + if (impl_window->update_area) { - gdk_region_union (private->update_area, visible_region); + gdk_region_union (impl_window->update_area, visible_region); } else { - update_windows = g_slist_prepend (update_windows, window); - private->update_area = gdk_region_copy (visible_region); + gdk_window_add_update_window ((GdkWindow *)impl_window); + impl_window->update_area = gdk_region_copy (visible_region); - gdk_window_schedule_update (window); + gdk_window_schedule_update ((GdkWindow *)impl_window); } } @@ -2978,6 +5023,38 @@ gdk_window_invalidate_region (GdkWindow *window, NULL); } +/** + * _gdk_window_invalidate_for_expose: + * @window: a #GdkWindow + * @region: a #GdkRegion + * + * Adds @region to the update area for @window. The update area is the + * region that needs to be redrawn, or "dirty region." The call + * gdk_window_process_updates() sends one or more expose events to the + * window, which together cover the entire update area. An + * application would normally redraw the contents of @window in + * response to those expose events. + * + * GDK will call gdk_window_process_all_updates() on your behalf + * whenever your program returns to the main loop and becomes idle, so + * normally there's no need to do that manually, you just need to + * invalidate regions that you know should be redrawn. + * + * This version of invalidation is used when you recieve expose events + * from the native window system. It exposes the native window, plus + * any non-native child windows (but not native child windows, as those would + * have gotten their own expose events). + **/ +void +_gdk_window_invalidate_for_expose (GdkWindow *window, + const GdkRegion *region) +{ + gdk_window_invalidate_maybe_recurse (window, region, + (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl, + NULL); +} + + /** * gdk_window_get_update_area: * @window: a #GdkWindow @@ -2995,18 +5072,43 @@ GdkRegion * gdk_window_get_update_area (GdkWindow *window) { GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *impl_window; GdkRegion *tmp_region; g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); - if (private->update_area) + impl_window = gdk_window_get_impl_window (private); + + if (impl_window->update_area) { - tmp_region = private->update_area; - private->update_area = NULL; + tmp_region = gdk_region_copy (private->clip_region_with_children); + /* Convert to impl coords */ + gdk_region_offset (tmp_region, private->abs_x, private->abs_y); + gdk_region_intersect (tmp_region, impl_window->update_area); - update_windows = g_slist_remove (update_windows, window); - - return tmp_region; + if (gdk_region_empty (tmp_region)) + { + gdk_region_destroy (tmp_region); + return NULL; + } + else + { + gdk_region_subtract (impl_window->update_area, tmp_region); + + if (gdk_region_empty (impl_window->update_area) && + impl_window->outstanding_moves == NULL) + { + gdk_region_destroy (impl_window->update_area); + impl_window->update_area = NULL; + + gdk_window_remove_update_window ((GdkWindow *)impl_window); + } + + /* Convert from impl coords */ + gdk_region_offset (tmp_region, -private->abs_x, -private->abs_y); + return tmp_region; + + } } else return NULL; @@ -3028,8 +5130,8 @@ _gdk_window_clear_update_area (GdkWindow *window) if (private->update_area) { - update_windows = g_slist_remove (update_windows, window); - + gdk_window_remove_update_window (window); + gdk_region_destroy (private->update_area); private->update_area = NULL; } @@ -3049,10 +5151,12 @@ void gdk_window_freeze_updates (GdkWindow *window) { GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *impl_window; g_return_if_fail (GDK_IS_WINDOW (window)); - private->update_freeze_count++; + impl_window = gdk_window_get_impl_window (private); + impl_window->update_freeze_count++; } /** @@ -3065,12 +5169,16 @@ void gdk_window_thaw_updates (GdkWindow *window) { GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *impl_window; g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (private->update_freeze_count > 0); - if (--private->update_freeze_count == 0) - gdk_window_schedule_update (window); + impl_window = gdk_window_get_impl_window (private); + + g_return_if_fail (impl_window->update_freeze_count > 0); + + if (--impl_window->update_freeze_count == 0) + gdk_window_schedule_update (GDK_WINDOW (impl_window)); } /** @@ -3339,6 +5447,8 @@ gdk_window_get_pointer (GdkWindow *window, if (mask) *mask = tmp_mask; + _gdk_display_enable_motion_hints (display); + return child; } @@ -3398,61 +5508,106 @@ gdk_window_foreign_new (GdkNativeWindow anid) return gdk_window_foreign_new_for_display (gdk_display_get_default (), 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) +static void +get_all_native_children (GdkWindowObject *private, + GList **native) { - GdkWindowObject *private; - - g_return_if_fail (GDK_IS_WINDOW (window)); - - private = (GdkWindowObject *) window; - if (private->destroyed) - return; + GdkWindowObject *child; + GList *l; + + for (l = private->children; l != NULL; l = l->next) + { + child = l->data; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, FALSE); + if (gdk_window_has_impl (child)) + *native = g_list_prepend (*native, child); + else + get_all_native_children (child, native); + } } + static inline void gdk_window_raise_internal (GdkWindow *window) { GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowObject *parent = private->parent; + GdkWindowObject *above; + GList *native_children; + GList *l, listhead; if (parent) { parent->children = g_list_remove (parent->children, window); parent->children = g_list_prepend (parent->children, window); } + + /* Just do native raise for toplevels */ + if (private->parent == NULL || + GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + { + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window); + } + else if (gdk_window_has_impl (private)) + { + above = find_native_sibling_above (parent, private); + if (above) + { + listhead.data = window; + listhead.next = NULL; + listhead.prev = NULL; + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above, + &listhead); + } + else + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window); + } + else + { + native_children = NULL; + get_all_native_children (private, &native_children); + if (native_children != NULL) + { + above = find_native_sibling_above (parent, private); + + if (above) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above, + native_children); + else + { + /* Right order, since native_chilren is bottom-opmost first */ + for (l = native_children; l != NULL; l = l->next) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (l->data); + } + + g_list_free (native_children); + } + + } } -/** - * 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 +show_all_visible_impls (GdkWindowObject *private) +{ + GdkWindowObject *child; + GList *l; + + for (l = private->children; l != NULL; l = l->next) + { + child = l->data; + if (GDK_WINDOW_IS_MAPPED (child)) + show_all_visible_impls (child); + } + + if (gdk_window_has_impl (private)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show ((GdkWindow *)private); +} + +static void +gdk_window_show_internal (GdkWindow *window, gboolean raise) { GdkWindowObject *private; + gboolean was_mapped; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -3460,31 +5615,186 @@ gdk_window_raise (GdkWindow *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 = private->parent; + was_mapped = GDK_WINDOW_IS_MAPPED (window); + + if (raise) + /* Keep children in (reverse) stacking order */ + gdk_window_raise_internal (window); - if (parent) + if (gdk_window_has_impl (private)) { - parent->children = g_list_remove (parent->children, window); - parent->children = g_list_append (parent->children, window); + if (!was_mapped) + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_WITHDRAWN, + 0); + } + else + { + private->state = 0; } -} -/** - * 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. + if (gdk_window_is_viewable (window)) + show_all_visible_impls (private); + + if (!was_mapped) + { + if (private->event_mask & GDK_STRUCTURE_MASK) + _gdk_make_event (GDK_WINDOW (private), GDK_MAP, NULL, FALSE); + + if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK) + _gdk_make_event (GDK_WINDOW (private), GDK_MAP, NULL, FALSE); + } + + if (!was_mapped || raise) + { + recompute_visible_regions (private, TRUE, FALSE); + + if (gdk_window_is_viewable (window)) + { + _gdk_syntesize_crossing_events_for_geometry_change (window); + gdk_window_invalidate_rect (window, NULL, TRUE); + } + } +} + +/** + * 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) +{ + gdk_window_show_internal (window, FALSE); +} + +/** + * 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); + + recompute_visible_regions (private, TRUE, FALSE); + + gdk_window_invalidate_rect (window, NULL, TRUE); +} + +static void +gdk_window_lower_internal (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *parent = private->parent; + GdkWindowObject *above; + GList *native_children; + GList *l, listhead; + + if (parent) + { + parent->children = g_list_remove (parent->children, window); + parent->children = g_list_append (parent->children, window); + } + + /* Just do native lower for toplevels */ + if (private->parent == NULL || + GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + { + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->lower (window); + } + else if (gdk_window_has_impl (private)) + { + above = find_native_sibling_above (parent, private); + if (above) + { + listhead.data = window; + listhead.next = NULL; + listhead.prev = NULL; + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above, + &listhead); + } + else + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window); + } + else + { + native_children = NULL; + get_all_native_children (private, &native_children); + if (native_children != NULL) + { + above = find_native_sibling_above (parent, private); + + if (above) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above, + native_children); + else + { + /* Right order, since native_chilren is bottom-opmost first */ + for (l = native_children; l != NULL; l = l->next) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (l->data); + } + + g_list_free (native_children); + } + + } +} + +static void +gdk_window_invalidate_in_parent (GdkWindowObject *private) +{ + GdkRectangle r, child; + + if (private->parent == NULL || + GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + return; + + /* get the visible rectangle of the parent */ + r.x = r.y = 0; + r.width = private->parent->width; + r.height = private->parent->height; + + child.x = private->x; + child.y = private->y; + child.width = private->width; + child.height = private->height; + gdk_rectangle_intersect (&r, &child, &r); + + gdk_window_invalidate_rect (GDK_WINDOW (private->parent), &r, TRUE); +} + + +/** + * 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 @@ -3508,7 +5818,10 @@ gdk_window_lower (GdkWindow *window) /* Keep children in (reverse) stacking order */ gdk_window_lower_internal (window); - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->lower (window); + recompute_visible_regions (private, TRUE, FALSE); + + _gdk_syntesize_crossing_events_for_geometry_change (window); + gdk_window_invalidate_in_parent (private); } /** @@ -3528,20 +5841,28 @@ gdk_window_lower (GdkWindow *window) 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_show_internal (window, TRUE); +} - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, TRUE); +static void +hide_all_visible_impls (GdkWindowObject *private) +{ + GdkWindowObject *child; + GList *l; + + for (l = private->children; l != NULL; l = l->next) + { + child = l->data; + + if (GDK_WINDOW_IS_MAPPED (child)) + hide_all_visible_impls (child); + } + + if (gdk_window_has_impl (private)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide ((GdkWindow *)private); } + /** * gdk_window_hide: * @window: a #GdkWindow @@ -3555,6 +5876,7 @@ void gdk_window_hide (GdkWindow *window) { GdkWindowObject *private; + gboolean was_mapped, was_viewable; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -3562,7 +5884,64 @@ gdk_window_hide (GdkWindow *window) if (private->destroyed) return; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide (window); + was_mapped = GDK_WINDOW_IS_MAPPED (private); + was_viewable = gdk_window_is_viewable (window); + + if (gdk_window_has_impl (private)) + { + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_WITHDRAWN); + } + else if (was_mapped) + { + GdkDisplay *display; + + /* May need to break grabs on children */ + display = gdk_drawable_get_display (window); + + if (_gdk_display_end_pointer_grab (display, + _gdk_windowing_window_get_next_serial (display), + window, + TRUE)) + gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); + + if (display->keyboard_grab.window != NULL) + { + if (is_parent_of (window, display->keyboard_grab.window)) + { + /* Call this ourselves, even though gdk_display_keyboard_ungrab + does so too, since we want to pass implicit == TRUE so the + broken grab event is generated */ + _gdk_display_unset_has_keyboard_grab (display, + TRUE); + gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME); + } + } + + private->state = GDK_WINDOW_STATE_WITHDRAWN; + } + + if (was_viewable) + hide_all_visible_impls (private); + + recompute_visible_regions (private, TRUE, FALSE); + + if (was_mapped) + { + if (private->event_mask & GDK_STRUCTURE_MASK) + _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE); + + if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK) + _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE); + + _gdk_syntesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent)); + } + + /* Invalidate the rect */ + gdk_window_invalidate_in_parent (private); } /** @@ -3577,6 +5956,7 @@ void gdk_window_withdraw (GdkWindow *window) { GdkWindowObject *private; + gboolean was_mapped; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -3584,7 +5964,25 @@ gdk_window_withdraw (GdkWindow *window) if (private->destroyed) return; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->withdraw (window); + was_mapped = GDK_WINDOW_IS_MAPPED (private); + + if (gdk_window_has_impl (private)) + { + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->withdraw (window); + + if (was_mapped) + { + if (private->event_mask & GDK_STRUCTURE_MASK) + _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE); + + if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK) + _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE); + + _gdk_syntesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent)); + } + + recompute_visible_regions (private, TRUE, FALSE); + } } /** @@ -3602,6 +6000,8 @@ gdk_window_set_events (GdkWindow *window, GdkEventMask event_mask) { GdkWindowObject *private; + GdkDisplay *display; + g_return_if_fail (GDK_IS_WINDOW (window)); @@ -3609,7 +6009,18 @@ gdk_window_set_events (GdkWindow *window, if (private->destroyed) return; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, event_mask); + /* If motion hint is disabled, enable motion events again */ + display = gdk_drawable_get_display (window); + if ((private->event_mask & GDK_POINTER_MOTION_HINT_MASK) && + !(event_mask & GDK_POINTER_MOTION_HINT_MASK)) + _gdk_display_enable_motion_hints (display); + + private->event_mask = event_mask; + + if (gdk_window_has_impl (private)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, + get_native_event_mask (private)); + } /** @@ -3631,106 +6042,397 @@ gdk_window_get_events (GdkWindow *window) if (private->destroyed) return 0; - return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_events (window); + return private->event_mask; } -/** - * 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_move_resize_toplevel (GdkWindow *window, + gboolean with_move, + gint x, + gint y, + gint width, + gint height) { GdkWindowObject *private; - - g_return_if_fail (GDK_IS_WINDOW (window)); + GdkRegion *old_region, *new_region; + GdkWindowObject *impl_window; + gboolean expose; + int old_x, old_y, old_abs_x, old_abs_y; + int dx, dy; + gboolean is_resize; private = (GdkWindowObject *) window; - if (private->destroyed) - return; - - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, TRUE, x, y, -1, -1); -} - -/** - * 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; + expose = FALSE; + old_region = NULL; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, FALSE, 0, 0, width, height); -} + impl_window = gdk_window_get_impl_window (private); + old_x = private->x; + old_y = private->y; -/** - * 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; + is_resize = (width != -1) || (height != -1); + + if (GDK_WINDOW_IS_MAPPED (window) && + !private->input_only) + { + expose = TRUE; + old_region = gdk_region_copy (private->clip_region); + } + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, with_move, x, y, width, height); - g_return_if_fail (GDK_IS_WINDOW (window)); + dx = private->x - old_x; + dy = private->y - old_y; + + old_abs_x = private->abs_x; + old_abs_y = private->abs_y; - private = (GdkWindowObject *) window; - if (private->destroyed) - return; + /* Avoid recomputing for pure toplevel moves, for performance reasons */ + if (is_resize) + recompute_visible_regions (private, TRUE, FALSE); + + if (expose) + { + new_region = gdk_region_copy (private->clip_region); + + /* This is the newly exposed area (due to any resize), + * X will expose it, but lets do that without the + * roundtrip + */ + gdk_region_subtract (new_region, old_region); + gdk_window_invalidate_region (window, new_region, TRUE); + + gdk_region_destroy (old_region); + gdk_region_destroy (new_region); + } - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, TRUE, x, y, width, height); + _gdk_syntesize_crossing_events_for_geometry_change (window); } -/** - * gdk_window_scroll: +static void +move_native_children (GdkWindowObject *private) +{ + GList *l; + GdkWindowObject *child; + + for (l = private->children; l; l = l->next) + { + child = l->data; + + if (child->impl != private->impl) + GDK_WINDOW_IMPL_GET_IFACE (child->impl)->move_resize ((GdkWindow *)child, TRUE, child->x, child->y, child->width, child->height); + else + move_native_children (child); + } +} + +static gboolean +collect_native_child_region_helper (GdkWindowObject *window, + GdkWindow *impl, + GdkRegion **region, + int x_offset, + int y_offset) +{ + GdkWindowObject *child; + GdkRegion *tmp; + GList *l; + + for (l = window->children; l != NULL; l = l->next) + { + child = l->data; + + if (child->impl != impl) + { + tmp = gdk_region_copy (child->clip_region); + gdk_region_offset (tmp, + x_offset + child->x, + y_offset + child->y); + if (*region == NULL) + *region = tmp; + else + { + gdk_region_union (*region, tmp); + gdk_region_destroy (tmp); + } + } + else + collect_native_child_region_helper (child, impl, region, + x_offset + child->x, + y_offset + child->y); + } + + return FALSE; +} + +static GdkRegion * +collect_native_child_region (GdkWindowObject *window, + gboolean include_this) +{ + GdkRegion *region; + + if (include_this && gdk_window_has_impl (window)) + return gdk_region_copy (window->clip_region); + + region = NULL; + + collect_native_child_region_helper (window, window->impl, ®ion, 0, 0); + + return region; +} + + +static void +gdk_window_move_resize_internal (GdkWindow *window, + gboolean with_move, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowObject *private; + GdkRegion *old_region, *new_region, *copy_area; + GdkRegion *old_native_child_region, *new_native_child_region; + GdkWindowObject *impl_window; + gboolean expose; + int old_x, old_y, old_abs_x, old_abs_y; + int dx, dy; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + if (private->destroyed) + return; + + if (private->parent == NULL || + GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + { + gdk_window_move_resize_toplevel (window, with_move, x, y, width, height); + return; + } + + /* Handle child windows */ + + expose = FALSE; + old_region = NULL; + + impl_window = gdk_window_get_impl_window (private); + + old_x = private->x; + old_y = private->y; + + if (GDK_WINDOW_IS_MAPPED (window) && + !private->input_only) + { + expose = TRUE; + + old_region = gdk_region_copy (private->clip_region); + /* Adjust region to parent window coords */ + gdk_region_offset (old_region, private->x, private->y); + } + + old_native_child_region = collect_native_child_region (private, TRUE); + if (old_native_child_region) + { + /* Adjust region to parent window coords */ + gdk_region_offset (old_native_child_region, private->x, private->y); + + /* Any native window move will immediately copy stuff to the destination, which may overwrite a + * source or destination for a delayed GdkWindowRegionMove. So, we need + * to flush those here for the parent window and all overlapped subwindows + * of it. And we need to do this before setting the new clips as those will be + * affecting this. + */ + gdk_window_flush_recursive (private->parent); + } + + /* Set the new position and size */ + if (with_move) + { + private->x = x; + private->y = y; + } + if (!(width < 0 && height < 0)) + { + if (width < 1) + width = 1; + private->width = width; + if (height < 1) + height = 1; + private->height = height; + } + + dx = private->x - old_x; + dy = private->y - old_y; + + old_abs_x = private->abs_x; + old_abs_y = private->abs_y; + + recompute_visible_regions (private, TRUE, FALSE); + + new_native_child_region = NULL; + if (old_native_child_region) + { + new_native_child_region = collect_native_child_region (private, TRUE); + /* Adjust region to parent window coords */ + gdk_region_offset (new_native_child_region, private->x, private->y); + } + + if (gdk_window_has_impl (private)) + { + /* Do the actual move after recomputing things, as this will have set the shape to + the now correct one, thus avoiding copying regions that should not be copied. */ + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, TRUE, private->x, private->y, private->width, private->height); + } + else if (old_abs_x != private->abs_x || + old_abs_y != private->abs_y) + move_native_children (private); + + if (expose) + { + new_region = gdk_region_copy (private->clip_region); + /* Adjust region to parent window coords */ + gdk_region_offset (new_region, private->x, private->y); + + /* copy_area: + * Part of the data at the new location can be copied from the + * old location, this area is the intersection of the old region + * moved as the copy will move it and then intersected with + * the new region. + * + * new_region: + * Everything in the old and new regions that is not copied must be + * invalidated (including children) as this is newly exposed + */ + copy_area = gdk_region_copy (new_region); + + gdk_region_union (new_region, old_region); + + if (old_native_child_region) + { + /* Don't copy from inside native children, as this is copied by + * the native window move. + */ + gdk_region_subtract (old_region, old_native_child_region); + } + gdk_region_offset (old_region, dx, dy); + + gdk_region_intersect (copy_area, old_region); + + if (new_native_child_region) + { + /* Don't copy any bits that would cause a read from the moved + native windows, as we can't read that data */ + gdk_region_offset (new_native_child_region, dx, dy); + gdk_region_subtract (copy_area, new_native_child_region); + } + + gdk_region_subtract (new_region, copy_area); + + /* Convert old region to impl coords */ + gdk_region_offset (old_region, -dx + private->abs_x - private->x, -dy + private->abs_y - private->y); + + /* convert from parent coords to impl */ + gdk_region_offset (copy_area, private->abs_x - private->x, private->abs_y - private->y); + + move_region_on_impl (impl_window, copy_area, dx, dy); /* takes ownership of copy_area */ + + /* Invalidate affected part in the parent window + * (no higher window should be affected) + * We also invalidate any children in that area, which could include + * this window if it still overlaps that area. + */ + gdk_window_invalidate_region (GDK_WINDOW (private->parent), new_region, TRUE); + + gdk_region_destroy (old_region); + gdk_region_destroy (new_region); + } + + if (old_native_child_region) + { + gdk_region_destroy (old_native_child_region); + gdk_region_destroy (new_native_child_region); + } + + _gdk_syntesize_crossing_events_for_geometry_change (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) +{ + gdk_window_move_resize_internal (window, TRUE, x, y, -1, -1); +} + +/** + * 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) +{ + gdk_window_move_resize_internal (window, FALSE, 0, 0, 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) +{ + gdk_window_move_resize_internal (window, TRUE, 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 @@ -3753,6 +6455,10 @@ gdk_window_scroll (GdkWindow *window, gint dy) { GdkWindowObject *private = (GdkWindowObject *) window; + GdkWindowObject *impl_window; + GdkRegion *copy_area, *noncopy_area; + GdkRegion *old_native_child_region, *new_native_child_region; + GList *tmp_list; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -3762,7 +6468,83 @@ gdk_window_scroll (GdkWindow *window, if (private->destroyed) return; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->scroll (window, dx, dy); + old_native_child_region = collect_native_child_region (private, FALSE); + if (old_native_child_region) + { + /* Any native window move will immediately copy stuff to the destination, which may overwrite a + * source or destination for a delayed GdkWindowRegionMove. So, we need + * to flush those here for the window and all overlapped subwindows + * of it. And we need to do this before setting the new clips as those will be + * affecting this. + */ + gdk_window_flush_recursive (private); + } + + + /* First move all child windows, without causing invalidation */ + + tmp_list = private->children; + while (tmp_list) + { + GdkWindow *child = GDK_WINDOW (tmp_list->data); + GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child); + + /* Just update the positions, the bits will move with the copy */ + child_obj->x += dx; + child_obj->y += dy; + + tmp_list = tmp_list->next; + } + + recompute_visible_regions (private, FALSE, TRUE); + + new_native_child_region = NULL; + if (old_native_child_region) + new_native_child_region = collect_native_child_region (private, FALSE); + + move_native_children (private); + + /* Then copy the actual bits of the window w/ child windows */ + + impl_window = gdk_window_get_impl_window (private); + + /* Calculate the area that can be gotten by copying the old area */ + copy_area = gdk_region_copy (private->clip_region); + if (old_native_child_region) + { + /* Don't copy from inside native children, as this is copied by + * the native window move. + */ + gdk_region_subtract (copy_area, old_native_child_region); + + /* Don't copy any bits that would cause a read from the moved + native windows, as we can't read that data */ + gdk_region_subtract (copy_area, new_native_child_region); + } + gdk_region_offset (copy_area, dx, dy); + gdk_region_intersect (copy_area, private->clip_region); + + /* And the rest need to be invalidated */ + noncopy_area = gdk_region_copy (private->clip_region); + gdk_region_subtract (noncopy_area, copy_area); + + /* convert from window coords to impl */ + gdk_region_offset (copy_area, private->abs_x, private->abs_y); + + move_region_on_impl (impl_window, copy_area, dx, dy); /* takes ownership of copy_area */ + + /* Invalidate not copied regions */ + gdk_window_invalidate_region (window, noncopy_area, TRUE); + + gdk_region_destroy (noncopy_area); + + if (old_native_child_region) + { + gdk_region_destroy (old_native_child_region); + gdk_region_destroy (new_native_child_region); + } + + _gdk_syntesize_crossing_events_for_geometry_change (window); } /** @@ -3787,6 +6569,9 @@ gdk_window_move_region (GdkWindow *window, gint dy) { GdkWindowObject *private = (GdkWindowObject *) window; + GdkWindowObject *impl_window; + GdkRegion *nocopy_area; + GdkRegion *copy_area; g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (region != NULL); @@ -3797,7 +6582,27 @@ gdk_window_move_region (GdkWindow *window, if (private->destroyed) return; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_region (window, region, dx, dy); + impl_window = gdk_window_get_impl_window (private); + + /* compute source regions */ + copy_area = gdk_region_copy (region); + gdk_region_intersect (copy_area, private->clip_region_with_children); + + /* compute destination regions */ + gdk_region_offset (copy_area, dx, dy); + gdk_region_intersect (copy_area, private->clip_region_with_children); + + /* invalidate parts of the region not covered by the copy */ + nocopy_area = gdk_region_copy (region); + gdk_region_offset (nocopy_area, dx, dy); + gdk_region_subtract (nocopy_area, copy_area); + gdk_window_invalidate_region (window, nocopy_area, FALSE); + gdk_region_destroy (nocopy_area); + + /* convert from window coords to impl */ + gdk_region_offset (copy_area, private->abs_x, private->abs_y); + + move_region_on_impl (impl_window, copy_area, dx, dy); /* Takes ownership of copy_area */ } /** @@ -3820,12 +6625,26 @@ gdk_window_set_background (GdkWindow *window, const GdkColor *color) { GdkWindowObject *private; + GdkColormap *colormap = gdk_drawable_get_colormap (window); g_return_if_fail (GDK_IS_WINDOW (window)); private = (GdkWindowObject *) 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; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, color); + if (!GDK_WINDOW_DESTROYED (window) && + gdk_window_has_impl (private) && + !private->input_only) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, &private->bg_color); } /** @@ -3867,7 +6686,56 @@ gdk_window_set_back_pixmap (GdkWindow *window, private = (GdkWindowObject *) window; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, pixmap, parent_relative); + 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) + private->bg_pixmap = g_object_ref (pixmap); + else + private->bg_pixmap = GDK_NO_BG; + + if (!GDK_WINDOW_DESTROYED (window) && + gdk_window_has_impl (private) && + !private->input_only) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap); +} + +static void +update_cursor (GdkDisplay *display) +{ + GdkWindowObject *pointer_window, *cursor_window; + GdkPointerGrabInfo *grab; + + pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer; + + cursor_window = pointer_window; + while (cursor_window->cursor == NULL && + cursor_window->parent != NULL && + cursor_window->parent->window_type != GDK_WINDOW_ROOT) + cursor_window = cursor_window->parent; + + /* We ignore the serials here and just pick the last grab + we've sent, as that would shortly be used anyway. */ + grab = _gdk_display_get_last_pointer_grab (display); + if (grab != NULL && + !is_parent_of (grab->window, (GdkWindow *)cursor_window)) + cursor_window = (GdkWindowObject *)grab->window; + + /* Set all cursors on toplevel, otherwise its tricky to keep track of + * which native window has what cursor set. */ + GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor + (gdk_window_get_toplevel ((GdkWindow *)pointer_window), + cursor_window->cursor); } /** @@ -3886,12 +6754,27 @@ gdk_window_set_cursor (GdkWindow *window, GdkCursor *cursor) { GdkWindowObject *private; + GdkDisplay *display; g_return_if_fail (GDK_IS_WINDOW (window)); private = (GdkWindowObject *) window; + display = gdk_drawable_get_display (window); - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_cursor (window, cursor); + if (private->cursor) + { + gdk_cursor_unref (private->cursor); + private->cursor = NULL; + } + + if (!GDK_WINDOW_DESTROYED (window)) + { + if (cursor) + private->cursor = gdk_cursor_ref (cursor); + + if (is_parent_of (window, display->pointer_info.window_under_pointer)) + update_cursor (display); + } } /** @@ -3950,9 +6833,23 @@ gdk_window_get_geometry (GdkWindow *window, if (!GDK_WINDOW_DESTROYED (window)) { - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y, - width, height, - depth); + if (gdk_window_has_impl (private)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y, + width, height, + depth); + else + { + if (x) + *x = private->x; + if (y) + *y = private->y; + if (width) + *width = private->width; + if (height) + *height = private->height; + if (depth) + *depth = private->depth; + } } } @@ -3979,27 +6876,77 @@ gdk_window_get_origin (GdkWindow *window, g_return_val_if_fail (GDK_IS_WINDOW (window), 0); private = (GdkWindowObject *) window; + + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_origin (window, x, y); - return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_origin (window, x, y); + if (x) + *x += private->abs_x; + if (y) + *y += private->abs_y; + + return TRUE; } + /** - * 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 + * gdk_window_get_deskrelative_origin: + * @window: a toplevel #GdkWindow + * @x: return location for X coordinate + * @y: return location for Y coordinate + * + * This gets the origin of a #GdkWindow relative to + * an Enlightenment-window-manager desktop. As long as you don't + * assume that the user's desktop/workspace covers the entire + * root window (i.e. you don't assume that the desktop begins + * at root window coordinate 0,0) this function is not necessary. + * It's deprecated for that reason. + * + * Return value: not meaningful + **/ +gboolean +gdk_window_get_deskrelative_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowObject *private; + gboolean return_val = FALSE; + gint tx = 0; + gint ty = 0; + + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + private = (GdkWindowObject *) window; + + if (!GDK_WINDOW_DESTROYED (window)) + { + return_val = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_deskrelative_origin (window, &tx, &ty); + + if (x) + *x = tx + private->abs_x; + if (y) + *y = ty + private->abs_y; + } + + return return_val; +} + +/** + * 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. @@ -4013,12 +6960,23 @@ gdk_window_shape_combine_mask (GdkWindow *window, gint y) { GdkWindowObject *private; + GdkRegion *region; 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); + if (mask) + region = _gdk_windowing_get_shape_for_mask (mask); + else + region = NULL; + + gdk_window_shape_combine_region (window, + region, + x, y); + + if (region) + gdk_region_destroy (region); } /** @@ -4051,12 +7009,88 @@ gdk_window_shape_combine_region (GdkWindow *window, gint offset_y) { GdkWindowObject *private; + GdkRegion *old_region, *new_region, *diff; 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); + if (GDK_WINDOW_DESTROYED (window)) + return; + + private->shaped = (shape_region != NULL); + + if (private->shape) + gdk_region_destroy (private->shape); + + old_region = NULL; + if (GDK_WINDOW_IS_MAPPED (window)) + old_region = gdk_region_copy (private->clip_region); + + if (shape_region) + { + private->shape = gdk_region_copy (shape_region); + gdk_region_offset (private->shape, offset_x, offset_y); + } + else + private->shape = NULL; + + recompute_visible_regions (private, TRUE, FALSE); + + if (old_region) + { + new_region = gdk_region_copy (private->clip_region); + + /* New area in the window, needs invalidation */ + diff = gdk_region_copy (new_region); + gdk_region_subtract (diff, old_region); + + gdk_window_invalidate_region (window, diff, TRUE); + + gdk_region_destroy (diff); + + if (private->parent != NULL && + GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT) + { + /* New area in the non-root parent window, needs invalidation */ + diff = gdk_region_copy (old_region); + gdk_region_subtract (diff, new_region); + + /* Adjust region to parent window coords */ + gdk_region_offset (diff, private->x, private->y); + + gdk_window_invalidate_region (GDK_WINDOW (private->parent), diff, TRUE); + + gdk_region_destroy (diff); + } + + gdk_region_destroy (new_region); + gdk_region_destroy (old_region); + } +} + +static void +do_child_shapes (GdkWindow *window, + gboolean merge) +{ + GdkWindowObject *private; + GdkRectangle r; + GdkRegion *region; + + private = (GdkWindowObject *) window; + + r.x = 0; + r.y = 0; + r.width = private->width; + r.height = private->height; + + region = gdk_region_rectangle (&r); + remove_child_area (private, NULL, FALSE, region); + + if (merge && private->shape) + gdk_region_subtract (region, private->shape); + + gdk_window_shape_combine_region (window, region, 0, 0); } /** @@ -4071,13 +7105,9 @@ gdk_window_shape_combine_region (GdkWindow *window, 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); + do_child_shapes (window, FALSE); } /** @@ -4095,6 +7125,94 @@ gdk_window_set_child_shapes (GdkWindow *window) */ void gdk_window_merge_child_shapes (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + do_child_shapes (window, TRUE); +} + +/** + * gdk_window_input_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 + * + * Like gdk_window_shape_combine_mask(), but the shape applies + * only to event handling. Mouse events which happen while + * the pointer position corresponds to an unset bit in the + * mask will be passed on the window below @window. + * + * An input shape is typically used with RGBA windows. + * The alpha channel of the window defines which pixels are + * invisible and allows for nicely antialiased borders, + * and the input shape controls where the window is + * "clickable". + * + * On the X11 platform, this requires version 1.1 of the + * shape extension. + * + * On the Win32 platform, this functionality is not present and the + * function does nothing. + * + * Since: 2.10 + */ +void +gdk_window_input_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y) +{ + GdkWindowObject *private; + GdkRegion *region; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *) window; + + if (mask) + region = _gdk_windowing_get_shape_for_mask (mask); + else + region = NULL; + + gdk_window_input_shape_combine_region (window, + region, + x, y); + + gdk_region_destroy (region); +} + +/** + * gdk_window_input_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 + * + * Like gdk_window_shape_combine_region(), but the shape applies + * only to event handling. Mouse events which happen while + * the pointer position corresponds to an unset bit in the + * mask will be passed on the window below @window. + * + * An input shape is typically used with RGBA windows. + * The alpha channel of the window defines which pixels are + * invisible and allows for nicely antialiased borders, + * and the input shape controls where the window is + * "clickable". + * + * On the X11 platform, this requires version 1.1 of the + * shape extension. + * + * On the Win32 platform, this functionality is not present and the + * function does nothing. + * + * Since: 2.10 + */ +void +gdk_window_input_shape_combine_region (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y) { GdkWindowObject *private; @@ -4102,7 +7220,94 @@ gdk_window_merge_child_shapes (GdkWindow *window) private = (GdkWindowObject *) window; - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->merge_child_shapes (window); + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (private->input_shape) + gdk_region_destroy (private->input_shape); + + if (shape_region) + { + private->input_shape = gdk_region_copy (shape_region); + gdk_region_offset (private->input_shape, offset_x, offset_y); + } + else + private->input_shape = NULL; + + if (gdk_window_has_impl (private)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0); + + /* Pointer may have e.g. moved outside window due to the input mask change */ + _gdk_syntesize_crossing_events_for_geometry_change (window); +} + +static void +do_child_input_shapes (GdkWindow *window, + gboolean merge) +{ + GdkWindowObject *private; + GdkRectangle r; + GdkRegion *region; + + private = (GdkWindowObject *) window; + + r.x = 0; + r.y = 0; + r.width = private->width; + r.height = private->height; + + region = gdk_region_rectangle (&r); + remove_child_area (private, NULL, TRUE, region); + + if (merge && private->shape) + gdk_region_subtract (region, private->shape); + if (merge && private->input_shape) + gdk_region_subtract (region, private->input_shape); + + gdk_window_input_shape_combine_region (window, region, 0, 0); +} + + +/** + * gdk_window_set_child_input_shapes: + * @window: a #GdkWindow + * + * Sets the input shape mask of @window to the union of input shape masks + * for all children of @window, ignoring the input shape mask of @window + * itself. Contrast with gdk_window_merge_child_input_shapes() which includes + * the input shape mask of @window in the masks to be merged. + * + * Since: 2.10 + **/ +void +gdk_window_set_child_input_shapes (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + do_child_input_shapes (window, FALSE); +} + +/** + * gdk_window_merge_child_input_shapes: + * @window: a #GdkWindow + * + * Merges the input shape masks for any child windows into the + * input shape mask for @window. i.e. the union of all input masks + * for @window and its children will become the new input mask + * for @window. See gdk_window_input_shape_combine_mask(). + * + * This function is distinct from gdk_window_set_child_input_shapes() + * because it includes @window's input shape mask in the set of + * shapes to be merged. + * + * Since: 2.10 + **/ +void +gdk_window_merge_child_input_shapes (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + do_child_input_shapes (window, TRUE); } @@ -4128,7 +7333,10 @@ gdk_window_set_static_gravities (GdkWindow *window, private = (GdkWindowObject *) window; - return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_static_gravities (window, use_static); + if (gdk_window_has_impl (private)) + return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_static_gravities (window, use_static); + + return FALSE; } /** @@ -4176,6 +7384,9 @@ gdk_window_set_composited (GdkWindow *window, if (private->composited == composited) return; + if (composited) + gdk_window_set_has_native (window, TRUE); + display = gdk_drawable_get_display (GDK_DRAWABLE (window)); if (!gdk_display_supports_composite (display) && composited) @@ -4187,6 +7398,11 @@ gdk_window_set_composited (GdkWindow *window, _gdk_windowing_window_set_composited (window, composited); + recompute_visible_regions (private, TRUE, FALSE); + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_window_invalidate_in_parent (private); + private->composited = composited; } @@ -4294,7 +7510,7 @@ gdk_window_redirect_to_drawable (GdkWindow *window, gint height) { GdkWindowObject *private; - + g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (GDK_IS_DRAWABLE (drawable)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT); @@ -4331,20 +7547,22 @@ static void window_get_size_rectangle (GdkWindow *window, GdkRectangle *rect) { + GdkWindowObject *private = (GdkWindowObject *) window; + rect->x = rect->y = 0; - gdk_drawable_get_size (GDK_DRAWABLE (window), &rect->width, &rect->height); + rect->width = private->width; + rect->height = private->height; } /* 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) + gboolean do_children, + gint *base_x_offset, + gint *base_y_offset) { GdkWindowObject *private = GDK_WINDOW_OBJECT (window); GdkRectangle visible_rect; @@ -4362,13 +7580,6 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window, window_get_size_rectangle (window, &visible_rect); - /* windows that a redirection has ben setup for need to be considered - * fully visible, in order to avoid missing redirected paint ops - * anywhere in the window area. - */ - if (private->redirect && private->redirect->redirected == private) - return gdk_region_rectangle (&visible_rect); - /* real_clip_region is in window coordinates */ real_clip_region = gdk_region_rectangle (&visible_rect); @@ -4381,27 +7592,38 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window, parentwin = lastwin->parent; /* Remove the areas of all overlapping windows above parentwin in the hiearachy */ - for (; parentwin != NULL && (parentwin == private || lastwin != (GdkWindowObject *)base_window); + for (; parentwin != NULL && + (parentwin == private || lastwin != (GdkWindowObject*) base_window); lastwin = parentwin, parentwin = lastwin->parent) { 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 (parentwin); + /* children is ordered in reverse stack order */ - for (cur = GDK_WINDOW_OBJECT (parentwin)->children; cur && cur->data != lastwin; cur = cur->next) + for (cur = 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 offscreen children, as they don't draw in their parent and + * don't take part in the clipping */ + if (gdk_window_is_offscreen (child_private)) + continue; + window_get_size_rectangle (child, &visible_rect); /* Convert rect to "window" coords */ @@ -4432,24 +7654,6 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window, gdk_region_destroy (tmpreg); } - if (gc) - { - GdkRegion *clip_region = _gdk_gc_get_clip_region (gc); - - if (clip_region) - { - /* clip_region is relative to gc clip origin which is relative to the window */ - /* offset it to window relative: */ - tmpreg = gdk_region_copy (clip_region); - gdk_region_offset (real_clip_region, - gc->clip_x_origin, - gc->clip_y_origin); - /* Intersect it with window hierarchy cliprect: */ - gdk_region_intersect (real_clip_region, tmpreg); - gdk_region_destroy (tmpreg); - } - } - if (base_x_offset) *base_x_offset = x_offset; if (base_y_offset) @@ -4458,9 +7662,9 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window, return real_clip_region; } -static void -gdk_window_add_damage (GdkWindow *toplevel, - GdkRegion *damaged_region) +void +_gdk_window_add_damage (GdkWindow *toplevel, + GdkRegion *damaged_region) { GdkDisplay *display; GdkEvent event = { 0, }; @@ -4474,80 +7678,1222 @@ gdk_window_add_damage (GdkWindow *toplevel, } static void -setup_redirect_clip (GdkWindow *window, - GdkGC *gc, - GdkWindowClipData *data) +gdk_window_redirect_free (GdkWindowRedirect *redirect) { - GdkWindowObject *private = (GdkWindowObject *)window; - GdkRegion *visible_region; - GdkRectangle dest_rect; - GdkRegion *tmpreg; - GdkWindow *toplevel; + g_object_unref (redirect->pixmap); + g_free (redirect); +} + +static void +convert_coords_to_child (GdkWindowObject *child, + double x, double y, + double *child_x, double *child_y) +{ + *child_x = x - child->x; + *child_y = y - child->y; +} + +static gboolean +point_in_window (GdkWindowObject *window, + double x, double y) +{ + return + x >= 0 && x < window->width && + y >= 0 && y < window->height && + (window->shape == NULL || + gdk_region_point_in (window->shape, + x, y)) && + (window->input_shape == NULL || + gdk_region_point_in (window->input_shape, + x, y)); +} - data->old_region = _gdk_gc_get_clip_region (gc); - if (data->old_region) - data->old_region = gdk_region_copy (data->old_region); +static GdkWindow * +convert_coords_to_toplevel (GdkWindow *window, + double child_x, double child_y, + double *toplevel_x, double *toplevel_y) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + gdouble x, y; - data->old_clip_x_origin = gc->clip_x_origin; - data->old_clip_y_origin = gc->clip_y_origin; + x = child_x; + y = child_y; - toplevel = GDK_WINDOW (private->redirect->redirected); + while (private->parent != NULL && + (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)) + { + x += private->x; + y += private->y; + private = private->parent; + } - /* Get the clip region for gc clip rect + window hierarchy in - window relative coords */ - visible_region = - _gdk_window_calculate_full_clip_region (window, toplevel, - gc, TRUE, - &data->x_offset, - &data->y_offset); + *toplevel_x = x; + *toplevel_y = y; + + return (GdkWindow *)private; +} - /* Compensate for the source pos/size */ - data->x_offset -= private->redirect->src_x; - data->y_offset -= private->redirect->src_y; - dest_rect.x = -data->x_offset; - dest_rect.y = -data->y_offset; - dest_rect.width = private->redirect->width; - dest_rect.height = private->redirect->height; - tmpreg = gdk_region_rectangle (&dest_rect); - gdk_region_intersect (visible_region, tmpreg); - gdk_region_destroy (tmpreg); - /* Compensate for the dest pos */ - data->x_offset += private->redirect->dest_x; - data->y_offset += private->redirect->dest_y; +static void +convert_toplevel_coords_to_window (GdkWindow *window, + gdouble toplevel_x, + gdouble toplevel_y, + gdouble *window_x, + gdouble *window_y) +{ + GdkWindowObject *private; + gdouble x, y; + GList *children, *l; - gdk_gc_set_clip_region (gc, visible_region); /* This resets clip origin! */ + private = GDK_WINDOW_OBJECT (window); + + x = toplevel_x; + y = toplevel_y; - /* offset clip and tiles from window coords to pixmaps coords */ - gdk_gc_offset (gc, -data->x_offset, -data->y_offset); + children = NULL; + while (private->parent != NULL && + (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)) + { + children = g_list_prepend (children, private); + private = private->parent; + } - /* Offset region to abs coords and add to damage */ - gdk_region_offset (visible_region, data->x_offset, data->y_offset); - gdk_window_add_damage (toplevel, visible_region); + for (l = children; l != NULL; l = l->next) + convert_coords_to_child (l->data, x, y, &x, &y); - gdk_region_destroy (visible_region); + g_list_free (children); + + *window_x = x; + *window_y = y; } -static void -reset_redirect_clip (GdkWindow *offscreen, - GdkGC *gc, - GdkWindowClipData *data) +GdkWindow * +_gdk_window_find_descendant_at (GdkWindow *toplevel, + double x, double y, + double *found_x, + double *found_y) { - /* offset back */ - gdk_gc_offset (gc, data->x_offset, data->y_offset); + GdkWindowObject *private, *sub; + double child_x, child_y; + GList *l; - /* reset old clip */ - gdk_gc_set_clip_region (gc, data->old_region); - if (data->old_region) - gdk_region_destroy (data->old_region); - gdk_gc_set_clip_origin (gc, data->old_clip_x_origin, data->old_clip_y_origin); -} + private = (GdkWindowObject *)toplevel; + + if (point_in_window (private, x, y)) + { + do + { + /* Children is ordered in reverse stack order, i.e. first is topmost */ + for (l = private->children; l != NULL; l = l->next) + { + sub = l->data; -static void -gdk_window_redirect_free (GdkWindowRedirect *redirect) -{ - g_object_unref (redirect->pixmap); - g_free (redirect); + if (!GDK_WINDOW_IS_MAPPED (sub)) + continue; + + convert_coords_to_child (sub, + x, y, + &child_x, &child_y); + if (point_in_window (sub, child_x, child_y)) + { + x = child_x; + y = child_y; + private = sub; + break; + } + } + } + while (l != NULL); + } + else + { + /* Not in window at all */ + private = NULL; + } + + if (found_x) + *found_x = x; + if (found_y) + *found_y = y; + + return (GdkWindow *)private; +} + +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_BUTTON_PRESS_MASK,/* GDK_SCROLL= 31 */ + 0, /* GDK_WINDOW_STATE = 32 */ + 0, /* GDK_SETTING = 33 */ + 0, /* GDK_OWNER_CHANGE = 34 */ + 0, /* GDK_GRAB_BROKEN = 35 */ + 0, /* GDK_DAMAGE = 36 */ +}; +G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST); + +/* 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 gboolean +is_button_type (GdkEventType type) +{ + return type == GDK_BUTTON_PRESS || + type == GDK_2BUTTON_PRESS || + type == GDK_3BUTTON_PRESS || + type == GDK_BUTTON_RELEASE || + type == GDK_SCROLL; +} + +static gboolean +is_motion_type (GdkEventType type) +{ + return type == GDK_MOTION_NOTIFY || + type == GDK_ENTER_NOTIFY || + type == GDK_LEAVE_NOTIFY; +} + +static GdkWindowObject * +find_common_ancestor (GdkWindowObject *win1, + GdkWindowObject *win2) +{ + GdkWindowObject *tmp; + GList *path1 = NULL, *path2 = NULL; + GList *list1, *list2; + + tmp = win1; + while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT) + { + path1 = g_list_prepend (path1, tmp); + tmp = tmp->parent; + } + + tmp = win2; + while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT) + { + 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 tmp; +} + +GdkEvent * +_gdk_make_event (GdkWindow *window, + GdkEventType type, + GdkEvent *event_in_queue, + gboolean before_event) +{ + GdkEvent *event = gdk_event_new (type); + guint32 the_time; + GdkModifierType the_state; + + the_time = gdk_event_get_time (event_in_queue); + gdk_event_get_state (event_in_queue, &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 (event_in_queue) + { + if (before_event) + _gdk_event_queue_insert_before (gdk_drawable_get_display (window), event_in_queue, event); + else + _gdk_event_queue_insert_after (gdk_drawable_get_display (window), event_in_queue, event); + } + else + _gdk_event_queue_append (gdk_drawable_get_display (window), event); + + return event; +} + +static void +send_crossing_event (GdkDisplay *display, + GdkWindowObject *toplevel, + GdkWindowObject *window, + GdkEventType type, + GdkCrossingMode mode, + GdkNotifyType notify_type, + GdkWindow *subwindow, + gint toplevel_x, + gint toplevel_y, + GdkModifierType mask, + guint32 time_, + GdkEvent *event_in_queue, + gulong serial) +{ + GdkEvent *event; + guint32 event_mask; + GdkPointerGrabInfo *grab; + + grab = _gdk_display_has_pointer_grab (display, serial); + + if (grab != NULL && + !grab->owner_events && + (GdkWindow *)window != grab->window) + return; + + if (type == GDK_LEAVE_NOTIFY) + event_mask = GDK_LEAVE_NOTIFY_MASK; + else + event_mask = GDK_ENTER_NOTIFY_MASK; + + if (window->event_mask & event_mask) + { + event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE); + event->crossing.time = time_; + event->crossing.subwindow = subwindow; + if (subwindow) + g_object_ref (subwindow); + convert_toplevel_coords_to_window ((GdkWindow *)window, + toplevel_x, toplevel_y, + &event->crossing.x, &event->crossing.y); + event->crossing.x_root = toplevel_x + toplevel->x; + event->crossing.y_root = toplevel_y + toplevel->y; + event->crossing.mode = mode; + event->crossing.detail = notify_type; + event->crossing.focus = FALSE; + event->crossing.state = mask; + } +} + + +/* The coordinates are in the toplevel window that src/dest are in. + * src and dest are always (if != NULL) in the same toplevel, as + * we get a leave-notify and set the window_under_pointer to null + * before crossing to another toplevel. + */ +void +_gdk_syntesize_crossing_events (GdkDisplay *display, + GdkWindow *src, + GdkWindow *dest, + GdkCrossingMode mode, + gint toplevel_x, + gint toplevel_y, + GdkModifierType mask, + guint32 time_, + GdkEvent *event_in_queue, + gulong serial) +{ + GdkWindowObject *c; + GdkWindowObject *win, *last, *next; + GList *path, *list; + gboolean non_linear; + GdkWindowObject *a; + GdkWindowObject *b; + GdkWindowObject *toplevel; + GdkNotifyType notify_type; + + /* TODO: Don't send events to toplevel, as we get those from the windowing system */ + + a = (GdkWindowObject *)src; + b = (GdkWindowObject *)dest; + if (a == b) + return; /* No crossings generated between src and dest */ + + c = find_common_ancestor (a, b); + + non_linear = (c != a) && (c != b); + + if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */ + { + toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)a); + + /* Traverse up from a to (excluding) c sending leave events */ + if (non_linear) + notify_type = GDK_NOTIFY_NONLINEAR; + else if (c == a) + notify_type = GDK_NOTIFY_INFERIOR; + else + notify_type = GDK_NOTIFY_ANCESTOR; + send_crossing_event (display, toplevel, + a, GDK_LEAVE_NOTIFY, + mode, + notify_type, + NULL, + toplevel_x, toplevel_y, + mask, time_, + event_in_queue, + serial); + + if (c != a) + { + if (non_linear) + notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL; + else + notify_type = GDK_NOTIFY_VIRTUAL; + + last = a; + win = a->parent; + while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT) + { + send_crossing_event (display, toplevel, + win, GDK_LEAVE_NOTIFY, + mode, + notify_type, + (GdkWindow *)last, + toplevel_x, toplevel_y, + mask, time_, + event_in_queue, + serial); + + last = win; + win = win->parent; + } + } + } + + if (b) /* Might not be a dest, e.g. if we're moving out of the window */ + { + toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)b); + + /* Traverse down from c to b */ + if (c != b) + { + path = NULL; + win = b->parent; + while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT) + { + path = g_list_prepend (path, win); + win = win->parent; + } + + if (non_linear) + notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL; + else + notify_type = GDK_NOTIFY_VIRTUAL; + + list = path; + while (list) + { + win = (GdkWindowObject *)list->data; + list = g_list_next (list); + if (list) + next = (GdkWindowObject *)list->data; + else + next = b; + + send_crossing_event (display, toplevel, + win, GDK_ENTER_NOTIFY, + mode, + notify_type, + (GdkWindow *)next, + toplevel_x, toplevel_y, + mask, time_, + event_in_queue, + serial); + } + g_list_free (path); + } + + + if (non_linear) + notify_type = GDK_NOTIFY_NONLINEAR; + else if (c == a) + notify_type = GDK_NOTIFY_ANCESTOR; + else + notify_type = GDK_NOTIFY_INFERIOR; + + send_crossing_event (display, toplevel, + b, GDK_ENTER_NOTIFY, + mode, + notify_type, + NULL, + toplevel_x, toplevel_y, + mask, time_, + event_in_queue, + serial); + } +} + +static GdkWindow * +get_toplevel (GdkWindow *w) +{ + GdkWindowObject *private = GDK_WINDOW_OBJECT (w); + + while (private->parent != NULL && + (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)) + private = private->parent; + + return GDK_WINDOW (private); +} + +/* Returns the window inside the event window with the pointer in it + * at the specified coordinates, or NULL if its not in any child of + * the toplevel. It also takes into account !owner_events grabs. + */ +static GdkWindow * +get_pointer_window (GdkDisplay *display, + GdkWindow *event_window, + gdouble toplevel_x, + gdouble toplevel_y, + gulong serial) +{ + GdkWindow *pointer_window; + GdkPointerGrabInfo *grab; + + if (event_window == display->pointer_info.toplevel_under_pointer) + pointer_window = + _gdk_window_find_descendant_at (event_window, + toplevel_x, toplevel_y, + NULL, NULL); + else + pointer_window = NULL; + + grab = _gdk_display_has_pointer_grab (display, serial); + if (grab != NULL && + !grab->owner_events && + pointer_window != grab->window) + pointer_window = NULL; + + return pointer_window; +} + +void +_gdk_display_set_window_under_pointer (GdkDisplay *display, + GdkWindow *window) +{ + GdkWindowObject *private; + + private = (GdkWindowObject *)window; + + if (display->pointer_info.window_under_pointer) + g_object_unref (display->pointer_info.window_under_pointer); + display->pointer_info.window_under_pointer = window; + if (window) + g_object_ref (window); + + if (window) + update_cursor (display); + + _gdk_display_enable_motion_hints (display); +} + +void +_gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window) +{ + GdkDisplay *display; + GdkWindow *changed_toplevel; + GdkWindow *new_window_under_pointer; + gulong serial; + + display = gdk_drawable_get_display (changed_window); + + serial = _gdk_windowing_window_get_next_serial (display); + changed_toplevel = get_toplevel (changed_window); + + if (changed_toplevel == display->pointer_info.toplevel_under_pointer) + { + new_window_under_pointer = + get_pointer_window (display, changed_toplevel, + display->pointer_info.toplevel_x, + display->pointer_info.toplevel_y, + serial); + if (new_window_under_pointer != + display->pointer_info.window_under_pointer) + { + _gdk_syntesize_crossing_events (display, + display->pointer_info.window_under_pointer, + new_window_under_pointer, + GDK_CROSSING_NORMAL, + display->pointer_info.toplevel_x, + display->pointer_info.toplevel_y, + display->pointer_info.state, + GDK_CURRENT_TIME, + NULL, + serial); + _gdk_display_set_window_under_pointer (display, new_window_under_pointer); + } + } +} + +/* Don't use for crossing events */ +static GdkWindow * +get_event_window (GdkDisplay *display, + GdkWindow *pointer_window, + GdkEventType type, + GdkModifierType mask, + guint *evmask_out, + gulong serial) +{ + guint evmask; + GdkWindow *grab_window; + GdkWindowObject *w; + GdkPointerGrabInfo *grab; + + grab = _gdk_display_has_pointer_grab (display, serial); + + if (grab != NULL && !grab->owner_events) + { + evmask = grab->event_mask; + evmask = update_evmask_for_button_motion (evmask, mask); + + grab_window = grab->window; + + if (evmask & type_masks[type]) + { + if (evmask_out) + *evmask_out = evmask; + return grab_window; + } + else + return NULL; + } + + w = (GdkWindowObject *)pointer_window; + while (w != NULL) + { + evmask = w->event_mask; + evmask = update_evmask_for_button_motion (evmask, mask); + + if (evmask & type_masks[type]) + { + if (evmask_out) + *evmask_out = evmask; + return (GdkWindow *)w; + } + + w = w->parent; + } + + if (grab != NULL && + grab->owner_events) + { + evmask = grab->event_mask; + evmask = update_evmask_for_button_motion (evmask, mask); + + if (evmask & type_masks[type]) + { + if (evmask_out) + *evmask_out = evmask; + return grab->window; + } + else + return NULL; + } + + return NULL; +} + +static gboolean +proxy_pointer_event (GdkDisplay *display, + GdkEvent *source_event, + gulong serial) +{ + GdkWindow *toplevel_window, *event_window; + GdkWindow *pointer_window; + GdkEvent *event; + guint state; + gdouble toplevel_x, toplevel_y; + guint32 time_; + + event_window = source_event->any.window; + gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y); + gdk_event_get_state (source_event, &state); + time_ = gdk_event_get_time (source_event); + toplevel_window = convert_coords_to_toplevel (event_window, + toplevel_x, toplevel_y, + &toplevel_x, &toplevel_y); + + + /* If we get crossing events with subwindow unexpectedly being NULL + that means there is a native subwindow that gdk doesn't know about. + We track these and forward them, with the correct virtual window + events inbetween. + This is important to get right, as metacity uses gdk for the frame + windows, but gdk doesn't know about the client windows reparented + into the frame. */ + if (((source_event->type == GDK_LEAVE_NOTIFY && + source_event->crossing.detail == GDK_NOTIFY_INFERIOR) || + (source_event->type == GDK_ENTER_NOTIFY && + (source_event->crossing.detail == GDK_NOTIFY_VIRTUAL || + source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))) && + source_event->crossing.subwindow == NULL) + { + /* Left for an unknown (to gdk) subwindow */ + + /* Send leave events from window under pointer to event window + that will get the subwindow == NULL window */ + _gdk_syntesize_crossing_events (display, + display->pointer_info.window_under_pointer, + event_window, + source_event->crossing.mode, + toplevel_x, toplevel_y, + state, time_, + source_event, + serial); + + /* Send subwindow == NULL event */ + send_crossing_event (display, + (GdkWindowObject *)toplevel_window, + (GdkWindowObject *)event_window, + source_event->type, + source_event->crossing.mode, + source_event->crossing.detail, + NULL, + toplevel_x, toplevel_y, + state, time_, + source_event, + serial); + + _gdk_display_set_window_under_pointer (display, NULL); + return TRUE; + } + + pointer_window = get_pointer_window (display, toplevel_window, + toplevel_x, toplevel_y, serial); + + if (((source_event->type == GDK_ENTER_NOTIFY && + source_event->crossing.detail == GDK_NOTIFY_INFERIOR) || + (source_event->type == GDK_LEAVE_NOTIFY && + (source_event->crossing.detail == GDK_NOTIFY_VIRTUAL || + source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))) && + source_event->crossing.subwindow == NULL) + { + /* Entered from an unknown (to gdk) subwindow */ + + /* Send subwindow == NULL event */ + send_crossing_event (display, + (GdkWindowObject *)toplevel_window, + (GdkWindowObject *)event_window, + source_event->type, + source_event->crossing.mode, + source_event->crossing.detail, + NULL, + toplevel_x, toplevel_y, + state, time_, + source_event, + serial); + + /* Send enter events from event window to pointer_window */ + _gdk_syntesize_crossing_events (display, + event_window, + pointer_window, + source_event->crossing.mode, + toplevel_x, toplevel_y, + state, time_, + source_event, + serial); + _gdk_display_set_window_under_pointer (display, pointer_window); + return TRUE; + } + + if (display->pointer_info.window_under_pointer != pointer_window) + { + /* Either a toplevel crossing notify that ended up inside a child window, + or a motion notify that got into another child window */ + + /* Different than last time, send crossing events */ + _gdk_syntesize_crossing_events (display, + display->pointer_info.window_under_pointer, + pointer_window, + GDK_CROSSING_NORMAL, + toplevel_x, toplevel_y, + state, time_, + source_event, + serial); + _gdk_display_set_window_under_pointer (display, pointer_window); + } + else if (source_event->type == GDK_MOTION_NOTIFY) + { + GdkWindow *event_win; + guint evmask; + gboolean is_hint; + + event_win = get_event_window (display, + pointer_window, + source_event->type, + state, + &evmask, + serial); + + is_hint = FALSE; + + if (event_win && + (evmask & GDK_POINTER_MOTION_HINT_MASK)) + { + if (display->pointer_info.motion_hint_serial != 0 && + serial < display->pointer_info.motion_hint_serial) + event_win = NULL; /* Ignore event */ + else + { + is_hint = TRUE; + display->pointer_info.motion_hint_serial = G_MAXULONG; + } + } + + if (event_win) + { + event = _gdk_make_event (event_win, GDK_MOTION_NOTIFY, source_event, FALSE); + event->motion.time = time_; + convert_toplevel_coords_to_window (event_win, + toplevel_x, toplevel_y, + &event->motion.x, &event->motion.y); + event->motion.x_root = source_event->motion.x_root; + event->motion.y_root = source_event->motion.y_root;; + event->motion.state = state; + event->motion.is_hint = is_hint; + event->motion.device = NULL; + event->motion.device = source_event->motion.device; + } + } + + /* unlink all move events from queue. + We handle our own, including our emulated masks. */ + return TRUE; +} + +#define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \ + GDK_BUTTON2_MASK | \ + GDK_BUTTON3_MASK | \ + GDK_BUTTON4_MASK | \ + GDK_BUTTON5_MASK) + +static gboolean +proxy_button_event (GdkEvent *source_event, + gulong serial) +{ + GdkWindow *toplevel_window, *event_window; + GdkWindow *event_win; + GdkWindow *pointer_window; + GdkEvent *event; + guint state; + guint32 time_; + GdkEventType type; + gdouble toplevel_x, toplevel_y; + GdkDisplay *display; + GdkWindowObject *w; + + type = source_event->any.type; + event_window = source_event->any.window; + gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y); + gdk_event_get_state (source_event, &state); + time_ = gdk_event_get_time (source_event); + display = gdk_drawable_get_display (source_event->any.window); + toplevel_window = convert_coords_to_toplevel (event_window, + toplevel_x, toplevel_y, + &toplevel_x, &toplevel_y); + + if (type == GDK_BUTTON_PRESS && + _gdk_display_has_pointer_grab (display, serial) == NULL) + { + pointer_window = + _gdk_window_find_descendant_at (toplevel_window, + toplevel_x, toplevel_y, + NULL, NULL); + + /* Find the event window, that gets the grab */ + w = (GdkWindowObject *)pointer_window; + while (w != NULL && w->parent->window_type != GDK_WINDOW_ROOT) + { + if (w->event_mask & GDK_BUTTON_PRESS_MASK) + break; + w = w->parent; + } + pointer_window = (GdkWindow *)w; + + _gdk_display_add_pointer_grab (display, + pointer_window, + toplevel_window, + FALSE, + gdk_window_get_events (pointer_window), + serial, + time_, + TRUE); + _gdk_display_pointer_grab_update (display, serial); + } + + pointer_window = get_pointer_window (display, toplevel_window, + toplevel_x, toplevel_y, + serial); + + event_win = get_event_window (display, + pointer_window, + type, state, + NULL, serial); + + if (event_win == NULL) + return TRUE; + + event = _gdk_make_event (event_win, type, source_event, FALSE); + + switch (type) + { + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + event->button.button = source_event->button.button; + convert_toplevel_coords_to_window (event_win, + toplevel_x, toplevel_y, + &event->button.x, &event->button.y); + event->button.x_root = source_event->button.x_root; + event->button.y_root = source_event->button.y_root; + event->button.state = state; + event->button.device = source_event->button.device; + + if (type == GDK_BUTTON_PRESS) + _gdk_event_button_generate (display, event); + return TRUE; + + case GDK_SCROLL: + event->scroll.direction = source_event->scroll.direction; + convert_toplevel_coords_to_window (event_win, + toplevel_x, toplevel_y, + &event->scroll.x, &event->scroll.y); + event->scroll.x_root = source_event->scroll.x_root; + event->scroll.y_root = source_event->scroll.y_root; + event->scroll.state = state; + event->scroll.device = source_event->scroll.device; + return TRUE; + + default: + return FALSE; + } + + return TRUE; /* Always unlink original, we want to obey the emulated event mask */ +} + +#ifdef DEBUG_WINDOW_PRINTING +static void +gdk_window_print (GdkWindowObject *window, + int indent) +{ + GdkRectangle r; + + g_print ("%*s%p: [%s] %d,%d %dx%d", indent, "", window, + window->user_data ? g_type_name_from_instance (window->user_data) : "no widget", + window->x, window->y, + window->width, window->height + ); + + if (gdk_window_has_impl (window)) + { +#ifdef GDK_WINDOWING_X11 + g_print (" impl(0x%lx)", gdk_x11_drawable_get_xid (GDK_DRAWABLE (window))); +#endif + } + + if (window->input_only) + g_print (" input-only"); + + if (!gdk_window_is_visible ((GdkWindow *)window)) + g_print (" hidden"); + + g_print (" abs[%d,%d]", + window->abs_x, window->abs_y); + + gdk_region_get_clipbox (window->clip_region, &r); + if (gdk_region_empty (window->clip_region)) + g_print (" clipbox[empty]"); + else + g_print (" clipbox[%d,%d %dx%d]", r.x, r.y, r.width, r.height); + + g_print ("\n"); +} + + +static void +gdk_window_print_tree (GdkWindow *window, + int indent, + gboolean include_input_only) +{ + GdkWindowObject *private; + GList *l; + + private = (GdkWindowObject *)window; + + if (private->input_only && !include_input_only) + return; + + gdk_window_print (private, indent); + + for (l = private->children; l != NULL; l = l->next) + gdk_window_print_tree (l->data, indent + 4, include_input_only); +} + +#endif /* DEBUG_WINDOW_PRINTING */ + +void +_gdk_windowing_got_event (GdkDisplay *display, + GList *event_link, + GdkEvent *event, + gulong serial) +{ + GdkWindow *event_window; + GdkWindowObject *event_private; + gdouble x, y; + gboolean unlink_event; + guint old_state, old_button; + GdkPointerGrabInfo *button_release_grab; + gboolean is_toplevel; + + if (gdk_event_get_time (event) != GDK_CURRENT_TIME) + display->last_event_time = gdk_event_get_time (event); + + _gdk_display_pointer_grab_update (display, + serial); + + event_window = event->any.window; + if (!event_window) + return; + + event_private = GDK_WINDOW_OBJECT (event_window); + +#ifdef DEBUG_WINDOW_PRINTING + if (event->type == GDK_KEY_PRESS && + (event->key.keyval == 0xa7 || + event->key.keyval == 0xbd)) + { + gdk_window_print_tree (event_window, 0, + event->key.keyval == 0xbd); + } +#endif + + if (!(is_button_type (event->type) || + is_motion_type (event->type)) || + GDK_WINDOW_TYPE (event_private) == GDK_WINDOW_ROOT) + return; + + is_toplevel = + event_private->parent == NULL || + GDK_WINDOW_TYPE (event_private->parent) == GDK_WINDOW_ROOT; + + if ((event->type == GDK_ENTER_NOTIFY || + event->type == GDK_LEAVE_NOTIFY) && + (event->crossing.mode == GDK_CROSSING_GRAB || + event->crossing.mode == GDK_CROSSING_UNGRAB) && + (_gdk_display_has_pointer_grab (display, serial) || + event->crossing.detail == GDK_NOTIFY_INFERIOR)) + { + /* We synthesize all crossing events due to grabs outselves, + * so we ignore the native ones caused by our native pointer_grab + * calls. Otherwise we would proxy these crossing event and cause + * multiple copies of crossing events for grabs. + * + * We do want to handle grabs from other clients though, as for + * instance alt-tab in metacity causes grabs like these and + * we want to handle those. Thus the has_pointer_grab check. + * + * Implicit grabs on child windows create some grabbing events + * that are sent before the button press. This means we can't + * detect these with the has_pointer_grab check (as the implicit + * grab is only noticed when we get button press event), so we + * detect these events by checking for INFERIOR enter or leave + * events. These should never be a problem to filter out. + */ + + /* We ended up in this window after some (perhaps other clients) + grab, so update the toplevel_under_window state */ + if (is_toplevel && + event->type == GDK_ENTER_NOTIFY && + event->crossing.mode == GDK_CROSSING_UNGRAB) + { + if (display->pointer_info.toplevel_under_pointer) + g_object_unref (display->pointer_info.toplevel_under_pointer); + display->pointer_info.toplevel_under_pointer = g_object_ref (event_window); + } + + unlink_event = TRUE; + goto out; + } + + /* Track toplevel_under_pointer */ + if (is_toplevel) + { + if (event->type == GDK_ENTER_NOTIFY && + event->crossing.detail != GDK_NOTIFY_INFERIOR) + { + if (display->pointer_info.toplevel_under_pointer) + g_object_unref (display->pointer_info.toplevel_under_pointer); + display->pointer_info.toplevel_under_pointer = g_object_ref (event_window); + } + else if (event->type == GDK_LEAVE_NOTIFY && + event->crossing.detail != GDK_NOTIFY_INFERIOR && + display->pointer_info.toplevel_under_pointer == event_window) + { + if (display->pointer_info.toplevel_under_pointer) + g_object_unref (display->pointer_info.toplevel_under_pointer); + display->pointer_info.toplevel_under_pointer = NULL; + } + } + + /* Store last pointer window and position/state */ + old_state = display->pointer_info.state; + old_button = display->pointer_info.button; + + gdk_event_get_coords (event, &x, &y); + convert_coords_to_toplevel (event_window, x, y, &x, &y); + display->pointer_info.toplevel_x = x; + display->pointer_info.toplevel_y = y; + gdk_event_get_state (event, &display->pointer_info.state); + if (event->type == GDK_BUTTON_PRESS || + event->type == GDK_BUTTON_RELEASE) + display->pointer_info.button = event->button.button; + + if (display->pointer_info.state != old_state || + display->pointer_info.button != old_button) + _gdk_display_enable_motion_hints (display); + + unlink_event = FALSE; + if (is_motion_type (event->type)) + unlink_event = proxy_pointer_event (display, + event, + serial); + else if (is_button_type (event->type)) + unlink_event = proxy_button_event (event, + serial); + + if (event->type == GDK_BUTTON_RELEASE) + { + button_release_grab = + _gdk_display_has_pointer_grab (display, serial); + if (button_release_grab && + button_release_grab->implicit && + (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0) + { + button_release_grab->serial_end = serial; + button_release_grab->implicit_ungrab = TRUE; + _gdk_display_pointer_grab_update (display, serial); + } + } + + out: + if (unlink_event) + { + _gdk_event_queue_remove_link (display, event_link); + g_list_free_1 (event_link); + gdk_event_free (event); + } } #define __GDK_WINDOW_C__ diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index 866bb6946..6a9985a4f 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -37,10 +37,10 @@ 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 _GdkWindowRedirect GdkWindowRedirect; /* Classes of windows. * InputOutput: Almost every window should be of this type. Such windows @@ -77,7 +77,8 @@ typedef enum GDK_WINDOW_CHILD, GDK_WINDOW_DIALOG, GDK_WINDOW_TEMP, - GDK_WINDOW_FOREIGN + GDK_WINDOW_FOREIGN, + GDK_WINDOW_OFFSCREEN } GdkWindowType; /* Window attribute mask values. @@ -259,6 +260,12 @@ typedef struct _GdkWindowObjectClass GdkWindowObjectClass; #define GDK_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW, GdkWindowObjectClass)) #define GDK_WINDOW_OBJECT(object) ((GdkWindowObject *) GDK_WINDOW (object)) +#ifndef GDK_COMPILATION +/* We used to export all of GdkWindowObject, but we don't want to keep doing so. + However, there are various parts of it accessed by macros and other code, + so we keep the old exported version public, but in reality it is larger. */ + +/**** DON'T CHANGE THIS STRUCT, the real version is in gdkinternals.h ****/ struct _GdkWindowObject { GdkDrawable parent_instance; @@ -308,6 +315,7 @@ struct _GdkWindowObject GdkWindowRedirect *redirect; }; +#endif struct _GdkWindowObjectClass { @@ -379,6 +387,8 @@ void gdk_window_move_region (GdkWindow *window, const GdkRegion *region, gint dx, gint dy); +void gdk_window_set_has_native (GdkWindow *window, + gboolean has_native); /* * This allows for making shaped (partially transparent) windows @@ -645,12 +655,18 @@ 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 */ +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); #ifndef GDK_DISABLE_DEPRECATED #define GDK_ROOT_PARENT() (gdk_get_default_root_window ()) diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h index f9f97b6fa..d63e5a1ff 100644 --- a/gdk/gdkwindowimpl.h +++ b/gdk/gdkwindowimpl.h @@ -43,12 +43,13 @@ struct _GdkWindowImplIface { GTypeInterface g_iface; - void (* show) (GdkWindow *window, - gboolean raise); + void (* show) (GdkWindow *window); void (* hide) (GdkWindow *window); void (* withdraw) (GdkWindow *window); void (* raise) (GdkWindow *window); void (* lower) (GdkWindow *window); + void (* restack_under) (GdkWindow *window, + GList *native_siblings); void (* move_resize) (GdkWindow *window, gboolean with_move, @@ -56,25 +57,10 @@ struct _GdkWindowImplIface 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); + GdkPixmap *pixmap); GdkEventMask (* get_events) (GdkWindow *window); void (* set_events) (GdkWindow *window, @@ -97,28 +83,74 @@ struct _GdkWindowImplIface gint (* get_origin) (GdkWindow *window, gint *x, gint *y); - void (* get_offsets) (GdkWindow *window, - gint *x_offset, - gint *y_offset); + gint (* get_deskrelative_origin) (GdkWindow *window, + gint *x, + gint *y); - 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); + void (* input_shape_combine_region) (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y); gboolean (* set_static_gravities) (GdkWindow *window, gboolean use_static); + + /* Called before processing updates for a window. This gives the windowing + * layer a chance to save the region for later use in avoiding duplicate + * exposes. The return value indicates whether the function has a saved + * the region; if the result is TRUE, then the windowing layer is responsible + * for destroying the region later. + */ + gboolean (* queue_antiexpose) (GdkWindow *window, + GdkRegion *update_area); + void (* queue_translation) (GdkWindow *window, + GdkRegion *area, + gint dx, + gint dy); + +/* Called to do the windowing system specific part of gdk_window_destroy(), + * + * window: The window being destroyed + * recursing: If TRUE, then this is being called because a parent + * was destroyed. This generally means that the call to the windowing system + * to destroy the window can be omitted, since it will be destroyed as a result + * of the parent being destroyed. Unless @foreign_destroy + * + * foreign_destroy: If TRUE, the window or a parent was destroyed by some external + * agency. The window has already been destroyed and no windowing + * system calls should be made. (This may never happen for some + * windowing systems.) + */ + void (* destroy) (GdkWindow *window, + gboolean recursing, + gboolean foreign_destroy); }; /* Interface Functions */ GType gdk_window_impl_get_type (void) G_GNUC_CONST; +/* private definitions from gdkwindow.h */ + +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; +}; + G_END_DECLS #endif /* __GDK_WINDOW_IMPL_H__ */ diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c index 3cc0f2e12..761b07fb3 100644 --- a/gdk/quartz/GdkQuartzView.c +++ b/gdk/quartz/GdkQuartzView.c @@ -35,6 +35,11 @@ return gdk_window; } +-(NSTrackingRectTag)trackingRect +{ + return trackingRect; +} + -(BOOL)isFlipped { return YES; @@ -67,47 +72,40 @@ if (NSEqualRects (rect, NSZeroRect)) return; - GDK_QUARTZ_ALLOC_POOL; - [self getRectsBeingDrawn:&drawn_rects count:&count]; - region = gdk_region_new (); - - for (i = 0; i < count; i++) - { - gdk_rect.x = drawn_rects[i].origin.x; - gdk_rect.y = drawn_rects[i].origin.y; - gdk_rect.width = drawn_rects[i].size.width; - gdk_rect.height = drawn_rects[i].size.height; - - gdk_region_union_with_rect (region, &gdk_rect); - } - - if (!gdk_region_empty (region)) + /* Note: arbitrary limit here to not degrade performace too much. It would + * be better to optimize the construction of the region below, by using + * _gdk_region_new_from_yxbanded_rects. + */ + if (count > 25) { - GdkEvent event; - gdk_rect.x = rect.origin.x; gdk_rect.y = rect.origin.y; gdk_rect.width = rect.size.width; gdk_rect.height = rect.size.height; - - event.expose.type = GDK_EXPOSE; - event.expose.window = g_object_ref (gdk_window); - event.expose.send_event = FALSE; - event.expose.count = 0; - event.expose.region = region; - event.expose.area = gdk_rect; - - impl->in_paint_rect_count++; - (*_gdk_event_func) (&event, _gdk_event_data); + region = gdk_region_rectangle (&gdk_rect); + } + else + { + region = gdk_region_new (); - impl->in_paint_rect_count--; + for (i = 0; i < count; i++) + { + gdk_rect.x = drawn_rects[i].origin.x; + gdk_rect.y = drawn_rects[i].origin.y; + gdk_rect.width = drawn_rects[i].size.width; + gdk_rect.height = drawn_rects[i].size.height; - g_object_unref (gdk_window); + gdk_region_union_with_rect (region, &gdk_rect); + } } + impl->in_paint_rect_count++; + _gdk_window_process_updates_recurse (gdk_window, region); + impl->in_paint_rect_count--; + gdk_region_destroy (region); if (needsInvalidateShadow) @@ -115,8 +113,6 @@ [[self window] invalidateShadow]; needsInvalidateShadow = NO; } - - GDK_QUARTZ_RELEASE_POOL; } -(void)setNeedsInvalidateShadow:(BOOL)invalidate @@ -133,6 +129,9 @@ GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); NSRect rect; + if (!impl->toplevel) + return; + if (trackingRect) { [self removeTrackingRect:trackingRect]; diff --git a/gdk/quartz/GdkQuartzView.h b/gdk/quartz/GdkQuartzView.h index 752c3989b..f9c9a9cab 100644 --- a/gdk/quartz/GdkQuartzView.h +++ b/gdk/quartz/GdkQuartzView.h @@ -29,6 +29,7 @@ -(void)setGdkWindow:(GdkWindow *)window; -(GdkWindow *)gdkWindow; +-(NSTrackingRectTag)trackingRect; -(void)setNeedsInvalidateShadow:(BOOL)invalidate; @end diff --git a/gdk/quartz/GdkQuartzWindow.c b/gdk/quartz/GdkQuartzWindow.c index 3f1681511..282b65b75 100644 --- a/gdk/quartz/GdkQuartzWindow.c +++ b/gdk/quartz/GdkQuartzWindow.c @@ -142,17 +142,8 @@ NSRect content_rect = [self contentRectForFrameRect:[self frame]]; GdkWindow *window = [[self contentView] gdkWindow]; GdkWindowObject *private = (GdkWindowObject *)window; - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); GdkEvent *event; - /* Ignore new position during showing/hiding the window, otherwise we - * would get the off-screen position that is used for hidden windows to - * get reliable MouseEntered events when showing them again. See comments - * in show() and hide(). - */ - if (inShowOrHide) - return; - private->x = content_rect.origin.x; private->y = _gdk_quartz_window_get_inverted_screen_y (content_rect.origin.y + content_rect.size.height); @@ -161,8 +152,8 @@ event->configure.window = g_object_ref (window); event->configure.x = private->x; event->configure.y = private->y; - event->configure.width = impl->width; - event->configure.height = impl->height; + event->configure.width = private->width; + event->configure.height = private->height; _gdk_event_queue_append (gdk_display_get_default (), event); } @@ -172,21 +163,22 @@ NSRect content_rect = [self contentRectForFrameRect:[self frame]]; GdkWindow *window = [[self contentView] gdkWindow]; GdkWindowObject *private = (GdkWindowObject *)window; - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); GdkEvent *event; - impl->width = content_rect.size.width; - impl->height = content_rect.size.height; + private->width = content_rect.size.width; + private->height = content_rect.size.height; + + [[self contentView] setFrame:NSMakeRect (0, 0, private->width, private->height)]; - [[self contentView] setFrame:NSMakeRect (0, 0, impl->width, impl->height)]; + _gdk_window_update_size (window); /* Synthesize a configure event */ event = gdk_event_new (GDK_CONFIGURE); event->configure.window = g_object_ref (window); event->configure.x = private->x; event->configure.y = private->y; - event->configure.width = impl->width; - event->configure.height = impl->height; + event->configure.width = private->width; + event->configure.height = private->height; _gdk_event_queue_append (gdk_display_get_default (), event); } @@ -279,32 +271,8 @@ GdkWindow *window = [[self contentView] gdkWindow]; GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - gboolean was_hidden; - int requested_x = 0, requested_y = 0; inShowOrHide = YES; - was_hidden = FALSE; - - if (!GDK_WINDOW_IS_MAPPED (window)) - { - NSRect content_rect; - NSRect frame_rect; - - was_hidden = TRUE; - - /* We move the window in place if it's not mapped. See comment in - * hide(). - */ - content_rect = - NSMakeRect (private->x, - _gdk_quartz_window_get_inverted_screen_y (private->y) - impl->height, - impl->width, impl->height); - frame_rect = [impl->toplevel frameRectForContentRect:content_rect]; - [impl->toplevel setFrame:frame_rect display:NO]; - - requested_x = frame_rect.origin.x; - requested_y = frame_rect.origin.y; - } if (makeKey) [impl->toplevel makeKeyAndOrderFront:impl->toplevel]; @@ -312,20 +280,6 @@ [impl->toplevel orderFront:nil]; inShowOrHide = NO; - - /* When the window manager didn't allow our request, update the position - * to what it really ended up as. - */ - if (was_hidden) - { - NSRect frame_rect; - - frame_rect = [impl->toplevel frame]; - if (requested_x != frame_rect.origin.x || requested_y != frame_rect.origin.y) - { - [self windowDidMove:nil]; - } - } } - (void)hide @@ -333,23 +287,9 @@ GdkWindow *window = [[self contentView] gdkWindow]; GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - NSRect content_rect; - NSRect frame_rect; inShowOrHide = YES; - - /* We move the window away when hiding, to make it possible to move it in - * place when showing to get reliable tracking rect events (which are used - * to generate crossing events). We have to do this, probably a bug in - * quartz. - */ - content_rect = NSMakeRect (-500 - impl->width, -500 - impl->height, - impl->width, impl->height); - frame_rect = [impl->toplevel frameRectForContentRect:content_rect]; - [impl->toplevel setFrame:frame_rect display:NO]; - [impl->toplevel orderOut:nil]; - inShowOrHide = NO; } diff --git a/gdk/quartz/gdkdisplay-quartz.c b/gdk/quartz/gdkdisplay-quartz.c index 9b83b13b7..9dbd93f18 100644 --- a/gdk/quartz/gdkdisplay-quartz.c +++ b/gdk/quartz/gdkdisplay-quartz.c @@ -178,3 +178,9 @@ gdk_display_supports_composite (GdkDisplay *display) /* FIXME: Implement */ return FALSE; } + +gulong +_gdk_windowing_window_get_next_serial (GdkDisplay *display) +{ + return 0; +} diff --git a/gdk/quartz/gdkdrawable-quartz.c b/gdk/quartz/gdkdrawable-quartz.c index 9ad9c66d2..72b678c0c 100644 --- a/gdk/quartz/gdkdrawable-quartz.c +++ b/gdk/quartz/gdkdrawable-quartz.c @@ -19,6 +19,7 @@ */ #include "config.h" +#include #include #include "gdkprivate-quartz.h" @@ -31,20 +32,56 @@ typedef struct { CGContextRef cg_context; } GdkQuartzCairoSurfaceData; +void +_gdk_windowing_set_cairo_surface_size (cairo_surface_t *surface, + int width, + int height) +{ + /* This is not supported with quartz surfaces. */ +} + static void gdk_quartz_cairo_surface_destroy (void *data) { GdkQuartzCairoSurfaceData *surface_data = data; GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (surface_data->drawable); - gdk_quartz_drawable_release_context (surface_data->drawable, - surface_data->cg_context); - impl->cairo_surface = NULL; + gdk_quartz_drawable_release_context (surface_data->drawable, + surface_data->cg_context); + g_free (surface_data); } +cairo_surface_t * +_gdk_windowing_create_cairo_surface (GdkDrawable *drawable, + int width, + int height) +{ + CGContextRef cg_context; + GdkQuartzCairoSurfaceData *surface_data; + cairo_surface_t *surface; + + cg_context = gdk_quartz_drawable_get_context (drawable, TRUE); + + if (!cg_context) + return NULL; + + surface_data = g_new (GdkQuartzCairoSurfaceData, 1); + surface_data->drawable = drawable; + surface_data->cg_context = cg_context; + + surface = cairo_quartz_surface_create_for_cg_context (cg_context, + width, height); + + cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key, + surface_data, + gdk_quartz_cairo_surface_destroy); + + return surface; +} + static cairo_surface_t * gdk_quartz_ref_cairo_surface (GdkDrawable *drawable) { @@ -56,24 +93,11 @@ gdk_quartz_ref_cairo_surface (GdkDrawable *drawable) if (!impl->cairo_surface) { - CGContextRef cg_context; int width, height; - GdkQuartzCairoSurfaceData *surface_data; - - cg_context = gdk_quartz_drawable_get_context (drawable, TRUE); - if (!cg_context) - return NULL; gdk_drawable_get_size (drawable, &width, &height); - - impl->cairo_surface = cairo_quartz_surface_create_for_cg_context (cg_context, width, height); - - surface_data = g_new (GdkQuartzCairoSurfaceData, 1); - surface_data->drawable = drawable; - surface_data->cg_context = cg_context; - - cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key, - surface_data, gdk_quartz_cairo_surface_destroy); + impl->cairo_surface = _gdk_windowing_create_cairo_surface (drawable, + width, height); } else cairo_surface_reference (impl->cairo_surface); @@ -183,8 +207,6 @@ gdk_quartz_draw_arc (GdkDrawable *drawable, GDK_QUARTZ_CONTEXT_FILL : GDK_QUARTZ_CONTEXT_STROKE); - CGContextSaveGState (context); - start_angle = angle1 * 2.0 * G_PI / 360.0 / 64.0; end_angle = start_angle + angle2 * 2.0 * G_PI / 360.0 / 64.0; @@ -233,8 +255,6 @@ gdk_quartz_draw_arc (GdkDrawable *drawable, CGContextStrokePath (context); } - CGContextRestoreGState (context); - gdk_quartz_drawable_release_context (drawable, context); } @@ -317,49 +337,69 @@ gdk_quartz_draw_drawable (GdkDrawable *drawable, int dest_depth = gdk_drawable_get_depth (drawable); GdkDrawableImplQuartz *src_impl; - if (GDK_IS_DRAWABLE_IMPL_QUARTZ (src)) + if (GDK_IS_WINDOW_IMPL_QUARTZ (src)) + { + GdkWindowImplQuartz *window_impl; + + window_impl = GDK_WINDOW_IMPL_QUARTZ (src); + + /* We do support moving areas on the same drawable, if it can be done + * by using a scroll. FIXME: We need to check that the params support + * this hack, and make sure it's done properly with any offsets etc? + */ + if (drawable == (GdkDrawable *)window_impl) + { + [window_impl->view scrollRect:NSMakeRect (xsrc, ysrc, width, height) + by:NSMakeSize (xdest - xsrc, ydest - ysrc)]; + + + } + else + g_warning ("Drawing with window source != dest is not supported"); + + return; + } + else if (GDK_IS_DRAWABLE_IMPL_QUARTZ (src)) src_impl = GDK_DRAWABLE_IMPL_QUARTZ (src); else if (GDK_IS_PIXMAP (src)) src_impl = GDK_DRAWABLE_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (src)->impl); - else if (GDK_IS_WINDOW (src)) + else { - src_impl = GDK_DRAWABLE_IMPL_QUARTZ (GDK_WINDOW_OBJECT (src)->impl); - /* FIXME: Implement drawing a window. */ + g_warning ("Unsupported source %s", G_OBJECT_TYPE_NAME (src)); return; } - else - g_assert_not_reached (); - + + /* Handle drawable and pixmap sources. */ if (src_depth == 1) { /* FIXME: src depth 1 is not supported yet */ + g_warning ("Source with depth 1 unsupported"); } else if (dest_depth != 0 && src_depth == dest_depth) { + GdkPixmapImplQuartz *pixmap_impl = GDK_PIXMAP_IMPL_QUARTZ (src_impl); CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE); if (!context) - return; + return; _gdk_quartz_gc_update_cg_context (gc, drawable, context, - GDK_QUARTZ_CONTEXT_STROKE); + GDK_QUARTZ_CONTEXT_STROKE); CGContextClipToRect (context, CGRectMake (xdest, ydest, width, height)); CGContextTranslateCTM (context, xdest - xsrc, ydest - ysrc + - GDK_PIXMAP_IMPL_QUARTZ (src_impl)->height); + pixmap_impl->height); CGContextScaleCTM (context, 1.0, -1.0); - CGContextDrawImage (context, - CGRectMake(0, 0, - GDK_PIXMAP_IMPL_QUARTZ (src_impl)->width, - GDK_PIXMAP_IMPL_QUARTZ (src_impl)->height), - GDK_PIXMAP_IMPL_QUARTZ (src_impl)->image); + CGContextDrawImage (context, + CGRectMake (0, 0, pixmap_impl->width, pixmap_impl->height), + pixmap_impl->image); gdk_quartz_drawable_release_context (drawable, context); } else g_warning ("Attempt to draw a drawable with depth %d to a drawable with depth %d", - src_depth, dest_depth); + src_depth, dest_depth); } static void @@ -681,6 +721,51 @@ gdk_quartz_drawable_get_context (GdkDrawable *drawable, return GDK_DRAWABLE_IMPL_QUARTZ_GET_CLASS (drawable)->get_context (drawable, antialias); } +/* Help preventing "beam sync penalty" where CG makes all graphics code + * block until the next vsync if we try to flush (including call display on + * a view) too often. We do this by limiting the manual flushing done + * outside of expose calls to less than some frequency when measured over + * the last 4 flushes. This is a bit arbitray, but seems to make it possible + * for some quick manual flushes (such as gtkruler or gimp's marching ants) + * without hitting the max flush frequency. + * + * If drawable NULL, no flushing is done, only registering that a flush was + * done externally. + */ +void +_gdk_quartz_drawable_flush (GdkDrawable *drawable) +{ + static struct timeval prev_tv; + static gint intervals[4]; + static gint index; + struct timeval tv; + gint ms; + + gettimeofday (&tv, NULL); + ms = (tv.tv_sec - prev_tv.tv_sec) * 1000 + (tv.tv_usec - prev_tv.tv_usec) / 1000; + intervals[index++ % 4] = ms; + + if (drawable) + { + ms = intervals[0] + intervals[1] + intervals[2] + intervals[3]; + + /* ~25Hz on average. */ + if (ms > 4*40) + { + if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable)) + { + GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable); + + [window_impl->toplevel flushWindow]; + } + + prev_tv = tv; + } + } + else + prev_tv = tv; +} + void gdk_quartz_drawable_release_context (GdkDrawable *drawable, CGContextRef cg_context) @@ -694,7 +779,10 @@ gdk_quartz_drawable_release_context (GdkDrawable *drawable, /* See comment in gdk_quartz_drawable_get_context(). */ if (window_impl->in_paint_rect_count == 0) - [window_impl->view unlockFocus]; + { + _gdk_quartz_drawable_flush (drawable); + [window_impl->view unlockFocus]; + } } else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable)) CGContextRelease (cg_context); diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c index bc301955d..db73a11c3 100644 --- a/gdk/quartz/gdkevents-quartz.c +++ b/gdk/quartz/gdkevents-quartz.c @@ -33,78 +33,15 @@ #include "gdkkeysyms.h" #include "gdkprivate-quartz.h" -/* This is the window the mouse is currently over */ -static GdkWindow *current_mouse_window; - /* This is the window corresponding to the key window */ static GdkWindow *current_keyboard_window; -/* This is the pointer grab window */ -GdkWindow *_gdk_quartz_pointer_grab_window; -static gboolean pointer_grab_owner_events; -static GdkEventMask pointer_grab_event_mask; -static gboolean pointer_grab_implicit; - -/* This is the keyboard grab window */ -GdkWindow * _gdk_quartz_keyboard_grab_window; -static gboolean keyboard_grab_owner_events; - /* This is the event mask and button state from the last event */ static GdkEventMask current_event_mask; static int current_button_state; -static void get_child_coordinates_from_ancestor (GdkWindow *ancestor_window, - gint ancestor_x, - gint ancestor_y, - GdkWindow *child_window, - gint *child_x, - gint *child_y); -static void get_ancestor_coordinates_from_child (GdkWindow *child_window, - gint child_x, - gint child_y, - GdkWindow *ancestor_window, - gint *ancestor_x, - gint *ancestor_y); -static void get_converted_window_coordinates (GdkWindow *in_window, - gint in_x, - gint in_y, - GdkWindow *out_window, - gint *out_x, - gint *out_y); static void append_event (GdkEvent *event); -static const gchar * -which_window_is_this (GdkWindow *window) -{ - static gchar buf[256]; - const gchar *name = NULL; - gpointer widget; - - /* Get rid of compiler warning. */ - if (0) which_window_is_this (window); - - if (window == _gdk_root) - name = "root"; - else if (window == NULL) - name = "null"; - - if (window) - { - gdk_window_get_user_data (window, &widget); - if (widget) - name = G_OBJECT_TYPE_NAME (widget); - } - - if (!name) - name = "unknown"; - - snprintf (buf, 256, "<%s (%p)%s>", - name, window, - window == current_mouse_window ? ", is mouse" : ""); - - return buf; -} - NSEvent * gdk_quartz_event_get_nsevent (GdkEvent *event) { @@ -112,12 +49,11 @@ gdk_quartz_event_get_nsevent (GdkEvent *event) return ((GdkEventPrivate *) event)->windowing_data; } -void +void _gdk_events_init (void) { _gdk_quartz_event_loop_init (); - current_mouse_window = g_object_ref (_gdk_root); current_keyboard_window = g_object_ref (_gdk_root); } @@ -135,45 +71,26 @@ gdk_event_get_graphics_expose (GdkWindow *window) return NULL; } -static void -generate_grab_broken_event (GdkWindow *window, - gboolean keyboard, - gboolean implicit, - GdkWindow *grab_window) -{ - if (!GDK_WINDOW_DESTROYED (window)) - { - GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN); - - event->grab_broken.window = window; - event->grab_broken.send_event = 0; - event->grab_broken.keyboard = keyboard; - event->grab_broken.implicit = implicit; - event->grab_broken.grab_window = grab_window; - - append_event (event); - } -} - GdkGrabStatus gdk_keyboard_grab (GdkWindow *window, gint owner_events, guint32 time) { + GdkDisplay *display; + GdkWindow *toplevel; + g_return_val_if_fail (window != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (window), 0); - if (_gdk_quartz_keyboard_grab_window) - { - if (_gdk_quartz_keyboard_grab_window != window) - generate_grab_broken_event (_gdk_quartz_keyboard_grab_window, - TRUE, FALSE, window); - - g_object_unref (_gdk_quartz_keyboard_grab_window); - } + display = gdk_drawable_get_display (window); + toplevel = gdk_window_get_toplevel (window); - _gdk_quartz_keyboard_grab_window = g_object_ref (window); - keyboard_grab_owner_events = owner_events; + _gdk_display_set_has_keyboard_grab (display, + window, + toplevel, + owner_events, + 0, + time); return GDK_GRAB_SUCCESS; } @@ -182,95 +99,20 @@ void gdk_display_keyboard_ungrab (GdkDisplay *display, guint32 time) { - if (_gdk_quartz_keyboard_grab_window) - g_object_unref (_gdk_quartz_keyboard_grab_window); - _gdk_quartz_keyboard_grab_window = NULL; -} - -gboolean -gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display, - GdkWindow **grab_window, - gboolean *owner_events) -{ - if (_gdk_quartz_keyboard_grab_window) - { - if (grab_window) - *grab_window = _gdk_quartz_keyboard_grab_window; - if (owner_events) - *owner_events = keyboard_grab_owner_events; - - return TRUE; - } - - return FALSE; -} - -static void -pointer_ungrab_internal (gboolean only_if_implicit) -{ - if (!_gdk_quartz_pointer_grab_window) - return; - - if (only_if_implicit && !pointer_grab_implicit) - return; - - g_object_unref (_gdk_quartz_pointer_grab_window); - _gdk_quartz_pointer_grab_window = NULL; - - pointer_grab_owner_events = FALSE; - pointer_grab_event_mask = 0; - pointer_grab_implicit = FALSE; - - /* FIXME: Send crossing events */ -} - -gboolean -gdk_display_pointer_is_grabbed (GdkDisplay *display) -{ - return (_gdk_quartz_pointer_grab_window != NULL && - !pointer_grab_implicit); -} - -gboolean -gdk_pointer_grab_info_libgtk_only (GdkDisplay *display, - GdkWindow **grab_window, - gboolean *owner_events) -{ - if (!_gdk_quartz_pointer_grab_window) - return FALSE; - - if (grab_window) - *grab_window = _gdk_quartz_pointer_grab_window; - - if (owner_events) - *owner_events = pointer_grab_owner_events; - - return TRUE; + _gdk_display_unset_has_keyboard_grab (display, FALSE); } void gdk_display_pointer_ungrab (GdkDisplay *display, guint32 time) { - pointer_ungrab_internal (FALSE); -} + GdkPointerGrabInfo *grab; -static GdkGrabStatus -pointer_grab_internal (GdkWindow *window, - gboolean owner_events, - GdkEventMask event_mask, - GdkWindow *confine_to, - GdkCursor *cursor, - gboolean implicit) -{ - /* FIXME: Send crossing events */ - - _gdk_quartz_pointer_grab_window = g_object_ref (window); - pointer_grab_owner_events = owner_events; - pointer_grab_event_mask = event_mask; - pointer_grab_implicit = implicit; + grab = _gdk_display_get_last_pointer_grab (display); + if (grab) + grab->serial_end = 0; - return GDK_GRAB_SUCCESS; + _gdk_display_pointer_grab_update (display, 0); } GdkGrabStatus @@ -281,45 +123,49 @@ gdk_pointer_grab (GdkWindow *window, GdkCursor *cursor, guint32 time) { + GdkWindow *native; + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0); - if (_gdk_quartz_pointer_grab_window) - { - if (_gdk_quartz_pointer_grab_window != window) - generate_grab_broken_event (_gdk_quartz_pointer_grab_window, - FALSE, pointer_grab_implicit, window); + native = gdk_window_get_toplevel (window); - pointer_ungrab_internal (FALSE); - } + /* TODO: What do we do for offscreens and their children? We need to proxy the grab somehow */ + if (!GDK_IS_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (native)->impl)) + return GDK_GRAB_SUCCESS; - return pointer_grab_internal (window, owner_events, event_mask, - confine_to, cursor, FALSE); + if (!_gdk_window_has_impl (window) && + !gdk_window_is_viewable (window)) + return GDK_GRAB_NOT_VIEWABLE; + + _gdk_display_add_pointer_grab (_gdk_display, + window, + native, + owner_events, + event_mask, + 0, + time, + FALSE); + + return GDK_GRAB_SUCCESS; } -/* This is used to break any grabs in the case where we have to due to - * the grab emulation. Instead of enforcing the desktop wide grab, we - * break it when the app loses focus for example. - */ static void -break_all_grabs (void) +break_all_grabs (guint32 time) { - if (_gdk_quartz_keyboard_grab_window) - { - generate_grab_broken_event (_gdk_quartz_keyboard_grab_window, - TRUE, FALSE, - NULL); - g_object_unref (_gdk_quartz_keyboard_grab_window); - _gdk_quartz_keyboard_grab_window = NULL; - } + GdkPointerGrabInfo *grab; + + if (_gdk_display->keyboard_grab.window) + _gdk_display_unset_has_keyboard_grab (_gdk_display, FALSE); - if (_gdk_quartz_pointer_grab_window) + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab) { - generate_grab_broken_event (_gdk_quartz_pointer_grab_window, - FALSE, pointer_grab_implicit, - NULL); - pointer_ungrab_internal (FALSE); + grab->serial_end = 0; + grab->implicit_ungrab = TRUE; } + + _gdk_display_pointer_grab_update (_gdk_display, 0); } static void @@ -341,81 +187,27 @@ append_event (GdkEvent *event) _gdk_event_queue_append (_gdk_display, event); } -static GdkFilterReturn -apply_filters (GdkWindow *window, - NSEvent *nsevent, - GList *filters) +static gint +gdk_event_apply_filters (NSEvent *nsevent, + GdkEvent *event, + GList *filters) { - GdkFilterReturn result = GDK_FILTER_CONTINUE; - GdkEvent *event; - GList *node; GList *tmp_list; - - event = gdk_event_new (GDK_NOTHING); - if (window != NULL) - event->any.window = g_object_ref (window); - ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING; - - /* I think GdkFilterFunc semantics require the passed-in event - * to already be in the queue. The filter func can generate - * more events and append them after it if it likes. - */ - node = _gdk_event_queue_append (_gdk_display, event); + GdkFilterReturn result; tmp_list = filters; + while (tmp_list) { - GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data; + GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data; tmp_list = tmp_list->next; result = filter->function (nsevent, event, filter->data); - if (result != GDK_FILTER_CONTINUE) - break; - } - - if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE) - { - _gdk_event_queue_remove_link (_gdk_display, node); - g_list_free_1 (node); - gdk_event_free (event); - } - else /* GDK_FILTER_TRANSLATE */ - { - ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING; - fixup_event (event); - } - return result; -} - -/* Checks if the passed in window is interested in the event mask, and - * if so, it's returned. If not, the event can be propagated through - * its ancestors until one with the right event mask is found, up to - * the nearest toplevel. - */ -static GdkWindow * -find_window_interested_in_event_mask (GdkWindow *window, - GdkEventMask event_mask, - gboolean propagate) -{ - GdkWindowObject *private; - - private = GDK_WINDOW_OBJECT (window); - while (private) - { - if (private->event_mask & event_mask) - return (GdkWindow *)private; - - if (!propagate) - return NULL; - - /* Don't traverse beyond toplevels. */ - if (GDK_WINDOW_TYPE (private) != GDK_WINDOW_CHILD) - break; - - private = private->parent; + if (result != GDK_FILTER_CONTINUE) + return result; } - return NULL; + return GDK_FILTER_CONTINUE; } static guint32 @@ -540,6 +332,14 @@ get_event_mask_from_ns_event (NSEvent *nsevent) g_assert_not_reached (); } } + break; + + case NSMouseEntered: + return GDK_ENTER_NOTIFY_MASK; + + case NSMouseExited: + return GDK_LEAVE_NOTIFY_MASK; + default: g_assert_not_reached (); } @@ -585,708 +385,64 @@ _gdk_quartz_events_update_focus_window (GdkWindow *window, if (got_focus) { if (current_keyboard_window) - { - event = create_focus_event (current_keyboard_window, FALSE); - append_event (event); - g_object_unref (current_keyboard_window); - current_keyboard_window = NULL; - } - - event = create_focus_event (window, TRUE); - append_event (event); - current_keyboard_window = g_object_ref (window); - } -} - -static void -convert_window_coordinates_to_root (GdkWindow *window, - gdouble x, - gdouble y, - gdouble *x_root, - gdouble *y_root) -{ - gint ox, oy; - - *x_root = x; - *y_root = y; - - if (gdk_window_get_origin (window, &ox, &oy)) - { - *x_root += ox; - *y_root += oy; - } -} - -/* FIXME: Refactor and share with scroll event. */ -static GdkEvent * -create_crossing_event (GdkWindow *window, - NSEvent *nsevent, - GdkEventType event_type, - GdkCrossingMode mode, - GdkNotifyType detail) -{ - GdkEvent *event; - gint x_tmp, y_tmp; - - event = gdk_event_new (event_type); - - event->crossing.window = window; - event->crossing.subwindow = NULL; /* FIXME */ - event->crossing.time = get_time_from_ns_event (nsevent); - - /* Split out this block: */ - { - NSWindow *nswindow; - GdkWindow *toplevel; - GdkWindowImplQuartz *impl; - NSPoint point; - - nswindow = [nsevent window]; - point = [nsevent locationInWindow]; - - toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow]; - - impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl); - - x_tmp = point.x; - y_tmp = impl->height - point.y; - - get_converted_window_coordinates (toplevel, - x_tmp, y_tmp, - window, - &x_tmp, &y_tmp); - } - - event->crossing.x = x_tmp; - event->crossing.y = y_tmp; - - convert_window_coordinates_to_root (window, - event->crossing.x, - event->crossing.y, - &event->crossing.x_root, - &event->crossing.y_root); - - event->crossing.mode = mode; - event->crossing.detail = detail; - event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent); - - /* FIXME: focus and button state */ - - return event; -} - -static void -synthesize_enter_event (GdkWindow *window, - NSEvent *nsevent, - GdkCrossingMode mode, - GdkNotifyType detail) -{ - GdkEvent *event; - - if (_gdk_quartz_pointer_grab_window != NULL && - !pointer_grab_owner_events && - !(pointer_grab_event_mask & GDK_ENTER_NOTIFY_MASK)) - return; - - if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_ENTER_NOTIFY_MASK)) - return; - - event = create_crossing_event (window, nsevent, GDK_ENTER_NOTIFY, - mode, detail); - - append_event (event); -} - -static void -synthesize_enter_events (GdkWindow *from, - GdkWindow *to, - NSEvent *nsevent, - GdkCrossingMode mode, - GdkNotifyType detail) -{ - GdkWindow *prev = gdk_window_get_parent (to); - - if (prev != from) - synthesize_enter_events (from, prev, nsevent, mode, detail); - synthesize_enter_event (to, nsevent, mode, detail); -} - -static void -synthesize_leave_event (GdkWindow *window, - NSEvent *nsevent, - GdkCrossingMode mode, - GdkNotifyType detail) -{ - GdkEvent *event; - - if (_gdk_quartz_pointer_grab_window != NULL && - !pointer_grab_owner_events && - !(pointer_grab_event_mask & GDK_LEAVE_NOTIFY_MASK)) - return; - - if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_LEAVE_NOTIFY_MASK)) - return; - - event = create_crossing_event (window, nsevent, GDK_LEAVE_NOTIFY, - mode, detail); - - append_event (event); -} - -static void -synthesize_leave_events (GdkWindow *from, - GdkWindow *to, - NSEvent *nsevent, - GdkCrossingMode mode, - GdkNotifyType detail) -{ - GdkWindow *next = gdk_window_get_parent (from); - - synthesize_leave_event (from, nsevent, mode, detail); - if (next != to) - synthesize_leave_events (next, to, nsevent, mode, detail); -} - -static void -synthesize_crossing_events (GdkWindow *window, - GdkCrossingMode mode, - NSEvent *nsevent, - gint x, - gint y) -{ - GdkWindow *intermediate, *tem, *common_ancestor; - - if (window == current_mouse_window) - return; - - if (_gdk_quartz_window_is_ancestor (current_mouse_window, window)) - { - /* Pointer has moved to an inferior window. */ - synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_INFERIOR); - - /* If there are intermediate windows, generate ENTER_NOTIFY - * events for them - */ - intermediate = gdk_window_get_parent (window); - - if (intermediate != current_mouse_window) - { - synthesize_enter_events (current_mouse_window, intermediate, nsevent, mode, GDK_NOTIFY_VIRTUAL); - } - - synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_ANCESTOR); - } - else if (_gdk_quartz_window_is_ancestor (window, current_mouse_window)) - { - /* Pointer has moved to an ancestor window. */ - synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_ANCESTOR); - - /* If there are intermediate windows, generate LEAVE_NOTIFY - * events for them - */ - intermediate = gdk_window_get_parent (current_mouse_window); - if (intermediate != window) - { - synthesize_leave_events (intermediate, window, nsevent, mode, GDK_NOTIFY_VIRTUAL); - } - - synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_INFERIOR); - } - else if (current_mouse_window) - { - /* Find least common ancestor of current_mouse_window and window */ - tem = current_mouse_window; - do { - common_ancestor = gdk_window_get_parent (tem); - tem = common_ancestor; - } while (common_ancestor && - !_gdk_quartz_window_is_ancestor (common_ancestor, window)); - if (common_ancestor) - { - synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_NONLINEAR); - intermediate = gdk_window_get_parent (current_mouse_window); - if (intermediate != common_ancestor) - { - synthesize_leave_events (intermediate, common_ancestor, - nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL); - } - intermediate = gdk_window_get_parent (window); - if (intermediate != common_ancestor) - { - synthesize_enter_events (common_ancestor, intermediate, - nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL); - } - synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_NONLINEAR); - } - } - else - { - /* This means we have no current_mouse_window, which probably - * means that there is a bug somewhere, we should always have - * the root in we don't have another window. Does this ever - * happen? - */ - g_warning ("Trying to create crossing event when current_mouse_window is NULL"); - } - - _gdk_quartz_events_update_mouse_window (window); - - /* FIXME: This does't work when someone calls gdk_window_set_cursor - * during a grab. The right behavior is that the cursor doesn't - * change when a grab is in effect, but in that case it does. - */ - if (window && !_gdk_quartz_pointer_grab_window) - _gdk_quartz_events_update_cursor (window); -} - -void -_gdk_quartz_events_send_map_events (GdkWindow *window) -{ - GList *list; - GdkWindow *interested_window; - GdkWindowObject *private = (GdkWindowObject *)window; - - interested_window = find_window_interested_in_event_mask (window, - GDK_STRUCTURE_MASK, - TRUE); - - if (interested_window) - { - GdkEvent *event = gdk_event_new (GDK_MAP); - event->any.window = interested_window; - append_event (event); - } - - for (list = private->children; list != NULL; list = list->next) - _gdk_quartz_events_send_map_events ((GdkWindow *)list->data); -} - -/* Get current mouse window */ -GdkWindow * -_gdk_quartz_events_get_mouse_window (gboolean consider_grabs) -{ - if (!consider_grabs) - return current_mouse_window; - - if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events) - return _gdk_quartz_pointer_grab_window; - - return current_mouse_window; -} - -/* Update mouse window */ -void -_gdk_quartz_events_update_mouse_window (GdkWindow *window) -{ - if (window == current_mouse_window) - return; - -#ifdef G_ENABLE_DEBUG - if (_gdk_debug_flags & GDK_DEBUG_EVENTS) - _gdk_quartz_window_debug_highlight (window, 0); -#endif /* G_ENABLE_DEBUG */ - - if (window) - g_object_ref (window); - if (current_mouse_window) - g_object_unref (current_mouse_window); - - current_mouse_window = window; -} - -/* Update current cursor */ -void -_gdk_quartz_events_update_cursor (GdkWindow *window) -{ - GdkWindowObject *private = GDK_WINDOW_OBJECT (window); - NSCursor *nscursor = nil; - - while (private) - { - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - - nscursor = impl->nscursor; - if (nscursor) - break; - - private = private->parent; - } - - GDK_QUARTZ_ALLOC_POOL; - - if (!nscursor) - nscursor = [NSCursor arrowCursor]; - - if ([NSCursor currentCursor] != nscursor) - [nscursor set]; - - GDK_QUARTZ_RELEASE_POOL; -} - -/* Translates coordinates from an ancestor window + coords, to - * coordinates that are relative the child window. - */ -static void -get_child_coordinates_from_ancestor (GdkWindow *ancestor_window, - gint ancestor_x, - gint ancestor_y, - GdkWindow *child_window, - gint *child_x, - gint *child_y) -{ - GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window); - GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window); - - while (child_private != ancestor_private) - { - ancestor_x -= child_private->x; - ancestor_y -= child_private->y; - - child_private = child_private->parent; - } - - *child_x = ancestor_x; - *child_y = ancestor_y; -} - -/* Translates coordinates from a child window + coords, to - * coordinates that are relative the ancestor window. - */ -static void -get_ancestor_coordinates_from_child (GdkWindow *child_window, - gint child_x, - gint child_y, - GdkWindow *ancestor_window, - gint *ancestor_x, - gint *ancestor_y) -{ - GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window); - GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window); - - while (child_private != ancestor_private) - { - child_x += child_private->x; - child_y += child_private->y; - - child_private = child_private->parent; - } - - *ancestor_x = child_x; - *ancestor_y = child_y; -} - -/* Translates coordinates relative to one window (in_window) into - * coordinates relative to another window (out_window). - */ -static void -get_converted_window_coordinates (GdkWindow *in_window, - gint in_x, - gint in_y, - GdkWindow *out_window, - gint *out_x, - gint *out_y) -{ - GdkWindow *in_toplevel; - GdkWindow *out_toplevel; - int in_origin_x, in_origin_y; - int out_origin_x, out_origin_y; - - if (in_window == out_window) - { - *out_x = in_x; - *out_y = in_y; - return; - } - - /* First translate to "in" toplevel coordinates, then on to "out" - * toplevel coordinates, and finally to "out" child (the passed in - * window) coordinates. - */ - - in_toplevel = gdk_window_get_toplevel (in_window); - out_toplevel = gdk_window_get_toplevel (out_window); - - /* Translate in_x, in_y to "in" toplevel coordinates. */ - get_ancestor_coordinates_from_child (in_window, in_x, in_y, - in_toplevel, &in_x, &in_y); - - gdk_window_get_origin (in_toplevel, &in_origin_x, &in_origin_y); - gdk_window_get_origin (out_toplevel, &out_origin_x, &out_origin_y); - - /* Translate in_x, in_y to "out" toplevel coordinates. */ - in_x -= out_origin_x - in_origin_x; - in_y -= out_origin_y - in_origin_y; - - get_child_coordinates_from_ancestor (out_toplevel, - in_x, in_y, - out_window, - out_x, out_y); -} - -/* Given a mouse NSEvent (must be a mouse event for a GDK window), - * finds the subwindow over which the pointer is located. Returns - * coordinates relative to the found window. If no window is found, - * returns the root window, and root window coordinates. - */ -static GdkWindow * -find_mouse_window_for_ns_event (NSEvent *nsevent, - gint *x_ret, - gint *y_ret) -{ - GdkWindow *event_toplevel; - GdkWindowImplQuartz *impl; - GdkWindow *mouse_toplevel; - GdkWindow *mouse_window; - NSPoint point; - gint x_tmp, y_tmp; - - event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow]; - impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl); - point = [nsevent locationInWindow]; - - x_tmp = point.x; - y_tmp = impl->height - point.y; - - mouse_toplevel = gdk_window_get_toplevel (current_mouse_window); - - get_converted_window_coordinates (event_toplevel, - x_tmp, y_tmp, - mouse_toplevel, - &x_tmp, &y_tmp); - - mouse_window = _gdk_quartz_window_find_child (mouse_toplevel, x_tmp, y_tmp); - if (mouse_window && mouse_window != mouse_toplevel) - { - get_child_coordinates_from_ancestor (mouse_toplevel, - x_tmp, y_tmp, - mouse_window, - &x_tmp, &y_tmp); - } - else if (!mouse_window) - { - /* This happens for events on the window title buttons and the - * desktop, treat those as being on the root window. - */ - get_converted_window_coordinates (mouse_toplevel, - x_tmp, y_tmp, - _gdk_root, - &x_tmp, &y_tmp); - mouse_window = _gdk_root; + { + event = create_focus_event (current_keyboard_window, FALSE); + append_event (event); + g_object_unref (current_keyboard_window); + current_keyboard_window = NULL; + } + + event = create_focus_event (window, TRUE); + append_event (event); + current_keyboard_window = g_object_ref (window); } - - *x_ret = x_tmp; - *y_ret = y_tmp; - - return mouse_window; } -/* Trigger crossing events if necessary. This is used when showing a new - * window, since the tracking rect API doesn't work reliably when a window - * shows up under the mouse cursor. It's done by finding the topmost window - * under the mouse pointer and synthesizing crossing events into that - * window. - */ void -_gdk_quartz_events_trigger_crossing_events (gboolean defer_to_mainloop) +_gdk_quartz_events_send_map_event (GdkWindow *window) { - NSPoint point; - gint x, y; - gint x_toplevel, y_toplevel; - GdkWindow *mouse_window; - GdkWindow *toplevel; - GdkWindowImplQuartz *impl; - guint flags = 0; - NSTimeInterval timestamp = 0; - NSEvent *current_event; - NSEvent *nsevent; - - if (defer_to_mainloop) - { - nsevent = [NSEvent otherEventWithType:NSApplicationDefined - location:NSZeroPoint - modifierFlags:0 - timestamp:0 - windowNumber:0 - context:nil - subtype:GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING - data1:0 - data2:0]; - [NSApp postEvent:nsevent atStart:NO]; - return; - } - - point = [NSEvent mouseLocation]; - x = point.x; - y = _gdk_quartz_window_get_inverted_screen_y (point.y); - - mouse_window = _gdk_quartz_window_find_child (_gdk_root, x, y); - if (!mouse_window || mouse_window == _gdk_root) - return; - - toplevel = gdk_window_get_toplevel (mouse_window); + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - /* We ignore crossing within the same toplevel since that is already - * handled elsewhere. - */ - if (toplevel == gdk_window_get_toplevel (current_mouse_window)) + if (!impl->toplevel) return; - get_converted_window_coordinates (_gdk_root, - x, y, - toplevel, - &x_toplevel, &y_toplevel); - - get_converted_window_coordinates (_gdk_root, - x, y, - mouse_window, - &x, &y); - - /* Fix up the event to be less fake if possible. */ - current_event = [NSApp currentEvent]; - if (current_event) + if (private->event_mask & GDK_STRUCTURE_MASK) { - flags = [current_event modifierFlags]; - timestamp = [current_event timestamp]; - } + GdkEvent event; - if (timestamp == 0) - timestamp = GetCurrentEventTime (); - - impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl); - nsevent = [NSEvent otherEventWithType:NSApplicationDefined - location:NSMakePoint (x_toplevel, impl->height - y_toplevel) - modifierFlags:flags - timestamp:timestamp - windowNumber:[impl->toplevel windowNumber] - context:nil - subtype:GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING - data1:0 - data2:0]; - -#ifdef G_ENABLE_DEBUG - /*_gdk_quartz_window_debug_highlight (mouse_window, 0);*/ -#endif - - synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y); + event.any.type = GDK_MAP; + event.any.window = window; + + gdk_event_put (&event); + } } -/* Synthesizes crossing events if necessary, based on the passed in - * NSEvent. Uses NSMouseEntered and NSMouseExisted for toplevels and - * the mouse moved/dragged events for child windows, to see if the - * mouse window has changed. - */ -static void -synthesize_crossing_events_for_ns_event (NSEvent *nsevent) +static GdkWindow * +find_toplevel_under_pointer (GdkDisplay *display, + NSPoint screen_point, + gint *x, + gint *y) { - NSEventType event_type; - GdkWindow *mouse_window; - gint x; - gint y; - - event_type = [nsevent type]; + GdkWindow *toplevel; - switch (event_type) + toplevel = display->pointer_info.toplevel_under_pointer; + if (toplevel) { - case NSMouseMoved: - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - /* We only handle moving the pointer to another GDK window. - * Leaving to a non-GDK toplevel window (or window title bar or - * the desktop) is covered by NSMouseExited events. - */ - mouse_window = find_mouse_window_for_ns_event (nsevent, &x, &y); - if (mouse_window != _gdk_root) - synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y); - - break; - - case NSMouseEntered: - { - GdkWindow *event_toplevel; - GdkWindowImplQuartz *impl; - NSPoint point; + GdkWindowObject *private; + NSWindow *nswindow; + NSPoint point; - /* This is the only case where we actually use the window from - * the event since we need to know which toplevel we entered - * so it can be tracked properly. - */ - event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow]; - impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl); + private = (GdkWindowObject *)toplevel; + nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel; - point = [nsevent locationInWindow]; + point = [nswindow convertScreenToBase:screen_point]; - x = point.x; - y = impl->height - point.y; - - mouse_window = _gdk_quartz_window_find_child (event_toplevel, x, y); - - /* Treat unknown windows (like the title bar buttons or - * desktop) as the root window. - */ - if (!mouse_window) - mouse_window = _gdk_root; - - if (mouse_window != event_toplevel) - get_converted_window_coordinates (event_toplevel, - x, y, - mouse_window, - &x, &y); - - synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y); - } - break; - - case NSMouseExited: - { - GdkWindow *event_toplevel; - GdkWindowImplQuartz *impl; - NSPoint point; - - /* We only use NSMouseExited when leaving to the root - * window. The other cases are handled above by checking the - * motion/button events, or getting a NSMouseEntered for - * another GDK window. The reason we don't use NSMouseExited - * for other windows is that quartz first delivers the entered - * event and then the exited which is the opposite from what - * we need. - */ - event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow]; - impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl); - point = [nsevent locationInWindow]; - - x = point.x; - y = impl->height - point.y; - - x += GDK_WINDOW_OBJECT (event_toplevel)->x; - y += GDK_WINDOW_OBJECT (event_toplevel)->y; - - /* If there is a window other than the root window at this - * position, it means we didn't exit to the root window and we - * ignore the event. (Note that we can get NULL here when swithing - * spaces for example.) - * - * FIXME: This is not enough, it doesn't catch the case where - * we leave a GDK window to a non-GDK window that has GDK - * windows below it. - */ - mouse_window = _gdk_quartz_window_find_child (_gdk_root, x, y); - - if (!mouse_window || - gdk_window_get_toplevel (mouse_window) == - gdk_window_get_toplevel (current_mouse_window)) - { - mouse_window = _gdk_root; - } - - if (mouse_window == _gdk_root) - synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, x, y); - } - break; - - default: - break; + *x = point.x; + *y = private->height - point.y; } + + return toplevel; } /* This function finds the correct window to send an event to, taking @@ -1295,10 +451,31 @@ synthesize_crossing_events_for_ns_event (NSEvent *nsevent) static GdkWindow * find_window_for_ns_event (NSEvent *nsevent, gint *x, - gint *y) + gint *y, + gint *x_root, + gint *y_root) { + GdkQuartzView *view; + GdkWindow *toplevel; + GdkWindowObject *private; + NSPoint point; + NSPoint screen_point; NSEventType event_type; + view = (GdkQuartzView *)[[nsevent window] contentView]; + + toplevel = [view gdkWindow]; + private = GDK_WINDOW_OBJECT (toplevel); + + point = [nsevent locationInWindow]; + screen_point = [[nsevent window] convertBaseToScreen:point]; + + *x = point.x; + *y = private->height - point.y; + + *x_root = screen_point.x; + *y_root = _gdk_quartz_window_get_inverted_screen_y (screen_point.y); + event_type = [nsevent type]; switch (event_type) @@ -1315,9 +492,10 @@ find_window_for_ns_event (NSEvent *nsevent, case NSRightMouseDragged: case NSOtherMouseDragged: { - GdkWindow *mouse_window; - GdkEventMask event_mask; - GdkWindow *real_window; + GdkDisplay *display; + GdkPointerGrabInfo *grab; + + display = gdk_drawable_get_display (toplevel); /* From the docs for XGrabPointer: * @@ -1327,53 +505,53 @@ find_window_for_ns_event (NSEvent *nsevent, * the grab_window and is reported only if selected by * event_mask. For either value of owner_events, unreported * events are discarded. - * - * This means we first try the owner, then the grab window, - * then give up. */ - if (_gdk_quartz_pointer_grab_window) + grab = _gdk_display_get_last_pointer_grab (display); + if (grab) { - if (pointer_grab_owner_events) - { - mouse_window = find_mouse_window_for_ns_event (nsevent, x, y); - event_mask = get_event_mask_from_ns_event (nsevent); - real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE); - - if (mouse_window && real_window && mouse_window != real_window) - get_ancestor_coordinates_from_child (mouse_window, - *x, *y, - real_window, - x, y); - - if (real_window) - return real_window; - } - - /* Finally check the grab window. */ - if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent)) - { - GdkWindow *event_toplevel; + if ((grab->event_mask & get_event_mask_from_ns_event (nsevent)) == 0) + return NULL; + + if (grab->owner_events) + { + /* For owner events, we need to use the toplevel under the + * pointer, not the window from the NSEvent, since that is + * reported with respect to the key window, which could be + * wrong. + */ + GdkWindow *toplevel_under_pointer; + gint x_tmp, y_tmp; + + toplevel_under_pointer = find_toplevel_under_pointer (display, + screen_point, + &x_tmp, &y_tmp); + if (toplevel_under_pointer) + { + toplevel = toplevel_under_pointer; + *x = x_tmp; + *y = y_tmp; + } + + return toplevel; + } + else + { + /* Finally check the grab window. */ GdkWindow *grab_toplevel; - NSPoint point; - int x_tmp, y_tmp; + GdkWindowObject *grab_private; + NSWindow *grab_nswindow; - event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow]; - grab_toplevel = gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window); - point = [nsevent locationInWindow]; + grab_toplevel = gdk_window_get_toplevel (grab->window); + grab_private = (GdkWindowObject *)grab_toplevel; - x_tmp = point.x; - y_tmp = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (grab_toplevel)->impl)->height - point.y; + grab_nswindow = ((GdkWindowImplQuartz *)grab_private->impl)->toplevel; + point = [grab_nswindow convertScreenToBase:screen_point]; - /* Translate the coordinates so they are relative to - * the grab window instead of the event toplevel for - * the cases where they are not the same. - */ - get_converted_window_coordinates (event_toplevel, - x_tmp, y_tmp, - _gdk_quartz_pointer_grab_window, - x, y); + /* Note: x_root and y_root are already right. */ + *x = point.x; + *y = grab_private->height - point.y; - return _gdk_quartz_pointer_grab_window; + return grab_toplevel; } return NULL; @@ -1381,42 +559,55 @@ find_window_for_ns_event (NSEvent *nsevent, else { /* The non-grabbed case. */ - mouse_window = find_mouse_window_for_ns_event (nsevent, x, y); - event_mask = get_event_mask_from_ns_event (nsevent); - real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE); - - /* We have to translate the coordinates if the actual - * window is different from the mouse window. - */ - if (mouse_window && real_window && mouse_window != real_window) - get_ancestor_coordinates_from_child (mouse_window, - *x, *y, - real_window, - x, y); - - return real_window; + GdkWindow *toplevel_under_pointer; + gint x_tmp, y_tmp; + + /* Ignore all events but mouse moved that might be on the title + * bar (above the content view). The reason is that otherwise + * gdk gets confused about getting e.g. button presses with no + * window (the title bar is not known to it). + */ + if (event_type != NSMouseMoved) + if (*y < 0) + return NULL; + + /* FIXME: Also need to leave resize events to cocoa somehow? */ + + /* As for owner events, we need to use the toplevel under the + * pointer, not the window from the NSEvent. + */ + toplevel_under_pointer = find_toplevel_under_pointer (display, + screen_point, + &x_tmp, &y_tmp); + if (toplevel_under_pointer) + { + toplevel = toplevel_under_pointer; + *x = x_tmp; + *y = y_tmp; + } + + return toplevel; } } break; case NSMouseEntered: case NSMouseExited: - /* Already handled in synthesize_crossing_events_for_ns_event. */ - break; + /* Only handle our own entered/exited events, not the ones for the + * titlebar buttons. + */ + if ([view trackingRect] == [nsevent trackingNumber]) + return toplevel; + else + return NULL; case NSKeyDown: case NSKeyUp: case NSFlagsChanged: - { - GdkEventMask event_mask; + if (_gdk_display->keyboard_grab.window && !_gdk_display->keyboard_grab.owner_events) + return gdk_window_get_toplevel (_gdk_display->keyboard_grab.window); - if (_gdk_quartz_keyboard_grab_window && !keyboard_grab_owner_events) - return _gdk_quartz_keyboard_grab_window; - - event_mask = get_event_mask_from_ns_event (nsevent); - return find_window_interested_in_event_mask (current_keyboard_window, event_mask, TRUE); - } - break; + return toplevel; default: /* Ignore everything else. */ @@ -1426,13 +617,42 @@ find_window_for_ns_event (NSEvent *nsevent, return NULL; } -static GdkEvent * -create_button_event (GdkWindow *window, - NSEvent *nsevent, - gint x, - gint y) +static void +fill_crossing_event (GdkWindow *toplevel, + GdkEvent *event, + NSEvent *nsevent, + gint x, + gint y, + gint x_root, + gint y_root, + GdkEventType event_type, + GdkCrossingMode mode, + GdkNotifyType detail) +{ + event->any.type = event_type; + event->crossing.window = toplevel; + event->crossing.subwindow = NULL; + event->crossing.time = get_time_from_ns_event (nsevent); + event->crossing.x = x; + event->crossing.y = y; + event->crossing.x_root = x_root; + event->crossing.y_root = y_root; + event->crossing.mode = mode; + event->crossing.detail = detail; + event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent); + + /* FIXME: Focus and button state? */ +} + +static void +fill_button_event (GdkWindow *window, + GdkEvent *event, + NSEvent *nsevent, + gint x, + gint y, + gint x_root, + gint y_root) { - GdkEvent *event; GdkEventType type; gint state; gint button; @@ -1458,110 +678,105 @@ create_button_event (GdkWindow *window, button = get_mouse_button_from_ns_event (nsevent); - event = gdk_event_new (type); + event->any.type = type; event->button.window = window; event->button.time = get_time_from_ns_event (nsevent); event->button.x = x; event->button.y = y; + event->button.x_root = x_root; + event->button.y_root = y_root; /* FIXME event->axes */ event->button.state = state; event->button.button = button; event->button.device = _gdk_display->core_pointer; - convert_window_coordinates_to_root (window, x, y, - &event->button.x_root, - &event->button.y_root); - - return event; } -static GdkEvent * -create_motion_event (GdkWindow *window, - NSEvent *nsevent, - gint x, - gint y) +static void +fill_motion_event (GdkWindow *window, + GdkEvent *event, + NSEvent *nsevent, + gint x, + gint y, + gint x_root, + gint y_root) { - GdkEvent *event; - GdkEventType type; - GdkModifierType state = 0; + GdkModifierType state; + + state = get_keyboard_modifiers_from_ns_event (nsevent); switch ([nsevent type]) { case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: - state = get_mouse_button_modifiers_from_ns_event (nsevent); - /* Fall through */ + state |= get_mouse_button_modifiers_from_ns_event (nsevent); + break; + case NSMouseMoved: - type = GDK_MOTION_NOTIFY; break; - default: - g_assert_not_reached (); } - state |= get_keyboard_modifiers_from_ns_event (nsevent); - - event = gdk_event_new (type); + event->any.type = GDK_MOTION_NOTIFY; event->motion.window = window; event->motion.time = get_time_from_ns_event (nsevent); event->motion.x = x; event->motion.y = y; + event->motion.x_root = x_root; + event->motion.y_root = y_root; /* FIXME event->axes */ event->motion.state = state; event->motion.is_hint = FALSE; event->motion.device = _gdk_display->core_pointer; - convert_window_coordinates_to_root (window, x, y, - &event->motion.x_root, &event->motion.y_root); - - return event; } -static GdkEvent * -create_scroll_event (GdkWindow *window, - NSEvent *nsevent, - GdkScrollDirection direction) +static void +fill_scroll_event (GdkWindow *window, + GdkEvent *event, + NSEvent *nsevent, + gint x, + gint y, + gint x_root, + gint y_root, + GdkScrollDirection direction) { - GdkEvent *event; + GdkWindowObject *private; NSPoint point; - - event = gdk_event_new (GDK_SCROLL); - event->scroll.window = window; - event->scroll.time = get_time_from_ns_event (nsevent); + + private = GDK_WINDOW_OBJECT (window); point = [nsevent locationInWindow]; - event->scroll.x = point.x; - event->scroll.y = point.y; - event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent); - convert_window_coordinates_to_root (window, event->scroll.x, event->scroll.y, - &event->scroll.x_root, - &event->scroll.y_root); + event->any.type = GDK_SCROLL; + event->scroll.window = window; + event->scroll.time = get_time_from_ns_event (nsevent); + event->scroll.x = x; + event->scroll.y = y; + event->scroll.x_root = x_root; + event->scroll.y_root = y_root; + event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent); event->scroll.direction = direction; event->scroll.device = _gdk_display->core_pointer; - - return event; } -static GdkEvent * -create_key_event (GdkWindow *window, - NSEvent *nsevent, - GdkEventType type) +static void +fill_key_event (GdkWindow *window, + GdkEvent *event, + NSEvent *nsevent, + GdkEventType type) { - GdkEvent *event; GdkEventPrivate *priv; gchar buf[7]; gunichar c = 0; - event = gdk_event_new (type); - priv = (GdkEventPrivate *) event; priv->windowing_data = [nsevent retain]; + event->any.type = type; event->key.window = window; event->key.time = get_time_from_ns_event (nsevent); event->key.state = get_keyboard_modifiers_from_ns_event (nsevent); event->key.hardware_keycode = [nsevent keyCode]; event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0; - event->key.keyval = GDK_VoidSymbol; gdk_keymap_translate_keyboard_state (NULL, @@ -1620,7 +835,7 @@ create_key_event (GdkWindow *window, if (event->key.keyval != GDK_VoidSymbol) c = gdk_keyval_to_unicode (event->key.keyval); - if (c) + if (c) { gsize bytes_written; gint len; @@ -1658,7 +873,59 @@ create_key_event (GdkWindow *window, event->key.window, event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)", event->key.keyval)); - return event; +} + +static gboolean +synthesize_crossing_event (GdkWindow *window, + GdkEvent *event, + NSEvent *nsevent, + gint x, + gint y, + gint x_root, + gint y_root) +{ + GdkWindowObject *private; + + private = GDK_WINDOW_OBJECT (window); + + switch ([nsevent type]) + { + case NSMouseEntered: + /* Enter events are considered always to be from the root window as we + * can't know for sure from what window we enter. + */ + if (!(private->event_mask & GDK_ENTER_NOTIFY_MASK)) + return FALSE; + + fill_crossing_event (window, event, nsevent, + x, y, + x_root, y_root, + GDK_ENTER_NOTIFY, + GDK_CROSSING_NORMAL, + GDK_NOTIFY_ANCESTOR); + return TRUE; + + case NSMouseExited: + /* Exited always is to the root window as far as we are concerned, + * since there is no way to reliably get information about what new + * window is entered when exiting one. + */ + if (!(private->event_mask & GDK_LEAVE_NOTIFY_MASK)) + return FALSE; + + fill_crossing_event (window, event, nsevent, + x, y, + x_root, y_root, + GDK_LEAVE_NOTIFY, + GDK_CROSSING_NORMAL, + GDK_NOTIFY_ANCESTOR); + return TRUE; + + default: + break; + } + + return FALSE; } GdkEventMask @@ -1668,40 +935,38 @@ _gdk_quartz_events_get_current_event_mask (void) } static gboolean -gdk_event_translate (NSEvent *nsevent) +gdk_event_translate (GdkEvent *event, + NSEvent *nsevent) { + NSEventType event_type; NSWindow *nswindow; GdkWindow *window; - GdkFilterReturn result; - GdkEvent *event; int x, y; + int x_root, y_root; + gboolean return_val; /* There is no support for real desktop wide grabs, so we break * grabs when the application loses focus (gets deactivated). */ - if ([nsevent type] == NSAppKitDefined) + event_type = [nsevent type]; + if (event_type == NSAppKitDefined) { if ([nsevent subtype] == NSApplicationDeactivatedEventType) - break_all_grabs (); + break_all_grabs (get_time_from_ns_event (nsevent)); /* This could potentially be used to break grabs when clicking * on the title. The subtype 20 is undocumented so it's probably * not a good idea: else if (subtype == 20) break_all_grabs (); */ - } - /* Handle our generated "fake" crossing events. */ - if ([nsevent type] == NSApplicationDefined && - [nsevent subtype] == GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING) - { - _gdk_quartz_events_trigger_crossing_events (FALSE); - return TRUE; + /* Leave all AppKit events to AppKit. */ + return FALSE; } /* Keep track of button state, since we don't get that information * for key events. */ - switch ([nsevent type]) + switch (event_type) { case NSLeftMouseDown: case NSRightMouseDown: @@ -1717,21 +982,21 @@ gdk_event_translate (NSEvent *nsevent) break; } - nswindow = [nsevent window]; - - /* Apply any global filters. */ if (_gdk_default_filters) { - result = apply_filters (NULL, nsevent, _gdk_default_filters); + /* Apply global filters */ + GdkFilterReturn result; - /* If result is GDK_FILTER_CONTINUE, we continue as if nothing - * happened. If it is GDK_FILTER_REMOVE, - * we return TRUE and won't send the message to Quartz. - */ - if (result == GDK_FILTER_REMOVE) - return TRUE; + result = gdk_event_apply_filters (nsevent, event, _gdk_default_filters); + if (result != GDK_FILTER_CONTINUE) + { + return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; + goto done; + } } + nswindow = [nsevent window]; + /* Ignore events for no window or ones not created by GDK. */ if (!nswindow || ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]]) return FALSE; @@ -1742,84 +1007,86 @@ gdk_event_translate (NSEvent *nsevent) */ if ([(GdkQuartzWindow *)nswindow isInMove]) { - break_all_grabs (); + break_all_grabs (get_time_from_ns_event (nsevent)); return FALSE; } - /* Take care of NSMouseEntered/Exited events and mouse movements - * events and emit the right GDK crossing events. - */ - synthesize_crossing_events_for_ns_event (nsevent); - /* Find the right GDK window to send the event to, taking grabs and * event masks into consideration. */ - window = find_window_for_ns_event (nsevent, &x, &y); + window = find_window_for_ns_event (nsevent, &x, &y, &x_root, &y_root); if (!window) return FALSE; /* Apply any window filters. */ - result = apply_filters (window, nsevent, ((GdkWindowObject *) window)->filters); - if (result == GDK_FILTER_REMOVE) - return TRUE; - - /* We need the appliction to be activated on clicks so that popups - * like context menus get events routed properly. This is handled - * automatically for left mouse button presses but not other - * buttons, so we do it here. + if (GDK_IS_WINDOW (window)) + { + GdkWindowObject *filter_private = (GdkWindowObject *) window; + GdkFilterReturn result; + + if (filter_private->filters) + { + g_object_ref (window); + + result = gdk_event_apply_filters (nsevent, event, filter_private->filters); + + g_object_unref (window); + + if (result != GDK_FILTER_CONTINUE) + { + return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; + goto done; + } + } + } + + /* If the app is not active leave the event to AppKit so the window gets + * focused correctly and don't do click-through (so we behave like most + * native apps). If the app is active, we focus the window and then handle + * the event, also to match native apps. */ - if ([nsevent type] == NSRightMouseDown || [nsevent type] == NSOtherMouseDown) + if ((event_type == NSRightMouseDown || + event_type == NSOtherMouseDown || + event_type == NSLeftMouseDown)) { + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); + if (![NSApp isActive]) - [NSApp activateIgnoringOtherApps:YES]; + { + [NSApp activateIgnoringOtherApps:YES]; + return FALSE; + } + else if (![impl->toplevel isKeyWindow]) + { + GdkPointerGrabInfo *grab; + + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (!grab) + [impl->toplevel makeKeyWindow]; + } } current_event_mask = get_event_mask_from_ns_event (nsevent); - switch ([nsevent type]) + return_val = TRUE; + + switch (event_type) { case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown: - { - GdkEventMask event_mask; - - /* Emulate implicit grab, when the window has both PRESS and RELEASE - * in its mask, like X. - */ - event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); - if (!_gdk_quartz_pointer_grab_window && - (GDK_WINDOW_OBJECT (window)->event_mask & event_mask) == event_mask) - { - pointer_grab_internal (window, FALSE, - GDK_WINDOW_OBJECT (window)->event_mask, - NULL, NULL, TRUE); - } - } - - event = create_button_event (window, nsevent, x, y); - append_event (event); - - _gdk_event_button_generate (_gdk_display, event); - break; - case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp: - event = create_button_event (window, nsevent, x, y); - append_event (event); - - /* Ungrab implicit grab */ - if (_gdk_quartz_pointer_grab_window && pointer_grab_implicit) - pointer_ungrab_internal (TRUE); + fill_button_event (window, event, nsevent, x, y, x_root, y_root); break; case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: case NSMouseMoved: - event = create_motion_event (window, nsevent, x, y); - append_event (event); + fill_motion_event (window, event, nsevent, x, y, x_root, y_root); break; case NSScrollWheel: @@ -1828,51 +1095,33 @@ gdk_event_translate (NSEvent *nsevent) float dy = [nsevent deltaY]; GdkScrollDirection direction; - /* The delta is how much the mouse wheel has moved. Since there's no such thing in GTK+ - * we accomodate by sending a different number of scroll wheel events. - */ - - /* First do y events */ - if (dy < 0.0) - { - dy = -dy; - direction = GDK_SCROLL_DOWN; - } - else - direction = GDK_SCROLL_UP; - - while (dy > 0.0) - { - event = create_scroll_event (window, nsevent, direction); - append_event (event); - dy--; - - /* Ignore the delta for now, things get too slow when the events queue up. */ - break; - } + if (dy != 0) + { + if (dy < 0.0) + direction = GDK_SCROLL_DOWN; + else + direction = GDK_SCROLL_UP; - /* Now do x events */ - if (dx < 0.0) - { - dx = -dx; - direction = GDK_SCROLL_RIGHT; - } - else - direction = GDK_SCROLL_LEFT; + fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction); + } - while (dx > 0.0) - { - event = create_scroll_event (window, nsevent, direction); - append_event (event); - dx--; - - /* Ignore the delta for now, things get too slow when the events queue up. */ - break; - } + if (dx != 0) + { + if (dx < 0.0) + direction = GDK_SCROLL_RIGHT; + else + direction = GDK_SCROLL_LEFT; + fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction); + } } break; + case NSMouseEntered: + case NSMouseExited: + return_val = synthesize_crossing_event (window, event, nsevent, x, y, x_root, y_root); + break; + case NSKeyDown: case NSKeyUp: case NSFlagsChanged: @@ -1881,38 +1130,75 @@ gdk_event_translate (NSEvent *nsevent) type = _gdk_quartz_keys_event_type (nsevent); if (type == GDK_NOTHING) - return FALSE; - - event = create_key_event (window, nsevent, type); - append_event (event); - return TRUE; + return_val = FALSE; + else + fill_key_event (window, event, nsevent, type); } break; default: /* Ignore everything elsee. */ + return_val = FALSE; break; } - return FALSE; + done: + if (return_val) + { + if (event->any.window) + g_object_ref (event->any.window); + if (((event->any.type == GDK_ENTER_NOTIFY) || + (event->any.type == GDK_LEAVE_NOTIFY)) && + (event->crossing.subwindow != NULL)) + g_object_ref (event->crossing.subwindow); + } + else + { + /* Mark this event as having no resources to be freed */ + event->any.window = NULL; + event->any.type = GDK_NOTHING; + } + + return return_val; } void _gdk_events_queue (GdkDisplay *display) { - NSEvent *event; + NSEvent *nsevent; - event = _gdk_quartz_event_loop_get_pending (); - if (event) + nsevent = _gdk_quartz_event_loop_get_pending (); + if (nsevent) { - if (!gdk_event_translate (event)) + GdkEvent *event; + GList *node; + + event = gdk_event_new (GDK_NOTHING); + + event->any.window = NULL; + event->any.send_event = FALSE; + + ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING; + + node = _gdk_event_queue_append (display, event); + + if (gdk_event_translate (event, nsevent)) + { + ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING; + _gdk_windowing_got_event (display, node, event, 0); + } + else { + _gdk_event_queue_remove_link (display, node); + g_list_free_1 (node); + gdk_event_free (event); + GDK_THREADS_LEAVE (); - [NSApp sendEvent:event]; + [NSApp sendEvent:nsevent]; GDK_THREADS_ENTER (); } - _gdk_quartz_event_loop_release_event (event); + _gdk_quartz_event_loop_release_event (nsevent); } } @@ -1922,7 +1208,7 @@ gdk_flush (void) /* Not supported. */ } -void +void gdk_display_add_client_message_filter (GdkDisplay *display, GdkAtom message_type, GdkFilterFunc func, @@ -1931,7 +1217,7 @@ gdk_display_add_client_message_filter (GdkDisplay *display, /* Not supported. */ } -void +void gdk_add_client_message_filter (GdkAtom message_type, GdkFilterFunc func, gpointer data) diff --git a/gdk/quartz/gdkgc-quartz.c b/gdk/quartz/gdkgc-quartz.c index ea7737910..c4da89328 100644 --- a/gdk/quartz/gdkgc-quartz.c +++ b/gdk/quartz/gdkgc-quartz.c @@ -208,7 +208,8 @@ _gdk_quartz_gc_new (GdkDrawable *drawable, void _gdk_windowing_gc_set_clip_region (GdkGC *gc, - const GdkRegion *region) + const GdkRegion *region, + gboolean reset_origin) { GdkGCQuartz *private = GDK_GC_QUARTZ (gc); @@ -224,8 +225,11 @@ _gdk_windowing_gc_set_clip_region (GdkGC *gc, private->have_clip_region = region != NULL; - gc->clip_x_origin = 0; - gc->clip_y_origin = 0; + if (reset_origin) + { + gc->clip_x_origin = 0; + gc->clip_y_origin = 0; + } } void @@ -281,7 +285,6 @@ gdk_quartz_draw_tiled_pattern (void *info, CGContextRef context) { GdkGC *gc = GDK_GC (info); - GdkGCQuartz *private = GDK_GC_QUARTZ (gc); CGImageRef pattern_image; size_t width, height; diff --git a/gdk/quartz/gdkgeometry-quartz.c b/gdk/quartz/gdkgeometry-quartz.c index 921128aec..eceb0717f 100644 --- a/gdk/quartz/gdkgeometry-quartz.c +++ b/gdk/quartz/gdkgeometry-quartz.c @@ -23,68 +23,16 @@ #include "gdkprivate-quartz.h" void -_gdk_quartz_window_scroll (GdkWindow *window, - gint dx, - gint dy) +_gdk_quartz_window_queue_translation (GdkWindow *window, + GdkRegion *area, + gint dx, + gint dy) { - NSRect visible_nsrect; - GdkRectangle visible_rect, scrolled_rect; - GdkRegion *visible_region, *scrolled_region; - GdkRectangle *rects; - gint n_rects, i; - GdkWindowObject *private = GDK_WINDOW_OBJECT (window); - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - GList *list; - - /* Move the current invalid region */ - if (private->update_area) - gdk_region_offset (private->update_area, dx, dy); - - visible_nsrect = [impl->view visibleRect]; - - visible_rect.x = visible_nsrect.origin.x; - visible_rect.y = visible_nsrect.origin.y; - visible_rect.width = visible_nsrect.size.width; - visible_rect.height = visible_nsrect.size.height; - - scrolled_rect = visible_rect; - scrolled_rect.x += dx; - scrolled_rect.y += dy; - - gdk_rectangle_intersect (&visible_rect, &scrolled_rect, &scrolled_rect); - - visible_region = gdk_region_rectangle (&visible_rect); - scrolled_region = gdk_region_rectangle (&scrolled_rect); - - gdk_region_subtract (visible_region, scrolled_region); - - [impl->view scrollRect:[impl->view bounds] by:NSMakeSize(dx, dy)]; - - gdk_region_get_rectangles (visible_region, &rects, &n_rects); - for (i = 0; i < n_rects; i++) - [impl->view setNeedsDisplayInRect:NSMakeRect (rects[i].x, rects[i].y, rects[i].width, rects[i].height)]; - - g_free (rects); - - gdk_region_destroy (visible_region); - gdk_region_destroy (scrolled_region); - - /* Move child windows */ - for (list = private->children; list; list = list->next) - { - GdkWindowObject *child = GDK_WINDOW_OBJECT (list->data); - - gdk_window_move (list->data, - child->x + dx, - child->y + dy); - } } -void -_gdk_quartz_window_move_region (GdkWindow *window, - const GdkRegion *region, - gint dx, - gint dy) +gboolean +_gdk_quartz_window_queue_antiexpose (GdkWindow *window, + GdkRegion *area) { - /* FIXME: Implement */ + return FALSE; } diff --git a/gdk/quartz/gdkinput.c b/gdk/quartz/gdkinput.c index 280af5e30..657d43590 100644 --- a/gdk/quartz/gdkinput.c +++ b/gdk/quartz/gdkinput.c @@ -206,7 +206,7 @@ gdk_device_get_history (GdkDevice *device, gint *n_events) { g_return_val_if_fail (window != NULL, FALSE); - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + g_return_val_if_fail (GDK_WINDOW_IS_QUARTZ (window), FALSE); g_return_val_if_fail (events != NULL, FALSE); g_return_val_if_fail (n_events != NULL, FALSE); @@ -262,7 +262,7 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask, GdkInputWindow *iw; g_return_if_fail (window != NULL); - g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_WINDOW_IS_QUARTZ (window)); window_private = (GdkWindowObject*) window; diff --git a/gdk/quartz/gdkpixmap-quartz.c b/gdk/quartz/gdkpixmap-quartz.c index e55ff9d1a..a74348089 100644 --- a/gdk/quartz/gdkpixmap-quartz.c +++ b/gdk/quartz/gdkpixmap-quartz.c @@ -137,10 +137,10 @@ data_provider_release (void *info, const void *data, size_t size) } 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; GdkDrawableImplQuartz *draw_impl; @@ -224,10 +224,10 @@ gdk_pixmap_new (GdkDrawable *drawable, } GdkPixmap * -gdk_bitmap_create_from_data (GdkDrawable *window, - const gchar *data, - gint width, - gint height) +_gdk_bitmap_create_from_data (GdkDrawable *window, + const gchar *data, + gint width, + gint height) { GdkPixmap *pixmap; GdkPixmapImplQuartz *impl; @@ -264,13 +264,13 @@ gdk_bitmap_create_from_data (GdkDrawable *window, } 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) { /* FIXME: Implement */ return NULL; diff --git a/gdk/quartz/gdkprivate-quartz.h b/gdk/quartz/gdkprivate-quartz.h index efffe6b62..9590d9b56 100644 --- a/gdk/quartz/gdkprivate-quartz.h +++ b/gdk/quartz/gdkprivate-quartz.h @@ -102,6 +102,8 @@ extern GdkWindow *_gdk_root; extern GdkDragContext *_gdk_quartz_drag_source_context; +#define GDK_WINDOW_IS_QUARTZ(win) (GDK_IS_WINDOW_IMPL_QUARTZ (((GdkWindowObject *)win)->impl)) + /* Initialization */ void _gdk_windowing_window_init (void); void _gdk_events_init (void); @@ -149,21 +151,13 @@ void _gdk_quartz_window_debug_highlight (GdkWindow *window, /* Events */ typedef enum { - GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP, - GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING + GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP } GdkQuartzEventSubType; void _gdk_quartz_events_update_focus_window (GdkWindow *new_window, gboolean got_focus); -GdkWindow * _gdk_quartz_events_get_mouse_window (gboolean consider_grabs); -void _gdk_quartz_events_update_mouse_window (GdkWindow *window); -void _gdk_quartz_events_update_cursor (GdkWindow *window); -void _gdk_quartz_events_send_map_events (GdkWindow *window); +void _gdk_quartz_events_send_map_event (GdkWindow *window); GdkEventMask _gdk_quartz_events_get_current_event_mask (void); -void _gdk_quartz_events_trigger_crossing_events(gboolean defer_to_mainloop); - -extern GdkWindow *_gdk_quartz_keyboard_grab_window; -extern GdkWindow *_gdk_quartz_pointer_grab_window; /* Event loop */ gboolean _gdk_quartz_event_loop_check_pending (void); @@ -186,14 +180,17 @@ gboolean _gdk_quartz_keys_is_modifier (guint keycode); /* Drawable */ void _gdk_quartz_drawable_finish (GdkDrawable *drawable); +void _gdk_quartz_drawable_flush (GdkDrawable *drawable); /* Geometry */ void _gdk_quartz_window_scroll (GdkWindow *window, gint dx, gint dy); -void _gdk_quartz_window_move_region (GdkWindow *window, - const GdkRegion *region, - gint dx, - gint dy); +void _gdk_quartz_window_queue_translation (GdkWindow *window, + GdkRegion *area, + gint dx, + gint dy); +gboolean _gdk_quartz_window_queue_antiexpose (GdkWindow *window, + GdkRegion *area); #endif /* __GDK_PRIVATE_QUARTZ_H__ */ diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c index c6ed9cb9e..aa8d437a4 100644 --- a/gdk/quartz/gdkwindow-quartz.c +++ b/gdk/quartz/gdkwindow-quartz.c @@ -28,8 +28,8 @@ static gpointer parent_class; -static GSList *update_windows; -static guint update_idle; +static GSList *update_nswindows; +static gboolean in_process_all_updates = FALSE; static GSList *main_window_stack; @@ -48,9 +48,10 @@ static void clear_toplevel_order (void); static FullscreenSavedGeometry *get_fullscreen_geometry (GdkWindow *window); -#define WINDOW_IS_TOPLEVEL(window) \ - (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ - GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN) +#define WINDOW_IS_TOPLEVEL(window) \ + (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ + GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \ + GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN) static void gdk_window_impl_iface_init (GdkWindowImplIface *iface); @@ -76,19 +77,6 @@ gdk_quartz_window_get_nswindow (GdkWindow *window) return ((GdkWindowImplQuartz *)private->impl)->toplevel; } -static void -gdk_window_impl_quartz_get_size (GdkDrawable *drawable, - gint *width, - gint *height) -{ - g_return_if_fail (GDK_IS_WINDOW_IMPL_QUARTZ (drawable)); - - if (width) - *width = GDK_WINDOW_IMPL_QUARTZ (drawable)->width; - if (height) - *height = GDK_WINDOW_IMPL_QUARTZ (drawable)->height; -} - static CGContextRef gdk_window_impl_quartz_get_context (GdkDrawable *drawable, gboolean antialias) @@ -104,7 +92,7 @@ gdk_window_impl_quartz_get_context (GdkDrawable *drawable, * is needed when called from outside "real" expose events, for * example for synthesized expose events when realizing windows * and for widgets that send fake expose events like the arrow - * buttons in spinbuttons. + * buttons in spinbuttons or the position marker in rulers. */ if (window_impl->in_paint_rect_count == 0) { @@ -150,54 +138,44 @@ gdk_window_impl_quartz_get_context (GdkDrawable *drawable, return cg_context; } -static GdkRegion* -gdk_window_impl_quartz_get_visible_region (GdkDrawable *drawable) +static void +check_grab_unmap (GdkWindow *window) { - GdkWindowObject *private = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper); - GdkRectangle rect; - GdkWindowImplQuartz *impl; - GList *windows = NULL, *l; + GdkDisplay *display = gdk_drawable_get_display (window); - /* FIXME: The clip rectangle should really be cached - * and recalculated when the window rectangle changes. - */ - while (private) + _gdk_display_end_pointer_grab (display, 0, window, TRUE); + + if (display->keyboard_grab.window) { - windows = g_list_prepend (windows, private); + GdkWindowObject *private = GDK_WINDOW_OBJECT (window); + GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->keyboard_grab.window); - if (private->parent == GDK_WINDOW_OBJECT (_gdk_root)) - break; + while (tmp && tmp != private) + tmp = tmp->parent; - private = private->parent; + if (tmp) + _gdk_display_unset_has_keyboard_grab (display, TRUE); } +} - /* Get rectangle for toplevel window */ - private = GDK_WINDOW_OBJECT (windows->data); - impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - - rect.x = 0; - rect.y = 0; - rect.width = impl->width; - rect.height = impl->height; +static void +check_grab_destroy (GdkWindow *window) +{ + GdkDisplay *display = gdk_drawable_get_display (window); + GdkPointerGrabInfo *grab; - /* Skip toplevel window since we have its rect */ - for (l = windows->next; l; l = l->next) + /* Make sure there is no lasting grab in this native window */ + grab = _gdk_display_get_last_pointer_grab (display); + if (grab && grab->native_window == window) { - private = GDK_WINDOW_OBJECT (l->data); - impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - GdkRectangle tmp_rect; - - tmp_rect.x = -MIN (0, private->x - rect.x); - tmp_rect.y = -MIN (0, private->y - rect.y); - tmp_rect.width = MIN (rect.width, impl->width + private->x - rect.x) - MAX (0, private->x - rect.x); - tmp_rect.height = MIN (rect.height, impl->height + private->y - rect.y) - MAX (0, private->y - rect.y); - - rect = tmp_rect; + /* Serials are always 0 in quartz, but for clarity: */ + grab->serial_end = grab->serial_start; + grab->implicit_ungrab = TRUE; } - - g_list_free (windows); - - return gdk_region_rectangle (&rect); + + if (window == display->keyboard_grab.native_window && + display->keyboard_grab.window != NULL) + _gdk_display_unset_has_keyboard_grab (display, TRUE); } static void @@ -205,8 +183,7 @@ gdk_window_impl_quartz_finalize (GObject *object) { GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (object); - if (impl->nscursor) - [impl->nscursor release]; + check_grab_destroy (GDK_DRAWABLE_IMPL_QUARTZ (object)->wrapper); if (impl->paint_clip_region) gdk_region_destroy (impl->paint_clip_region); @@ -220,56 +197,58 @@ gdk_window_impl_quartz_finalize (GObject *object) static void gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass) { - GdkDrawableImplQuartzClass *drawable_quartz_class = GDK_DRAWABLE_IMPL_QUARTZ_CLASS (klass); - GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkDrawableImplQuartzClass *drawable_quartz_class = GDK_DRAWABLE_IMPL_QUARTZ_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = gdk_window_impl_quartz_finalize; - drawable_class->get_size = gdk_window_impl_quartz_get_size; - drawable_quartz_class->get_context = gdk_window_impl_quartz_get_context; - - /* Visible and clip regions are the same */ - drawable_class->get_clip_region = gdk_window_impl_quartz_get_visible_region; - drawable_class->get_visible_region = gdk_window_impl_quartz_get_visible_region; } static void gdk_window_impl_quartz_init (GdkWindowImplQuartz *impl) { - impl->width = 1; - impl->height = 1; impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL; } static void gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable, + GdkWindow *window, const GdkRegion *region) { GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable); - GdkDrawableImplQuartz *drawable_impl; + GdkWindowObject *private = (GdkWindowObject*)window; int n_rects; - GdkRectangle *rects; + GdkRectangle *rects = NULL; GdkPixmap *bg_pixmap; - GdkWindow *window; + GdkRegion *clipped_and_offset_region; + gboolean free_clipped_and_offset_region = TRUE; + + bg_pixmap = private->bg_pixmap; - drawable_impl = GDK_DRAWABLE_IMPL_QUARTZ (impl); - bg_pixmap = GDK_WINDOW_OBJECT (drawable_impl->wrapper)->bg_pixmap; + clipped_and_offset_region = gdk_region_copy (region); + + gdk_region_intersect (clipped_and_offset_region, + private->clip_region_with_children); + gdk_region_offset (clipped_and_offset_region, + private->abs_x, private->abs_y); if (impl->begin_paint_count == 0) - impl->paint_clip_region = gdk_region_copy (region); + { + impl->paint_clip_region = clipped_and_offset_region; + free_clipped_and_offset_region = FALSE; + } else - gdk_region_union (impl->paint_clip_region, region); + gdk_region_union (impl->paint_clip_region, clipped_and_offset_region); impl->begin_paint_count++; if (bg_pixmap == GDK_NO_BG) - return; + goto done; - gdk_region_get_rectangles (region, &rects, &n_rects); + gdk_region_get_rectangles (clipped_and_offset_region, &rects, &n_rects); if (bg_pixmap == NULL) { @@ -278,9 +257,9 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable, gint i; cg_context = gdk_quartz_drawable_get_context (GDK_DRAWABLE (impl), FALSE); - _gdk_quartz_colormap_get_rgba_from_pixel (gdk_drawable_get_colormap (drawable_impl->wrapper), - GDK_WINDOW_OBJECT (drawable_impl->wrapper)->bg_color.pixel, - &r, &g, &b, &a); + _gdk_quartz_colormap_get_rgba_from_pixel (gdk_drawable_get_colormap (window), + private->bg_color.pixel, + &r, &g, &b, &a); CGContextSetRGBFillColor (cg_context, r, g, b, a); for (i = 0; i < n_rects; i++) @@ -301,7 +280,6 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable, x_offset = y_offset = 0; - window = GDK_WINDOW (drawable_impl->wrapper); while (window && bg_pixmap == GDK_PARENT_RELATIVE_BG) { /* If this window should have the same background as the parent, @@ -319,8 +297,7 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable, /* Parent relative background but the parent doesn't have a * pixmap. */ - g_free (rects); - return; + goto done; } /* Note: There should be a CG API to draw tiled images, we might @@ -350,6 +327,9 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable, g_object_unref (gc); } + done: + if (free_clipped_and_offset_region) + gdk_region_destroy (clipped_and_offset_region); g_free (rects); } @@ -367,155 +347,97 @@ gdk_window_impl_quartz_end_paint (GdkPaintable *paintable) } } -static void -gdk_window_quartz_process_updates_internal (GdkWindow *window) -{ - GdkWindowObject *private = (GdkWindowObject *) window; - GdkWindowImplQuartz *impl = (GdkWindowImplQuartz *) private->impl; - - if (private->update_area) - { - int i, n_rects; - GdkRectangle *rects; - - gdk_region_get_rectangles (private->update_area, &rects, &n_rects); - - gdk_region_destroy (private->update_area); - private->update_area = NULL; - - for (i = 0; i < n_rects; i++) - { - [impl->view setNeedsDisplayInRect:NSMakeRect (rects[i].x, rects[i].y, - rects[i].width, rects[i].height)]; - } - - [impl->view displayIfNeeded]; - - g_free (rects); - } -} - -static void -gdk_window_quartz_process_all_updates (void) +void +_gdk_windowing_window_process_updates_recurse (GdkWindow *window, + GdkRegion *region) { - GSList *old_update_windows = update_windows; - GSList *tmp_list = update_windows; - GSList *nswindows; - - update_idle = 0; - update_windows = NULL; - nswindows = NULL; - - g_slist_foreach (old_update_windows, (GFunc) g_object_ref, NULL); - - GDK_QUARTZ_ALLOC_POOL; + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowImplQuartz *impl = (GdkWindowImplQuartz *)private->impl; + int i, n_rects; + GdkRectangle *rects; - while (tmp_list) + /* Make sure to only flush each toplevel at most once if we're called + * from process_all_updates. + */ + if (in_process_all_updates) { - GdkWindow *window = tmp_list->data; GdkWindow *toplevel; - /* Only flush each toplevel at most once. */ toplevel = gdk_window_get_toplevel (window); if (toplevel) { - GdkWindowObject *private; - GdkWindowImplQuartz *impl; + GdkWindowObject *toplevel_private; + GdkWindowImplQuartz *toplevel_impl; NSWindow *nswindow; - private = (GdkWindowObject *) toplevel; - impl = (GdkWindowImplQuartz *) private->impl; - nswindow = impl->toplevel; + toplevel_private = (GdkWindowObject *)toplevel; + toplevel_impl = (GdkWindowImplQuartz *)toplevel_private->impl; + nswindow = toplevel_impl->toplevel; + /* In theory, we could skip the flush disabling, since we only + * have one NSView. + */ if (nswindow && ![nswindow isFlushWindowDisabled]) { + [nswindow retain]; [nswindow disableFlushWindow]; - nswindows = g_slist_prepend (nswindows, nswindow); + update_nswindows = g_slist_prepend (update_nswindows, nswindow); } } - - gdk_window_quartz_process_updates_internal (tmp_list->data); - - g_object_unref (tmp_list->data); - tmp_list = tmp_list->next; } - tmp_list = nswindows; - while (tmp_list) - { - NSWindow *nswindow = tmp_list->data; - - [nswindow enableFlushWindow]; - [nswindow flushWindow]; + gdk_region_get_rectangles (region, &rects, &n_rects); - tmp_list = tmp_list->next; + for (i = 0; i < n_rects; i++) + { + [impl->view setNeedsDisplayInRect:NSMakeRect (rects[i].x, rects[i].y, + rects[i].width, rects[i].height)]; } - - GDK_QUARTZ_RELEASE_POOL; - g_slist_free (old_update_windows); - g_slist_free (nswindows); + g_free (rects); + + /* NOTE: I'm not sure if we should displayIfNeeded here. It slows down a + * lot (since it triggers the beam syncing) and things seem to work + * without it. + */ } -static gboolean -gdk_window_quartz_update_idle (gpointer data) +void +_gdk_windowing_before_process_all_updates (void) { - gdk_window_quartz_process_all_updates (); + in_process_all_updates = TRUE; - return FALSE; + NSDisableScreenUpdates (); } -static void -gdk_window_impl_quartz_invalidate_maybe_recurse (GdkPaintable *paintable, - const GdkRegion *region, - gboolean (*child_func) (GdkWindow *, gpointer), - gpointer user_data) -{ - GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (paintable); - GdkDrawableImplQuartz *drawable_impl = (GdkDrawableImplQuartz *) window_impl; - GdkWindow *window = (GdkWindow *) drawable_impl->wrapper; - GdkWindowObject *private = (GdkWindowObject *) window; - GdkRegion *visible_region; +void +_gdk_windowing_after_process_all_updates (void) +{ + GSList *old_update_nswindows = update_nswindows; + GSList *tmp_list = update_nswindows; - visible_region = gdk_drawable_get_visible_region (window); - gdk_region_intersect (visible_region, region); + update_nswindows = NULL; - if (private->update_area) - { - gdk_region_union (private->update_area, visible_region); - gdk_region_destroy (visible_region); - } - else + while (tmp_list) { - /* FIXME: When the update_window/update_area handling is abstracted in - * some way, we can remove this check. Currently it might be cleared - * in the generic code without us knowing, see bug #530801. - */ - if (!g_slist_find (update_windows, window)) - update_windows = g_slist_prepend (update_windows, window); - private->update_area = visible_region; + NSWindow *nswindow = tmp_list->data; - if (update_idle == 0) - update_idle = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW, - gdk_window_quartz_update_idle, NULL, NULL); - } -} + [[nswindow contentView] displayIfNeeded]; -static void -gdk_window_impl_quartz_process_updates (GdkPaintable *paintable, - gboolean update_children) -{ - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable); - GdkDrawableImplQuartz *drawable_impl = (GdkDrawableImplQuartz *) impl; - GdkWindowObject *private = (GdkWindowObject *) drawable_impl->wrapper; + _gdk_quartz_drawable_flush (NULL); - if (private->update_area) - { - GDK_QUARTZ_ALLOC_POOL; - gdk_window_quartz_process_updates_internal ((GdkWindow *) private); - update_windows = g_slist_remove (update_windows, private); - GDK_QUARTZ_RELEASE_POOL; + [nswindow enableFlushWindow]; + [nswindow flushWindow]; + [nswindow release]; + + tmp_list = tmp_list->next; } + + g_slist_free (old_update_nswindows); + + in_process_all_updates = FALSE; + + NSEnableScreenUpdates (); } static void @@ -523,9 +445,6 @@ gdk_window_impl_quartz_paintable_init (GdkPaintableIface *iface) { iface->begin_paint_region = gdk_window_impl_quartz_begin_paint_region; iface->end_paint = gdk_window_impl_quartz_end_paint; - - iface->invalidate_maybe_recurse = gdk_window_impl_quartz_invalidate_maybe_recurse; - iface->process_updates = gdk_window_impl_quartz_process_updates; } GType @@ -621,7 +540,6 @@ void _gdk_quartz_window_debug_highlight (GdkWindow *window, gint number) { GdkWindowObject *private = GDK_WINDOW_OBJECT (window); - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); gint x, y; GdkWindow *toplevel; gint tx, ty; @@ -652,8 +570,8 @@ _gdk_quartz_window_debug_highlight (GdkWindow *window, gint number) y += ty; rect = NSMakeRect (x, - _gdk_quartz_window_get_inverted_screen_y (y + impl->height), - impl->width, impl->height); + _gdk_quartz_window_get_inverted_screen_y (y + private->height), + private->width, private->height); if (debug_window[number] && NSEqualRects (rect, old_rect[number])) return; @@ -775,7 +693,7 @@ find_child_window_helper (GdkWindow *window, if (titlebar_height > 0 && x >= temp_x && y >= temp_y - titlebar_height && - x < temp_x + child_impl->width && y < temp_y) + x < temp_x + child_private->width && y < temp_y) { /* The root means "unknown" i.e. a window not managed by * GDK. @@ -785,7 +703,7 @@ find_child_window_helper (GdkWindow *window, } if (x >= temp_x && y >= temp_y && - x < temp_x + child_impl->width && y < temp_y + child_impl->height) + x < temp_x + child_private->width && y < temp_y + child_private->height) { /* Look for child windows. */ return find_child_window_helper (l->data, @@ -807,9 +725,8 @@ _gdk_quartz_window_find_child (GdkWindow *window, gint y) { GdkWindowObject *private = GDK_WINDOW_OBJECT (window); - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - if (x >= 0 && y >= 0 && x < impl->width && y < impl->height) + if (x >= 0 && y >= 0 && x < private->width && y < private->height) return find_child_window_helper (window, x, y, 0, 0); return NULL; @@ -857,101 +774,45 @@ _gdk_quartz_window_did_resign_main (GdkWindow *window) clear_toplevel_order (); } -GdkWindow * -_gdk_window_new (GdkWindow *parent, - GdkWindowAttr *attributes, - gint attributes_mask) +void +_gdk_window_impl_new (GdkWindow *window, + GdkWindow *real_parent, + GdkScreen *screen, + GdkVisual *visual, + GdkEventMask event_mask, + GdkWindowAttr *attributes, + gint attributes_mask) { - GdkWindow *window; GdkWindowObject *private; GdkWindowImplQuartz *impl; GdkDrawableImplQuartz *draw_impl; - GdkVisual *visual; GdkWindowImplQuartz *parent_impl; - if (parent && GDK_WINDOW_DESTROYED (parent)) - return NULL; - GDK_QUARTZ_ALLOC_POOL; - if (!parent) - parent = _gdk_root; - - window = g_object_new (GDK_TYPE_WINDOW, NULL); - private = (GdkWindowObject *)window; - private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); - impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - draw_impl = GDK_DRAWABLE_IMPL_QUARTZ (private->impl); + impl = g_object_new (_gdk_window_impl_get_type (), NULL); + private->impl = (GdkDrawable *)impl; + draw_impl = GDK_DRAWABLE_IMPL_QUARTZ (impl); draw_impl->wrapper = GDK_DRAWABLE (window); - private->parent = (GdkWindowObject *)parent; parent_impl = GDK_WINDOW_IMPL_QUARTZ (private->parent->impl); - private->accept_focus = TRUE; - private->focus_on_map = TRUE; - - if (attributes_mask & GDK_WA_X) - private->x = attributes->x; - else - private->x = 0; - - if (attributes_mask & GDK_WA_Y) - private->y = attributes->y; - else if (attributes_mask & GDK_WA_X) - private->y = 100; - else - private->y = 0; - - private->event_mask = attributes->event_mask; - - impl->width = attributes->width > 1 ? attributes->width : 1; - impl->height = attributes->height > 1 ? attributes->height : 1; - - if (attributes_mask & GDK_WA_VISUAL) - visual = attributes->visual; - else - visual = gdk_screen_get_system_visual (_gdk_screen); - - if (attributes->wclass == GDK_INPUT_ONLY) - { - /* Backwards compatiblity - we've always ignored - * attributes->window_type for input-only windows - * before - */ - if (parent == _gdk_root) - private->window_type = GDK_WINDOW_TEMP; - else - private->window_type = GDK_WINDOW_CHILD; - } - else - private->window_type = attributes->window_type; - - /* Sanity checks */ switch (private->window_type) { case GDK_WINDOW_TOPLEVEL: case GDK_WINDOW_DIALOG: case GDK_WINDOW_TEMP: - if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT) + if (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT) { - g_warning (G_STRLOC "Toplevel windows must be created as children of\n" - "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN"); + /* The common code warns for this case */ + parent_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (_gdk_root)->impl); } - case GDK_WINDOW_CHILD: - break; - default: - g_warning (G_STRLOC "cannot make windows of type %d", private->window_type); - GDK_QUARTZ_RELEASE_POOL; - return NULL; } - if (attributes->wclass == GDK_INPUT_OUTPUT) + if (!private->input_only) { - private->input_only = FALSE; - private->depth = visual->depth; - if (attributes_mask & GDK_WA_COLORMAP) { draw_impl->colormap = attributes->colormap; @@ -974,22 +835,15 @@ _gdk_window_new (GdkWindow *parent, draw_impl->colormap = gdk_colormap_new (visual, FALSE); } } - - private->bg_color.pixel = 0; - private->bg_color.red = private->bg_color.green = private->bg_color.blue = 0; } else { - private->depth = 0; - private->input_only = TRUE; draw_impl->colormap = gdk_screen_get_system_colormap (_gdk_screen); g_object_ref (draw_impl->colormap); } - private->parent->children = g_list_prepend (private->parent->children, window); - /* Maintain the z-ordered list of children. */ - if (parent != _gdk_root) + if (private->parent != (GdkWindowObject *)_gdk_root) parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window); else clear_toplevel_order (); @@ -1008,13 +862,10 @@ _gdk_window_new (GdkWindow *parent, int style_mask; const char *title; - /* Big hack: We start out outside the screen and move the - * window in before showing it. This makes the initial - * MouseEntered event work if the window ends up right under - * the mouse pointer, bad quartz. - */ - content_rect = NSMakeRect (-500 - impl->width, -500 - impl->height, - impl->width, impl->height); + content_rect = NSMakeRect (private->x, + _gdk_quartz_window_get_inverted_screen_y (private->y) - private->height, + private->width, + private->height); if (attributes->window_type == GDK_WINDOW_TEMP || attributes->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN) @@ -1047,6 +898,9 @@ _gdk_window_new (GdkWindow *parent, [impl->toplevel setBackgroundColor:[NSColor clearColor]]; } + content_rect.origin.x = 0; + content_rect.origin.y = 0; + impl->view = [[GdkQuartzView alloc] initWithFrame:content_rect]; [impl->view setGdkWindow:window]; [impl->toplevel setContentView:impl->view]; @@ -1055,11 +909,14 @@ _gdk_window_new (GdkWindow *parent, case GDK_WINDOW_CHILD: { - GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (parent)->impl); + GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (private->parent)->impl); - if (attributes->wclass == GDK_INPUT_OUTPUT) + if (!private->input_only) { - NSRect frame_rect = NSMakeRect (private->x, private->y, impl->width, impl->height); + NSRect frame_rect = NSMakeRect (private->x + private->parent->abs_x, + private->y + private->parent->abs_y, + private->width, + private->height); impl->view = [[GdkQuartzView alloc] initWithFrame:frame_rect]; @@ -1080,8 +937,6 @@ _gdk_window_new (GdkWindow *parent, if (attributes_mask & GDK_WA_TYPE_HINT) gdk_window_set_type_hint (window, attributes->type_hint); - - return window; } void @@ -1098,12 +953,18 @@ _gdk_windowing_window_init (void) private = (GdkWindowObject *)_gdk_root; private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); + private->impl_window = private; /* Note: This needs to be reworked for multi-screen support. */ impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (_gdk_root)->impl); rect = [[NSScreen mainScreen] frame]; - impl->width = rect.size.width; - impl->height = rect.size.height; + + private->x = 0; + private->y = 0; + private->abs_x = 0; + private->abs_y = 0; + private->width = rect.size.width; + private->height = rect.size.height; private->state = 0; /* We don't want GDK_WINDOW_STATE_WITHDRAWN here */ private->window_type = GDK_WINDOW_ROOT; @@ -1116,20 +977,18 @@ _gdk_windowing_window_init (void) g_object_ref (drawable_impl->colormap); } -void -_gdk_windowing_window_destroy (GdkWindow *window, - gboolean recursing, - gboolean foreign_destroy) +static void +_gdk_quartz_window_destroy (GdkWindow *window, + gboolean recursing, + gboolean foreign_destroy) { GdkWindowObject *private; GdkWindowImplQuartz *impl; GdkWindowObject *parent; - GdkWindow *mouse_window; private = GDK_WINDOW_OBJECT (window); impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - update_windows = g_slist_remove (update_windows, window); main_window_stack = g_slist_remove (main_window_stack, window); g_list_free (impl->sorted_children); @@ -1143,22 +1002,8 @@ _gdk_windowing_window_destroy (GdkWindow *window, parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window); } - /* If the destroyed window was targeted for a pointer or keyboard - * grab, release the grab. - */ - if (window == _gdk_quartz_pointer_grab_window) - gdk_pointer_ungrab (0); - - if (window == _gdk_quartz_keyboard_grab_window) - gdk_keyboard_ungrab (0); - _gdk_quartz_drawable_finish (GDK_DRAWABLE (impl)); - mouse_window = _gdk_quartz_events_get_mouse_window (FALSE); - if (window == mouse_window || - _gdk_quartz_window_is_ancestor (window, mouse_window)) - _gdk_quartz_events_update_mouse_window (_gdk_root); - if (!recursing && !foreign_destroy) { GDK_QUARTZ_ALLOC_POOL; @@ -1178,39 +1023,16 @@ _gdk_windowing_window_destroy_foreign (GdkWindow *window) /* Foreign windows aren't supported in OSX. */ } -static gboolean -all_parents_shown (GdkWindowObject *private) -{ - while (GDK_WINDOW_IS_MAPPED (private)) - { - if (private->parent) - private = (GdkWindowObject *)private->parent; - else - return TRUE; - } - - return FALSE; -} - -/* Note: the raise argument is not really used, it doesn't seem - * possible to show a window without raising it? - */ +/* FIXME: This might be possible to simplify with client-side windows. */ static void -gdk_window_quartz_show (GdkWindow *window, - gboolean raise) +gdk_window_quartz_show (GdkWindow *window) { - GdkWindowObject *private; - GdkWindowImplQuartz *impl; + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); gboolean focus_on_map; - if (GDK_WINDOW_DESTROYED (window)) - return; - GDK_QUARTZ_ALLOC_POOL; - private = (GdkWindowObject *)window; - impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - if (!GDK_WINDOW_IS_MAPPED (window)) focus_on_map = private->focus_on_map; else @@ -1220,14 +1042,13 @@ gdk_window_quartz_show (GdkWindow *window, { gboolean make_key; - /* Move the window into place, to guarantee that we get the - * initial MouseEntered event. - */ - make_key = (private->accept_focus && focus_on_map && raise && + make_key = (private->accept_focus && focus_on_map && private->window_type != GDK_WINDOW_TEMP); [(GdkQuartzWindow*)impl->toplevel showAndMakeKey:make_key]; clear_toplevel_order (); + + _gdk_quartz_events_send_map_event (window); } else { @@ -1236,9 +1057,6 @@ gdk_window_quartz_show (GdkWindow *window, [impl->view setNeedsDisplay:YES]; - if (all_parents_shown (private->parent)) - _gdk_quartz_events_send_map_events (window); - gdk_synthesize_window_state (window, GDK_WINDOW_STATE_WITHDRAWN, 0); if (private->state & GDK_WINDOW_STATE_MAXIMIZED) @@ -1250,12 +1068,6 @@ gdk_window_quartz_show (GdkWindow *window, if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for)) _gdk_quartz_window_attach_to_parent (window); - /* Create a crossing event for windows that pop up under the mouse. Part - * of the workarounds for problems with the tracking rect API. - */ - if (impl->toplevel) - _gdk_quartz_events_trigger_crossing_events (TRUE); - GDK_QUARTZ_RELEASE_POOL; } @@ -1310,24 +1122,12 @@ gdk_window_quartz_hide (GdkWindow *window) { GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplQuartz *impl; - GdkWindow *mouse_window; /* Make sure we're not stuck in fullscreen mode. */ if (get_fullscreen_geometry (window)) SetSystemUIMode (kUIModeNormal, 0); - if (GDK_WINDOW_DESTROYED (window)) - return; - - mouse_window = _gdk_quartz_events_get_mouse_window (FALSE); - if (window == mouse_window || - _gdk_quartz_window_is_ancestor (window, mouse_window)) - _gdk_quartz_events_update_mouse_window (_gdk_root); - - if (GDK_WINDOW_IS_MAPPED (window)) - gdk_synthesize_window_state (window, - 0, - GDK_WINDOW_STATE_WITHDRAWN); + check_grab_unmap (window); _gdk_window_clear_update_area (window); @@ -1349,12 +1149,6 @@ gdk_window_quartz_hide (GdkWindow *window) { [impl->view setHidden:YES]; } - - if (window == _gdk_quartz_pointer_grab_window) - gdk_pointer_ungrab (0); - - if (window == _gdk_quartz_keyboard_grab_window) - gdk_keyboard_ungrab (0); } void @@ -1386,8 +1180,8 @@ move_resize_window_internal (GdkWindow *window, if ((x == -1 || (x == private->x)) && (y == -1 || (y == private->y)) && - (width == -1 || (width == impl->width)) && - (height == -1 || (height == impl->height))) + (width == -1 || (width == private->width)) && + (height == -1 || (height == private->height))) { return; } @@ -1426,10 +1220,10 @@ move_resize_window_internal (GdkWindow *window, } if (width != -1) - impl->width = width; + private->width = width; if (height != -1) - impl->height = height; + private->height = height; GDK_QUARTZ_ALLOC_POOL; @@ -1438,19 +1232,12 @@ move_resize_window_internal (GdkWindow *window, NSRect content_rect; NSRect frame_rect; - /* We don't update the NSWindow while unmapped, since we move windows - * off-screen when hiding in order for MouseEntered to be triggered - * reliably when showing windows and they appear under the mouse. - */ - if (GDK_WINDOW_IS_MAPPED (window)) - { - content_rect = NSMakeRect (private->x, - _gdk_quartz_window_get_inverted_screen_y (private->y + impl->height), - impl->width, impl->height); + content_rect = NSMakeRect (private->x, + _gdk_quartz_window_get_inverted_screen_y (private->y + private->height), + private->width, private->height); - frame_rect = [impl->toplevel frameRectForContentRect:content_rect]; - [impl->toplevel setFrame:frame_rect display:YES]; - } + frame_rect = [impl->toplevel frameRectForContentRect:content_rect]; + [impl->toplevel setFrame:frame_rect display:YES]; } else { @@ -1458,7 +1245,7 @@ move_resize_window_internal (GdkWindow *window, { NSRect nsrect; - nsrect = NSMakeRect (private->x, private->y, impl->width, impl->height); + nsrect = NSMakeRect (private->x, private->y, private->width, private->height); /* The newly visible area of this window in a coordinate * system rooted at the origin of this window. @@ -1588,6 +1375,9 @@ gdk_window_quartz_move_resize (GdkWindow *window, } } +/* FIXME: This might need fixing (reparenting didn't work before client-side + * windows either). + */ static gboolean gdk_window_quartz_reparent (GdkWindow *window, GdkWindow *new_parent, @@ -1598,7 +1388,7 @@ gdk_window_quartz_reparent (GdkWindow *window, GdkWindowImplQuartz *impl, *old_parent_impl, *new_parent_impl; NSView *view, *new_parent_view; - if (!new_parent || new_parent == _gdk_root) + if (new_parent == _gdk_root) { /* Could be added, just needs implementing. */ g_warning ("Reparenting to root window is not supported yet in the Mac OS X backend"); @@ -1623,31 +1413,16 @@ gdk_window_quartz_reparent (GdkWindow *window, [view release]; - private->x = x; - private->y = y; - private->parent = (GdkWindowObject *)new_parent; + private->parent = new_parent_private; if (old_parent_private) { - old_parent_private->children = g_list_remove (old_parent_private->children, window); old_parent_impl->sorted_children = g_list_remove (old_parent_impl->sorted_children, window); } - new_parent_private->children = g_list_prepend (new_parent_private->children, window); new_parent_impl->sorted_children = g_list_prepend (new_parent_impl->sorted_children, window); - return TRUE; -} - -static void -gdk_window_quartz_clear_area (GdkWindow *window, - gint x, - gint y, - gint width, - gint height, - gboolean send_expose) -{ - /* FIXME: Implement */ + return FALSE; } /* Get the toplevel ordering from NSApp and update our own list. We do @@ -1767,87 +1542,38 @@ static void gdk_window_quartz_set_background (GdkWindow *window, const GdkColor *color) { - GdkWindowObject *private = (GdkWindowObject *)window; - GdkWindowImplQuartz *impl; - - if (GDK_WINDOW_DESTROYED (window)) - return; - - impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - - private->bg_color = *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; + /* FIXME: We could theoretically set the background color for toplevels + * here. (Currently we draw the background before emitting expose events) + */ } static void gdk_window_quartz_set_back_pixmap (GdkWindow *window, - GdkPixmap *pixmap, - gboolean parent_relative) + GdkPixmap *pixmap) { - GdkWindowObject *private = (GdkWindowObject *)window; - - if (GDK_WINDOW_DESTROYED (window)) - 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; - GDK_NOTE (MISC, g_print (G_STRLOC ": setting background pixmap to parent_relative\n")); - } - else - { - if (pixmap) - { - g_object_ref (pixmap); - private->bg_pixmap = pixmap; - } - else - { - private->bg_pixmap = GDK_NO_BG; - } - } + /* FIXME: Could theoretically set some background image here. (Currently + * the back pixmap is drawn before emitting expose events. + */ } static void gdk_window_quartz_set_cursor (GdkWindow *window, GdkCursor *cursor) { - GdkWindowImplQuartz *impl; GdkCursorPrivate *cursor_private; NSCursor *nscursor; - impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); cursor_private = (GdkCursorPrivate *)cursor; if (GDK_WINDOW_DESTROYED (window)) return; - GDK_QUARTZ_ALLOC_POOL; - if (!cursor) - nscursor = NULL; + nscursor = [NSCursor arrowCursor]; else - nscursor = [cursor_private->nscursor retain]; - - if (impl->nscursor) - [impl->nscursor release]; - - impl->nscursor = nscursor; + nscursor = cursor_private->nscursor; - GDK_QUARTZ_RELEASE_POOL; - - _gdk_quartz_events_update_cursor (_gdk_quartz_events_get_mouse_window (TRUE)); + [nscursor set]; } static void @@ -1859,12 +1585,14 @@ gdk_window_quartz_get_geometry (GdkWindow *window, gint *depth) { GdkWindowImplQuartz *impl; + GdkWindowObject *private; NSRect ns_rect; if (GDK_WINDOW_DESTROYED (window)) return; impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); + private = GDK_WINDOW_OBJECT (window); if (window == _gdk_root) { if (x) @@ -1873,9 +1601,9 @@ gdk_window_quartz_get_geometry (GdkWindow *window, *y = 0; if (width) - *width = impl->width; + *width = private->width; if (height) - *height = impl->height; + *height = private->height; } else if (WINDOW_IS_TOPLEVEL (window)) { @@ -1950,8 +1678,11 @@ gdk_window_quartz_get_origin (GdkWindow *window, if (window == _gdk_root) { - *x = 0; - *y = 0; + if (x) + *x = 0; + if (y) + *y = 0; + return 1; } @@ -1967,8 +1698,11 @@ gdk_window_quartz_get_origin (GdkWindow *window, while (private != GDK_WINDOW_OBJECT (toplevel)) { - tmp_x += private->x; - tmp_y += private->y; + if (_gdk_window_has_impl ((GdkWindow *)private)) + { + tmp_x += private->x; + tmp_y += private->y; + } private = private->parent; } @@ -1981,13 +1715,11 @@ gdk_window_quartz_get_origin (GdkWindow *window, return TRUE; } -gboolean -gdk_window_get_deskrelative_origin (GdkWindow *window, - gint *x, - gint *y) +static gboolean +gdk_window_quartz_get_deskrelative_origin (GdkWindow *window, + gint *x, + gint *y) { - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); - return gdk_window_get_origin (window, x, y); } @@ -1998,8 +1730,6 @@ gdk_window_get_root_origin (GdkWindow *window, { GdkRectangle rect; - g_return_if_fail (GDK_IS_WINDOW (window)); - rect.x = 0; rect.y = 0; @@ -2040,6 +1770,8 @@ _gdk_windowing_window_get_pointer (GdkDisplay *display, gint x_tmp, y_tmp; GdkWindow *found_window; + g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + if (GDK_WINDOW_DESTROYED (window)) { *x = 0; @@ -2065,23 +1797,15 @@ _gdk_windowing_window_get_pointer (GdkDisplay *display, NSWindow *nswindow; impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl); + private = GDK_WINDOW_OBJECT (toplevel); nswindow = impl->toplevel; point = [nswindow mouseLocationOutsideOfEventStream]; - x_tmp = point.x; - y_tmp = impl->height - point.y; - } - /* The coords are relative to the toplevel of the passed in window - * at this point, make them relative to the passed in window: - */ - private = GDK_WINDOW_OBJECT (window); - while (private != toplevel) - { - x_tmp -= private->x; - y_tmp -= private->y; + x_tmp = point.x; + y_tmp = private->height - point.y; - private = private->parent; + window = (GdkWindow *)toplevel; } found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp); @@ -2107,18 +1831,19 @@ gdk_display_warp_pointer (GdkDisplay *display, /* Returns coordinates relative to the found window. */ GdkWindow * -_gdk_windowing_window_at_pointer (GdkDisplay *display, - gint *win_x, - gint *win_y) +_gdk_windowing_window_at_pointer (GdkDisplay *display, + gint *win_x, + gint *win_y, + GdkModifierType *mask) { - GdkModifierType mask; GdkWindow *found_window; gint x, y; + GdkModifierType tmp_mask = 0; found_window = _gdk_windowing_window_get_pointer (display, _gdk_root, &x, &y, - &mask); + &tmp_mask); if (found_window) { GdkWindowObject *private; @@ -2145,6 +1870,9 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display, *win_y = -1; } + if (mask) + *mask = tmp_mask; + return found_window; } @@ -2161,16 +1889,17 @@ static void gdk_window_quartz_set_events (GdkWindow *window, GdkEventMask event_mask) { - if (!GDK_WINDOW_DESTROYED (window)) - { - GDK_WINDOW_OBJECT (window)->event_mask = event_mask; - } + /* The mask is set in the common code. */ } void gdk_window_set_urgency_hint (GdkWindow *window, gboolean urgent) { + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; + /* FIXME: Implement */ } @@ -2181,10 +1910,10 @@ gdk_window_set_geometry_hints (GdkWindow *window, { GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (geometry != NULL); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; impl = GDK_WINDOW_IMPL_QUARTZ (((GdkWindowObject *) window)->impl); @@ -2258,10 +1987,10 @@ gdk_window_set_title (GdkWindow *window, { GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (title != NULL); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + WINDOW_IS_TOPLEVEL (window)) return; impl = GDK_WINDOW_IMPL_QUARTZ (((GdkWindowObject *)window)->impl); @@ -2278,6 +2007,10 @@ void gdk_window_set_role (GdkWindow *window, const gchar *role) { + if (GDK_WINDOW_DESTROYED (window) || + WINDOW_IS_TOPLEVEL (window)) + return; + /* FIXME: Implement */ } @@ -2288,7 +2021,8 @@ gdk_window_set_transient_for (GdkWindow *window, GdkWindowImplQuartz *window_impl; GdkWindowImplQuartz *parent_impl; - if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (parent)) + if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent) && + WINDOW_IS_TOPLEVEL (window)) return; window_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); @@ -2343,38 +2077,14 @@ gdk_window_quartz_shape_combine_region (GdkWindow *window, } static void -gdk_window_quartz_shape_combine_mask (GdkWindow *window, - GdkBitmap *mask, - gint x, - gint y) -{ - /* FIXME: Implement */ -} - -void -gdk_window_input_shape_combine_mask (GdkWindow *window, - GdkBitmap *mask, - gint x, - gint y) +gdk_window_quartz_input_shape_combine_region (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y) { /* FIXME: Implement */ } -void -gdk_window_input_shape_combine_region (GdkWindow *window, - const GdkRegion *shape_region, - gint offset_x, - gint offset_y) -{ - /* FIXME: Implement */ -} - -void -gdk_window_set_child_input_shapes (GdkWindow *window) -{ - /* FIXME: IMplement */ -} - void gdk_window_set_override_redirect (GdkWindow *window, gboolean override_redirect) @@ -2388,35 +2098,19 @@ gdk_window_set_accept_focus (GdkWindow *window, { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject *)window; private->accept_focus = accept_focus != FALSE; } -static void -gdk_window_quartz_set_child_shapes (GdkWindow *window) -{ - /* FIXME: Implement */ -} - -static void -gdk_window_quartz_merge_child_shapes (GdkWindow *window) -{ - /* FIXME: Implement */ -} - -void -gdk_window_merge_child_input_shapes (GdkWindow *window) -{ - /* FIXME: Implement */ -} - static gboolean gdk_window_quartz_set_static_gravities (GdkWindow *window, gboolean use_static) { + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return FALSE; + /* FIXME: Implement */ return FALSE; } @@ -2427,8 +2121,6 @@ gdk_window_set_focus_on_map (GdkWindow *window, { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject *)window; private->focus_on_map = focus_on_map != FALSE; @@ -2440,8 +2132,6 @@ gdk_window_set_icon (GdkWindow *window, GdkPixmap *pixmap, GdkBitmap *mask) { - g_return_if_fail (GDK_IS_WINDOW (window)); - /* FIXME: Implement */ } @@ -2449,8 +2139,6 @@ void gdk_window_set_icon_name (GdkWindow *window, const gchar *name) { - g_return_if_fail (GDK_IS_WINDOW (window)); - /* FIXME: Implement */ } @@ -2461,20 +2149,19 @@ gdk_window_focus (GdkWindow *window, GdkWindowObject *private; GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject*) window; impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - if (impl->toplevel) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; + + if (private->accept_focus && private->window_type != GDK_WINDOW_TEMP) { - if (private->accept_focus && private->window_type != GDK_WINDOW_TEMP) - { - GDK_QUARTZ_ALLOC_POOL; - [impl->toplevel makeKeyAndOrderFront:impl->toplevel]; - clear_toplevel_order (); - GDK_QUARTZ_RELEASE_POOL; - } + GDK_QUARTZ_ALLOC_POOL; + [impl->toplevel makeKeyAndOrderFront:impl->toplevel]; + clear_toplevel_order (); + GDK_QUARTZ_RELEASE_POOL; } } @@ -2564,9 +2251,8 @@ gdk_window_set_type_hint (GdkWindow *window, { GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; impl = GDK_WINDOW_IMPL_QUARTZ (((GdkWindowObject *) window)->impl); @@ -2584,7 +2270,8 @@ gdk_window_set_type_hint (GdkWindow *window, GdkWindowTypeHint gdk_window_get_type_hint (GdkWindow *window) { - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return GDK_WINDOW_TYPE_HINT_NORMAL; return GDK_WINDOW_IMPL_QUARTZ (((GdkWindowObject *) window)->impl)->type_hint; @@ -2594,7 +2281,9 @@ void gdk_window_set_modal_hint (GdkWindow *window, gboolean modal) { - g_return_if_fail (GDK_IS_WINDOW (window)); + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; /* FIXME: Implement */ } @@ -2603,7 +2292,9 @@ void gdk_window_set_skip_taskbar_hint (GdkWindow *window, gboolean skips_taskbar) { - g_return_if_fail (GDK_IS_WINDOW (window)); + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; /* FIXME: Implement */ } @@ -2612,7 +2303,9 @@ void gdk_window_set_skip_pager_hint (GdkWindow *window, gboolean skips_pager) { - g_return_if_fail (GDK_IS_WINDOW (window)); + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; /* FIXME: Implement */ } @@ -2661,9 +2354,8 @@ gdk_window_begin_move_drag (GdkWindow *window, GdkWindowObject *private; GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; private = GDK_WINDOW_OBJECT (window); @@ -2694,7 +2386,6 @@ gdk_window_get_frame_extents (GdkWindow *window, GdkWindowImplQuartz *impl; NSRect ns_rect; - g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (rect != NULL); private = GDK_WINDOW_OBJECT (window); @@ -2704,9 +2395,6 @@ gdk_window_get_frame_extents (GdkWindow *window, rect->width = 1; rect->height = 1; - if (GDK_WINDOW_DESTROYED (window)) - return; - toplevel = gdk_window_get_toplevel (window); impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl); @@ -2726,10 +2414,8 @@ gdk_window_set_decorations (GdkWindow *window, int old_mask, new_mask; NSView *old_view; - g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (WINDOW_IS_TOPLEVEL (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); @@ -2804,10 +2490,8 @@ gdk_window_get_decorations (GdkWindow *window, { GdkWindowImplQuartz *impl; - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); - g_return_val_if_fail (WINDOW_IS_TOPLEVEL (window), FALSE); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return FALSE; impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); @@ -2838,14 +2522,6 @@ gdk_window_set_functions (GdkWindow *window, /* FIXME: Implement */ } -static void -gdk_window_quartz_get_offsets (GdkWindow *window, - gint *x_offset, - gint *y_offset) -{ - *x_offset = *y_offset = 0; -} - gboolean _gdk_windowing_window_queue_antiexpose (GdkWindow *window, GdkRegion *area) @@ -2856,13 +2532,17 @@ _gdk_windowing_window_queue_antiexpose (GdkWindow *window, void gdk_window_stick (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; } void gdk_window_unstick (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; } void @@ -2870,9 +2550,8 @@ gdk_window_maximize (GdkWindow *window) { GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); @@ -2899,9 +2578,8 @@ gdk_window_unmaximize (GdkWindow *window) { GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); @@ -2928,11 +2606,10 @@ gdk_window_iconify (GdkWindow *window) { GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; - + impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); if (GDK_WINDOW_IS_MAPPED (window)) @@ -2957,9 +2634,8 @@ gdk_window_deiconify (GdkWindow *window) { GdkWindowImplQuartz *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); @@ -2992,11 +2668,11 @@ gdk_window_fullscreen (GdkWindow *window) { FullscreenSavedGeometry *geometry; GdkWindowObject *private = (GdkWindowObject *) window; - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); NSRect frame; - g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (WINDOW_IS_TOPLEVEL (window)); + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; geometry = get_fullscreen_geometry (window); if (!geometry) @@ -3005,8 +2681,8 @@ gdk_window_fullscreen (GdkWindow *window) geometry->x = private->x; geometry->y = private->y; - geometry->width = impl->width; - geometry->height = impl->height; + geometry->width = private->width; + geometry->height = private->height; if (!gdk_window_get_decorations (window, &geometry->decor)) geometry->decor = GDK_DECOR_ALL; @@ -3033,8 +2709,9 @@ gdk_window_unfullscreen (GdkWindow *window) { FullscreenSavedGeometry *geometry; - g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (WINDOW_IS_TOPLEVEL (window)); + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; geometry = get_fullscreen_geometry (window); if (geometry) @@ -3063,9 +2740,9 @@ gdk_window_set_keep_above (GdkWindow *window, gboolean setting) gint level; g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (WINDOW_IS_TOPLEVEL (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; level = window_type_hint_to_level (gdk_window_get_type_hint (window)); @@ -3082,9 +2759,9 @@ gdk_window_set_keep_below (GdkWindow *window, gboolean setting) gint level; g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (WINDOW_IS_TOPLEVEL (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; level = window_type_hint_to_level (gdk_window_get_type_hint (window)); @@ -3096,9 +2773,12 @@ gdk_window_set_keep_below (GdkWindow *window, gboolean setting) GdkWindow * gdk_window_get_group (GdkWindow *window) { - g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL); + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return NULL; + /* FIXME: Implement */ return NULL; @@ -3146,11 +2826,17 @@ gdk_window_configure_finished (GdkWindow *window) void gdk_window_destroy_notify (GdkWindow *window) { + check_grab_destroy (window); } void gdk_window_beep (GdkWindow *window) { + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + gdk_display_beep (_gdk_display); } @@ -3164,7 +2850,8 @@ gdk_window_set_opacity (GdkWindow *window, g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (WINDOW_IS_TOPLEVEL (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (opacity < 0) @@ -3188,22 +2875,20 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface) iface->withdraw = gdk_window_quartz_withdraw; iface->set_events = gdk_window_quartz_set_events; iface->get_events = gdk_window_quartz_get_events; - iface->clear_area = gdk_window_quartz_clear_area; iface->raise = gdk_window_quartz_raise; iface->lower = gdk_window_quartz_lower; iface->move_resize = gdk_window_quartz_move_resize; - iface->scroll = _gdk_quartz_window_scroll; - iface->move_region = _gdk_quartz_window_move_region; iface->set_background = gdk_window_quartz_set_background; iface->set_back_pixmap = gdk_window_quartz_set_back_pixmap; iface->reparent = gdk_window_quartz_reparent; iface->set_cursor = gdk_window_quartz_set_cursor; iface->get_geometry = gdk_window_quartz_get_geometry; iface->get_origin = gdk_window_quartz_get_origin; - iface->shape_combine_mask = gdk_window_quartz_shape_combine_mask; + iface->get_deskrelative_origin = gdk_window_quartz_get_deskrelative_origin; iface->shape_combine_region = gdk_window_quartz_shape_combine_region; - iface->set_child_shapes = gdk_window_quartz_set_child_shapes; - iface->merge_child_shapes = gdk_window_quartz_merge_child_shapes; + iface->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region; iface->set_static_gravities = gdk_window_quartz_set_static_gravities; - iface->get_offsets = gdk_window_quartz_get_offsets; + iface->queue_antiexpose = _gdk_quartz_window_queue_antiexpose; + iface->queue_translation = _gdk_quartz_window_queue_translation; + iface->destroy = _gdk_quartz_window_destroy; } diff --git a/gdk/quartz/gdkwindow-quartz.h b/gdk/quartz/gdkwindow-quartz.h index b3e3fb9db..89f2ec06b 100644 --- a/gdk/quartz/gdkwindow-quartz.h +++ b/gdk/quartz/gdkwindow-quartz.h @@ -45,17 +45,12 @@ struct _GdkWindowImplQuartz { GdkDrawableImplQuartz parent_instance; - gint width; - gint height; - NSWindow *toplevel; NSTrackingRectTag tracking_rect; GdkQuartzView *view; GdkWindowTypeHint type_hint; - NSCursor *nscursor; - GdkRegion *paint_clip_region; gint begin_paint_count; gint in_paint_rect_count; diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c index 75fde0865..340d243f3 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -36,6 +36,12 @@ _gdk_windowing_set_default_display (GdkDisplay *display) g_assert (display == NULL || _gdk_display == display); } +gulong +_gdk_windowing_window_get_next_serial (GdkDisplay *display) +{ + return 0; +} + #ifdef HAVE_MONITOR_INFO static BOOL CALLBACK count_monitor (HMONITOR hmonitor, @@ -200,7 +206,7 @@ gdk_display_open (const gchar *display_name) _gdk_visual_init (); gdk_screen_set_default_colormap (_gdk_screen, gdk_screen_get_system_colormap (_gdk_screen)); - _gdk_windowing_window_init (); + _gdk_windowing_window_init (_gdk_screen); _gdk_windowing_image_init (); _gdk_events_init (); _gdk_input_init (_gdk_display); diff --git a/gdk/win32/gdkdrawable-win32.c b/gdk/win32/gdkdrawable-win32.c index e762ae0f0..4ccf0b3b6 100644 --- a/gdk/win32/gdkdrawable-win32.c +++ b/gdk/win32/gdkdrawable-win32.c @@ -1657,16 +1657,45 @@ _gdk_win32_blit (gboolean use_fg_bg, else g_assert_not_reached (); + if (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl) && + GDK_IS_PIXMAP_IMPL_WIN32 (src_impl)) + { + GdkPixmapImplWin32 *src_pixmap = GDK_PIXMAP_IMPL_WIN32 (src_impl); + + if (xsrc < 0) + { + width += xsrc; + xdest -= xsrc; + xsrc = 0; + } + + if (ysrc < 0) + { + height += ysrc; + ydest -= ysrc; + ysrc = 0; + } + + if (xsrc + width > src_pixmap->width) + width = src_pixmap->width - xsrc; + if (ysrc + height > src_pixmap->height) + height = src_pixmap->height - ysrc; + } + hdc = gdk_win32_hdc_get (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND); gdk_drawable_get_size (src, &src_width, &src_height); if ((src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1)) == NULL) - WIN32_GDI_FAILED ("CreateRectRgn"); + { + WIN32_GDI_FAILED ("CreateRectRgn"); + } else if ((draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1)) == NULL) - WIN32_GDI_FAILED ("CreateRectRgn"); + { + WIN32_GDI_FAILED ("CreateRectRgn"); + } else { if (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl)) @@ -1731,6 +1760,7 @@ _gdk_win32_blit (gboolean use_fg_bg, xsrc, ysrc, xdest, ydest, width, height); else blit_from_window (hdc, GDK_GC_WIN32 (gc), src_impl, xsrc, ysrc, xdest, ydest, width, height); + gdk_win32_hdc_release (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND); } @@ -1807,7 +1837,9 @@ _gdk_win32_drawable_acquire_dc (GdkDrawable *drawable) return impl->hdc; } else - return NULL; + { + return NULL; + } } /** @@ -1844,6 +1876,27 @@ _gdk_win32_drawable_release_dc (GdkDrawable *drawable) } } +cairo_surface_t * +_gdk_windowing_create_cairo_surface (GdkDrawable *drawable, + gint width, + gint height) +{ + GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable); + RECT rect; + + HDC hdc = _gdk_win32_drawable_acquire_dc (drawable); + if (!hdc) + { + return NULL; + } + + GetClipBox (hdc, &rect); + g_print ("create_cairo_surface(): [%d %d %d %d]\n", + rect.left, rect.top, rect.right, rect.bottom); + + return cairo_win32_surface_create (hdc); +} + static void gdk_win32_cairo_surface_destroy (void *data) { @@ -1864,21 +1917,29 @@ gdk_win32_ref_cairo_surface (GdkDrawable *drawable) if (!impl->cairo_surface) { - HDC hdc = _gdk_win32_drawable_acquire_dc (drawable); - if (!hdc) - return NULL; - - impl->cairo_surface = cairo_win32_surface_create (hdc); + // On Win32 cairo surface, width and height are determined from the DC + impl->cairo_surface = _gdk_windowing_create_cairo_surface (drawable, 0, 0); cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key, drawable, gdk_win32_cairo_surface_destroy); } else - cairo_surface_reference (impl->cairo_surface); + { + cairo_surface_reference (impl->cairo_surface); + } return impl->cairo_surface; } +void +_gdk_windowing_set_cairo_surface_size (cairo_surface_t *surface, + gint width, + gint height) +{ + // Do nothing. The surface size is determined by the DC + g_print ("*** set_cairo_surface_size()\n"); +} + static gint gdk_win32_get_depth (GdkDrawable *drawable) { @@ -1922,10 +1983,11 @@ _gdk_win32_drawable_finish (GdkDrawable *drawable) if (impl->cairo_surface) { cairo_surface_finish (impl->cairo_surface); - cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key, - NULL, NULL); + cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key, NULL, NULL); } + + g_print ("hdc_count == %d\n", impl->hdc_count); - g_assert (impl->hdc_count == 0); + //g_assert (impl->hdc_count == 0); } diff --git a/gdk/win32/gdkdrawable-win32.h b/gdk/win32/gdkdrawable-win32.h index d11ee6ad9..72082705a 100644 --- a/gdk/win32/gdkdrawable-win32.h +++ b/gdk/win32/gdkdrawable-win32.h @@ -61,7 +61,6 @@ struct _GdkDrawableImplWin32 struct _GdkDrawableImplWin32Class { GdkDrawableClass parent_class; - }; GType gdk_drawable_impl_win32_get_type (void); diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 3cdd66f0e..67217e34e 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -1,7 +1,7 @@ /* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1998-2002 Tor Lillqvist - * Copyright (C) 2007-2008 Cody Russell + * Copyright (C) 2007-2009 Cody Russell * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -99,6 +99,7 @@ static gboolean is_modally_blocked (GdkWindow *window); /* Private variable declarations */ +#if 0 static GdkWindow *p_grab_window = NULL; /* Window that currently holds * the pointer grab */ @@ -108,6 +109,7 @@ static GdkWindow *p_grab_confine_to = NULL; static GdkWindow *k_grab_window = NULL; /* Window the holds the * keyboard grab */ +#endif static GList *client_filters; /* Filters for client messages */ @@ -482,131 +484,43 @@ gdk_pointer_grab (GdkWindow *window, GdkCursor *cursor, guint32 time) { - HCURSOR hcursor; - GdkCursorPrivate *cursor_private; - gint return_val = GDK_GRAB_SUCCESS; + GdkWindow *native; - 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); - - cursor_private = (GdkCursorPrivate*) cursor; - - if (!cursor) - hcursor = NULL; - else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL) - WIN32_API_FAILED ("CopyCursor"); - - return_val = _gdk_input_grab_pointer (window, - owner_events, - event_mask, - confine_to, - time); - - if (return_val == GDK_GRAB_SUCCESS) - { - if (!GDK_WINDOW_DESTROYED (window)) - { - GDK_NOTE (EVENTS, g_print ("%sgdk_pointer_grab: %p %s %p %s%s", - (debug_indent > 0 ? "\n" : ""), - GDK_WINDOW_HWND (window), - (owner_events ? "TRUE" : "FALSE"), - hcursor, - event_mask_string (event_mask), - (debug_indent == 0 ? "\n" : ""))); - - p_grab_mask = event_mask; - p_grab_owner_events = owner_events; - p_grab_automatic = FALSE; - - SetCapture (GDK_WINDOW_HWND (window)); - return_val = GDK_GRAB_SUCCESS; - } - else - return_val = GDK_GRAB_ALREADY_GRABBED; - } - - if (return_val == GDK_GRAB_SUCCESS) - { - GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl); - - if (p_grab_window != NULL && p_grab_window != window) - generate_grab_broken_event (p_grab_window, FALSE, window); - - assign_object (&p_grab_window, window); - - if (p_grab_cursor != NULL) - { - if (GetCursor () == p_grab_cursor) - SetCursor (NULL); - DestroyCursor (p_grab_cursor); - } - p_grab_cursor = hcursor; + native = gdk_window_get_toplevel (window); - if (p_grab_cursor != NULL) - SetCursor (p_grab_cursor); - else if (impl->hcursor != NULL) - SetCursor (impl->hcursor); - else - SetCursor (LoadCursor (NULL, IDC_ARROW)); - - if (confine_to != NULL) - { - gint x, y, width, height; - RECT rect; + if (!GDK_IS_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (native)->impl)) + return GDK_GRAB_SUCCESS; - gdk_window_get_origin (confine_to, &x, &y); - gdk_drawable_get_size (confine_to, &width, &height); + if (!_gdk_window_has_impl (window) && + !gdk_window_is_viewable (window)) + return GDK_GRAB_NOT_VIEWABLE; - x -= _gdk_offset_x; - y -= _gdk_offset_y; - - rect.left = x; - rect.top = y; - rect.right = x + width; - rect.bottom = y + height; - API_CALL (ClipCursor, (&rect)); - p_grab_confine_to = confine_to; - } + _gdk_display_add_pointer_grab (_gdk_display, + window, + native, + owner_events, + event_mask, + 0, + time, + FALSE); - /* FIXME: Generate GDK_CROSSING_GRAB events */ - } - - return return_val; + return GDK_GRAB_SUCCESS; } void gdk_display_pointer_ungrab (GdkDisplay *display, guint32 time) { - g_return_if_fail (display == _gdk_display); - - GDK_NOTE (EVENTS, g_print ("%sgdk_display_pointer_ungrab%s", - (debug_indent > 0 ? "\n" : ""), - (debug_indent == 0 ? "\n" : ""))); - - _gdk_input_ungrab_pointer (time); - - if (GetCapture () != NULL) - ReleaseCapture (); + GdkPointerGrabInfo *info; - /* FIXME: Generate GDK_CROSSING_UNGRAB events */ - - assign_object (&p_grab_window, NULL); - if (p_grab_cursor != NULL) - { - if (GetCursor () == p_grab_cursor) - SetCursor (NULL); - DestroyCursor (p_grab_cursor); - p_grab_cursor = NULL; - } + info = _gdk_display_get_last_pointer_grab (display); + if (info) + info->serial_end = 0; - if (p_grab_confine_to != NULL) - { - API_CALL (ClipCursor, (NULL)); - p_grab_confine_to = NULL; - } + _gdk_display_pointer_grab_update (display, 0); } static GdkWindow * @@ -632,13 +546,19 @@ find_real_window_for_grabbed_mouse_event (GdkWindow* reported_window, GetClientRect (hwnd, &rect); ScreenToClient (hwnd, &pt); if (!PtInRect (&rect, pt)) - return _gdk_root; + { + g_print ("find_real_window_for_grabbed_mouse_event(), PtInRect() failed\n"); + return _gdk_root; + } other_window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd); } if (other_window == NULL) - return _gdk_root; + { + g_print ("find_real_window_for_grabbed_mouse_event(), other_window == NULL\n"); + return _gdk_root; + } return other_window; } @@ -647,155 +567,47 @@ static GdkWindow* find_window_for_mouse_event (GdkWindow* reported_window, MSG* msg) { - if (p_grab_window == NULL || !p_grab_owner_events) + GdkPointerGrabInfo *info = _gdk_display_get_last_pointer_grab (_gdk_display); + + if (!info || !info->window || !info->owner_events) return reported_window; else return find_real_window_for_grabbed_mouse_event (reported_window, msg); } -gboolean -gdk_display_pointer_is_grabbed (GdkDisplay *display) -{ - g_return_val_if_fail (display == _gdk_display, FALSE); - GDK_NOTE (EVENTS, g_print ("gdk_pointer_is_grabbed: %s\n", - p_grab_window != NULL ? "TRUE" : "FALSE")); - return p_grab_window != NULL; -} - -gboolean -gdk_pointer_grab_info_libgtk_only (GdkDisplay *display, - GdkWindow **grab_window, - gboolean *owner_events) -{ - g_return_val_if_fail (display == _gdk_display, FALSE); - - if (p_grab_window != NULL) - { - if (grab_window) - *grab_window = p_grab_window; - if (owner_events) - *owner_events = p_grab_owner_events; - - return TRUE; - } - else - return FALSE; -} - GdkGrabStatus gdk_keyboard_grab (GdkWindow *window, gboolean owner_events, guint32 time) { - GdkWindow *real_focus_window, *grab_focus_window; + GdkDisplay *display; + GdkWindow *toplevel; - gint return_val; - g_return_val_if_fail (window != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (window), 0); GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %p%s\n", GDK_WINDOW_HWND (window), owner_events ? " OWNER_EVENTS" : "")); - if (!GDK_WINDOW_DESTROYED (window)) - { - k_grab_owner_events = owner_events; - return_val = GDK_GRAB_SUCCESS; - } - else - return_val = GDK_GRAB_ALREADY_GRABBED; - - if (return_val == GDK_GRAB_SUCCESS) - { - if (k_grab_window != NULL && k_grab_window != window) - generate_grab_broken_event (k_grab_window, TRUE, window); + display = gdk_drawable_get_display (window); + toplevel = gdk_window_get_toplevel (window); - assign_object (&k_grab_window, window); + _gdk_display_set_has_keyboard_grab (display, + window, + toplevel, + owner_events, + 0, + time); - if (!k_grab_owner_events) - { - real_focus_window = gdk_win32_handle_table_lookup ((GdkNativeWindow) GetFocus ()); - if (real_focus_window) - real_focus_window = gdk_window_get_toplevel (real_focus_window); - grab_focus_window = gdk_window_get_toplevel (k_grab_window); - if (real_focus_window != grab_focus_window) - { - /* Generate events for focus change from the window that really - * has focus to the grabber. - */ - if (real_focus_window && !GDK_WINDOW_DESTROYED (real_focus_window) - && (((GdkWindowObject *) real_focus_window)->event_mask - & GDK_FOCUS_CHANGE_MASK)) - generate_focus_event (real_focus_window, FALSE); - - if (((GdkWindowObject *) grab_focus_window)->event_mask - & GDK_FOCUS_CHANGE_MASK) - generate_focus_event (grab_focus_window, TRUE); - } - } - } - - return return_val; + return GDK_GRAB_SUCCESS; } void gdk_display_keyboard_ungrab (GdkDisplay *display, guint32 time) { - GdkWindow *real_focus_window, *grab_focus_window; - - g_return_if_fail (display == _gdk_display); - GDK_NOTE (EVENTS, g_print ("gdk_display_keyboard_ungrab\n")); - - if (k_grab_window && !k_grab_owner_events) - { - real_focus_window = gdk_win32_handle_table_lookup ((GdkNativeWindow) GetFocus ()); - if (real_focus_window) - real_focus_window = gdk_window_get_toplevel (real_focus_window); - if (!GDK_WINDOW_DESTROYED (k_grab_window)) - grab_focus_window = gdk_window_get_toplevel (k_grab_window); - else - grab_focus_window = NULL; - if (real_focus_window != grab_focus_window) - { - /* Generate events for focus change from grabber to the window that - * really has focus. Important for example if a new window is created - * while focus is grabbed. - */ - if (grab_focus_window - && (((GdkWindowObject *) grab_focus_window)->event_mask - & GDK_FOCUS_CHANGE_MASK)) - generate_focus_event (grab_focus_window, FALSE); - - if (real_focus_window && !GDK_WINDOW_DESTROYED (real_focus_window) - && (((GdkWindowObject *) real_focus_window)->event_mask - & GDK_FOCUS_CHANGE_MASK)) - generate_focus_event (real_focus_window, TRUE); - } - } - - assign_object (&k_grab_window, NULL); -} - -gboolean -gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display, - GdkWindow **grab_window, - gboolean *owner_events) -{ - g_return_val_if_fail (display == _gdk_display, FALSE); - - if (k_grab_window) - { - if (grab_window) - *grab_window = k_grab_window; - if (owner_events) - *owner_events = k_grab_owner_events; - - return TRUE; - } - else - return FALSE; + _gdk_display_unset_has_keyboard_grab (display, FALSE); } void @@ -808,7 +620,7 @@ gdk_display_add_client_message_filter (GdkDisplay *display, gdk_add_client_message_filter (message_type, func, data); } -void +void gdk_add_client_message_filter (GdkAtom message_type, GdkFilterFunc func, gpointer data) @@ -1393,22 +1205,20 @@ synthesize_enter_or_leave_event (GdkWindow *window, gint y) { GdkEvent *event; - gint xoffset, yoffset; event = gdk_event_new (type); event->crossing.window = window; event->crossing.subwindow = NULL; event->crossing.time = _gdk_win32_get_next_tick (msg->time); - _gdk_win32_windowing_window_get_offsets (window, &xoffset, &yoffset); - event->crossing.x = x + xoffset; - event->crossing.y = y + yoffset; + event->crossing.x = x; + event->crossing.y = y; event->crossing.x_root = msg->pt.x + _gdk_offset_x; event->crossing.y_root = msg->pt.y + _gdk_offset_y; event->crossing.mode = mode; event->crossing.detail = detail; event->crossing.focus = TRUE; /* FIXME: Set correctly */ event->crossing.state = 0; /* FIXME: Set correctly */ - + append_event (event); if (type == GDK_ENTER_NOTIFY && @@ -1423,8 +1233,11 @@ synthesize_leave_event (GdkWindow *window, GdkNotifyType detail) { POINT pt; + GdkPointerGrabInfo *grab; + + grab = _gdk_display_get_last_pointer_grab (_gdk_display); - if (p_grab_window != NULL && !p_grab_owner_events && !(p_grab_mask & GDK_LEAVE_NOTIFY_MASK)) + if (grab && grab->window != NULL && !grab->owner_events && !(grab->event_mask & GDK_LEAVE_NOTIFY_MASK)) return; if (!(((GdkWindowObject *) window)->event_mask & GDK_LEAVE_NOTIFY_MASK)) @@ -1457,8 +1270,11 @@ synthesize_enter_event (GdkWindow *window, GdkNotifyType detail) { POINT pt; + GdkPointerGrabInfo *grab; - if (p_grab_window != NULL && !p_grab_owner_events && !(p_grab_mask & GDK_ENTER_NOTIFY_MASK)) + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + + if (grab && grab->window != NULL && !grab->owner_events && !(grab->event_mask & GDK_ENTER_NOTIFY_MASK)) return; if (!(((GdkWindowObject *) window)->event_mask & GDK_ENTER_NOTIFY_MASK)) @@ -1491,6 +1307,7 @@ synthesize_enter_events (GdkWindow *from, if (prev != from) synthesize_enter_events (from, prev, msg, mode, detail); + synthesize_enter_event (to, msg, mode, detail); } @@ -1504,6 +1321,7 @@ synthesize_leave_events (GdkWindow *from, GdkWindow *next = gdk_window_get_parent (from); synthesize_leave_event (from, msg, mode, detail); + if (next != to) synthesize_leave_events (next, to, msg, mode, detail); } @@ -1855,10 +1673,12 @@ handle_configure_event (MSG *msg, { RECT client_rect; POINT point; + GdkWindowObject *window_object; GetClientRect (msg->hwnd, &client_rect); point.x = client_rect.left; /* always 0 */ point.y = client_rect.top; + /* top level windows need screen coords */ if (gdk_window_get_parent (window) == _gdk_root) { @@ -1867,13 +1687,17 @@ handle_configure_event (MSG *msg, point.y += _gdk_offset_y; } - GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->width = client_rect.right - client_rect.left; - GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->height = client_rect.bottom - client_rect.top; + window_object = GDK_WINDOW_OBJECT (window); + + window_object->width = client_rect.right - client_rect.left; + window_object->height = client_rect.bottom - client_rect.top; - ((GdkWindowObject *) window)->x = point.x; - ((GdkWindowObject *) window)->y = point.y; + window_object->x = point.x; + window_object->y = point.y; + + _gdk_window_update_size (window); - if (((GdkWindowObject *) window)->event_mask & GDK_STRUCTURE_MASK) + if (window_object->event_mask & GDK_STRUCTURE_MASK) { GdkEvent *event = gdk_event_new (GDK_CONFIGURE); @@ -1953,7 +1777,6 @@ handle_wm_paint (MSG *msg, HDC hdc; PAINTSTRUCT paintstruct; GdkRegion *update_region; - gint xoffset, yoffset; if (GetUpdateRgn (msg->hwnd, hrgn, FALSE) == ERROR) { @@ -2037,9 +1860,10 @@ handle_wm_paint (MSG *msg, update_region = _gdk_win32_hrgn_to_region (hrgn); - _gdk_win32_windowing_window_get_offsets (window, &xoffset, &yoffset); - gdk_region_offset (update_region, xoffset, yoffset); - + + //_gdk_win32_windowing_window_get_offsets (window, &xoffset, &yoffset); + //gdk_region_offset (update_region, xoffset, yoffset); + _gdk_window_process_expose (window, update_region); gdk_region_destroy (update_region); @@ -2097,7 +1921,6 @@ generate_button_event (GdkEventType type, MSG *msg) { GdkEvent *event = gdk_event_new (type); - gint xoffset, yoffset; event->button.window = window; event->button.time = _gdk_win32_get_next_tick (msg->time); @@ -2105,9 +1928,6 @@ generate_button_event (GdkEventType type, translate_mouse_coords (orig_window, window, msg); event->button.x = current_x = (gint16) GET_X_LPARAM (msg->lParam); event->button.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam); - _gdk_win32_windowing_window_get_offsets (window, &xoffset, &yoffset); - event->button.x += xoffset; - event->button.y += yoffset; event->button.x_root = msg->pt.x + _gdk_offset_x; event->button.y_root = msg->pt.y + _gdk_offset_y; event->button.axes = NULL; @@ -2283,7 +2103,11 @@ gdk_event_translate (MSG *msg, GdkWindowImplWin32 *impl; GdkWindow *orig_window, *new_window; - gint xoffset, yoffset; + + GdkPointerGrabInfo *grab = NULL; + GdkWindow *grab_window = NULL; + guint grab_mask = 0; + gboolean grab_owner_events = FALSE; static gint update_colors_counter = 0; gint button; @@ -2461,7 +2285,7 @@ gdk_event_translate (MSG *msg, /* Let the system handle Alt-Tab, Alt-Space and Alt-F4 unless * the keyboard is grabbed. */ - if (k_grab_window == NULL && + if (_gdk_display->keyboard_grab.window == NULL && (msg->wParam == VK_TAB || msg->wParam == VK_SPACE || msg->wParam == VK_F4)) @@ -2486,7 +2310,9 @@ gdk_event_translate (MSG *msg, break; if (!propagate (&window, msg, - k_grab_window, k_grab_owner_events, GDK_ALL_EVENTS_MASK, + _gdk_display->keyboard_grab.window, + _gdk_display->keyboard_grab.owner_events, + GDK_ALL_EVENTS_MASK, doesnt_want_key, FALSE)) break; @@ -2588,7 +2414,9 @@ gdk_event_translate (MSG *msg, break; if (!propagate (&window, msg, - k_grab_window, k_grab_owner_events, GDK_ALL_EVENTS_MASK, + _gdk_display->keyboard_grab.window, + _gdk_display->keyboard_grab.owner_events, + GDK_ALL_EVENTS_MASK, doesnt_want_char, FALSE)) break; @@ -2654,21 +2482,32 @@ gdk_event_translate (MSG *msg, assign_object (&window, find_window_for_mouse_event (window, msg)); - if (p_grab_window != NULL) + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab) + { + grab_window = grab->window; + grab_mask = grab->event_mask; + grab_owner_events = grab->owner_events; + } + + if (grab_window != NULL) { GdkWindow *real_window = find_real_window_for_grabbed_mouse_event (window, msg); if (real_window != current_window) - synthesize_crossing_events (real_window, GDK_CROSSING_NORMAL, msg); + { + synthesize_crossing_events (real_window, GDK_CROSSING_NORMAL, msg); + } } else { if (window != current_window) - synthesize_crossing_events (window, GDK_CROSSING_NORMAL, msg); + { + synthesize_crossing_events (window, GDK_CROSSING_NORMAL, msg); + } } - if (!propagate (&window, msg, - p_grab_window, p_grab_owner_events, p_grab_mask, + if (!propagate (&window, msg, grab_window, grab_owner_events, grab_mask, doesnt_want_button_press, TRUE)) break; @@ -2676,7 +2515,8 @@ gdk_event_translate (MSG *msg, break; /* Emulate X11's automatic active grab */ - if (!p_grab_window) + /* XXX: Do we still want this with CSW? -- Cody */ + if (!grab_window) { /* No explicit active grab, let's start one automatically */ GDK_NOTE (EVENTS, g_print (" (automatic grab)")); @@ -2687,6 +2527,8 @@ gdk_event_translate (MSG *msg, p_grab_automatic = TRUE; } + g_print ("generate_button_event()\n"); + generate_button_event (GDK_BUTTON_PRESS, button, window, orig_window, msg); @@ -2718,7 +2560,15 @@ gdk_event_translate (MSG *msg, assign_object (&window, find_window_for_mouse_event (window, msg)); - if (p_grab_window != NULL) + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab != NULL) + { + grab_window = grab->window; + grab_owner_events = grab->owner_events; + grab_mask = grab->event_mask; + } + + if (grab_window != NULL) { GdkWindow *real_window = find_real_window_for_grabbed_mouse_event (window, msg); @@ -2740,9 +2590,8 @@ gdk_event_translate (MSG *msg, } #endif - if (!propagate (&window, msg, - p_grab_window, p_grab_owner_events, p_grab_mask, - doesnt_want_button_release, TRUE)) + if (!propagate (&window, msg, grab_window, grab_owner_events, + grab_mask, doesnt_want_button_release, TRUE)) { } else if (!GDK_WINDOW_DESTROYED (window)) @@ -2751,11 +2600,9 @@ gdk_event_translate (MSG *msg, window, orig_window, msg); } - if (p_grab_window != NULL && - p_grab_automatic && - (msg->wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) == 0) + if (grab_window != NULL && p_grab_automatic && + (msg->wParam && (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) == 0) { - /* Terminate automatic grab */ gdk_pointer_ungrab (0); } @@ -2781,53 +2628,68 @@ gdk_event_translate (MSG *msg, assign_object (&window, find_window_for_mouse_event (window, msg)); - if (p_grab_window != NULL) + if (window != current_window) + synthesize_crossing_events (window, GDK_CROSSING_NORMAL, msg); + + GdkPointerGrabInfo *grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab != NULL) + { + grab_window = grab->window; + grab_owner_events = grab->owner_events; + grab_mask = grab->event_mask; + } + + if (grab_window != NULL) { GdkWindow *real_window = find_real_window_for_grabbed_mouse_event (window, msg); if (real_window != current_window) { - if (p_grab_owner_events) + if (grab_owner_events) { synthesize_crossing_events (real_window, GDK_CROSSING_NORMAL, msg); } - else if (current_window == p_grab_window) + else if (current_window == grab_window) { - synthesize_leave_event (p_grab_window, msg, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR); + synthesize_leave_event (grab_window, msg, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR); assign_object (¤t_window, _gdk_root); } - else if (real_window == p_grab_window) + else if (real_window == grab_window) { - synthesize_enter_event (p_grab_window, msg, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR); - assign_object (¤t_window, p_grab_window); + synthesize_enter_event (grab_window, msg, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR); + assign_object (¤t_window, grab_window); } } } else { if (window != current_window) - synthesize_crossing_events (window, GDK_CROSSING_NORMAL, msg); + { + synthesize_crossing_events (window, GDK_CROSSING_NORMAL, msg); + } } - if (!propagate (&window, msg, - p_grab_window, p_grab_owner_events, p_grab_mask, +#if 0 // XXX - this seems to always block us from creating motion notify events -- Cody + if (!propagate (&window, msg, grab_window, grab_owner_events, grab_mask, doesnt_want_button_motion, TRUE)) - break; + { + break; + } +#endif if (GDK_WINDOW_DESTROYED (window)) break; if (window != orig_window) - translate_mouse_coords (orig_window, window, msg); + { + translate_mouse_coords (orig_window, window, msg); + } event = gdk_event_new (GDK_MOTION_NOTIFY); event->motion.window = window; event->motion.time = _gdk_win32_get_next_tick (msg->time); event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam); event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam); - _gdk_win32_windowing_window_get_offsets (window, &xoffset, &yoffset); - event->motion.x += xoffset; - event->motion.y += yoffset; event->motion.x_root = current_root_x; event->motion.y_root = current_root_y; event->motion.axes = NULL; @@ -2901,9 +2763,19 @@ gdk_event_translate (MSG *msg, assign_object (&window, new_window); } - if (!propagate (&window, msg, - p_grab_window, p_grab_owner_events, p_grab_mask, - doesnt_want_scroll, TRUE)) + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab != NULL) + { + grab_window = grab->window; + grab_mask = grab->event_mask; + grab_owner_events = grab->owner_events; + } + + if (!propagate (&window, msg, grab_window, + grab_owner_events, + grab_mask, + doesnt_want_scroll, + TRUE)) break; if (GDK_WINDOW_DESTROYED (window)) @@ -2916,9 +2788,8 @@ gdk_event_translate (MSG *msg, event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ? GDK_SCROLL_UP : GDK_SCROLL_DOWN; event->scroll.time = _gdk_win32_get_next_tick (msg->time); - _gdk_win32_windowing_window_get_offsets (window, &xoffset, &yoffset); - event->scroll.x = (gint16) point.x + xoffset; - event->scroll.y = (gint16) point.y + yoffset; + event->scroll.x = (gint16) point.x; + event->scroll.y = (gint16) point.y; event->scroll.x_root = (gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x; event->scroll.y_root = (gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y; event->scroll.state = build_pointer_event_state (msg); @@ -3022,16 +2893,16 @@ gdk_event_translate (MSG *msg, break; case WM_KILLFOCUS: - if (p_grab_window != NULL && !GDK_WINDOW_DESTROYED (p_grab_window)) - generate_grab_broken_event (p_grab_window, FALSE, NULL); - - if (k_grab_window != NULL && !GDK_WINDOW_DESTROYED (k_grab_window) - && k_grab_window != p_grab_window) - generate_grab_broken_event (k_grab_window, TRUE, NULL); + if (_gdk_display->keyboard_grab.window != NULL && + !GDK_WINDOW_DESTROYED (_gdk_display->keyboard_grab.window)) + { + generate_grab_broken_event (_gdk_display->keyboard_grab.window, FALSE, NULL); + } /* fallthrough */ case WM_SETFOCUS: - if (k_grab_window != NULL && !k_grab_owner_events) + if (_gdk_display->keyboard_grab.window != NULL && + !_gdk_display->keyboard_grab.owner_events) break; if (!(((GdkWindowObject *) window)->event_mask & GDK_FOCUS_CHANGE_MASK)) @@ -3068,10 +2939,16 @@ gdk_event_translate (MSG *msg, GDK_NOTE (EVENTS, g_print (" %#x %#x", LOWORD (msg->lParam), HIWORD (msg->lParam))); - if (p_grab_window == NULL && LOWORD (msg->lParam) != HTCLIENT) + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab != NULL) + { + grab_window = grab->window; + } + + if (grab_window == NULL && LOWORD (msg->lParam) != HTCLIENT) break; - if (p_grab_window != NULL && p_grab_cursor != NULL) + if (grab_window != NULL && p_grab_cursor != NULL) hcursor = p_grab_cursor; else if (!GDK_WINDOW_DESTROYED (window)) hcursor = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->hcursor; @@ -3121,15 +2998,15 @@ gdk_event_translate (MSG *msg, SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner)); } - if (p_grab_window == window) + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab != NULL) { - gdk_pointer_ungrab (msg->time); + if (grab->window == window) + gdk_pointer_ungrab (msg->time); } - if (k_grab_window == window) - { - gdk_keyboard_ungrab (msg->time); - } + if (_gdk_display->keyboard_grab.window == window) + gdk_keyboard_ungrab (msg->time); } return_val = TRUE; @@ -3159,11 +3036,13 @@ gdk_event_translate (MSG *msg, if (msg->wParam == SIZE_MINIMIZED) { /* Don't generate any GDK event. This is *not* an UNMAP. */ - - if (p_grab_window == window) - gdk_pointer_ungrab (msg->time); - - if (k_grab_window == window) + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab != NULL) + { + if (grab->window == window) + gdk_pointer_ungrab (msg->time); + } + if (_gdk_display->keyboard_grab.window == window) gdk_keyboard_ungrab (msg->time); gdk_synthesize_window_state (window, @@ -3604,10 +3483,14 @@ gdk_event_translate (MSG *msg, if (window == current_window) assign_object (¤t_window, _gdk_root); - if (p_grab_window == window) - gdk_pointer_ungrab (msg->time); + grab = _gdk_display_get_last_pointer_grab (_gdk_display); + if (grab != NULL) + { + if (grab->window == window) + gdk_pointer_ungrab (msg->time); + } - if (k_grab_window == window) + if (_gdk_display->keyboard_grab.window == window) gdk_keyboard_ungrab (msg->time); if ((window != NULL) && (msg->hwnd != GetDesktopWindow ())) diff --git a/gdk/win32/gdkgc-win32.c b/gdk/win32/gdkgc-win32.c index c255f4b15..d1e2909b7 100644 --- a/gdk/win32/gdkgc-win32.c +++ b/gdk/win32/gdkgc-win32.c @@ -572,7 +572,8 @@ gdk_win32_gc_set_dashes (GdkGC *gc, void _gdk_windowing_gc_set_clip_region (GdkGC *gc, - const GdkRegion *region) + const GdkRegion *region, + gboolean reset_origin) { GdkGCWin32 *win32_gc = GDK_GC_WIN32 (gc); @@ -596,9 +597,12 @@ _gdk_windowing_gc_set_clip_region (GdkGC *gc, win32_gc->values_mask &= ~GDK_GC_CLIP_MASK; } - gc->clip_x_origin = 0; - gc->clip_y_origin = 0; - + if (reset_origin) + { + gc->clip_x_origin = 0; + gc->clip_y_origin = 0; + } + win32_gc->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN); } diff --git a/gdk/win32/gdkgeometry-win32.c b/gdk/win32/gdkgeometry-win32.c index 61dbf7628..833fc5b62 100644 --- a/gdk/win32/gdkgeometry-win32.c +++ b/gdk/win32/gdkgeometry-win32.c @@ -42,196 +42,15 @@ #include "gdk.h" /* For gdk_rectangle_intersect */ #include "gdkregion.h" #include "gdkregion-generic.h" +#include "gdkinternals.h" #include "gdkprivate-win32.h" #define SIZE_LIMIT 32767 typedef struct _GdkWindowParentPos GdkWindowParentPos; -struct _GdkWindowParentPos -{ - gint x; - gint y; - gint win32_x; - gint win32_y; - GdkRectangle clip_rect; -}; - -static void gdk_window_compute_position (GdkWindowImplWin32 *window, - GdkWindowParentPos *parent_pos, - GdkWin32PositionInfo *info); -static void gdk_window_compute_parent_pos (GdkWindowImplWin32 *window, - GdkWindowParentPos *parent_pos); - -static void gdk_window_postmove (GdkWindow *window, - GdkWindowParentPos *parent_pos, - gboolean anti_scroll); -static void gdk_window_tmp_unset_bg (GdkWindow *window); -static void gdk_window_tmp_reset_bg (GdkWindow *window); -static GdkRegion *gdk_window_clip_changed (GdkWindow *window, - GdkRectangle *old_clip, - GdkRectangle *new_clip); -static void gdk_window_post_scroll (GdkWindow *window, - GdkRegion *new_clip_region); - -void -_gdk_win32_windowing_window_get_offsets (GdkWindow *window, - gint *x_offset, - gint *y_offset) -{ - GdkWindowImplWin32 *impl = - GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); - - *x_offset = impl->position_info.x_offset; - *y_offset = impl->position_info.y_offset; -} - -void -_gdk_window_init_position (GdkWindow *window) -{ - GdkWindowParentPos parent_pos; - GdkWindowImplWin32 *impl; - - g_return_if_fail (GDK_IS_WINDOW (window)); - - impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); - - gdk_window_compute_parent_pos (impl, &parent_pos); - gdk_window_compute_position (impl, &parent_pos, &impl->position_info); -} - -void -_gdk_win32_window_scroll (GdkWindow *window, - gint dx, - gint dy) -{ - GdkRegion *invalidate_region; - GdkWindowImplWin32 *impl; - GdkWindowObject *obj; - GList *tmp_list; - GdkWindowParentPos parent_pos; - HRGN native_invalidate_region; - - GDK_NOTE (EVENTS, g_print ("gdk_window_scroll: %p %d,%d\n", - GDK_WINDOW_HWND (window), dx, dy)); - - obj = GDK_WINDOW_OBJECT (window); - impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); - - /* Move the current invalid region */ - if (obj->update_area) - gdk_region_offset (obj->update_area, dx, dy); - - gdk_window_compute_parent_pos (impl, &parent_pos); - - parent_pos.x += obj->x; - parent_pos.y += obj->y; - parent_pos.win32_x += impl->position_info.x; - parent_pos.win32_y += impl->position_info.y; - parent_pos.clip_rect = impl->position_info.clip_rect; - - gdk_window_tmp_unset_bg (window); - - native_invalidate_region = CreateRectRgn (0, 0, 0, 0); - if (native_invalidate_region == NULL) - WIN32_API_FAILED ("CreateRectRgn"); - - API_CALL (ScrollWindowEx, (GDK_WINDOW_HWND (window), - dx, dy, NULL, NULL, - native_invalidate_region, NULL, SW_SCROLLCHILDREN)); - - if (impl->position_info.no_bg) - gdk_window_tmp_reset_bg (window); - - tmp_list = obj->children; - while (tmp_list) - { - GDK_WINDOW_OBJECT(tmp_list->data)->x += dx; - GDK_WINDOW_OBJECT(tmp_list->data)->y += dy; - gdk_window_postmove (tmp_list->data, &parent_pos, FALSE); - tmp_list = tmp_list->next; - } - - if (native_invalidate_region != NULL) - { - invalidate_region = _gdk_win32_hrgn_to_region (native_invalidate_region); - gdk_region_offset (invalidate_region, impl->position_info.x_offset, - impl->position_info.y_offset); - gdk_window_invalidate_region (window, invalidate_region, TRUE); - gdk_region_destroy (invalidate_region); - GDI_CALL (DeleteObject, (native_invalidate_region)); - } -} - -void -_gdk_win32_window_move_region (GdkWindow *window, - const GdkRegion *region, - gint dx, - gint dy) -{ - GdkRegion *invalidate_region; - GdkWindowImplWin32 *impl; - GdkWindowObject *obj; - GdkRectangle src_rect, dest_rect; - HRGN hrgn; - RECT clipRect, destRect; - - obj = GDK_WINDOW_OBJECT (window); - impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); - - /* Move the current invalid region */ - if (obj->update_area) - gdk_region_offset (obj->update_area, dx, dy); - - /* impl->position_info.clip_rect isn't meaningful for toplevels */ - if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD) - src_rect = impl->position_info.clip_rect; - else - { - src_rect.x = 0; - src_rect.y = 0; - src_rect.width = impl->width; - src_rect.height = impl->height; - } - - invalidate_region = gdk_region_rectangle (&src_rect); - - dest_rect = src_rect; - dest_rect.x += dx; - dest_rect.y += dy; - gdk_rectangle_intersect (&dest_rect, &src_rect, &dest_rect); - - if (dest_rect.width > 0 && dest_rect.height > 0) - { - GdkRegion *tmp_region; - - tmp_region = gdk_region_rectangle (&dest_rect); - gdk_region_subtract (invalidate_region, tmp_region); - gdk_region_destroy (tmp_region); - } - - /* no guffaw scroll on win32 */ - hrgn = _gdk_win32_gdkregion_to_hrgn(invalidate_region, 0, 0); - gdk_region_destroy (invalidate_region); - destRect.left = dest_rect.y; - destRect.top = dest_rect.x; - destRect.right = dest_rect.x + dest_rect.width; - destRect.bottom = dest_rect.y + dest_rect.height; - clipRect.left = src_rect.y; - clipRect.top = src_rect.x; - clipRect.right = src_rect.x + src_rect.width; - clipRect.bottom = src_rect.y + src_rect.height; - - g_print ("ScrollWindowEx(%d, %d, ...) - if you see this work, remove trace;)\n", dx, dy); - API_CALL(ScrollWindowEx, (GDK_WINDOW_HWND (window), - dx, dy, /* in: scroll offsets */ - NULL, /* in: scroll rect, NULL == entire client area */ - &clipRect, /* in: restrict to */ - hrgn, /* in: update region */ - NULL, /* out: update rect */ - SW_INVALIDATE)); - API_CALL(DeleteObject, (hrgn)); -} +static void tmp_unset_bg (GdkWindow *window); +static void tmp_reset_bg (GdkWindow *window); void _gdk_window_move_resize_child (GdkWindow *window, @@ -242,443 +61,189 @@ _gdk_window_move_resize_child (GdkWindow *window, { GdkWindowImplWin32 *impl; GdkWindowObject *obj; - GdkWin32PositionInfo new_info; - GdkWindowParentPos parent_pos; - GList *tmp_list; - gint d_xoffset, d_yoffset; - gint dx, dy; gboolean is_move; gboolean is_resize; - GdkRegion *new_clip_region; - + g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); obj = GDK_WINDOW_OBJECT (window); impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); + + is_move = (x - obj->x != 0) && (y - obj->y != 0); + is_resize = obj->width != width && obj->height != height; GDK_NOTE (MISC, g_print ("_gdk_window_move_resize_child: %s@%+d%+d %dx%d@%+d%+d\n", _gdk_win32_drawable_description (window), - obj->x, obj->y, - width, height, x, y)); + obj->x, obj->y, width, height, x, y)); - dx = x - obj->x; - dy = y - obj->y; + if (width > 65535 || height > 65535) + { + g_warning ("Native children wider or taller than 65535 pixels are not supported."); - is_move = dx != 0 || dy != 0; - is_resize = impl->width != width || impl->height != height; - - if (!is_move && !is_resize) - { - GDK_NOTE (MISC, g_print ("... neither move or resize\n")); - return; - } - - GDK_NOTE (MISC, g_print ("... %s%s\n", - is_move ? "is_move " : "", - is_resize ? "is_resize" : "")); + if (width > 65535) + width = 65535; + if (height > 65535) + height = 65535; + } obj->x = x; obj->y = y; - impl->width = width; - impl->height = height; - - gdk_window_compute_parent_pos (impl, &parent_pos); - gdk_window_compute_position (impl, &parent_pos, &new_info); + obj->width = width; + obj->height = height; - new_clip_region = - gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect); - - parent_pos.x += obj->x; - parent_pos.y += obj->y; - parent_pos.win32_x += new_info.x; - parent_pos.win32_y += new_info.y; - parent_pos.clip_rect = new_info.clip_rect; - - d_xoffset = new_info.x_offset - impl->position_info.x_offset; - d_yoffset = new_info.y_offset - impl->position_info.y_offset; + _gdk_win32_window_tmp_unset_parent_bg (window); + _gdk_win32_window_tmp_unset_bg (window, TRUE); - if (d_xoffset != 0 || d_yoffset != 0) - { - GDK_NOTE (MISC, g_print ("... d_offset=%+d%+d\n", d_xoffset, d_yoffset)); - - if (!ScrollWindowEx (GDK_WINDOW_HWND (window), - -d_xoffset, -d_yoffset, /* in: scroll offsets */ - NULL, /* in: scroll rect, NULL == entire client area */ - NULL, /* in: restrict to */ - NULL, /* in: update region */ - NULL, /* out: update rect */ - SW_SCROLLCHILDREN)) - WIN32_API_FAILED ("ScrollWindowEx"); - - if (dx != d_xoffset || dy != d_yoffset || is_resize) - { - GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%d,%d," - "NOACTIVATE|NOZORDER%s%s)\n", - GDK_WINDOW_HWND (window), - new_info.x, new_info.y, - new_info.width, new_info.height, - (is_move ? "" : "|NOMOVE"), - (is_resize ? "" : "|NOSIZE"))); - - API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL, - new_info.x, new_info.y, - new_info.width, new_info.height, - SWP_NOACTIVATE | SWP_NOZORDER | - (is_move ? 0 : SWP_NOMOVE) | - (is_resize ? 0 : SWP_NOSIZE))); - } - - if (impl->position_info.no_bg) - gdk_window_tmp_reset_bg (window); - - if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj)) - { - GDK_NOTE (MISC, g_print ("... ShowWindow(%p, SW_SHOWNA)\n", - GDK_WINDOW_HWND (window))); - ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNA); - } - - impl->position_info = new_info; - - tmp_list = obj->children; - while (tmp_list) - { - gdk_window_postmove (tmp_list->data, &parent_pos, FALSE); - tmp_list = tmp_list->next; - } - } - else - { - if (impl->position_info.mapped && !new_info.mapped) - { - GDK_NOTE (MISC, g_print ("... ShowWindow(%p, SW_HIDE)\n", - GDK_WINDOW_HWND (window))); - ShowWindow (GDK_WINDOW_HWND (window), SW_HIDE); - } - - GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%d,%d," - "NOACTIVATE|NOZORDER%s%s)\n", - GDK_WINDOW_HWND (window), - new_info.x, new_info.y, - new_info.width, new_info.height, - (is_move ? "" : "|NOMOVE"), - (is_resize ? "" : "|NOSIZE"))); - - API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL, - new_info.x, new_info.y, - new_info.width, new_info.height, - SWP_NOACTIVATE | SWP_NOZORDER | - (is_move ? 0 : SWP_NOMOVE) | - (is_resize ? 0 : SWP_NOSIZE))); - - tmp_list = obj->children; - while (tmp_list) - { - gdk_window_postmove (tmp_list->data, &parent_pos, FALSE); - tmp_list = tmp_list->next; - } - - if (impl->position_info.no_bg) - gdk_window_tmp_reset_bg (window); - - if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj)) - { - GDK_NOTE (MISC, g_print ("... ShowWindow(%p, SW_SHOWNA)\n", - GDK_WINDOW_HWND (window))); - ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNA); - } - - impl->position_info = new_info; - } - if (new_clip_region) - gdk_window_post_scroll (window, new_clip_region); + GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%d,%d," + "NOACTIVATE|NOZORDER%s%s)\n", + GDK_WINDOW_HWND (window), + obj->x + obj->parent->abs_x, obj->y + obj->parent->abs_y, + width, height, + (is_move ? "" : "|NOMOVE"), + (is_resize ? "" : "|NOSIZE"))); + + API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL, + obj->x + obj->parent->abs_x, obj->y + obj->parent->abs_y, + width, height, + SWP_NOACTIVATE | SWP_NOZORDER | + (is_move ? 0 : SWP_NOMOVE) | + (is_resize ? 0 : SWP_NOSIZE))); + + //_gdk_win32_window_tmp_reset_parent_bg (window); + _gdk_win32_window_tmp_reset_bg (window, TRUE); } -static void -gdk_window_compute_position (GdkWindowImplWin32 *window, - GdkWindowParentPos *parent_pos, - GdkWin32PositionInfo *info) +void +_gdk_window_process_expose (GdkWindow *window, + GdkRegion *invalidate_region) { - GdkWindowObject *wrapper; - int parent_x_offset; - int parent_y_offset; - - g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (window)); - - wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_WIN32 (window)->wrapper); - - info->big = FALSE; + GdkWindowImplWin32 *impl; + //GdkRegion *clip_region; + impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); - if (window->width <= SIZE_LIMIT) - { - info->width = window->width; - info->x = parent_pos->x + wrapper->x - parent_pos->win32_x; - } - else - { - info->big = TRUE; - info->width = SIZE_LIMIT; - if (parent_pos->x + wrapper->x < -(SIZE_LIMIT/2)) - { - if (parent_pos->x + wrapper->x + window->width < (SIZE_LIMIT/2)) - info->x = parent_pos->x + wrapper->x + window->width - info->width - parent_pos->win32_x; - else - info->x = -(SIZE_LIMIT/2) - parent_pos->win32_x; - } - else - info->x = parent_pos->x + wrapper->x - parent_pos->win32_x; - } + GDK_NOTE (EVENTS, g_print ("_gdk_window_process_expose: %p %s\n", + GDK_WINDOW_HWND (window), + _gdk_win32_gdkregion_to_string (invalidate_region))); - if (window->height <= SIZE_LIMIT) - { - info->height = window->height; - info->y = parent_pos->y + wrapper->y - parent_pos->win32_y; - } + if (!gdk_region_empty (invalidate_region)) + _gdk_window_invalidate_for_expose (window, invalidate_region); else - { - info->big = TRUE; - info->height = SIZE_LIMIT; - if (parent_pos->y + wrapper->y < -(SIZE_LIMIT/2)) - { - if (parent_pos->y + wrapper->y + window->height < (SIZE_LIMIT/2)) - info->y = parent_pos->y + wrapper->y + window->height - info->height - parent_pos->win32_y; - else - info->y = -(SIZE_LIMIT/2) - parent_pos->win32_y; - } - else - info->y = parent_pos->y + wrapper->y - parent_pos->win32_y; - } - - parent_x_offset = parent_pos->win32_x - parent_pos->x; - parent_y_offset = parent_pos->win32_y - parent_pos->y; + g_print ("process_expose(), empty region\n"); - info->x_offset = parent_x_offset + info->x - wrapper->x; - info->y_offset = parent_y_offset + info->y - wrapper->y; - - /* We don't considering the clipping of toplevel windows and their immediate children - * by their parents, and simply always map those windows. - */ - if (parent_pos->clip_rect.width == G_MAXINT) - info->mapped = TRUE; - /* Check if the window would wrap around into the visible space in either direction */ - else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 || - info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 || - info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 || - info->y + info->height + parent_y_offset > parent_pos->clip_rect.y + 65536) - info->mapped = FALSE; - else - info->mapped = TRUE; - - info->no_bg = FALSE; - - if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD) - { - info->clip_rect.x = wrapper->x; - info->clip_rect.y = wrapper->y; - info->clip_rect.width = window->width; - info->clip_rect.height = window->height; - - gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect); - - info->clip_rect.x -= wrapper->x; - info->clip_rect.y -= wrapper->y; - } - else - { - info->clip_rect.x = 0; - info->clip_rect.y = 0; - info->clip_rect.width = G_MAXINT; - info->clip_rect.height = G_MAXINT; - } + //gdk_region_destroy (invalidate_region); } -static void -gdk_window_compute_parent_pos (GdkWindowImplWin32 *window, - GdkWindowParentPos *parent_pos) +void +_gdk_win32_window_tmp_unset_bg (GdkWindow *window, + gboolean recurse) { - GdkWindowObject *wrapper; - GdkWindowObject *parent; - GdkRectangle tmp_clip; - - int clip_xoffset = 0; - int clip_yoffset = 0; + GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (window)); + g_return_if_fail (GDK_IS_WINDOW (window)); - wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_WIN32 (window)->wrapper); - - parent_pos->x = 0; - parent_pos->y = 0; - parent_pos->win32_x = 0; - parent_pos->win32_y = 0; - - /* We take a simple approach here and simply consider toplevel - * windows not to clip their children on the right/bottom, since the - * size of toplevel windows is not directly under our - * control. Clipping only really matters when scrolling and - * generally we aren't going to be moving the immediate child of a - * toplevel beyond the bounds of that toplevel. - * - * We could go ahead and recompute the clips of toplevel windows and - * their descendents when we receive size notification, but it would - * probably not be an improvement in most cases. - */ - parent_pos->clip_rect.x = 0; - parent_pos->clip_rect.y = 0; - parent_pos->clip_rect.width = G_MAXINT; - parent_pos->clip_rect.height = G_MAXINT; + private = (GdkWindowObject *)window; - parent = (GdkWindowObject *)wrapper->parent; - while (parent && parent->window_type == GDK_WINDOW_CHILD) - { - GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (parent->impl); - - tmp_clip.x = - clip_xoffset; - tmp_clip.y = - clip_yoffset; - tmp_clip.width = impl->width; - tmp_clip.height = impl->height; + if (private->input_only || private->destroyed || + (private->window_type != GDK_WINDOW_ROOT && + !GDK_WINDOW_IS_MAPPED (window))) + return; - gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect); + if (_gdk_window_has_impl (window) && + GDK_WINDOW_IS_WIN32 (window) && + private->window_type != GDK_WINDOW_ROOT && + private->window_type != GDK_WINDOW_FOREIGN) + tmp_unset_bg (window); - parent_pos->x += parent->x; - parent_pos->y += parent->y; - parent_pos->win32_x += impl->position_info.x; - parent_pos->win32_y += impl->position_info.y; - - clip_xoffset += parent->x; - clip_yoffset += parent->y; + if (recurse) + { + GList *l; - parent = (GdkWindowObject *)parent->parent; + for (l = private->children; l != NULL; l = l->next) + _gdk_win32_window_tmp_unset_bg (l->data, TRUE); } } static void -gdk_window_postmove (GdkWindow *window, - GdkWindowParentPos *parent_pos, - gboolean anti_scroll) +tmp_unset_bg (GdkWindow *window) { GdkWindowImplWin32 *impl; GdkWindowObject *obj; - GdkWin32PositionInfo new_info; - GList *tmp_list; - gint d_xoffset, d_yoffset; - GdkWindowParentPos this_pos; - GdkRegion *new_clip_region; obj = (GdkWindowObject *) window; impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); - - gdk_window_compute_position (impl, parent_pos, &new_info); - - new_clip_region = - gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect); - this_pos.x = parent_pos->x + obj->x; - this_pos.y = parent_pos->y + obj->y; - this_pos.win32_x = parent_pos->win32_x + new_info.x; - this_pos.win32_y = parent_pos->win32_y + new_info.y; - this_pos.clip_rect = new_info.clip_rect; + impl->no_bg = TRUE; - if (impl->position_info.mapped && !new_info.mapped) - ShowWindow (GDK_WINDOW_HWND (window), SW_HIDE); - - d_xoffset = new_info.x_offset - impl->position_info.x_offset; - d_yoffset = new_info.y_offset - impl->position_info.y_offset; - - if (anti_scroll || (anti_scroll = d_xoffset != 0 || d_yoffset != 0)) + /* + * The X version sets background = None to avoid updateing for a moment. + * Not sure if this could really emulate it. + */ + if (obj->bg_pixmap != GDK_NO_BG) { - GDK_NOTE (MISC, g_print ("gdk_window_postmove: %s@%+d%+d\n" - "... SetWindowPos(%p,NULL,%d,%d,0,0," - "NOREDRAW|NOZORDER|NOACTIVATE|NOSIZE)\n", - _gdk_win32_drawable_description (window), - obj->x, obj->y, - GDK_WINDOW_HWND (window), - new_info.x, new_info.y)); - - API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL, - new_info.x, new_info.y, - 0, 0, - SWP_NOREDRAW | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE)); - } - - if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj)) - ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNA); - - if (impl->position_info.no_bg) - gdk_window_tmp_reset_bg (window); - - impl->position_info = new_info; + ///* handled in WM_ERASEBKGRND proceesing */; - if (new_clip_region) - gdk_window_post_scroll (window, new_clip_region); - - tmp_list = obj->children; - while (tmp_list) - { - gdk_window_postmove (tmp_list->data, &this_pos, anti_scroll); - tmp_list = tmp_list->next; + //HDC hdc = GetDC (GDK_WINDOW_HWND (window)); + //erase_background (window, hdc); } } -gboolean -_gdk_windowing_window_queue_antiexpose (GdkWindow *window, - GdkRegion *area) +static void +tmp_reset_bg (GdkWindow *window) { - HRGN hrgn = _gdk_win32_gdkregion_to_hrgn (area, 0, 0); - - GDK_NOTE (EVENTS, g_print ("_gdk_windowing_window_queue_antiexpose: ValidateRgn %p %s\n", - GDK_WINDOW_HWND (window), - _gdk_win32_gdkregion_to_string (area))); - - ValidateRgn (GDK_WINDOW_HWND (window), hrgn); + GdkWindowObject *obj; + GdkWindowImplWin32 *impl; - DeleteObject (hrgn); + obj = GDK_WINDOW_OBJECT (window); + impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); - return FALSE; + impl->no_bg = FALSE; } void -_gdk_window_process_expose (GdkWindow *window, - GdkRegion *invalidate_region) +_gdk_win32_window_tmp_unset_parent_bg (GdkWindow *window) { - GdkWindowImplWin32 *impl; - GdkRegion *clip_region; - impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); - - GDK_NOTE (EVENTS, g_print ("_gdk_window_process_expose: %p %s\n", - GDK_WINDOW_HWND (window), - _gdk_win32_gdkregion_to_string (invalidate_region))); - clip_region = gdk_region_rectangle (&impl->position_info.clip_rect); - gdk_region_intersect (invalidate_region, clip_region); + GdkWindowObject *private = (GdkWindowObject*)window; - if (!gdk_region_empty (invalidate_region)) - gdk_window_invalidate_region (window, invalidate_region, FALSE); - - gdk_region_destroy (clip_region); + if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + return; + + window = _gdk_window_get_impl_window ((GdkWindow*)private->parent); + _gdk_win32_window_tmp_unset_bg (window, FALSE); } -static void -gdk_window_tmp_unset_bg (GdkWindow *window) +void +_gdk_win32_window_tmp_reset_bg (GdkWindow *window, + gboolean recurse) { - GdkWindowImplWin32 *impl; - GdkWindowObject *obj; + GdkWindowObject *private; - obj = (GdkWindowObject *) window; - impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); + g_return_if_fail (GDK_IS_WINDOW (window)); - impl->position_info.no_bg = TRUE; + if (private->input_only || private->destroyed || + (private->window_type != GDK_WINDOW_ROOT && !GDK_WINDOW_IS_MAPPED (window))) + return; - /* - * The X version sets background = None to avoid updateing for a moment. - * Not sure if this could really emulate it. - */ - if (obj->bg_pixmap != GDK_NO_BG) - /* handled in WM_ERASEBKGRND proceesing */; + if (_gdk_window_has_impl (window) && + GDK_WINDOW_IS_WIN32 (window) && + private->window_type != GDK_WINDOW_ROOT && + private->window_type != GDK_WINDOW_FOREIGN) + { + tmp_reset_bg (window); + } + + if (recurse) + { + GList *l; + + for (l = private->children; l != NULL; l = l->next) + _gdk_win32_window_tmp_reset_bg (l->data, TRUE); + } } -static void -gdk_window_tmp_reset_bg (GdkWindow *window) +/* +void +_gdk_win32_window_tmp_reset_bg (GdkWindow *window) { GdkWindowImplWin32 *impl; GdkWindowObject *obj; @@ -686,9 +251,11 @@ gdk_window_tmp_reset_bg (GdkWindow *window) obj = (GdkWindowObject *) window; impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); - impl->position_info.no_bg = FALSE; + impl->no_bg = FALSE; } +*/ +#if 0 static GdkRegion * gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, @@ -723,11 +290,14 @@ gdk_window_clip_changed (GdkWindow *window, gdk_region_destroy (new_clip_region); new_clip_region = NULL; } + gdk_region_destroy (old_clip_region); return new_clip_region; } +#endif +#if 0 static void gdk_window_post_scroll (GdkWindow *window, GdkRegion *new_clip_region) @@ -737,5 +307,8 @@ gdk_window_post_scroll (GdkWindow *window, _gdk_win32_gdkregion_to_string (new_clip_region))); gdk_window_invalidate_region (window, new_clip_region, FALSE); + g_print ("gdk_window_post_scroll\n"); gdk_region_destroy (new_clip_region); } + +#endif diff --git a/gdk/win32/gdkinput-win32.c b/gdk/win32/gdkinput-win32.c index d844a5832..1510c24b4 100644 --- a/gdk/win32/gdkinput-win32.c +++ b/gdk/win32/gdkinput-win32.c @@ -647,7 +647,8 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, gdouble *x_out, gdouble *y_out) { - GdkWindowImplWin32 *impl, *root_impl; + GdkWindowImplWin32 *root_impl; + GdkWindowObject *window_object; int i; int x_axis = 0; @@ -656,33 +657,31 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, double device_width, device_height; double x_offset, y_offset, x_scale, y_scale; - impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (input_window->window)->impl); + window_object = GDK_WINDOW_OBJECT (input_window); for (i=0; iinfo.num_axes; i++) { switch (gdkdev->info.axes[i].use) - { - case GDK_AXIS_X: - x_axis = i; - break; - case GDK_AXIS_Y: - y_axis = i; - break; - default: - break; - } + { + case GDK_AXIS_X: + x_axis = i; + break; + case GDK_AXIS_Y: + y_axis = i; + break; + default: + break; + } } - device_width = gdkdev->axes[x_axis].max_value - - gdkdev->axes[x_axis].min_value; - device_height = gdkdev->axes[y_axis].max_value - - gdkdev->axes[y_axis].min_value; + device_width = gdkdev->axes[x_axis].max_value - gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - gdkdev->axes[y_axis].min_value; if (gdkdev->info.mode == GDK_MODE_SCREEN) { root_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl); - x_scale = root_impl->width / device_width; - y_scale = root_impl->height / device_height; + x_scale = GDK_WINDOW_OBJECT (_gdk_root)->width / device_width; + y_scale = GDK_WINDOW_OBJECT (_gdk_root)->height / device_height; x_offset = - input_window->root_x; y_offset = - input_window->root_y; @@ -692,50 +691,48 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / (device_width*gdkdev->axes[x_axis].resolution); - if (device_aspect * impl->width >= impl->height) - { - /* device taller than window */ - x_scale = impl->width / device_width; - y_scale = (x_scale * gdkdev->axes[x_axis].resolution) - / gdkdev->axes[y_axis].resolution; - - x_offset = 0; - y_offset = -(device_height * y_scale - - impl->height)/2; - } + if (device_aspect * window_object->width >= window_object->height) + { + /* device taller than window */ + x_scale = window_object->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - window_object->height) / 2; + } else - { - /* window taller than device */ - y_scale = impl->height / device_height; - x_scale = (y_scale * gdkdev->axes[y_axis].resolution) - / gdkdev->axes[x_axis].resolution; + { + /* window taller than device */ + y_scale = window_object->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; - y_offset = 0; - x_offset = - (device_width * x_scale - impl->width)/2; - } + y_offset = 0; + x_offset = - (device_width * x_scale - window_object->width) / 2; + } } - for (i=0; iinfo.num_axes; i++) + for (i = 0; i < gdkdev->info.num_axes; i++) { switch (gdkdev->info.axes[i].use) - { - case GDK_AXIS_X: - axis_out[i] = x_offset + x_scale*axis_data[x_axis]; - if (x_out) - *x_out = axis_out[i]; - break; - case GDK_AXIS_Y: - axis_out[i] = y_offset + y_scale*axis_data[y_axis]; - if (y_out) - *y_out = axis_out[i]; - break; - default: - axis_out[i] = - (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) + - gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) / - (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value); - break; - } + { + case GDK_AXIS_X: + axis_out[i] = x_offset + x_scale * axis_data[x_axis]; + if (x_out) + *x_out = axis_out[i]; + break; + case GDK_AXIS_Y: + axis_out[i] = y_offset + y_scale * axis_data[y_axis]; + if (y_out) + *y_out = axis_out[i]; + break; + default: + axis_out[i] = + (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) + + gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) / + (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value); + break; + } } } diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c index 4d6e0de64..d31771d0f 100644 --- a/gdk/win32/gdkmain-win32.c +++ b/gdk/win32/gdkmain-win32.c @@ -149,13 +149,15 @@ gdk_get_use_xshm (void) gint gdk_screen_get_width (GdkScreen *screen) { - return GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl)->width; + //return GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl)->width; + return GDK_WINDOW_OBJECT (_gdk_root)->width; } gint gdk_screen_get_height (GdkScreen *screen) { - return GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl)->height; + //return GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl)->height; + return GDK_WINDOW_OBJECT (_gdk_root)->height; } gint gdk_screen_get_width_mm (GdkScreen *screen) @@ -1163,6 +1165,8 @@ _gdk_win32_drawable_description (GdkDrawable *d) { gint width, height, depth; + g_return_val_if_fail (GDK_IS_DRAWABLE (d), NULL); + gdk_drawable_get_size (d, &width, &height); depth = gdk_drawable_get_depth (d); diff --git a/gdk/win32/gdkpixmap-win32.c b/gdk/win32/gdkpixmap-win32.c index 911fa9ddb..860bff20c 100644 --- a/gdk/win32/gdkpixmap-win32.c +++ b/gdk/win32/gdkpixmap-win32.c @@ -130,7 +130,7 @@ gdk_pixmap_impl_win32_get_size (GdkDrawable *drawable, } GdkPixmap* -gdk_pixmap_new (GdkDrawable *drawable, +_gdk_pixmap_new (GdkDrawable *drawable, gint width, gint height, gint depth) @@ -348,7 +348,7 @@ static const unsigned char mirror[256] = { }; GdkPixmap * -gdk_bitmap_create_from_data (GdkDrawable *drawable, +_gdk_bitmap_create_from_data (GdkDrawable *drawable, const gchar *data, gint width, gint height) @@ -388,7 +388,7 @@ gdk_bitmap_create_from_data (GdkDrawable *drawable, } GdkPixmap* -gdk_pixmap_create_from_data (GdkDrawable *drawable, +_gdk_pixmap_create_from_data (GdkDrawable *drawable, const gchar *data, gint width, gint height, diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 810a28a7a..84284a86a 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -112,6 +112,11 @@ #define GDK_IS_GC_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_GC_WIN32)) #define GDK_GC_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_GC_WIN32, GdkGCWin32Class)) +//#define GDK_WINDOW_SCREEN(win) (_gdk_screen) +GdkScreen *GDK_WINDOW_SCREEN(GObject *win); + +#define GDK_WINDOW_IS_WIN32(win) (GDK_IS_WINDOW_IMPL_WIN32 (((GdkWindowObject *)win)->impl)) + typedef struct _GdkColormapPrivateWin32 GdkColormapPrivateWin32; typedef struct _GdkCursorPrivate GdkCursorPrivate; typedef struct _GdkWin32SingleFont GdkWin32SingleFont; @@ -455,7 +460,7 @@ HICON _gdk_win32_pixbuf_to_hcursor (GdkPixbuf *pixbuf, gboolean _gdk_win32_pixbuf_to_hicon_supports_alpha (void); /* Initialization */ -void _gdk_windowing_window_init (void); +void _gdk_windowing_window_init (GdkScreen *screen); void _gdk_root_window_size_init (void); void _gdk_monitor_init(void); void _gdk_visual_init (void); diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index 340cc2a06..d220da187 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -2,7 +2,7 @@ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1998-2004 Tor Lillqvist * Copyright (C) 2001-2004 Hans Breuer - * Copyright (C) 2007 Cody Russell + * Copyright (C) 2007-2009 Cody Russell * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -39,10 +39,6 @@ static GdkColormap* gdk_window_impl_win32_get_colormap (GdkDrawable *drawable); static void gdk_window_impl_win32_set_colormap (GdkDrawable *drawable, GdkColormap *cmap); -static void gdk_window_impl_win32_get_size (GdkDrawable *drawable, - gint *width, - gint *height); -static GdkRegion* gdk_window_impl_win32_get_visible_region (GdkDrawable *drawable); static void gdk_window_impl_win32_init (GdkWindowImplWin32 *window); static void gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass); static void gdk_window_impl_win32_finalize (GObject *object); @@ -56,10 +52,17 @@ static gboolean _gdk_window_get_functions (GdkWindow *window, #define WINDOW_IS_TOPLEVEL(window) \ (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ - GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN) + GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \ + GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN) static void gdk_window_impl_iface_init (GdkWindowImplIface *iface); +GdkScreen * +GDK_WINDOW_SCREEN (GObject *win) +{ + return _gdk_screen; +} + GType _gdk_window_impl_win32_get_type (void) { @@ -107,8 +110,6 @@ _gdk_window_impl_get_type (void) static void gdk_window_impl_win32_init (GdkWindowImplWin32 *impl) { - impl->width = 1; - impl->height = 1; impl->toplevel_window_type = -1; impl->hcursor = NULL; impl->hicon_big = NULL; @@ -134,11 +135,6 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass) drawable_class->set_colormap = gdk_window_impl_win32_set_colormap; drawable_class->get_colormap = gdk_window_impl_win32_get_colormap; - drawable_class->get_size = gdk_window_impl_win32_get_size; - - /* Visible and clip regions are the same */ - drawable_class->get_clip_region = gdk_window_impl_win32_get_visible_region; - drawable_class->get_visible_region = gdk_window_impl_win32_get_visible_region; } static void @@ -236,53 +232,28 @@ gdk_window_impl_win32_set_colormap (GdkDrawable *drawable, } } -static void -gdk_window_impl_win32_get_size (GdkDrawable *drawable, - gint *width, - gint *height) -{ - g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (drawable)); - - if (width) - *width = GDK_WINDOW_IMPL_WIN32 (drawable)->width; - if (height) - *height = GDK_WINDOW_IMPL_WIN32 (drawable)->height; -} - -static GdkRegion* -gdk_window_impl_win32_get_visible_region (GdkDrawable *drawable) -{ - GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (drawable); - GdkRectangle result_rect; - - result_rect.x = 0; - result_rect.y = 0; - result_rect.width = impl->width; - result_rect.height = impl->height; - - gdk_rectangle_intersect (&result_rect, &impl->position_info.clip_rect, &result_rect); - - return gdk_region_rectangle (&result_rect); -} - void _gdk_root_window_size_init (void) { - GdkWindowImplWin32 *impl; + GdkWindowObject *window_object; + //GdkWindowImplWin32 *impl; GdkRectangle rect; int i; - impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) _gdk_root)->impl); + window_object = GDK_WINDOW_OBJECT (_gdk_root); + //impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) _gdk_root)->impl); rect = _gdk_monitors[0].rect; for (i = 1; i < _gdk_num_monitors; i++) gdk_rectangle_union (&rect, &_gdk_monitors[i].rect, &rect); - impl->width = rect.width; - impl->height = rect.height; + window_object->width = rect.width; + window_object->height = rect.height; + //impl->width = rect.width; + //impl->height = rect.height; } void -_gdk_windowing_window_init (void) +_gdk_windowing_window_init (GdkScreen *screen) { GdkWindowObject *private; GdkDrawableImplWin32 *draw_impl; @@ -292,6 +263,8 @@ _gdk_windowing_window_init (void) _gdk_root = g_object_new (GDK_TYPE_WINDOW, NULL); private = (GdkWindowObject *)_gdk_root; private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); + private->impl_window = private; + draw_impl = GDK_DRAWABLE_IMPL_WIN32 (private->impl); draw_impl->handle = GetDesktopWindow (); @@ -303,8 +276,13 @@ _gdk_windowing_window_init (void) private->depth = gdk_visual_get_system ()->depth; _gdk_root_window_size_init (); - - _gdk_window_init_position (GDK_WINDOW (private)); + + private->x = 0; + private->y = 0; + private->abs_x = 0; + private->abs_y = 0; + private->width = GetSystemMetrics (SM_CXSCREEN); + private->height = GetSystemMetrics (SM_CYSCREEN); gdk_win32_handle_table_insert ((HANDLE *) &draw_impl->handle, _gdk_root); @@ -486,102 +464,64 @@ RegisterGdkClass (GdkWindowType wtype, GdkWindowTypeHint wtype_hint) return klass; } -static GdkWindow* -gdk_window_new_internal (GdkWindow *parent, - GdkWindowAttr *attributes, - gint attributes_mask, - gboolean from_set_skip_taskbar_hint) +void +_gdk_window_impl_new (GdkWindow *window, + GdkWindow *real_parent, + GdkScreen *screen, + GdkVisual *visual, + GdkEventMask event_mask, + GdkWindowAttr *attributes, + gint attributes_mask) { HWND hwndNew; HANDLE hparent; ATOM klass = 0; DWORD dwStyle = 0, dwExStyle; RECT rect; - GdkWindow *window; GdkWindow *orig_parent; GdkWindowObject *private; GdkWindowImplWin32 *impl; GdkDrawableImplWin32 *draw_impl; - GdkVisual *visual; const gchar *title; wchar_t *wtitle; gint window_width, window_height; gint offset_x = 0, offset_y = 0; - g_return_val_if_fail (attributes != NULL, NULL); + private = (GdkWindowObject *)window; - if (!parent) - parent = _gdk_root; - - g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL); - - orig_parent = parent; + orig_parent = real_parent; GDK_NOTE (MISC, g_print ("gdk_window_new_internal: %s\n", - (attributes->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" : - (attributes->window_type == GDK_WINDOW_CHILD ? "CHILD" : - (attributes->window_type == GDK_WINDOW_DIALOG ? "DIALOG" : + (attributes->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" : + (attributes->window_type == GDK_WINDOW_CHILD ? "CHILD" : + (attributes->window_type == GDK_WINDOW_DIALOG ? "DIALOG" : (attributes->window_type == GDK_WINDOW_TEMP ? "TEMP" : - "???")))))); + "???")))))); - if (GDK_WINDOW_DESTROYED (parent)) - return NULL; - - hparent = GDK_WINDOW_HWND (parent); + hparent = GDK_WINDOW_HWND (real_parent); - window = g_object_new (GDK_TYPE_WINDOW, NULL); - private = (GdkWindowObject *)window; - private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); - impl = GDK_WINDOW_IMPL_WIN32 (private->impl); - draw_impl = GDK_DRAWABLE_IMPL_WIN32 (private->impl); + impl = g_object_new (_gdk_window_impl_get_type (), NULL); + private->impl = (GdkDrawable *)impl; + draw_impl = GDK_DRAWABLE_IMPL_WIN32 (impl); draw_impl->wrapper = GDK_DRAWABLE (window); - /* Windows with a foreign parent are treated as if they are children - * of the root window, except for actual creation. - */ - if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN) - parent = _gdk_root; - - private->parent = (GdkWindowObject *)parent; + // XXX: xattributes_mask = 0 - private->accept_focus = TRUE; - private->focus_on_map = TRUE; - - if (attributes_mask & GDK_WA_X) - private->x = attributes->x; - else - private->x = 0; - - if (attributes_mask & GDK_WA_Y) - private->y = attributes->y; - else if (attributes_mask & GDK_WA_X) - private->y = 100; /* ??? We must put it somewhere... */ - else - private->y = 0; - +#if 0 if (attributes_mask & GDK_WA_VISUAL) visual = attributes->visual; else visual = gdk_visual_get_system (); +#endif +#if 0 impl->width = (attributes->width > 1) ? (attributes->width) : (1); impl->height = (attributes->height > 1) ? (attributes->height) : (1); +#endif impl->extension_events_selected = FALSE; - if (attributes->wclass == GDK_INPUT_ONLY) - { - /* Backwards compatiblity - we've always ignored - * attributes->window_type for input-only windows - * before - */ - if (parent == _gdk_root) - private->window_type = GDK_WINDOW_TEMP; - else - private->window_type = GDK_WINDOW_CHILD; - } - else - private->window_type = attributes->window_type; + // XXX ? if (attributes->wclass == GDK_INPUT_OUTPUT) { dwExStyle = 0; @@ -592,8 +532,8 @@ gdk_window_new_internal (GdkWindow *parent, if (attributes_mask & GDK_WA_COLORMAP) { draw_impl->colormap = attributes->colormap; - g_object_ref (attributes->colormap); - } + g_object_ref (attributes->colormap); + } else { draw_impl->colormap = gdk_screen_get_system_colormap (_gdk_screen); @@ -618,10 +558,9 @@ gdk_window_new_internal (GdkWindow *parent, { case GDK_WINDOW_TOPLEVEL: case GDK_WINDOW_DIALOG: - if (parent != _gdk_root) + if (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT) { - g_warning (G_STRLOC ": Toplevel windows must be created as children\n" - "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN"); + /* The common code warns for this case. */ hparent = GetDesktopWindow (); } /* Children of foreign windows aren't toplevel windows */ @@ -641,34 +580,32 @@ gdk_window_new_internal (GdkWindow *parent, } break; + /* case GDK_WINDOW_CHILD: dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; break; + */ case GDK_WINDOW_TEMP: /* A temp window is not necessarily a top level window */ - dwStyle = (_gdk_root == parent ? WS_POPUP : WS_CHILDWINDOW); + dwStyle = (_gdk_root == real_parent ? WS_POPUP : WS_CHILDWINDOW); dwStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS; dwExStyle |= WS_EX_TOOLWINDOW; offset_x = _gdk_offset_x; offset_y = _gdk_offset_y; break; - case GDK_WINDOW_ROOT: - g_error ("cannot make windows of type GDK_WINDOW_ROOT"); - break; - default: g_assert_not_reached (); } - _gdk_window_init_position (GDK_WINDOW (private)); + //_gdk_window_init_position (GDK_WINDOW (private)); if (private->window_type != GDK_WINDOW_CHILD) { rect.left = rect.top = 0; - rect.right = impl->position_info.width; - rect.bottom = impl->position_info.height; + rect.right = private->width; + rect.bottom = private->height; AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); @@ -677,8 +614,8 @@ gdk_window_new_internal (GdkWindow *parent, } else { - window_width = impl->position_info.width; - window_height = impl->position_info.height; + window_width = private->width; + window_height = private->height; } if (attributes_mask & GDK_WA_TITLE) @@ -706,17 +643,17 @@ gdk_window_new_internal (GdkWindow *parent, wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL); hwndNew = CreateWindowExW (dwExStyle, - MAKEINTRESOURCEW (klass), - wtitle, - dwStyle, - ((attributes_mask & GDK_WA_X) ? - impl->position_info.x - offset_x : CW_USEDEFAULT), - impl->position_info.y - offset_y, - window_width, window_height, - hparent, - NULL, - _gdk_app_hmodule, - window); + MAKEINTRESOURCEW (klass), + wtitle, + dwStyle, + ((attributes_mask & GDK_WA_X) ? + private->x - offset_x : CW_USEDEFAULT), + private->y - offset_y, + window_width, window_height, + hparent, + NULL, + _gdk_app_hmodule, + window); if (GDK_WINDOW_HWND (window) != hwndNew) { g_warning ("gdk_window_new: gdk_event_translate::WM_CREATE (%p, %p) HWND mismatch.", @@ -746,8 +683,8 @@ gdk_window_new_internal (GdkWindow *parent, title, window_width, window_height, ((attributes_mask & GDK_WA_X) ? - impl->position_info.x - offset_x: CW_USEDEFAULT), - impl->position_info.y - offset_y, + private->x - offset_x: CW_USEDEFAULT), + private->y - offset_y, hparent, GDK_WINDOW_HWND (window))); @@ -760,25 +697,15 @@ gdk_window_new_internal (GdkWindow *parent, { WIN32_API_FAILED ("CreateWindowExW"); g_object_unref (window); - return NULL; + return; } - if (!from_set_skip_taskbar_hint && private->window_type == GDK_WINDOW_TEMP) - gdk_window_set_skip_taskbar_hint (window, TRUE); +// if (!from_set_skip_taskbar_hint && private->window_type == GDK_WINDOW_TEMP) +// gdk_window_set_skip_taskbar_hint (window, TRUE); gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? (attributes->cursor) : NULL)); - - return window; -} - -GdkWindow* -_gdk_window_new (GdkWindow *parent, - GdkWindowAttr *attributes, - gint attributes_mask) -{ - return gdk_window_new_internal (parent, attributes, attributes_mask, FALSE); } GdkWindow * @@ -819,8 +746,8 @@ gdk_window_foreign_new_for_display (GdkDisplay *display, ScreenToClient (parent, &point); private->x = point.x; private->y = point.y; - impl->width = rect.right - rect.left; - impl->height = rect.bottom - rect.top; + private->width = rect.right - rect.left; + private->height = rect.bottom - rect.top; private->window_type = GDK_WINDOW_FOREIGN; private->destroyed = FALSE; private->event_mask = GDK_ALL_EVENTS_MASK; /* XXX */ @@ -836,7 +763,7 @@ gdk_window_foreign_new_for_display (GdkDisplay *display, private->depth = gdk_visual_get_system ()->depth; - _gdk_window_init_position (GDK_WINDOW (private)); + //_gdk_window_init_position (GDK_WINDOW (private)); g_object_ref (window); gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window); @@ -956,11 +883,17 @@ get_outer_rect (GdkWindow *window, } static void -adjust_for_gravity_hints (GdkWindowImplWin32 *impl, - RECT *outer_rect, - gint *x, - gint *y) +adjust_for_gravity_hints (GdkWindow *window, + RECT *outer_rect, + gint *x, + gint *y) { + GdkWindowObject *obj; + GdkWindowImplWin32 *impl; + + obj = GDK_WINDOW_OBJECT (window); + impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); + if (impl->hint_flags & GDK_HINT_WIN_GRAVITY) { gint orig_x = *x, orig_y = *y; @@ -971,14 +904,14 @@ adjust_for_gravity_hints (GdkWindowImplWin32 *impl, case GDK_GRAVITY_CENTER: case GDK_GRAVITY_SOUTH: *x -= (outer_rect->right - outer_rect->left) / 2; - *x += impl->width / 2; + *x += obj->width / 2; break; case GDK_GRAVITY_SOUTH_EAST: case GDK_GRAVITY_EAST: case GDK_GRAVITY_NORTH_EAST: *x -= outer_rect->right - outer_rect->left; - *x += impl->width; + *x += obj->width; break; case GDK_GRAVITY_STATIC: @@ -995,14 +928,14 @@ adjust_for_gravity_hints (GdkWindowImplWin32 *impl, case GDK_GRAVITY_CENTER: case GDK_GRAVITY_EAST: *y -= (outer_rect->bottom - outer_rect->top) / 2; - *y += impl->height / 2; + *y += obj->height / 2; break; case GDK_GRAVITY_SOUTH_WEST: case GDK_GRAVITY_SOUTH: case GDK_GRAVITY_SOUTH_EAST: *y -= outer_rect->bottom - outer_rect->top; - *y += impl->height; + *y += obj->height; break; case GDK_GRAVITY_STATIC: @@ -1039,7 +972,7 @@ show_window_internal (GdkWindow *window, GDK_NOTE (MISC, g_print ("show_window_internal: %p: %s%s%s\n", GDK_WINDOW_HWND (window), _gdk_win32_window_state_to_string (private->state), - (raise ? " raise" : ""), + //(raise ? " raise" : ""), (deiconify ? " deiconify" : ""))); /* If asked to show (not deiconify) an withdrawn and iconified @@ -1100,10 +1033,10 @@ show_window_internal (GdkWindow *window, { UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE; - if (!raise) - flags |= SWP_NOZORDER; + if (!raise) + flags |= SWP_NOZORDER; if (!raise || GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP || !focus_on_map) - flags |= SWP_NOACTIVATE; + flags |= SWP_NOACTIVATE; SetWindowPos (GDK_WINDOW_HWND (window), top, 0, 0, 0, 0, flags); @@ -1169,9 +1102,9 @@ show_window_internal (GdkWindow *window, } static void -gdk_win32_window_show (GdkWindow *window, gboolean raise) +gdk_win32_window_show (GdkWindow *window) { - show_window_internal (window, raise, FALSE); + show_window_internal (window, FALSE, FALSE); } static void @@ -1251,15 +1184,15 @@ gdk_win32_window_move (GdkWindow *window, */ if (GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) != GetDesktopWindow ()) { - _gdk_window_move_resize_child (window, x, y, impl->width, impl->height); + _gdk_window_move_resize_child (window, x, y, private->width, private->height); } else { RECT outer_rect; - get_outer_rect (window, impl->width, impl->height, &outer_rect); + get_outer_rect (window, private->width, private->height, &outer_rect); - adjust_for_gravity_hints (impl, &outer_rect, &x, &y); + adjust_for_gravity_hints (window, &outer_rect, &x, &y); GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,0,0," "NOACTIVATE|NOSIZE|NOZORDER)\n", @@ -1329,7 +1262,7 @@ gdk_win32_window_move_resize_internal (GdkWindow *window, gint width, gint height) { - GdkWindowObject *private = (GdkWindowObject*) window; + GdkWindowObject *private; GdkWindowImplWin32 *impl; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -1342,6 +1275,7 @@ gdk_win32_window_move_resize_internal (GdkWindow *window, if (height < 1) height = 1; + private = GDK_WINDOW_OBJECT (window); impl = GDK_WINDOW_IMPL_WIN32 (private->impl); if (private->state & GDK_WINDOW_STATE_FULLSCREEN) @@ -1361,7 +1295,7 @@ gdk_win32_window_move_resize_internal (GdkWindow *window, get_outer_rect (window, width, height, &outer_rect); - adjust_for_gravity_hints (impl, &outer_rect, &x, &y); + adjust_for_gravity_hints (window, &outer_rect, &x, &y); GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%ld,%ld," "NOACTIVATE|NOZORDER)\n", @@ -1452,7 +1386,7 @@ gdk_win32_window_reparent (GdkWindow *window, GDK_WINDOW_HWND (new_parent))); API_CALL (MoveWindow, (GDK_WINDOW_HWND (window), - x, y, impl->width, impl->height, TRUE)); + x, y, window_private->width, window_private->height, TRUE)); /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like * the root window @@ -1492,7 +1426,7 @@ gdk_win32_window_reparent (GdkWindow *window, g_list_remove (old_parent_private->children, window); parent_private->children = g_list_prepend (parent_private->children, window); - _gdk_window_init_position (GDK_WINDOW (window_private)); + //_gdk_window_init_position (GDK_WINDOW (window_private)); return FALSE; } @@ -1501,6 +1435,7 @@ static void erase_background (GdkWindow *window, HDC hdc) { +#if 0 HDC bgdc = NULL; HBRUSH hbr = NULL; HPALETTE holdpal = NULL; @@ -1513,7 +1448,7 @@ erase_background (GdkWindow *window, if (((GdkWindowObject *) window)->input_only || ((GdkWindowObject *) window)->bg_pixmap == GDK_NO_BG || - GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->position_info.no_bg) + GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->no_bg) { return; } @@ -1549,7 +1484,7 @@ erase_background (GdkWindow *window, window = GDK_WINDOW (((GdkWindowObject *) window)->parent); } - if (GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->position_info.no_bg) + if (GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->no_bg) { /* Improves scolling effect, e.g. main buttons of testgtk */ return; @@ -1628,6 +1563,7 @@ erase_background (GdkWindow *window, DeleteDC (bgdc); } } +#endif } static void @@ -1639,8 +1575,10 @@ gdk_win32_window_clear_area (GdkWindow *window, gboolean send_expose) { GdkWindowImplWin32 *impl; + GdkWindowObject *obj; - impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); + obj = GDK_WINDOW_OBJECT (window); + impl = GDK_WINDOW_IMPL_WIN32 (obj->impl); if (!GDK_WINDOW_DESTROYED (window)) { @@ -1652,9 +1590,9 @@ gdk_win32_window_clear_area (GdkWindow *window, if (!send_expose) { if (width == 0) - width = impl->width - x; + width = obj->width - x; if (height == 0) - height = impl->height - y; + height = obj->height - y; GDK_NOTE (MISC, g_print ("_gdk_windowing_window_clear_area: %p: " "%dx%d@%+d%+d\n", GDK_WINDOW_HWND (window), @@ -2118,6 +2056,7 @@ static void gdk_win32_window_set_background (GdkWindow *window, const GdkColor *color) { +#if 0 GdkWindowObject *private = (GdkWindowObject *)window; GDK_NOTE (MISC, g_print ("gdk_window_set_background: %p: %s\n", @@ -2133,42 +2072,23 @@ gdk_win32_window_set_background (GdkWindow *window, g_object_unref (private->bg_pixmap); private->bg_pixmap = NULL; } +#endif } static void gdk_win32_window_set_back_pixmap (GdkWindow *window, - GdkPixmap *pixmap, - gint parent_relative) + GdkPixmap *pixmap) { GdkWindowObject *private = (GdkWindowObject *)window; - 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) + if (pixmap == GDK_PARENT_RELATIVE_BG || pixmap == GDK_NO_BG) { - private->bg_pixmap = GDK_PARENT_RELATIVE_BG; - GDK_NOTE (MISC, g_print (G_STRLOC ": setting background pixmap to parent_relative\n")); - } - else - { - if (pixmap) - { - g_object_ref (pixmap); - private->bg_pixmap = pixmap; - } - else - { - private->bg_pixmap = GDK_NO_BG; - } + private->bg_pixmap = pixmap; } } @@ -2376,14 +2296,21 @@ gdk_win32_window_get_origin (GdkWindow *window, return return_val; } -gboolean -gdk_window_get_deskrelative_origin (GdkWindow *window, - gint *x, - gint *y) +static gboolean +gdk_win32_window_get_deskrelative_origin (GdkWindow *window, + gint *x, + gint *y) { return gdk_window_get_origin (window, x, y); } +static void +gdk_win32_window_restack_under (GdkWindow *window, + GList *native_siblings) +{ + // ### TODO +} + void gdk_window_get_root_origin (GdkWindow *window, gint *x, @@ -2545,7 +2472,8 @@ gdk_display_warp_pointer (GdkDisplay *display, GdkWindow* _gdk_windowing_window_at_pointer (GdkDisplay *display, gint *win_x, - gint *win_y) + gint *win_y, + GdkModifierType *mask) { GdkWindow *window; POINT point, pointc; @@ -2665,27 +2593,6 @@ gdk_win32_window_shape_combine_mask (GdkWindow *window, } } -void -gdk_window_input_shape_combine_mask (GdkWindow *window, - GdkBitmap *mask, - gint x, - gint y) -{ - g_return_if_fail (GDK_IS_WINDOW (window)); - - /* Not yet implemented - * - * I don't think there is anything in the Win32 API to directly - * support this. And anyway, as we don't currently support RGBA - * windows, it doesn't really matter. - * - * When we do support RGBA, input shape functionality could probably - * be implemented by saving the input shape region in the per-window - * private data, and then simply checking before generating an input - * event whether the event's coordinates are inside the region. - */ -} - void gdk_window_set_override_redirect (GdkWindow *window, gboolean override_redirect) @@ -3195,6 +3102,7 @@ gdk_win32_window_merge_child_shapes (GdkWindow *window) gdk_propagate_shapes (GDK_WINDOW_HWND (window), TRUE); } +#if 0 void gdk_window_set_child_input_shapes (GdkWindow *window) { @@ -3204,7 +3112,9 @@ gdk_window_set_child_input_shapes (GdkWindow *window) * gdk_window_input_shape_combine_mask(). */ } +#endif +#if 0 void gdk_window_merge_child_input_shapes (GdkWindow *window) { @@ -3214,6 +3124,7 @@ gdk_window_merge_child_input_shapes (GdkWindow *window) * gdk_window_input_shape_combine_mask(). */ } +#endif static gboolean gdk_win32_window_set_static_gravities (GdkWindow *window, @@ -3651,7 +3562,7 @@ gdk_window_set_skip_taskbar_hint (GdkWindow *window, gboolean skips_taskbar) { static GdkWindow *owner = NULL; - GdkWindowAttr wa; + //GdkWindowAttr wa; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -3664,14 +3575,16 @@ gdk_window_set_skip_taskbar_hint (GdkWindow *window, if (skips_taskbar) { +#if 0 if (owner == NULL) - { - wa.window_type = GDK_WINDOW_TEMP; - wa.wclass = GDK_INPUT_OUTPUT; - wa.width = wa.height = 1; - wa.event_mask = 0; - owner = gdk_window_new_internal (NULL, &wa, 0, TRUE); - } + { + wa.window_type = GDK_WINDOW_TEMP; + wa.wclass = GDK_INPUT_OUTPUT; + wa.width = wa.height = 1; + wa.event_mask = 0; + owner = gdk_window_new_internal (NULL, &wa, 0, TRUE); + } +#endif SetWindowLongPtr (GDK_WINDOW_HWND (window), GWLP_HWNDPARENT, (LONG_PTR) GDK_WINDOW_HWND (owner)); @@ -3771,19 +3684,6 @@ gdk_win32_window_shape_combine_region (GdkWindow *window, } } -void -gdk_window_input_shape_combine_region (GdkWindow *window, - const GdkRegion *shape_region, - gint offset_x, - gint offset_y) -{ - g_return_if_fail (GDK_IS_WINDOW (window)); - - /* Not yet implemented. See comment in - * gdk_window_input_shape_combine_mask(). - */ -} - GdkWindow * gdk_window_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid) @@ -3849,11 +3749,88 @@ gdk_window_set_opacity (GdkWindow *window, } } +GdkRegion * +_gdk_windowing_get_shape_for_mask (GdkBitmap *mask) +{ + // XXX: TODO + return NULL; +} + void _gdk_windowing_window_set_composited (GdkWindow *window, gboolean composited) { } +GdkRegion * +_gdk_windowing_window_get_shape (GdkWindow *window) +{ + return NULL; +} + +GdkRegion * +_gdk_windowing_window_get_input_shape (GdkWindow *window) +{ + return NULL; +} + +static void +_gdk_win32_window_destroy (GdkWindow *window, + gboolean recursing, + gboolean foreign_destroy) +{ +} + +static gboolean +_gdk_win32_window_queue_antiexpose (GdkWindow *window, + GdkRegion *area) +{ + HRGN hrgn = _gdk_win32_gdkregion_to_hrgn (area, 0, 0); + + GDK_NOTE (EVENTS, g_print ("_gdk_windowing_window_queue_antiexpose: ValidateRgn %p %s\n", + GDK_WINDOW_HWND (window), + _gdk_win32_gdkregion_to_string (area))); + + ValidateRgn (GDK_WINDOW_HWND (window), hrgn); + + DeleteObject (hrgn); + + return FALSE; +} + +static void +_gdk_win32_window_queue_translation (GdkWindow *window, + GdkRegion *area, + gint dx, + gint dy) +{ + g_print ("queue_translation\n"); +} + +static void +gdk_win32_input_shape_combine_region (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y) +{ +} + +void +_gdk_windowing_window_process_updates_recurse (GdkWindow *window, + GdkRegion *region) +{ + _gdk_window_process_updates_recurse (window, region); +} + +void +_gdk_windowing_before_process_all_updates (void) +{ +} + +void +_gdk_windowing_after_process_all_updates (void) +{ +} + static void gdk_window_impl_iface_init (GdkWindowImplIface *iface) { @@ -3862,22 +3839,21 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface) iface->withdraw = gdk_win32_window_withdraw; iface->set_events = gdk_win32_window_set_events; iface->get_events = gdk_win32_window_get_events; - iface->clear_area = gdk_win32_window_clear_area; iface->raise = gdk_win32_window_raise; iface->lower = gdk_win32_window_lower; + iface->restack_under = gdk_win32_window_restack_under; iface->move_resize = gdk_win32_window_move_resize; - iface->scroll = _gdk_win32_window_scroll; - iface->move_region = _gdk_win32_window_move_region; iface->set_background = gdk_win32_window_set_background; iface->set_back_pixmap = gdk_win32_window_set_back_pixmap; iface->reparent = gdk_win32_window_reparent; iface->set_cursor = gdk_win32_window_set_cursor; iface->get_geometry = gdk_win32_window_get_geometry; iface->get_origin = gdk_win32_window_get_origin; - iface->shape_combine_mask = gdk_win32_window_shape_combine_mask; iface->shape_combine_region = gdk_win32_window_shape_combine_region; - iface->set_child_shapes = gdk_win32_window_set_child_shapes; - iface->merge_child_shapes = gdk_win32_window_merge_child_shapes; + iface->input_shape_combine_region = gdk_win32_input_shape_combine_region; + iface->get_deskrelative_origin = gdk_win32_window_get_deskrelative_origin; iface->set_static_gravities = gdk_win32_window_set_static_gravities; - iface->get_offsets = _gdk_win32_windowing_window_get_offsets; + iface->queue_antiexpose = _gdk_win32_window_queue_antiexpose; + iface->queue_translation = _gdk_win32_window_queue_translation; + iface->destroy = _gdk_win32_window_destroy; } diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h index fbc461c94..f488e59fa 100644 --- a/gdk/win32/gdkwindow-win32.h +++ b/gdk/win32/gdkwindow-win32.h @@ -33,6 +33,7 @@ G_BEGIN_DECLS typedef struct _GdkWin32PositionInfo GdkWin32PositionInfo; +#if 0 struct _GdkWin32PositionInfo { gint x; @@ -49,6 +50,7 @@ struct _GdkWin32PositionInfo */ GdkRectangle clip_rect; /* visible rectangle of window */ }; +#endif /* Window implementation for Win32 @@ -68,11 +70,6 @@ struct _GdkWindowImplWin32 { GdkDrawableImplWin32 parent_instance; - gint width; - gint height; - - GdkWin32PositionInfo position_info; - gint8 toplevel_window_type; HCURSOR hcursor; @@ -91,6 +88,8 @@ struct _GdkWindowImplWin32 GSList *transient_children; gint num_transients; gboolean changing_state; + + guint no_bg : 1; }; struct _GdkWindowImplWin32Class @@ -100,6 +99,14 @@ struct _GdkWindowImplWin32Class GType _gdk_window_impl_win32_get_type (void); +void _gdk_win32_window_tmp_unset_bg (GdkWindow *window, + gboolean recurse); +void _gdk_win32_window_tmp_reset_bg (GdkWindow *window, + gboolean recurse); + +void _gdk_win32_window_tmp_unset_parent_bg (GdkWindow *window); +void _gdk_win32_window_tmp_reset_parent_bg (GdkWindow *window); + G_END_DECLS #endif /* __GDK_WINDOW_WIN32_H__ */ diff --git a/gdk/x11/gdkasync.c b/gdk/x11/gdkasync.c index 3f90d5944..e412ed2f7 100644 --- a/gdk/x11/gdkasync.c +++ b/gdk/x11/gdkasync.c @@ -57,6 +57,7 @@ typedef struct _ChildInfoState ChildInfoState; typedef struct _ListChildrenState ListChildrenState; typedef struct _SendEventState SendEventState; typedef struct _SetInputFocusState SetInputFocusState; +typedef struct _RoundtripState RoundtripState; typedef enum { CHILD_INFO_GET_PROPERTY, @@ -112,6 +113,16 @@ struct _SetInputFocusState gulong get_input_focus_req; }; +struct _RoundtripState +{ + Display *dpy; + _XAsyncHandler async; + gulong get_input_focus_req; + GdkDisplay *display; + GdkRoundTripCallback callback; + gpointer data; +}; + static gboolean callback_idle (gpointer data) { @@ -743,5 +754,92 @@ _gdk_x11_get_window_child_info (GdkDisplay *display, return !state.have_error; } +static gboolean +roundtrip_callback_idle (gpointer data) +{ + RoundtripState *state = (RoundtripState *)data; + + state->callback (state->display, state->data, state->get_input_focus_req); + + g_free (state); + + return FALSE; +} + +static Bool +roundtrip_handler (Display *dpy, + xReply *rep, + char *buf, + int len, + XPointer data) +{ + RoundtripState *state = (RoundtripState *)data; + + if (dpy->last_request_read == state->get_input_focus_req) + { + xGetInputFocusReply replbuf; + xGetInputFocusReply *repl; + + if (rep->generic.type != X_Error) + { + /* Actually does nothing, since there are no additional bytes + * to read, but maintain good form. + */ + repl = (xGetInputFocusReply *) + _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len, + (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2, + True); + } + + + if (state->callback) + gdk_threads_add_idle (roundtrip_callback_idle, state); + + DeqAsyncHandler(state->dpy, &state->async); + + return (rep->generic.type != X_Error); + } + + return False; +} + +void +_gdk_x11_roundtrip_async (GdkDisplay *display, + GdkRoundTripCallback callback, + gpointer data) +{ + Display *dpy; + RoundtripState *state; + + dpy = GDK_DISPLAY_XDISPLAY (display); + + state = g_new (RoundtripState, 1); + + state->display = display; + state->dpy = dpy; + state->callback = callback; + state->data = data; + + LockDisplay(dpy); + + state->async.next = dpy->async_handlers; + state->async.handler = roundtrip_handler; + state->async.data = (XPointer) state; + dpy->async_handlers = &state->async; + + /* + * XSync (dpy, 0) + */ + { + xReq *req; + + GetEmptyReq(GetInputFocus, req); + state->get_input_focus_req = dpy->request; + } + + UnlockDisplay(dpy); + SyncHandle(); +} + #define __GDK_ASYNC_C__ #include "gdkaliasdef.c" diff --git a/gdk/x11/gdkasync.h b/gdk/x11/gdkasync.h index 91897f380..44aa18c47 100644 --- a/gdk/x11/gdkasync.h +++ b/gdk/x11/gdkasync.h @@ -31,6 +31,9 @@ typedef struct _GdkChildInfoX11 GdkChildInfoX11; typedef void (*GdkSendXEventCallback) (Window window, gboolean success, gpointer data); +typedef void (*GdkRoundTripCallback) (GdkDisplay *display, + gpointer data, + gulong serial); struct _GdkChildInfoX11 { @@ -63,6 +66,10 @@ gboolean _gdk_x11_get_window_child_info (GdkDisplay *display, GdkChildInfoX11 **children, guint *nchildren); +void _gdk_x11_roundtrip_async (GdkDisplay *display, + GdkRoundTripCallback callback, + gpointer data); + G_END_DECLS #endif /* __GDK_ASYNC_H__ */ diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index c51a4956f..a517404e1 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -31,6 +31,7 @@ #include #include "gdkx.h" +#include "gdkasync.h" #include "gdkdisplay.h" #include "gdkdisplay-x11.h" #include "gdkscreen.h" @@ -444,6 +445,13 @@ process_internal_connection (GIOChannel *gioc, return TRUE; } +gulong +_gdk_windowing_window_get_next_serial (GdkDisplay *display) +{ + return NextRequest (GDK_DISPLAY_XDISPLAY (display)); +} + + static GdkInternalConnection * gdk_add_connection_handler (Display *display, guint fd) @@ -584,6 +592,20 @@ _gdk_x11_display_is_root_window (GdkDisplay *display, return FALSE; } +struct XPointerUngrabInfo { + GdkDisplay *display; + guint32 time; +}; + +static void +pointer_ungrab_callback (GdkDisplay *display, + gpointer data, + gulong serial) +{ + _gdk_display_pointer_grab_update (display, serial); +} + + #define XSERVER_TIME_IS_LATER(time1, time2) \ ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) || \ (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 )) \ @@ -600,43 +622,35 @@ _gdk_x11_display_is_root_window (GdkDisplay *display, */ void gdk_display_pointer_ungrab (GdkDisplay *display, - guint32 time) + guint32 time_) { Display *xdisplay; GdkDisplayX11 *display_x11; + GdkPointerGrabInfo *grab; + unsigned long serial; g_return_if_fail (GDK_IS_DISPLAY (display)); display_x11 = GDK_DISPLAY_X11 (display); xdisplay = GDK_DISPLAY_XDISPLAY (display); + + serial = NextRequest (xdisplay); - _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 || - display_x11->pointer_xgrab_time == GDK_CURRENT_TIME || - !XSERVER_TIME_IS_LATER (display_x11->pointer_xgrab_time, time)) - display_x11->pointer_xgrab_window = NULL; -} - -/** - * gdk_display_pointer_is_grabbed: - * @display: a #GdkDisplay - * - * Test if the pointer is grabbed. - * - * Returns: %TRUE if an active X pointer grab is in effect - * - * Since: 2.2 - */ -gboolean -gdk_display_pointer_is_grabbed (GdkDisplay *display) -{ - g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE); - - return (GDK_DISPLAY_X11 (display)->pointer_xgrab_window != NULL && - !GDK_DISPLAY_X11 (display)->pointer_xgrab_implicit); + grab = _gdk_display_get_last_pointer_grab (display); + if (grab && + (time_ == GDK_CURRENT_TIME || + grab->time == GDK_CURRENT_TIME || + !XSERVER_TIME_IS_LATER (grab->time, time_))) + { + grab->serial_end = serial; + _gdk_x11_roundtrip_async (display, + pointer_ungrab_callback, + NULL); + } } /** @@ -664,9 +678,9 @@ gdk_display_keyboard_ungrab (GdkDisplay *display, XFlush (xdisplay); if (time == GDK_CURRENT_TIME || - display_x11->keyboard_xgrab_time == GDK_CURRENT_TIME || - !XSERVER_TIME_IS_LATER (display_x11->keyboard_xgrab_time, time)) - display_x11->keyboard_xgrab_window = NULL; + display->keyboard_grab.time == GDK_CURRENT_TIME || + !XSERVER_TIME_IS_LATER (display->keyboard_grab.time, time)) + _gdk_display_unset_has_keyboard_grab (display, FALSE); } /** @@ -1335,7 +1349,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_X11 (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 0ade8f083..e92418d37 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -30,6 +30,7 @@ #include #include #include +#include #include /* For gdk_get_program_class() */ G_BEGIN_DECLS @@ -93,21 +94,6 @@ struct _GdkDisplayX11 * (grabs, properties etc.) Otherwise always TRUE. */ gboolean trusted_client; - /* Information about current pointer and keyboard grabs held by this - * client. If gdk_pointer_xgrab_window or gdk_keyboard_xgrab_window - * window is NULL, then the other associated fields are ignored - */ - GdkWindowObject *pointer_xgrab_window; - gulong pointer_xgrab_serial; - gboolean pointer_xgrab_owner_events; - gboolean pointer_xgrab_implicit; - guint32 pointer_xgrab_time; - - GdkWindowObject *keyboard_xgrab_window; - gulong keyboard_xgrab_serial; - gboolean keyboard_xgrab_owner_events; - guint32 keyboard_xgrab_time; - /* drag and drop information */ GdkDragContext *current_dest_drag; @@ -169,6 +155,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 82ef44226..118d793c7 100644 --- a/gdk/x11/gdkdnd-x11.c +++ b/gdk/x11/gdkdnd-x11.c @@ -2992,6 +2992,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_X11 (window), NULL); new_context = gdk_drag_context_new (); new_context->is_source = TRUE; @@ -3197,7 +3198,7 @@ gdk_drag_find_window_for_screen (GdkDragContext *context, window_cache = drag_context_find_window_cache (context, screen); dest = get_client_window_at_coords (window_cache, - drag_window ? + drag_window && GDK_WINDOW_IS_X11 (drag_window) ? GDK_DRAWABLE_XID (drag_window) : None, x_root, y_root); @@ -3267,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_X11 (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 a19c7a2e2..e6ea4f185 100644 --- a/gdk/x11/gdkdrawable-x11.c +++ b/gdk/x11/gdkdrawable-x11.c @@ -634,13 +634,50 @@ gdk_x11_draw_drawable (GdkDrawable *drawable, if (GDK_IS_DRAWABLE_IMPL_X11 (src)) src_impl = GDK_DRAWABLE_IMPL_X11 (src); + else if (GDK_IS_WINDOW (src)) + src_impl = GDK_DRAWABLE_IMPL_X11(((GdkWindowObject *)src)->impl); else - src_impl = NULL; + src_impl = GDK_DRAWABLE_IMPL_X11(((GdkPixmapObject *)src)->impl); + + if (GDK_IS_WINDOW_IMPL_X11 (impl) && + GDK_IS_PIXMAP_IMPL_X11 (src_impl)) + { + GdkPixmapImplX11 *src_pixmap = GDK_PIXMAP_IMPL_X11 (src_impl); + /* Work around an Xserver bug where non-visible areas from + * a pixmap to a window will clear the window background + * in destination areas that are supposed to be clipped out. + * This is a problem with client side windows as this means + * things may draw outside the virtual windows. This could + * also happen for window to window copies, but I don't + * think we generate any calls like that. + * + * See: + * http://lists.freedesktop.org/archives/xorg/2009-February/043318.html + */ + if (xsrc < 0) + { + width += xsrc; + xdest -= xsrc; + xsrc = 0; + } + + if (ysrc < 0) + { + height += ysrc; + ydest -= ysrc; + ysrc = 0; + } + + if (xsrc + width > src_pixmap->width) + width = src_pixmap->width - xsrc; + if (ysrc + height > src_pixmap->height) + height = src_pixmap->height - ysrc; + } if (src_depth == 1) { XCopyArea (GDK_SCREEN_XDISPLAY (impl->screen), - src_impl ? src_impl->xid : GDK_DRAWABLE_XID (src), + src_impl->xid, impl->xid, GDK_GC_GET_XGC (gc), xsrc, ysrc, @@ -650,7 +687,7 @@ gdk_x11_draw_drawable (GdkDrawable *drawable, else if (dest_depth != 0 && src_depth == dest_depth) { XCopyArea (GDK_SCREEN_XDISPLAY (impl->screen), - src_impl ? src_impl->xid : GDK_DRAWABLE_XID (src), + src_impl->xid, impl->xid, GDK_GC_GET_XGC (gc), xsrc, ysrc, @@ -870,7 +907,29 @@ gdk_x11_drawable_get_xid (GdkDrawable *drawable) GdkDrawable *impl; if (GDK_IS_WINDOW (drawable)) - impl = ((GdkPixmapObject *)drawable)->impl; + { + GdkWindow *window = (GdkWindow *)drawable; + + /* Try to ensure the window has a native window */ + if (!_gdk_window_has_impl (window)) + { + gdk_window_set_has_native (window, TRUE); + + /* We sync here to ensure the window is created in the Xserver when + * this function returns. This is required because the returned XID + * for this window must be valid immediately, even with another + * connection to the Xserver */ + gdk_display_sync (gdk_drawable_get_display (window)); + } + + if (!GDK_WINDOW_IS_X11 (window)) + { + g_warning (G_STRLOC " drawable is not a native X11 window"); + return None; + } + + impl = ((GdkWindowObject *)drawable)->impl; + } else if (GDK_IS_PIXMAP (drawable)) impl = ((GdkPixmapObject *)drawable)->impl; else @@ -1447,6 +1506,45 @@ gdk_x11_cairo_surface_destroy (void *data) impl->cairo_surface = NULL; } +void +_gdk_windowing_set_cairo_surface_size (cairo_surface_t *surface, + int width, + int height) +{ + cairo_xlib_surface_set_size (surface, width, height); +} + +cairo_surface_t * +_gdk_windowing_create_cairo_surface (GdkDrawable *drawable, + int width, + int height) +{ + GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable); + GdkVisual *visual; + + visual = gdk_drawable_get_visual (drawable); + if (visual) + return cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (impl->screen), + impl->xid, + GDK_VISUAL_XVISUAL (visual), + width, height); + else if (gdk_drawable_get_depth (drawable) == 1) + return cairo_xlib_surface_create_for_bitmap (GDK_SCREEN_XDISPLAY (impl->screen), + impl->xid, + GDK_SCREEN_XSCREEN (impl->screen), + width, height); + else + { + g_warning ("Using Cairo rendering requires the drawable argument to\n" + "have a specified colormap. All windows have a colormap,\n" + "however, pixmaps only have colormap by default if they\n" + "were created with a non-NULL window argument. Otherwise\n" + "a colormap must be set on them with gdk_drawable_set_colormap"); + return NULL; + } + +} + static cairo_surface_t * gdk_x11_ref_cairo_surface (GdkDrawable *drawable) { @@ -1458,35 +1556,15 @@ gdk_x11_ref_cairo_surface (GdkDrawable *drawable) if (!impl->cairo_surface) { - GdkVisual *visual = NULL; int width, height; - visual = gdk_drawable_get_visual (drawable); - gdk_drawable_get_size (drawable, &width, &height); - if (visual) - impl->cairo_surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (impl->screen), - impl->xid, - GDK_VISUAL_XVISUAL (visual), - width, height); - else if (gdk_drawable_get_depth (drawable) == 1) - impl->cairo_surface = cairo_xlib_surface_create_for_bitmap (GDK_SCREEN_XDISPLAY (impl->screen), - impl->xid, - GDK_SCREEN_XSCREEN (impl->screen), - width, height); - else - { - g_warning ("Using Cairo rendering requires the drawable argument to\n" - "have a specified colormap. All windows have a colormap,\n" - "however, pixmaps only have colormap by default if they\n" - "were created with a non-NULL window argument. Otherwise\n" - "a colormap must be set on them with gdk_drawable_set_colormap"); - return NULL; - } - - cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key, - drawable, gdk_x11_cairo_surface_destroy); + impl->cairo_surface = _gdk_windowing_create_cairo_surface (drawable, width, height); + + if (impl->cairo_surface) + cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key, + drawable, gdk_x11_cairo_surface_destroy); } else cairo_surface_reference (impl->cairo_surface); diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index 359471de9..8d3141a8e 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -313,7 +313,7 @@ gdk_event_get_graphics_expose (GdkWindow *window) GdkEvent *event; g_return_val_if_fail (window != NULL, NULL); - + XIfEvent (GDK_WINDOW_XDISPLAY (window), &xevent, graphics_expose_predicate, (XPointer) window); @@ -867,6 +867,24 @@ set_user_time (GdkWindow *window, gdk_event_get_time (event)); } +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 gboolean gdk_event_translate (GdkDisplay *display, GdkEvent *event, @@ -879,7 +897,6 @@ gdk_event_translate (GdkDisplay *display, GdkWindow *filter_window; GdkWindowImplX11 *window_impl = NULL; gboolean return_val; - gint xoffset, yoffset; GdkScreen *screen = NULL; GdkScreenX11 *screen_x11 = NULL; GdkToplevelX11 *toplevel = NULL; @@ -942,6 +959,24 @@ gdk_event_translate (GdkDisplay *display, if (window != NULL) { + /* Apply keyboard grabs to non-native windows */ + if (/* Is key event */ + (xevent->type == KeyPress || xevent->type == KeyRelease) && + /* And we have a grab */ + display->keyboard_grab.window != NULL && + ( + /* The window is not a descendant of the grabbed window */ + !is_parent_of ((GdkWindow *)display->keyboard_grab.window, window) || + /* Or owner event is false */ + !display->keyboard_grab.owner_events + ) + ) + { + /* Report key event against grab window */ + window = display->keyboard_grab.window;; + window_private = (GdkWindowObject *) window; + } + window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl); /* Move key events on focus window to the real toplevel, and @@ -1041,16 +1076,6 @@ gdk_event_translate (GdkDisplay *display, return_val = TRUE; - if (window) - { - _gdk_x11_window_get_offsets (window, &xoffset, &yoffset); - } - else - { - xoffset = 0; - yoffset = 0; - } - switch (xevent->type) { case KeyPress: @@ -1129,8 +1154,8 @@ gdk_event_translate (GdkDisplay *display, event->scroll.window = window; event->scroll.time = xevent->xbutton.time; - event->scroll.x = xevent->xbutton.x + xoffset; - event->scroll.y = xevent->xbutton.y + yoffset; + event->scroll.x = xevent->xbutton.x; + event->scroll.y = xevent->xbutton.y; event->scroll.x_root = (gfloat)xevent->xbutton.x_root; event->scroll.y_root = (gfloat)xevent->xbutton.y_root; event->scroll.state = (GdkModifierType) xevent->xbutton.state; @@ -1148,8 +1173,8 @@ gdk_event_translate (GdkDisplay *display, event->button.type = GDK_BUTTON_PRESS; event->button.window = window; event->button.time = xevent->xbutton.time; - event->button.x = xevent->xbutton.x + xoffset; - event->button.y = xevent->xbutton.y + yoffset; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; event->button.x_root = (gfloat)xevent->xbutton.x_root; event->button.y_root = (gfloat)xevent->xbutton.y_root; event->button.axes = NULL; @@ -1162,14 +1187,11 @@ gdk_event_translate (GdkDisplay *display, return_val = FALSE; break; } - - _gdk_event_button_generate (display, event); break; } set_user_time (window, event); - _gdk_xgrab_check_button_event (window, xevent); break; case ButtonRelease: @@ -1198,8 +1220,8 @@ gdk_event_translate (GdkDisplay *display, event->button.type = GDK_BUTTON_RELEASE; event->button.window = window; event->button.time = xevent->xbutton.time; - event->button.x = xevent->xbutton.x + xoffset; - event->button.y = xevent->xbutton.y + yoffset; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; event->button.x_root = (gfloat)xevent->xbutton.x_root; event->button.y_root = (gfloat)xevent->xbutton.y_root; event->button.axes = NULL; @@ -1208,12 +1230,8 @@ gdk_event_translate (GdkDisplay *display, event->button.device = display->core_pointer; if (!set_screen_from_root (display, event, xevent->xbutton.root)) - { - return_val = FALSE; - break; - } - - _gdk_xgrab_check_button_event (window, xevent); + return_val = FALSE; + break; case MotionNotify: @@ -1234,8 +1252,8 @@ gdk_event_translate (GdkDisplay *display, event->motion.type = GDK_MOTION_NOTIFY; event->motion.window = window; event->motion.time = xevent->xmotion.time; - event->motion.x = xevent->xmotion.x + xoffset; - event->motion.y = xevent->xmotion.y + yoffset; + event->motion.x = xevent->xmotion.x; + event->motion.y = xevent->xmotion.y; event->motion.x_root = (gfloat)xevent->xmotion.x_root; event->motion.y_root = (gfloat)xevent->xmotion.y_root; event->motion.axes = NULL; @@ -1304,8 +1322,8 @@ gdk_event_translate (GdkDisplay *display, event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; - event->crossing.x = xevent->xcrossing.x + xoffset; - event->crossing.y = xevent->xcrossing.y + yoffset; + event->crossing.x = xevent->xcrossing.x; + event->crossing.y = xevent->xcrossing.y; event->crossing.x_root = xevent->xcrossing.x_root; event->crossing.y_root = xevent->xcrossing.y_root; @@ -1399,8 +1417,8 @@ gdk_event_translate (GdkDisplay *display, event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; - event->crossing.x = xevent->xcrossing.x + xoffset; - event->crossing.y = xevent->xcrossing.y + yoffset; + event->crossing.x = xevent->xcrossing.x; + event->crossing.y = xevent->xcrossing.y; event->crossing.x_root = xevent->xcrossing.x_root; event->crossing.y_root = xevent->xcrossing.y_root; @@ -1596,8 +1614,8 @@ gdk_event_translate (GdkDisplay *display, { GdkRectangle expose_rect; - expose_rect.x = xevent->xexpose.x + xoffset; - expose_rect.y = xevent->xexpose.y + yoffset; + expose_rect.x = xevent->xexpose.x; + expose_rect.y = xevent->xexpose.y; expose_rect.width = xevent->xexpose.width; expose_rect.height = xevent->xexpose.height; @@ -1636,8 +1654,8 @@ gdk_event_translate (GdkDisplay *display, break; } - expose_rect.x = xevent->xgraphicsexpose.x + xoffset; - expose_rect.y = xevent->xgraphicsexpose.y + yoffset; + expose_rect.x = xevent->xgraphicsexpose.x; + expose_rect.y = xevent->xgraphicsexpose.y; expose_rect.width = xevent->xgraphicsexpose.width; expose_rect.height = xevent->xgraphicsexpose.height; @@ -1826,9 +1844,9 @@ gdk_event_translate (GdkDisplay *display, : "")); if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT) { - window_impl->width = xevent->xconfigure.width; - window_impl->height = xevent->xconfigure.height; - + window_private->width = xevent->xconfigure.width; + window_private->height = xevent->xconfigure.height; + _gdk_x11_drawable_update_size (window_private->impl); _gdk_x11_screen_size_changed (screen, xevent); } @@ -1847,7 +1865,7 @@ gdk_event_translate (GdkDisplay *display, } #endif - if (!window || + if (!window || xevent->xconfigure.event != xevent->xconfigure.window || GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD || GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT) @@ -1887,9 +1905,10 @@ gdk_event_translate (GdkDisplay *display, } window_private->x = event->configure.x; window_private->y = event->configure.y; - window_impl->width = xevent->xconfigure.width; - window_impl->height = xevent->xconfigure.height; + window_private->width = xevent->xconfigure.width; + window_private->height = xevent->xconfigure.height; + _gdk_window_update_size (window); _gdk_x11_drawable_update_size (window_private->impl); if (window_private->resize_count >= 1) @@ -2180,7 +2199,7 @@ gdk_event_translate (GdkDisplay *display, if (window) g_object_unref (window); - + return return_val; } @@ -2301,6 +2320,7 @@ _gdk_events_queue (GdkDisplay *display) if (gdk_event_translate (display, event, &xevent, FALSE)) { ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING; + _gdk_windowing_got_event (display, node, event, xevent.xany.serial); } else { diff --git a/gdk/x11/gdkgc-x11.c b/gdk/x11/gdkgc-x11.c index 8c3e34071..0a6869a21 100644 --- a/gdk/x11/gdkgc-x11.c +++ b/gdk/x11/gdkgc-x11.c @@ -608,7 +608,8 @@ gdk_x11_gc_values_to_xvalues (GdkGCValues *values, void _gdk_windowing_gc_set_clip_region (GdkGC *gc, - const GdkRegion *region) + const GdkRegion *region, + gboolean reset_origin) { GdkGCX11 *x11_gc = GDK_GC_X11 (gc); @@ -623,8 +624,11 @@ _gdk_windowing_gc_set_clip_region (GdkGC *gc, x11_gc->have_clip_region = region != NULL; - gc->clip_x_origin = 0; - gc->clip_y_origin = 0; + if (reset_origin) + { + gc->clip_x_origin = 0; + gc->clip_y_origin = 0; + } x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP; } diff --git a/gdk/x11/gdkgeometry-x11.c b/gdk/x11/gdkgeometry-x11.c index 9271f090d..6bd71c3b4 100644 --- a/gdk/x11/gdkgeometry-x11.c +++ b/gdk/x11/gdkgeometry-x11.c @@ -165,417 +165,6 @@ struct _GdkWindowQueueItem } u; }; -struct _GdkWindowParentPos -{ - gint x; - gint y; - gint x11_x; - gint x11_y; - GdkRectangle clip_rect; -}; - -static void gdk_window_compute_position (GdkWindowImplX11 *window, - GdkWindowParentPos *parent_pos, - GdkXPositionInfo *info); -static void gdk_window_compute_parent_pos (GdkWindowImplX11 *window, - GdkWindowParentPos *parent_pos); -static void gdk_window_premove (GdkWindow *window, - GdkWindowParentPos *parent_pos); -static void gdk_window_postmove (GdkWindow *window, - GdkWindowParentPos *parent_pos); -static void gdk_window_queue_translation (GdkWindow *window, - GdkRegion *area, - gint dx, - gint dy); -static void gdk_window_clip_changed (GdkWindow *window, - GdkRectangle *old_clip, - GdkRectangle *new_clip); - -void -_gdk_x11_window_get_offsets (GdkWindow *window, - gint *x_offset, - gint *y_offset) -{ - GdkWindowImplX11 *impl = - GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl); - - *x_offset = impl->position_info.x_offset; - *y_offset = impl->position_info.y_offset; -} - -void -_gdk_window_init_position (GdkWindow *window) -{ - GdkWindowParentPos parent_pos; - GdkWindowImplX11 *impl; - - g_return_if_fail (GDK_IS_WINDOW (window)); - - impl = - GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl); - - gdk_window_compute_parent_pos (impl, &parent_pos); - gdk_window_compute_position (impl, &parent_pos, &impl->position_info); -} - -static void -gdk_window_copy_area_scroll (GdkWindow *window, - GdkRectangle *dest_rect, - gint dx, - gint dy) -{ - GdkWindowObject *obj = GDK_WINDOW_OBJECT (window); - GList *l; - - if (dest_rect->width > 0 && dest_rect->height > 0) - { - GdkGC *gc; - - gc = _gdk_drawable_get_scratch_gc (window, TRUE); - - gdk_window_queue_translation (window, NULL, dx, dy); - - XCopyArea (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - GDK_WINDOW_XID (window), - gdk_x11_gc_get_xgc (gc), - dest_rect->x - dx, dest_rect->y - dy, - dest_rect->width, dest_rect->height, - dest_rect->x, dest_rect->y); - } - - for (l = obj->children; l; l = l->next) - { - GdkWindow *child = (GdkWindow*) l->data; - GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child); - - gdk_window_move (child, child_obj->x + dx, child_obj->y + dy); - } -} - -static void -compute_intermediate_position (GdkXPositionInfo *position_info, - GdkXPositionInfo *new_info, - gint d_xoffset, - gint d_yoffset, - GdkRectangle *new_position) -{ - gint new_x0, new_x1, new_y0, new_y1; - - /* Wrap d_xoffset, d_yoffset into [-32768,32767] range. For the - * purposes of subwindow movement, it doesn't matter if we are - * off by a factor of 65536, and if we don't do this range - * reduction, we'll end up with invalid widths. - */ - d_xoffset = (gint16)d_xoffset; - d_yoffset = (gint16)d_yoffset; - - if (d_xoffset < 0) - { - new_x0 = position_info->x + d_xoffset; - new_x1 = position_info->x + position_info->width; - } - else - { - new_x0 = position_info->x; - new_x1 = position_info->x + new_info->width + d_xoffset; - } - - new_position->x = new_x0; - new_position->width = new_x1 - new_x0; - - if (d_yoffset < 0) - { - new_y0 = position_info->y + d_yoffset; - new_y1 = position_info->y + position_info->height; - } - else - { - new_y0 = position_info->y; - new_y1 = position_info->y + new_info->height + d_yoffset; - } - - new_position->y = new_y0; - new_position->height = new_y1 - new_y0; -} - -static void -translate_pos (GdkWindowParentPos *dest, GdkWindowParentPos *src, - GdkWindowObject *obj, GdkXPositionInfo *pos_info, - gboolean set_clip) -{ - dest->x = src->x + obj->x; - dest->y = src->y + obj->y; - dest->x11_x = src->x11_x + pos_info->x; - dest->x11_y = src->x11_y + pos_info->y; - - if (set_clip) - dest->clip_rect = pos_info->clip_rect; -} - -static void -move (GdkWindow *window, GdkXPositionInfo *pos) -{ - XMoveWindow (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), pos->x, pos->y); -} - -static void -move_relative (GdkWindow *window, GdkRectangle *rect, - gint dx, gint dy) -{ - XMoveWindow (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - rect->x + dx, rect->y + dy); -} - -static void -move_resize (GdkWindow *window, GdkRectangle *pos) -{ - XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - pos->x, pos->y, pos->width, pos->height); -} - -static void -gdk_window_guffaw_scroll (GdkWindow *window, - gint dx, - gint dy) -{ - GdkWindowObject *obj = GDK_WINDOW_OBJECT (window); - GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl); - - gint d_xoffset = -dx; - gint d_yoffset = -dy; - GdkRectangle new_position; - GdkXPositionInfo new_info; - GdkWindowParentPos parent_pos; - GList *l; - - gdk_window_compute_parent_pos (impl, &parent_pos); - gdk_window_compute_position (impl, &parent_pos, &new_info); - - translate_pos (&parent_pos, &parent_pos, obj, &new_info, TRUE); - - _gdk_x11_window_tmp_unset_bg (window, FALSE);; - - if (dx > 0 || dy > 0) - gdk_window_queue_translation (window, NULL, MAX (dx, 0), MAX (dy, 0)); - - gdk_window_set_static_gravities (window, TRUE); - - compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset, - &new_position); - - move_resize (window, &new_position); - - for (l = obj->children; l; l = l->next) - { - GdkWindow *child = (GdkWindow*) l->data; - GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child); - - child_obj->x -= d_xoffset; - child_obj->y -= d_yoffset; - - gdk_window_premove (child, &parent_pos); - } - - move_relative (window, &new_position, -d_xoffset, -d_yoffset); - - if (dx < 0 || dy < 0) - gdk_window_queue_translation (window, NULL, MIN (dx, 0), MIN (dy, 0)); - - move_resize (window, (GdkRectangle *) &impl->position_info); - - if (impl->position_info.no_bg) - _gdk_x11_window_tmp_reset_bg (window, FALSE); - - impl->position_info = new_info; - - g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos); -} - -void -_gdk_x11_window_scroll (GdkWindow *window, - gint dx, - gint dy) -{ - gboolean can_guffaw_scroll = FALSE; - GdkRegion *invalidate_region; - GdkWindowImplX11 *impl; - GdkWindowObject *obj; - GdkRectangle src_rect, dest_rect; - - obj = GDK_WINDOW_OBJECT (window); - impl = GDK_WINDOW_IMPL_X11 (obj->impl); - - /* Move the current invalid region */ - if (obj->update_area) - gdk_region_offset (obj->update_area, dx, dy); - - /* impl->position_info.clip_rect isn't meaningful for toplevels */ - if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD) - src_rect = impl->position_info.clip_rect; - else - { - src_rect.x = 0; - src_rect.y = 0; - src_rect.width = impl->width; - src_rect.height = impl->height; - } - - invalidate_region = gdk_region_rectangle (&src_rect); - - dest_rect = src_rect; - dest_rect.x += dx; - dest_rect.y += dy; - gdk_rectangle_intersect (&dest_rect, &src_rect, &dest_rect); - - if (dest_rect.width > 0 && dest_rect.height > 0) - { - GdkRegion *tmp_region; - - tmp_region = gdk_region_rectangle (&dest_rect); - gdk_region_subtract (invalidate_region, tmp_region); - gdk_region_destroy (tmp_region); - } - - gdk_window_invalidate_region (window, invalidate_region, TRUE); - gdk_region_destroy (invalidate_region); - - /* We can guffaw scroll if we are a child window, and the parent - * does not extend beyond our edges. Otherwise, we use XCopyArea, then - * move any children later - */ - if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD) - { - GdkWindowImplX11 *parent_impl = GDK_WINDOW_IMPL_X11 (obj->parent->impl); - can_guffaw_scroll = ((dx == 0 || (obj->x <= 0 && obj->x + impl->width >= parent_impl->width)) && - (dy == 0 || (obj->y <= 0 && obj->y + impl->height >= parent_impl->height))); - } - - if (!obj->children || !can_guffaw_scroll) - gdk_window_copy_area_scroll (window, &dest_rect, dx, dy); - else - gdk_window_guffaw_scroll (window, dx, dy); -} - -void -_gdk_x11_window_move_region (GdkWindow *window, - const GdkRegion *region, - gint dx, - gint dy) -{ - GdkWindowImplX11 *impl; - GdkWindowObject *private; - GdkRegion *window_clip; - GdkRegion *src_region; - GdkRegion *brought_in; - GdkRegion *dest_region; - GdkRegion *moving_invalid_region; - GdkRectangle dest_extents; - GdkGC *gc; - - private = GDK_WINDOW_OBJECT (window); - impl = GDK_WINDOW_IMPL_X11 (private->impl); - - window_clip = gdk_region_rectangle (&impl->position_info.clip_rect); - - /* compute source regions */ - src_region = gdk_region_copy (region); - brought_in = gdk_region_copy (region); - gdk_region_intersect (src_region, window_clip); - - gdk_region_subtract (brought_in, src_region); - gdk_region_offset (brought_in, dx, dy); - - /* compute destination regions */ - dest_region = gdk_region_copy (src_region); - gdk_region_offset (dest_region, dx, dy); - gdk_region_intersect (dest_region, window_clip); - gdk_region_get_clipbox (dest_region, &dest_extents); - - gdk_region_destroy (window_clip); - - /* calculating moving part of current invalid area */ - moving_invalid_region = NULL; - if (private->update_area) - { - moving_invalid_region = gdk_region_copy (private->update_area); - gdk_region_intersect (moving_invalid_region, src_region); - gdk_region_offset (moving_invalid_region, dx, dy); - } - - /* invalidate all of the src region */ - gdk_window_invalidate_region (window, src_region, FALSE); - - /* un-invalidate destination region */ - if (private->update_area) - gdk_region_subtract (private->update_area, dest_region); - - /* invalidate moving parts of existing update area */ - if (moving_invalid_region) - { - gdk_window_invalidate_region (window, moving_invalid_region, FALSE); - gdk_region_destroy (moving_invalid_region); - } - - /* invalidate area brought in from off-screen */ - gdk_window_invalidate_region (window, brought_in, FALSE); - gdk_region_destroy (brought_in); - - /* Actually do the moving */ - gdk_window_queue_translation (window, src_region, dx, dy); - - gc = _gdk_drawable_get_scratch_gc (window, TRUE); - gdk_gc_set_clip_region (gc, dest_region); - - XCopyArea (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - GDK_WINDOW_XID (window), - GDK_GC_XGC (gc), - dest_extents.x - dx, dest_extents.y - dy, - dest_extents.width, dest_extents.height, - dest_extents.x, dest_extents.y); - - /* Unset clip region of cached GC */ - gdk_gc_set_clip_region (gc, NULL); - - gdk_region_destroy (src_region); - gdk_region_destroy (dest_region); -} - -static void -reset_backgrounds (GdkWindow *window) -{ - GdkWindowObject *obj = (GdkWindowObject *)window; - - _gdk_x11_window_tmp_reset_bg (window, FALSE); - - if (obj->parent) - _gdk_x11_window_tmp_reset_bg ((GdkWindow *)obj->parent, FALSE); -} - -static void -map_if_needed (GdkWindow *window, GdkXPositionInfo *pos_info) -{ - GdkWindowObject *obj = (GdkWindowObject *) window; - GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl); - - if (!impl->position_info.mapped && pos_info->mapped && GDK_WINDOW_IS_MAPPED (obj)) - XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window)); -} - -static void -unmap_if_needed (GdkWindow *window, GdkXPositionInfo *pos_info) -{ - GdkWindowObject *obj = (GdkWindowObject *) window; - GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl); - - if (impl->position_info.mapped && !pos_info->mapped) - XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window)); -} - void _gdk_window_move_resize_child (GdkWindow *window, gint x, @@ -585,15 +174,6 @@ _gdk_window_move_resize_child (GdkWindow *window, { GdkWindowImplX11 *impl; GdkWindowObject *obj; - GdkXPositionInfo new_info; - GdkWindowParentPos parent_pos; - - gint d_xoffset, d_yoffset; - gint dx, dy; - gboolean is_move; - gboolean is_resize; - - GdkRectangle old_pos; g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); @@ -601,325 +181,36 @@ _gdk_window_move_resize_child (GdkWindow *window, impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl); obj = GDK_WINDOW_OBJECT (window); - dx = x - obj->x; - dy = y - obj->y; - - is_move = dx != 0 || dy != 0; - is_resize = impl->width != width || impl->height != height; - - if (!is_move && !is_resize) - return; - - old_pos.x = obj->x; - old_pos.y = obj->y; - old_pos.width = impl->width; - old_pos.height = impl->height; - - obj->x = x; - obj->y = y; - impl->width = width; - impl->height = height; - - gdk_window_compute_parent_pos (impl, &parent_pos); - gdk_window_compute_position (impl, &parent_pos, &new_info); - - gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect); - - translate_pos (&parent_pos, &parent_pos, obj, &new_info, TRUE); - - d_xoffset = new_info.x_offset - impl->position_info.x_offset; - d_yoffset = new_info.y_offset - impl->position_info.y_offset; - - if (d_xoffset != 0 || d_yoffset != 0) + if (width > 65535 || + height > 65535) { - GdkRectangle new_position; - - gdk_window_set_static_gravities (window, TRUE); - - if (d_xoffset < 0 || d_yoffset < 0) - gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0)); - - compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset, - &new_position); + g_warning ("Native children wider or taller than 65535 pixels are not supported"); - move_resize (window, &new_position); - - g_list_foreach (obj->children, (GFunc) gdk_window_premove, &parent_pos); - - move_relative (window, &new_position, dx, dy); - - if (d_xoffset > 0 || d_yoffset > 0) - gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0)); - - move_resize (window, (GdkRectangle *) &new_info); - - reset_backgrounds (window); - - map_if_needed (window, &new_info); - - impl->position_info = new_info; - - g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos); + if (width > 65535) + width = 65535; + if (height > 65535) + height = 65535; } - else - { - if (is_move && is_resize) - gdk_window_set_static_gravities (window, FALSE); - - unmap_if_needed (window, &new_info); - - g_list_foreach (obj->children, (GFunc) gdk_window_premove, &parent_pos); - - if (is_resize) - move_resize (window, (GdkRectangle *) &new_info); - else - move (window, &new_info); - - g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos); - - reset_backgrounds (window); - - map_if_needed (window, &new_info); - - impl->position_info = new_info; - } - - if (GDK_WINDOW_IS_MAPPED (obj) && obj->parent && !obj->input_only) - gdk_window_invalidate_rect ((GdkWindow *)obj->parent, &old_pos, FALSE); -} - -static void -gdk_window_compute_position (GdkWindowImplX11 *window, - GdkWindowParentPos *parent_pos, - GdkXPositionInfo *info) -{ - GdkWindowObject *wrapper; - int parent_x_offset; - int parent_y_offset; - - g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window)); - - wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper); - - info->big = FALSE; - - if (window->width <= 32767) - { - info->width = window->width; - info->x = parent_pos->x + wrapper->x - parent_pos->x11_x; - } - else - { - info->big = TRUE; - info->width = 32767; - if (parent_pos->x + wrapper->x < -16384) - { - if (parent_pos->x + wrapper->x + window->width < 16384) - info->x = parent_pos->x + wrapper->x + window->width - info->width - parent_pos->x11_x; - else - info->x = -16384 - parent_pos->x11_x; - } - else - info->x = parent_pos->x + wrapper->x - parent_pos->x11_x; - } - - if (window->height <= 32767) - { - info->height = window->height; - info->y = parent_pos->y + wrapper->y - parent_pos->x11_y; - } - else - { - info->big = TRUE; - info->height = 32767; - if (parent_pos->y + wrapper->y < -16384) - { - if (parent_pos->y + wrapper->y + window->height < 16384) - info->y = parent_pos->y + wrapper->y + window->height - info->height - parent_pos->x11_y; - else - info->y = -16384 - parent_pos->x11_y; - } - else - info->y = parent_pos->y + wrapper->y - parent_pos->x11_y; - } - - parent_x_offset = parent_pos->x11_x - parent_pos->x; - parent_y_offset = parent_pos->x11_y - parent_pos->y; - info->x_offset = parent_x_offset + info->x - wrapper->x; - info->y_offset = parent_y_offset + info->y - wrapper->y; - - /* We don't considering the clipping of toplevel windows and their immediate children - * by their parents, and simply always map those windows. - */ - if (parent_pos->clip_rect.width == G_MAXINT) - info->mapped = TRUE; - /* Check if the window would wrap around into the visible space in either direction */ - else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 || - info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 || - info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 || - info->y + info->height + parent_y_offset > parent_pos->clip_rect.y + 65536) - info->mapped = FALSE; - else - info->mapped = TRUE; - - info->no_bg = FALSE; - - if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD) - { - info->clip_rect.x = wrapper->x; - info->clip_rect.y = wrapper->y; - info->clip_rect.width = window->width; - info->clip_rect.height = window->height; - - gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect); - - info->clip_rect.x -= wrapper->x; - info->clip_rect.y -= wrapper->y; - } - else - { - info->clip_rect.x = 0; - info->clip_rect.y = 0; - info->clip_rect.width = G_MAXINT; - info->clip_rect.height = G_MAXINT; - } -} - -static void -gdk_window_compute_parent_pos (GdkWindowImplX11 *window, - GdkWindowParentPos *parent_pos) -{ - GdkWindowObject *wrapper; - GdkWindowObject *parent; - GdkRectangle tmp_clip; - - int clip_xoffset = 0; - int clip_yoffset = 0; - - g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window)); - - wrapper = - GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper); - - parent_pos->x = 0; - parent_pos->y = 0; - parent_pos->x11_x = 0; - parent_pos->x11_y = 0; - - /* We take a simple approach here and simply consider toplevel - * windows not to clip their children on the right/bottom, since the - * size of toplevel windows is not directly under our - * control. Clipping only really matters when scrolling and - * generally we aren't going to be moving the immediate child of a - * toplevel beyond the bounds of that toplevel. - * - * We could go ahead and recompute the clips of toplevel windows and - * their descendents when we receive size notification, but it would - * probably not be an improvement in most cases. - */ - parent_pos->clip_rect.x = 0; - parent_pos->clip_rect.y = 0; - parent_pos->clip_rect.width = G_MAXINT; - parent_pos->clip_rect.height = G_MAXINT; - - parent = (GdkWindowObject *)wrapper->parent; - while (parent && parent->window_type == GDK_WINDOW_CHILD) - { - GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (parent->impl); - - tmp_clip.x = - clip_xoffset; - tmp_clip.y = - clip_yoffset; - tmp_clip.width = impl->width; - tmp_clip.height = impl->height; - - gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect); - - translate_pos (parent_pos, parent_pos, parent, - &impl->position_info, FALSE); - - clip_xoffset += parent->x; - clip_yoffset += parent->y; - - parent = (GdkWindowObject *)parent->parent; - } -} - -static void -gdk_window_premove (GdkWindow *window, - GdkWindowParentPos *parent_pos) -{ - GdkWindowImplX11 *impl; - GdkWindowObject *obj; - GdkXPositionInfo new_info; - gint d_xoffset, d_yoffset; - GdkWindowParentPos this_pos; - - obj = (GdkWindowObject *) window; - impl = GDK_WINDOW_IMPL_X11 (obj->impl); - - gdk_window_compute_position (impl, parent_pos, &new_info); - - gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect); - - translate_pos (&this_pos, parent_pos, obj, &new_info, TRUE); - - unmap_if_needed (window, &new_info); - - d_xoffset = new_info.x_offset - impl->position_info.x_offset; - d_yoffset = new_info.y_offset - impl->position_info.y_offset; - - if (d_xoffset != 0 || d_yoffset != 0) - { - GdkRectangle new_position; - - if (d_xoffset < 0 || d_yoffset < 0) - gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0)); - - compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset, - &new_position); - - move_resize (window, &new_position); - } - - g_list_foreach (obj->children, (GFunc) gdk_window_premove, &this_pos); -} - -static void -gdk_window_postmove (GdkWindow *window, - GdkWindowParentPos *parent_pos) -{ - GdkWindowImplX11 *impl; - GdkWindowObject *obj; - GdkXPositionInfo new_info; - gint d_xoffset, d_yoffset; - GdkWindowParentPos this_pos; - - obj = (GdkWindowObject *) window; - impl = GDK_WINDOW_IMPL_X11 (obj->impl); - - gdk_window_compute_position (impl, parent_pos, &new_info); + obj->x = x; + obj->y = y; + obj->width = width; + obj->height = height; - translate_pos (&this_pos, parent_pos, obj, &new_info, TRUE); + /* We don't really care about origin overflow, because on overflow + the window won't be visible anyway and thus it will be shaped + to nothing */ - d_xoffset = new_info.x_offset - impl->position_info.x_offset; - d_yoffset = new_info.y_offset - impl->position_info.y_offset; - if (d_xoffset != 0 || d_yoffset != 0) - { - if (d_xoffset > 0 || d_yoffset > 0) - gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0)); - - move_resize (window, (GdkRectangle *) &new_info); - } - - map_if_needed (window, &new_info); - - reset_backgrounds (window); - - impl->position_info = new_info; - - g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &this_pos); + _gdk_x11_window_tmp_unset_parent_bg (window); + _gdk_x11_window_tmp_unset_bg (window, TRUE); + XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + obj->x + obj->parent->abs_x, + obj->y + obj->parent->abs_y, + width, height); + _gdk_x11_window_tmp_reset_parent_bg (window); + _gdk_x11_window_tmp_reset_bg (window, TRUE); } static Bool @@ -1050,11 +341,11 @@ gdk_window_queue (GdkWindow *window, g_queue_push_tail (display_x11->translate_queue, item); } -static void -gdk_window_queue_translation (GdkWindow *window, - GdkRegion *area, - gint dx, - gint dy) +void +_gdk_x11_window_queue_translation (GdkWindow *window, + GdkRegion *area, + gint dx, + gint dy) { GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1); item->type = GDK_WINDOW_QUEUE_TRANSLATE; @@ -1066,8 +357,8 @@ gdk_window_queue_translation (GdkWindow *window, } gboolean -_gdk_windowing_window_queue_antiexpose (GdkWindow *window, - GdkRegion *area) +_gdk_x11_window_queue_antiexpose (GdkWindow *window, + GdkRegion *area) { GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1); item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE; @@ -1085,7 +376,6 @@ _gdk_window_process_expose (GdkWindow *window, { GdkWindowImplX11 *impl; GdkRegion *invalidate_region = gdk_region_rectangle (area); - GdkRegion *clip_region; GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl); @@ -1134,57 +424,10 @@ _gdk_window_process_expose (GdkWindow *window, } } - clip_region = gdk_region_rectangle (&impl->position_info.clip_rect); - gdk_region_intersect (invalidate_region, clip_region); - if (!gdk_region_empty (invalidate_region)) - gdk_window_invalidate_region (window, invalidate_region, FALSE); + _gdk_window_invalidate_for_expose (window, invalidate_region); gdk_region_destroy (invalidate_region); - gdk_region_destroy (clip_region); -} - -static void -gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip) -{ - GdkWindowImplX11 *impl; - GdkWindowObject *obj; - GdkRegion *old_clip_region; - GdkRegion *new_clip_region; - - if (((GdkWindowObject *)window)->input_only) - return; - - obj = (GdkWindowObject *) window; - impl = GDK_WINDOW_IMPL_X11 (obj->impl); - - old_clip_region = gdk_region_rectangle (old_clip); - new_clip_region = gdk_region_rectangle (new_clip); - - /* We need to update this here because gdk_window_invalidate_region makes - * use if it (through gdk_drawable_get_visible_region - */ - impl->position_info.clip_rect = *new_clip; - - /* Trim invalid region of window to new clip rectangle - */ - if (obj->update_area) - gdk_region_intersect (obj->update_area, new_clip_region); - - /* Invalidate newly exposed portion of window - */ - gdk_region_subtract (new_clip_region, old_clip_region); - if (!gdk_region_empty (new_clip_region)) - { - _gdk_x11_window_tmp_unset_bg (window, FALSE);; - gdk_window_invalidate_region (window, new_clip_region, FALSE); - } - - if (obj->parent) - _gdk_x11_window_tmp_unset_bg ((GdkWindow *)obj->parent, FALSE); - - gdk_region_destroy (new_clip_region); - gdk_region_destroy (old_clip_region); } #define __GDK_GEOMETRY_X11_C__ diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c index 8faf70484..9e2d81889 100644 --- a/gdk/x11/gdkinput-x11.c +++ b/gdk/x11/gdkinput-x11.c @@ -416,15 +416,15 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, gdouble *x_out, gdouble *y_out) { - GdkWindowImplX11 *impl; + GdkWindowObject *window_private; int i; int x_axis = 0; int y_axis = 0; double device_width, device_height; double x_offset, y_offset, x_scale, y_scale; - - impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *) input_window->window)->impl); + + window_private = (GdkWindowObject *) input_window->window; for (i=0; iinfo.num_axes; i++) { @@ -476,26 +476,26 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, } device_aspect = (device_height*y_resolution) / (device_width*x_resolution); - if (device_aspect * impl->width >= impl->height) + if (device_aspect * window_private->width >= window_private->height) { /* device taller than window */ - x_scale = impl->width / device_width; + x_scale = window_private->width / device_width; y_scale = (x_scale * x_resolution) / y_resolution; x_offset = 0; y_offset = -(device_height * y_scale - - impl->height)/2; + window_private->height)/2; } else { /* window taller than device */ - y_scale = impl->height / device_height; + y_scale = window_private->height / device_height; x_scale = (y_scale * y_resolution) / x_resolution; y_offset = 0; - x_offset = - (device_width * x_scale - impl->width)/2; + x_offset = - (device_width * x_scale - window_private->width)/2; } } diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c index 0d48e13f3..95a301d24 100644 --- a/gdk/x11/gdkinput.c +++ b/gdk/x11/gdkinput.c @@ -251,7 +251,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_WINDOW_IS_X11 (window), FALSE); if (GDK_WINDOW_DESTROYED (window)) /* Nothing */ ; @@ -324,6 +324,11 @@ _gdk_input_window_find(GdkWindow *window) GList *tmp_list; GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); + /* Ensure we have a native window, or the input stuff won't work. + Its possible we could emulate this also, but at least this should make + it work. */ + gdk_window_set_has_native (window, TRUE); + for (tmp_list=display_x11->input_windows; tmp_list; tmp_list=tmp_list->next) if (((GdkInputWindow *)(tmp_list->data))->window == window) return (GdkInputWindow *)(tmp_list->data); @@ -347,7 +352,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_WINDOW_IS_X11 (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 7bede228a..41639c478 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -44,6 +44,7 @@ #include "gdk.h" #include "gdkx.h" +#include "gdkasync.h" #include "gdkdisplay-x11.h" #include "gdkinternals.h" #include "gdkintl.h" @@ -137,25 +138,22 @@ gdk_x11_convert_grab_status (gint status) return 0; } +struct XPointerGrabInfo { + GdkDisplay *display; + GdkWindow *window; + GdkWindow *native_window; + gboolean owner_events; + gulong serial; + guint event_mask; + guint32 time; +}; + static void -generate_grab_broken_event (GdkWindow *window, - gboolean keyboard, - gboolean implicit, - GdkWindow *grab_window) +has_pointer_grab_callback (GdkDisplay *display, + gpointer data, + gulong serial) { - if (!GDK_WINDOW_DESTROYED (window)) - { - GdkEvent event; - - event.type = GDK_GRAB_BROKEN; - event.grab_broken.window = window; - event.grab_broken.send_event = 0; - event.grab_broken.keyboard = keyboard; - event.grab_broken.implicit = implicit; - event.grab_broken.grab_window = grab_window; - - gdk_event_put (&event); - } + _gdk_display_pointer_grab_update (display, serial); } /* @@ -191,6 +189,7 @@ gdk_pointer_grab (GdkWindow * window, { gint return_val; GdkCursorPrivate *cursor_private; + GdkWindow *native; GdkDisplayX11 *display_x11; guint xevent_mask; Window xwindow; @@ -202,13 +201,30 @@ 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); + + native = gdk_window_get_toplevel (window); + + /* We need a native window for confine to to work, ensure we have one */ + if (confine_to) + gdk_window_set_has_native (confine_to, TRUE); + + /* TODO: What do we do for offscreens and their children? We need to proxy the grab somehow */ + if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl)) + return GDK_GRAB_SUCCESS; + + if (!_gdk_window_has_impl (window) && + !gdk_window_is_viewable (window)) + return GDK_GRAB_NOT_VIEWABLE; - display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); + if (confine_to) + confine_to = _gdk_window_get_impl_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; @@ -229,8 +245,13 @@ gdk_pointer_grab (GdkWindow * window, if (event_mask & (1 << (i + 1))) xevent_mask |= _gdk_event_mask_table[i]; } + + /* We don't want to set a native motion hint mask, as we're emulating motion + * hints. If we set a native one we just wouldn't get any events. + */ + xevent_mask &= ~PointerMotionHintMask; - return_val = _gdk_input_grab_pointer (window, + return_val = _gdk_input_grab_pointer (native, owner_events, event_mask, confine_to, @@ -239,14 +260,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, @@ -261,59 +282,23 @@ gdk_pointer_grab (GdkWindow * window, if (return_val == GrabSuccess) { - 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); - - display_x11->pointer_xgrab_window = (GdkWindowObject *)window; - display_x11->pointer_xgrab_serial = serial; - display_x11->pointer_xgrab_owner_events = owner_events; - display_x11->pointer_xgrab_time = time; - display_x11->pointer_xgrab_implicit = FALSE; + _gdk_display_add_pointer_grab (GDK_DISPLAY_OBJECT (display_x11), + window, + native, + owner_events, + event_mask, + serial, + time, + FALSE); + + _gdk_x11_roundtrip_async (GDK_DISPLAY_OBJECT (display_x11), + has_pointer_grab_callback, + NULL); } return gdk_x11_convert_grab_status (return_val); } -/** - * gdk_pointer_grab_info_libgtk_only: - * @display: the #GdkDisplay for which to get the grab information - * @grab_window: location to store current grab window - * @owner_events: location to store boolean indicating whether - * the @owner_events flag to gdk_pointer_grab() was %TRUE. - * - * Determines information about the current pointer grab. - * This is not public API and must not be used by applications. - * - * Return value: %TRUE if this application currently has the - * pointer grabbed. - **/ -gboolean -gdk_pointer_grab_info_libgtk_only (GdkDisplay *display, - GdkWindow **grab_window, - gboolean *owner_events) -{ - GdkDisplayX11 *display_x11; - - g_return_val_if_fail (GDK_IS_DISPLAY (display), False); - - display_x11 = GDK_DISPLAY_X11 (display); - - if (display_x11->pointer_xgrab_window) - { - if (grab_window) - *grab_window = (GdkWindow *)display_x11->pointer_xgrab_window; - if (owner_events) - *owner_events = display_x11->pointer_xgrab_owner_events; - - return TRUE; - } - else - return FALSE; -} - /* *-------------------------------------------------------------- * gdk_keyboard_grab @@ -341,24 +326,33 @@ gdk_keyboard_grab (GdkWindow * window, { gint return_val; unsigned long serial; + GdkDisplay *display; 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_toplevel (window); - if (!GDK_WINDOW_DESTROYED (window)) + /* TODO: What do we do for offscreens and children? We need to proxy the grab somehow */ + if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl)) + return GDK_GRAB_SUCCESS; + + display = GDK_WINDOW_DISPLAY (native); + display_x11 = GDK_DISPLAY_X11 (display); + + 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); @@ -371,58 +365,14 @@ gdk_keyboard_grab (GdkWindow * window, return_val = AlreadyGrabbed; if (return_val == GrabSuccess) - { - if (display_x11->keyboard_xgrab_window != NULL && - display_x11->keyboard_xgrab_window != (GdkWindowObject *)window) - generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), - TRUE, FALSE, window); - - display_x11->keyboard_xgrab_window = (GdkWindowObject *)window; - display_x11->keyboard_xgrab_serial = serial; - display_x11->keyboard_xgrab_owner_events = owner_events; - display_x11->keyboard_xgrab_time = time; - } + _gdk_display_set_has_keyboard_grab (display, + window, native, + owner_events, + serial, time); return gdk_x11_convert_grab_status (return_val); } -/** - * gdk_keyboard_grab_info_libgtk_only: - * @display: the display for which to get the grab information - * @grab_window: location to store current grab window - * @owner_events: location to store boolean indicating whether - * the @owner_events flag to gdk_keyboard_grab() was %TRUE. - * - * Determines information about the current keyboard grab. - * This is not public API and must not be used by applications. - * - * Return value: %TRUE if this application currently has the - * keyboard grabbed. - **/ -gboolean -gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display, - GdkWindow **grab_window, - gboolean *owner_events) -{ - GdkDisplayX11 *display_x11; - - g_return_val_if_fail (GDK_IS_DISPLAY (display), False); - - display_x11 = GDK_DISPLAY_X11 (display); - - if (display_x11->keyboard_xgrab_window) - { - if (grab_window) - *grab_window = (GdkWindow *)display_x11->keyboard_xgrab_window; - if (owner_events) - *owner_events = display_x11->keyboard_xgrab_owner_events; - - return TRUE; - } - else - return FALSE; -} - /** * _gdk_xgrab_check_unmap: * @window: a #GdkWindow @@ -437,42 +387,21 @@ void _gdk_xgrab_check_unmap (GdkWindow *window, gulong serial) { - GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window)); - - if (display_x11->pointer_xgrab_window && - serial >= display_x11->pointer_xgrab_serial) - { - GdkWindowObject *private = GDK_WINDOW_OBJECT (window); - GdkWindowObject *tmp = display_x11->pointer_xgrab_window; + GdkDisplay *display = gdk_drawable_get_display (window); - while (tmp && tmp != private) - tmp = tmp->parent; + _gdk_display_end_pointer_grab (display, serial, window, TRUE); - if (tmp) - { - 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 (display_x11->keyboard_xgrab_window && - serial >= display_x11->keyboard_xgrab_serial) + if (display->keyboard_grab.window && + serial >= display->keyboard_grab.serial) { GdkWindowObject *private = GDK_WINDOW_OBJECT (window); - GdkWindowObject *tmp = display_x11->keyboard_xgrab_window; - + GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->keyboard_grab.window); while (tmp && tmp != private) tmp = tmp->parent; if (tmp) - { - generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), - TRUE, FALSE, NULL); - display_x11->keyboard_xgrab_window = NULL; - } + _gdk_display_unset_has_keyboard_grab (display, TRUE); } } @@ -486,67 +415,26 @@ _gdk_xgrab_check_unmap (GdkWindow *window, void _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) - { - generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), - FALSE, display_x11->pointer_xgrab_implicit, - NULL); - display_x11->pointer_xgrab_window = NULL; - } + GdkDisplay *display = gdk_drawable_get_display (window); + GdkPointerGrabInfo *grab; - if ((GdkWindowObject *)window == display_x11->keyboard_xgrab_window) + /* Make sure there is no lasting grab in this native + window */ + grab = _gdk_display_get_last_pointer_grab (display); + if (grab && grab->native_window == window) { - generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), - TRUE, FALSE, NULL); - display_x11->keyboard_xgrab_window = NULL; + /* We don't know the actual serial to end, but it + doesn't really matter as this only happens + after we get told of the destroy from the + server so we know its ended in the server, + just make sure its ended. */ + grab->serial_end = grab->serial_start; + grab->implicit_ungrab = TRUE; } -} - -#define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \ - GDK_BUTTON2_MASK | \ - GDK_BUTTON3_MASK | \ - GDK_BUTTON4_MASK | \ - GDK_BUTTON5_MASK) - -/** - * _gdk_xgrab_check_button_event: - * @window: a #GdkWindow - * @event: an XEvent of type ButtonPress or ButtonRelease - * - * Checks to see if a button event starts or ends an implicit grab. - **/ -void -_gdk_xgrab_check_button_event (GdkWindow *window, - XEvent *xevent) -{ - GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window)); - /* track implicit grabs for button presses */ - switch (xevent->type) - { - case ButtonPress: - if (!display_x11->pointer_xgrab_window) - { - display_x11->pointer_xgrab_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; - display_x11->pointer_xgrab_implicit = TRUE; - } - break; - case ButtonRelease: - if (display_x11->pointer_xgrab_window && - display_x11->pointer_xgrab_implicit && - (xevent->xbutton.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0) - { - display_x11->pointer_xgrab_window = NULL; - } - break; - default: - g_assert_not_reached (); - } + if (window == display->keyboard_grab.native_window && + display->keyboard_grab.window != NULL) + _gdk_display_unset_has_keyboard_grab (display, TRUE); } void diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c index 7984b5a08..1fcaf5a9b 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 f24a0df4c..871fa74fd 100644 --- a/gdk/x11/gdkprivate-x11.h +++ b/gdk/x11/gdkprivate-x11.h @@ -118,7 +118,6 @@ GdkImage *_gdk_x11_copy_to_image (GdkDrawable *drawable, Pixmap _gdk_x11_image_get_shm_pixmap (GdkImage *image); /* Routines from gdkgeometry-x11.c */ -void _gdk_window_init_position (GdkWindow *window); void _gdk_window_move_resize_child (GdkWindow *window, gint x, gint y, @@ -128,13 +127,12 @@ 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); +gboolean _gdk_x11_window_queue_antiexpose (GdkWindow *window, + GdkRegion *area); +void _gdk_x11_window_queue_translation (GdkWindow *window, + GdkRegion *area, + gint dx, + gint dy); void _gdk_selection_window_destroyed (GdkWindow *window); gboolean _gdk_selection_filter_clear_event (XSelectionClearEvent *event); @@ -166,8 +164,6 @@ void _gdk_x11_initialize_locale (void); void _gdk_xgrab_check_unmap (GdkWindow *window, gulong serial); void _gdk_xgrab_check_destroy (GdkWindow *window); -void _gdk_xgrab_check_button_event (GdkWindow *window, - XEvent *xevent); gboolean _gdk_x11_display_is_root_window (GdkDisplay *display, Window xroot_window); @@ -216,5 +212,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_WINDOW_IS_X11(win) (GDK_IS_WINDOW_IMPL_X11 (((GdkWindowObject *)win)->impl)) #endif /* __GDK_PRIVATE_X11_H__ */ diff --git a/gdk/x11/gdkproperty-x11.c b/gdk/x11/gdkproperty-x11.c index 116f47d9f..9123990b6 100644 --- a/gdk/x11/gdkproperty-x11.c +++ b/gdk/x11/gdkproperty-x11.c @@ -543,7 +543,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_WINDOW_IS_X11 (window), FALSE); if (!window) { @@ -552,6 +552,8 @@ gdk_property_get (GdkWindow *window, GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n")); } + else if (!GDK_WINDOW_IS_X11 (window)) + return FALSE; if (GDK_WINDOW_DESTROYED (window)) return FALSE; @@ -677,7 +679,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_WINDOW_IS_X11 (window)); if (!window) { @@ -688,7 +690,8 @@ gdk_property_change (GdkWindow *window, GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n")); } - + else if (!GDK_WINDOW_IS_X11 (window)) + return; if (GDK_WINDOW_DESTROYED (window)) return; @@ -728,7 +731,7 @@ void gdk_property_delete (GdkWindow *window, GdkAtom property) { - g_return_if_fail (!window || GDK_IS_WINDOW (window)); + g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window)); if (!window) { @@ -738,6 +741,8 @@ gdk_property_delete (GdkWindow *window, GDK_NOTE (MULTIHEAD, g_message ("gdk_property_delete(): window is NULL\n")); } + else if (!GDK_WINDOW_IS_X11 (window)) + return; if (GDK_WINDOW_DESTROYED (window)) return; diff --git a/gdk/x11/gdkselection-x11.c b/gdk/x11/gdkselection-x11.c index 6045dadea..7d23080fd 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_X11 (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_X11 (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_WINDOW_IS_X11 (requestor), 0); display = GDK_WINDOW_DISPLAY (requestor); - if (GDK_WINDOW_DESTROYED (requestor)) + if (GDK_WINDOW_DESTROYED (requestor) || !GDK_WINDOW_IS_X11 (requestor)) goto err; t = NULL; diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index 77033fea7..e29dc7b14 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -112,16 +112,13 @@ static void move_to_current_desktop (GdkWindow *window); static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable); static void gdk_window_impl_x11_set_colormap (GdkDrawable *drawable, GdkColormap *cmap); -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_iface_init (GdkWindowImplIface *iface); -#define WINDOW_IS_TOPLEVEL(window) \ - (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ - GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN) +#define WINDOW_IS_TOPLEVEL(window) \ + (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ + GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \ + GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN) /* Return whether time1 is considered later than time2 as far as xserver * time is concerned. Accounts for wraparound. @@ -146,8 +143,6 @@ _gdk_window_impl_get_type (void) static void gdk_window_impl_x11_init (GdkWindowImplX11 *impl) { - impl->width = 1; - impl->height = 1; impl->toplevel_window_type = -1; } @@ -181,11 +176,6 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass) drawable_class->set_colormap = gdk_window_impl_x11_set_colormap; drawable_class->get_colormap = gdk_window_impl_x11_get_colormap; - drawable_class->get_size = gdk_window_impl_x11_get_size; - - /* Visible and clip regions are the same */ - drawable_class->get_clip_region = gdk_window_impl_x11_get_visible_region; - drawable_class->get_visible_region = gdk_window_impl_x11_get_visible_region; } static void @@ -230,14 +220,7 @@ tmp_unset_bg (GdkWindow *window) obj = (GdkWindowObject *) window; impl = GDK_WINDOW_IMPL_X11 (obj->impl); - /* For windows without EXPOSURE_MASK, we can't do this - * unsetting because such windows depend on the drawing - * that the X server is going to do - */ - if (!(obj->event_mask & GDK_EXPOSURE_MASK)) - return; - - impl->position_info.no_bg = TRUE; + impl->no_bg = TRUE; if (obj->bg_pixmap != GDK_NO_BG) XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window), @@ -253,10 +236,7 @@ tmp_reset_bg (GdkWindow *window) obj = (GdkWindowObject *) window; impl = GDK_WINDOW_IMPL_X11 (obj->impl); - if (!(obj->event_mask & GDK_EXPOSURE_MASK)) - return; - - impl->position_info.no_bg = FALSE; + impl->no_bg = FALSE; if (obj->bg_pixmap == GDK_NO_BG) return; @@ -301,15 +281,13 @@ _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))) - { - return; - } - - if (private->window_type != GDK_WINDOW_ROOT && + return; + + if (_gdk_window_has_impl (window) && + GDK_WINDOW_IS_X11 (window) && + private->window_type != GDK_WINDOW_ROOT && private->window_type != GDK_WINDOW_FOREIGN) - { - tmp_unset_bg (window); - } + tmp_unset_bg (window); if (recurse) { @@ -320,6 +298,19 @@ _gdk_x11_window_tmp_unset_bg (GdkWindow *window, } } +void +_gdk_x11_window_tmp_unset_parent_bg (GdkWindow *window) +{ + GdkWindowObject *private; + private = (GdkWindowObject*) window; + + if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + return; + + window = _gdk_window_get_impl_window ((GdkWindow *)private->parent); + _gdk_x11_window_tmp_unset_bg (window, FALSE); +} + void _gdk_x11_window_tmp_reset_bg (GdkWindow *window, gboolean recurse) @@ -333,15 +324,14 @@ _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))) - { - return; - } + return; - if (private->window_type != GDK_WINDOW_ROOT && + + if (_gdk_window_has_impl (window) && + GDK_WINDOW_IS_X11 (window) && + private->window_type != GDK_WINDOW_ROOT && private->window_type != GDK_WINDOW_FOREIGN) - { - tmp_reset_bg (window); - } + tmp_reset_bg (window); if (recurse) { @@ -352,6 +342,20 @@ _gdk_x11_window_tmp_reset_bg (GdkWindow *window, } } +void +_gdk_x11_window_tmp_reset_parent_bg (GdkWindow *window) +{ + GdkWindowObject *private; + private = (GdkWindowObject*) window; + + if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT) + return; + + window = _gdk_window_get_impl_window ((GdkWindow *)private->parent); + + _gdk_x11_window_tmp_reset_bg (window, FALSE); +} + static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable) { @@ -409,35 +413,6 @@ gdk_window_impl_x11_set_colormap (GdkDrawable *drawable, } -static void -gdk_window_impl_x11_get_size (GdkDrawable *drawable, - gint *width, - gint *height) -{ - g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable)); - - if (width) - *width = GDK_WINDOW_IMPL_X11 (drawable)->width; - if (height) - *height = GDK_WINDOW_IMPL_X11 (drawable)->height; -} - -static GdkRegion* -gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable) -{ - GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (drawable); - GdkRectangle result_rect; - - result_rect.x = 0; - result_rect.y = 0; - result_rect.width = impl->width; - result_rect.height = impl->height; - - gdk_rectangle_intersect (&result_rect, &impl->position_info.clip_rect, &result_rect); - - return gdk_region_rectangle (&result_rect); -} - void _gdk_windowing_window_init (GdkScreen * screen) { @@ -457,6 +432,7 @@ _gdk_windowing_window_init (GdkScreen * screen) private = (GdkWindowObject *) screen_x11->root_window; private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); + private->impl_window = private; impl = GDK_WINDOW_IMPL_X11 (private->impl); draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl); @@ -469,12 +445,14 @@ _gdk_windowing_window_init (GdkScreen * screen) private->window_type = GDK_WINDOW_ROOT; private->depth = DefaultDepthOfScreen (screen_x11->xscreen); - - impl->width = WidthOfScreen (screen_x11->xscreen); - impl->height = HeightOfScreen (screen_x11->xscreen); - - _gdk_window_init_position (GDK_WINDOW (private)); + private->x = 0; + private->y = 0; + private->abs_x = 0; + private->abs_y = 0; + private->width = WidthOfScreen (screen_x11->xscreen); + private->height = HeightOfScreen (screen_x11->xscreen); + _gdk_xid_table_insert (screen_x11->display, &screen_x11->xroot_window, screen_x11->root_window); @@ -589,7 +567,6 @@ setup_toplevel_window (GdkWindow *window, { GdkWindowObject *obj = (GdkWindowObject *)window; GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window); - GdkWindowImplX11 *impl = (GdkWindowImplX11 *)obj->impl; Display *xdisplay = GDK_WINDOW_XDISPLAY (window); XID xid = GDK_WINDOW_XID (window); XID xparent = GDK_WINDOW_XID (parent); @@ -619,8 +596,8 @@ setup_toplevel_window (GdkWindow *window, * correct value??? */ size_hints.flags = PSize; - size_hints.width = impl->width; - size_hints.height = impl->height; + size_hints.width = obj->width; + size_hints.height = obj->height; XSetWMNormalHints (xdisplay, xid, &size_hints); @@ -656,19 +633,20 @@ setup_toplevel_window (GdkWindow *window, ensure_sync_counter (window); } -GdkWindow * -_gdk_window_new (GdkWindow *parent, - GdkWindowAttr *attributes, - gint attributes_mask) +void +_gdk_window_impl_new (GdkWindow *window, + GdkWindow *real_parent, + GdkScreen *screen, + GdkVisual *visual, + GdkEventMask event_mask, + GdkWindowAttr *attributes, + gint attributes_mask) { - GdkWindow *window; GdkWindowObject *private; GdkWindowImplX11 *impl; GdkDrawableImplX11 *draw_impl; GdkScreenX11 *screen_x11; - GdkScreen *screen; - GdkVisual *visual; Window xparent; Visual *xvisual; Display *xdisplay; @@ -677,117 +655,34 @@ _gdk_window_new (GdkWindow *parent, XSetWindowAttributes xattributes; long xattributes_mask; XClassHint *class_hint; - int x, y, depth; unsigned int class; const char *title; int i; - g_return_val_if_fail (attributes != NULL, NULL); + private = (GdkWindowObject *) window; - if (!parent) - { - GDK_NOTE (MULTIHEAD, - g_warning ("gdk_window_new(): no parent specified reverting to parent = default root window")); - - screen = gdk_screen_get_default (); - parent = gdk_screen_get_root_window (screen); - } - else - screen = gdk_drawable_get_screen (parent); - screen_x11 = GDK_SCREEN_X11 (screen); - - g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL); - - if (GDK_WINDOW_DESTROYED (parent)) - return NULL; + xparent = GDK_WINDOW_XID (real_parent); - xparent = GDK_WINDOW_XID (parent); - - window = g_object_new (GDK_TYPE_WINDOW, NULL); - - 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); + impl = g_object_new (_gdk_window_impl_get_type (), NULL); + private->impl = (GdkDrawable *)impl; + draw_impl = GDK_DRAWABLE_IMPL_X11 (impl); draw_impl->wrapper = GDK_DRAWABLE (window); draw_impl->screen = screen; xdisplay = screen_x11->xdisplay; - /* Windows with a foreign parent are treated as if they are children - * of the root window, except for actual creation. - */ - if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN) - parent = gdk_screen_get_root_window (screen); - - private->parent = (GdkWindowObject *)parent; - - private->accept_focus = TRUE; - private->focus_on_map = TRUE; - xattributes_mask = 0; - - 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; - impl->width = (attributes->width > 1) ? (attributes->width) : (1); - impl->height = (attributes->height > 1) ? (attributes->height) : (1); - - if (attributes->wclass == GDK_INPUT_ONLY) - { - /* Backwards compatiblity - we've always ignored - * attributes->window_type for input-only windows - * before - */ - if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT) - private->window_type = GDK_WINDOW_TEMP; - else - private->window_type = GDK_WINDOW_CHILD; - } - else - private->window_type = attributes->window_type; - - /* Work around a bug where Xorg refuses to map toplevel InputOnly windows - * from an untrusted client: http://bugs.freedesktop.org/show_bug.cgi?id=6988 - */ - if (attributes->wclass == GDK_INPUT_ONLY && - GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT && - !G_LIKELY (GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (parent))->trusted_client)) - { - g_warning ("Coercing GDK_INPUT_ONLY toplevel window to GDK_INPUT_OUTPUT to work around bug in Xorg server"); - attributes->wclass = GDK_INPUT_OUTPUT; - } - _gdk_window_init_position (GDK_WINDOW (private)); - if (impl->position_info.big) - private->guffaw_gravity = TRUE; - - if (attributes_mask & GDK_WA_VISUAL) - visual = attributes->visual; - else - visual = gdk_screen_get_system_visual (screen); xvisual = ((GdkVisualPrivate*) visual)->xvisual; xattributes.event_mask = StructureNotifyMask | PropertyChangeMask; for (i = 0; i < _gdk_nenvent_masks; i++) { - if (attributes->event_mask & (1 << (i + 1))) + if (event_mask & (1 << (i + 1))) xattributes.event_mask |= _gdk_event_mask_table[i]; } - private->event_mask = attributes->event_mask; - if (xattributes.event_mask) xattributes_mask |= CWEventMask; @@ -814,27 +709,17 @@ _gdk_window_new (GdkWindow *parent, case GDK_WINDOW_TOPLEVEL: case GDK_WINDOW_DIALOG: case GDK_WINDOW_TEMP: - if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT) + if (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT) { - g_warning (G_STRLOC "Toplevel windows must be created as children of\n" - "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN"); + /* The common code warns for this case */ xparent = GDK_SCREEN_XROOTWIN (screen); } - case GDK_WINDOW_CHILD: - break; - default: - g_warning (G_STRLOC "cannot make windows of type %d", private->window_type); - return NULL; } - if (attributes->wclass == GDK_INPUT_OUTPUT) + if (!private->input_only) { class = InputOutput; - depth = visual->depth; - private->input_only = FALSE; - private->depth = depth; - if (attributes_mask & GDK_WA_COLORMAP) { draw_impl->colormap = attributes->colormap; @@ -853,12 +738,8 @@ _gdk_window_new (GdkWindow *parent, } } - private->bg_color.pixel = BlackPixel (xdisplay, screen_x11->screen_num); - private->bg_color.red = private->bg_color.green = private->bg_color.blue = 0; xattributes.background_pixel = private->bg_color.pixel; - private->bg_pixmap = NULL; - xattributes.border_pixel = BlackPixel (xdisplay, screen_x11->screen_num); xattributes_mask |= CWBorderPixel | CWBackPixel; @@ -884,30 +765,32 @@ _gdk_window_new (GdkWindow *parent, } else { - depth = 0; - private->depth = 0; class = InputOnly; - private->input_only = TRUE; draw_impl->colormap = gdk_screen_get_system_colormap (screen); g_object_ref (draw_impl->colormap); } + if (private->width > 65535 || + private->height > 65535) + { + g_warning ("Native Windows wider or taller than 65535 pixels are not supported"); + + if (private->width > 65535) + private->width = 65535; + if (private->height > 65535) + private->height = 65535; + } + xid = draw_impl->xid = XCreateWindow (xdisplay, xparent, - impl->position_info.x, impl->position_info.y, - impl->position_info.width, impl->position_info.height, - 0, depth, class, xvisual, + private->x + private->parent->abs_x, + private->y + private->parent->abs_y, + private->width, private->height, + 0, private->depth, class, xvisual, xattributes_mask, &xattributes); g_object_ref (window); _gdk_xid_table_insert (screen_x11->display, &draw_impl->xid, window); - - gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? - (attributes->cursor) : - NULL)); - - if (private->parent) - private->parent->children = g_list_prepend (private->parent->children, window); - + switch (GDK_WINDOW_TYPE (private)) { case GDK_WINDOW_DIALOG: @@ -929,11 +812,11 @@ _gdk_window_new (GdkWindow *parent, XFree (class_hint); } - setup_toplevel_window (window, parent); + setup_toplevel_window (window, (GdkWindow *)private->parent); break; case GDK_WINDOW_CHILD: - if ((attributes->wclass == GDK_INPUT_OUTPUT) && + if (!private->input_only && (draw_impl->colormap != gdk_screen_get_system_colormap (screen)) && (draw_impl->colormap != gdk_drawable_get_colormap (gdk_window_get_toplevel (window)))) { @@ -948,8 +831,6 @@ _gdk_window_new (GdkWindow *parent, if (attributes_mask & GDK_WA_TYPE_HINT) gdk_window_set_type_hint (window, attributes->type_hint); - - return window; } static GdkEventMask @@ -1027,6 +908,7 @@ gdk_window_foreign_new_for_display (GdkDisplay *display, private = (GdkWindowObject *) window; private->impl = g_object_new (_gdk_window_impl_get_type (), NULL); + private->impl_window = private; impl = GDK_WINDOW_IMPL_X11 (private->impl); draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl); @@ -1044,8 +926,8 @@ gdk_window_foreign_new_for_display (GdkDisplay *display, private->x = attrs.x; private->y = attrs.y; - impl->width = attrs.width; - impl->height = attrs.height; + private->width = attrs.width; + private->height = attrs.height; private->window_type = GDK_WINDOW_FOREIGN; private->destroyed = FALSE; @@ -1058,10 +940,12 @@ gdk_window_foreign_new_for_display (GdkDisplay *display, private->depth = attrs.depth; - _gdk_window_init_position (GDK_WINDOW (private)); - g_object_ref (window); _gdk_xid_table_insert (display, &GDK_WINDOW_XID (window), window); + + /* Update the clip region, etc */ + _gdk_window_update_size (window); + return window; } @@ -1140,10 +1024,10 @@ gdk_toplevel_x11_free_contents (GdkDisplay *display, #endif } -void -_gdk_windowing_window_destroy (GdkWindow *window, - gboolean recursing, - gboolean foreign_destroy) +static void +_gdk_x11_window_destroy (GdkWindow *window, + gboolean recursing, + gboolean foreign_destroy) { GdkWindowObject *private = (GdkWindowObject *)window; GdkToplevelX11 *toplevel; @@ -1215,8 +1099,6 @@ gdk_window_destroy_notify (GdkWindow *window) { GdkWindowImplX11 *window_impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - window_impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl); if (!GDK_WINDOW_DESTROYED (window)) @@ -1419,66 +1301,43 @@ set_initial_hints (GdkWindow *window) } static void -gdk_window_x11_show (GdkWindow *window, - gboolean raise) +gdk_window_x11_show (GdkWindow *window) { - GdkWindowObject *private; + GdkWindowObject *private = (GdkWindowObject*) window; GdkDisplay *display; GdkDisplayX11 *display_x11; GdkToplevelX11 *toplevel; - - private = (GdkWindowObject*) window; - if (!private->destroyed) - { - GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl); - Display *xdisplay = GDK_WINDOW_XDISPLAY (window); - Window xwindow = GDK_WINDOW_XID (window); + GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl); + Display *xdisplay = GDK_WINDOW_XDISPLAY (window); + Window xwindow = GDK_WINDOW_XID (window); + gboolean unset_bg; - if (raise) - XRaiseWindow (xdisplay, xwindow); - - if (!GDK_WINDOW_IS_MAPPED (window)) - { - set_initial_hints (window); - - gdk_synthesize_window_state (window, - GDK_WINDOW_STATE_WITHDRAWN, - 0); - } + set_initial_hints (window); - g_assert (GDK_WINDOW_IS_MAPPED (window)); - - if (WINDOW_IS_TOPLEVEL (window)) - { - display = gdk_drawable_get_display (window); - display_x11 = GDK_DISPLAY_X11 (display); - toplevel = _gdk_x11_window_get_toplevel (window); - - if (toplevel->user_time != 0 && + if (WINDOW_IS_TOPLEVEL (window)) + { + display = gdk_drawable_get_display (window); + display_x11 = GDK_DISPLAY_X11 (display); + toplevel = _gdk_x11_window_get_toplevel (window); + + if (toplevel->user_time != 0 && display_x11->user_time != 0 && - XSERVER_TIME_IS_LATER (display_x11->user_time, toplevel->user_time)) - gdk_x11_window_set_user_time (window, display_x11->user_time); - } - - if (impl->position_info.mapped) - { - gboolean unset_bg = !private->input_only && - (private->window_type == GDK_WINDOW_CHILD || - impl->override_redirect) && - gdk_window_is_viewable (window); - - if (unset_bg) - _gdk_x11_window_tmp_unset_bg (window, TRUE); - - XMapWindow (xdisplay, xwindow); - - if (unset_bg) - { - _gdk_x11_window_tmp_reset_bg (window, TRUE); - gdk_window_invalidate_rect (window, NULL, TRUE); - } - } + XSERVER_TIME_IS_LATER (display_x11->user_time, toplevel->user_time)) + gdk_x11_window_set_user_time (window, display_x11->user_time); } + + unset_bg = !private->input_only && + (private->window_type == GDK_WINDOW_CHILD || + impl->override_redirect) && + gdk_window_is_viewable (window); + + if (unset_bg) + _gdk_x11_window_tmp_unset_bg (window, TRUE); + + XMapWindow (xdisplay, xwindow); + + if (unset_bg) + _gdk_x11_window_tmp_reset_bg (window, TRUE); } static void @@ -1491,7 +1350,7 @@ pre_unmap (GdkWindow *window) return; if (private->window_type == GDK_WINDOW_CHILD) - start_window = (GdkWindow *)private->parent; + start_window = _gdk_window_get_impl_window ((GdkWindow *)private->parent); else if (private->window_type == GDK_WINDOW_TEMP) start_window = get_root (window); @@ -1509,7 +1368,7 @@ post_unmap (GdkWindow *window) return; if (private->window_type == GDK_WINDOW_CHILD) - start_window = (GdkWindow *)private->parent; + start_window = _gdk_window_get_impl_window ((GdkWindow *)private->parent); else if (private->window_type == GDK_WINDOW_TEMP) start_window = get_root (window); @@ -1559,24 +1418,12 @@ gdk_window_x11_hide (GdkWindow *window) break; } - if (!private->destroyed) - { - if (GDK_WINDOW_IS_MAPPED (window)) - gdk_synthesize_window_state (window, - 0, - GDK_WINDOW_STATE_WITHDRAWN); - - g_assert (!GDK_WINDOW_IS_MAPPED (window)); - - _gdk_window_clear_update_area (window); - - pre_unmap (window); - - XUnmapWindow (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window)); - - post_unmap (window); - } + _gdk_window_clear_update_area (window); + + pre_unmap (window); + XUnmapWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window)); + post_unmap (window); } static void @@ -1615,7 +1462,7 @@ window_x11_move (GdkWindow *window, { _gdk_window_move_resize_child (window, x, y, - impl->width, impl->height); + private->width, private->height); } else { @@ -1649,7 +1496,6 @@ window_x11_resize (GdkWindow *window, _gdk_window_move_resize_child (window, private->x, private->y, width, height); - _gdk_x11_drawable_update_size (private->impl); } else { @@ -1661,13 +1507,13 @@ window_x11_resize (GdkWindow *window, if (impl->override_redirect) { - impl->width = width; - impl->height = height; + private->width = width; + private->height = height; _gdk_x11_drawable_update_size (private->impl); } else { - if (width != impl->width || height != impl->height) + if (width != private->width || height != private->height) private->resize_count += 1; } } @@ -1708,14 +1554,14 @@ window_x11_move_resize (GdkWindow *window, private->x = x; private->y = y; - impl->width = width; - impl->height = height; + private->width = width; + private->height = height; _gdk_x11_drawable_update_size (private->impl); } else { - if (width != impl->width || height != impl->height) + if (width != private->width || height != private->height) private->resize_count += 1; } } @@ -1750,31 +1596,25 @@ gdk_window_x11_reparent (GdkWindow *window, GdkWindowObject *parent_private; GdkWindowObject *old_parent_private; GdkWindowImplX11 *impl; - gboolean was_toplevel; - - if (!new_parent) - new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window)); window_private = (GdkWindowObject*) window; old_parent_private = (GdkWindowObject*)window_private->parent; parent_private = (GdkWindowObject*) new_parent; impl = GDK_WINDOW_IMPL_X11 (window_private->impl); + _gdk_x11_window_tmp_unset_bg (window, TRUE); + _gdk_x11_window_tmp_unset_parent_bg (window); XReparentWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), GDK_WINDOW_XID (new_parent), - x, y); - - window_private->x = x; - window_private->y = y; + parent_private->abs_x + x, parent_private->abs_y + y); + _gdk_x11_window_tmp_reset_parent_bg (window); + _gdk_x11_window_tmp_reset_bg (window, TRUE); - /* 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; + window_private->parent = parent_private; /* Switch the window type as appropriate */ @@ -1782,83 +1622,79 @@ gdk_window_x11_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) - GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL; + /* Reparenting to toplevel */ + + if (!WINDOW_IS_TOPLEVEL (window) && + GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN) + { + /* This is also done in common code at a later stage, but we + need it in setup_toplevel, so do it here too */ + if (window_private->toplevel_window_type != -1) + GDK_WINDOW_TYPE (window) = window_private->toplevel_window_type; + else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD) + GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL; + + /* Wasn't a toplevel, set up */ + setup_toplevel_window (window, new_parent); + } - if (WINDOW_IS_TOPLEVEL (window) && !was_toplevel) - setup_toplevel_window (window, new_parent); break; + case GDK_WINDOW_TOPLEVEL: case GDK_WINDOW_CHILD: case GDK_WINDOW_DIALOG: case GDK_WINDOW_TEMP: - if (WINDOW_IS_TOPLEVEL (window)) + if (WINDOW_IS_TOPLEVEL (window) && + impl->toplevel) { - /* Save the original window type so we can restore it if the - * window is reparented back to be a toplevel - */ - impl->toplevel_window_type = GDK_WINDOW_TYPE (window); - GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD; - if (impl->toplevel) + if (impl->toplevel->focus_window) { - if (impl->toplevel->focus_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); - impl->toplevel = NULL; + 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); + impl->toplevel = NULL; } } - 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)); - return FALSE; } static void -gdk_window_x11_clear_area (GdkWindow *window, - gint x, - gint y, - gint width, - gint height, - gboolean send_expose) +gdk_window_x11_raise (GdkWindow *window) { - if (!GDK_WINDOW_DESTROYED (window)) - XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), - x, y, width, height, - send_expose); + XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); } static void -gdk_window_x11_raise (GdkWindow *window) +gdk_window_x11_restack_under (GdkWindow *window, + GList *native_siblings /* in requested order, first is bottom-most */) { - if (!GDK_WINDOW_DESTROYED (window)) - XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); + Window *windows; + int n_windows, i; + GList *l; + + n_windows = g_list_length (native_siblings) + 1; + windows = g_new (Window, n_windows); + + windows[0] = GDK_WINDOW_XID (window); + /* Reverse order, as input order is bottom-most first */ + i = n_windows - 1; + for (l = native_siblings; l != NULL; l = l->next) + windows[i--] = GDK_WINDOW_XID (l->data); + + XRestackWindows (GDK_WINDOW_XDISPLAY (window), windows, n_windows); + + g_free (windows); } static void gdk_window_x11_lower (GdkWindow *window) { - if (!GDK_WINDOW_DESTROYED (window)) - XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); + XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); } /** @@ -1959,10 +1795,11 @@ gdk_window_focus (GdkWindow *window, guint32 timestamp) { GdkDisplay *display; - - g_return_if_fail (GDK_IS_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + g_return_if_fail (WINDOW_IS_TOPLEVEL (window)); + + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; display = GDK_WINDOW_DISPLAY (window); @@ -2032,9 +1869,8 @@ gdk_window_set_hints (GdkWindow *window, { XSizeHints size_hints; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; size_hints.flags = 0; @@ -2087,9 +1923,8 @@ gdk_window_set_type_hint (GdkWindow *window, GdkDisplay *display; Atom atom; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; display = gdk_drawable_get_display (window); @@ -2172,7 +2007,8 @@ gdk_window_get_type_hint (GdkWindow *window) g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return GDK_WINDOW_TYPE_HINT_NORMAL; type = GDK_WINDOW_TYPE_HINT_NORMAL; @@ -2273,9 +2109,8 @@ gdk_window_set_modal_hint (GdkWindow *window, { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; private = (GdkWindowObject*) window; @@ -2308,10 +2143,10 @@ gdk_window_set_skip_taskbar_hint (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -2345,10 +2180,10 @@ gdk_window_set_skip_pager_hint (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -2376,10 +2211,10 @@ gdk_window_set_urgency_hint (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -2424,9 +2259,8 @@ gdk_window_set_geometry_hints (GdkWindow *window, { XSizeHints size_hints; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; size_hints.flags = 0; @@ -2533,7 +2367,8 @@ gdk_window_get_geometry_hints (GdkWindow *window, *geom_mask = 0; - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; size_hints = XAllocSizeHints (); @@ -2688,10 +2523,10 @@ gdk_window_set_title (GdkWindow *window, Display *xdisplay; Window xwindow; - g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (title != NULL); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; display = gdk_drawable_get_display (window); @@ -2738,11 +2573,10 @@ gdk_window_set_role (GdkWindow *window, { GdkDisplay *display; - g_return_if_fail (GDK_IS_WINDOW (window)); - display = gdk_drawable_get_display (window); - if (!GDK_WINDOW_DESTROYED (window)) + if (!GDK_WINDOW_DESTROYED (window) && + WINDOW_IS_TOPLEVEL (window)) { if (role) XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), @@ -2767,7 +2601,7 @@ gdk_window_set_role (GdkWindow *window, **/ void gdk_window_set_startup_id (GdkWindow *window, - const gchar *startup_id) + const gchar *startup_id) { GdkDisplay *display; @@ -2775,13 +2609,14 @@ gdk_window_set_startup_id (GdkWindow *window, display = gdk_drawable_get_display (window); - if (!GDK_WINDOW_DESTROYED (window)) + if (!GDK_WINDOW_DESTROYED (window) && + WINDOW_IS_TOPLEVEL (window)) { if (startup_id) XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"), gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8, - PropModeReplace, startup_id, strlen (startup_id)); + PropModeReplace, (unsigned char *)startup_id, strlen (startup_id)); else XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID")); @@ -2806,9 +2641,8 @@ void gdk_window_set_transient_for (GdkWindow *window, GdkWindow *parent) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent)) + if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent) && + WINDOW_IS_TOPLEVEL (window)) XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), GDK_WINDOW_XID (parent)); @@ -2818,62 +2652,22 @@ static void gdk_window_x11_set_background (GdkWindow *window, const GdkColor *color) { - GdkWindowObject *private = (GdkWindowObject *)window; - GdkColormap *colormap = gdk_drawable_get_colormap (window); - - if (!GDK_WINDOW_DESTROYED (window)) - XSetWindowBackground (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), color->pixel); - - 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; + XSetWindowBackground (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), color->pixel); } static void gdk_window_x11_set_back_pixmap (GdkWindow *window, - GdkPixmap *pixmap, - gboolean parent_relative) + GdkPixmap *pixmap) { - GdkWindowObject *private = (GdkWindowObject *)window; Pixmap xpixmap; - 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) - { - xpixmap = ParentRelative; - private->bg_pixmap = GDK_PARENT_RELATIVE_BG; - } + if (pixmap == GDK_PARENT_RELATIVE_BG) + xpixmap = ParentRelative; + else if (pixmap == GDK_NO_BG) + xpixmap = None; else - { - if (pixmap) - { - g_object_ref (pixmap); - private->bg_pixmap = pixmap; - xpixmap = GDK_PIXMAP_XID (pixmap); - } - else - { - xpixmap = None; - private->bg_pixmap = GDK_NO_BG; - } - } + xpixmap = GDK_PIXMAP_XID (pixmap); if (!GDK_WINDOW_DESTROYED (window)) XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window), @@ -2996,81 +2790,54 @@ gdk_window_x11_get_origin (GdkWindow *window, return return_val; } -/** - * gdk_window_get_deskrelative_origin: - * @window: a toplevel #GdkWindow - * @x: return location for X coordinate - * @y: return location for Y coordinate - * - * This gets the origin of a #GdkWindow relative to - * an Enlightenment-window-manager desktop. As long as you don't - * assume that the user's desktop/workspace covers the entire - * root window (i.e. you don't assume that the desktop begins - * at root window coordinate 0,0) this function is not necessary. - * It's deprecated for that reason. - * - * Return value: not meaningful - **/ -gboolean -gdk_window_get_deskrelative_origin (GdkWindow *window, - gint *x, - gint *y) +static gboolean +gdk_window_x11_get_deskrelative_origin (GdkWindow *window, + gint *x, + gint *y) { gboolean return_val = FALSE; gint num_children, format_return; Window win, *child, parent, root; - gint tx = 0; - gint ty = 0; Atom type_return; Atom atom; gulong number_return, bytes_after_return; guchar *data_return; - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + atom = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), + "ENLIGHTENMENT_DESKTOP"); + win = GDK_WINDOW_XID (window); - if (!GDK_WINDOW_DESTROYED (window)) + while (XQueryTree (GDK_WINDOW_XDISPLAY (window), win, &root, &parent, + &child, (unsigned int *)&num_children)) { - atom = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), - "ENLIGHTENMENT_DESKTOP"); - win = GDK_WINDOW_XID (window); + if ((child) && (num_children > 0)) + XFree (child); + + if (!parent) + break; + else + win = parent; + + if (win == root) + break; - while (XQueryTree (GDK_WINDOW_XDISPLAY (window), win, &root, &parent, - &child, (unsigned int *)&num_children)) + data_return = NULL; + XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), win, atom, 0, 0, + False, XA_CARDINAL, &type_return, &format_return, + &number_return, &bytes_after_return, &data_return); + + if (type_return == XA_CARDINAL) { - if ((child) && (num_children > 0)) - XFree (child); - - if (!parent) - break; - else - win = parent; - - if (win == root) - break; - - data_return = NULL; - XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), win, atom, 0, 0, - False, XA_CARDINAL, &type_return, &format_return, - &number_return, &bytes_after_return, &data_return); - - if (type_return == XA_CARDINAL) - { - XFree (data_return); - break; - } + XFree (data_return); + break; } - - return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - win, - 0, 0, &tx, &ty, - &root); - if (x) - *x = tx; - if (y) - *y = ty; } + return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + win, + 0, 0, x, y, + &root); return return_val; } @@ -3092,8 +2859,6 @@ gdk_window_get_root_origin (GdkWindow *window, { GdkRectangle rect; - g_return_if_fail (GDK_IS_WINDOW (window)); - gdk_window_get_frame_extents (window, &rect); if (x) @@ -3138,7 +2903,6 @@ 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 (rect != NULL); private = (GdkWindowObject*) window; @@ -3148,9 +2912,6 @@ gdk_window_get_frame_extents (GdkWindow *window, rect->width = 1; rect->height = 1; - if (GDK_WINDOW_DESTROYED (window)) - return; - while (private->parent && ((GdkWindowObject*) private->parent)->parent) private = (GdkWindowObject*) private->parent; @@ -3343,12 +3104,9 @@ _gdk_windowing_window_get_pointer (GdkDisplay *display, int winx = 0; int winy = 0; unsigned int xmask = 0; - gint xoffset, yoffset; g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); - _gdk_x11_window_get_offsets (window, &xoffset, &yoffset); - return_val = NULL; if (!GDK_WINDOW_DESTROYED (window)) { @@ -3374,8 +3132,8 @@ _gdk_windowing_window_get_pointer (GdkDisplay *display, } } - *x = winx + xoffset; - *y = winy + yoffset; + *x = winx; + *y = winy; *mask = xmask; return return_val; @@ -3420,7 +3178,8 @@ gdk_display_warp_pointer (GdkDisplay *display, GdkWindow* _gdk_windowing_window_at_pointer (GdkDisplay *display, gint *win_x, - gint *win_y) + gint *win_y, + GdkModifierType *mask) { GdkWindow *window; GdkScreen *screen; @@ -3529,7 +3288,9 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display, window = gdk_window_lookup_for_display (display, xwindow_last); *win_x = window ? winx : -1; *win_y = window ? winy : -1; - + if (mask) + *mask = xmask; + return window; } @@ -3564,7 +3325,6 @@ gdk_window_x11_set_events (GdkWindow *window, if (!GDK_WINDOW_DESTROYED (window)) { - GDK_WINDOW_OBJECT (window)->event_mask = event_mask; if (GDK_WINDOW_XID (window) != GDK_WINDOW_XROOTWIN (window)) xevent_mask = StructureNotifyMask | PropertyChangeMask; for (i = 0; i < _gdk_nenvent_masks; i++) @@ -3624,112 +3384,6 @@ gdk_window_add_colormap_windows (GdkWindow *window) XFree (old_windows); } -#define WARN_SHAPE_TOO_BIG() g_warning ("GdkWindow is too large to allow the use of shape masks or shape regions.") - -/* - * This needs the X11 shape extension. - * If not available, shaped windows will look - * ugly, but programs still work. Stefan Wille - */ -static inline void -do_shape_combine_mask (GdkWindow *window, - GdkBitmap *mask, - gint x, - gint y, - gint shape) -{ - GdkWindowObject *private = (GdkWindowObject *)window; - Pixmap pixmap; - gint xoffset, yoffset; - -#ifdef HAVE_SHAPE_EXT - if (GDK_WINDOW_DESTROYED (window)) - return; - - _gdk_x11_window_get_offsets (window, &xoffset, &yoffset); - - if (xoffset != 0 || yoffset != 0) - { - WARN_SHAPE_TOO_BIG (); - return; - } - - if (shape == ShapeBounding - ? gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)) - : gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window))) - { - if (mask) - { - pixmap = GDK_PIXMAP_XID (mask); - - private->shaped = (shape == ShapeBounding); - } - else - { - x = 0; - y = 0; - pixmap = None; - - private->shaped = FALSE; - } - - XShapeCombineMask (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - shape, - x, y, - pixmap, - ShapeSet); - } -#endif /* HAVE_SHAPE_EXT */ -} - -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); -} - -/** - * gdk_window_input_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 - * - * Like gdk_window_shape_combine_mask(), but the shape applies - * only to event handling. Mouse events which happen while - * the pointer position corresponds to an unset bit in the - * mask will be passed on the window below @window. - * - * An input shape is typically used with RGBA windows. - * The alpha channel of the window defines which pixels are - * invisible and allows for nicely antialiased borders, - * and the input shape controls where the window is - * "clickable". - * - * On the X11 platform, this requires version 1.1 of the - * shape extension. - * - * On the Win32 platform, this functionality is not present and the - * function does nothing. - * - * Since: 2.10 - */ -void -gdk_window_input_shape_combine_mask (GdkWindow *window, - GdkBitmap *mask, - gint x, - gint y) -{ -#ifdef ShapeInput - do_shape_combine_mask (window, mask, x, y, ShapeInput); -#endif -} - - static inline void do_shape_combine_region (GdkWindow *window, const GdkRegion *shape_region, @@ -3738,24 +3392,38 @@ do_shape_combine_region (GdkWindow *window, gint shape) { GdkWindowObject *private = (GdkWindowObject *)window; - gint xoffset, yoffset; #ifdef HAVE_SHAPE_EXT if (GDK_WINDOW_DESTROYED (window)) return; - _gdk_x11_window_get_offsets (window, &xoffset, &yoffset); - - if (xoffset != 0 || yoffset != 0) - { - WARN_SHAPE_TOO_BIG (); - return; - } - if (shape_region == NULL) { /* Use NULL mask to unset the shape */ - gdk_window_shape_combine_mask (window, NULL, 0, 0); + if (shape == ShapeBounding + ? gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)) + : gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window))) + { + if (shape == ShapeBounding) + private->shaped = FALSE; + + if (shape == ShapeBounding) + { + _gdk_x11_window_tmp_unset_parent_bg (window); + _gdk_x11_window_tmp_unset_bg (window, TRUE); + } + XShapeCombineMask (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + shape, + 0, 0, + None, + ShapeSet); + if (shape == ShapeBounding) + { + _gdk_x11_window_tmp_reset_parent_bg (window); + _gdk_x11_window_tmp_reset_bg (window, TRUE); + } + } return; } @@ -3766,12 +3434,18 @@ do_shape_combine_region (GdkWindow *window, gint n_rects = 0; XRectangle *xrects = NULL; - private->shaped = shape == ShapeBounding; + if (shape == ShapeBounding) + private->shaped = TRUE; _gdk_region_get_xrectangles (shape_region, 0, 0, &xrects, &n_rects); + if (shape == ShapeBounding) + { + _gdk_x11_window_tmp_unset_parent_bg (window); + _gdk_x11_window_tmp_unset_bg (window, TRUE); + } XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), shape, @@ -3780,6 +3454,12 @@ do_shape_combine_region (GdkWindow *window, ShapeSet, YXBanded); + if (shape == ShapeBounding) + { + _gdk_x11_window_tmp_reset_parent_bg (window); + _gdk_x11_window_tmp_reset_bg (window, TRUE); + } + g_free (xrects); } #endif /* HAVE_SHAPE_EXT */ @@ -3794,37 +3474,11 @@ gdk_window_x11_shape_combine_region (GdkWindow *window, do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding); } -/** - * gdk_window_input_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 - * - * Like gdk_window_shape_combine_region(), but the shape applies - * only to event handling. Mouse events which happen while - * the pointer position corresponds to an unset bit in the - * mask will be passed on the window below @window. - * - * An input shape is typically used with RGBA windows. - * The alpha channel of the window defines which pixels are - * invisible and allows for nicely antialiased borders, - * and the input shape controls where the window is - * "clickable". - * - * On the X11 platform, this requires version 1.1 of the - * shape extension. - * - * On the Win32 platform, this functionality is not present and the - * function does nothing. - * - * Since: 2.10 - */ -void -gdk_window_input_shape_combine_region (GdkWindow *window, - const GdkRegion *shape_region, - gint offset_x, - gint offset_y) +static void +gdk_window_x11_input_shape_combine_region (GdkWindow *window, + const GdkRegion *shape_region, + gint offset_x, + gint offset_y) { #ifdef ShapeInput do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeInput); @@ -3853,9 +3507,8 @@ gdk_window_set_override_redirect (GdkWindow *window, { XSetWindowAttributes attr; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (!GDK_WINDOW_DESTROYED (window)) + if (!GDK_WINDOW_DESTROYED (window) && + WINDOW_IS_TOPLEVEL (window)) { GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl); @@ -3889,8 +3542,6 @@ gdk_window_set_accept_focus (GdkWindow *window, { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject *)window; accept_focus = accept_focus != FALSE; @@ -3899,7 +3550,8 @@ gdk_window_set_accept_focus (GdkWindow *window, { private->accept_focus = accept_focus; - if (!GDK_WINDOW_DESTROYED (window)) + if (!GDK_WINDOW_DESTROYED (window) && + WINDOW_IS_TOPLEVEL (window)) update_wm_hints (window, FALSE); } } @@ -3926,8 +3578,6 @@ gdk_window_set_focus_on_map (GdkWindow *window, { GdkWindowObject *private; - g_return_if_fail (GDK_IS_WINDOW (window)); - private = (GdkWindowObject *)window; focus_on_map = focus_on_map != FALSE; @@ -3935,8 +3585,10 @@ gdk_window_set_focus_on_map (GdkWindow *window, if (private->focus_on_map != focus_on_map) { private->focus_on_map = focus_on_map; - - if ((!GDK_WINDOW_DESTROYED (window)) && (!private->focus_on_map)) + + if ((!GDK_WINDOW_DESTROYED (window)) && + (!private->focus_on_map) && + WINDOW_IS_TOPLEVEL (window)) gdk_x11_window_set_user_time (window, 0); } } @@ -3971,9 +3623,8 @@ gdk_x11_window_set_user_time (GdkWindow *window, glong timestamp_long = (glong)timestamp; Window xid; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; display = gdk_drawable_get_display (window); @@ -4043,9 +3694,8 @@ gdk_window_set_icon_list (GdkWindow *window, GdkDisplay *display; gint n; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; display = gdk_drawable_get_display (window); @@ -4155,10 +3805,10 @@ gdk_window_set_icon (GdkWindow *window, { GdkToplevelX11 *toplevel; - g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -4220,9 +3870,8 @@ gdk_window_set_icon_name (GdkWindow *window, { GdkDisplay *display; - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + WINDOW_IS_TOPLEVEL (window)) return; display = gdk_drawable_get_display (window); @@ -4267,9 +3916,8 @@ gdk_window_set_icon_name (GdkWindow *window, void gdk_window_iconify (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4301,9 +3949,8 @@ gdk_window_iconify (GdkWindow *window) void gdk_window_deiconify (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4337,9 +3984,8 @@ gdk_window_deiconify (GdkWindow *window) void gdk_window_stick (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4394,9 +4040,8 @@ gdk_window_stick (GdkWindow *window) void gdk_window_unstick (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4438,9 +4083,8 @@ gdk_window_unstick (GdkWindow *window) void gdk_window_maximize (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4473,9 +4117,8 @@ gdk_window_maximize (GdkWindow *window) void gdk_window_unmaximize (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4511,9 +4154,8 @@ gdk_window_unmaximize (GdkWindow *window) void gdk_window_fullscreen (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4547,9 +4189,8 @@ gdk_window_fullscreen (GdkWindow *window) void gdk_window_unfullscreen (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4586,7 +4227,8 @@ gdk_window_set_keep_above (GdkWindow *window, { g_return_if_fail (GDK_IS_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4627,7 +4269,8 @@ gdk_window_set_keep_below (GdkWindow *window, gboolean setting) { g_return_if_fail (GDK_IS_WINDOW (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (GDK_WINDOW_IS_MAPPED (window)) @@ -4661,10 +4304,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_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return NULL; toplevel = _gdk_x11_window_get_toplevel (window); @@ -4698,7 +4341,9 @@ gdk_window_set_group (GdkWindow *window, g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader)); - if (GDK_WINDOW_DESTROYED (window) || (leader != NULL && GDK_WINDOW_DESTROYED (leader))) + if (GDK_WINDOW_DESTROYED (window) || + (leader != NULL && GDK_WINDOW_DESTROYED (leader)) || + !WINDOW_IS_TOPLEVEL (window)) return; toplevel = _gdk_x11_window_get_toplevel (window); @@ -4823,8 +4468,10 @@ gdk_window_set_decorations (GdkWindow *window, GdkWMDecoration decorations) { MotifWmHints hints; - - g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; /* initialize to zero to avoid writing uninitialized data to socket */ memset(&hints, 0, sizeof(hints)); @@ -4849,8 +4496,10 @@ gdk_window_get_decorations(GdkWindow *window, MotifWmHints *hints; gboolean result = FALSE; - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); - + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return FALSE; + hints = gdk_window_get_mwm_hints (window); if (hints) @@ -4895,6 +4544,10 @@ gdk_window_set_functions (GdkWindow *window, MotifWmHints hints; g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) + return; /* initialize to zero to avoid writing uninitialized data to socket */ memset(&hints, 0, sizeof(hints)); @@ -4904,409 +4557,108 @@ gdk_window_set_functions (GdkWindow *window, gdk_window_set_mwm_hints (window, &hints); } -#ifdef HAVE_SHAPE_EXT - -/* - * propagate the shapes from all child windows of a GDK window to the parent - * window. Shamelessly ripped from Enlightenment's code - * - * - Raster - */ -struct _gdk_span +static GdkRegion * +xwindow_get_shape (Display *xdisplay, + Window window, + gint shape_type) { - gint start; - gint end; - struct _gdk_span *next; -}; + GdkRegion *shape; + GdkRectangle *rl; + XRectangle *xrl; + gint rn, ord, i; -static void -gdk_add_to_span (struct _gdk_span **s, - gint x, - gint xx) -{ - struct _gdk_span *ptr1, *ptr2, *noo, *ss; - gchar spanning; - - ptr2 = NULL; - ptr1 = *s; - spanning = 0; - ss = NULL; - /* scan the spans for this line */ - while (ptr1) - { - /* -- -> new span */ - /* == -> existing span */ - /* ## -> spans intersect */ - /* if we are in the middle of spanning the span into the line */ - if (spanning) - { - /* case: ---- ==== */ - if (xx < ptr1->start - 1) - { - /* ends before next span - extend to here */ - ss->end = xx; - return; - } - /* case: ----##=== */ - else if (xx <= ptr1->end) - { - /* crosses into next span - delete next span and append */ - ss->end = ptr1->end; - ss->next = ptr1->next; - g_free (ptr1); - return; - } - /* case: ---###--- */ - else - { - /* overlaps next span - delete and keep checking */ - ss->next = ptr1->next; - g_free (ptr1); - ptr1 = ss; - } - } - /* otherwise havent started spanning it in yet */ - else - { - /* case: ---- ==== */ - if (xx < ptr1->start - 1) - { - /* insert span here in list */ - noo = g_malloc (sizeof (struct _gdk_span)); - - if (noo) - { - noo->start = x; - noo->end = xx; - noo->next = ptr1; - if (ptr2) - ptr2->next = noo; - else - *s = noo; - } - return; - } - /* case: ----##=== */ - else if ((x < ptr1->start) && (xx <= ptr1->end)) - { - /* expand this span to the left point of the new one */ - ptr1->start = x; - return; - } - /* case: ===###=== */ - else if ((x >= ptr1->start) && (xx <= ptr1->end)) - { - /* throw the span away */ - return; - } - /* case: ---###--- */ - else if ((x < ptr1->start) && (xx > ptr1->end)) - { - ss = ptr1; - spanning = 1; - ptr1->start = x; - ptr1->end = xx; - } - /* case: ===##---- */ - else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end)) - { - ss = ptr1; - spanning = 1; - ptr1->end = xx; - } - /* case: ==== ---- */ - /* case handled by next loop iteration - first case */ - } - ptr2 = ptr1; - ptr1 = ptr1->next; - } - /* it started in the middle but spans beyond your current list */ - if (spanning) - { - ptr2->end = xx; - return; - } - /* it does not start inside a span or in the middle, so add it to the end */ - noo = g_malloc (sizeof (struct _gdk_span)); + shape = NULL; - if (noo) - { - noo->start = x; - noo->end = xx; - if (ptr2) - { - noo->next = ptr2->next; - ptr2->next = noo; - } - else - { - noo->next = NULL; - *s = noo; - } - } - return; -} - -static void -gdk_add_rectangles (Display *disp, - Window win, - struct _gdk_span **spans, - gint basew, - gint baseh, - gint x, - gint y) -{ - gint a, k; - gint x1, y1, x2, y2; - gint rn, ord; - XRectangle *rl; - - rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord); - if (rl) - { - /* go through all clip rects in this window's shape */ - for (k = 0; k < rn; k++) - { - /* for each clip rect, add it to each line's spans */ - x1 = x + rl[k].x; - x2 = x + rl[k].x + (rl[k].width - 1); - y1 = y + rl[k].y; - y2 = y + rl[k].y + (rl[k].height - 1); - if (x1 < 0) - x1 = 0; - if (y1 < 0) - y1 = 0; - if (x2 >= basew) - x2 = basew - 1; - if (y2 >= baseh) - y2 = baseh - 1; - for (a = y1; a <= y2; a++) - { - if ((x2 - x1) >= 0) - gdk_add_to_span (&spans[a], x1, x2); - } - } - XFree (rl); - } -} - -static void -gdk_propagate_shapes (Display *disp, - Window win, - gboolean merge, - int shape) -{ - Window rt, par, *list = NULL; - gint i, j, num = 0, num_rects = 0; - gint x, y, contig; - guint w, h, d; - gint baseh, basew; - XRectangle *rects = NULL; - struct _gdk_span **spans = NULL, *ptr1, *ptr2, *ptr3; - XWindowAttributes xatt; - - XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d); - if (h <= 0) - return; - basew = w; - baseh = h; - spans = g_malloc (sizeof (struct _gdk_span *) * h); +#if defined(HAVE_SHAPE_EXT) + xrl = XShapeGetRectangles (xdisplay, + window, + shape_type, &rn, &ord); - for (i = 0; i < h; i++) - spans[i] = NULL; - XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num); - if (list) - { - /* go through all child windows and create/insert spans */ - for (i = 0; i < num; i++) - { - if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped)) - if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d)) - gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y); - } - if (merge) - gdk_add_rectangles (disp, win, spans, basew, baseh, x, y); - - /* go through the spans list and build a list of rects */ - rects = g_malloc (sizeof (XRectangle) * 256); - num_rects = 0; - for (i = 0; i < baseh; i++) - { - ptr1 = spans[i]; - /* go through the line for all spans */ - while (ptr1) - { - rects[num_rects].x = ptr1->start; - rects[num_rects].y = i; - rects[num_rects].width = ptr1->end - ptr1->start + 1; - rects[num_rects].height = 1; - j = i + 1; - /* if there are more lines */ - contig = 1; - /* while contigous rects (same start/end coords) exist */ - while ((contig) && (j < baseh)) - { - /* search next line for spans matching this one */ - contig = 0; - ptr2 = spans[j]; - ptr3 = NULL; - while (ptr2) - { - /* if we have an exact span match set contig */ - if ((ptr2->start == ptr1->start) && - (ptr2->end == ptr1->end)) - { - contig = 1; - /* remove the span - not needed */ - if (ptr3) - { - ptr3->next = ptr2->next; - g_free (ptr2); - ptr2 = NULL; - } - else - { - spans[j] = ptr2->next; - g_free (ptr2); - ptr2 = NULL; - } - break; - } - /* gone past the span point no point looking */ - else if (ptr2->start < ptr1->start) - break; - if (ptr2) - { - ptr3 = ptr2; - ptr2 = ptr2->next; - } - } - /* if a contiguous span was found increase the rect h */ - if (contig) - { - rects[num_rects].height++; - j++; - } - } - /* up the rect count */ - num_rects++; - /* every 256 new rects increase the rect array */ - if ((num_rects % 256) == 0) - rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256)); - ptr1 = ptr1->next; - } - } - /* set the rects as the shape mask */ - if (rects) - { - XShapeCombineRectangles (disp, win, shape, 0, 0, rects, num_rects, - ShapeSet, YXSorted); - g_free (rects); - } - XFree (list); - } - /* free up all the spans we made */ - for (i = 0; i < baseh; i++) + if (rn == 0) + return gdk_region_new (); /* Empty */ + + if (ord != YXBanded) { - ptr1 = spans[i]; - while (ptr1) - { - ptr2 = ptr1; - ptr1 = ptr1->next; - g_free (ptr2); - } + /* This really shouldn't happen with any xserver, as they + generally convert regions to YXBanded internally */ + g_warning ("non YXBanded shape masks not supported"); + XFree (xrl); + return NULL; } - g_free (spans); -} -#endif /* HAVE_SHAPE_EXT */ - -static inline void -do_child_shapes (GdkWindow *window, - gboolean merge) -{ -#ifdef HAVE_SHAPE_EXT - if (!GDK_WINDOW_DESTROYED (window) && - gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))) + rl = g_new (GdkRectangle, rn); + for (i = 0; i < rn; i++) { - gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - merge, - ShapeBounding); + rl[i].x = xrl[i].x; + rl[i].y = xrl[i].y; + rl[i].width = xrl[i].width; + rl[i].height = xrl[i].height; } + XFree (xrl); + + shape = _gdk_region_new_from_yxbanded_rects (rl, rn); + g_free (rl); #endif + + return shape; } -static void -gdk_window_x11_set_child_shapes (GdkWindow *window) -{ - do_child_shapes (window, FALSE); -} -static void -gdk_window_x11_merge_child_shapes (GdkWindow *window) +GdkRegion * +_gdk_windowing_get_shape_for_mask (GdkBitmap *mask) { - do_child_shapes (window, TRUE); + GdkDisplay *display; + Window window; + GdkRegion *region; + + display = gdk_drawable_get_display (GDK_DRAWABLE (mask)); + + window = XCreateSimpleWindow (GDK_DISPLAY_XDISPLAY (display), + GDK_SCREEN_XROOTWIN (gdk_display_get_default_screen (display)), + -1, -1, 1, 1, 0, + 0, 0); + XShapeCombineMask (GDK_DISPLAY_XDISPLAY (display), + window, + ShapeBounding, + 0, 0, + GDK_PIXMAP_XID (mask), + ShapeSet); + + region = xwindow_get_shape (GDK_DISPLAY_XDISPLAY (display), + window, ShapeBounding); + + XDestroyWindow (GDK_DISPLAY_XDISPLAY (display), + window); + + return region; } -static inline void -do_child_input_shapes (GdkWindow *window, - gboolean merge) +GdkRegion * +_gdk_windowing_window_get_shape (GdkWindow *window) { -#if defined(HAVE_SHAPE_EXT) && defined(ShapeInput) +#if defined(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), - merge, - ShapeInput); - } + return xwindow_get_shape (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), ShapeBounding); #endif -} -/** - * gdk_window_set_child_input_shapes: - * @window: a #GdkWindow - * - * Sets the input shape mask of @window to the union of input shape masks - * for all children of @window, ignoring the input shape mask of @window - * itself. Contrast with gdk_window_merge_child_input_shapes() which includes - * the input shape mask of @window in the masks to be merged. - * - * Since: 2.10 - **/ -void -gdk_window_set_child_input_shapes (GdkWindow *window) -{ - g_return_if_fail (GDK_IS_WINDOW (window)); - - do_child_input_shapes (window, FALSE); + return NULL; } -/** - * gdk_window_merge_child_input_shapes: - * @window: a #GdkWindow - * - * Merges the input shape masks for any child windows into the - * input shape mask for @window. i.e. the union of all input masks - * for @window and its children will become the new input mask - * for @window. See gdk_window_input_shape_combine_mask(). - * - * This function is distinct from gdk_window_set_child_input_shapes() - * because it includes @window's input shape mask in the set of - * shapes to be merged. - * - * Since: 2.10 - **/ -void -gdk_window_merge_child_input_shapes (GdkWindow *window) +GdkRegion * +_gdk_windowing_window_get_input_shape (GdkWindow *window) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - do_child_input_shapes (window, TRUE); -} +#if defined(HAVE_SHAPE_EXT) + if (!GDK_WINDOW_DESTROYED (window) && + gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))) + return xwindow_get_shape (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + ShapeInput); +#endif + return NULL; +} static void gdk_window_set_static_bit_gravity (GdkWindow *window, @@ -5939,9 +5291,8 @@ gdk_window_begin_resize_drag (GdkWindow *window, gint root_y, guint32 timestamp) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), @@ -5974,9 +5325,8 @@ gdk_window_begin_move_drag (GdkWindow *window, gint root_y, guint32 timestamp) { - g_return_if_fail (GDK_IS_WINDOW (window)); - - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), @@ -6010,12 +5360,17 @@ gdk_window_enable_synchronized_configure (GdkWindow *window) GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplX11 *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); - + if (!GDK_IS_WINDOW_IMPL_X11 (private->impl)) + return; + impl = GDK_WINDOW_IMPL_X11 (private->impl); if (!impl->use_synchronized_configure) { + /* This basically means you want to do fancy X specific stuff, so + ensure we have a native window */ + gdk_window_set_has_native (window, TRUE); + impl->use_synchronized_configure = TRUE; ensure_sync_counter (window); } @@ -6041,7 +5396,8 @@ gdk_window_configure_finished (GdkWindow *window) { GdkWindowImplX11 *impl; - g_return_if_fail (GDK_IS_WINDOW (window)); + if (!WINDOW_IS_TOPLEVEL (window)) + return; impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl); if (!impl->use_synchronized_configure) @@ -6082,6 +5438,11 @@ gdk_window_beep (GdkWindow *window) { GdkDisplay *display; + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + display = GDK_WINDOW_DISPLAY (window); #ifdef HAVE_XKB @@ -6123,7 +5484,8 @@ gdk_window_set_opacity (GdkWindow *window, g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (WINDOW_IS_TOPLEVEL (window)); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL (window)) return; display = gdk_drawable_get_display (window); @@ -6181,6 +5543,23 @@ _gdk_windowing_window_set_composited (GdkWindow *window, #endif } +void +_gdk_windowing_window_process_updates_recurse (GdkWindow *window, + GdkRegion *region) +{ + _gdk_window_process_updates_recurse (window, region); +} + +void +_gdk_windowing_before_process_all_updates (void) +{ +} + +void +_gdk_windowing_after_process_all_updates (void) +{ +} + static void gdk_window_impl_iface_init (GdkWindowImplIface *iface) { @@ -6189,24 +5568,23 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface) 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->restack_under = gdk_window_x11_restack_under; 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->get_deskrelative_origin = gdk_window_x11_get_deskrelative_origin; 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->input_shape_combine_region = gdk_window_x11_input_shape_combine_region; iface->set_static_gravities = gdk_window_x11_set_static_gravities; - iface->get_offsets = _gdk_x11_window_get_offsets; + iface->queue_antiexpose = _gdk_x11_window_queue_antiexpose; + iface->queue_translation = _gdk_x11_window_queue_translation; + iface->destroy = _gdk_x11_window_destroy; } #define __GDK_WINDOW_X11_C__ diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h index 2a2799b07..9a7f2aed3 100644 --- a/gdk/x11/gdkwindow-x11.h +++ b/gdk/x11/gdkwindow-x11.h @@ -44,22 +44,6 @@ typedef struct _GdkWindowImplX11 GdkWindowImplX11; typedef struct _GdkWindowImplX11Class GdkWindowImplX11Class; typedef struct _GdkXPositionInfo GdkXPositionInfo; -struct _GdkXPositionInfo -{ - gint x; - gint y; - gint width; - gint height; - gint x_offset; /* Offsets to add to X coordinates within window */ - gint y_offset; /* to get GDK coodinates within window */ - guint big : 1; - guint mapped : 1; - guint no_bg : 1; /* Set when the window background is temporarily - * unset during resizing and scaling */ - GdkRectangle clip_rect; /* visible rectangle of window */ -}; - - /* Window implementation for X11 */ @@ -74,13 +58,11 @@ struct _GdkWindowImplX11 { GdkDrawableImplX11 parent_instance; - gint width; - gint height; - - GdkXPositionInfo position_info; GdkToplevelX11 *toplevel; /* Toplevel-specific information */ GdkCursor *cursor; gint8 toplevel_window_type; + guint no_bg : 1; /* Set when the window background is temporarily + * unset during resizing and scaling */ guint override_redirect : 1; guint use_synchronized_configure : 1; @@ -158,15 +140,16 @@ struct _GdkToplevelX11 GType gdk_window_impl_x11_get_type (void); -void gdk_x11_window_set_user_time (GdkWindow *window, - guint32 timestamp); - -GdkToplevelX11 *_gdk_x11_window_get_toplevel (GdkWindow *window); -void _gdk_x11_window_tmp_unset_bg (GdkWindow *window, - gboolean recurse); -void _gdk_x11_window_tmp_reset_bg (GdkWindow *window, - gboolean recurse); +void gdk_x11_window_set_user_time (GdkWindow *window, + guint32 timestamp); +GdkToplevelX11 *_gdk_x11_window_get_toplevel (GdkWindow *window); +void _gdk_x11_window_tmp_unset_bg (GdkWindow *window, + gboolean recurse); +void _gdk_x11_window_tmp_reset_bg (GdkWindow *window, + gboolean recurse); +void _gdk_x11_window_tmp_unset_parent_bg (GdkWindow *window); +void _gdk_x11_window_tmp_reset_parent_bg (GdkWindow *window); GdkCursor *_gdk_x11_window_get_cursor (GdkWindow *window); void _gdk_x11_window_get_offsets (GdkWindow *window, diff --git a/tests/Makefile.am b/tests/Makefile.am index 924ac9984..48e440550 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -26,6 +26,7 @@ endif noinst_PROGRAMS = $(TEST_PROGS) \ simple \ + flicker \ print-editor \ testaccel \ testassistant \ @@ -55,6 +56,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \ testmultiscreen \ testnotebookdnd \ testnouiprint \ + testoffscreen \ testprint \ testrgb \ testrecentchooser \ @@ -78,6 +80,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \ testtreesort \ treestoretest \ testxinerama \ + testwindows \ pixbuf-read \ pixbuf-lowmem \ pixbuf-randomly-modified \ @@ -103,6 +106,7 @@ endif endif +flicker_DEPENDENCIES = $(TEST_DEPS) simple_DEPENDENCIES = $(TEST_DEPS) print_editor_DEPENDENCIES = $(TEST_DEPS) testicontheme_DEPENDENCIES = $(TEST_DEPS) @@ -133,6 +137,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) @@ -160,7 +165,9 @@ testactions_DEPENDENCIES = $(TEST_DEPS) testgrouping_DEPENDENCIES = $(TEST_DEPS) testtooltips_DEPENDENCIES = $(TEST_DEPS) testvolumebutton_DEPENDENCIES = $(TEST_DEPS) +testwindows_DEPENDENCIES = $(TEST_DEPS) +flicker_LDADD = $(LDADDS) simple_LDADD = $(LDADDS) print_editor_LDADD = $(LDADDS) testaccel_LDADD = $(LDADDS) @@ -191,6 +198,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) @@ -225,6 +233,7 @@ testactions_LDADD = $(LDADDS) testgrouping_LDADD = $(LDADDS) testtooltips_LDADD = $(LDADDS) testvolumebutton_LDADD = $(LDADDS) +testwindows_LDADD = $(LDADDS) testentrycompletion_SOURCES = \ @@ -317,6 +326,14 @@ testrecentchoosermenu_SOURCES = \ testvolumebutton_SOURCES = \ testvolumebutton.c +testoffscreen_SOURCES = \ + gtkoffscreenbox.c \ + gtkoffscreenbox.h \ + testoffscreen.c + +testwindow_SOURCES = \ + testwindows.c + EXTRA_DIST += \ prop-editor.h \ testgtk.1 \ diff --git a/tests/flicker.c b/tests/flicker.c new file mode 100644 index 000000000..39c9601c3 --- /dev/null +++ b/tests/flicker.c @@ -0,0 +1,216 @@ +#include + +GtkWidget* +create_flicker (void) +{ + GtkWidget *window1; + GtkWidget *hpaned1; + GtkWidget *vpaned2; + GtkWidget *hbox2; + GtkObject *spinbutton7_adj; + GtkWidget *spinbutton7; + GtkObject *spinbutton8_adj; + GtkWidget *spinbutton8; + GtkWidget *vbox1; + GtkObject *spinbutton9_adj; + GtkWidget *spinbutton9; + GtkObject *spinbutton10_adj; + GtkWidget *spinbutton10; + GtkObject *spinbutton11_adj; + GtkWidget *spinbutton11; + GtkObject *spinbutton12_adj; + GtkWidget *spinbutton12; + GtkObject *spinbutton13_adj; + GtkWidget *spinbutton13; + GtkObject *spinbutton14_adj; + GtkWidget *spinbutton14; + GtkObject *spinbutton15_adj; + GtkWidget *spinbutton15; + GtkObject *spinbutton16_adj; + GtkWidget *spinbutton16; + GtkWidget *vpaned1; + GtkWidget *hbox1; + GtkObject *spinbutton17_adj; + GtkWidget *spinbutton17; + GtkObject *spinbutton18_adj; + GtkWidget *spinbutton18; + GtkObject *spinbutton19_adj; + GtkWidget *spinbutton19; + GtkWidget *vbox2; + GtkObject *spinbutton20_adj; + GtkWidget *spinbutton20; + GtkObject *spinbutton21_adj; + GtkWidget *spinbutton21; + GtkObject *spinbutton22_adj; + GtkWidget *spinbutton22; + GtkObject *spinbutton23_adj; + GtkWidget *spinbutton23; + GtkObject *spinbutton24_adj; + GtkWidget *spinbutton24; + GtkObject *spinbutton25_adj; + GtkWidget *spinbutton25; + GtkObject *spinbutton26_adj; + GtkWidget *spinbutton26; + GtkObject *spinbutton27_adj; + GtkWidget *spinbutton27; + + window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window1), 500, 400); + gtk_window_set_title (GTK_WINDOW (window1), "window1"); + + hpaned1 = gtk_hpaned_new (); + gtk_widget_show (hpaned1); + gtk_container_add (GTK_CONTAINER (window1), hpaned1); + gtk_paned_set_position (GTK_PANED (hpaned1), 100); + + vpaned2 = gtk_vpaned_new (); + gtk_widget_show (vpaned2); + gtk_paned_pack1 (GTK_PANED (hpaned1), vpaned2, FALSE, TRUE); + gtk_paned_set_position (GTK_PANED (vpaned2), 100); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_paned_pack1 (GTK_PANED (vpaned2), hbox2, FALSE, TRUE); + + spinbutton7_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton7 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton7_adj), 1, 0); + gtk_widget_show (spinbutton7); + gtk_box_pack_start (GTK_BOX (hbox2), spinbutton7, TRUE, TRUE, 0); + + spinbutton8_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton8 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton8_adj), 1, 0); + gtk_widget_show (spinbutton8); + gtk_box_pack_start (GTK_BOX (hbox2), spinbutton8, TRUE, TRUE, 0); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_paned_pack2 (GTK_PANED (vpaned2), vbox1, TRUE, TRUE); + + spinbutton9_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton9 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton9_adj), 1, 0); + gtk_widget_show (spinbutton9); + gtk_box_pack_start (GTK_BOX (vbox1), spinbutton9, FALSE, FALSE, 0); + + spinbutton10_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton10 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton10_adj), 1, 0); + gtk_widget_show (spinbutton10); + gtk_box_pack_start (GTK_BOX (vbox1), spinbutton10, FALSE, FALSE, 0); + + spinbutton11_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton11 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton11_adj), 1, 0); + gtk_widget_show (spinbutton11); + gtk_box_pack_start (GTK_BOX (vbox1), spinbutton11, FALSE, FALSE, 0); + + spinbutton12_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton12 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton12_adj), 1, 0); + gtk_widget_show (spinbutton12); + gtk_box_pack_start (GTK_BOX (vbox1), spinbutton12, FALSE, FALSE, 0); + + spinbutton13_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton13 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton13_adj), 1, 0); + gtk_widget_show (spinbutton13); + gtk_box_pack_start (GTK_BOX (vbox1), spinbutton13, FALSE, FALSE, 0); + + spinbutton14_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton14 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton14_adj), 1, 0); + gtk_widget_show (spinbutton14); + gtk_box_pack_start (GTK_BOX (vbox1), spinbutton14, FALSE, FALSE, 0); + + spinbutton15_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton15 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton15_adj), 1, 0); + gtk_widget_show (spinbutton15); + gtk_box_pack_start (GTK_BOX (vbox1), spinbutton15, FALSE, FALSE, 0); + + spinbutton16_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton16 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton16_adj), 1, 0); + gtk_widget_show (spinbutton16); + gtk_box_pack_start (GTK_BOX (vbox1), spinbutton16, FALSE, FALSE, 0); + + vpaned1 = gtk_vpaned_new (); + gtk_widget_show (vpaned1); + gtk_paned_pack2 (GTK_PANED (hpaned1), vpaned1, TRUE, TRUE); + gtk_paned_set_position (GTK_PANED (vpaned1), 0); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_paned_pack1 (GTK_PANED (vpaned1), hbox1, FALSE, TRUE); + + spinbutton17_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton17 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton17_adj), 1, 0); + gtk_widget_show (spinbutton17); + gtk_box_pack_start (GTK_BOX (hbox1), spinbutton17, TRUE, TRUE, 0); + + spinbutton18_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton18 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton18_adj), 1, 0); + gtk_widget_show (spinbutton18); + gtk_box_pack_start (GTK_BOX (hbox1), spinbutton18, TRUE, TRUE, 0); + + spinbutton19_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton19 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton19_adj), 1, 0); + gtk_widget_show (spinbutton19); + gtk_box_pack_start (GTK_BOX (hbox1), spinbutton19, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_paned_pack2 (GTK_PANED (vpaned1), vbox2, FALSE, FALSE); + + spinbutton20_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton20 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton20_adj), 1, 0); + gtk_widget_show (spinbutton20); + gtk_box_pack_start (GTK_BOX (vbox2), spinbutton20, FALSE, FALSE, 0); + + spinbutton21_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton21 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton21_adj), 1, 0); + gtk_widget_show (spinbutton21); + gtk_box_pack_start (GTK_BOX (vbox2), spinbutton21, FALSE, FALSE, 0); + + spinbutton22_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton22 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton22_adj), 1, 0); + gtk_widget_show (spinbutton22); + gtk_box_pack_start (GTK_BOX (vbox2), spinbutton22, FALSE, FALSE, 0); + + spinbutton23_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton23 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton23_adj), 1, 0); + gtk_widget_show (spinbutton23); + gtk_box_pack_start (GTK_BOX (vbox2), spinbutton23, FALSE, FALSE, 0); + + spinbutton24_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton24 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton24_adj), 1, 0); + gtk_widget_show (spinbutton24); + gtk_box_pack_start (GTK_BOX (vbox2), spinbutton24, FALSE, FALSE, 0); + + spinbutton25_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton25 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton25_adj), 1, 0); + gtk_widget_show (spinbutton25); + gtk_box_pack_start (GTK_BOX (vbox2), spinbutton25, FALSE, FALSE, 0); + + spinbutton26_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton26 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton26_adj), 1, 0); + gtk_widget_show (spinbutton26); + gtk_box_pack_start (GTK_BOX (vbox2), spinbutton26, TRUE, FALSE, 0); + + spinbutton27_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + spinbutton27 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton27_adj), 1, 0); + gtk_widget_show (spinbutton27); + gtk_box_pack_end (GTK_BOX (vbox2), spinbutton27, FALSE, FALSE, 0); + + + return window1; +} + + +int +main (int argc, char *argv[]) +{ + GtkWidget *window1; + + gtk_set_locale (); + gtk_init (&argc, &argv); + + window1 = create_flicker (); + gtk_widget_show (window1); + + gtk_main (); + return 0; +} + diff --git a/tests/gtkoffscreenbox.c b/tests/gtkoffscreenbox.c new file mode 100644 index 000000000..5a0749bd2 --- /dev/null +++ b/tests/gtkoffscreenbox.c @@ -0,0 +1,478 @@ +/* + * gtkoffscreenbox.c + */ + +#include "config.h" + +#include +#include + +#include "gtkoffscreenbox.h" + +static void gtk_offscreen_box_realize (GtkWidget *widget); +static void gtk_offscreen_box_unrealize (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 gboolean gtk_offscreen_box_damage (GtkWidget *widget, + GdkEventExpose *event); +static gboolean 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); + +#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->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), + 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) +{ + GtkOffscreenBox *offscreen_box = GTK_OFFSCREEN_BOX (widget); + GdkWindowAttr attributes; + gint attributes_mask; + gint border_width; + GtkRequisition child_requisition; + int start_y = 0; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + 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); + + attributes.window_type = GDK_WINDOW_OFFSCREEN; + + /* Child 1 */ + attributes.x = attributes.y = 0; + if (offscreen_box->child1 && GTK_WIDGET_VISIBLE (offscreen_box->child1)) + { + attributes.width = offscreen_box->child1->allocation.width; + attributes.height = offscreen_box->child1->allocation.height; + start_y += offscreen_box->child1->allocation.height; + } + offscreen_box->offscreen_window1 = gdk_window_new (NULL, + &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 */ + attributes.y = start_y; + child_requisition.width = child_requisition.height = 0; + if (offscreen_box->child2 && GTK_WIDGET_VISIBLE (offscreen_box->child2)) + { + attributes.width = offscreen_box->child2->allocation.width; + attributes.height = offscreen_box->child2->allocation.height; + } + offscreen_box->offscreen_window2 = gdk_window_new (NULL, + &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 = 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) +{ + GtkOffscreenBox *offscreen_box = GTK_OFFSCREEN_BOX (container); + + if (offscreen_box->child1 && offscreen_box->child2) + return G_TYPE_NONE; + + return GTK_TYPE_WIDGET; +} + +static void +gtk_offscreen_box_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkOffscreenBox *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_OFFSCREEN_BOX (offscreen_box)); + 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_OFFSCREEN_BOX (offscreen_box)); + 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 = GTK_OFFSCREEN_BOX (container); + gboolean was_visible; + + 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 = GTK_OFFSCREEN_BOX (container); + + g_return_if_fail (callback != NULL); + + if (offscreen_box->child1) + (*callback) (offscreen_box->child1, callback_data); + if (offscreen_box->child2) + (*callback) (offscreen_box->child2, callback_data); +} + +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; + 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)) + { + GtkRequisition child_requisition; + GtkAllocation child_allocation; + + 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 = MAX (1, (gint) widget->allocation.width - 2 * border_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)) + { + GtkRequisition child_requisition; + GtkAllocation child_allocation; + + 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 = MAX (1, (gint) widget->allocation.width - 2 * border_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 (GtkWidget *widget, + GdkEventExpose *event) +{ + gdk_window_invalidate_rect (widget->window, NULL, FALSE); + + return TRUE; +} + +static gboolean +gtk_offscreen_box_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkOffscreenBox *offscreen_box = GTK_OFFSCREEN_BOX (widget); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + if (event->window == widget->window) + { + GdkPixmap *pixmap; + GtkAllocation child_area; + cairo_t *cr; + int start_y = 0; + + if (offscreen_box->child1 && GTK_WIDGET_VISIBLE (offscreen_box->child1)) + { + pixmap = gdk_window_get_offscreen_pixmap (offscreen_box->offscreen_window1); + child_area = offscreen_box->child1->allocation; + + cr = gdk_cairo_create (widget->window); + + gdk_cairo_set_source_pixmap (cr, pixmap, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); + + start_y += child_area.height; + } + + if (offscreen_box->child2 && GTK_WIDGET_VISIBLE (offscreen_box->child2)) + { + gint w, h; + + pixmap = gdk_window_get_offscreen_pixmap (offscreen_box->offscreen_window2); + child_area = offscreen_box->child2->allocation; + + cr = gdk_cairo_create (widget->window); + + /* transform */ + cairo_translate (cr, 0, start_y); + cairo_translate (cr, child_area.width / 2, child_area.height / 2); + cairo_rotate (cr, offscreen_box->angle); + cairo_translate (cr, -child_area.width / 2, -child_area.height / 2); + + /* clip */ + gdk_drawable_get_size (pixmap, &w, &h); + cairo_rectangle (cr, 0, 0, w, h); + cairo_clip (cr); + + /* paint */ + gdk_cairo_set_source_pixmap (cr, pixmap, 0, 0); + cairo_paint (cr); + + cairo_destroy (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; +} diff --git a/tests/gtkoffscreenbox.h b/tests/gtkoffscreenbox.h new file mode 100644 index 000000000..aa1d15d77 --- /dev/null +++ b/tests/gtkoffscreenbox.h @@ -0,0 +1,52 @@ +#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; + + 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/testclientmessage.c b/tests/testclientmessage.c index 436e9e80d..bd1a09710 100644 --- a/tests/testclientmessage.c +++ b/tests/testclientmessage.c @@ -1,122 +1,122 @@ -/* testclientmessage.c - * Copyright (C) 2008 Novell, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -static GdkAtom my_type; -static GdkAtom random_type; - -static void -send_known (void) -{ - GdkEvent *event = gdk_event_new (GDK_CLIENT_EVENT); - static int counter = 42; - int i; - - event->client.window = NULL; - event->client.message_type = my_type; - event->client.data_format = 32; - event->client.data.l[0] = counter++; - for (i = 1; i < 5; i++) - event->client.data.l[i] = 0; - - gdk_screen_broadcast_client_message (gdk_display_get_default_screen (gdk_display_get_default ()), event); - - gdk_event_free (event); -} - -void -send_random (void) -{ - GdkEvent *event = gdk_event_new (GDK_CLIENT_EVENT); - static int counter = 1; - int i; - - event->client.window = NULL; - event->client.message_type = random_type; - event->client.data_format = 32; - event->client.data.l[0] = counter++; - for (i = 1; i < 5; i++) - event->client.data.l[i] = 0; - - gdk_screen_broadcast_client_message (gdk_display_get_default_screen (gdk_display_get_default ()), event); - - gdk_event_free (event); -} - -static GdkFilterReturn -filter_func (GdkXEvent *xevent, - GdkEvent *event, - gpointer data) -{ - g_print ("Got matching client message!\n"); - return GDK_FILTER_REMOVE; -} - -int -main (int argc, char **argv) -{ - GtkWidget *window; - GtkWidget *vbox; - GtkWidget *button; - - gtk_init (&argc, &argv); - - my_type = gdk_atom_intern ("GtkTestClientMessage", FALSE); - random_type = gdk_atom_intern (g_strdup_printf ("GtkTestClientMessage-%d", - g_rand_int_range (g_rand_new (), 1, 99)), - FALSE); - - g_print ("using random client message type %s\n", gdk_atom_name (random_type)); - - window = g_object_connect (g_object_new (gtk_window_get_type (), - "type", GTK_WINDOW_TOPLEVEL, - "title", "testclientmessage", - "border_width", 10, - NULL), - "signal::destroy", gtk_main_quit, NULL, - NULL); - vbox = g_object_new (gtk_vbox_get_type (), - "GtkWidget::parent", window, - "GtkWidget::visible", TRUE, - NULL); - button = g_object_connect (g_object_new (gtk_button_get_type (), - "GtkButton::label", "send known client message", - "GtkWidget::parent", vbox, - "GtkWidget::visible", TRUE, - NULL), - "signal::clicked", send_known, NULL, - NULL); - button = g_object_connect (g_object_new (gtk_button_get_type (), - "GtkButton::label", "send random client message", - "GtkWidget::parent", vbox, - "GtkWidget::visible", TRUE, - NULL), - "signal::clicked", send_random, NULL, - NULL); - gdk_display_add_client_message_filter (gdk_display_get_default (), - my_type, - filter_func, - NULL); - gtk_widget_show (window); - - gtk_main (); - - return 0; -} +/* testclientmessage.c + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include + +static GdkAtom my_type; +static GdkAtom random_type; + +static void +send_known (void) +{ + GdkEvent *event = gdk_event_new (GDK_CLIENT_EVENT); + static int counter = 42; + int i; + + event->client.window = NULL; + event->client.message_type = my_type; + event->client.data_format = 32; + event->client.data.l[0] = counter++; + for (i = 1; i < 5; i++) + event->client.data.l[i] = 0; + + gdk_screen_broadcast_client_message (gdk_display_get_default_screen (gdk_display_get_default ()), event); + + gdk_event_free (event); +} + +void +send_random (void) +{ + GdkEvent *event = gdk_event_new (GDK_CLIENT_EVENT); + static int counter = 1; + int i; + + event->client.window = NULL; + event->client.message_type = random_type; + event->client.data_format = 32; + event->client.data.l[0] = counter++; + for (i = 1; i < 5; i++) + event->client.data.l[i] = 0; + + gdk_screen_broadcast_client_message (gdk_display_get_default_screen (gdk_display_get_default ()), event); + + gdk_event_free (event); +} + +static GdkFilterReturn +filter_func (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + g_print ("Got matching client message!\n"); + return GDK_FILTER_REMOVE; +} + +int +main (int argc, char **argv) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *button; + + gtk_init (&argc, &argv); + + my_type = gdk_atom_intern ("GtkTestClientMessage", FALSE); + random_type = gdk_atom_intern (g_strdup_printf ("GtkTestClientMessage-%d", + g_rand_int_range (g_rand_new (), 1, 99)), + FALSE); + + g_print ("using random client message type %s\n", gdk_atom_name (random_type)); + + window = g_object_connect (g_object_new (gtk_window_get_type (), + "type", GTK_WINDOW_TOPLEVEL, + "title", "testclientmessage", + "border_width", 10, + NULL), + "signal::destroy", gtk_main_quit, NULL, + NULL); + vbox = g_object_new (gtk_vbox_get_type (), + "GtkWidget::parent", window, + "GtkWidget::visible", TRUE, + NULL); + button = g_object_connect (g_object_new (gtk_button_get_type (), + "GtkButton::label", "send known client message", + "GtkWidget::parent", vbox, + "GtkWidget::visible", TRUE, + NULL), + "signal::clicked", send_known, NULL, + NULL); + button = g_object_connect (g_object_new (gtk_button_get_type (), + "GtkButton::label", "send random client message", + "GtkWidget::parent", vbox, + "GtkWidget::visible", TRUE, + NULL), + "signal::clicked", send_random, NULL, + NULL); + gdk_display_add_client_message_filter (gdk_display_get_default (), + my_type, + filter_func, + NULL); + gtk_widget_show (window); + + gtk_main (); + + return 0; +} diff --git a/tests/testoffscreen.c b/tests/testoffscreen.c new file mode 100644 index 000000000..f332d62c4 --- /dev/null +++ b/tests/testoffscreen.c @@ -0,0 +1,381 @@ +/* + * testoffscreen.c + */ + +#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); +} + +static gboolean +layout_expose_handler (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkLayout *layout = GTK_LAYOUT (widget); + + gint i,j; + gint imin, imax, jmin, jmax; + + 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; i < imax; i++) + for (j = jmin; j < jmax; j++) + if ((i + j) % 2) + gdk_draw_rectangle (layout->bin_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; + +static 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++) + { + g_snprintf (buf, sizeof (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++) + { + g_snprintf (buf, sizeof (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); +} + +static void +create_treeview (GtkWidget *vbox) +{ + GtkWidget *scrolledwindow; + GtkListStore *store; + GtkWidget *tree_view; + GSList *stock_ids; + GSList *list; + + scrolledwindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), + GTK_SHADOW_IN); + + gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0); + + store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); + g_object_unref (store); + + gtk_container_add (GTK_CONTAINER (scrolledwindow), tree_view); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), -1, + "Icon", + gtk_cell_renderer_pixbuf_new (), + "stock-id", 0, + NULL); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), -1, + "Label", + gtk_cell_renderer_text_new (), + "text", 1, + NULL); + + stock_ids = gtk_stock_list_ids (); + + for (list = stock_ids; list; list = g_slist_next (list)) + { + const gchar *stock_id = list->data; + GtkStockItem item; + + if (gtk_stock_lookup (stock_id, &item)) + { + gtk_list_store_insert_with_values (store, NULL, -1, + 0, item.stock_id, + 1, item.label, + -1); + } + } + + g_slist_foreach (stock_ids, (GFunc) g_free, NULL); + g_slist_free (stock_ids); +} + +static GtkWidget * +create_widgets (void) +{ + GtkWidget *main_hbox, *main_vbox; + GtkWidget *vbox, *hbox, *label, *combo, *entry, *button, *cb; + GtkWidget *sw, *text_view; + GList *cbitems = NULL; + + main_vbox = gtk_vbox_new (0, FALSE); + + main_hbox = gtk_hbox_new (0, FALSE); + gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (0, FALSE); + gtk_box_pack_start (GTK_BOX (main_hbox), vbox, TRUE, TRUE, 0); + + 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); + + create_treeview (main_hbox); + + return main_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; + GtkWidget *offscreen = NULL; + 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) + { + GtkWidget *widget2, *box2, *offscreen2; + + offscreen2 = gtk_offscreen_box_new (); + gtk_box_pack_start (GTK_BOX (widget), offscreen2, FALSE, FALSE, 0); + + g_signal_connect (scale, "value_changed", + G_CALLBACK (scale_changed), + offscreen2); + + box2 = gtk_vbox_new (FALSE, 0); + gtk_offscreen_box_add2 (GTK_OFFSCREEN_BOX (offscreen2), box2); + + widget2 = gtk_button_new_with_label ("Offscreen in offscreen"); + gtk_box_pack_start (GTK_BOX (box2), widget2, FALSE, FALSE, 0); + + widget2 = gtk_entry_new (); + gtk_entry_set_text (GTK_ENTRY (widget2), "Offscreen in offscreen"); + gtk_box_pack_start (GTK_BOX (box2), widget2, 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; +} diff --git a/tests/testwindows.c b/tests/testwindows.c new file mode 100644 index 000000000..842f8566a --- /dev/null +++ b/tests/testwindows.c @@ -0,0 +1,1035 @@ +#include +#include + +static GtkWidget *darea; +static GtkTreeStore *window_store = NULL; +static GtkWidget *treeview; + +static void update_store (void); + +static GtkWidget *main_window; + +static gboolean +window_has_impl (GdkWindow *window) +{ + GdkWindowObject *w; + w = (GdkWindowObject *)window; + return w->parent == NULL || w->parent->impl != w->impl; +} + +GdkWindow * +create_window (GdkWindow *parent, + int x, int y, int w, int h, + GdkColor *color) +{ + GdkWindowAttr attributes; + gint attributes_mask; + GdkWindow *window; + GdkColor *bg; + + attributes.x = x; + attributes.y = y; + attributes.width = w; + attributes.height = h; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = GDK_STRUCTURE_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_EXPOSURE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK; + attributes.wclass = GDK_INPUT_OUTPUT; + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + window = gdk_window_new (parent, &attributes, attributes_mask); + gdk_window_set_user_data (window, darea); + + bg = g_new (GdkColor, 1); + if (color) + *bg = *color; + else + { + bg->red = g_random_int_range (0, 0xffff); + bg->blue = g_random_int_range (0, 0xffff); + bg->green = g_random_int_range (0, 0xffff);; + } + + gdk_rgb_find_color (gtk_widget_get_colormap (darea), bg); + gdk_window_set_background (window, bg); + g_object_set_data_full (G_OBJECT (window), "color", bg, g_free); + + gdk_window_show (window); + + return window; +} + +static void +add_window_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GList **selected = data; + GdkWindow *window; + + gtk_tree_model_get (GTK_TREE_MODEL (window_store), + iter, + 0, &window, + -1); + + *selected = g_list_prepend (*selected, window); +} + +static GList * +get_selected_windows (void) +{ + GtkTreeSelection *sel; + GList *selected; + + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + + selected = NULL; + gtk_tree_selection_selected_foreach (sel, add_window_cb, &selected); + + return selected; +} + +static gboolean +find_window_helper (GtkTreeModel *model, + GdkWindow *window, + GtkTreeIter *iter, + GtkTreeIter *selected_iter) +{ + GtkTreeIter child_iter; + GdkWindow *w; + + do + { + gtk_tree_model_get (model, iter, + 0, &w, + -1); + if (w == window) + { + *selected_iter = *iter; + return TRUE; + } + + if (gtk_tree_model_iter_children (model, + &child_iter, + iter)) + { + if (find_window_helper (model, window, &child_iter, selected_iter)) + return TRUE; + } + } while (gtk_tree_model_iter_next (model, iter)); + + return FALSE; +} + +static gboolean +find_window (GdkWindow *window, + GtkTreeIter *window_iter) +{ + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (window_store), &iter)) + return FALSE; + + return find_window_helper (GTK_TREE_MODEL (window_store), + window, + &iter, + window_iter); +} + +static void +toggle_selection_window (GdkWindow *window) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + + if (window != NULL && + find_window (window, &iter)) + { + if (gtk_tree_selection_iter_is_selected (selection, &iter)) + gtk_tree_selection_unselect_iter (selection, &iter); + else + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +unselect_windows (void) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + + gtk_tree_selection_unselect_all (selection); +} + + +static void +select_window (GdkWindow *window) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + + if (window != NULL && + find_window (window, &iter)) + gtk_tree_selection_select_iter (selection, &iter); +} + +static void +select_windows (GList *windows) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + GList *l; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + gtk_tree_selection_unselect_all (selection); + + for (l = windows; l != NULL; l = l->next) + { + if (find_window (l->data, &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +add_window_clicked (GtkWidget *button, + gpointer data) +{ + GdkWindow *parent; + GList *l; + + l = get_selected_windows (); + if (l != NULL) + parent = l->data; + else + parent = darea->window; + + g_list_free (l); + + create_window (parent, 10, 10, 100, 100, NULL); + update_store (); +} + +static void +remove_window_clicked (GtkWidget *button, + gpointer data) +{ + GList *l, *selected; + + selected = get_selected_windows (); + + for (l = selected; l != NULL; l = l->next) + gdk_window_destroy (l->data); + + g_list_free (selected); + + update_store (); +} + +static void save_children (GString *s, GdkWindow *window); + +static void +save_window (GString *s, + GdkWindow *window) +{ + gint x, y, w, h; + GdkColor *color; + + gdk_window_get_position (window, &x, &y); + gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h); + color = g_object_get_data (G_OBJECT (window), "color"); + + g_string_append_printf (s, "%d,%d %dx%d (%d,%d,%d) %d %d\n", + x, y, w, h, + color->red, color->green, color->blue, + window_has_impl (window), + g_list_length (gdk_window_peek_children (window))); + + save_children (s, window); +} + + +static void +save_children (GString *s, + GdkWindow *window) +{ + GList *l; + GdkWindow *child; + + for (l = g_list_reverse (gdk_window_peek_children (window)); + l != NULL; + l = l->next) + { + child = l->data; + + save_window (s, child); + } +} + + +static void +save_clicked (GtkWidget *button, + gpointer data) +{ + GString *s; + GtkWidget *dialog; + GFile *file; + + s = g_string_new (""); + + save_children (s, darea->window); + + dialog = gtk_file_chooser_dialog_new ("Filename for window data", + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); + + g_file_replace_contents (file, + s->str, s->len, + NULL, FALSE, + 0, NULL, NULL, NULL); + + g_object_unref (file); + } + + gtk_widget_destroy (dialog); + g_string_free (s, TRUE); +} + +static void +destroy_children (GdkWindow *window) +{ + GList *l; + GdkWindow *child; + + for (l = gdk_window_peek_children (window); + l != NULL; + l = l->next) + { + child = l->data; + + destroy_children (child); + gdk_window_destroy (child); + } +} + +static char ** +parse_window (GdkWindow *parent, char **lines) +{ + int x, y, w, h, r, g, b, native, n_children; + GdkWindow *window; + GdkColor color; + int i; + + if (*lines == NULL) + return lines; + + if (sscanf(*lines, "%d,%d %dx%d (%d,%d,%d) %d %d", + &x, &y, &w, &h, &r, &g, &b, &native, &n_children) == 9) + { + lines++; + color.red = r; + color.green = g; + color.blue = b; + window = create_window (parent, x, y, w, h, &color); + if (native) + gdk_window_set_has_native (window, TRUE); + + for (i = 0; i < n_children; i++) + lines = parse_window (window, lines); + } + else + lines++; + + return lines; +} + +static void +load_file (GFile *file) +{ + char *data; + char **lines, **l; + + if (g_file_load_contents (file, NULL, &data, NULL, NULL, NULL)) + { + destroy_children (darea->window); + + lines = g_strsplit (data, "\n", -1); + + l = lines; + while (*l != NULL) + l = parse_window (darea->window, l); + } + + update_store (); +} + +static void +move_window_clicked (GtkWidget *button, + gpointer data) +{ + GdkWindow *window; + GtkDirectionType direction; + GList *selected, *l; + gint x, y; + + direction = GPOINTER_TO_INT (data); + + selected = get_selected_windows (); + + for (l = selected; l != NULL; l = l->next) + { + window = l->data; + + gdk_window_get_position (window, &x, &y); + + switch (direction) { + case GTK_DIR_UP: + y -= 10; + break; + case GTK_DIR_DOWN: + y += 10; + break; + case GTK_DIR_LEFT: + x -= 10; + break; + case GTK_DIR_RIGHT: + x += 10; + break; + default: + break; + } + + gdk_window_move (window, x, y); + } + + g_list_free (selected); +} + +static void +manual_clicked (GtkWidget *button, + gpointer data) +{ + GdkWindow *window; + GList *selected, *l; + int x, y, w, h; + GtkWidget *dialog, *table, *label, *xspin, *yspin, *wspin, *hspin; + + + selected = get_selected_windows (); + + if (selected == NULL) + return; + + gdk_window_get_position (selected->data, &x, &y); + gdk_drawable_get_size (selected->data, &w, &h); + + dialog = gtk_dialog_new_with_buttons ("Select new position and size", + GTK_WINDOW (main_window), + GTK_DIALOG_MODAL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); + + + table = gtk_table_new (2, 4, TRUE); + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), + table, + FALSE, FALSE, + 2); + + + label = gtk_label_new ("x:"); + gtk_table_attach_defaults (GTK_TABLE (table), + label, + 0, 1, + 0, 1); + label = gtk_label_new ("y:"); + gtk_table_attach_defaults (GTK_TABLE (table), + label, + 0, 1, + 1, 2); + label = gtk_label_new ("width:"); + gtk_table_attach_defaults (GTK_TABLE (table), + label, + 0, 1, + 2, 3); + label = gtk_label_new ("height:"); + gtk_table_attach_defaults (GTK_TABLE (table), + label, + 0, 1, + 3, 4); + + xspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (xspin), x); + gtk_table_attach_defaults (GTK_TABLE (table), + xspin, + 1, 2, + 0, 1); + yspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (yspin), y); + gtk_table_attach_defaults (GTK_TABLE (table), + yspin, + 1, 2, + 1, 2); + wspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (wspin), w); + gtk_table_attach_defaults (GTK_TABLE (table), + wspin, + 1, 2, + 2, 3); + hspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (hspin), h); + gtk_table_attach_defaults (GTK_TABLE (table), + hspin, + 1, 2, + 3, 4); + + gtk_widget_show_all (dialog); + + gtk_dialog_run (GTK_DIALOG (dialog)); + + x = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (xspin)); + y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (yspin)); + w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (wspin)); + h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (hspin)); + + gtk_widget_destroy (dialog); + + for (l = selected; l != NULL; l = l->next) + { + window = l->data; + + gdk_window_move_resize (window, x, y, w, h); + } + + g_list_free (selected); +} + +static void +scroll_window_clicked (GtkWidget *button, + gpointer data) +{ + GdkWindow *window; + GtkDirectionType direction; + GList *selected, *l; + gint dx, dy; + + direction = GPOINTER_TO_INT (data); + + selected = get_selected_windows (); + + dx = 0; dy = 0; + switch (direction) { + case GTK_DIR_UP: + dy = 10; + break; + case GTK_DIR_DOWN: + dy = -10; + break; + case GTK_DIR_LEFT: + dx = 10; + break; + case GTK_DIR_RIGHT: + dx = -10; + break; + default: + break; + } + + for (l = selected; l != NULL; l = l->next) + { + window = l->data; + + gdk_window_scroll (window, dx, dy); + } + + g_list_free (selected); +} + + +static void +raise_window_clicked (GtkWidget *button, + gpointer data) +{ + GList *selected, *l; + GdkWindow *window; + + selected = get_selected_windows (); + + for (l = selected; l != NULL; l = l->next) + { + window = l->data; + + gdk_window_raise (window); + } + + g_list_free (selected); + + update_store (); +} + +static void +lower_window_clicked (GtkWidget *button, + gpointer data) +{ + GList *selected, *l; + GdkWindow *window; + + selected = get_selected_windows (); + + for (l = selected; l != NULL; l = l->next) + { + window = l->data; + + gdk_window_lower (window); + } + + g_list_free (selected); + + update_store (); +} + + +static void +smaller_window_clicked (GtkWidget *button, + gpointer data) +{ + GList *selected, *l; + GdkWindow *window; + int w, h; + + selected = get_selected_windows (); + + for (l = selected; l != NULL; l = l->next) + { + window = l->data; + + gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h); + + w -= 10; + h -= 10; + if (w < 1) + w = 1; + if (h < 1) + h = 1; + + gdk_window_resize (window, w, h); + } + + g_list_free (selected); +} + +static void +larger_window_clicked (GtkWidget *button, + gpointer data) +{ + GList *selected, *l; + GdkWindow *window; + int w, h; + + selected = get_selected_windows (); + + for (l = selected; l != NULL; l = l->next) + { + window = l->data; + + gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h); + + w += 10; + h += 10; + + gdk_window_resize (window, w, h); + } + + g_list_free (selected); +} + +static void +native_window_clicked (GtkWidget *button, + gpointer data) +{ + GList *selected, *l; + GdkWindow *window; + + selected = get_selected_windows (); + + for (l = selected; l != NULL; l = l->next) + { + window = l->data; + + gdk_window_set_has_native (window, TRUE); + } + + g_list_free (selected); + + update_store (); +} + +static gboolean +darea_button_release_event (GtkWidget *widget, + GdkEventButton *event) +{ + if ((event->state & GDK_CONTROL_MASK) != 0) + { + toggle_selection_window (event->window); + } + else + { + unselect_windows (); + select_window (event->window); + } + + return TRUE; +} + +static void +render_window_cell (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) +{ + GdkWindow *window; + char *name; + + gtk_tree_model_get (GTK_TREE_MODEL (window_store), + iter, + 0, &window, + -1); + + if (window_has_impl (window)) + name = g_strdup_printf ("%p (native)", window); + else + name = g_strdup_printf ("%p", window); + g_object_set (cell, + "text", name, + "background-gdk", &((GdkWindowObject *)window)->bg_color, + NULL); +} + +static void +add_children (GtkTreeStore *store, + GdkWindow *window, + GtkTreeIter *window_iter) +{ + GList *l; + GtkTreeIter child_iter; + + for (l = gdk_window_peek_children (window); + l != NULL; + l = l->next) + { + gtk_tree_store_append (store, &child_iter, window_iter); + gtk_tree_store_set (store, &child_iter, + 0, l->data, + -1); + + add_children (store, l->data, &child_iter); + } +} + +static void +update_store (void) +{ + GList *selected; + + selected = get_selected_windows (); + + gtk_tree_store_clear (window_store); + + add_children (window_store, darea->window, NULL); + gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview)); + + select_windows (selected); + g_list_free (selected); +} + + +int +main (int argc, char **argv) +{ + GtkWidget *window, *vbox, *hbox, *frame; + GtkWidget *button, *scrolled, *table; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GdkColor black = {0}; + GFile *file; + + gtk_init (&argc, &argv); + + main_window = window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (window), 0); + + g_signal_connect (G_OBJECT (window), "delete-event", gtk_main_quit, NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_container_add (GTK_CONTAINER (window), hbox); + gtk_widget_show (hbox); + + frame = gtk_frame_new ("GdkWindows"); + gtk_box_pack_start (GTK_BOX (hbox), + frame, + FALSE, FALSE, + 5); + gtk_widget_show (frame); + + darea = gtk_drawing_area_new (); + /*gtk_widget_set_double_buffered (darea, FALSE);*/ + gtk_widget_add_events (darea, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + gtk_widget_set_size_request (darea, 500, 500); + g_signal_connect (darea, "button_release_event", + G_CALLBACK (darea_button_release_event), + NULL); + + + gtk_container_add (GTK_CONTAINER (frame), darea); + gtk_widget_realize (darea); + gtk_widget_show (darea); + gtk_widget_modify_bg (darea, GTK_STATE_NORMAL, + &black); + + + vbox = gtk_vbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (hbox), + vbox, + FALSE, FALSE, + 5); + gtk_widget_show (vbox); + + window_store = gtk_tree_store_new (1, GDK_TYPE_WINDOW); + + treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window_store)); + gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), + GTK_SELECTION_MULTIPLE); + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, "Window"); + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_cell_data_func (column, + renderer, + render_window_cell, + NULL, NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + + scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_size_request (scrolled, 200, 400); + gtk_container_add (GTK_CONTAINER (scrolled), treeview); + gtk_box_pack_start (GTK_BOX (vbox), + scrolled, + FALSE, FALSE, + 5); + gtk_widget_show (scrolled); + gtk_widget_show (treeview); + + table = gtk_table_new (4, 4, TRUE); + gtk_box_pack_start (GTK_BOX (vbox), + table, + FALSE, FALSE, + 2); + gtk_widget_show (table); + + button = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_stock (GTK_STOCK_GO_BACK, + GTK_ICON_SIZE_BUTTON)); + g_signal_connect (button, "clicked", + G_CALLBACK (move_window_clicked), + GINT_TO_POINTER (GTK_DIR_LEFT)); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 0, 1, + 1, 2); + gtk_widget_show (button); + + button = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_stock (GTK_STOCK_GO_UP, + GTK_ICON_SIZE_BUTTON)); + g_signal_connect (button, "clicked", + G_CALLBACK (move_window_clicked), + GINT_TO_POINTER (GTK_DIR_UP)); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 1, 2, + 0, 1); + gtk_widget_show (button); + + button = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, + GTK_ICON_SIZE_BUTTON)); + g_signal_connect (button, "clicked", + G_CALLBACK (move_window_clicked), + GINT_TO_POINTER (GTK_DIR_RIGHT)); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 2, 3, + 1, 2); + gtk_widget_show (button); + + button = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, + GTK_ICON_SIZE_BUTTON)); + g_signal_connect (button, "clicked", + G_CALLBACK (move_window_clicked), + GINT_TO_POINTER (GTK_DIR_DOWN)); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 1, 2, + 2, 3); + gtk_widget_show (button); + + + button = gtk_button_new_with_label ("Raise"); + g_signal_connect (button, "clicked", + G_CALLBACK (raise_window_clicked), + NULL); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 0, 1, + 0, 1); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Lower"); + g_signal_connect (button, "clicked", + G_CALLBACK (lower_window_clicked), + NULL); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 0, 1, + 2, 3); + gtk_widget_show (button); + + + button = gtk_button_new_with_label ("Smaller"); + g_signal_connect (button, "clicked", + G_CALLBACK (smaller_window_clicked), + NULL); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 2, 3, + 0, 1); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Larger"); + g_signal_connect (button, "clicked", + G_CALLBACK (larger_window_clicked), + NULL); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 2, 3, + 2, 3); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Native"); + g_signal_connect (button, "clicked", + G_CALLBACK (native_window_clicked), + NULL); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 1, 2, + 1, 2); + gtk_widget_show (button); + + + button = gtk_button_new_with_label ("scroll"); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_stock (GTK_STOCK_GO_UP, + GTK_ICON_SIZE_BUTTON)); + g_signal_connect (button, "clicked", + G_CALLBACK (scroll_window_clicked), + GINT_TO_POINTER (GTK_DIR_UP)); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 3, 4, + 0, 1); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("scroll"); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, + GTK_ICON_SIZE_BUTTON)); + g_signal_connect (button, "clicked", + G_CALLBACK (scroll_window_clicked), + GINT_TO_POINTER (GTK_DIR_DOWN)); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 3, 4, + 1, 2); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Manual"); + g_signal_connect (button, "clicked", + G_CALLBACK (manual_clicked), + NULL); + gtk_table_attach_defaults (GTK_TABLE (table), + button, + 3, 4, + 2, 3); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Add window"); + gtk_box_pack_start (GTK_BOX (vbox), + button, + FALSE, FALSE, + 2); + gtk_widget_show (button); + g_signal_connect (button, "clicked", + G_CALLBACK (add_window_clicked), + NULL); + + button = gtk_button_new_with_label ("Remove window"); + gtk_box_pack_start (GTK_BOX (vbox), + button, + FALSE, FALSE, + 2); + gtk_widget_show (button); + g_signal_connect (button, "clicked", + G_CALLBACK (remove_window_clicked), + NULL); + + button = gtk_button_new_with_label ("Save"); + gtk_box_pack_start (GTK_BOX (vbox), + button, + FALSE, FALSE, + 2); + gtk_widget_show (button); + g_signal_connect (button, "clicked", + G_CALLBACK (save_clicked), + NULL); + + gtk_widget_show (window); + + if (argc == 2) + { + file = g_file_new_for_commandline_arg (argv[1]); + load_file (file); + g_object_unref (file); + } + + gtk_main (); + + return 0; +}