diff --git a/ChangeLog b/ChangeLog index ead83d7b7..148112d2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2002-05-10 Havoc Pennington + + * src/tools/metacity-window-demo.c: add override redirect test + window + + * src/stack.c (raise_window_relative_to_managed_windows): new + function, used to avoid moving windows above override redirect + popup windows. + + * src/display.c (event_callback): don't lower panels on + LeaveNotify if they have focus, #70895 + 2002-05-10 Havoc Pennington * src/window.c (constrain_position): when maximizing/fullscreening diff --git a/src/display.c b/src/display.c index 325586fff..e7c3a838c 100644 --- a/src/display.c +++ b/src/display.c @@ -1074,7 +1074,8 @@ event_callback (XEvent *event, if (window->type == META_WINDOW_DOCK && event->xcrossing.mode != NotifyGrab && - event->xcrossing.mode != NotifyUngrab) + event->xcrossing.mode != NotifyUngrab && + !window->has_focus) meta_window_lower (window); } break; diff --git a/src/stack.c b/src/stack.c index b31f89ef7..1b1cf8af9 100644 --- a/src/stack.c +++ b/src/stack.c @@ -370,6 +370,98 @@ sort_window_list (GList *list) return list; } +static void +raise_window_relative_to_managed_windows (MetaScreen *screen, + Window xwindow) +{ + /* This function is used to avoid raising a window above popup + * menus and other such things. + */ + + Window ignored1, ignored2; + Window *children; + int n_children; + int i; + + /* Normally XQueryTree() means "must grab server" but here + * we don't, since we know we won't manage any new windows + * or restack any windows before using the XQueryTree results. + */ + + meta_error_trap_push (screen->display); + + XQueryTree (screen->display->xdisplay, + screen->xroot, + &ignored1, &ignored2, &children, &n_children); + + if (meta_error_trap_pop (screen->display)) + { + meta_topic (META_DEBUG_STACK, + "Error querying root children to raise window 0x%lx\n", + xwindow); + return; + } + + /* Children are in order from bottom to top. We want to + * find the topmost managed child, then configure + * our window to be above it. + */ + i = n_children - 1; + while (i >= 0) + { + if (children[i] == xwindow) + { + /* Do nothing. This means we're already the topmost managed + * window, but it DOES NOT mean we are already just above + * the topmost managed window. This is important because if + * an override redirect window is up, and we map a new + * managed window, the new window is probably above the old + * popup by default, and we want to push it below that + * popup. So keep looking for a sibling managed window + * to be moved below. + */ + } + else if (meta_display_lookup_x_window (screen->display, + children[i]) != NULL) + { + XWindowChanges changes; + + /* children[i] is the topmost managed child */ + meta_topic (META_DEBUG_STACK, + "Moving 0x%lx above topmost managed child window 0x%lx\n", + xwindow, children[i]); + + changes.sibling = children[i]; + changes.stack_mode = Above; + + meta_error_trap_push (screen->display); + XConfigureWindow (screen->display->xdisplay, + xwindow, + CWSibling | CWStackMode, + &changes); + meta_error_trap_pop (screen->display); + + break; + } + + --i; + } + + if (i < 0) + { + /* No sibling to use, just lower ourselves to the bottom + * to be sure we're below any override redirect windows. + */ + meta_error_trap_push (screen->display); + XLowerWindow (screen->display->xdisplay, + xwindow); + meta_error_trap_pop (screen->display); + } + + if (children) + XFree (children); +} + static void meta_stack_sync_to_server (MetaStack *stack) { @@ -696,10 +788,10 @@ meta_stack_sync_to_server (MetaStack *stack) /* Move *newp below last_window */ if (last_window == None) { - meta_topic (META_DEBUG_STACK, "Raising window 0x%lx to the top\n", *newp); - - XRaiseWindow (stack->screen->display->xdisplay, - *newp); + meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp); + + raise_window_relative_to_managed_windows (stack->screen, + *newp); } else { diff --git a/src/tools/metacity-window-demo.c b/src/tools/metacity-window-demo.c index 73b27c478..825f6b751 100644 --- a/src/tools/metacity-window-demo.c +++ b/src/tools/metacity-window-demo.c @@ -310,6 +310,28 @@ menu_cb (gpointer callback_data, gtk_widget_show_all (window); } +static void +override_redirect_cb (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *label; + + window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_title (GTK_WINDOW (window), "Override Redirect"); + + vbox = gtk_vbox_new (FALSE, 0); + + gtk_container_add (GTK_CONTAINER (window), vbox); + + label = gtk_label_new ("This is an override\nredirect window\nand should not be managed"); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + gtk_widget_show_all (window); +} + static gboolean focus_in_event_cb (GtkWidget *window, GdkEvent *event, @@ -522,7 +544,8 @@ static GtkItemFactoryEntry menu_items[] = { "/Windows/_All docks", NULL, dock_cb, DOCK_ALL, NULL }, { "/Windows/Des_ktop", NULL, desktop_cb, 0, NULL }, { "/Windows/Me_nu", NULL, menu_cb, 0, NULL }, - { "/Windows/Tool_bar", NULL, toolbar_cb, 0, NULL } + { "/Windows/Tool_bar", NULL, toolbar_cb, 0, NULL }, + { "/Windows/Override Redirect", NULL, override_redirect_cb, 0, NULL } }; static void