remove XSync, error traps already do that

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

	* src/display.c (meta_display_grab_window_buttons): remove XSync,
	error traps already do that
	(meta_display_grab_window_buttons): implement

	* src/keybindings.c:
	src/display.c: wire up the tab window, it rulez!
This commit is contained in:
Havoc Pennington 2001-08-19 18:09:10 +00:00 committed by Havoc Pennington
parent f70993be97
commit b2444df787
13 changed files with 555 additions and 166 deletions

View File

@ -1,3 +1,12 @@
2001-08-19 Havoc Pennington <hp@pobox.com>
* src/display.c (meta_display_grab_window_buttons): remove XSync,
error traps already do that
(meta_display_grab_window_buttons): implement
* src/keybindings.c:
src/display.c: wire up the tab window, it rulez!
2001-08-19 Havoc Pennington <hp@pobox.com> 2001-08-19 Havoc Pennington <hp@pobox.com>
* src/tabpopup.c: add prototype thingy to display windows we're * src/tabpopup.c: add prototype thingy to display windows we're

9
README
View File

@ -194,9 +194,12 @@ METACITY BUGS, NON-FEATURES, AND CAVEATS
- Should support click-to-focus as an option. - Should support click-to-focus as an option.
- Windows has a neat way of implementing Alt-Tab for - There is some sort of race condition with Alt-Tab that can
window cycling that I would like to copy. (The little sometimes result in the focus not moving.
popup window thing.)
- The focus rectangle around the icons in the Alt-Tab popup
is ugly, should use a GTK-like focus rectangle, or maybe
make it look selected, not sure.
- Should Metacity support flipping in right-to-left locales? - Should Metacity support flipping in right-to-left locales?
I don't know what window managers look like in a right-to-left I don't know what window managers look like in a right-to-left

View File

