Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/app/widgets/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 29 kB image not shown  

Quelle  gimpsearchpopup.c   Sprache: C

 

/* 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 "gimphelp-ids.h"
#include "gimppopup.h"
#include "gimpsearchpopup.h"
#include "gimptoggleaction.h"
#include "gimpwidgets-utils.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);
#ifdef G_OS_WIN32
static void       gimp_search_popup_realize              (GimpSearchPopup   *search_popup,
                                                          gpointer           data);
#endif
static void       gimp_search_popup_confirm              (GimpPopup *popup);

/* Signal handlers on the search entry */
static void       keyword_entry_icon_press               (GtkEntry             *entry,
                                                          GtkEntryIconPosition  icon_pos,
                                                          GdkEvent             *event,
                                                          GimpSearchPopup      *popup);
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 void       gimp_search_popup_help                 (GimpSearchPopup   *popup);


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);

#ifdef G_OS_WIN32
  g_signal_connect (search_popup, "realize",
                    G_CALLBACK (gimp_search_popup_realize),
                    NULL);
#endif
}

/************ 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)
{
  gchar        **accels;
  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         *shortcut_helper  = NULL;
  const gchar   *menu_path;
  gchar         *menu_path_helper = NULL;
  const gchar   *tooltip;
  gchar         *escaped_tooltip  = NULL;
  gboolean       has_tooltip      = FALSE;
  gboolean       sensitive        = FALSE;
  const gchar   *sensitive_reason = NULL;
  gchar         *escaped_reason   = NULL;

  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 = "gimp-toggle-on";
      else
        icon_name = "gimp-toggle-off";
    }
  else
    {
      icon_name = gimp_action_get_icon_name (action);
    }

  accels = gimp_action_get_display_accels (action);
  if (accels && accels[0])
    {
      gchar *formatted_label;
      gchar *formatted_value;

      /* TRANSLATORS: a helper label indicating the shortcut for an action,
       * it will be used within the generic "%s: %s" (also localized) string.
       * e.g.: "shortcut: Ctrl+Alt+O"
       */

      formatted_label = g_markup_printf_escaped ("<u>%s</u>", _("shortcut"));
      formatted_value = g_markup_escape_text (accels[0], -1);

      /* TRANSLATORS: generic "title: value" label which will be used in various ways. */
      shortcut_helper = g_strdup_printf (_("%s: %s"), formatted_label, formatted_value);

      g_free (formatted_label);
      g_free (formatted_value);
    }
  g_strfreev (accels);

  if ((menu_path = gimp_action_get_menu_path (action)) != NULL)
    {
      if (strlen (menu_path) > 0)
        {
          gchar *formatted_label;
          gchar *formatted_value;

          /* TRANSLATORS: a helper label indicating the menu path for an action,
           * it will be used within the generic "%s: %s" (also localized) string.
           * e.g.: "Menu: Filters > Generic"
           */

          formatted_label = g_markup_printf_escaped ("<u>%s</u>", _("menu"));
          formatted_value = g_markup_escape_text (menu_path, -1);

          /* TRANSLATORS: generic "title: value" label which will be used in various ways. */
          menu_path_helper = g_strdup_printf (_("%s: %s"), formatted_label, formatted_value);

          g_free (formatted_label);
          g_free (formatted_value);
        }
    }

  tooltip = gimp_action_get_tooltip (action);
  if (tooltip != NULL)
    {
      escaped_tooltip = g_markup_escape_text (tooltip, -1);
      has_tooltip = TRUE;
    }

  sensitive = gimp_action_is_sensitive (action, &sensitive_reason);
  if (sensitive_reason != NULL)
    {
      escaped_reason = g_markup_escape_text (sensitive_reason, -1);
    }

  markup = g_strdup_printf ("%s"                                           /* Label           */
                            "<small>%s%s"                                  /* Shortcut        */
                            "%s%s"                                         /* Menu path       */
                            "%s<span weight='light'>%s</span>"             /* Tooltip         */
                            "%s<i><span weight='ultralight'>%s</span></i>" /* Inactive reason */
                            "</small>",
                            escaped_label,

                            shortcut_helper ? " | " : "",
                            shortcut_helper ? shortcut_helper : "",

                            menu_path_helper ? " | " : "",
                            menu_path_helper ? menu_path_helper : "",

                            has_tooltip ? "\n" : "",
                            has_tooltip ? escaped_tooltip : "",
                            escaped_reason ? "\n" : "",
                            escaped_reason ? escaped_reason : "");

  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, sensitive,
                      -1);

  g_free (markup);
  g_free (action_name);
  g_free (label);
  g_free (escaped_label);
  g_free (escaped_tooltip);
  g_free (escaped_reason);
  g_free (menu_path_helper);
  g_free (shortcut_helper);
}

