From 3e1c68b88a5e4d0fd688929fafe280efe73734f8 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 30 Aug 2001 04:01:38 +0000 Subject: [PATCH] avoid focusing a window on tab popup popdown 2001-08-29 Havoc Pennington * src/display.c (event_callback): avoid focusing a window on tab popup popdown * src/screen.c (meta_screen_ensure_tab_popup): compute frame outline size here --- ChangeLog | 8 +++ src/core.c | 29 ++++------- src/core.h | 10 ++-- src/display.c | 26 +++++++-- src/display.h | 4 ++ src/place.c | 6 ++- src/screen.c | 27 ++++++++++ src/tabpopup.c | 139 +++++++++++++++++++++++++------------------------ src/tabpopup.h | 55 +++++++++++++++++++ src/ui.c | 24 ++++++++- src/ui.h | 24 ++------- 11 files changed, 237 insertions(+), 115 deletions(-) create mode 100644 src/tabpopup.h diff --git a/ChangeLog b/ChangeLog index 3f1a1e8c9..bc8bf05bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2001-08-29 Havoc Pennington + + * src/display.c (event_callback): avoid focusing a window on tab + popup popdown + + * src/screen.c (meta_screen_ensure_tab_popup): compute frame + outline size here + 2001-08-29 Havoc Pennington * src/tabpopup.c: Switch back to outline. diff --git a/src/core.c b/src/core.c index 622397cf1..ae36b4bcf 100644 --- a/src/core.c +++ b/src/core.c @@ -23,24 +23,6 @@ #include "frame.h" #include "workspace.h" -void -meta_core_get_outer_rect (Display *xdisplay, - Window frame_xwindow, - GdkRectangle *rect) -{ - MetaDisplay *display; - MetaWindow *window; - MetaRectangle r; - - display = meta_display_for_x_display (xdisplay); - window = meta_display_lookup_x_window (display, frame_xwindow); - - if (window == NULL || window->frame == NULL) - meta_bug ("No such frame window 0x%lx!\n", frame_xwindow); - - -} - void meta_core_get_frame_size (Display *xdisplay, Window frame_xwindow, @@ -510,3 +492,14 @@ meta_core_set_screen_cursor (Display *xdisplay, meta_screen_set_cursor (window->screen, cursor); } + +void +meta_core_increment_event_serial (Display *xdisplay) +{ + MetaDisplay *display; + + display = meta_display_for_x_display (xdisplay); + + meta_display_increment_event_serial (display); +} + diff --git a/src/core.h b/src/core.h index 766bbb047..24b2c6339 100644 --- a/src/core.h +++ b/src/core.h @@ -28,10 +28,6 @@ #include "frames.h" #include "common.h" -void meta_core_get_outer_rect (Display *xdisplay, - Window frame_xwindow, - GdkRectangle *rect); - void meta_core_get_frame_size (Display *xdisplay, Window frame_xwindow, int *width, @@ -128,6 +124,12 @@ void meta_core_set_screen_cursor (Display *xdisplay, Window frame_on_screen, MetaCursor cursor); +/* Used because we ignore EnterNotify when a window is unmapped that + * really shouldn't cause focus changes, by comparing the event serial + * of the EnterNotify and the UnmapNotify. + */ +void meta_core_increment_event_serial (Display *display); + #endif diff --git a/src/display.c b/src/display.c index f709f4199..2a17d41e8 100644 --- a/src/display.c +++ b/src/display.c @@ -288,6 +288,8 @@ meta_display_open (const char *name) display->last_button_num = 0; display->is_double_click = FALSE; + display->last_ignored_unmap_serial = 0; + display->grab_op = META_GRAB_OP_NONE; display->grab_window = NULL; @@ -644,6 +646,16 @@ event_callback (XEvent *event, display->last_button_xwindow = event->xbutton.window; display->last_button_time = event->xbutton.time; } + else if (event->type == UnmapNotify) + { + if (meta_ui_window_should_not_cause_focus (display->xdisplay, + event->xunmap.window)) + { + display->last_ignored_unmap_serial = event->xany.serial; + meta_verbose ("Will not focus on EnterNotify with serial %lu\n", + display->last_ignored_unmap_serial); + } + } modified = event_get_modified_window (display, event); @@ -728,7 +740,7 @@ event_callback (XEvent *event, break; case EnterNotify: /* do this even if window->has_focus to avoid races */ - if (window) + if (window && event->xany.serial != display->last_ignored_unmap_serial) meta_window_focus (window, event->xcrossing.time); break; case LeaveNotify: @@ -1263,8 +1275,9 @@ meta_spew_event (MetaDisplay *display, else winname = g_strdup_printf ("0x%lx", event->xany.window); - meta_verbose ("%s on %s%s %s\n", name, winname, - extra ? ":" : "", extra ? extra : ""); + meta_verbose ("%s on %s%s %s serial %lu\n", name, winname, + extra ? ":" : "", extra ? extra : "", + event->xany.serial); g_free (winname); @@ -1645,3 +1658,10 @@ meta_display_ungrab_window_buttons (MetaDisplay *display, } } +void +meta_display_increment_event_serial (MetaDisplay *display) +{ + /* We just make some random X request */ + XDeleteProperty (display->xdisplay, display->leader_window, + display->atom_motif_wm_hints); +} diff --git a/src/display.h b/src/display.h index a94aa8f50..b2552dab4 100644 --- a/src/display.h +++ b/src/display.h @@ -124,6 +124,8 @@ struct _MetaDisplay Window last_button_xwindow; int last_button_num; guint is_double_click : 1; + + unsigned long last_ignored_unmap_serial; /* current window operation */ MetaGrabOp grab_op; @@ -189,5 +191,7 @@ void meta_display_grab_window_buttons (MetaDisplay *display, void meta_display_ungrab_window_buttons (MetaDisplay *display, Window xwindow); +/* make a request to ensure the event serial has changed */ +void meta_display_increment_event_serial (MetaDisplay *display); #endif diff --git a/src/place.c b/src/place.c index 1e091f4d0..0226af412 100644 --- a/src/place.c +++ b/src/place.c @@ -220,7 +220,11 @@ meta_window_place (MetaWindow *window, */ meta_verbose ("Placing window %s\n", window->desc); - + + /* FIXME copying Mac, when placing a dialog + * put it at 1/5 down and horizontally centered + */ + if (window->xtransient_for != None) { /* Center horizontally, at top of parent vertically */ diff --git a/src/screen.c b/src/screen.c index 22ab84e44..cb486f23d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -491,6 +491,33 @@ meta_screen_ensure_tab_popup (MetaScreen *screen) entries[i].y = r.y; entries[i].width = r.width; entries[i].height = r.height; + + /* Find inside of highlight rectangle to be used + * when window is outlined for tabbing. + * This should be the size of the east/west frame, + * and the size of the south frame, on those sides. + * on the top it should be the size of the south frame + * edge. + */ + if (window->frame) + { + int south = window->frame->rect.height - window->frame->child_y - + window->rect.height; + int east = window->frame->child_x; + entries[i].inner_x = east; + entries[i].inner_y = south; + entries[i].inner_width = window->rect.width; + entries[i].inner_height = window->frame->rect.height - south * 2; + } + else + { + /* Use an arbitrary border size */ +#define OUTLINE_WIDTH 5 + entries[i].inner_x = OUTLINE_WIDTH; + entries[i].inner_y = OUTLINE_WIDTH; + entries[i].inner_width = window->rect.width - OUTLINE_WIDTH * 2; + entries[i].inner_height = window->rect.height - OUTLINE_WIDTH * 2; + } ++i; tmp = tmp->next; diff --git a/src/tabpopup.c b/src/tabpopup.c index 34e325b06..47edfba95 100644 --- a/src/tabpopup.c +++ b/src/tabpopup.c @@ -19,14 +19,14 @@ * 02111-1307, USA. */ -#include "ui.h" #include "util.h" +#include "core.h" +#include "tabpopup.h" #include #include #define OUTSIDE_SELECT_RECT 2 #define INSIDE_SELECT_RECT 2 -#define OUTLINE_WIDTH 5 typedef struct _TabEntry TabEntry; @@ -37,6 +37,7 @@ struct _TabEntry GdkPixbuf *icon; GtkWidget *widget; GdkRectangle rect; + GdkRectangle inner_rect; }; struct _MetaTabPopup @@ -60,35 +61,31 @@ outline_window_expose (GtkWidget *widget, { MetaTabPopup *popup; int w, h; - int icon_x, icon_y; + TabEntry *te; popup = data; if (popup->current_selected_entry == NULL) return FALSE; + + te = popup->current_selected_entry; gdk_window_get_size (widget->window, &w, &h); gdk_draw_rectangle (widget->window, widget->style->white_gc, - TRUE, - OUTLINE_WIDTH, OUTLINE_WIDTH, - w - OUTLINE_WIDTH * 2, - h - OUTLINE_WIDTH * 2); - - icon_x = (w - gdk_pixbuf_get_width (popup->current_selected_entry->icon)) / 2; - icon_y = (h - gdk_pixbuf_get_height (popup->current_selected_entry->icon)) / 2; - - gdk_pixbuf_render_to_drawable_alpha (popup->current_selected_entry->icon, - widget->window, - 0, 0, icon_x, icon_y, - gdk_pixbuf_get_width (popup->current_selected_entry->icon), - gdk_pixbuf_get_height (popup->current_selected_entry->icon), - GDK_PIXBUF_ALPHA_FULL, - 128, - GDK_RGB_DITHER_NORMAL, - 0, 0); + FALSE, + 0, 0, + te->rect.width - 1, + te->rect.height - 1); + gdk_draw_rectangle (widget->window, + widget->style->white_gc, + FALSE, + te->inner_rect.x - 1, te->inner_rect.y - 1, + te->inner_rect.width + 1, + te->inner_rect.height + 1); + return FALSE; } @@ -101,6 +98,8 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries) int width; int height; GtkWidget *table; + GtkWidget *vbox; + GtkWidget *align; GList *tmp; GtkWidget *frame; int max_label_width; @@ -110,10 +109,9 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries) popup->outline_window = gtk_window_new (GTK_WINDOW_POPUP); gtk_widget_set_app_paintable (popup->outline_window, TRUE); gtk_widget_realize (popup->outline_window); -#if 0 + g_signal_connect (G_OBJECT (popup->outline_window), "expose_event", G_CALLBACK (outline_window_expose), popup); -#endif popup->window = gtk_window_new (GTK_WINDOW_POPUP); gtk_window_set_position (GTK_WINDOW (popup->window), @@ -142,6 +140,11 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries) te->rect.y = entries[i].y; te->rect.width = entries[i].width; te->rect.height = entries[i].height; + + te->inner_rect.x = entries[i].inner_x; + te->inner_rect.y = entries[i].inner_y; + te->inner_rect.width = entries[i].inner_width; + te->inner_rect.height = entries[i].inner_height; tab_entries = g_list_prepend (tab_entries, te); @@ -155,7 +158,8 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries) if (i % width) height += 1; - table = gtk_table_new (height + 1, width, FALSE); + table = gtk_table_new (height, width, FALSE); + vbox = gtk_vbox_new (FALSE, 0); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); @@ -163,17 +167,19 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries) gtk_container_add (GTK_CONTAINER (popup->window), frame); gtk_container_add (GTK_CONTAINER (frame), - table); + vbox); + align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); + + gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0); + + gtk_container_add (GTK_CONTAINER (align), + table); popup->label = gtk_label_new (""); - - gtk_table_attach (GTK_TABLE (table), - popup->label, - 0, width, height, height + 1, - GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, - 3, 3); - + gtk_misc_set_padding (GTK_MISC (popup->label), 3, 3); + + gtk_box_pack_end (GTK_BOX (vbox), popup->label, FALSE, FALSE, 0); max_label_width = 0; top = 0; @@ -205,7 +211,7 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries) gtk_table_attach (GTK_TABLE (table), te->widget, left, right, top, bottom, - GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, + 0, 0, 0, 0); /* Efficiency rules! */ @@ -227,8 +233,10 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries) /* remove all the temporary text */ gtk_label_set_text (GTK_LABEL (popup->label), ""); + max_label_width += 20; /* add random padding */ + gtk_window_set_default_size (GTK_WINDOW (popup->window), - max_label_width + 20 /* random number */, + max_label_width, -1); return popup; @@ -267,15 +275,20 @@ meta_ui_tab_popup_set_showing (MetaTabPopup *popup, if (showing) gtk_widget_show_all (popup->window); else - gtk_widget_hide (popup->window); + { + gtk_widget_hide (popup->window); + meta_core_increment_event_serial (gdk_display); + } } static void display_entry (MetaTabPopup *popup, TabEntry *te) { - GdkRectangle inner; GdkRectangle rect; + GdkRegion *region; + GdkRegion *inner_region; + if (popup->current_selected_entry) unselect_image (popup->current_selected_entry->widget); @@ -285,42 +298,34 @@ display_entry (MetaTabPopup *popup, /* Do stuff behind gtk's back */ gdk_window_hide (popup->outline_window->window); - + meta_core_increment_event_serial (gdk_display); + rect = te->rect; rect.x = 0; rect.y = 0; - - inner = rect; - inner.x += OUTLINE_WIDTH; - inner.y += OUTLINE_WIDTH; - inner.width -= OUTLINE_WIDTH * 2; - inner.height -= OUTLINE_WIDTH * 2; - if (inner.width >= 0 || inner.height >= 0) - { - GdkRegion *region; - GdkRegion *inner_region; - gdk_window_move_resize (popup->outline_window->window, - te->rect.x, te->rect.y, - te->rect.width, te->rect.height); - - gdk_window_set_background (popup->outline_window->window, - &popup->outline_window->style->black); - - region = gdk_region_rectangle (&rect); - inner_region = gdk_region_rectangle (&inner); - gdk_region_subtract (region, inner_region); - gdk_region_destroy (inner_region); - - gdk_window_shape_combine_region (popup->outline_window->window, - region, - 0, 0); - - /* This should piss off gtk a bit, but we don't want to raise - * above the tab popup - */ - gdk_window_show_unraised (popup->outline_window->window); - } + gdk_window_move_resize (popup->outline_window->window, + te->rect.x, te->rect.y, + te->rect.width, te->rect.height); + + gdk_window_set_background (popup->outline_window->window, + &popup->outline_window->style->black); + + region = gdk_region_rectangle (&rect); + inner_region = gdk_region_rectangle (&te->inner_rect); + gdk_region_subtract (region, inner_region); + gdk_region_destroy (inner_region); + + gdk_window_shape_combine_region (popup->outline_window->window, + region, + 0, 0); + + gdk_region_destroy (region); + + /* This should piss off gtk a bit, but we don't want to raise + * above the tab popup + */ + gdk_window_show_unraised (popup->outline_window->window); /* Must be before we handle an expose for the outline window */ popup->current_selected_entry = te; diff --git a/src/tabpopup.h b/src/tabpopup.h new file mode 100644 index 000000000..f861f02f3 --- /dev/null +++ b/src/tabpopup.h @@ -0,0 +1,55 @@ +/* Metacity tab popup window */ + +/* + * Copyright (C) 2001 Havoc Pennington + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_TABPOPUP_H +#define META_TABPOPUP_H + +/* Don't include gtk.h or gdk.h here */ +#include "common.h" +#include +#include +#include + +typedef struct _MetaTabEntry MetaTabEntry; +typedef struct _MetaTabPopup MetaTabPopup; + +struct _MetaTabEntry +{ + Window xwindow; + const char *title; + GdkPixbuf *icon; + int x, y, width, height; + int inner_x, inner_y, inner_width, inner_height; +}; + +MetaTabPopup* meta_ui_tab_popup_new (const MetaTabEntry *entries); +void meta_ui_tab_popup_free (MetaTabPopup *popup); +void meta_ui_tab_popup_set_showing (MetaTabPopup *popup, + gboolean showing); +void meta_ui_tab_popup_forward (MetaTabPopup *popup); +void meta_ui_tab_popup_backward (MetaTabPopup *popup); +Window meta_ui_tab_popup_get_selected (MetaTabPopup *popup); +void meta_ui_tab_popup_select (MetaTabPopup *popup, + Window xwindow); + + +#endif + diff --git a/src/ui.c b/src/ui.c index ff9d1ba8a..7dd50e802 100644 --- a/src/ui.c +++ b/src/ui.c @@ -171,7 +171,7 @@ meta_ui_unmap_frame (MetaUI *ui, window = gdk_xid_table_lookup (xwindow); - if (window) + if (window) gdk_window_hide (window); } @@ -270,7 +270,10 @@ meta_image_window_set_showing (MetaImageWindow *iw, if (showing) gtk_widget_show_all (iw->window); else - gtk_widget_hide (iw->window); + { + gtk_widget_hide (iw->window); + meta_core_increment_event_serial (gdk_display); + } } void @@ -424,3 +427,20 @@ meta_ui_get_default_window_icon (MetaUI *ui) GTK_ICON_SIZE_LARGE_TOOLBAR, NULL); } + +gboolean +meta_ui_window_should_not_cause_focus (Display *xdisplay, + Window xwindow) +{ + GdkWindow *window; + + window = gdk_xid_table_lookup (xwindow); + + /* we shouldn't cause focus if we're an override redirect + * toplevel which is not foreign + */ + if (window && gdk_window_get_type (window) == GDK_WINDOW_TEMP) + return TRUE; + else + return FALSE; +} diff --git a/src/ui.h b/src/ui.h index 6f6adbfa5..11417c0e1 100644 --- a/src/ui.h +++ b/src/ui.h @@ -101,6 +101,7 @@ void meta_image_window_set_position (MetaImageWindow *iw, int x, int y); +/* FIXME these lack a display arg */ GdkPixbuf* meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest, Window xwindow, int src_x, @@ -128,27 +129,10 @@ void meta_ui_pop_delay_exposes (MetaUI *ui); GdkPixbuf* meta_ui_get_default_window_icon (MetaUI *ui); -typedef struct _MetaTabEntry MetaTabEntry; -typedef struct _MetaTabPopup MetaTabPopup; - -struct _MetaTabEntry -{ - Window xwindow; - const char *title; - GdkPixbuf *icon; - int x, y, width, height; -}; - -MetaTabPopup* meta_ui_tab_popup_new (const MetaTabEntry *entries); -void meta_ui_tab_popup_free (MetaTabPopup *popup); -void meta_ui_tab_popup_set_showing (MetaTabPopup *popup, - gboolean showing); -void meta_ui_tab_popup_forward (MetaTabPopup *popup); -void meta_ui_tab_popup_backward (MetaTabPopup *popup); -Window meta_ui_tab_popup_get_selected (MetaTabPopup *popup); -void meta_ui_tab_popup_select (MetaTabPopup *popup, - Window xwindow); +gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay, + Window xwindow); +#include "tabpopup.h" #endif