[gtk: 1/2] Implement GtkColorPicker for Windows
- From: Luca Bacci <lbacci src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk: 1/2] Implement GtkColorPicker for Windows
- Date: Thu, 1 Sep 2022 20:39:16 +0000 (UTC)
commit 86a38918d78d079d0a51a9911ecc68df2fb19328
Author: Luca Bacci <luca bacci982 gmail com>
Date: Fri Aug 26 15:34:01 2022 +0200
Implement GtkColorPicker for Windows
Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/5136
gtk/gtkcolorpicker.c | 15 ++-
gtk/gtkcolorpickerwin32.c | 246 +++++++++++++++++++++++++++++++++++++++
gtk/gtkcolorpickerwin32private.h | 41 +++++++
gtk/meson.build | 5 +-
4 files changed, 304 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkcolorpicker.c b/gtk/gtkcolorpicker.c
index 6b3f5f79c1..2c1b62b2fb 100644
--- a/gtk/gtkcolorpicker.c
+++ b/gtk/gtkcolorpicker.c
@@ -21,6 +21,11 @@
#include "gtkcolorpickerportalprivate.h"
#include "gtkcolorpickershellprivate.h"
#include "gtkcolorpickerkwinprivate.h"
+
+#ifdef G_OS_WIN32
+#include "gtkcolorpickerwin32private.h"
+#endif
+
#include <gio/gio.h>
@@ -51,13 +56,19 @@ gtk_color_picker_pick_finish (GtkColorPicker *picker,
GtkColorPicker *
gtk_color_picker_new (void)
{
- GtkColorPicker *picker;
+ GtkColorPicker *picker = NULL;
- picker = gtk_color_picker_portal_new ();
+#if defined (G_OS_UNIX)
+ if (!picker)
+ picker = gtk_color_picker_portal_new ();
if (!picker)
picker = gtk_color_picker_shell_new ();
if (!picker)
picker = gtk_color_picker_kwin_new ();
+#elif defined (G_OS_WIN32)
+ if (!picker)
+ picker = gtk_color_picker_win32_new ();
+#endif
if (!picker)
g_debug ("No suitable GtkColorPicker implementation");
diff --git a/gtk/gtkcolorpickerwin32.c b/gtk/gtkcolorpickerwin32.c
new file mode 100644
index 0000000000..c53364ef5e
--- /dev/null
+++ b/gtk/gtkcolorpickerwin32.c
@@ -0,0 +1,246 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2022 the GTK team
+ *
+ * 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 "gtkcolorpickerwin32private.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+GList *pickers;
+HHOOK hook;
+
+static void remove_hook (void);
+
+extern IMAGE_DOS_HEADER __ImageBase;
+#define this_hmodule ((HMODULE)&__ImageBase)
+
+struct _GtkColorPickerWin32
+{
+ GObject parent_instance;
+
+ GTask *task;
+ POINT point;
+};
+
+struct _GtkColorPickerWin32Class
+{
+ GObjectClass parent_class;
+};
+
+static GInitableIface *initable_parent_iface;
+static void gtk_color_picker_win32_initable_iface_init (GInitableIface *iface);
+static void gtk_color_picker_win32_iface_init (GtkColorPickerInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkColorPickerWin32, gtk_color_picker_win32, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gtk_color_picker_win32_initable_iface_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_PICKER, gtk_color_picker_win32_iface_init))
+
+static gboolean
+gtk_color_picker_win32_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return TRUE;
+}
+
+static void
+gtk_color_picker_win32_initable_iface_init (GInitableIface *iface)
+{
+ initable_parent_iface = g_type_interface_peek_parent (iface);
+ iface->init = gtk_color_picker_win32_initable_init;
+}
+
+static void
+gtk_color_picker_win32_init (GtkColorPickerWin32 *picker)
+{
+}
+
+static void
+gtk_color_picker_win32_class_init (GtkColorPickerWin32Class *class)
+{
+}
+
+GtkColorPicker *
+gtk_color_picker_win32_new (void)
+{
+ return GTK_COLOR_PICKER (g_initable_new (GTK_TYPE_COLOR_PICKER_WIN32, NULL, NULL, NULL));
+}
+
+static void
+on_task_completed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ gpointer source = g_task_get_source_object (G_TASK (object));
+ GtkColorPickerWin32 *picker = GTK_COLOR_PICKER_WIN32 (source);
+
+ g_clear_object (&picker->task);
+}
+
+static void
+pick_color (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GtkColorPickerWin32 *picker = GTK_COLOR_PICKER_WIN32 (source_object);
+ GdkRGBA rgba = (GdkRGBA) { 1.0, 1.0, 1.0, 1.0 };
+ HDC hdc = GetDC(HWND_DESKTOP);
+
+ if (hdc)
+ {
+ COLORREF color = GetPixel(hdc, picker->point.x, picker->point.y);
+
+ rgba = (GdkRGBA){
+ (double) GetRValue (color) / 255.0,
+ (double) GetGValue (color) / 255.0,
+ (double) GetBValue (color) / 255.0,
+ 1.0,
+ };
+
+ ReleaseDC (HWND_DESKTOP, hdc);
+ }
+
+ g_task_return_pointer (task,
+ gdk_rgba_copy (&rgba),
+ (GDestroyNotify) gdk_rgba_free);
+}
+
+static void
+picked (GtkColorPickerWin32 *picker)
+{
+ g_task_run_in_thread (picker->task, pick_color);
+}
+
+static LRESULT CALLBACK
+mouse_proc (int nCode,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ if (nCode == HC_ACTION)
+ {
+ MSLLHOOKSTRUCT *info = (MSLLHOOKSTRUCT*) lParam;
+
+ switch (wParam)
+ {
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_XBUTTONDOWN:
+ {
+ GtkColorPickerWin32 *picker = GTK_COLOR_PICKER_WIN32 (pickers->data);
+
+ if (!pickers)
+ break;
+
+ /* A low-level mouse hook always receives screen points in
+ * per-monitor DPI aware screen coordinates, regardless of
+ * the DPI awareness setting of the application. */
+ picker->point = info->pt;
+
+ picked (picker);
+
+ pickers = g_list_delete_link (pickers, pickers);
+
+ /* It's safe to remove a hook from within its callback */
+ if (!pickers)
+ remove_hook ();
+
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return CallNextHookEx(NULL, nCode, wParam, lParam);
+}
+
+static gboolean
+ensure_mouse_hook (void)
+{
+ if (!hook)
+ {
+ hook = SetWindowsHookEx (WH_MOUSE_LL, mouse_proc, this_hmodule, 0);
+ if (!hook)
+ {
+ g_warning ("SetWindowsHookEx failed with error code "
+ "%"G_GUINT32_FORMAT, (unsigned) GetLastError ());
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+remove_hook (void)
+{
+ if (hook)
+ {
+ UnhookWindowsHookEx (hook);
+ hook = NULL;
+ }
+}
+
+static void
+gtk_color_picker_win32_pick (GtkColorPicker *cp,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GtkColorPickerWin32 *picker = GTK_COLOR_PICKER_WIN32 (cp);
+
+ if (picker->task)
+ return;
+
+ picker->task = g_task_new (picker, NULL, callback, user_data);
+ g_task_set_name (picker->task, "GtkColorPicker");
+ g_signal_connect (picker->task, "notify::completed",
+ G_CALLBACK (on_task_completed),
+ NULL);
+
+ if (!ensure_mouse_hook ())
+ {
+ g_task_return_new_error (picker->task,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Cannot capture the mouse pointer");
+ return;
+ }
+
+ pickers = g_list_prepend (pickers, cp);
+}
+
+static GdkRGBA *
+gtk_color_picker_win32_pick_finish (GtkColorPicker *cp,
+ GAsyncResult *res,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (res, cp), NULL);
+
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static void
+gtk_color_picker_win32_iface_init (GtkColorPickerInterface *iface)
+{
+ iface->pick = gtk_color_picker_win32_pick;
+ iface->pick_finish = gtk_color_picker_win32_pick_finish;
+}
diff --git a/gtk/gtkcolorpickerwin32private.h b/gtk/gtkcolorpickerwin32private.h
new file mode 100644
index 0000000000..1d4a423637
--- /dev/null
+++ b/gtk/gtkcolorpickerwin32private.h
@@ -0,0 +1,41 @@
+/*
+ * GTK - The GIMP Toolkit
+ * Copyright (C) 2022 the GTK team
+ * 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/>.
+ */
+
+#ifndef __GTK_COLOR_PICKER_WIN32_H__
+#define __GTK_COLOR_PICKER_WIN32_H__
+
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkcolorpickerprivate.h>
+
+G_BEGIN_DECLS
+
+
+#define GTK_TYPE_COLOR_PICKER_WIN32 gtk_color_picker_win32_get_type ()
+G_DECLARE_FINAL_TYPE (GtkColorPickerWin32, gtk_color_picker_win32, GTK, COLOR_PICKER_WIN32, GObject)
+
+GDK_AVAILABLE_IN_ALL
+GtkColorPicker * gtk_color_picker_win32_new (void);
+
+G_END_DECLS
+
+#endif /* __GTK_COLOR_PICKER_WIN32_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 5a76290dad..080bffe0a6 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -793,7 +793,10 @@ if os_win32
])
gtk_sources += gtk_win32_print_sources
- gtk_sources += ['gtkimcontextime.c']
+ gtk_sources += [
+ 'gtkcolorpickerwin32.c',
+ 'gtkimcontextime.c'
+ ]
if cc.has_header_symbol('windows.h', 'IPrintDialogCallback')
cdata.set('HAVE_IPRINTDIALOGCALLBACK', 1)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]