Blame src/shortcuts/dzl-shortcuts-window.c

Packit Service c6b782
/* dzl-shortcuts-window.c
Packit Service c6b782
 *
Packit Service c6b782
 * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
Packit Service c6b782
 *
Packit Service c6b782
 *  This library is free software; you can redistribute it and/or
Packit Service c6b782
 *  modify it under the terms of the GNU Library General Public License as
Packit Service c6b782
 *  published by the Free Software Foundation; either version 2 of the
Packit Service c6b782
 *  License, or (at your option) any later version.
Packit Service c6b782
 *
Packit Service c6b782
 *  This library is distributed in the hope that it will be useful,
Packit Service c6b782
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service c6b782
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service c6b782
 *  Library General Public License for more details.
Packit Service c6b782
 *
Packit Service c6b782
 *  You should have received a copy of the GNU Library General Public
Packit Service c6b782
 *  License along with this library. If not, see <http://www.gnu.org/licenses/>.
Packit Service c6b782
 */
Packit Service c6b782
Packit Service c6b782
#include <glib/gi18n.h>
Packit Service c6b782
Packit Service c6b782
#include "config.h"
Packit Service c6b782
Packit Service c6b782
#include "shortcuts/dzl-shortcuts-window.h"
Packit Service c6b782
#include "shortcuts/dzl-shortcuts-section.h"
Packit Service c6b782
#include "shortcuts/dzl-shortcuts-group.h"
Packit Service c6b782
#include "shortcuts/dzl-shortcuts-shortcut-private.h"
Packit Service c6b782
Packit Service c6b782
/**
Packit Service c6b782
 * SECTION:dzl-shortcuts-window
Packit Service c6b782
 * @Title: DzlShortcutsWindow
Packit Service c6b782
 * @Short_description: Toplevel which shows help for shortcuts
Packit Service c6b782
 *
Packit Service c6b782
 * A DzlShortcutsWindow shows brief information about the keyboard shortcuts
Packit Service c6b782
 * and gestures of an application. The shortcuts can be grouped, and you can
Packit Service c6b782
 * have multiple sections in this window, corresponding to the major modes of
Packit Service c6b782
 * your application.
Packit Service c6b782
 *
Packit Service c6b782
 * Additionally, the shortcuts can be filtered by the current view, to avoid
Packit Service c6b782
 * showing information that is not relevant in the current application context.
Packit Service c6b782
 *
Packit Service c6b782
 * The recommended way to construct a DzlShortcutsWindow is with GtkBuilder,
Packit Service c6b782
 * by populating a #DzlShortcutsWindow with one or more #DzlShortcutsSection
Packit Service c6b782
 * objects, which contain #DzlShortcutsGroups that in turn contain objects of
Packit Service c6b782
 * class #DzlShortcutsShortcut.
Packit Service c6b782
 *
Packit Service c6b782
 * # A simple example:
Packit Service c6b782
 *
Packit Service c6b782
 * ![](gedit-shortcuts.png)
Packit Service c6b782
 *
Packit Service c6b782
 * This example has as single section. As you can see, the shortcut groups
Packit Service c6b782
 * are arranged in columns, and spread across several pages if there are too
Packit Service c6b782
 * many to find on a single page.
Packit Service c6b782
 *
Packit Service c6b782
 * The .ui file for this example can be found [here](https://git.gnome.org/browse/gtk+/tree/demos/gtk-demo/shortcuts-gedit.ui).
Packit Service c6b782
 *
Packit Service c6b782
 * # An example with multiple views:
Packit Service c6b782
 *
Packit Service c6b782
 * ![](clocks-shortcuts.png)
Packit Service c6b782
 *
Packit Service c6b782
 * This example shows a #DzlShortcutsWindow that has been configured to show only
Packit Service c6b782
 * the shortcuts relevant to the "stopwatch" view.
Packit Service c6b782
 *
Packit Service c6b782
 * The .ui file for this example can be found [here](https://git.gnome.org/browse/gtk+/tree/demos/gtk-demo/shortcuts-clocks.ui).
Packit Service c6b782
 *
Packit Service c6b782
 * # An example with multiple sections:
Packit Service c6b782
 *
Packit Service c6b782
 * ![](builder-shortcuts.png)
Packit Service c6b782
 *
Packit Service c6b782
 * This example shows a #DzlShortcutsWindow with two sections, "Editor Shortcuts"
Packit Service c6b782
 * and "Terminal Shortcuts".
Packit Service c6b782
 *
Packit Service c6b782
 * The .ui file for this example can be found [here](https://git.gnome.org/browse/gtk+/tree/demos/gtk-demo/shortcuts-builder.ui).
Packit Service c6b782
 */
Packit Service c6b782
Packit Service c6b782
typedef struct
Packit Service c6b782
{
Packit Service c6b782
  GHashTable     *keywords;
Packit Service c6b782
  gchar          *initial_section;
Packit Service c6b782
  gchar          *last_section_name;
Packit Service c6b782
  gchar          *view_name;
Packit Service c6b782
  GtkSizeGroup   *search_text_group;
Packit Service c6b782
  GtkSizeGroup   *search_image_group;
Packit Service c6b782
  GHashTable     *search_items_hash;
Packit Service c6b782
Packit Service c6b782
  GtkStack       *stack;
Packit Service c6b782
  GtkStack       *title_stack;
Packit Service c6b782
  GtkMenuButton  *menu_button;
Packit Service c6b782
  GtkLabel       *menu_label;
Packit Service c6b782
  GtkSearchBar   *search_bar;
Packit Service c6b782
  GtkSearchEntry *search_entry;
Packit Service c6b782
  GtkHeaderBar   *header_bar;
Packit Service c6b782
  GtkWidget      *main_box;
Packit Service c6b782
  GtkPopover     *popover;
Packit Service c6b782
  GtkListBox     *list_box;
Packit Service c6b782
  GtkBox         *search_gestures;
Packit Service c6b782
  GtkBox         *search_shortcuts;
Packit Service c6b782
Packit Service c6b782
  GtkWindow      *window;
Packit Service c6b782
  gulong          keys_changed_id;
Packit Service c6b782
} DzlShortcutsWindowPrivate;
Packit Service c6b782
Packit Service c6b782
typedef struct
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self;
Packit Service c6b782
  GtkBuilder        *builder;
Packit Service c6b782
  GQueue            *stack;
Packit Service c6b782
  gchar             *property_name;
Packit Service c6b782
  guint              translatable : 1;
