summaryrefslogtreecommitdiffstats
path: root/app/widgets/gimpsearchpopup.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:13:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:13:10 +0000
commit3c57dd931145d43f2b0aef96c4d178135956bf91 (patch)
tree3de698981e9f0cc2c4f9569b19a5f3595e741f6b /app/widgets/gimpsearchpopup.c
parentInitial commit. (diff)
downloadgimp-3c57dd931145d43f2b0aef96c4d178135956bf91.tar.xz
gimp-3c57dd931145d43f2b0aef96c4d178135956bf91.zip
Adding upstream version 2.10.36.upstream/2.10.36
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'app/widgets/gimpsearchpopup.c')
-rw-r--r--app/widgets/gimpsearchpopup.c773
1 files changed, 773 insertions, 0 deletions
diff --git a/app/widgets/gimpsearchpopup.c b/app/widgets/gimpsearchpopup.c
new file mode 100644
index 0000000..fb43477
--- /dev/null
+++ b/app/widgets/gimpsearchpopup.c
@@ -0,0 +1,773 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpsearchpopup.c
+ * Copyright (C) 2015 Jehan <jehan at girinstud.io>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "core/gimp.h"
+
+#include "gimpaction.h"
+#include "gimppopup.h"
+#include "gimpsearchpopup.h"
+#include "gimptoggleaction.h"
+#include "gimpuimanager.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+ COLUMN_ICON,
+ COLUMN_MARKUP,
+ COLUMN_TOOLTIP,
+ COLUMN_ACTION,
+ COLUMN_SENSITIVE,
+ COLUMN_SECTION,
+ N_COL
+};
+
+enum
+{
+ PROP_0,
+ PROP_GIMP,
+ PROP_CALLBACK,
+ PROP_CALLBACK_DATA
+};
+
+
+struct _GimpSearchPopupPrivate
+{
+ Gimp *gimp;
+ GtkWidget *keyword_entry;
+ GtkWidget *results_list;
+ GtkWidget *list_view;
+
+ GimpSearchPopupCallback build_results;
+ gpointer build_results_data;
+};
+
+
+static void gimp_search_popup_constructed (GObject *object);
+static void gimp_search_popup_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_search_popup_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_search_popup_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+
+static void gimp_search_popup_confirm (GimpPopup *popup);
+
+/* Signal handlers on the search entry */
+static gboolean keyword_entry_key_press_event (GtkWidget *widget,
+ GdkEventKey *event,
+ GimpSearchPopup *popup);
+static gboolean keyword_entry_key_release_event (GtkWidget *widget,
+ GdkEventKey *event,
+ GimpSearchPopup *popup);
+
+/* Signal handlers on the results list */
+static gboolean results_list_key_press_event (GtkWidget *widget,
+ GdkEventKey *kevent,
+ GimpSearchPopup *popup);
+static void results_list_row_activated (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *col,
+ GimpSearchPopup *popup);
+
+/* Utils */
+static void gimp_search_popup_run_selected (GimpSearchPopup *popup);
+static void gimp_search_popup_setup_results (GtkWidget **results_list,
+ GtkWidget **list_view);
+
+static gchar * gimp_search_popup_find_accel_label (GimpAction *action);
+static gboolean gimp_search_popup_view_accel_find_func (GtkAccelKey *key,
+ GClosure *closure,
+ gpointer data);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpSearchPopup, gimp_search_popup, GIMP_TYPE_POPUP)
+
+#define parent_class gimp_search_popup_parent_class
+
+static gint window_height = 0;
+
+
+static void
+gimp_search_popup_class_init (GimpSearchPopupClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GimpPopupClass *popup_class = GIMP_POPUP_CLASS (klass);
+
+ object_class->constructed = gimp_search_popup_constructed;
+ object_class->set_property = gimp_search_popup_set_property;
+ object_class->get_property = gimp_search_popup_get_property;
+
+ widget_class->size_allocate = gimp_search_popup_size_allocate;
+
+ popup_class->confirm = gimp_search_popup_confirm;
+
+ /**
+ * GimpSearchPopup:gimp:
+ *
+ * The #Gimp object.
+ */
+ g_object_class_install_property (object_class, PROP_GIMP,
+ g_param_spec_object ("gimp",
+ NULL, NULL,
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * GimpSearchPopup:callback:
+ *
+ * The #GimpSearchPopupCallback used to fill in results.
+ */
+ g_object_class_install_property (object_class, PROP_CALLBACK,
+ g_param_spec_pointer ("callback", NULL, NULL,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * GimpSearchPopup:callback-data:
+ *
+ * The #GPointer fed as last parameter to the #GimpSearchPopupCallback.
+ */
+ g_object_class_install_property (object_class, PROP_CALLBACK_DATA,
+ g_param_spec_pointer ("callback-data", NULL, NULL,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gimp_search_popup_init (GimpSearchPopup *search_popup)
+{
+ search_popup->priv = gimp_search_popup_get_instance_private (search_popup);
+}
+
+/************ Public Functions ****************/
+
+/**
+ * gimp_search_popup_new:
+ * @gimp: #Gimp object.
+ * @role: the role to give to the #GtkWindow.
+ * @title: the #GtkWindow title.
+ * @callback: the #GimpSearchPopupCallback used to fill in results.
+ * @callback_data: data fed to @callback.
+ *
+ * Returns: a new #GimpSearchPopup.
+ */
+GtkWidget *
+gimp_search_popup_new (Gimp *gimp,
+ const gchar *role,
+ const gchar *title,
+ GimpSearchPopupCallback callback,
+ gpointer callback_data)
+{
+ GtkWidget *widget;
+
+ widget = g_object_new (GIMP_TYPE_SEARCH_POPUP,
+ "type", GTK_WINDOW_TOPLEVEL,
+ "type-hint", GDK_WINDOW_TYPE_HINT_DIALOG,
+ "decorated", TRUE,
+ "modal", TRUE,
+ "role", role,
+ "title", title,
+
+ "gimp", gimp,
+ "callback", callback,
+ "callback-data", callback_data,
+ NULL);
+ gtk_window_set_modal (GTK_WINDOW (widget), FALSE);
+
+
+ return widget;
+}
+
+/**
+ * gimp_search_popup_add_result:
+ * @popup: the #GimpSearchPopup.
+ * @action: a #GimpAction to add in results list.
+ * @section: the section to add @action.
+ *
+ * Adds @action in the @popup's results at @section.
+ * The section only indicates relative order. If you want some items
+ * to appear before other, simply use lower @section.
+ */
+void
+gimp_search_popup_add_result (GimpSearchPopup *popup,
+ GimpAction *action,
+ gint section)
+{
+ GtkTreeIter iter;
+ GtkTreeIter next_section;
+ GtkListStore *store;
+ GtkTreeModel *model;
+ gchar *markup;
+ gchar *action_name;
+ gchar *label;
+ gchar *escaped_label = NULL;
+ const gchar *icon_name;
+ gchar *accel_string;
+ gchar *escaped_accel = NULL;
+ gboolean has_shortcut = FALSE;
+ const gchar *tooltip;
+ gchar *escaped_tooltip = NULL;
+ gboolean has_tooltip = FALSE;
+
+ label = g_strstrip (gimp_strip_uline (gimp_action_get_label (action)));
+
+ if (! label || strlen (label) == 0)
+ {
+ g_free (label);
+ return;
+ }
+
+ escaped_label = g_markup_escape_text (label, -1);
+
+ if (GIMP_IS_TOGGLE_ACTION (action))
+ {
+ if (gimp_toggle_action_get_active (GIMP_TOGGLE_ACTION (action)))
+ icon_name = "gtk-ok";
+ else
+ icon_name = "gtk-no";
+ }
+ else
+ {
+ icon_name = gimp_action_get_icon_name (action);
+ }
+
+ accel_string = gimp_search_popup_find_accel_label (action);
+ if (accel_string)
+ {
+ escaped_accel = g_markup_escape_text (accel_string, -1);
+ has_shortcut = TRUE;
+ }
+
+ tooltip = gimp_action_get_tooltip (action);
+ if (tooltip != NULL)
+ {
+ escaped_tooltip = g_markup_escape_text (tooltip, -1);
+ has_tooltip = TRUE;
+ }
+
+ markup = g_strdup_printf ("%s<small>%s%s%s<span weight='light'>%s</span></small>",
+ escaped_label,
+ has_shortcut ? " | " : "",
+ has_shortcut ? escaped_accel : "",
+ has_tooltip ? "\n" : "",
+ has_tooltip ? escaped_tooltip : "");
+
+ action_name = g_markup_escape_text (gimp_action_get_name (action), -1);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (popup->priv->results_list));
+ store = GTK_LIST_STORE (model);
+ if (gtk_tree_model_get_iter_first (model, &next_section))
+ {
+ while (TRUE)
+ {
+ gint iter_section;
+
+ gtk_tree_model_get (model, &next_section,
+ COLUMN_SECTION, &iter_section, -1);
+ if (iter_section > section)
+ {
+ gtk_list_store_insert_before (store, &iter, &next_section);
+ break;
+ }
+ else if (! gtk_tree_model_iter_next (model, &next_section))
+ {
+ gtk_list_store_append (store, &iter);
+ break;
+ }
+ }
+ }
+ else
+ {
+ gtk_list_store_append (store, &iter);
+ }
+
+ gtk_list_store_set (store, &iter,
+ COLUMN_ICON, icon_name,
+ COLUMN_MARKUP, markup,
+ COLUMN_TOOLTIP, action_name,
+ COLUMN_ACTION, action,
+ COLUMN_SECTION, section,
+ COLUMN_SENSITIVE, gimp_action_is_sensitive (action),
+ -1);
+
+ g_free (accel_string);
+ g_free (markup);
+ g_free (action_name);
+ g_free (label);
+ g_free (escaped_accel);
+ g_free (escaped_label);
+ g_free (escaped_tooltip);
+}
+
+/************ Private Functions ****************/
+
+static void
+gimp_search_popup_constructed (GObject *object)
+{
+ GimpSearchPopup *popup = GIMP_SEARCH_POPUP (object);
+ GdkScreen *screen = gdk_screen_get_default ();
+ GtkWidget *main_vbox;
+
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ gtk_container_add (GTK_CONTAINER (popup), main_vbox);
+ gtk_widget_show (main_vbox);
+
+ popup->priv->keyword_entry = gtk_entry_new ();
+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY (popup->priv->keyword_entry),
+ GTK_ENTRY_ICON_PRIMARY, "edit-find");
+ gtk_entry_set_icon_activatable (GTK_ENTRY (popup->priv->keyword_entry),
+ GTK_ENTRY_ICON_PRIMARY, FALSE);
+ gtk_box_pack_start (GTK_BOX (main_vbox),
+ popup->priv->keyword_entry,
+ FALSE, FALSE, 0);
+ gtk_widget_show (popup->priv->keyword_entry);
+
+ gimp_search_popup_setup_results (&popup->priv->results_list,
+ &popup->priv->list_view);
+ gtk_box_pack_start (GTK_BOX (main_vbox),
+ popup->priv->list_view, TRUE, TRUE, 0);
+
+ gtk_widget_set_events (GTK_WIDGET (object),
+ GDK_KEY_RELEASE_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_SCROLL_MASK);
+
+ g_signal_connect (popup->priv->keyword_entry, "key-press-event",
+ G_CALLBACK (keyword_entry_key_press_event),
+ popup);
+ g_signal_connect (popup->priv->keyword_entry, "key-release-event",
+ G_CALLBACK (keyword_entry_key_release_event),
+ popup);
+
+ g_signal_connect (popup->priv->results_list, "key-press-event",
+ G_CALLBACK (results_list_key_press_event),
+ popup);
+ g_signal_connect (popup->priv->results_list, "row-activated",
+ G_CALLBACK (results_list_row_activated),
+ popup);
+
+ /* Default size of the search popup showing the result list is half
+ * the screen. */
+ if (window_height == 0)
+ window_height = gdk_screen_get_height (screen) / 2;
+}
+
+static void
+gimp_search_popup_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpSearchPopup *search_popup = GIMP_SEARCH_POPUP (object);
+
+ switch (property_id)
+ {
+ case PROP_GIMP:
+ search_popup->priv->gimp = g_value_get_object (value);
+ break;
+ case PROP_CALLBACK:
+ search_popup->priv->build_results = g_value_get_pointer (value);
+ break;
+ case PROP_CALLBACK_DATA:
+ search_popup->priv->build_results_data = g_value_get_pointer (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_search_popup_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpSearchPopup *search_popup = GIMP_SEARCH_POPUP (object);
+
+ switch (property_id)
+ {
+ case PROP_GIMP:
+ g_value_set_object (value, search_popup->priv->gimp);
+ break;
+ case PROP_CALLBACK:
+ g_value_set_pointer (value, search_popup->priv->build_results);
+ break;
+ case PROP_CALLBACK_DATA:
+ g_value_set_pointer (value, search_popup->priv->build_results_data);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_search_popup_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GimpSearchPopup *popup = GIMP_SEARCH_POPUP (widget);
+
+ GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+
+ if (gtk_widget_get_visible (widget) &&
+ gtk_widget_get_visible (popup->priv->list_view))
+ {
+ GdkScreen *screen = gdk_screen_get_default ();
+
+ /* Save the window height when results are shown so that resizes
+ * by the user are saved across searches.
+ */
+ window_height = MAX (gdk_screen_get_height (screen) / 4,
+ allocation->height);
+ }
+}
+
+static void
+gimp_search_popup_confirm (GimpPopup *popup)
+{
+ GimpSearchPopup *search_popup = GIMP_SEARCH_POPUP (popup);
+
+ gimp_search_popup_run_selected (search_popup);
+}
+
+static gboolean
+keyword_entry_key_press_event (GtkWidget *widget,
+ GdkEventKey *event,
+ GimpSearchPopup *popup)
+{
+ gboolean event_processed = FALSE;
+
+ if (event->keyval == GDK_KEY_Down &&
+ gtk_widget_get_visible (popup->priv->list_view))
+ {
+ GtkTreeView *tree_view = GTK_TREE_VIEW (popup->priv->results_list);
+
+ /* When hitting the down key while editing, select directly the
+ * second item, since the first could have run directly with
+ * Enter. */
+ gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view),
+ gtk_tree_path_new_from_string ("1"));
+ gtk_widget_grab_focus (GTK_WIDGET (popup->priv->results_list));
+ event_processed = TRUE;
+ }
+
+ return event_processed;
+}
+
+static gboolean
+keyword_entry_key_release_event (GtkWidget *widget,
+ GdkEventKey *event,
+ GimpSearchPopup *popup)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (popup->priv->results_list);
+ gchar *entry_text;
+ gint width;
+
+ /* These keys are already managed by key bindings. */
+ if (event->keyval == GDK_KEY_Escape ||
+ event->keyval == GDK_KEY_Return ||
+ event->keyval == GDK_KEY_KP_Enter ||
+ event->keyval == GDK_KEY_ISO_Enter)
+ {
+ return FALSE;
+ }
+
+ gtk_window_get_size (GTK_WINDOW (popup), &width, NULL);
+ entry_text = g_strstrip (gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1));
+
+ if (strcmp (entry_text, "") != 0)
+ {
+ gtk_window_resize (GTK_WINDOW (popup),
+ width, window_height);
+ gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (tree_view)));
+ gtk_widget_show_all (popup->priv->list_view);
+ popup->priv->build_results (popup, entry_text,
+ popup->priv->build_results_data);
+ gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view),
+ gtk_tree_path_new_from_string ("0"));
+ }
+ else if (strcmp (entry_text, "") == 0 && (event->keyval == GDK_KEY_Down))
+ {
+ gtk_window_resize (GTK_WINDOW (popup),
+ width, window_height);
+ gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (tree_view)));
+ gtk_widget_show_all (popup->priv->list_view);
+ popup->priv->build_results (popup, NULL,
+ popup->priv->build_results_data);
+ gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view),
+ gtk_tree_path_new_from_string ("0"));
+ }
+ else
+ {
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_selection_unselect_path (selection, path);
+
+ gtk_tree_path_free (path);
+ }
+
+ gtk_widget_hide (popup->priv->list_view);
+ gtk_window_resize (GTK_WINDOW (popup), width, 1);
+ }
+
+ g_free (entry_text);
+
+ return TRUE;
+}
+
+static gboolean
+results_list_key_press_event (GtkWidget *widget,
+ GdkEventKey *kevent,
+ GimpSearchPopup *popup)
+{
+ /* These keys are already managed by key bindings. */
+ g_return_val_if_fail (kevent->keyval != GDK_KEY_Escape &&
+ kevent->keyval != GDK_KEY_Return &&
+ kevent->keyval != GDK_KEY_KP_Enter &&
+ kevent->keyval != GDK_KEY_ISO_Enter,
+ FALSE);
+
+ switch (kevent->keyval)
+ {
+ case GDK_KEY_Up:
+ {
+ gboolean event_processed = FALSE;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (popup->priv->results_list));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
+
+ if (strcmp (gtk_tree_path_to_string (path), "0") == 0)
+ {
+ gint start_pos;
+ gint end_pos;
+
+ gtk_editable_get_selection_bounds (GTK_EDITABLE (popup->priv->keyword_entry),
+ &start_pos, &end_pos);
+ gtk_widget_grab_focus ((GTK_WIDGET (popup->priv->keyword_entry)));
+ gtk_editable_select_region (GTK_EDITABLE (popup->priv->keyword_entry),
+ start_pos, end_pos);
+
+ event_processed = TRUE;
+ }
+
+ gtk_tree_path_free (path);
+ }
+
+ return event_processed;
+ }
+ case GDK_KEY_Down:
+ {
+ return FALSE;
+ }
+ default:
+ {
+ gint start_pos;
+ gint end_pos;
+
+ gtk_editable_get_selection_bounds (GTK_EDITABLE (popup->priv->keyword_entry),
+ &start_pos, &end_pos);
+ gtk_widget_grab_focus ((GTK_WIDGET (popup->priv->keyword_entry)));
+ gtk_editable_select_region (GTK_EDITABLE (popup->priv->keyword_entry),
+ start_pos, end_pos);
+ gtk_widget_event (GTK_WIDGET (popup->priv->keyword_entry),
+ (GdkEvent *) kevent);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+results_list_row_activated (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *col,
+ GimpSearchPopup *popup)
+{
+ gimp_search_popup_run_selected (popup);
+}
+
+static void
+gimp_search_popup_run_selected (GimpSearchPopup *popup)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (popup->priv->results_list));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ GimpAction *action;
+
+ gtk_tree_model_get (model, &iter, COLUMN_ACTION, &action, -1);
+
+ if (gimp_action_is_sensitive (action))
+ {
+ /* Close the search popup on activation. */
+ GIMP_POPUP_CLASS (parent_class)->cancel (GIMP_POPUP (popup));
+
+ gimp_action_activate (action);
+ }
+
+ g_object_unref (action);
+ }
+}
+
+static void
+gimp_search_popup_setup_results (GtkWidget **results_list,
+ GtkWidget **list_view)
+{
+ gint wid1 = 100;
+ GtkListStore *store;
+ GtkCellRenderer *cell;
+ GtkTreeViewColumn *column;
+
+ *list_view = gtk_scrolled_window_new (NULL, NULL);
+ store = gtk_list_store_new (N_COL,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ GIMP_TYPE_ACTION,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT);
+ *results_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (*results_list), FALSE);
+#ifdef GIMP_UNSTABLE
+ gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (*results_list),
+ COLUMN_TOOLTIP);
+#endif
+
+ cell = gtk_cell_renderer_pixbuf_new ();
+ column = gtk_tree_view_column_new_with_attributes (NULL, cell,
+ "icon-name", COLUMN_ICON,
+ "sensitive", COLUMN_SENSITIVE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (*results_list), column);
+ gtk_tree_view_column_set_min_width (column, 22);
+
+ cell = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (NULL, cell,
+ "markup", COLUMN_MARKUP,
+ "sensitive", COLUMN_SENSITIVE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (*results_list), column);
+ gtk_tree_view_column_set_max_width (column, wid1);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (*list_view),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+
+ gtk_container_add (GTK_CONTAINER (*list_view), *results_list);
+ g_object_unref (G_OBJECT (store));
+}
+
+static gchar *
+gimp_search_popup_find_accel_label (GimpAction *action)
+{
+ guint accel_key = 0;
+ GdkModifierType accel_mask = 0;
+ GClosure *accel_closure = NULL;
+ gchar *accel_string;
+ GtkAccelGroup *accel_group;
+ GimpUIManager *manager;
+
+ manager = gimp_ui_managers_from_name ("<Image>")->data;
+ accel_group = gimp_ui_manager_get_accel_group (manager);
+ accel_closure = gimp_action_get_accel_closure (action);
+
+ if (accel_closure)
+ {
+ GtkAccelKey *key;
+
+ key = gtk_accel_group_find (accel_group,
+ gimp_search_popup_view_accel_find_func,
+ accel_closure);
+ if (key &&
+ key->accel_key &&
+ key->accel_flags & GTK_ACCEL_VISIBLE)
+ {
+ accel_key = key->accel_key;
+ accel_mask = key->accel_mods;
+ }
+ }
+
+ accel_string = gtk_accelerator_get_label (accel_key, accel_mask);
+
+ if (strcmp (g_strstrip (accel_string), "") == 0)
+ {
+ /* The value returned by gtk_accelerator_get_label() must be
+ * freed after use.
+ */
+ g_clear_pointer (&accel_string, g_free);
+ }
+
+ return accel_string;
+}
+
+static gboolean
+gimp_search_popup_view_accel_find_func (GtkAccelKey *key,
+ GClosure *closure,
+ gpointer data)
+{
+ return (GClosure *) data == closure;
+}