[wing/wip/eventwindow] Add event window class
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [wing/wip/eventwindow] Add event window class
- Date: Wed, 5 Apr 2017 15:29:24 +0000 (UTC)
commit 7b091701f0a4c563d8e6f6efe6b5c779de9cded3
Author: Ignacio Casal Quinteiro <qignacio amazon com>
Date: Wed Apr 5 17:28:37 2017 +0200
Add event window class
Provides a way to listen to global events by creating an
invisible window.
wing/meson.build | 2 +
wing/wing.h | 1 +
wing/wingeventwindow.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++++
wing/wingeventwindow.h | 54 ++++++++
4 files changed, 410 insertions(+), 0 deletions(-)
---
diff --git a/wing/meson.build b/wing/meson.build
index c696a68..14fdaae 100644
--- a/wing/meson.build
+++ b/wing/meson.build
@@ -1,5 +1,6 @@
headers = [
'wing.h',
+ 'wingeventwindow.h',
'wingversionmacros.h',
'wingnamedpipeclient.h',
'wingnamedpipeconnection.h',
@@ -15,6 +16,7 @@ private_headers = [
]
sources = [
+ 'wingeventwindow.c',
'wing-init.c',
'wingnamedpipeclient.c',
'wingnamedpipeconnection.c',
diff --git a/wing/wing.h b/wing/wing.h
index 2280725..146655d 100644
--- a/wing/wing.h
+++ b/wing/wing.h
@@ -21,6 +21,7 @@
#define __WING_H__
#include <wing/wingversionmacros.h>
+#include <wing/wingeventwindow.h>
#include <wing/wingnamedpipeclient.h>
#include <wing/wingnamedpipelistener.h>
#include <wing/wingnamedpipeconnection.h>
diff --git a/wing/wingeventwindow.c b/wing/wingeventwindow.c
new file mode 100644
index 0000000..dc746c2
--- /dev/null
+++ b/wing/wingeventwindow.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright © 2017 NICE s.r.l.
+ *
+ * This program 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 licence 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/>.
+ *
+ * Authors: Ignacio Casal Quinteiro <ignacio casal nice-software com>
+ */
+
+#include "wingeventwindow.h"
+#include <gio/gio.h>
+#include <glib.h>
+
+#define WINDOW_USER_DATA_KEY L"WING_EVENT_WINDOW"
+
+typedef LRESULT (CALLBACK *WinProcHook) (HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+typedef struct
+{
+ WingEventCallback callback;
+ gpointer user_data;
+} Message;
+
+struct _WingEventWindow
+{
+ GObject parent_instance;
+
+ gchar *name;
+ wchar_t *namew;
+ HWND hwnd;
+ guint watch_id;
+ GIOChannel *channel;
+ GHashTable *messages;
+};
+
+enum
+{
+ PROP_0,
+ PROP_NAME,
+ LAST_PROP
+};
+
+static GParamSpec *props[LAST_PROP];
+
+static void wing_event_window_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (WingEventWindow,
+ wing_event_window,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ wing_event_window_initable_iface_init))
+
+static Message *
+create_message (WingEventCallback callback,
+ gpointer user_data)
+{
+ Message *message;
+
+ message = g_slice_new (Message);
+ message->callback = callback;
+ message->user_data = user_data;
+
+ return message;
+}
+
+static void
+free_message (Message *message)
+{
+ g_slice_free (Message, message);
+}
+
+static void
+wing_event_window_finalize (GObject *object)
+{
+ WingEventWindow *window = WING_EVENT_WINDOW (object);
+
+ g_free (window->name);
+ g_free (window->namew);
+ DestroyWindow (window->hwnd);
+
+ G_OBJECT_CLASS (wing_event_window_parent_class)->finalize (object);
+}
+
+static void
+wing_event_window_dispose (GObject *object)
+{
+ WingEventWindow *window = WING_EVENT_WINDOW (object);
+
+ if (window->watch_id != 0)
+ {
+ g_source_remove (window->watch_id);
+ window->watch_id = 0;
+ }
+
+ g_clear_pointer (&window->messages, g_hash_table_unref);
+
+ if (window->channel != NULL)
+ {
+ g_io_channel_shutdown (window->channel, FALSE, NULL);
+ g_io_channel_unref (window->channel);
+ window->channel = NULL;
+ }
+
+ G_OBJECT_CLASS (wing_event_window_parent_class)->dispose (object);
+}
+
+static void
+wing_event_window_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ WingEventWindow *window = WING_EVENT_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, window->name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+wing_event_window_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ WingEventWindow *window = WING_EVENT_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ window->name = g_value_dup_string (value);
+ if (window->name != NULL)
+ window->namew = g_utf8_to_utf16 (window->name, -1, NULL, NULL, NULL);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static LRESULT CALLBACK
+wnd_proc (HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ if (message == WM_NCCREATE)
+ {
+ CREATESTRUCT *cs = (CREATESTRUCT *)lparam;
+ SetPropW (hwnd, WINDOW_USER_DATA_KEY, (HANDLE)cs->lpCreateParams);
+ return 1;
+ }
+ else if (message == WM_DESTROY)
+ {
+ PostQuitMessage (0);
+ return 0;
+ }
+ else
+ {
+ WingEventWindow *window = WING_EVENT_WINDOW (GetProp (hwnd, WINDOW_USER_DATA_KEY));
+ Message *m;
+
+ m = (Message *)g_hash_table_lookup (window->messages, GUINT_TO_POINTER(message));
+ if (m != NULL)
+ {
+ if (m->callback (window, wparam, lparam, m->user_data))
+ return 0;
+ }
+
+ return DefWindowProc (hwnd, message, wparam, lparam);
+ }
+}
+
+static ATOM
+register_window_class (WingEventWindow *window)
+{
+ WNDCLASSEX wc;
+
+ wc.cbSize = sizeof (WNDCLASSEX);
+
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = wnd_proc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle (NULL);
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = window->namew;
+ wc.hIconSm = NULL;
+
+ return RegisterClassEx (&wc);
+}
+
+static gboolean
+recv_windows_message (GIOChannel *channel,
+ GIOCondition cond,
+ gpointer data)
+{
+ GIOStatus status;
+ MSG msg;
+
+ while (TRUE)
+ {
+ gsize bytes_read;
+
+ status = g_io_channel_read_chars (channel, (gchar *)&msg, sizeof (MSG),
+ &bytes_read, NULL);
+
+ if (status == G_IO_STATUS_AGAIN)
+ continue;
+
+ break;
+ }
+
+ if (status == G_IO_STATUS_NORMAL)
+ DispatchMessage (&msg);
+
+ return TRUE;
+}
+
+static void
+wing_event_window_class_init (WingEventWindowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = wing_event_window_finalize;
+ object_class->dispose = wing_event_window_dispose;
+ object_class->get_property = wing_event_window_get_property;
+ object_class->set_property = wing_event_window_set_property;
+
+ props[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+}
+
+static void
+wing_event_window_init (WingEventWindow *window)
+{
+ window->messages = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ (GDestroyNotify)free_message);
+}
+
+static gboolean
+wing_event_window_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WingEventWindow *window = WING_EVENT_WINDOW (initable);
+ long style;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+
+ if (!register_window_class (window))
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Window Registration Failed");
+ return FALSE;
+ }
+
+ window->hwnd = CreateWindowW (window->namew, window->namew, WS_POPUPWINDOW,
+ 0, 100000, 1, 1, NULL, NULL,
+ GetModuleHandle (NULL), window);
+ if (!window->hwnd)
+ {
+ gchar *err_msg;
+
+ err_msg = g_win32_error_message (GetLastError ());
+
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Could not create window '%s': %s",
+ window->name, err_msg);
+ g_free (err_msg);
+ return FALSE;
+ }
+
+ /* Special style to remove the application from the Windows taskbar */
+ ShowWindow (window->hwnd, SW_HIDE);
+ style = GetWindowLong (window->hwnd, GWL_EXSTYLE);
+ style |= WS_EX_TOOLWINDOW; /* flags don't work - windows remains in taskbar */
+ style &= ~(WS_EX_APPWINDOW);
+ SetWindowLong (window->hwnd, GWL_EXSTYLE, style);
+ ShowWindow (window->hwnd, SW_SHOW);
+
+ window->channel = g_io_channel_win32_new_messages ((gsize)window->hwnd);
+ g_io_channel_set_encoding (window->channel, NULL, NULL);
+ window->watch_id = g_io_add_watch (window->channel, G_IO_IN, recv_windows_message, window);
+
+ return TRUE;
+}
+
+static void
+wing_event_window_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = wing_event_window_initable_init;
+}
+
+WingEventWindow *
+wing_event_window_new (const gchar *name,
+ GError **error)
+{
+ return g_initable_new (WING_TYPE_EVENT_WINDOW,
+ NULL, error,
+ "name", name,
+ NULL);
+}
+
+void
+wing_event_window_connect (WingEventWindow *window,
+ guint message,
+ WingEventCallback callback,
+ gpointer user_data)
+{
+ Message *m;
+
+ g_return_if_fail(WING_IS_EVENT_WINDOW(window));
+ g_return_if_fail(callback != NULL);
+
+ m = create_message(callback, user_data);
+ g_hash_table_insert(window->messages, GUINT_TO_POINTER(message), m);
+}
+
+/* ex:set ts=4 et: */
diff --git a/wing/wingeventwindow.h b/wing/wingeventwindow.h
new file mode 100644
index 0000000..e2e8ff2
--- /dev/null
+++ b/wing/wingeventwindow.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2017 NICE s.r.l.
+ *
+ * This program 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 licence 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/>.
+ *
+ * Authors: Ignacio Casal Quinteiro <ignacio casal nice-software com>
+ */
+
+#ifndef WING_EVENT_WINDOW_H
+#define WING_EVENT_WINDOW_H
+
+#include <glib-object.h>
+#include <wing/wingversionmacros.h>
+
+#include <Windows.h>
+
+G_BEGIN_DECLS
+
+#define WING_TYPE_EVENT_WINDOW (wing_event_window_get_type ())
+
+WING_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (WingEventWindow, wing_event_window, DCV, WIN32_EVENT_WINDOW, GObject)
+
+typedef gboolean (* WingEventCallback) (WingEventWindow *window,
+ WPARAM wparam,
+ LPARAM lparam,
+ gpointer user_data);
+
+WING_AVAILABLE_IN_ALL
+WingEventWindow *wing_event_window_new (const gchar *name,
+ GError **error);
+
+WING_AVAILABLE_IN_ALL
+void wing_event_window_connect (WingEventWindow *window,
+ guint message,
+ WingEventCallback callback,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* WING_EVENT_WINDOW_H */
+
+/* ex:set ts=4 et: */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]