Packit Service c6b782
} ViewsParserData;
Packit Service c6b782
Packit Service c6b782
Packit Service c6b782
G_DEFINE_TYPE_WITH_PRIVATE (DzlShortcutsWindow, dzl_shortcuts_window, GTK_TYPE_WINDOW)
Packit Service c6b782
Packit Service c6b782
Packit Service c6b782
enum {
Packit Service c6b782
  CLOSE,
Packit Service c6b782
  SEARCH,
Packit Service c6b782
  LAST_SIGNAL
Packit Service c6b782
};
Packit Service c6b782
Packit Service c6b782
enum {
Packit Service c6b782
  PROP_0,
Packit Service c6b782
  PROP_SECTION_NAME,
Packit Service c6b782
  PROP_VIEW_NAME,
Packit Service c6b782
  LAST_PROP
Packit Service c6b782
};
Packit Service c6b782
Packit Service c6b782
static GParamSpec *properties[LAST_PROP];
Packit Service c6b782
static guint signals[LAST_SIGNAL];
Packit Service c6b782
Packit Service c6b782
Packit Service c6b782
static gint
Packit Service c6b782
number_of_children (GtkContainer *container)
Packit Service c6b782
{
Packit Service c6b782
  GList *children;
Packit Service c6b782
  gint n;
Packit Service c6b782
Packit Service c6b782
  children = gtk_container_get_children (container);
Packit Service c6b782
  n = g_list_length (children);
Packit Service c6b782
  g_list_free (children);
Packit Service c6b782
Packit Service c6b782
  return n;
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
update_title_stack (DzlShortcutsWindow *self)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
  GtkWidget *visible_child;
Packit Service c6b782
Packit Service c6b782
  visible_child = gtk_stack_get_visible_child (priv->stack);
Packit Service c6b782
Packit Service c6b782
  if (DZL_IS_SHORTCUTS_SECTION (visible_child))
Packit Service c6b782
    {
Packit Service c6b782
      if (number_of_children (GTK_CONTAINER (priv->stack)) > 3)
Packit Service c6b782
        {
Packit Service c6b782
          gchar *title;
Packit Service c6b782
Packit Service c6b782
          gtk_stack_set_visible_child_name (priv->title_stack, "sections");
Packit Service c6b782
          g_object_get (visible_child, "title", &title, NULL);
Packit Service c6b782
          gtk_label_set_label (priv->menu_label, title);
Packit Service c6b782
          g_free (title);
Packit Service c6b782
        }
Packit Service c6b782
      else
Packit Service c6b782
        {
Packit Service c6b782
          gtk_stack_set_visible_child_name (priv->title_stack, "title");
Packit Service c6b782
        }
Packit Service c6b782
    }
Packit Service c6b782
  else if (visible_child != NULL)
Packit Service c6b782
    {
Packit Service c6b782
      gtk_stack_set_visible_child_name (priv->title_stack, "search");
Packit Service c6b782
    }
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_add_search_item (GtkWidget *child, gpointer data)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = data;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
  GtkWidget *item;
Packit Service c6b782
  gchar *accelerator = NULL;
Packit Service c6b782
  gchar *title = NULL;
Packit Service c6b782
  gchar *hash_key = NULL;
Packit Service c6b782
  GIcon *icon = NULL;
Packit Service c6b782
  gboolean icon_set = FALSE;
Packit Service c6b782
  gboolean subtitle_set = FALSE;
Packit Service c6b782
  GtkTextDirection direction;
Packit Service c6b782
  GtkShortcutType shortcut_type;
Packit Service c6b782
  gchar *action_name = NULL;
Packit Service c6b782
  gchar *subtitle;
Packit Service c6b782
  gchar *str;
Packit Service c6b782
  gchar *keywords;
Packit Service c6b782
Packit Service c6b782
  if (DZL_IS_SHORTCUTS_SHORTCUT (child))
Packit Service c6b782
    {
Packit Service c6b782
      GEnumClass *class;
Packit Service c6b782
      GEnumValue *value;
Packit Service c6b782
Packit Service c6b782
      g_object_get (child,
Packit Service c6b782
                    "accelerator", &accelerator,
Packit Service c6b782
                    "title", &title,
Packit Service c6b782
                    "direction", &direction,
Packit Service c6b782
                    "icon-set", &icon_set,
Packit Service c6b782
                    "subtitle-set", &subtitle_set,
Packit Service c6b782
                    "shortcut-type", &shortcut_type,
Packit Service c6b782
                    "action-name", &action_name,
Packit Service c6b782
                    NULL);
Packit Service c6b782
Packit Service c6b782
      class = G_ENUM_CLASS (g_type_class_ref (GTK_TYPE_SHORTCUT_TYPE));
Packit Service c6b782
      value = g_enum_get_value (class, shortcut_type);
Packit Service c6b782
Packit Service c6b782
      hash_key = g_strdup_printf ("%s-%s-%s", title, value->value_nick, accelerator);
Packit Service c6b782
Packit Service c6b782
      g_type_class_unref (class);
Packit Service c6b782
Packit Service c6b782
      if (g_hash_table_contains (priv->search_items_hash, hash_key))
Packit Service c6b782
        {
Packit Service c6b782
          g_free (hash_key);
Packit Service c6b782
          g_free (title);
Packit Service c6b782
          g_free (accelerator);
Packit Service c6b782
          return;
Packit Service c6b782
        }
Packit Service c6b782
Packit Service c6b782
      g_hash_table_insert (priv->search_items_hash, hash_key, GINT_TO_POINTER (1));
Packit Service c6b782
Packit Service c6b782
      item = g_object_new (DZL_TYPE_SHORTCUTS_SHORTCUT,
Packit Service c6b782
                           "accelerator", accelerator,
Packit Service c6b782
                           "title", title,
Packit Service c6b782
                           "direction", direction,
Packit Service c6b782
                           "shortcut-type", shortcut_type,
Packit Service c6b782
                           "accel-size-group", priv->search_image_group,
Packit Service c6b782
                           "title-size-group", priv->search_text_group,
Packit Service c6b782
                           "action-name", action_name,
Packit Service c6b782
                           NULL);
Packit Service c6b782
      if (icon_set)
Packit Service c6b782
        {
Packit Service c6b782
          g_object_get (child, "icon", &icon, NULL);
Packit Service c6b782
          g_object_set (item, "icon", icon, NULL);
Packit Service c6b782
          g_clear_object (&icon);
Packit Service c6b782
        }
Packit Service c6b782
      if (subtitle_set)
Packit Service c6b782
        {
Packit Service c6b782
          g_object_get (child, "subtitle", &subtitle, NULL);
Packit Service c6b782
          g_object_set (item, "subtitle", subtitle, NULL);
Packit Service c6b782
          g_free (subtitle);
Packit Service c6b782
        }
Packit Service c6b782
      str = g_strdup_printf ("%s %s", accelerator, title);
Packit Service c6b782
      keywords = g_utf8_strdown (str, -1);
Packit Service c6b782
Packit Service c6b782
      g_hash_table_insert (priv->keywords, item, keywords);
Packit Service c6b782
      if (shortcut_type == GTK_SHORTCUT_ACCELERATOR)
Packit Service c6b782
        gtk_container_add (GTK_CONTAINER (priv->search_shortcuts), item);
Packit Service c6b782
      else
Packit Service c6b782
        gtk_container_add (GTK_CONTAINER (priv->search_gestures), item);
Packit Service c6b782
Packit Service c6b782
      g_free (title);
Packit Service c6b782
      g_free (accelerator);
Packit Service c6b782
      g_free (str);
Packit Service c6b782
      g_free (action_name);
Packit Service c6b782
    }
Packit Service c6b782
  else if (GTK_IS_CONTAINER (child))
Packit Service c6b782
    {
Packit Service c6b782
      gtk_container_foreach (GTK_CONTAINER (child), dzl_shortcuts_window_add_search_item, self);
Packit Service c6b782
    }
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
section_notify_cb (GObject    *section,
Packit Service c6b782
                   GParamSpec *pspec,
Packit Service c6b782
                   gpointer    data)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = data;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  if (strcmp (pspec->name, "section-name") == 0)
Packit Service c6b782
    {
Packit Service c6b782
      gchar *name;
Packit Service c6b782
Packit Service c6b782
      g_object_get (section, "section-name", &name, NULL);
Packit Service c6b782
      gtk_container_child_set (GTK_CONTAINER (priv->stack), GTK_WIDGET (section), "name", name, NULL);
Packit Service c6b782
      g_free (name);
Packit Service c6b782
    }
Packit Service c6b782
  else if (strcmp (pspec->name, "title") == 0)
Packit Service c6b782
    {
Packit Service c6b782
      gchar *title;
Packit Service c6b782
      GtkWidget *label;
Packit Service c6b782
Packit Service c6b782
      label = g_object_get_data (section, "gtk-shortcuts-title");
Packit Service c6b782
      g_object_get (section, "title", &title, NULL);
Packit Service c6b782
      gtk_label_set_label (GTK_LABEL (label), title);
Packit Service c6b782
      g_free (title);
Packit Service c6b782
    }
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_add_section (DzlShortcutsWindow  *self,
Packit Service c6b782
                                  DzlShortcutsSection *section)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
  GtkListBoxRow *row;
Packit Service c6b782
  gchar *title;
Packit Service c6b782
  gchar *name;
Packit Service c6b782
  const gchar *visible_section;
Packit Service c6b782
  GtkWidget *label;
Packit Service c6b782
Packit Service c6b782
  gtk_container_foreach (GTK_CONTAINER (section), dzl_shortcuts_window_add_search_item, self);
Packit Service c6b782
Packit Service c6b782
  g_object_get (section,
Packit Service c6b782
                "section-name", &name,
Packit Service c6b782
                "title", &title,
Packit Service c6b782
                NULL);
Packit Service c6b782
Packit Service c6b782
  g_signal_connect (section, "notify", G_CALLBACK (section_notify_cb), self);
Packit Service c6b782
Packit Service c6b782
  if (name == NULL)
Packit Service c6b782
    name = g_strdup ("shortcuts");
Packit Service c6b782
Packit Service c6b782
  gtk_stack_add_titled (priv->stack, GTK_WIDGET (section), name, title);
Packit Service c6b782
Packit Service c6b782
  visible_section = gtk_stack_get_visible_child_name (priv->stack);
Packit Service c6b782
  if (strcmp (visible_section, "internal-search") == 0 ||
Packit Service c6b782
      (priv->initial_section && strcmp (priv->initial_section, visible_section) == 0))
Packit Service c6b782
    gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (section));