@ -67,9 +67,13 @@ typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu,
int workspace, int workspace,
gpointer data); gpointer data);
/* when changing this enum, there are various switch statements
* you have to update
*/
typedef enum typedef enum
{ {
META_GRAB_OP_NONE, META_GRAB_OP_NONE,
/* Mouse ops */ /* Mouse ops */
META_GRAB_OP_MOVING, META_GRAB_OP_MOVING,
META_GRAB_OP_RESIZING_SE, META_GRAB_OP_RESIZING_SE,
@ -80,6 +84,7 @@ typedef enum
META_GRAB_OP_RESIZING_NW, META_GRAB_OP_RESIZING_NW,
META_GRAB_OP_RESIZING_W, META_GRAB_OP_RESIZING_W,
META_GRAB_OP_RESIZING_E, META_GRAB_OP_RESIZING_E,
/* Keyboard ops */ /* Keyboard ops */
META_GRAB_OP_KEYBOARD_MOVING, META_GRAB_OP_KEYBOARD_MOVING,
META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN, META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
@ -87,6 +92,13 @@ typedef enum
META_GRAB_OP_KEYBOARD_RESIZING_N, META_GRAB_OP_KEYBOARD_RESIZING_N,
META_GRAB_OP_KEYBOARD_RESIZING_W, META_GRAB_OP_KEYBOARD_RESIZING_W,
META_GRAB_OP_KEYBOARD_RESIZING_E, META_GRAB_OP_KEYBOARD_RESIZING_E,
META_GRAB_OP_KEYBOARD_RESIZING_SE,
META_GRAB_OP_KEYBOARD_RESIZING_NE,
META_GRAB_OP_KEYBOARD_RESIZING_SW,
META_GRAB_OP_KEYBOARD_RESIZING_NW,
META_GRAB_OP_KEYBOARD_TABBING,
/* Frame button ops */ /* Frame button ops */
META_GRAB_OP_CLICKING_MINIMIZE, META_GRAB_OP_CLICKING_MINIMIZE,
META_GRAB_OP_CLICKING_MAXIMIZE, META_GRAB_OP_CLICKING_MAXIMIZE,

View File

@ -592,6 +592,11 @@ grab_op_is_keyboard (MetaGrabOp op)
case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_N:
case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_W:
case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_E:
case META_GRAB_OP_KEYBOARD_RESIZING_SE:
case META_GRAB_OP_KEYBOARD_RESIZING_NE:
case META_GRAB_OP_KEYBOARD_RESIZING_SW:
case META_GRAB_OP_KEYBOARD_RESIZING_NW:
case META_GRAB_OP_KEYBOARD_TABBING:
return TRUE; return TRUE;
break; break;
@ -1240,6 +1245,7 @@ meta_spew_event (MetaDisplay *display,
name = "MappingNotify"; name = "MappingNotify";
break; break;
default: default:
meta_verbose ("Unknown event type %d\n", event->xany.type);
name = "Unknown event type"; name = "Unknown event type";
break; break;
} }
@ -1453,9 +1459,9 @@ meta_display_begin_grab_op (MetaDisplay *display,
if (pointer_already_grabbed) if (pointer_already_grabbed)
display->grab_have_pointer = TRUE; display->grab_have_pointer = TRUE;
/* We XGrabPointer even if we already have an autograb, /* We XGrabPointer even if we already have an autograb,
* just to set the cursor and event mask * just to set the cursor and event mask
*/ */
cursor = xcursor_for_op (display, op); cursor = xcursor_for_op (display, op);
@ -1481,27 +1487,16 @@ meta_display_begin_grab_op (MetaDisplay *display,
return FALSE; return FALSE;
} }
switch (op) if (grab_op_is_keyboard (op))
{ {
case META_GRAB_OP_KEYBOARD_MOVING:
case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
case META_GRAB_OP_KEYBOARD_RESIZING_S:
case META_GRAB_OP_KEYBOARD_RESIZING_N:
case META_GRAB_OP_KEYBOARD_RESIZING_W:
case META_GRAB_OP_KEYBOARD_RESIZING_E:
if (meta_window_grab_all_keys (window)) if (meta_window_grab_all_keys (window))
display->grab_have_keyboard = TRUE; display->grab_have_keyboard = TRUE;
if (!display->grab_have_keyboard) if (!display->grab_have_keyboard)
{ {
meta_verbose ("XGrabKeyboard() failed\n"); meta_verbose ("grabbing all keys failed\n");
return FALSE; return FALSE;
} }
break;
default:
/* non-keyboard grab ops */
break;
} }
display->grab_op = op; display->grab_op = op;
@ -1520,6 +1515,10 @@ meta_display_begin_grab_op (MetaDisplay *display,
g_assert (display->grab_window != NULL); g_assert (display->grab_window != NULL);
g_assert (display->grab_op != META_GRAB_OP_NONE); g_assert (display->grab_op != META_GRAB_OP_NONE);
/* Do this last, after everything is set up. */
if (op == META_GRAB_OP_KEYBOARD_TABBING)
meta_screen_ensure_tab_popup (window->screen);
return TRUE; return TRUE;
} }
@ -1530,6 +1529,12 @@ meta_display_end_grab_op (MetaDisplay *display,
if (display->grab_op == META_GRAB_OP_NONE) if (display->grab_op == META_GRAB_OP_NONE)
return; return;
if (display->grab_op == META_GRAB_OP_KEYBOARD_TABBING)
{
meta_ui_tab_popup_free (display->grab_window->screen->tab_popup);
display->grab_window->screen->tab_popup = NULL;
}
if (display->grab_have_pointer) if (display->grab_have_pointer)
XUngrabPointer (display->xdisplay, timestamp); XUngrabPointer (display->xdisplay, timestamp);
@ -1549,6 +1554,11 @@ meta_display_grab_window_buttons (MetaDisplay *display,
*/ */
meta_verbose ("Grabbing window buttons for 0x%lx\n", xwindow); meta_verbose ("Grabbing window buttons for 0x%lx\n", xwindow);
/* FIXME If we ignored errors here instead of spewing, we could
* put one big error trap around the loop and avoid a bunch of
* XSync()
*/
{ {
int i = 1; int i = 1;
while (i < 4) while (i < 4)
@ -1562,11 +1572,10 @@ meta_display_grab_window_buttons (MetaDisplay *display,
PointerMotionMask | PointerMotionHintMask, PointerMotionMask | PointerMotionHintMask,
GrabModeAsync, GrabModeAsync, GrabModeAsync, GrabModeAsync,
False, None); False, None);
XSync (display->xdisplay, False);
result = meta_error_trap_pop (display); result = meta_error_trap_pop (display);
if (result != Success) if (result != Success)
meta_warning ("Failed to grab button %d with Mod1Mask for frame 0x%lx error code %d\n", meta_warning ("Failed to grab button %d with Mod1Mask for window 0x%lx error code %d\n",
i, xwindow, result); i, xwindow, result);
@ -1582,11 +1591,10 @@ meta_display_grab_window_buttons (MetaDisplay *display,
PointerMotionMask | PointerMotionHintMask, PointerMotionMask | PointerMotionHintMask,
GrabModeAsync, GrabModeAsync, GrabModeAsync, GrabModeAsync,
False, None); False, None);
XSync (display->xdisplay, False);
result = meta_error_trap_pop (display); result = meta_error_trap_pop (display);
if (result != Success) if (result != Success)
meta_warning ("Failed to grab button %d with ControlMask for frame 0x%lx error code %d\n", meta_warning ("Failed to grab button %d with ControlMask for window 0x%lx error code %d\n",
i, xwindow, result); i, xwindow, result);
} }
@ -1599,7 +1607,32 @@ void
meta_display_ungrab_window_buttons (MetaDisplay *display, meta_display_ungrab_window_buttons (MetaDisplay *display,
Window xwindow) Window xwindow)
{ {
/* FIXME If we ignored errors here instead of spewing, we could
* put one big error trap around the loop and avoid a bunch of
* XSync()
*/
int i = 1;
while (i < 4)
{
int result;
meta_error_trap_push (display);
XUngrabButton (display->xdisplay, i, Mod1Mask, xwindow);
result = meta_error_trap_pop (display);
if (result != Success)
meta_warning ("Failed to ungrab button %d with Mod1Mask for window 0x%lx error code %d\n",
i, xwindow, result);
meta_error_trap_push (display);
XUngrabButton (display->xdisplay, i, ControlMask, xwindow);
result = meta_error_trap_pop (display);
if (result != Success)
meta_warning ("Failed to ungrab button %d with ControlMask for window 0x%lx error code %d\n",
i, xwindow, result);
++i;
}
} }

