Blame src/terminal-accels.c

Packit Service 3bdf47
/*
Packit Service 3bdf47
 * Copyright © 2001, 2002 Havoc Pennington, Red Hat Inc.
Packit Service 3bdf47
 * Copyright © 2008, 2011, 2012, 2013 Christian Persch
Packit Service 3bdf47
 *
Packit Service 3bdf47
 * This program is free software: you can redistribute it and/or modify
Packit Service 3bdf47
 * it under the terms of the GNU General Public License as published by
Packit Service 3bdf47
 * the Free Software Foundation, either version 3 of the License, or
Packit Service 3bdf47
 * (at your option) any later version.
Packit Service 3bdf47
 *
Packit Service 3bdf47
 * This program is distributed in the hope that it will be useful,
Packit Service 3bdf47
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 3bdf47
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 3bdf47
 * GNU General Public License for more details.
Packit Service 3bdf47
 *
Packit Service 3bdf47
 * You should have received a copy of the GNU General Public License
Packit Service 3bdf47
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 3bdf47
 */
Packit Service 3bdf47
Packit Service 3bdf47
#include "config.h"
Packit Service 3bdf47
Packit Service 3bdf47
#include <string.h>
Packit Service 3bdf47
Packit Service 3bdf47
#include <glib.h>
Packit Service 3bdf47
#include <glib/gi18n.h>
Packit Service 503ba8
#include <gdk/gdk.h>
Packit Service 3bdf47
#include <gtk/gtk.h>
Packit Service 3bdf47
Packit Service 3bdf47
#include "terminal-accels.h"
Packit Service 3bdf47
#include "terminal-app.h"
Packit Service 3bdf47
#include "terminal-debug.h"
Packit Service 3bdf47
#include "terminal-schemas.h"
Packit Service 3bdf47
#include "terminal-intl.h"
Packit Service 3bdf47
#include "terminal-util.h"
Packit Service 3bdf47
#include "terminal-libgsystem.h"
Packit Service 3bdf47
Packit Service 3bdf47
/* NOTES
Packit Service 3bdf47
 *
Packit Service 3bdf47
 * There are two sources of keybindings changes, from GSettings and from
Packit Service 3bdf47
 * the accel map (happens with in-place menu editing).
Packit Service 3bdf47
 *
Packit Service 3bdf47
 * When a keybinding gconf key changes, we propagate that into the
Packit Service 3bdf47
 * accel map.
Packit Service 3bdf47
 * When the accel map changes, we queue a sync to GSettings.
Packit Service 3bdf47
 *
Packit Service 3bdf47
 * To avoid infinite loops, we short-circuit in both directions
Packit Service 3bdf47
 * if the value is unchanged from last known.
Packit Service 3bdf47
 *
Packit Service 3bdf47
 * In the keybinding editor, when editing or clearing an accel, we write
Packit Service 3bdf47
 * the change directly to GSettings and rely on the callback to
Packit Service 3bdf47
 * actually apply the change to the accel map.
Packit Service 3bdf47
 */