Packit Service c6b782
Packit Service c6b782
  row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
Packit Service c6b782
                      "visible", TRUE,
Packit Service c6b782
                      NULL);
Packit Service c6b782
  g_object_set_data (G_OBJECT (row), "gtk-shortcuts-section", section);
Packit Service c6b782
  label = g_object_new (GTK_TYPE_LABEL,
Packit Service c6b782
                        "margin", 6,
Packit Service c6b782
                        "label", title,
Packit Service c6b782
                        "xalign", 0.5f,
Packit Service c6b782
                        "visible", TRUE,
Packit Service c6b782
                        NULL);
Packit Service c6b782
  g_object_set_data (G_OBJECT (section), "gtk-shortcuts-title", label);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (label));
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (priv->list_box), GTK_WIDGET (row));
Packit Service c6b782
Packit Service c6b782
  update_title_stack (self);
Packit Service c6b782
Packit Service c6b782
  g_free (name);
Packit Service c6b782
  g_free (title);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_add (GtkContainer *container,
Packit Service c6b782
                          GtkWidget    *widget)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)container;
Packit Service c6b782
Packit Service c6b782
  if (DZL_IS_SHORTCUTS_SECTION (widget))
Packit Service c6b782
    dzl_shortcuts_window_add_section (self, DZL_SHORTCUTS_SECTION (widget));
Packit Service c6b782
  else
Packit Service c6b782
    g_warning ("Can't add children of type %s to %s",
Packit Service c6b782
               G_OBJECT_TYPE_NAME (widget),
Packit Service c6b782
               G_OBJECT_TYPE_NAME (container));
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_remove (GtkContainer *container,
Packit Service c6b782
                             GtkWidget    *widget)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)container;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  g_signal_handlers_disconnect_by_func (widget, section_notify_cb, self);
Packit Service c6b782
Packit Service c6b782
  if (widget == (GtkWidget *)priv->header_bar ||
Packit Service c6b782
      widget == (GtkWidget *)priv->main_box)
Packit Service c6b782
    GTK_CONTAINER_CLASS (dzl_shortcuts_window_parent_class)->remove (container, widget);
Packit Service c6b782
  else
Packit Service c6b782
    gtk_container_remove (GTK_CONTAINER (priv->stack), widget);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_forall (GtkContainer *container,
Packit Service c6b782
                             gboolean      include_internal,
Packit Service c6b782
                             GtkCallback   callback,
Packit Service c6b782
                             gpointer      callback_data)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)container;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  if (include_internal)
Packit Service c6b782
    {
Packit Service c6b782
      GTK_CONTAINER_CLASS (dzl_shortcuts_window_parent_class)->forall (container, include_internal, callback, callback_data);
Packit Service c6b782
    }
Packit Service c6b782
  else
