diff --git a/ChangeLog b/ChangeLog index f506569d7..7dd0f71a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2002-04-28 Havoc Pennington + + * README: remove caveats about keybindings + + * src/metacity.schemas: add schemas for all the keybindings. + + * src/window.c (meta_window_activate): if in "show desktop" mode + when a window is activated, leave show desktop mode. So e.g. + when you click on a task in the task list, show desktop mode + will be turned off. + + * src/workspace.c (meta_workspace_get_neighbor): new function + that doesn't quite work yet (needs support for getting + workspace layout from the pager) + + * src/prefs.c: keybindings stuff + + * src/keybindings.c: make keybindings configurable + + * src/ui.c (meta_ui_parse_accelerator): new function + 2002-04-25 Havoc Pennington * metacity.spec: fix to install gconf schemas diff --git a/README b/README index c31882d59..d1fc30f37 100644 --- a/README +++ b/README @@ -51,19 +51,25 @@ METACITY FEATURES gconftool-2 --type=string --set /apps/metacity/general/focus_mode sloppy gconftool-2 --type=string --set /apps/metacity/general/focus_mode click - - Global keybindings: - Alt-F1 to Alt-F6 switch workspaces - Alt-1 to Alt-6 switch workspaces + - Global keybinding defaults: + Alt-Tab forward cycle window focus Alt-Shift-Tab backward cycle focus Alt-Ctrl-Tab forward cycle focus among panels Alt-Ctrl-Shift-Tab backward cycle focus among panels Alt-Escape focus previous window - Ctrl-Alt-Left Arrow previous workspace - Ctrl-Alt-Right Arrow next workspace + Alt-Left Arrow previous workspace + Alt-Right Arrow next workspace Ctrl-Alt-D minimize/unminimize all, to show desktop + Change keybindings for example: + + unst gconftool-2 --type=string --set /apps/metacity/global_keybindings/switch_to_workspace_1 'F1' + + See metacity.schemas for available bindings. + - Window keybindings: + Alt-space window menu Mnemonics work in the menu. That is, Alt-space then underlined @@ -77,6 +83,9 @@ METACITY FEATURES Choose Resize from menu, and nothing happens yet, but eventually I might implement something. + Keybindings for things like maximize window, etc. can be bound, + but don't exist by default. See metacity.schemas. + - Window mouse bindings: Clicking anywhere on frame with button 1 will raise/focus window @@ -130,23 +139,10 @@ METACITY FEATURES METACITY BUGS, NON-FEATURES, AND CAVEATS === - - If you want keybindings which are not the ones mentioned above - as features, you have to edit keybindings.c and recompile. - - - Some of the default keybindings (notable Alt+number) are total - crackrock. This is just because I like those keybindings and - things aren't configurable yet. Once bindings are configurable - the dumb defaults will go away. - - You need an EWMH-spec compliant pager/tasklist to be able to navigate graphically; this does NOT include GNOME 1.x, but should include GNOME 2 and KDE 3. - - Metacity turns off its keybindings for Emacs, because I use - Alt-space in Emacs, and getting a window menu annoys me. - This is a broken feature that will go away when keybindings are - configurable. - - I haven't even read the ICCCM section about colormaps. So if you have an 8-bit display you are probably screwed. diff --git a/src/display.c b/src/display.c index f1a9c646a..bd6fc9bc7 100644 --- a/src/display.c +++ b/src/display.c @@ -552,6 +552,8 @@ meta_display_close (MetaDisplay *display) all_displays = g_slist_remove (all_displays, display); + meta_display_shutdown_keys (display); + g_free (display); if (all_displays == NULL) @@ -1308,6 +1310,10 @@ event_callback (XEvent *event, } break; case MappingNotify: + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&event->xmapping); + meta_display_process_mapping_event (display, event); break; default: break; @@ -2027,6 +2033,7 @@ meta_display_begin_grab_op (MetaDisplay *display, display->grab_window = window; display->grab_xwindow = grab_xwindow; display->grab_button = button; + display->grab_mask = modmask; display->grab_root_x = root_x; display->grab_root_y = root_y; display->grab_initial_window_pos = display->grab_window->rect; @@ -2108,9 +2115,6 @@ meta_display_end_grab_op (MetaDisplay *display, } } -#define IGNORED_MODIFIERS (LockMask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) -#define INTERESTING_MODIFIERS (~IGNORED_MODIFIERS) - static void meta_change_button_grab (MetaDisplay *display, Window xwindow, @@ -2119,22 +2123,16 @@ meta_change_button_grab (MetaDisplay *display, int button, int modmask) { - /* Instead of this hacky mess copied from fvwm, WindowMaker just - * grabs with all numlock/scrolllock combinations and doesn't grab - * for other weird bits. - */ int ignored_mask; - g_return_if_fail ((modmask & INTERESTING_MODIFIERS) == modmask); - ignored_mask = 0; - while (ignored_mask < IGNORED_MODIFIERS) + while (ignored_mask < (int) display->ignored_modifier_mask) { int result; - if (ignored_mask & INTERESTING_MODIFIERS) + if (ignored_mask & ~(display->ignored_modifier_mask)) { - /* Not a combination of IGNORED_MODIFIERS + /* Not a combination of ignored modifiers * (it contains some non-ignored modifiers) */ ++ignored_mask; diff --git a/src/display.h b/src/display.h index 9de86b5dd..9bf2945b2 100644 --- a/src/display.h +++ b/src/display.h @@ -40,13 +40,14 @@ struct _MetaRectangle int height; }; -typedef struct _MetaDisplay MetaDisplay; -typedef struct _MetaFrame MetaFrame; -typedef struct _MetaScreen MetaScreen; -typedef struct _MetaStack MetaStack; -typedef struct _MetaUISlave MetaUISlave; -typedef struct _MetaWindow MetaWindow; -typedef struct _MetaWorkspace MetaWorkspace; +typedef struct _MetaDisplay MetaDisplay; +typedef struct _MetaFrame MetaFrame; +typedef struct _MetaKeyBinding MetaKeyBinding; +typedef struct _MetaScreen MetaScreen; +typedef struct _MetaStack MetaStack; +typedef struct _MetaUISlave MetaUISlave; +typedef struct _MetaWindow MetaWindow; +typedef struct _MetaWorkspace MetaWorkspace; typedef void (* MetaWindowPingFunc) (MetaDisplay *display, Window xwindow, @@ -188,6 +189,22 @@ struct _MetaDisplay guint grab_have_keyboard : 1; MetaRectangle grab_initial_window_pos; MetaResizePopup *grab_resize_popup; + + + /* Keybindings stuff */ + MetaKeyBinding *screen_bindings; + int n_screen_bindings; + MetaKeyBinding *window_bindings; + int n_window_bindings; + int min_keycode; + int max_keycode; + KeySym *keymap; + int keysyms_per_keycode; + XModifierKeymap *modmap; + unsigned int ignored_modifier_mask; + unsigned int num_lock_mask; + unsigned int scroll_lock_mask; + unsigned int mode_switch_mask; }; gboolean meta_display_open (const char *name); diff --git a/src/keybindings.c b/src/keybindings.c index b259cf246..7181e971d 100644 --- a/src/keybindings.c +++ b/src/keybindings.c @@ -1,7 +1,7 @@ /* Metacity Keybindings */ /* - * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2001 Havoc Pennington, 2002 Red Hat Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -26,62 +26,77 @@ #include "ui.h" #include "frame.h" #include "place.h" +#include "prefs.h" #include +#include -/* Plainly we'll want some more configurable keybinding system - * eventually. - */ static gboolean all_bindings_disabled = FALSE; -typedef void (* MetaKeyHandler) (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); +typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); -static void handle_activate_workspace (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); -static void handle_activate_menu (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); -static void handle_tab_forward (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); -static void handle_tab_backward (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); -static void handle_focus_previous (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); -static void handle_toggle_fullscreen (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); -static void handle_workspace_left (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); -static void handle_workspace_right (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); -static void handle_toggle_desktop (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); +static void handle_activate_workspace (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_activate_menu (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_tab_forward (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_focus_previous (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_toggle_fullscreen (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_toggle_desktop (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_toggle_maximize (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_toggle_shade (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_close_window (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_begin_move (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_begin_resize (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_toggle_sticky (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); +static void handle_move_to_workspace (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding); /* debug */ static void handle_spew_mark (MetaDisplay *display, MetaWindow *window, XEvent *event, - gpointer data); + MetaKeyBinding *binding); static gboolean process_keyboard_move_grab (MetaDisplay *display, MetaWindow *window, @@ -93,86 +108,473 @@ static gboolean process_tab_grab (MetaDisplay *display, XEvent *event, KeySym keysym); -typedef struct _MetaKeyBinding MetaKeyBinding; +static void regrab_screen_bindings (MetaDisplay *display); +static void regrab_window_bindings (MetaDisplay *display); + +typedef struct +{ + const char *name; + MetaKeyHandlerFunc func; + void *data; +} MetaKeyHandler; struct _MetaKeyBinding { + const char *name; KeySym keysym; - gulong mask; - int event_type; - MetaKeyHandler handler; - gpointer data; + unsigned int mask; int keycode; + const MetaKeyHandler *handler; }; -#define IGNORED_MODIFIERS (LockMask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) -#define INTERESTING_MODIFIERS (~IGNORED_MODIFIERS) - -static MetaKeyBinding screen_bindings[] = { - { XK_F1, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (0), 0 }, - { XK_F2, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (1), 0 }, - { XK_F3, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (2), 0 }, - { XK_F4, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (3), 0 }, - { XK_F5, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (4), 0 }, - { XK_F6, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (5), 0 }, - { XK_1, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (0), 0 }, - { XK_2, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (1), 0 }, - { XK_3, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (2), 0 }, - { XK_4, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (3), 0 }, - { XK_5, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (4), 0 }, - { XK_6, Mod1Mask, KeyPress, handle_activate_workspace, GINT_TO_POINTER (5), 0 }, - { XK_Tab, Mod1Mask, KeyPress, handle_tab_forward, GINT_TO_POINTER (META_TAB_LIST_NORMAL), 0 }, - { XK_ISO_Left_Tab, ShiftMask | Mod1Mask, KeyPress, handle_tab_backward, GINT_TO_POINTER (META_TAB_LIST_NORMAL), 0 }, - { XK_Tab, ShiftMask | Mod1Mask, KeyPress, handle_tab_backward, GINT_TO_POINTER (META_TAB_LIST_NORMAL), 0 }, - { XK_Tab, Mod1Mask | ControlMask, KeyPress, handle_tab_forward, GINT_TO_POINTER (META_TAB_LIST_DOCKS), 0 }, - { XK_ISO_Left_Tab, ShiftMask | Mod1Mask | ControlMask, KeyPress, handle_tab_backward, GINT_TO_POINTER (META_TAB_LIST_DOCKS), 0 }, - { XK_Tab, ShiftMask | Mod1Mask | ControlMask, KeyPress, handle_tab_backward, GINT_TO_POINTER (META_TAB_LIST_DOCKS), 0 }, - { XK_Escape, Mod1Mask, KeyPress, handle_focus_previous, NULL, 0 }, - { XK_Left, Mod1Mask | ControlMask, KeyPress, handle_workspace_left, NULL, 0 }, - { XK_Right, Mod1Mask | ControlMask, KeyPress, handle_workspace_right, NULL, 0 }, - /* I don't like this binding, but haven't picked the right one yet */ - { XK_d, Mod1Mask | ControlMask, KeyPress, handle_toggle_desktop, NULL, 0 }, - { None, 0, 0, NULL, NULL, 0 } -}; - -static MetaKeyBinding debug_bindings[] = { - { XK_m, Mod1Mask | ControlMask | ShiftMask, KeyPress, handle_spew_mark, NULL, 0 }, - { None, 0, 0, NULL, NULL, 0 } +static const MetaKeyHandler screen_handlers[] = { + { META_KEYBINDING_WORKSPACE_1, handle_activate_workspace, + GINT_TO_POINTER (0) }, + { META_KEYBINDING_WORKSPACE_2, handle_activate_workspace, + GINT_TO_POINTER (1) }, + { META_KEYBINDING_WORKSPACE_3, handle_activate_workspace, + GINT_TO_POINTER (2) }, + { META_KEYBINDING_WORKSPACE_4, handle_activate_workspace, + GINT_TO_POINTER (3) }, + { META_KEYBINDING_WORKSPACE_5, handle_activate_workspace, + GINT_TO_POINTER (4) }, + { META_KEYBINDING_WORKSPACE_6, handle_activate_workspace, + GINT_TO_POINTER (5) }, + { META_KEYBINDING_WORKSPACE_7, handle_activate_workspace, + GINT_TO_POINTER (6) }, + { META_KEYBINDING_WORKSPACE_8, handle_activate_workspace, + GINT_TO_POINTER (7) }, + { META_KEYBINDING_WORKSPACE_9, handle_activate_workspace, + GINT_TO_POINTER (8) }, + { META_KEYBINDING_WORKSPACE_10, handle_activate_workspace, + GINT_TO_POINTER (9) }, + { META_KEYBINDING_WORKSPACE_11, handle_activate_workspace, + GINT_TO_POINTER (10) }, + { META_KEYBINDING_WORKSPACE_12, handle_activate_workspace, + GINT_TO_POINTER (11) }, + { META_KEYBINDING_WORKSPACE_LEFT, handle_activate_workspace, + GINT_TO_POINTER (META_MOTION_LEFT) }, + { META_KEYBINDING_WORKSPACE_RIGHT, handle_activate_workspace, + GINT_TO_POINTER (META_MOTION_RIGHT) }, + { META_KEYBINDING_WORKSPACE_UP, handle_activate_workspace, + GINT_TO_POINTER (META_MOTION_UP) }, + { META_KEYBINDING_WORKSPACE_DOWN, handle_activate_workspace, + GINT_TO_POINTER (META_MOTION_DOWN) }, + { META_KEYBINDING_SWITCH_WINDOWS, handle_tab_forward, + GINT_TO_POINTER (META_TAB_LIST_NORMAL) }, + { META_KEYBINDING_SWITCH_PANELS, handle_tab_forward, + GINT_TO_POINTER (META_TAB_LIST_DOCKS) }, + { META_KEYBINDING_FOCUS_PREVIOUS, handle_focus_previous, + NULL }, + { META_KEYBINDING_SHOW_DESKTOP, handle_toggle_desktop, + NULL }, + { NULL, NULL, NULL } }; -static MetaKeyBinding window_bindings[] = { - { XK_space, Mod1Mask, KeyPress, handle_activate_menu, NULL, 0 }, - { XK_Tab, Mod1Mask, KeyPress, handle_tab_forward, NULL, 0 }, - { XK_ISO_Left_Tab, ShiftMask | Mod1Mask, KeyPress, handle_tab_backward, NULL, 0 }, - { XK_Tab, ShiftMask | Mod1Mask, KeyPress, handle_tab_backward, NULL, 0 }, - { XK_Escape, Mod1Mask, KeyPress, handle_focus_previous, NULL, 0 }, - /* Crack! */ - { XK_f, ControlMask | Mod1Mask, KeyPress, handle_toggle_fullscreen, NULL, 0 }, - { None, 0, 0, NULL, NULL, 0 } +static const MetaKeyHandler window_handlers[] = { + { META_KEYBINDING_WINDOW_MENU, handle_activate_menu, NULL }, + { META_KEYBINDING_TOGGLE_FULLSCREEN, handle_toggle_fullscreen, NULL }, + { META_KEYBINDING_TOGGLE_MAXIMIZE, handle_toggle_maximize, NULL }, + { META_KEYBINDING_TOGGLE_SHADE, handle_toggle_shade, NULL }, + { META_KEYBINDING_CLOSE, handle_close_window, NULL }, + { META_KEYBINDING_BEGIN_MOVE, handle_begin_move, }, + { META_KEYBINDING_BEGIN_RESIZE, handle_begin_resize, }, + { META_KEYBINDING_TOGGLE_STICKY, handle_toggle_sticky, }, + { META_KEYBINDING_MOVE_WORKSPACE_1, handle_move_to_workspace, + GINT_TO_POINTER (0) }, + { META_KEYBINDING_MOVE_WORKSPACE_2, handle_move_to_workspace, + GINT_TO_POINTER (1) }, + { META_KEYBINDING_MOVE_WORKSPACE_3, handle_move_to_workspace, + GINT_TO_POINTER (2) }, + { META_KEYBINDING_MOVE_WORKSPACE_4, handle_move_to_workspace, + GINT_TO_POINTER (3) }, + { META_KEYBINDING_MOVE_WORKSPACE_5, handle_move_to_workspace, + GINT_TO_POINTER (4) }, + { META_KEYBINDING_MOVE_WORKSPACE_6, handle_move_to_workspace, + GINT_TO_POINTER (5) }, + { META_KEYBINDING_MOVE_WORKSPACE_7, handle_move_to_workspace, + GINT_TO_POINTER (6) }, + { META_KEYBINDING_MOVE_WORKSPACE_8, handle_move_to_workspace, + GINT_TO_POINTER (7) }, + { META_KEYBINDING_MOVE_WORKSPACE_9, handle_move_to_workspace, + GINT_TO_POINTER (8) }, + { META_KEYBINDING_MOVE_WORKSPACE_10, handle_move_to_workspace, + GINT_TO_POINTER (9) }, + { META_KEYBINDING_MOVE_WORKSPACE_11, handle_move_to_workspace, + GINT_TO_POINTER (10) }, + { META_KEYBINDING_MOVE_WORKSPACE_12, handle_move_to_workspace, + GINT_TO_POINTER (11) }, + { META_KEYBINDING_MOVE_WORKSPACE_LEFT, handle_move_to_workspace, + GINT_TO_POINTER (META_MOTION_LEFT) }, + { META_KEYBINDING_MOVE_WORKSPACE_RIGHT, handle_move_to_workspace, + GINT_TO_POINTER (META_MOTION_RIGHT) }, + { META_KEYBINDING_MOVE_WORKSPACE_UP, handle_move_to_workspace, + GINT_TO_POINTER (META_MOTION_UP) }, + { META_KEYBINDING_MOVE_WORKSPACE_DOWN, handle_move_to_workspace, + GINT_TO_POINTER (META_MOTION_DOWN) }, + { NULL, NULL, NULL } }; static void -init_bindings (MetaDisplay *display, - MetaKeyBinding *bindings) +reload_keymap (MetaDisplay *display) { - int i; + if (display->keymap) + meta_XFree (display->keymap); - i = 0; - while (bindings[i].keysym != None) + display->keymap = XGetKeyboardMapping (display->xdisplay, + display->min_keycode, + display->max_keycode - + display->min_keycode, + &display->keysyms_per_keycode); +} + +static void +reload_modmap (MetaDisplay *display) +{ + XModifierKeymap *modmap; + int map_size; + int i; + + if (display->modmap) + XFreeModifiermap (display->modmap); + + modmap = XGetModifierMapping (display->xdisplay); + display->modmap = modmap; + + display->ignored_modifier_mask = 0; + + /* Multiple bits may get set in each of these */ + display->num_lock_mask = 0; + display->scroll_lock_mask = 0; + display->mode_switch_mask = 0; + + /* there are 8 modifiers, and the first 3 are shift, shift lock, + * and control + */ + map_size = 8 * modmap->max_keypermod; + i = 3 * modmap->max_keypermod; + while (i < map_size) { - bindings[i].keycode = XKeysymToKeycode (display->xdisplay, - bindings[i].keysym); + /* get the key code at this point in the map, + * see if its keysym is one we're interested in + */ + int keycode = modmap->modifiermap[i]; + + if (keycode >= display->min_keycode && + keycode <= display->max_keycode) + { + int j = 0; + KeySym *syms = display->keymap + + (keycode - display->min_keycode) * display->keysyms_per_keycode; + + while (j < display->keysyms_per_keycode) + { + if (syms[j] == XK_Mode_switch) + { + /* This modifier swaps groups */ + + /* Mod1Mask is 1 << 3 for example, i.e. the + * fourth modifier, i / keyspermod is the modifier + * index + */ + + display->mode_switch_mask |= (1 << ( i / modmap->max_keypermod)); + } + else if (syms[j] == XK_Num_Lock) + { + display->num_lock_mask |= (1 << ( i / modmap->max_keypermod)); + } + else if (syms[j] == XK_Scroll_Lock) + { + display->scroll_lock_mask |= (1 << ( i / modmap->max_keypermod)); + } + + ++j; + } + } ++i; } -} + + display->ignored_modifier_mask = (display->mode_switch_mask | + display->num_lock_mask | + display->scroll_lock_mask); + + meta_topic (META_DEBUG_KEYBINDINGS, + "Ignoring modmask 0x%x num lock 0x%x mode switch 0x%x scroll lock 0x%x\n", + display->ignored_modifier_mask, + display->num_lock_mask, + display->mode_switch_mask, + display->scroll_lock_mask); +} + +static void +reload_keycodes (MetaDisplay *display) +{ + meta_topic (META_DEBUG_KEYBINDINGS, + "Reloading keycodes for binding tables\n"); + + if (display->screen_bindings) + { + int i; + + i = 0; + while (display->screen_bindings[i].keysym != None) + { + display->screen_bindings[i].keycode = XKeysymToKeycode (display->xdisplay, + display->screen_bindings[i].keysym); + + ++i; + } + } + + if (display->window_bindings) + { + int i; + + i = 0; + while (display->window_bindings[i].keysym != None) + { + display->window_bindings[i].keycode = XKeysymToKeycode (display->xdisplay, + display->window_bindings[i].keysym); + + ++i; + } + } +} + +static void +rebuild_screen_binding_table (MetaDisplay *display) +{ + const MetaKeyPref *prefs; + int n_bindings; + int src, dest; + + meta_topic (META_DEBUG_KEYBINDINGS, + "Rebuilding screen binding table from preferences\n"); + + meta_prefs_get_screen_bindings (&prefs, &n_bindings); + g_free (display->screen_bindings); + display->screen_bindings = g_new0 (MetaKeyBinding, n_bindings); + + src = 0; + dest = 0; + while (src < n_bindings) + { + if (prefs[src].keysym != None && + prefs[src].mask != 0) + { + display->screen_bindings[dest].name = prefs[src].name; + display->screen_bindings[dest].keysym = prefs[src].keysym; + display->screen_bindings[dest].mask = prefs[src].mask; + ++dest; + } + + ++src; + } + + display->n_screen_bindings = dest; + + meta_topic (META_DEBUG_KEYBINDINGS, + "%d screen bindings in table\n", + display->n_screen_bindings); +} + +static void +rebuild_window_binding_table (MetaDisplay *display) +{ + const MetaKeyPref *prefs; + int n_bindings; + int src, dest; + + meta_topic (META_DEBUG_KEYBINDINGS, + "Rebuilding window binding table from preferences\n"); + + meta_prefs_get_window_bindings (&prefs, &n_bindings); + g_free (display->window_bindings); + display->window_bindings = g_new0 (MetaKeyBinding, n_bindings); + + src = 0; + dest = 0; + while (src < n_bindings) + { + if (prefs[src].keysym != None && + prefs[src].mask != 0) + { + display->window_bindings[dest].name = prefs[src].name; + display->window_bindings[dest].keysym = prefs[src].keysym; + display->window_bindings[dest].mask = prefs[src].mask; + ++dest; + } + + ++src; + } + + display->n_window_bindings = dest; + + meta_topic (META_DEBUG_KEYBINDINGS, + "%d window bindings in table\n", + display->n_window_bindings); +} + +static void +regrab_screen_bindings (MetaDisplay *display) +{ + GSList *tmp; + + tmp = display->screens; + while (tmp != NULL) + { + MetaScreen *screen = tmp->data; + + meta_screen_ungrab_keys (screen); + meta_screen_grab_keys (screen); + + tmp = tmp->next; + } +} + +static void +regrab_window_bindings (MetaDisplay *display) +{ + GSList *windows; + GSList *tmp; + + windows = meta_display_list_windows (display); + + tmp = windows; + while (tmp != NULL) + { + MetaWindow *w = tmp->data; + + meta_window_ungrab_keys (w); + meta_window_grab_keys (w); + + tmp = tmp->next; + } + + g_slist_free (windows); +} + +void +meta_display_process_mapping_event (MetaDisplay *display, + XEvent *event) +{ + if (event->xmapping.request == MappingModifier) + { + meta_topic (META_DEBUG_KEYBINDINGS, + "Received MappingModifier event, will reload modmap and redo keybindings\n"); + + reload_modmap (display); + + regrab_screen_bindings (display); + regrab_window_bindings (display); + } + else if (event->xmapping.request == MappingKeyboard) + { + meta_topic (META_DEBUG_KEYBINDINGS, + "Received MappingKeyboard event, will reload keycodes and redo keybindings\n"); + + reload_keymap (display); + reload_modmap (display); + + reload_keycodes (display); + + regrab_screen_bindings (display); + regrab_window_bindings (display); + } +} + +static void +bindings_changed_callback (MetaPreference pref, + void *data) +{ + MetaDisplay *display; + + display = data; + + switch (pref) + { + case META_PREF_SCREEN_KEYBINDINGS: + rebuild_screen_binding_table (display); + reload_keycodes (display); + regrab_screen_bindings (display); + break; + case META_PREF_WINDOW_KEYBINDINGS: + rebuild_window_binding_table (display); + reload_keycodes (display); + regrab_window_bindings (display); + break; + default: + break; + } +} + void meta_display_init_keys (MetaDisplay *display) { - init_bindings (display, screen_bindings); - init_bindings (display, window_bindings); - init_bindings (display, debug_bindings); + /* Keybindings */ + display->keymap = NULL; + display->keysyms_per_keycode = 0; + display->modmap = NULL; + display->min_keycode = 0; + display->max_keycode = 0; + display->ignored_modifier_mask = 0; + display->num_lock_mask = 0; + display->scroll_lock_mask = 0; + display->mode_switch_mask = 0; + display->screen_bindings = NULL; + display->n_screen_bindings = 0; + display->window_bindings = NULL; + display->n_window_bindings = 0; + + XDisplayKeycodes (display->xdisplay, + &display->min_keycode, + &display->max_keycode); + + meta_topic (META_DEBUG_KEYBINDINGS, + "Display has keycode range %d to %d\n", + display->min_keycode, + display->max_keycode); + + reload_keymap (display); + reload_modmap (display); + + rebuild_window_binding_table (display); + rebuild_screen_binding_table (display); + + reload_keycodes (display); + + /* Keys are actually grabbed in meta_screen_grab_keys() */ + + meta_prefs_add_listener (bindings_changed_callback, display); +} + +void +meta_display_shutdown_keys (MetaDisplay *display) +{ + meta_prefs_remove_listener (bindings_changed_callback, display); + + if (display->keymap) + meta_XFree (display->keymap); + + if (display->modmap) + XFreeModifiermap (display->modmap); + g_free (display->screen_bindings); + g_free (display->window_bindings); +} + +static const char* +keysym_name (int keysym) +{ + const char *name; + + name = XKeysymToString (keysym); + if (name == NULL) + name = "(unknown)"; + + return name; } /* Grab/ungrab, ignoring all annoying modifiers like NumLock etc. */ @@ -188,23 +590,29 @@ meta_change_keygrab (MetaDisplay *display, int ignored_mask; /* Grab keycode/modmask, together with - * all combinations of IGNORED_MODIFIERS. + * all combinations of ignored modifiers. * X provides no better way to do this. */ - /* Instead of this hacky mess copied from fvwm, WindowMaker just - * grabs with all numlock/scrolllock combinations and doesn't grab - * for other weird bits. - */ - - /* modmask can't contain any non-interesting modifiers */ - g_return_if_fail ((modmask & INTERESTING_MODIFIERS) == modmask); + + if ((modmask & ~(display->ignored_modifier_mask)) == 0) + { + meta_topic (META_DEBUG_KEYBINDINGS, + "Unable to grab/ungrab keybinding because it has no modifiers\n"); + return; + } + + meta_topic (META_DEBUG_KEYBINDINGS, + "%s keybinding %s mask 0x%x\n", + grab ? "Grabbing" : "Ungrabbing", + keysym_name (keysym), + modmask); ignored_mask = 0; - while (ignored_mask < IGNORED_MODIFIERS) + while (ignored_mask < (int) display->ignored_modifier_mask) { - if (ignored_mask & INTERESTING_MODIFIERS) + if (ignored_mask & ~(display->ignored_modifier_mask)) { - /* Not a combination of IGNORED_MODIFIERS + /* Not a combination of ignored modifiers * (it contains some non-ignored modifiers) */ ++ignored_mask; @@ -226,15 +634,9 @@ meta_change_keygrab (MetaDisplay *display, result = meta_error_trap_pop (display); if (grab && result != Success) - { - const char *name; - - name = XKeysymToString (keysym); - if (name == NULL) - name = "(unknown)"; - + { if (result == BadAccess) - meta_warning (_("Some other program is already using the key %s with modifiers %x as a binding\n"), name, modmask | ignored_mask); + meta_warning (_("Some other program is already using the key %s with modifiers %x as a binding\n"), keysym_name (keysym), modmask | ignored_mask); } ++ignored_mask; @@ -251,25 +653,18 @@ meta_grab_key (MetaDisplay *display, meta_change_keygrab (display, xwindow, TRUE, keysym, keycode, modmask); } -static void -meta_ungrab_key (MetaDisplay *display, - Window xwindow, - int keysym, - int keycode, - int modmask) -{ - meta_change_keygrab (display, xwindow, FALSE, keysym, keycode, modmask); -} - static void grab_keys (MetaKeyBinding *bindings, + int n_bindings, MetaDisplay *display, Window xwindow) { int i; + g_assert (n_bindings == 0 || bindings != NULL); + i = 0; - while (bindings[i].keysym != None) + while (i < n_bindings) { if (bindings[i].keycode != 0) { @@ -284,41 +679,44 @@ grab_keys (MetaKeyBinding *bindings, } static void -ungrab_keys (MetaKeyBinding *bindings, - MetaDisplay *display, - Window xwindow) +ungrab_all_keys (MetaDisplay *display, + Window xwindow) { - int i; + int result; + + meta_error_trap_push (display); - i = 0; - while (bindings[i].keysym != None) - { - if (bindings[i].keycode != 0) - { - meta_ungrab_key (display, xwindow, - bindings[i].keysym, - bindings[i].keycode, - bindings[i].mask); - } + XUngrabKey (display->xdisplay, AnyKey, AnyModifier, + xwindow); - ++i; - } + result = meta_error_trap_pop (display); + + if (result != Success) + meta_topic (META_DEBUG_KEYBINDINGS, + "Ungrabbing all keys on 0x%lx failed\n", xwindow); } void -meta_screen_grab_keys (MetaScreen *screen) +meta_screen_grab_keys (MetaScreen *screen) { - grab_keys (screen_bindings, screen->display, screen->xroot); - if (meta_is_debugging ()) - grab_keys (debug_bindings, screen->display, screen->xroot); + if (screen->keys_grabbed) + return; + + grab_keys (screen->display->screen_bindings, + screen->display->n_screen_bindings, + screen->display, screen->xroot); + + screen->keys_grabbed = TRUE; } void meta_screen_ungrab_keys (MetaScreen *screen) { - ungrab_keys (screen_bindings, screen->display, screen->xroot); - if (meta_is_debugging ()) - ungrab_keys (debug_bindings, screen->display, screen->xroot); + if (screen->keys_grabbed) + { + ungrab_all_keys (screen->display, screen->xroot); + screen->keys_grabbed = FALSE; + } } void @@ -330,21 +728,17 @@ meta_window_grab_keys (MetaWindow *window) if (window->keys_grabbed) { if (window->frame && !window->grab_on_frame) - ungrab_keys (window_bindings, window->display, - window->xwindow); + ungrab_all_keys (window->display, window->xwindow); else if (window->frame == NULL && window->grab_on_frame) ; /* continue to regrab on client window */ else return; /* already all good */ } - - /* no keybindings for Emacs ;-) */ - if (window->res_class && - g_strcasecmp (window->res_class, "Emacs") == 0) - return; - grab_keys (window_bindings, window->display, + grab_keys (window->display->window_bindings, + window->display->n_window_bindings, + window->display, window->frame ? window->frame->xwindow : window->xwindow); window->keys_grabbed = TRUE; @@ -358,11 +752,11 @@ meta_window_ungrab_keys (MetaWindow *window) { if (window->grab_on_frame && window->frame != NULL) - ungrab_keys (window_bindings, window->display, - window->frame->xwindow); + ungrab_all_keys (window->display, + window->frame->xwindow); else if (!window->grab_on_frame) - ungrab_keys (window_bindings, window->display, - window->xwindow); + ungrab_all_keys (window->display, + window->xwindow); } } @@ -397,7 +791,8 @@ meta_window_grab_all_keys (MetaWindow *window) result = meta_error_trap_pop (window->display); if (result != Success) { - meta_verbose ("Global key grab failed for window %s\n", window->desc); + meta_topic (META_DEBUG_KEYBINDINGS, + "Global key grab failed for window %s\n", window->desc); return FALSE; } else @@ -415,12 +810,14 @@ meta_window_grab_all_keys (MetaWindow *window) result = meta_error_trap_pop (window->display); if (result != Success) { - meta_verbose ("XGrabKeyboard() failed for window %s\n", - window->desc); + meta_topic (META_DEBUG_KEYBINDINGS, + "XGrabKeyboard() failed for window %s\n", + window->desc); return FALSE; } - meta_verbose ("Grabbed all keys on window %s\n", window->desc); + meta_topic (META_DEBUG_KEYBINDINGS, + "Grabbed all keys on window %s\n", window->desc); window->keys_grabbed = FALSE; window->all_keys_grabbed = TRUE; @@ -447,8 +844,9 @@ meta_window_ungrab_all_keys (MetaWindow *window) AnyKey, AnyModifier, grabwindow); - meta_verbose ("Ungrabbing keyboard with timestamp %lu\n", - timestamp); + meta_topic (META_DEBUG_KEYBINDINGS, + "Ungrabbing keyboard with timestamp %lu\n", + timestamp); XUngrabKeyboard (window->display->xdisplay, timestamp); meta_error_trap_pop (window->display); @@ -467,18 +865,15 @@ is_modifier (MetaDisplay *display, { int i; int map_size; - XModifierKeymap *mod_keymap; - gboolean retval = FALSE; + gboolean retval = FALSE; + + g_assert (display->modmap); - /* FIXME this is ass-slow, cache the modmap */ - - mod_keymap = XGetModifierMapping (display->xdisplay); - - map_size = 8 * mod_keymap->max_keypermod; + map_size = 8 * display->modmap->max_keypermod; i = 0; while (i < map_size) { - if (keycode == mod_keymap->modifiermap[i]) + if (keycode == display->modmap->modifiermap[i]) { retval = TRUE; break; @@ -486,30 +881,52 @@ is_modifier (MetaDisplay *display, ++i; } - XFreeModifiermap (mod_keymap); - return retval; } -#define MOD1_INDEX 3 /* shift, lock, control, mod1 */ +/* Indexes: + * shift = 0 + * lock = 1 + * control = 2 + * mod1 = 3 + * mod2 = 4 + * mod3 = 5 + * mod4 = 6 + * mod5 = 7 + */ + static gboolean -is_mod1_key (MetaDisplay *display, - unsigned int keycode) +is_specific_modifier (MetaDisplay *display, + unsigned int keycode, + unsigned int mask) { int i; int end; - XModifierKeymap *mod_keymap; gboolean retval = FALSE; + int mod_index; - /* FIXME this is ass-slow, cache the modmap */ + g_assert (display->modmap); + + meta_topic (META_DEBUG_KEYBINDINGS, + "Checking whether code 0x%x is bound to modifier 0x%x\n", + keycode, mask); - mod_keymap = XGetModifierMapping (display->xdisplay); + mod_index = 0; + mask = mask >> 1; + while (mask != 0) + { + mod_index += 1; + mask = mask >> 1; + } + + meta_topic (META_DEBUG_KEYBINDINGS, + "Modifier has index %d\n", mod_index); - end = (MOD1_INDEX + 1) * mod_keymap->max_keypermod; - i = MOD1_INDEX * mod_keymap->max_keypermod; + end = (mod_index + 1) * display->modmap->max_keypermod; + i = mod_index * display->modmap->max_keypermod; while (i < end) { - if (keycode == mod_keymap->modifiermap[i]) + if (keycode == display->modmap->modifiermap[i]) { retval = TRUE; break; @@ -517,29 +934,94 @@ is_mod1_key (MetaDisplay *display, ++i; } - XFreeModifiermap (mod_keymap); - return retval; } +static gboolean +keycode_is_primary_modifier (MetaDisplay *display, + unsigned int keycode, + unsigned int entire_binding_mask) +{ + /* The idea here is to see if the "main" modifier + * for Alt+Tab has been pressed/released. So if the binding + * is Alt+Shift+Tab then releasing Alt is the thing that + * ends the operation. It's pretty random how we order + * these. + */ + unsigned int masks[] = { Mod5Mask, Mod4Mask, Mod3Mask, + Mod2Mask, Mod1Mask, ControlMask, + ShiftMask, LockMask }; + + int i; + + meta_topic (META_DEBUG_KEYBINDINGS, + "Checking whether code 0x%x is the primary modifier of mask 0x%x\n", + keycode, entire_binding_mask); + + i = 0; + while (i < (int) G_N_ELEMENTS (masks)) + { + if (entire_binding_mask & masks[i]) + return is_specific_modifier (display, keycode, masks[i]); + ++i; + } + + return FALSE; +} + +static const MetaKeyHandler* +find_handler (const MetaKeyHandler *handlers, + const char *name) +{ + const MetaKeyHandler *iter; + + iter = handlers; + while (iter->name) + { + if (strcmp (iter->name, + name) == 0) + return iter; + + ++iter; + } + + return NULL; +} + static void -process_event (MetaKeyBinding *bindings, - MetaDisplay *display, - MetaWindow *window, - XEvent *event, - KeySym keysym) +process_event (MetaKeyBinding *bindings, + int n_bindings, + const MetaKeyHandler *handlers, + MetaDisplay *display, + MetaWindow *window, + XEvent *event, + KeySym keysym) { int i; i = 0; - while (bindings[i].keysym != None) + while (i < n_bindings) { if (bindings[i].keysym == keysym && - ((event->xkey.state & INTERESTING_MODIFIERS) == + ((event->xkey.state & ~(display->ignored_modifier_mask)) == bindings[i].mask) && - bindings[i].event_type == event->type) + event->type == KeyPress) { - (* bindings[i].handler) (display, window, event, bindings[i].data); + const MetaKeyHandler *handler; + + if (bindings[i].handler) + handler = bindings[i].handler; + else + { + handler = find_handler (handlers, bindings[i].name); + bindings[i].handler = handler; /* cache */ + } + + if (handler == NULL) + meta_bug ("Binding %s has no handler\n", bindings[i].name); + + (* handler->func) (display, window, event, + &bindings[i]); break; } @@ -565,20 +1047,25 @@ meta_display_process_key_event (MetaDisplay *display, keysym = XKeycodeToKeysym (display->xdisplay, event->xkey.keycode, 0); - meta_verbose ("Processing key %s event, keysym: %s state: 0x%x window: %s\n", - event->type == KeyPress ? "press" : "release", - XKeysymToString (keysym), event->xkey.state, - window ? window->desc : "(no window)"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Processing key %s event, keysym: %s state: 0x%x window: %s\n", + event->type == KeyPress ? "press" : "release", + XKeysymToString (keysym), event->xkey.state, + window ? window->desc : "(no window)"); if (window == NULL || !window->all_keys_grabbed) { /* Do the normal keybindings */ - process_event (screen_bindings, display, NULL, event, keysym); - if (meta_is_debugging ()) - process_event (debug_bindings, display, NULL, event, keysym); + process_event (display->screen_bindings, + display->n_screen_bindings, + screen_handlers, + display, NULL, event, keysym); if (window) - process_event (window_bindings, display, window, event, keysym); + process_event (display->window_bindings, + display->n_window_bindings, + window_handlers, + display, window, event, keysym); return; } @@ -598,12 +1085,14 @@ meta_display_process_key_event (MetaDisplay *display, switch (display->grab_op) { case META_GRAB_OP_KEYBOARD_MOVING: - meta_verbose ("Processing event for keyboard move\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Processing event for keyboard move\n"); handled = process_keyboard_move_grab (display, window, event, keysym); break; case META_GRAB_OP_KEYBOARD_TABBING_NORMAL: case META_GRAB_OP_KEYBOARD_TABBING_DOCK: - meta_verbose ("Processing event for keyboard tabbing\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Processing event for keyboard tabbing\n"); handled = process_tab_grab (display, window, event, keysym); break; default: @@ -614,8 +1103,9 @@ meta_display_process_key_event (MetaDisplay *display, /* 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_topic (META_DEBUG_KEYBINDINGS, + "Ending grab op %d on key event sym %s\n", + display->grab_op, XKeysymToString (keysym)); meta_display_end_grab_op (display, event->xkey.time); } } @@ -656,11 +1146,11 @@ process_keyboard_move_grab (MetaDisplay *display, else incr = NORMAL_INCREMENT; - /* When moving by increments, we still snap to edges if the move - * to the edge is smaller than the increment. This is because - * Shift + arrow to snap is sort of a hidden feature. This way - * people using just arrows shouldn't get too frustrated. - */ + /* When moving by increments, we still snap to edges if the move + * to the edge is smaller than the increment. This is because + * Shift + arrow to snap is sort of a hidden feature. This way + * people using just arrows shouldn't get too frustrated. + */ switch (keysym) { @@ -738,7 +1228,8 @@ process_tab_grab (MetaDisplay *display, g_return_val_if_fail (screen->tab_popup != NULL, FALSE); if (event->type == KeyRelease && - is_mod1_key (display, event->xkey.keycode)) + keycode_is_primary_modifier (display, event->xkey.keycode, + display->grab_mask)) { /* We're done, move to the new window. */ Window target_xwindow; @@ -749,14 +1240,17 @@ process_tab_grab (MetaDisplay *display, target_window = meta_display_lookup_x_window (display, target_xwindow); - meta_verbose ("Ending tab operation, Mod1 released\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Ending tab operation, primary modifier released\n"); if (target_window) { - meta_verbose ("Ending grab early so we can focus the target window\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Ending grab early so we can focus the target window\n"); meta_display_end_grab_op (display, event->xkey.time); - meta_verbose ("Activating target window\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Activating target window\n"); meta_topic (META_DEBUG_FOCUS, "Activating %s due to tab popup selection\n", target_window->desc); @@ -786,7 +1280,8 @@ process_tab_grab (MetaDisplay *display, meta_ui_tab_popup_forward (screen->tab_popup); /* continue grab */ - meta_verbose ("Tab key pressed, moving tab focus in popup\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Tab key pressed, moving tab focus in popup\n"); return TRUE; break; @@ -795,7 +1290,8 @@ process_tab_grab (MetaDisplay *display, } /* end grab */ - meta_verbose ("Ending tabbing, uninteresting key pressed\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Ending tabbing, uninteresting key pressed\n"); return FALSE; } @@ -841,48 +1337,34 @@ switch_to_workspace (MetaDisplay *display, } static void -handle_activate_workspace (MetaDisplay *display, - MetaWindow *event_window, - XEvent *event, - gpointer data) +handle_activate_workspace (MetaDisplay *display, + MetaWindow *event_window, + XEvent *event, + MetaKeyBinding *binding) { int which; MetaWorkspace *workspace; - which = GPOINTER_TO_INT (data); + which = GPOINTER_TO_INT (binding->handler->data); - workspace = meta_display_get_workspace_by_index (display, which); - - if (workspace) + workspace = NULL; + if (which < 0) { - switch_to_workspace (display, workspace); + MetaScreen *screen; + + screen = meta_display_screen_for_root (display, + event->xkey.root); + + if (screen == NULL) + return; + + workspace = meta_workspace_get_neighbor (screen->active_workspace, + which); } else { - /* We could offer to create it I suppose */ + workspace = meta_display_get_workspace_by_index (display, which); } -} - -static void -handle_workspace_left (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data) -{ - MetaWorkspace *workspace; - MetaScreen *screen; - int i; - - screen = meta_display_screen_for_root (display, - event->xkey.root); - - if (screen == NULL) - return; - - i = meta_workspace_index (screen->active_workspace); - --i; - - workspace = meta_display_get_workspace_by_index (display, i); if (workspace) { @@ -895,41 +1377,10 @@ handle_workspace_left (MetaDisplay *display, } static void -handle_workspace_right (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data) -{ - MetaWorkspace *workspace; - MetaScreen *screen; - int i; - - screen = meta_display_screen_for_root (display, - event->xkey.root); - - if (screen == NULL) - return; - - i = meta_workspace_index (screen->active_workspace); - ++i; - - workspace = meta_display_get_workspace_by_index (display, i); - - if (workspace) - { - switch_to_workspace (display, workspace); - } - else - { - /* We could offer to create it I suppose */ - } -} - -static void -handle_toggle_desktop (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data) +handle_toggle_desktop (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) { if (display->showing_desktop) meta_display_unshow_desktop (display); @@ -938,10 +1389,10 @@ handle_toggle_desktop (MetaDisplay *display, } static void -handle_activate_menu (MetaDisplay *display, - MetaWindow *event_window, - XEvent *event, - gpointer data) +handle_activate_menu (MetaDisplay *display, + MetaWindow *event_window, + XEvent *event, + MetaKeyBinding *binding) { if (display->focus_window) { @@ -974,17 +1425,22 @@ op_from_tab_type (MetaTabList type) } static void -handle_tab_forward (MetaDisplay *display, - MetaWindow *event_window, - XEvent *event, - gpointer data) +handle_tab_forward (MetaDisplay *display, + MetaWindow *event_window, + XEvent *event, + MetaKeyBinding *binding) { MetaWindow *window; MetaTabList type; - - type = GPOINTER_TO_INT (data); + gboolean backward; - meta_verbose ("Tab forward type = %d\n", type); + type = GPOINTER_TO_INT (binding->handler->data); + + meta_topic (META_DEBUG_KEYBINDINGS, + "Tab type = %d\n", type); + + /* backward if shift is down, this isn't configurable */ + backward = (event->xkey.state & ShiftMask) != 0; window = NULL; @@ -994,7 +1450,7 @@ handle_tab_forward (MetaDisplay *display, type, display->focus_window->screen->active_workspace, display->focus_window, - FALSE); + backward); } if (window == NULL) @@ -1013,20 +1469,22 @@ handle_tab_forward (MetaDisplay *display, type, screen->active_workspace, NULL, - FALSE); + backward); } } if (window) { - meta_verbose ("Starting tab forward, showing popup\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Starting tab between windows, showing popup\n"); if (meta_display_begin_grab_op (window->display, display->focus_window ? display->focus_window : window, op_from_tab_type (type), FALSE, - 0, 0, + 0, + event->xkey.state & ~(display->ignored_modifier_mask), event->xkey.time, 0, 0)) { @@ -1040,81 +1498,16 @@ handle_tab_forward (MetaDisplay *display, } static void -handle_tab_backward (MetaDisplay *display, - MetaWindow *event_window, - XEvent *event, - gpointer data) -{ - MetaWindow *window; - MetaTabList type; - - type = GPOINTER_TO_INT (data); - - meta_verbose ("Tab backward type = %d\n", type); - - window = NULL; - - if (display->focus_window != NULL) - { - window = meta_display_get_tab_next (display, - type, - display->focus_window->screen->active_workspace, - display->focus_window, - TRUE); - } - - if (window == NULL) - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xkey.root); - - /* We get the screen because event_window may be NULL, - * in which case we can't use event_window->screen - */ - if (screen) - { - window = meta_display_get_tab_next (screen->display, - type, - screen->active_workspace, - NULL, - TRUE); - } - } - - if (window) - { - meta_verbose ("Starting tab backward, showing popup\n"); - - if (meta_display_begin_grab_op (window->display, - display->focus_window ? - display->focus_window : window, - op_from_tab_type (type), - 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); - } - } -} - -static void -handle_focus_previous (MetaDisplay *display, - MetaWindow *event_window, - XEvent *event, - gpointer data) +handle_focus_previous (MetaDisplay *display, + MetaWindow *event_window, + XEvent *event, + MetaKeyBinding *binding) { MetaWindow *window; MetaScreen *screen; - meta_verbose ("Focus previous window\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Focus previous window\n"); screen = meta_display_screen_for_root (display, event->xkey.root); @@ -1162,10 +1555,10 @@ handle_focus_previous (MetaDisplay *display, } static void -handle_toggle_fullscreen (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data) +handle_toggle_fullscreen (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) { if (window) { @@ -1177,10 +1570,132 @@ handle_toggle_fullscreen (MetaDisplay *display, } static void -handle_spew_mark (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data) +handle_toggle_maximize (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) +{ + if (window) + { + if (window->maximized) + meta_window_unmaximize (window); + else + meta_window_maximize (window); + } +} + +static void +handle_toggle_shade (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) +{ + if (window) + { + if (window->shaded) + meta_window_unshade (window); + else + meta_window_shade (window); + } +} + +static void +handle_close_window (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) +{ + if (window) + meta_window_delete (window, event->xkey.time); +} + +static void +handle_begin_move (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) +{ + if (window) + { + meta_window_raise (window); + meta_display_begin_grab_op (window->display, + window, + META_GRAB_OP_KEYBOARD_MOVING, + FALSE, 0, 0, + event->xkey.time, + 0, 0); + } +} + +static void +handle_begin_resize (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) +{ + /* FIXME */ +} + +static void +handle_toggle_sticky (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) +{ + if (window) + { + if (window->on_all_workspaces) + meta_window_unstick (window); + else + meta_window_stick (window); + } +} + +static void +handle_move_to_workspace (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) +{ + int which; + MetaWorkspace *workspace; + + which = GPOINTER_TO_INT (binding->handler->data); + + workspace = NULL; + if (which < 0) + { + MetaScreen *screen; + + screen = meta_display_screen_for_root (display, + event->xkey.root); + + if (screen == NULL) + return; + + workspace = meta_workspace_get_neighbor (screen->active_workspace, + which); + } + else + { + workspace = meta_display_get_workspace_by_index (display, which); + } + + if (workspace) + { + meta_window_change_workspace (window, workspace); + } + else + { + /* We could offer to create it I suppose */ + } +} + +static void +handle_spew_mark (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) { meta_verbose ("-- MARK MARK MARK MARK --\n"); } @@ -1191,11 +1706,13 @@ meta_set_keybindings_disabled (gboolean setting) if (meta_is_debugging ()) { all_bindings_disabled = setting; - meta_verbose ("Keybindings %s\n", all_bindings_disabled ? "disabled" : "enabled"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Keybindings %s\n", all_bindings_disabled ? "disabled" : "enabled"); } else { - meta_verbose ("Ignoring keybindings disable message, not in debug mode\n"); + meta_topic (META_DEBUG_KEYBINDINGS, + "Ignoring keybindings disable message, not in debug mode\n"); } } diff --git a/src/keybindings.h b/src/keybindings.h index 85255a78a..20187e075 100644 --- a/src/keybindings.h +++ b/src/keybindings.h @@ -25,17 +25,20 @@ #include "display.h" #include "window.h" -void meta_display_init_keys (MetaDisplay *display); -void meta_screen_grab_keys (MetaScreen *screen); -void meta_screen_ungrab_keys (MetaScreen *screen); -void meta_window_grab_keys (MetaWindow *window); -void meta_window_ungrab_keys (MetaWindow *window); -gboolean meta_window_grab_all_keys (MetaWindow *window); -void meta_window_ungrab_all_keys (MetaWindow *window); -void meta_display_process_key_event (MetaDisplay *display, - MetaWindow *window, - XEvent *event); -void meta_set_keybindings_disabled (gboolean setting); +void meta_display_init_keys (MetaDisplay *display); +void meta_display_shutdown_keys (MetaDisplay *display); +void meta_screen_grab_keys (MetaScreen *screen); +void meta_screen_ungrab_keys (MetaScreen *screen); +void meta_window_grab_keys (MetaWindow *window); +void meta_window_ungrab_keys (MetaWindow *window); +gboolean meta_window_grab_all_keys (MetaWindow *window); +void meta_window_ungrab_all_keys (MetaWindow *window); +void meta_display_process_key_event (MetaDisplay *display, + MetaWindow *window, + XEvent *event); +void meta_set_keybindings_disabled (gboolean setting); +void meta_display_process_mapping_event (MetaDisplay *display, + XEvent *event); #endif diff --git a/src/metacity.schemas b/src/metacity.schemas index e8aa7b349..e77241801 100644 --- a/src/metacity.schemas +++ b/src/metacity.schemas @@ -107,11 +107,11 @@ - + - /schemas/apps/metacity/keybindings/activate_window_menu - /apps/metacity/keybindings/activate_window_menu + /schemas/apps/metacity/window_keybindings/activate_window_menu + /apps/metacity/window_keybindings/activate_window_menu metacity string <Alt>space @@ -119,18 +119,1034 @@ Activate window menu The keybinding used to activate the window menu. - The format looks like "<Control>a" or "<Shift><Alt>F1" or - "<Release>z" (the last one is for key release). The parser is + The format looks like "<Control>a" or "<Shift><Alt>F1. + The parser is fairly liberal and allows lower or upper case, and also - abbreviations such as "<Ctl>" and "<Ctrl>". This option can be - set to a single string, or a list of strings; if a list, - all of the given keybindings will be present. If you set + abbreviations such as "<Ctl>" and "<Ctrl>". If +you set the option to the special string "disabled", then there will be no keybinding for this action. + + + /schemas/apps/metacity/window_keybindings/toggle_fullscreen + /apps/metacity/window_keybindings/toggle_fullscreen + metacity + string + disabled + + Toggle fullscreen mode + + The keybinding used to toggle fullscreen mode. + The format looks like "<Control>a" or "<Shift><Alt>F1. + The parser is + fairly liberal and allows lower or upper case, and also + abbreviations such as "<Ctl>" and "<Ctrl>". If +you set + the option to the special string "disabled", then there + will be no keybinding for this action. + + + + + + /schemas/apps/metacity/window_keybindings/toggle_maximized + /apps/metacity/window_keybindings/toggle_maximized + metacity + string + disabled + + Toggle maximization state + + The keybinding used to toggle maximization. + The format looks like "<Control>a" or "<Shift><Alt>F1. + The parser is + fairly liberal and allows lower or upper case, and also + abbreviations such as "<Ctl>" and "<Ctrl>". If +you set + the option to the special string "disabled", then there + will be no keybinding for this action. + + + + + + /schemas/apps/metacity/window_keybindings/toggle_shaded + /apps/metacity/window_keybindings/toggle_shaded + metacity + string + disabled + + Toggle shaded state + + The keybinding used to toggle shaded/unshaded state. + The format looks like "<Control>a" or "<Shift><Alt>F1. + The parser is + fairly liberal and allows lower or upper case, and also + abbreviations such as "<Ctl>" and "<Ctrl>". If +you set + the option to the special string "disabled", then there + will be no keybinding for this action. + + + + + + /schemas/apps/metacity/window_keybindings/close + /apps/metacity/window_keybindings/close + metacity + string + disabled + + Close a window + + The keybinding used to close a window. + The format looks like "<Control>a" or "<Shift><Alt>F1. + The parser is + fairly liberal and allows lower or upper case, and also + abbreviations such as "<Ctl>" and "<Ctrl>". If +you set + the option to the special string "disabled", then there + will be no keybinding for this action. + + + + + + /schemas/apps/metacity/window_keybindings/begin_move + /apps/metacity/window_keybindings/begin_move + metacity + string + disabled + + Move a window + + The keybinding used to enter "move mode" and begin moving a + window using the keyboard. + The format looks like "<Control>a" or "<Shift><Alt>F1. + The parser is + fairly liberal and allows lower or upper case, and also + abbreviations such as "<Ctl>" and "<Ctrl>". If +you set + the option to the special string "disabled", then there + will be no keybinding for this action. + + + + + + /schemas/apps/metacity/window_keybindings/begin_resize + /apps/metacity/window_keybindings/begin_resize + metacity + string + disabled + + Move a window + + The keybinding used to enter "resize mode" and begin resizing a + window using the keyboard. + The format looks like "<Control>a" or "<Shift><Alt>F1. + The parser is + fairly liberal and allows lower or upper case, and also + abbreviations such as "<Ctl>" and "<Ctrl>". If +you set + the option to the special string "disabled", then there + will be no keybinding for this action. + + + + + + /schemas/apps/metacity/window_keybindings/toggle_on_all_workspaces + /apps/metacity/window_keybindings/toggle_on_all_workspaces + metacity + string + disabled + + Toggle whether the window is on all workspaces + + The keybinding used to toggle whether the window is on all + workspaces or just one. + The format looks like "<Control>a" or "<Shift><Alt>F1. + The parser is + fairly liberal and allows lower or upper case, and also + abbreviations such as "<Ctl>" and "<Ctrl>". If +you set + the option to the special string "disabled", then there + will be no keybinding for this action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_1 + /apps/metacity/window_keybindings/move_to_workspace_1 + metacity + string + disabled + + Move window to workspace 1 + + The keybinding used to move a window to workspace 1. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_2 + /apps/metacity/window_keybindings/move_to_workspace_2 + metacity + string + disabled + + Move window to workspace 2 + + The keybinding used to move a window to workspace 2. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_3 + /apps/metacity/window_keybindings/move_to_workspace_3 + metacity + string + disabled + + Move window to workspace 3 + + The keybinding used to move a window to workspace 3. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_4 + /apps/metacity/window_keybindings/move_to_workspace_4 + metacity + string + disabled + + Move window to workspace 4 + + The keybinding used to move a window to workspace 4. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_5 + /apps/metacity/window_keybindings/move_to_workspace_5 + metacity + string + disabled + + Move window to workspace 5 + + The keybinding used to move a window to workspace 5. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_6 + /apps/metacity/window_keybindings/move_to_workspace_6 + metacity + string + disabled + + Move window to workspace 6 + + The keybinding used to move a window to workspace 6. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_7 + /apps/metacity/window_keybindings/move_to_workspace_7 + metacity + string + disabled + + Move window to workspace 7 + + The keybinding used to move a window to workspace 7. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_8 + /apps/metacity/window_keybindings/move_to_workspace_8 + metacity + string + disabled + + Move window to workspace 8 + + The keybinding used to move a window to workspace 8. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_9 + /apps/metacity/window_keybindings/move_to_workspace_9 + metacity + string + disabled + + Move window to workspace 9 + + The keybinding used to move a window to workspace 9. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_10 + /apps/metacity/window_keybindings/move_to_workspace_10 + metacity + string + disabled + + Move window to workspace 10 + + The keybinding used to move a window to workspace 10. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_11 + /apps/metacity/window_keybindings/move_to_workspace_11 + metacity + string + disabled + + Move window to workspace 11 + + The keybinding used to move a window to workspace 11. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_12 + /apps/metacity/window_keybindings/move_to_workspace_12 + metacity + string + disabled + + Move window to workspace 6 + + The keybinding used to move a window to workspace 6. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_left + /apps/metacity/window_keybindings/move_to_workspace_left + metacity + string + disabled + + Move window one workspace to the left + + The keybinding used to move a window one workspace to the left. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_right + /apps/metacity/window_keybindings/move_to_workspace_right + metacity + string + disabled + + Move window one workspace to the right + + The keybinding used to move a window one workspace to the right. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_up + /apps/metacity/window_keybindings/move_to_workspace_up + metacity + string + disabled + + Move window one workspace up + + The keybinding used to move a window one workspace up. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/window_keybindings/move_to_workspace_down + /apps/metacity/window_keybindings/move_to_workspace_down + metacity + string + disabled + + Move window one workspace down + + The keybinding used to move a window one workspace down. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + + + /schemas/apps/metacity/global_keybindings/switch_windows + /apps/metacity/global_keybindings/switch_windows + metacity + string + <Alt>Tab + + Move focus between windows + + The keybinding used to move focus between windows. + (Traditionally <Alt>Tab) + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/global_keybindings/switch_panels + /apps/metacity/global_keybindings/switch_panels + metacity + string + <Control><Alt>Tab + + Move focus between panels and the desktop + + The keybinding used to move focus between panels and + the desktop. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/global_keybindings/focus_previous_window + /apps/metacity/global_keybindings/focus_previous_window + metacity + string + <Alt>Escape + + Move focus to the previously-focused window + + The keybinding used to move focus back to the window which last + had the focus. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/global_keybindings/show_desktop + /apps/metacity/global_keybindings/show_desktop + metacity + string + <Control><Alt>d + + Hide all windows and focus desktop + + The keybinding used to hide all normal windows and set the + focus to the desktop background. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_1 + /apps/metacity/global_keybindings/switch_to_workspace_1 + metacity + string + disabled + + Switch to workspace 1 + + The keybinding that switches to workspace 1. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_2 + /apps/metacity/global_keybindings/switch_to_workspace_2 + metacity + string + disabled + + Switch to workspace 2 + + The keybinding that switches to workspace 2. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_3 + /apps/metacity/global_keybindings/switch_to_workspace_3 + metacity + string + disabled + + Switch to workspace 3 + + The keybinding that switches to workspace 3. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_4 + /apps/metacity/global_keybindings/switch_to_workspace_4 + metacity + string + disabled + + Switch to workspace 4 + + The keybinding that switches to workspace 4. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_5 + /apps/metacity/global_keybindings/switch_to_workspace_5 + metacity + string + disabled + + Switch to workspace 5 + + The keybinding that switches to workspace 5. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_6 + /apps/metacity/global_keybindings/switch_to_workspace_6 + metacity + string + disabled + + Switch to workspace 6 + + The keybinding that switches to workspace 6. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_7 + /apps/metacity/global_keybindings/switch_to_workspace_7 + metacity + string + disabled + + Switch to workspace 7 + + The keybinding that switches to workspace 7. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_8 + /apps/metacity/global_keybindings/switch_to_workspace_8 + metacity + string + disabled + + Switch to workspace 8 + + The keybinding that switches to workspace 8. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_9 + /apps/metacity/global_keybindings/switch_to_workspace_9 + metacity + string + disabled + + Switch to workspace 9 + + The keybinding that switches to workspace 9. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_10 + /apps/metacity/global_keybindings/switch_to_workspace_10 + metacity + string + disabled + + Switch to workspace 10 + + The keybinding that switches to workspace 10. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_11 + /apps/metacity/global_keybindings/switch_to_workspace_11 + metacity + string + disabled + + Switch to workspace 11 + + The keybinding that switches to workspace 11. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_12 + /apps/metacity/global_keybindings/switch_to_workspace_12 + metacity + string + disabled + + Switch to workspace 12 + + The keybinding that switches to workspace 12. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_left + /apps/metacity/global_keybindings/switch_to_workspace_left + metacity + string + <Alt>Left + + Switch to workspace on the left + + The keybinding that switches to the workspace on the left + of the current workspace. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_right + /apps/metacity/global_keybindings/switch_to_workspace_right + metacity + string + <Alt>Right + + Switch to workspace on the right + + The keybinding that switches to the workspace on the right + of the current workspace. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_up + /apps/metacity/global_keybindings/switch_to_workspace_up + metacity + string + <Alt>Up + + Switch to workspace above the current space + + The keybinding that switches to the workspace above + the current workspace. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/global_keybindings/switch_to_workspace_down + /apps/metacity/global_keybindings/switch_to_workspace_down + metacity + string + <Alt>Down + + Switch to workspace below the current space + + The keybinding that switches to the workspace below + the current workspace. + + The format looks like "<Control>a" or + "<Shift><Alt>F1. + + The parser is fairly liberal and allows lower or upper case, + and also abbreviations such as "<Ctl>" and + "<Ctrl>". If you set the option to the special string + "disabled", then there will be no keybinding for this + action. + + + + + + + /schemas/apps/metacity/general/application_based /apps/metacity/general/application_based @@ -138,7 +1154,7 @@ bool false - Navigation works in terms of applications not windows + (Not implemented) Navigation works in terms of applications not windows If true, then Metacity works in terms of applications rather than windows. The concept is a bit abstract, but diff --git a/src/prefs.c b/src/prefs.c index ba898f587..def0f07d3 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -21,6 +21,7 @@ #include #include "prefs.h" +#include "ui.h" #include "util.h" #include #include @@ -36,6 +37,9 @@ #define KEY_NUM_WORKSPACES "/apps/metacity/general/num_workspaces" #define KEY_APPLICATION_BASED "/apps/metacity/general/application_based" +#define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings" +#define KEY_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings" + static GConfClient *default_client = NULL; static GList *listeners = NULL; static GList *changes = NULL; @@ -55,6 +59,13 @@ static gboolean update_focus_mode (const char *value); static gboolean update_theme (const char *value); static gboolean update_num_workspaces (int value); static gboolean update_application_based (gboolean value); +static gboolean update_window_binding (const char *name, + const char *value); +static gboolean update_screen_binding (const char *name, + const char *value); +static void init_bindings (void); +static gboolean update_binding (MetaKeyPref *binding, + const char *value); static void queue_changed (MetaPreference pref); static void change_notify (GConfClient *client, @@ -173,9 +184,11 @@ queue_changed (MetaPreference pref) else meta_verbose ("Change of pref %s was already pending\n", meta_preference_to_string (pref)); - + + /* add idle at priority below the gconf notify idle */ if (changed_idle == 0) - changed_idle = g_idle_add (changed_idle_handler, NULL); + changed_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 10, + changed_idle_handler, NULL, NULL); } static void @@ -251,6 +264,9 @@ meta_prefs_init (void) &err); cleanup_error (&err); update_application_based (bool_val); + + /* Load keybindings prefs */ + init_bindings (); gconf_client_notify_add (default_client, "/apps/metacity", change_notify, @@ -260,6 +276,27 @@ meta_prefs_init (void) cleanup_error (&err); } +/* from eel */ +static gboolean +str_has_prefix (const char *haystack, const char *needle) +{ + const char *h, *n; + + /* Eat one character at a time. */ + h = haystack == NULL ? "" : haystack; + n = needle == NULL ? "" : needle; + do + { + if (*n == '\0') + return TRUE; + if (*h == '\0') + return FALSE; + } + while (*h++ == *n++); + + return FALSE; +} + static void change_notify (GConfClient *client, guint cnxn_id, @@ -388,6 +425,38 @@ change_notify (GConfClient *client, if (update_application_based (b)) queue_changed (META_PREF_APPLICATION_BASED); } + else if (str_has_prefix (key, KEY_WINDOW_BINDINGS_PREFIX)) + { + const char *str; + + if (value && value->type != GCONF_VALUE_STRING) + { + meta_warning (_("GConf key \"%s\" is set to an invalid type\n"), + key); + goto out; + } + + str = value ? gconf_value_get_string (value) : NULL; + + if (update_window_binding (key, str)) + queue_changed (META_PREF_WINDOW_KEYBINDINGS); + } + else if (str_has_prefix (key, KEY_SCREEN_BINDINGS_PREFIX)) + { + const char *str; + + if (value && value->type != GCONF_VALUE_STRING) + { + meta_warning (_("GConf key \"%s\" is set to an invalid type\n"), + key); + goto out; + } + + str = value ? gconf_value_get_string (value) : NULL; + + if (update_screen_binding (key, str)) + queue_changed (META_PREF_SCREEN_KEYBINDINGS); + } else { meta_verbose ("Key %s doesn't mean anything to Metacity\n", @@ -589,27 +658,27 @@ meta_preference_to_string (MetaPreference pref) { case META_PREF_FOCUS_MODE: return "FOCUS_MODE"; - break; case META_PREF_THEME: return "THEME"; - break; case META_PREF_TITLEBAR_FONT: return "TITLEBAR_FONT"; - break; case META_PREF_TITLEBAR_FONT_SIZE: return "TITLEBAR_FONT_SIZE"; - break; case META_PREF_NUM_WORKSPACES: return "NUM_WORKSPACES"; - break; case META_PREF_APPLICATION_BASED: return "APPLICATION_BASED"; - break; + + case META_PREF_SCREEN_KEYBINDINGS: + return "SCREEN_KEYBINDINGS"; + + case META_PREF_WINDOW_KEYBINDINGS: + return "WINDOW_KEYBINDINGS"; } return "(unknown)"; @@ -642,3 +711,222 @@ meta_prefs_set_num_workspaces (int n_workspaces) g_error_free (err); } } + +static MetaKeyPref screen_bindings[] = { + { META_KEYBINDING_WORKSPACE_1, 0, 0 }, + { META_KEYBINDING_WORKSPACE_2, 0, 0 }, + { META_KEYBINDING_WORKSPACE_3, 0, 0 }, + { META_KEYBINDING_WORKSPACE_4, 0, 0 }, + { META_KEYBINDING_WORKSPACE_5, 0, 0 }, + { META_KEYBINDING_WORKSPACE_6, 0, 0 }, + { META_KEYBINDING_WORKSPACE_7, 0, 0 }, + { META_KEYBINDING_WORKSPACE_8, 0, 0 }, + { META_KEYBINDING_WORKSPACE_9, 0, 0 }, + { META_KEYBINDING_WORKSPACE_10, 0, 0 }, + { META_KEYBINDING_WORKSPACE_11, 0, 0 }, + { META_KEYBINDING_WORKSPACE_12, 0, 0 }, + { META_KEYBINDING_WORKSPACE_LEFT, 0, 0 }, + { META_KEYBINDING_WORKSPACE_RIGHT, 0, 0 }, + { META_KEYBINDING_WORKSPACE_UP, 0, 0 }, + { META_KEYBINDING_WORKSPACE_DOWN, 0, 0 }, + { META_KEYBINDING_SWITCH_WINDOWS, 0, 0 }, + { META_KEYBINDING_SWITCH_PANELS, 0, 0 }, + { META_KEYBINDING_FOCUS_PREVIOUS, 0, 0 }, + { META_KEYBINDING_SHOW_DESKTOP, 0, 0 }, + { NULL, 0, 0 } +}; + +static MetaKeyPref window_bindings[] = { + { META_KEYBINDING_WINDOW_MENU, 0, 0 }, + { META_KEYBINDING_TOGGLE_FULLSCREEN, 0, 0 }, + { META_KEYBINDING_TOGGLE_MAXIMIZE, 0, 0 }, + { META_KEYBINDING_TOGGLE_SHADE, 0, 0 }, + { META_KEYBINDING_CLOSE, 0, 0 }, + { META_KEYBINDING_BEGIN_MOVE, 0, 0 }, + { META_KEYBINDING_BEGIN_RESIZE, 0, 0 }, + { META_KEYBINDING_TOGGLE_STICKY, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_1, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_2, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_3, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_4, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_5, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_6, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_7, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_8, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_9, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_10, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_11, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_12, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_LEFT, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_RIGHT, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_UP, 0, 0 }, + { META_KEYBINDING_MOVE_WORKSPACE_DOWN, 0, 0 }, + { NULL, 0, 0 } +}; + +static void +init_bindings (void) +{ + int i; + GError *err; + + i = 0; + while (window_bindings[i].name) + { + char *str_val; + char *key; + + key = g_strconcat (KEY_WINDOW_BINDINGS_PREFIX, "/", + window_bindings[i].name, NULL); + + err = NULL; + str_val = gconf_client_get_string (default_client, key, &err); + cleanup_error (&err); + + update_binding (&window_bindings[i], str_val); + + g_free (str_val); + g_free (key); + + ++i; + } + + i = 0; + while (screen_bindings[i].name) + { + char *str_val; + char *key; + + key = g_strconcat (KEY_SCREEN_BINDINGS_PREFIX, "/", + screen_bindings[i].name, NULL); + + err = NULL; + str_val = gconf_client_get_string (default_client, key, &err); + cleanup_error (&err); + + update_binding (&screen_bindings[i], str_val); + + g_free (str_val); + g_free (key); + + ++i; + } +} + +static gboolean +update_binding (MetaKeyPref *binding, + const char *value) +{ + unsigned int keysym; + unsigned long mask; + gboolean changed; + + meta_topic (META_DEBUG_KEYBINDINGS, + "Binding \"%s\" has new gconf value \"%s\"\n", + binding->name, value ? value : "none"); + + keysym = 0; + mask = 0; + if (value) + { + if (!meta_ui_parse_accelerator (value, &keysym, &mask)) + { + meta_topic (META_DEBUG_KEYBINDINGS, + "Failed to parse new gconf value\n"); + meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\""), + value, binding->name); + } + } + + changed = FALSE; + if (keysym != binding->keysym || + mask != binding->mask) + { + changed = TRUE; + + binding->keysym = keysym; + binding->mask = mask; + + meta_topic (META_DEBUG_KEYBINDINGS, + "New keybinding for \"%s\" is keysym = 0x%x mask = 0x%lx\n", + binding->name, binding->keysym, binding->mask); + } + else + { + meta_topic (META_DEBUG_KEYBINDINGS, + "Keybinding for \"%s\" is unchanged\n", binding->name); + } + + return changed; +} + +static const gchar* +relative_key (const gchar* key) +{ + const gchar* end; + + end = strrchr (key, '/'); + + ++end; + + return end; +} + +/* Return value is TRUE if a preference changed and we need to + * notify + */ +static gboolean +find_and_update_binding (MetaKeyPref *bindings, + const char *name, + const char *value) +{ + const char *key; + int i; + + if (*name == '/') + key = relative_key (name); + else + key = name; + + i = 0; + while (bindings[i].name && + strcmp (key, bindings[i].name) != 0) + ++i; + + if (bindings[i].name) + return update_binding (&bindings[i], value); + else + return FALSE; +} + +static gboolean +update_window_binding (const char *name, + const char *value) +{ + return find_and_update_binding (window_bindings, name, value); +} + +static gboolean +update_screen_binding (const char *name, + const char *value) +{ + return find_and_update_binding (screen_bindings, name, value); +} + +void +meta_prefs_get_screen_bindings (const MetaKeyPref **bindings, + int *n_bindings) +{ + + *bindings = screen_bindings; + *n_bindings = (int) G_N_ELEMENTS (screen_bindings) - 1; +} + +void +meta_prefs_get_window_bindings (const MetaKeyPref **bindings, + int *n_bindings) +{ + *bindings = window_bindings; + *n_bindings = (int) G_N_ELEMENTS (window_bindings) - 1; +} + diff --git a/src/prefs.h b/src/prefs.h index 0684dd2ca..2b94ee774 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -33,7 +33,9 @@ typedef enum META_PREF_TITLEBAR_FONT, META_PREF_TITLEBAR_FONT_SIZE, META_PREF_NUM_WORKSPACES, - META_PREF_APPLICATION_BASED + META_PREF_APPLICATION_BASED, + META_PREF_WINDOW_KEYBINDINGS, + META_PREF_SCREEN_KEYBINDINGS } MetaPreference; typedef void (* MetaPrefsChangedFunc) (MetaPreference pref, @@ -58,6 +60,66 @@ gboolean meta_prefs_get_application_based (void); void meta_prefs_set_num_workspaces (int n_workspaces); +/* Screen bindings */ +#define META_KEYBINDING_WORKSPACE_1 "switch_to_workspace_1" +#define META_KEYBINDING_WORKSPACE_2 "switch_to_workspace_2" +#define META_KEYBINDING_WORKSPACE_3 "switch_to_workspace_3" +#define META_KEYBINDING_WORKSPACE_4 "switch_to_workspace_4" +#define META_KEYBINDING_WORKSPACE_5 "switch_to_workspace_5" +#define META_KEYBINDING_WORKSPACE_6 "switch_to_workspace_6" +#define META_KEYBINDING_WORKSPACE_7 "switch_to_workspace_7" +#define META_KEYBINDING_WORKSPACE_8 "switch_to_workspace_8" +#define META_KEYBINDING_WORKSPACE_9 "switch_to_workspace_9" +#define META_KEYBINDING_WORKSPACE_10 "switch_to_workspace_10" +#define META_KEYBINDING_WORKSPACE_11 "switch_to_workspace_11" +#define META_KEYBINDING_WORKSPACE_12 "switch_to_workspace_12" +#define META_KEYBINDING_WORKSPACE_LEFT "switch_to_workspace_left" +#define META_KEYBINDING_WORKSPACE_RIGHT "switch_to_workspace_right" +#define META_KEYBINDING_WORKSPACE_UP "switch_to_workspace_up" +#define META_KEYBINDING_WORKSPACE_DOWN "switch_to_workspace_down" +#define META_KEYBINDING_SWITCH_WINDOWS "switch_windows" +#define META_KEYBINDING_SWITCH_PANELS "switch_panels" +#define META_KEYBINDING_FOCUS_PREVIOUS "focus_previous_window" +#define META_KEYBINDING_SHOW_DESKTOP "show_desktop" + +/* Window bindings */ +#define META_KEYBINDING_WINDOW_MENU "activate_window_menu" +#define META_KEYBINDING_TOGGLE_FULLSCREEN "toggle_fullscreen" +#define META_KEYBINDING_TOGGLE_MAXIMIZE "toggle_maximized" +#define META_KEYBINDING_TOGGLE_SHADE "toggle_shaded" +#define META_KEYBINDING_CLOSE "close" +#define META_KEYBINDING_BEGIN_MOVE "begin_move" +#define META_KEYBINDING_BEGIN_RESIZE "begin_resize" +#define META_KEYBINDING_TOGGLE_STICKY "toggle_on_all_workspaces" +#define META_KEYBINDING_MOVE_WORKSPACE_1 "move_to_workspace_1" +#define META_KEYBINDING_MOVE_WORKSPACE_2 "move_to_workspace_2" +#define META_KEYBINDING_MOVE_WORKSPACE_3 "move_to_workspace_3" +#define META_KEYBINDING_MOVE_WORKSPACE_4 "move_to_workspace_4" +#define META_KEYBINDING_MOVE_WORKSPACE_5 "move_to_workspace_5" +#define META_KEYBINDING_MOVE_WORKSPACE_6 "move_to_workspace_6" +#define META_KEYBINDING_MOVE_WORKSPACE_7 "move_to_workspace_7" +#define META_KEYBINDING_MOVE_WORKSPACE_8 "move_to_workspace_8" +#define META_KEYBINDING_MOVE_WORKSPACE_9 "move_to_workspace_9" +#define META_KEYBINDING_MOVE_WORKSPACE_10 "move_to_workspace_10" +#define META_KEYBINDING_MOVE_WORKSPACE_11 "move_to_workspace_11" +#define META_KEYBINDING_MOVE_WORKSPACE_12 "move_to_workspace_12" +#define META_KEYBINDING_MOVE_WORKSPACE_LEFT "move_to_workspace_left" +#define META_KEYBINDING_MOVE_WORKSPACE_RIGHT "move_to_workspace_right" +#define META_KEYBINDING_MOVE_WORKSPACE_UP "move_to_workspace_up" +#define META_KEYBINDING_MOVE_WORKSPACE_DOWN "move_to_workspace_down" + +typedef struct +{ + const char *name; + unsigned int keysym; + unsigned long mask; +} MetaKeyPref; + +void meta_prefs_get_screen_bindings (const MetaKeyPref **bindings, + int *n_bindings); +void meta_prefs_get_window_bindings (const MetaKeyPref **bindings, + int *n_bindings); + #endif diff --git a/src/screen.c b/src/screen.c index f02e99d2d..9a5f2d566 100644 --- a/src/screen.c +++ b/src/screen.c @@ -312,7 +312,8 @@ meta_screen_new (MetaDisplay *display, */ screen->active_workspace = meta_workspace_new (screen); update_num_workspaces (screen); - + + screen->keys_grabbed = FALSE; meta_screen_grab_keys (screen); screen->ui = meta_ui_new (screen->display->xdisplay, diff --git a/src/screen.h b/src/screen.h index 6b8c3549a..12915e7b3 100644 --- a/src/screen.h +++ b/src/screen.h @@ -62,6 +62,8 @@ struct _MetaScreen MetaXineramaScreenInfo *xinerama_infos; int n_xinerama_infos; + + guint keys_grabbed : 1; }; MetaScreen* meta_screen_new (MetaDisplay *display, diff --git a/src/ui.c b/src/ui.c index 5a512ec37..1dbd662a9 100644 --- a/src/ui.c +++ b/src/ui.c @@ -31,6 +31,8 @@ #include +#include + struct _MetaUI { Display *xdisplay; @@ -592,3 +594,47 @@ meta_ui_have_a_theme (void) { return meta_theme_get_current () != NULL; } + +gboolean +meta_ui_parse_accelerator (const char *accel, + unsigned int *keysym, + unsigned long *mask) +{ + GdkModifierType gdk_mask = 0; + guint gdk_sym = 0; + + *keysym = 0; + *mask = 0; + + if (strcmp (accel, "disabled") == 0) + return TRUE; + + gtk_accelerator_parse (accel, &gdk_sym, &gdk_mask); + + if (gdk_sym == None) + return FALSE; + + if (gdk_mask & GDK_RELEASE_MASK) /* we don't allow this */ + return FALSE; + + *keysym = gdk_sym; + + if (gdk_mask & GDK_SHIFT_MASK) + *mask |= ShiftMask; + if (gdk_mask & GDK_LOCK_MASK) + *mask |= LockMask; + if (gdk_mask & GDK_CONTROL_MASK) + *mask |= ControlMask; + if (gdk_mask & GDK_MOD1_MASK) + *mask |= Mod1Mask; + if (gdk_mask & GDK_MOD2_MASK) + *mask |= Mod2Mask; + if (gdk_mask & GDK_MOD3_MASK) + *mask |= Mod3Mask; + if (gdk_mask & GDK_MOD4_MASK) + *mask |= Mod4Mask; + if (gdk_mask & GDK_MOD5_MASK) + *mask |= Mod5Mask; + + return TRUE; +} diff --git a/src/ui.h b/src/ui.h index 1e63f66a6..f0f38c5a9 100644 --- a/src/ui.h +++ b/src/ui.h @@ -145,6 +145,9 @@ void meta_ui_set_current_theme (const char *name, gboolean force_reload); gboolean meta_ui_have_a_theme (void); +gboolean meta_ui_parse_accelerator (const char *accel, + unsigned int *keysym, + unsigned long *mask); #include "tabpopup.h" diff --git a/src/util.c b/src/util.c index e90c7afa9..a48edf44c 100644 --- a/src/util.c +++ b/src/util.c @@ -192,6 +192,8 @@ topic_name (MetaDebugTopic topic) return "PING"; case META_DEBUG_XINERAMA: return "XINERAMA"; + case META_DEBUG_KEYBINDINGS: + return "KEYBINDINGS"; } return "Window manager"; diff --git a/src/util.h b/src/util.h index fa651aa90..52b87c97b 100644 --- a/src/util.h +++ b/src/util.h @@ -56,7 +56,8 @@ typedef enum META_DEBUG_GEOMETRY = 1 << 8, META_DEBUG_PLACEMENT = 1 << 9, META_DEBUG_PING = 1 << 10, - META_DEBUG_XINERAMA = 1 << 11 + META_DEBUG_XINERAMA = 1 << 11, + META_DEBUG_KEYBINDINGS = 1 << 12 } MetaDebugTopic; diff --git a/src/window.c b/src/window.c index 3cbf700e7..e27f61ac3 100644 --- a/src/window.c +++ b/src/window.c @@ -1569,6 +1569,12 @@ void meta_window_activate (MetaWindow *window, guint32 timestamp) { + /* disable show desktop mode unless we're a desktop component */ + if (window->display->showing_desktop && + window->type != META_WINDOW_DESKTOP && + window->type != META_WINDOW_DOCK) + meta_display_unshow_desktop (window->display); + /* Get window on current workspace */ if (!meta_window_visible_on_workspace (window, window->screen->active_workspace)) @@ -5104,6 +5110,7 @@ menu_callback (MetaWindowMenu *menu, break; case META_MENU_OP_RESIZE: + /* FIXME */ break; case 0: diff --git a/src/workspace.c b/src/workspace.c index e88a976c4..a673deba8 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -441,3 +441,31 @@ meta_workspace_get_work_area (MetaWorkspace *workspace, *area = workspace->work_area; } + +MetaWorkspace* +meta_workspace_get_neighbor (MetaWorkspace *workspace, + MetaMotionDirection direction) +{ + /* FIXME this isn't using any sane layout, just assuming + * the spaces are in a big row + */ + int i; + + i = meta_workspace_index (workspace); + + switch (direction) + { + case META_MOTION_LEFT: + --i; + break; + case META_MOTION_RIGHT: + ++i; + break; + case META_MOTION_UP: + case META_MOTION_DOWN: + return NULL; + } + + return meta_display_get_workspace_by_index (workspace->screen->display, + i); +} diff --git a/src/workspace.h b/src/workspace.h index 46439d245..c55af458e 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -24,6 +24,17 @@ #include "window.h" +/* Negative to avoid conflicting with real workspace + * numbers + */ +typedef enum +{ + META_MOTION_UP = -1, + META_MOTION_DOWN = -2, + META_MOTION_LEFT = -3, + META_MOTION_RIGHT = -4 +} MetaMotionDirection; + struct _MetaWorkspace { MetaScreen *screen; @@ -55,6 +66,9 @@ void meta_workspace_get_work_area (MetaWorkspace *workspace, MetaRectangle *area); +MetaWorkspace* meta_workspace_get_neighbor (MetaWorkspace *workspace, + MetaMotionDirection direction); + #endif