Packit Service 3bdf47
Packit Service 3bdf47
#define KEY_CLOSE_TAB           "close-tab"
Packit Service 3bdf47
#define KEY_CLOSE_WINDOW        "close-window"
Packit Service 3bdf47
#define KEY_COPY                "copy"
Packit Service 3bdf47
#define KEY_COPY_HTML           "copy-html"
Packit Service 3bdf47
#define KEY_DETACH_TAB          "detach-tab"
Packit Service 3bdf47
#define KEY_EXPORT              "export"
Packit Service 3bdf47
#define KEY_FIND                "find"
Packit Service 3bdf47
#define KEY_FIND_CLEAR          "find-clear"
Packit Service 3bdf47
#define KEY_FIND_PREV           "find-previous"
Packit Service 3bdf47
#define KEY_FIND_NEXT           "find-next"
Packit Service 3bdf47
#define KEY_FULL_SCREEN         "full-screen"
Packit Service 3bdf47
#define KEY_HELP                "help"
Packit Service 3bdf47
#define KEY_MOVE_TAB_LEFT       "move-tab-left"
Packit Service 3bdf47
#define KEY_MOVE_TAB_RIGHT      "move-tab-right"
Packit Service 3bdf47
#define KEY_NEW_TAB             "new-tab"
Packit Service 3bdf47
#define KEY_NEW_WINDOW          "new-window"
Packit Service 3bdf47
#define KEY_NEXT_TAB            "next-tab"
Packit Service 3bdf47
#define KEY_PASTE               "paste"
Packit Service 3bdf47
#define KEY_PREFERENCES         "preferences"
Packit Service 3bdf47
#define KEY_PREV_TAB            "prev-tab"
Packit Service 3bdf47
#define KEY_PRINT               "print"
Packit Service 3bdf47
#define KEY_READ_ONLY           "read-only"
Packit Service 3bdf47
#define KEY_RESET_AND_CLEAR     "reset-and-clear"
Packit Service 3bdf47
#define KEY_RESET               "reset"
Packit Service 3bdf47
#define KEY_SAVE_CONTENTS       "save-contents"
Packit Service 3bdf47
#define KEY_SELECT_ALL          "select-all"
Packit Service 6eccb4
#define KEY_SET_TERMINAL_TITLE  "set-terminal-title"
Packit Service 3bdf47
#define KEY_TOGGLE_MENUBAR      "toggle-menubar"
Packit Service 3bdf47
#define KEY_ZOOM_IN             "zoom-in"
Packit Service 3bdf47
#define KEY_ZOOM_NORMAL         "zoom-normal"
Packit Service 3bdf47
#define KEY_ZOOM_OUT            "zoom-out"
Packit Service 3bdf47
#define KEY_SWITCH_TAB_PREFIX   "switch-to-tab-"
Packit Service 3bdf47
Packit Service 3bdf47
#if 1
Packit Service 3bdf47
/*
Packit Service 3bdf47
* We don't want to enable content saving until vte supports it async.
Packit Service 3bdf47
* So we disable this code for stable versions.
Packit Service 3bdf47
*/
Packit Service 3bdf47
#include "terminal-version.h"
Packit Service 3bdf47
Packit Service 3bdf47
#if (TERMINAL_MINOR_VERSION & 1) != 0
Packit Service 3bdf47
#define ENABLE_SAVE
Packit Service 3bdf47
#else
Packit Service 3bdf47
#undef ENABLE_SAVE
Packit Service 3bdf47
#endif
Packit Service 3bdf47
#endif
Packit Service 3bdf47
Packit Service 3bdf47
typedef struct
Packit Service 3bdf47
{
Packit Service 3bdf47
  const char *user_visible_name;
Packit Service 3bdf47
  const char *settings_key;
Packit Service 3bdf47
  const char *action_name;
Packit Service 3bdf47
  const GVariantType *action_parameter_type;
Packit Service 3bdf47
  const char *action_parameter;
Packit Service 3bdf47
  GVariant *parameter;
Packit Service 3bdf47
  const char *shadow_action_name;
Packit Service 3bdf47
} KeyEntry;
Packit Service 3bdf47
Packit Service 3bdf47
typedef struct
Packit Service 3bdf47
{
Packit Service 3bdf47
  KeyEntry *key_entry;
Packit Service 3bdf47
  guint n_elements;
Packit Service 3bdf47
  const char *user_visible_name;
Packit Service 3bdf47
} KeyEntryList;
Packit Service 3bdf47
Packit Service 3bdf47
#define ENTRY_FULL(name, key, action, type, parameter, shadow_name) \
Packit Service 3bdf47
  { name, key, "win." action, (const GVariantType *) type, parameter, NULL, shadow_name }
Packit Service 3bdf47
#define ENTRY(name, key, action, type, parameter) \
Packit Service 3bdf47
  ENTRY_FULL (name, key, action, type, parameter, "win.shadow")
Packit Service 3bdf47
#define ENTRY_MDI(name, key, action, type, parameter) \
Packit Service 3bdf47
  ENTRY_FULL (name, key, action, type, parameter, "win.shadow-mdi")