Packit Service c6b782
    {
Packit Service c6b782
      if (priv->stack)
Packit Service c6b782
        {
Packit Service c6b782
          GList *children, *l;
Packit Service c6b782
          GtkWidget *search;
Packit Service c6b782
          GtkWidget *empty;
Packit Service c6b782
Packit Service c6b782
          search = gtk_stack_get_child_by_name (GTK_STACK (priv->stack), "internal-search");
Packit Service c6b782
          empty = gtk_stack_get_child_by_name (GTK_STACK (priv->stack), "no-search-results");
Packit Service c6b782
          children = gtk_container_get_children (GTK_CONTAINER (priv->stack));
Packit Service c6b782
          for (l = children; l; l = l->next)
Packit Service c6b782
            {
Packit Service c6b782
              GtkWidget *child = l->data;
Packit Service c6b782
Packit Service c6b782
              if (include_internal ||
Packit Service c6b782
                  (child != search && child != empty))
Packit Service c6b782
                callback (child, callback_data);
Packit Service c6b782
            }
Packit Service c6b782
          g_list_free (children);
Packit Service c6b782
        }
Packit Service c6b782
    }
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_set_view_name (DzlShortcutsWindow *self,
Packit Service c6b782
                                    const gchar        *view_name)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
  GList *sections, *l;
Packit Service c6b782
Packit Service c6b782
  g_free (priv->view_name);
Packit Service c6b782
  priv->view_name = g_strdup (view_name);
Packit Service c6b782
Packit Service c6b782
  sections = gtk_container_get_children (GTK_CONTAINER (priv->stack));
Packit Service c6b782
  for (l = sections; l; l = l->next)
Packit Service c6b782
    {
Packit Service c6b782
      DzlShortcutsSection *section = l->data;
Packit Service c6b782
Packit Service c6b782
      if (DZL_IS_SHORTCUTS_SECTION (section))
Packit Service c6b782
        g_object_set (section, "view-name", priv->view_name, NULL);
Packit Service c6b782
    }
Packit Service c6b782
  g_list_free (sections);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_set_section_name (DzlShortcutsWindow *self,
Packit Service c6b782
                                       const gchar        *section_name)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
  GtkWidget *section = NULL;
Packit Service c6b782
Packit Service c6b782
  g_free (priv->initial_section);
Packit Service c6b782
  priv->initial_section = g_strdup (section_name);
Packit Service c6b782
Packit Service c6b782
  if (section_name)
Packit Service c6b782
    section = gtk_stack_get_child_by_name (priv->stack, section_name);
Packit Service c6b782
  if (section)
Packit Service c6b782
    gtk_stack_set_visible_child (priv->stack, section);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
update_accels_cb (GtkWidget *widget,
Packit Service c6b782
                  gpointer   data)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = data;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  if (DZL_IS_SHORTCUTS_SHORTCUT (widget))
Packit Service c6b782
    dzl_shortcuts_shortcut_update_accel (DZL_SHORTCUTS_SHORTCUT (widget), priv->window);
Packit Service c6b782
  else if (GTK_IS_CONTAINER (widget))
Packit Service c6b782
    gtk_container_foreach (GTK_CONTAINER (widget), update_accels_cb, self);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
update_accels_for_actions (DzlShortcutsWindow *self)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  if (priv->window)
Packit Service c6b782
    gtk_container_forall (GTK_CONTAINER (self), update_accels_cb, self);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
keys_changed_handler (GtkWindow          *window,
Packit Service c6b782
                      DzlShortcutsWindow *self)
