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

View File

@ -129,6 +129,15 @@ typedef struct
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,
* 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
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
void
meta_display_get_compositor_version (MetaDisplay *display,

View File

@ -234,7 +234,14 @@ reload_keycodes (MetaDisplay *display)
{
meta_topic (META_DEBUG_KEYBINDINGS,
"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)
{
int i;
@ -421,6 +428,19 @@ rebuild_key_binding_table (MetaDisplay *display)
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
regrab_key_bindings (MetaDisplay *display)
{
@ -521,6 +541,7 @@ bindings_changed_callback (MetaPreference pref,
{
case META_PREF_KEYBINDINGS:
rebuild_key_binding_table (display);
rebuild_special_bindings (display);
reload_keycodes (display);
reload_modifiers (display);
regrab_key_bindings (display);
@ -562,6 +583,7 @@ meta_display_init_keys (MetaDisplay *display)
reload_modmap (display);
rebuild_key_binding_table (display);
rebuild_special_bindings (display);
reload_keycodes (display);
reload_modifiers (display);
@ -742,11 +764,18 @@ ungrab_all_keys (MetaDisplay *display,
void
meta_screen_grab_keys (MetaScreen *screen)
{
MetaDisplay *display = screen->display;
if (screen->all_keys_grabbed)
return;
if (screen->keys_grabbed)
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,
screen->display->n_key_bindings,
@ -1140,6 +1169,31 @@ primary_modifier_still_pressed (MetaDisplay *display,
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 */
static gboolean
process_event (MetaKeyBinding *bindings,
@ -1238,6 +1292,7 @@ meta_display_process_key_event (MetaDisplay *display,
KeySym keysym;
gboolean keep_grab;
gboolean all_keys_grabbed;
gboolean handled;
const char *str;
MetaScreen *screen;
@ -1361,11 +1416,15 @@ meta_display_process_key_event (MetaDisplay *display,
return;
}
}
handled = process_overlay_key (display, screen, event, keysym);
/* Do the normal keybindings */
process_event (display->key_bindings,
display->n_key_bindings,
display, screen, window, event, keysym,
!all_keys_grabbed && window);
if (!handled)
process_event (display->key_bindings,
display->n_key_bindings,
display, screen, window, event, keysym,
!all_keys_grabbed && window);
}
static gboolean

View File

@ -57,6 +57,7 @@
#define KEY_TERMINAL_DIR "/desktop/gnome/applications/terminal"
#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_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings"
#define KEY_LIST_BINDINGS_SUFFIX "_list"
@ -1217,6 +1218,10 @@ change_notify (GConfClient *client,
if (update_workspace_name (key, str))
queue_changed (META_PREF_WORKSPACE_NAMES);
}
else if (g_str_equal (key, KEY_OVERLAY_KEY))
{
queue_changed (META_PREF_KEYBINDINGS);
}
#ifdef WITH_CLUTTER
else if (g_str_equal (key, KEY_CLUTTER_PLUGINS) && !clutter_plugins_overridden)
{
@ -1873,6 +1878,8 @@ static MetaKeyPref key_bindings[] = {
};
#undef keybind
static MetaKeyCombo overlay_key_combo = { 0, 0, 0 };
#ifndef HAVE_GCONF
/**
@ -1906,6 +1913,37 @@ static MetaSimpleKeyMapping key_string_bindings[] = {
#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
init_bindings (void)
{
@ -1959,9 +1997,11 @@ init_bindings (void)
++i;
}
#else /* HAVE_GCONF */
int i = 0;
int which = 0;
while (key_string_bindings[i].name)
{
if (key_string_bindings[i].keybinding == NULL) {
@ -1980,6 +2020,8 @@ init_bindings (void)
++i;
}
#endif /* HAVE_GCONF */
init_special_bindings ();
}
static void
@ -2688,6 +2730,12 @@ meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
*n_bindings = (int) G_N_ELEMENTS (key_bindings) - 1;
}
void
meta_prefs_get_overlay_binding (MetaKeyCombo *combo)
{
*combo = overlay_key_combo;
}
MetaActionTitlebar
meta_prefs_get_action_double_click_titlebar (void)
{

View File

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