Files
gimp/app/widgets/gimpwidgets-utils.c
Michael Natterer f4af9b549e Globally switch to saying "window_id" instead of just "window"
when dealing with native window handles. Also get rid of using
GdkNativeWindow and simply consistently use guint32 all over the
place. This is more obvious and consistent and keeps the diff to the
gtk3-port branch smaller.
2011-02-06 12:07:55 +01:00

1208 lines
33 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpwidgets-utils.c
* Copyright (C) 1999-2003 Michael Natterer <mitch@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#ifdef GDK_WINDOWING_WIN32
#include <gdk/gdkwin32.h>
#endif
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#include "libgimpbase/gimpbase.h"
#include "libgimpmath/gimpmath.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "widgets-types.h"
#include "gimpdialogfactory.h"
#include "gimpdock.h"
#include "gimpdockwindow.h"
#include "gimperrordialog.h"
#include "gimpwidgets-utils.h"
#include "gimp-intl.h"
#define GIMP_TOOL_OPTIONS_GUI_KEY "gimp-tool-options-gui"
/**
* 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.
**/
void
gimp_menu_position (GtkMenu *menu,
gint *x,
gint *y)
{
GtkWidget *widget;
GdkScreen *screen;
GtkRequisition requisition;
GdkRectangle rect;
gint monitor;
g_return_if_fail (GTK_IS_MENU (menu));
g_return_if_fail (x != NULL);
g_return_if_fail (y != NULL);
widget = GTK_WIDGET (menu);
screen = gtk_widget_get_screen (widget);
monitor = gdk_screen_get_monitor_at_point (screen, *x, *y);
gdk_screen_get_monitor_geometry (screen, monitor, &rect);
gtk_menu_set_screen (menu, screen);
gtk_widget_size_request (widget, &requisition);
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
{
*x -= requisition.width;
if (*x < rect.x)
*x += requisition.width;
}
else
{
if (*x + requisition.width > rect.x + rect.width)
*x -= requisition.width;
}
if (*x < rect.x)
*x = rect.x;
if (*y + requisition.height > rect.y + rect.height)
*y -= requisition.height;
if (*y < rect.y)
*y = rect.y;
}
/**
* gimp_button_menu_position:
* @button: a button widget to popup the menu from
* @menu: the menu to position
* @position: the preferred popup direction for the menu (left or right)
* @x: return location for x coordinate
* @y: return location for y coordinate
*
* Utility function to position a menu that pops up from a button.
**/
void
gimp_button_menu_position (GtkWidget *button,
GtkMenu *menu,
GtkPositionType position,
gint *x,
gint *y)
{
GdkScreen *screen;
GtkAllocation button_allocation;
GtkRequisition menu_requisition;
GdkRectangle rect;
gint monitor;
g_return_if_fail (GTK_IS_WIDGET (button));
g_return_if_fail (gtk_widget_get_realized (button));
g_return_if_fail (GTK_IS_MENU (menu));
g_return_if_fail (x != NULL);
g_return_if_fail (y != NULL);
gtk_widget_get_allocation (button, &button_allocation);
if (gtk_widget_get_direction (button) == GTK_TEXT_DIR_RTL)
{
switch (position)
{
case GTK_POS_LEFT: position = GTK_POS_RIGHT; break;
case GTK_POS_RIGHT: position = GTK_POS_LEFT; break;
default:
break;
}
}
*x = 0;
*y = 0;
if (! gtk_widget_get_has_window (button))
{
*x += button_allocation.x;
*y += button_allocation.y;
}
gdk_window_get_root_coords (gtk_widget_get_window (button), *x, *y, x, y);
gtk_widget_size_request (GTK_WIDGET (menu), &menu_requisition);
screen = gtk_widget_get_screen (button);
monitor = gdk_screen_get_monitor_at_point (screen, *x, *y);
gdk_screen_get_monitor_geometry (screen, monitor, &rect);
gtk_menu_set_screen (menu, screen);
switch (position)
{
case GTK_POS_LEFT:
*x -= menu_requisition.width;
if (*x < rect.x)
*x += menu_requisition.width + button_allocation.width;
break;
case GTK_POS_RIGHT:
*x += button_allocation.width;
if (*x + menu_requisition.width > rect.x + rect.width)
*x -= button_allocation.width + menu_requisition.width;
break;
default:
g_warning ("%s: unhandled position (%d)", G_STRFUNC, position);
break;
}
*y += button_allocation.height / 2;
if (*y + menu_requisition.height > rect.y + rect.height)
*y -= menu_requisition.height;
if (*y < rect.y)
*y = rect.y;
}
void
gimp_table_attach_stock (GtkTable *table,
gint row,
const gchar *stock_id,
GtkWidget *widget,
gint colspan,
gboolean left_align)
{
GtkWidget *image;
g_return_if_fail (GTK_IS_TABLE (table));
g_return_if_fail (stock_id != NULL);
g_return_if_fail (GTK_IS_WIDGET (widget));
image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
gtk_misc_set_alignment (GTK_MISC (image), 1.0, 0.5);
gtk_table_attach (table, image, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (image);
if (left_align)
{
GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
widget = hbox;
}
gtk_table_attach (table, widget, 1, 1 + colspan, row, row + 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show (widget);
}
void
gimp_enum_radio_box_add (GtkBox *box,
GtkWidget *widget,
gint enum_value,
gboolean below)
{
GList *children;
GList *list;
gint pos;
g_return_if_fail (GTK_IS_BOX (box));
g_return_if_fail (GTK_IS_WIDGET (widget));
children = gtk_container_get_children (GTK_CONTAINER (box));
for (list = children, pos = 1;
list;
list = g_list_next (list), pos++)
{
if (GTK_IS_RADIO_BUTTON (list->data) &&
GPOINTER_TO_INT (g_object_get_data (list->data, "gimp-item-data")) ==
enum_value)
{
GtkWidget *radio = list->data;
GtkWidget *hbox;
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (box), hbox, pos);
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));
spacer = gtk_vbox_new (FALSE, 0);
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);
}
gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
g_object_set_data (G_OBJECT (radio), "set_sensitive", widget);
g_signal_connect (radio, "toggled",
G_CALLBACK (gimp_toggle_button_sensitive_update),
NULL);
gtk_widget_set_sensitive (widget,
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (list->data)));
gtk_widget_show (hbox);
break;
}
}
g_list_free (children);
}
void
gimp_enum_radio_frame_add (GtkFrame *frame,
GtkWidget *widget,
gint enum_value,
gboolean below)
{
GtkWidget *vbox;
g_return_if_fail (GTK_IS_FRAME (frame));
g_return_if_fail (GTK_IS_WIDGET (widget));
vbox = gtk_bin_get_child (GTK_BIN (frame));
g_return_if_fail (GTK_IS_VBOX (vbox));
gimp_enum_radio_box_add (GTK_BOX (vbox), widget, enum_value, below);
}
GtkIconSize
gimp_get_icon_size (GtkWidget *widget,
const gchar *stock_id,
GtkIconSize max_size,
gint width,
gint height)
{
GtkIconSet *icon_set;
GtkIconSize *sizes;
gint n_sizes;
gint i;
gint width_diff = 1024;
gint height_diff = 1024;
gint max_width;
gint max_height;
GtkIconSize icon_size = GTK_ICON_SIZE_MENU;
GtkSettings *settings;
g_return_val_if_fail (GTK_IS_WIDGET (widget), icon_size);
g_return_val_if_fail (stock_id != NULL, icon_size);
g_return_val_if_fail (width > 0, icon_size);
g_return_val_if_fail (height > 0, icon_size);
icon_set = gtk_style_lookup_icon_set (gtk_widget_get_style (widget),
stock_id);
if (! icon_set)
return GTK_ICON_SIZE_INVALID;
settings = gtk_widget_get_settings (widget);
if (! gtk_icon_size_lookup_for_settings (settings, max_size,
&max_width, &max_height))
{
max_width = 1024;
max_height = 1024;
}
gtk_icon_set_get_sizes (icon_set, &sizes, &n_sizes);
for (i = 0; i < n_sizes; i++)
{
gint icon_width;
gint icon_height;
if (gtk_icon_size_lookup_for_settings (settings, sizes[i],
&icon_width, &icon_height))
{
if (icon_width <= width &&
icon_height <= height &&
icon_width <= max_width &&
icon_height <= max_height &&
((width - icon_width) < width_diff ||
(height - icon_height) < height_diff))
{
width_diff = width - icon_width;
height_diff = height - icon_height;
icon_size = sizes[i];
}
}
}
g_free (sizes);
return icon_size;
}
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;
}
const gchar *
gimp_get_mod_name_shift (void)
{
static gchar *mod_name_shift = NULL;
if (! mod_name_shift)
{
GtkAccelLabelClass *accel_label_class;
accel_label_class = g_type_class_ref (GTK_TYPE_ACCEL_LABEL);
mod_name_shift = g_strdup (accel_label_class->mod_name_shift);
g_type_class_unref (accel_label_class);
}
return (const gchar *) mod_name_shift;
}
const gchar *
gimp_get_mod_name_control (void)
{
static gchar *mod_name_control = NULL;
if (! mod_name_control)
{
GtkAccelLabelClass *accel_label_class;
accel_label_class = g_type_class_ref (GTK_TYPE_ACCEL_LABEL);
mod_name_control = g_strdup (accel_label_class->mod_name_control);
g_type_class_unref (accel_label_class);
}
return (const gchar *) mod_name_control;
}
const gchar *
gimp_get_mod_name_alt (void)
{
static gchar *mod_name_alt = NULL;
if (! mod_name_alt)
{
GtkAccelLabelClass *accel_label_class;
accel_label_class = g_type_class_ref (GTK_TYPE_ACCEL_LABEL);
mod_name_alt = g_strdup (accel_label_class->mod_name_alt);
g_type_class_unref (accel_label_class);
}
return (const gchar *) mod_name_alt;
}
const gchar *
gimp_get_mod_separator (void)
{
static gchar *mod_separator = NULL;
if (! mod_separator)
{
GtkAccelLabelClass *accel_label_class;
accel_label_class = g_type_class_ref (GTK_TYPE_ACCEL_LABEL);
mod_separator = g_strdup (accel_label_class->mod_separator);
g_type_class_unref (accel_label_class);
}
return (const gchar *) mod_separator;
}
const gchar *
gimp_get_mod_string (GdkModifierType modifiers)
{
static struct
{
GdkModifierType modifiers;
gchar *name;
}
modifier_strings[] =
{
{ GDK_SHIFT_MASK, NULL },
{ GDK_CONTROL_MASK, NULL },
{ GDK_MOD1_MASK, NULL },
{ GDK_SHIFT_MASK | GDK_CONTROL_MASK, NULL },
{ GDK_SHIFT_MASK | GDK_MOD1_MASK, NULL },
{ GDK_CONTROL_MASK | GDK_MOD1_MASK, NULL },
{ GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK, NULL }
};
gint i;
for (i = 0; i < G_N_ELEMENTS (modifier_strings); i++)
{
if (modifiers == modifier_strings[i].modifiers)
{
if (! modifier_strings[i].name)
{
GString *str = g_string_new (NULL);
if (modifiers & GDK_SHIFT_MASK)
{
g_string_append (str, gimp_get_mod_name_shift ());
}
if (modifiers & GDK_CONTROL_MASK)
{
if (str->len)
g_string_append (str, gimp_get_mod_separator ());
g_string_append (str, gimp_get_mod_name_control ());
}
if (modifiers & GDK_MOD1_MASK)
{
if (str->len)
g_string_append (str, gimp_get_mod_separator ());
g_string_append (str, gimp_get_mod_name_alt ());
}
modifier_strings[i].name = g_string_free (str, FALSE);
}
return modifier_strings[i].name;
}
}
return NULL;
}
#define BUF_SIZE 100
/**
* gimp_suggest_modifiers:
* @message: initial text for the message
* @modifiers: bit mask of modifiers that should be suggested
* @shift_format: optional format string for the Shift modifier
* @control_format: optional format string for the Ctrl modifier
* @alt_format: optional format string for the Alt modifier
*
* 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
* strings #shift_format, #control_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.
*
* Return value: a newly allocated string containing the message.
**/
gchar *
gimp_suggest_modifiers (const gchar *message,
GdkModifierType modifiers,
const gchar *shift_format,
const gchar *control_format,
const gchar *alt_format)
{
gchar msg_buf[3][BUF_SIZE];
gint num_msgs = 0;
gboolean try = FALSE;
if (modifiers & GDK_SHIFT_MASK)
{
if (shift_format && *shift_format)
{
g_snprintf (msg_buf[num_msgs], BUF_SIZE, shift_format,
gimp_get_mod_name_shift ());
}
else
{
g_strlcpy (msg_buf[num_msgs], gimp_get_mod_name_shift (), BUF_SIZE);
try = TRUE;
}
num_msgs++;
}
if (modifiers & GDK_CONTROL_MASK)
{
if (control_format && *control_format)
{
g_snprintf (msg_buf[num_msgs], BUF_SIZE, control_format,
gimp_get_mod_name_control ());
}
else
{
g_strlcpy (msg_buf[num_msgs], gimp_get_mod_name_control (), BUF_SIZE);
try = TRUE;
}
num_msgs++;
}
if (modifiers & GDK_MOD1_MASK)
{
if (alt_format && *alt_format)
{
g_snprintf (msg_buf[num_msgs], BUF_SIZE, alt_format,
gimp_get_mod_name_alt ());
}
else
{
g_strlcpy (msg_buf[num_msgs], gimp_get_mod_name_alt (), BUF_SIZE);
try = TRUE;
}
num_msgs++;
}
/* This convoluted way to build the message using multiple format strings
* tries to make the messages easier to translate to other languages.
*/
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);
}
#undef BUF_SIZE
/**
* gimp_get_screen_resolution:
* @screen: a #GdkScreen or %NULL
* @xres: returns the horizontal screen resolution (in dpi)
* @yres: returns the vertical screen resolution (in dpi)
*
* Retrieves the screen resolution from GDK. If @screen is %NULL, the
* default screen is used.
**/
void
gimp_get_screen_resolution (GdkScreen *screen,
gdouble *xres,
gdouble *yres)
{
gint width, height;
gint width_mm, height_mm;
gdouble x = 0.0;
gdouble y = 0.0;
g_return_if_fail (screen == NULL || GDK_IS_SCREEN (screen));
g_return_if_fail (xres != NULL);
g_return_if_fail (yres != NULL);
if (!screen)
screen = gdk_screen_get_default ();
width = gdk_screen_get_width (screen);
height = gdk_screen_get_height (screen);
width_mm = gdk_screen_get_width_mm (screen);
height_mm = gdk_screen_get_height_mm (screen);
/*
* 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)
{
x = (width * 25.4) / (gdouble) width_mm;
y = (height * 25.4) / (gdouble) height_mm;
}
if (x < GIMP_MIN_RESOLUTION || x > GIMP_MAX_RESOLUTION ||
y < GIMP_MIN_RESOLUTION || y > GIMP_MAX_RESOLUTION)
{
g_warning ("GDK returned bogus values for the screen resolution, "
"using 96 dpi instead.");
x = 96.0;
y = 96.0;
}
/* round the value to full integers to give more pleasant results */
*xres = ROUND (x);
*yres = ROUND (y);
}
/**
* gimp_rgb_get_gdk_color:
* @rgb: the source color as #GimpRGB
* @gdk_color: pointer to a #GdkColor
*
* Initializes @gdk_color from a #GimpRGB. This function does not
* allocate the color for you. Depending on how you want to use it,
* you may have to call gdk_colormap_alloc_color().
**/
void
gimp_rgb_get_gdk_color (const GimpRGB *rgb,
GdkColor *gdk_color)
{
guchar r, g, b;
g_return_if_fail (rgb != NULL);
g_return_if_fail (gdk_color != NULL);
gimp_rgb_get_uchar (rgb, &r, &g, &b);
gdk_color->red = (r << 8) | r;
gdk_color->green = (g << 8) | g;
gdk_color->blue = (b << 8) | b;
}
/**
* gimp_rgb_set_gdk_color:
* @rgb: a #GimpRGB that is to be set
* @gdk_color: pointer to the source #GdkColor
*
* Initializes @rgb from a #GdkColor. This function does not touch
* the alpha value of @rgb.
**/
void
gimp_rgb_set_gdk_color (GimpRGB *rgb,
const GdkColor *gdk_color)
{
guchar r, g, b;
g_return_if_fail (rgb != NULL);
g_return_if_fail (gdk_color != NULL);
r = gdk_color->red >> 8;
g = gdk_color->green >> 8;
b = gdk_color->blue >> 8;
gimp_rgb_set_uchar (rgb, r, g, b);
}
void
gimp_window_set_hint (GtkWindow *window,
GimpWindowHint hint)
{
g_return_if_fail (GTK_IS_WINDOW (window));
switch (hint)
{
case GIMP_WINDOW_HINT_NORMAL:
gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_NORMAL);
break;
case GIMP_WINDOW_HINT_UTILITY:
gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_UTILITY);
break;
case GIMP_WINDOW_HINT_KEEP_ABOVE:
gtk_window_set_keep_above (window, TRUE);
break;
}
}
/**
* gimp_window_get_native_id:
* @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.
*
* Return value: a native window ID of the window's #GdkWindow or 0
* if the window isn't realized yet
*/
guint32
gimp_window_get_native_id (GtkWindow *window)
{
g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
#ifdef GDK_NATIVE_WINDOW_POINTER
#ifdef __GNUC__
#warning gimp_window_get_native() unimplementable for the target windowing system
#endif
return 0;
#endif
#ifdef GDK_WINDOWING_WIN32
if (window && gtk_widget_get_realized (GTK_WIDGET (window)))
return GDK_WINDOW_HWND (gtk_widget_get_window (GTK_WIDGET (window)));
#endif
#ifdef GDK_WINDOWING_X11
if (window && gtk_widget_get_realized (GTK_WIDGET (window)))
return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (window)));
#endif
return 0;
}
static void
gimp_window_transient_realized (GtkWidget *window,
GdkWindow *parent)
{
if (gtk_widget_get_realized (window))
gdk_window_set_transient_for (gtk_widget_get_window (window), parent);
}
/* similar to what we have in libgimp/gimpui.c */
void
gimp_window_set_transient_for (GtkWindow *window,
guint32 parent_ID)
{
/* 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
*/
#ifndef GDK_WINDOWING_WIN32
GdkWindow *parent;
parent = gdk_window_foreign_new_for_display (gdk_display_get_default (),
parent_ID);
if (! parent)
return;
if (gtk_widget_get_realized (GTK_WIDGET (window)))
gdk_window_set_transient_for (gtk_widget_get_window (GTK_WIDGET (window)),
parent);
g_signal_connect_object (window, "realize",
G_CALLBACK (gimp_window_transient_realized),
parent, 0);
g_object_unref (parent);
#endif
}
void
gimp_toggle_button_set_visible (GtkToggleButton *toggle,
GtkWidget *widget)
{
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle));
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_widget_set_visible (widget,
gtk_toggle_button_get_active (toggle));
}
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)
{
GtkAction *action;
GtkAccelKey *accel_key;
const gchar *tooltip;
const gchar *help_id;
action = g_object_get_data (G_OBJECT (widget), "gimp-accel-action");
tooltip = gtk_action_get_tooltip (action);
help_id = g_object_get_qdata (G_OBJECT (action), GIMP_HELP_ID);
accel_key = gtk_accel_group_find (accel_group,
gimp_widget_accel_find_func,
accel_closure);
if (accel_key &&
accel_key->accel_key &&
accel_key->accel_flags & GTK_ACCEL_VISIBLE)
{
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);
g_free (accel);
g_free (escaped);
gimp_help_set_help_data_with_markup (widget, tmp, help_id);
g_free (tmp);
}
else
{
gimp_help_set_help_data (widget, tooltip, help_id);
}
}
}
void
gimp_widget_set_accel_help (GtkWidget *widget,
GtkAction *action)
{
GClosure *accel_closure = gtk_action_get_accel_closure (action);
if (accel_closure)
{
GtkAccelGroup *accel_group;
g_object_set_data (G_OBJECT (widget), "gimp-accel-closure",
accel_closure);
g_object_set_data (G_OBJECT (widget), "gimp-accel-action",
action);
accel_group = gtk_accel_group_from_accel_closure (accel_closure);
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
{
const gchar *tooltip;
const gchar *help_id;
tooltip = gtk_action_get_tooltip (action);
help_id = g_object_get_qdata (G_OBJECT (action), GIMP_HELP_ID);
gimp_help_set_help_data (widget, tooltip, help_id);
}
}
const gchar *
gimp_get_message_stock_id (GimpMessageSeverity severity)
{
switch (severity)
{
case GIMP_MESSAGE_INFO:
return GIMP_STOCK_INFO;
case GIMP_MESSAGE_WARNING:
return GIMP_STOCK_WARNING;
case GIMP_MESSAGE_ERROR:
return GIMP_STOCK_ERROR;
}
g_return_val_if_reached (GIMP_STOCK_WARNING);
}
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);
}
void
gimp_pango_layout_set_weight (PangoLayout *layout,
PangoWeight weight)
{
PangoAttrList *attrs;
PangoAttribute *attr;
g_return_if_fail (PANGO_IS_LAYOUT (layout));
attrs = pango_attr_list_new ();
attr = pango_attr_weight_new (weight);
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);
}
/**
* gimp_highlight_widget:
* @widget:
* @highlight:
*
* Calls gtk_drag_highlight() on @widget if @highlight is %TRUE,
* calls gtk_drag_unhighlight() otherwise.
**/
void
gimp_highlight_widget (GtkWidget *widget,
gboolean highlight)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
if (highlight)
gtk_drag_highlight (widget);
else
gtk_drag_unhighlight (widget);
}
/**
* gimp_dock_with_window_new:
* @factory: a #GimpDialogFacotry
* @screen: the #GdkScreen the dock window should appear on
* @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,
GdkScreen *screen,
gboolean toolbox)
{
GtkWidget *dock_window = NULL;
GtkWidget *dock = NULL;
GimpUIManager *ui_manager = NULL;
g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
/* 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
*/
dock_window =
gimp_dialog_factory_dialog_new (factory,
screen,
NULL /*ui_manager*/,
(toolbox ?
"gimp-toolbox-window" :
"gimp-dock-window"),
-1 /*view_size*/,
FALSE /*present*/);
/* Create the dock */
ui_manager = gimp_dock_window_get_ui_manager (GIMP_DOCK_WINDOW (dock_window));
dock = gimp_dialog_factory_dialog_new (factory,
screen,
ui_manager,
(toolbox ?
"gimp-toolbox" :
"gimp-dock"),
-1 /*view_size*/,
FALSE /*present*/);
if (dock)
{
/* Put the dock in the dock window */
gimp_dock_window_add_dock (GIMP_DOCK_WINDOW (dock_window),
GIMP_DOCK (dock),
-1);
}
return dock;
}
GtkWidget *
gimp_tools_get_tool_options_gui (GimpToolOptions *tool_options)
{
return g_object_get_data (G_OBJECT (tool_options),
GIMP_TOOL_OPTIONS_GUI_KEY);
}
void
gimp_tools_set_tool_options_gui (GimpToolOptions *tool_options,
GtkWidget *widget)
{
g_object_set_data_full (G_OBJECT (tool_options),
GIMP_TOOL_OPTIONS_GUI_KEY,
widget,
widget ? (GDestroyNotify) g_object_unref : NULL);
}
void
gimp_widget_flush_expose (GtkWidget *widget)
{
GList *event_list = NULL;
g_return_if_fail (GTK_IS_WIDGET (widget));
if (! gtk_widget_is_drawable (widget))
return;
gdk_window_process_updates (gtk_widget_get_window (widget), FALSE);
while (gdk_events_pending ())
{
GdkEvent *event = gdk_event_get ();
if (! event)
break;
if (gtk_get_event_widget (event) == widget &&
event->any.type == GDK_EXPOSE)
{
if (gtk_widget_get_double_buffered (widget))
{
gdk_window_begin_paint_region (event->any.window,
event->expose.region);
gtk_widget_send_expose (widget, event);
gdk_window_end_paint (event->any.window);
}
else
{
gdk_window_flush (event->any.window);
gtk_widget_send_expose (widget, event);
}
gdk_event_free (event);
}
else
{
event_list = g_list_prepend (event_list, event);
}
}
event_list = g_list_reverse (event_list);
g_list_foreach (event_list, (GFunc) gdk_event_put, NULL);
g_list_foreach (event_list, (GFunc) gdk_event_free, NULL);
g_list_free (event_list);
}