Add support for a "meta key" which initiates extended WM operations

This patch adds the concept of a special key for WM operations, and
the default is Super_L, which on extended PC hardware is the
"Windows key".  What we do is handle the special case of a press
and release of this key (without any other intervening keys).

Super_L+<key> should still be passed to applications.  In the future
we may want to also take some of these keybindings (e.g. Super+TAB)
though.

http://bugzilla.gnome.org/show_bug.cgi?id=563047
This commit is contained in:
Colin Walters 2008-12-02 18:13:11 -05:00 committed by Owen W. Taylor
parent c4a4de0056
commit 514d00698d
7 changed files with 168 additions and 5 deletions

View File

@ -38,6 +38,7 @@
#include "boxes.h" #include "boxes.h"
#include "display.h" #include "display.h"
#include "keybindings-private.h" #include "keybindings-private.h"
#include "prefs.h"
#ifdef HAVE_STARTUP_NOTIFICATION #ifdef HAVE_STARTUP_NOTIFICATION
#include <libsn/sn.h> #include <libsn/sn.h>
@ -214,6 +215,8 @@ struct _MetaDisplay
unsigned int hyper_mask; unsigned int hyper_mask;
unsigned int super_mask; unsigned int super_mask;
unsigned int meta_mask; unsigned int meta_mask;
MetaKeyCombo overlay_key_combo;
gboolean overlay_key_only_pressed;
/* Xinerama cache */ /* Xinerama cache */
unsigned int xinerama_cache_invalidated : 1; unsigned int xinerama_cache_invalidated : 1;
@ -434,4 +437,6 @@ void meta_display_queue_autoraise_callback (MetaDisplay *display,
MetaWindow *window); MetaWindow *window);
void meta_display_remove_autoraise_callback (MetaDisplay *display); void meta_display_remove_autoraise_callback (MetaDisplay *display);
void meta_display_overlay_key_activate (MetaDisplay *display);
#endif #endif

View File

