From ce096b5fa63a1c99d123248d4679969c032f06f4 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 22 Oct 2021 12:12:30 -0300 Subject: Add a GTK4 variant This commits adds a GTK4 variant, libcolord-gtk4. An effort was made to keep the changes as separate and self-contained as possible. The new GTK4 code of the sample window and widget is introduced in separated files, reusing the cd-sample-{window,widget}.h headers. There was only one place in CdWindow that required split GTK3 / GTK4 paths, and fortunately it is a rather trivial one. --- libcolord-gtk/cd-sample-widget-gtk4.c | 209 ++++++++++++++++++++++++++++++++++ libcolord-gtk/cd-sample-window-gtk4.c | 189 ++++++++++++++++++++++++++++++ libcolord-gtk/cd-self-test-gtk4.c | 133 ++++++++++++++++++++++ libcolord-gtk/cd-window.c | 14 +++ libcolord-gtk/meson.build | 62 ++++++++++ 5 files changed, 607 insertions(+) create mode 100644 libcolord-gtk/cd-sample-widget-gtk4.c create mode 100644 libcolord-gtk/cd-sample-window-gtk4.c create mode 100644 libcolord-gtk/cd-self-test-gtk4.c (limited to 'libcolord-gtk') diff --git a/libcolord-gtk/cd-sample-widget-gtk4.c b/libcolord-gtk/cd-sample-widget-gtk4.c new file mode 100644 index 0000000..a5abffa --- /dev/null +++ b/libcolord-gtk/cd-sample-widget-gtk4.c @@ -0,0 +1,209 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2021 Georges Basile Stavracas Neto + * 2012 Richard Hughes + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * 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.1 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include + +#include "cd-sample-widget.h" + +struct CdSampleWidgetPrivate +{ + cairo_t *cr; + CdColorRGB color; +}; + +G_DEFINE_TYPE_WITH_CODE (CdSampleWidget, cd_sample_widget, GTK_TYPE_DRAWING_AREA, + G_ADD_PRIVATE (CdSampleWidget)); + +enum +{ + PROP_0, + PROP_COLOR, +}; + +/** + * up_sample_get_property: + **/ +static void +up_sample_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + CdSampleWidget *sample = CD_SAMPLE_WIDGET (object); + CdSampleWidgetPrivate *priv = cd_sample_widget_get_instance_private (sample); + switch (prop_id) { + case PROP_COLOR: + g_value_set_boxed (value, &priv->color); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * up_sample_set_property: + **/ +static void +up_sample_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + CdColorRGB *tmp; + CdSampleWidget *sample = CD_SAMPLE_WIDGET (object); + CdSampleWidgetPrivate *priv = cd_sample_widget_get_instance_private (sample); + + switch (prop_id) { + case PROP_COLOR: + tmp = g_value_get_boxed (value); + cd_color_rgb_copy (tmp, &priv->color); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + /* refresh widget */ + gtk_widget_hide (GTK_WIDGET (sample)); + gtk_widget_show (GTK_WIDGET (sample)); +} + +/** + * cd_sample_widget_draw_rounded_rectangle: + **/ +static void +cd_sample_widget_draw_rounded_rectangle (cairo_t *cr, + gdouble x, + gdouble y, + gdouble width, + gdouble height, + gdouble corner_radius) +{ + gdouble aspect = width / height; + gdouble radius = corner_radius / aspect; + gdouble degrees = G_PI / 180.0; + + cairo_new_sub_path (cr); + cairo_arc (cr, x + width - radius, y + radius, + radius, -90 * degrees, 0 * degrees); + cairo_arc (cr, x + width - radius, y + height - radius, + radius, 0 * degrees, 90 * degrees); + cairo_arc (cr, x + radius, y + height - radius, + radius, 90 * degrees, 180 * degrees); + cairo_arc (cr, x + radius, y + radius, + radius, 180 * degrees, 270 * degrees); + cairo_close_path (cr); +} + +/** + * cd_sample_widget_draw: + **/ +static void +cd_sample_widget_draw (GtkDrawingArea *drawing_area, + cairo_t *cr, + int width, + int height, + gpointer user_data) +{ + CdSampleWidget *sample = CD_SAMPLE_WIDGET (drawing_area); + CdSampleWidgetPrivate *priv = cd_sample_widget_get_instance_private (sample); + CdColorRGB *color; + + color = &priv->color; + cairo_save (cr); + cairo_set_source_rgb (cr, color->R, color->G, color->B); + cd_sample_widget_draw_rounded_rectangle (cr, 0, 0, width, height, 10.5); + cairo_fill_preserve (cr); + cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 1.0); + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + cairo_restore (cr); +} + +/** + * cd_sample_widget_class_init: + **/ +static void +cd_sample_widget_class_init (CdSampleWidgetClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->get_property = up_sample_get_property; + object_class->set_property = up_sample_set_property; + + /* properties */ + g_object_class_install_property (object_class, + PROP_COLOR, + g_param_spec_boxed ("color", NULL, NULL, + CD_TYPE_COLOR_RGB, + G_PARAM_READWRITE)); +} + +/** + * cd_sample_widget_init: + **/ +static void +cd_sample_widget_init (CdSampleWidget *sample) +{ + CdSampleWidgetPrivate *priv = cd_sample_widget_get_instance_private (sample); + + gtk_widget_set_cursor (GTK_WIDGET (sample), gdk_cursor_new_from_name ("blank", NULL)); + cd_color_rgb_set (&priv->color, 1.0, 1.0, 1.0); + gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (sample), + cd_sample_widget_draw, + sample, NULL); +} + +/** + * cd_sample_widget_set_color: + * @sample: This class instance + * @color: A color + * + * Sets the color for the sample widget + * + * Since: 0.1.24 + **/ +void +cd_sample_widget_set_color (CdSampleWidget *sample, const CdColorRGB *color) +{ + CdSampleWidgetPrivate *priv; + + g_return_if_fail (color != NULL); + g_return_if_fail (CD_IS_SAMPLE_WIDGET (sample)); + + priv = cd_sample_widget_get_instance_private (sample); + + /* set new color and refresh */ + cd_color_rgb_copy (color, &priv->color); + gtk_widget_queue_draw (GTK_WIDGET (sample)); +} + +/** + * cd_sample_widget_new: + * + * Return value: A new #CdSampleWidget object. + * + * Since: 0.1.24 + **/ +GtkWidget * +cd_sample_widget_new (void) +{ + return g_object_new (CD_TYPE_SAMPLE_WIDGET, NULL); +} diff --git a/libcolord-gtk/cd-sample-window-gtk4.c b/libcolord-gtk/cd-sample-window-gtk4.c new file mode 100644 index 0000000..a7e09bc --- /dev/null +++ b/libcolord-gtk/cd-sample-window-gtk4.c @@ -0,0 +1,189 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2021 Georges Basile Stavracas Neto + * 2009-2012 Richard Hughes + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * 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.1 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include + +#include + +#include "cd-sample-widget.h" +#include "cd-sample-window.h" + +static void cd_sample_window_finalize (GObject *object); + +#define CD_SAMPLE_WINDOW_PULSE_DELAY 80 /* ms */ + +/** + * CdSampleWindowPrivate: + * + * Private #CdSampleWindow data + **/ +struct _CdSampleWindowPrivate +{ + GtkWidget *sample_widget; + GtkWidget *progress_bar; + guint pulse_id; +}; + +G_DEFINE_TYPE_WITH_CODE (CdSampleWindow, cd_sample_window, GTK_TYPE_WINDOW, + G_ADD_PRIVATE (CdSampleWindow)) + +/** + * cd_sample_window_pulse_cb: + **/ +static gboolean +cd_sample_window_pulse_cb (CdSampleWindow *sample_window) +{ + CdSampleWindowPrivate *priv = cd_sample_window_get_instance_private (sample_window); + gtk_progress_bar_pulse (GTK_PROGRESS_BAR (priv->progress_bar)); + return TRUE; +} + +/** + * cd_sample_window_set_fraction: + * @sample_window: a valid #CdSampleWindow instance + * @fraction: the fraction value to show, or -1 for pulsing. + * + * Sets the percentage value on the window. + * + * Since: 0.1.22 + **/ +void +cd_sample_window_set_fraction (CdSampleWindow *sample_window, + gdouble fraction) +{ + CdSampleWindowPrivate *priv = cd_sample_window_get_instance_private (sample_window); + + /* make pulse */ + if (fraction == -1) { + if (priv->pulse_id == 0) { + priv->pulse_id = g_timeout_add (CD_SAMPLE_WINDOW_PULSE_DELAY, + (GSourceFunc) cd_sample_window_pulse_cb, + sample_window); + } + return; + } + + /* no more pulsing */ + if (priv->pulse_id != 0) { + g_source_remove (priv->pulse_id); + priv->pulse_id = 0; + } + + /* set static value */ + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progress_bar), fraction); +} + +/** + * cd_sample_window_set_color: + * @sample_window: a valid #CdSampleWindow instance + * @color: the color + * + * Sets the window to a specific color. + * + * Since: 0.1.22 + **/ +void +cd_sample_window_set_color (CdSampleWindow *sample_window, + const CdColorRGB *color) +{ + CdSampleWindowPrivate *priv = cd_sample_window_get_instance_private (sample_window); + + g_debug ("setting RGB: %f, %f, %f", color->R, color->G, color->B); + cd_sample_widget_set_color (CD_SAMPLE_WIDGET (priv->sample_widget), color); + + /* force redraw */ + gtk_widget_set_visible (priv->sample_widget, FALSE); + gtk_widget_set_visible (priv->sample_widget, TRUE); +} + +/** + * cd_sample_window_class_init: + **/ +static void +cd_sample_window_class_init (CdSampleWindowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = cd_sample_window_finalize; +} + +/** + * cd_sample_window_init: + **/ +static void +cd_sample_window_init (CdSampleWindow *sample_window) +{ + CdSampleWindowPrivate *priv = cd_sample_window_get_instance_private (sample_window); + GtkWindow *window = GTK_WINDOW (sample_window); + GtkWidget *vbox; + priv->sample_widget = cd_sample_widget_new (); + priv->progress_bar = gtk_progress_bar_new (); + + /* pack in two widgets into the window */ + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_window_set_child (window, vbox); + gtk_box_append (GTK_BOX (vbox), priv->sample_widget); + gtk_box_append (GTK_BOX (vbox), priv->progress_bar); + gtk_widget_set_size_request (priv->sample_widget, 400, 400); + + gtk_widget_set_cursor (GTK_WIDGET (window), gdk_cursor_new_from_name ("blank", NULL)); +} + +/** + * cd_sample_window_finalize: + **/ +static void +cd_sample_window_finalize (GObject *object) +{ + CdSampleWindow *sample_window = CD_SAMPLE_WINDOW (object); + CdSampleWindowPrivate *priv = cd_sample_window_get_instance_private (sample_window); + + if (priv->pulse_id != 0) + g_source_remove (priv->pulse_id); + + G_OBJECT_CLASS (cd_sample_window_parent_class)->finalize (object); +} + +/** + * cd_sample_window_new: + * + * Return value: a new #CdSampleWindow object. + * + * Since: 0.1.22 + **/ +GtkWindow * +cd_sample_window_new (void) +{ + CdSampleWindow *sample_window; + sample_window = g_object_new (CD_TYPE_SAMPLE_WINDOW, + "decorated", FALSE, + "default-height", 400, + "default-width", 400, + "deletable", FALSE, + "destroy-with-parent", TRUE, + "icon-name", "icc-profile", + "resizable", FALSE, + "title", "calibration square", + NULL); + return GTK_WINDOW (sample_window); +} diff --git a/libcolord-gtk/cd-self-test-gtk4.c b/libcolord-gtk/cd-self-test-gtk4.c new file mode 100644 index 0000000..a8a6e4b --- /dev/null +++ b/libcolord-gtk/cd-self-test-gtk4.c @@ -0,0 +1,133 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2021 Georges Basile Stavracas Neto + * 2010-2012 Richard Hughes + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * 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.1 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "cd-sample-window.h" +#include "cd-window.h" + +static void +cd_window_get_profile_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CdWindow *window = CD_WINDOW (source); + GtkWidget *widget = GTK_WIDGET (user_data); + GError *error = NULL; + CdProfile *profile; + + profile = cd_window_get_profile_finish (window, + res, + &error); + g_assert_no_error (error); + g_assert (profile != NULL); + g_debug ("profile was %s", cd_profile_get_filename (profile)); + g_object_unref (profile); + + /* kill the dialog */ + gtk_window_destroy (GTK_WINDOW (widget)); +} + +static void +map_cb (GtkWidget *this_widget, gpointer user_data) +{ + CdWindow *window = CD_WINDOW (user_data); + + /* get the profile for this widget */ + cd_window_get_profile (window, + this_widget, + NULL, + cd_window_get_profile_cb, + this_widget); +} + +static void +colord_window_func (void) +{ + CdWindow *window; + GtkWidget *dialog; + + window = cd_window_new (); + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "%s", "Hello world"); + g_signal_connect (dialog, "map", + G_CALLBACK (map_cb), + window); + gtk_window_present (GTK_WINDOW (dialog)); +} + +static gboolean +colord_sample_window_loop_cb (GMainLoop *loop) +{ + g_main_loop_quit (loop); + return FALSE; +} + +static void +colord_sample_window_func (void) +{ + GtkWindow *window; + GMainLoop *loop; + CdColorRGB source; + + window = cd_sample_window_new (); + g_assert (window != NULL); + source.R = 1.0f; + source.G = 1.0f; + source.B = 0.0f; + cd_sample_window_set_color (CD_SAMPLE_WINDOW (window), &source); + cd_sample_window_set_fraction (CD_SAMPLE_WINDOW (window), -1); + + /* move to the center of device lvds1 */ + gtk_window_present (window); + + loop = g_main_loop_new (NULL, FALSE); + g_timeout_add_seconds (5, (GSourceFunc) colord_sample_window_loop_cb, loop); + g_main_loop_run (loop); + + g_main_loop_unref (loop); + gtk_window_destroy (GTK_WINDOW (window)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + gtk_init (); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/colord/window", colord_window_func); + g_test_add_func ("/colors/sample-window", colord_sample_window_func); + return g_test_run (); +} + diff --git a/libcolord-gtk/cd-window.c b/libcolord-gtk/cd-window.c index 75351b1..45f65ad 100644 --- a/libcolord-gtk/cd-window.c +++ b/libcolord-gtk/cd-window.c @@ -377,6 +377,8 @@ cd_window_update_widget_plug_name (CdWindow *window, { CdWindowPrivate *priv = window->priv; gchar *plug_name; + +#ifndef BUILD_COLORD_GTK4 GdkScreen *screen; GdkWindow *gdk_window; gint monitor_num; @@ -388,6 +390,18 @@ cd_window_update_widget_plug_name (CdWindow *window, monitor_num = gdk_screen_get_monitor_at_window (screen, gdk_window); plug_name = gdk_screen_get_monitor_plug_name (screen, monitor_num); +#else + GdkSurface *surface; + GdkDisplay *display; + GdkMonitor *monitor; + GtkNative *native; + + native = gtk_widget_get_native (widget); + surface = gtk_native_get_surface (native); + display = gtk_widget_get_display (widget); + monitor = gdk_display_get_monitor_at_surface (display, surface); + plug_name = g_strdup (gdk_monitor_get_connector (monitor)); +#endif /* ignoring MAP as plug_name has not changed */ if (g_strcmp0 (plug_name, priv->plug_name) == 0) { diff --git a/libcolord-gtk/meson.build b/libcolord-gtk/meson.build index 612f991..5815f2a 100644 --- a/libcolord-gtk/meson.build +++ b/libcolord-gtk/meson.build @@ -144,6 +144,68 @@ if get_option('gtk2') ) endif +if get_option('gtk4') + colord_gtk4 = shared_library( + 'colord-gtk4', + sources : [ + 'cd-sample-widget-gtk4.c', + 'cd-sample-window-gtk4.c', + 'cd-window.c', + 'cd-window-sync.c', + ], + soversion : lt_current, + version : lt_version, + dependencies : [ + glib, + gio, + gtk4, + colord, + ], + c_args : [ + cargs, + '-DBUILD_COLORD_GTK4', + ], + include_directories : [ + root_incdir, + ], + install : true + ) + + pkgg.generate( + libraries : colord_gtk4, + requires : [ 'colord', 'gtk4' ], + subdirs : 'colord-1', + version : meson.project_version(), + name : 'colord-gtk4', + filebase : 'colord-gtk4', + description : 'colord-gtk4 is GTK4 integration for libcolord', + ) + + if get_option('tests') + e = executable( + 'colord-gtk4-test', + sources : [ + 'cd-self-test-gtk4.c', + ], + include_directories : [ + root_incdir, + ], + dependencies : [ + glib, + gio, + gtk4, + colord, + ], + link_with : colord_gtk4, + c_args : [ + cargs, + ] + ) + test('colord-gtk4-test-private', e) + endif + +endif + if get_option('tests') e = executable( 'colord-gtk-test', -- cgit v1.2.1