Updated with upstream update

This commit is contained in:
2023-10-30 15:55:30 -07:00
parent 098531073c
commit 3bbdd873ef
584 changed files with 91827 additions and 70362 deletions

View File

@ -62,6 +62,7 @@ libpikawidgets_sources_introspectable = files(
'pikalabeled.c',
'pikalabelintwidget.c',
'pikalabelspin.c',
'pikalabelstringwidget.c',
'pikalabelentry.c',
'pikamemsizeentry.c',
'pikanumberpairentry.c',

View File

@ -21,6 +21,7 @@
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
@ -29,9 +30,18 @@
#include "pikadialog.h"
#include "pikahelpui.h"
#include "pikawidgetsutils.h"
#include "libpika/libpika-intl.h"
#ifdef G_OS_WIN32
#include <dwmapi.h>
#include <gdk/gdkwin32.h>
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
#endif
/**
* SECTION: pikadialog
@ -58,32 +68,35 @@ struct _PikaDialogPrivate
PikaHelpFunc help_func;
gchar *help_id;
GtkWidget *help_button;
GBytes *window_handle;
};
#define GET_PRIVATE(obj) (((PikaDialog *) (obj))->priv)
static void pika_dialog_constructed (GObject *object);
static void pika_dialog_dispose (GObject *object);
static void pika_dialog_finalize (GObject *object);
static void pika_dialog_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_dialog_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_dialog_constructed (GObject *object);
static void pika_dialog_dispose (GObject *object);
static void pika_dialog_finalize (GObject *object);
static void pika_dialog_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_dialog_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_dialog_hide (GtkWidget *widget);
static gboolean pika_dialog_delete_event (GtkWidget *widget,
GdkEventAny *event);
static void pika_dialog_hide (GtkWidget *widget);
static gboolean pika_dialog_delete_event (GtkWidget *widget,
GdkEventAny *event);
static void pika_dialog_close (GtkDialog *dialog);
static void pika_dialog_close (GtkDialog *dialog);
static void pika_dialog_response (GtkDialog *dialog,
gint response_id);
static void pika_dialog_response (GtkDialog *dialog,
gint response_id);
static void pika_dialog_set_title_bar_theme (GtkWidget *dialog);
G_DEFINE_TYPE_WITH_PRIVATE (PikaDialog, pika_dialog, GTK_TYPE_DIALOG)
@ -157,6 +170,12 @@ pika_dialog_init (PikaDialog *dialog)
g_signal_connect (dialog, "response",
G_CALLBACK (pika_dialog_response),
NULL);
#ifdef G_OS_WIN32
g_signal_connect (GTK_WIDGET (dialog), "map",
G_CALLBACK (pika_dialog_set_title_bar_theme),
NULL);
#endif
}
static void
@ -177,6 +196,8 @@ pika_dialog_constructed (GObject *object)
_("_Help"),
GTK_RESPONSE_HELP);
}
pika_widget_set_native_handle (GTK_WIDGET (object), &private->window_handle);
}
static void
@ -650,6 +671,10 @@ pika_dialog_run (PikaDialog *dialog)
gtk_window_present (GTK_WINDOW (dialog));
#ifdef G_OS_WIN32
pika_dialog_set_title_bar_theme (GTK_WIDGET (dialog));
#endif
response_handler = g_signal_connect (dialog, "response",
G_CALLBACK (run_response_handler),
&ri);
@ -711,6 +736,26 @@ pika_dialog_set_alternative_button_order_from_array (PikaDialog *dialog,
G_GNUC_END_IGNORE_DEPRECATIONS;
}
/**
* pika_dialog_get_native_handle:
* @dialog: The #PikaDialog
*
* Returns an opaque data handle representing the window in the currently
* running platform. You should not try to use this directly. Usually this is to
* be used in functions such as [func@Gimp.brushes_popup] which will allow the
* core process to set this [class@Dialog] as parent to the newly created popup.
*
* Returns: (transfer none): an opaque [struct@GLib.Bytes] identifying this
* window.
*
* Since: 3.0
**/
GBytes *
pika_dialog_get_native_handle (PikaDialog *dialog)
{
return dialog->priv->window_handle;
}
/**
* pika_dialogs_show_help_button: (skip)
* @show: whether a help button should be added when creating a PikaDialog
@ -724,3 +769,46 @@ pika_dialogs_show_help_button (gboolean show)
{
show_help_button = show ? TRUE : FALSE;
}
void
pika_dialog_set_title_bar_theme (GtkWidget *dialog)
{
#ifdef G_OS_WIN32
HWND hwnd;
gboolean use_dark_mode = FALSE;
GdkWindow *window = NULL;
window = gtk_widget_get_window (GTK_WIDGET (dialog));
if (window)
{
GtkStyleContext *style;
GdkRGBA *color = NULL;
hwnd = (HWND) gdk_win32_window_get_handle (window);
/* Workaround since we don't have access to PikaGuiConfig.
* If the background color is below the threshold, then we're
* likely in dark mode.
*/
style = gtk_widget_get_style_context (GTK_WIDGET (dialog));
gtk_style_context_get (style, gtk_style_context_get_state (style),
GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &color,
NULL);
if (color)
{
if (color->red < 0.5 && color->green < 0.5 && color->blue < 0.5)
use_dark_mode = TRUE;
gdk_rgba_free (color);
}
DwmSetWindowAttribute (hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE,
&use_dark_mode, sizeof (use_dark_mode));
UpdateWindow (hwnd);
ShowWindow (hwnd, 5);
/* Toggle the window's visibility so the title bar change appears */
gdk_window_hide (window);
gdk_window_show (window);
}
#endif
}

