Compare commits

..

4 Commits

Author SHA1 Message Date
Matthias Clasen
01bcd96d16 Reimplement gtk_choose_color without a dialog
This commit introduces a private GtkColorChooserWindow
which is a copy of GtkColorChooserDialog with the dialog
bits redone, and uses it for the async color choose API.

When GtkColorChooserDialog is dropped, the color chooser
window can be renamed (and made public, if desired).

We want to get rid of GtkDialog. This is a step in that direction.
2022-10-23 08:05:17 -04:00
Matthias Clasen
951773452a wip: Add async api to choose a file
This is an experiment to replace explicit use
of chooser dialogs with an async API.
2022-10-22 23:53:13 -04:00
Matthias Clasen
d0af6f812d wip: Add async api to choose a font
This is an experiment to replace explicit use
of chooser dialogs with an async API.
2022-10-22 23:53:13 -04:00
Matthias Clasen
b665a95558 wip: Add async api to choose a color
This is an experiment to replace explicit use
of chooser dialogs with an async API.
2022-10-22 23:53:13 -04:00
27 changed files with 1280 additions and 5169 deletions

View File

@@ -78,20 +78,16 @@
#include <gtk/gtkcenterbox.h>
#include <gtk/gtkcenterlayout.h>
#include <gtk/gtkcheckbutton.h>
#include <gtk/gtkchoice.h>
#include <gtk/gtkcolorbutton.h>
#include <gtk/gtkcolorchooser.h>
#include <gtk/gtkcolorchooserdialog.h>
#include <gtk/gtkcolorchooserwidget.h>
#include <gtk/gtkcolordialog.h>
#include <gtk/gtkcolordialogbutton.h>
#include <gtk/gtkcolorutils.h>
#include <gtk/gtkcolumnview.h>
#include <gtk/gtkcolumnviewcolumn.h>
#include <gtk/gtkcolumnviewsorter.h>
#include <gtk/deprecated/gtkcombobox.h>
#include <gtk/deprecated/gtkcomboboxtext.h>
#include <gtk/gtkchoice.h>
#include <gtk/gtkconstraintlayout.h>
#include <gtk/gtkconstraint.h>
#include <gtk/gtkcssprovider.h>
@@ -128,7 +124,6 @@
#include <gtk/gtkfilechooserdialog.h>
#include <gtk/gtkfilechoosernative.h>
#include <gtk/gtkfilechooserwidget.h>
#include <gtk/gtkfiledialog.h>
#include <gtk/gtkfilefilter.h>
#include <gtk/gtkfilter.h>
#include <gtk/gtkfilterlistmodel.h>
@@ -139,8 +134,6 @@
#include <gtk/gtkfontchooser.h>
#include <gtk/gtkfontchooserdialog.h>
#include <gtk/gtkfontchooserwidget.h>
#include <gtk/gtkfontdialog.h>
#include <gtk/gtkfontdialogbutton.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkgesture.h>
#include <gtk/gtkgestureclick.h>
@@ -164,7 +157,6 @@
#include <gtk/gtkimcontextsimple.h>
#include <gtk/gtkimmulticontext.h>
#include <gtk/gtkinfobar.h>
#include <gtk/gtkinfodialog.h>
#include <gtk/gtkinscription.h>
#include <gtk/gtklabel.h>
#include <gtk/gtklayoutmanager.h>

View File

@@ -225,7 +225,6 @@
#include "gtkicontheme.h"
#include "gtkiconthemeprivate.h"
#include "gtkdebug.h"
#include "gtkstringlist.h"
static void gtk_builder_finalize (GObject *object);
@@ -552,19 +551,6 @@ gtk_builder_get_parameters (GtkBuilder *builder,
if (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) == GTK_TYPE_EXPRESSION)
gtk_value_set_expression (&property_value, prop->value);
else if (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) == G_TYPE_STRV)
{
GStrvBuilder *strv = g_strv_builder_new ();
for (guint j = 0; j < g_list_model_get_n_items (G_LIST_MODEL (prop->value)); j++)
{
GtkStringObject *s = g_list_model_get_item (G_LIST_MODEL (prop->value), j);
g_strv_builder_add (strv, gtk_string_object_get_string (s));
g_object_unref (s);
}
g_value_set_boxed (&property_value, g_strv_builder_end (strv));
}
else
g_assert_not_reached ();
}

View File

@@ -1039,10 +1039,6 @@ free_property_info (PropertyInfo *info)
{
if (G_PARAM_SPEC_VALUE_TYPE (info->pspec) == GTK_TYPE_EXPRESSION)
gtk_expression_unref (info->value);
else if (G_PARAM_SPEC_VALUE_TYPE (info->pspec) == G_TYPE_STRV)
{
/* info->value is in the hash table of objects */
}
else
g_assert_not_reached();
}
@@ -1727,11 +1723,8 @@ parse_custom (GtkBuildableParseContext *context,
object = ((ObjectInfo*)child_info->parent)->object;
child = child_info->object;
}
else if (parent_info->tag_type == TAG_PROPERTY)
{
g_print ("custom markup in <property>\n");
return FALSE;
}
else
return FALSE;
if (!gtk_buildable_custom_tag_start (GTK_BUILDABLE (object),
data->builder,
@@ -1954,10 +1947,7 @@ end_element (GtkBuildableParseContext *context,
if (child_info)
child_info->object = object_info->object;
if (prop_info)
{
g_string_assign (prop_info->text, object_info->id);
prop_info->value = object_info->object;
}
g_string_assign (prop_info->text, object_info->id);
if (GTK_IS_BUILDABLE (object_info->object) &&
GTK_BUILDABLE_GET_IFACE (object_info->object)->parser_finished)
@@ -2084,7 +2074,7 @@ end_element (GtkBuildableParseContext *context,
g_set_error (error,
GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_UNHANDLED_TAG,
"Unhandled end tag: </%s>", element_name);
"Unhandled tag: <%s>", element_name);
_gtk_builder_prefix_error (data->builder, context, error);
}
}

View File

@@ -1,93 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkchoice.h"
struct _GtkChoice
{
GObject parent_instance;
char *label;
char **options;
};
G_DEFINE_TYPE (GtkChoice, gtk_choice, G_TYPE_OBJECT)
static void
gtk_choice_init (GtkChoice *self)
{
}
static void
gtk_choice_finalize (GObject *object)
{
GtkChoice *self = GTK_CHOICE (object);
g_free (self->label);
g_strfreev (self->options);
G_OBJECT_CLASS (gtk_choice_parent_class)->finalize (object);
}
static void
gtk_choice_class_init (GtkChoiceClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_choice_finalize;
}
/* }}} */
/* {{{ Public API */
GtkChoice *
gtk_choice_new (const char *label,
const char * const *options)
{
GtkChoice *self;
self = g_object_new (GTK_TYPE_CHOICE, NULL);
self->label = g_strdup (label);
self->options = g_strdupv ((char **)options);
return self;
}
const char *
gtk_choice_get_label (GtkChoice *choice)
{
g_return_val_if_fail (GTK_IS_CHOICE (choice), NULL);
return choice->label;
}
const char * const *
gtk_choice_get_options (GtkChoice *choice)
{
g_return_val_if_fail (GTK_IS_CHOICE (choice), NULL);
return (const char * const *)choice->options;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -1,45 +0,0 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2022 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GTK_TYPE_CHOICE (gtk_choice_get_type ())
GDK_AVAILABLE_IN_4_10
G_DECLARE_FINAL_TYPE (GtkChoice, gtk_choice, GTK, CHOICE, GObject)
GDK_AVAILABLE_IN_4_10
GtkChoice * gtk_choice_new (const char *label,
const char * const *options);
GDK_AVAILABLE_IN_4_10
const char * gtk_choice_get_label (GtkChoice *choice);
GDK_AVAILABLE_IN_4_10
const char * const *
gtk_choice_get_options (GtkChoice *choice);
G_END_DECLS

View File

@@ -83,6 +83,32 @@ void gtk_color_chooser_add_palette (GtkColorChooser *chooser,
int n_colors,
GdkRGBA *colors);
typedef void (*GtkColorChooserPrepareCallback) (GtkColorChooser *chooser,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_choose_color (GtkWindow *parent,
const char *title,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_choose_color_full (GtkWindow *parent,
const char *title,
GtkColorChooserPrepareCallback prepare,
gpointer prepare_data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
gboolean gtk_choose_color_finish (GtkColorChooser *chooser,
GAsyncResult *result,
GdkRGBA *color,
GError **error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkColorChooser, g_object_unref)
G_END_DECLS

439
gtk/gtkcolorchooserwindow.c Normal file
View File

@@ -0,0 +1,439 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkwindow.h"
#include "gtkwindowprivate.h"
#include "gtkbutton.h"
#include "gtkbox.h"
#include "gtkprivate.h"
#include "gtksettings.h"
#include "gtkcolorchooserprivate.h"
#include "gtkcolorchooserwindowprivate.h"
#include "gtkcolorchooserwidget.h"
/*
* GtkColorChooserWindow:
*
* A window for choosing a color.
*
* ![An example GtkColorChooserWindow](colorchooser.png)
*
* `GtkColorChooserWindow` implements the [iface@Gtk.ColorChooser] interface
* and does not provide much API of its own.
*
* To create a `GtkColorChooserWindow`, use [ctor@Gtk.ColorChooserWindow.new].
*
* To change the initially selected color, use
* [method@Gtk.ColorChooser.set_rgba]. To get the selected color use
* [method@Gtk.ColorChooser.get_rgba].
*/
typedef struct _GtkColorChooserWindowClass GtkColorChooserWindowClass;
struct _GtkColorChooserWindow
{
GtkWindow parent_instance;
GtkWidget *chooser;
};
struct _GtkColorChooserWindowClass
{
GtkWindowClass parent_class;
};
enum
{
PROP_ZERO,
PROP_RGBA,
PROP_USE_ALPHA,
PROP_SHOW_EDITOR
};
static void gtk_color_chooser_window_iface_init (GtkColorChooserInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkColorChooserWindow, gtk_color_chooser_window, GTK_TYPE_WINDOW,
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
gtk_color_chooser_window_iface_init))
static void
propagate_notify (GObject *o,
GParamSpec *pspec,
GtkColorChooserWindow *cc)
{
g_object_notify (G_OBJECT (cc), pspec->name);
}
static void
save_color (GtkColorChooserWindow *window)
{
GdkRGBA color;
/* This causes the color chooser widget to save the
* selected and custom colors to GSettings.
*/
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (window), &color);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (window), &color);
}
enum
{
RESPONSE_OK,
RESPONSE_CANCEL
};
static void
response_cb (GtkWindow *window,
int response);
static void
color_activated_cb (GtkColorChooser *chooser,
GdkRGBA *color,
GtkWindow *window)
{
save_color (GTK_COLOR_CHOOSER_WINDOW (window));
response_cb (GTK_WINDOW (window), RESPONSE_OK);
}
static void
ok_button_cb (GtkButton *button,
GtkWindow *window)
{
response_cb (window, RESPONSE_OK);
}
static void
cancel_button_cb (GtkButton *button,
GtkWindow *window)
{
response_cb (window, RESPONSE_CANCEL);
}
static void
gtk_color_chooser_window_init (GtkColorChooserWindow *cc)
{
gtk_widget_init_template (GTK_WIDGET (cc));
}
static void
gtk_color_chooser_window_unmap (GtkWidget *widget)
{
GTK_WIDGET_CLASS (gtk_color_chooser_window_parent_class)->unmap (widget);
/* We never want the window to come up with the editor,
* even if it was showing the editor the last time it was used.
*/
g_object_set (widget, "show-editor", FALSE, NULL);
}
static void
gtk_color_chooser_window_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorChooserWindow *cc = GTK_COLOR_CHOOSER_WINDOW (object);
switch (prop_id)
{
case PROP_RGBA:
{
GdkRGBA color;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (cc), &color);
g_value_set_boxed (value, &color);
}
break;
case PROP_USE_ALPHA:
g_value_set_boolean (value, gtk_color_chooser_get_use_alpha (GTK_COLOR_CHOOSER (cc->chooser)));
break;
case PROP_SHOW_EDITOR:
{
gboolean show_editor;
g_object_get (cc->chooser, "show-editor", &show_editor, NULL);
g_value_set_boolean (value, show_editor);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_chooser_window_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorChooserWindow *cc = GTK_COLOR_CHOOSER_WINDOW (object);
switch (prop_id)
{
case PROP_RGBA:
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc), g_value_get_boxed (value));
break;
case PROP_USE_ALPHA:
if (gtk_color_chooser_get_use_alpha (GTK_COLOR_CHOOSER (cc->chooser)) != g_value_get_boolean (value))
{
gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (cc->chooser), g_value_get_boolean (value));
g_object_notify_by_pspec (object, pspec);
}
break;
case PROP_SHOW_EDITOR:
g_object_set (cc->chooser,
"show-editor", g_value_get_boolean (value),
NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_chooser_window_dispose (GObject *object)
{
GtkColorChooserWindow *cc = GTK_COLOR_CHOOSER_WINDOW (object);
g_clear_pointer (&cc->chooser, gtk_widget_unparent);
G_OBJECT_CLASS (gtk_color_chooser_window_parent_class)->dispose (object);
}
static void
gtk_color_chooser_window_class_init (GtkColorChooserWindowClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = gtk_color_chooser_window_dispose;
object_class->get_property = gtk_color_chooser_window_get_property;
object_class->set_property = gtk_color_chooser_window_set_property;
widget_class->unmap = gtk_color_chooser_window_unmap;
g_object_class_override_property (object_class, PROP_RGBA, "rgba");
g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
g_object_class_install_property (object_class, PROP_SHOW_EDITOR,
g_param_spec_boolean ("show-editor", NULL, NULL,
FALSE, GTK_PARAM_READWRITE));
/* Bind class to template
*/
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/libgtk/ui/gtkcolorchooserwindow.ui");
gtk_widget_class_bind_template_child (widget_class, GtkColorChooserWindow, chooser);
gtk_widget_class_bind_template_callback (widget_class, propagate_notify);
gtk_widget_class_bind_template_callback (widget_class, color_activated_cb);
gtk_widget_class_bind_template_callback (widget_class, ok_button_cb);
gtk_widget_class_bind_template_callback (widget_class, cancel_button_cb);
}
static void
gtk_color_chooser_window_get_rgba (GtkColorChooser *chooser,
GdkRGBA *color)
{
GtkColorChooserWindow *cc = GTK_COLOR_CHOOSER_WINDOW (chooser);
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (cc->chooser), color);
}
static void
gtk_color_chooser_window_set_rgba (GtkColorChooser *chooser,
const GdkRGBA *color)
{
GtkColorChooserWindow *cc = GTK_COLOR_CHOOSER_WINDOW (chooser);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->chooser), color);
}
static void
gtk_color_chooser_window_add_palette (GtkColorChooser *chooser,
GtkOrientation orientation,
int colors_per_line,
int n_colors,
GdkRGBA *colors)
{
GtkColorChooserWindow *cc = GTK_COLOR_CHOOSER_WINDOW (chooser);
gtk_color_chooser_add_palette (GTK_COLOR_CHOOSER (cc->chooser),
orientation, colors_per_line, n_colors, colors);
}
static void
gtk_color_chooser_window_iface_init (GtkColorChooserInterface *iface)
{
iface->get_rgba = gtk_color_chooser_window_get_rgba;
iface->set_rgba = gtk_color_chooser_window_set_rgba;
iface->add_palette = gtk_color_chooser_window_add_palette;
}
/*
* gtk_color_chooser_window_new:
* @title: (nullable): Title of the window
* @parent: (nullable): Transient parent of the window
*
* Creates a new `GtkColorChooserWindow`.
*
* Returns: a new `GtkColorChooserWindow`
*/
GtkWidget *
gtk_color_chooser_window_new (const char *title,
GtkWindow *parent)
{
return g_object_new (GTK_TYPE_COLOR_CHOOSER_WINDOW,
"title", title,
"transient-for", parent,
NULL);
}
static void
cancelled_cb (GCancellable *cancellable,
GtkWindow *window)
{
response_cb (window, RESPONSE_CANCEL);
}
static void
response_cb (GtkWindow *window,
int response)
{
GTask *task = G_TASK (g_object_get_data (G_OBJECT (window), "task"));
GCancellable *cancellable = g_task_get_cancellable (task);
if (cancellable)
g_signal_handlers_disconnect_by_func (cancellable, cancelled_cb, window);
if (response == RESPONSE_OK)
{
save_color (GTK_COLOR_CHOOSER_WINDOW (window));
g_task_return_boolean (task, TRUE);
}
else
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
g_object_unref (task);
gtk_window_destroy (GTK_WINDOW (window));
}
/**
* gtk_choose_color:
* @parent: (nullable): parent window
* @title: title for the color chooser
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): callback to call when the action is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents a color chooser to let the user
* pick a color.
*
* The @callback will be called when the window is closed.
* It should call [function@Gtk.choose_color_finish] to
* find out whether the operation was completed successfully,
* and to obtain the resulting color.
*/
void
gtk_choose_color (GtkWindow *parent,
const char *title,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
gtk_choose_color_full (parent, title, NULL, NULL, cancellable, callback, user_data);
}
/**
* gtk_choose_color_full:
* @parent: (nullable): parent window
* @title: title for the color chooser
* @prepare: (nullable) (scope call): callback to set up the color chooser
* @prepare_data: (closure prepare): data to pass to @prepare
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): callback to call when the action is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents a color chooser to let the user
* pick a color.
*
* In addition to [function@Gtk.choose_color], this function takes
* a @prepare callback that lets you set up the color chooser according
* to your needs.
*
* The @callback will be called when the window is closed.
* It should call [function@Gtk.choose_color_finish] to
* find out whether the operation was completed successfully,
* and to obtain the resulting color.
*/
void
gtk_choose_color_full (GtkWindow *parent,
const char *title,
GtkColorChooserPrepareCallback prepare,
gpointer prepare_data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkWidget *window;
GTask *task;
window = gtk_color_chooser_window_new (title, parent);
if (prepare)
prepare (GTK_COLOR_CHOOSER (window), prepare);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), window);
task = g_task_new (window, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_choose_color_full);
g_object_set_data (G_OBJECT (window), "task", task);
gtk_window_present (GTK_WINDOW (window));
}
/**
* gtk_choose_color_finish:
* @chooser: the `GtkColorChooser`
* @result: `GAsyncResult` that was passed to @callback
* @color: return location for the color
* @error: return location for an error
*
* Finishes a gtk_choose_color() or gtk_choose_color_full() call
* and returns the results.
*
* If this function returns `TRUE`, @color contains
* the color that was chosen.
*
* Returns: `TRUE` if the operation was successful
*/
gboolean
gtk_choose_color_finish (GtkColorChooser *chooser,
GAsyncResult *result,
GdkRGBA *color,
GError **error)
{
if (!g_task_propagate_boolean (G_TASK (result), error))
return FALSE;
gtk_color_chooser_get_rgba (chooser, color);
return TRUE;
}