Packit Service c6b782
{
Packit Service c6b782
  update_accels_for_actions (self);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
void
Packit Service c6b782
dzl_shortcuts_window_set_window (DzlShortcutsWindow *self,
Packit Service c6b782
                                 GtkWindow          *window)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  if (priv->keys_changed_id)
Packit Service c6b782
    {
Packit Service c6b782
      g_signal_handler_disconnect (priv->window, priv->keys_changed_id);
Packit Service c6b782
      priv->keys_changed_id = 0;
Packit Service c6b782
    }
Packit Service c6b782
Packit Service c6b782
  priv->window = window;
Packit Service c6b782
Packit Service c6b782
  if (priv->window)
Packit Service c6b782
    priv->keys_changed_id = g_signal_connect (window, "keys-changed",
Packit Service c6b782
                                              G_CALLBACK (keys_changed_handler),
Packit Service c6b782
                                              self);
Packit Service c6b782
Packit Service c6b782
  update_accels_for_actions (self);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window__list_box__row_activated (DzlShortcutsWindow *self,
Packit Service c6b782
                                               GtkListBoxRow      *row,
Packit Service c6b782
                                               GtkListBox         *list_box)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
  GtkWidget *section;
Packit Service c6b782
Packit Service c6b782
  section = g_object_get_data (G_OBJECT (row), "gtk-shortcuts-section");
Packit Service c6b782
  gtk_stack_set_visible_child (priv->stack, section);
Packit Service c6b782
  gtk_popover_popdown (priv->popover);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static gboolean
Packit Service c6b782
hidden_by_direction (GtkWidget *widget)
Packit Service c6b782
{
Packit Service c6b782
  if (DZL_IS_SHORTCUTS_SHORTCUT (widget))
Packit Service c6b782
    {
Packit Service c6b782
      GtkTextDirection dir;
Packit Service c6b782
Packit Service c6b782
      g_object_get (widget, "direction", &dir, NULL);
Packit Service c6b782
      if (dir != GTK_TEXT_DIR_NONE &&
Packit Service c6b782
          dir != gtk_widget_get_direction (widget))
Packit Service c6b782
        return TRUE;
Packit Service c6b782
    }
Packit Service c6b782
Packit Service c6b782
  return FALSE;
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window__entry__changed (DzlShortcutsWindow *self,
Packit Service c6b782
                                     GtkSearchEntry      *search_entry)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
  gchar *downcase = NULL;
Packit Service c6b782
  GHashTableIter iter;
Packit Service c6b782
  const gchar *text;
Packit Service c6b782
  const gchar *last_section_name;
Packit Service c6b782
  gpointer key;
Packit Service c6b782
  gpointer value;
Packit Service c6b782
  gboolean has_result;
Packit Service c6b782
Packit Service c6b782
  text = gtk_entry_get_text (GTK_ENTRY (search_entry));
Packit Service c6b782
Packit Service c6b782
  if (!text || !*text)
Packit Service c6b782
    {
Packit Service c6b782
      if (priv->last_section_name != NULL)
Packit Service c6b782
        {
Packit Service c6b782
          gtk_stack_set_visible_child_name (priv->stack, priv->last_section_name);
Packit Service c6b782
          return;
Packit Service c6b782
Packit Service c6b782
        }
Packit Service c6b782
    }
Packit Service c6b782
Packit Service c6b782
  last_section_name = gtk_stack_get_visible_child_name (priv->stack);
Packit Service c6b782
Packit Service c6b782
  if (g_strcmp0 (last_section_name, "internal-search") != 0 &&
Packit Service c6b782
      g_strcmp0 (last_section_name, "no-search-results") != 0)
Packit Service c6b782
    {
Packit Service c6b782
      g_free (priv->last_section_name);
Packit Service c6b782
      priv->last_section_name = g_strdup (last_section_name);
Packit Service c6b782
    }
Packit Service c6b782
Packit Service c6b782
  downcase = g_utf8_strdown (text, -1);
Packit Service c6b782
Packit Service c6b782
  g_hash_table_iter_init (&iter, priv->keywords);
Packit Service c6b782
Packit Service c6b782
  has_result = FALSE;
Packit Service c6b782
  while (g_hash_table_iter_next (&iter, &key, &value))
Packit Service c6b782
    {
Packit Service c6b782
      GtkWidget *widget = key;
Packit Service c6b782
      const gchar *keywords = value;
Packit Service c6b782
      gboolean match;
Packit Service c6b782
Packit Service c6b782
      if (hidden_by_direction (widget))
Packit Service c6b782
        match = FALSE;
Packit Service c6b782
      else
Packit Service c6b782
        match = strstr (keywords, downcase) != NULL;
Packit Service c6b782
Packit Service c6b782
      gtk_widget_set_visible (widget, match);
Packit Service c6b782
      has_result |= match;
Packit Service c6b782
    }
Packit Service c6b782
Packit Service c6b782
  g_free (downcase);
Packit Service c6b782
Packit Service c6b782
  if (has_result)
Packit Service c6b782
    gtk_stack_set_visible_child_name (priv->stack, "internal-search");
Packit Service c6b782
  else
Packit Service c6b782
    gtk_stack_set_visible_child_name (priv->stack, "no-search-results");
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window__search_mode__changed (DzlShortcutsWindow *self)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  if (!gtk_search_bar_get_search_mode (priv->search_bar))
Packit Service c6b782
    {
Packit Service c6b782
      if (priv->last_section_name != NULL)
Packit Service c6b782
        gtk_stack_set_visible_child_name (priv->stack, priv->last_section_name);
Packit Service c6b782
    }
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_close (DzlShortcutsWindow *self)
Packit Service c6b782
{
Packit Service c6b782
  gtk_window_close (GTK_WINDOW (self));
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_search (DzlShortcutsWindow *self)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  gtk_search_bar_set_search_mode (priv->search_bar, TRUE);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_constructed (GObject *object)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)object;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  G_OBJECT_CLASS (dzl_shortcuts_window_parent_class)->constructed (object);
Packit Service c6b782
Packit Service c6b782
  if (priv->initial_section != NULL)
Packit Service c6b782
    gtk_stack_set_visible_child_name (priv->stack, priv->initial_section);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_finalize (GObject *object)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)object;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  g_clear_pointer (&priv->keywords, g_hash_table_unref);
Packit Service c6b782
  g_clear_pointer (&priv->initial_section, g_free);
Packit Service c6b782
  g_clear_pointer (&priv->view_name, g_free);
Packit Service c6b782
  g_clear_pointer (&priv->last_section_name, g_free);
Packit Service c6b782
  g_clear_pointer (&priv->search_items_hash, g_hash_table_unref);
Packit Service c6b782
Packit Service c6b782
  g_clear_object (&priv->search_image_group);
Packit Service c6b782
  g_clear_object (&priv->search_text_group);
Packit Service c6b782
Packit Service c6b782
  G_OBJECT_CLASS (dzl_shortcuts_window_parent_class)->finalize (object);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_dispose (GObject *object)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)object;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  g_signal_handlers_disconnect_by_func (priv->stack, G_CALLBACK (update_title_stack), self);
Packit Service c6b782
Packit Service c6b782
  dzl_shortcuts_window_set_window (self, NULL);
Packit Service c6b782
Packit Service c6b782
  if (priv->header_bar)
Packit Service c6b782
    {
Packit Service c6b782
      gtk_widget_destroy (GTK_WIDGET (priv->header_bar));
Packit Service c6b782
      priv->header_bar = NULL;
Packit Service c6b782
      priv->popover = NULL;
Packit Service c6b782
    }
Packit Service c6b782
Packit Service c6b782
  G_OBJECT_CLASS (dzl_shortcuts_window_parent_class)->dispose (object);
Packit Service c6b782
Packit Service c6b782
#if 0
Packit Service c6b782
  if (priv->main_box)
Packit Service c6b782
    {
Packit Service c6b782
      gtk_widget_destroy (GTK_WIDGET (priv->main_box));
Packit Service c6b782
      priv->main_box = NULL;
Packit Service c6b782
    }
Packit Service c6b782
#endif
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_get_property (GObject    *object,
Packit Service c6b782
                                  guint       prop_id,
Packit Service c6b782
                                  GValue     *value,
Packit Service c6b782
                                  GParamSpec *pspec)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)object;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  switch (prop_id)
Packit Service c6b782
    {
Packit Service c6b782
    case PROP_SECTION_NAME:
Packit Service c6b782
      {
Packit Service c6b782
        GtkWidget *child = gtk_stack_get_visible_child (priv->stack);
Packit Service c6b782
Packit Service c6b782
        if (child != NULL)
Packit Service c6b782
          {
Packit Service c6b782
            gchar *name = NULL;
Packit Service c6b782
Packit Service c6b782
            gtk_container_child_get (GTK_CONTAINER (priv->stack), child,
Packit Service c6b782
                                     "name", &name,
Packit Service c6b782
                                     NULL);
Packit Service c6b782
            g_value_take_string (value, name);
Packit Service c6b782
          }
Packit Service c6b782
      }
Packit Service c6b782
      break;
Packit Service c6b782
Packit Service c6b782
    case PROP_VIEW_NAME:
Packit Service c6b782
      g_value_set_string (value, priv->view_name);
Packit Service c6b782
      break;
Packit Service c6b782
Packit Service c6b782
    default:
Packit Service c6b782
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service c6b782
    }
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_set_property (GObject      *object,
Packit Service c6b782
                                  guint         prop_id,
Packit Service c6b782
                                  const GValue *value,
Packit Service c6b782
                                  GParamSpec   *pspec)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)object;
Packit Service c6b782
Packit Service c6b782
  switch (prop_id)