View File

@ -62,9 +62,19 @@ static void handle_workspace_left (MetaDisplay *display,
XEvent *event, XEvent *event,
gpointer data); gpointer data);
static void handle_workspace_right (MetaDisplay *display, static void handle_workspace_right (MetaDisplay *display,
MetaWindow *window, MetaWindow *window,
XEvent *event, XEvent *event,
gpointer data); gpointer data);
static gboolean process_keyboard_move_grab (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
KeySym keysym);
static gboolean process_tab_grab (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
KeySym keysym);
typedef struct _MetaKeyBinding MetaKeyBinding; typedef struct _MetaKeyBinding MetaKeyBinding;
@ -281,10 +291,30 @@ meta_window_grab_all_keys (MetaWindow *window)
} }
else else
{ {
window->keys_grabbed = FALSE; /* Also grab the keyboard, so we get key releases and all key
window->all_keys_grabbed = TRUE; * presses
window->grab_on_frame = window->frame != NULL; */
return TRUE; meta_error_trap_push (window->display);
/* FIXME CurrentTime bogus */
XGrabKeyboard (window->display->xdisplay,
grabwindow, True,
GrabModeAsync, GrabModeAsync,
CurrentTime);
result = meta_error_trap_pop (window->display);
if (result != Success)
{
meta_verbose ("XGrabKeyboard() failed for window %s\n",
window->desc);
return FALSE;
}
meta_verbose ("Grabbed all keys on window %s\n", window->desc);
window->keys_grabbed = FALSE;
window->all_keys_grabbed = TRUE;
window->grab_on_frame = window->frame != NULL;
return TRUE;
} }
} }
@ -302,6 +332,8 @@ meta_window_ungrab_all_keys (MetaWindow *window)
XUngrabKey (window->display->xdisplay, XUngrabKey (window->display->xdisplay,
AnyKey, AnyModifier, AnyKey, AnyModifier,
grabwindow); grabwindow);
/* FIXME CurrentTime bogus */
XUngrabKeyboard (window->display->xdisplay, CurrentTime);
meta_error_trap_pop (window->display); meta_error_trap_pop (window->display);
window->grab_on_frame = FALSE; window->grab_on_frame = FALSE;
@ -317,29 +349,61 @@ static gboolean
is_modifier (MetaDisplay *display, is_modifier (MetaDisplay *display,
unsigned int keycode) unsigned int keycode)
{ {
int i; int i;
int map_size; int map_size;
XModifierKeymap *mod_keymap; XModifierKeymap *mod_keymap;
gboolean retval = FALSE; gboolean retval = FALSE;
/* FIXME this is ass-slow, cache the modmap */ /* FIXME this is ass-slow, cache the modmap */
mod_keymap = XGetModifierMapping (display->xdisplay); mod_keymap = XGetModifierMapping (display->xdisplay);
map_size = 8 * mod_keymap->max_keypermod; map_size = 8 * mod_keymap->max_keypermod;
i = 0; i = 0;
while (i < map_size) { while (i < map_size)
{
if (keycode == mod_keymap->modifiermap[i])
{
retval = TRUE;
break;
}
++i;
}
if (keycode == mod_keymap->modifiermap[i]) { XFreeModifiermap (mod_keymap);
retval = TRUE;
break;
}
++i;
}
XFreeModifiermap (mod_keymap); return retval;
}
return retval; #define MOD1_INDEX 3 /* shift, lock, control, mod1 */
static gboolean
is_mod1_key (MetaDisplay *display,
unsigned int keycode)
{
int i;
int end;
XModifierKeymap *mod_keymap;
gboolean retval = FALSE;
/* FIXME this is ass-slow, cache the modmap */
mod_keymap = XGetModifierMapping (display->xdisplay);
end = (MOD1_INDEX + 1) * mod_keymap->max_keypermod;
i = MOD1_INDEX * mod_keymap->max_keypermod;
while (i < end)
{
if (keycode == mod_keymap->modifiermap[i])
{
retval = TRUE;
break;
}
++i;
}
XFreeModifiermap (mod_keymap);
return retval;
} }
static void static void
@ -384,57 +448,89 @@ meta_display_process_key_event (MetaDisplay *display,
XKeysymToString (keysym), event->xkey.state, XKeysymToString (keysym), event->xkey.state,
window ? window->desc : "(no window)"); window ? window->desc : "(no window)");
if (window == NULL || !window->all_keys_grabbed) if (display->grab_op == META_GRAB_OP_NONE &&
(window == NULL || !window->all_keys_grabbed))
{ {
/* Do the normal keybindings */ /* Do the normal keybindings */
process_event (screen_bindings, display, NULL, event, keysym); process_event (screen_bindings, display, NULL, event, keysym);
if (window) if (window)
process_event (window_bindings, display, window, event, keysym); process_event (window_bindings, display, window, event, keysym);
return; return;
} }
if (display->grab_op == META_GRAB_OP_NONE)
return;
/* If we get here we have a global grab, because /* If we get here we have a global grab, because
* we're in some special keyboard mode such as window move * we're in some special keyboard mode such as window move
* mode. * mode.
*/ */
if (display->grab_op == META_GRAB_OP_NONE) handled = FALSE;
return;
/* don't end grabs on modifier key presses */ if (window == display->grab_window)
if (is_modifier (display, event->xkey.keycode)) {
return; switch (display->grab_op)
{
case META_GRAB_OP_KEYBOARD_MOVING:
meta_verbose ("Processing event for keyboard move\n");
handled = process_keyboard_move_grab (display, window, event, keysym);
break;
case META_GRAB_OP_KEYBOARD_TABBING:
meta_verbose ("Processing event for keyboard tabbing\n");
handled = process_tab_grab (display, window, event, keysym);
break;
default:
break;
}
}
/* end grab if a key that isn't used gets pressed */
if (!handled)
{
meta_verbose ("Ending grab op %d on key event sym %s\n",
display->grab_op, XKeysymToString (keysym));
meta_display_end_grab_op (display, event->xkey.time);
}
}
static gboolean
process_keyboard_move_grab (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
KeySym keysym)
{
gboolean handled;
int x, y;
int incr;
gboolean smart_snap;
int edge;
handled = FALSE; handled = FALSE;
if (display->grab_op == META_GRAB_OP_KEYBOARD_MOVING && /* don't care about releases, but eat them, don't end grab */
display->grab_window == window) if (event->type == KeyRelease)
{ return TRUE;
int x, y;
int incr;
gboolean smart_snap;
int edge;
if (event->type == KeyRelease) /* don't end grab on modifier key presses */
return; /* don't care about releases */ if (is_modifier (display, event->xkey.keycode))
return TRUE;
if (window == NULL) meta_window_get_position (window, &x, &y);
meta_bug ("NULL window while doing keyboard grab op\n");
meta_window_get_position (window, &x, &y); smart_snap = (event->xkey.state & ShiftMask) != 0;
smart_snap = (event->xkey.state & ShiftMask) != 0;
#define SMALL_INCREMENT 1 #define SMALL_INCREMENT 1
#define NORMAL_INCREMENT 10 #define NORMAL_INCREMENT 10
if (smart_snap) if (smart_snap)
incr = 0; incr = 0;
else if (event->xkey.state & ControlMask) else if (event->xkey.state & ControlMask)
incr = SMALL_INCREMENT; incr = SMALL_INCREMENT;
else else
incr = NORMAL_INCREMENT; incr = NORMAL_INCREMENT;
/* When moving by increments, we still snap to edges if the move /* When moving by increments, we still snap to edges if the move
* to the edge is smaller than the increment. This is because * to the edge is smaller than the increment. This is because
@ -442,71 +538,138 @@ meta_display_process_key_event (MetaDisplay *display,
* people using just arrows shouldn't get too frustrated. * people using just arrows shouldn't get too frustrated.
*/ */
switch (keysym) switch (keysym)
{
case XK_Up:
case XK_KP_Up:
edge = meta_window_find_next_horizontal_edge (window, FALSE);
y -= incr;
if (smart_snap || ((edge > y) && ABS (edge - y) < incr))
y = edge;
handled = TRUE;
break;
case XK_Down:
case XK_KP_Down:
edge = meta_window_find_next_horizontal_edge (window, TRUE);
y += incr;
if (smart_snap || ((edge < y) && ABS (edge - y) < incr))
y = edge;
handled = TRUE;
break;
case XK_Left:
case XK_KP_Left:
edge = meta_window_find_next_vertical_edge (window, FALSE);
x -= incr;
if (smart_snap || ((edge > x) && ABS (edge - x) < incr))
x = edge;
handled = TRUE;
break;
case XK_Right:
case XK_KP_Right:
edge = meta_window_find_next_vertical_edge (window, TRUE);
x += incr;
if (smart_snap || ((edge < x) && ABS (edge - x) < incr))
x = edge;
handled = TRUE;
break;
case XK_Escape:
/* End move and restore to original position */
meta_window_move_resize (display->grab_window,
display->grab_initial_window_pos.x,
display->grab_initial_window_pos.y,
display->grab_initial_window_pos.width,
display->grab_initial_window_pos.height);
break;
default:
break;
}
if (handled)
meta_window_move (window, x, y);
return handled;
}
static gboolean
process_tab_grab (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
KeySym keysym)
{
MetaScreen *screen;
window = NULL; /* be sure we don't use this, it's irrelevant */
screen = display->grab_window->screen;
g_return_val_if_fail (screen->tab_popup != NULL, FALSE);
if (event->type == KeyRelease &&
is_mod1_key (display, event->xkey.keycode))
{
/* We're done, move to the new window. */
Window target_xwindow;
MetaWindow *target_window;
target_xwindow =
meta_ui_tab_popup_get_selected (screen->tab_popup);
target_window =
meta_display_lookup_x_window (display, target_xwindow);
meta_verbose ("Ending tab operation, Mod1 released\n");
if (target_window)
{ {
case XK_Up: meta_verbose ("Ending grab early so we can focus the target window\n");
case XK_KP_Up: meta_display_end_grab_op (display, event->xkey.time);
edge = meta_window_find_next_horizontal_edge (window, FALSE);
y -= incr;
if (smart_snap || ((edge > y) && ABS (edge - y) < incr)) meta_verbose ("Focusing target window\n");
y = edge; meta_window_raise (target_window);
meta_window_focus (target_window, event->xkey.time);
handled = TRUE; return TRUE; /* we already ended the grab */
break;
case XK_Down:
case XK_KP_Down:
edge = meta_window_find_next_horizontal_edge (window, TRUE);
y += incr;
if (smart_snap || ((edge < y) && ABS (edge - y) < incr))
y = edge;
handled = TRUE;
break;
case XK_Left:
case XK_KP_Left:
edge = meta_window_find_next_vertical_edge (window, FALSE);
x -= incr;
if (smart_snap || ((edge > x) && ABS (edge - x) < incr))
x = edge;
handled = TRUE;
break;
case XK_Right:
case XK_KP_Right:
edge = meta_window_find_next_vertical_edge (window, TRUE);
x += incr;
if (smart_snap || ((edge < x) && ABS (edge - x) < incr))
x = edge;
handled = TRUE;
break;
case XK_Escape:
/* End move and restore to original position */
meta_window_move_resize (display->grab_window,
display->grab_initial_window_pos.x,
display->grab_initial_window_pos.y,
display->grab_initial_window_pos.width,
display->grab_initial_window_pos.height);
break;
default:
break;
} }
if (handled) return FALSE; /* end grab */
meta_window_move (window, x, y);
} }
/* end grab if a key that isn't used gets pressed */ /* don't care about other releases, but eat them, don't end grab */
if (!handled) if (event->type == KeyRelease)
return TRUE;
/* don't end grab on modifier key presses */
if (is_modifier (display, event->xkey.keycode))
return TRUE;
switch (keysym)
{ {
meta_verbose ("Ending grab op %d on key press event sym %s\n", case XK_ISO_Left_Tab:
display->grab_op, XKeysymToString (keysym)); case XK_Tab:
meta_display_end_grab_op (display, event->xkey.time); if (event->xkey.state & ShiftMask)
meta_ui_tab_popup_backward (screen->tab_popup);
else
meta_ui_tab_popup_forward (screen->tab_popup);
/* continue grab */
meta_verbose ("Tab key pressed, moving tab focus in popup\n");
return TRUE;
break;
default:
break;
} }
/* end grab */
meta_verbose ("Ending tabbing, uninteresting key pressed\n");
return FALSE;
} }
static void static void
@ -694,8 +857,22 @@ handle_tab_forward (MetaDisplay *display,
if (window) if (window)
{ {
meta_window_raise (window); meta_verbose ("Starting tab forward, showing popup\n");
meta_window_focus (window, event->xkey.time);
meta_display_begin_grab_op (window->display,
display->focus_window ?
display->focus_window : window,
META_GRAB_OP_KEYBOARD_TABBING,
FALSE,
0, 0,
event->xkey.time,
0, 0);
meta_ui_tab_popup_select (window->screen->tab_popup,
window->xwindow);
/* only after selecting proper window */
meta_ui_tab_popup_set_showing (window->screen->tab_popup,
TRUE);
} }
} }
@ -738,8 +915,22 @@ handle_tab_backward (MetaDisplay *display,
if (window) if (window)
{ {
meta_window_raise (window); meta_verbose ("Starting tab backward, showing popup\n");
meta_window_focus (window, event->xkey.time);
meta_display_begin_grab_op (window->display,
display->focus_window ?
display->focus_window : window,
META_GRAB_OP_KEYBOARD_TABBING,
FALSE,
0, 0,
event->xkey.time,
0, 0);
meta_ui_tab_popup_select (window->screen->tab_popup,
window->xwindow);
/* only after selecting proper window */
meta_ui_tab_popup_set_showing (window->screen->tab_popup,
TRUE);
} }
} }

