From bc98ea9ce1884bdc4837579c4d226d227b425a52 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Sat, 14 Mar 1998 05:15:16 +0000 Subject: [PATCH] Don't resize windows when request is rejected by WM. Only use the resize Sat Mar 14 00:03:34 1998 Owen Taylor * gtk/gtkwindow.c: Don't resize windows when request is rejected by WM. Only use the resize count to guess whether a Configure event was a rejection by the WM, or a move. * gdk/gdk.c gdk/gdktypes.h: - Don't XDestroyWindow foreign windows (If they're a child of one of our windows, reparent them to root and send them a WM delete event, otherwise, just delete the GTK structure.) Handle notification of their deletion properly. (Made foreign windows a seperate window type to do this) * gtk/gtkobject.c (gtk_object_set_data_full): Call the DestroyNotify when replacing the object data. --- gdk/gdktypes.h | 4 +- gdk/gdkwindow.c | 110 ++++++++++++++++++++++++++++++++-------- gdk/x11/gdkwindow-x11.c | 110 ++++++++++++++++++++++++++++++++-------- gtk/gtkwindow.c | 28 +++------- 4 files changed, 186 insertions(+), 66 deletions(-) diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h index 931fdf78b0..bfb21a3964 100644 --- a/gdk/gdktypes.h +++ b/gdk/gdktypes.h @@ -110,6 +110,7 @@ typedef void* GdkIM; * and pixmaps transparently. (ie. You shouldn't pass a * pixmap to any procedure which accepts a window with the * exception of the drawing functions). + * Foreign: A window that actually belongs to another application */ typedef enum { @@ -118,7 +119,8 @@ typedef enum GDK_WINDOW_CHILD, GDK_WINDOW_DIALOG, GDK_WINDOW_TEMP, - GDK_WINDOW_PIXMAP + GDK_WINDOW_PIXMAP, + GDK_WINDOW_FOREIGN } GdkWindowType; /* Classes of windows. diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 7cbaf4b603..4d75318441 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -414,13 +414,21 @@ gdk_window_foreign_new (guint32 anid) GdkWindow *window; GdkWindowPrivate *private; XWindowAttributes attrs; + Window root, parent; + Window *children; + guint nchildren; private = g_new (GdkWindowPrivate, 1); window = (GdkWindow*) private; XGetWindowAttributes (gdk_display, anid, &attrs); - private->parent = NULL; + /* FIXME: This is pretty expensive. Maybe the caller should supply + * the parent */ + XQueryTree (gdk_display, anid, &root, &parent, &children, &nchildren); + XFree (children); + private->parent = gdk_xid_table_lookup (parent); + private->xwindow = anid; private->xdisplay = gdk_display; private->x = attrs.x; @@ -429,15 +437,20 @@ gdk_window_foreign_new (guint32 anid) private->height = attrs.height; private->resize_count = 0; private->ref_count = 1; - if (anid == attrs.root) - private->window_type = GDK_WINDOW_ROOT; - else - private->window_type = GDK_WINDOW_TOPLEVEL; - /* the above is probably wrong, but it may not be worth the extra - X call to get it right */ - + private->window_type = GDK_WINDOW_FOREIGN; private->destroyed = FALSE; private->extension_events = 0; + + + private->dnd_drag_data_type = None; + private->dnd_drag_data_typesavail = + private->dnd_drop_data_typesavail = NULL; + private->dnd_drop_enabled = private->dnd_drag_enabled = + private->dnd_drag_accepted = private->dnd_drag_datashow = + private->dnd_drop_data_numtypesavail = + private->dnd_drag_data_numtypesavail = 0; + private->dnd_drag_eventmask = private->dnd_drag_savedeventmask = 0; + private->filters = NULL; window->user_data = NULL; @@ -455,7 +468,8 @@ gdk_window_foreign_new (guint32 anid) window. */ static void -gdk_window_internal_destroy (GdkWindow *window, int xdestroy) +gdk_window_internal_destroy (GdkWindow *window, gboolean xdestroy, + gboolean our_destroy) { GdkWindowPrivate *private; GdkWindowPrivate *temp_private; @@ -473,23 +487,28 @@ gdk_window_internal_destroy (GdkWindow *window, int xdestroy) case GDK_WINDOW_CHILD: case GDK_WINDOW_DIALOG: case GDK_WINDOW_TEMP: + case GDK_WINDOW_FOREIGN: if (!private->destroyed) { - children = gdk_window_get_children (window); - tmp = children; - - while (tmp) + if (private->window_type != GDK_WINDOW_FOREIGN) { - temp_window = tmp->data; - tmp = tmp->next; + children = gdk_window_get_children (window); + tmp = children; - temp_private = (GdkWindowPrivate*) temp_window; - if (temp_private) - gdk_window_internal_destroy (temp_window, FALSE); + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private) + gdk_window_internal_destroy (temp_window, FALSE, + our_destroy); + } + + g_list_free (children); } - g_list_free (children); - if (private->extension_events != 0) gdk_input_window_destroy (window); @@ -504,8 +523,47 @@ gdk_window_internal_destroy (GdkWindow *window, int xdestroy) private->dnd_drop_data_typesavail = NULL; } - if (xdestroy) + if (private->filters) + { + tmp = private->filters; + + while (tmp) + { + g_free (tmp->data); + tmp = tmp->next; + } + + g_list_free (private->filters); + private->filters = NULL; + } + + if (private->window_type == GDK_WINDOW_FOREIGN) + { + if (our_destroy && (private->parent != NULL)) + { + /* It's somebody elses window, but in our heirarchy, + * so reparent it to the root window, and then send + * it a delete event, as if we were a WM + */ + XClientMessageEvent xevent; + + gdk_window_hide (window); + gdk_window_reparent (window, NULL, 0, 0); + + xevent.type = ClientMessage; + xevent.window = private->xwindow; + xevent.message_type = gdk_wm_protocols; + xevent.format = 32; + xevent.data.l[0] = gdk_wm_delete_window; + xevent.data.l[1] = CurrentTime; + + XSendEvent (private->xdisplay, private->xwindow, + False, 0, (XEvent *)&xevent); + } + } + else if (xdestroy) XDestroyWindow (private->xdisplay, private->xwindow); + private->destroyed = TRUE; } break; @@ -526,7 +584,7 @@ gdk_window_internal_destroy (GdkWindow *window, int xdestroy) void gdk_window_destroy (GdkWindow *window) { - gdk_window_internal_destroy (window, TRUE); + gdk_window_internal_destroy (window, TRUE, TRUE); gdk_window_unref (window); } @@ -541,6 +599,14 @@ gdk_window_destroy_notify (GdkWindow *window) private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + if (private->window_type == GDK_WINDOW_FOREIGN) + gdk_window_internal_destroy (window, FALSE, FALSE); + else + g_warning ("Window %#lx unexpectedly destroyed", private->xwindow); + } + gdk_xid_table_remove (private->xwindow); gdk_window_unref (window); } diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index 7cbaf4b603..4d75318441 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -414,13 +414,21 @@ gdk_window_foreign_new (guint32 anid) GdkWindow *window; GdkWindowPrivate *private; XWindowAttributes attrs; + Window root, parent; + Window *children; + guint nchildren; private = g_new (GdkWindowPrivate, 1); window = (GdkWindow*) private; XGetWindowAttributes (gdk_display, anid, &attrs); - private->parent = NULL; + /* FIXME: This is pretty expensive. Maybe the caller should supply + * the parent */ + XQueryTree (gdk_display, anid, &root, &parent, &children, &nchildren); + XFree (children); + private->parent = gdk_xid_table_lookup (parent); + private->xwindow = anid; private->xdisplay = gdk_display; private->x = attrs.x; @@ -429,15 +437,20 @@ gdk_window_foreign_new (guint32 anid) private->height = attrs.height; private->resize_count = 0; private->ref_count = 1; - if (anid == attrs.root) - private->window_type = GDK_WINDOW_ROOT; - else - private->window_type = GDK_WINDOW_TOPLEVEL; - /* the above is probably wrong, but it may not be worth the extra - X call to get it right */ - + private->window_type = GDK_WINDOW_FOREIGN; private->destroyed = FALSE; private->extension_events = 0; + + + private->dnd_drag_data_type = None; + private->dnd_drag_data_typesavail = + private->dnd_drop_data_typesavail = NULL; + private->dnd_drop_enabled = private->dnd_drag_enabled = + private->dnd_drag_accepted = private->dnd_drag_datashow = + private->dnd_drop_data_numtypesavail = + private->dnd_drag_data_numtypesavail = 0; + private->dnd_drag_eventmask = private->dnd_drag_savedeventmask = 0; + private->filters = NULL; window->user_data = NULL; @@ -455,7 +468,8 @@ gdk_window_foreign_new (guint32 anid) window. */ static void -gdk_window_internal_destroy (GdkWindow *window, int xdestroy) +gdk_window_internal_destroy (GdkWindow *window, gboolean xdestroy, + gboolean our_destroy) { GdkWindowPrivate *private; GdkWindowPrivate *temp_private; @@ -473,23 +487,28 @@ gdk_window_internal_destroy (GdkWindow *window, int xdestroy) case GDK_WINDOW_CHILD: case GDK_WINDOW_DIALOG: case GDK_WINDOW_TEMP: + case GDK_WINDOW_FOREIGN: if (!private->destroyed) { - children = gdk_window_get_children (window); - tmp = children; - - while (tmp) + if (private->window_type != GDK_WINDOW_FOREIGN) { - temp_window = tmp->data; - tmp = tmp->next; + children = gdk_window_get_children (window); + tmp = children; - temp_private = (GdkWindowPrivate*) temp_window; - if (temp_private) - gdk_window_internal_destroy (temp_window, FALSE); + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private) + gdk_window_internal_destroy (temp_window, FALSE, + our_destroy); + } + + g_list_free (children); } - g_list_free (children); - if (private->extension_events != 0) gdk_input_window_destroy (window); @@ -504,8 +523,47 @@ gdk_window_internal_destroy (GdkWindow *window, int xdestroy) private->dnd_drop_data_typesavail = NULL; } - if (xdestroy) + if (private->filters) + { + tmp = private->filters; + + while (tmp) + { + g_free (tmp->data); + tmp = tmp->next; + } + + g_list_free (private->filters); + private->filters = NULL; + } + + if (private->window_type == GDK_WINDOW_FOREIGN) + { + if (our_destroy && (private->parent != NULL)) + { + /* It's somebody elses window, but in our heirarchy, + * so reparent it to the root window, and then send + * it a delete event, as if we were a WM + */ + XClientMessageEvent xevent; + + gdk_window_hide (window); + gdk_window_reparent (window, NULL, 0, 0); + + xevent.type = ClientMessage; + xevent.window = private->xwindow; + xevent.message_type = gdk_wm_protocols; + xevent.format = 32; + xevent.data.l[0] = gdk_wm_delete_window; + xevent.data.l[1] = CurrentTime; + + XSendEvent (private->xdisplay, private->xwindow, + False, 0, (XEvent *)&xevent); + } + } + else if (xdestroy) XDestroyWindow (private->xdisplay, private->xwindow); + private->destroyed = TRUE; } break; @@ -526,7 +584,7 @@ gdk_window_internal_destroy (GdkWindow *window, int xdestroy) void gdk_window_destroy (GdkWindow *window) { - gdk_window_internal_destroy (window, TRUE); + gdk_window_internal_destroy (window, TRUE, TRUE); gdk_window_unref (window); } @@ -541,6 +599,14 @@ gdk_window_destroy_notify (GdkWindow *window) private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + if (private->window_type == GDK_WINDOW_FOREIGN) + gdk_window_internal_destroy (window, FALSE, FALSE); + else + g_warning ("Window %#lx unexpectedly destroyed", private->xwindow); + } + gdk_xid_table_remove (private->xwindow); gdk_window_unref (window); } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 6b87710d00..9785a36c9e 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -718,7 +718,8 @@ gtk_window_configure_event (GtkWidget *widget, /* If the window was merely moved, do nothing */ if ((widget->allocation.width == event->width) && - (widget->allocation.height == event->height)) + (widget->allocation.height == event->height) && + (window->resize_count == 0)) return FALSE; window = GTK_WINDOW (widget); @@ -737,19 +738,7 @@ gtk_window_configure_event (GtkWidget *widget, gtk_widget_map (window->bin.child); if (window->resize_count > 0) - { - window->resize_count -= 1; - - if ((window->resize_count == 0) && - ((event->width != widget->requisition.width) || - (event->height != widget->requisition.height))) - { - window->resize_count = 1; - gdk_window_resize (widget->window, - widget->requisition.width, - widget->requisition.height); - } - } + window->resize_count -= 1; window->handling_resize = FALSE; @@ -1068,13 +1057,10 @@ gtk_real_window_move_resize (GtkWindow *window, (width < widget->requisition.width) || (height < widget->requisition.height)) { - if (window->resize_count == 0) - { - window->resize_count = 1; - gdk_window_resize (widget->window, - widget->requisition.width, - widget->requisition.height); - } + window->resize_count += 1; + gdk_window_resize (widget->window, + widget->requisition.width, + widget->requisition.height); } else {