Packit Service c6b782
    {
Packit Service c6b782
    case PROP_SECTION_NAME:
Packit Service c6b782
      dzl_shortcuts_window_set_section_name (self, g_value_get_string (value));
Packit Service c6b782
      break;
Packit Service c6b782
Packit Service c6b782
    case PROP_VIEW_NAME:
Packit Service c6b782
      dzl_shortcuts_window_set_view_name (self, g_value_get_string (value));
Packit Service c6b782
      break;
Packit Service c6b782
Packit Service c6b782
    default:
Packit Service c6b782
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service c6b782
    }
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_unmap (GtkWidget *widget)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = (DzlShortcutsWindow *)widget;
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  gtk_search_bar_set_search_mode (priv->search_bar, FALSE);
Packit Service c6b782
Packit Service c6b782
  GTK_WIDGET_CLASS (dzl_shortcuts_window_parent_class)->unmap (widget);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static GType
Packit Service c6b782
dzl_shortcuts_window_child_type (GtkContainer *container)
Packit Service c6b782
{
Packit Service c6b782
  return GTK_TYPE_SHORTCUTS_SECTION;
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_class_init (DzlShortcutsWindowClass *klass)
Packit Service c6b782
{
Packit Service c6b782
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit Service c6b782
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
Packit Service c6b782
  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
Packit Service c6b782
  GtkBindingSet *binding_set = gtk_binding_set_by_class (klass);
Packit Service c6b782
Packit Service c6b782
  object_class->constructed = dzl_shortcuts_window_constructed;
Packit Service c6b782
  object_class->finalize = dzl_shortcuts_window_finalize;
Packit Service c6b782
  object_class->get_property = dzl_shortcuts_window_get_property;
Packit Service c6b782
  object_class->set_property = dzl_shortcuts_window_set_property;
Packit Service c6b782
  object_class->dispose = dzl_shortcuts_window_dispose;
Packit Service c6b782
Packit Service c6b782
  widget_class->unmap = dzl_shortcuts_window_unmap;
Packit Service c6b782
  container_class->add = dzl_shortcuts_window_add;
Packit Service c6b782
  container_class->remove = dzl_shortcuts_window_remove;
Packit Service c6b782
  container_class->child_type = dzl_shortcuts_window_child_type;
Packit Service c6b782
  container_class->forall = dzl_shortcuts_window_forall;
Packit Service c6b782
Packit Service c6b782
  klass->close = dzl_shortcuts_window_close;
Packit Service c6b782
  klass->search = dzl_shortcuts_window_search;
Packit Service c6b782
Packit Service c6b782
  /**
Packit Service c6b782
   * DzlShortcutsWindow:section-name:
Packit Service c6b782
   *
Packit Service c6b782
   * The name of the section to show.
Packit Service c6b782
   *
Packit Service c6b782
   * This should be the section-name of one of the #DzlShortcutsSection
Packit Service c6b782
   * objects that are in this shortcuts window.
Packit Service c6b782
   */
Packit Service c6b782
  properties[PROP_SECTION_NAME] =
Packit Service c6b782
    g_param_spec_string ("section-name", _("Section Name"), _("Section Name"),
Packit Service c6b782
                         "internal-search",
Packit Service c6b782
                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit Service c6b782
Packit Service c6b782
  /**
Packit Service c6b782
   * DzlShortcutsWindow:view-name:
Packit Service c6b782
   *
Packit Service c6b782
   * The view name by which to filter the contents.
Packit Service c6b782
   *
Packit Service c6b782
   * This should correspond to the #DzlShortcutsGroup:view property of some of
Packit Service c6b782
   * the #DzlShortcutsGroup objects that are inside this shortcuts window.
Packit Service c6b782
   *
Packit Service c6b782
   * Set this to %NULL to show all groups.
Packit Service c6b782
   */
Packit Service c6b782
  properties[PROP_VIEW_NAME] =
Packit Service c6b782
    g_param_spec_string ("view-name", _("View Name"), _("View Name"),
Packit Service c6b782
                         NULL,
Packit Service c6b782
                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit Service c6b782
Packit Service c6b782
  g_object_class_install_properties (object_class, LAST_PROP, properties);
Packit Service c6b782
Packit Service c6b782
  /**
Packit Service c6b782
   * DzlShortcutsWindow::close:
Packit Service c6b782
   *
Packit Service c6b782
   * The ::close signal is a
Packit Service c6b782
   * [keybinding signal][GtkBindingSignal]
Packit Service c6b782
   * which gets emitted when the user uses a keybinding to close
Packit Service c6b782
   * the window.
Packit Service c6b782
   *
Packit Service c6b782
   * The default binding for this signal is the Escape key.
Packit Service c6b782
   */
Packit Service c6b782
  signals[CLOSE] = g_signal_new (_("close"),
Packit Service c6b782
                                 G_TYPE_FROM_CLASS (klass),
Packit Service c6b782
                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
Packit Service c6b782
                                 G_STRUCT_OFFSET (DzlShortcutsWindowClass, close),
Packit Service c6b782
                                 NULL, NULL, NULL,
Packit Service c6b782
                                 G_TYPE_NONE,
Packit Service c6b782
                                 0);
Packit Service c6b782
Packit Service c6b782
  /**
Packit Service c6b782
   * DzlShortcutsWindow::search:
Packit Service c6b782
   *
Packit Service c6b782
   * The ::search signal is a
Packit Service c6b782
   * [keybinding signal][GtkBindingSignal]
Packit Service c6b782
   * which gets emitted when the user uses a keybinding to start a search.
Packit Service c6b782
   *
Packit Service c6b782
   * The default binding for this signal is Control-F.
Packit Service c6b782
   */
Packit Service c6b782
  signals[SEARCH] = g_signal_new (_("search"),
Packit Service c6b782
                                 G_TYPE_FROM_CLASS (klass),
Packit Service c6b782
                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
Packit Service c6b782
                                 G_STRUCT_OFFSET (DzlShortcutsWindowClass, search),
Packit Service c6b782
                                 NULL, NULL, NULL,
Packit Service c6b782
                                 G_TYPE_NONE,
Packit Service c6b782
                                 0);
Packit Service c6b782
Packit Service c6b782
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
Packit Service c6b782
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "search", 0);
Packit Service c6b782
Packit Service c6b782
  g_type_ensure (GTK_TYPE_SHORTCUTS_GROUP);
Packit Service c6b782
  g_type_ensure (GTK_TYPE_SHORTCUTS_SHORTCUT);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static gboolean
Packit Service c6b782
window_key_press_event_cb (GtkWidget *window,
Packit Service c6b782
                           GdkEvent  *event,
Packit Service c6b782
                           gpointer   data)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindow *self = DZL_SHORTCUTS_WINDOW (window);
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
Packit Service c6b782
  return gtk_search_bar_handle_event (priv->search_bar, event);
Packit Service c6b782
}
Packit Service c6b782
Packit Service c6b782
static void
Packit Service c6b782
dzl_shortcuts_window_init (DzlShortcutsWindow *self)
Packit Service c6b782
{
Packit Service c6b782
  DzlShortcutsWindowPrivate *priv = dzl_shortcuts_window_get_instance_private (self);
Packit Service c6b782
  GtkToggleButton *search_button;
Packit Service c6b782
  GtkBox *menu_box;
Packit Service c6b782
  GtkBox *box;
Packit Service c6b782
  GtkArrow *arrow;
Packit Service c6b782
  GtkWidget *scroller;
Packit Service c6b782
  GtkWidget *label;
Packit Service c6b782
  GtkWidget *empty;
Packit Service c6b782
  PangoAttrList *attributes;
Packit Service c6b782
Packit Service c6b782
  gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
Packit Service c6b782
  gtk_window_set_type_hint (GTK_WINDOW (self), GDK_WINDOW_TYPE_HINT_DIALOG);
Packit Service c6b782
Packit Service c6b782
  g_signal_connect (self, "key-press-event",
Packit Service c6b782
                    G_CALLBACK (window_key_press_event_cb), NULL);
Packit Service c6b782
Packit Service c6b782
  priv->keywords = g_hash_table_new_full (NULL, NULL, NULL, g_free);
Packit Service c6b782
  priv->search_items_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
Packit Service c6b782
Packit Service c6b782
  priv->search_text_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
Packit Service c6b782
  priv->search_image_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
Packit Service c6b782
Packit Service c6b782
  priv->header_bar = g_object_new (GTK_TYPE_HEADER_BAR,
Packit Service c6b782
                                   "show-close-button", TRUE,
Packit Service c6b782
                                   "visible", TRUE,
Packit Service c6b782
                                   NULL);
Packit Service c6b782
  gtk_window_set_titlebar (GTK_WINDOW (self), GTK_WIDGET (priv->header_bar));
Packit Service c6b782
Packit Service c6b782
  search_button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
Packit Service c6b782
                                "child", g_object_new (GTK_TYPE_IMAGE,
Packit Service c6b782
                                                       "visible", TRUE,
Packit Service c6b782
                                                       "icon-name", "edit-find-symbolic",
Packit Service c6b782
                                                       NULL),
Packit Service c6b782
                                "visible", TRUE,
Packit Service c6b782
                                NULL);
Packit Service c6b782
  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (search_button)), "image-button");
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (priv->header_bar), GTK_WIDGET (search_button));
Packit Service c6b782
Packit Service c6b782
  priv->main_box = g_object_new (GTK_TYPE_BOX,
Packit Service c6b782
                           "orientation", GTK_ORIENTATION_VERTICAL,
Packit Service c6b782
                           "visible", TRUE,
Packit Service c6b782
                           NULL);