View File

@ -198,6 +198,8 @@ meta_screen_new (MetaDisplay *display,
screen->ui = meta_ui_new (screen->display->xdisplay, screen->ui = meta_ui_new (screen->display->xdisplay,
screen->xscreen); screen->xscreen);
screen->tab_popup = NULL;
screen->stack = meta_stack_new (screen); screen->stack = meta_stack_new (screen);
meta_verbose ("Added screen %d ('%s') root 0x%lx\n", meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
@ -423,3 +425,45 @@ meta_screen_set_cursor (MetaScreen *screen,
XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor); XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
XFreeCursor (screen->display->xdisplay, xcursor); XFreeCursor (screen->display->xdisplay, xcursor);
} }
void
meta_screen_ensure_tab_popup (MetaScreen *screen)
{
MetaTabEntry *entries;
GSList *tab_list;
GSList *tmp;
int len;
int i;
if (screen->tab_popup)
return;
tab_list = meta_stack_get_tab_list (screen->stack);
len = g_slist_length (tab_list);
entries = g_new (MetaTabEntry, len + 1);
entries[len].xwindow = None;
entries[len].title = NULL;
entries[len].icon = NULL;
i = 0;
tmp = tab_list;
while (i < len)
{
MetaWindow *window;
window = tmp->data;
entries[i].xwindow = window->xwindow;
entries[i].title = window->title;
entries[i].icon = window->icon;
++i;
tmp = tmp->next;
}
screen->tab_popup = meta_ui_tab_popup_new (entries);
g_free (entries);
/* don't show tab popup, since proper window isn't selected yet */
}

