2006-12-09 21:33:38 +00:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1999-09-27 17:58:10 +00:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2003-03-13 13:08:37 +00:00
|
|
|
* gimpwidgets-utils.c
|
|
|
|
* Copyright (C) 1999-2003 Michael Natterer <mitch@gimp.org>
|
1999-09-27 17:58:10 +00:00
|
|
|
*
|
2009-01-17 22:28:01 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1999-09-27 17:58:10 +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
|
1999-09-27 17:58:10 +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/>.
|
1999-09-27 17:58:10 +00:00
|
|
|
*/
|
2000-12-16 21:37:03 +00:00
|
|
|
|
1999-12-28 18:30:01 +00:00
|
|
|
#include "config.h"
|
2000-02-02 01:21:36 +00:00
|
|
|
|
2001-02-04 04:51:17 +00:00
|
|
|
#include <string.h>
|
2000-02-02 01:21:36 +00:00
|
|
|
|
2012-03-30 15:08:54 +02:00
|
|
|
#include <gegl.h>
|
2000-12-16 21:37:03 +00:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2005-09-09 18:07:31 +00:00
|
|
|
#ifdef GDK_WINDOWING_WIN32
|
|
|
|
#include <gdk/gdkwin32.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
#include <gdk/gdkx.h>
|
|
|
|
#endif
|
|
|
|
|
2020-12-30 12:22:42 +01:00
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
#include <gdk/gdkwayland.h>
|
|
|
|
#endif
|
|
|
|
|
2018-06-25 01:31:09 +02:00
|
|
|
#ifdef PLATFORM_OSX
|
2018-10-24 10:45:07 +02:00
|
|
|
#include <ApplicationServices/ApplicationServices.h>
|
2018-06-25 01:31:09 +02:00
|
|
|
#endif
|
|
|
|
|
2003-05-29 11:34:30 +00:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2011-05-31 17:40:10 +02:00
|
|
|
#include "libgimpconfig/gimpconfig.h"
|
2007-03-09 13:00:01 +00:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2003-06-10 16:44:44 +00:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
2001-01-24 22:36:18 +00:00
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
|
2001-05-25 16:04:54 +00:00
|
|
|
#include "widgets-types.h"
|
2000-12-29 15:22:01 +00:00
|
|
|
|
2016-05-22 01:19:18 +02:00
|
|
|
#include "gegl/gimp-babl.h"
|
|
|
|
|
2022-03-05 14:32:34 +01:00
|
|
|
#include "core/gimp.h"
|
|
|
|
|
|
|
|
#include "gimpaction.h"
|
2019-07-02 03:54:38 +02:00
|
|
|
#include "gimpaction.h"
|
2010-02-20 16:55:35 +01:00
|
|
|
#include "gimpdialogfactory.h"
|
|
|
|
#include "gimpdock.h"
|
2011-05-13 18:56:03 +02:00
|
|
|
#include "gimpdockcontainer.h"
|
2010-02-20 16:55:35 +01:00
|
|
|
#include "gimpdockwindow.h"
|
2004-08-25 17:58:52 +00:00
|
|
|
#include "gimperrordialog.h"
|
2011-05-31 17:40:10 +02:00
|
|
|
#include "gimpsessioninfo.h"
|
2001-05-25 16:04:54 +00:00
|
|
|
#include "gimpwidgets-utils.h"
|
2022-03-05 14:32:34 +01:00
|
|
|
#include "gimpwindowstrategy.h"
|
1999-09-27 17:58:10 +00:00
|
|
|
|
2003-03-25 16:38:19 +00:00
|
|
|
#include "gimp-intl.h"
|
1999-09-27 17:58:10 +00:00
|
|
|
|
2000-12-16 21:37:03 +00:00
|
|
|
|
2018-09-27 02:31:39 -04:00
|
|
|
#define GIMP_TOOL_OPTIONS_GUI_KEY "gimp-tool-options-gui"
|
|
|
|
#define GIMP_TOOL_OPTIONS_GUI_FUNC_KEY "gimp-tool-options-gui-func"
|
2010-10-31 13:05:15 +01:00
|
|
|
|
|
|
|
|
2022-03-05 17:29:44 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GList **blink_script;
|
|
|
|
const gchar *widget_identifier;
|
|
|
|
} BlinkData;
|
|
|
|
|
|
|
|
|
2022-03-05 14:32:34 +01:00
|
|
|
static void gimp_search_widget_rec (GtkWidget *widget,
|
2022-03-05 17:29:44 +01:00
|
|
|
BlinkData *data);
|
2022-03-05 14:32:34 +01:00
|
|
|
|
|
|
|
|
2018-05-02 14:50:22 +02:00
|
|
|
GtkWidget *
|
|
|
|
gimp_menu_item_get_image (GtkMenuItem *item)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GTK_IS_MENU_ITEM (item), NULL);
|
|
|
|
|
|
|
|
return g_object_get_data (G_OBJECT (item), "gimp-menu-item-image");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_menu_item_set_image (GtkMenuItem *item,
|
|
|
|
GtkWidget *image)
|
|
|
|
{
|
|
|
|
GtkWidget *hbox;
|
|
|
|
GtkWidget *label;
|
|
|
|
GtkWidget *old_image;
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_MENU_ITEM (item));
|
|
|
|
g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));
|
|
|
|
|
|
|
|
hbox = g_object_get_data (G_OBJECT (item), "gimp-menu-item-hbox");
|
|
|
|
|
|
|
|
if (! hbox)
|
|
|
|
{
|
|
|
|
if (! image)
|
|
|
|
return;
|
|
|
|
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
2018-05-23 22:21:52 +02:00
|
|
|
g_object_set_data (G_OBJECT (item), "gimp-menu-item-hbox", hbox);
|
2018-05-02 14:50:22 +02:00
|
|
|
|
|
|
|
label = gtk_bin_get_child (GTK_BIN (item));
|
2018-05-23 22:21:52 +02:00
|
|
|
g_object_set_data (G_OBJECT (item), "gimp-menu-item-label", label);
|
2018-05-02 14:50:22 +02:00
|
|
|
|
|
|
|
g_object_ref (label);
|
|
|
|
gtk_container_remove (GTK_CONTAINER (item), label);
|
|
|
|
gtk_container_add (GTK_CONTAINER (hbox), label);
|
|
|
|
g_object_unref (label);
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (item), hbox);
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
}
|
|
|
|
|
|
|
|
old_image = g_object_get_data (G_OBJECT (item), "gimp-menu-item-image");
|
|
|
|
|
|
|
|
if (old_image != image)
|
|
|
|
{
|
|
|
|
if (old_image)
|
|
|
|
{
|
|
|
|
gtk_widget_destroy (old_image);
|
|
|
|
g_object_set_data (G_OBJECT (item), "gimp-menu-item-image", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (image)
|
|
|
|
{
|
|
|
|
gtk_container_add (GTK_CONTAINER (hbox), image);
|
|
|
|
gtk_box_reorder_child (GTK_BOX (hbox), image, 0);
|
|
|
|
g_object_set_data (G_OBJECT (item), "gimp-menu-item-image", image);
|
|
|
|
gtk_widget_show (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-19 18:08:15 +00:00
|
|
|
/**
|
|
|
|
* gimp_menu_position:
|
|
|
|
* @menu: a #GtkMenu widget
|
|
|
|
* @x: pointer to horizontal position
|
|
|
|
* @y: pointer to vertical position
|
|
|
|
*
|
|
|
|
* Positions a #GtkMenu so that it pops up on screen. This function
|
|
|
|
* takes care of the preferred popup direction (taken from the widget
|
|
|
|
* render direction) and it handles multiple monitors representing a
|
|
|
|
* single #GdkScreen (Xinerama).
|
|
|
|
*
|
|
|
|
* You should call this function with @x and @y initialized to the
|
|
|
|
* origin of the menu. This is typically the center of the widget the
|
|
|
|
* menu is popped up from. gimp_menu_position() will then decide if
|
|
|
|
* and how these initial values need to be changed.
|
|
|
|
**/
|
2001-04-20 16:27:44 +00:00
|
|
|
void
|
2003-11-19 18:08:15 +00:00
|
|
|
gimp_menu_position (GtkMenu *menu,
|
2006-04-12 12:49:29 +00:00
|
|
|
gint *x,
|
|
|
|
gint *y)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2003-11-19 18:08:15 +00:00
|
|
|
GtkWidget *widget;
|
|
|
|
GtkRequisition requisition;
|
2018-05-04 13:20:46 +02:00
|
|
|
GdkRectangle workarea;
|
2001-08-04 20:38:54 +00:00
|
|
|
|
2001-11-30 14:41:56 +00:00
|
|
|
g_return_if_fail (GTK_IS_MENU (menu));
|
2001-08-04 20:38:54 +00:00
|
|
|
g_return_if_fail (x != NULL);
|
|
|
|
g_return_if_fail (y != NULL);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2003-11-19 18:08:15 +00:00
|
|
|
widget = GTK_WIDGET (menu);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2018-05-04 13:20:46 +02:00
|
|
|
gdk_monitor_get_workarea (gimp_widget_get_monitor (widget), &workarea);
|
2000-03-28 23:02:05 +00:00
|
|
|
|
2018-05-04 13:20:46 +02:00
|
|
|
gtk_menu_set_screen (menu, gtk_widget_get_screen (widget));
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2010-10-19 12:11:59 +02:00
|
|
|
gtk_widget_get_preferred_size (widget, &requisition, NULL);
|
2003-09-24 14:23:32 +00:00
|
|
|
|
2003-11-19 18:08:15 +00:00
|
|
|
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
|
|
|
{
|
|
|
|
*x -= requisition.width;
|
2018-05-04 13:20:46 +02:00
|
|
|
if (*x < workarea.x)
|
2003-11-19 18:08:15 +00:00
|
|
|
*x += requisition.width;
|
2003-09-24 14:23:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-04 13:20:46 +02:00
|
|
|
if (*x + requisition.width > workarea.x + workarea.width)
|
2003-11-19 18:08:15 +00:00
|
|
|
*x -= requisition.width;
|
2003-09-24 14:23:32 +00:00
|
|
|
}
|
|
|
|
|
2018-05-04 13:20:46 +02:00
|
|
|
if (*x < workarea.x)
|
|
|
|
*x = workarea.x;
|
2001-08-04 20:38:54 +00:00
|
|
|
|
2018-05-04 13:20:46 +02:00
|
|
|
if (*y + requisition.height > workarea.y + workarea.height)
|
2003-11-19 18:08:15 +00:00
|
|
|
*y -= requisition.height;
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2018-05-04 13:20:46 +02:00
|
|
|
if (*y < workarea.y)
|
|
|
|
*y = workarea.y;
|
2001-08-04 20:38:54 +00:00
|
|
|
}
|
|
|
|
|
2002-10-09 15:42:38 +00:00
|
|
|
void
|
2018-04-29 18:40:43 +02:00
|
|
|
gimp_grid_attach_icon (GtkGrid *grid,
|
|
|
|
gint row,
|
|
|
|
const gchar *icon_name,
|
|
|
|
GtkWidget *widget,
|
|
|
|
gint columns)
|
2002-10-09 15:42:38 +00:00
|
|
|
{
|
2003-02-05 22:15:39 +00:00
|
|
|
GtkWidget *image;
|
2002-10-09 15:42:38 +00:00
|
|
|
|
2018-04-29 18:40:43 +02:00
|
|
|
g_return_if_fail (GTK_IS_GRID (grid));
|
2014-05-07 15:30:38 +02:00
|
|
|
g_return_if_fail (icon_name != NULL);
|
2005-09-02 17:22:29 +00:00
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
2003-02-05 18:23:58 +00:00
|
|
|
|
2014-05-07 15:30:38 +02:00
|
|
|
image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
|
2018-04-29 01:51:36 +02:00
|
|
|
gtk_widget_set_halign (image, GTK_ALIGN_END);
|
2018-04-29 18:40:43 +02:00
|
|
|
gtk_grid_attach (grid, image, 0, row, 1, 1);
|
2005-09-02 17:22:29 +00:00
|
|
|
gtk_widget_show (image);
|
2003-09-09 11:35:27 +00:00
|
|
|
|
2018-04-29 18:40:43 +02:00
|
|
|
gtk_grid_attach (grid, widget, 1, row, columns, 1);
|
2005-09-02 17:22:29 +00:00
|
|
|
gtk_widget_show (widget);
|
2002-10-09 15:42:38 +00:00
|
|
|
}
|
2002-12-19 16:33:29 +00:00
|
|
|
|
2004-10-12 12:06:50 +00:00
|
|
|
void
|
2008-10-24 22:34:24 +00:00
|
|
|
gimp_enum_radio_box_add (GtkBox *box,
|
|
|
|
GtkWidget *widget,
|
2008-10-28 17:40:32 +00:00
|
|
|
gint enum_value,
|
|
|
|
gboolean below)
|
2004-10-12 12:06:50 +00:00
|
|
|
{
|
2008-10-24 22:34:24 +00:00
|
|
|
GList *children;
|
|
|
|
GList *list;
|
|
|
|
gint pos;
|
2004-10-12 12:06:50 +00:00
|
|
|
|
2008-10-24 22:34:24 +00:00
|
|
|
g_return_if_fail (GTK_IS_BOX (box));
|
2004-10-12 12:06:50 +00:00
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
|
2008-10-24 22:34:24 +00:00
|
|
|
children = gtk_container_get_children (GTK_CONTAINER (box));
|
2004-10-12 12:06:50 +00:00
|
|
|
|
2004-10-14 13:44:06 +00:00
|
|
|
for (list = children, pos = 1;
|
2004-10-12 12:06:50 +00:00
|
|
|
list;
|
2004-10-14 13:44:06 +00:00
|
|
|
list = g_list_next (list), pos++)
|
2004-10-12 12:06:50 +00:00
|
|
|
{
|
2004-10-14 13:44:06 +00:00
|
|
|
if (GTK_IS_RADIO_BUTTON (list->data) &&
|
|
|
|
GPOINTER_TO_INT (g_object_get_data (list->data, "gimp-item-data")) ==
|
2004-10-12 12:06:50 +00:00
|
|
|
enum_value)
|
|
|
|
{
|
2004-10-14 13:44:06 +00:00
|
|
|
GtkWidget *radio = list->data;
|
|
|
|
GtkWidget *hbox;
|
2008-06-28 15:50:27 +00:00
|
|
|
|
2011-09-30 11:29:11 +02:00
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
2008-10-28 17:40:32 +00:00
|
|
|
gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
|
|
|
|
gtk_box_reorder_child (GTK_BOX (box), hbox, pos);
|
2004-10-14 13:44:06 +00:00
|
|
|
|
2008-10-28 17:40:32 +00:00
|
|
|
if (below)
|
|
|
|
{
|
|
|
|
GtkWidget *spacer;
|
|
|
|
gint indicator_size;
|
|
|
|
gint indicator_spacing;
|
|
|
|
gint focus_width;
|
|
|
|
gint focus_padding;
|
|
|
|
gint border_width;
|
|
|
|
|
|
|
|
gtk_widget_style_get (radio,
|
|
|
|
"indicator-size", &indicator_size,
|
|
|
|
"indicator-spacing", &indicator_spacing,
|
|
|
|
"focus-line-width", &focus_width,
|
|
|
|
"focus-padding", &focus_padding,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
border_width = gtk_container_get_border_width (GTK_CONTAINER (radio));
|
|
|
|
|
2011-09-30 11:29:11 +02:00
|
|
|
spacer = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
2008-10-28 17:40:32 +00:00
|
|
|
gtk_widget_set_size_request (spacer,
|
|
|
|
indicator_size +
|
|
|
|
3 * indicator_spacing +
|
|
|
|
focus_width +
|
|
|
|
focus_padding +
|
|
|
|
border_width,
|
|
|
|
-1);
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), spacer, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (spacer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GtkSizeGroup *size_group;
|
|
|
|
|
|
|
|
size_group = g_object_get_data (G_OBJECT (box), "size-group");
|
|
|
|
|
|
|
|
if (! size_group)
|
|
|
|
{
|
|
|
|
size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
|
|
|
|
g_object_set_data (G_OBJECT (box), "size-group", size_group);
|
|
|
|
|
|
|
|
gtk_size_group_add_widget (size_group, radio);
|
|
|
|
g_object_unref (size_group);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gtk_size_group_add_widget (size_group, radio);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_box_set_spacing (GTK_BOX (hbox), 4);
|
|
|
|
|
|
|
|
g_object_ref (radio);
|
|
|
|
gtk_container_remove (GTK_CONTAINER (box), radio);
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), radio, FALSE, FALSE, 0);
|
|
|
|
g_object_unref (radio);
|
|
|
|
}
|
2004-10-14 13:44:06 +00:00
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show (widget);
|
|
|
|
|
2011-05-11 11:43:19 +02:00
|
|
|
g_object_bind_property (radio, "active",
|
|
|
|
widget, "sensitive",
|
|
|
|
G_BINDING_SYNC_CREATE);
|
2004-10-12 12:06:50 +00:00
|
|
|
|
2004-10-14 13:44:06 +00:00
|
|
|
gtk_widget_show (hbox);
|
|
|
|
|
2004-10-12 12:06:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-14 13:44:06 +00:00
|
|
|
g_list_free (children);
|
2004-10-12 12:06:50 +00:00
|
|
|
}
|
|
|
|
|
2008-10-24 22:34:24 +00:00
|
|
|
void
|
|
|
|
gimp_enum_radio_frame_add (GtkFrame *frame,
|
|
|
|
GtkWidget *widget,
|
2008-10-28 17:40:32 +00:00
|
|
|
gint enum_value,
|
|
|
|
gboolean below)
|
2008-10-24 22:34:24 +00:00
|
|
|
{
|
2011-07-27 20:21:58 +02:00
|
|
|
GtkWidget *box;
|
2008-10-24 22:34:24 +00:00
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_FRAME (frame));
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
|
2011-07-27 20:21:58 +02:00
|
|
|
box = gtk_bin_get_child (GTK_BIN (frame));
|
2008-10-24 22:34:24 +00:00
|
|
|
|
2011-07-27 20:21:58 +02:00
|
|
|
g_return_if_fail (GTK_IS_BOX (box));
|
2008-10-24 22:34:24 +00:00
|
|
|
|
2011-07-27 20:21:58 +02:00
|
|
|
gimp_enum_radio_box_add (GTK_BOX (box), widget, enum_value, below);
|
2008-10-24 22:34:24 +00:00
|
|
|
}
|
|
|
|
|
2018-06-24 17:11:24 +02:00
|
|
|
/**
|
|
|
|
* gimp_widget_load_icon:
|
|
|
|
* @widget: parent widget (to determine icon theme and
|
|
|
|
* style)
|
|
|
|
* @icon_name: icon name
|
|
|
|
* @size: requested pixel size
|
|
|
|
*
|
|
|
|
* Loads an icon into a pixbuf with size as close as possible to @size.
|
|
|
|
* If icon does not exist or fail to load, the function will fallback to
|
2018-06-24 18:21:24 +02:00
|
|
|
* "gimp-wilber-eek" instead to prevent NULL pixbuf. As a last resort,
|
|
|
|
* if even the fallback failed to load, a magenta @size square will be
|
|
|
|
* returned, so this function is guaranteed to always return a
|
|
|
|
* #GdkPixbuf.
|
2018-06-24 17:11:24 +02:00
|
|
|
*
|
2019-08-03 00:10:14 +02:00
|
|
|
* Returns: a newly allocated #GdkPixbuf containing @icon_name at
|
2018-06-24 18:21:24 +02:00
|
|
|
* size @size or a fallback icon/size.
|
2018-06-24 17:11:24 +02:00
|
|
|
**/
|
2014-05-08 09:11:31 +02:00
|
|
|
GdkPixbuf *
|
|
|
|
gimp_widget_load_icon (GtkWidget *widget,
|
|
|
|
const gchar *icon_name,
|
|
|
|
gint size)
|
|
|
|
{
|
2018-06-25 15:32:24 +02:00
|
|
|
GdkPixbuf *pixbuf = NULL;
|
2014-05-08 09:11:31 +02:00
|
|
|
GtkIconTheme *icon_theme;
|
2018-05-30 09:39:04 +02:00
|
|
|
GtkIconInfo *icon_info;
|
|
|
|
gchar *name;
|
|
|
|
gint scale_factor;
|
2014-05-08 09:11:31 +02:00
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
|
|
|
|
g_return_val_if_fail (icon_name != NULL, NULL);
|
|
|
|
|
|
|
|
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
|
2018-05-30 09:39:04 +02:00
|
|
|
scale_factor = gtk_widget_get_scale_factor (widget);
|
|
|
|
name = g_strdup_printf ("%s-symbolic", icon_name);
|
|
|
|
/* This will find the symbolic icon and fallback to non-symbolic
|
|
|
|
* depending on icon theme.
|
|
|
|
*/
|
2018-12-31 18:44:35 +01:00
|
|
|
icon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, name,
|
|
|
|
size, scale_factor,
|
|
|
|
GTK_ICON_LOOKUP_GENERIC_FALLBACK);
|
2018-05-30 09:39:04 +02:00
|
|
|
g_free (name);
|
|
|
|
|
2018-06-25 15:32:24 +02:00
|
|
|
if (icon_info)
|
|
|
|
{
|
|
|
|
pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info,
|
|
|
|
gtk_widget_get_style_context (widget),
|
|
|
|
NULL, NULL);
|
|
|
|
g_object_unref (icon_info);
|
|
|
|
if (! pixbuf)
|
|
|
|
/* The icon was seemingly present in the current icon theme, yet
|
|
|
|
* it failed to load. Maybe the file is broken?
|
|
|
|
* As last resort, try to load "gimp-wilber-eek" as fallback.
|
|
|
|
* Note that we are not making more checks, so if the fallback
|
|
|
|
* icon fails to load as well, the function may still return NULL.
|
|
|
|
*/
|
|
|
|
g_printerr ("WARNING: icon '%s' failed to load. Check the files "
|
|
|
|
"in your icon theme.\n", icon_name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
g_printerr ("WARNING: icon theme has no icon '%s'.\n", icon_name);
|
|
|
|
|
|
|
|
/* First fallback: gimp-wilber-eek */
|
|
|
|
if (! pixbuf)
|
2014-05-08 09:11:31 +02:00
|
|
|
{
|
2018-05-30 09:39:04 +02:00
|
|
|
icon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme,
|
|
|
|
GIMP_ICON_WILBER_EEK "-symbolic",
|
|
|
|
size, scale_factor,
|
|
|
|
GTK_ICON_LOOKUP_GENERIC_FALLBACK);
|
2018-06-24 17:27:36 +02:00
|
|
|
if (icon_info)
|
2018-06-24 16:59:39 +02:00
|
|
|
{
|
2018-06-25 15:32:24 +02:00
|
|
|
pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info,
|
|
|
|
gtk_widget_get_style_context (widget),
|
|
|
|
NULL, NULL);
|
2018-06-24 16:59:39 +02:00
|
|
|
g_object_unref (icon_info);
|
2018-06-24 18:21:24 +02:00
|
|
|
if (! pixbuf)
|
2018-06-25 15:32:24 +02:00
|
|
|
g_printerr ("WARNING: icon '%s' failed to load. Check the files "
|
|
|
|
"in your icon theme.\n", GIMP_ICON_WILBER_EEK);
|
|
|
|
}
|
|
|
|
else
|
2018-12-31 18:44:35 +01:00
|
|
|
{
|
|
|
|
g_printerr ("WARNING: icon theme has no icon '%s'.\n",
|
|
|
|
GIMP_ICON_WILBER_EEK);
|
|
|
|
}
|
2018-06-25 15:32:24 +02:00
|
|
|
}
|
2018-06-24 18:21:24 +02:00
|
|
|
|
2018-06-25 15:32:24 +02:00
|
|
|
/* Last fallback: just a magenta square. */
|
|
|
|
if (! pixbuf)
|
|
|
|
{
|
|
|
|
/* As last resort, just draw an ugly magenta square. */
|
|
|
|
guchar *data;
|
2018-12-31 18:44:35 +01:00
|
|
|
gint rowstride = 3 * size * scale_factor;
|
2018-06-25 15:32:24 +02:00
|
|
|
gint i, j;
|
2018-06-24 18:21:24 +02:00
|
|
|
|
2018-06-25 15:32:24 +02:00
|
|
|
data = g_new (guchar, rowstride * size);
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
{
|
2018-12-31 18:44:35 +01:00
|
|
|
for (j = 0; j < size * scale_factor; j++)
|
2018-06-25 15:32:24 +02:00
|
|
|
{
|
|
|
|
data[i * rowstride + j * 3] = 255;
|
|
|
|
data[i * rowstride + j * 3 + 1] = 0;
|
|
|
|
data[i * rowstride + j * 3 + 2] = 255;
|
2018-06-24 18:21:24 +02:00
|
|
|
}
|
2018-06-24 16:59:39 +02:00
|
|
|
}
|
2018-06-25 15:32:24 +02:00
|
|
|
pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, FALSE,
|
2018-12-31 18:44:35 +01:00
|
|
|
8,
|
|
|
|
size * scale_factor,
|
|
|
|
size * scale_factor, rowstride,
|
2018-06-25 15:32:24 +02:00
|
|
|
(GdkPixbufDestroyNotify) g_free,
|
|
|
|
NULL);
|
2018-06-24 16:59:39 +02:00
|
|
|
}
|
|
|
|
|
2018-06-25 16:15:25 +02:00
|
|
|
/* Small assertion test to get a warning if we ever get NULL return
|
|
|
|
* value, as this is never supposed to happen.
|
|
|
|
*/
|
|
|
|
g_return_val_if_fail (pixbuf != NULL, NULL);
|
|
|
|
|
2018-06-24 16:59:39 +02:00
|
|
|
return pixbuf;
|
2014-05-08 09:11:31 +02:00
|
|
|
}
|
|
|
|
|
2010-06-11 22:38:34 +02:00
|
|
|
GimpTabStyle
|
|
|
|
gimp_preview_tab_style_to_icon (GimpTabStyle tab_style)
|
|
|
|
{
|
|
|
|
switch (tab_style)
|
|
|
|
{
|
|
|
|
case GIMP_TAB_STYLE_PREVIEW:
|
|
|
|
tab_style = GIMP_TAB_STYLE_ICON;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TAB_STYLE_PREVIEW_NAME:
|
|
|
|
tab_style = GIMP_TAB_STYLE_ICON_NAME;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TAB_STYLE_PREVIEW_BLURB:
|
|
|
|
tab_style = GIMP_TAB_STYLE_ICON_BLURB;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tab_style;
|
|
|
|
}
|
|
|
|
|
2004-06-28 23:30:57 +00:00
|
|
|
const gchar *
|
|
|
|
gimp_get_mod_string (GdkModifierType modifiers)
|
|
|
|
{
|
2011-10-05 01:28:45 +02:00
|
|
|
static GHashTable *mod_labels;
|
2011-10-05 18:47:37 +02:00
|
|
|
gchar *label;
|
2004-06-28 23:30:57 +00:00
|
|
|
|
2011-10-05 01:28:45 +02:00
|
|
|
if (! modifiers)
|
|
|
|
return NULL;
|
2004-06-28 23:30:57 +00:00
|
|
|
|
2011-10-05 01:28:45 +02:00
|
|
|
if (G_UNLIKELY (! mod_labels))
|
|
|
|
mod_labels = g_hash_table_new (g_int_hash, g_int_equal);
|
2004-06-28 23:30:57 +00:00
|
|
|
|
2011-10-06 22:26:43 +02:00
|
|
|
modifiers = gimp_replace_virtual_modifiers (modifiers);
|
|
|
|
|
2011-10-05 01:28:45 +02:00
|
|
|
label = g_hash_table_lookup (mod_labels, &modifiers);
|
2004-06-28 23:30:57 +00:00
|
|
|
|
2011-10-05 18:47:37 +02:00
|
|
|
if (! label)
|
|
|
|
{
|
|
|
|
GtkAccelLabelClass *accel_label_class;
|
2004-06-28 23:30:57 +00:00
|
|
|
|
2011-10-05 18:47:37 +02:00
|
|
|
label = gtk_accelerator_get_label (0, modifiers);
|
2004-06-28 23:30:57 +00:00
|
|
|
|
2011-10-05 18:47:37 +02:00
|
|
|
accel_label_class = g_type_class_ref (GTK_TYPE_ACCEL_LABEL);
|
2011-10-05 01:28:45 +02:00
|
|
|
|
2011-10-05 18:47:37 +02:00
|
|
|
if (accel_label_class->mod_separator &&
|
|
|
|
*accel_label_class->mod_separator)
|
|
|
|
{
|
|
|
|
gchar *sep = g_strrstr (label, accel_label_class->mod_separator);
|
2011-10-05 01:28:45 +02:00
|
|
|
|
2011-10-05 18:47:37 +02:00
|
|
|
if (sep - label ==
|
|
|
|
strlen (label) - strlen (accel_label_class->mod_separator))
|
|
|
|
*sep = '\0';
|
|
|
|
}
|
2004-06-28 23:30:57 +00:00
|
|
|
|
2011-10-05 18:47:37 +02:00
|
|
|
g_type_class_unref (accel_label_class);
|
2011-10-05 01:28:45 +02:00
|
|
|
|
2011-10-05 18:47:37 +02:00
|
|
|
g_hash_table_insert (mod_labels,
|
2021-08-26 17:18:32 +02:00
|
|
|
g_memdup2 (&modifiers, sizeof (GdkModifierType)),
|
2011-10-05 18:47:37 +02:00
|
|
|
label);
|
|
|
|
}
|
2011-10-05 01:28:45 +02:00
|
|
|
|
|
|
|
return label;
|
2004-07-20 18:50:20 +00:00
|
|
|
}
|
|
|
|
|
2006-08-01 23:42:12 +00:00
|
|
|
#define BUF_SIZE 100
|
|
|
|
/**
|
|
|
|
* gimp_suggest_modifiers:
|
2015-10-17 15:31:08 +02:00
|
|
|
* @message: initial text for the message
|
|
|
|
* @modifiers: bit mask of modifiers that should be suggested
|
|
|
|
* @extend_selection_format: optional format string for the
|
|
|
|
* "Extend selection" modifier
|
|
|
|
* @toggle_behavior_format: optional format string for the
|
|
|
|
* "Toggle behavior" modifier
|
|
|
|
* @alt_format: optional format string for the Alt modifier
|
2006-08-01 23:42:12 +00:00
|
|
|
*
|
|
|
|
* Utility function to build a message suggesting to use some
|
|
|
|
* modifiers for performing different actions (only Shift, Ctrl and
|
|
|
|
* Alt are currently supported). If some of these modifiers are
|
|
|
|
* already active, they will not be suggested. The optional format
|
2015-10-17 15:31:08 +02:00
|
|
|
* strings #extend_selection_format, #toggle_behavior_format and
|
|
|
|
* #alt_format may be used to describe what the modifier will do.
|
|
|
|
* They must contain a single '%%s' which will be replaced by the name
|
|
|
|
* of the modifier. They can also be %NULL if the modifier name
|
|
|
|
* should be left alone.
|
2006-08-01 23:42:12 +00:00
|
|
|
*
|
2019-08-03 00:10:14 +02:00
|
|
|
* Returns: a newly allocated string containing the message.
|
2006-08-01 23:42:12 +00:00
|
|
|
**/
|
|
|
|
gchar *
|
|
|
|
gimp_suggest_modifiers (const gchar *message,
|
|
|
|
GdkModifierType modifiers,
|
2015-10-17 15:31:08 +02:00
|
|
|
const gchar *extend_selection_format,
|
|
|
|
const gchar *toggle_behavior_format,
|
2006-08-01 23:42:12 +00:00
|
|
|
const gchar *alt_format)
|
|
|
|
{
|
2015-10-17 15:31:08 +02:00
|
|
|
GdkModifierType extend_mask = gimp_get_extend_selection_mask ();
|
|
|
|
GdkModifierType toggle_mask = gimp_get_toggle_behavior_mask ();
|
|
|
|
gchar msg_buf[3][BUF_SIZE];
|
|
|
|
gint num_msgs = 0;
|
|
|
|
gboolean try = FALSE;
|
2006-08-01 23:42:12 +00:00
|
|
|
|
2015-10-17 15:31:08 +02:00
|
|
|
if (modifiers & extend_mask)
|
2006-08-01 23:42:12 +00:00
|
|
|
{
|
2015-10-17 15:31:08 +02:00
|
|
|
if (extend_selection_format && *extend_selection_format)
|
2006-09-12 06:37:54 +00:00
|
|
|
{
|
2015-10-17 15:31:08 +02:00
|
|
|
g_snprintf (msg_buf[num_msgs], BUF_SIZE, extend_selection_format,
|
|
|
|
gimp_get_mod_string (extend_mask));
|
2006-09-12 06:37:54 +00:00
|
|
|
}
|
2006-08-01 23:42:12 +00:00
|
|
|
else
|
2006-09-12 06:37:54 +00:00
|
|
|
{
|
2011-10-06 22:53:42 +02:00
|
|
|
g_strlcpy (msg_buf[num_msgs],
|
2015-10-17 15:31:08 +02:00
|
|
|
gimp_get_mod_string (extend_mask), BUF_SIZE);
|
2006-09-12 06:37:54 +00:00
|
|
|
try = TRUE;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:42:12 +00:00
|
|
|
num_msgs++;
|
|
|
|
}
|
2006-09-12 06:37:54 +00:00
|
|
|
|
2015-10-17 15:31:08 +02:00
|
|
|
if (modifiers & toggle_mask)
|
2006-08-01 23:42:12 +00:00
|
|
|
{
|
2015-10-17 15:31:08 +02:00
|
|
|
if (toggle_behavior_format && *toggle_behavior_format)
|
2006-09-12 06:37:54 +00:00
|
|
|
{
|
2015-10-17 15:31:08 +02:00
|
|
|
g_snprintf (msg_buf[num_msgs], BUF_SIZE, toggle_behavior_format,
|
|
|
|
gimp_get_mod_string (toggle_mask));
|
2006-09-12 06:37:54 +00:00
|
|
|
}
|
2006-08-01 23:42:12 +00:00
|
|
|
else
|
2006-09-12 06:37:54 +00:00
|
|
|
{
|
2011-10-06 22:53:42 +02:00
|
|
|
g_strlcpy (msg_buf[num_msgs],
|
2015-10-17 15:31:08 +02:00
|
|
|
gimp_get_mod_string (toggle_mask), BUF_SIZE);
|
2006-09-12 06:37:54 +00:00
|
|
|
try = TRUE;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:42:12 +00:00
|
|
|
num_msgs++;
|
|
|
|
}
|
2006-09-12 06:37:54 +00:00
|
|
|
|
2006-08-01 23:42:12 +00:00
|
|
|
if (modifiers & GDK_MOD1_MASK)
|
|
|
|
{
|
|
|
|
if (alt_format && *alt_format)
|
2006-09-12 06:37:54 +00:00
|
|
|
{
|
|
|
|
g_snprintf (msg_buf[num_msgs], BUF_SIZE, alt_format,
|
2011-10-05 01:28:45 +02:00
|
|
|
gimp_get_mod_string (GDK_MOD1_MASK));
|
2006-09-12 06:37:54 +00:00
|
|
|
}
|
2006-08-01 23:42:12 +00:00
|
|
|
else
|
2006-09-12 06:37:54 +00:00
|
|
|
{
|
2011-10-06 22:53:42 +02:00
|
|
|
g_strlcpy (msg_buf[num_msgs],
|
|
|
|
gimp_get_mod_string (GDK_MOD1_MASK), BUF_SIZE);
|
2006-09-12 06:37:54 +00:00
|
|
|
try = TRUE;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:42:12 +00:00
|
|
|
num_msgs++;
|
|
|
|
}
|
2006-09-12 06:37:54 +00:00
|
|
|
|
2006-08-01 23:42:12 +00:00
|
|
|
/* This convoluted way to build the message using multiple format strings
|
|
|
|
* tries to make the messages easier to translate to other languages.
|
|
|
|
*/
|
2006-09-12 06:37:54 +00:00
|
|
|
|
|
|
|
switch (num_msgs)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
return g_strdup_printf (try ? _("%s (try %s)") : _("%s (%s)"),
|
|
|
|
message, msg_buf[0]);
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
return g_strdup_printf (_("%s (try %s, %s)"),
|
|
|
|
message, msg_buf[0], msg_buf[1]);
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
return g_strdup_printf (_("%s (try %s, %s, %s)"),
|
|
|
|
message, msg_buf[0], msg_buf[1], msg_buf[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return g_strdup (message);
|
2006-08-01 23:42:12 +00:00
|
|
|
}
|
|
|
|
#undef BUF_SIZE
|
2004-06-28 23:30:57 +00:00
|
|
|
|
2011-10-05 19:15:17 +02:00
|
|
|
GimpChannelOps
|
2011-10-06 10:24:49 +02:00
|
|
|
gimp_modifiers_to_channel_op (GdkModifierType modifiers)
|
2011-10-05 19:15:17 +02:00
|
|
|
{
|
2011-10-06 10:24:49 +02:00
|
|
|
GdkModifierType extend_mask = gimp_get_extend_selection_mask ();
|
|
|
|
GdkModifierType modify_mask = gimp_get_modify_selection_mask ();
|
2011-10-05 19:15:17 +02:00
|
|
|
|
|
|
|
if (modifiers & extend_mask)
|
|
|
|
{
|
|
|
|
if (modifiers & modify_mask)
|
|
|
|
{
|
|
|
|
return GIMP_CHANNEL_OP_INTERSECT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return GIMP_CHANNEL_OP_ADD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (modifiers & modify_mask)
|
|
|
|
{
|
|
|
|
return GIMP_CHANNEL_OP_SUBTRACT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GIMP_CHANNEL_OP_REPLACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkModifierType
|
|
|
|
gimp_replace_virtual_modifiers (GdkModifierType modifiers)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
GdkModifierType result = 0;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
{
|
|
|
|
GdkModifierType real = 1 << i;
|
|
|
|
|
|
|
|
if (modifiers & real)
|
|
|
|
{
|
|
|
|
GdkModifierType virtual = real;
|
|
|
|
|
|
|
|
gdk_keymap_add_virtual_modifiers (gdk_keymap_get_for_display (display),
|
|
|
|
&virtual);
|
|
|
|
|
|
|
|
if (virtual == real)
|
|
|
|
result |= virtual;
|
|
|
|
else
|
|
|
|
result |= virtual & ~real;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-11-08 10:00:20 +01:00
|
|
|
GdkModifierType
|
|
|
|
gimp_get_primary_accelerator_mask (void)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
|
|
|
|
return gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
|
|
|
|
}
|
|
|
|
|
2011-10-06 10:20:23 +02:00
|
|
|
GdkModifierType
|
|
|
|
gimp_get_extend_selection_mask (void)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
|
|
|
|
return gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
GDK_MODIFIER_INTENT_EXTEND_SELECTION);
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkModifierType
|
|
|
|
gimp_get_modify_selection_mask (void)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
|
|
|
|
return gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
GDK_MODIFIER_INTENT_MODIFY_SELECTION);
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkModifierType
|
|
|
|
gimp_get_toggle_behavior_mask (void)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
|
|
|
|
/* use the modify selection modifier */
|
|
|
|
return gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
GDK_MODIFIER_INTENT_MODIFY_SELECTION);
|
|
|
|
}
|
|
|
|
|
2011-10-06 16:42:42 +02:00
|
|
|
GdkModifierType
|
|
|
|
gimp_get_constrain_behavior_mask (void)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
|
|
|
|
/* use the modify selection modifier */
|
|
|
|
return gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
GDK_MODIFIER_INTENT_MODIFY_SELECTION);
|
|
|
|
}
|
|
|
|
|
2011-10-10 00:17:20 +02:00
|
|
|
GdkModifierType
|
|
|
|
gimp_get_all_modifiers_mask (void)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
|
|
|
|
return (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK |
|
|
|
|
gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR) |
|
|
|
|
gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
GDK_MODIFIER_INTENT_EXTEND_SELECTION) |
|
|
|
|
gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
GDK_MODIFIER_INTENT_MODIFY_SELECTION));
|
|
|
|
}
|
|
|
|
|
2003-06-10 16:44:44 +00:00
|
|
|
/**
|
2014-05-02 23:56:16 +02:00
|
|
|
* gimp_get_monitor_resolution:
|
|
|
|
* @screen: a #GdkScreen
|
|
|
|
* @monitor: a monitor number
|
|
|
|
* @xres: returns the horizontal monitor resolution (in dpi)
|
|
|
|
* @yres: returns the vertical monitor resolution (in dpi)
|
2003-09-09 11:35:27 +00:00
|
|
|
*
|
2014-05-02 23:56:16 +02:00
|
|
|
* Retrieves the monitor's resolution from GDK.
|
2003-06-10 16:44:44 +00:00
|
|
|
**/
|
2003-05-29 11:34:30 +00:00
|
|
|
void
|
2018-04-29 17:27:47 +02:00
|
|
|
gimp_get_monitor_resolution (GdkMonitor *monitor,
|
|
|
|
gdouble *xres,
|
|
|
|
gdouble *yres)
|
2003-05-29 11:34:30 +00:00
|
|
|
{
|
2014-05-02 23:56:16 +02:00
|
|
|
GdkRectangle size_pixels;
|
|
|
|
gint width_mm, height_mm;
|
|
|
|
gdouble x = 0.0;
|
|
|
|
gdouble y = 0.0;
|
2018-06-25 01:31:09 +02:00
|
|
|
#ifdef PLATFORM_OSX
|
|
|
|
CGSize size;
|
|
|
|
#endif
|
2003-05-29 11:34:30 +00:00
|
|
|
|
2018-04-29 17:27:47 +02:00
|
|
|
g_return_if_fail (GDK_IS_MONITOR (monitor));
|
2003-05-29 11:34:30 +00:00
|
|
|
g_return_if_fail (xres != NULL);
|
|
|
|
g_return_if_fail (yres != NULL);
|
|
|
|
|
2018-06-25 01:31:09 +02:00
|
|
|
#ifndef PLATFORM_OSX
|
2018-04-29 17:27:47 +02:00
|
|
|
gdk_monitor_get_geometry (monitor, &size_pixels);
|
2003-05-29 11:34:30 +00:00
|
|
|
|
2018-04-29 17:27:47 +02:00
|
|
|
width_mm = gdk_monitor_get_width_mm (monitor);
|
|
|
|
height_mm = gdk_monitor_get_height_mm (monitor);
|
2018-06-25 01:31:09 +02:00
|
|
|
#else
|
|
|
|
width_mm = 0;
|
|
|
|
height_mm = 0;
|
|
|
|
size = CGDisplayScreenSize (kCGDirectMainDisplay);
|
|
|
|
if (!CGSizeEqualToSize (size, CGSizeZero))
|
|
|
|
{
|
|
|
|
width_mm = size.width;
|
|
|
|
height_mm = size.height;
|
|
|
|
}
|
|
|
|
size_pixels.width = CGDisplayPixelsWide (kCGDirectMainDisplay);
|
|
|
|
size_pixels.height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
|
|
|
|
#endif
|
2003-05-29 11:34:30 +00:00
|
|
|
/*
|
|
|
|
* From xdpyinfo.c:
|
|
|
|
*
|
|
|
|
* there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
|
|
|
|
*
|
|
|
|
* dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
|
|
|
|
* = N pixels / (M inch / 25.4)
|
|
|
|
* = N * 25.4 pixels / M inch
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (width_mm > 0 && height_mm > 0)
|
|
|
|
{
|
2014-05-02 23:56:16 +02:00
|
|
|
x = (size_pixels.width * 25.4) / (gdouble) width_mm;
|
|
|
|
y = (size_pixels.height * 25.4) / (gdouble) height_mm;
|
2003-05-29 11:34:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (x < GIMP_MIN_RESOLUTION || x > GIMP_MAX_RESOLUTION ||
|
|
|
|
y < GIMP_MIN_RESOLUTION || y > GIMP_MAX_RESOLUTION)
|
|
|
|
{
|
2014-05-03 17:17:46 +02:00
|
|
|
g_printerr ("gimp_get_monitor_resolution(): GDK returned bogus "
|
2014-05-08 12:12:19 +02:00
|
|
|
"values for the monitor resolution, using 96 dpi instead.\n");
|
2003-05-29 11:34:30 +00:00
|
|
|
|
2007-02-01 10:44:01 +00:00
|
|
|
x = 96.0;
|
|
|
|
y = 96.0;
|
2003-05-29 11:34:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* round the value to full integers to give more pleasant results */
|
|
|
|
*xres = ROUND (x);
|
|
|
|
*yres = ROUND (y);
|
|
|
|
}
|
2003-06-10 16:44:44 +00:00
|
|
|
|
2011-02-07 22:16:05 +01:00
|
|
|
gboolean
|
|
|
|
gimp_get_style_color (GtkWidget *widget,
|
|
|
|
const gchar *property_name,
|
|
|
|
GdkRGBA *color)
|
|
|
|
{
|
|
|
|
GdkRGBA *c = NULL;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
|
|
|
g_return_val_if_fail (property_name != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (color != NULL, FALSE);
|
|
|
|
|
|
|
|
gtk_widget_style_get (widget,
|
|
|
|
property_name, &c,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (c)
|
|
|
|
{
|
|
|
|
*color = *c;
|
|
|
|
gdk_rgba_free (c);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return ugly magenta to indicate that something is wrong */
|
|
|
|
color->red = 1.0;
|
|
|
|
color->green = 1.0;
|
|
|
|
color->blue = 0.0;
|
|
|
|
color->alpha = 1.0;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-01-16 23:18:23 +00:00
|
|
|
void
|
|
|
|
gimp_window_set_hint (GtkWindow *window,
|
|
|
|
GimpWindowHint hint)
|
2003-11-20 20:36:55 +00:00
|
|
|
{
|
2004-01-16 23:18:23 +00:00
|
|
|
g_return_if_fail (GTK_IS_WINDOW (window));
|
|
|
|
|
2003-11-20 20:36:55 +00:00
|
|
|
switch (hint)
|
|
|
|
{
|
2004-01-16 23:18:23 +00:00
|
|
|
case GIMP_WINDOW_HINT_NORMAL:
|
|
|
|
gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_NORMAL);
|
|
|
|
break;
|
2003-11-20 20:36:55 +00:00
|
|
|
|
2004-01-16 23:18:23 +00:00
|
|
|
case GIMP_WINDOW_HINT_UTILITY:
|
|
|
|
gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_UTILITY);
|
|
|
|
break;
|
2004-05-04 13:31:57 +00:00
|
|
|
|
|
|
|
case GIMP_WINDOW_HINT_KEEP_ABOVE:
|
|
|
|
gtk_window_set_keep_above (window, TRUE);
|
|
|
|
break;
|
2003-11-20 20:36:55 +00:00
|
|
|
}
|
|
|
|
}
|
2004-08-10 22:21:56 +00:00
|
|
|
|
2005-09-09 18:07:31 +00:00
|
|
|
/**
|
2011-02-06 12:07:55 +01:00
|
|
|
* gimp_window_get_native_id:
|
2005-09-09 18:07:31 +00:00
|
|
|
* @window: a #GtkWindow
|
|
|
|
*
|
|
|
|
* This function is used to pass a window handle to plug-ins so that
|
|
|
|
* they can set their dialog windows transient to the parent window.
|
|
|
|
*
|
2019-08-03 00:10:14 +02:00
|
|
|
* Returns: a native window ID of the window's #GdkWindow or 0
|
2005-09-09 18:07:31 +00:00
|
|
|
* if the window isn't realized yet
|
|
|
|
*/
|
2011-02-06 12:07:55 +01:00
|
|
|
guint32
|
|
|
|
gimp_window_get_native_id (GtkWindow *window)
|
2005-09-09 18:07:31 +00:00
|
|
|
{
|
2020-12-30 12:22:42 +01:00
|
|
|
GdkWindow *surface;
|
|
|
|
|
2005-09-09 18:07:31 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
|
|
|
|
|
2020-12-30 12:22:42 +01:00
|
|
|
surface = gtk_widget_get_window (GTK_WIDGET (window));
|
|
|
|
if (!surface) /* aka window is not yet realized */
|
|
|
|
return 0;
|
2005-09-09 18:07:31 +00:00
|
|
|
|
|
|
|
#ifdef GDK_WINDOWING_WIN32
|
2020-12-30 12:22:42 +01:00
|
|
|
if (GDK_IS_WIN32_WINDOW (surface))
|
2011-02-06 12:07:55 +01:00
|
|
|
return GDK_WINDOW_HWND (gtk_widget_get_window (GTK_WIDGET (window)));
|
2005-09-09 18:07:31 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
2020-12-30 12:22:42 +01:00
|
|
|
if (GDK_IS_X11_WINDOW (surface))
|
2009-03-22 16:35:53 +00:00
|
|
|
return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (window)));
|
2005-09-09 18:07:31 +00:00
|
|
|
#endif
|
|
|
|
|
2020-12-30 12:22:42 +01:00
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
if (GDK_IS_WAYLAND_WINDOW (surface))
|
|
|
|
g_debug ("Getting window ID for progress not supported on Wayland yet");
|
|
|
|
#endif
|
|
|
|
|
2011-02-06 12:07:55 +01:00
|
|
|
return 0;
|
2005-09-09 18:07:31 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 14:02:38 +02:00
|
|
|
#ifndef GDK_WINDOWING_WIN32
|
2006-09-22 09:24:41 +00:00
|
|
|
static void
|
|
|
|
gimp_window_transient_realized (GtkWidget *window,
|
|
|
|
GdkWindow *parent)
|
|
|
|
{
|
2010-04-19 19:21:07 +02:00
|
|
|
if (gtk_widget_get_realized (window))
|
2009-03-22 16:35:53 +00:00
|
|
|
gdk_window_set_transient_for (gtk_widget_get_window (window), parent);
|
2006-09-22 09:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* similar to what we have in libgimp/gimpui.c */
|
2011-02-16 22:51:02 +01:00
|
|
|
static GdkWindow *
|
|
|
|
gimp_get_foreign_window (guint32 window)
|
|
|
|
{
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
2020-06-21 12:54:13 +02:00
|
|
|
if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
|
|
|
|
return gdk_x11_window_foreign_new_for_display (gdk_display_get_default (),
|
|
|
|
window);
|
2011-02-16 22:51:02 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef GDK_WINDOWING_WIN32
|
|
|
|
return gdk_win32_window_foreign_new_for_display (gdk_display_get_default (),
|
|
|
|
window);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-10-10 14:02:38 +02:00
|
|
|
#endif
|
2011-02-16 22:51:02 +01:00
|
|
|
|
2006-09-22 09:24:41 +00:00
|
|
|
void
|
|
|
|
gimp_window_set_transient_for (GtkWindow *window,
|
|
|
|
guint32 parent_ID)
|
|
|
|
{
|
2006-10-16 11:55:50 +00:00
|
|
|
/* Cross-process transient-for is broken in gdk/win32 <= 2.10.6. It
|
|
|
|
* causes hangs, at least when used as by the gimp and script-fu
|
|
|
|
* processes. In some newer GTK+ version it will be fixed to be a
|
|
|
|
* no-op. If it eventually is fixed to actually work, change this to
|
|
|
|
* a run-time check of GTK+ version. Remember to change also the
|
|
|
|
* function with the same name in libgimp/gimpui.c
|
2019-10-10 14:02:38 +02:00
|
|
|
*
|
|
|
|
* Note: this hanging bug is still happening with GTK+3 as of 2019-10,
|
|
|
|
* with steps described in comment 4 in:
|
|
|
|
* https://bugzilla.gnome.org/show_bug.cgi?id=359538
|
2006-10-16 11:55:50 +00:00
|
|
|
*/
|
|
|
|
#ifndef GDK_WINDOWING_WIN32
|
2006-09-22 09:24:41 +00:00
|
|
|
GdkWindow *parent;
|
|
|
|
|
2011-02-16 22:51:02 +01:00
|
|
|
parent = gimp_get_foreign_window (parent_ID);
|
2006-09-22 09:24:41 +00:00
|
|
|
if (! parent)
|
|
|
|
return;
|
|
|
|
|
2010-04-19 19:21:07 +02:00
|
|
|
if (gtk_widget_get_realized (GTK_WIDGET (window)))
|
2009-03-22 16:35:53 +00:00
|
|
|
gdk_window_set_transient_for (gtk_widget_get_window (GTK_WIDGET (window)),
|
|
|
|
parent);
|
2006-09-22 09:24:41 +00:00
|
|
|
|
|
|
|
g_signal_connect_object (window, "realize",
|
|
|
|
G_CALLBACK (gimp_window_transient_realized),
|
|
|
|
parent, 0);
|
|
|
|
|
|
|
|
g_object_unref (parent);
|
2006-10-16 11:55:50 +00:00
|
|
|
#endif
|
2006-09-22 09:24:41 +00:00
|
|
|
}
|
|
|
|
|
2005-09-16 00:46:21 +00:00
|
|
|
static gboolean
|
|
|
|
gimp_widget_accel_find_func (GtkAccelKey *key,
|
|
|
|
GClosure *closure,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
return (GClosure *) data == closure;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_widget_accel_changed (GtkAccelGroup *accel_group,
|
|
|
|
guint unused1,
|
|
|
|
GdkModifierType unused2,
|
|
|
|
GClosure *accel_closure,
|
|
|
|
GtkWidget *widget)
|
|
|
|
{
|
|
|
|
GClosure *widget_closure;
|
|
|
|
|
|
|
|
widget_closure = g_object_get_data (G_OBJECT (widget), "gimp-accel-closure");
|
|
|
|
|
|
|
|
if (accel_closure == widget_closure)
|
|
|
|
{
|
2019-07-02 03:54:38 +02:00
|
|
|
GimpAction *action;
|
2005-09-16 00:46:21 +00:00
|
|
|
GtkAccelKey *accel_key;
|
2009-05-24 22:29:18 +02:00
|
|
|
const gchar *tooltip;
|
2005-09-16 00:46:21 +00:00
|
|
|
const gchar *help_id;
|
|
|
|
|
|
|
|
action = g_object_get_data (G_OBJECT (widget), "gimp-accel-action");
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
tooltip = gimp_action_get_tooltip (action);
|
|
|
|
help_id = gimp_action_get_help_id (action);
|
2005-09-16 00:46:21 +00:00
|
|
|
|
|
|
|
accel_key = gtk_accel_group_find (accel_group,
|
|
|
|
gimp_widget_accel_find_func,
|
|
|
|
accel_closure);
|
|
|
|
|
|
|
|
if (accel_key &&
|
|
|
|
accel_key->accel_key &&
|
2016-09-09 23:28:37 +02:00
|
|
|
(accel_key->accel_flags & GTK_ACCEL_VISIBLE))
|
2005-09-16 00:46:21 +00:00
|
|
|
{
|
2007-11-26 17:04:39 +00:00
|
|
|
gchar *escaped = g_markup_escape_text (tooltip, -1);
|
|
|
|
gchar *accel = gtk_accelerator_get_label (accel_key->accel_key,
|
|
|
|
accel_key->accel_mods);
|
|
|
|
gchar *tmp = g_strdup_printf ("%s <b>%s</b>", escaped, accel);
|
2005-10-31 11:29:01 +00:00
|
|
|
|
2007-09-25 11:12:56 +00:00
|
|
|
g_free (accel);
|
2007-11-26 17:04:39 +00:00
|
|
|
g_free (escaped);
|
|
|
|
|
|
|
|
gimp_help_set_help_data_with_markup (widget, tmp, help_id);
|
|
|
|
g_free (tmp);
|
2005-09-16 00:46:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-11-26 17:04:39 +00:00
|
|
|
gimp_help_set_help_data (widget, tooltip, help_id);
|
2005-09-16 00:46:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 23:28:37 +02:00
|
|
|
static void gimp_accel_help_widget_weak_notify (gpointer accel_group,
|
|
|
|
GObject *where_widget_was);
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_accel_help_accel_group_weak_notify (gpointer widget,
|
|
|
|
GObject *where_accel_group_was)
|
|
|
|
{
|
|
|
|
g_object_weak_unref (widget,
|
|
|
|
gimp_accel_help_widget_weak_notify,
|
|
|
|
where_accel_group_was);
|
|
|
|
|
|
|
|
g_object_set_data (widget, "gimp-accel-group", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_accel_help_widget_weak_notify (gpointer accel_group,
|
|
|
|
GObject *where_widget_was)
|
|
|
|
{
|
|
|
|
g_object_weak_unref (accel_group,
|
|
|
|
gimp_accel_help_accel_group_weak_notify,
|
|
|
|
where_widget_was);
|
|
|
|
}
|
|
|
|
|
2005-09-16 00:46:21 +00:00
|
|
|
void
|
2019-07-02 03:54:38 +02:00
|
|
|
gimp_widget_set_accel_help (GtkWidget *widget,
|
|
|
|
GimpAction *action)
|
2005-09-16 00:46:21 +00:00
|
|
|
{
|
2016-09-09 23:28:37 +02:00
|
|
|
GtkAccelGroup *accel_group;
|
|
|
|
GClosure *accel_closure;
|
|
|
|
|
|
|
|
accel_group = g_object_get_data (G_OBJECT (widget), "gimp-accel-group");
|
|
|
|
|
|
|
|
if (accel_group)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (accel_group,
|
|
|
|
gimp_widget_accel_changed,
|
|
|
|
widget);
|
|
|
|
g_object_weak_unref (G_OBJECT (accel_group),
|
|
|
|
gimp_accel_help_accel_group_weak_notify,
|
|
|
|
widget);
|
|
|
|
g_object_weak_unref (G_OBJECT (widget),
|
|
|
|
gimp_accel_help_widget_weak_notify,
|
|
|
|
accel_group);
|
|
|
|
g_object_set_data (G_OBJECT (widget), "gimp-accel-group", NULL);
|
|
|
|
}
|
|
|
|
|
2019-07-02 03:54:38 +02:00
|
|
|
accel_closure = gimp_action_get_accel_closure (action);
|
2005-09-16 00:46:21 +00:00
|
|
|
|
|
|
|
if (accel_closure)
|
|
|
|
{
|
2016-09-09 23:28:37 +02:00
|
|
|
accel_group = gtk_accel_group_from_accel_closure (accel_closure);
|
|
|
|
|
|
|
|
g_object_set_data (G_OBJECT (widget), "gimp-accel-group",
|
|
|
|
accel_group);
|
|
|
|
g_object_weak_ref (G_OBJECT (accel_group),
|
|
|
|
gimp_accel_help_accel_group_weak_notify,
|
|
|
|
widget);
|
|
|
|
g_object_weak_ref (G_OBJECT (widget),
|
|
|
|
gimp_accel_help_widget_weak_notify,
|
|
|
|
accel_group);
|
2005-09-16 00:46:21 +00:00
|
|
|
|
|
|
|
g_object_set_data (G_OBJECT (widget), "gimp-accel-closure",
|
|
|
|
accel_closure);
|
|
|
|
g_object_set_data (G_OBJECT (widget), "gimp-accel-action",
|
|
|
|
action);
|
|
|
|
|
|
|
|
g_signal_connect_object (accel_group, "accel-changed",
|
|
|
|
G_CALLBACK (gimp_widget_accel_changed),
|
|
|
|
widget, 0);
|
|
|
|
|
|
|
|
gimp_widget_accel_changed (accel_group,
|
|
|
|
0, 0,
|
|
|
|
accel_closure,
|
|
|
|
widget);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-02 03:54:38 +02:00
|
|
|
gimp_help_set_help_data (widget,
|
|
|
|
gimp_action_get_tooltip (action),
|
|
|
|
gimp_action_get_help_id (action));
|
2005-09-16 00:46:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2006-08-11 12:56:26 +00:00
|
|
|
|
2006-10-09 08:17:22 +00:00
|
|
|
const gchar *
|
2014-05-07 15:30:38 +02:00
|
|
|
gimp_get_message_icon_name (GimpMessageSeverity severity)
|
2006-08-11 12:56:26 +00:00
|
|
|
{
|
2006-10-09 08:17:22 +00:00
|
|
|
switch (severity)
|
|
|
|
{
|
|
|
|
case GIMP_MESSAGE_INFO:
|
2017-03-05 16:01:59 +01:00
|
|
|
return GIMP_ICON_DIALOG_INFORMATION;
|
2006-08-11 12:56:26 +00:00
|
|
|
|
2006-10-09 08:17:22 +00:00
|
|
|
case GIMP_MESSAGE_WARNING:
|
2017-03-05 16:01:59 +01:00
|
|
|
return GIMP_ICON_DIALOG_WARNING;
|
2006-08-11 12:56:26 +00:00
|
|
|
|
2006-10-09 08:17:22 +00:00
|
|
|
case GIMP_MESSAGE_ERROR:
|
2017-03-05 16:01:59 +01:00
|
|
|
return GIMP_ICON_DIALOG_ERROR;
|
2018-02-12 17:20:53 +01:00
|
|
|
|
|
|
|
case GIMP_MESSAGE_BUG_WARNING:
|
|
|
|
case GIMP_MESSAGE_BUG_CRITICAL:
|
|
|
|
return GIMP_ICON_WILBER_EEK;
|
2006-10-09 08:17:22 +00:00
|
|
|
}
|
2006-08-11 12:56:26 +00:00
|
|
|
|
2017-03-05 16:01:59 +01:00
|
|
|
g_return_val_if_reached (GIMP_ICON_DIALOG_WARNING);
|
2006-08-11 12:56:26 +00:00
|
|
|
}
|
2008-03-19 09:29:30 +00:00
|
|
|
|
2016-10-29 16:50:13 +02:00
|
|
|
gboolean
|
|
|
|
gimp_get_color_tag_color (GimpColorTag color_tag,
|
2017-12-07 16:42:54 -05:00
|
|
|
GimpRGB *color,
|
|
|
|
gboolean inherited)
|
2016-10-29 16:50:13 +02:00
|
|
|
{
|
|
|
|
static const struct
|
|
|
|
{
|
|
|
|
guchar r;
|
|
|
|
guchar g;
|
|
|
|
guchar b;
|
|
|
|
}
|
|
|
|
colors[] =
|
|
|
|
{
|
2017-02-19 14:06:43 +03:00
|
|
|
{ 0, 0, 0 }, /* none */
|
|
|
|
{ 84, 102, 159 }, /* blue */
|
|
|
|
{ 111, 143, 48 }, /* green */
|
|
|
|
{ 210, 182, 45 }, /* yellow */
|
|
|
|
{ 217, 122, 38 }, /* orange */
|
|
|
|
{ 87, 53, 25 }, /* brown */
|
|
|
|
{ 170, 42, 47 }, /* red */
|
|
|
|
{ 99, 66, 174 }, /* violet */
|
|
|
|
{ 87, 87, 87 } /* gray */
|
2016-10-29 16:50:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
g_return_val_if_fail (color != NULL, FALSE);
|
2017-12-07 16:42:54 -05:00
|
|
|
g_return_val_if_fail (color_tag < G_N_ELEMENTS (colors), FALSE);
|
2016-10-29 16:50:13 +02:00
|
|
|
|
|
|
|
if (color_tag > GIMP_COLOR_TAG_NONE)
|
|
|
|
{
|
|
|
|
gimp_rgba_set_uchar (color,
|
|
|
|
colors[color_tag].r,
|
|
|
|
colors[color_tag].g,
|
|
|
|
colors[color_tag].b,
|
|
|
|
255);
|
|
|
|
|
2017-12-07 16:42:54 -05:00
|
|
|
if (inherited)
|
|
|
|
{
|
|
|
|
gimp_rgb_composite (color, &(GimpRGB) {1.0, 1.0, 1.0, 0.2},
|
|
|
|
GIMP_RGB_COMPOSITE_NORMAL);
|
|
|
|
}
|
|
|
|
|
2016-10-29 16:50:13 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-09-30 11:16:28 +00:00
|
|
|
void
|
|
|
|
gimp_pango_layout_set_scale (PangoLayout *layout,
|
|
|
|
gdouble scale)
|
|
|
|
{
|
|
|
|
PangoAttrList *attrs;
|
|
|
|
PangoAttribute *attr;
|
|
|
|
|
|
|
|
g_return_if_fail (PANGO_IS_LAYOUT (layout));
|
|
|
|
|
|
|
|
attrs = pango_attr_list_new ();
|
|
|
|
|
|
|
|
attr = pango_attr_scale_new (scale);
|
|
|
|
attr->start_index = 0;
|
|
|
|
attr->end_index = -1;
|
|
|
|
pango_attr_list_insert (attrs, attr);
|
|
|
|
|
|
|
|
pango_layout_set_attributes (layout, attrs);
|
|
|
|
pango_attr_list_unref (attrs);
|
|
|
|
}
|
|
|
|
|
2008-03-19 09:29:30 +00:00
|
|
|
void
|
|
|
|
gimp_pango_layout_set_weight (PangoLayout *layout,
|
|
|
|
PangoWeight weight)
|
|
|
|
{
|
|
|
|
PangoAttrList *attrs;
|
|
|
|
PangoAttribute *attr;
|
|
|
|
|
2008-09-30 11:16:28 +00:00
|
|
|
g_return_if_fail (PANGO_IS_LAYOUT (layout));
|
|
|
|
|
2008-03-19 09:29:30 +00:00
|
|
|
attrs = pango_attr_list_new ();
|
|
|
|
|
2008-09-30 11:09:06 +00:00
|
|
|
attr = pango_attr_weight_new (weight);
|
2008-03-19 09:29:30 +00:00
|
|
|
attr->start_index = 0;
|
|
|
|
attr->end_index = -1;
|
|
|
|
pango_attr_list_insert (attrs, attr);
|
|
|
|
|
|
|
|
pango_layout_set_attributes (layout, attrs);
|
|
|
|
pango_attr_list_unref (attrs);
|
|
|
|
}
|
2009-11-28 19:12:39 +01:00
|
|
|
|
2017-10-28 09:30:42 -04:00
|
|
|
static gboolean
|
2018-02-11 17:25:33 +01:00
|
|
|
gimp_highlight_widget_draw (GtkWidget *widget,
|
|
|
|
cairo_t *cr,
|
|
|
|
gpointer data)
|
2017-10-28 09:30:42 -04:00
|
|
|
{
|
2021-02-09 11:50:23 +01:00
|
|
|
GdkRectangle *rect = (GdkRectangle *) data;
|
|
|
|
|
2018-05-13 15:11:13 +02:00
|
|
|
/* this code is a straight copy of draw_flash() from gtk-inspector's
|
|
|
|
* inspect-button.c
|
2017-10-28 09:30:42 -04:00
|
|
|
*/
|
|
|
|
|
2018-05-13 15:11:13 +02:00
|
|
|
GtkAllocation alloc;
|
2017-10-28 09:30:42 -04:00
|
|
|
|
2021-02-09 11:50:23 +01:00
|
|
|
if (rect)
|
|
|
|
{
|
|
|
|
alloc.x = rect->x;
|
|
|
|
alloc.y = rect->y;
|
|
|
|
alloc.width = rect->width;
|
|
|
|
alloc.height = rect->height;
|
|
|
|
}
|
|
|
|
else if (GTK_IS_WINDOW (widget))
|
2018-05-13 15:11:13 +02:00
|
|
|
{
|
|
|
|
GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
|
|
|
|
/* We don't want to draw the drag highlight around the
|
|
|
|
* CSD window decorations
|
|
|
|
*/
|
|
|
|
if (child == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gtk_widget_get_allocation (child, &alloc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
alloc.x = 0;
|
|
|
|
alloc.y = 0;
|
|
|
|
alloc.width = gtk_widget_get_allocated_width (widget);
|
|
|
|
alloc.height = gtk_widget_get_allocated_height (widget);
|
|
|
|
}
|
2017-10-28 09:30:42 -04:00
|
|
|
|
2018-05-13 15:11:13 +02:00
|
|
|
cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.2);
|
2018-02-11 17:25:33 +01:00
|
|
|
cairo_rectangle (cr,
|
2018-05-13 15:11:13 +02:00
|
|
|
alloc.x + 0.5, alloc.y + 0.5,
|
|
|
|
alloc.width - 1, alloc.height - 1);
|
|
|
|
cairo_fill (cr);
|
2017-10-28 09:30:42 -04:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-11-28 19:12:39 +01:00
|
|
|
/**
|
|
|
|
* gimp_highlight_widget:
|
|
|
|
* @widget:
|
|
|
|
* @highlight:
|
2021-02-09 11:50:23 +01:00
|
|
|
* @rect:
|
2009-11-28 19:12:39 +01:00
|
|
|
*
|
2017-10-28 09:30:42 -04:00
|
|
|
* Turns highlighting for @widget on or off according to
|
2017-10-29 09:48:00 -04:00
|
|
|
* @highlight, in a similar fashion to gtk_drag_highlight()
|
|
|
|
* and gtk_drag_unhighlight().
|
2021-02-09 11:50:23 +01:00
|
|
|
*
|
|
|
|
* If @rect is %NULL, highlight the full widget, otherwise highlight the
|
|
|
|
* specific rectangle in widget coordinates.
|
|
|
|
* When unhighlighting (i.e. @highlight is %FALSE), the value of @rect
|
|
|
|
* doesn't matter, as the previously used rectangle will be reused.
|
2009-11-28 19:12:39 +01:00
|
|
|
**/
|
|
|
|
void
|
2021-02-09 11:50:23 +01:00
|
|
|
gimp_highlight_widget (GtkWidget *widget,
|
|
|
|
gboolean highlight,
|
|
|
|
GdkRectangle *rect)
|
2009-11-28 19:12:39 +01:00
|
|
|
{
|
2021-02-09 11:50:23 +01:00
|
|
|
GdkRectangle *old_rect;
|
|
|
|
gboolean old_highlight;
|
2018-05-23 19:45:03 +02:00
|
|
|
|
2009-11-28 19:12:39 +01:00
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
|
2018-05-23 19:45:03 +02:00
|
|
|
highlight = highlight ? TRUE : FALSE;
|
|
|
|
|
|
|
|
old_highlight = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
|
|
|
|
"gimp-widget-highlight"));
|
2021-02-09 11:50:23 +01:00
|
|
|
old_rect = g_object_get_data (G_OBJECT (widget), "gimp-widget-highlight-rect");
|
|
|
|
|
2021-02-25 19:24:54 +01:00
|
|
|
if (highlight && old_highlight &&
|
|
|
|
rect && old_rect && ! gdk_rectangle_equal (rect, old_rect))
|
2021-02-09 11:50:23 +01:00
|
|
|
{
|
|
|
|
/* Highlight area changed. */
|
|
|
|
gimp_highlight_widget (widget, FALSE, NULL);
|
|
|
|
old_highlight = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
|
|
|
|
"gimp-widget-highlight"));
|
|
|
|
old_rect = g_object_get_data (G_OBJECT (widget), "gimp-widget-highlight-rect");
|
|
|
|
}
|
2018-05-23 19:45:03 +02:00
|
|
|
|
|
|
|
if (highlight != old_highlight)
|
2017-10-28 09:30:42 -04:00
|
|
|
{
|
2018-05-23 19:45:03 +02:00
|
|
|
if (highlight)
|
|
|
|
{
|
2021-02-09 11:50:23 +01:00
|
|
|
GdkRectangle *new_rect = NULL;
|
|
|
|
|
|
|
|
if (rect)
|
|
|
|
{
|
|
|
|
new_rect = g_new0 (GdkRectangle, 1);
|
|
|
|
*new_rect = *rect;
|
|
|
|
g_object_set_data_full (G_OBJECT (widget),
|
|
|
|
"gimp-widget-highlight-rect",
|
|
|
|
new_rect,
|
|
|
|
(GDestroyNotify) g_free);
|
|
|
|
}
|
2018-05-23 19:45:03 +02:00
|
|
|
g_signal_connect_after (widget, "draw",
|
|
|
|
G_CALLBACK (gimp_highlight_widget_draw),
|
2021-02-09 11:50:23 +01:00
|
|
|
new_rect);
|
2018-05-23 19:45:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-09 11:50:23 +01:00
|
|
|
if (old_rect)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (widget,
|
|
|
|
gimp_highlight_widget_draw,
|
|
|
|
old_rect);
|
|
|
|
g_object_set_data (G_OBJECT (widget),
|
|
|
|
"gimp-widget-highlight-rect",
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2018-05-23 19:45:03 +02:00
|
|
|
g_signal_handlers_disconnect_by_func (widget,
|
|
|
|
gimp_highlight_widget_draw,
|
|
|
|
NULL);
|
|
|
|
}
|
2017-10-28 09:30:42 -04:00
|
|
|
|
2018-05-23 19:45:03 +02:00
|
|
|
g_object_set_data (G_OBJECT (widget),
|
|
|
|
"gimp-widget-highlight",
|
|
|
|
GINT_TO_POINTER (highlight));
|
|
|
|
|
|
|
|
gtk_widget_queue_draw (widget);
|
|
|
|
}
|
2009-11-28 19:12:39 +01:00
|
|
|
}
|
2010-02-20 16:55:35 +01:00
|
|
|
|
2017-10-29 09:48:00 -04:00
|
|
|
typedef struct
|
|
|
|
{
|
2021-02-09 11:50:23 +01:00
|
|
|
gint timeout_id;
|
|
|
|
gint counter;
|
|
|
|
GdkRectangle *rect;
|
2017-10-29 09:48:00 -04:00
|
|
|
} WidgetBlink;
|
|
|
|
|
|
|
|
static WidgetBlink *
|
|
|
|
widget_blink_new (void)
|
|
|
|
{
|
|
|
|
WidgetBlink *blink;
|
|
|
|
|
|
|
|
blink = g_slice_new (WidgetBlink);
|
|
|
|
|
|
|
|
blink->timeout_id = 0;
|
|
|
|
blink->counter = 0;
|
2021-02-09 11:50:23 +01:00
|
|
|
blink->rect = NULL;
|
2017-10-29 09:48:00 -04:00
|
|
|
|
|
|
|
return blink;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
widget_blink_free (WidgetBlink *blink)
|
|
|
|
{
|
|
|
|
if (blink->timeout_id)
|
|
|
|
{
|
|
|
|
g_source_remove (blink->timeout_id);
|
|
|
|
blink->timeout_id = 0;
|
|
|
|
}
|
|
|
|
|
2021-02-09 11:50:23 +01:00
|
|
|
if (blink->rect)
|
|
|
|
g_slice_free (GdkRectangle, blink->rect);
|
|
|
|
|
2017-10-29 09:48:00 -04:00
|
|
|
g_slice_free (WidgetBlink, blink);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_widget_blink_timeout (GtkWidget *widget)
|
|
|
|
{
|
|
|
|
WidgetBlink *blink;
|
2022-03-05 17:29:44 +01:00
|
|
|
GList *script;
|
2017-10-29 09:48:00 -04:00
|
|
|
|
2022-03-05 17:29:44 +01:00
|
|
|
blink = g_object_get_data (G_OBJECT (widget), "gimp-widget-blink");
|
|
|
|
script = g_object_get_data (G_OBJECT (widget), "gimp-widget-blink-script");
|
2017-10-29 09:48:00 -04:00
|
|
|
|
2021-02-09 11:50:23 +01:00
|
|
|
gimp_highlight_widget (widget, blink->counter % 2 == 1, blink->rect);
|
2017-10-29 09:48:00 -04:00
|
|
|
blink->counter++;
|
|
|
|
|
|
|
|
if (blink->counter == 3)
|
|
|
|
{
|
|
|
|
blink->timeout_id = 0;
|
|
|
|
|
|
|
|
g_object_set_data (G_OBJECT (widget), "gimp-widget-blink", NULL);
|
|
|
|
|
2022-03-05 17:29:44 +01:00
|
|
|
if (script)
|
|
|
|
{
|
|
|
|
GtkWidget *next_widget = script->data;
|
|
|
|
|
|
|
|
if (script->next)
|
|
|
|
g_object_set_data_full (G_OBJECT (next_widget), "gimp-widget-blink-script",
|
|
|
|
g_list_copy (script->next),
|
|
|
|
(GDestroyNotify) g_list_free);
|
|
|
|
|
|
|
|
gimp_widget_blink (next_widget);
|
|
|
|
|
|
|
|
g_object_set_data (G_OBJECT (widget), "gimp-widget-blink-script", NULL);
|
|
|
|
}
|
|
|
|
|
2017-10-29 09:48:00 -04:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_widget_blink (GtkWidget *widget)
|
|
|
|
{
|
|
|
|
WidgetBlink *blink;
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
|
2018-05-23 19:45:03 +02:00
|
|
|
gimp_widget_blink_cancel (widget);
|
|
|
|
|
2017-10-29 09:48:00 -04:00
|
|
|
blink = widget_blink_new ();
|
|
|
|
|
|
|
|
g_object_set_data_full (G_OBJECT (widget), "gimp-widget-blink", blink,
|
|
|
|
(GDestroyNotify) widget_blink_free);
|
|
|
|
|
|
|
|
blink->timeout_id = g_timeout_add (150,
|
|
|
|
(GSourceFunc) gimp_widget_blink_timeout,
|
|
|
|
widget);
|
|
|
|
|
2021-02-09 11:50:23 +01:00
|
|
|
gimp_highlight_widget (widget, TRUE, NULL);
|
|
|
|
|
|
|
|
while ((widget = gtk_widget_get_parent (widget)))
|
|
|
|
gimp_widget_blink_cancel (widget);
|
|
|
|
}
|
|
|
|
|
2022-03-05 17:29:44 +01:00
|
|
|
void
|
|
|
|
gimp_widget_script_blink (GtkWidget *widget,
|
|
|
|
GList **blink_scenario)
|
|
|
|
{
|
|
|
|
*blink_scenario = g_list_append (*blink_scenario, widget);
|
|
|
|
|
|
|
|
while ((widget = gtk_widget_get_parent (widget)))
|
|
|
|
gimp_widget_blink_cancel (widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_blink_play_script (GList *blink_scenario)
|
|
|
|
{
|
|
|
|
g_return_if_fail (g_list_length (blink_scenario) > 0);
|
|
|
|
|
|
|
|
g_object_set_data_full (G_OBJECT (blink_scenario->data),
|
|
|
|
"gimp-widget-blink-script",
|
|
|
|
g_list_copy (blink_scenario->next),
|
|
|
|
(GDestroyNotify) g_list_free);
|
|
|
|
gimp_widget_blink (blink_scenario->data);
|
|
|
|
}
|
|
|
|
|
2021-02-09 11:50:23 +01:00
|
|
|
void
|
|
|
|
gimp_widget_blink_rect (GtkWidget *widget,
|
|
|
|
GdkRectangle *rect)
|
|
|
|
{
|
|
|
|
WidgetBlink *blink;
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
|
|
|
|
gimp_widget_blink_cancel (widget);
|
|
|
|
|
|
|
|
blink = widget_blink_new ();
|
|
|
|
blink->rect = g_slice_new (GdkRectangle);
|
|
|
|
*(blink->rect) = *rect;
|
|
|
|
|
|
|
|
g_object_set_data_full (G_OBJECT (widget), "gimp-widget-blink", blink,
|
|
|
|
(GDestroyNotify) widget_blink_free);
|
|
|
|
|
|
|
|
blink->timeout_id = g_timeout_add (150,
|
|
|
|
(GSourceFunc) gimp_widget_blink_timeout,
|
|
|
|
widget);
|
|
|
|
|
|
|
|
gimp_highlight_widget (widget, TRUE, blink->rect);
|
2018-12-10 07:57:02 -05:00
|
|
|
|
|
|
|
while ((widget = gtk_widget_get_parent (widget)))
|
|
|
|
gimp_widget_blink_cancel (widget);
|
2017-10-29 09:48:00 -04:00
|
|
|
}
|
|
|
|
|
2018-05-23 19:45:03 +02:00
|
|
|
void
|
|
|
|
gimp_widget_blink_cancel (GtkWidget *widget)
|
2017-10-29 09:48:00 -04:00
|
|
|
{
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
|
2018-12-10 14:14:34 -05:00
|
|
|
if (g_object_get_data (G_OBJECT (widget), "gimp-widget-blink"))
|
|
|
|
{
|
2021-02-09 11:50:23 +01:00
|
|
|
gimp_highlight_widget (widget, FALSE, NULL);
|
2017-10-29 09:48:00 -04:00
|
|
|
|
2018-12-10 14:14:34 -05:00
|
|
|
g_object_set_data (G_OBJECT (widget), "gimp-widget-blink", NULL);
|
|
|
|
}
|
2017-10-29 09:48:00 -04:00
|
|
|
}
|
|
|
|
|
2022-03-05 14:32:34 +01:00
|
|
|
/**
|
|
|
|
* gimp_blink_dockable:
|
|
|
|
* @gimp:
|
|
|
|
* @dockable_identifier:
|
|
|
|
* @widget_identifier:
|
2022-03-05 17:29:44 +01:00
|
|
|
* @blink_scenario:
|
2022-03-05 14:32:34 +01:00
|
|
|
*
|
|
|
|
* This function will raise the dockable identified by
|
|
|
|
* @dockable_identifier. The list of dockable identifiers can be found
|
|
|
|
* in `app/dialogs/dialogs.c`.
|
|
|
|
*
|
|
|
|
* Then it will find the widget identified by @widget_identifier. Note
|
|
|
|
* that for propwidgets, this is usually the associated property name.
|
2022-03-05 17:29:44 +01:00
|
|
|
*
|
|
|
|
* Finally it will either blink this widget immediately to raise
|
|
|
|
* attention, or add it to the @blink_scenario if not %NULL. The blink
|
|
|
|
* scenario must be explicitly started with gimp_blink_play_script()
|
|
|
|
* when ready.
|
2022-03-05 14:32:34 +01:00
|
|
|
*/
|
|
|
|
void
|
2022-03-05 17:29:44 +01:00
|
|
|
gimp_blink_dockable (Gimp *gimp,
|
|
|
|
const gchar *dockable_identifier,
|
|
|
|
const gchar *widget_identifier,
|
|
|
|
GList **blink_scenario)
|
2022-03-05 14:32:34 +01:00
|
|
|
{
|
|
|
|
GtkWidget *dockable;
|
|
|
|
GdkMonitor *monitor;
|
2022-03-05 17:29:44 +01:00
|
|
|
BlinkData *data;
|
2022-03-05 14:32:34 +01:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_GIMP (gimp));
|
|
|
|
|
|
|
|
monitor = gimp_get_monitor_at_pointer ();
|
|
|
|
|
|
|
|
dockable = gimp_window_strategy_show_dockable_dialog (
|
|
|
|
GIMP_WINDOW_STRATEGY (gimp_get_window_strategy (gimp)),
|
|
|
|
gimp,
|
|
|
|
gimp_dialog_factory_get_singleton (),
|
|
|
|
monitor,
|
|
|
|
dockable_identifier);
|
|
|
|
|
|
|
|
if (! dockable)
|
|
|
|
return;
|
|
|
|
|
2022-03-05 22:59:55 +01:00
|
|
|
if (widget_identifier)
|
|
|
|
{
|
|
|
|
data = g_slice_new (BlinkData);
|
|
|
|
data->blink_script = blink_scenario;
|
|
|
|
data->widget_identifier = widget_identifier;
|
|
|
|
gtk_container_foreach (GTK_CONTAINER (dockable),
|
|
|
|
(GtkCallback) gimp_search_widget_rec,
|
|
|
|
(gpointer) data);
|
|
|
|
g_slice_free (BlinkData, data);
|
|
|
|
}
|
2022-03-05 14:32:34 +01:00
|
|
|
}
|
|
|
|
|
2010-02-20 16:55:35 +01:00
|
|
|
/**
|
|
|
|
* gimp_dock_with_window_new:
|
|
|
|
* @factory: a #GimpDialogFacotry
|
2018-04-29 17:27:47 +02:00
|
|
|
* @monitor: the #GdkMonitor the dock window should appear on
|
2010-02-20 16:55:35 +01:00
|
|
|
* @toolbox: if %TRUE; gives a "gimp-toolbox-window" with a
|
|
|
|
* "gimp-toolbox", "gimp-dock-window"+"gimp-dock"
|
|
|
|
* otherwise
|
|
|
|
*
|
|
|
|
* Returns: the newly created #GimpDock with the #GimpDockWindow
|
|
|
|
**/
|
|
|
|
GtkWidget *
|
|
|
|
gimp_dock_with_window_new (GimpDialogFactory *factory,
|
2018-04-29 17:27:47 +02:00
|
|
|
GdkMonitor *monitor,
|
2010-02-20 16:55:35 +01:00
|
|
|
gboolean toolbox)
|
|
|
|
{
|
2011-05-13 18:56:03 +02:00
|
|
|
GtkWidget *dock_window;
|
|
|
|
GimpDockContainer *dock_container;
|
|
|
|
GtkWidget *dock;
|
|
|
|
GimpUIManager *ui_manager;
|
2010-02-20 16:55:35 +01:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
|
2018-04-29 17:27:47 +02:00
|
|
|
g_return_val_if_fail (GDK_IS_MONITOR (monitor), NULL);
|
2010-02-20 16:55:35 +01:00
|
|
|
|
|
|
|
/* Create a dock window to put the dock in. We need to create the
|
|
|
|
* dock window before the dock because the dock has a dependency to
|
|
|
|
* the ui manager in the dock window
|
|
|
|
*/
|
2018-04-29 17:27:47 +02:00
|
|
|
dock_window = gimp_dialog_factory_dialog_new (factory, monitor,
|
2011-02-22 16:27:18 +01:00
|
|
|
NULL /*ui_manager*/,
|
2018-05-03 00:55:44 +02:00
|
|
|
NULL,
|
2011-02-22 16:27:18 +01:00
|
|
|
(toolbox ?
|
|
|
|
"gimp-toolbox-window" :
|
|
|
|
"gimp-dock-window"),
|
|
|
|
-1 /*view_size*/,
|
|
|
|
FALSE /*present*/);
|
|
|
|
|
2011-05-13 18:56:03 +02:00
|
|
|
dock_container = GIMP_DOCK_CONTAINER (dock_window);
|
|
|
|
ui_manager = gimp_dock_container_get_ui_manager (dock_container);
|
2018-04-29 17:27:47 +02:00
|
|
|
dock = gimp_dialog_factory_dialog_new (factory, monitor,
|
2011-05-13 18:56:03 +02:00
|
|
|
ui_manager,
|
2018-05-03 00:55:44 +02:00
|
|
|
dock_window,
|
2011-05-13 18:56:03 +02:00
|
|
|
(toolbox ?
|
|
|
|
"gimp-toolbox" :
|
|
|
|
"gimp-dock"),
|
|
|
|
-1 /*view_size*/,
|
|
|
|
FALSE /*present*/);
|
2011-02-22 16:27:18 +01:00
|
|
|
|
2010-02-20 16:55:35 +01:00
|
|
|
if (dock)
|
2011-02-22 16:27:18 +01:00
|
|
|
gimp_dock_window_add_dock (GIMP_DOCK_WINDOW (dock_window),
|
|
|
|
GIMP_DOCK (dock),
|
|
|
|
-1);
|
2010-02-20 16:55:35 +01:00
|
|
|
|
|
|
|
return dock;
|
|
|
|
}
|
2010-10-31 13:05:15 +01:00
|
|
|
|
|
|
|
GtkWidget *
|
|
|
|
gimp_tools_get_tool_options_gui (GimpToolOptions *tool_options)
|
|
|
|
{
|
2018-09-27 02:31:39 -04:00
|
|
|
GtkWidget *widget;
|
|
|
|
|
|
|
|
widget = g_object_get_data (G_OBJECT (tool_options),
|
|
|
|
GIMP_TOOL_OPTIONS_GUI_KEY);
|
|
|
|
|
|
|
|
if (! widget)
|
|
|
|
{
|
|
|
|
GimpToolOptionsGUIFunc func;
|
|
|
|
|
|
|
|
func = g_object_get_data (G_OBJECT (tool_options),
|
|
|
|
GIMP_TOOL_OPTIONS_GUI_FUNC_KEY);
|
|
|
|
|
|
|
|
if (func)
|
|
|
|
{
|
|
|
|
widget = func (tool_options);
|
|
|
|
|
|
|
|
gimp_tools_set_tool_options_gui (tool_options, widget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return widget;
|
2010-10-31 13:05:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-09-27 02:31:39 -04:00
|
|
|
gimp_tools_set_tool_options_gui (GimpToolOptions *tool_options,
|
|
|
|
GtkWidget *widget)
|
2010-10-31 13:05:15 +01:00
|
|
|
{
|
2018-09-27 02:31:39 -04:00
|
|
|
GtkWidget *prev_widget;
|
|
|
|
|
|
|
|
prev_widget = g_object_get_data (G_OBJECT (tool_options),
|
|
|
|
GIMP_TOOL_OPTIONS_GUI_KEY);
|
|
|
|
|
|
|
|
if (widget == prev_widget)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (prev_widget)
|
|
|
|
gtk_widget_destroy (prev_widget);
|
|
|
|
|
2010-11-10 00:13:07 +01:00
|
|
|
g_object_set_data_full (G_OBJECT (tool_options),
|
|
|
|
GIMP_TOOL_OPTIONS_GUI_KEY,
|
2018-09-27 02:31:39 -04:00
|
|
|
widget ? g_object_ref_sink (widget) : NULL,
|
2010-11-10 00:13:07 +01:00
|
|
|
widget ? (GDestroyNotify) g_object_unref : NULL);
|
2010-10-31 13:05:15 +01:00
|
|
|
}
|
2010-11-09 19:33:15 +01:00
|
|
|
|
2018-09-27 02:31:39 -04:00
|
|
|
void
|
|
|
|
gimp_tools_set_tool_options_gui_func (GimpToolOptions *tool_options,
|
|
|
|
GimpToolOptionsGUIFunc func)
|
|
|
|
{
|
|
|
|
g_object_set_data (G_OBJECT (tool_options),
|
|
|
|
GIMP_TOOL_OPTIONS_GUI_FUNC_KEY,
|
|
|
|
func);
|
|
|
|
}
|
|
|
|
|
2015-10-27 21:41:32 +01:00
|
|
|
gboolean
|
|
|
|
gimp_widget_get_fully_opaque (GtkWidget *widget)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
|
|
|
|
|
|
|
return g_object_get_data (G_OBJECT (widget),
|
|
|
|
"gimp-widget-fully-opaque") != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_widget_set_fully_opaque (GtkWidget *widget,
|
|
|
|
gboolean fully_opaque)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
|
|
|
|
return g_object_set_data (G_OBJECT (widget),
|
|
|
|
"gimp-widget-fully-opaque",
|
|
|
|
GINT_TO_POINTER (fully_opaque));
|
|
|
|
}
|
|
|
|
|
2018-08-20 14:14:26 -04:00
|
|
|
static void
|
|
|
|
gimp_gtk_container_clear_callback (GtkWidget *widget,
|
|
|
|
GtkContainer *container)
|
|
|
|
{
|
|
|
|
gtk_container_remove (container, widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_gtk_container_clear (GtkContainer *container)
|
|
|
|
{
|
|
|
|
gtk_container_foreach (container,
|
|
|
|
(GtkCallback) gimp_gtk_container_clear_callback,
|
|
|
|
container);
|
|
|
|
}
|
|
|
|
|
2018-05-17 12:52:13 +02:00
|
|
|
void
|
|
|
|
gimp_button_set_suggested (GtkWidget *button,
|
|
|
|
gboolean suggested,
|
|
|
|
GtkReliefStyle default_relief)
|
|
|
|
{
|
|
|
|
GtkStyleContext *style;
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_BUTTON (button));
|
|
|
|
|
|
|
|
style = gtk_widget_get_style_context (button);
|
|
|
|
|
|
|
|
if (suggested)
|
|
|
|
{
|
|
|
|
gtk_style_context_add_class (style, "suggested-action");
|
|
|
|
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gtk_style_context_remove_class (style, "suggested-action");
|
|
|
|
gtk_button_set_relief (GTK_BUTTON (button), default_relief);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_button_set_destructive (GtkWidget *button,
|
|
|
|
gboolean destructive,
|
|
|
|
GtkReliefStyle default_relief)
|
|
|
|
{
|
|
|
|
GtkStyleContext *style;
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_BUTTON (button));
|
|
|
|
|
|
|
|
style = gtk_widget_get_style_context (button);
|
|
|
|
|
|
|
|
if (destructive)
|
|
|
|
{
|
|
|
|
gtk_style_context_add_class (style, "destructive-action");
|
|
|
|
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gtk_style_context_remove_class (style, "destructive-action");
|
|
|
|
gtk_button_set_relief (GTK_BUTTON (button), default_relief);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-01 23:21:21 +03:00
|
|
|
void
|
|
|
|
gimp_gtk_adjustment_chain (GtkAdjustment *adjustment1,
|
|
|
|
GtkAdjustment *adjustment2)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment1));
|
|
|
|
g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment2));
|
|
|
|
|
|
|
|
g_object_bind_property (adjustment1, "value",
|
|
|
|
adjustment2, "lower",
|
|
|
|
G_BINDING_SYNC_CREATE);
|
|
|
|
g_object_bind_property (adjustment2, "value",
|
|
|
|
adjustment1, "upper",
|
|
|
|
G_BINDING_SYNC_CREATE);
|
|
|
|
}
|
|
|
|
|
2011-02-24 12:34:57 +01:00
|
|
|
static gboolean
|
|
|
|
gimp_print_event_free (gpointer data)
|
|
|
|
{
|
|
|
|
g_free (data);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gimp_print_event (const GdkEvent *event)
|
|
|
|
{
|
|
|
|
gchar *str;
|
2011-02-27 15:59:07 +01:00
|
|
|
gchar *tmp;
|
2011-02-24 12:34:57 +01:00
|
|
|
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case GDK_ENTER_NOTIFY:
|
2011-02-27 15:59:07 +01:00
|
|
|
str = g_strdup_printf ("ENTER_NOTIFY (mode %d)",
|
|
|
|
event->crossing.mode);
|
2011-02-24 12:34:57 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_LEAVE_NOTIFY:
|
2011-02-27 15:59:07 +01:00
|
|
|
str = g_strdup_printf ("LEAVE_NOTIFY (mode %d)",
|
|
|
|
event->crossing.mode);
|
2011-02-24 12:34:57 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_PROXIMITY_IN:
|
|
|
|
str = g_strdup ("PROXIMITY_IN");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_PROXIMITY_OUT:
|
|
|
|
str = g_strdup ("PROXIMITY_OUT");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_FOCUS_CHANGE:
|
|
|
|
if (event->focus_change.in)
|
|
|
|
str = g_strdup ("FOCUS_IN");
|
|
|
|
else
|
|
|
|
str = g_strdup ("FOCUS_OUT");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_BUTTON_PRESS:
|
|
|
|
str = g_strdup_printf ("BUTTON_PRESS (%d @ %0.0f:%0.0f)",
|
|
|
|
event->button.button,
|
|
|
|
event->button.x,
|
|
|
|
event->button.y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_2BUTTON_PRESS:
|
|
|
|
str = g_strdup_printf ("2BUTTON_PRESS (%d @ %0.0f:%0.0f)",
|
|
|
|
event->button.button,
|
|
|
|
event->button.x,
|
|
|
|
event->button.y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_3BUTTON_PRESS:
|
|
|
|
str = g_strdup_printf ("3BUTTON_PRESS (%d @ %0.0f:%0.0f)",
|
|
|
|
event->button.button,
|
|
|
|
event->button.x,
|
|
|
|
event->button.y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
|
|
str = g_strdup_printf ("BUTTON_RELEASE (%d @ %0.0f:%0.0f)",
|
|
|
|
event->button.button,
|
|
|
|
event->button.x,
|
|
|
|
event->button.y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_SCROLL:
|
|
|
|
str = g_strdup_printf ("SCROLL (%d)",
|
|
|
|
event->scroll.direction);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_MOTION_NOTIFY:
|
|
|
|
str = g_strdup_printf ("MOTION_NOTIFY (%0.0f:%0.0f %d)",
|
|
|
|
event->motion.x,
|
|
|
|
event->motion.y,
|
|
|
|
event->motion.time);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_KEY_PRESS:
|
|
|
|
str = g_strdup_printf ("KEY_PRESS (%d, %s)",
|
|
|
|
event->key.keyval,
|
|
|
|
gdk_keyval_name (event->key.keyval) ?
|
|
|
|
gdk_keyval_name (event->key.keyval) : "<none>");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_KEY_RELEASE:
|
|
|
|
str = g_strdup_printf ("KEY_RELEASE (%d, %s)",
|
|
|
|
event->key.keyval,
|
|
|
|
gdk_keyval_name (event->key.keyval) ?
|
|
|
|
gdk_keyval_name (event->key.keyval) : "<none>");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
str = g_strdup_printf ("UNHANDLED (type %d)",
|
|
|
|
event->type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-02-27 15:59:07 +01:00
|
|
|
tmp = g_strdup_printf ("%s (device '%s', source device '%s')",
|
|
|
|
str,
|
|
|
|
gdk_device_get_name (gdk_event_get_device (event)),
|
|
|
|
gdk_device_get_name (gdk_event_get_source_device (event)));
|
|
|
|
g_free (str);
|
|
|
|
str = tmp;
|
|
|
|
|
2011-02-24 12:34:57 +01:00
|
|
|
g_idle_add (gimp_print_event_free, str);
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
2016-05-22 01:19:18 +02:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_color_profile_store_add_defaults (GimpColorProfileStore *store,
|
|
|
|
GimpColorConfig *config,
|
|
|
|
GimpImageBaseType base_type,
|
|
|
|
GimpPrecision precision,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GimpColorProfile *profile;
|
|
|
|
gchar *label;
|
2016-05-22 13:24:20 +02:00
|
|
|
GError *my_error = NULL;
|
2016-05-22 01:19:18 +02:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_COLOR_PROFILE_STORE (store), FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_COLOR_CONFIG (config), FALSE);
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 14:23:01 +02:00
|
|
|
profile = gimp_babl_get_builtin_color_profile (base_type,
|
|
|
|
gimp_babl_trc (precision));
|
2016-05-22 01:19:18 +02:00
|
|
|
|
|
|
|
if (base_type == GIMP_GRAY)
|
|
|
|
{
|
|
|
|
label = g_strdup_printf (_("Built-in grayscale (%s)"),
|
|
|
|
gimp_color_profile_get_label (profile));
|
|
|
|
|
2016-05-22 13:24:20 +02:00
|
|
|
profile = gimp_color_config_get_gray_color_profile (config, &my_error);
|
2016-05-22 01:19:18 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
label = g_strdup_printf (_("Built-in RGB (%s)"),
|
|
|
|
gimp_color_profile_get_label (profile));
|
|
|
|
|
2016-05-22 13:24:20 +02:00
|
|
|
profile = gimp_color_config_get_rgb_color_profile (config, &my_error);
|
2016-05-22 01:19:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gimp_color_profile_store_add_file (store, NULL, label);
|
|
|
|
g_free (label);
|
|
|
|
|
|
|
|
if (profile)
|
|
|
|
{
|
2018-05-05 20:07:27 +02:00
|
|
|
gchar *path;
|
2016-05-22 01:19:18 +02:00
|
|
|
GFile *file;
|
|
|
|
|
|
|
|
if (base_type == GIMP_GRAY)
|
|
|
|
{
|
2018-05-05 20:07:27 +02:00
|
|
|
g_object_get (config, "gray-profile", &path, NULL);
|
|
|
|
file = gimp_file_new_for_config_path (path, NULL);
|
|
|
|
g_free (path);
|
2016-05-22 01:19:18 +02:00
|
|
|
|
|
|
|
label = g_strdup_printf (_("Preferred grayscale (%s)"),
|
|
|
|
gimp_color_profile_get_label (profile));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-05 20:07:27 +02:00
|
|
|
g_object_get (config, "rgb-profile", &path, NULL);
|
|
|
|
file = gimp_file_new_for_config_path (path, NULL);
|
|
|
|
g_free (path);
|
2016-05-22 01:19:18 +02:00
|
|
|
|
|
|
|
label = g_strdup_printf (_("Preferred RGB (%s)"),
|
|
|
|
gimp_color_profile_get_label (profile));
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (profile);
|
|
|
|
|
|
|
|
gimp_color_profile_store_add_file (store, file, label);
|
|
|
|
|
|
|
|
g_object_unref (file);
|
|
|
|
g_free (label);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2016-05-22 13:24:20 +02:00
|
|
|
else if (my_error)
|
|
|
|
{
|
|
|
|
g_propagate_error (error, my_error);
|
2016-05-22 01:19:18 +02:00
|
|
|
|
2016-05-22 13:24:20 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
2016-05-22 01:19:18 +02:00
|
|
|
}
|
2018-01-02 23:09:00 +01:00
|
|
|
|
|
|
|
static void
|
|
|
|
connect_path_show (GimpColorProfileChooserDialog *dialog)
|
|
|
|
{
|
|
|
|
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
|
|
|
|
GFile *file = gtk_file_chooser_get_file (chooser);
|
|
|
|
|
|
|
|
if (file)
|
|
|
|
{
|
|
|
|
/* if something is already selected in this dialog,
|
|
|
|
* leave it alone
|
|
|
|
*/
|
|
|
|
g_object_unref (file);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GObject *config;
|
|
|
|
const gchar *property;
|
|
|
|
gchar *path = NULL;
|
|
|
|
|
|
|
|
config = g_object_get_data (G_OBJECT (dialog), "profile-path-config");
|
|
|
|
property = g_object_get_data (G_OBJECT (dialog), "profile-path-property");
|
|
|
|
|
|
|
|
g_object_get (config, property, &path, NULL);
|
|
|
|
|
|
|
|
if (path)
|
|
|
|
{
|
|
|
|
GFile *folder = gimp_file_new_for_config_path (path, NULL);
|
|
|
|
|
|
|
|
if (folder)
|
|
|
|
{
|
|
|
|
gtk_file_chooser_set_current_folder_file (chooser, folder, NULL);
|
|
|
|
g_object_unref (folder);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
connect_path_response (GimpColorProfileChooserDialog *dialog,
|
|
|
|
gint response)
|
|
|
|
{
|
|
|
|
if (response == GTK_RESPONSE_ACCEPT)
|
|
|
|
{
|
|
|
|
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
|
|
|
|
GFile *file = gtk_file_chooser_get_file (chooser);
|
|
|
|
|
|
|
|
if (file)
|
|
|
|
{
|
|
|
|
GFile *folder = gtk_file_chooser_get_current_folder_file (chooser);
|
|
|
|
|
|
|
|
if (folder)
|
|
|
|
{
|
|
|
|
GObject *config;
|
|
|
|
const gchar *property;
|
|
|
|
gchar *path = NULL;
|
|
|
|
|
|
|
|
config = g_object_get_data (G_OBJECT (dialog),
|
|
|
|
"profile-path-config");
|
|
|
|
property = g_object_get_data (G_OBJECT (dialog),
|
|
|
|
"profile-path-property");
|
|
|
|
|
|
|
|
path = gimp_file_get_config_path (folder, NULL);
|
|
|
|
|
|
|
|
g_object_set (config, property, path, NULL);
|
|
|
|
|
|
|
|
if (path)
|
|
|
|
g_free (path);
|
|
|
|
|
|
|
|
g_object_unref (folder);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_color_profile_chooser_dialog_connect_path (GtkWidget *dialog,
|
|
|
|
GObject *config,
|
|
|
|
const gchar *property_name)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_COLOR_PROFILE_CHOOSER_DIALOG (dialog));
|
|
|
|
g_return_if_fail (G_IS_OBJECT (config));
|
|
|
|
g_return_if_fail (property_name != NULL);
|
|
|
|
|
|
|
|
g_object_set_data_full (G_OBJECT (dialog), "profile-path-config",
|
|
|
|
g_object_ref (config),
|
|
|
|
(GDestroyNotify) g_object_unref);
|
|
|
|
g_object_set_data_full (G_OBJECT (dialog), "profile-path-property",
|
|
|
|
g_strdup (property_name),
|
|
|
|
(GDestroyNotify) g_free);
|
|
|
|
|
|
|
|
g_signal_connect (dialog, "show",
|
|
|
|
G_CALLBACK (connect_path_show),
|
|
|
|
NULL);
|
|
|
|
g_signal_connect (dialog, "response",
|
|
|
|
G_CALLBACK (connect_path_response),
|
|
|
|
NULL);
|
|
|
|
}
|
2019-02-19 15:31:50 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
gimp_widget_flush_expose (void)
|
|
|
|
{
|
|
|
|
while (g_main_context_pending (NULL))
|
|
|
|
g_main_context_iteration (NULL, FALSE);
|
|
|
|
}
|
2022-03-05 14:32:34 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* private functions */
|
|
|
|
|
|
|
|
static void
|
2022-03-05 17:29:44 +01:00
|
|
|
gimp_search_widget_rec (GtkWidget *widget,
|
|
|
|
BlinkData *data)
|
2022-03-05 14:32:34 +01:00
|
|
|
{
|
2022-03-05 17:29:44 +01:00
|
|
|
GList **blink_script = data->blink_script;
|
|
|
|
const gchar *searched_id = data->widget_identifier;
|
|
|
|
|
2022-03-05 14:32:34 +01:00
|
|
|
if (gtk_widget_is_visible (widget))
|
|
|
|
{
|
|
|
|
const gchar *id;
|
|
|
|
|
|
|
|
id = g_object_get_data (G_OBJECT (widget),
|
|
|
|
"gimp-widget-identifier");
|
|
|
|
|
|
|
|
if (id && g_strcmp0 (id, searched_id) == 0)
|
|
|
|
{
|
|
|
|
/* Giving focus to help scrolling the dockable so that the
|
|
|
|
* widget is visible. Note that it seems to work fine if the
|
|
|
|
* dockable was already present, not if it was just created.
|
|
|
|
*
|
|
|
|
* TODO: this should be fixed so that we always make the
|
|
|
|
* widget visible before blinking, otherwise it's a bit
|
|
|
|
* useless when this happens.
|
|
|
|
*/
|
|
|
|
gtk_widget_grab_focus (widget);
|
2022-03-05 17:29:44 +01:00
|
|
|
if (blink_script)
|
|
|
|
gimp_widget_script_blink (widget, blink_script);
|
|
|
|
else
|
|
|
|
gimp_widget_blink (widget);
|
2022-03-05 14:32:34 +01:00
|
|
|
}
|
|
|
|
else if (GTK_IS_CONTAINER (widget))
|
|
|
|
{
|
|
|
|
gtk_container_foreach (GTK_CONTAINER (widget),
|
|
|
|
(GtkCallback) gimp_search_widget_rec,
|
2022-03-05 17:29:44 +01:00
|
|
|
(gpointer) data);
|
2022-03-05 14:32:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|