Packit Service c6b782
  GTK_CONTAINER_CLASS (dzl_shortcuts_window_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (priv->main_box));
Packit Service c6b782
Packit Service c6b782
  priv->search_bar = g_object_new (GTK_TYPE_SEARCH_BAR,
Packit Service c6b782
                                   "visible", TRUE,
Packit Service c6b782
                                   NULL);
Packit Service c6b782
  g_object_bind_property (priv->search_bar, "search-mode-enabled",
Packit Service c6b782
                          search_button, "active",
Packit Service c6b782
                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (priv->main_box), GTK_WIDGET (priv->search_bar));
Packit Service c6b782
Packit Service c6b782
  priv->stack = g_object_new (GTK_TYPE_STACK,
Packit Service c6b782
                              "expand", TRUE,
Packit Service c6b782
                              "homogeneous", TRUE,
Packit Service c6b782
                              "transition-type", GTK_STACK_TRANSITION_TYPE_CROSSFADE,
Packit Service c6b782
                              "visible", TRUE,
Packit Service c6b782
                              NULL);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (priv->main_box), GTK_WIDGET (priv->stack));
Packit Service c6b782
Packit Service c6b782
  priv->title_stack = g_object_new (GTK_TYPE_STACK,
Packit Service c6b782
                                    "visible", TRUE,
Packit Service c6b782
                                    NULL);
Packit Service c6b782
  gtk_header_bar_set_custom_title (priv->header_bar, GTK_WIDGET (priv->title_stack));
Packit Service c6b782
Packit Service c6b782
  label = gtk_label_new (_("Shortcuts"));
Packit Service c6b782
  gtk_widget_show (label);
Packit Service c6b782
  gtk_style_context_add_class (gtk_widget_get_style_context (label), GTK_STYLE_CLASS_TITLE);
Packit Service c6b782
  gtk_stack_add_named (priv->title_stack, label, "title");
Packit Service c6b782
Packit Service c6b782
  label = gtk_label_new (_("Search Results"));
Packit Service c6b782
  gtk_widget_show (label);
Packit Service c6b782
  gtk_style_context_add_class (gtk_widget_get_style_context (label), GTK_STYLE_CLASS_TITLE);
Packit Service c6b782
  gtk_stack_add_named (priv->title_stack, label, "search");
Packit Service c6b782
Packit Service c6b782
  priv->menu_button = g_object_new (GTK_TYPE_MENU_BUTTON,
Packit Service c6b782
                                    "focus-on-click", FALSE,
Packit Service c6b782
                                    "visible", TRUE,
Packit Service c6b782
                                    "relief", GTK_RELIEF_NONE,
Packit Service c6b782
                                    NULL);
Packit Service c6b782
  gtk_stack_add_named (priv->title_stack, GTK_WIDGET (priv->menu_button), "sections");
Packit Service c6b782
Packit Service c6b782
  menu_box = g_object_new (GTK_TYPE_BOX,
Packit Service c6b782
                           "orientation", GTK_ORIENTATION_HORIZONTAL,
Packit Service c6b782
                           "spacing", 6,
Packit Service c6b782
                           "visible", TRUE,
Packit Service c6b782
                           NULL);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (priv->menu_button), GTK_WIDGET (menu_box));
Packit Service c6b782
Packit Service c6b782
  priv->menu_label = g_object_new (GTK_TYPE_LABEL,
Packit Service c6b782
                                   "visible", TRUE,
Packit Service c6b782
                                   NULL);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (menu_box), GTK_WIDGET (priv->menu_label));
Packit Service c6b782
Packit Service c6b782
  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
Packit Service c6b782
  arrow = g_object_new (GTK_TYPE_ARROW,
Packit Service c6b782
                        "arrow-type", GTK_ARROW_DOWN,
Packit Service c6b782
                        "visible", TRUE,
Packit Service c6b782
                        NULL);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (menu_box), GTK_WIDGET (arrow));
Packit Service c6b782
  G_GNUC_END_IGNORE_DEPRECATIONS;
Packit Service c6b782
Packit Service c6b782
  priv->popover = g_object_new (GTK_TYPE_POPOVER,
Packit Service c6b782
                                "border-width", 6,
Packit Service c6b782
                                "relative-to", priv->menu_button,
Packit Service c6b782
                                "position", GTK_POS_BOTTOM,
Packit Service c6b782
                                NULL);