View File

@ -98,6 +98,8 @@ void pika_dialog_set_alternative_button_order_from_array
gint n_buttons,
gint *order);
GBytes * pika_dialog_get_native_handle (PikaDialog *dialog);
/* for internal use only! */
void pika_dialogs_show_help_button (gboolean show);

View File

@ -461,13 +461,14 @@ pika_label_spin_set_increments (PikaLabelSpin *spin,
gdouble upper;
g_return_if_fail (PIKA_IS_LABEL_SPIN (spin));
g_return_if_fail (step < page);
g_return_if_fail (step <= page);
spinbutton = GTK_SPIN_BUTTON (priv->spinbutton);
gtk_spin_button_get_range (spinbutton, &lower, &upper);
g_return_if_fail (upper >= lower);
g_return_if_fail (step < upper - lower && page < upper - lower);
g_return_if_fail ((upper == lower || step <= upper - lower) &&
(upper == lower || page <= upper - lower));
g_object_freeze_notify (G_OBJECT (spinbutton));
gtk_adjustment_set_step_increment (gtk_spin_button_get_adjustment (spinbutton), step);

View File

@ -572,7 +572,7 @@ pika_preview_area_draw (PikaPreviewArea *area,
if (! priv->buf)
{
priv->rowstride = ((priv->width * 3) + 3) & ~3;
priv->buf = g_new (guchar, priv->rowstride * priv->height);
priv->buf = g_new0 (guchar, priv->rowstride * priv->height);
}
size = 1 << (2 + priv->check_size);
@ -880,7 +880,7 @@ pika_preview_area_blend (PikaPreviewArea *area,
if (! priv->buf)
{
priv->rowstride = ((priv->width * 3) + 3) & ~3;
priv->buf = g_new (guchar, priv->rowstride * priv->height);
priv->buf = g_new0 (guchar, priv->rowstride * priv->height);
}
size = 1 << (2 + priv->check_size);
@ -1279,7 +1279,7 @@ pika_preview_area_mask (PikaPreviewArea *area,
if (! priv->buf)
{
priv->rowstride = ((priv->width * 3) + 3) & ~3;
priv->buf = g_new (guchar, priv->rowstride * priv->height);
priv->buf = g_new0 (guchar, priv->rowstride * priv->height);
}
size = 1 << (2 + priv->check_size);
@ -1852,7 +1852,7 @@ pika_preview_area_fill (PikaPreviewArea *area,
if (! priv->buf)
{
priv->rowstride = ((priv->width * 3) + 3) & ~3;
priv->buf = g_new (guchar, priv->rowstride * priv->height);
priv->buf = g_new0 (guchar, priv->rowstride * priv->height);
}
dest = priv->buf + x * 3 + y * priv->rowstride;
@ -1875,6 +1875,32 @@ pika_preview_area_fill (PikaPreviewArea *area,
pika_preview_area_queue_draw (area, x, y, width, height);
}
/**
* pika_preview_area_reset:
* @area: a #PikaPreviewArea widget.
*
* Reset any previous drawing done through [class@GimpUi.PreviewArea] functions.
*
* Since: 3.0
**/
void
pika_preview_area_reset (PikaPreviewArea *area)
{
PikaPreviewAreaPrivate *priv = GET_PRIVATE (area);
GtkAllocation allocation;
if (priv->buf)
{
g_free (priv->buf);
priv->buf = NULL;
priv->rowstride = 0;
}
gtk_widget_get_allocation (GTK_WIDGET (area), &allocation);
pika_preview_area_queue_draw (area, 0, 0, allocation.width, allocation.height);
}
/**
* pika_preview_area_set_offsets:
* @area: a #PikaPreviewArea

View File

@ -103,6 +103,7 @@ void pika_preview_area_fill (PikaPreviewArea *area,
guchar red,
guchar green,
guchar blue);
void pika_preview_area_reset (PikaPreviewArea *area);
void pika_preview_area_set_offsets (PikaPreviewArea *area,
gint x,

View File

@ -45,50 +45,49 @@
/* utility function prototypes */
static void set_param_spec (GObject *object,
GtkWidget *widget,
GParamSpec *param_spec);
static void set_radio_spec (GObject *object,
GParamSpec *param_spec);
static GParamSpec * get_param_spec (GObject *object);
static void set_param_spec (GObject *object,
GtkWidget *widget,
GParamSpec *param_spec);
static void set_radio_spec (GObject *object,
GParamSpec *param_spec);
static GParamSpec * get_param_spec (GObject *object);
static GParamSpec * find_param_spec (GObject *object,
const gchar *property_name,
const gchar *strloc);
static GParamSpec * check_param_spec_quiet (
GObject *object,
const gchar *property_name,
GType type,
const gchar *strloc);
static GParamSpec * check_param_spec (GObject *object,
const gchar *property_name,
GType type,
const gchar *strloc);
static GParamSpec * check_param_spec_w (GObject *object,
const gchar *property_name,
GType type,
const gchar *strloc);
static GParamSpec * find_param_spec (GObject *object,
const gchar *property_name,
const gchar *strloc);
static GParamSpec * check_param_spec_quiet (GObject *object,
const gchar *property_name,
GType type,
const gchar *strloc);
static GParamSpec * check_param_spec (GObject *object,
const gchar *property_name,
GType type,
const gchar *strloc);
static GParamSpec * check_param_spec_w (GObject *object,
const gchar *property_name,
GType type,
const gchar *strloc);
static gboolean get_numeric_values (GObject *object,
GParamSpec *param_spec,
gdouble *value,
gdouble *lower,
gdouble *upper,
const gchar *strloc);
static gboolean get_numeric_values (GObject *object,
GParamSpec *param_spec,
gdouble *value,
gdouble *lower,
gdouble *upper,
const gchar *strloc);
static void connect_notify (GObject *config,
const gchar *property_name,
GCallback callback,
gpointer callback_data);
static void connect_notify (GObject *config,
const gchar *property_name,
GCallback callback,
gpointer callback_data);
static gboolean pika_prop_widget_double_to_factor (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer user_data);
static gboolean pika_prop_widget_double_from_factor (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer user_data);
static gboolean pika_prop_widget_double_to_factor (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer user_data);
static gboolean pika_prop_widget_double_from_factor (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer user_data);
/******************/
@ -2543,6 +2542,11 @@ static void pika_prop_string_combo_box_notify (GObject *config,
GParamSpec *param_spec,
GtkWidget *widget);
static gboolean
pika_prop_choice_combo_box_is_sensitive (const gchar *nick,
PikaChoice *choice);
/**
* pika_prop_string_combo_box_new:
* @config: Object to which property is attached.
@ -2604,6 +2608,74 @@ pika_prop_string_combo_box_new (GObject *config,
return combo_box;
}
/**
* pika_prop_choice_combo_box_new:
* @config: Object to which property is attached.
* @property_name: Name of %PikaChoice property controlled by combo box.
*
* Creates a #PikaStringComboBox widget to display and set the
* specified property.
*
* Returns: (transfer full): The newly created #PikaStringComboBox widget.
*
* Since: 2.4
*/
GtkWidget *
pika_prop_choice_combo_box_new (GObject *config,
const gchar *property_name)
{
GParamSpec *param_spec;
PikaParamSpecChoice *cspec;
GtkWidget *combo_box;
GtkListStore *store;
GList *values;
GList *iter;
g_return_val_if_fail (G_IS_OBJECT (config), NULL);
g_return_val_if_fail (property_name != NULL, NULL);
param_spec = check_param_spec_w (config, property_name,
PIKA_TYPE_PARAM_CHOICE, G_STRFUNC);
if (! param_spec)
return NULL;
cspec = PIKA_PARAM_SPEC_CHOICE (param_spec);
values = pika_choice_list_nicks (cspec->choice);
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
for (iter = values; iter; iter = iter->next)
{
const gchar *nick = iter->data;
const gchar *label = pika_choice_get_label (cspec->choice, nick);
gtk_list_store_insert_with_values (store, NULL, -1,
0, nick,
1, label,
-1);
}
combo_box = pika_string_combo_box_new (GTK_TREE_MODEL (store), 0, 1);
g_object_unref (store);
pika_string_combo_box_set_sensitivity (PIKA_STRING_COMBO_BOX (combo_box),
(PikaStringSensitivityFunc) pika_prop_choice_combo_box_is_sensitive,
cspec->choice, NULL);
g_signal_connect_swapped (cspec->choice, "sensitivity-changed",
G_CALLBACK (gtk_widget_queue_draw),
combo_box);
g_object_bind_property (config, property_name,
combo_box, "value",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
pika_widget_set_bound_property (combo_box, config, property_name);
gtk_widget_show (combo_box);
return combo_box;
}
static void
pika_prop_string_combo_box_callback (GtkWidget *widget,
GObject *config)
@ -2651,6 +2723,13 @@ pika_prop_string_combo_box_notify (GObject *config,
g_free (value);
}
static gboolean
pika_prop_choice_combo_box_is_sensitive (const gchar *nick,
PikaChoice *choice)
{
return pika_choice_is_valid (choice, nick);
}
/*************************/
/* file chooser button */

View File

@ -23,8 +23,8 @@
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_PROP_WIDGETS_H__
#define __PIKA_PROP_WIDGETS_H__
#ifndef __PIKAWIDGETS_PROP_WIDGETS_H__
#define __PIKAWIDGETS_PROP_WIDGETS_H__
G_BEGIN_DECLS
@ -166,6 +166,8 @@ GtkWidget * pika_prop_string_combo_box_new (GObject *config,
GtkTreeModel *model,
gint id_column,
gint label_column);
GtkWidget * pika_prop_choice_combo_box_new (GObject *config,
const gchar *property_name);
/* PikaParamPath */
@ -250,4 +252,4 @@ GtkWidget * pika_prop_icon_image_new (GObject *config,
G_END_DECLS
#endif /* __PIKA_PROP_WIDGETS_H__ */
#endif /* __PIKAWIDGETS_PROP_WIDGETS_H__ */

View File

@ -390,10 +390,10 @@ pika_ruler_update_position (PikaRuler *ruler,
gdouble x,
gdouble y)
{
PikaRulerPrivate *priv = GET_PRIVATE (ruler);
PikaRulerPrivate *priv = GET_PRIVATE (ruler);
GtkAllocation allocation;
gdouble lower;
gdouble upper;
gdouble lower = 0;
gdouble upper = 0;
gtk_widget_get_allocation (GTK_WIDGET (ruler), &allocation);
pika_ruler_get_range (ruler, &lower, &upper, NULL);
@ -1005,7 +1005,8 @@ pika_ruler_draw_ticks (PikaRuler *ruler)
gint i;
gint width, height;
gint length, ideal_length;
gdouble lower, upper; /* Upper and lower limits, in ruler units */
gdouble lower = 0; /* Upper and lower limits, in ruler units */
gdouble upper = 0;
gdouble increment; /* Number of pixels per unit */
gint scale; /* Number of units per major unit */
gdouble start, end, cur;
@ -1209,7 +1210,8 @@ pika_ruler_get_pos_rect (PikaRuler *ruler,
GtkAllocation allocation;
GtkBorder border;
gint width, height;
gdouble upper, lower;
gdouble upper = 0;
gdouble lower = 0;
gdouble increment;
GdkRectangle rect = { 0, };

View File

@ -46,29 +46,40 @@ enum
PROP_0,
PROP_ID_COLUMN,
PROP_LABEL_COLUMN,
PROP_ELLIPSIZE
PROP_ELLIPSIZE,
PROP_VALUE
};
struct _PikaStringComboBoxPrivate
{
gint id_column;
gint label_column;
GtkCellRenderer *text_renderer;
gint id_column;
gint label_column;
GtkCellRenderer *text_renderer;
PikaStringSensitivityFunc sensitivity_func;
gpointer sensitivity_data;
GDestroyNotify sensitivity_destroy;
};
#define GET_PRIVATE(obj) (((PikaStringComboBox *) (obj))->priv)
static void pika_string_combo_box_constructed (GObject *object);
static void pika_string_combo_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_string_combo_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_string_combo_box_constructed (GObject *object);
static void pika_string_combo_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_string_combo_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_string_combo_box_cell_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
PikaStringComboBoxPrivate *priv);
G_DEFINE_TYPE_WITH_PRIVATE (PikaStringComboBox, pika_string_combo_box,
@ -138,6 +149,22 @@ pika_string_combo_box_class_init (PikaStringComboBoxClass *klass)
PANGO_TYPE_ELLIPSIZE_MODE,
PANGO_ELLIPSIZE_NONE,
PIKA_PARAM_READWRITE));
/**
* PikaStringComboBox:value:
*
* The active value (different from the "active" property of
* GtkComboBox which is the active index).
*
* Since: 3.0
*/
g_object_class_install_property (object_class, PROP_VALUE,
g_param_spec_string ("value",
"Value",
"Value of active item",
NULL,
PIKA_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY));
}
static void
@ -160,6 +187,16 @@ pika_string_combo_box_constructed (GObject *object)
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (object), cell,
"text", priv->label_column,
NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (object), priv->text_renderer,
(GtkCellLayoutDataFunc) pika_string_combo_box_cell_data_func,
priv, NULL);
/* The "changed" signal of the GtkComboBox also triggers a "value" property
* notification.
*/
g_signal_connect (object, "changed",
G_CALLBACK (g_object_notify),
"value");
}
static void
@ -184,6 +221,11 @@ pika_string_combo_box_set_property (GObject *object,
g_object_set_property (G_OBJECT (priv->text_renderer),
pspec->name, value);
break;
case PROP_VALUE:
pika_string_combo_box_set_active (PIKA_STRING_COMBO_BOX (object),
g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -212,6 +254,15 @@ pika_string_combo_box_get_property (GObject *object,
g_object_get_property (G_OBJECT (priv->text_renderer),
pspec->name, value);
break;
case PROP_VALUE:
{
gchar *v;
v = pika_string_combo_box_get_active (PIKA_STRING_COMBO_BOX (object));
g_value_take_string (value, v);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -292,7 +343,7 @@ pika_string_combo_box_new (GtkTreeModel *model,
* selected item in the @combo_box.
*
* Returns: %TRUE on success or %FALSE if there was no item for
* this value.
* this value.
*
* Since: 2.4
**/
@ -315,6 +366,7 @@ pika_string_combo_box_set_active (PikaStringComboBox *combo_box,
if (pika_string_model_lookup (model, column, id, &iter))
{
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
g_object_notify (G_OBJECT (combo_box), "value");
return TRUE;
}
@ -323,6 +375,7 @@ pika_string_combo_box_set_active (PikaStringComboBox *combo_box,
else
{
gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), -1);
g_object_notify (G_OBJECT (combo_box), "value");
return TRUE;
}
@ -362,3 +415,74 @@ pika_string_combo_box_get_active (PikaStringComboBox *combo_box)
return NULL;
}
/**
* pika_string_combo_box_set_sensitivity:
* @combo_box: a #PikaStringComboBox
* @func: a function that returns a boolean value, or %NULL to unset
* @data: data to pass to @func
* @destroy: destroy notification for @data
*
* Sets a function that is used to decide about the sensitivity of
* rows in the @combo_box. Use this if you want to set certain rows
* insensitive.
*
* Calling gtk_widget_queue_draw() on the @combo_box will cause the
* sensitivity to be updated.
*
* Since: 3.0
**/
void
pika_string_combo_box_set_sensitivity (PikaStringComboBox *combo_box,
PikaStringSensitivityFunc func,
gpointer data,
GDestroyNotify destroy)
{
PikaStringComboBoxPrivate *priv;
g_return_if_fail (PIKA_IS_STRING_COMBO_BOX (combo_box));
priv = GET_PRIVATE (combo_box);
if (priv->sensitivity_destroy)
{
GDestroyNotify d = priv->sensitivity_destroy;
priv->sensitivity_destroy = NULL;
d (priv->sensitivity_data);
}
priv->sensitivity_func = func;
priv->sensitivity_data = data;
priv->sensitivity_destroy = destroy;
gtk_widget_queue_draw (GTK_WIDGET (combo_box));
}
/* Private functions. */
static void
pika_string_combo_box_cell_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
PikaStringComboBoxPrivate *priv)
{
if (priv->sensitivity_func)
{
gchar *id;
gboolean sensitive;
gtk_tree_model_get (tree_model, iter,
priv->id_column, &id,
-1);
sensitive = priv->sensitivity_func (id, priv->sensitivity_data);
g_object_set (cell,
"sensitive", sensitive,
NULL);
g_free (id);
}
}

View File

@ -29,6 +29,15 @@
G_BEGIN_DECLS
/**
* PikaStringSensitivityFunc:
* @id: the string value from the column @id_column as passed to [ctor@StringComboBox.new].
* @data: (closure): the data passed in [method@StringComboBox.set_sensitivity].
*/
typedef gboolean (* PikaStringSensitivityFunc) (const gchar *id,
gpointer data);
#define PIKA_TYPE_STRING_COMBO_BOX (pika_string_combo_box_get_type ())
#define PIKA_STRING_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_STRING_COMBO_BOX, PikaStringComboBox))
#define PIKA_STRING_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_STRING_COMBO_BOX, PikaStringComboBoxClass))
@ -63,15 +72,19 @@ struct _PikaStringComboBoxClass
};
GType pika_string_combo_box_get_type (void) G_GNUC_CONST;
GType pika_string_combo_box_get_type (void) G_GNUC_CONST;
GtkWidget * pika_string_combo_box_new (GtkTreeModel *model,
gint id_column,
gint label_column);
gboolean pika_string_combo_box_set_active (PikaStringComboBox *combo_box,
const gchar *id);
gchar * pika_string_combo_box_get_active (PikaStringComboBox *combo_box);
GtkWidget * pika_string_combo_box_new (GtkTreeModel *model,
gint id_column,
gint label_column);
gboolean pika_string_combo_box_set_active (PikaStringComboBox *combo_box,
const gchar *id);
gchar * pika_string_combo_box_get_active (PikaStringComboBox *combo_box);
void pika_string_combo_box_set_sensitivity (PikaStringComboBox *combo_box,
PikaStringSensitivityFunc func,
gpointer data,
GDestroyNotify destroy);
G_END_DECLS

View File

@ -158,6 +158,7 @@ EXPORTS
pika_dialog_add_button
pika_dialog_add_buttons
pika_dialog_add_buttons_valist
pika_dialog_get_native_handle
pika_dialog_get_type
pika_dialog_new
pika_dialog_new_valist
@ -266,6 +267,9 @@ EXPORTS
pika_label_spin_set_digits
pika_label_spin_set_increments
pika_label_spin_set_value
pika_label_string_widget_get_type
pika_label_string_widget_get_widget
pika_label_string_widget_new
pika_labeled_get_label
pika_labeled_get_text
pika_labeled_get_type
@ -332,6 +336,7 @@ EXPORTS
pika_preview_area_mask
pika_preview_area_menu_popup
pika_preview_area_new
pika_preview_area_reset
pika_preview_area_set_color_config
pika_preview_area_set_colormap
pika_preview_area_set_max_size
@ -360,6 +365,7 @@ EXPORTS
pika_prop_boolean_combo_box_new
pika_prop_boolean_radio_frame_new
pika_prop_check_button_new
pika_prop_choice_combo_box_new
pika_prop_color_area_new
pika_prop_color_select_new
pika_prop_coordinates_connect
@ -468,6 +474,7 @@ EXPORTS
pika_string_combo_box_get_type
pika_string_combo_box_new
pika_string_combo_box_set_active
pika_string_combo_box_set_sensitivity
pika_toggle_button_update
pika_uint_adjustment_update
pika_unit_combo_box_get_active
@ -492,6 +499,7 @@ EXPORTS
pika_widget_get_monitor
pika_widget_set_bound_property
pika_widget_set_identifier
pika_widget_set_native_handle
pika_widget_track_monitor
pika_widgets_error_quark
pika_widgets_init

View File

@ -67,6 +67,7 @@
#include <libpikawidgets/pikalabelentry.h>
#include <libpikawidgets/pikalabelintwidget.h>
#include <libpikawidgets/pikalabelspin.h>
#include <libpikawidgets/pikalabelstringwidget.h>
#include <libpikawidgets/pikamemsizeentry.h>
#include <libpikawidgets/pikanumberpairentry.h>
#include <libpikawidgets/pikaoffsetarea.h>

View File

@ -26,6 +26,16 @@
#include <gegl.h>
#include <gtk/gtk.h>
#ifdef GDK_WINDOWING_WIN32
#include <gdk/gdkwin32.h>
#endif
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#endif
#ifdef G_OS_WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
@ -61,6 +71,19 @@
**/
#ifdef GDK_WINDOWING_WAYLAND
static void pika_widget_wayland_window_exported (GdkWindow *window,
const char *handle,
GBytes **phandle);
#endif
static void pika_widget_set_handle_on_realize (GtkWidget *widget,
GBytes **phandle);
static gboolean pika_widget_set_handle_on_mapped (GtkWidget *widget,
GdkEventAny *event,
GBytes **phandle);
static GtkWidget *
find_mnemonic_widget (GtkWidget *widget,
gint level)
@ -1036,3 +1059,145 @@ pika_widget_get_color_transform (GtkWidget *widget,
return NULL;
}
/**
* pika_widget_set_native_handle:
* @widget: a #GtkWindow
* @handle: (out): pointer to store the native handle as a #GBytes.
*
* This function is used to store the handle representing @window into
* @handle so that it can later be reused to set other windows as
* transient to this one (even in other processes, such as plug-ins).
*
* Depending on the platform, the actual content of @handle can be
* various types. Moreover it may be filled asynchronously in a
* callback, so you should not assume that @handle is set after running
* this function.
*
* This convenience function is safe to use even before @widget is
* visible as it will set the handle once it is mapped.
*/
void
pika_widget_set_native_handle (GtkWidget *widget,
GBytes **handle)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (handle != NULL && *handle == NULL);
/* This may seem overly complicated but there is a reason: "map-event" can
* only be received by widgets with their own windows (see description of
* gtk_widget_set_events()). Instead we could just use "realize" which is
* received by every widgets (even by the ones whose window actually belongs
* to a parent widget), but this causes process locks on Wayland (see comment
* in pika_widget_set_handle_on_mapped()).
* This is why we do this weird case-based dance.
*/
if (gtk_widget_get_has_window (widget))
{
gtk_widget_add_events (widget, GDK_STRUCTURE_MASK);
g_signal_connect (widget, "map-event",
G_CALLBACK (pika_widget_set_handle_on_mapped),
handle);
}
else
{
g_signal_connect (widget, "realize",
G_CALLBACK (pika_widget_set_handle_on_realize),
handle);
}
if (gtk_widget_get_realized (widget))
pika_widget_set_handle_on_mapped (widget, NULL, handle);
}
/* Private functions */
#ifdef GDK_WINDOWING_WAYLAND
static void
pika_widget_wayland_window_exported (GdkWindow *window,
const char *handle,
GBytes **phandle)
{
GBytes *wayland_handle;
wayland_handle = g_bytes_new (handle, strlen (handle));
g_bytes_unref (*phandle);
*phandle = wayland_handle;
}
#endif
static void
pika_widget_set_handle_on_realize (GtkWidget *widget,
GBytes **phandle)
{
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
gtk_widget_add_events (toplevel, GDK_STRUCTURE_MASK);
g_signal_connect (toplevel, "map-event",
G_CALLBACK (pika_widget_set_handle_on_mapped),
phandle);
if (gtk_widget_get_mapped (toplevel))
pika_widget_set_handle_on_mapped (widget, NULL, phandle);
}
static gboolean
pika_widget_set_handle_on_mapped (GtkWidget *widget,
GdkEventAny *event,
GBytes **phandle)
{
GdkWindow *surface;
GBytes *handle = NULL;
#if defined (GDK_WINDOWING_WIN32) || defined (GDK_WINDOWING_X11)
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
widget = toplevel;
#endif
g_clear_pointer (phandle, g_bytes_unref);
surface = gtk_widget_get_window (GTK_WIDGET (widget));
g_return_val_if_fail (surface != NULL, FALSE);
#ifdef GDK_WINDOWING_WIN32
if (GDK_IS_WIN32_WINDOW (surface))
{
HANDLE id;
id = GDK_WINDOW_HWND (gtk_widget_get_window (GTK_WIDGET (widget)));
handle = g_bytes_new (&id, sizeof (HANDLE));
}
#endif
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_WINDOW (surface))
{
Window id;
id = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (widget)));
handle = g_bytes_new (&id, sizeof (Window));
}
#endif
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW (surface))
{
/* I don't run this on "realize" event because somehow it locks
* the whole processus in Wayland. The "map-event" happens
* slightly after the window became visible and I didn't
* experience any lock.
*/
if (! gdk_wayland_window_export_handle (surface,
(GdkWaylandWindowExported) pika_widget_wayland_window_exported,
phandle, NULL))
g_printerr ("%s: gdk_wayland_window_export_handle() failed. "
"It will not be possible to set windows in other processes as transient to this display shell.\n",
G_STRFUNC);
}
#endif
*phandle = handle;
return FALSE;
}

View File

@ -65,6 +65,8 @@ PikaColorTransform * pika_widget_get_color_transform (GtkWidget *widget,
PikaColorRenderingIntent proof_intent,
gboolean proof_bpc);
void pika_widget_set_native_handle (GtkWidget *widget,
GBytes **handle);
G_END_DECLS