View File

@@ -0,0 +1,46 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_COLOR_CHOOSER_WINDOW_PRIVATE_H___
#define __GTK_COLOR_CHOOSER_WINDOW_PRIVATE_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkwindow.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_CHOOSER_WINDOW (gtk_color_chooser_window_get_type ())
#define GTK_COLOR_CHOOSER_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_CHOOSER_WINDOW, GtkColorChooserWindow))
#define GTK_IS_COLOR_CHOOSER_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_CHOOSER_WINDOW))
typedef struct _GtkColorChooserWindow GtkColorChooserWindow;
GDK_AVAILABLE_IN_ALL
GType gtk_color_chooser_window_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_color_chooser_window_new (const char *title,
GtkWindow *parent);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkColorChooserWindow, g_object_unref)
G_END_DECLS
#endif /* __GTK_COLOR_CHOOSER_WINDOW_PRIVATE_H__ */

View File

@@ -1,475 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcolordialog.h"
#include "gtkcolorchooserdialog.h"
#include "gtkcolorchooser.h"
#include "gtkbutton.h"
#include <glib/gi18n-lib.h>
/**
* GtkColorDialog:
*
* A `GtkColorDialog` object collects the arguments that
* are needed to present a color chooser dialog to the
* user, such as a title for the dialog and whether it
* should be modal.
*
* The dialog is shown with the [function@Gtk.ColorDialog.choose_rgba]
* function. This API follows the GIO async pattern, and the
* result can be obtained by calling
* [function@Gtk.ColorDialog.choose_rgba_finish].
*
* See [class@Gtk.ColorDialogButton] for a convenient control
* that uses `GtkColorDialog` and presents the results.
*
* `GtkColorDialog was added in GTK 4.10.
*/
/* {{{ GObject implementation */
struct _GtkColorDialog
{
GObject parent_instance;
char *title;
unsigned int modal : 1;
unsigned int with_alpha : 1;
};
enum
{
PROP_TITLE = 1,
PROP_MODAL,
PROP_WITH_ALPHA,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
G_DEFINE_TYPE (GtkColorDialog, gtk_color_dialog, G_TYPE_OBJECT)
static void
gtk_color_dialog_init (GtkColorDialog *self)
{
self->title = g_strdup (_("Pick a Color"));
self->modal = TRUE;
self->with_alpha = TRUE;
}
static void
gtk_color_dialog_finalize (GObject *object)
{
GtkColorDialog *self = GTK_COLOR_DIALOG (object);
g_free (self->title);
G_OBJECT_CLASS (gtk_color_dialog_parent_class)->finalize (object);
}
static void
gtk_color_dialog_get_property (GObject *object,
unsigned int property_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorDialog *self = GTK_COLOR_DIALOG (object);
switch (property_id)
{
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_MODAL:
g_value_set_boolean (value, self->modal);
break;
case PROP_WITH_ALPHA:
g_value_set_boolean (value, self->with_alpha);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_color_dialog_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorDialog *self = GTK_COLOR_DIALOG (object);
switch (prop_id)
{
case PROP_TITLE:
gtk_color_dialog_set_title (self, g_value_get_string (value));
break;
case PROP_MODAL:
gtk_color_dialog_set_modal (self, g_value_get_boolean (value));
break;
case PROP_WITH_ALPHA:
gtk_color_dialog_set_with_alpha (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_dialog_class_init (GtkColorDialogClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_color_dialog_finalize;
object_class->get_property = gtk_color_dialog_get_property;
object_class->set_property = gtk_color_dialog_set_property;
/**
* GtkColorDialog:title: (attributes org.gtk.Property.get=gtk_color_dialog_get_title org.gtk.Property.set=gtk_color_dialog_set_title)
*
* A title that may be shown on the color chooser
* dialog that is presented by [function@Gtk.ColorDialog.choose_rgba].
*
* Since: 4.10
*/
properties[PROP_TITLE] =
g_param_spec_string ("title", NULL, NULL,
NULL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkColorDialog:modal: (attributes org.gtk.Property.get=gtk_color_dialog_get_modal org.gtk.Property.set=gtk_color_dialog_set_modal)
*
* Whether the color chooser dialog is modal.
*
* Since: 4.10
*/
properties[PROP_MODAL] =
g_param_spec_boolean ("modal", NULL, NULL,
TRUE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkColorDialog:with-alpha: (attributes org.gtk.Property.get=gtk_color_dialog_get_with_alpha org.gtk.Property.set=gtk_color_dialog_set_with_alpha)
*
* Whether colors may have alpha (translucency).
*
* When with-alpha is %FALSE, the color that is selected
* will be forced to have alpha == 1.
*
* Since: 4.10
*/
properties[PROP_WITH_ALPHA] =
g_param_spec_boolean ("with-alpha", NULL, NULL,
TRUE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}
/* }}} */
/* {{{ Constructor */
/**
* gtk_color_dialog_new:
*
* Creates a new `GtkColorDialog` object.
*
* Returns: the new `GtkColorDialog`
*
* Since: 4.10
*/
GtkColorDialog *
gtk_color_dialog_new (void)
{
return g_object_new (GTK_TYPE_COLOR_DIALOG, NULL);
}
/* }}} */
/* {{{ Getters and setters */
/**
* gtk_color_dialog_get_title:
* @self: a `GtkColorDialog`
*
* Returns the title that will be shown on the
* color chooser dialog.
*
* Returns: the title
*
* Since: 4.10
*/
const char *
gtk_color_dialog_get_title (GtkColorDialog *self)
{
g_return_val_if_fail (GTK_IS_COLOR_DIALOG (self), NULL);
return self->title;
}
/**
* gtk_color_dialog_set_title:
* @self: a `GtkColorDialog`
* @title: the new title
*
* Sets the title that will be shown on the
* color chooser dialog.
*
* Since: 4.10
*/
void
gtk_color_dialog_set_title (GtkColorDialog *self,
const char *title)
{
char *new_title;
g_return_if_fail (GTK_IS_COLOR_DIALOG (self));
g_return_if_fail (title != NULL);
if (g_str_equal (self->title, title))
return;
new_title = g_strdup (title);
g_free (self->title);
self->title = new_title;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]);
}
/**
* gtk_color_dialog_get_modal:
* @self: a `GtkColorDialog`
*
* Returns whether the color chooser dialog
* blocks interaction with the parent window
* while it is presented.
*
* Returns: `TRUE` if the color chooser dialog is modal
*
* Since: 4.10
*/
gboolean
gtk_color_dialog_get_modal (GtkColorDialog *self)
{
g_return_val_if_fail (GTK_IS_COLOR_DIALOG (self), TRUE);
return self->modal;
}
/**
* gtk_color_dialog_set_modal:
* @self: a `GtkColorDialog`
* @modal: the new value
*
* Sets whether the color chooser dialog
* blocks interaction with the parent window
* while it is presented.
*
* Since: 4.10
*/
void
gtk_color_dialog_set_modal (GtkColorDialog *self,
gboolean modal)
{
g_return_if_fail (GTK_IS_COLOR_DIALOG (self));
if (self->modal == modal)
return;
self->modal = modal;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODAL]);
}
/**
* gtk_color_dialog_get_with_alpha:
* @self: a `GtkColorDialog`
*
* Returns whether colors may have alpha.
*
* Returns: `TRUE` if colors may have alpha
*
* Since: 4.10
*/
gboolean
gtk_color_dialog_get_with_alpha (GtkColorDialog *self)
{
g_return_val_if_fail (GTK_IS_COLOR_DIALOG (self), TRUE);
return self->with_alpha;
}
/**
* gtk_color_dialog_set_with_alpha:
* @self: a `GtkColorDialog`
* @with_alpha: the new value
*
* Sets whether colors may have alpha.
*
* Since: 4.10
*/
void
gtk_color_dialog_set_with_alpha (GtkColorDialog *self,
gboolean with_alpha)
{
g_return_if_fail (GTK_IS_COLOR_DIALOG (self));
if (self->with_alpha == with_alpha)
return;
self->with_alpha = with_alpha;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WITH_ALPHA]);
}
/* }}} */
/* {{{ Async API */
static void response_cb (GTask *task,
int response);
static void
cancelled_cb (GCancellable *cancellable,
GTask *task)
{
response_cb (task, GTK_RESPONSE_CANCEL);
}
static void
response_cb (GTask *task,
int response)
{
GCancellable *cancellable;
cancellable = g_task_get_cancellable (task);
if (cancellable)
g_signal_handlers_disconnect_by_func (cancellable, cancelled_cb, task);
if (response == GTK_RESPONSE_OK)
{
GtkColorChooserDialog *window;
GdkRGBA color;
window = GTK_COLOR_CHOOSER_DIALOG (g_task_get_task_data (task));
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (window), &color);
g_task_return_pointer (task, &color, NULL);
}
else
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
g_object_unref (task);
}
/**
* gtk_color_dialog_choose_rgba:
* @self: a `GtkColorDialog`
* @parent: (nullable): the parent `GtkWindow`
* @initial_color: (nullable): the color to select initially
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): a callback to call when the operation is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function initiates a color choice operation by
* presenting a color chooser dialog to the user.
*
* The @callback will be called when the dialog is dismissed.
* It should call [function@Gtk.ColorDialog.choose_rgba_finish]
* to obtain the result.
*
* Since: 4.10
*/
void
gtk_color_dialog_choose_rgba (GtkColorDialog *self,
GtkWindow *parent,
const GdkRGBA *initial_color,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkWidget *window;
GTask *task;
g_return_if_fail (GTK_IS_COLOR_DIALOG (self));
window = gtk_color_chooser_dialog_new (self->title, parent);
if (initial_color)
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (window), initial_color);
gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (window), self->with_alpha);
gtk_window_set_modal (GTK_WINDOW (window), self->modal);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_color_dialog_choose_rgba);
g_task_set_task_data (task, window, (GDestroyNotify) gtk_window_destroy);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), task);
g_signal_connect_swapped (window, "response", G_CALLBACK (response_cb), task);
gtk_window_present (GTK_WINDOW (window));
}
/**
* gtk_color_dialog_choose_rgba_finish:
* @self: a `GtkColorDialog`
* @result: a `GAsyncResult`
* @color: (out caller-allocates): return location for the color
* @error: return location for an error
*
* Finishes the [function@Gtk.ColorDialog.choose_rgba] call and
* returns the resulting color.
*
* Returns: `TRUE` if a color was selected. Otherwise,
* `FALSE` is returned and @error is set
*
* Since: 4.10
*/
gboolean
gtk_color_dialog_choose_rgba_finish (GtkColorDialog *self,
GAsyncResult *result,
GdkRGBA *color,
GError **error)
{
GdkRGBA *ret;
ret = g_task_propagate_pointer (G_TASK (result), error);
if (ret)
{
*color = *ret;
return TRUE;
}
return FALSE;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -1,73 +0,0 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2022 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
#include <gtk/gtkwindow.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_DIALOG (gtk_color_dialog_get_type ())
GDK_AVAILABLE_IN_4_10
G_DECLARE_FINAL_TYPE (GtkColorDialog, gtk_color_dialog, GTK, COLOR_DIALOG, GObject)
GDK_AVAILABLE_IN_4_10
GtkColorDialog *gtk_color_dialog_new (void);
GDK_AVAILABLE_IN_4_10
const char * gtk_color_dialog_get_title (GtkColorDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_color_dialog_set_title (GtkColorDialog *self,
const char *title);
GDK_AVAILABLE_IN_4_10
gboolean gtk_color_dialog_get_modal (GtkColorDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_color_dialog_set_modal (GtkColorDialog *self,
gboolean modal);
GDK_AVAILABLE_IN_4_10
gboolean gtk_color_dialog_get_with_alpha (GtkColorDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_color_dialog_set_with_alpha (GtkColorDialog *self,
gboolean with_alpha);
GDK_AVAILABLE_IN_4_10
void gtk_color_dialog_choose_rgba (GtkColorDialog *self,
GtkWindow *parent,
const GdkRGBA *initial_color,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_4_10
gboolean gtk_color_dialog_choose_rgba_finish (GtkColorDialog *self,
GAsyncResult *result,
GdkRGBA *color,
GError **error);
G_END_DECLS

View File

@@ -1,483 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcolordialogbutton.h"
#include "gtkbinlayout.h"
#include "gtkbutton.h"
#include "gtkcolorswatchprivate.h"
#include "gtkdragsource.h"
#include "gtkdroptarget.h"
#include <glib/gi18n-lib.h>
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtksnapshot.h"
#include "gtkwidgetprivate.h"
static gboolean drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y,
GtkColorDialogButton *self);
static GdkContentProvider *
drag_prepare (GtkDragSource *source,
double x,
double y,
GtkColorDialogButton *self);
static void button_clicked (GtkColorDialogButton *self);
/**
* GtkColorDialogButton:
*
* The `GtkColorDialogButton` is a wrapped around a [class@Gtk.ColorDialog]
* and allows to open a color chooser dialog to change the color.
*
* ![An example GtkColorDialogButton](color-button.png)
*
* It is suitable widget for selecting a color in a preference dialog.
*
* # CSS nodes
*
* ```
* colorbutton
* ╰── button.color
* ╰── [content]
* ```
*
* `GtkColorDialogButton` has a single CSS node with name colorbutton which
* contains a button node. To differentiate it from a plain `GtkButton`,
* it gets the .color style class.
*/
/* {{{ GObject implementation */
struct _GtkColorDialogButton
{
GtkWidget parent_instance;
GtkWidget *button;
GtkWidget *swatch;
GtkColorDialog *dialog;
GdkRGBA color;
};
/* Properties */
enum
{
PROP_DIALOG = 1,
PROP_COLOR,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
G_DEFINE_TYPE (GtkColorDialogButton, gtk_color_dialog_button, GTK_TYPE_WIDGET)
static void
gtk_color_dialog_button_init (GtkColorDialogButton *self)
{
PangoLayout *layout;
PangoRectangle rect;
GtkDragSource *source;
GtkDropTarget *dest;
self->button = gtk_button_new ();
g_signal_connect_swapped (self->button, "clicked", G_CALLBACK (button_clicked), self);
gtk_widget_set_parent (self->button, GTK_WIDGET (self));
self->swatch = g_object_new (GTK_TYPE_COLOR_SWATCH,
"accessible-role", GTK_ACCESSIBLE_ROLE_IMG,
"selectable", FALSE,
"has-menu", FALSE,
"can-drag", FALSE,
NULL);
gtk_widget_set_can_focus (self->swatch, FALSE);
gtk_widget_remove_css_class (self->swatch, "activatable");
layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "Black");
pango_layout_get_pixel_extents (layout, NULL, &rect);
g_object_unref (layout);
gtk_widget_set_size_request (self->swatch, rect.width, rect.height);
gtk_button_set_child (GTK_BUTTON (self->button), self->swatch);
dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (drop), self);
gtk_widget_add_controller (GTK_WIDGET (self->button), GTK_EVENT_CONTROLLER (dest));
source = gtk_drag_source_new ();
g_signal_connect (source, "prepare", G_CALLBACK (drag_prepare), self);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (source),
GTK_PHASE_CAPTURE);
gtk_widget_add_controller (self->button, GTK_EVENT_CONTROLLER (source));
gtk_widget_add_css_class (self->button, "color");
}
static void
gtk_color_dialog_button_set_property (GObject *object,
unsigned int param_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorDialogButton *self = GTK_COLOR_DIALOG_BUTTON (object);
switch (param_id)
{
case PROP_DIALOG:
gtk_color_dialog_button_set_dialog (self, g_value_get_object (value));
break;
case PROP_COLOR:
gtk_color_dialog_button_set_color (self, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gtk_color_dialog_button_get_property (GObject *object,
unsigned int param_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorDialogButton *self = GTK_COLOR_DIALOG_BUTTON (object);
switch (param_id)
{
case PROP_DIALOG:
g_value_set_object (value, self->dialog);
break;
case PROP_COLOR:
g_value_set_boxed (value, &self->color);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gtk_color_dialog_button_dispose (GObject *object)
{
GtkColorDialogButton *self = GTK_COLOR_DIALOG_BUTTON (object);
g_clear_pointer (&self->button, gtk_widget_unparent);
G_OBJECT_CLASS (gtk_color_dialog_button_parent_class)->dispose (object);
}
static void
gtk_color_dialog_button_finalize (GObject *object)
{
GtkColorDialogButton *self = GTK_COLOR_DIALOG_BUTTON (object);
g_clear_object (&self->dialog);
G_OBJECT_CLASS (gtk_color_dialog_button_parent_class)->finalize (object);
}
static void
gtk_color_dialog_button_class_init (GtkColorDialogButtonClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->get_property = gtk_color_dialog_button_get_property;
object_class->set_property = gtk_color_dialog_button_set_property;
object_class->dispose = gtk_color_dialog_button_dispose;
object_class->finalize = gtk_color_dialog_button_finalize;
widget_class->grab_focus = gtk_widget_grab_focus_child;
widget_class->focus = gtk_widget_focus_child;
/**
* GtkColorDialogButton:dialog: (attributes org.gtk.Property.get=gtk_color_dialog_button_get_dialog org.gtk.Property.set=gtk_color_dialog_button_set_dialog)
*
* The `GtkColorDialog` that contains parameters for
* the color chooser dialog.
*
* Since: 4.10
*/
properties[PROP_DIALOG] =
g_param_spec_object ("dialog", NULL, NULL,
GTK_TYPE_COLOR_DIALOG,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkColorDialogButton:color: (attributes org.gtk.Property.get=gtk_color_dialog_button_get_color org.gtk.Property.set=gtk_color_dialog_button_set_color)
*
* The selected color.
*
* This property can be set to give the button its initial
* color, and it will be updated to reflect the users choice
* in the color chooser dialog.
*
* Listen to `notify::color` to get informed about changes
* to the buttons color.
*
* Since: 4.10
*/
properties[PROP_COLOR] =
g_param_spec_boxed ("color", NULL, NULL,
GDK_TYPE_RGBA,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_css_name (widget_class, "colorbutton");
}
/* }}} */
/* {{{ Private API, callbacks */
static guint
scale_round (double value,
double scale)
{
value = floor (value * scale + 0.5);
value = CLAMP (value, 0, scale);
return (guint)value;
}
static char *
accessible_color_name (const GdkRGBA *color)
{
if (color->alpha < 1.0)
return g_strdup_printf (_("Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"),
scale_round (color->red, 100),
scale_round (color->green, 100),
scale_round (color->blue, 100),
scale_round (color->alpha, 100));
else
return g_strdup_printf (_("Red %d%%, Green %d%%, Blue %d%%"),
scale_round (color->red, 100),
scale_round (color->green, 100),
scale_round (color->blue, 100));
}
static gboolean
drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y,
GtkColorDialogButton *self)
{
GdkRGBA *color = g_value_get_boxed (value);
gtk_color_dialog_button_set_color (self, color);
return TRUE;
}
static GdkContentProvider *
drag_prepare (GtkDragSource *source,
double x,
double y,
GtkColorDialogButton *self)
{
GdkRGBA color;
gtk_color_swatch_get_rgba (GTK_COLOR_SWATCH (self->swatch), &color);
return gdk_content_provider_new_typed (GDK_TYPE_RGBA, &color);
}
static void
color_chosen (GObject *source,
GAsyncResult *result,
gpointer data)
{
GtkColorDialogButton *self = data;
GdkRGBA color;
GError *error = NULL;
if (gtk_color_dialog_choose_rgba_finish (self->dialog, result, &color, &error))
{
gtk_color_dialog_button_set_color (self, &color);
}
else
{
g_print ("%s\n", error->message);
g_error_free (error);
}
}
static void
button_clicked (GtkColorDialogButton *self)
{
GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (self));
GtkWindow *parent = NULL;
if (GTK_IS_WINDOW (root))
parent = GTK_WINDOW (root);
gtk_color_dialog_choose_rgba (self->dialog, parent, &self->color,
NULL, color_chosen, self);
}
/* }}} */
/* {{{ Constructor */
/**
* gtk_color_dialog_button_new:
* @dialog: (nullable) (transfer full): the `GtkColorDialog` to use
*
* Creates a new `GtkColorDialogButton` with the
* given `GtkColorDialog`.
*
* You can pass `NULL` to this function and set a `GtkColorDialog`
* later. The button will be insensitive until that happens.
*
* Returns: the new `GtkColorDialogButton`
*
* Since: 4.10
*/
GtkWidget *
gtk_color_dialog_button_new (GtkColorDialog *dialog)
{
GtkWidget *self;
g_return_val_if_fail (GTK_IS_COLOR_DIALOG (dialog), NULL);
self = g_object_new (GTK_TYPE_COLOR_DIALOG_BUTTON,
"dialog", dialog,
NULL);
g_clear_object (&dialog);
return self;
}
/* }}} */
/* {{{ Getters and setters */
/**
* gtk_color_dialog_button_get_dialog:
* @self: a `GtkColorDialogButton`
*
* Returns the `GtkColorDialog` of @self.
*
* Returns: (transfer none) (nullable): the `GtkColorDialog`
*
* Since: 4.10
*/
GtkColorDialog *
gtk_color_dialog_button_get_dialog (GtkColorDialogButton *self)
{
g_return_val_if_fail (GTK_IS_COLOR_DIALOG_BUTTON (self), NULL);
return self->dialog;
}
/**
* gtk_color_dialog_button_set_dialog:
* @self: a `GtkColorDialogButton`
* @dialog: the new `GtkColorDialog`
*
* Sets a `GtkColorDialog` object to use for
* creating the color chooser dialog that is
* presented when the user clicks the button.
*
* Since: 4.10
*/
void
gtk_color_dialog_button_set_dialog (GtkColorDialogButton *self,
GtkColorDialog *dialog)
{
g_return_if_fail (GTK_IS_COLOR_DIALOG_BUTTON (self));
g_return_if_fail (GTK_IS_COLOR_DIALOG (dialog));
if (!g_set_object (&self->dialog, dialog))
return;
gtk_widget_set_sensitive (self->button, dialog != NULL);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DIALOG]);
}
/**
* gtk_color_dialog_button_get_color:
* @self: a `GtkColorDialogButton`
*
* Returns the color of the button.
*
* This function is what should be used to obtain
* the color that was choosen by the user. To get
* informed about changes, listen to "notify::color".
*
* Returns: the color
*
* Since: 4.10
*/
const GdkRGBA *
gtk_color_dialog_button_get_color (GtkColorDialogButton *self)
{
g_return_val_if_fail (GTK_IS_COLOR_DIALOG_BUTTON (self), NULL);
return &self->color;
}
/**
* gtk_color_dialog_button_set_color:
* @self: a `GtkColorDialogButton`
* @color: the new color
*
* Sets the color of the button.
*
* Since: 4.10
*/
void
gtk_color_dialog_button_set_color (GtkColorDialogButton *self,
const GdkRGBA *color)
{
char *text;
g_return_if_fail (GTK_IS_COLOR_DIALOG_BUTTON (self));
g_return_if_fail (color != NULL);
if (gdk_rgba_equal (&self->color, color))
return;
self->color = *color;
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (self->swatch), color);
text = accessible_color_name (color);
gtk_accessible_update_property (GTK_ACCESSIBLE (self->swatch),
GTK_ACCESSIBLE_PROPERTY_LABEL, text,
-1);
g_free (text);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR]);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -1,53 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkbutton.h>
#include <gtk/gtkcolordialog.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_DIALOG_BUTTON (gtk_color_dialog_button_get_type ())
GDK_AVAILABLE_IN_4_10
G_DECLARE_FINAL_TYPE (GtkColorDialogButton, gtk_color_dialog_button, GTK, COLOR_DIALOG_BUTTON, GtkWidget)
GDK_AVAILABLE_IN_4_10
GtkWidget * gtk_color_dialog_button_new (GtkColorDialog *dialog);
GDK_AVAILABLE_IN_4_10
GtkColorDialog *gtk_color_dialog_button_get_dialog (GtkColorDialogButton *self);
GDK_AVAILABLE_IN_4_10
void gtk_color_dialog_button_set_dialog (GtkColorDialogButton *self,
GtkColorDialog *dialog);
GDK_AVAILABLE_IN_4_10
const GdkRGBA * gtk_color_dialog_button_get_color (GtkColorDialogButton *self);
GDK_AVAILABLE_IN_4_10
void gtk_color_dialog_button_set_color (GtkColorDialogButton *self,
const GdkRGBA *color);
G_END_DECLS

View File

@@ -183,6 +183,34 @@ GDK_AVAILABLE_IN_ALL
const char * gtk_file_chooser_get_choice (GtkFileChooser *chooser,
const char *id);
typedef void (*GtkFileChooserPrepareCallback) (GtkFileChooser *chooser,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_choose_file (GtkWindow *parent,
const char *title,
GtkFileChooserAction action,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_choose_file_full (GtkWindow *parent,
const char *title,
GtkFileChooserAction action,
GtkFileChooserPrepareCallback prepare,
gpointer prepare_data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
gboolean gtk_choose_file_finish (GtkFileChooser *chooser,
GAsyncResult *result,
GError **error);
G_END_DECLS
#endif /* __GTK_FILE_CHOOSER_H__ */

View File

@@ -735,3 +735,140 @@ gtk_file_chooser_dialog_new (const char *title,
return result;
}
static void
cancelled_cb (GCancellable *cancellable,
GtkDialog *dialog)
{
gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
}
static void
choose_response_cb (GtkDialog *dialog,
int response,
GTask *task)
{
GCancellable *cancellable = g_task_get_cancellable (task);
if (cancellable)
g_signal_handlers_disconnect_by_func (cancellable, cancelled_cb, dialog);
if (response == GTK_RESPONSE_OK)
g_task_return_boolean (task, TRUE);
else
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
g_object_unref (task);
gtk_window_destroy (GTK_WINDOW (dialog));
}
/**
* gtk_choose_file:
* @parent: (nullable): parent window
* @title: title for the font chooser
* @action: the action for the file chooser
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): callback to call when the action is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents a file chooser to let the user
* pick a file.
*
* The @callback will be called when the dialog is closed.
* It should call [function@Gtk.choose_file_finish] to
* find out whether the operation was completed successfully,
* and use [class@Gtk.FileChooser] API to obtain the results.
*/
void
gtk_choose_file (GtkWindow *parent,
const char *title,
GtkFileChooserAction action,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
gtk_choose_file_full (parent, title, action, NULL, NULL, cancellable, callback, user_data);
}
/**
* gtk_choose_file_full:
* @parent: (nullable): parent window
* @title: title for the file chooser
* @action: the action for the file chooser
* @prepare: (nullable) (scope call): callback to set up the file chooser
* @prepare_data: (closure prepare): data to pass to @prepare
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): callback to call when the action is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents a file chooser to let the user
* choose a file.
*
* In addition to [function@Gtk.choose_file], this function takes
* a @prepare callback that lets you set up the file chooser according
* to your needs.
*
* The @callback will be called when the dialog is closed.
* It should use [function@Gtk.choose_file_finish] to find
* out whether the operation was completed successfully,
* and use [class@Gtk.FileChooser] API to obtain the results.
*/
void
gtk_choose_file_full (GtkWindow *parent,
const char *title,
GtkFileChooserAction action,
GtkFileChooserPrepareCallback prepare,
gpointer prepare_data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkWidget *dialog;
GTask *task;
const char *button[] = {
N_("_Open"),
N_("_Save"),
N_("_Select")
};
dialog = gtk_file_chooser_dialog_new (title, parent, action,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_(button[action]), GTK_RESPONSE_OK,
NULL);
if (prepare)
prepare (GTK_FILE_CHOOSER (dialog), prepare);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), dialog);
task = g_task_new (dialog, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_choose_file_full);
g_signal_connect (dialog, "response", G_CALLBACK (choose_response_cb), task);
gtk_window_present (GTK_WINDOW (dialog));
}
/**
* gtk_choose_file_finish:
* @chooser: the `GtkFileChooser`
* @result: `GAsyncResult` that was passed to @callback
* @error: return location for an error
*
* Finishes a gtk_choose_file() or gtk_choose_file_full() call
* and returns whether the operation was successful.
*
* If this function returns `TRUE`, you can use
* [class@Gtk.FileChooser] API to get the results.
*
* Returns: `TRUE` if the operation was successful
*/
gboolean
gtk_choose_file_finish (GtkFileChooser *chooser,
GAsyncResult *result,
GError **error)
{
return g_task_propagate_boolean (G_TASK (result), error);
}

View File

@@ -1,914 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkfiledialog.h"
#include "gtk/gtkchoice.h"
#include "gtkfilechooserdialog.h"
#include <glib/gi18n-lib.h>
/**
* GtkFileDialog:
*
* A `GtkFileDialog` object collects the arguments that
* are needed to present a file chooser dialog to the
* user, such as a title for the dialog and whether it
* should be modal.
*
* The dialog is shown with the [function@Gtk.FileDialog.choose_rgba]
* function. This API follows the GIO async pattern, and the
* result can be obtained by calling
* [function@Gtk.FileDialog.choose_rgba_finish].
*
* See [class@Gtk.FileDialogButton] for a convenient control
* that uses `GtkFileDialog` and presents the results.
*
* `GtkFileDialog was added in GTK 4.10.
*/
/* {{{ GObject implementation */
struct _GtkFileDialog
{
GObject parent_instance;
char *title;
unsigned int modal : 1;
unsigned int select_multiple : 1;
unsigned int create_folders : 1;
GListModel *filters;
GListModel *shortcuts;
GListModel *choices;
};
enum
{
PROP_TITLE = 1,
PROP_MODAL,
PROP_SELECT_MULTIPLE,
PROP_CREATE_FOLDERS,
PROP_FILTERS,
PROP_SHORTCUTS,
PROP_CHOICES,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
G_DEFINE_TYPE (GtkFileDialog, gtk_file_dialog, G_TYPE_OBJECT)
static void
gtk_file_dialog_init (GtkFileDialog *self)
{
self->title = g_strdup (_("Pick a File"));
self->modal = TRUE;
self->create_folders = TRUE;
}
static void
gtk_file_dialog_finalize (GObject *object)
{
GtkFileDialog *self = GTK_FILE_DIALOG (object);
g_free (self->title);
g_clear_object (&self->filters);
g_clear_object (&self->shortcuts);
g_clear_object (&self->choices);
G_OBJECT_CLASS (gtk_file_dialog_parent_class)->finalize (object);
}
static void
gtk_file_dialog_get_property (GObject *object,
unsigned int property_id,
GValue *value,
GParamSpec *pspec)
{
GtkFileDialog *self = GTK_FILE_DIALOG (object);
switch (property_id)
{
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_MODAL:
g_value_set_boolean (value, self->modal);
break;
case PROP_SELECT_MULTIPLE:
g_value_set_boolean (value, self->select_multiple);
break;
case PROP_CREATE_FOLDERS:
g_value_set_boolean (value, self->create_folders);
break;
case PROP_FILTERS:
g_value_set_object (value, self->filters);
break;
case PROP_SHORTCUTS:
g_value_set_object (value, self->shortcuts);
break;
case PROP_CHOICES:
g_value_set_object (value, self->choices);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_file_dialog_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkFileDialog *self = GTK_FILE_DIALOG (object);
switch (prop_id)
{
case PROP_TITLE:
gtk_file_dialog_set_title (self, g_value_get_string (value));
break;
case PROP_MODAL:
gtk_file_dialog_set_modal (self, g_value_get_boolean (value));
break;
case PROP_SELECT_MULTIPLE:
gtk_file_dialog_set_select_multiple (self, g_value_get_boolean (value));
break;
case PROP_CREATE_FOLDERS:
gtk_file_dialog_set_create_folders (self, g_value_get_boolean (value));
break;
case PROP_FILTERS:
gtk_file_dialog_set_filters (self, g_value_get_object (value));
break;
case PROP_SHORTCUTS:
gtk_file_dialog_set_shortcuts (self, g_value_get_object (value));
break;
case PROP_CHOICES:
gtk_file_dialog_set_choices (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_file_dialog_class_init (GtkFileDialogClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_file_dialog_finalize;
object_class->get_property = gtk_file_dialog_get_property;
object_class->set_property = gtk_file_dialog_set_property;
/**
* GtkFileDialog:title: (attributes org.gtk.Property.get=gtk_file_dialog_get_title org.gtk.Property.set=gtk_color_dialog_set_title)
*
* A title that may be shown on the file chooser
* dialog that is presented by [function@Gtk.FileDialog.choose_rgba].
*
* Since: 4.10
*/
properties[PROP_TITLE] =
g_param_spec_string ("title", NULL, NULL,
NULL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFileDialog:modal: (attributes org.gtk.Property.get=gtk_file_dialog_get_modal org.gtk.Property.set=gtk_color_dialog_set_modal)
*
* Whether the file chooser dialog is modal.
*
* Since: 4.10
*/
properties[PROP_MODAL] =
g_param_spec_boolean ("modal", NULL, NULL,
TRUE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFileDialog:select-multiple: (attributes org.gtk.Property.get=gtk_file_dialog_get_select_multiple org.gtk.Property.set=gtk_color_dialog_set_select_multiple)
*
* Whether the file chooser dialog allows to select more than one file.
*
* Since: 4.10
*/
properties[PROP_SELECT_MULTIPLE] =
g_param_spec_boolean ("select-multiple", NULL, NULL,
FALSE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFileDialog:create-folders: (attributes org.gtk.Property.get=gtk_file_dialog_get_create_folders org.gtk.Property.set=gtk_color_dialog_set_create_folders)
*
* Whether the file chooser dialog will allow to create new folders.
*
* Since: 4.10
*/
properties[PROP_CREATE_FOLDERS] =
g_param_spec_boolean ("create-folders", NULL, NULL,
TRUE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_FILTERS] =
g_param_spec_object ("filters", NULL, NULL,
G_TYPE_LIST_MODEL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_SHORTCUTS] =
g_param_spec_object ("shortcuts", NULL, NULL,
G_TYPE_LIST_MODEL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_CHOICES] =
g_param_spec_object ("choices", NULL, NULL,
G_TYPE_LIST_MODEL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}
/* }}} */
/* {{{ Utilities */
static void
file_chooser_set_filters (GtkFileChooser *chooser,
GListModel *filters)
{
if (!filters)
return;
for (unsigned int i = 0; i < g_list_model_get_n_items (filters); i++)
{
GtkFileFilter *filter = g_list_model_get_item (filters, i);
gtk_file_chooser_add_filter (chooser, filter);
g_object_unref (filter);
}
}
static void
file_chooser_set_shortcuts (GtkFileChooser *chooser,
GListModel *shortcuts)
{
if (!shortcuts)
return;
for (unsigned int i = 0; i < g_list_model_get_n_items (shortcuts); i++)
{
GFile *shortcut = g_list_model_get_item (shortcuts, i);
gtk_file_chooser_add_shortcut_folder (chooser, shortcut, NULL);
g_object_unref (shortcut);
}
}
static void
file_chooser_set_choices (GtkFileChooser *chooser,
GListModel *choices)
{
if (!choices)
return;
for (unsigned int i = 0; i < g_list_model_get_n_items (choices); i++)
{
GtkChoice *choice = g_list_model_get_item (choices, i);
char *id;
const char *label;
char **options;
const char * const *option_labels;
label = gtk_choice_get_label (choice);
option_labels = gtk_choice_get_options (choice);
id = g_strdup_printf ("choice %u", i);
if (option_labels)
{
GStrvBuilder *strv = g_strv_builder_new ();
for (unsigned int j = 0; option_labels[j]; j++)
{
char *option = g_strdup_printf ("option %u", j);
g_strv_builder_add (strv, option);
g_free (option);
}
options = g_strv_builder_end (strv);
}
else
options = NULL;
gtk_file_chooser_add_choice (chooser, id, label, (const char **)options, (const char **)option_labels);
g_free (id);
g_strfreev (options);
g_object_unref (choice);
}
}
static char **
file_chooser_get_options (GtkFileChooser *chooser,
GListModel *choices)
{
GStrvBuilder *strv;
if (!choices)
return NULL;
strv = g_strv_builder_new ();
for (unsigned int i = 0; i < g_list_model_get_n_items (choices); i++)
{
GtkChoice *choice = g_list_model_get_item (choices, i);
char *id;
const char *option;
unsigned int pos;
const char *option_label;
id = g_strdup_printf ("choice %u", i);
option = gtk_file_chooser_get_choice (chooser, id);
pos = (unsigned int) g_ascii_strtoull (option + strlen ("option "), NULL, 10);
option_label = gtk_choice_get_options (choice)[pos];
g_strv_builder_add (strv, option_label);
g_free (id);
g_object_unref (choice);
}
return g_strv_builder_end (strv);
}
/* }}} */
/* {{{ Public API */
/* {{{ Constructor */
/**
* gtk_file_dialog_new:
*
* Creates a new `GtkFileDialog` object.
*
* Returns: the new `GtkFileDialog`
*
* Since: 4.10
*/
GtkFileDialog *
gtk_file_dialog_new (void)
{
return g_object_new (GTK_TYPE_FILE_DIALOG, NULL);
}
/* }}} */
/* {{{ Getters and setters */
/**
* gtk_file_dialog_get_title:
* @self: a `GtkFileDialog`
*
* Returns the title that will be shown on the
* file chooser dialog.
*
* Returns: the title
*
* Since: 4.10
*/
const char *
gtk_file_dialog_get_title (GtkFileDialog *self)
{
g_return_val_if_fail (GTK_IS_FILE_DIALOG (self), NULL);
return self->title;
}
/**
* gtk_file_dialog_set_title:
* @self: a `GtkFileDialog`
* @title: the new title
*
* Sets the title that will be shown on the
* file chooser dialog.
*
* Since: 4.10
*/
void
gtk_file_dialog_set_title (GtkFileDialog *self,
const char *title)
{
char *new_title;
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
g_return_if_fail (title != NULL);
if (g_strcmp0 (self->title, title) == 0)
return;
new_title = g_strdup (title);
g_free (self->title);
self->title = new_title;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]);
}
/**
* gtk_file_dialog_get_modal:
* @self: a `GtkFileDialog`
*
* Returns whether the file chooser dialog
* blocks interaction with the parent window
* while it is presented.
*
* Returns: `TRUE` if the file chooser dialog is modal
*
* Since: 4.10
*/
gboolean
gtk_file_dialog_get_modal (GtkFileDialog *self)
{
g_return_val_if_fail (GTK_IS_FILE_DIALOG (self), TRUE);
return self->modal;
}
/**
* gtk_file_dialog_set_modal:
* @self: a `GtkFileDialog`
* @modal: the new value
*
* Sets whether the file chooser dialog
* blocks interaction with the parent window
* while it is presented.
*
* Since: 4.10
*/
void
gtk_file_dialog_set_modal (GtkFileDialog *self,
gboolean modal)
{
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
if (self->modal == modal)
return;
self->modal = modal;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODAL]);
}
/**
* gtk_file_dialog_get_select_multiple:
* @self: a `GtkFileDialog`
*
* Returns whether the file chooser dialog
* allows to select multiple files.
*
* Returns: `TRUE` if the file chooser dialog allows multi-selection
*
* Since: 4.10
*/
gboolean
gtk_file_dialog_get_select_multiple (GtkFileDialog *self)
{
g_return_val_if_fail (GTK_IS_FILE_DIALOG (self), FALSE);
return self->select_multiple;
}
/**
* gtk_file_dialog_set_select_multiple:
* @self: a `GtkFileDialog`
* @modal: the new value
*
* Sets whether the file chooser dialog
* allows to select multiple files.
*
* Since: 4.10
*/
void
gtk_file_dialog_set_select_multiple (GtkFileDialog *self,
gboolean select_multiple)
{
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
if (self->select_multiple == select_multiple)
return;
self->select_multiple = select_multiple;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECT_MULTIPLE]);
}
/**
* gtk_file_dialog_get_create_folders:
* @self: a `GtkFileDialog`
*
* Returns whether the file chooser dialog
* allows to create folders.
*
* Returns: `TRUE` if the file chooser dialog allows folder creation
*
* Since: 4.10
*/
gboolean
gtk_file_dialog_get_create_folders (GtkFileDialog *self)
{
g_return_val_if_fail (GTK_IS_FILE_DIALOG (self), FALSE);
return self->create_folders;
}
/**
* gtk_file_dialog_set_create_folders:
* @self: a `GtkFileDialog`
* @modal: the new value
*
* Sets whether the file chooser dialog
* allows to create folders.
*
* Since: 4.10
*/
void
gtk_file_dialog_set_create_folders (GtkFileDialog *self,
gboolean create_folders)
{
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
if (self->create_folders == create_folders)
return;
self->create_folders = create_folders;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CREATE_FOLDERS]);
}
void
gtk_file_dialog_set_filters (GtkFileDialog *self,
GListModel *filters)
{
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
g_return_if_fail (G_IS_LIST_MODEL (filters));
g_return_if_fail (g_list_model_get_item_type (G_LIST_MODEL (filters)) == GTK_TYPE_FILE_FILTER);
if (!g_set_object (&self->filters, filters))
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILTERS]);
}
GListModel *
gtk_file_dialog_get_filters (GtkFileDialog *self)
{
g_return_val_if_fail (GTK_IS_FILE_DIALOG (self), NULL);
return self->filters;
}
void
gtk_file_dialog_set_shortcuts (GtkFileDialog *self,
GListModel *shortcuts)
{
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
g_return_if_fail (G_IS_LIST_MODEL (shortcuts));
g_return_if_fail (g_list_model_get_item_type (G_LIST_MODEL (shortcuts)) == G_TYPE_FILE);
if (!g_set_object (&self->shortcuts, shortcuts))
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHORTCUTS]);
}
GListModel *
gtk_file_dialog_get_shortcuts (GtkFileDialog *self)
{
g_return_val_if_fail (GTK_IS_FILE_DIALOG (self), NULL);
return self->shortcuts;
}
void
gtk_file_dialog_set_choices (GtkFileDialog *self,
GListModel *choices)
{
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
g_return_if_fail (G_IS_LIST_MODEL (choices));
g_return_if_fail (g_list_model_get_item_type (G_LIST_MODEL (choices)) == GTK_TYPE_CHOICE);
if (!g_set_object (&self->choices, choices))
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CHOICES]);
}
GListModel *
gtk_file_dialog_get_choices (GtkFileDialog *self)
{
g_return_val_if_fail (GTK_IS_FILE_DIALOG (self), NULL);
return self->choices;
}
/* }}} */
/* {{{ Async API */
typedef struct
{
GListModel *files;
char **options;
} FileResult;
static void response_cb (GTask *task,
int response);
static void
cancelled_cb (GCancellable *cancellable,
GTask *task)
{
response_cb (task, GTK_RESPONSE_CANCEL);
}
static void
response_cb (GTask *task,
int response)
{
GCancellable *cancellable;
cancellable = g_task_get_cancellable (task);
if (cancellable)
g_signal_handlers_disconnect_by_func (cancellable, cancelled_cb, task);
if (response == GTK_RESPONSE_OK)
{
GtkFileDialog *self;
GtkFileChooserDialog *window;
FileResult file_result;
self = GTK_FILE_DIALOG (g_task_get_source_object (task));
window = GTK_FILE_CHOOSER_DIALOG (g_task_get_task_data (task));
file_result.files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (window));
file_result.options = file_chooser_get_options (GTK_FILE_CHOOSER (window),
gtk_file_dialog_get_choices (self));
g_task_return_pointer (task, &file_result, NULL);
}
else
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
g_object_unref (task);
}
static void
dialog_response (GtkDialog *dialog,
int response,
GTask *task)
{
response_cb (task, response);
}
static GtkFileChooserDialog *
create_file_chooser_dialog (GtkFileDialog *self,
GtkWindow *parent,
GtkFileChooserAction action)
{
GtkWidget *window;
const char *accept[] = {
N_("_Open"), N_("_Save"), N_("_Select")
};
window = gtk_file_chooser_dialog_new (self->title, parent,
action,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_(accept[action]), GTK_RESPONSE_OK,
NULL);
gtk_window_set_modal (GTK_WINDOW (window), self->modal);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (window), self->select_multiple);
gtk_file_chooser_set_create_folders (GTK_FILE_CHOOSER (window), self->create_folders);
file_chooser_set_filters (GTK_FILE_CHOOSER (window), self->filters);
file_chooser_set_shortcuts (GTK_FILE_CHOOSER (window), self->shortcuts);
file_chooser_set_choices (GTK_FILE_CHOOSER (window), self->choices);
return GTK_FILE_CHOOSER_DIALOG (window);
}
static gboolean
finish_file_op (GtkFileDialog *self,
GAsyncResult *result,
GListModel **files,
char ***options,
GError **error)
{
FileResult *ret;
ret = g_task_propagate_pointer (G_TASK (result), error);
if (ret)
{
*files = ret->files;
if (options)
*options = ret->options;
else
g_strfreev (ret->options);
return TRUE;
}
return FALSE;
}
/**
* gtk_file_dialog_open:
* @self: a `GtkFileDialog`
* @parent: (nullable): the parent `GtkWindow`
* @initial_file: (nullable): the file to select initially
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): a callback to call when the operation is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function initiates a file selection operation by
* presenting a file chooser dialog to the user.
*
* The @callback will be called when the dialog is dismissed.
* It should call [function@Gtk.FileDialog.open_finish]
* to obtain the result.
*
* Since: 4.10
*/
void
gtk_file_dialog_open (GtkFileDialog *self,
GtkWindow *parent,
GFile *initial_file,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkFileChooserDialog *window;
GTask *task;
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
window = create_file_chooser_dialog (self, parent, GTK_FILE_CHOOSER_ACTION_OPEN);
if (initial_file)
gtk_file_chooser_set_file (GTK_FILE_CHOOSER (window), initial_file, NULL);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_file_dialog_open);
g_task_set_task_data (task, window, (GDestroyNotify) gtk_window_destroy);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), task);
g_signal_connect (window, "response", G_CALLBACK (dialog_response), task);
gtk_window_present (GTK_WINDOW (window));
}
/**
* gtk_file_dialog_open_finish:
* @self: a `GtkFileDialog`
* @result: a `GAsyncResult`
* @files: (out caller-allocates): return location for the selected files
* @options: (out caller-allocates): return location for choices
* @error: return location for an error
*
* Finishes the [function@Gtk.FileDialog.open] call and
* returns the resulting files as a `GListModel` of `GFiles`.
*
* Returns: `TRUE` if a file was selected. Otherwise,
* `FALSE` is returned and @error is set
*
* Since: 4.10
*/
gboolean
gtk_file_dialog_open_finish (GtkFileDialog *self,
GAsyncResult *result,
GListModel **files,
char ***options,
GError **error)
{
return finish_file_op (self, result, files, options, error);
}
void
gtk_file_dialog_select_folder (GtkFileDialog *self,
GtkWindow *parent,
GFile *current_folder,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkFileChooserDialog *window;
GTask *task;
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
window = create_file_chooser_dialog (self, parent, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
if (current_folder)
gtk_file_chooser_set_file (GTK_FILE_CHOOSER (window), current_folder, NULL);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_file_dialog_select_folder);
g_task_set_task_data (task, window, (GDestroyNotify) gtk_window_destroy);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), task);
g_signal_connect (window, "response", G_CALLBACK (dialog_response), task);
gtk_window_present (GTK_WINDOW (window));
}
gboolean
gtk_file_dialog_select_folder_finish (GtkFileDialog *self,
GAsyncResult *result,
GListModel **files,
char ***options,
GError **error)
{
return finish_file_op (self, result, files, options, error);
}
void
gtk_file_dialog_save (GtkFileDialog *self,
GtkWindow *parent,
GFile *current_folder,
const char *current_name,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkFileChooserDialog *window;
GTask *task;
g_return_if_fail (GTK_IS_FILE_DIALOG (self));
window = create_file_chooser_dialog (self, parent, GTK_FILE_CHOOSER_ACTION_SAVE);
if (current_folder)
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (window), current_folder, NULL);
if (current_name)
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (window), current_name);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_file_dialog_save);
g_task_set_task_data (task, window, (GDestroyNotify) gtk_window_destroy);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), task);
g_signal_connect (window, "response", G_CALLBACK (dialog_response), task);
gtk_window_present (GTK_WINDOW (window));
}
gboolean
gtk_file_dialog_save_finish (GtkFileDialog *self,
GAsyncResult *result,
GListModel **files,
char ***options,
GError **error)
{
return finish_file_op (self, result, files, options, error);
}
/* }}} */
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -1,130 +0,0 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2022 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
#include <gtk/gtkwindow.h>
G_BEGIN_DECLS
#define GTK_TYPE_FILE_DIALOG (gtk_file_dialog_get_type ())
GDK_AVAILABLE_IN_4_10
G_DECLARE_FINAL_TYPE (GtkFileDialog, gtk_file_dialog, GTK, FILE_DIALOG, GObject)
GDK_AVAILABLE_IN_4_10
GtkFileDialog * gtk_file_dialog_new (void);
GDK_AVAILABLE_IN_4_10
const char * gtk_file_dialog_get_title (GtkFileDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_set_title (GtkFileDialog *self,
const char *title);
GDK_AVAILABLE_IN_4_10
gboolean gtk_file_dialog_get_modal (GtkFileDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_set_modal (GtkFileDialog *self,
gboolean modal);
GDK_AVAILABLE_IN_4_10
gboolean gtk_file_dialog_get_select_multiple (GtkFileDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_set_select_multiple (GtkFileDialog *self,
gboolean select_multiple);
GDK_AVAILABLE_IN_4_10
gboolean gtk_file_dialog_get_create_folders (GtkFileDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_set_create_folders (GtkFileDialog *self,
gboolean create_folders);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_set_filters (GtkFileDialog *self,
GListModel *filters);
GDK_AVAILABLE_IN_4_10
GListModel * gtk_file_dialog_get_filters (GtkFileDialog *dialog);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_set_shortcuts (GtkFileDialog *self,
GListModel *filters);
GDK_AVAILABLE_IN_4_10
GListModel * gtk_file_dialog_get_shortcuts (GtkFileDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_set_choices (GtkFileDialog *self,
GListModel *filters);
GDK_AVAILABLE_IN_4_10
GListModel * gtk_file_dialog_get_choices (GtkFileDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_open (GtkFileDialog *self,
GtkWindow *parent,
GFile *current_file,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_4_10
gboolean gtk_file_dialog_open_finish (GtkFileDialog *self,
GAsyncResult *result,
GListModel **files,
char ***options,
GError **error);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_select_folder (GtkFileDialog *self,
GtkWindow *parent,
GFile *current_folder,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_4_10
gboolean gtk_file_dialog_select_folder_finish
(GtkFileDialog *self,
GAsyncResult *result,
GListModel **files,
char ***options,
GError **error);
GDK_AVAILABLE_IN_4_10
void gtk_file_dialog_save (GtkFileDialog *dialog,
GtkWindow *parent,
GFile *current_folder,
const char *current_name,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_4_10
gboolean gtk_file_dialog_save_finish (GtkFileDialog *self,
GAsyncResult *result,
GListModel **files,
char ***choices,
GError **error);
G_END_DECLS

View File

@@ -161,6 +161,31 @@ GDK_AVAILABLE_IN_ALL
void gtk_font_chooser_set_language (GtkFontChooser *fontchooser,
const char *language);
typedef void (*GtkFontChooserPrepareCallback) (GtkFontChooser *chooser,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_choose_font (GtkWindow *parent,
const char *title,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_choose_font_full (GtkWindow *parent,
const char *title,
GtkFontChooserPrepareCallback prepare,
gpointer prepare_data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
gboolean gtk_choose_font_finish (GtkFontChooser *chooser,
GAsyncResult *result,
GError **error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkFontChooser, g_object_unref)
G_END_DECLS

View File

@@ -324,3 +324,127 @@ gtk_font_chooser_dialog_buildable_get_internal_child (GtkBuildable *buildable,
return parent_buildable_iface->get_internal_child (buildable, builder, childname);
}
static void
cancelled_cb (GCancellable *cancellable,
GtkDialog *dialog)
{
gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
}
static void
response_cb (GtkDialog *dialog,
int response,
GTask *task)
{
GCancellable *cancellable = g_task_get_cancellable (task);
if (cancellable)
g_signal_handlers_disconnect_by_func (cancellable, cancelled_cb, dialog);
if (response == GTK_RESPONSE_OK)
g_task_return_boolean (task, TRUE);
else
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
g_object_unref (task);
gtk_window_destroy (GTK_WINDOW (dialog));
}
/**
* gtk_choose_font:
* @parent: (nullable): parent window
* @title: title for the font chooser
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): callback to call when the action is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents a font chooser to let the user
* pick a font.
*
* The @callback will be called when the dialog is closed.
* It should call [function@Gtk.choose_font_finish] to
* find out whether the operation was completed successfully,
* and use [class@Gtk.FontChooser] API to obtain the results.
*/
void
gtk_choose_font (GtkWindow *parent,
const char *title,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
gtk_choose_font_full (parent, title, NULL, NULL, cancellable, callback, user_data);
}
/**
* gtk_choose_font_full:
* @parent: (nullable): parent window
* @title: title for the font chooser
* @prepare: (nullable) (scope call): callback to set up the font chooser
* @prepare_data: (closure prepare): data to pass to @prepare
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): callback to call when the action is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents a font chooser to let the user
* choose a font.
*
* In addition to [function@Gtk.choose_font], this function takes
* a @prepare callback that lets you set up the font chooser according
* to your needs.
*
* The @callback will be called when the dialog is closed.
* It should use [function@Gtk.choose_font_finish] to find
* out whether the operation was completed successfully,
* and use [class@Gtk.FontChooser] API to obtain the results.
*/
void
gtk_choose_font_full (GtkWindow *parent,
const char *title,
GtkFontChooserPrepareCallback prepare,
gpointer prepare_data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkWidget *dialog;
GTask *task;
dialog = gtk_font_chooser_dialog_new (title, parent);
if (prepare)
prepare (GTK_FONT_CHOOSER (dialog), prepare);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), dialog);
task = g_task_new (dialog, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_choose_font_full);
g_signal_connect (dialog, "response", G_CALLBACK (response_cb), task);
gtk_window_present (GTK_WINDOW (dialog));
}
/**
* gtk_choose_font_finish:
* @chooser: the `GtkFontChooser`
* @result: `GAsyncResult` that was passed to @callback
* @error: return location for an error
*
* Finishes a gtk_choose_font() or gtk_choose_font_full() call
* and returns whether the operation was successful.
*
* If this function returns `TRUE`, you can use
* [class@Gtk.FontChooser] API to get the results.
*
* Returns: `TRUE` if the operation was successful
*/
gboolean
gtk_choose_font_finish (GtkFontChooser *chooser,
GAsyncResult *result,
GError **error)
{
return g_task_propagate_boolean (G_TASK (result), error);
}

View File

@@ -1,671 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkfontdialog.h"
#include "gtkfontchooserdialog.h"
#include "gtkbutton.h"
#include "gtktypebuiltins.h"
#include <glib/gi18n-lib.h>
/**
* GtkFontDialog:
*
* A `GtkFontDialog` object collects the arguments that
* are needed to present a font chooser dialog to the
* user, such as a title for the dialog and whether it
* should be modal.
*
* The dialog is shown with the [function@Gtk.FontDialog.choose_font]
* function. This API follows the GIO async pattern, and the
* result can be obtained by calling
* [function@Gtk.FontDialog.choose_font_finish].
*
* See [class@Gtk.FontDialogButton] for a convenient control
* that uses `GtkFontDialog` and presents the results.
*
* `GtkFontDialog was added in GTK 4.10.
*/
/* {{{ GObject implementation */
struct _GtkFontDialog
{
GObject parent_instance;
char *title;
GtkFontChooserLevel level;
PangoLanguage *language;
PangoFontMap *fontmap;
unsigned int modal : 1;
GtkFontFilterFunc filter;
gpointer filter_data;
GDestroyNotify filter_data_destroy;
};
enum
{
PROP_TITLE = 1,
PROP_MODAL,
PROP_LEVEL,
PROP_LANGUAGE,
PROP_FONTMAP,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
G_DEFINE_TYPE (GtkFontDialog, gtk_font_dialog, G_TYPE_OBJECT)
#define DEFAULT_LEVEL (GTK_FONT_CHOOSER_LEVEL_FAMILY| \
GTK_FONT_CHOOSER_LEVEL_STYLE| \
GTK_FONT_CHOOSER_LEVEL_SIZE)
static void
gtk_font_dialog_init (GtkFontDialog *self)
{
self->title = g_strdup (_("Pick a Font"));
self->modal = TRUE;
self->level = DEFAULT_LEVEL;
self->language = pango_language_get_default ();
}
static void
gtk_font_dialog_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkFontDialog *self = GTK_FONT_DIALOG (object);
switch (property_id)
{
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_MODAL:
g_value_set_boolean (value, self->modal);
break;
case PROP_LEVEL:
g_value_set_flags (value, self->level);
break;
case PROP_LANGUAGE:
g_value_set_boxed (value, self->language);
break;
case PROP_FONTMAP:
g_value_set_object (value, self->fontmap);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_font_dialog_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkFontDialog *self = GTK_FONT_DIALOG (object);
switch (property_id)
{
case PROP_TITLE:
gtk_font_dialog_set_title (self, g_value_get_string (value));
break;
case PROP_MODAL:
gtk_font_dialog_set_modal (self, g_value_get_boolean (value));
break;
case PROP_LEVEL:
gtk_font_dialog_set_level (self, g_value_get_flags (value));
break;
case PROP_LANGUAGE:
gtk_font_dialog_set_language (self, g_value_get_boxed (value));
break;
case PROP_FONTMAP:
gtk_font_dialog_set_fontmap (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_font_dialog_finalize (GObject *object)
{
GtkFontDialog *self = GTK_FONT_DIALOG (object);
g_free (self->title);
g_clear_object (&self->fontmap);
g_clear_pointer (&self->filter_data, self->filter_data_destroy);
G_OBJECT_CLASS (gtk_font_dialog_parent_class)->finalize (object);
}
static void
gtk_font_dialog_class_init (GtkFontDialogClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->get_property = gtk_font_dialog_get_property;
object_class->set_property = gtk_font_dialog_set_property;
object_class->finalize = gtk_font_dialog_finalize;
/**
* GtkFontDialog:title: (attributes org.gtk.Property.get=gtk_font_dialog_get_title org.gtk.Property.set=gtk_font_dialog_set_title)
*
* A title that may be shown on the font chooser
* dialog that is presented by [function@Gtk.FontDialog.choose_font].
*
* Since: 4.10
*/
properties[PROP_TITLE] =
g_param_spec_string ("title", NULL, NULL,
NULL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFontDialog:modal: (attributes org.gtk.Property.get=gtk_font_dialog_get_modal org.gtk.Property.set=gtk_font_dialog_set_modal)
*
* Whether the font chooser dialog is modal.
*
* Since: 4.10
*/
properties[PROP_MODAL] =
g_param_spec_boolean ("modal", NULL, NULL,
TRUE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFontDialog:level: (attributes org.gtk.Property.get=gtk_font_dialog_get_level org.gtk.Property.set=gtk_font_dialog_set_level)
*
* The level of granularity to offer for selecting fonts.
*
* Since: 4.10
*/
properties[PROP_LEVEL] =
g_param_spec_flags ("level", NULL, NULL,
GTK_TYPE_FONT_CHOOSER_LEVEL,
DEFAULT_LEVEL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFontDialog:language: (attributes org.gtk.Property.get=gtk_font_dialog_get_language org.gtk.Property.set=gtk_font_dialog_set_language)
*
* The language for which the font features are selected.
*
* Since: 4.10
*/
properties[PROP_LANGUAGE] =
g_param_spec_boxed ("language", NULL, NULL,
PANGO_TYPE_LANGUAGE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFontDialog:fontmap: (attributes org.gtk.Property.get=gtk_font_dialog_get_fontmap org.gtk.Property.set=gtk_font_dialog_set_fontmap)
*
* Sets a custom font map to select fonts from.
*
* A custom font map can be used to present application-specific
* fonts instead of or in addition to the normal system fonts.
*
* Since: 4.10
*/
properties[PROP_FONTMAP] =
g_param_spec_object ("fontmap", NULL, NULL,
PANGO_TYPE_FONT_MAP,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}
/* }}} */
/* {{{ Constructor */
/**
* gtk_font_dialog_new:
*
* Creates a new `GtkFontDialog` object.
*
* Returns: the new `GtkFontDialog`
*
* Since: 4.10
*/
GtkFontDialog *
gtk_font_dialog_new (void)
{
return g_object_new (GTK_TYPE_FONT_DIALOG, NULL);
}
/* }}} */
/* {{{ Getters and setters */
/**
* gtk_font_dialog_get_title:
* @self: a `GtkFontDialog`
*
* Returns the title that will be shown on the
* font chooser dialog.
*
* Returns: the title
*
* Since: 4.10
*/
const char *
gtk_font_dialog_get_title (GtkFontDialog *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG (self), NULL);
return self->title;
}
/**
* gtk_font_dialog_set_title:
* @self: a `GtkFontDialog`
* @title: the new title
*
* Sets the title that will be shown on the
* font chooser dialog.
*
* Since: 4.10
*/
void
gtk_font_dialog_set_title (GtkFontDialog *self,
const char *title)
{
char *new_title;
g_return_if_fail (GTK_IS_FONT_DIALOG (self));
g_return_if_fail (title != NULL);
if (g_str_equal (self->title, title))
return;
new_title = g_strdup (title);
g_free (self->title);
self->title = new_title;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]);
}
/**
* gtk_font_dialog_get_modal:
* @self: a `GtkFontDialog`
*
* Returns whether the font chooser dialog
* blocks interaction with the parent window
* while it is presented.
*
* Returns: `TRUE` if the font chooser dialog is modal
*
* Since: 4.10
*/
gboolean
gtk_font_dialog_get_modal (GtkFontDialog *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG (self), TRUE);
return self->modal;
}
/**
* gtk_font_dialog_set_modal:
* @self: a `GtkFontDialog`
* @modal: the new value
*
* Sets whether the font chooser dialog
* blocks interaction with the parent window
* while it is presented.
*
* Since: 4.10
*/
void
gtk_font_dialog_set_modal (GtkFontDialog *self,
gboolean modal)
{
g_return_if_fail (GTK_IS_FONT_DIALOG (self));
if (self->modal == modal)
return;
self->modal = modal;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODAL]);
}
/**
* gtk_font_dialog_get_level:
* @self: a `GtkFontDialog`
*
* Returns the level of granularity for selecting fonts.
*
* Returns: the level of granularity
*
* Since: 4.10
*/
GtkFontChooserLevel
gtk_font_dialog_get_level (GtkFontDialog *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG (self), DEFAULT_LEVEL);
return self->level;
}
/**
* gtk_font_dialog_set_level:
* @self: a `GtkFontDialog`
* @level: the new value
*
* Sets the level of granularity for selecting fonts.
*
* Since: 4.10
*/
void
gtk_font_dialog_set_level (GtkFontDialog *self,
GtkFontChooserLevel level)
{
g_return_if_fail (GTK_IS_FONT_DIALOG (self));
if (self->level == level)
return;
self->level = level;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LEVEL]);
}
/**
* gtk_font_dialog_get_language:
* @self: a `GtkFontDialog`
*
* Returns the language for which font features are applied.
*
* Returns: (nullable): the language for font features
*
* Since: 4.10
*/
PangoLanguage *
gtk_font_dialog_get_language (GtkFontDialog *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG (self), NULL);
return self->language;
}
/**
* gtk_font_dialog_set_language:
* @self: a `GtkFontDialog`
* @language: the language for font features
*
* Sets the language for which font features are applied.
*
* Since: 4.10
*/
void
gtk_font_dialog_set_language (GtkFontDialog *self,
PangoLanguage *language)
{
g_return_if_fail (GTK_IS_FONT_DIALOG (self));
if (self->language == language)
return;
self->language = language;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LANGUAGE]);
}
/**
* gtk_font_dialog_get_fontmap
* @self: a `GtkFontDialog`
*
* Returns the fontmap from which fonts are selected,
* or `NULL` for the default fontmap.
*
* Returns: (nullable) (transfer none): the fontmap
*
* Since: 4.10
*/
PangoFontMap *
gtk_font_dialog_get_fontmap (GtkFontDialog *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG (self), NULL);
return self->fontmap;
}
/**
* gtk_font_dialog_set_fontmap:
* @self: a `GtkFontDialog`
* @fontmap: (nullable): the fontmap
*
* Sets the fontmap from which fonts are selected.
*
* If @fontmap is `NULL`, the default fontmap is used.
*
* Since: 4.10
*/
void
gtk_font_dialog_set_fontmap (GtkFontDialog *self,
PangoFontMap *fontmap)
{
g_return_if_fail (GTK_IS_FONT_DIALOG (self));
if (g_set_object (&self->fontmap, fontmap))
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FONTMAP]);
}
/**
* gtk_font_dialog_set_filter:
* @self: a `GtkFontDialog`
* @filter: (nullable): a `GtkFontFilterFunc`
* @user_data: (closure): data to pass to @filter
* @destroy: function to call to free @data when it is no longer needed
*
* Adds a filter function that decides which fonts to display
* in the font chooser dialog.
*
* Since: 4.10
*/
void
gtk_font_dialog_set_filter (GtkFontDialog *self,
GtkFontFilterFunc filter,
gpointer filter_data,
GDestroyNotify filter_data_destroy)
{
g_return_if_fail (GTK_IS_FONT_DIALOG (self));
g_clear_pointer (&self->filter_data, self->filter_data_destroy);
self->filter = filter;
self->filter_data = filter_data;
self->filter_data_destroy = filter_data_destroy;
}
/* }}} */
/* {{{ Async API */
static void response_cb (GTask *task,
int response);
static void
cancelled_cb (GCancellable *cancellable,
GTask *task)
{
response_cb (task, GTK_RESPONSE_CANCEL);
}
typedef struct
{
PangoFontDescription *font_desc;
char *font_features;
} FontResult;
static void
response_cb (GTask *task,
int response)
{
GCancellable *cancellable;
cancellable = g_task_get_cancellable (task);
if (cancellable)
g_signal_handlers_disconnect_by_func (cancellable, cancelled_cb, task);
if (response == GTK_RESPONSE_OK)
{
GtkFontChooserDialog *window;
FontResult font_result;
window = GTK_FONT_CHOOSER_DIALOG (g_task_get_task_data (task));
font_result.font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (window));
font_result.font_features = gtk_font_chooser_get_font_features (GTK_FONT_CHOOSER (window));
g_task_return_pointer (task, &font_result, NULL);
}
else
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
g_object_unref (task);
}
static void
dialog_response (GtkDialog *dialog,
int response,
GTask *task)
{
response_cb (task, response);
}
/**
* gtk_font_dialog_choose_font:
* @self: a `GtkFontDialog`
* @parent: (nullable): the parent `GtkWindow`
* @initial_font: (nullable): the font to select initially
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): a callback to call when the operation is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function initiates a font selection operation by
* presenting a font chooser dialog to the user.
*
* The @callback will be called when the dialog is dismissed.
* It should call [function@Gtk.FontDialog.choose_font_finish]
* to obtain the result.
*
* Since: 4.10
*/
void
gtk_font_dialog_choose_font (GtkFontDialog *self,
GtkWindow *parent,
PangoFontDescription *initial_font,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkFontChooserDialog *window;
GTask *task;
g_return_if_fail (GTK_IS_FONT_DIALOG (self));
window = GTK_FONT_CHOOSER_DIALOG (gtk_font_chooser_dialog_new (self->title, parent));
gtk_font_chooser_set_level (GTK_FONT_CHOOSER (window), self->level);
if (self->language)
gtk_font_chooser_set_language (GTK_FONT_CHOOSER (window), pango_language_to_string (self->language));
if (self->fontmap)
gtk_font_chooser_set_font_map (GTK_FONT_CHOOSER (window), self->fontmap);
if (initial_font)
gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (window), initial_font);
if (self->filter)
gtk_font_chooser_set_filter_func (GTK_FONT_CHOOSER (window),
self->filter,
self->filter_data,
self->filter_data_destroy);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_font_dialog_choose_font);
g_task_set_task_data (task, window, (GDestroyNotify) gtk_window_destroy);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), task);
g_signal_connect (window, "response", G_CALLBACK (dialog_response), task);
gtk_window_present (GTK_WINDOW (window));
}
/**
* gtk_font_dialog_choose_font_finish:
* @self: a `GtkFontDialog`
* @result: a `GAsyncResult`
* @font_desc: (out caller-allocates): return location for font description
* @font_features: (out caller-allocates): return location for font features
* @error: return location for an error
*
* Finishes the [function@Gtk.FontDialog.choose_font] call and
* returns the resulting font description and font features.
*
* Returns: `TRUE` if a font was selected. Otherwise,
* `FALSE` is returned and @error is set
*
* Since: 4.10
*/
gboolean
gtk_font_dialog_choose_font_finish (GtkFontDialog *self,
GAsyncResult *result,
PangoFontDescription **font_desc,
char **font_features,
GError **error)
{
FontResult *font_result;
font_result = g_task_propagate_pointer (G_TASK (result), error);
if (font_result)
{
*font_desc = font_result->font_desc;
*font_features = font_result->font_features;
return TRUE;
}
return FALSE;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -1,97 +0,0 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2022 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtkfontchooser.h>
G_BEGIN_DECLS
#define GTK_TYPE_FONT_DIALOG (gtk_font_dialog_get_type ())
GDK_AVAILABLE_IN_4_10
G_DECLARE_FINAL_TYPE (GtkFontDialog, gtk_font_dialog, GTK, FONT_DIALOG, GObject)
GDK_AVAILABLE_IN_4_10
GtkFontDialog * gtk_font_dialog_new (void);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_set_title (GtkFontDialog *self,
const char *title);
GDK_AVAILABLE_IN_4_10
gboolean gtk_font_dialog_get_modal (GtkFontDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_set_modal (GtkFontDialog *self,
gboolean modal);
GDK_AVAILABLE_IN_4_10
const char * gtk_font_dialog_get_title (GtkFontDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_set_level (GtkFontDialog *self,
GtkFontChooserLevel level);
GDK_AVAILABLE_IN_4_10
GtkFontChooserLevel
gtk_font_dialog_get_level (GtkFontDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_set_language (GtkFontDialog *self,
PangoLanguage *language);
GDK_AVAILABLE_IN_4_10
PangoLanguage * gtk_font_dialog_get_language (GtkFontDialog *self);
GDK_AVAILABLE_IN_4_10
PangoFontMap * gtk_font_dialog_get_fontmap (GtkFontDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_set_fontmap (GtkFontDialog *self,
PangoFontMap *fontmap);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_set_filter (GtkFontDialog *self,
GtkFontFilterFunc filter,
gpointer user_data,
GDestroyNotify destroy);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_choose_font (GtkFontDialog *self,
GtkWindow *parent,
PangoFontDescription *initial_font,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_4_10
gboolean gtk_font_dialog_choose_font_finish
(GtkFontDialog *self,
GAsyncResult *result,
PangoFontDescription **font_desc,
char **font_features,
GError **error);
G_END_DECLS

View File

@@ -1,778 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkfontdialogbutton.h"
#include "gtkbinlayout.h"
#include "gtkbox.h"
#include "gtkseparator.h"
#include "gtkbutton.h"
#include "gtklabel.h"
#include <glib/gi18n-lib.h>
#include "gtkmain.h"
#include "gtkprivate.h"
#include "gtkwidgetprivate.h"
static void button_clicked (GtkFontDialogButton *self);
/**
* GtkFontDialogButton:
*
* The `GtkFontDialogButton` is wrapped around a [class@Gtk.FontDialog]
* and allows to open a font chooser dialog to change the font.
*
* ![An example GtkFontDialogButton](font-button.png)
*
* It is suitable widget for selecting a font in a preference dialog.
*
* # CSS nodes
*
* ```
* fontbutton
* ╰── button.font
* ╰── [content]
* ```
*
* `GtkFontDialogButton` has a single CSS node with name fontbutton which
* contains a button node with the .font style class.
*/
/* {{{ GObject implementation */
struct _GtkFontDialogButton
{
GtkWidget parent_instance;
GtkWidget *button;
GtkWidget *font_label;
GtkWidget *size_label;
GtkWidget *font_size_box;
guint use_font : 1;
guint use_size : 1;
GtkFontDialog *dialog;
PangoFontDescription *font_desc;
char *font_features;
PangoFontFamily *font_family;
PangoFontFace *font_face;
};
/* Properties */
enum
{
PROP_DIALOG = 1,
PROP_FONT_DESC,
PROP_FONT_FEATURES,
PROP_USE_FONT,
PROP_USE_SIZE,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
G_DEFINE_TYPE (GtkFontDialogButton, gtk_font_dialog_button, GTK_TYPE_WIDGET)
static void
gtk_font_dialog_button_init (GtkFontDialogButton *self)
{
GtkWidget *box;
PangoFontDescription *font_desc;
self->button = gtk_button_new ();
g_signal_connect_swapped (self->button, "clicked", G_CALLBACK (button_clicked), self);
self->font_label = gtk_label_new (_("Font"));
gtk_widget_set_hexpand (self->font_label, TRUE);
self->size_label = gtk_label_new ("14");
self->font_size_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_append (GTK_BOX (box), self->font_label);
gtk_box_append (GTK_BOX (self->font_size_box), gtk_separator_new (GTK_ORIENTATION_VERTICAL));
gtk_box_append (GTK_BOX (self->font_size_box), self->size_label);
gtk_box_append (GTK_BOX (box), self->font_size_box);
gtk_button_set_child (GTK_BUTTON (self->button), box);
gtk_widget_set_parent (self->button, GTK_WIDGET (self));
self->use_font = FALSE;
self->use_size = FALSE;
font_desc = pango_font_description_from_string ("Sans 12");
gtk_font_dialog_button_set_font_desc (self, font_desc);
pango_font_description_free (font_desc);
gtk_widget_add_css_class (self->button, "font");
}
static void
gtk_font_dialog_button_set_property (GObject *object,
unsigned int param_id,
const GValue *value,
GParamSpec *pspec)
{
GtkFontDialogButton *self = GTK_FONT_DIALOG_BUTTON (object);
switch (param_id)
{
case PROP_DIALOG:
gtk_font_dialog_button_set_dialog (self, g_value_get_object (value));
break;
case PROP_FONT_DESC:
gtk_font_dialog_button_set_font_desc (self, g_value_get_boxed (value));
break;
case PROP_FONT_FEATURES:
gtk_font_dialog_button_set_font_features (self, g_value_get_string (value));
break;
case PROP_USE_FONT:
gtk_font_dialog_button_set_use_font (self, g_value_get_boolean (value));
break;
case PROP_USE_SIZE:
gtk_font_dialog_button_set_use_size (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gtk_font_dialog_button_get_property (GObject *object,
unsigned int param_id,
GValue *value,
GParamSpec *pspec)
{
GtkFontDialogButton *self = GTK_FONT_DIALOG_BUTTON (object);
switch (param_id)
{
case PROP_DIALOG:
g_value_set_object (value, self->dialog);
break;
case PROP_FONT_DESC:
g_value_set_boxed (value, self->font_desc);
break;
case PROP_FONT_FEATURES:
g_value_set_string (value, self->font_features);
break;
case PROP_USE_FONT:
g_value_set_boolean (value, self->use_font);
break;
case PROP_USE_SIZE:
g_value_set_boolean (value, self->use_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gtk_font_dialog_button_dispose (GObject *object)
{
GtkFontDialogButton *self = GTK_FONT_DIALOG_BUTTON (object);
g_clear_pointer (&self->button, gtk_widget_unparent);
G_OBJECT_CLASS (gtk_font_dialog_button_parent_class)->dispose (object);
}
static void
gtk_font_dialog_button_finalize (GObject *object)
{
GtkFontDialogButton *self = GTK_FONT_DIALOG_BUTTON (object);
g_clear_object (&self->dialog);
pango_font_description_free (self->font_desc);
g_clear_object (&self->font_family);
g_clear_object (&self->font_face);
g_free (self->font_features);
G_OBJECT_CLASS (gtk_font_dialog_button_parent_class)->finalize (object);
}
static void
gtk_font_dialog_button_class_init (GtkFontDialogButtonClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->get_property = gtk_font_dialog_button_get_property;
object_class->set_property = gtk_font_dialog_button_set_property;
object_class->dispose = gtk_font_dialog_button_dispose;
object_class->finalize = gtk_font_dialog_button_finalize;
widget_class->grab_focus = gtk_widget_grab_focus_child;
widget_class->focus = gtk_widget_focus_child;
/**
* GtkFontDialogButton:dialog: (attributes org.gtk.Property.get=gtk_font_dialog_button_get_dialog org.gtk.Property.set=gtk_font_dialog_button_set_dialog)
*
* The `GtkFontDialog` that contains parameters for
* the font chooser dialog.
*
* Since: 4.10
*/
properties[PROP_DIALOG] =
g_param_spec_object ("dialog", NULL, NULL,
GTK_TYPE_FONT_DIALOG,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFontDialogButton:font-desc: (attributes org.gtk.Property.get=gtk_font_dialog_button_get_font_desc org.gtk.Property.set=gtk_font_dialog_button_set_font_desc)
*
* The selected font.
*
* This property can be set to give the button its initial
* font, and it will be updated to reflect the users choice
* in the font chooser dialog.
*
* Listen to `notify::font-desc` to get informed about changes
* to the buttons font.
*
* Since: 4.10
*/
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", NULL, NULL,
PANGO_TYPE_FONT_DESCRIPTION,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFontDialogButton:font-features: (attributes org.gtk.Property.get=gtk_font_dialog_button_get_font_features org.gtk.Property.set=gtk_font_dialog_button_set_font_features)
*
* The selected font features.
*
* This property will be updated to reflect the users choice
* in the font chooser dialog.
*
* Listen to `notify::font-features` to get informed about changes
* to the buttons font features.
*
* Since: 4.10
*/
properties[PROP_FONT_FEATURES] =
g_param_spec_string ("font-features", NULL, NULL,
NULL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFontDialogButton:use-font: (attributes org.gtk.Property.get=gtk_font_dialog_button_get_use_font org.gtk.Property.set=gtk_font_dialog_button_set_use_font)
*
* Whether the buttons label will be drawn in the selected font.
*/
properties[PROP_USE_FONT] =
g_param_spec_boolean ("use-font", NULL, NULL,
FALSE,
GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkFontDialogButton:use-size: (attributes org.gtk.Property.get=gtk_font_dialog_button_get_use_size org.gtk.Property.set=gtk_font_dialog_button_set_use_size)
*
* Whether the buttons label will use the selected font size.
*/
properties[PROP_USE_SIZE] =
g_param_spec_boolean ("use-size", NULL, NULL,
FALSE,
GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_css_name (widget_class, "fontbutton");
}
/* }}} */
/* {{{ Private API, callbacks */
static void
font_chosen (GObject *source,
GAsyncResult *result,
gpointer data)
{
GtkFontDialogButton *self = data;
PangoFontDescription *desc;
char *features;
GError *error = NULL;
if (gtk_font_dialog_choose_font_finish (self->dialog, result, &desc, &features, &error))
{
gtk_font_dialog_button_set_font_desc (self, desc);
gtk_font_dialog_button_set_font_features (self, features);
}
else
{
g_print ("%s\n", error->message);
g_error_free (error);
}
}
static void
button_clicked (GtkFontDialogButton *self)
{
GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (self));
GtkWindow *parent = NULL;
if (GTK_IS_WINDOW (root))
parent = GTK_WINDOW (root);
gtk_font_dialog_choose_font (self->dialog, parent, self->font_desc,
NULL, font_chosen, self);
}
static gboolean
font_description_style_equal (const PangoFontDescription *a,
const PangoFontDescription *b)
{
return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
}
static void
update_font_data (GtkFontDialogButton *self)
{
PangoFontMap *fontmap = NULL;
const char *family_name;
g_assert (self->font_desc != NULL);
g_clear_object (&self->font_family);
g_clear_object (&self->font_face);
family_name = pango_font_description_get_family (self->font_desc);
if (family_name == NULL)
return;
if (self->dialog)
fontmap = gtk_font_dialog_get_fontmap (self->dialog);
if (!fontmap)
fontmap = pango_cairo_font_map_get_default ();
for (unsigned int i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (fontmap)); i++)
{
PangoFontFamily *family = g_list_model_get_item (G_LIST_MODEL (fontmap), i);
const char *name = pango_font_family_get_name (family);
g_object_unref (family);
if (g_ascii_strcasecmp (name, family_name) == 0)
{
g_set_object (&self->font_family, family);
break;
}
}
for (unsigned i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->font_family)); i++)
{
PangoFontFace *face = g_list_model_get_item (G_LIST_MODEL (self->font_family), i);
PangoFontDescription *tmp_desc = pango_font_face_describe (face);
g_object_unref (face);
if (font_description_style_equal (tmp_desc, self->font_desc))
{
g_set_object (&self->font_face, face);
pango_font_description_free (tmp_desc);
break;
}
else
pango_font_description_free (tmp_desc);
}
}
static void
update_font_info (GtkFontDialogButton *self)
{
const char *fam_name;
const char *face_name;
char *family_style;
GtkFontChooserLevel level;
if (self->font_family)
fam_name = pango_font_family_get_name (self->font_family);
else
fam_name = C_("font", "None");
if (self->font_face)
face_name = pango_font_face_get_face_name (self->font_face);
else
face_name = "";
if (self->dialog)
level = gtk_font_dialog_get_level (self->dialog);
else
level = GTK_FONT_CHOOSER_LEVEL_STYLE|GTK_FONT_CHOOSER_LEVEL_SIZE;
if ((level & GTK_FONT_CHOOSER_LEVEL_STYLE) != 0)
family_style = g_strconcat (fam_name, " ", face_name, NULL);
else
family_style = g_strdup (fam_name);
gtk_label_set_text (GTK_LABEL (self->font_label), family_style);
g_free (family_style);
if ((level & GTK_FONT_CHOOSER_LEVEL_SIZE) != 0)
{
/* mirror Pango, which doesn't translate this either */
char *size = g_strdup_printf ("%2.4g%s",
pango_font_description_get_size (self->font_desc) / (double)PANGO_SCALE,
pango_font_description_get_size_is_absolute (self->font_desc) ? "px" : "");
gtk_label_set_text (GTK_LABEL (self->size_label), size);
g_free (size);
gtk_widget_show (self->font_size_box);
}
else
gtk_widget_hide (self->font_size_box);
}
static void
apply_use_font (GtkFontDialogButton *self)
{
if (!self->use_font)
gtk_label_set_attributes (GTK_LABEL (self->font_label), NULL);
else
{
PangoFontDescription *desc;
PangoAttrList *attrs;
PangoLanguage *language = NULL;
desc = pango_font_description_copy (self->font_desc);
if (!self->use_size)
pango_font_description_unset_fields (desc, PANGO_FONT_MASK_SIZE);
attrs = pango_attr_list_new ();
/* Prevent font fallback */
pango_attr_list_insert (attrs, pango_attr_fallback_new (FALSE));
/* Force current font and features */
pango_attr_list_insert (attrs, pango_attr_font_desc_new (desc));
if (self->font_features)
pango_attr_list_insert (attrs, pango_attr_font_features_new (self->font_features));
if (self->dialog)
language = gtk_font_dialog_get_language (self->dialog);
if (language)
pango_attr_list_insert (attrs, pango_attr_language_new (language));
gtk_label_set_attributes (GTK_LABEL (self->font_label), attrs);
pango_attr_list_unref (attrs);
pango_font_description_free (desc);
}
}
/* }}} */
/* {{{ Public API */
/* {{{ Constructor */
/**
* gtk_font_dialog_button_new:
* @dialog: (nullable) (transfer full): the `GtkFontDialog` to use
*
* Creates a new `GtkFontDialogButton` with the
* given `GtkFontDialog`.
*
* You can pass `NULL` to this function and set a `GtkFontDialog`
* later. The button will be insensitive until that happens.
*
* Returns: the new `GtkFontDialogButton`
*
* Since: 4.10
*/
GtkWidget *
gtk_font_dialog_button_new (GtkFontDialog *dialog)
{
GtkWidget *self;
g_return_val_if_fail (GTK_IS_FONT_DIALOG (dialog), NULL);
self = g_object_new (GTK_TYPE_FONT_DIALOG_BUTTON,
"dialog", dialog,
NULL);
g_clear_object (&dialog);
return self;
}
/* }}} */
/* {{{ Setters and Getters */
/**
* gtk_font_dialog_button_set_dialog:
* @self: a `GtkFontDialogButton`
* @dialog: the new `GtkFontDialog`
*
* Sets a `GtkFontDialog` object to use for
* creating the font chooser dialog that is
* presented when the user clicks the button.
*
* Since: 4.10
*/
void
gtk_font_dialog_button_set_dialog (GtkFontDialogButton *self,
GtkFontDialog *dialog)
{
g_return_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self));
g_return_if_fail (dialog == NULL || GTK_IS_FONT_DIALOG (dialog));
if (!g_set_object (&self->dialog, dialog))
return;
gtk_widget_set_sensitive (self->button, dialog != NULL);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DIALOG]);
}
/**
* gtk_font_dialog_button_get_dialog:
* @self: a `GtkFontDialogButton`
*
* Returns the `GtkFontDialog` of @self.
*
* Returns: (nullable) (transfer none): the `GtkFontDialog`
*
* Since: 4.10
*/
GtkFontDialog *
gtk_font_dialog_button_get_dialog (GtkFontDialogButton *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self), NULL);
return self->dialog;
}
/**
* gtk_font_dialog_button_set_font_desc:
* @self: a `GtkFontDialogButton`
* @font_desc: the new font
*
* Sets the font of the button.
*
* Since: 4.10
*/
void
gtk_font_dialog_button_set_font_desc (GtkFontDialogButton *self,
PangoFontDescription *font_desc)
{
g_return_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self));
g_return_if_fail (font_desc != NULL);
if (self->font_desc == font_desc ||
(self->font_desc && font_desc &&
pango_font_description_equal (self->font_desc, font_desc)))
return;
if (self->font_desc)
pango_font_description_free (self->font_desc);
self->font_desc = pango_font_description_copy (font_desc);
update_font_data (self);
update_font_info (self);
apply_use_font (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FONT_DESC]);
}
/**
* gtk_font_dialog_button_get_font_desc:
* @self: a `GtkFontDialogButton`
*
* Returns the font of the button.
*
* This function is what should be used to obtain
* the font that was choosen by the user. To get
* informed about changes, listen to "notify::font-desc".
*
* Returns: (transfer none) (nullable): the font
*
* Since: 4.10
*/
PangoFontDescription *
gtk_font_dialog_button_get_font_desc (GtkFontDialogButton *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self), NULL);
return self->font_desc;
}
/**
* gtk_font_dialog_button_set_font_features:
* @self: a `GtkFontDialogButton`
* @font_features: (nullable): the font features
*
* Sets the font features of the button.
*
* Since: 4.10
*/
void
gtk_font_dialog_button_set_font_features (GtkFontDialogButton *self,
const char *font_features)
{
char *new_features;
g_return_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self));
if (g_strcmp0 (self->font_features, font_features) == 0)
return;
new_features = g_strdup (font_features);
g_free (self->font_features);
self->font_features = new_features;
apply_use_font (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FONT_FEATURES]);
}
/**
* gtk_font_dialog_button_get_font_features:
* @self: a `GtkFontDialogButton`
*
* Returns the font features of the button.
*
* This function is what should be used to obtain
* the font features that were choosen by the user.
* To get informed about changes, listen to
* "notify::font-features".
*
* Returns: (transfer none) (nullable): the font features
*
* Since: 4.10
*/
const char *
gtk_font_dialog_button_get_font_features (GtkFontDialogButton *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self), NULL);
return self->font_features;
}
/**
* gtk_font_dialog_button_set_use_font:
* @self: a `GtkFontDialogButton`
* @use_font: If `TRUE`, font name will be written using
* the chosen font
*
* If @use_font is `TRUE`, the font name will be written
* using the selected font.
*
* Since: 4.10
*/
void
gtk_font_dialog_button_set_use_font (GtkFontDialogButton *self,
gboolean use_font)
{
g_return_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self));
if (self->use_font == use_font)
return;
self->use_font = use_font;
apply_use_font (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USE_FONT]);
}
/**
* gtk_font_dialog_button_get_use_font:
* @self: a `GtkFontDialogButton`
*
* Returns whether the selected font is used in the label.
*
* Returns: whether the selected font is used in the label
*
* Since: 4.10
*/
gboolean
gtk_font_dialog_button_get_use_font (GtkFontDialogButton *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self), FALSE);
return self->use_font;
}
/**
* gtk_font_dialog_button_set_use_size:
* @self: a `GtkFontDialogButton`
* @use_size: If `TRUE`, font name will be written using
* the chosen font size
*
* If @use_size is `TRUE`, the font name will be written
* using the selected font size.
*
* Since: 4.10
*/
void
gtk_font_dialog_button_set_use_size (GtkFontDialogButton *self,
gboolean use_size)
{
g_return_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self));
if (self->use_size == use_size)
return;
self->use_size = use_size;
apply_use_font (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USE_SIZE]);
}
/**
* gtk_font_dialog_button_get_use_size:
* @self: a `GtkFontDialogButton`
*
* Returns whether the selected font size is used in the label.
*
* Returns: whether the selected font size is used in the label
*
* Since: 4.10
*/
gboolean
gtk_font_dialog_button_get_use_size (GtkFontDialogButton *self)
{
g_return_val_if_fail (GTK_IS_FONT_DIALOG_BUTTON (self), FALSE);
return self->use_size;
}
/* }}} */
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -1,76 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkbutton.h>
#include <gtk/gtkfontdialog.h>
G_BEGIN_DECLS
#define GTK_TYPE_FONT_DIALOG_BUTTON (gtk_font_dialog_button_get_type ())
GDK_AVAILABLE_IN_4_10
G_DECLARE_FINAL_TYPE (GtkFontDialogButton, gtk_font_dialog_button, GTK, FONT_DIALOG_BUTTON, GtkWidget)
GDK_AVAILABLE_IN_4_10
GtkWidget * gtk_font_dialog_button_new (GtkFontDialog *dialog);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_button_set_dialog (GtkFontDialogButton *self,
GtkFontDialog *dialog);
GDK_AVAILABLE_IN_4_10
GtkFontDialog * gtk_font_dialog_button_get_dialog (GtkFontDialogButton *self);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_button_set_font_desc (GtkFontDialogButton *self,
PangoFontDescription *font_desc);
GDK_AVAILABLE_IN_4_10
PangoFontDescription *
gtk_font_dialog_button_get_font_desc (GtkFontDialogButton *self);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_button_set_font_features
(GtkFontDialogButton *self,
const char *font_features);
GDK_AVAILABLE_IN_4_10
const char * gtk_font_dialog_button_get_font_features (GtkFontDialogButton *self);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_button_set_use_font (GtkFontDialogButton *self,
gboolean use_font);
GDK_AVAILABLE_IN_4_10
gboolean gtk_font_dialog_button_get_use_font (GtkFontDialogButton *self);
GDK_AVAILABLE_IN_4_10
void gtk_font_dialog_button_set_use_size (GtkFontDialogButton *self,
gboolean use_size);
GDK_AVAILABLE_IN_4_10
gboolean gtk_font_dialog_button_get_use_size (GtkFontDialogButton *self);
G_END_DECLS