Packit Service c6b782
  gtk_menu_button_set_popover (priv->menu_button, GTK_WIDGET (priv->popover));
Packit Service c6b782
Packit Service c6b782
  priv->list_box = g_object_new (GTK_TYPE_LIST_BOX,
Packit Service c6b782
                                 "selection-mode", GTK_SELECTION_NONE,
Packit Service c6b782
                                 "visible", TRUE,
Packit Service c6b782
                                 NULL);
Packit Service c6b782
  g_signal_connect_object (priv->list_box,
Packit Service c6b782
                           "row-activated",
Packit Service c6b782
                           G_CALLBACK (dzl_shortcuts_window__list_box__row_activated),
Packit Service c6b782
                           self,
Packit Service c6b782
                           G_CONNECT_SWAPPED);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (priv->popover), GTK_WIDGET (priv->list_box));
Packit Service c6b782
Packit Service c6b782
  priv->search_entry = GTK_SEARCH_ENTRY (gtk_search_entry_new ());
Packit Service c6b782
  gtk_widget_show (GTK_WIDGET (priv->search_entry));
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (priv->search_bar), GTK_WIDGET (priv->search_entry));
Packit Service c6b782
  g_object_set (priv->search_entry,
Packit Service c6b782
                "placeholder-text", _("Search Shortcuts"),
Packit Service c6b782
                "width-chars", 40,
Packit Service c6b782
                NULL);
Packit Service c6b782
  g_signal_connect_object (priv->search_entry,
Packit Service c6b782
                           "search-changed",
Packit Service c6b782
                           G_CALLBACK (dzl_shortcuts_window__entry__changed),
Packit Service c6b782
                           self,
Packit Service c6b782
                           G_CONNECT_SWAPPED);
Packit Service c6b782
  g_signal_connect_object (priv->search_bar,
Packit Service c6b782
                           "notify::search-mode-enabled",
Packit Service c6b782
                           G_CALLBACK (dzl_shortcuts_window__search_mode__changed),
Packit Service c6b782
                           self,
Packit Service c6b782
                           G_CONNECT_SWAPPED);
Packit Service c6b782
Packit Service c6b782
  scroller = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
Packit Service c6b782
                           "visible", TRUE,
Packit Service c6b782
                           NULL);
Packit Service c6b782
  box = g_object_new (GTK_TYPE_BOX,
Packit Service c6b782
                      "border-width", 24,
Packit Service c6b782
                      "halign", GTK_ALIGN_CENTER,
Packit Service c6b782
                      "spacing", 24,
Packit Service c6b782
                      "orientation", GTK_ORIENTATION_VERTICAL,
Packit Service c6b782
                      "visible", TRUE,
Packit Service c6b782
                      NULL);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (box));
Packit Service c6b782
  gtk_stack_add_named (priv->stack, scroller, "internal-search");
Packit Service c6b782
Packit Service c6b782
  priv->search_shortcuts = g_object_new (GTK_TYPE_BOX,
Packit Service c6b782
                                         "halign", GTK_ALIGN_CENTER,
Packit Service c6b782
                                         "spacing", 6,
Packit Service c6b782
                                         "orientation", GTK_ORIENTATION_VERTICAL,
Packit Service c6b782
                                         "visible", TRUE,
Packit Service c6b782
                                         NULL);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (priv->search_shortcuts));
Packit Service c6b782
Packit Service c6b782
  priv->search_gestures = g_object_new (GTK_TYPE_BOX,
Packit Service c6b782
                                        "halign", GTK_ALIGN_CENTER,
Packit Service c6b782
                                        "spacing", 6,
Packit Service c6b782
                                        "orientation", GTK_ORIENTATION_VERTICAL,
Packit Service c6b782
                                        "visible", TRUE,
Packit Service c6b782
                                        NULL);
Packit Service c6b782
  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (priv->search_gestures));
Packit Service c6b782
Packit Service c6b782
  empty = g_object_new (GTK_TYPE_GRID,
Packit Service c6b782
                        "visible", TRUE,
Packit Service c6b782
                        "row-spacing", 12,
Packit Service c6b782
                        "margin", 12,
Packit Service c6b782
                        "hexpand", TRUE,
Packit Service c6b782
                        "vexpand", TRUE,
Packit Service c6b782
                        "halign", GTK_ALIGN_CENTER,
Packit Service c6b782
                        "valign", GTK_ALIGN_CENTER,
Packit Service c6b782
                        NULL);
Packit Service c6b782
  gtk_style_context_add_class (gtk_widget_get_style_context (empty), GTK_STYLE_CLASS_DIM_LABEL);
Packit Service c6b782
  gtk_grid_attach (GTK_GRID (empty),
Packit Service c6b782
                   g_object_new (GTK_TYPE_IMAGE,
Packit Service c6b782
                                 "visible", TRUE,
Packit Service c6b782
                                 "icon-name", "edit-find-symbolic",
Packit Service c6b782
                                 "pixel-size", 72,
Packit Service c6b782
                                 NULL),
Packit Service c6b782
                   0, 0, 1, 1);
Packit Service c6b782
  attributes = pango_attr_list_new ();
Packit Service c6b782
  pango_attr_list_insert (attributes, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
Packit Service c6b782
  pango_attr_list_insert (attributes, pango_attr_scale_new (1.44));
Packit Service c6b782
  label = g_object_new (GTK_TYPE_LABEL,
Packit Service c6b782
                        "visible", TRUE,
Packit Service c6b782
                        "label", _("No Results Found"),
Packit Service c6b782
                        "attributes", attributes,
Packit Service c6b782
                        NULL);
Packit Service c6b782
  pango_attr_list_unref (attributes);
Packit Service c6b782
  gtk_grid_attach (GTK_GRID (empty), label, 0, 1, 1, 1);
Packit Service c6b782
  label = g_object_new (GTK_TYPE_LABEL,
Packit Service c6b782
                        "visible", TRUE,
Packit Service c6b782
                        "label", _("Try a different search"),
Packit Service c6b782
                        NULL);
Packit Service c6b782
  gtk_grid_attach (GTK_GRID (empty), label, 0, 2, 1, 1);
Packit Service c6b782
Packit Service c6b782
  gtk_stack_add_named (priv->stack, empty, "no-search-results");
Packit Service c6b782
Packit Service c6b782
  g_signal_connect_object (priv->stack, "notify::visible-child",
Packit Service c6b782
                           G_CALLBACK (update_title_stack), self, G_CONNECT_SWAPPED);
Packit Service c6b782
Packit Service c6b782
}