diff --git a/src/Makefile.am b/src/Makefile.am index 7137cf5..e882e05 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,7 +70,9 @@ xfwm4_SOURCES = \ workspaces.h \ xsync.c \ xsync.h \ - xpm-color-table.h + xpm-color-table.h \ + xfce-shortcuts-provider.h \ + xfce-shortcuts-provider.c xfwm4_CFLAGS = \ $(GTK_CFLAGS) \ diff --git a/src/keyboard.c b/src/keyboard.c index 0792935..b4dbfc2 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -27,12 +27,29 @@ #include #include +#include #include #include #include #include #include "keyboard.h" +#define MODIFIER_MASK (GDK_SHIFT_MASK | \ + GDK_CONTROL_MASK | \ + GDK_MOD1_MASK | \ + GDK_MOD2_MASK | \ + GDK_MOD3_MASK | \ + GDK_MOD4_MASK | \ + GDK_MOD5_MASK) + +#define IGNORE_MASK (0x2000 | \ + GDK_LOCK_MASK | \ + GDK_HYPER_MASK | \ + GDK_SUPER_MASK | \ + GDK_META_MASK | \ + NumLockMask | \ + ScrollLockMask) + unsigned int AltMask; unsigned int MetaMask; unsigned int NumLockMask; @@ -40,85 +57,38 @@ unsigned int ScrollLockMask; unsigned int SuperMask; unsigned int HyperMask; -static gboolean -getKeycode (Display *dpy, const char *str, KeyCode *keycode) +static KeyCode +getKeycode (Display *dpy, const char *str) { - unsigned int value; - KeySym keysym; + GdkModifierType keysym; - keysym = XStringToKeysym (str); - if (keysym == NoSymbol) - { - if (sscanf (str, "0x%X", (unsigned int *) &value) != 1) - { - *keycode = 0; - return FALSE; - } - *keycode = (KeyCode) value; - } - else - { - *keycode = XKeysymToKeycode (dpy, keysym); - } - return TRUE; + gtk_accelerator_parse (str, &keysym, NULL); + return XKeysymToKeycode (dpy, keysym); } -int +guint getModifierMap (const char *str) { - gchar *tmp; - int map; + guint map; - tmp = g_ascii_strdown ((gchar *) str, strlen (str)); - map = 0; + gtk_accelerator_parse (str, NULL, &map); - if (strstr (tmp, "shift")) - { - map |= ShiftMask; - } - if (strstr (tmp, "control")) - { - map |= ControlMask; - } - if (strstr (tmp, "alt")) - { - map |= AltMask; - } - if (strstr (tmp, "meta")) - { - map |= MetaMask; - } - if (strstr (tmp, "super")) + if ((map & GDK_SUPER_MASK) == GDK_SUPER_MASK) { map |= SuperMask; } - if (strstr (tmp, "hyper")) + + if ((map & GDK_HYPER_MASK) == GDK_HYPER_MASK) { map |= HyperMask; } - if (strstr (tmp, "mod1")) - { - map |= Mod1Mask; - } - if (strstr (tmp, "mod2")) - { - map |= Mod2Mask; - } - if (strstr (tmp, "mod3")) - { - map |= Mod3Mask; - } - if (strstr (tmp, "mod4")) - { - map |= Mod4Mask; - } - if (strstr (tmp, "mod5")) + + if ((map & GDK_META_MASK) == GDK_META_MASK) { - map |= Mod5Mask; + map |= MetaMask; } - g_free (tmp); - return map; + return map & MODIFIER_MASK & ~IGNORE_MASK; } void @@ -134,25 +104,20 @@ parseKeyString (Display * dpy, MyKey * key, const char *str) key->keycode = 0; key->modifier = 0; - g_return_if_fail (str != NULL); - - if (!g_ascii_strcasecmp (str, "none")) + if (str == NULL) { return; } - k = strrchr (str, '+'); - if (k) - { - /* There is a modifier */ - getKeycode (dpy, ++k, &key->keycode); - key->modifier = getModifierMap (str); - } - else + if (!g_ascii_strcasecmp (str, "none")) { - getKeycode (dpy, str, &key->keycode); - key->modifier = 0; + return; } + + key->keycode = getKeycode (dpy, str); + key->modifier = getModifierMap (str); + + TRACE ("keycode = 0x%x, modifier = 0x%x", key->keycode, key->modifier); } gboolean @@ -353,10 +318,6 @@ initModifiers (Display * dpy) { ScrollLockMask = (1 << (i / modmap->max_keypermod)); } - else if (!AltMask && ((syms[j] == XK_Alt_L) || (syms[j] == XK_Alt_R))) - { - AltMask = (1 << (i / modmap->max_keypermod)); - } else if (!SuperMask && ((syms[j] == XK_Super_L) || (syms[j] == XK_Super_R))) { SuperMask = (1 << (i / modmap->max_keypermod)); diff --git a/src/keyboard.h b/src/keyboard.h index b6549df..faad8a6 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -35,6 +35,7 @@ struct _MyKey { KeyCode keycode; int modifier; + gchar *internal_name; }; extern unsigned int AltMask; @@ -44,7 +45,7 @@ extern unsigned int ScrollLockMask; extern unsigned int SuperMask; extern unsigned int HyperMask; -int getModifierMap (const char *); +guint getModifierMap (const char *); void parseKeyString (Display *, MyKey *, const char *); diff --git a/src/screen.h b/src/screen.h index dae3878..1b9b44f 100644 --- a/src/screen.h +++ b/src/screen.h @@ -39,6 +39,8 @@ #ifndef INC_SCREEN_H #define INC_SCREEN_H +#include "xfce-shortcuts-provider.h" + #include "display.h" #include "settings.h" #include "mywindow.h" @@ -117,7 +119,9 @@ struct _ScreenInfo /* xfconf */ XfconfChannel *xfwm4_channel; - XfconfChannel *keys_channel; + + /* Shortcuts */ + XfceShortcutsProvider *shortcuts_provider; /* Per screen parameters */ XfwmParams *params; diff --git a/src/settings.c b/src/settings.c index 0e8b302..839a15b 100644 --- a/src/settings.c +++ b/src/settings.c @@ -32,6 +32,8 @@ #include #include +#include "xfce-shortcuts-provider.h" + #include "screen.h" #include "hints.h" #include "parserc.h" @@ -41,8 +43,7 @@ #include "compositor.h" #include "ui_style.h" -#define CHANNEL1 "xfwm4" -#define CHANNEL2 "xfwm4_keys" +#define CHANNEL_XFWM "xfwm4" #define DEFAULT_KEYTHEME "Default" #define KEYTHEMERC "keythemerc" @@ -61,16 +62,28 @@ static void loadRcData (ScreenInfo *, Settings *); static void loadTheme (ScreenInfo *, Settings *); -static gboolean loadKeyBindings (ScreenInfo *, - Settings *); +static void loadKeyBindings (ScreenInfo *); static void unloadTheme (ScreenInfo *); +static void unloadKeyBindings (ScreenInfo *); static void unloadSettings (ScreenInfo *); static gboolean reloadScreenSettings (ScreenInfo *, int); +static void parseShortcut (ScreenInfo *, + int, + const gchar *, + GList *); +static const gchar *getShortcut (const gchar *, + GList *); static void cb_xfwm4_channel_property_changed (XfconfChannel *, const gchar *, const GValue *, ScreenInfo *); +static void cb_shortcut_added (XfceShortcutsProvider *, + const gchar *, + ScreenInfo *); +static void cb_shortcut_removed (XfceShortcutsProvider *, + const gchar *, + ScreenInfo *); static void update_grabs (ScreenInfo *screen_info) @@ -129,6 +142,8 @@ set_settings_margin (ScreenInfo *screen_info, int idx, int value) static void set_easy_click (ScreenInfo *screen_info, const char *modifier) { + gchar *modstr; + g_return_if_fail (screen_info != NULL); g_return_if_fail (modifier != NULL); @@ -138,7 +153,9 @@ set_easy_click (ScreenInfo *screen_info, const char *modifier) } else { - screen_info->params->easy_click = getModifierMap (modifier); + modstr = g_strdup_printf ("<%s>", modifier); + screen_info->params->easy_click = getModifierMap (modstr); + g_free (modstr); } } @@ -535,9 +552,10 @@ loadTheme (ScreenInfo *screen_info, Settings *rc) g_free (theme); } -static gboolean -loadKeyBindings (ScreenInfo *screen_info, Settings *rc) +static void +loadKeyBindings (ScreenInfo *screen_info) { + GList *shortcuts; gchar keyname[30]; Display *dpy; gchar *keytheme; @@ -545,86 +563,65 @@ loadKeyBindings (ScreenInfo *screen_info, Settings *rc) guint i; dpy = myScreenGetXDisplay (screen_info); - /* - Load defaults keytheme so that even if there are - missing shortcuts in an older user defined key theme - the missing keys will be taken from the default - */ - keytheme = getThemeDir (DEFAULT_KEYTHEME, KEYTHEMERC); - parseRc (KEYTHEMERC, keytheme, rc); - g_free (keytheme); - keythemevalue = getStringValue ("keytheme", rc); - if (keythemevalue) - { - keytheme = getThemeDir (keythemevalue, KEYTHEMERC); - if (!parseRc (KEYTHEMERC, keytheme, rc)) - { - g_warning ("Specified key theme \"%s\" missing, using default", keythemevalue); - } - g_free (keytheme); - - if (!checkRc (rc)) - { - g_warning ("Missing values in defaults file"); - return FALSE; - } - } - - parseKeyString (dpy, &screen_info->params->keys[KEY_CANCEL], getStringValue ("cancel_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_DOWN], getStringValue ("down_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_LEFT], getStringValue ("left_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_RIGHT], getStringValue ("right_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_UP], getStringValue ("up_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_ADD_WORKSPACE], getStringValue ("add_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_ADD_ADJACENT_WORKSPACE], getStringValue ("add_adjacent_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_CLOSE_WINDOW], getStringValue ("close_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_CYCLE_WINDOWS], getStringValue ("cycle_windows_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_DEL_WORKSPACE], getStringValue ("del_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_DEL_ACTIVE_WORKSPACE], getStringValue ("del_active_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_DOWN_WORKSPACE], getStringValue ("down_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_FILL_HORIZ], getStringValue ("fill_horiz_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_FILL_VERT], getStringValue ("fill_vert_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_FILL_WINDOW], getStringValue ("fill_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_HIDE_WINDOW], getStringValue ("hide_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_LEFT_WORKSPACE], getStringValue ("left_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_LOWER_WINDOW], getStringValue ("lower_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MOVE], getStringValue ("move_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MAXIMIZE_HORIZ], getStringValue ("maximize_horiz_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MAXIMIZE_VERT], getStringValue ("maximize_vert_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MAXIMIZE_WINDOW], getStringValue ("maximize_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MOVE_DOWN_WORKSPACE], getStringValue ("move_window_down_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MOVE_LEFT_WORKSPACE], getStringValue ("move_window_left_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MOVE_NEXT_WORKSPACE], getStringValue ("move_window_next_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MOVE_PREV_WORKSPACE], getStringValue ("move_window_prev_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MOVE_RIGHT_WORKSPACE], getStringValue ("move_window_right_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_MOVE_UP_WORKSPACE], getStringValue ("move_window_up_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_NEXT_WORKSPACE], getStringValue ("next_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_POPUP_MENU], getStringValue ("popup_menu_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_PREV_WORKSPACE], getStringValue ("prev_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_RAISE_WINDOW], getStringValue ("raise_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_RESIZE], getStringValue ("resize_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_RIGHT_WORKSPACE], getStringValue ("right_workspace_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_SHADE_WINDOW], getStringValue ("shade_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_SHOW_DESKTOP], getStringValue("show_desktop_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_STICK_WINDOW], getStringValue ("stick_window_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_TOGGLE_ABOVE], getStringValue ("above_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_TOGGLE_FULLSCREEN], getStringValue ("fullscreen_key", rc)); - parseKeyString (dpy, &screen_info->params->keys[KEY_UP_WORKSPACE], getStringValue ("up_workspace_key", rc)); + shortcuts = xfce_shortcuts_provider_get_shortcuts (screen_info->shortcuts_provider); + + parseShortcut (screen_info, KEY_CANCEL, "cancel_key", shortcuts); + parseShortcut (screen_info, KEY_DOWN, "down_key", shortcuts); + parseShortcut (screen_info, KEY_LEFT, "left_key", shortcuts); + parseShortcut (screen_info, KEY_RIGHT, "right_key", shortcuts); + parseShortcut (screen_info, KEY_UP, "up_key", shortcuts); + parseShortcut (screen_info, KEY_ADD_WORKSPACE, "add_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_ADD_ADJACENT_WORKSPACE, "add_adjacent_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_CLOSE_WINDOW, "close_window_key", shortcuts); + parseShortcut (screen_info, KEY_CYCLE_WINDOWS, "cycle_windows_key", shortcuts); + parseShortcut (screen_info, KEY_DEL_WORKSPACE, "del_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_DEL_ACTIVE_WORKSPACE, "del_active_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_DOWN_WORKSPACE, "down_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_FILL_HORIZ, "fill_horiz_key", shortcuts); + parseShortcut (screen_info, KEY_FILL_VERT, "fill_vert_key", shortcuts); + parseShortcut (screen_info, KEY_FILL_WINDOW, "fill_window_key", shortcuts); + parseShortcut (screen_info, KEY_HIDE_WINDOW, "hide_window_key", shortcuts); + parseShortcut (screen_info, KEY_LEFT_WORKSPACE, "left_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_LOWER_WINDOW, "lower_window_key", shortcuts); + parseShortcut (screen_info, KEY_MOVE, "move_window_key", shortcuts); + parseShortcut (screen_info, KEY_MAXIMIZE_HORIZ, "maximize_horiz_key", shortcuts); + parseShortcut (screen_info, KEY_MAXIMIZE_VERT, "maximize_vert_key", shortcuts); + parseShortcut (screen_info, KEY_MAXIMIZE_WINDOW, "maximize_window_key", shortcuts); + parseShortcut (screen_info, KEY_MOVE_DOWN_WORKSPACE, "move_window_down_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_MOVE_LEFT_WORKSPACE, "move_window_left_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_MOVE_NEXT_WORKSPACE, "move_window_next_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_MOVE_PREV_WORKSPACE, "move_window_prev_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_MOVE_RIGHT_WORKSPACE, "move_window_right_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_MOVE_UP_WORKSPACE, "move_window_up_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_NEXT_WORKSPACE, "next_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_POPUP_MENU, "popup_menu_key", shortcuts); + parseShortcut (screen_info, KEY_PREV_WORKSPACE, "prev_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_RAISE_WINDOW, "raise_window_key", shortcuts); + parseShortcut (screen_info, KEY_RESIZE, "resize_window_key", shortcuts); + parseShortcut (screen_info, KEY_RIGHT_WORKSPACE, "right_workspace_key", shortcuts); + parseShortcut (screen_info, KEY_SHADE_WINDOW, "shade_window_key", shortcuts); + parseShortcut (screen_info, KEY_SHOW_DESKTOP, "show_desktop_key", shortcuts); + parseShortcut (screen_info, KEY_STICK_WINDOW, "stick_window_key", shortcuts); + parseShortcut (screen_info, KEY_TOGGLE_ABOVE, "above_key", shortcuts); + parseShortcut (screen_info, KEY_TOGGLE_FULLSCREEN, "fullscreen_key", shortcuts); + parseShortcut (screen_info, KEY_UP_WORKSPACE, "up_workspace_key", shortcuts); for (i = 0; i < 12; i++) { g_snprintf(keyname, sizeof (keyname), "move_window_workspace_%d_key", i + 1); - parseKeyString (dpy, &screen_info->params->keys[KEY_MOVE_WORKSPACE_1 + i], getStringValue (keyname, rc)); + parseShortcut (screen_info, KEY_MOVE_WORKSPACE_1 + i, keyname, shortcuts); g_snprintf(keyname, sizeof (keyname), "workspace_%d_key", i + 1); - parseKeyString (dpy, &screen_info->params->keys[KEY_WORKSPACE_1 + i], getStringValue (keyname, rc)); + parseShortcut (screen_info, KEY_WORKSPACE_1 + i, keyname, shortcuts); } + xfce_shortcuts_free (shortcuts); + myScreenUngrabKeys (screen_info); myScreenGrabKeys (screen_info); - return TRUE; + return; } gboolean @@ -802,11 +799,7 @@ loadSettings (ScreenInfo *screen_info) loadTheme (screen_info, rc); update_grabs (screen_info); - if (!loadKeyBindings (screen_info, rc)) - { - freeRc (rc); - return FALSE; - } + loadKeyBindings (screen_info); screen_info->params->borderless_maximize = getBoolValue ("borderless_maximize", rc); @@ -978,6 +971,20 @@ unloadTheme (ScreenInfo *screen_info) } } + +static void +unloadKeyBindings (ScreenInfo *screen_info) +{ + int i; + + g_return_if_fail (screen_info); + + for (i = 0; i < KEY_COUNT; ++i) + { + g_free (screen_info->params->keys[i].internal_name); + } +} + static void unloadSettings (ScreenInfo *screen_info) { @@ -986,6 +993,7 @@ unloadSettings (ScreenInfo *screen_info) TRACE ("entering unloadSettings"); unloadTheme (screen_info); + unloadKeyBindings (screen_info); } static gboolean @@ -1056,11 +1064,15 @@ initSettings (ScreenInfo *screen_info) val = 0; i = 0; - screen_info->xfwm4_channel = xfconf_channel_new(CHANNEL1); - screen_info->keys_channel = xfconf_channel_new(CHANNEL2); - - g_signal_connect (G_OBJECT(screen_info->xfwm4_channel), "property-changed", (GCallback)cb_xfwm4_channel_property_changed, screen_info); + screen_info->xfwm4_channel = xfconf_channel_new(CHANNEL_XFWM); + g_signal_connect (screen_info->xfwm4_channel, "property-changed", + G_CALLBACK (cb_xfwm4_channel_property_changed), screen_info); + screen_info->shortcuts_provider = xfce_shortcuts_provider_new ("xfwm4"); + g_signal_connect (screen_info->shortcuts_provider, "shortcut-added", + G_CALLBACK (cb_shortcut_added), screen_info); + g_signal_connect (screen_info->shortcuts_provider, "shortcut-removed", + G_CALLBACK (cb_shortcut_removed), screen_info); if (!loadSettings (screen_info)) { @@ -1360,3 +1372,108 @@ cb_xfwm4_channel_property_changed(XfconfChannel *channel, const gchar *property_ } } } + +static void +cb_shortcut_added (XfceShortcutsProvider *provider, const gchar *shortcut, + ScreenInfo *screen_info) +{ + XfceShortcut *sc; + Display *dpy; + int i; + + g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider)); + g_return_if_fail (shortcut); + g_return_if_fail (screen_info); + + sc = xfce_shortcuts_provider_get_shortcut (provider, shortcut); + + if (sc == NULL) + { + return; + } + + dpy = myScreenGetXDisplay (screen_info); + + for (i = 0; i < KEY_COUNT; ++i) + { + if (g_str_equal (screen_info->params->keys[i].internal_name, sc->command)) + { + parseKeyString (dpy, &screen_info->params->keys[i], shortcut); + + myScreenUngrabKeys (screen_info); + myScreenGrabKeys (screen_info); + break; + } + } + + xfce_shortcut_free (sc); +} + +static void +cb_shortcut_removed (XfceShortcutsProvider *provider, const gchar *shortcut, + ScreenInfo *screen_info) +{ + MyKey key; + Display *dpy; + int i; + + g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider)); + g_return_if_fail (screen_info); + g_return_if_fail (shortcut); + + dpy = myScreenGetXDisplay (screen_info); + + parseKeyString (dpy, &key, shortcut); + + for (i = 0; i < KEY_COUNT; ++i) + { + if (screen_info->params->keys[i].keycode == key.keycode && + screen_info->params->keys[i].modifier == key.modifier) + { + screen_info->params->keys[i].keycode = 0; + screen_info->params->keys[i].modifier = 0; + + myScreenUngrabKeys (screen_info); + myScreenGrabKeys (screen_info); + break; + } + } +} + +static void +parseShortcut (ScreenInfo *screen_info, int index, const gchar *name, + GList *shortcuts) +{ + Display *dpy; + const gchar *shortcut; + + g_return_if_fail (screen_info); + g_return_if_fail (index >= 0 && index < KEY_COUNT); + + dpy = myScreenGetXDisplay (screen_info); + shortcut = getShortcut (name, shortcuts); + parseKeyString (dpy, &screen_info->params->keys[index], shortcut); + + screen_info->params->keys[index].internal_name = g_strdup (name); +} + +static const gchar * +getShortcut (const gchar *name, GList *shortcuts) +{ + XfceShortcut *shortcut; + GList *iter; + const gchar *result = NULL; + + for (iter = shortcuts; iter != NULL; iter = g_list_next (iter)) + { + shortcut = iter->data; + + if (g_str_equal (shortcut->command, name)) + { + result = shortcut->shortcut; + break; + } + } + + return result; +} diff --git a/src/xfce-shortcuts-provider.c b/src/xfce-shortcuts-provider.c new file mode 100644 index 0000000..97ff14e --- /dev/null +++ b/src/xfce-shortcuts-provider.c @@ -0,0 +1,676 @@ +/* vi:set sw=2 sts=2 ts=2 et ai: */ +/*- + * Copyright (c) 2008 Jannis Pohlmann . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include + +#include +#include + +#include "xfce-shortcuts-provider.h" + + + +#define XFCE_SHORTCUTS_PROVIDER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), XFCE_TYPE_SHORTCUTS_PROVIDER, XfceShortcutsProviderPrivate)) + + + +/* Property identifiers */ +enum +{ + PROP_0, + PROP_NAME, +}; + + + +typedef struct _XfceShortcutsProviderContext XfceShortcutsProviderContext; + + + +static void xfce_shortcuts_provider_class_init (XfceShortcutsProviderClass *klass); +static void xfce_shortcuts_provider_init (XfceShortcutsProvider *provider); +static void xfce_shortcuts_provider_constructed (GObject *object); +static void xfce_shortcuts_provider_finalize (GObject *object); +static void xfce_shortcuts_provider_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void xfce_shortcuts_provider_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void xfce_shortcuts_provider_register (XfceShortcutsProvider *provider); +static void xfce_shortcuts_provider_property_changed (XfconfChannel *channel, + gchar *property, + GValue *value, + XfceShortcutsProvider *provider); + + + +struct _XfceShortcutsProviderPrivate +{ + XfconfChannel *channel; + gchar *name; + gchar *default_base_property; + gchar *custom_base_property; +}; + +struct _XfceShortcutsProviderContext +{ + XfceShortcutsProvider *provider; + GList *list; + const gchar *base_property; +}; + + + +static GObjectClass *xfce_shortcuts_provider_parent_class = NULL; + + + +GType +xfce_shortcuts_provider_get_type (void) +{ + static GType type = G_TYPE_INVALID; + + if (G_UNLIKELY (type == G_TYPE_INVALID)) + { + static const GTypeInfo info = + { + sizeof (XfceShortcutsProviderClass), + NULL, + NULL, + (GClassInitFunc) xfce_shortcuts_provider_class_init, + NULL, + NULL, + sizeof (XfceShortcutsProvider), + 0, + (GInstanceInitFunc) xfce_shortcuts_provider_init, + NULL, + }; + + type = g_type_register_static (G_TYPE_OBJECT, "XfceShortcutsProvider", &info, 0); + } + + return type; +} + + + +static void +xfce_shortcuts_provider_class_init (XfceShortcutsProviderClass *klass) +{ + GObjectClass *gobject_class; + + g_type_class_add_private (klass, sizeof (XfceShortcutsProviderPrivate)); + + /* Determine the parent type class */ + xfce_shortcuts_provider_parent_class = g_type_class_peek_parent (klass); + + gobject_class = G_OBJECT_CLASS (klass); +#if GLIB_CHECK_VERSION (2,14,0) + gobject_class->constructed = xfce_shortcuts_provider_constructed; +#endif + gobject_class->finalize = xfce_shortcuts_provider_finalize; + gobject_class->get_property = xfce_shortcuts_provider_get_property; + gobject_class->set_property = xfce_shortcuts_provider_set_property; + + g_object_class_install_property (gobject_class, + PROP_NAME, + g_param_spec_string ("name", + "name", + "name", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + g_signal_new ("shortcut-removed", + XFCE_TYPE_SHORTCUTS_PROVIDER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + g_signal_new ("shortcut-added", + XFCE_TYPE_SHORTCUTS_PROVIDER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); +} + + + +static void +xfce_shortcuts_provider_init (XfceShortcutsProvider *provider) +{ + provider->priv = XFCE_SHORTCUTS_PROVIDER_GET_PRIVATE (provider); + + provider->priv->channel = xfconf_channel_new ("xfce4-keyboard-shortcuts"); + + g_signal_connect (provider->priv->channel, "property-changed", + G_CALLBACK (xfce_shortcuts_provider_property_changed), provider); +} + + + +static void +xfce_shortcuts_provider_constructed (GObject *object) +{ + XfceShortcutsProvider *provider = XFCE_SHORTCUTS_PROVIDER (object); + + xfce_shortcuts_provider_register (provider); + + provider->priv->default_base_property = g_strdup_printf ("/%s/default", provider->priv->name); + provider->priv->custom_base_property = g_strdup_printf ("/%s/custom", provider->priv->name); + + if (!xfce_shortcuts_provider_is_custom (provider)) + xfce_shortcuts_provider_reset_to_defaults (provider); +} + + + +static void +xfce_shortcuts_provider_finalize (GObject *object) +{ + XfceShortcutsProvider *provider = XFCE_SHORTCUTS_PROVIDER (object); + + g_free (provider->priv->name); + g_free (provider->priv->custom_base_property); + g_free (provider->priv->default_base_property); + + g_object_unref (provider->priv->channel); + + (*G_OBJECT_CLASS (xfce_shortcuts_provider_parent_class)->finalize) (object); +} + + + +static void +xfce_shortcuts_provider_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + XfceShortcutsProvider *provider = XFCE_SHORTCUTS_PROVIDER (object); + + switch (prop_id) + { + case PROP_NAME: + g_value_set_string (value, provider->priv->name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +xfce_shortcuts_provider_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + XfceShortcutsProvider *provider = XFCE_SHORTCUTS_PROVIDER (object); + + switch (prop_id) + { + case PROP_NAME: + g_free (provider->priv->name); + provider->priv->name = g_strdup (g_value_get_string (value)); + g_object_notify (object, "name"); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +xfce_shortcuts_provider_register (XfceShortcutsProvider *provider) +{ + gchar **provider_names; + const gchar **names; + gboolean already_registered = FALSE; + gint length; + gint i; + + g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider)); + + provider_names = xfconf_channel_get_string_list (provider->priv->channel, "/providers"); + + for (i = 0; provider_names != NULL && provider_names[i] != NULL; ++i) + if (G_UNLIKELY (g_str_equal (provider_names[i], xfce_shortcuts_provider_get_name (provider)))) + { + already_registered = TRUE; + break; + } + + length = i; + + if (G_UNLIKELY (!already_registered)) + { + names = g_new0 (const gchar *, length + 1); + for (i = 0; provider_names != NULL && provider_names[i] != NULL; ++i) + names[i] = provider_names[i]; + names[i++] = xfce_shortcuts_provider_get_name (provider); + names[i] = NULL; + + xfconf_channel_set_string_list (provider->priv->channel, "/providers", names); + + g_free (names); + } + + g_strfreev (provider_names); +} + + + +static void +xfce_shortcuts_provider_property_changed (XfconfChannel *channel, + gchar *property, + GValue *value, + XfceShortcutsProvider *provider) +{ + const gchar *shortcut; + gchar *override_property; + + g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider)); + + DBG ("property = %s", property); + + if (!g_str_has_prefix (property, provider->priv->custom_base_property)) + return; + + override_property = g_strconcat (provider->priv->custom_base_property, "/override", NULL); + + if (G_UNLIKELY (g_utf8_collate (property, override_property) == 0)) + { + g_free (override_property); + return; + } + g_free (override_property); + + shortcut = property + strlen (provider->priv->custom_base_property) + strlen ("/"); + + if (G_VALUE_TYPE (value) != G_TYPE_INVALID) + g_signal_emit_by_name (provider, "shortcut-added", shortcut); + else + g_signal_emit_by_name (provider, "shortcut-removed", shortcut); +} + + + +XfceShortcutsProvider * +xfce_shortcuts_provider_new (const gchar *name) +{ + GObject *object = g_object_new (XFCE_TYPE_SHORTCUTS_PROVIDER, "name", name, NULL); + +#if !GLIB_CHECK_VERSION (2,14,0) + xfce_shortcuts_provider_constructed (object); +#endif + + return XFCE_SHORTCUTS_PROVIDER (object); +} + + + +GList * +xfce_shortcuts_provider_get_providers (void) +{ + GList *providers = NULL; + XfconfChannel *channel; + gchar **names; + gint i; + + channel = xfconf_channel_get ("xfce4-keyboard-shortcuts"); + names = xfconf_channel_get_string_list (channel, "/providers"); + + if (G_LIKELY (names != NULL)) + { + for (i = 0; names[i] != NULL; ++i) + providers = g_list_append (providers, xfce_shortcuts_provider_new (names[i])); + g_strfreev (names); + } + + return providers; +} + + + +void +xfce_shortcuts_provider_free_providers (GList *providers) +{ + GList *iter; + + for (iter = g_list_first (providers); iter != NULL; iter = g_list_next (iter)) + g_object_unref (iter->data); + + g_list_free (providers); +} + + + +const gchar * +xfce_shortcuts_provider_get_name (XfceShortcutsProvider *provider) +{ + g_return_val_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider), NULL); + return provider->priv->name; +} + + + +gboolean +xfce_shortcuts_provider_is_custom (XfceShortcutsProvider *provider) +{ + gchar *property; + gboolean override; + + g_return_val_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider), FALSE); + g_return_val_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel), FALSE); + + property = g_strconcat (provider->priv->custom_base_property, "/override", NULL); + override = xfconf_channel_get_bool (provider->priv->channel, property, FALSE); + g_free (property); + + return override; +} + + + +void +xfce_shortcuts_provider_reset_to_defaults (XfceShortcutsProvider *provider) +{ + g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider)); + g_return_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel)); + + DBG ("property = %s", provider->priv->custom_base_property); + + xfconf_channel_reset_property (provider->priv->channel, provider->priv->custom_base_property, TRUE); + xfce_shortcuts_provider_clone_defaults (provider); +} + + + +static gboolean +_xfce_shortcuts_provider_clone_default (const gchar *property, + const GValue *value, + XfceShortcutsProvider *provider) +{ + const gchar *shortcut; + const gchar *command; + gchar *custom_property; + + g_return_val_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider), TRUE); + g_return_val_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel), TRUE); + + if (G_UNLIKELY (!G_IS_VALUE (value) || G_VALUE_TYPE (value) != G_TYPE_STRING)) + return FALSE; + + shortcut = property + strlen (provider->priv->default_base_property) + strlen ("/"); + command = g_value_get_string (value); + + DBG ("shortcut = %s, command = %s", shortcut, command); + + custom_property = g_strconcat (provider->priv->custom_base_property, "/", shortcut, NULL); + xfconf_channel_set_string (provider->priv->channel, custom_property, command); + g_free (custom_property); + + return FALSE; +} + + + +void +xfce_shortcuts_provider_clone_defaults (XfceShortcutsProvider *provider) +{ + GHashTable *properties; + gchar *property; + + g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider)); + g_return_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel)); + + /* Get default command shortcuts */ + properties = xfconf_channel_get_properties (provider->priv->channel, provider->priv->default_base_property); + + if (G_LIKELY (properties != NULL)) + { + /* Copy from /commands/default to /commands/custom property by property */ + g_hash_table_foreach (properties, (GHFunc) _xfce_shortcuts_provider_clone_default, provider); + + g_hash_table_destroy (properties); + } + + DBG ("adding override property"); + + /* Add the override property */ + property = g_strconcat (provider->priv->custom_base_property, "/override", NULL); + xfconf_channel_set_bool (provider->priv->channel, property, TRUE); + g_free (property); +} + + + +static gboolean +_xfce_shortcuts_provider_get_shortcut (const gchar *property, + const GValue *value, + XfceShortcutsProviderContext *context) +{ + XfceShortcut *sc; + const gchar *shortcut; + const gchar *command; + + g_return_val_if_fail (context != NULL, TRUE); + g_return_val_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (context->provider), TRUE); + + if (G_VALUE_TYPE (value) != G_TYPE_STRING) + return FALSE; + + if (!g_str_has_prefix (property, context->provider->priv->custom_base_property)) + return FALSE; + + shortcut = property + strlen (context->provider->priv->custom_base_property) + strlen ("/"); + command = g_value_get_string (value); + + if (G_LIKELY (shortcut != NULL && command != NULL && g_utf8_strlen (shortcut, -1) > 0 && g_utf8_strlen (command, -1) > 0)) + { + sc = g_new0 (XfceShortcut, 1); + + sc->property_name = g_strdup (property); + sc->shortcut = g_strdup (shortcut); + sc->command = g_strdup (command); + + context->list = g_list_append (context->list, sc); + } + + return FALSE; +} + + + +GList * +xfce_shortcuts_provider_get_shortcuts (XfceShortcutsProvider *provider) +{ + XfceShortcutsProviderContext context; + GHashTable *properties; + + g_return_val_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider), NULL); + g_return_val_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel), NULL); + + properties = xfconf_channel_get_properties (provider->priv->channel, provider->priv->custom_base_property); + + context.provider = provider; + context.list = NULL; + + if (G_LIKELY (properties != NULL)) + g_hash_table_foreach (properties, (GHFunc) _xfce_shortcuts_provider_get_shortcut, &context); + + return context.list; +} + + + +XfceShortcut * +xfce_shortcuts_provider_get_shortcut (XfceShortcutsProvider *provider, + const gchar *shortcut) +{ + XfceShortcut *sc = NULL; + gchar *base_property; + gchar *property; + gchar *command; + + g_return_val_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider), NULL); + g_return_val_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel), NULL); + + if (G_LIKELY (xfce_shortcuts_provider_is_custom (provider))) + base_property = provider->priv->custom_base_property; + else + base_property = provider->priv->default_base_property; + + property = g_strconcat (base_property, "/", shortcut, NULL); + command = xfconf_channel_get_string (provider->priv->channel, property, NULL); + + if (G_LIKELY (command != NULL)) + { + sc = g_new0 (XfceShortcut, 1); + sc->command = command; + sc->property_name = g_strdup (property); + sc->shortcut = g_strdup (shortcut); + } + + g_free (property); + + return sc; +} + + + +gboolean +xfce_shortcuts_provider_has_shortcut (XfceShortcutsProvider *provider, + const gchar *shortcut) +{ + gchar *base_property; + gchar *property; + gboolean has_property; + + g_return_val_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider), FALSE); + g_return_val_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel), FALSE); + + if (G_LIKELY (xfce_shortcuts_provider_is_custom (provider))) + base_property = provider->priv->custom_base_property; + else + base_property = provider->priv->default_base_property; + + property = g_strconcat (base_property, "/", shortcut, NULL); + has_property = xfconf_channel_has_property (provider->priv->channel, property); + g_free (property); + + return has_property; +} + + + +void +xfce_shortcuts_provider_set_shortcut (XfceShortcutsProvider *provider, + const gchar *shortcut, + const gchar *command) +{ + gchar *property; + + g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider)); + g_return_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel)); + g_return_if_fail (shortcut != NULL && command != NULL); + + /* Only allow custom shortcuts to be changed */ + if (G_UNLIKELY (!xfce_shortcuts_provider_is_custom (provider))) + return; + + property = g_strconcat (provider->priv->custom_base_property, "/", shortcut, NULL); + + if (xfconf_channel_has_property (provider->priv->channel, property)) + xfconf_channel_reset_property (provider->priv->channel, property, FALSE); + + xfconf_channel_set_string (provider->priv->channel, property, command); + + g_free (property); +} + + + +void +xfce_shortcuts_provider_reset_shortcut (XfceShortcutsProvider *provider, + const gchar *shortcut) +{ + gchar *property; + + g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (provider)); + g_return_if_fail (XFCONF_IS_CHANNEL (provider->priv->channel)); + g_return_if_fail (shortcut != NULL); + + property = g_strconcat (provider->priv->custom_base_property, "/", shortcut, NULL); + + DBG ("property = %s", property); + + xfconf_channel_reset_property (provider->priv->channel, property, FALSE); + g_free (property); +} + + + +void +xfce_shortcuts_free (GList *shortcuts) +{ + g_list_foreach (shortcuts, (GFunc) xfce_shortcut_free, NULL); +} + + + +void +xfce_shortcut_free (XfceShortcut *shortcut) +{ + if (G_UNLIKELY (shortcut == NULL)) + return; + + g_free (shortcut->property_name); + g_free (shortcut->shortcut); + g_free (shortcut->command); + g_free (shortcut); +} diff --git a/src/xfce-shortcuts-provider.h b/src/xfce-shortcuts-provider.h new file mode 100644 index 0000000..5f1d7c7 --- /dev/null +++ b/src/xfce-shortcuts-provider.h @@ -0,0 +1,87 @@ +/* vi:set sw=2 sts=2 ts=2 et ai: */ +/*- + * Copyright (c) 2008 Jannis Pohlmann . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __XFCE_SHORTCUTS_PROVIDER_H__ +#define __XFCE_SHORTCUTS_PROVIDER_H__ + +#include + +G_BEGIN_DECLS; + +typedef struct _XfceShortcut XfceShortcut; + +typedef struct _XfceShortcutsProviderPrivate XfceShortcutsProviderPrivate; +typedef struct _XfceShortcutsProviderClass XfceShortcutsProviderClass; +typedef struct _XfceShortcutsProvider XfceShortcutsProvider; + +#define XFCE_TYPE_SHORTCUTS_PROVIDER (xfce_shortcuts_provider_get_type ()) +#define XFCE_SHORTCUTS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_SHORTCUTS_PROVIDER, XfceShortcutsProvider)) +#define XFCE_SHORTCUTS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_SHORTCUTS_PROVIDER, XfceShortcutsProviderClass)) +#define XFCE_IS_SHORTCUTS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_SHORTCUTS_PROVIDER)) +#define XFCE_IS_SHORTCUTS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_SHORTCUTS_PROVIDER) +#define XFCE_SHORTCUTS_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_SHORTCUTS_PROVIDER, XfceShortcutsProviderClass)) + +GType xfce_shortcuts_provider_get_type (void) G_GNUC_CONST; + +XfceShortcutsProvider *xfce_shortcuts_provider_new (const gchar *name) G_GNUC_MALLOC; +GList *xfce_shortcuts_provider_get_providers (void) G_GNUC_MALLOC; +void xfce_shortcuts_provider_free_providers (GList *providers); +const gchar *xfce_shortcuts_provider_get_name (XfceShortcutsProvider *provider); +gboolean xfce_shortcuts_provider_is_custom (XfceShortcutsProvider *provider); +void xfce_shortcuts_provider_reset_to_defaults (XfceShortcutsProvider *provider); +void xfce_shortcuts_provider_clone_defaults (XfceShortcutsProvider *provider); +GList *xfce_shortcuts_provider_get_shortcuts (XfceShortcutsProvider *provider); +XfceShortcut *xfce_shortcuts_provider_get_shortcut (XfceShortcutsProvider *provider, + const gchar *shortcut); +gboolean xfce_shortcuts_provider_has_shortcut (XfceShortcutsProvider *provider, + const gchar *shortcut); +void xfce_shortcuts_provider_set_shortcut (XfceShortcutsProvider *provider, + const gchar *shortcut, + const gchar *command); +void xfce_shortcuts_provider_reset_shortcut (XfceShortcutsProvider *provider, + const gchar *shortcut); + +void xfce_shortcuts_free (GList *shortcuts); +void xfce_shortcut_free (XfceShortcut *shortcut); + + + +struct _XfceShortcutsProviderClass +{ + GObjectClass __parent__; +}; + +struct _XfceShortcutsProvider +{ + GObject __parent__; + + XfceShortcutsProviderPrivate *priv; +}; + +struct _XfceShortcut +{ + gchar *property_name; + gchar *shortcut; + gchar *command; +}; + +G_END_DECLS; + +#endif /* !__XFCE_SHORTCUTS_PROVIDER_H__ */