View File

@ -39,6 +39,7 @@ struct _MetaScreen
int width; int width;
int height; int height;
MetaUI *ui; MetaUI *ui;
MetaTabPopup *tab_popup;
MetaWorkspace *active_workspace; MetaWorkspace *active_workspace;
@ -63,6 +64,8 @@ int meta_screen_get_n_workspaces (MetaScreen *scree
void meta_screen_set_cursor (MetaScreen *screen, void meta_screen_set_cursor (MetaScreen *screen,
MetaCursor cursor); MetaCursor cursor);
void meta_screen_ensure_tab_popup (MetaScreen *screen);
#endif #endif

View File

@ -902,6 +902,41 @@ meta_stack_get_tab_next (MetaStack *stack,
return find_tab_forward (stack, NULL, -1); return find_tab_forward (stack, NULL, -1);
} }
GSList*
meta_stack_get_tab_list (MetaStack *stack)
{
GSList *list;
int i;
list = NULL;
i = 0;
while (i < stack->windows->len)
{
MetaWindow *window;
MetaWorkspace *workspace;
window = meta_display_lookup_x_window (stack->screen->display,
GET_XWINDOW (stack, i));
if (window)
workspace = window->screen->active_workspace;
else
workspace = NULL;
if (window && IN_TAB_CHAIN (window) &&
(workspace == NULL ||
meta_workspace_contains_window (workspace, window)))
list = g_slist_prepend (list, window);
++i;
}
list = g_slist_reverse (list);
return list;
}
int int
meta_stack_windows_cmp (MetaStack *stack, meta_stack_windows_cmp (MetaStack *stack,
MetaWindow *window_a, MetaWindow *window_a,

View File

@ -95,6 +95,7 @@ MetaWindow* meta_stack_get_below (MetaStack *stack,
MetaWindow* meta_stack_get_tab_next (MetaStack *stack, MetaWindow* meta_stack_get_tab_next (MetaStack *stack,
MetaWindow *window, MetaWindow *window,
gboolean backward); gboolean backward);
GSList* meta_stack_get_tab_list (MetaStack *stack);
/* -1 if a < b, etc. */ /* -1 if a < b, etc. */
int meta_stack_windows_cmp (MetaStack *stack, int meta_stack_windows_cmp (MetaStack *stack,
MetaWindow *window_a, MetaWindow *window_a,

View File

@ -40,6 +40,7 @@ struct _MetaTabPopup
GtkWidget *label; GtkWidget *label;
GList *current; GList *current;
GList *entries; GList *entries;
GtkWidget *current_selected_widget;
}; };
MetaTabPopup* MetaTabPopup*
@ -52,11 +53,18 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries)
int height; int height;
GtkWidget *table; GtkWidget *table;
GList *tmp; GList *tmp;
GtkWidget *frame;
popup = g_new (MetaTabPopup, 1); popup = g_new (MetaTabPopup, 1);
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_WIN_POS_CENTER_ALWAYS);
/* enable resizing, to get never-shrink behavior */
gtk_window_set_resizable (GTK_WINDOW (popup->window),
TRUE);
popup->current = NULL; popup->current = NULL;
popup->entries = NULL; popup->entries = NULL;
popup->current_selected_widget = NULL;
tab_entries = NULL; tab_entries = NULL;
i = 0; i = 0;
@ -85,32 +93,51 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries)
table = gtk_table_new (height + 1, width, FALSE); table = gtk_table_new (height + 1, width, FALSE);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
gtk_container_set_border_width (GTK_CONTAINER (table), 1);
gtk_container_add (GTK_CONTAINER (popup->window),
frame);
gtk_container_add (GTK_CONTAINER (frame),
table);
popup->label = gtk_label_new (""); popup->label = gtk_label_new ("");
gtk_table_attach (GTK_TABLE (table), gtk_table_attach (GTK_TABLE (table),
popup->label, popup->label,
0, width, height - 1, height, 0, width, height, height + 1,
0, 0, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
0, 0); 0, 2);
left = 0;
right = 1;
top = 0; top = 0;
bottom = 1; bottom = 1;
tmp = popup->entries; tmp = popup->entries;
while (tmp && top < height) while (tmp && top < height)
{ {
left = 0;
right = 1;
while (tmp && left < width) while (tmp && left < width)
{ {
GtkWidget *image; GtkWidget *image;
GtkWidget *highlight;
TabEntry *te; TabEntry *te;
te = tmp->data; te = tmp->data;
highlight = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (highlight),
GTK_SHADOW_NONE);
image = gtk_image_new_from_pixbuf (te->icon); image = gtk_image_new_from_pixbuf (te->icon);
gtk_misc_set_padding (GTK_MISC (image), 3, 3);
te->widget = image; gtk_container_add (GTK_CONTAINER (highlight), image);
te->widget = highlight;
gtk_table_attach (GTK_TABLE (table), gtk_table_attach (GTK_TABLE (table),
te->widget, te->widget,
@ -121,9 +148,11 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries)
tmp = tmp->next; tmp = tmp->next;
++left; ++left;
++right;
} }
++top; ++top;
++bottom;
} }
return popup; return popup;
@ -169,7 +198,16 @@ static void
display_entry (MetaTabPopup *popup, display_entry (MetaTabPopup *popup,
TabEntry *te) TabEntry *te)
{ {
if (popup->current_selected_widget)
{
gtk_frame_set_shadow_type (GTK_FRAME (popup->current_selected_widget),
GTK_SHADOW_NONE);
}
gtk_label_set_text (GTK_LABEL (popup->label), te->title); gtk_label_set_text (GTK_LABEL (popup->label), te->title);
gtk_frame_set_shadow_type (GTK_FRAME (te->widget),
GTK_SHADOW_ETCHED_IN);
popup->current_selected_widget = te->widget;
} }
void void