View File

@@ -1,715 +0,0 @@
/*
* GTK - The GIMP Toolkit
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkinfodialog.h"
#include "gtkbutton.h"
#include "gtkmessagedialog.h"
#include <glib/gi18n-lib.h>
/**
* GtkInfoDialog:
*
* A `GtkInfoDialog` object collects the arguments that
* are needed to present a info chooser dialog to the
* user, such as a title for the dialog and whether it
* should be modal.
*
* The dialog is shown with the [function@Gtk.InfoDialog.present]
* function. This API follows the GIO async pattern, and the
* result can be obtained by calling
* [function@Gtk.InfoDialog.present_finish].
*
* `GtkInfoDialog was added in GTK 4.10.
*/
/* {{{ GObject implementation */
struct _GtkInfoDialog
{
GObject parent_instance;
char *heading;
char *body;
char **buttons;
unsigned int modal : 1;
unsigned int heading_use_markup: 1;
unsigned int body_use_markup: 1;
};
enum
{
PROP_MODAL = 1,
PROP_HEADING,
PROP_HEADING_USE_MARKUP,
PROP_BODY,
PROP_BODY_USE_MARKUP,
PROP_BUTTONS,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
G_DEFINE_TYPE (GtkInfoDialog, gtk_info_dialog, G_TYPE_OBJECT)
static void
gtk_info_dialog_init (GtkInfoDialog *self)
{
self->modal = TRUE;
}
static void
gtk_info_dialog_finalize (GObject *object)
{
GtkInfoDialog *self = GTK_INFO_DIALOG (object);
g_free (self->heading);
g_free (self->body);
g_strfreev (self->buttons);
G_OBJECT_CLASS (gtk_info_dialog_parent_class)->finalize (object);
}
static void
gtk_info_dialog_get_property (GObject *object,
unsigned int property_id,
GValue *value,
GParamSpec *pspec)
{
GtkInfoDialog *self = GTK_INFO_DIALOG (object);
switch (property_id)
{
case PROP_MODAL:
g_value_set_boolean (value, self->modal);
break;
case PROP_HEADING:
g_value_set_string (value, self->heading);
break;
case PROP_HEADING_USE_MARKUP:
g_value_set_boolean (value, self->heading_use_markup);
break;
case PROP_BODY:
g_value_set_string (value, self->body);
break;
case PROP_BODY_USE_MARKUP:
g_value_set_boolean (value, self->body_use_markup);
break;
case PROP_BUTTONS:
g_value_set_boxed (value, self->buttons);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_info_dialog_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkInfoDialog *self = GTK_INFO_DIALOG (object);
switch (prop_id)
{
case PROP_MODAL:
gtk_info_dialog_set_modal (self, g_value_get_boolean (value));
break;
case PROP_HEADING:
gtk_info_dialog_set_heading (self, g_value_get_string (value));
break;
case PROP_HEADING_USE_MARKUP:
gtk_info_dialog_set_heading_use_markup (self, g_value_get_boolean (value));
break;
case PROP_BODY:
gtk_info_dialog_set_body (self, g_value_get_string (value));
break;
case PROP_BODY_USE_MARKUP:
gtk_info_dialog_set_body_use_markup (self, g_value_get_boolean (value));
break;
case PROP_BUTTONS:
gtk_info_dialog_set_buttons (self, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_info_dialog_class_init (GtkInfoDialogClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_info_dialog_finalize;
object_class->get_property = gtk_info_dialog_get_property;
object_class->set_property = gtk_info_dialog_set_property;
/**
* GtkInfoDialog:modal: (attributes org.gtk.Property.get=gtk_info_dialog_get_modal org.gtk.Property.set=gtk_color_dialog_set_modal)
*
* Whether the info chooser dialog is modal.
*
* Since: 4.10
*/
properties[PROP_MODAL] =
g_param_spec_boolean ("modal", NULL, NULL,
TRUE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkInfoDialog:heading: (attributes org.gtk.Property.get=gtk_info_dialog_get_heading org.gtk.Property.set=gtk_color_dialog_set_heading)
*
* The heading for the dialog that is presented
* by [function@Gtk.InfoDialog.present].
*
* Since: 4.10
*/
properties[PROP_HEADING] =
g_param_spec_string ("heading", NULL, NULL,
NULL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkInfoDialog:heading-use-markup: (attributes org.gtk.Property.get=gtk_info_dialog_get_heading_use_markup org.gtk.Property.set=gtk_color_dialog_set_heading_use_markup)
*
* Whether the heading uses markup.
*
* Since: 4.10
*/
properties[PROP_HEADING_USE_MARKUP] =
g_param_spec_boolean ("heading-use-markup", NULL, NULL,
FALSE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkInfoDialog:body: (attributes org.gtk.Property.get=gtk_info_dialog_get_body org.gtk.Property.set=gtk_color_dialog_set_body)
*
* The body text for the dialog that is presented
* by [function@Gtk.InfoDialog.present].
*
* Since: 4.10
*/
properties[PROP_BODY] =
g_param_spec_string ("body", NULL, NULL,
NULL,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkInfoDialog:body-use-markup: (attributes org.gtk.Property.get=gtk_info_dialog_get_body_use_markup org.gtk.Property.set=gtk_color_dialog_set_body_use_markup)
*
* Whether the body text uses markup.
*
* Since: 4.10
*/
properties[PROP_BODY_USE_MARKUP] =
g_param_spec_boolean ("body-use-markup", NULL, NULL,
FALSE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkInfoDialog:buttons: (attributes org.gtk.Property.get=gtk_info_dialog_get_buttons org.gtk.Property.set=gtk_color_dialog_set_buttons)
*
* The labels for buttons to show in the dialog that is presented
* by [function@Gtk.InfoDialog.present].
*
* The labels should be translated and may contain a _ to indicate
* mnemonic characters.
*
* Since: 4.10
*/
properties[PROP_BUTTONS] =
g_param_spec_boxed ("buttons", NULL, NULL,
G_TYPE_STRV,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}
/* }}} */
/* {{{ Constructor */
/**
* gtk_info_dialog_new:
*
* Creates a new `GtkInfoDialog` object.
*
* Returns: the new `GtkInfoDialog`
*
* Since: 4.10
*/
GtkInfoDialog *
gtk_info_dialog_new (void)
{
return g_object_new (GTK_TYPE_INFO_DIALOG, NULL);
}
/* }}} */
/* {{{ Getters and setters */
/**
* gtk_info_dialog_get_modal:
* @self: a `GtkInfoDialog`
*
* Returns whether the info chooser dialog
* blocks interaction with the parent window
* while it is presented.
*
* Returns: `TRUE` if the info chooser dialog is modal
*
* Since: 4.10
*/
gboolean
gtk_info_dialog_get_modal (GtkInfoDialog *self)
{
g_return_val_if_fail (GTK_IS_INFO_DIALOG (self), TRUE);
return self->modal;
}
/**
* gtk_info_dialog_set_modal:
* @self: a `GtkInfoDialog`
* @modal: the new value
*
* Sets whether the info chooser dialog
* blocks interaction with the parent window
* while it is presented.
*
* Since: 4.10
*/
void
gtk_info_dialog_set_modal (GtkInfoDialog *self,
gboolean modal)
{
g_return_if_fail (GTK_IS_INFO_DIALOG (self));
if (self->modal == modal)
return;
self->modal = modal;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODAL]);
}
/**
* gtk_info_dialog_get_heading:
* @self: a `GtkInfoDialog`
*
* Returns the heading that will be shown in the
* info dialog.
*
* Returns: the heading
*
* Since: 4.10
*/
const char *
gtk_info_dialog_get_heading (GtkInfoDialog *self)
{
g_return_val_if_fail (GTK_IS_INFO_DIALOG (self), NULL);
return self->heading;
}
/**
* gtk_info_dialog_set_heading:
* @self: a `GtkInfoDialog`
* @text: the new heading
*
* Sets the heading that will be shown in the
* info dialog.
*
* Since: 4.10
*/
void
gtk_info_dialog_set_heading (GtkInfoDialog *self,
const char *text)
{
char *new_text;
g_return_if_fail (GTK_IS_INFO_DIALOG (self));
g_return_if_fail (text != NULL);
if (g_strcmp0 (self->heading, text) == 0)
return;
new_text = g_strdup (text);
g_free (self->heading);
self->heading = new_text;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADING]);
}
/**
* gtk_info_dialog_get_heading_use_markup:
* @self: a `GtkInfoDialog`
*
* Returns whether the heading uses markup.
*
* Returns: `TRUE` if the heading uses markup
*
* Since: 4.10
*/
gboolean
gtk_info_dialog_get_heading_use_markup (GtkInfoDialog *self)
{
g_return_val_if_fail (GTK_IS_INFO_DIALOG (self), FALSE);
return self->heading_use_markup;
}
/**
* gtk_info_dialog_set_heading_use_markup:
* @self: a `GtkInfoDialog`
* @use_markup: the new value
*
* Sets whether the heading uses markup.
*
* Since: 4.10
*/
void
gtk_info_dialog_set_heading_use_markup (GtkInfoDialog *self,
gboolean use_markup)
{
g_return_if_fail (GTK_IS_INFO_DIALOG (self));
if (self->heading_use_markup == use_markup)
return;
self->heading_use_markup = use_markup;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADING_USE_MARKUP]);
}
/**
* gtk_info_dialog_get_body:
* @self: a `GtkInfoDialog`
*
* Returns the body text that will be shown
* in the info dialog.
*
* Returns: the body text
*
* Since: 4.10
*/
const char *
gtk_info_dialog_get_body (GtkInfoDialog *self)
{
g_return_val_if_fail (GTK_IS_INFO_DIALOG (self), NULL);
return self->body;
}
/**
* gtk_info_dialog_set_body:
* @self: a `GtkInfoDialog`
* @text: the new text
*
* Sets the body text that will be shown
* in the info dialog.
*
* Since: 4.10
*/
void
gtk_info_dialog_set_body (GtkInfoDialog *self,
const char *text)
{
char *new_text;
g_return_if_fail (GTK_IS_INFO_DIALOG (self));
g_return_if_fail (text != NULL);
if (g_strcmp0 (self->body, text) == 0)
return;
new_text = g_strdup (text);
g_free (self->body);
self->body = new_text;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BODY]);
}
/**
* gtk_info_dialog_get_body_use_markup:
* @self: a `GtkInfoDialog`
*
* Returns whether the body text uses markup.
*
* Returns: `TRUE` if body text uses markup
*
* Since: 4.10
*/
gboolean
gtk_info_dialog_get_body_use_markup (GtkInfoDialog *self)
{
g_return_val_if_fail (GTK_IS_INFO_DIALOG (self), FALSE);
return self->body_use_markup;
}
/**
* gtk_info_dialog_set_body_use_markup:
* @self: a `GtkInfoDialog`
* @use_markup: the new value
*
* Sets whether the body text uses markup.
*
* Since: 4.10
*/
void
gtk_info_dialog_set_body_use_markup (GtkInfoDialog *self,
gboolean use_markup)
{
g_return_if_fail (GTK_IS_INFO_DIALOG (self));
if (self->body_use_markup == use_markup)
return;
self->body_use_markup = use_markup;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BODY_USE_MARKUP]);
}
/**
* gtk_info_dialog_get_buttons:
* @self: a `GtkInfoDialog`
*
* Returns the button labels for the info dialog.
*
* Returns: (nullable) (transfer none): the button labels
*
* Since: 4.10
*/
const char * const *
gtk_info_dialog_get_buttons (GtkInfoDialog *self)
{
g_return_val_if_fail (GTK_IS_INFO_DIALOG (self), NULL);
return (const char * const *) self->buttons;
}
/**
* gtk_info_dialog_set_buttons:
* @self: a `GtkInfoDialog`
* @labels: the new button labels
*
* Sets the button labels for the info dialog.
*
* Since: 4.10
*/
void
gtk_info_dialog_set_buttons (GtkInfoDialog *self,
const char * const *labels)
{
g_return_if_fail (GTK_IS_INFO_DIALOG (self));
g_return_if_fail (labels != NULL);
g_strfreev (self->buttons);
self->buttons = g_strdupv ((char **)labels);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BUTTONS]);
}
/* }}} */
/* {{{ Convenience API */
/**
* gtk_info_dialog_set_heading_markup:
* @self: a `GtkInfoDialog`
* @text: the new heading
*
* Sets the heading that will be shown in the
* info dialog, and marks it as using markup.
*
* Since: 4.10
*/
void
gtk_info_dialog_set_heading_markup (GtkInfoDialog *self,
const char *text)
{
g_object_freeze_notify (G_OBJECT (self));
gtk_info_dialog_set_heading (self, text);
gtk_info_dialog_set_heading_use_markup (self, TRUE);
g_object_thaw_notify (G_OBJECT (self));
}
/**
* gtk_info_dialog_set_body_markup:
* @self: a `GtkInfoDialog`
* @text: the new heading
*
* Sets the body text that will be shown in the
* info dialog, and marks it as using markup.
*
* Since: 4.10
*/
void
gtk_info_dialog_set_body_markup (GtkInfoDialog *self,
const char *text)
{
g_object_freeze_notify (G_OBJECT (self));
gtk_info_dialog_set_body (self, text);
gtk_info_dialog_set_body_use_markup (self, TRUE);
g_object_thaw_notify (G_OBJECT (self));
}
/* }}} */
/* {{{ Async API */
static void response_cb (GTask *task,
int response);
static void
cancelled_cb (GCancellable *cancellable,
GTask *task)
{
response_cb (task, -1);
}
static void
response_cb (GTask *task,
int response)
{
GCancellable *cancellable;
cancellable = g_task_get_cancellable (task);
if (cancellable)
g_signal_handlers_disconnect_by_func (cancellable, cancelled_cb, task);
if (response >= 0)
g_task_return_int (task, response);
else
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
g_object_unref (task);
}
static void
dialog_response (GtkDialog *dialog,
int response,
GTask *task)
{
response_cb (task, response);
}
/**
* gtk_info_dialog_present:
* @self: a `GtkInfoDialog`
* @parent: (nullable): the parent `GtkWindow`
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): a callback to call when the operation is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents an info dialog to the user.
*
* The @callback will be called when the dialog is dismissed.
* It should call [function@Gtk.InfoDialog.present_finish]
* to obtain the result.
*
* Since: 4.10
*/
void
gtk_info_dialog_present (GtkInfoDialog *self,
GtkWindow *parent,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkMessageDialog *window;
GTask *task;
g_return_if_fail (GTK_IS_INFO_DIALOG (self));
window = g_object_new (GTK_TYPE_MESSAGE_DIALOG,
"transient-for", parent,
"destroy-with-parent", TRUE,
"modal", self->modal,
"text", self->heading,
"use-markup", self->heading_use_markup,
"secondary-text", self->body,
"secondary-use-markup", self->body_use_markup,
NULL);
if (self->buttons)
{
for (int i = 0; self->buttons[i]; i++)
gtk_dialog_add_button (GTK_DIALOG (window), self->buttons[i], i);
}
else
gtk_dialog_add_button (GTK_DIALOG (window), _("Close"), 0);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_info_dialog_present);
g_task_set_task_data (task, window, (GDestroyNotify) gtk_window_destroy);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), task);
g_signal_connect (window, "response", G_CALLBACK (dialog_response), task);
gtk_window_present (GTK_WINDOW (window));
}
/**
* gtk_info_dialog_present_finish:
* @self: a `GtkInfoDialog`
* @result: a `GAsyncResult`
* @button: (out caller-allocates): return location for button
* @error: return location for an error
*
* Finishes the [function@Gtk.InfoDialog.present] call
* and returns the button that was clicked.
*
* Returns: `TRUE` if a button was clicked.
* Otherwise, `FALSE` is returned and @error is set
*
* Since: 4.10
*/
gboolean
gtk_info_dialog_present_finish (GtkInfoDialog *self,
GAsyncResult *result,
int *button,
GError **error)
{
*button = (int) g_task_propagate_int (G_TASK (result), error);
return ! (error && *error);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -1,104 +0,0 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2022 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
#include <gtk/gtkwindow.h>
G_BEGIN_DECLS
#define GTK_TYPE_INFO_DIALOG (gtk_info_dialog_get_type ())
GDK_AVAILABLE_IN_4_10
G_DECLARE_FINAL_TYPE (GtkInfoDialog, gtk_info_dialog, GTK, INFO_DIALOG, GObject)
GDK_AVAILABLE_IN_4_10
GtkInfoDialog * gtk_info_dialog_new (void);
GDK_AVAILABLE_IN_4_10
gboolean gtk_info_dialog_get_modal (GtkInfoDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_set_modal (GtkInfoDialog *self,
gboolean modal);
GDK_AVAILABLE_IN_4_10
const char * gtk_info_dialog_get_heading (GtkInfoDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_set_heading (GtkInfoDialog *self,
const char *text);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_set_heading_markup (GtkInfoDialog *self,
const char *text);
GDK_AVAILABLE_IN_4_10
gboolean gtk_info_dialog_get_heading_use_markup
(GtkInfoDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_set_heading_use_markup
(GtkInfoDialog *self,
gboolean use_markup);
GDK_AVAILABLE_IN_4_10
const char * gtk_info_dialog_get_body (GtkInfoDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_set_body (GtkInfoDialog *self,
const char *text);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_set_body_markup (GtkInfoDialog *self,
const char *text);
GDK_AVAILABLE_IN_4_10
gboolean gtk_info_dialog_get_body_use_markup (GtkInfoDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_set_body_use_markup (GtkInfoDialog *self,
gboolean use_markup);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_set_buttons (GtkInfoDialog *self,
const char * const *labels);
GDK_AVAILABLE_IN_4_10
const char * const *
gtk_info_dialog_get_buttons (GtkInfoDialog *self);
GDK_AVAILABLE_IN_4_10
void gtk_info_dialog_present (GtkInfoDialog *self,
GtkWindow *parent,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_4_10
gboolean gtk_info_dialog_present_finish (GtkInfoDialog *self,
GAsyncResult *result,
int *button,
GError **error);
G_END_DECLS

View File

@@ -109,7 +109,6 @@ gtk_private_sources = files([
'gtkfilechoosernativeportal.c',
'gtkfilechooserutils.c',
'gtkfilechoosercell.c',
'gtkfiledialog.c',
'gtkfilesystemmodel.c',
'gtkfilethumbnail.c',
'gtkgizmo.c',
@@ -183,13 +182,11 @@ gtk_public_sources = files([
'gtkcenterbox.c',
'gtkcenterlayout.c',
'gtkcheckbutton.c',
'gtkchoice.c',
'gtkcolorbutton.c',
'gtkcolorchooser.c',
'gtkcolorchooserdialog.c',
'gtkcolorchooserwidget.c',
'gtkcolordialog.c',
'gtkcolordialogbutton.c',
'gtkcolorchooserwindow.c',
'gtkcolorutils.c',
'gtkcolumnview.c',
'gtkcolumnviewcolumn.c',
@@ -241,8 +238,6 @@ gtk_public_sources = files([
'gtkfontchooserdialog.c',
'gtkfontchooserutils.c',
'gtkfontchooserwidget.c',
'gtkfontdialog.c',
'gtkfontdialogbutton.c',
'gtkframe.c',
'gtkgesture.c',
'gtkgesturedrag.c',
@@ -267,7 +262,6 @@ gtk_public_sources = files([
'gtkimmodule.c',
'gtkimmulticontext.c',
'gtkinfobar.c',
'gtkinfodialog.c',
'gtkinscription.c',
'gtklabel.c',
'gtklayoutchild.c',
@@ -445,13 +439,10 @@ gtk_public_headers = files([
'gtkcenterbox.h',
'gtkcenterlayout.h',
'gtkcheckbutton.h',
'gtkchoice.h',
'gtkcolorbutton.h',
'gtkcolorchooser.h',
'gtkcolorchooserdialog.h',
'gtkcolorchooserwidget.h',
'gtkcolordialog.h',
'gtkcolordialogbutton.h',
'gtkcolorutils.h',
'gtkcolumnview.h',
'gtkcolumnviewcolumn.h',
@@ -491,7 +482,6 @@ gtk_public_headers = files([
'gtkfilechooserdialog.h',
'gtkfilechoosernative.h',
'gtkfilechooserwidget.h',
'gtkfiledialog.h',
'gtkfilefilter.h',
'gtkfilter.h',
'gtkfilterlistmodel.h',
@@ -503,8 +493,6 @@ gtk_public_headers = files([
'gtkfontchooser.h',
'gtkfontchooserdialog.h',
'gtkfontchooserwidget.h',
'gtkfontdialog.h',
'gtkfontdialogbutton.h',
'gtkframe.h',
'gtkgesture.h',
'gtkgesturedrag.h',
@@ -528,7 +516,6 @@ gtk_public_headers = files([
'gtkimmodule.h',
'gtkimmulticontext.h',
'gtkinfobar.h',
'gtkinfodialog.h',
'gtkinscription.h',
'gtklabel.h',
'gtklayoutchild.h',

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk40">
<template class="GtkColorChooserWindow" parent="GtkWindow">
<property name="title" translatable="yes">Select a Color</property>
<property name="resizable">0</property>
<property name="default-widget">ok_button</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">0</property>
<child type="start">
<object class="GtkButton" id="cancel_button">
<property name="use-underline">1</property>
<property name="label" translatable="yes">_Cancel</property>
<signal name="clicked" handler="cancel_button_cb"/>
</object>
</child>
<child type="end">
<object class="GtkButton" id="ok_button">
<property name="label" translatable="yes">_Select</property>
<property name="use-underline">1</property>
<signal name="clicked" handler="ok_button_cb"/>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<property name="spacing">2</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<child>
<object class="GtkColorChooserWidget" id="chooser">
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="rgba">rgb(255,255,255)</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<signal name="color-activated" handler="color_activated_cb" swapped="no"/>
<signal name="notify::rgba" handler="propagate_notify" swapped="no"/>
<signal name="notify::show-editor" handler="propagate_notify" swapped="no"/>
</object>
</child>
</object>
</child>
</template>
</interface>

808
po/sr.po

File diff suppressed because it is too large Load Diff