2006-12-09 21:33:38 +00:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2004-04-21 16:33:17 +00:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* gimpuimanager.c
|
|
|
|
* Copyright (C) 2004 Michael Natterer <mitch@gimp.org>
|
|
|
|
*
|
2009-01-17 22:28:01 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2004-04-21 16:33:17 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-17 22:28:01 +00:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2004-04-21 16:33:17 +00:00
|
|
|
* (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
|
2018-07-11 23:27:07 +02:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2004-04-21 16:33:17 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
2013-11-01 22:28:18 +01:00
|
|
|
#include <gegl.h>
|
2004-04-21 16:33:17 +00:00
|
|
|
#include <gtk/gtk.h>
|
2004-05-09 23:28:37 +00:00
|
|
|
#include <gdk/gdkkeysyms.h>
|
2004-04-21 16:33:17 +00:00
|
|
|
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
2004-05-09 23:28:37 +00:00
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
2004-04-21 16:33:17 +00:00
|
|
|
|
|
|
|
#include "widgets-types.h"
|
|
|
|
|
|
|
|
#include "core/gimp.h"
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
#include "gimpaction.h"
|
2004-04-21 16:33:17 +00:00
|
|
|
#include "gimpactiongroup.h"
|
2004-05-09 23:28:37 +00:00
|
|
|
#include "gimphelp.h"
|
|
|
|
#include "gimphelp-ids.h"
|
2023-02-23 19:05:58 +01:00
|
|
|
#include "gimpmenu.h"
|
|
|
|
#include "gimpmenushell.h"
|
2019-07-02 03:54:38 +02:00
|
|
|
#include "gimptoggleaction.h"
|
2004-04-21 16:33:17 +00:00
|
|
|
#include "gimpuimanager.h"
|
|
|
|
|
2004-12-01 13:27:03 +00:00
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
2004-04-27 12:28:27 +00:00
|
|
|
PROP_NAME,
|
2004-04-21 16:33:17 +00:00
|
|
|
PROP_GIMP
|
|
|
|
};
|
|
|
|
|
2004-04-30 15:29:11 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
UPDATE,
|
2006-03-09 15:26:33 +00:00
|
|
|
SHOW_TOOLTIP,
|
|
|
|
HIDE_TOOLTIP,
|
2023-02-08 23:11:43 +01:00
|
|
|
UI_ADDED,
|
2004-04-30 15:29:11 +00:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2023-02-08 23:11:43 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gchar *path;
|
|
|
|
gchar *action_name;
|
2023-02-10 12:57:29 +01:00
|
|
|
gchar *placeholder;
|
2023-02-08 23:11:43 +01:00
|
|
|
gboolean top;
|
|
|
|
} GimpUIManagerMenuItem;
|
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
|
2011-01-14 09:38:11 +01:00
|
|
|
static void gimp_ui_manager_constructed (GObject *object);
|
2008-08-20 18:20:42 +00:00
|
|
|
static void gimp_ui_manager_dispose (GObject *object);
|
|
|
|
static void gimp_ui_manager_finalize (GObject *object);
|
|
|
|
static void gimp_ui_manager_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_ui_manager_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_ui_manager_connect_proxy (GtkUIManager *manager,
|
|
|
|
GtkAction *action,
|
|
|
|
GtkWidget *proxy);
|
2019-07-02 03:54:38 +02:00
|
|
|
static GtkWidget *gimp_ui_manager_get_widget_impl (GtkUIManager *manager,
|
2008-08-20 18:20:42 +00:00
|
|
|
const gchar *path);
|
2019-07-02 03:54:38 +02:00
|
|
|
static GtkAction *gimp_ui_manager_get_action_impl (GtkUIManager *manager,
|
2008-08-20 18:20:42 +00:00
|
|
|
const gchar *path);
|
|
|
|
static void gimp_ui_manager_real_update (GimpUIManager *manager,
|
|
|
|
gpointer update_data);
|
2004-05-17 13:38:03 +00:00
|
|
|
static GimpUIManagerUIEntry *
|
2008-08-20 18:20:42 +00:00
|
|
|
gimp_ui_manager_entry_get (GimpUIManager *manager,
|
|
|
|
const gchar *ui_path);
|
|
|
|
static gboolean gimp_ui_manager_entry_load (GimpUIManager *manager,
|
|
|
|
GimpUIManagerUIEntry *entry,
|
|
|
|
GError **error);
|
2005-02-08 20:55:00 +00:00
|
|
|
static GimpUIManagerUIEntry *
|
2008-08-20 18:20:42 +00:00
|
|
|
gimp_ui_manager_entry_ensure (GimpUIManager *manager,
|
|
|
|
const gchar *path);
|
2014-07-21 02:34:39 +02:00
|
|
|
static void gimp_ui_manager_delete_popdown_data (GtkWidget *widget,
|
2008-08-20 18:20:42 +00:00
|
|
|
GimpUIManager *manager);
|
|
|
|
static void gimp_ui_manager_item_realize (GtkWidget *widget,
|
|
|
|
GimpUIManager *manager);
|
|
|
|
static void gimp_ui_manager_menu_item_select (GtkWidget *widget,
|
|
|
|
GimpUIManager *manager);
|
|
|
|
static void gimp_ui_manager_menu_item_deselect (GtkWidget *widget,
|
|
|
|
GimpUIManager *manager);
|
|
|
|
static gboolean gimp_ui_manager_item_key_press (GtkWidget *widget,
|
|
|
|
GdkEventKey *kevent,
|
|
|
|
GimpUIManager *manager);
|
|
|
|
static GtkWidget *find_widget_under_pointer (GdkWindow *window,
|
|
|
|
gint *x,
|
|
|
|
gint *y);
|
2004-05-09 23:28:37 +00:00
|
|
|
|
2023-02-22 19:58:43 +01:00
|
|
|
static void gimp_ui_manager_fill_model (GimpUIManager *manager,
|
|
|
|
GMenuModel *model);
|
2023-02-08 23:11:43 +01:00
|
|
|
static void gimp_ui_manager_menu_item_free (GimpUIManagerMenuItem *item);
|
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
|
2006-05-15 09:46:31 +00:00
|
|
|
G_DEFINE_TYPE (GimpUIManager, gimp_ui_manager, GTK_TYPE_UI_MANAGER)
|
2004-04-30 15:29:11 +00:00
|
|
|
|
2005-12-19 22:37:49 +00:00
|
|
|
#define parent_class gimp_ui_manager_parent_class
|
2004-04-21 16:33:17 +00:00
|
|
|
|
2005-12-19 22:37:49 +00:00
|
|
|
static guint manager_signals[LAST_SIGNAL] = { 0 };
|
2004-04-21 16:33:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ui_manager_class_init (GimpUIManagerClass *klass)
|
|
|
|
{
|
2004-05-09 23:28:37 +00:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GtkUIManagerClass *manager_class = GTK_UI_MANAGER_CLASS (klass);
|
2004-04-21 16:33:17 +00:00
|
|
|
|
2011-01-14 09:38:11 +01:00
|
|
|
object_class->constructed = gimp_ui_manager_constructed;
|
2004-05-09 23:28:37 +00:00
|
|
|
object_class->dispose = gimp_ui_manager_dispose;
|
|
|
|
object_class->finalize = gimp_ui_manager_finalize;
|
|
|
|
object_class->set_property = gimp_ui_manager_set_property;
|
|
|
|
object_class->get_property = gimp_ui_manager_get_property;
|
|
|
|
|
2004-09-16 14:31:39 +00:00
|
|
|
manager_class->connect_proxy = gimp_ui_manager_connect_proxy;
|
2019-07-02 03:54:38 +02:00
|
|
|
manager_class->get_widget = gimp_ui_manager_get_widget_impl;
|
|
|
|
manager_class->get_action = gimp_ui_manager_get_action_impl;
|
2004-04-21 16:33:17 +00:00
|
|
|
|
2004-05-09 23:28:37 +00:00
|
|
|
klass->update = gimp_ui_manager_real_update;
|
2004-04-30 15:29:11 +00:00
|
|
|
|
|
|
|
manager_signals[UPDATE] =
|
|
|
|
g_signal_new ("update",
|
2006-04-12 12:49:29 +00:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET (GimpUIManagerClass, update),
|
2020-01-12 11:06:05 +01:00
|
|
|
NULL, NULL, NULL,
|
2006-04-12 12:49:29 +00:00
|
|
|
G_TYPE_NONE, 1,
|
2004-04-30 15:29:11 +00:00
|
|
|
G_TYPE_POINTER);
|
|
|
|
|
2006-03-09 15:26:33 +00:00
|
|
|
manager_signals[SHOW_TOOLTIP] =
|
|
|
|
g_signal_new ("show-tooltip",
|
2006-04-12 12:49:29 +00:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET (GimpUIManagerClass, show_tooltip),
|
2020-01-12 11:06:05 +01:00
|
|
|
NULL, NULL, NULL,
|
2006-04-12 12:49:29 +00:00
|
|
|
G_TYPE_NONE, 1,
|
2006-03-09 15:26:33 +00:00
|
|
|
G_TYPE_STRING);
|
|
|
|
|
|
|
|
manager_signals[HIDE_TOOLTIP] =
|
|
|
|
g_signal_new ("hide-tooltip",
|
2006-04-12 12:49:29 +00:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET (GimpUIManagerClass, hide_tooltip),
|
2020-01-12 11:06:05 +01:00
|
|
|
NULL, NULL, NULL,
|
2006-04-12 12:49:29 +00:00
|
|
|
G_TYPE_NONE, 0,
|
2006-03-09 15:26:33 +00:00
|
|
|
G_TYPE_NONE);
|
2023-02-08 23:11:43 +01:00
|
|
|
manager_signals[UI_ADDED] =
|
|
|
|
g_signal_new ("ui-added",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET (GimpUIManagerClass, ui_added),
|
|
|
|
NULL, NULL, NULL,
|
2023-02-10 12:57:29 +01:00
|
|
|
G_TYPE_NONE, 4,
|
|
|
|
G_TYPE_STRING,
|
2023-02-08 23:11:43 +01:00
|
|
|
G_TYPE_STRING,
|
|
|
|
G_TYPE_STRING,
|
|
|
|
G_TYPE_BOOLEAN);
|
|
|
|
|
2006-03-09 15:26:33 +00:00
|
|
|
|
2004-04-27 12:28:27 +00:00
|
|
|
g_object_class_install_property (object_class, PROP_NAME,
|
|
|
|
g_param_spec_string ("name",
|
|
|
|
NULL, NULL,
|
|
|
|
NULL,
|
2006-01-18 20:29:40 +00:00
|
|
|
GIMP_PARAM_READWRITE |
|
2004-04-27 12:28:27 +00:00
|
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
g_object_class_install_property (object_class, PROP_GIMP,
|
|
|
|
g_param_spec_object ("gimp",
|
|
|
|
NULL, NULL,
|
|
|
|
GIMP_TYPE_GIMP,
|
2006-01-18 20:29:40 +00:00
|
|
|
GIMP_PARAM_READWRITE |
|
2004-04-21 16:33:17 +00:00
|
|
|
G_PARAM_CONSTRUCT_ONLY));
|
2004-04-27 12:28:27 +00:00
|
|
|
|
|
|
|
klass->managers = g_hash_table_new_full (g_str_hash, g_str_equal,
|
|
|
|
g_free, NULL);
|
2004-04-21 16:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ui_manager_init (GimpUIManager *manager)
|
|
|
|
{
|
2004-04-27 12:28:27 +00:00
|
|
|
manager->name = NULL;
|
2004-04-21 16:33:17 +00:00
|
|
|
manager->gimp = NULL;
|
|
|
|
}
|
|
|
|
|
2011-01-14 09:38:11 +01:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_constructed (GObject *object)
|
2004-04-27 12:28:27 +00:00
|
|
|
{
|
2011-01-14 09:38:11 +01:00
|
|
|
GimpUIManager *manager = GIMP_UI_MANAGER (object);
|
2004-04-27 12:28:27 +00:00
|
|
|
|
2012-11-12 21:51:22 +01:00
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
2004-04-27 12:28:27 +00:00
|
|
|
|
|
|
|
if (manager->name)
|
|
|
|
{
|
|
|
|
GimpUIManagerClass *manager_class;
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
manager_class = GIMP_UI_MANAGER_GET_CLASS (object);
|
|
|
|
|
|
|
|
list = g_hash_table_lookup (manager_class->managers, manager->name);
|
|
|
|
|
|
|
|
list = g_list_append (list, manager);
|
|
|
|
|
|
|
|
g_hash_table_replace (manager_class->managers,
|
|
|
|
g_strdup (manager->name), list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ui_manager_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
GimpUIManager *manager = GIMP_UI_MANAGER (object);
|
|
|
|
|
|
|
|
if (manager->name)
|
|
|
|
{
|
|
|
|
GimpUIManagerClass *manager_class;
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
manager_class = GIMP_UI_MANAGER_GET_CLASS (object);
|
|
|
|
|
|
|
|
list = g_hash_table_lookup (manager_class->managers, manager->name);
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
{
|
|
|
|
list = g_list_remove (list, manager);
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
g_hash_table_replace (manager_class->managers,
|
|
|
|
g_strdup (manager->name), list);
|
|
|
|
else
|
|
|
|
g_hash_table_remove (manager_class->managers, manager->name);
|
|
|
|
}
|
|
|
|
}
|
2004-05-09 23:28:37 +00:00
|
|
|
|
2004-04-27 12:28:27 +00:00
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GimpUIManager *manager = GIMP_UI_MANAGER (object);
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
for (list = manager->registered_uis; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpUIManagerUIEntry *entry = list->data;
|
|
|
|
|
2004-04-26 15:51:21 +00:00
|
|
|
g_free (entry->ui_path);
|
2004-04-21 16:33:17 +00:00
|
|
|
g_free (entry->basename);
|
2023-02-22 17:07:32 +01:00
|
|
|
g_clear_object (&entry->builder);
|
2004-04-22 17:14:22 +00:00
|
|
|
|
|
|
|
if (entry->widget)
|
|
|
|
g_object_unref (entry->widget);
|
|
|
|
|
2007-05-22 15:14:41 +00:00
|
|
|
g_slice_free (GimpUIManagerUIEntry, entry);
|
2004-04-21 16:33:17 +00:00
|
|
|
}
|
|
|
|
|
2019-05-27 17:47:55 +02:00
|
|
|
g_clear_pointer (&manager->registered_uis, g_list_free);
|
|
|
|
g_clear_pointer (&manager->name, g_free);
|
2004-04-27 12:28:27 +00:00
|
|
|
|
2023-02-08 23:11:43 +01:00
|
|
|
g_list_free_full (manager->ui_items,
|
|
|
|
(GDestroyNotify) gimp_ui_manager_menu_item_free);
|
|
|
|
|
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ui_manager_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GimpUIManager *manager = GIMP_UI_MANAGER (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2004-04-27 12:28:27 +00:00
|
|
|
case PROP_NAME:
|
|
|
|
g_free (manager->name);
|
|
|
|
manager->name = g_value_dup_string (value);
|
|
|
|
break;
|
2009-03-05 21:51:56 +00:00
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
case PROP_GIMP:
|
|
|
|
manager->gimp = g_value_get_object (value);
|
|
|
|
break;
|
2009-03-05 21:51:56 +00:00
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ui_manager_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GimpUIManager *manager = GIMP_UI_MANAGER (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2004-04-27 12:28:27 +00:00
|
|
|
case PROP_NAME:
|
|
|
|
g_value_set_string (value, manager->name);
|
|
|
|
break;
|
2009-03-05 21:51:56 +00:00
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
case PROP_GIMP:
|
|
|
|
g_value_set_object (value, manager->gimp);
|
|
|
|
break;
|
2009-03-05 21:51:56 +00:00
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-09 23:28:37 +00:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_connect_proxy (GtkUIManager *manager,
|
|
|
|
GtkAction *action,
|
|
|
|
GtkWidget *proxy)
|
|
|
|
{
|
|
|
|
g_object_set_qdata (G_OBJECT (proxy), GIMP_HELP_ID,
|
2009-03-05 21:51:56 +00:00
|
|
|
g_object_get_qdata (G_OBJECT (action), GIMP_HELP_ID));
|
2004-05-09 23:28:37 +00:00
|
|
|
|
|
|
|
if (GTK_IS_MENU_ITEM (proxy))
|
2007-03-31 12:25:03 +00:00
|
|
|
{
|
|
|
|
g_signal_connect (proxy, "select",
|
|
|
|
G_CALLBACK (gimp_ui_manager_menu_item_select),
|
|
|
|
manager);
|
|
|
|
g_signal_connect (proxy, "deselect",
|
|
|
|
G_CALLBACK (gimp_ui_manager_menu_item_deselect),
|
|
|
|
manager);
|
|
|
|
|
|
|
|
g_signal_connect_after (proxy, "realize",
|
|
|
|
G_CALLBACK (gimp_ui_manager_item_realize),
|
|
|
|
manager);
|
|
|
|
}
|
2004-05-09 23:28:37 +00:00
|
|
|
}
|
|
|
|
|
2005-02-08 20:55:00 +00:00
|
|
|
static GtkWidget *
|
2019-07-02 03:54:38 +02:00
|
|
|
gimp_ui_manager_get_widget_impl (GtkUIManager *manager,
|
|
|
|
const gchar *path)
|
2005-02-08 20:55:00 +00:00
|
|
|
{
|
|
|
|
GimpUIManagerUIEntry *entry;
|
|
|
|
|
|
|
|
entry = gimp_ui_manager_entry_ensure (GIMP_UI_MANAGER (manager), path);
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
{
|
|
|
|
if (! strcmp (entry->ui_path, path))
|
|
|
|
return entry->widget;
|
|
|
|
|
|
|
|
return GTK_UI_MANAGER_CLASS (parent_class)->get_widget (manager, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkAction *
|
2019-07-02 03:54:38 +02:00
|
|
|
gimp_ui_manager_get_action_impl (GtkUIManager *manager,
|
|
|
|
const gchar *path)
|
2005-02-08 20:55:00 +00:00
|
|
|
{
|
|
|
|
if (gimp_ui_manager_entry_ensure (GIMP_UI_MANAGER (manager), path))
|
|
|
|
return GTK_UI_MANAGER_CLASS (parent_class)->get_action (manager, path);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-04-30 15:29:11 +00:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_real_update (GimpUIManager *manager,
|
|
|
|
gpointer update_data)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
for (list = gimp_ui_manager_get_action_groups (manager);
|
2004-04-30 15:29:11 +00:00
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
|
|
|
{
|
|
|
|
gimp_action_group_update (list->data, update_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
/**
|
|
|
|
* gimp_ui_manager_new:
|
|
|
|
* @gimp: the @Gimp instance this ui manager belongs to
|
2004-05-24 14:51:15 +00:00
|
|
|
* @name: the UI manager's name.
|
2004-04-21 16:33:17 +00:00
|
|
|
*
|
|
|
|
* Creates a new #GimpUIManager object.
|
|
|
|
*
|
|
|
|
* Returns: the new #GimpUIManager
|
|
|
|
*/
|
|
|
|
GimpUIManager *
|
2004-04-27 12:28:27 +00:00
|
|
|
gimp_ui_manager_new (Gimp *gimp,
|
|
|
|
const gchar *name)
|
2004-04-21 16:33:17 +00:00
|
|
|
{
|
|
|
|
GimpUIManager *manager;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
|
|
|
|
|
|
manager = g_object_new (GIMP_TYPE_UI_MANAGER,
|
2004-04-27 12:28:27 +00:00
|
|
|
"name", name,
|
2004-04-21 16:33:17 +00:00
|
|
|
"gimp", gimp,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
return manager;
|
|
|
|
}
|
|
|
|
|
2004-04-27 12:28:27 +00:00
|
|
|
GList *
|
|
|
|
gimp_ui_managers_from_name (const gchar *name)
|
|
|
|
{
|
|
|
|
GimpUIManagerClass *manager_class;
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
|
|
|
|
manager_class = g_type_class_ref (GIMP_TYPE_UI_MANAGER);
|
|
|
|
|
|
|
|
list = g_hash_table_lookup (manager_class->managers, name);
|
|
|
|
|
|
|
|
g_type_class_unref (manager_class);
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
void
|
|
|
|
gimp_ui_manager_update (GimpUIManager *manager,
|
|
|
|
gpointer update_data)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_UI_MANAGER (manager));
|
|
|
|
|
2004-04-30 15:29:11 +00:00
|
|
|
g_signal_emit (manager, manager_signals[UPDATE], 0, update_data);
|
2004-04-29 12:52:29 +00:00
|
|
|
}
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
void
|
|
|
|
gimp_ui_manager_insert_action_group (GimpUIManager *manager,
|
|
|
|
GimpActionGroup *group,
|
|
|
|
gint pos)
|
|
|
|
{
|
|
|
|
gtk_ui_manager_insert_action_group ((GtkUIManager *) manager,
|
|
|
|
(GtkActionGroup *) group,
|
|
|
|
pos);
|
|
|
|
}
|
|
|
|
|
2004-04-29 12:52:29 +00:00
|
|
|
GimpActionGroup *
|
2005-02-08 20:55:00 +00:00
|
|
|
gimp_ui_manager_get_action_group (GimpUIManager *manager,
|
|
|
|
const gchar *name)
|
2004-04-29 12:52:29 +00:00
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_UI_MANAGER (manager), NULL);
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
for (list = gimp_ui_manager_get_action_groups (manager);
|
2005-02-08 20:55:00 +00:00
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
2004-04-21 16:33:17 +00:00
|
|
|
{
|
2004-04-29 12:52:29 +00:00
|
|
|
GimpActionGroup *group = list->data;
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
if (! strcmp (name, gimp_action_group_get_name (group)))
|
2004-04-29 12:52:29 +00:00
|
|
|
return group;
|
2004-04-21 16:33:17 +00:00
|
|
|
}
|
2004-04-29 12:52:29 +00:00
|
|
|
|
|
|
|
return NULL;
|
2004-04-21 16:33:17 +00:00
|
|
|
}
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
GList *
|
|
|
|
gimp_ui_manager_get_action_groups (GimpUIManager *manager)
|
|
|
|
{
|
|
|
|
return gtk_ui_manager_get_action_groups ((GtkUIManager *) manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkAccelGroup *
|
|
|
|
gimp_ui_manager_get_accel_group (GimpUIManager *manager)
|
|
|
|
{
|
|
|
|
return gtk_ui_manager_get_accel_group ((GtkUIManager *) manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkWidget *
|
|
|
|
gimp_ui_manager_get_widget (GimpUIManager *manager,
|
|
|
|
const gchar *path)
|
|
|
|
{
|
|
|
|
return gtk_ui_manager_get_widget ((GtkUIManager *) manager, path);
|
|
|
|
}
|
|
|
|
|
2023-02-22 17:07:32 +01:00
|
|
|
GMenuModel *
|
|
|
|
gimp_ui_manager_get_model (GimpUIManager *manager,
|
|
|
|
const gchar *path)
|
|
|
|
{
|
|
|
|
GimpUIManagerUIEntry *entry;
|
|
|
|
GMenuModel *model;
|
|
|
|
gchar *filename;
|
|
|
|
gchar *full_basename;
|
|
|
|
|
|
|
|
entry = gimp_ui_manager_entry_ensure (manager, path);
|
|
|
|
full_basename = g_strconcat (entry->basename, ".ui", NULL);
|
|
|
|
filename = g_build_filename (gimp_data_directory (), "menus",
|
|
|
|
full_basename, NULL);
|
|
|
|
|
|
|
|
if (entry->builder == NULL)
|
2023-02-22 19:58:43 +01:00
|
|
|
{
|
|
|
|
/* The model is owned by the builder which I have to keep around. */
|
|
|
|
entry->builder = gtk_builder_new_from_file (filename);
|
|
|
|
|
|
|
|
gimp_ui_manager_fill_model (manager,
|
|
|
|
G_MENU_MODEL (gtk_builder_get_object (entry->builder, path)));
|
|
|
|
}
|
2023-02-22 17:07:32 +01:00
|
|
|
|
|
|
|
model = G_MENU_MODEL (gtk_builder_get_object (entry->builder, path));
|
|
|
|
g_free (filename);
|
|
|
|
g_free (full_basename);
|
|
|
|
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
gchar *
|
|
|
|
gimp_ui_manager_get_ui (GimpUIManager *manager)
|
|
|
|
{
|
|
|
|
return gtk_ui_manager_get_ui ((GtkUIManager *) manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
guint
|
|
|
|
gimp_ui_manager_new_merge_id (GimpUIManager *manager)
|
|
|
|
{
|
|
|
|
return gtk_ui_manager_new_merge_id ((GtkUIManager *) manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_ui_manager_add_ui (GimpUIManager *manager,
|
|
|
|
guint merge_id,
|
|
|
|
const gchar *path,
|
|
|
|
const gchar *name,
|
|
|
|
const gchar *action,
|
|
|
|
GtkUIManagerItemType type,
|
|
|
|
gboolean top)
|
|
|
|
{
|
|
|
|
gtk_ui_manager_add_ui ((GtkUIManager *) manager, merge_id,
|
|
|
|
path, name, action, type, top);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_ui_manager_remove_ui (GimpUIManager *manager,
|
|
|
|
guint merge_id)
|
|
|
|
{
|
|
|
|
gtk_ui_manager_remove_ui ((GtkUIManager *) manager, merge_id);
|
|
|
|
}
|
|
|
|
|
2023-02-08 23:11:43 +01:00
|
|
|
void
|
|
|
|
gimp_ui_manager_add_ui2 (GimpUIManager *manager,
|
|
|
|
const gchar *path,
|
|
|
|
const gchar *action_name,
|
2023-02-10 12:57:29 +01:00
|
|
|
const gchar *placeholder,
|
2023-02-08 23:11:43 +01:00
|
|
|
gboolean top)
|
|
|
|
{
|
|
|
|
GimpUIManagerMenuItem *item;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_UI_MANAGER (manager));
|
|
|
|
g_return_if_fail (path != NULL);
|
|
|
|
g_return_if_fail (action_name != NULL);
|
|
|
|
|
|
|
|
item = g_slice_new0 (GimpUIManagerMenuItem);
|
|
|
|
item->path = g_strdup (path);
|
|
|
|
item->action_name = g_strdup (action_name);
|
2023-02-10 12:57:29 +01:00
|
|
|
item->placeholder = placeholder ? g_strdup (placeholder) : NULL;
|
2023-02-08 23:11:43 +01:00
|
|
|
item->top = top;
|
|
|
|
manager->ui_items = g_list_prepend (manager->ui_items, item);
|
|
|
|
|
2023-02-10 12:57:29 +01:00
|
|
|
g_signal_emit (manager, manager_signals[UI_ADDED], 0, path, action_name, placeholder, top);
|
2023-02-08 23:11:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_ui_manager_foreach_ui (GimpUIManager *manager,
|
|
|
|
GimpUIMenuCallback callback,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
for (GList *iter = g_list_last (manager->ui_items); iter; iter = iter->prev)
|
|
|
|
{
|
|
|
|
GimpUIManagerMenuItem *item = iter->data;
|
|
|
|
|
2023-02-10 12:57:29 +01:00
|
|
|
callback (manager, item->path, item->action_name, item->placeholder, item->top, user_data);
|
2023-02-08 23:11:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
void
|
|
|
|
gimp_ui_manager_ensure_update (GimpUIManager *manager)
|
|
|
|
{
|
|
|
|
gtk_ui_manager_ensure_update ((GtkUIManager *) manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpAction *
|
|
|
|
gimp_ui_manager_get_action (GimpUIManager *manager,
|
|
|
|
const gchar *path)
|
|
|
|
{
|
|
|
|
return (GimpAction *) gtk_ui_manager_get_action ((GtkUIManager *) manager,
|
|
|
|
path);
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpAction *
|
2004-12-08 13:52:28 +00:00
|
|
|
gimp_ui_manager_find_action (GimpUIManager *manager,
|
|
|
|
const gchar *group_name,
|
|
|
|
const gchar *action_name)
|
2004-10-16 17:29:42 +00:00
|
|
|
{
|
|
|
|
GimpActionGroup *group;
|
2019-07-02 03:54:38 +02:00
|
|
|
GimpAction *action = NULL;
|
2004-10-16 17:29:42 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_UI_MANAGER (manager), NULL);
|
|
|
|
g_return_val_if_fail (action_name != NULL, NULL);
|
|
|
|
|
2005-05-11 21:15:16 +00:00
|
|
|
if (group_name)
|
|
|
|
{
|
|
|
|
group = gimp_ui_manager_get_action_group (manager, group_name);
|
2004-10-16 17:29:42 +00:00
|
|
|
|
2005-05-11 21:15:16 +00:00
|
|
|
if (group)
|
2019-07-02 03:54:38 +02:00
|
|
|
action = gimp_action_group_get_action (group, action_name);
|
2005-05-11 21:15:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GList *list;
|
2004-10-16 17:29:42 +00:00
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
for (list = gimp_ui_manager_get_action_groups (manager);
|
2005-05-11 21:15:16 +00:00
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
|
|
|
{
|
|
|
|
group = list->data;
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
action = gimp_action_group_get_action (group, action_name);
|
2005-05-11 21:15:16 +00:00
|
|
|
|
|
|
|
if (action)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return action;
|
2004-10-16 17:29:42 +00:00
|
|
|
}
|
|
|
|
|
2006-12-15 12:03:47 +00:00
|
|
|
gboolean
|
|
|
|
gimp_ui_manager_activate_action (GimpUIManager *manager,
|
|
|
|
const gchar *group_name,
|
|
|
|
const gchar *action_name)
|
|
|
|
{
|
2019-07-02 03:54:38 +02:00
|
|
|
GimpAction *action;
|
2006-12-15 12:03:47 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_UI_MANAGER (manager), FALSE);
|
|
|
|
g_return_val_if_fail (action_name != NULL, FALSE);
|
|
|
|
|
|
|
|
action = gimp_ui_manager_find_action (manager, group_name, action_name);
|
|
|
|
|
|
|
|
if (action)
|
2019-07-02 03:54:38 +02:00
|
|
|
gimp_action_activate (action);
|
2006-12-15 12:03:47 +00:00
|
|
|
|
|
|
|
return (action != NULL);
|
|
|
|
}
|
|
|
|
|
2016-10-01 01:06:02 +02:00
|
|
|
gboolean
|
|
|
|
gimp_ui_manager_toggle_action (GimpUIManager *manager,
|
|
|
|
const gchar *group_name,
|
|
|
|
const gchar *action_name,
|
|
|
|
gboolean active)
|
|
|
|
{
|
2019-07-02 03:54:38 +02:00
|
|
|
GimpAction *action;
|
2016-10-01 01:06:02 +02:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_UI_MANAGER (manager), FALSE);
|
|
|
|
g_return_val_if_fail (action_name != NULL, FALSE);
|
|
|
|
|
|
|
|
action = gimp_ui_manager_find_action (manager, group_name, action_name);
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
if (GIMP_IS_TOGGLE_ACTION (action))
|
|
|
|
gimp_toggle_action_set_active (GIMP_TOGGLE_ACTION (action),
|
|
|
|
active ? TRUE : FALSE);
|
2016-10-01 01:06:02 +02:00
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
return GIMP_IS_TOGGLE_ACTION (action);
|
2016-10-01 01:06:02 +02:00
|
|
|
}
|
2006-12-15 12:03:47 +00:00
|
|
|
|
2004-04-21 16:33:17 +00:00
|
|
|
void
|
2004-04-26 15:51:21 +00:00
|
|
|
gimp_ui_manager_ui_register (GimpUIManager *manager,
|
|
|
|
const gchar *ui_path,
|
|
|
|
const gchar *basename,
|
|
|
|
GimpUIManagerSetupFunc setup_func)
|
2004-04-21 16:33:17 +00:00
|
|
|
{
|
|
|
|
GimpUIManagerUIEntry *entry;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_UI_MANAGER (manager));
|
2004-04-26 15:51:21 +00:00
|
|
|
g_return_if_fail (ui_path != NULL);
|
2004-04-21 16:33:17 +00:00
|
|
|
g_return_if_fail (basename != NULL);
|
2004-05-17 13:38:03 +00:00
|
|
|
g_return_if_fail (gimp_ui_manager_entry_get (manager, ui_path) == NULL);
|
2004-04-21 16:33:17 +00:00
|
|
|
|
2007-05-22 15:14:41 +00:00
|
|
|
entry = g_slice_new0 (GimpUIManagerUIEntry);
|
2004-04-21 16:33:17 +00:00
|
|
|
|
2004-04-26 15:51:21 +00:00
|
|
|
entry->ui_path = g_strdup (ui_path);
|
2004-04-21 16:33:17 +00:00
|
|
|
entry->basename = g_strdup (basename);
|
2004-04-26 15:51:21 +00:00
|
|
|
entry->setup_func = setup_func;
|
2004-04-22 17:14:22 +00:00
|
|
|
entry->merge_id = 0;
|
|
|
|
entry->widget = NULL;
|
2023-02-22 17:07:32 +01:00
|
|
|
entry->builder = NULL;
|
2004-04-21 16:33:17 +00:00
|
|
|
|
|
|
|
manager->registered_uis = g_list_prepend (manager->registered_uis, entry);
|
|
|
|
}
|
|
|
|
|
2018-05-02 00:44:38 +02:00
|
|
|
void
|
|
|
|
gimp_ui_manager_ui_popup_at_widget (GimpUIManager *manager,
|
|
|
|
const gchar *ui_path,
|
2023-02-27 18:49:45 +01:00
|
|
|
GimpUIManager *child_ui_manager,
|
|
|
|
const gchar *child_ui_path,
|
2018-05-02 00:44:38 +02:00
|
|
|
GtkWidget *widget,
|
|
|
|
GdkGravity widget_anchor,
|
|
|
|
GdkGravity menu_anchor,
|
|
|
|
const GdkEvent *trigger_event,
|
|
|
|
GDestroyNotify popdown_func,
|
|
|
|
gpointer popdown_data)
|
|
|
|
{
|
2023-02-22 19:58:43 +01:00
|
|
|
GMenuModel *model;
|
|
|
|
GtkWidget *menu;
|
2018-05-02 00:44:38 +02:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_UI_MANAGER (manager));
|
|
|
|
g_return_if_fail (ui_path != NULL);
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
|
2023-02-22 19:58:43 +01:00
|
|
|
model = gimp_ui_manager_get_model (manager, ui_path);
|
2023-02-23 19:05:58 +01:00
|
|
|
menu = gimp_menu_new (manager);
|
2023-02-22 19:58:43 +01:00
|
|
|
gtk_menu_attach_to_widget (GTK_MENU (menu), widget, NULL);
|
2023-02-23 19:05:58 +01:00
|
|
|
gimp_menu_shell_fill (GIMP_MENU_SHELL (menu), model, NULL);
|
2018-05-02 00:44:38 +02:00
|
|
|
|
|
|
|
if (! menu)
|
|
|
|
return;
|
|
|
|
|
2023-02-27 18:49:45 +01:00
|
|
|
if (child_ui_manager != NULL && child_ui_path != NULL)
|
|
|
|
{
|
|
|
|
GMenuModel *child_model;
|
|
|
|
GtkWidget *child_menu;
|
|
|
|
|
|
|
|
/* TODO GMenu: the "icon" attribute set in the .ui file should be visible. */
|
|
|
|
child_model = gimp_ui_manager_get_model (child_ui_manager, child_ui_path);
|
|
|
|
child_menu = gimp_menu_new (child_ui_manager);
|
|
|
|
gimp_menu_shell_fill (GIMP_MENU_SHELL (child_menu), child_model, NULL);
|
|
|
|
|
|
|
|
gimp_menu_shell_merge (GIMP_MENU_SHELL (menu), GIMP_MENU_SHELL (child_menu), TRUE);
|
|
|
|
}
|
|
|
|
|
2018-05-02 00:44:38 +02:00
|
|
|
if (popdown_func && popdown_data)
|
|
|
|
{
|
|
|
|
g_object_set_data_full (G_OBJECT (manager), "popdown-data",
|
|
|
|
popdown_data, popdown_func);
|
|
|
|
g_signal_connect (menu, "selection-done",
|
|
|
|
G_CALLBACK (gimp_ui_manager_delete_popdown_data),
|
|
|
|
manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_menu_popup_at_widget (GTK_MENU (menu), widget,
|
|
|
|
widget_anchor,
|
|
|
|
menu_anchor,
|
|
|
|
trigger_event);
|
|
|
|
}
|
|
|
|
|
2018-05-02 12:19:32 +02:00
|
|
|
void
|
|
|
|
gimp_ui_manager_ui_popup_at_pointer (GimpUIManager *manager,
|
|
|
|
const gchar *ui_path,
|
2023-02-22 19:58:43 +01:00
|
|
|
GtkWidget *attached_widget,
|
2018-05-02 12:19:32 +02:00
|
|
|
const GdkEvent *trigger_event,
|
|
|
|
GDestroyNotify popdown_func,
|
|
|
|
gpointer popdown_data)
|
|
|
|
{
|
2023-02-22 19:58:43 +01:00
|
|
|
GMenuModel *model;
|
|
|
|
GtkWidget *menu;
|
2018-05-02 12:19:32 +02:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_UI_MANAGER (manager));
|
|
|
|
g_return_if_fail (ui_path != NULL);
|
|
|
|
|
2023-02-22 19:58:43 +01:00
|
|
|
model = gimp_ui_manager_get_model (manager, ui_path);
|
2023-02-23 19:05:58 +01:00
|
|
|
menu = gimp_menu_new (manager);
|
2023-02-22 19:58:43 +01:00
|
|
|
gtk_menu_attach_to_widget (GTK_MENU (menu), attached_widget, NULL);
|
2023-02-23 19:05:58 +01:00
|
|
|
gimp_menu_shell_fill (GIMP_MENU_SHELL (menu), model, NULL);
|
2018-05-02 12:19:32 +02:00
|
|
|
|
|
|
|
if (! menu)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (popdown_func && popdown_data)
|
|
|
|
{
|
|
|
|
g_object_set_data_full (G_OBJECT (manager), "popdown-data",
|
|
|
|
popdown_data, popdown_func);
|
|
|
|
g_signal_connect (menu, "selection-done",
|
|
|
|
G_CALLBACK (gimp_ui_manager_delete_popdown_data),
|
|
|
|
manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_menu_popup_at_pointer (GTK_MENU (menu), trigger_event);
|
|
|
|
}
|
|
|
|
|
2021-12-08 00:09:08 +01:00
|
|
|
void
|
|
|
|
gimp_ui_manager_ui_popup_at_rect (GimpUIManager *manager,
|
|
|
|
const gchar *ui_path,
|
2023-02-22 19:58:43 +01:00
|
|
|
GtkWidget *attached_widget,
|
2021-12-08 00:09:08 +01:00
|
|
|
GdkWindow *window,
|
|
|
|
const GdkRectangle *rect,
|
|
|
|
GdkGravity rect_anchor,
|
|
|
|
GdkGravity menu_anchor,
|
|
|
|
const GdkEvent *trigger_event,
|
|
|
|
GDestroyNotify popdown_func,
|
|
|
|
gpointer popdown_data)
|
|
|
|
{
|
2023-02-22 19:58:43 +01:00
|
|
|
GMenuModel *model;
|
|
|
|
GtkWidget *menu;
|
2021-12-08 00:09:08 +01:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_UI_MANAGER (manager));
|
|
|
|
g_return_if_fail (ui_path != NULL);
|
|
|
|
|
2023-02-22 19:58:43 +01:00
|
|
|
model = gimp_ui_manager_get_model (manager, ui_path);
|
2023-02-23 19:05:58 +01:00
|
|
|
menu = gimp_menu_new (manager);
|
2023-02-22 19:58:43 +01:00
|
|
|
gtk_menu_attach_to_widget (GTK_MENU (menu), attached_widget, NULL);
|
2023-02-23 19:05:58 +01:00
|
|
|
gimp_menu_shell_fill (GIMP_MENU_SHELL (menu), model, NULL);
|
2021-12-08 00:09:08 +01:00
|
|
|
|
|
|
|
if (! menu)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (popdown_func && popdown_data)
|
|
|
|
{
|
|
|
|
g_object_set_data_full (G_OBJECT (manager), "popdown-data",
|
|
|
|
popdown_data, popdown_func);
|
|
|
|
g_signal_connect (menu, "selection-done",
|
|
|
|
G_CALLBACK (gimp_ui_manager_delete_popdown_data),
|
|
|
|
manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_menu_popup_at_rect (GTK_MENU (menu), window,
|
|
|
|
rect, rect_anchor, menu_anchor,
|
|
|
|
trigger_event);
|
|
|
|
}
|
|
|
|
|
2004-04-30 15:29:11 +00:00
|
|
|
|
2004-05-17 13:38:03 +00:00
|
|
|
/* private functions */
|
2004-04-22 17:14:22 +00:00
|
|
|
|
2004-05-17 13:38:03 +00:00
|
|
|
static GimpUIManagerUIEntry *
|
|
|
|
gimp_ui_manager_entry_get (GimpUIManager *manager,
|
|
|
|
const gchar *ui_path)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
gchar *path;
|
2004-04-26 15:51:21 +00:00
|
|
|
|
2004-05-17 13:38:03 +00:00
|
|
|
path = g_strdup (ui_path);
|
2004-04-22 17:14:22 +00:00
|
|
|
|
2004-05-17 13:38:03 +00:00
|
|
|
if (strlen (path) > 1)
|
|
|
|
{
|
|
|
|
gchar *p = strchr (path + 1, '/');
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
*p = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
for (list = manager->registered_uis; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpUIManagerUIEntry *entry = list->data;
|
|
|
|
|
|
|
|
if (! strcmp (entry->ui_path, path))
|
|
|
|
{
|
|
|
|
g_free (path);
|
|
|
|
|
|
|
|
return entry;
|
2004-04-21 16:33:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-17 13:38:03 +00:00
|
|
|
g_free (path);
|
2004-04-21 16:33:17 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-04-22 17:14:22 +00:00
|
|
|
|
2004-05-17 13:38:03 +00:00
|
|
|
static gboolean
|
|
|
|
gimp_ui_manager_entry_load (GimpUIManager *manager,
|
|
|
|
GimpUIManagerUIEntry *entry,
|
|
|
|
GError **error)
|
|
|
|
{
|
2018-07-01 18:49:50 +02:00
|
|
|
gchar *filename = NULL;
|
2023-02-22 17:07:32 +01:00
|
|
|
gchar *full_basename;
|
2018-07-01 18:49:50 +02:00
|
|
|
const gchar *menus_path_override = g_getenv ("GIMP_TESTING_MENUS_PATH");
|
2010-01-08 15:04:35 +01:00
|
|
|
|
2023-02-22 17:07:32 +01:00
|
|
|
full_basename = g_strconcat (entry->basename, ".xml", NULL);
|
2010-01-08 15:04:35 +01:00
|
|
|
/* In order for test cases to be able to run without GIMP being
|
|
|
|
* installed yet, allow them to override the menus directory to the
|
|
|
|
* menus dir in the source root
|
|
|
|
*/
|
2018-07-01 18:49:50 +02:00
|
|
|
if (menus_path_override)
|
|
|
|
{
|
|
|
|
GList *path = gimp_path_parse (menus_path_override, 2, FALSE, NULL);
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
for (list = path; list; list = g_list_next (list))
|
|
|
|
{
|
2023-02-22 17:07:32 +01:00
|
|
|
filename = g_build_filename (list->data, full_basename, NULL);
|
2018-07-01 18:49:50 +02:00
|
|
|
|
|
|
|
if (! list->next ||
|
|
|
|
g_file_test (filename, G_FILE_TEST_EXISTS))
|
|
|
|
break;
|
|
|
|
|
|
|
|
g_free (filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free_full (path, g_free);
|
|
|
|
}
|
2010-01-08 15:04:35 +01:00
|
|
|
else
|
2018-07-01 18:49:50 +02:00
|
|
|
{
|
|
|
|
filename = g_build_filename (gimp_data_directory (), "menus",
|
2023-02-22 17:07:32 +01:00
|
|
|
full_basename, NULL);
|
2018-07-01 18:49:50 +02:00
|
|
|
}
|
2004-05-17 13:38:03 +00:00
|
|
|
|
2004-10-29 21:54:32 +00:00
|
|
|
if (manager->gimp->be_verbose)
|
|
|
|
g_print ("loading menu '%s' for %s\n",
|
|
|
|
gimp_filename_to_utf8 (filename), entry->ui_path);
|
2004-05-17 13:38:03 +00:00
|
|
|
|
|
|
|
entry->merge_id = gtk_ui_manager_add_ui_from_file (GTK_UI_MANAGER (manager),
|
|
|
|
filename, error);
|
|
|
|
|
|
|
|
g_free (filename);
|
2023-02-22 17:07:32 +01:00
|
|
|
g_free (full_basename);
|
2004-05-17 13:38:03 +00:00
|
|
|
|
|
|
|
if (! entry->merge_id)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2005-02-08 20:55:00 +00:00
|
|
|
static GimpUIManagerUIEntry *
|
|
|
|
gimp_ui_manager_entry_ensure (GimpUIManager *manager,
|
|
|
|
const gchar *path)
|
|
|
|
{
|
|
|
|
GimpUIManagerUIEntry *entry;
|
|
|
|
|
|
|
|
entry = gimp_ui_manager_entry_get (manager, path);
|
|
|
|
|
|
|
|
if (! entry)
|
|
|
|
{
|
|
|
|
g_warning ("%s: no entry registered for \"%s\"", G_STRFUNC, path);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! entry->merge_id)
|
|
|
|
{
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (! gimp_ui_manager_entry_load (manager, entry, &error))
|
|
|
|
{
|
2005-05-21 14:13:33 +00:00
|
|
|
if (error->domain == G_FILE_ERROR &&
|
|
|
|
error->code == G_FILE_ERROR_EXIST)
|
|
|
|
{
|
2006-10-09 18:49:15 +00:00
|
|
|
gimp_message (manager->gimp, NULL, GIMP_MESSAGE_ERROR,
|
|
|
|
"%s\n\n%s\n\n%s",
|
|
|
|
_("Your GIMP installation is incomplete:"),
|
|
|
|
error->message,
|
2009-01-21 21:52:15 +00:00
|
|
|
_("Please make sure the menu XML files are "
|
|
|
|
"correctly installed."));
|
2005-05-21 14:13:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-02-22 17:07:32 +01:00
|
|
|
gchar *full_basename = g_strconcat (entry->basename, ".xml", NULL);
|
|
|
|
|
2006-10-09 18:49:15 +00:00
|
|
|
gimp_message (manager->gimp, NULL, GIMP_MESSAGE_ERROR,
|
|
|
|
_("There was an error parsing the menu definition "
|
|
|
|
"from %s: %s"),
|
2023-02-22 17:07:32 +01:00
|
|
|
gimp_filename_to_utf8 (full_basename),
|
2006-10-09 18:49:15 +00:00
|
|
|
error->message);
|
2023-02-22 17:07:32 +01:00
|
|
|
g_free (full_basename);
|
2005-05-21 14:13:33 +00:00
|
|
|
}
|
|
|
|
|
2005-02-08 20:55:00 +00:00
|
|
|
g_clear_error (&error);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! entry->widget)
|
|
|
|
{
|
|
|
|
GtkUIManager *gtk_manager = GTK_UI_MANAGER (manager);
|
|
|
|
|
|
|
|
entry->widget =
|
|
|
|
GTK_UI_MANAGER_CLASS (parent_class)->get_widget (gtk_manager,
|
|
|
|
entry->ui_path);
|
|
|
|
|
|
|
|
if (entry->widget)
|
|
|
|
{
|
|
|
|
g_object_ref (entry->widget);
|
|
|
|
|
|
|
|
/* take ownership of popup menus */
|
|
|
|
if (GTK_IS_MENU (entry->widget))
|
2006-07-05 13:40:47 +00:00
|
|
|
{
|
|
|
|
g_object_ref_sink (entry->widget);
|
|
|
|
g_object_unref (entry->widget);
|
|
|
|
}
|
2005-02-08 20:55:00 +00:00
|
|
|
|
|
|
|
if (entry->setup_func)
|
|
|
|
entry->setup_func (manager, entry->ui_path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-02-22 17:07:32 +01:00
|
|
|
gchar *full_basename = g_strconcat (entry->basename, ".xml", NULL);
|
|
|
|
|
2005-02-08 20:55:00 +00:00
|
|
|
g_warning ("%s: \"%s\" does not contain registered toplevel "
|
|
|
|
"widget \"%s\"",
|
2023-02-22 17:07:32 +01:00
|
|
|
G_STRFUNC, full_basename, entry->ui_path);
|
|
|
|
g_free (full_basename);
|
2005-02-08 20:55:00 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2004-04-22 17:14:22 +00:00
|
|
|
static void
|
2014-07-21 02:34:39 +02:00
|
|
|
gimp_ui_manager_delete_popdown_data (GtkWidget *widget,
|
2004-05-17 13:38:03 +00:00
|
|
|
GimpUIManager *manager)
|
2004-04-22 17:14:22 +00:00
|
|
|
{
|
2014-07-21 02:34:39 +02:00
|
|
|
g_signal_handlers_disconnect_by_func (widget,
|
2004-05-17 13:38:03 +00:00
|
|
|
gimp_ui_manager_delete_popdown_data,
|
2004-04-22 17:14:22 +00:00
|
|
|
manager);
|
2004-05-17 13:38:03 +00:00
|
|
|
g_object_set_data (G_OBJECT (manager), "popdown-data", NULL);
|
2004-04-22 17:14:22 +00:00
|
|
|
}
|
|
|
|
|
2004-05-09 23:28:37 +00:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_item_realize (GtkWidget *widget,
|
|
|
|
GimpUIManager *manager)
|
|
|
|
{
|
2008-06-28 15:50:27 +00:00
|
|
|
GtkWidget *menu;
|
2004-05-09 23:28:37 +00:00
|
|
|
GtkWidget *submenu;
|
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_func (widget,
|
|
|
|
gimp_ui_manager_item_realize,
|
|
|
|
manager);
|
|
|
|
|
2008-06-28 15:50:27 +00:00
|
|
|
menu = gtk_widget_get_parent (widget);
|
|
|
|
|
|
|
|
if (GTK_IS_MENU_SHELL (menu))
|
2004-05-09 23:28:37 +00:00
|
|
|
{
|
|
|
|
static GQuark quark_key_press_connected = 0;
|
|
|
|
|
|
|
|
if (! quark_key_press_connected)
|
|
|
|
quark_key_press_connected =
|
|
|
|
g_quark_from_static_string ("gimp-menu-item-key-press-connected");
|
|
|
|
|
2008-06-28 15:50:27 +00:00
|
|
|
if (! GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (menu),
|
2004-05-09 23:28:37 +00:00
|
|
|
quark_key_press_connected)))
|
|
|
|
{
|
2008-06-28 15:50:27 +00:00
|
|
|
g_signal_connect (menu, "key-press-event",
|
2004-05-09 23:28:37 +00:00
|
|
|
G_CALLBACK (gimp_ui_manager_item_key_press),
|
|
|
|
manager);
|
|
|
|
|
2008-06-28 15:50:27 +00:00
|
|
|
g_object_set_qdata (G_OBJECT (menu),
|
2004-05-09 23:28:37 +00:00
|
|
|
quark_key_press_connected,
|
|
|
|
GINT_TO_POINTER (TRUE));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
|
|
|
|
|
|
|
|
if (submenu)
|
|
|
|
g_object_set_qdata (G_OBJECT (submenu), GIMP_HELP_ID,
|
|
|
|
g_object_get_qdata (G_OBJECT (widget),
|
|
|
|
GIMP_HELP_ID));
|
|
|
|
}
|
|
|
|
|
2006-03-10 10:05:38 +00:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_menu_item_select (GtkWidget *widget,
|
|
|
|
GimpUIManager *manager)
|
2006-03-09 15:26:33 +00:00
|
|
|
{
|
2009-05-24 10:38:09 -07:00
|
|
|
GtkAction *action =
|
|
|
|
gtk_activatable_get_related_action (GTK_ACTIVATABLE (widget));
|
2006-03-09 15:26:33 +00:00
|
|
|
|
|
|
|
if (action)
|
|
|
|
{
|
2019-07-02 03:54:38 +02:00
|
|
|
const gchar *tooltip = gimp_action_get_tooltip (GIMP_ACTION (action));
|
2006-03-09 15:26:33 +00:00
|
|
|
|
|
|
|
if (tooltip)
|
2009-05-24 22:29:18 +02:00
|
|
|
g_signal_emit (manager, manager_signals[SHOW_TOOLTIP], 0, tooltip);
|
2006-03-09 15:26:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-10 10:05:38 +00:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_menu_item_deselect (GtkWidget *widget,
|
|
|
|
GimpUIManager *manager)
|
2006-03-09 15:26:33 +00:00
|
|
|
{
|
|
|
|
g_signal_emit (manager, manager_signals[HIDE_TOOLTIP], 0);
|
|
|
|
}
|
|
|
|
|
2004-05-09 23:28:37 +00:00
|
|
|
static gboolean
|
|
|
|
gimp_ui_manager_item_key_press (GtkWidget *widget,
|
|
|
|
GdkEventKey *kevent,
|
|
|
|
GimpUIManager *manager)
|
|
|
|
{
|
|
|
|
gchar *help_id = NULL;
|
|
|
|
|
2020-01-29 21:52:17 +02:00
|
|
|
while (! help_id && GTK_IS_MENU_SHELL (widget))
|
2004-05-09 23:28:37 +00:00
|
|
|
{
|
2010-12-29 15:41:39 +01:00
|
|
|
GtkWidget *menu_item;
|
|
|
|
|
|
|
|
menu_item = gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (widget));
|
2004-05-09 23:28:37 +00:00
|
|
|
|
2008-08-27 19:36:41 +00:00
|
|
|
if (! menu_item && GTK_IS_MENU (widget))
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
2010-02-11 10:34:48 +01:00
|
|
|
GtkWidget *parent = gtk_widget_get_parent (widget);
|
|
|
|
GdkWindow *window = gtk_widget_get_window (parent);
|
2008-08-20 18:20:42 +00:00
|
|
|
|
2020-01-03 21:26:21 +01:00
|
|
|
if (window)
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
2020-01-03 21:26:21 +01:00
|
|
|
gint x, y;
|
|
|
|
|
|
|
|
gdk_window_get_pointer (window, &x, &y, NULL);
|
|
|
|
menu_item = find_widget_under_pointer (window, &x, &y);
|
|
|
|
|
|
|
|
if (menu_item && ! GTK_IS_MENU_ITEM (menu_item))
|
|
|
|
{
|
|
|
|
menu_item = gtk_widget_get_ancestor (menu_item,
|
|
|
|
GTK_TYPE_MENU_ITEM);
|
2008-08-20 18:20:42 +00:00
|
|
|
|
2020-01-03 21:26:21 +01:00
|
|
|
if (! GTK_IS_MENU_ITEM (menu_item))
|
|
|
|
menu_item = NULL;
|
|
|
|
}
|
2008-08-20 18:20:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-09 23:28:37 +00:00
|
|
|
/* first, get the help page from the item...
|
|
|
|
*/
|
|
|
|
if (menu_item)
|
|
|
|
{
|
|
|
|
help_id = g_object_get_qdata (G_OBJECT (menu_item), GIMP_HELP_ID);
|
|
|
|
|
|
|
|
if (help_id && ! strlen (help_id))
|
|
|
|
help_id = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ...then try the parent menu...
|
|
|
|
*/
|
|
|
|
if (! help_id)
|
|
|
|
{
|
|
|
|
help_id = g_object_get_qdata (G_OBJECT (widget), GIMP_HELP_ID);
|
|
|
|
|
|
|
|
if (help_id && ! strlen (help_id))
|
|
|
|
help_id = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ...finally try the menu's parent (if any)
|
|
|
|
*/
|
|
|
|
if (! help_id)
|
|
|
|
{
|
|
|
|
menu_item = NULL;
|
|
|
|
|
|
|
|
if (GTK_IS_MENU (widget))
|
|
|
|
menu_item = gtk_menu_get_attach_widget (GTK_MENU (widget));
|
|
|
|
|
|
|
|
if (! menu_item)
|
|
|
|
break;
|
|
|
|
|
2008-06-28 15:50:27 +00:00
|
|
|
widget = gtk_widget_get_parent (menu_item);
|
2004-05-09 23:28:37 +00:00
|
|
|
|
|
|
|
if (! widget)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For any valid accelerator key except F1, continue with the
|
|
|
|
* standard GtkMenuShell callback and assign a new shortcut, but
|
|
|
|
* don't assign a shortcut to the help menu entries ...
|
|
|
|
*/
|
2011-03-29 15:27:25 +02:00
|
|
|
if (kevent->keyval != GDK_KEY_F1)
|
2004-05-09 23:28:37 +00:00
|
|
|
{
|
|
|
|
if (help_id &&
|
|
|
|
gtk_accelerator_valid (kevent->keyval, 0) &&
|
|
|
|
(strcmp (help_id, GIMP_HELP_HELP) == 0 ||
|
|
|
|
strcmp (help_id, GIMP_HELP_HELP_CONTEXT) == 0))
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ...finally, if F1 was pressed over any menu, show its help page... */
|
|
|
|
|
|
|
|
if (help_id)
|
|
|
|
{
|
|
|
|
gchar *help_domain = NULL;
|
|
|
|
gchar *help_string = NULL;
|
|
|
|
gchar *domain_separator;
|
|
|
|
|
|
|
|
help_id = g_strdup (help_id);
|
|
|
|
|
|
|
|
domain_separator = strchr (help_id, '?');
|
|
|
|
|
|
|
|
if (domain_separator)
|
|
|
|
{
|
|
|
|
*domain_separator = '\0';
|
|
|
|
|
|
|
|
help_domain = g_strdup (help_id);
|
|
|
|
help_string = g_strdup (domain_separator + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
help_string = g_strdup (help_id);
|
|
|
|
}
|
|
|
|
|
2008-06-10 09:54:54 +00:00
|
|
|
gimp_help (manager->gimp, NULL, help_domain, help_string);
|
2004-05-09 23:28:37 +00:00
|
|
|
|
|
|
|
g_free (help_domain);
|
|
|
|
g_free (help_string);
|
|
|
|
g_free (help_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2008-08-20 18:20:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Stuff below taken from gtktooltip.c
|
|
|
|
*/
|
|
|
|
|
2009-07-20 11:53:02 +02:00
|
|
|
/* FIXME: remove this crack as soon as a GTK+ widget_under_pointer() is available */
|
2008-08-20 18:20:42 +00:00
|
|
|
|
|
|
|
struct ChildLocation
|
|
|
|
{
|
|
|
|
GtkWidget *child;
|
|
|
|
GtkWidget *container;
|
|
|
|
|
|
|
|
gint x;
|
|
|
|
gint y;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
child_location_foreach (GtkWidget *child,
|
2009-05-28 22:52:41 +10:00
|
|
|
gpointer data)
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
|
|
|
gint x, y;
|
|
|
|
struct ChildLocation *child_loc = data;
|
|
|
|
|
|
|
|
/* Ignore invisible widgets */
|
2009-11-11 21:00:14 +01:00
|
|
|
if (! gtk_widget_is_drawable (child))
|
2008-08-20 18:20:42 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* (child_loc->x, child_loc->y) are relative to
|
|
|
|
* child_loc->container's allocation.
|
|
|
|
*/
|
|
|
|
|
2009-05-28 22:52:41 +10:00
|
|
|
if (! child_loc->child &&
|
2008-08-20 18:20:42 +00:00
|
|
|
gtk_widget_translate_coordinates (child_loc->container, child,
|
2009-05-28 22:52:41 +10:00
|
|
|
child_loc->x, child_loc->y,
|
|
|
|
&x, &y))
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
2009-11-11 21:00:14 +01:00
|
|
|
GtkAllocation child_allocation;
|
|
|
|
|
|
|
|
gtk_widget_get_allocation (child, &child_allocation);
|
|
|
|
|
2008-08-20 18:20:42 +00:00
|
|
|
#ifdef DEBUG_TOOLTIP
|
|
|
|
g_print ("candidate: %s alloc=[(%d,%d) %dx%d] (%d, %d)->(%d, %d)\n",
|
2009-05-28 22:52:41 +10:00
|
|
|
gtk_widget_get_name (child),
|
2009-11-11 21:00:14 +01:00
|
|
|
child_allocation.x,
|
|
|
|
child_allocation.y,
|
|
|
|
child_allocation.width,
|
|
|
|
child_allocation.height,
|
2009-05-28 22:52:41 +10:00
|
|
|
child_loc->x, child_loc->y,
|
|
|
|
x, y);
|
2008-08-20 18:20:42 +00:00
|
|
|
#endif /* DEBUG_TOOLTIP */
|
|
|
|
|
|
|
|
/* (x, y) relative to child's allocation. */
|
2009-11-11 21:00:14 +01:00
|
|
|
if (x >= 0 && x < child_allocation.width
|
|
|
|
&& y >= 0 && y < child_allocation.height)
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
2009-05-28 22:52:41 +10:00
|
|
|
if (GTK_IS_CONTAINER (child))
|
|
|
|
{
|
|
|
|
struct ChildLocation tmp = { NULL, NULL, 0, 0 };
|
|
|
|
|
|
|
|
/* Take (x, y) relative the child's allocation and
|
|
|
|
* recurse.
|
|
|
|
*/
|
|
|
|
tmp.x = x;
|
|
|
|
tmp.y = y;
|
|
|
|
tmp.container = child;
|
|
|
|
|
|
|
|
gtk_container_forall (GTK_CONTAINER (child),
|
|
|
|
child_location_foreach, &tmp);
|
|
|
|
|
|
|
|
if (tmp.child)
|
|
|
|
child_loc->child = tmp.child;
|
|
|
|
else
|
|
|
|
child_loc->child = child;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
child_loc->child = child;
|
|
|
|
}
|
|
|
|
}
|
2008-08-20 18:20:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Translates coordinates from dest_widget->window relative (src_x, src_y),
|
|
|
|
* to allocation relative (dest_x, dest_y) of dest_widget.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
window_to_alloc (GtkWidget *dest_widget,
|
2009-05-28 22:52:41 +10:00
|
|
|
gint src_x,
|
|
|
|
gint src_y,
|
|
|
|
gint *dest_x,
|
|
|
|
gint *dest_y)
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
2009-11-11 21:00:14 +01:00
|
|
|
GtkAllocation dest_allocation;
|
|
|
|
|
|
|
|
gtk_widget_get_allocation (dest_widget, &dest_allocation);
|
|
|
|
|
2008-08-20 18:20:42 +00:00
|
|
|
/* Translate from window relative to allocation relative */
|
2009-11-11 21:00:14 +01:00
|
|
|
if (gtk_widget_get_has_window (dest_widget) &&
|
|
|
|
gtk_widget_get_parent (dest_widget))
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
|
|
|
gint wx, wy;
|
2009-11-11 21:00:14 +01:00
|
|
|
|
2009-03-22 16:35:53 +00:00
|
|
|
gdk_window_get_position (gtk_widget_get_window (dest_widget), &wx, &wy);
|
2008-08-20 18:20:42 +00:00
|
|
|
|
|
|
|
/* Offset coordinates if widget->window is smaller than
|
|
|
|
* widget->allocation.
|
|
|
|
*/
|
2009-11-11 21:00:14 +01:00
|
|
|
src_x += wx - dest_allocation.x;
|
|
|
|
src_y += wy - dest_allocation.y;
|
2008-08-20 18:20:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-11-11 21:00:14 +01:00
|
|
|
src_x -= dest_allocation.x;
|
|
|
|
src_y -= dest_allocation.y;
|
2008-08-20 18:20:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dest_x)
|
|
|
|
*dest_x = src_x;
|
|
|
|
if (dest_y)
|
|
|
|
*dest_y = src_y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget *
|
|
|
|
find_widget_under_pointer (GdkWindow *window,
|
2009-05-28 22:52:41 +10:00
|
|
|
gint *x,
|
|
|
|
gint *y)
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
|
|
|
GtkWidget *event_widget;
|
|
|
|
struct ChildLocation child_loc = { NULL, NULL, 0, 0 };
|
|
|
|
|
|
|
|
gdk_window_get_user_data (window, (void **)&event_widget);
|
|
|
|
|
2009-05-28 22:52:41 +10:00
|
|
|
if (! event_widget)
|
2008-08-20 18:20:42 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
#ifdef DEBUG_TOOLTIP
|
|
|
|
g_print ("event window %p (belonging to %p (%s)) (%d, %d)\n",
|
2009-05-28 22:52:41 +10:00
|
|
|
window, event_widget, gtk_widget_get_name (event_widget),
|
|
|
|
*x, *y);
|
2008-08-20 18:20:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Coordinates are relative to event window */
|
|
|
|
child_loc.x = *x;
|
|
|
|
child_loc.y = *y;
|
|
|
|
|
|
|
|
/* We go down the window hierarchy to the widget->window,
|
|
|
|
* coordinates stay relative to the current window.
|
|
|
|
* We end up with window == widget->window, coordinates relative to that.
|
|
|
|
*/
|
2009-03-22 16:35:53 +00:00
|
|
|
while (window && window != gtk_widget_get_window (event_widget))
|
2008-08-20 18:20:42 +00:00
|
|
|
{
|
|
|
|
gint px, py;
|
|
|
|
|
|
|
|
gdk_window_get_position (window, &px, &py);
|
|
|
|
child_loc.x += px;
|
|
|
|
child_loc.y += py;
|
|
|
|
|
|
|
|
window = gdk_window_get_parent (window);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Failing to find widget->window can happen for e.g. a detached handle box;
|
|
|
|
* chaining ::query-tooltip up to its parent probably makes little sense,
|
|
|
|
* and users better implement tooltips on handle_box->child.
|
|
|
|
* so we simply ignore the event for tooltips here.
|
|
|
|
*/
|
|
|
|
if (!window)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Convert the window relative coordinates to allocation
|
|
|
|
* relative coordinates.
|
|
|
|
*/
|
|
|
|
window_to_alloc (event_widget,
|
2009-05-28 22:52:41 +10:00
|
|
|
child_loc.x, child_loc.y,
|
|
|
|
&child_loc.x, &child_loc.y);
|
2008-08-20 18:20:42 +00:00
|
|
|
|
|
|
|
if (GTK_IS_CONTAINER (event_widget))
|
|
|
|
{
|
|
|
|
GtkWidget *container = event_widget;
|
|
|
|
|
|
|
|
child_loc.container = event_widget;
|
|
|
|
child_loc.child = NULL;
|
|
|
|
|
|
|
|
gtk_container_forall (GTK_CONTAINER (event_widget),
|
2009-05-28 22:52:41 +10:00
|
|
|
child_location_foreach, &child_loc);
|
2008-08-20 18:20:42 +00:00
|
|
|
|
|
|
|
/* Here we have a widget, with coordinates relative to
|
|
|
|
* child_loc.container's allocation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (child_loc.child)
|
2009-05-28 22:52:41 +10:00
|
|
|
event_widget = child_loc.child;
|
2008-08-20 18:20:42 +00:00
|
|
|
else if (child_loc.container)
|
2009-05-28 22:52:41 +10:00
|
|
|
event_widget = child_loc.container;
|
2008-08-20 18:20:42 +00:00
|
|
|
|
|
|
|
/* Translate to event_widget's allocation */
|
|
|
|
gtk_widget_translate_coordinates (container, event_widget,
|
2009-05-28 22:52:41 +10:00
|
|
|
child_loc.x, child_loc.y,
|
|
|
|
&child_loc.x, &child_loc.y);
|
2008-08-20 18:20:42 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We return (x, y) relative to the allocation of event_widget. */
|
2013-06-15 23:07:06 +02:00
|
|
|
*x = child_loc.x;
|
|
|
|
*y = child_loc.y;
|
2008-08-20 18:20:42 +00:00
|
|
|
|
|
|
|
return event_widget;
|
|
|
|
}
|
2023-02-08 23:11:43 +01:00
|
|
|
|
2023-02-22 19:58:43 +01:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_fill_model (GimpUIManager *manager,
|
|
|
|
GMenuModel *model)
|
|
|
|
{
|
|
|
|
gint n_items;
|
|
|
|
|
|
|
|
g_return_if_fail (G_IS_MENU_MODEL (model));
|
|
|
|
|
|
|
|
n_items = g_menu_model_get_n_items (model);
|
|
|
|
for (int i = 0; i < n_items; i++)
|
|
|
|
{
|
|
|
|
GMenuModel *subsection;
|
|
|
|
GMenuModel *submenu;
|
|
|
|
gchar *label = NULL;
|
|
|
|
gchar *action_name = NULL;
|
|
|
|
|
|
|
|
subsection = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
|
|
|
|
submenu = g_menu_model_get_item_link (model, i, G_MENU_LINK_SUBMENU);
|
|
|
|
g_menu_model_get_item_attribute (model, i, G_MENU_ATTRIBUTE_LABEL, "s", &label);
|
|
|
|
g_menu_model_get_item_attribute (model, i, G_MENU_ATTRIBUTE_ACTION, "s", &action_name);
|
|
|
|
|
|
|
|
if (subsection != NULL)
|
|
|
|
{
|
|
|
|
gimp_ui_manager_fill_model (manager, subsection);
|
|
|
|
}
|
|
|
|
else if (submenu != NULL)
|
|
|
|
{
|
|
|
|
gimp_ui_manager_fill_model (manager, submenu);
|
|
|
|
}
|
|
|
|
else if (action_name != NULL)
|
|
|
|
{
|
|
|
|
/* Update the label, unless it's a placeholder (no action name). */
|
|
|
|
GApplication *app;
|
|
|
|
GAction *action;
|
|
|
|
|
|
|
|
app = manager->gimp->app;
|
|
|
|
action = g_action_map_lookup_action (G_ACTION_MAP (app), action_name + 4);
|
|
|
|
g_menu_remove (G_MENU (model), i);
|
|
|
|
g_menu_insert (G_MENU (model), i,
|
|
|
|
gimp_action_get_label (GIMP_ACTION (action)),
|
|
|
|
action_name);
|
|
|
|
}
|
|
|
|
g_free (label);
|
|
|
|
g_free (action_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-08 23:11:43 +01:00
|
|
|
static void
|
|
|
|
gimp_ui_manager_menu_item_free (GimpUIManagerMenuItem *item)
|
|
|
|
{
|
|
|
|
g_free (item->path);
|
|
|
|
g_free (item->action_name);
|
|
|
|
|
|
|
|
g_slice_free (GimpUIManagerMenuItem, item);
|
|
|
|
}
|