/************ Private Functions ****************/

static void
gimp_search_popup_constructed (GObject *object)
{
  GimpSearchPopup *popup = GIMP_SEARCH_POPUP (object);
  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_entry_set_icon_from_icon_name (GTK_ENTRY (popup->priv->keyword_entry),
                                     GTK_ENTRY_ICON_SECONDARY, GIMP_ICON_HELP);
  gtk_entry_set_icon_activatable (GTK_ENTRY (popup->priv->keyword_entry),
                                  GTK_ENTRY_ICON_SECONDARY, TRUE);
  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       |
                         GDK_SMOOTH_SCROLL_MASK);

  g_signal_connect (popup->priv->keyword_entry, "icon-press",
                    G_CALLBACK (keyword_entry_icon_press),
                    popup);
  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);
}

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);
  GdkRectangle     workarea;

  GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);

  gdk_monitor_get_workarea (gimp_widget_get_monitor (widget),
                            &workarea);

  if (window_height == 0)
    {
      /* Default to half the monitor */
      window_height = workarea.height / 2;
    }

  if (gtk_widget_get_visible (widget) &&
      gtk_widget_get_visible (popup->priv->list_view))
    {
      /* Save the window height when results are shown so that resizes
       * by the user are saved across searches.
       */

      window_height = MAX (workarea.height / 4, allocation->height);
    }
}

#ifdef G_OS_WIN32
static void
gimp_search_popup_realize (GimpSearchPopup *search_popup,
                           gpointer         data)
{
  /* Since this popup is initially modal to the main window,
   * toggling the visibility of the GdkWindow causes odd
   * behavior. Instead, we change the opacity on launch to
   * refresh the titlebar theme */

  gimp_window_set_title_bar_theme (search_popup->priv->gimp,
                                   GTK_WIDGET (search_popup));

  gtk_widget_set_opacity (GTK_WIDGET (search_popup), 0);
  gtk_widget_set_opacity (GTK_WIDGET (search_popup), 1);
}
#endif

static void
gimp_search_popup_confirm (GimpPopup *popup)
{
  GimpSearchPopup *search_popup = GIMP_SEARCH_POPUP (popup);

  gimp_search_popup_run_selected (search_popup);
}

static void
keyword_entry_icon_press (GtkEntry             *entry,
                          GtkEntryIconPosition  icon_pos,
                          GdkEvent             *event,
                          GimpSearchPopup      *popup)
{
  if (icon_pos == GTK_ENTRY_ICON_SECONDARY)
    gimp_search_popup_help (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);
      GtkTreePath *path;

      /* When hitting the down key while editing, select directly the
       * second item, since the first could have run directly with
       * Enter. */

      path = gtk_tree_path_new_from_string ("1");
      gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view), path);
      gtk_tree_path_free (path);

      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);
  GtkTreePath *path;
  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 (event->keyval == GDK_KEY_F1)
    {
      gimp_search_popup_help (popup);
    }
  else if (strcmp (entry_text, "") != 0)
    {
      path = gtk_tree_path_new_from_string ("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), path);
      gtk_tree_path_free (path);
    }
  else if (strcmp (entry_text, "") == 0 && (event->keyval == GDK_KEY_Down))
    {
      path = gtk_tree_path_new_from_string ("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, NULL,
                                  popup->priv->build_results_data);
      gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view), path);
      gtk_tree_path_free (path);
    }
  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))
        {
          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);
            gchar       *path_str;

            path_str = gtk_tree_path_to_string (path);
            if (strcmp (path_str, "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;
              }

            g_free (path_str);
            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, NULL))
        {
          /* 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 void
gimp_search_popup_help (GimpSearchPopup *popup)
{
  GtkTreeView      *tree_view;
  const gchar      *help_id = NULL;
  GimpAction       *action  = NULL;
  GtkTreeSelection *selection;
  GtkTreeModel     *model;
  GtkTreeIter       iter;

  tree_view = GTK_TREE_VIEW (popup->priv->results_list);
  selection = gtk_tree_view_get_selection (tree_view);

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      gtk_tree_model_get (model, &iter, COLUMN_ACTION, &action, -1);
      help_id = gimp_action_get_help_id (action);
    }

  if (help_id == NULL)
    help_id = GIMP_HELP_ACTION_SEARCH_DIALOG;

  gimp_help (popup->priv->gimp, NULL, NULL, help_id);
  g_clear_object (&action);
}

Messung
CHZG
819710092

¤ Dauer der Verarbeitung: 0.6 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.