avoid focusing a window on tab popup popdown

2001-08-29  Havoc Pennington  <hp@pobox.com>

	* 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
This commit is contained in:
Havoc Pennington 2001-08-30 04:01:38 +00:00 committed by Havoc Pennington
parent 6d31d4756e
commit 3e1c68b88a
11 changed files with 237 additions and 115 deletions

View File

@ -1,3 +1,11 @@
2001-08-29 Havoc Pennington <hp@pobox.com>
* 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 <hp@redhat.com> 2001-08-29 Havoc Pennington <hp@redhat.com>
* src/tabpopup.c: Switch back to outline. * src/tabpopup.c: Switch back to outline.

View File

@ -23,24 +23,6 @@
#include "frame.h" #include "frame.h"
#include "workspace.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 void
meta_core_get_frame_size (Display *xdisplay, meta_core_get_frame_size (Display *xdisplay,
Window frame_xwindow, Window frame_xwindow,
@ -510,3 +492,14 @@ meta_core_set_screen_cursor (Display *xdisplay,
meta_screen_set_cursor (window->screen, cursor); 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);
}

View File

@ -28,10 +28,6 @@
#include "frames.h" #include "frames.h"
#include "common.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, void meta_core_get_frame_size (Display *xdisplay,
Window frame_xwindow, Window frame_xwindow,
int *width, int *width,
@ -128,6 +124,12 @@ void meta_core_set_screen_cursor (Display *xdisplay,
Window frame_on_screen, Window frame_on_screen,
MetaCursor cursor); 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 #endif

View File

@ -288,6 +288,8 @@ meta_display_open (const char *name)
display->last_button_num = 0; display->last_button_num = 0;
display->is_double_click = FALSE; display->is_double_click = FALSE;
display->last_ignored_unmap_serial = 0;
display->grab_op = META_GRAB_OP_NONE; display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL; display->grab_window = NULL;
@ -644,6 +646,16 @@ event_callback (XEvent *event,
display->last_button_xwindow = event->xbutton.window; display->last_button_xwindow = event->xbutton.window;
display->last_button_time = event->xbutton.time; 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); modified = event_get_modified_window (display, event);
@ -728,7 +740,7 @@ event_callback (XEvent *event,
break; break;
case EnterNotify: case EnterNotify:
/* do this even if window->has_focus to avoid races */ /* 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); meta_window_focus (window, event->xcrossing.time);
break; break;
case LeaveNotify: case LeaveNotify:
@ -1263,8 +1275,9 @@ meta_spew_event (MetaDisplay *display,
else else
winname = g_strdup_printf ("0x%lx", event->xany.window); winname = g_strdup_printf ("0x%lx", event->xany.window);
meta_verbose ("%s on %s%s %s\n", name, winname, meta_verbose ("%s on %s%s %s serial %lu\n", name, winname,
extra ? ":" : "", extra ? extra : ""); extra ? ":" : "", extra ? extra : "",
event->xany.serial);
g_free (winname); 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);
}

View File

@ -124,6 +124,8 @@ struct _MetaDisplay
Window last_button_xwindow; Window last_button_xwindow;
int last_button_num; int last_button_num;
guint is_double_click : 1; guint is_double_click : 1;
unsigned long last_ignored_unmap_serial;
/* current window operation */ /* current window operation */
MetaGrabOp grab_op; MetaGrabOp grab_op;
@ -189,5 +191,7 @@ void meta_display_grab_window_buttons (MetaDisplay *display,
void meta_display_ungrab_window_buttons (MetaDisplay *display, void meta_display_ungrab_window_buttons (MetaDisplay *display,
Window xwindow); Window xwindow);
/* make a request to ensure the event serial has changed */
void meta_display_increment_event_serial (MetaDisplay *display);
#endif #endif

View File

@ -220,7 +220,11 @@ meta_window_place (MetaWindow *window,
*/ */
meta_verbose ("Placing window %s\n", window->desc); 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) if (window->xtransient_for != None)
{ {
/* Center horizontally, at top of parent vertically */ /* Center horizontally, at top of parent vertically */

View File

@ -491,6 +491,33 @@ meta_screen_ensure_tab_popup (MetaScreen *screen)
entries[i].y = r.y; entries[i].y = r.y;
entries[i].width = r.width; entries[i].width = r.width;
entries[i].height = r.height; 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; ++i;
tmp = tmp->next; tmp = tmp->next;

View File

@ -19,14 +19,14 @@
* 02111-1307, USA. * 02111-1307, USA.
*/ */
#include "ui.h"
#include "util.h" #include "util.h"
#include "core.h"
#include "tabpopup.h"
#include <math.h> #include <math.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#define OUTSIDE_SELECT_RECT 2 #define OUTSIDE_SELECT_RECT 2
#define INSIDE_SELECT_RECT 2 #define INSIDE_SELECT_RECT 2
#define OUTLINE_WIDTH 5
typedef struct _TabEntry TabEntry; typedef struct _TabEntry TabEntry;
@ -37,6 +37,7 @@ struct _TabEntry
GdkPixbuf *icon; GdkPixbuf *icon;
GtkWidget *widget; GtkWidget *widget;
GdkRectangle rect; GdkRectangle rect;
GdkRectangle inner_rect;
}; };
struct _MetaTabPopup struct _MetaTabPopup
@ -60,35 +61,31 @@ outline_window_expose (GtkWidget *widget,
{ {
MetaTabPopup *popup; MetaTabPopup *popup;
int w, h; int w, h;
int icon_x, icon_y; TabEntry *te;
popup = data; popup = data;
if (popup->current_selected_entry == NULL) if (popup->current_selected_entry == NULL)
return FALSE; return FALSE;
te = popup->current_selected_entry;
gdk_window_get_size (widget->window, &w, &h); gdk_window_get_size (widget->window, &w, &h);
gdk_draw_rectangle (widget->window, gdk_draw_rectangle (widget->window,
widget->style->white_gc, widget->style->white_gc,
TRUE, FALSE,
OUTLINE_WIDTH, OUTLINE_WIDTH, 0, 0,
w - OUTLINE_WIDTH * 2, te->rect.width - 1,
h - OUTLINE_WIDTH * 2); te->rect.height - 1);
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);
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; return FALSE;
} }
@ -101,6 +98,8 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries)
int width; int width;
int height; int height;
GtkWidget *table; GtkWidget *table;
GtkWidget *vbox;
GtkWidget *align;
GList *tmp; GList *tmp;
GtkWidget *frame; GtkWidget *frame;
int max_label_width; 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); popup->outline_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_widget_set_app_paintable (popup->outline_window, TRUE); gtk_widget_set_app_paintable (popup->outline_window, TRUE);
gtk_widget_realize (popup->outline_window); gtk_widget_realize (popup->outline_window);
#if 0
g_signal_connect (G_OBJECT (popup->outline_window), "expose_event", g_signal_connect (G_OBJECT (popup->outline_window), "expose_event",
G_CALLBACK (outline_window_expose), popup); G_CALLBACK (outline_window_expose), popup);
#endif
popup->window = gtk_window_new (GTK_WINDOW_POPUP); popup->window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_position (GTK_WINDOW (popup->window), 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.y = entries[i].y;
te->rect.width = entries[i].width; te->rect.width = entries[i].width;
te->rect.height = entries[i].height; 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); tab_entries = g_list_prepend (tab_entries, te);
@ -155,7 +158,8 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries)
if (i % width) if (i % width)
height += 1; 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); frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); 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), gtk_container_add (GTK_CONTAINER (popup->window),
frame); frame);
gtk_container_add (GTK_CONTAINER (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 (""); popup->label = gtk_label_new ("");
gtk_misc_set_padding (GTK_MISC (popup->label), 3, 3);
gtk_table_attach (GTK_TABLE (table),
popup->label, gtk_box_pack_end (GTK_BOX (vbox), popup->label, FALSE, FALSE, 0);
0, width, height, height + 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3, 3);
max_label_width = 0; max_label_width = 0;
top = 0; top = 0;
@ -205,7 +211,7 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries)
gtk_table_attach (GTK_TABLE (table), gtk_table_attach (GTK_TABLE (table),
te->widget, te->widget,
left, right, top, bottom, left, right, top, bottom,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0,
0, 0); 0, 0);
/* Efficiency rules! */ /* Efficiency rules! */
@ -227,8 +233,10 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries)
/* remove all the temporary text */ /* remove all the temporary text */
gtk_label_set_text (GTK_LABEL (popup->label), ""); gtk_label_set_text (GTK_LABEL (popup->label), "");
max_label_width += 20; /* add random padding */
gtk_window_set_default_size (GTK_WINDOW (popup->window), gtk_window_set_default_size (GTK_WINDOW (popup->window),
max_label_width + 20 /* random number */, max_label_width,
-1); -1);
return popup; return popup;
@ -267,15 +275,20 @@ meta_ui_tab_popup_set_showing (MetaTabPopup *popup,
if (showing) if (showing)
gtk_widget_show_all (popup->window); gtk_widget_show_all (popup->window);
else else
gtk_widget_hide (popup->window); {
gtk_widget_hide (popup->window);
meta_core_increment_event_serial (gdk_display);
}
} }
static void static void
display_entry (MetaTabPopup *popup, display_entry (MetaTabPopup *popup,
TabEntry *te) TabEntry *te)
{ {
GdkRectangle inner;
GdkRectangle rect; GdkRectangle rect;
GdkRegion *region;
GdkRegion *inner_region;
if (popup->current_selected_entry) if (popup->current_selected_entry)
unselect_image (popup->current_selected_entry->widget); unselect_image (popup->current_selected_entry->widget);
@ -285,42 +298,34 @@ display_entry (MetaTabPopup *popup,
/* Do stuff behind gtk's back */ /* Do stuff behind gtk's back */
gdk_window_hide (popup->outline_window->window); gdk_window_hide (popup->outline_window->window);
meta_core_increment_event_serial (gdk_display);
rect = te->rect; rect = te->rect;
rect.x = 0; rect.x = 0;
rect.y = 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, gdk_window_move_resize (popup->outline_window->window,
te->rect.x, te->rect.y, te->rect.x, te->rect.y,
te->rect.width, te->rect.height); te->rect.width, te->rect.height);
gdk_window_set_background (popup->outline_window->window, gdk_window_set_background (popup->outline_window->window,
&popup->outline_window->style->black); &popup->outline_window->style->black);
region = gdk_region_rectangle (&rect); region = gdk_region_rectangle (&rect);
inner_region = gdk_region_rectangle (&inner); inner_region = gdk_region_rectangle (&te->inner_rect);
gdk_region_subtract (region, inner_region); gdk_region_subtract (region, inner_region);
gdk_region_destroy (inner_region); gdk_region_destroy (inner_region);
gdk_window_shape_combine_region (popup->outline_window->window, gdk_window_shape_combine_region (popup->outline_window->window,
region, region,
0, 0); 0, 0);
/* This should piss off gtk a bit, but we don't want to raise gdk_region_destroy (region);
* above the tab popup
*/ /* This should piss off gtk a bit, but we don't want to raise
gdk_window_show_unraised (popup->outline_window->window); * above the tab popup
} */
gdk_window_show_unraised (popup->outline_window->window);
/* Must be before we handle an expose for the outline window */ /* Must be before we handle an expose for the outline window */
popup->current_selected_entry = te; popup->current_selected_entry = te;

55
src/tabpopup.h Normal file
View File

@ -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 <X11/Xlib.h>
#include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
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

View File

@ -171,7 +171,7 @@ meta_ui_unmap_frame (MetaUI *ui,
window = gdk_xid_table_lookup (xwindow); window = gdk_xid_table_lookup (xwindow);
if (window) if (window)
gdk_window_hide (window); gdk_window_hide (window);
} }
@ -270,7 +270,10 @@ meta_image_window_set_showing (MetaImageWindow *iw,
if (showing) if (showing)
gtk_widget_show_all (iw->window); gtk_widget_show_all (iw->window);
else else
gtk_widget_hide (iw->window); {
gtk_widget_hide (iw->window);
meta_core_increment_event_serial (gdk_display);
}
} }
void void
@ -424,3 +427,20 @@ meta_ui_get_default_window_icon (MetaUI *ui)
GTK_ICON_SIZE_LARGE_TOOLBAR, GTK_ICON_SIZE_LARGE_TOOLBAR,
NULL); 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;
}

View File

@ -101,6 +101,7 @@ void meta_image_window_set_position (MetaImageWindow *iw,
int x, int x,
int y); int y);
/* FIXME these lack a display arg */
GdkPixbuf* meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest, GdkPixbuf* meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest,
Window xwindow, Window xwindow,
int src_x, int src_x,
@ -128,27 +129,10 @@ void meta_ui_pop_delay_exposes (MetaUI *ui);
GdkPixbuf* meta_ui_get_default_window_icon (MetaUI *ui); GdkPixbuf* meta_ui_get_default_window_icon (MetaUI *ui);
typedef struct _MetaTabEntry MetaTabEntry; gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay,
typedef struct _MetaTabPopup MetaTabPopup; Window xwindow);
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);
#include "tabpopup.h"
#endif #endif