@ -129,6 +129,15 @@ typedef struct
G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT); G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);
/* Signals */
enum
{
OVERLAY_KEY,
LAST_SIGNAL
};
static guint display_signals [LAST_SIGNAL] = { 0 };
/** /**
* The display we're managing. This is a singleton object. (Historically, * The display we're managing. This is a singleton object. (Historically,
* this was a list of displays, but there was never any way to add more * this was a list of displays, but there was never any way to add more
@ -168,6 +177,14 @@ MetaGroup* get_focussed_group (MetaDisplay *display);
static void static void
meta_display_class_init (MetaDisplayClass *klass) meta_display_class_init (MetaDisplayClass *klass)
{ {
display_signals[OVERLAY_KEY] =
g_signal_new ("overlay-key",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
} }
/** /**
@ -5167,6 +5184,12 @@ meta_display_remove_autoraise_callback (MetaDisplay *display)
} }
} }
void
meta_display_overlay_key_activate (MetaDisplay *display)
{
g_signal_emit (display, display_signals[OVERLAY_KEY], 0);
}
#ifdef HAVE_COMPOSITE_EXTENSIONS #ifdef HAVE_COMPOSITE_EXTENSIONS
void void
meta_display_get_compositor_version (MetaDisplay *display, meta_display_get_compositor_version (MetaDisplay *display,

View File

@ -234,7 +234,14 @@ reload_keycodes (MetaDisplay *display)
{ {
meta_topic (META_DEBUG_KEYBINDINGS, meta_topic (META_DEBUG_KEYBINDINGS,
"Reloading keycodes for binding tables\n"); "Reloading keycodes for binding tables\n");
if (display->overlay_key_combo.keysym
&& display->overlay_key_combo.keycode == 0)
{
display->overlay_key_combo.keycode = XKeysymToKeycode (
display->xdisplay, display->overlay_key_combo.keysym);
}
if (display->key_bindings) if (display->key_bindings)
{ {
int i; int i;
@ -421,6 +428,19 @@ rebuild_key_binding_table (MetaDisplay *display)
prefs, n_prefs); prefs, n_prefs);
} }
static void
rebuild_special_bindings (MetaDisplay *display)
{
MetaKeyCombo combo;
meta_prefs_get_overlay_binding (&combo);
if (combo.keysym != None || combo.keycode != 0)
{
display->overlay_key_combo = combo;
}
}
static void static void
regrab_key_bindings (MetaDisplay *display) regrab_key_bindings (MetaDisplay *display)
{ {
@ -521,6 +541,7 @@ bindings_changed_callback (MetaPreference pref,
{ {
case META_PREF_KEYBINDINGS: case META_PREF_KEYBINDINGS:
rebuild_key_binding_table (display); rebuild_key_binding_table (display);
rebuild_special_bindings (display);
reload_keycodes (display); reload_keycodes (display);
reload_modifiers (display); reload_modifiers (display);
regrab_key_bindings (display); regrab_key_bindings (display);
@ -562,6 +583,7 @@ meta_display_init_keys (MetaDisplay *display)
reload_modmap (display); reload_modmap (display);
rebuild_key_binding_table (display); rebuild_key_binding_table (display);
rebuild_special_bindings (display);
reload_keycodes (display); reload_keycodes (display);
reload_modifiers (display); reload_modifiers (display);
@ -742,11 +764,18 @@ ungrab_all_keys (MetaDisplay *display,
void void
meta_screen_grab_keys (MetaScreen *screen) meta_screen_grab_keys (MetaScreen *screen)
{ {
MetaDisplay *display = screen->display;
if (screen->all_keys_grabbed) if (screen->all_keys_grabbed)
return; return;
if (screen->keys_grabbed) if (screen->keys_grabbed)
return; return;
if (display->overlay_key_combo.keycode != 0)
meta_grab_key (display, screen->xroot,
display->overlay_key_combo.keysym,
display->overlay_key_combo.keycode,
display->overlay_key_combo.modifiers);
grab_keys (screen->display->key_bindings, grab_keys (screen->display->key_bindings,
screen->display->n_key_bindings, screen->display->n_key_bindings,
@ -1140,6 +1169,31 @@ primary_modifier_still_pressed (MetaDisplay *display,
return TRUE; return TRUE;
} }
static gboolean
process_overlay_key (MetaDisplay *display,
MetaScreen *Screen,
XEvent *event,
KeySym keysym)
{
if (event->xkey.keycode != display->overlay_key_combo.keycode)
{
display->overlay_key_only_pressed = FALSE;
return FALSE;
}
if (event->xkey.type == KeyPress)
{
display->overlay_key_only_pressed = TRUE;
}
else if (event->xkey.type == KeyRelease && display->overlay_key_only_pressed)
{
display->overlay_key_only_pressed = FALSE;
meta_display_overlay_key_activate (display);
}
return TRUE;
}
/* now called from only one place, may be worth merging */ /* now called from only one place, may be worth merging */
static gboolean static gboolean
process_event (MetaKeyBinding *bindings, process_event (MetaKeyBinding *bindings,
@ -1238,6 +1292,7 @@ meta_display_process_key_event (MetaDisplay *display,
KeySym keysym; KeySym keysym;
gboolean keep_grab; gboolean keep_grab;
gboolean all_keys_grabbed; gboolean all_keys_grabbed;
gboolean handled;
const char *str; const char *str;
MetaScreen *screen; MetaScreen *screen;
@ -1361,11 +1416,15 @@ meta_display_process_key_event (MetaDisplay *display,
return; return;
} }
} }
handled = process_overlay_key (display, screen, event, keysym);
/* Do the normal keybindings */ /* Do the normal keybindings */
process_event (display->key_bindings, if (!handled)
display->n_key_bindings, process_event (display->key_bindings,
display, screen, window, event, keysym, display->n_key_bindings,
!all_keys_grabbed && window); display, screen, window, event, keysym,
!all_keys_grabbed && window);
} }
static gboolean static gboolean

View File