View File

@ -345,3 +345,12 @@ meta_ui_pop_delay_exposes (MetaUI *ui)
meta_frames_pop_delay_exposes (ui->frames); meta_frames_pop_delay_exposes (ui->frames);
} }
GdkPixbuf*
meta_ui_get_default_window_icon (MetaUI *ui)
{
/* FIXME */
return gtk_widget_render_icon (GTK_WIDGET (ui->frames),
GTK_STOCK_NEW,
GTK_ICON_SIZE_LARGE_TOOLBAR,
NULL);
}

View File

@ -117,6 +117,8 @@ GdkPixbuf* meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest,
void meta_ui_push_delay_exposes (MetaUI *ui); void meta_ui_push_delay_exposes (MetaUI *ui);
void meta_ui_pop_delay_exposes (MetaUI *ui); void meta_ui_pop_delay_exposes (MetaUI *ui);
GdkPixbuf* meta_ui_get_default_window_icon (MetaUI *ui);
typedef struct _MetaTabEntry MetaTabEntry; typedef struct _MetaTabEntry MetaTabEntry;
typedef struct _MetaTabPopup MetaTabPopup; typedef struct _MetaTabPopup MetaTabPopup;

View File

@ -653,6 +653,9 @@ meta_window_free (MetaWindow *window)
meta_error_trap_pop (window->display); meta_error_trap_pop (window->display);
if (window->icon)
g_object_unref (G_OBJECT (window->icon));
g_free (window->sm_client_id); g_free (window->sm_client_id);
g_free (window->role); g_free (window->role);
g_free (window->res_class); g_free (window->res_class);
@ -3500,14 +3503,20 @@ update_icon (MetaWindow *window)
{ {
meta_error_trap_push (window->display); meta_error_trap_push (window->display);
#if 0
if (window->icon) if (window->icon)
{ {
g_object_unref (G_OBJECT (window->icon)); g_object_unref (G_OBJECT (window->icon));
window->icon = NULL; window->icon = NULL;
} }
#endif
/* FIXME */ /* FIXME */
/* Fallback */
if (window->icon == NULL)
window->icon = meta_ui_get_default_window_icon (window->screen->ui);
return meta_error_trap_pop (window->display); return meta_error_trap_pop (window->display);
} }