Packit Service 3bdf47
Packit Service 3bdf47
static KeyEntry file_entries[] = {
Packit Service 3bdf47
  ENTRY (N_("New Tab"),       KEY_NEW_TAB,       "new-terminal",  "(ss)",  "('tab','current')"   ),
Packit Service 3bdf47
  ENTRY (N_("New Window"),    KEY_NEW_WINDOW,    "new-terminal",  "(ss)",  "('window','current')"),
Packit Service 3bdf47
#ifdef ENABLE_SAVE
Packit Service 3bdf47
  ENTRY (N_("Save Contents"), KEY_SAVE_CONTENTS, "save-contents", NULL,    NULL                  ),
Packit Service 3bdf47
#endif
Packit Service 3bdf47
#ifdef ENABLE_EXPORT
Packit Service 3bdf47
  ENTRY (N_("Export"),        KEY_EXPORT,        "export",        NULL,    NULL                  ),
Packit Service 3bdf47
#endif
Packit Service 3bdf47
#ifdef ENABLE_PRINT
Packit Service 3bdf47
  ENTRY (N_("Print"),         KEY_PRINT,         "print",         NULL,    NULL                  ),
Packit Service 3bdf47
#endif
Packit Service 3bdf47
  ENTRY (N_("Close Tab"),     KEY_CLOSE_TAB,     "close",         "s",     "'tab'"               ),
Packit Service 3bdf47
  ENTRY (N_("Close Window"),  KEY_CLOSE_WINDOW,  "close",         "s",     "'window'"            ),
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
static KeyEntry edit_entries[] = {
Packit Service 3bdf47
  ENTRY (N_("Copy"),                KEY_COPY,                "copy",         "s", "'text'"   ),
Packit Service 3bdf47
  ENTRY (N_("Copy as HTML"),        KEY_COPY_HTML,           "copy",         "s", "'html'"   ),
Packit Service 3bdf47
  ENTRY (N_("Paste"),               KEY_PASTE,               "paste-text",   NULL, NULL      ),
Packit Service 3bdf47
  ENTRY (N_("Select All"),          KEY_SELECT_ALL,          "select-all",   NULL, NULL      ),
Packit Service 3bdf47
  ENTRY (N_("Preferences"),         KEY_PREFERENCES,         "edit-preferences",  NULL, NULL      ),
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
static KeyEntry search_entries[] = {
Packit Service 3bdf47
  ENTRY (N_("Find"),            KEY_FIND,       "find",          NULL, NULL),
Packit Service 3bdf47
  ENTRY (N_("Find Next"),       KEY_FIND_NEXT,  "find-forward",  NULL, NULL),
Packit Service 3bdf47
  ENTRY (N_("Find Previous"),   KEY_FIND_PREV,  "find-backward", NULL, NULL),
Packit Service 3bdf47
  ENTRY (N_("Clear Highlight"), KEY_FIND_CLEAR, "find-clear",    NULL, NULL)
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
static KeyEntry view_entries[] = {
Packit Service 3bdf47
  ENTRY (N_("Hide and Show Menubar"), KEY_TOGGLE_MENUBAR, "menubar-visible", NULL, NULL),
Packit Service 3bdf47
  ENTRY (N_("Full Screen"),           KEY_FULL_SCREEN,    "fullscreen",      NULL, NULL),
Packit Service 3bdf47
  ENTRY (N_("Zoom In"),               KEY_ZOOM_IN,        "zoom-in",         NULL, NULL),
Packit Service 3bdf47
  ENTRY (N_("Zoom Out"),              KEY_ZOOM_OUT,       "zoom-out",        NULL, NULL),
Packit Service 3bdf47
  ENTRY (N_("Normal Size"),           KEY_ZOOM_NORMAL,    "zoom-normal",     NULL, NULL)
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
static KeyEntry terminal_entries[] = {
Packit Service 3bdf47
  ENTRY (N_("Read-Only"),       KEY_READ_ONLY,          "read-only", NULL, NULL   ),
Packit Service 3bdf47
  ENTRY (N_("Reset"),           KEY_RESET,              "reset",     "b",  "false"),
Packit Service 3bdf47
  ENTRY (N_("Reset and Clear"), KEY_RESET_AND_CLEAR,    "reset",     "b",  "true" ),
Packit Service 6eccb4
  ENTRY (N_("Set Title"),       KEY_SET_TERMINAL_TITLE, "set-title", NULL, NULL   ),
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
static KeyEntry tabs_entries[] = {
Packit Service 3bdf47
  ENTRY_MDI (N_("Switch to Previous Tab"), KEY_PREV_TAB,       "tab-switch-left",  NULL, NULL),
Packit Service 3bdf47
  ENTRY_MDI (N_("Switch to Next Tab"),     KEY_NEXT_TAB,       "tab-switch-right", NULL, NULL),
Packit Service 3bdf47
  ENTRY_MDI (N_("Move Tab to the Left"),   KEY_MOVE_TAB_LEFT,  "tab-move-left",    NULL, NULL),
Packit Service 3bdf47
  ENTRY_MDI (N_("Move Tab to the Right"),  KEY_MOVE_TAB_RIGHT, "tab-move-right",   NULL, NULL),
Packit Service 3bdf47
  ENTRY_MDI (N_("Detach Tab"),             KEY_DETACH_TAB,     "tab-detach",       NULL, NULL),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "1", "active-tab", "i", "0"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "2", "active-tab", "i", "1"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "3", "active-tab", "i", "2"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "4", "active-tab", "i", "3"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "5", "active-tab", "i", "4"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "6", "active-tab", "i", "5"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "7", "active-tab", "i", "6"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "8", "active-tab", "i", "7"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "9", "active-tab", "i", "8"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "10", "active-tab", "i", "9"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "11", "active-tab", "i", "10"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "12", "active-tab", "i", "11"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "13", "active-tab", "i", "12"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "14", "active-tab", "i", "13"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "15", "active-tab", "i", "14"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "16", "active-tab", "i", "15"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "17", "active-tab", "i", "16"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "18", "active-tab", "i", "17"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "19", "active-tab", "i", "18"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "20", "active-tab", "i", "19"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "21", "active-tab", "i", "20"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "22", "active-tab", "i", "21"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "23", "active-tab", "i", "22"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "24", "active-tab", "i", "23"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "25", "active-tab", "i", "24"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "26", "active-tab", "i", "25"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "27", "active-tab", "i", "26"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "28", "active-tab", "i", "27"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "29", "active-tab", "i", "28"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "30", "active-tab", "i", "29"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "31", "active-tab", "i", "30"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "32", "active-tab", "i", "31"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "33", "active-tab", "i", "32"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "34", "active-tab", "i", "33"),
Packit Service 3bdf47
  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "35", "active-tab", "i", "34"),
Packit Service 3bdf47
  ENTRY_MDI (N_("Switch to Last Tab"), KEY_SWITCH_TAB_PREFIX "last", "active-tab", "i", "-1"),
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
static KeyEntry help_entries[] = {
Packit Service 3bdf47
  ENTRY (N_("Contents"), KEY_HELP, "help", NULL, NULL)
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
#undef ENTRY_FULL
Packit Service 3bdf47
#undef ENTRY
Packit Service 3bdf47
#undef ENTRY_MDI
Packit Service 3bdf47
Packit Service 3bdf47
static KeyEntryList all_entries[] =
Packit Service 3bdf47
{
Packit Service 3bdf47
  { file_entries, G_N_ELEMENTS (file_entries), N_("File") },
Packit Service 3bdf47
  { edit_entries, G_N_ELEMENTS (edit_entries), N_("Edit") },
Packit Service 3bdf47
  { view_entries, G_N_ELEMENTS (view_entries), N_("View") },
Packit Service 3bdf47
  { search_entries, G_N_ELEMENTS (search_entries), N_("Search") },
Packit Service 3bdf47
  { terminal_entries, G_N_ELEMENTS (terminal_entries), N_("Terminal") },
Packit Service 3bdf47
  { tabs_entries, G_N_ELEMENTS (tabs_entries), N_("Tabs") },
Packit Service 3bdf47
  { help_entries, G_N_ELEMENTS (help_entries), N_("Help") }
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
enum
Packit Service 3bdf47
{
Packit Service 3bdf47
  ACTION_COLUMN,
Packit Service 3bdf47
  KEYVAL_COLUMN,
Packit Service 3bdf47
  N_COLUMNS
Packit Service 3bdf47
};
Packit Service 3bdf47
Packit Service 3bdf47
static GHashTable *settings_key_to_entry;
Packit Service 3bdf47
static GSettings *keybinding_settings = NULL;
Packit Service 3bdf47
Packit Service 3bdf47
GS_DEFINE_CLEANUP_FUNCTION(GtkTreePath*, _terminal_local_free_tree_path, gtk_tree_path_free)
Packit Service 3bdf47
#define terminal_free_tree_path __attribute__((__cleanup__(_terminal_local_free_tree_path)))
Packit Service 3bdf47
Packit Service 3bdf47
static char*
Packit Service 3bdf47
binding_name (guint            keyval,
Packit Service 3bdf47
              GdkModifierType  mask)
Packit Service 3bdf47
{
Packit Service 3bdf47
  if (keyval != 0)
Packit Service 3bdf47
    return gtk_accelerator_name (keyval, mask);
Packit Service 3bdf47
Packit Service 3bdf47
  return g_strdup ("disabled");
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 503ba8
static guint
Packit Service 503ba8
get_alternate_accel_key (guint key)
Packit Service 503ba8
{
Packit Service 503ba8
  guint retval = 0;
Packit Service 503ba8
Packit Service 503ba8
  switch (key) {
Packit Service 503ba8
    case GDK_KEY_0:
Packit Service 503ba8
      retval = GDK_KEY_KP_0;
Packit Service 503ba8
      break;
Packit Service 503ba8
    case GDK_KEY_minus:
Packit Service 503ba8
      retval = GDK_KEY_KP_Subtract;
Packit Service 503ba8
      break;
Packit Service 503ba8
    case GDK_KEY_plus:
Packit Service 503ba8
      retval = GDK_KEY_KP_Add;
Packit Service 503ba8
      break;
Packit Service 503ba8
    case GDK_KEY_KP_0:
Packit Service 503ba8
      retval = GDK_KEY_0;
Packit Service 503ba8
      break;
Packit Service 503ba8
    case GDK_KEY_KP_Add:
Packit Service 503ba8
      retval = GDK_KEY_plus;
Packit Service 503ba8
      break;
Packit Service 503ba8
    case GDK_KEY_KP_Subtract:
Packit Service 503ba8
      retval = GDK_KEY_minus;
Packit Service 503ba8
      break;
Packit Service 503ba8
    default:
Packit Service 503ba8
      break;
Packit Service 503ba8
  }
Packit Service 503ba8
Packit Service 503ba8
  return retval;
Packit Service 503ba8
}
Packit Service 503ba8
Packit Service 3bdf47
static void
Packit Service 3bdf47
key_changed_cb (GSettings *settings,
Packit Service 3bdf47
                const char *settings_key,
Packit Service 3bdf47
                gpointer user_data)
Packit Service 3bdf47
{
Packit Service 3bdf47
  GtkApplication *application = user_data;
Packit Service 503ba8
  const gchar *accels[3] = { NULL, NULL, NULL };
Packit Service 503ba8
  gsize accels_offset = 0;
Packit Service 3bdf47
Packit Service 3bdf47
  _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
Packit Service 3bdf47
                         "key %s changed\n",
Packit Service 3bdf47
                         settings_key);
Packit Service 3bdf47
Packit Service 3bdf47
  KeyEntry *key_entry = g_hash_table_lookup (settings_key_to_entry, settings_key);
Packit Service 3bdf47
  if (!key_entry)
Packit Service 3bdf47
    {
Packit Service 3bdf47
      /* shouldn't really happen, but let's be safe */
Packit Service 3bdf47
      _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
Packit Service 3bdf47
                             "  WARNING: KeyEntry for changed key not found, bailing out\n");
Packit Service 3bdf47
      return;
Packit Service 3bdf47
    }
Packit Service 3bdf47
Packit Service 3bdf47
  gs_free char *value = g_settings_get_string (settings, settings_key);
Packit Service 503ba8
  gs_free char *alternate_value = NULL;
Packit Service 3bdf47
Packit Service 3bdf47
  gs_free char *detailed = g_action_print_detailed_name (key_entry->action_name,
Packit Service 3bdf47
                                                         key_entry->parameter);
Packit Service 3bdf47
  gs_unref_variant GVariant *shadow_parameter = g_variant_new_string (detailed);
Packit Service 503ba8
  gs_free char *shadow_detailed = g_action_print_detailed_name (key_entry->shadow_action_name,
Packit Service 503ba8
                                                                shadow_parameter);
Packit Service 3bdf47
Packit Service 3bdf47
  /* We want to always consume the action's accelerators, even if the corresponding
Packit Service 3bdf47
   * action is insensitive, so the corresponding shortcut key escape code isn't sent
Packit Service 3bdf47
   * to the terminal. See bug #453193, bug #138609, and bug #559728.
Packit Service 3bdf47
   * Since GtkApplication's accelerators don't use GtkAccelGroup, we have no way
Packit Service 3bdf47
   * to intercept/chain on its activation. The only way to do this that I found
Packit Service 3bdf47
   * was to install an extra action with the same accelerator that shadows
Packit Service 3bdf47
   * the real action and gets activated when the shadowed action is disabled.
Packit Service 3bdf47
   */
Packit Service 3bdf47
Packit Service 3bdf47
  if (g_str_equal (value, "disabled")) {
Packit Service 503ba8
    accels[0] = NULL;
Packit Service 3bdf47
  } else {
Packit Service 503ba8
    accels[accels_offset] = value;
Packit Service 503ba8
    accels_offset++;
Packit Service 503ba8
Packit Service 503ba8
    GdkModifierType mods;
Packit Service 503ba8
    guint key;
Packit Service 503ba8
    gtk_accelerator_parse (value, &key, &mods;;
Packit Service 503ba8
Packit Service 503ba8
    guint alternate_key = get_alternate_accel_key (key);
Packit Service 503ba8
Packit Service 503ba8
    if (alternate_key != 0) {
Packit Service 503ba8
      alternate_value = gtk_accelerator_name (alternate_key, mods);
Packit Service 503ba8
      accels[accels_offset] = alternate_value;
Packit Service 503ba8
      accels_offset++;
Packit Service 503ba8
    }
Packit Service 3bdf47
  }
Packit Service 503ba8
Packit Service 503ba8
  gtk_application_set_accels_for_action (application,
Packit Service 503ba8
                                         detailed,
Packit Service 503ba8
                                         accels);
Packit Service 503ba8
  gtk_application_set_accels_for_action (application,
Packit Service 503ba8
                                         shadow_detailed,
Packit Service 503ba8
                                         accels);
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
void
Packit Service 3bdf47
terminal_accels_init (GApplication *application,
Packit Service 3bdf47
                      GSettings *settings)
Packit Service 3bdf47
{
Packit Service 3bdf47
  guint i, j;
Packit Service 3bdf47
Packit Service 3bdf47
  keybinding_settings = g_object_ref (settings);
Packit Service 3bdf47
Packit Service 3bdf47
  settings_key_to_entry = g_hash_table_new (g_str_hash, g_str_equal);
Packit Service 3bdf47
Packit Service 3bdf47
  /* Initialise names of tab_switch_entries */
Packit Service 3bdf47
  j = 1;
Packit Service 3bdf47
  for (i = 0; i < G_N_ELEMENTS (tabs_entries); i++)
Packit Service 3bdf47
    {
Packit Service 3bdf47
      gs_free char *name = NULL;
Packit Service 3bdf47
Packit Service 3bdf47
      if (tabs_entries[i].user_visible_name != NULL)
Packit Service 3bdf47
        continue;
Packit Service 3bdf47
Packit Service 3bdf47
      name = g_strdup_printf (_("Switch to Tab %u"), j++);
Packit Service 3bdf47
      tabs_entries[i].user_visible_name = g_intern_string (name);
Packit Service 3bdf47
    }
Packit Service 3bdf47
Packit Service 3bdf47
  for (i = 0; i < G_N_ELEMENTS (all_entries); ++i)
Packit Service 3bdf47
    {
Packit Service 3bdf47
      for (j = 0; j < all_entries[i].n_elements; ++j)
Packit Service 3bdf47
	{
Packit Service 3bdf47
	  KeyEntry *key_entry;
Packit Service 3bdf47
Packit Service 3bdf47
	  key_entry = &(all_entries[i].key_entry[j]);
Packit Service 3bdf47
          if (key_entry->action_parameter) {
Packit Service 3bdf47
            GError *err = NULL;
Packit Service 3bdf47
            key_entry->parameter = g_variant_parse (key_entry->action_parameter_type,
Packit Service 3bdf47
                                                    key_entry->action_parameter,
Packit Service 3bdf47
                                                    NULL, NULL, &err;;
Packit Service 3bdf47
            g_assert_no_error (err);
Packit Service 3bdf47
Packit Service 3bdf47
            g_assert (key_entry->parameter != NULL);
Packit Service 3bdf47
          }
Packit Service 3bdf47
Packit Service 3bdf47
          g_hash_table_insert (settings_key_to_entry,
Packit Service 3bdf47
                               (gpointer) key_entry->settings_key,
Packit Service 3bdf47
                               key_entry);
Packit Service 3bdf47
Packit Service 3bdf47
          key_changed_cb (keybinding_settings, key_entry->settings_key, application);
Packit Service 3bdf47
	}
Packit Service 3bdf47
    }
Packit Service 3bdf47
Packit Service 3bdf47
  g_signal_connect (keybinding_settings, "changed", G_CALLBACK (key_changed_cb), application);
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
void
Packit Service 3bdf47
terminal_accels_shutdown (void)
Packit Service 3bdf47
{
Packit Service 3bdf47
  guint i, j;
Packit Service 3bdf47
Packit Service 3bdf47
  for (i = 0; i < G_N_ELEMENTS (all_entries); ++i) {
Packit Service 3bdf47
    for (j = 0; j < all_entries[i].n_elements; ++j) {
Packit Service 3bdf47
      KeyEntry *key_entry;
Packit Service 3bdf47
Packit Service 3bdf47
      key_entry = &(all_entries[i].key_entry[j]);
Packit Service 3bdf47
      if (key_entry->parameter)
Packit Service 3bdf47
        g_variant_unref (key_entry->parameter);
Packit Service 3bdf47
    }
Packit Service 3bdf47
  }
Packit Service 3bdf47
Packit Service 3bdf47
  g_signal_handlers_disconnect_by_func (keybinding_settings,
Packit Service 3bdf47
                                        G_CALLBACK (key_changed_cb),
Packit Service 3bdf47
                                        g_application_get_default ());
Packit Service 3bdf47
Packit Service 3bdf47
  g_clear_pointer (&settings_key_to_entry, (GDestroyNotify) g_hash_table_unref);
Packit Service 3bdf47
  g_clear_object (&keybinding_settings);
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
static gboolean
Packit Service 3bdf47
foreach_row_cb (GtkTreeModel *model,
Packit Service 3bdf47
                GtkTreePath  *path,
Packit Service 3bdf47
                GtkTreeIter  *iter,
Packit Service 3bdf47
                gpointer      data)
Packit Service 3bdf47
{
Packit Service 3bdf47
  const char *key = data;
Packit Service 3bdf47
  KeyEntry *key_entry;
Packit Service 3bdf47
Packit Service 3bdf47
  gtk_tree_model_get (model, iter,
Packit Service 3bdf47
		      KEYVAL_COLUMN, &key_entry,
Packit Service 3bdf47
		      -1);
Packit Service 3bdf47
Packit Service 3bdf47
  if (key_entry == NULL ||
Packit Service 3bdf47
      !g_str_equal (key_entry->settings_key, key))
Packit Service 3bdf47
    return FALSE;
Packit Service 3bdf47
Packit Service 3bdf47
  gtk_tree_model_row_changed (model, path, iter);
Packit Service 3bdf47
  return TRUE;
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
static void
Packit Service 3bdf47
treeview_key_changed_cb (GSettings *settings,
Packit Service 3bdf47
                         const char *key,
Packit Service 3bdf47
                         GtkTreeView *tree_view)
Packit Service 3bdf47
{
Packit Service 3bdf47
  gtk_tree_model_foreach (gtk_tree_view_get_model (tree_view), foreach_row_cb, (gpointer) key);
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
static void
Packit Service 3bdf47
accel_set_func (GtkTreeViewColumn *tree_column,
Packit Service 3bdf47
                GtkCellRenderer   *cell,
Packit Service 3bdf47
                GtkTreeModel      *model,
Packit Service 3bdf47
                GtkTreeIter       *iter,
Packit Service 3bdf47
                gpointer           data)
Packit Service 3bdf47
{
Packit Service 3bdf47
  KeyEntry *ke;
Packit Service 3bdf47
Packit Service 3bdf47
  gtk_tree_model_get (model, iter,
Packit Service 3bdf47
                      KEYVAL_COLUMN, &ke,
Packit Service 3bdf47
                      -1);
Packit Service 3bdf47
Packit Service 3bdf47
  if (ke == NULL) {
Packit Service 3bdf47
    /* This is a title row */
Packit Service 3bdf47
    g_object_set (cell,
Packit Service 3bdf47
                  "visible", FALSE,
Packit Service 3bdf47
		  NULL);
Packit Service 3bdf47
  } else {
Packit Service 3bdf47
    gs_free char *value;
Packit Service 3bdf47
    guint key;
Packit Service 3bdf47
    GdkModifierType mods;
Packit Service 3bdf47
    gboolean writable;
Packit Service 3bdf47
    GtkWidget *button = data;
Packit Service 3bdf47
Packit Service 3bdf47
    value = g_settings_get_string (keybinding_settings, ke->settings_key);
Packit Service 3bdf47
    gtk_accelerator_parse (value, &key, &mods;;
Packit Service 3bdf47
Packit Service 3bdf47
    writable = g_settings_is_writable (keybinding_settings, ke->settings_key) &&
Packit Service 3bdf47
               gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
Packit Service 3bdf47
Packit Service 3bdf47
    g_object_set (cell,
Packit Service 3bdf47
                  "visible", TRUE,
Packit Service 3bdf47
                  "sensitive", writable,
Packit Service 3bdf47
                  "editable", writable,
Packit Service 3bdf47
                  "accel-key", key,
Packit Service 3bdf47
                  "accel-mods", mods,
Packit Service 3bdf47
		  NULL);
Packit Service 3bdf47
  }
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
static void
Packit Service 3bdf47
accel_update (GtkTreeView          *view,
Packit Service 3bdf47
              GtkCellRendererAccel *cell,
Packit Service 3bdf47
              gchar                *path_string,
Packit Service 3bdf47
              guint                 keyval,
Packit Service 3bdf47
              GdkModifierType       mask)
Packit Service 3bdf47
{
Packit Service 3bdf47
  GtkTreeModel *model;
Packit Service 3bdf47
  terminal_free_tree_path GtkTreePath *path = NULL;
Packit Service 3bdf47
  GtkTreeIter iter;
Packit Service 3bdf47
  KeyEntry *ke;
Packit Service 3bdf47
  gs_free char *str = NULL;
Packit Service 3bdf47
Packit Service 3bdf47
  model = gtk_tree_view_get_model (view);
Packit Service 3bdf47
Packit Service 3bdf47
  path = gtk_tree_path_new_from_string (path_string);
Packit Service 3bdf47
  if (!path)
Packit Service 3bdf47
    return;
Packit Service 3bdf47
Packit Service 3bdf47
  if (!gtk_tree_model_get_iter (model, &iter, path))
Packit Service 3bdf47
    return;
Packit Service 3bdf47
Packit Service 3bdf47
  gtk_tree_model_get (model, &iter, KEYVAL_COLUMN, &ke, -1);
Packit Service 3bdf47
Packit Service 3bdf47
  /* sanity check */
Packit Service 3bdf47
  if (ke == NULL)
Packit Service 3bdf47
    return;
Packit Service 3bdf47
Packit Service 3bdf47
  str = binding_name (keyval, mask);
Packit Service 3bdf47
  g_settings_set_string (keybinding_settings, ke->settings_key, str);
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
static void
Packit Service 3bdf47
accel_edited_callback (GtkCellRendererAccel *cell,
Packit Service 3bdf47
                       gchar                *path_string,
Packit Service 3bdf47
                       guint                 keyval,
Packit Service 3bdf47
                       GdkModifierType       mask,
Packit Service 3bdf47
                       guint                 hardware_keycode,
Packit Service 3bdf47
                       GtkTreeView          *view)
Packit Service 3bdf47
{
Packit Service 3bdf47
  accel_update (view, cell, path_string, keyval, mask);
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
static void
Packit Service 3bdf47
accel_cleared_callback (GtkCellRendererAccel *cell,
Packit Service 3bdf47
                        gchar                *path_string,
Packit Service 3bdf47
                        GtkTreeView          *view)
Packit Service 3bdf47
{
Packit Service 3bdf47
  accel_update (view, cell, path_string, 0, 0);
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
static void
Packit Service 3bdf47
treeview_destroy_cb (GtkWidget *tree_view,
Packit Service 3bdf47
                     gpointer user_data)
Packit Service 3bdf47
{
Packit Service 3bdf47
  g_signal_handlers_disconnect_by_func (keybinding_settings,
Packit Service 3bdf47
                                        G_CALLBACK (treeview_key_changed_cb),
Packit Service 3bdf47
                                        tree_view);
Packit Service 3bdf47
}
Packit Service 3bdf47
Packit Service 3bdf47
#ifdef ENABLE_DEBUG
Packit Service 3bdf47
static void
Packit Service 3bdf47
row_changed (GtkTreeModel *tree_model,
Packit Service 3bdf47
             GtkTreePath  *path,
Packit Service 3bdf47
             GtkTreeIter  *iter,
Packit Service 3bdf47
             gpointer      user_data)
Packit Service 3bdf47
{
Packit Service 3bdf47
  _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
Packit Service 3bdf47
                         "ROW-CHANGED [%s]\n", gtk_tree_path_to_string (path) /* leak */);
Packit Service 3bdf47
}
Packit Service 3bdf47
#endif
Packit Service 3bdf47
Packit Service 3bdf47
void
Packit Service 3bdf47
terminal_accels_fill_treeview (GtkWidget *tree_view,
Packit Service 3bdf47
                               GtkWidget *disable_shortcuts_button)
Packit Service 3bdf47
{
Packit Service 3bdf47
  GtkTreeViewColumn *column;
Packit Service 3bdf47
  GtkCellRenderer *cell_renderer;
Packit Service 3bdf47
  gs_unref_object GtkTreeStore *tree = NULL;
Packit Service 3bdf47
  guint i;
Packit Service 3bdf47
Packit Service 3bdf47
  /* Column 1 */
Packit Service 3bdf47
  cell_renderer = gtk_cell_renderer_text_new ();
Packit Service 3bdf47
  column = gtk_tree_view_column_new_with_attributes (_("_Action"),
Packit Service 3bdf47
						     cell_renderer,
Packit Service 3bdf47
						     "text", ACTION_COLUMN,
Packit Service 3bdf47
						     NULL);
Packit Service 3bdf47
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
Packit Service 3bdf47
Packit Service 3bdf47
  /* Column 2 */
Packit Service 3bdf47
  cell_renderer = gtk_cell_renderer_accel_new ();
Packit Service 3bdf47
  g_object_set (cell_renderer,
Packit Service 3bdf47
                "editable", TRUE,
Packit Service 3bdf47
                "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_GTK,
Packit Service 3bdf47
                NULL);
Packit Service 3bdf47
Packit Service 3bdf47
  g_signal_connect (cell_renderer, "accel-edited",
Packit Service 3bdf47
                    G_CALLBACK (accel_edited_callback), tree_view);
Packit Service 3bdf47
  g_signal_connect (cell_renderer, "accel-cleared",
Packit Service 3bdf47
                    G_CALLBACK (accel_cleared_callback), tree_view);
Packit Service 3bdf47
Packit Service 3bdf47
  column = gtk_tree_view_column_new ();
Packit Service 3bdf47
  gtk_tree_view_column_set_title (column, _("Shortcut _Key"));
Packit Service 3bdf47
  gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
Packit Service 3bdf47
  gtk_tree_view_column_set_cell_data_func (column, cell_renderer, accel_set_func,
Packit Service 3bdf47
                                           disable_shortcuts_button, NULL);
Packit Service 3bdf47
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
Packit Service 3bdf47
Packit Service 3bdf47
  /* Add the data */
Packit Service 3bdf47
Packit Service 3bdf47
  tree = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
Packit Service 3bdf47
Packit Service 3bdf47
#ifdef ENABLE_DEBUG
Packit Service 3bdf47
  _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ACCELS)
Packit Service 3bdf47
    g_signal_connect (tree, "row-changed", G_CALLBACK (row_changed), NULL);
Packit Service 3bdf47
#endif
Packit Service 3bdf47
Packit Service 3bdf47
  for (i = 0; i < G_N_ELEMENTS (all_entries); ++i)
Packit Service 3bdf47
    {
Packit Service 3bdf47
      GtkTreeIter parent_iter;
Packit Service 3bdf47
      guint j;
Packit Service 3bdf47
Packit Service 3bdf47
      gtk_tree_store_insert_with_values (tree, &parent_iter, NULL, -1,
Packit Service 3bdf47
                                         ACTION_COLUMN, _(all_entries[i].user_visible_name),
Packit Service 3bdf47
                                         KEYVAL_COLUMN, NULL,
Packit Service 3bdf47
                                         -1);
Packit Service 3bdf47
Packit Service 3bdf47
      for (j = 0; j < all_entries[i].n_elements; ++j)
Packit Service 3bdf47
	{
Packit Service 3bdf47
	  KeyEntry *key_entry = &(all_entries[i].key_entry[j]);
Packit Service 3bdf47
	  GtkTreeIter iter;
Packit Service 3bdf47
Packit Service 3bdf47
          gtk_tree_store_insert_with_values (tree, &iter, &parent_iter, -1,
Packit Service 3bdf47
                                             ACTION_COLUMN, _(key_entry->user_visible_name),
Packit Service 3bdf47
                                             KEYVAL_COLUMN, key_entry,
Packit Service 3bdf47
                                             -1);
Packit Service 3bdf47
	}
Packit Service 3bdf47
    }
Packit Service 3bdf47
Packit Service 3bdf47
  gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (tree));
Packit Service 3bdf47
Packit Service 3bdf47
  gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
Packit Service 3bdf47
Packit Service 3bdf47
  g_signal_connect (keybinding_settings, "changed",
Packit Service 3bdf47
                    G_CALLBACK (treeview_key_changed_cb), tree_view);
Packit Service 3bdf47
  g_signal_connect (tree_view, "destroy",
Packit Service 3bdf47
                    G_CALLBACK (treeview_destroy_cb), tree);
Packit Service 3bdf47
}