@ -57,6 +57,7 @@
#define KEY_TERMINAL_DIR "/desktop/gnome/applications/terminal" #define KEY_TERMINAL_DIR "/desktop/gnome/applications/terminal"
#define KEY_TERMINAL_COMMAND KEY_TERMINAL_DIR "/exec" #define KEY_TERMINAL_COMMAND KEY_TERMINAL_DIR "/exec"
#define KEY_OVERLAY_KEY "/apps/metacity/general/overlay_key"
#define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings" #define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings"
#define KEY_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings" #define KEY_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings"
#define KEY_LIST_BINDINGS_SUFFIX "_list" #define KEY_LIST_BINDINGS_SUFFIX "_list"
@ -1217,6 +1218,10 @@ change_notify (GConfClient *client,
if (update_workspace_name (key, str)) if (update_workspace_name (key, str))
queue_changed (META_PREF_WORKSPACE_NAMES); queue_changed (META_PREF_WORKSPACE_NAMES);
} }
else if (g_str_equal (key, KEY_OVERLAY_KEY))
{
queue_changed (META_PREF_KEYBINDINGS);
}
#ifdef WITH_CLUTTER #ifdef WITH_CLUTTER
else if (g_str_equal (key, KEY_CLUTTER_PLUGINS) && !clutter_plugins_overridden) else if (g_str_equal (key, KEY_CLUTTER_PLUGINS) && !clutter_plugins_overridden)
{ {
@ -1873,6 +1878,8 @@ static MetaKeyPref key_bindings[] = {
}; };
#undef keybind #undef keybind
static MetaKeyCombo overlay_key_combo = { 0, 0, 0 };
#ifndef HAVE_GCONF #ifndef HAVE_GCONF
/** /**
@ -1906,6 +1913,37 @@ static MetaSimpleKeyMapping key_string_bindings[] = {
#endif /* NOT HAVE_GCONF */ #endif /* NOT HAVE_GCONF */
/* These bindings are for modifiers alone, so they need special handling */
static void
init_special_bindings (void)
{
#ifdef HAVE_GCONF
char *val;
GError *err = NULL;
#endif
/* Default values for bindings which are global, but take special handling */
meta_ui_parse_accelerator ("Super_L", &overlay_key_combo.keysym,
&overlay_key_combo.keycode,
&overlay_key_combo.modifiers);
#ifdef HAVE_GCONF
val = gconf_client_get_string (default_client, KEY_OVERLAY_KEY, &err);
cleanup_error (&err);
if (val && meta_ui_parse_accelerator (val, &overlay_key_combo.keysym,
&overlay_key_combo.keycode,
&overlay_key_combo.modifiers))
;
else
{
meta_topic (META_DEBUG_KEYBINDINGS,
"Failed to parse value for overlay_key\n");
}
g_free (val);
#endif
}
static void static void
init_bindings (void) init_bindings (void)
{ {
@ -1959,9 +1997,11 @@ init_bindings (void)
++i; ++i;
} }
#else /* HAVE_GCONF */ #else /* HAVE_GCONF */
int i = 0; int i = 0;
int which = 0; int which = 0;
while (key_string_bindings[i].name) while (key_string_bindings[i].name)
{ {
if (key_string_bindings[i].keybinding == NULL) { if (key_string_bindings[i].keybinding == NULL) {
@ -1980,6 +2020,8 @@ init_bindings (void)
++i; ++i;
} }
#endif /* HAVE_GCONF */ #endif /* HAVE_GCONF */
init_special_bindings ();
} }
static void static void
@ -2688,6 +2730,12 @@ meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
*n_bindings = (int) G_N_ELEMENTS (key_bindings) - 1; *n_bindings = (int) G_N_ELEMENTS (key_bindings) - 1;
} }
void
meta_prefs_get_overlay_binding (MetaKeyCombo *combo)
{
*combo = overlay_key_combo;
}
MetaActionTitlebar MetaActionTitlebar
meta_prefs_get_action_double_click_titlebar (void) meta_prefs_get_action_double_click_titlebar (void)
{ {

View File

@ -2980,6 +2980,13 @@ meta_screen_get_screen_number (MetaScreen *screen)
return screen->number; return screen->number;
} }
/**
* meta_screen_get_display:
* Retrieve the display associated with screen.
* @screen: A #MetaScreen
*
* Returns: (transfer none): Display
*/
MetaDisplay * MetaDisplay *
meta_screen_get_display (MetaScreen *screen) meta_screen_get_display (MetaScreen *screen)
{ {

View File

@ -247,6 +247,8 @@ void meta_prefs_get_window_binding (const char *name,
unsigned int *keysym, unsigned int *keysym,
MetaVirtualModifier *modifiers); MetaVirtualModifier *modifiers);
void meta_prefs_get_overlay_binding (MetaKeyCombo *combo);
typedef enum typedef enum
{ {
META_VISUAL_BELL_INVALID = 0, META_VISUAL_BELL_INVALID = 0,

View File

@ -3,6 +3,25 @@
<!-- General preferences --> <!-- General preferences -->
<schema>
<key>/schemas/apps/metacity/general/overlay_key</key>
<applyto>/apps/metacity/general/overlay_key</applyto>
<owner>metacity</owner>
<type>string</type>
<default>&lt;Super_L&gt;</default>
<locale name="C">
<short>Modifier to use for extended window management operations</short>
<long>
This key will initiate the "overlay", which is a combination window
overview and application launching system. The default is intended
to be the "Windows key" on PC hardware.
It's expected that this binding either the default or set to
the empty string.
</long>
</locale>
</schema>
<schema> <schema>
<key>/schemas/apps/metacity/general/mouse_button_modifier</key> <key>/schemas/apps/metacity/general/mouse_button_modifier</key>
<applyto>/apps/metacity/general/mouse_button_modifier</applyto> <applyto>/apps/metacity/general/mouse_button_modifier</applyto>