[Xfce4-commits] [apps/xfdashboard] 02/03: Added experimental GDK backend
noreply at xfce.org
noreply at xfce.org
Fri Jun 2 08:39:38 CEST 2017
This is an automated email from the git hooks/post-receive script.
n o m a d p u s h e d a c o m m i t t o b r a n c h m a s t e r
in repository apps/xfdashboard.
commit 404d782bc2888135885736a2d5e54097eb38bf40
Author: Stephan Haller <nomad at froevel.de>
Date: Fri Jun 2 08:21:36 2017 +0200
Added experimental GDK backend
Enhancement for GH #129
---
libxfdashboard/Makefile.am | 17 +
libxfdashboard/gdk/window-content-gdk.c | 2612 +++++++++++++++++++++
libxfdashboard/gdk/window-content-gdk.h | 111 +
libxfdashboard/gdk/window-tracker-gdk.c | 2100 +++++++++++++++++
libxfdashboard/gdk/window-tracker-gdk.h | 90 +
libxfdashboard/gdk/window-tracker-monitor-gdk.c | 425 ++++
libxfdashboard/gdk/window-tracker-monitor-gdk.h | 76 +
libxfdashboard/gdk/window-tracker-window-gdk.c | 1890 +++++++++++++++
libxfdashboard/gdk/window-tracker-window-gdk.h | 82 +
libxfdashboard/gdk/window-tracker-workspace-gdk.c | 442 ++++
libxfdashboard/gdk/window-tracker-workspace-gdk.h | 82 +
11 files changed, 7927 insertions(+)
diff --git a/libxfdashboard/Makefile.am b/libxfdashboard/Makefile.am
index 6b5e6f2..0f6cc00 100644
--- a/libxfdashboard/Makefile.am
+++ b/libxfdashboard/Makefile.am
@@ -246,6 +246,23 @@ libxfdashboard_la_LIBADD += \
$(XINERAMA_LIBS)
endif
+gdk_headers = \
+ gdk/window-content-gdk.h \
+ gdk/window-tracker-gdk.h \
+ gdk/window-tracker-monitor-gdk.h \
+ gdk/window-tracker-window-gdk.h \
+ gdk/window-tracker-workspace-gdk.h
+
+gdk_sources = \
+ gdk/window-content-gdk.c \
+ gdk/window-tracker-gdk.c \
+ gdk/window-tracker-monitor-gdk.c \
+ gdk/window-tracker-window-gdk.c \
+ gdk/window-tracker-workspace-gdk.c
+
+libxfdashboard_la_headers += $(gdk_headers)
+libxfdashboard_la_SOURCES += $(gdk_sources)
+
libxfdashboard_la_includedir = \
$(includedir)/xfdashboard/libxfdashboard
diff --git a/libxfdashboard/gdk/window-content-gdk.c b/libxfdashboard/gdk/window-content-gdk.c
new file mode 100644
index 0000000..55da077
--- /dev/null
+++ b/libxfdashboard/gdk/window-content-gdk.c
@@ -0,0 +1,2612 @@
+/*
+ * window: A managed window of window manager
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define COGL_ENABLE_EXPERIMENTAL_API
+#define CLUTTER_ENABLE_EXPERIMENTAL_API
+
+#include <libxfdashboard/gdk/window-content-gdk.h>
+
+#include <glib/gi18n-lib.h>
+#include <clutter/gdk/clutter-gdk.h>
+#include <clutter/x11/clutter-x11.h>
+#include <cogl/cogl-texture-pixmap-x11.h>
+#ifdef HAVE_XCOMPOSITE
+#include <X11/extensions/Xcomposite.h>
+#endif
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+#include <gdk/gdkx.h>
+
+#include <libxfdashboard/window-content.h>
+#include <libxfdashboard/gdk/window-tracker-window-gdk.h>
+#include <libxfdashboard/application.h>
+#include <libxfdashboard/marshal.h>
+#include <libxfdashboard/stylable.h>
+#include <libxfdashboard/window-tracker.h>
+#include <libxfdashboard/enums.h>
+#include <libxfdashboard/compat.h>
+#include <libxfdashboard/debug.h>
+
+
+/* Definitions */
+typedef enum /*< skip,prefix=XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE >*/
+{
+ XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_NONE=0,
+ XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_UNMINIMIZING,
+ XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_REMINIMIZING,
+ XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_DONE
+} XfdashboardWindowContentGDKWorkaroundMode;
+
+/* Define this class in GObject system */
+static void _xfdashboard_window_content_clutter_content_iface_init(ClutterContentIface *iface);
+static void _xfdashboard_window_content_gdk_stylable_iface_init(XfdashboardStylableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowContentGDK,
+ xfdashboard_window_content_gdk,
+ XFDASHBOARD_TYPE_WINDOW_CONTENT,
+ G_IMPLEMENT_INTERFACE(CLUTTER_TYPE_CONTENT, _xfdashboard_window_content_clutter_content_iface_init)
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_STYLABLE, _xfdashboard_window_content_gdk_stylable_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_CONTENT_GDK_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_CONTENT_GDK, XfdashboardWindowContentGDKPrivate))
+
+struct _XfdashboardWindowContentGDKPrivate
+{
+ /* Properties related */
+ XfdashboardWindowTrackerWindowGDK *window;
+ ClutterColor *outlineColor;
+ gfloat outlineWidth;
+ gboolean isSuspended;
+ gboolean includeWindowFrame;
+
+ gboolean unmappedWindowIconXFill;
+ gboolean unmappedWindowIconYFill;
+ gfloat unmappedWindowIconXAlign;
+ gfloat unmappedWindowIconYAlign;
+ gfloat unmappedWindowIconXScale;
+ gfloat unmappedWindowIconYScale;
+ XfdashboardAnchorPoint unmappedWindowIconAnchorPoint;
+
+ gchar *styleClasses;
+ gchar *stylePseudoClasses;
+
+ /* Instance related */
+ gboolean isFallback;
+ CoglTexture *texture;
+ Window xWindowID;
+ Pixmap pixmap;
+#ifdef HAVE_XDAMAGE
+ Damage damage;
+#endif
+
+ guint suspendSignalID;
+ gboolean isMapped;
+ gboolean isAppSuspended;
+
+ XfdashboardWindowTracker *windowTracker;
+ XfdashboardWindowContentGDKWorkaroundMode workaroundMode;
+ guint workaroundStateSignalID;
+
+ gboolean suspendAfterResumeOnIdle;
+};
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ PROP_WINDOW,
+
+ PROP_SUSPENDED,
+
+ PROP_OUTLINE_COLOR,
+ PROP_OUTLINE_WIDTH,
+
+ PROP_INCLUDE_WINDOW_FRAME,
+
+ PROP_UNMAPPED_WINDOW_ICON_X_FILL,
+ PROP_UNMAPPED_WINDOW_ICON_Y_FILL,
+ PROP_UNMAPPED_WINDOW_ICON_X_ALIGN,
+ PROP_UNMAPPED_WINDOW_ICON_Y_ALIGN,
+ PROP_UNMAPPED_WINDOW_ICON_X_SCALE,
+ PROP_UNMAPPED_WINDOW_ICON_Y_SCALE,
+ PROP_UNMAPPED_WINDOW_ICON_ANCHOR_POINT,
+
+ /* From interface: XfdashboardStylable */
+ PROP_STYLE_CLASSES,
+ PROP_STYLE_PSEUDO_CLASSES,
+
+ PROP_LAST
+};
+
+static GParamSpec* XfdashboardWindowContentGDKProperties[PROP_LAST]={ 0, };
+
+/* IMPLEMENTATION: Private variables and methods */
+#define COMPOSITE_VERSION_MIN_MAJOR 0
+#define COMPOSITE_VERSION_MIN_MINOR 2
+
+#define WORKAROUND_UNMAPPED_WINDOW_XFCONF_PROP "/enable-unmapped-window-workaround"
+#define DEFAULT_WORKAROUND_UNMAPPED_WINDOW FALSE
+
+#define WINDOW_CONTENT_CREATION_PRIORITY_XFCONF_PROP "/window-content-creation-priority"
+#define DEFAULT_WINDOW_CONTENT_GDK_CREATION_PRIORITY "immediate"
+
+struct _XfdashboardWindowContentGDKPriorityMap
+{
+ const gchar *name;
+ gint priority;
+};
+typedef struct _XfdashboardWindowContentGDKPriorityMap XfdashboardWindowContentGDKPriorityMap;
+
+static gboolean _xfdashboard_window_content_gdk_have_checked_extensions=FALSE;
+static gboolean _xfdashboard_window_content_gdk_have_composite_extension=FALSE;
+static gboolean _xfdashboard_window_content_gdk_have_damage_extension=FALSE;
+static int _xfdashboard_window_content_gdk_damage_event_base=0;
+
+static GList* _xfdashboard_window_content_gdk_resume_idle_queue=NULL;
+static guint _xfdashboard_window_content_gdk_resume_idle_id=0;
+static guint _xfdashboard_window_content_gdk_resume_shutdown_signal_id=0;
+
+static guint _xfdashboard_window_content_gdk_xfconf_priority_notify_id=0;
+static gint _xfdashboard_window_content_gdk_window_creation_priority=-1;
+static XfdashboardWindowContentGDKPriorityMap _xfdashboard_window_content_gdk_window_creation_priority_map[]=
+ {
+ { "immediate", -1 }, /* First entry is default value */
+ { "high", G_PRIORITY_HIGH_IDLE },
+ { "normal", G_PRIORITY_DEFAULT_IDLE },
+ { "low", G_PRIORITY_LOW },
+ { NULL, 0 },
+ };
+static guint _xfdashboard_window_content_gdk_window_creation_shutdown_signal_id=0;
+
+/* Forward declarations */
+static void _xfdashboard_window_content_gdk_suspend(XfdashboardWindowContentGDK *self);
+static void _xfdashboard_window_content_gdk_resume(XfdashboardWindowContentGDK *self);
+static gboolean _xfdashboard_window_content_gdk_resume_on_idle(gpointer inUserData);
+
+/* Remove all entries from resume queue and release all allocated resources */
+static void _xfdashboard_window_content_gdk_destroy_resume_queue(void)
+{
+ XfdashboardApplication *application;
+ gint queueSize;
+
+ /* Disconnect application "shutdown" signal handler */
+ if(_xfdashboard_window_content_gdk_resume_shutdown_signal_id)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Disconnecting shutdown signal handler %u because of resume queue destruction",
+ _xfdashboard_window_content_gdk_resume_shutdown_signal_id);
+
+ application=xfdashboard_application_get_default();
+ g_signal_handler_disconnect(application, _xfdashboard_window_content_gdk_resume_shutdown_signal_id);
+ _xfdashboard_window_content_gdk_resume_shutdown_signal_id=0;
+ }
+
+ /* Remove idle source if available */
+ if(_xfdashboard_window_content_gdk_resume_idle_id)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Removing resume window content idle source with ID %u",
+ _xfdashboard_window_content_gdk_resume_idle_id);
+
+ g_source_remove(_xfdashboard_window_content_gdk_resume_idle_id);
+ _xfdashboard_window_content_gdk_resume_idle_id=0;
+ }
+
+ /* Destroy resume-on-idle queue if available*/
+ if(_xfdashboard_window_content_gdk_resume_idle_queue)
+ {
+ queueSize=g_list_length(_xfdashboard_window_content_gdk_resume_idle_queue);
+ if(queueSize>0) g_warning(_("Destroying window content resume queue containing %d windows."), queueSize);
+#ifdef DEBUG
+ if(queueSize>0)
+ {
+ GList *iter;
+ XfdashboardWindowContentGDK *content;
+ XfdashboardWindowTrackerWindow *window;
+
+ for(iter=_xfdashboard_window_content_gdk_resume_idle_queue; iter; iter=g_list_next(iter))
+ {
+ content=XFDASHBOARD_WINDOW_CONTENT_GDK(iter->data);
+ window=xfdashboard_window_content_gdk_get_window(content);
+ g_print("Window content in resume queue: Item %s@%p for window '%s'\n",
+ G_OBJECT_TYPE_NAME(content), content,
+ xfdashboard_window_tracker_window_get_name(window));
+ }
+ }
+#endif
+
+ XFDASHBOARD_DEBUG(NULL, WINDOWS, "Destroying window content resume queue");
+ g_list_free(_xfdashboard_window_content_gdk_resume_idle_queue);
+ _xfdashboard_window_content_gdk_resume_idle_queue=NULL;
+ }
+}
+
+/* Remove window content from resume on idle queue */
+static void _xfdashboard_window_content_gdk_resume_on_idle_remove(XfdashboardWindowContentGDK *self)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+
+ priv=self->priv;
+
+ /* Remove window content from queue */
+ if(_xfdashboard_window_content_gdk_resume_idle_queue)
+ {
+ GList *queueEntry;
+
+ /* Lookup window content in queue and remove it from queue. If queue is empty
+ * after removal, remove idle source also.
+ */
+ queueEntry=g_list_find(_xfdashboard_window_content_gdk_resume_idle_queue, self);
+ if(queueEntry)
+ {
+ /* Remove window content from queue */
+ _xfdashboard_window_content_gdk_resume_idle_queue=g_list_delete_link(_xfdashboard_window_content_gdk_resume_idle_queue, queueEntry);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Removed queue entry %p for window '%s' because of releasing resources",
+ queueEntry,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ }
+ }
+
+ /* If queue is empty remove idle source as well */
+ if(!_xfdashboard_window_content_gdk_resume_idle_queue &&
+ _xfdashboard_window_content_gdk_resume_idle_id)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Removing idle source with ID %u because queue is empty",
+ _xfdashboard_window_content_gdk_resume_idle_id);
+
+ g_source_remove(_xfdashboard_window_content_gdk_resume_idle_id);
+ _xfdashboard_window_content_gdk_resume_idle_id=0;
+ }
+}
+
+/* Add window content to resume on idle queue */
+static void _xfdashboard_window_content_gdk_resume_on_idle_add(XfdashboardWindowContentGDK *self)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+
+ priv=self->priv;
+
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Using resume on idle for window '%s'",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+
+ /* Only add callback to resume window content if no one was added */
+ if(!g_list_find(_xfdashboard_window_content_gdk_resume_idle_queue, self))
+ {
+ /* Queue window content for resume */
+ _xfdashboard_window_content_gdk_resume_idle_queue=g_list_append(_xfdashboard_window_content_gdk_resume_idle_queue, self);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Queued window resume of '%s'",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ }
+
+ /* Create idle source for resuming queued window contents but with
+ * high priority to get window content created as soon as possible.
+ */
+ if(_xfdashboard_window_content_gdk_resume_idle_queue &&
+ !_xfdashboard_window_content_gdk_resume_idle_id)
+ {
+ _xfdashboard_window_content_gdk_resume_idle_id=clutter_threads_add_idle_full(_xfdashboard_window_content_gdk_window_creation_priority,
+ _xfdashboard_window_content_gdk_resume_on_idle,
+ NULL,
+ NULL);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Created idle source with ID %u with priority of %d because of new resume queue created for window resume of '%s'",
+ _xfdashboard_window_content_gdk_resume_idle_id,
+ _xfdashboard_window_content_gdk_window_creation_priority,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ }
+
+ /* Connect to "shutdown" signal of application to clean up resume queue */
+ if(!_xfdashboard_window_content_gdk_resume_shutdown_signal_id)
+ {
+ XfdashboardApplication *application;
+
+ application=xfdashboard_application_get_default();
+ _xfdashboard_window_content_gdk_resume_shutdown_signal_id=g_signal_connect(application,
+ "shutdown-final",
+ G_CALLBACK(_xfdashboard_window_content_gdk_destroy_resume_queue),
+ NULL);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Connected to shutdown signal with handler ID %u for resume queue destruction",
+ _xfdashboard_window_content_gdk_resume_shutdown_signal_id);
+ }
+}
+
+/* Value for window creation priority in xfconf has changed */
+static void _xfdashboard_window_content_gdk_on_window_creation_priority_value_changed(XfconfChannel *inChannel,
+ const gchar *inProperty,
+ const GValue *inValue,
+ gpointer inUserData)
+{
+ const gchar *priorityValue;
+ XfdashboardWindowContentGDKPriorityMap *found;
+
+ g_return_if_fail(g_strcmp0(inProperty, WINDOW_CONTENT_CREATION_PRIORITY_XFCONF_PROP)==0);
+ g_return_if_fail(inValue && G_VALUE_HOLDS_STRING(inValue));
+
+ /* Determine priority from new value */
+ priorityValue=g_value_get_string(inValue);
+ found=_xfdashboard_window_content_gdk_window_creation_priority_map;
+ while(found->name && g_strcmp0(priorityValue, found->name)!=0) found++;
+
+ /* Set default value if no match was found in priority map was found */
+ if(!found || !found->name)
+ {
+ /* Default value is the first one in mapping */
+ found=_xfdashboard_window_content_gdk_window_creation_priority_map;
+
+ g_warning(_("Unknown value '%s' for property '%s' - defaulting to '%s' with priority of %d"),
+ priorityValue,
+ inProperty,
+ found->name,
+ found->priority);
+ }
+
+ /* Set priority */
+ if(found)
+ {
+ _xfdashboard_window_content_gdk_window_creation_priority=found->priority;
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Setting window creation priority to '%s' with priority of %d",
+ found->name,
+ found->priority);
+ }
+}
+
+/* Disconnect signal handler for xfconf value change notification on window priority */
+static void _xfdashboard_window_content_gdk_on_window_creation_priority_shutdown(void)
+{
+ XfdashboardApplication *application;
+
+ /* Disconnect application "shutdown" signal handler */
+ if(_xfdashboard_window_content_gdk_window_creation_shutdown_signal_id)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Disconnecting shutdown signal handler %u for window creation priority value change notifications",
+ _xfdashboard_window_content_gdk_window_creation_shutdown_signal_id);
+
+ application=xfdashboard_application_get_default();
+ g_signal_handler_disconnect(application, _xfdashboard_window_content_gdk_window_creation_shutdown_signal_id);
+ _xfdashboard_window_content_gdk_window_creation_shutdown_signal_id=0;
+ }
+
+ /* Disconnect property changed signal handler */
+ if(_xfdashboard_window_content_gdk_xfconf_priority_notify_id)
+ {
+ XfconfChannel *xfconfChannel;
+
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Disconnecting property changed signal handler %u for window creation priority value change notifications",
+ _xfdashboard_window_content_gdk_xfconf_priority_notify_id);
+
+ xfconfChannel=xfdashboard_application_get_xfconf_channel(NULL);
+ g_signal_handler_disconnect(xfconfChannel, _xfdashboard_window_content_gdk_xfconf_priority_notify_id);
+ _xfdashboard_window_content_gdk_xfconf_priority_notify_id=0;
+ }
+}
+
+/* Check if we should workaround unmapped window for requested window and set up workaround */
+static void _xfdashboard_window_content_gdk_on_workaround_state_changed(XfdashboardWindowContentGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+ XfdashboardWindowTrackerWindowState windowState;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ priv=self->priv;
+
+ /* Handle state change of window */
+ windowState=xfdashboard_window_tracker_window_get_state(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window));
+
+ switch(priv->workaroundMode)
+ {
+ case XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_UNMINIMIZING:
+ /* Check if window is unminized now, then update content texture and
+ * minimize window again.
+ */
+ if(!(windowState & XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_MINIMIZED))
+ {
+ if(priv->texture &&
+ priv->workaroundMode!=XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_NONE &&
+ priv->isMapped==TRUE)
+ {
+ /* Copy current texture as it might get inaccessible. If we copy it now
+ * when can draw the last image known. If we can copy it successfully
+ * replace current texture with the copied one.
+ */
+ CoglPixelFormat textureFormat;
+ guint textureWidth;
+ guint textureHeight;
+ gint textureSize;
+ guint8 *textureData;
+
+ textureFormat=cogl_texture_get_format(priv->texture);
+ textureSize=cogl_texture_get_data(priv->texture, textureFormat, 0, NULL);
+ textureWidth=cogl_texture_get_width(priv->texture);
+ textureHeight=cogl_texture_get_height(priv->texture);
+ textureData=g_malloc(textureSize);
+ if(textureData)
+ {
+ CoglTexture *copyTexture;
+ gint copyTextureSize;
+#if COGL_VERSION_CHECK(1, 18, 0)
+ ClutterBackend *backend;
+ CoglContext *context;
+ CoglError *error;
+#endif
+
+ /* Get texture data to copy */
+ copyTextureSize=cogl_texture_get_data(priv->texture, textureFormat, 0, textureData);
+ if(copyTextureSize)
+ {
+#if COGL_VERSION_CHECK(1, 18, 0)
+ error=NULL;
+
+ backend=clutter_get_default_backend();
+ context=clutter_backend_get_cogl_context(backend);
+ copyTexture=cogl_texture_2d_new_from_data(context,
+ textureWidth,
+ textureHeight,
+ textureFormat,
+ 0,
+ textureData,
+ &error);
+
+ if(!copyTexture || error)
+ {
+ /* Show warning */
+ g_warning(_("Could not create copy of texture of mininized window '%s': %s"),
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)),
+ (error && error->message) ? error->message : _("Unknown error"));
+
+ /* Release allocated resources */
+ if(copyTexture)
+ {
+ cogl_object_unref(copyTexture);
+ copyTexture=NULL;
+ }
+
+ if(error)
+ {
+ cogl_error_free(error);
+ error=NULL;
+ }
+ }
+#else
+ copyTexture=cogl_texture_new_from_data(textureWidth,
+ textureHeight,
+ COGL_TEXTURE_NONE,
+ textureFormat,
+ textureFormat,
+ 0,
+ textureData);
+ if(!copyTexture)
+ {
+ /* Show warning */
+ g_warning(_("Could not create copy of texture of mininized window '%s'"),
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ }
+#endif
+
+ if(copyTexture)
+ {
+ cogl_object_unref(priv->texture);
+ priv->texture=copyTexture;
+ }
+ }
+ else g_warning(_("Could not determine size of texture of minimized window '%s'"),
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ }
+ else
+ {
+ g_warning(_("Could not allocate memory for copy of texture of mininized window '%s'"),
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ }
+ }
+
+ xfdashboard_window_tracker_window_hide(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window));
+ priv->workaroundMode=XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_REMINIMIZING;
+ }
+ break;
+
+ case XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_REMINIMIZING:
+ /* Check if window is now minized again, so stop workaround and
+ * disconnecting signals.
+ */
+ if(windowState & XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_MINIMIZED)
+ {
+ priv->workaroundMode=XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_DONE;
+ if(priv->workaroundStateSignalID)
+ {
+ g_signal_handler_disconnect(priv->windowTracker, priv->workaroundStateSignalID);
+ priv->workaroundStateSignalID=0;
+ }
+ }
+ break;
+
+ default:
+ /* We should never get here but if we do it is more or less
+ * a critical error. Ensure that window is minimized (again)
+ * and stop xfdashboard.
+ */
+ xfdashboard_window_tracker_window_hide(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window));
+ g_assert_not_reached();
+ break;
+ }
+}
+
+static void _xfdashboard_window_content_gdk_setup_workaround(XfdashboardWindowContentGDK *self, XfdashboardWindowTrackerWindowGDK *inWindow)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+ gboolean doWorkaround;
+ XfdashboardWindowTrackerWindowState windowState;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inWindow!=NULL && XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ priv=self->priv;
+
+ /* Check if should workaround unmapped windows at all */
+ doWorkaround=xfconf_channel_get_bool(xfdashboard_application_get_xfconf_channel(NULL),
+ WORKAROUND_UNMAPPED_WINDOW_XFCONF_PROP,
+ DEFAULT_WORKAROUND_UNMAPPED_WINDOW);
+ if(!doWorkaround) return;
+
+ /* Only workaround unmapped windows */
+ windowState=xfdashboard_window_tracker_window_get_state(XFDASHBOARD_WINDOW_TRACKER_WINDOW(inWindow));
+ if(!(windowState & XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_MINIMIZED)) return;
+
+ /* Check if workaround is already set up */
+ if(priv->workaroundMode!=XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_NONE) return;
+
+ /* Set flag that workaround is (going to be) set up */
+ priv->workaroundMode=XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_UNMINIMIZING;
+
+ /* The workaround is as follows:
+ *
+ * 1.) Set up signal handlers to get notified about changes of window
+ * 2.) Unminimize window
+ * 3.) If window is visible it will be activated by design, so reactivate
+ * last active window
+ * 4.) Minimize window again
+ * 5.) Stop watching for changes of window by disconnecting signal handlers
+ */
+ priv->workaroundStateSignalID=g_signal_connect_swapped(priv->windowTracker,
+ "window-state-changed",
+ G_CALLBACK(_xfdashboard_window_content_gdk_on_workaround_state_changed),
+ self);
+ xfdashboard_window_tracker_window_show(XFDASHBOARD_WINDOW_TRACKER_WINDOW(inWindow));
+}
+
+/* Check extension and set up basics */
+static void _xfdashboard_window_content_gdk_check_extension(void)
+{
+ Display *display G_GNUC_UNUSED;
+#ifdef HAVE_XDAMAGE
+ int damageError=0;
+#endif
+#ifdef HAVE_XCOMPOSITE
+ int compositeEventBase=0;
+ int compositeError=0;
+ int compositeMajor, compositeMinor;
+#endif
+
+ /* Check if we have already checked extensions */
+ if(_xfdashboard_window_content_gdk_have_checked_extensions!=FALSE) return;
+
+ /* Mark that we have check for extensions regardless of any error*/
+ _xfdashboard_window_content_gdk_have_checked_extensions=TRUE;
+
+ /* Get display */
+ display=gdk_x11_display_get_xdisplay(clutter_gdk_get_default_display());
+
+ /* Check for composite extenstion */
+ _xfdashboard_window_content_gdk_have_composite_extension=FALSE;
+#ifdef HAVE_XCOMPOSITE
+ if(XCompositeQueryExtension(display, &compositeEventBase, &compositeError))
+ {
+ compositeMajor=compositeMinor=0;
+ if(XCompositeQueryVersion(display, &compositeMajor, &compositeMinor))
+ {
+ if(compositeMajor>=COMPOSITE_VERSION_MIN_MAJOR && compositeMinor>=COMPOSITE_VERSION_MIN_MINOR)
+ {
+ _xfdashboard_window_content_gdk_have_composite_extension=TRUE;
+ }
+ else
+ {
+ g_warning(_("Need at least version %d.%d of composite extension but found %d.%d - using only fallback images"),
+ COMPOSITE_VERSION_MIN_MAJOR, COMPOSITE_VERSION_MIN_MINOR, compositeMajor, compositeMinor);
+ }
+ }
+ else g_warning(_("Query for X composite extension failed - using only fallback imagess"));
+ }
+ else g_warning(_("X does not support composite extension - using only fallback images"));
+#endif
+
+ /* Get base of damage event in X */
+ _xfdashboard_window_content_gdk_have_damage_extension=FALSE;
+ _xfdashboard_window_content_gdk_damage_event_base=0;
+
+#ifdef HAVE_XDAMAGE
+ if(XDamageQueryExtension(display, &_xfdashboard_window_content_gdk_damage_event_base, &damageError))
+ {
+ _xfdashboard_window_content_gdk_have_damage_extension=TRUE;
+ }
+ else
+ {
+ g_warning(_("Query for X damage extension resulted in error code %d - using only still images of windows"),
+ damageError);
+ }
+#endif
+}
+
+/* Suspension state of application changed */
+static void _xfdashboard_window_content_gdk_on_application_suspended_changed(XfdashboardWindowContentGDK *self,
+ GParamSpec *inSpec,
+ gpointer inUserData)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+ XfdashboardApplication *app;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(XFDASHBOARD_IS_APPLICATION(inUserData));
+
+ priv=self->priv;
+ app=XFDASHBOARD_APPLICATION(inUserData);
+
+ /* Get application suspend state */
+ priv->isAppSuspended=xfdashboard_application_is_suspended(app);
+
+ /* If application is suspended then suspend this window too ... */
+ if(priv->isAppSuspended)
+ {
+ _xfdashboard_window_content_gdk_suspend(self);
+ }
+ /* ... otherwise resume window if it is mapped */
+ else
+ {
+ if(priv->isMapped) _xfdashboard_window_content_gdk_resume(self);
+ }
+}
+
+/* Filter X events for damages */
+static GdkFilterReturn _xfdashboard_window_content_gdk_on_gdk_event(GdkXEvent *inXEvent,
+ GdkEvent *inEvent,
+ gpointer inUserData)
+{
+ XfdashboardWindowContentGDK *self;
+ XfdashboardWindowContentGDKPrivate *priv;
+ XEvent *xEvent;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(inUserData), GDK_FILTER_CONTINUE);
+
+ self=XFDASHBOARD_WINDOW_CONTENT_GDK(inUserData);
+ priv=self->priv;
+ xEvent=(XEvent*)inXEvent;
+
+ /* Check for mapped, unmapped related X events as pixmap, damage, texture etc.
+ * needs to get resumed (acquired) or suspended (released)
+ */
+ if(xEvent->xany.window==priv->xWindowID)
+ {
+ switch(xEvent->type)
+ {
+ case MapNotify:
+ case ConfigureNotify:
+ priv->isMapped=TRUE;
+ if(!priv->isAppSuspended) _xfdashboard_window_content_gdk_resume(self);
+ break;
+
+ case UnmapNotify:
+ case DestroyNotify:
+ priv->isMapped=FALSE;
+ _xfdashboard_window_content_gdk_suspend(self);
+ break;
+
+ default:
+ /* We do not handle this type of X event, drop through ... */
+ break;
+ }
+ }
+
+ /* Check for damage event */
+#ifdef HAVE_XDAMAGE
+ if(_xfdashboard_window_content_gdk_have_damage_extension &&
+ _xfdashboard_window_content_gdk_damage_event_base &&
+ xEvent->type==(_xfdashboard_window_content_gdk_damage_event_base + XDamageNotify) &&
+ ((XDamageNotifyEvent*)xEvent)->damage==priv->damage &&
+ priv->workaroundMode==XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_NONE)
+ {
+ /* Update texture for live window content */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+ }
+#endif
+
+ return(GDK_FILTER_CONTINUE);
+}
+
+/* Release all resources used by this instance */
+static void _xfdashboard_window_content_gdk_release_resources(XfdashboardWindowContentGDK *self)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+ Display *display;
+ gint trapError;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+
+ priv=self->priv;
+
+ /* This live update will be suspended so remove it from queue */
+ _xfdashboard_window_content_gdk_resume_on_idle_remove(self);
+
+ /* Get display as it used more than once ;) */
+ display=gdk_x11_display_get_xdisplay(clutter_gdk_get_default_display());
+
+ /* Release resources. It might be important to release them
+ * in reverse order as they were created.
+ */
+ clutter_x11_trap_x_errors();
+ {
+ if(priv->texture)
+ {
+ cogl_object_unref(priv->texture);
+ priv->texture=NULL;
+ }
+
+#ifdef HAVE_XDAMAGE
+ if(priv->damage!=None)
+ {
+ XDamageDestroy(display, priv->damage);
+ XSync(display, False);
+ priv->damage=None;
+ }
+#endif
+ if(priv->pixmap!=None)
+ {
+ XFreePixmap(display, priv->pixmap);
+ priv->pixmap=None;
+ }
+
+ if(priv->xWindowID!=None)
+ {
+#ifdef HAVE_XCOMPOSITE
+ if(_xfdashboard_window_content_gdk_have_composite_extension)
+ {
+ XCompositeUnredirectWindow(display, priv->xWindowID, CompositeRedirectAutomatic);
+ XSync(display, False);
+ }
+#endif
+ priv->xWindowID=None;
+ }
+
+ /* Window is suspended now */
+ if(priv->isSuspended!=TRUE)
+ {
+ priv->isSuspended=TRUE;
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_SUSPENDED]);
+ }
+ }
+
+ /* Check if everything went well */
+ trapError=clutter_x11_untrap_x_errors();
+ if(trapError!=0)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "X error %d occured while releasing resources for window '%s'",
+ trapError,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ return;
+ }
+
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Released resources for window '%s' to handle live texture updates",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+}
+
+/* Suspend from handling live updates */
+static void _xfdashboard_window_content_gdk_suspend(XfdashboardWindowContentGDK *self)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+ Display *display;
+ gint trapError;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+
+ priv=self->priv;
+
+ /* This live update will be suspended so remove it from queue */
+ _xfdashboard_window_content_gdk_resume_on_idle_remove(self);
+
+ /* Get display as it used more than once ;) */
+ display=gdk_x11_display_get_xdisplay(clutter_gdk_get_default_display());
+
+ /* Release resources */
+ clutter_x11_trap_x_errors();
+ {
+ /* Suspend live updates from texture */
+ if(priv->texture && !priv->isFallback)
+ {
+#ifdef HAVE_XDAMAGE
+ cogl_texture_pixmap_x11_set_damage_object(COGL_TEXTURE_PIXMAP_X11(priv->texture), 0, 0);
+#endif
+ }
+
+ /* Release damage */
+#ifdef HAVE_XDAMAGE
+ if(priv->damage!=None)
+ {
+ XDamageDestroy(display, priv->damage);
+ XSync(display, False);
+ priv->damage=None;
+ }
+#endif
+
+ /* Release pixmap */
+ if(priv->pixmap!=None)
+ {
+ XFreePixmap(display, priv->pixmap);
+ priv->pixmap=None;
+ }
+
+ /* Window is suspended now */
+ if(priv->isSuspended!=TRUE)
+ {
+ priv->isSuspended=TRUE;
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_SUSPENDED]);
+ }
+ }
+
+ /* Check if everything went well */
+ trapError=clutter_x11_untrap_x_errors();
+ if(trapError!=0)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "X error %d occured while suspending '%s",
+ trapError,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ return;
+ }
+
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Successfully suspended live texture updates for window '%s'",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+}
+
+/* Resume to handle live window updates */
+static gboolean _xfdashboard_window_content_gdk_resume_on_idle(gpointer inUserData)
+{
+ XfdashboardWindowContentGDK *self;
+ XfdashboardWindowContentGDKPrivate *priv;
+ GList *queueEntry;
+ Display *display;
+ CoglContext *context;
+ GError *error;
+ gint trapError;
+ CoglTexture *windowTexture;
+ gboolean doContinueSource;
+
+ error=NULL;
+ windowTexture=NULL;
+
+ /* Get window content object from first entry in queue and remove it from queue */
+ queueEntry=g_list_first(_xfdashboard_window_content_gdk_resume_idle_queue);
+ if(!queueEntry)
+ {
+ g_warning(_("Resume handler called for empty queue."));
+
+ /* Queue must be empty but ensure it will */
+ if(_xfdashboard_window_content_gdk_resume_idle_queue)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS, "Ensuring that window content resume queue is empty");
+ g_list_free(_xfdashboard_window_content_gdk_resume_idle_queue);
+ _xfdashboard_window_content_gdk_resume_idle_queue=NULL;
+ }
+
+ /* Queue must be empty so remove idle source */
+ _xfdashboard_window_content_gdk_resume_idle_id=0;
+ return(G_SOURCE_REMOVE);
+ }
+
+ self=XFDASHBOARD_WINDOW_CONTENT_GDK(queueEntry->data);
+ priv=self->priv;
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Entering idle source with ID %u for window resume of '%s'",
+ _xfdashboard_window_content_gdk_resume_idle_id,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Removing queued entry %p for window resume of '%s'",
+ queueEntry,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ _xfdashboard_window_content_gdk_resume_idle_queue=g_list_delete_link(_xfdashboard_window_content_gdk_resume_idle_queue, queueEntry);
+ if(_xfdashboard_window_content_gdk_resume_idle_queue)
+ {
+ doContinueSource=G_SOURCE_CONTINUE;
+ }
+ else
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Resume idle source with ID %u will be remove because queue is empty",
+ _xfdashboard_window_content_gdk_resume_idle_id);
+
+ doContinueSource=G_SOURCE_REMOVE;
+ _xfdashboard_window_content_gdk_resume_idle_id=0;
+ }
+
+
+ /* We need at least the X composite extension to display images of windows
+ * if still images or live updated ones
+ */
+ if(!_xfdashboard_window_content_gdk_have_composite_extension)
+ {
+ return(doContinueSource);
+ }
+
+ /* Get display as it used more than once ;) */
+ display=gdk_x11_display_get_xdisplay(clutter_gdk_get_default_display());
+
+ /* Set up resources */
+ clutter_x11_trap_x_errors();
+ while(1)
+ {
+#ifdef HAVE_XCOMPOSITE
+ /* Get pixmap to render texture for */
+ priv->pixmap=XCompositeNameWindowPixmap(display, priv->xWindowID);
+ XSync(display, False);
+ if(priv->pixmap==None)
+ {
+ g_warning(_("Could not get pixmap for window '%s"), xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+
+ /* Set flag to suspend window content after resuming because of error */
+ priv->suspendAfterResumeOnIdle=TRUE;
+ break;
+ }
+#else
+ /* We should never get here as existance of composite extension was checked before */
+ g_critical(_("Cannot resume window '%s' as composite extension is not available"),
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ break;
+#endif
+
+ /* Create cogl X11 texture for live updates */
+ context=clutter_backend_get_cogl_context(clutter_get_default_backend());
+ windowTexture=COGL_TEXTURE(cogl_texture_pixmap_x11_new(context, priv->pixmap, FALSE, &error));
+ if(!windowTexture || error)
+ {
+ /* Creating texture may fail if window is _NOT_ on active workspace
+ * so display error message just as debug message (this time)
+ */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Could not create texture for window '%s': %s",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)),
+ error ? error->message : _("Unknown error"));
+ if(error)
+ {
+ g_error_free(error);
+ error=NULL;
+ }
+
+ if(windowTexture)
+ {
+ cogl_object_unref(windowTexture);
+ windowTexture=NULL;
+ }
+
+ /* Set flag to suspend window content after resuming because of error */
+ priv->suspendAfterResumeOnIdle=TRUE;
+
+ break;
+ }
+
+ /* Set up damage to get notified about changed in pixmap */
+#ifdef HAVE_XDAMAGE
+ if(_xfdashboard_window_content_gdk_have_damage_extension)
+ {
+ priv->damage=XDamageCreate(display, priv->pixmap, XDamageReportBoundingBox);
+ XSync(display, False);
+ if(priv->damage==None)
+ {
+ g_warning(_("Could not create damage for window '%s' - using still image of window"), xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ }
+ }
+#endif
+
+ /* Release old texture (should be the fallback texture) and set new texture */
+ if(priv->texture)
+ {
+ cogl_object_unref(priv->texture);
+ priv->texture=windowTexture;
+ }
+
+ /* Set damage to new window texture */
+#ifdef HAVE_XDAMAGE
+ if(_xfdashboard_window_content_gdk_have_damage_extension &&
+ priv->damage!=None)
+ {
+ cogl_texture_pixmap_x11_set_damage_object(COGL_TEXTURE_PIXMAP_X11(priv->texture), priv->damage, COGL_TEXTURE_PIXMAP_X11_DAMAGE_BOUNDING_BOX);
+ }
+#endif
+
+ /* Now we use the window as texture and not the fallback texture anymore */
+ priv->isFallback=FALSE;
+
+ /* Window is not suspended anymore */
+ if(priv->isSuspended!=FALSE)
+ {
+ priv->isSuspended=FALSE;
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_SUSPENDED]);
+ }
+
+ /* Invalidate content to get it redrawn as soon as possible */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* We were able to set up window content so this window is definitely mapped */
+ priv->isMapped=TRUE;
+
+ /* End reached so break to get out of while loop */
+ break;
+ }
+
+ /* Check if window content should be suspended again after resume was done,
+ * e.g. initial window content creation in suspended daemon mode.
+ */
+ if(priv->suspendAfterResumeOnIdle)
+ {
+ _xfdashboard_window_content_gdk_suspend(self);
+ priv->suspendAfterResumeOnIdle=FALSE;
+ }
+
+ /* Check if everything went well */
+ trapError=clutter_x11_untrap_x_errors();
+ if(trapError!=0)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "X error %d occured while resuming window '%s",
+ trapError,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ return(doContinueSource);
+ }
+
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Resuming live texture updates for window '%s'",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ return(doContinueSource);
+}
+
+static void _xfdashboard_window_content_gdk_resume(XfdashboardWindowContentGDK *self)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+ Display *display;
+ CoglContext *context;
+ GError *error;
+ gint trapError;
+ CoglTexture *windowTexture;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(self->priv->window);
+
+ priv=self->priv;
+ error=NULL;
+ windowTexture=NULL;
+
+ /* Check if to use new experimental code to resume window content
+ * in an idle source.
+ */
+ if(_xfdashboard_window_content_gdk_window_creation_priority>0)
+ {
+ _xfdashboard_window_content_gdk_resume_on_idle_add(self);
+ return;
+ }
+
+ /* We need at least the X composite extension to display images of windows
+ * if still images or live updated ones
+ */
+ if(!_xfdashboard_window_content_gdk_have_composite_extension) return;
+
+ /* Get display as it used more than once ;) */
+ display=gdk_x11_display_get_xdisplay(clutter_gdk_get_default_display());
+
+ /* Set up resources */
+ clutter_x11_trap_x_errors();
+ while(1)
+ {
+#ifdef HAVE_XCOMPOSITE
+ /* Get pixmap to render texture for */
+ priv->pixmap=XCompositeNameWindowPixmap(display, priv->xWindowID);
+ XSync(display, False);
+ if(priv->pixmap==None)
+ {
+ g_warning(_("Could not get pixmap for window '%s"), xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ _xfdashboard_window_content_gdk_suspend(self);
+ break;
+ }
+#else
+ /* We should never get here as existance of composite extension was checked before */
+ g_critical(_("Cannot resume window '%s' as composite extension is not available"),
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ break;
+#endif
+
+ /* Create cogl X11 texture for live updates */
+ context=clutter_backend_get_cogl_context(clutter_get_default_backend());
+ windowTexture=COGL_TEXTURE(cogl_texture_pixmap_x11_new(context, priv->pixmap, FALSE, &error));
+ if(!windowTexture || error)
+ {
+ /* Creating texture may fail if window is _NOT_ on active workspace
+ * so display error message just as debug message (this time)
+ */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Could not create texture for window '%s': %s",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)),
+ error ? error->message : _("Unknown error"));
+ if(error)
+ {
+ g_error_free(error);
+ error=NULL;
+ }
+
+ if(windowTexture)
+ {
+ cogl_object_unref(windowTexture);
+ windowTexture=NULL;
+ }
+
+ _xfdashboard_window_content_gdk_suspend(self);
+
+ break;
+ }
+
+ /* Set up damage to get notified about changed in pixmap */
+#ifdef HAVE_XDAMAGE
+ if(_xfdashboard_window_content_gdk_have_damage_extension)
+ {
+ priv->damage=XDamageCreate(display, priv->pixmap, XDamageReportBoundingBox);
+ XSync(display, False);
+ if(priv->damage==None)
+ {
+ g_warning(_("Could not create damage for window '%s' - using still image of window"), xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ }
+ }
+#endif
+
+ /* Release old texture (should be the fallback texture) and set new texture */
+ if(priv->texture)
+ {
+ cogl_object_unref(priv->texture);
+ priv->texture=windowTexture;
+ }
+
+ /* Set damage to new window texture */
+#ifdef HAVE_XDAMAGE
+ if(_xfdashboard_window_content_gdk_have_damage_extension &&
+ priv->damage!=None)
+ {
+ cogl_texture_pixmap_x11_set_damage_object(COGL_TEXTURE_PIXMAP_X11(priv->texture), priv->damage, COGL_TEXTURE_PIXMAP_X11_DAMAGE_BOUNDING_BOX);
+ }
+#endif
+
+ /* Now we use the window as texture and not the fallback texture anymore */
+ priv->isFallback=FALSE;
+
+ /* Window is not suspended anymore */
+ if(priv->isSuspended!=FALSE)
+ {
+ priv->isSuspended=FALSE;
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_SUSPENDED]);
+ }
+
+ /* Invalidate content to get it redrawn as soon as possible */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* We were able to set up window content so this window is definitely mapped */
+ priv->isMapped=TRUE;
+
+ /* End reached so break to get out of while loop */
+ break;
+ }
+
+ /* Check if everything went well */
+ trapError=clutter_x11_untrap_x_errors();
+ if(trapError!=0)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "X error %d occured while resuming window '%s",
+ trapError,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ return;
+ }
+
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Resuming live texture updates for window '%s'",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+}
+
+/* Find X window for window frame of given X window content */
+static Window _xfdashboard_window_content_gdk_get_window_frame_xid(Display *inDisplay,
+ XfdashboardWindowTrackerWindowGDK *inWindow)
+{
+ Window xWindowID;
+ Window iterXWindowID;
+ Window rootXWindowID;
+ Window foundXWindowID;
+ GdkWindow *gdkWindow;
+ GdkWMDecoration gdkWindowDecoration;
+
+ g_return_val_if_fail(inDisplay, 0);
+ g_return_val_if_fail(inWindow, 0);
+
+ /* Get X window */
+ xWindowID=xfdashboard_window_tracker_window_gdk_get_xid(inWindow);
+ g_return_val_if_fail(xWindowID!=0, 0);
+
+ /* Check if window is client side decorated and if it has no decorations
+ * so skip finding window frame and behave like we did not found it.
+ */
+ XSync(inDisplay, False);
+ gdkWindow=gdk_x11_window_foreign_new_for_display(gdk_x11_lookup_xdisplay(inDisplay), xWindowID);
+ if(gdkWindow)
+ {
+ if(!gdk_window_get_decorations(gdkWindow, &gdkWindowDecoration) ||
+ gdkWindowDecoration==0)
+ {
+ XFDASHBOARD_DEBUG(inWindow, WINDOWS,
+ "Window '%s' has either CSD not enabled or no decorations applied so skip finding window frame",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(inWindow)));
+
+ /* Release allocated resources */
+ g_object_unref(gdkWindow);
+
+ /* Skip finding window frame and return "not-found" result */
+ return(0);
+ }
+ g_object_unref(gdkWindow);
+ }
+ else
+ {
+ XFDASHBOARD_DEBUG(inWindow, WINDOWS,
+ "Could not get window decoration from window '%s'",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(inWindow)));
+ }
+
+ /* Iterate through X window tree list upwards until root window reached.
+ * The last X window before root window is the one we are looking for.
+ */
+ rootXWindowID=0;
+ foundXWindowID=0;
+ for(iterXWindowID=xWindowID; iterXWindowID && iterXWindowID!=rootXWindowID; )
+ {
+ Window *children;
+ guint numberChildren;
+
+ children=NULL;
+ numberChildren=0;
+ foundXWindowID=iterXWindowID;
+ if(!XQueryTree(inDisplay, iterXWindowID, &rootXWindowID, &iterXWindowID, &children, &numberChildren))
+ {
+ iterXWindowID=0;
+ }
+ if(children) XFree(children);
+ }
+
+ /* Return found X window ID */
+ return(foundXWindowID);
+}
+
+/* Set window to handle and to display */
+static void _xfdashboard_window_content_gdk_set_window(XfdashboardWindowContentGDK *self, XfdashboardWindowTrackerWindowGDK *inWindow)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+ XfdashboardApplication *application;
+ Display *display;
+ GdkPixbuf *windowIcon;
+ XWindowAttributes windowAttrs;
+#if COGL_VERSION_CHECK(1, 18, 0)
+ ClutterBackend *backend;
+ CoglContext *context;
+ CoglError *error;
+#endif
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inWindow!=NULL && XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+ g_return_if_fail(self->priv->window==NULL);
+ g_return_if_fail(self->priv->xWindowID==0);
+
+ priv=self->priv;
+
+ /* Freeze notifications and collect them */
+ g_object_freeze_notify(G_OBJECT(self));
+
+ /* Get display as it used more than once ;) */
+ display=gdk_x11_display_get_xdisplay(clutter_gdk_get_default_display());
+
+ /* Set new value */
+ priv->window=inWindow;
+
+ /* Create fallback texture first in case we cannot create
+ * a live updated texture for window in the next steps
+ */
+ windowIcon=xfdashboard_window_tracker_window_get_icon(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window));
+#if COGL_VERSION_CHECK(1, 18, 0)
+ error=NULL;
+
+ backend=clutter_get_default_backend();
+ context=clutter_backend_get_cogl_context(backend);
+ priv->texture=cogl_texture_2d_new_from_data(context,
+ gdk_pixbuf_get_width(windowIcon),
+ gdk_pixbuf_get_height(windowIcon),
+ gdk_pixbuf_get_has_alpha(windowIcon) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
+ gdk_pixbuf_get_rowstride(windowIcon),
+ gdk_pixbuf_get_pixels(windowIcon),
+ &error);
+
+ if(!priv->texture || error)
+ {
+ /* Show warning */
+ g_warning(_("Could not create fallback texture for window '%s': %s"),
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)),
+ (error && error->message) ? error->message : _("Unknown error"));
+
+ /* Release allocated resources */
+ if(priv->texture)
+ {
+ cogl_object_unref(priv->texture);
+ priv->texture=NULL;
+ }
+
+ if(error)
+ {
+ cogl_error_free(error);
+ error=NULL;
+ }
+ }
+#else
+ priv->texture=cogl_texture_new_from_data(gdk_pixbuf_get_width(windowIcon),
+ gdk_pixbuf_get_height(windowIcon),
+ COGL_TEXTURE_NONE,
+ gdk_pixbuf_get_has_alpha(windowIcon) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
+ COGL_PIXEL_FORMAT_ANY,
+ gdk_pixbuf_get_rowstride(windowIcon),
+ gdk_pixbuf_get_pixels(windowIcon));
+#endif
+
+ priv->isFallback=TRUE;
+
+ /* Get X window and its attributes */
+ if(priv->includeWindowFrame)
+ {
+ priv->xWindowID=_xfdashboard_window_content_gdk_get_window_frame_xid(display, priv->window);
+ }
+
+ if(!priv->xWindowID)
+ {
+ priv->xWindowID=xfdashboard_window_tracker_window_gdk_get_xid(priv->window);
+ }
+
+ if(!XGetWindowAttributes(display, priv->xWindowID, &windowAttrs))
+ {
+ g_warning(_("Could not get attributes of window '%s'"), xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ XSync(display, False);
+ }
+
+ /* We need at least the X composite extension to display images of windows
+ * if still images or live updated ones by redirecting window
+ */
+#ifdef HAVE_XCOMPOSITE
+ if(_xfdashboard_window_content_gdk_have_composite_extension)
+ {
+ /* Redirect window */
+ XCompositeRedirectWindow(display, priv->xWindowID, CompositeRedirectAutomatic);
+ XSync(display, False);
+ }
+#endif
+
+ /* We are interested in receiving mapping events of windows */
+ XSelectInput(display, priv->xWindowID, windowAttrs.your_event_mask | StructureNotifyMask);
+
+ /* Acquire new window and handle live updates */
+ _xfdashboard_window_content_gdk_resume(self);
+ priv->isMapped=!priv->isSuspended;
+
+ /* But suspend window immediately again if application is suspended
+ * (xfdashboard runs in daemon mode and is not active currently)
+ */
+ application=xfdashboard_application_get_default();
+ if(xfdashboard_application_is_suspended(application))
+ {
+ if(_xfdashboard_window_content_gdk_window_creation_priority>0)
+ {
+ priv->suspendAfterResumeOnIdle=TRUE;
+ }
+ else
+ {
+ _xfdashboard_window_content_gdk_suspend(self);
+ }
+ }
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_WINDOW]);
+
+ /* Thaw notifications and send them now */
+ g_object_thaw_notify(G_OBJECT(self));
+
+ /* Set up workaround mechanism for unmapped windows if wanted and needed */
+ _xfdashboard_window_content_gdk_setup_workaround(self, inWindow);
+}
+
+
+/* IMPLEMENTATION: ClutterContent */
+
+/* Paint texture */
+static void _xdashboard_window_content_clutter_content_iface_paint_content(ClutterContent *inContent,
+ ClutterActor *inActor,
+ ClutterPaintNode *inRootNode)
+{
+ XfdashboardWindowContentGDK *self=XFDASHBOARD_WINDOW_CONTENT_GDK(inContent);
+ XfdashboardWindowContentGDKPrivate *priv=self->priv;
+ ClutterScalingFilter minFilter, magFilter;
+ ClutterPaintNode *node;
+ ClutterActorBox textureAllocationBox;
+ ClutterActorBox textureCoordBox;
+ ClutterActorBox outlineBox;
+ ClutterColor color;
+ guint8 opacity;
+ ClutterColor outlineColor;
+ ClutterActorBox outlinePath;
+
+ /* Check if we have a texture to paint */
+ if(priv->texture==NULL) return;
+
+ /* Get needed data for painting */
+ clutter_actor_box_init(&textureCoordBox, 0.0f, 0.0f, 1.0f, 1.0f);
+ clutter_actor_get_content_box(inActor, &textureAllocationBox);
+ clutter_actor_get_content_box(inActor, &outlineBox);
+ clutter_actor_get_content_scaling_filters(inActor, &minFilter, &magFilter);
+ opacity=clutter_actor_get_paint_opacity(inActor);
+
+ color.red=opacity;
+ color.green=opacity;
+ color.blue=opacity;
+ color.alpha=opacity;
+
+ /* Draw background if texture is a fallback */
+ if(priv->isFallback)
+ {
+ ClutterColor backgroundColor;
+
+ /* Set up background color */
+ backgroundColor.red=0;
+ backgroundColor.green=0;
+ backgroundColor.blue=0;
+ backgroundColor.alpha=opacity;
+
+ /* Draw background */
+ node=clutter_color_node_new(&backgroundColor);
+ clutter_paint_node_set_name(node, "fallback-background");
+ clutter_paint_node_add_rectangle(node, &outlineBox);
+ clutter_paint_node_add_child(inRootNode, node);
+ clutter_paint_node_unref(node);
+ }
+
+ /* Determine actor box allocation to draw texture into when unmapped window
+ * icon (fallback) will be drawn. We can skip calculation if unmapped window
+ * icon should be expanded in both (x and y) direction.
+ */
+ if(priv->isFallback &&
+ (!priv->unmappedWindowIconXFill || !priv->unmappedWindowIconYFill))
+ {
+ gfloat allocationWidth;
+ gfloat allocationHeight;
+
+ /* Get width and height of allocation */
+ allocationWidth=(outlineBox.x2-outlineBox.x1);
+ allocationHeight=(outlineBox.y2-outlineBox.y1);
+
+ /* Determine left and right boundary of unmapped window icon
+ * if unmapped window icon should not expand in X axis.
+ */
+ if(!priv->unmappedWindowIconXFill)
+ {
+ gfloat offset;
+ gfloat textureWidth;
+ gfloat oversize;
+
+ /* Get scaled width of unmapped window icon */
+ textureWidth=cogl_texture_get_width(priv->texture);
+ textureWidth*=priv->unmappedWindowIconXScale;
+
+ /* Get boundary in X axis depending on gravity and scaled width */
+ offset=(priv->unmappedWindowIconXAlign*allocationWidth);
+ switch(priv->unmappedWindowIconAnchorPoint)
+ {
+ /* Align to left boundary.
+ * This is also the default if gravity is none or undefined.
+ */
+ default:
+ case XFDASHBOARD_ANCHOR_POINT_NONE:
+ case XFDASHBOARD_ANCHOR_POINT_WEST:
+ case XFDASHBOARD_ANCHOR_POINT_NORTH_WEST:
+ case XFDASHBOARD_ANCHOR_POINT_SOUTH_WEST:
+ break;
+
+ /* Align to center of X axis */
+ case XFDASHBOARD_ANCHOR_POINT_CENTER:
+ case XFDASHBOARD_ANCHOR_POINT_NORTH:
+ case XFDASHBOARD_ANCHOR_POINT_SOUTH:
+ offset-=(textureWidth/2.0f);
+ break;
+
+ /* Align to right boundary */
+ case XFDASHBOARD_ANCHOR_POINT_EAST:
+ case XFDASHBOARD_ANCHOR_POINT_NORTH_EAST:
+ case XFDASHBOARD_ANCHOR_POINT_SOUTH_EAST:
+ offset-=textureWidth;
+ break;
+ }
+
+ /* Set boundary in X axis */
+ textureAllocationBox.x1=outlineBox.x1+offset;
+ textureAllocationBox.x2=textureAllocationBox.x1+textureWidth;
+
+ /* Clip texture in X axis if it does not fit into allocation */
+ if(textureAllocationBox.x1<outlineBox.x1)
+ {
+ oversize=outlineBox.x1-textureAllocationBox.x1;
+ textureCoordBox.x1=oversize/textureWidth;
+ textureAllocationBox.x1=outlineBox.x1;
+ }
+
+ if(textureAllocationBox.x2>outlineBox.x2)
+ {
+ oversize=textureAllocationBox.x2-outlineBox.x2;
+ textureCoordBox.x2=1.0f-(oversize/textureWidth);
+ textureAllocationBox.x2=outlineBox.x2;
+ }
+ }
+
+ /* Determine left and right boundary of unmapped window icon
+ * if unmapped window icon should not expand in X axis.
+ */
+ if(!priv->unmappedWindowIconYFill)
+ {
+ gfloat offset;
+ gfloat textureHeight;
+ gfloat oversize;
+
+ /* Get scaled width of unmapped window icon */
+ textureHeight=cogl_texture_get_height(priv->texture);
+ textureHeight*=priv->unmappedWindowIconYScale;
+
+ /* Get boundary in Y axis depending on gravity and scaled width */
+ offset=(priv->unmappedWindowIconYAlign*allocationHeight);
+ switch(priv->unmappedWindowIconAnchorPoint)
+ {
+ /* Align to upper boundary.
+ * This is also the default if gravity is none or undefined.
+ */
+ default:
+ case XFDASHBOARD_ANCHOR_POINT_NONE:
+ case XFDASHBOARD_ANCHOR_POINT_NORTH:
+ case XFDASHBOARD_ANCHOR_POINT_NORTH_WEST:
+ case XFDASHBOARD_ANCHOR_POINT_NORTH_EAST:
+ break;
+
+ /* Align to center of Y axis */
+ case XFDASHBOARD_ANCHOR_POINT_CENTER:
+ case XFDASHBOARD_ANCHOR_POINT_WEST:
+ case XFDASHBOARD_ANCHOR_POINT_EAST:
+ offset-=(textureHeight/2.0f);
+ break;
+
+ /* Align to lower boundary */
+ case XFDASHBOARD_ANCHOR_POINT_SOUTH:
+ case XFDASHBOARD_ANCHOR_POINT_SOUTH_WEST:
+ case XFDASHBOARD_ANCHOR_POINT_SOUTH_EAST:
+ offset-=textureHeight;
+ break;
+ }
+
+ /* Set boundary in Y axis */
+ textureAllocationBox.y1=outlineBox.y1+offset;
+ textureAllocationBox.y2=textureAllocationBox.y1+textureHeight;
+
+ /* Clip texture in Y axis if it does not fit into allocation */
+ if(textureAllocationBox.y1<outlineBox.y1)
+ {
+ oversize=outlineBox.y1-textureAllocationBox.y1;
+ textureCoordBox.y1=oversize/textureHeight;
+ textureAllocationBox.y1=outlineBox.y1;
+ }
+
+ if(textureAllocationBox.y2>outlineBox.y2)
+ {
+ oversize=textureAllocationBox.y2-outlineBox.y2;
+ textureCoordBox.y2=1.0f-(oversize/textureHeight);
+ textureAllocationBox.y2=outlineBox.y2;
+ }
+ }
+ }
+
+ /* Set up paint nodes for texture */
+ node=clutter_texture_node_new(priv->texture, &color, minFilter, magFilter);
+ clutter_paint_node_set_name(node, G_OBJECT_TYPE_NAME(self));
+ clutter_paint_node_add_texture_rectangle(node,
+ &textureAllocationBox,
+ textureCoordBox.x1,
+ textureCoordBox.y1,
+ textureCoordBox.x2,
+ textureCoordBox.y2);
+ clutter_paint_node_add_child(inRootNode, node);
+ clutter_paint_node_unref(node);
+
+ /* Draw outline (color is depending is texture is fallback or not.
+ * That should be done last to get outline always visible
+ */
+ if(priv->isFallback || priv->outlineColor==NULL)
+ {
+ outlineColor.red=0xff;
+ outlineColor.green=0xff;
+ outlineColor.blue=0xff;
+ outlineColor.alpha=opacity;
+ }
+ else
+ {
+ outlineColor.red=priv->outlineColor->red;
+ outlineColor.green=priv->outlineColor->green;
+ outlineColor.blue=priv->outlineColor->blue;
+ outlineColor.alpha=opacity;
+ }
+
+ node=clutter_color_node_new(&outlineColor);
+ clutter_paint_node_set_name(node, "outline-top");
+ clutter_actor_box_init_rect(&outlinePath, outlineBox.x1, 0.0f, outlineBox.x2-outlineBox.x1, priv->outlineWidth);
+ clutter_paint_node_add_rectangle(node, &outlinePath);
+ clutter_paint_node_add_child(inRootNode, node);
+ clutter_paint_node_unref(node);
+
+ node=clutter_color_node_new(&outlineColor);
+ clutter_paint_node_set_name(node, "outline-bottom");
+ clutter_actor_box_init_rect(&outlinePath, outlineBox.x1, outlineBox.y2-priv->outlineWidth, outlineBox.x2-outlineBox.x1, priv->outlineWidth);
+ clutter_paint_node_add_rectangle(node, &outlinePath);
+ clutter_paint_node_add_child(inRootNode, node);
+ clutter_paint_node_unref(node);
+
+ node=clutter_color_node_new(&outlineColor);
+ clutter_paint_node_set_name(node, "outline-left");
+ clutter_actor_box_init_rect(&outlinePath, outlineBox.x1, outlineBox.y1, priv->outlineWidth, outlineBox.y2-outlineBox.y1);
+ clutter_paint_node_add_rectangle(node, &outlinePath);
+ clutter_paint_node_add_child(inRootNode, node);
+ clutter_paint_node_unref(node);
+
+ node=clutter_color_node_new(&outlineColor);
+ clutter_paint_node_set_name(node, "outline-right");
+ clutter_actor_box_init_rect(&outlinePath, outlineBox.x2-priv->outlineWidth, outlineBox.y1, priv->outlineWidth, outlineBox.y2-outlineBox.y1);
+ clutter_paint_node_add_rectangle(node, &outlinePath);
+ clutter_paint_node_add_child(inRootNode, node);
+ clutter_paint_node_unref(node);
+}
+
+/* Get preferred size of texture */
+static gboolean _xdashboard_window_content_clutter_content_iface_get_preferred_size(ClutterContent *inContent,
+ gfloat *outWidth,
+ gfloat *outHeight)
+{
+ XfdashboardWindowContentGDKPrivate *priv=XFDASHBOARD_WINDOW_CONTENT_GDK(inContent)->priv;
+ gfloat w, h;
+
+ /* No texture - no size to retrieve */
+ if(priv->texture==NULL) return(FALSE);
+
+ /* If window is suspended or if we use the fallback image
+ * get real window size ...
+ */
+ if(priv->isFallback || priv->isSuspended)
+ {
+ /* Is a fallback texture so get real window size */
+ gint windowW, windowH;
+
+ xfdashboard_window_tracker_window_get_geometry(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window), NULL, NULL, &windowW, &windowH);
+ w=windowW;
+ h=windowH;
+ }
+ else
+ {
+ /* ... otherwise get size of texture */
+ w=cogl_texture_get_width(priv->texture);
+ h=cogl_texture_get_height(priv->texture);
+ }
+
+ /* Set result values */
+ if(outWidth) *outWidth=w;
+ if(outHeight) *outHeight=h;
+
+ return(TRUE);
+}
+
+/* Initialize interface of type ClutterContent */
+static void _xfdashboard_window_content_clutter_content_iface_init(ClutterContentIface *iface)
+{
+ iface->get_preferred_size=_xdashboard_window_content_clutter_content_iface_get_preferred_size;
+ iface->paint_content=_xdashboard_window_content_clutter_content_iface_paint_content;
+}
+
+/* IMPLEMENTATION: Interface XfdashboardStylable */
+
+/* Get stylable properties of stage */
+static void _xfdashboard_window_content_gdk_stylable_get_stylable_properties(XfdashboardStylable *self,
+ GHashTable *ioStylableProperties)
+{
+ g_return_if_fail(XFDASHBOARD_IS_STYLABLE(self));
+
+ /* Add stylable properties to hashtable */
+ xfdashboard_stylable_add_stylable_property(self, ioStylableProperties, "include-window-frame");
+ xfdashboard_stylable_add_stylable_property(self, ioStylableProperties, "unmapped-window-icon-x-fill");
+ xfdashboard_stylable_add_stylable_property(self, ioStylableProperties, "unmapped-window-icon-y-fill");
+ xfdashboard_stylable_add_stylable_property(self, ioStylableProperties, "unmapped-window-icon-x-align");
+ xfdashboard_stylable_add_stylable_property(self, ioStylableProperties, "unmapped-window-icon-y-align");
+ xfdashboard_stylable_add_stylable_property(self, ioStylableProperties, "unmapped-window-icon-x-scale");
+ xfdashboard_stylable_add_stylable_property(self, ioStylableProperties, "unmapped-window-icon-y-scale");
+ xfdashboard_stylable_add_stylable_property(self, ioStylableProperties, "unmapped-window-icon-anchor-point");
+}
+
+/* Get/set style classes of stage */
+static const gchar* _xfdashboard_window_content_gdk_stylable_get_classes(XfdashboardStylable *inStylable)
+{
+ /* Not implemented */
+ return(NULL);
+}
+
+static void _xfdashboard_window_content_gdk_stylable_set_classes(XfdashboardStylable *inStylable, const gchar *inStyleClasses)
+{
+ /* Not implemented */
+}
+
+/* Get/set style pseudo-classes of stage */
+static const gchar* _xfdashboard_window_content_gdk_stylable_get_pseudo_classes(XfdashboardStylable *inStylable)
+{
+ /* Not implemented */
+ return(NULL);
+}
+
+static void _xfdashboard_window_content_gdk_stylable_set_pseudo_classes(XfdashboardStylable *inStylable, const gchar *inStylePseudoClasses)
+{
+ /* Not implemented */
+}
+
+/* Interface initialization
+ * Set up default functions
+ */
+void _xfdashboard_window_content_gdk_stylable_iface_init(XfdashboardStylableInterface *iface)
+{
+ iface->get_stylable_properties=_xfdashboard_window_content_gdk_stylable_get_stylable_properties;
+ iface->get_classes=_xfdashboard_window_content_gdk_stylable_get_classes;
+ iface->set_classes=_xfdashboard_window_content_gdk_stylable_set_classes;
+ iface->get_pseudo_classes=_xfdashboard_window_content_gdk_stylable_get_pseudo_classes;
+ iface->set_pseudo_classes=_xfdashboard_window_content_gdk_stylable_set_pseudo_classes;
+}
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_content_gdk_dispose(GObject *inObject)
+{
+ XfdashboardWindowContentGDK *self=XFDASHBOARD_WINDOW_CONTENT_GDK(inObject);
+ XfdashboardWindowContentGDKPrivate *priv=self->priv;
+
+ /* Dispose allocated resources */
+ gdk_window_remove_filter(NULL, _xfdashboard_window_content_gdk_on_gdk_event, self);
+
+ _xfdashboard_window_content_gdk_release_resources(self);
+
+ if(priv->workaroundStateSignalID)
+ {
+ g_signal_handler_disconnect(priv->windowTracker, priv->workaroundStateSignalID);
+ priv->workaroundStateSignalID=0;
+
+ /* This signal was still connected to the window tracker so the window may be unminized
+ * and need to ensure it is minimized again. We need to do this now, before we release
+ * our handle to the window (priv->window).
+ */
+ xfdashboard_window_tracker_window_hide(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window));
+ }
+
+ if(priv->windowTracker)
+ {
+ g_signal_handlers_disconnect_by_data(priv->windowTracker, self);
+ g_object_unref(priv->windowTracker);
+ priv->windowTracker=NULL;
+ }
+
+ if(priv->window)
+ {
+ /* Disconnect signals */
+ g_signal_handlers_disconnect_by_data(priv->window, self);
+
+ /* libwnck resources should never be freed. Just set to NULL */
+ priv->window=NULL;
+ }
+
+ if(priv->suspendSignalID)
+ {
+ g_signal_handler_disconnect(xfdashboard_application_get_default(), priv->suspendSignalID);
+ priv->suspendSignalID=0;
+ }
+
+ if(priv->outlineColor)
+ {
+ clutter_color_free(priv->outlineColor);
+ priv->outlineColor=NULL;
+ }
+
+ if(priv->styleClasses)
+ {
+ g_free(priv->styleClasses);
+ priv->styleClasses=NULL;
+ }
+
+ if(priv->stylePseudoClasses)
+ {
+ g_free(priv->stylePseudoClasses);
+ priv->stylePseudoClasses=NULL;
+ }
+
+ /* Call parent's class dispose method */
+ G_OBJECT_CLASS(xfdashboard_window_content_gdk_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_content_gdk_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowContentGDK *self=XFDASHBOARD_WINDOW_CONTENT_GDK(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_WINDOW:
+ _xfdashboard_window_content_gdk_set_window(self, XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(g_value_get_object(inValue)));
+ break;
+
+ case PROP_OUTLINE_COLOR:
+ xfdashboard_window_content_gdk_set_outline_color(self, clutter_value_get_color(inValue));
+ break;
+
+ case PROP_OUTLINE_WIDTH:
+ xfdashboard_window_content_gdk_set_outline_width(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_INCLUDE_WINDOW_FRAME:
+ xfdashboard_window_content_gdk_set_include_window_frame(self, g_value_get_boolean(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_FILL:
+ xfdashboard_window_content_gdk_set_unmapped_window_icon_x_fill(self, g_value_get_boolean(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_FILL:
+ xfdashboard_window_content_gdk_set_unmapped_window_icon_y_fill(self, g_value_get_boolean(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_ALIGN:
+ xfdashboard_window_content_gdk_set_unmapped_window_icon_x_align(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_ALIGN:
+ xfdashboard_window_content_gdk_set_unmapped_window_icon_y_align(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_SCALE:
+ xfdashboard_window_content_gdk_set_unmapped_window_icon_x_scale(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_SCALE:
+ xfdashboard_window_content_gdk_set_unmapped_window_icon_y_scale(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_ANCHOR_POINT:
+ xfdashboard_window_content_gdk_set_unmapped_window_icon_anchor_point(self, g_value_get_enum(inValue));
+ break;
+
+ case PROP_STYLE_CLASSES:
+ _xfdashboard_window_content_gdk_stylable_set_classes(XFDASHBOARD_STYLABLE(self), g_value_get_string(inValue));
+ break;
+
+ case PROP_STYLE_PSEUDO_CLASSES:
+ _xfdashboard_window_content_gdk_stylable_set_pseudo_classes(XFDASHBOARD_STYLABLE(self), g_value_get_string(inValue));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+static void _xfdashboard_window_content_gdk_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowContentGDK *self=XFDASHBOARD_WINDOW_CONTENT_GDK(inObject);
+ XfdashboardWindowContentGDKPrivate *priv=self->priv;
+
+ switch(inPropID)
+ {
+ case PROP_WINDOW:
+ g_value_set_object(outValue, priv->window);
+ break;
+
+ case PROP_SUSPENDED:
+ g_value_set_boolean(outValue, priv->isSuspended);
+ break;
+
+ case PROP_OUTLINE_COLOR:
+ clutter_value_set_color(outValue, priv->outlineColor);
+ break;
+
+ case PROP_OUTLINE_WIDTH:
+ g_value_set_float(outValue, priv->outlineWidth);
+ break;
+
+ case PROP_INCLUDE_WINDOW_FRAME:
+ g_value_set_boolean(outValue, priv->includeWindowFrame);
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_FILL:
+ g_value_set_boolean(outValue, priv->unmappedWindowIconXFill);
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_FILL:
+ g_value_set_boolean(outValue, priv->unmappedWindowIconYFill);
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_ALIGN:
+ g_value_set_float(outValue, priv->unmappedWindowIconXAlign);
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_ALIGN:
+ g_value_set_float(outValue, priv->unmappedWindowIconYAlign);
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_SCALE:
+ g_value_set_float(outValue, priv->unmappedWindowIconXScale);
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_SCALE:
+ g_value_set_float(outValue, priv->unmappedWindowIconYScale);
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_ANCHOR_POINT:
+ g_value_set_enum(outValue, priv->unmappedWindowIconAnchorPoint);
+ break;
+
+ case PROP_STYLE_CLASSES:
+ g_value_set_string(outValue, priv->styleClasses);
+ break;
+
+ case PROP_STYLE_PSEUDO_CLASSES:
+ g_value_set_string(outValue, priv->stylePseudoClasses);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+/* Class initialization
+ * Override functions in parent classes and define properties
+ * and signals
+ */
+void xfdashboard_window_content_gdk_class_init(XfdashboardWindowContentGDKClass *klass)
+{
+ GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
+ XfdashboardStylableInterface *stylableIface;
+ GParamSpec *paramSpec;
+
+ /* Override functions */
+ gobjectClass->dispose=_xfdashboard_window_content_gdk_dispose;
+ gobjectClass->set_property=_xfdashboard_window_content_gdk_set_property;
+ gobjectClass->get_property=_xfdashboard_window_content_gdk_get_property;
+
+ stylableIface=g_type_default_interface_ref(XFDASHBOARD_TYPE_STYLABLE);
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowContentGDKPrivate));
+
+ /* Define properties */
+ XfdashboardWindowContentGDKProperties[PROP_WINDOW]=
+ g_param_spec_object("window",
+ _("Window"),
+ _("The window to handle and display"),
+ XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+
+ XfdashboardWindowContentGDKProperties[PROP_SUSPENDED]=
+ g_param_spec_boolean("suspended",
+ _("Suspended"),
+ _("Is this window suspended"),
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_OUTLINE_COLOR]=
+ clutter_param_spec_color("outline-color",
+ _("Outline color"),
+ _("Color to draw outline of mapped windows with"),
+ CLUTTER_COLOR_Black,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_OUTLINE_WIDTH]=
+ g_param_spec_float("outline-width",
+ _("Outline width"),
+ _("Width of line used to draw outline of mapped windows"),
+ 0.0f, G_MAXFLOAT,
+ 1.0f,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_INCLUDE_WINDOW_FRAME]=
+ g_param_spec_boolean("include-window-frame",
+ _("Include window frame"),
+ _("Whether the window frame should be included or only the window content should be shown"),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_X_FILL]=
+ g_param_spec_boolean("unmapped-window-icon-x-fill",
+ _("Unmapped window icon X fill"),
+ _("Whether the unmapped window icon should fill up horizontal space"),
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_Y_FILL]=
+ g_param_spec_boolean("unmapped-window-icon-y-fill",
+ _("Unmapped window icon y fill"),
+ _("Whether the unmapped window icon should fill up vertical space"),
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_X_ALIGN]=
+ g_param_spec_float("unmapped-window-icon-x-align",
+ _("Unmapped window icon X align"),
+ _("The alignment of the unmapped window icon on the X axis within the allocation in normalized coordinate between 0 and 1"),
+ 0.0f, 1.0f,
+ 0.0f,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_Y_ALIGN]=
+ g_param_spec_float("unmapped-window-icon-y-align",
+ _("Unmapped window icon Y align"),
+ _("The alignment of the unmapped window icon on the Y axis within the allocation in normalized coordinate between 0 and 1"),
+ 0.0f, 1.0f,
+ 0.0f,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_X_SCALE]=
+ g_param_spec_float("unmapped-window-icon-x-scale",
+ _("Unmapped window icon X scale"),
+ _("Scale factor of unmapped window icon on the X axis"),
+ 0.0f, G_MAXFLOAT,
+ 1.0f,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_Y_SCALE]=
+ g_param_spec_float("unmapped-window-icon-y-scale",
+ _("Unmapped window icon Y scale"),
+ _("Scale factor of unmapped window icon on the Y axis"),
+ 0.0f, G_MAXFLOAT,
+ 1.0f,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_ANCHOR_POINT]=
+ g_param_spec_enum("unmapped-window-icon-anchor-point",
+ _("Unmapped window icon anchor point"),
+ _("The anchor point of unmapped window icon"),
+ XFDASHBOARD_TYPE_ANCHOR_POINT,
+ XFDASHBOARD_ANCHOR_POINT_NONE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ paramSpec=g_object_interface_find_property(stylableIface, "style-classes");
+ XfdashboardWindowContentGDKProperties[PROP_STYLE_CLASSES]=
+ g_param_spec_override("style-classes", paramSpec);
+
+ paramSpec=g_object_interface_find_property(stylableIface, "style-pseudo-classes");
+ XfdashboardWindowContentGDKProperties[PROP_STYLE_PSEUDO_CLASSES]=
+ g_param_spec_override("style-pseudo-classes", paramSpec);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowContentGDKProperties);
+
+ /* Release allocated resources */
+ g_type_default_interface_unref(stylableIface);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_window_content_gdk_init(XfdashboardWindowContentGDK *self)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+ XfdashboardApplication *app;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_CONTENT_GDK_GET_PRIVATE(self);
+
+ /* Set default values */
+ priv->window=NULL;
+ priv->texture=NULL;
+ priv->xWindowID=None;
+ priv->pixmap=None;
+#ifdef HAVE_XDAMAGE
+ priv->damage=None;
+#endif
+ priv->isFallback=FALSE;
+ priv->outlineColor=clutter_color_copy(CLUTTER_COLOR_Black);
+ priv->outlineWidth=1.0f;
+ priv->isSuspended=TRUE;
+ priv->suspendSignalID=0;
+ priv->isMapped=FALSE;
+ priv->includeWindowFrame=FALSE;
+ priv->styleClasses=NULL;
+ priv->stylePseudoClasses=NULL;
+ priv->windowTracker=xfdashboard_window_tracker_get_default();
+ priv->workaroundMode=XFDASHBOARD_WINDOW_CONTENT_GDK_WORKAROUND_MODE_NONE;
+ priv->workaroundStateSignalID=0;
+ priv->unmappedWindowIconXFill=FALSE;
+ priv->unmappedWindowIconYFill=FALSE;
+ priv->unmappedWindowIconXAlign=0.0f;
+ priv->unmappedWindowIconYAlign=0.0f;
+ priv->unmappedWindowIconXScale=1.0f;
+ priv->unmappedWindowIconYScale=1.0f;
+ priv->unmappedWindowIconAnchorPoint=XFDASHBOARD_ANCHOR_POINT_NONE;
+ priv->suspendAfterResumeOnIdle=FALSE;
+
+ /* Check extensions (will only be done once) */
+ _xfdashboard_window_content_gdk_check_extension();
+
+ /* Add event filter for this instance */
+ gdk_window_add_filter(NULL, _xfdashboard_window_content_gdk_on_gdk_event, self);
+
+ /* Style content */
+ xfdashboard_stylable_invalidate(XFDASHBOARD_STYLABLE(self));
+
+ /* Handle suspension signals from application */
+ app=xfdashboard_application_get_default();
+ priv->suspendSignalID=g_signal_connect_swapped(app,
+ "notify::is-suspended",
+ G_CALLBACK(_xfdashboard_window_content_gdk_on_application_suspended_changed),
+ self);
+ priv->isAppSuspended=xfdashboard_application_is_suspended(app);
+
+ /* Register global signal handler for xfconf value change notification
+ * if not done already.
+ */
+ if(!_xfdashboard_window_content_gdk_xfconf_priority_notify_id)
+ {
+ XfconfChannel *xfconfChannel;
+ gchar *detailedSignal;
+
+ /* Connect to property changed signal in xfconf */
+ xfconfChannel=xfdashboard_application_get_xfconf_channel(NULL);
+ detailedSignal=g_strconcat("property-changed::", WINDOW_CONTENT_CREATION_PRIORITY_XFCONF_PROP, NULL);
+ _xfdashboard_window_content_gdk_xfconf_priority_notify_id=g_signal_connect(xfconfChannel,
+ detailedSignal,
+ G_CALLBACK(_xfdashboard_window_content_gdk_on_window_creation_priority_value_changed),
+ NULL);
+ if(detailedSignal) g_free(detailedSignal);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Connected to property changed signal with handler ID %u for xfconf value change notifications",
+ _xfdashboard_window_content_gdk_xfconf_priority_notify_id);
+
+ /* Connect to application shutdown signal for xfconf value change notification */
+ _xfdashboard_window_content_gdk_window_creation_shutdown_signal_id=g_signal_connect(app,
+ "shutdown-final",
+ G_CALLBACK(_xfdashboard_window_content_gdk_on_window_creation_priority_shutdown),
+ NULL);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Connected to shutdown signal with handler ID %u for xfconf value change notifications",
+ _xfdashboard_window_content_gdk_window_creation_shutdown_signal_id);
+ }
+}
+
+/* IMPLEMENTATION: Public API */
+
+/* Create new instance */
+ClutterContent* xfdashboard_window_content_gdk_new_for_window(XfdashboardWindowTrackerWindowGDK *inWindow)
+{
+ ClutterContent *content;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ /* Create window content */
+ content=CLUTTER_CONTENT(g_object_new(XFDASHBOARD_TYPE_WINDOW_CONTENT_GDK,
+ "window", inWindow,
+ NULL));
+
+ return(content);
+}
+
+/* Get window to handle and to display */
+XfdashboardWindowTrackerWindow* xfdashboard_window_content_gdk_get_window(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), NULL);
+
+ return(XFDASHBOARD_WINDOW_TRACKER_WINDOW(self->priv->window));
+}
+
+/* Get state of suspension */
+gboolean xfdashboard_window_content_gdk_is_suspended(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), TRUE);
+
+ return(self->priv->isSuspended);
+}
+
+/* Get/set color to draw outline with */
+const ClutterColor* xfdashboard_window_content_gdk_get_outline_color(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), NULL);
+
+ return(self->priv->outlineColor);
+}
+
+void xfdashboard_window_content_gdk_set_outline_color(XfdashboardWindowContentGDK *self, const ClutterColor *inColor)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inColor);
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->outlineColor==NULL || clutter_color_equal(inColor, priv->outlineColor)==FALSE)
+ {
+ /* Set value */
+ if(priv->outlineColor) clutter_color_free(priv->outlineColor);
+ priv->outlineColor=clutter_color_copy(inColor);
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_OUTLINE_COLOR]);
+ }
+}
+
+/* Get/set line width for outline */
+gfloat xfdashboard_window_content_gdk_get_outline_width(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), 0.0f);
+
+ return(self->priv->outlineWidth);
+}
+
+void xfdashboard_window_content_gdk_set_outline_width(XfdashboardWindowContentGDK *self, const gfloat inWidth)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inWidth>=0.0f);
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->outlineWidth!=inWidth)
+ {
+ /* Set value */
+ priv->outlineWidth=inWidth;
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_OUTLINE_WIDTH]);
+ }
+}
+
+/* Get/set flag to indicate whether to include the window frame or not */
+gboolean xfdashboard_window_content_gdk_get_include_window_frame(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), TRUE);
+
+ return(self->priv->includeWindowFrame);
+}
+
+void xfdashboard_window_content_gdk_set_include_window_frame(XfdashboardWindowContentGDK *self, const gboolean inIncludeFrame)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->includeWindowFrame!=inIncludeFrame)
+ {
+ /* Set value */
+ priv->includeWindowFrame=inIncludeFrame;
+
+ /* (Re-)Setup window content */
+ if(priv->window)
+ {
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ /* Re-setup window by releasing all resources first and unsetting window
+ * but remember window to set it again.
+ */
+ _xfdashboard_window_content_gdk_release_resources(self);
+
+ /* libwnck resources should never be freed. Just set to NULL */
+ window=priv->window;
+ priv->window=NULL;
+
+ /* Now set same window again which causes this object to set up all
+ * needed X resources again.
+ */
+ _xfdashboard_window_content_gdk_set_window(self, window);
+ }
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_INCLUDE_WINDOW_FRAME]);
+ }
+}
+
+/* Get/set x fill of unmapped window icon */
+gboolean xfdashboard_window_content_gdk_get_unmapped_window_icon_x_fill(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), FALSE);
+
+ return(self->priv->unmappedWindowIconXFill);
+}
+
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_x_fill(XfdashboardWindowContentGDK *self, const gboolean inFill)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->unmappedWindowIconXFill!=inFill)
+ {
+ /* Set value */
+ priv->unmappedWindowIconXFill=inFill;
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_X_FILL]);
+ }
+}
+
+/* Get/set y fill of unmapped window icon */
+gboolean xfdashboard_window_content_gdk_get_unmapped_window_icon_y_fill(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), FALSE);
+
+ return(self->priv->unmappedWindowIconYFill);
+}
+
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_y_fill(XfdashboardWindowContentGDK *self, const gboolean inFill)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->unmappedWindowIconYFill!=inFill)
+ {
+ /* Set value */
+ priv->unmappedWindowIconYFill=inFill;
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_Y_FILL]);
+ }
+}
+
+/* Get/set x align of unmapped window icon */
+gfloat xfdashboard_window_content_gdk_get_unmapped_window_icon_x_align(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), 0.0f);
+
+ return(self->priv->unmappedWindowIconXAlign);
+}
+
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_x_align(XfdashboardWindowContentGDK *self, const gfloat inAlign)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inAlign>=0.0f && inAlign<=1.0f);
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->unmappedWindowIconXAlign!=inAlign)
+ {
+ /* Set value */
+ priv->unmappedWindowIconXAlign=inAlign;
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_X_ALIGN]);
+ }
+}
+
+/* Get/set y align of unmapped window icon */
+gfloat xfdashboard_window_content_gdk_get_unmapped_window_icon_y_align(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), 0.0f);
+
+ return(self->priv->unmappedWindowIconYAlign);
+}
+
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_y_align(XfdashboardWindowContentGDK *self, const gfloat inAlign)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inAlign>=0.0f && inAlign<=1.0f);
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->unmappedWindowIconYAlign!=inAlign)
+ {
+ /* Set value */
+ priv->unmappedWindowIconYAlign=inAlign;
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_Y_ALIGN]);
+ }
+}
+
+/* Get/set x scale of unmapped window icon */
+gfloat xfdashboard_window_content_gdk_get_unmapped_window_icon_x_scale(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), 0.0f);
+
+ return(self->priv->unmappedWindowIconXScale);
+}
+
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_x_scale(XfdashboardWindowContentGDK *self, const gfloat inScale)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inScale>=0.0f);
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->unmappedWindowIconXScale!=inScale)
+ {
+ /* Set value */
+ priv->unmappedWindowIconXScale=inScale;
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_X_SCALE]);
+ }
+}
+
+/* Get/set y scale of unmapped window icon */
+gfloat xfdashboard_window_content_gdk_get_unmapped_window_icon_y_scale(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), 0.0f);
+
+ return(self->priv->unmappedWindowIconYScale);
+}
+
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_y_scale(XfdashboardWindowContentGDK *self, const gfloat inScale)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inScale>=0.0f);
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->unmappedWindowIconYScale!=inScale)
+ {
+ /* Set value */
+ priv->unmappedWindowIconYScale=inScale;
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_Y_SCALE]);
+ }
+}
+
+/* Get/set gravity (anchor point) of unmapped window icon */
+XfdashboardAnchorPoint xfdashboard_window_content_gdk_get_unmapped_window_icon_anchor_point(XfdashboardWindowContentGDK *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self), XFDASHBOARD_ANCHOR_POINT_NONE);
+
+ return(self->priv->unmappedWindowIconAnchorPoint);
+}
+
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_anchor_point(XfdashboardWindowContentGDK *self, const XfdashboardAnchorPoint inAnchorPoint)
+{
+ XfdashboardWindowContentGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_GDK(self));
+ g_return_if_fail(inAnchorPoint>=XFDASHBOARD_ANCHOR_POINT_NONE);
+ g_return_if_fail(inAnchorPoint<=XFDASHBOARD_ANCHOR_POINT_CENTER);
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->unmappedWindowIconAnchorPoint!=inAnchorPoint)
+ {
+ /* Set value */
+ priv->unmappedWindowIconAnchorPoint=inAnchorPoint;
+
+ /* Invalidate ourselve to get us redrawn */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentGDKProperties[PROP_UNMAPPED_WINDOW_ICON_ANCHOR_POINT]);
+ }
+}
diff --git a/libxfdashboard/gdk/window-content-gdk.h b/libxfdashboard/gdk/window-content-gdk.h
new file mode 100644
index 0000000..985cb00
--- /dev/null
+++ b/libxfdashboard/gdk/window-content-gdk.h
@@ -0,0 +1,111 @@
+/*
+ * window-content: A content to share texture of a window
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifndef __LIBXFDASHBOARD_WINDOW_CONTENT_GDK__
+#define __LIBXFDASHBOARD_WINDOW_CONTENT_GDK__
+
+#if !defined(__LIBXFDASHBOARD_H_INSIDE__) && !defined(LIBXFDASHBOARD_COMPILATION)
+#error "Only <libxfdashboard/libxfdashboard.h> can be included directly."
+#endif
+
+#include <clutter/clutter.h>
+
+#include <libxfdashboard/gdk/window-tracker-window-gdk.h>
+#include <libxfdashboard/window-tracker-window.h>
+#include <libxfdashboard/types.h>
+
+G_BEGIN_DECLS
+
+#define XFDASHBOARD_TYPE_WINDOW_CONTENT_GDK (xfdashboard_window_content_gdk_get_type())
+#define XFDASHBOARD_WINDOW_CONTENT_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_CONTENT_GDK, XfdashboardWindowContentGDK))
+#define XFDASHBOARD_IS_WINDOW_CONTENT_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_CONTENT_GDK))
+#define XFDASHBOARD_WINDOW_CONTENT_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_CONTENT_GDK, XfdashboardWindowContentGDKClass))
+#define XFDASHBOARD_IS_WINDOW_CONTENT_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_CONTENT_GDK))
+#define XFDASHBOARD_WINDOW_CONTENT_GDK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_CONTENT_GDK, XfdashboardWindowContentGDKClass))
+
+typedef struct _XfdashboardWindowContentGDK XfdashboardWindowContentGDK;
+typedef struct _XfdashboardWindowContentGDKClass XfdashboardWindowContentGDKClass;
+typedef struct _XfdashboardWindowContentGDKPrivate XfdashboardWindowContentGDKPrivate;
+
+struct _XfdashboardWindowContentGDK
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowContentGDKPrivate *priv;
+};
+
+struct _XfdashboardWindowContentGDKClass
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+};
+
+/* Public API */
+GType xfdashboard_window_content_gdk_get_type(void) G_GNUC_CONST;
+
+ClutterContent* xfdashboard_window_content_gdk_new_for_window(XfdashboardWindowTrackerWindowGDK *inWindow);
+
+XfdashboardWindowTrackerWindow* xfdashboard_window_content_gdk_get_window(XfdashboardWindowContentGDK *self);
+
+gboolean xfdashboard_window_content_gdk_is_suspended(XfdashboardWindowContentGDK *self);
+
+const ClutterColor* xfdashboard_window_content_gdk_get_outline_color(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_outline_color(XfdashboardWindowContentGDK *self, const ClutterColor *inColor);
+
+gfloat xfdashboard_window_content_gdk_get_outline_width(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_outline_width(XfdashboardWindowContentGDK *self, const gfloat inWidth);
+
+gboolean xfdashboard_window_content_gdk_get_include_window_frame(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_include_window_frame(XfdashboardWindowContentGDK *self, const gboolean inIncludeFrame);
+
+gboolean xfdashboard_window_content_gdk_get_unmapped_window_icon_x_fill(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_x_fill(XfdashboardWindowContentGDK *self, const gboolean inFill);
+
+gboolean xfdashboard_window_content_gdk_get_unmapped_window_icon_y_fill(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_y_fill(XfdashboardWindowContentGDK *self, const gboolean inFill);
+
+gfloat xfdashboard_window_content_gdk_get_unmapped_window_icon_x_align(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_x_align(XfdashboardWindowContentGDK *self, const gfloat inAlign);
+
+gfloat xfdashboard_window_content_gdk_get_unmapped_window_icon_y_align(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_y_align(XfdashboardWindowContentGDK *self, const gfloat inAlign);
+
+gfloat xfdashboard_window_content_gdk_get_unmapped_window_icon_x_scale(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_x_scale(XfdashboardWindowContentGDK *self, const gfloat inScale);
+
+gfloat xfdashboard_window_content_gdk_get_unmapped_window_icon_y_scale(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_y_scale(XfdashboardWindowContentGDK *self, const gfloat inScale);
+
+XfdashboardAnchorPoint xfdashboard_window_content_gdk_get_unmapped_window_icon_anchor_point(XfdashboardWindowContentGDK *self);
+void xfdashboard_window_content_gdk_set_unmapped_window_icon_anchor_point(XfdashboardWindowContentGDK *self, const XfdashboardAnchorPoint inAnchorPoint);
+
+G_END_DECLS
+
+#endif
diff --git a/libxfdashboard/gdk/window-tracker-gdk.c b/libxfdashboard/gdk/window-tracker-gdk.c
new file mode 100644
index 0000000..f51b699
--- /dev/null
+++ b/libxfdashboard/gdk/window-tracker-gdk.c
@@ -0,0 +1,2100 @@
+/*
+ * window-tracker: Tracks windows, workspaces, monitors and
+ * listens for changes. It also bundles libwnck into one
+ * class.
+ * By wrapping libwnck objects we can use a virtual
+ * stable API while the API in libwnck changes within versions.
+ * We only need to use #ifdefs in window tracker object
+ * and nowhere else in the code.
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libxfdashboard/gdk/window-tracker-gdk.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+#include <glib/gi18n-lib.h>
+#include <clutter/clutter.h>
+#include <clutter/gdk/clutter-gdk.h>
+#include <clutter/x11/clutter-x11.h>
+#include <gdk/gdkx.h>
+#ifdef HAVE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
+#include <libxfdashboard/window-tracker.h>
+#include <libxfdashboard/gdk/window-tracker-monitor-gdk.h>
+#include <libxfdashboard/gdk/window-tracker-window-gdk.h>
+#include <libxfdashboard/gdk/window-tracker-workspace-gdk.h>
+#include <libxfdashboard/marshal.h>
+#include <libxfdashboard/application.h>
+#include <libxfdashboard/compat.h>
+#include <libxfdashboard/debug.h>
+
+
+/* Define this class in GObject system */
+static void _xfdashboard_window_tracker_gdk_window_tracker_iface_init(XfdashboardWindowTrackerInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerGDK,
+ xfdashboard_window_tracker_gdk,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER, _xfdashboard_window_tracker_gdk_window_tracker_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_TRACKER_GDK_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_GDK, XfdashboardWindowTrackerGDKPrivate))
+
+struct _XfdashboardWindowTrackerGDKPrivate
+{
+ /* Properties related */
+ XfdashboardWindowTrackerWindowGDK *activeWindow;
+ XfdashboardWindowTrackerWorkspaceGDK *activeWorkspace;
+ XfdashboardWindowTrackerMonitorGDK *primaryMonitor;
+
+ /* Instance related */
+ GList *windows;
+ GList *windowsStacked;
+ GList *workspaces;
+ GList *monitors;
+
+ XfdashboardApplication *application;
+ gboolean isAppSuspended;
+ guint suspendSignalID;
+
+ WnckScreen *screen;
+
+ gboolean supportsMultipleMonitors;
+ GdkScreen *gdkScreen;
+#if GTK_CHECK_VERSION(3, 22, 0)
+ GdkDisplay *gdkDisplay;
+ gboolean needScreenSizeUpdate;
+ gint screenWidth, screenHeight;
+#endif
+};
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ /* Overriden properties of interface: XfdashboardWindowTracker */
+ PROP_ACTIVE_WINDOW,
+ PROP_ACTIVE_WORKSPACE,
+ PROP_PRIMARY_MONITOR,
+
+ PROP_LAST
+};
+
+static GParamSpec* XfdashboardWindowTrackerGDKProperties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+
+/* Free workspace object */
+static void _xfdashboard_window_tracker_gdk_free_workspace(XfdashboardWindowTrackerGDK *self,
+ XfdashboardWindowTrackerWorkspaceGDK *inWorkspace)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ GList *iter;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace));
+
+ priv=self->priv;
+
+#if DEBUG
+ /* There must be only one reference on that workspace object */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Freeing workspace %s@%p named '%s' with ref-count=%d",
+ G_OBJECT_TYPE_NAME(inWorkspace), inWorkspace,
+ xfdashboard_window_tracker_workspace_get_name(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE(inWorkspace)),
+ G_OBJECT(inWorkspace)->ref_count);
+ g_assert(G_OBJECT(inWorkspace)->ref_count==1);
+#endif
+
+ /* Find entry in workspace list and remove it if found */
+ iter=g_list_find(priv->workspaces, inWorkspace);
+ if(iter)
+ {
+ priv->workspaces=g_list_delete_link(priv->workspaces, iter);
+ }
+
+ /* Free workspace object */
+ g_object_unref(inWorkspace);
+}
+
+/* Get workspace object for requested wnck workspace */
+static XfdashboardWindowTrackerWorkspaceGDK* _xfdashboard_window_tracker_gdk_get_workspace_for_wnck(XfdashboardWindowTrackerGDK *self,
+ WnckWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ GList *iter;
+ XfdashboardWindowTrackerWorkspaceGDK *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self), NULL);
+ g_return_val_if_fail(WNCK_IS_WORKSPACE(inWorkspace), NULL);
+
+ priv=self->priv;
+
+ /* Iterate through list of workspace object and check if an object for the
+ * request wnck workspace exist. If one is found then return this existing
+ * workspace object.
+ */
+ for(iter=priv->workspaces; iter; iter=g_list_next(iter))
+ {
+ /* Get currently iterated workspace object */
+ workspace=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(iter->data);
+ if(!workspace) continue;
+
+ /* Check if this workspace object wraps the requested wnck workspace */
+ if(xfdashboard_window_tracker_workspace_gdk_get_workspace(workspace)==inWorkspace)
+ {
+ /* Return existing workspace object */
+ return(workspace);
+ }
+ }
+
+ /* If we get here, return NULL as we have not found a matching workspace
+ * object for the requested wnck workspace.
+ */
+ return(NULL);
+}
+
+/* Create workspace object which must not exist yet */
+static XfdashboardWindowTrackerWorkspaceGDK* _xfdashboard_window_tracker_gdk_create_workspace_for_wnck(XfdashboardWindowTrackerGDK *self,
+ WnckWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ XfdashboardWindowTrackerWorkspaceGDK *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self), NULL);
+ g_return_val_if_fail(WNCK_IS_WORKSPACE(inWorkspace), NULL);
+
+ priv=self->priv;
+
+ /* Iterate through list of workspace object and check if an object for the
+ * request wnck workspace exist. If one is found then the existing workspace object.
+ */
+ workspace=_xfdashboard_window_tracker_gdk_get_workspace_for_wnck(self, inWorkspace);
+ if(workspace)
+ {
+ /* Return existing workspace object */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "A workspace object %s@%p for wnck workspace %s@%p named '%s' exists already",
+ G_OBJECT_TYPE_NAME(workspace), workspace,
+ G_OBJECT_TYPE_NAME(inWorkspace), inWorkspace, wnck_workspace_get_name(inWorkspace));
+
+ return(workspace);
+ }
+
+ /* Create workspace object */
+ workspace=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(g_object_new(XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK,
+ "workspace", inWorkspace,
+ NULL));
+ if(!workspace)
+ {
+ g_critical(_("Could not create workspace object of type %s for workspace '%s'"),
+ g_type_name(XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK),
+ wnck_workspace_get_name(inWorkspace));
+ return(NULL);
+ }
+
+ /* Add new workspace object to list of workspace objects */
+ priv->workspaces=g_list_prepend(priv->workspaces, workspace);
+
+ /* Return new workspace object */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Created workspace object %s@%p for wnck workspace %s@%p named '%s'",
+ G_OBJECT_TYPE_NAME(workspace), workspace,
+ G_OBJECT_TYPE_NAME(inWorkspace), inWorkspace, wnck_workspace_get_name(inWorkspace));
+ return(workspace);
+}
+
+/* Free window object */
+static void _xfdashboard_window_tracker_gdk_free_window(XfdashboardWindowTrackerGDK *self,
+ XfdashboardWindowTrackerWindowGDK *inWindow)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ GList *iter;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ priv=self->priv;
+
+#if DEBUG
+ /* There must be only one reference on that window object */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Freeing window %s@%p named '%s' with ref-count=%d",
+ G_OBJECT_TYPE_NAME(inWindow), inWindow,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(inWindow)),
+ G_OBJECT(inWindow)->ref_count);
+ g_assert(G_OBJECT(inWindow)->ref_count==1);
+#endif
+
+ /* Find entry in window lists and remove it if found */
+ iter=g_list_find(priv->windows, inWindow);
+ if(iter)
+ {
+ priv->windows=g_list_delete_link(priv->windows, iter);
+ }
+
+ iter=g_list_find(priv->windowsStacked, inWindow);
+ if(iter)
+ {
+ priv->windowsStacked=g_list_delete_link(priv->windowsStacked, iter);
+ }
+
+ /* Free window object */
+ g_object_unref(inWindow);
+}
+
+/* Get window object for requested wnck window */
+static XfdashboardWindowTrackerWindowGDK* _xfdashboard_window_tracker_gdk_get_window_for_wnck(XfdashboardWindowTrackerGDK *self,
+ WnckWindow *inWindow)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ GList *iter;
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self), NULL);
+ g_return_val_if_fail(WNCK_IS_WINDOW(inWindow), NULL);
+
+ priv=self->priv;
+
+ /* Iterate through list of window object and check if an object for the
+ * request wnck window exist. If one is found then return this existing
+ * window object.
+ */
+ for(iter=priv->windows; iter; iter=g_list_next(iter))
+ {
+ /* Get currently iterated window object */
+ if(!XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(iter->data)) continue;
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(iter->data);
+ if(!window) continue;
+
+ /* Check if this window object wraps the requested wnck window */
+ if(xfdashboard_window_tracker_window_gdk_get_window(window)==inWindow)
+ {
+ /* Return existing window object */
+ return(window);
+ }
+ }
+
+ /* If we get here, return NULL as we have not found a matching window
+ * object for the requested wnck window.
+ */
+ return(NULL);
+}
+
+/* Build correctly ordered list of windows in stacked order. The list will not
+ * take a reference at the window object and must not be unreffed if list is
+ * freed.
+ */
+static void _xfdashboard_window_tracker_gdk_build_stacked_windows_list(XfdashboardWindowTrackerGDK *self)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ GList *wnckWindowsStacked;
+ GList *newWindowsStacked;
+ GList *iter;
+ WnckWindow *wnckWindow;
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+
+ priv=self->priv;
+
+ /* Get list of stacked windows from wnck */
+ wnckWindowsStacked=wnck_screen_get_windows_stacked(priv->screen);
+
+ /* Build new list of stacked windows containing window objects */
+ newWindowsStacked=NULL;
+ for(iter=wnckWindowsStacked; iter; iter=g_list_next(iter))
+ {
+ /* Get wnck window iterated */
+ wnckWindow=WNCK_WINDOW(iter->data);
+ if(!wnckWindow) continue;
+
+ /* Lookup window object from wnck window iterated */
+ window=_xfdashboard_window_tracker_gdk_get_window_for_wnck(self, wnckWindow);
+ if(window)
+ {
+ newWindowsStacked=g_list_prepend(newWindowsStacked, window);
+ }
+ }
+ newWindowsStacked=g_list_reverse(newWindowsStacked);
+
+ /* Release old stacked windows list */
+ g_list_free(priv->windowsStacked);
+ priv->windowsStacked=newWindowsStacked;
+}
+
+/* Create window object which must not exist yet */
+static XfdashboardWindowTrackerWindowGDK* _xfdashboard_window_tracker_gdk_create_window_for_wnck(XfdashboardWindowTrackerGDK *self,
+ WnckWindow *inWindow)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self), NULL);
+ g_return_val_if_fail(WNCK_IS_WINDOW(inWindow), NULL);
+
+ priv=self->priv;
+
+ /* Iterate through list of window object and check if an object for the
+ * request wnck window exist. If one is found then the existing window object.
+ */
+ window=_xfdashboard_window_tracker_gdk_get_window_for_wnck(self, inWindow);
+ if(window)
+ {
+ /* Return existing window object */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "A window object %s@%p for wnck window %s@%p named '%s' exists already",
+ G_OBJECT_TYPE_NAME(window), window,
+ G_OBJECT_TYPE_NAME(inWindow), inWindow, wnck_window_get_name(inWindow));
+
+ return(window);
+ }
+
+ /* Create window object */
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(g_object_new(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK,
+ "window", inWindow,
+ NULL));
+ if(!window)
+ {
+ g_critical(_("Could not create window object of type %s for window '%s'"),
+ g_type_name(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK),
+ wnck_window_get_name(inWindow));
+ return(NULL);
+ }
+
+ /* Add new window object to list of window objects */
+ priv->windows=g_list_prepend(priv->windows, window);
+
+ /* Assume window stacking changed to get correctly ordered list of windows */
+ _xfdashboard_window_tracker_gdk_build_stacked_windows_list(self);
+
+ /* Return new window object */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Created window object %s@%p for wnck window %s@%p named '%s'",
+ G_OBJECT_TYPE_NAME(window), window,
+ G_OBJECT_TYPE_NAME(inWindow), inWindow, wnck_window_get_name(inWindow));
+ return(window);
+}
+
+/* Position and/or size of window has changed */
+static void _xfdashboard_window_tracker_gdk_on_window_geometry_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' changed position and/or size",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window)));
+ g_signal_emit_by_name(self, "window-geometry-changed", window);
+}
+
+/* Action items of window has changed */
+static void _xfdashboard_window_tracker_gdk_on_window_actions_changed(XfdashboardWindowTrackerGDK *self,
+ XfdashboardWindowTrackerWindowAction inChangedMask,
+ XfdashboardWindowTrackerWindowAction inNewValue,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' changed actions to %u with mask %u",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window)),
+ inNewValue, inChangedMask);
+ g_signal_emit_by_name(self, "window-actions-changed", window);
+}
+
+/* State of window has changed */
+static void _xfdashboard_window_tracker_gdk_on_window_state_changed(XfdashboardWindowTrackerGDK *self,
+ XfdashboardWindowTrackerWindowState inChangedMask,
+ XfdashboardWindowTrackerWindowState inNewValue,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' changed state to %u with mask %u",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window)),
+ inNewValue, inChangedMask);
+ g_signal_emit_by_name(self, "window-state-changed", window);
+}
+
+/* Icon of window has changed */
+static void _xfdashboard_window_tracker_gdk_on_window_icon_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' changed its icon",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window)));
+ g_signal_emit_by_name(self, "window-icon-changed", window);
+}
+
+/* Name of window has changed */
+static void _xfdashboard_window_tracker_gdk_on_window_name_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window changed its name to '%s'",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window)));
+ g_signal_emit_by_name(self, "window-name-changed", window);
+}
+
+/* A window has moved to another monitor */
+static void _xfdashboard_window_tracker_gdk_on_window_monitor_changed(XfdashboardWindowTrackerGDK *self,
+ XfdashboardWindowTrackerMonitor *inOldMonitor,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDK *window;
+ XfdashboardWindowTrackerMonitor *newMonitor;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(!inOldMonitor || XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(inOldMonitor));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ /* Get monitor window resides on. */
+ newMonitor=xfdashboard_window_tracker_window_get_monitor(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window));
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' moved from monitor %d (%s) to %d (%s)",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window)),
+ inOldMonitor ? xfdashboard_window_tracker_monitor_get_number(inOldMonitor) : -1,
+ (inOldMonitor && xfdashboard_window_tracker_monitor_is_primary(inOldMonitor)) ? "primary" : "non-primary",
+ newMonitor ? xfdashboard_window_tracker_monitor_get_number(newMonitor) : -1,
+ (newMonitor && xfdashboard_window_tracker_monitor_is_primary(newMonitor)) ? "primary" : "non-primary");
+ g_signal_emit_by_name(self, "window-monitor-changed", window, inOldMonitor, newMonitor);
+}
+
+/* A window has moved to another workspace */
+static void _xfdashboard_window_tracker_gdk_on_window_workspace_changed(XfdashboardWindowTrackerGDK *self,
+ XfdashboardWindowTrackerWorkspace *inOldWorkspace,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDK *window;
+ XfdashboardWindowTrackerWorkspace *newWorkspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(!inOldWorkspace || XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inOldWorkspace));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ /* Get workspace window resides on. */
+ newWorkspace=xfdashboard_window_tracker_window_get_workspace(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window));
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' moved to workspace %d (%s)",
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window)),
+ newWorkspace ? xfdashboard_window_tracker_workspace_get_number(newWorkspace) : -1,
+ newWorkspace ? xfdashboard_window_tracker_workspace_get_name(newWorkspace) : "<nil>");
+ g_signal_emit_by_name(self, "window-workspace-changed", window, newWorkspace);
+}
+
+/* A window was activated */
+static void _xfdashboard_window_tracker_gdk_on_active_window_changed(XfdashboardWindowTrackerGDK *self,
+ WnckWindow *inPreviousWindow,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ WnckScreen *screen;
+ XfdashboardWindowTrackerWindowGDK *oldActiveWindow;
+ XfdashboardWindowTrackerWindowGDK *newActiveWindow;
+ WnckWindow *activeWindow;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(inPreviousWindow==NULL || WNCK_IS_WINDOW(inPreviousWindow));
+ g_return_if_fail(WNCK_IS_SCREEN(inUserData));
+
+ priv=self->priv;
+ screen=WNCK_SCREEN(inUserData);
+
+ /* Get and remember new active window */
+ oldActiveWindow=priv->activeWindow;
+
+ newActiveWindow=NULL;
+ activeWindow=wnck_screen_get_active_window(screen);
+ if(activeWindow)
+ {
+ newActiveWindow=_xfdashboard_window_tracker_gdk_get_window_for_wnck(self, activeWindow);
+ if(!newActiveWindow)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "No window object of type %s found for new active wnck window %s@%p named '%s'",
+ g_type_name(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK),
+ G_OBJECT_TYPE_NAME(activeWindow), activeWindow, wnck_window_get_name(activeWindow));
+
+ return;
+ }
+ }
+
+ priv->activeWindow=newActiveWindow;
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Active window changed from '%s' to '%s'",
+ oldActiveWindow ? xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(oldActiveWindow)) : "<nil>",
+ newActiveWindow ? xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(newActiveWindow)) : "<nil>");
+ g_signal_emit_by_name(self, "active-window-changed", oldActiveWindow, priv->activeWindow);
+}
+
+/* A window was closed */
+static void _xfdashboard_window_tracker_gdk_on_window_closed(XfdashboardWindowTrackerGDK *self,
+ WnckWindow *inWindow,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(WNCK_IS_WINDOW(inWindow));
+ g_return_if_fail(WNCK_IS_SCREEN(inUserData));
+
+ priv=self->priv;
+
+ /* Should not happen but if closed window is the last active known one, then
+ * reset to NULL
+ */
+ if(xfdashboard_window_tracker_window_gdk_get_window(priv->activeWindow)==inWindow)
+ {
+ priv->activeWindow=NULL;
+ }
+
+ /* Get window object for closed wnck window */
+ window=_xfdashboard_window_tracker_gdk_get_window_for_wnck(self, inWindow);
+ if(!window)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "No window object of type %s found for wnck window %s@%p named '%s'",
+ g_type_name(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK),
+ G_OBJECT_TYPE_NAME(inWindow), inWindow, wnck_window_get_name(inWindow));
+
+ return;
+ }
+
+ /* Remove all signal handlers for closed window */
+ g_signal_handlers_disconnect_by_data(window, self);
+
+ /* Emit signals */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' closed",
+ wnck_window_get_name(inWindow));
+ g_signal_emit_by_name(self, "window-closed", window);
+
+ /* Remove window from window list */
+ _xfdashboard_window_tracker_gdk_free_window(self, window);
+}
+
+/* A new window was opened */
+static void _xfdashboard_window_tracker_gdk_on_window_opened(XfdashboardWindowTrackerGDK *self,
+ WnckWindow *inWindow,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(WNCK_IS_WINDOW(inWindow));
+ g_return_if_fail(WNCK_IS_SCREEN(inUserData));
+
+ priv=self->priv;
+
+ /* Create window object */
+ window=_xfdashboard_window_tracker_gdk_create_window_for_wnck(self, inWindow);
+ if(!window) return;
+
+ /* Connect signals on newly opened window */
+ g_signal_connect_swapped(window, "actions-changed", G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_actions_changed), self);
+ g_signal_connect_swapped(window, "state-changed", G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_state_changed), self);
+ g_signal_connect_swapped(window, "icon-changed", G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_icon_changed), self);
+ g_signal_connect_swapped(window, "name-changed", G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_name_changed), self);
+ g_signal_connect_swapped(window, "monitor-changed", G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_monitor_changed), self);
+ g_signal_connect_swapped(window, "workspace-changed", G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_workspace_changed), self);
+ g_signal_connect_swapped(window, "geometry-changed", G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_geometry_changed), self);
+
+ /* Block signal handler for 'geometry-changed' at window if application is suspended */
+ if(priv->isAppSuspended)
+ {
+ g_signal_handlers_block_by_func(window, _xfdashboard_window_tracker_gdk_on_window_geometry_changed, self);
+ }
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' created",
+ wnck_window_get_name(inWindow));
+ g_signal_emit_by_name(self, "window-opened", window);
+}
+
+/* Window stacking has changed */
+static void _xfdashboard_window_tracker_gdk_on_window_stacking_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+
+ /* Before emitting the signal, build a correctly ordered list of windows */
+ _xfdashboard_window_tracker_gdk_build_stacked_windows_list(self);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS, "Window stacking has changed");
+ g_signal_emit_by_name(self, "window-stacking-changed");
+}
+
+/* A workspace changed its name */
+static void _xfdashboard_window_tracker_gdk_on_workspace_name_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inUserData));
+
+ workspace=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inUserData);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Workspace #%d changed name to '%s'",
+ xfdashboard_window_tracker_workspace_get_number(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE(workspace)),
+ xfdashboard_window_tracker_workspace_get_name(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE(workspace)));
+ g_signal_emit_by_name(self, "workspace-name-changed", workspace);
+
+}
+
+/* A workspace was activated */
+static void _xfdashboard_window_tracker_gdk_on_active_workspace_changed(XfdashboardWindowTrackerGDK *self,
+ WnckWorkspace *inPreviousWorkspace,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ WnckScreen *screen;
+ XfdashboardWindowTrackerWorkspaceGDK *oldActiveWorkspace;
+ XfdashboardWindowTrackerWorkspaceGDK *newActiveWorkspace;
+ WnckWorkspace *activeWorkspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(inPreviousWorkspace==NULL || WNCK_IS_WORKSPACE(inPreviousWorkspace));
+ g_return_if_fail(WNCK_IS_SCREEN(inUserData));
+
+ priv=self->priv;
+ screen=WNCK_SCREEN(inUserData);
+
+ /* Get and remember new active workspace */
+ oldActiveWorkspace=priv->activeWorkspace;
+
+ newActiveWorkspace=NULL;
+ activeWorkspace=wnck_screen_get_active_workspace(screen);
+ if(activeWorkspace)
+ {
+ newActiveWorkspace=_xfdashboard_window_tracker_gdk_get_workspace_for_wnck(self, activeWorkspace);
+ if(!newActiveWorkspace)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "No workspace object of type %s found for new active wnck workspace %s@%p named '%s'",
+ g_type_name(XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK),
+ G_OBJECT_TYPE_NAME(activeWorkspace), activeWorkspace, wnck_workspace_get_name(activeWorkspace));
+
+ return;
+ }
+ }
+
+ priv->activeWorkspace=newActiveWorkspace;
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Active workspace changed from #%d (%s) to #%d (%s)",
+ oldActiveWorkspace ? wnck_workspace_get_number(inPreviousWorkspace) : -1,
+ oldActiveWorkspace ? wnck_workspace_get_name(inPreviousWorkspace) : "<nil>",
+ priv->activeWorkspace ? wnck_workspace_get_number(activeWorkspace) : -1,
+ priv->activeWorkspace ? wnck_workspace_get_name(activeWorkspace) : "<nil>");
+ g_signal_emit_by_name(self, "active-workspace-changed", oldActiveWorkspace, priv->activeWorkspace);
+}
+
+/* A workspace was destroyed */
+static void _xfdashboard_window_tracker_gdk_on_workspace_destroyed(XfdashboardWindowTrackerGDK *self,
+ WnckWorkspace *inWorkspace,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ XfdashboardWindowTrackerWorkspaceGDK *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(WNCK_IS_WORKSPACE(inWorkspace));
+ g_return_if_fail(WNCK_IS_SCREEN(inUserData));
+
+ priv=self->priv;
+
+ /* Should not happen but if destroyed workspace is the last active known one,
+ * then reset to NULL
+ */
+ if(xfdashboard_window_tracker_workspace_gdk_get_workspace(priv->activeWorkspace)==inWorkspace)
+ {
+ priv->activeWorkspace=NULL;
+ }
+
+ /* Get workspace object for wnck workspace */
+ workspace=_xfdashboard_window_tracker_gdk_get_workspace_for_wnck(self, inWorkspace);
+ if(!workspace)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "No workspace object of type %s found for wnck workspace %s@%p named '%s'",
+ g_type_name(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK),
+ G_OBJECT_TYPE_NAME(inWorkspace), inWorkspace, wnck_workspace_get_name(inWorkspace));
+
+ return;
+ }
+
+ /* Remove all signal handlers for closed window */
+ g_signal_handlers_disconnect_by_data(workspace, self);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Workspace #%d (%s) destroyed",
+ wnck_workspace_get_number(inWorkspace),
+ wnck_workspace_get_name(inWorkspace));
+ g_signal_emit_by_name(self, "workspace-removed", workspace);
+
+ /* Remove workspace from workspace list */
+ _xfdashboard_window_tracker_gdk_free_workspace(self, workspace);
+}
+
+/* A new workspace was created */
+static void _xfdashboard_window_tracker_gdk_on_workspace_created(XfdashboardWindowTrackerGDK *self,
+ WnckWorkspace *inWorkspace,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(WNCK_IS_WORKSPACE(inWorkspace));
+ g_return_if_fail(WNCK_IS_SCREEN(inUserData));
+
+ /* Create workspace object */
+ workspace=_xfdashboard_window_tracker_gdk_create_workspace_for_wnck(self, inWorkspace);
+ if(!workspace) return;
+
+ /* Connect signals on newly created workspace */
+ g_signal_connect_swapped(workspace, "name-changed", G_CALLBACK(_xfdashboard_window_tracker_gdk_on_workspace_name_changed), self);
+
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "New workspace #%d (%s) created",
+ wnck_workspace_get_number(inWorkspace),
+ wnck_workspace_get_name(inWorkspace));
+ g_signal_emit_by_name(self, "workspace-added", workspace);
+}
+
+/* Primary monitor has changed */
+static void _xfdashboard_window_tracker_gdk_on_primary_monitor_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ XfdashboardWindowTrackerMonitorGDK *monitor;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(inUserData));
+
+ priv=self->priv;
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inUserData);
+
+ /* If monitor emitting this signal is the (new) primary one
+ * then update primary monitor value of this instance.
+ */
+ if(xfdashboard_window_tracker_monitor_is_primary(XFDASHBOARD_WINDOW_TRACKER_MONITOR(monitor)) &&
+ priv->primaryMonitor!=monitor)
+ {
+ XfdashboardWindowTrackerMonitorGDK *oldMonitor;
+
+ /* Remember old monitor for signal emission */
+ oldMonitor=priv->primaryMonitor;
+
+ /* Set value */
+ priv->primaryMonitor=monitor;
+
+ /* Emit signal */
+ g_signal_emit_by_name(self, "primary-monitor-changed", oldMonitor, priv->primaryMonitor);
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerGDKProperties[PROP_PRIMARY_MONITOR]);
+
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Primary monitor changed from %d to %d",
+ oldMonitor ? xfdashboard_window_tracker_monitor_get_number(XFDASHBOARD_WINDOW_TRACKER_MONITOR(oldMonitor)) : -1,
+ xfdashboard_window_tracker_monitor_get_number(XFDASHBOARD_WINDOW_TRACKER_MONITOR(monitor)));
+ }
+}
+
+/* A monitor has changed its position and/or size */
+static void _xfdashboard_window_tracker_gdk_on_monitor_geometry_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerMonitorGDK *monitor;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(inUserData));
+
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inUserData);
+
+ /* A monitor changed its position and/or size so re-emit the signal */
+ g_signal_emit_by_name(self, "monitor-geometry-changed", monitor);
+}
+
+/* Create a monitor object */
+static XfdashboardWindowTrackerMonitorGDK* _xfdashboard_window_tracker_gdk_monitor_new(XfdashboardWindowTrackerGDK *self,
+ guint inMonitorIndex)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ XfdashboardWindowTrackerMonitorGDK *monitor;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self), NULL);
+ g_return_val_if_fail(inMonitorIndex>=g_list_length(self->priv->monitors), NULL);
+
+ priv=self->priv;
+
+ /* Create monitor object */
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(g_object_new(XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_GDK,
+ "monitor-index", inMonitorIndex,
+ NULL));
+ priv->monitors=g_list_append(priv->monitors, monitor);
+
+ /* Connect signals */
+ g_signal_connect_swapped(monitor,
+ "primary-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_primary_monitor_changed),
+ self);
+ g_signal_connect_swapped(monitor,
+ "geometry-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_monitor_geometry_changed),
+ self);
+
+ /* Emit signal */
+ g_signal_emit_by_name(self, "monitor-added", monitor);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Monitor %d added",
+ inMonitorIndex);
+
+ /* If we newly added monitor is the primary one then emit signal. We could not
+ * have done it yet because the signals were connect to new monitor object
+ * after its creation.
+ */
+ if(xfdashboard_window_tracker_monitor_is_primary(XFDASHBOARD_WINDOW_TRACKER_MONITOR(monitor)))
+ {
+ _xfdashboard_window_tracker_gdk_on_primary_monitor_changed(self, monitor);
+ }
+
+ /* Return newly created monitor */
+ return(monitor);
+}
+
+/* Free a monitor object */
+static void _xfdashboard_window_tracker_gdk_monitor_free(XfdashboardWindowTrackerGDK *self,
+ XfdashboardWindowTrackerMonitorGDK *inMonitor)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ GList *iter;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(inMonitor));
+
+ priv=self->priv;
+
+ /* Find monitor to free */
+ iter=g_list_find(priv->monitors, inMonitor);
+ if(!iter)
+ {
+ g_critical(_("Cannot release unknown monitor %d"),
+ xfdashboard_window_tracker_monitor_get_number(XFDASHBOARD_WINDOW_TRACKER_MONITOR(inMonitor)));
+ return;
+ }
+
+ /* Disconnect signals */
+ g_signal_handlers_disconnect_by_data(inMonitor, self);
+
+ /* Emit signal */
+ g_signal_emit_by_name(self, "monitor-removed", inMonitor);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Monitor %d removed",
+ xfdashboard_window_tracker_monitor_get_number(XFDASHBOARD_WINDOW_TRACKER_MONITOR(inMonitor)));
+
+ /* Remove monitor object from list */
+ priv->monitors=g_list_delete_link(priv->monitors, iter);
+
+ /* Unref monitor object. Usually this is the last reference released
+ * and the object will be destroyed.
+ */
+ g_object_unref(inMonitor);
+}
+
+#ifdef HAVE_XINERAMA
+/* Number of monitors, primary monitor or size of any monitor changed */
+static void _xfdashboard_window_tracker_gdk_on_monitors_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ GdkScreen *screen;
+ gint currentMonitorCount;
+ gint newMonitorCount;
+ gint i;
+ XfdashboardWindowTrackerMonitorGDK *monitor;
+ GList *iter;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(GDK_IS_SCREEN(inUserData));
+
+ priv=self->priv;
+ screen=GDK_SCREEN(inUserData);
+
+ /* Get current monitor states */
+ currentMonitorCount=g_list_length(priv->monitors);
+
+ /* Get new monitor state */
+#if GTK_CHECK_VERSION(3, 22, 0)
+ newMonitorCount=gdk_display_get_n_monitors(gdk_screen_get_display(screen));
+#else
+ newMonitorCount=gdk_screen_get_n_monitors(screen);
+#endif
+ if(newMonitorCount!=currentMonitorCount)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Number of monitors changed from %d to %d",
+ currentMonitorCount,
+ newMonitorCount);
+ }
+
+ /* There is no need to check if size of any monitor has changed because
+ * XfdashboardWindowTrackerMonitor instances should also be connected to
+ * this signal and will raise a signal if their size changed. This instance
+ * is connected to this "monitor-has-changed-signal' and will re-emit them.
+ * The same is with primary monitor.
+ */
+
+ /* If number of monitors has increased create newly added monitors */
+ if(newMonitorCount>currentMonitorCount)
+ {
+ for(i=currentMonitorCount; i<newMonitorCount; i++)
+ {
+ /* Create monitor object */
+ _xfdashboard_window_tracker_gdk_monitor_new(self, i);
+ }
+ }
+
+ /* If number of monitors has decreased remove all monitors beyond
+ * the new number of monitors.
+ */
+ if(newMonitorCount<currentMonitorCount)
+ {
+ for(i=currentMonitorCount; i>newMonitorCount; i--)
+ {
+ /* Get monitor object */
+ iter=g_list_last(priv->monitors);
+ if(!iter) continue;
+
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(iter->data);
+
+ /* Free monitor object */
+ _xfdashboard_window_tracker_gdk_monitor_free(self, monitor);
+ }
+ }
+
+#if GTK_CHECK_VERSION(3, 22, 0)
+ /* Set flag to recalculate screen size which must have changed as monitors
+ * were added or removed.
+ */
+ priv->needScreenSizeUpdate=TRUE;
+#endif
+}
+#endif
+
+/* Total size of screen changed */
+static void _xfdashboard_window_tracker_gdk_on_screen_size_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ gint w, h;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+
+ priv=self->priv;
+
+ /* Get new total size of screen */
+ priv->needScreenSizeUpdate=TRUE;
+ xfdashboard_window_tracker_get_screen_size(XFDASHBOARD_WINDOW_TRACKER(self), &w, &h);
+
+ /* Emit signal to tell that screen size has changed */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Screen size changed to %dx%d",
+ w,
+ h);
+ g_signal_emit_by_name(self, "screen-size-changed");
+}
+
+/* Window manager has changed */
+static void _xfdashboard_window_tracker_gdk_on_window_manager_changed(XfdashboardWindowTrackerGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+
+ priv=self->priv;
+
+ /* Emit signal to tell that window manager has changed */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window manager changed to %s",
+ wnck_screen_get_window_manager_name(priv->screen));
+ g_signal_emit_by_name(self, "window-manager-changed");
+}
+
+/* Suspension state of application changed */
+static void _xfdashboard_window_tracker_gdk_on_application_suspended_changed(XfdashboardWindowTrackerGDK *self,
+ GParamSpec *inSpec,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ XfdashboardApplication *app;
+ GList *iter;
+ XfdashboardWindowTrackerWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_APPLICATION(inUserData));
+
+ priv=self->priv;
+ app=XFDASHBOARD_APPLICATION(inUserData);
+
+ /* Get application suspend state */
+ priv->isAppSuspended=xfdashboard_application_is_suspended(app);
+
+ /* Iterate through all windows and connect handler to signal 'geometry-changed'
+ * if application was resumed or disconnect signal handler if it was suspended.
+ */
+ for(iter=xfdashboard_window_tracker_get_windows(XFDASHBOARD_WINDOW_TRACKER(self)); iter; iter=g_list_next(iter))
+ {
+ /* Get window */
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW(iter->data);
+ if(!window) continue;
+
+ /* If application was suspended disconnect signal handlers ... */
+ if(priv->isAppSuspended)
+ {
+ g_signal_handlers_block_by_func(window, _xfdashboard_window_tracker_gdk_on_window_geometry_changed, self);
+ }
+ /* ... otherwise if application was resumed reconnect signals handlers
+ * and emit 'geometry-changed' signal to reflect latest changes of
+ * position and size of window.
+ */
+ else
+ {
+ /* Reconnect signal handler */
+ g_signal_handlers_unblock_by_func(window, _xfdashboard_window_tracker_gdk_on_window_geometry_changed, self);
+
+ /* Call signal handler to reflect latest changes */
+ _xfdashboard_window_tracker_gdk_on_window_geometry_changed(self, window);
+ }
+ }
+}
+
+
+/* IMPLEMENTATION: Interface XfdashboardWindowTracker */
+
+/* Get list of all windows (if wanted in stack order) */
+static GList* _xfdashboard_window_tracker_gdk_window_tracker_get_windows(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Return list of window objects created */
+ return(priv->windows);
+}
+
+/* Get list of all windows in stack order */
+static GList* _xfdashboard_window_tracker_gdk_window_tracker_get_windows_stacked(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Return list of window in stack order */
+ return(priv->windowsStacked);
+}
+
+/* Get active window */
+static XfdashboardWindowTrackerWindow* _xfdashboard_window_tracker_gdk_window_tracker_get_active_window(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ return(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->activeWindow));
+}
+
+/* Get number of workspaces */
+static gint _xfdashboard_window_tracker_gdk_window_tracker_get_workspaces_count(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Return number of workspaces */
+ return(wnck_screen_get_workspace_count(priv->screen));
+}
+
+/* Get list of workspaces */
+static GList* _xfdashboard_window_tracker_gdk_window_tracker_get_workspaces(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Return list of workspaces */
+ return(priv->workspaces);
+}
+
+/* Get active workspace */
+static XfdashboardWindowTrackerWorkspace* _xfdashboard_window_tracker_gdk_window_tracker_get_active_workspace(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ return(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE(priv->activeWorkspace));
+}
+
+/* Get workspace by number */
+static XfdashboardWindowTrackerWorkspace* _xfdashboard_window_tracker_gdk_window_tracker_get_workspace_by_number(XfdashboardWindowTracker *inWindowTracker,
+ gint inNumber)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ WnckWorkspace *wnckWorkspace;
+ XfdashboardWindowTrackerWorkspaceGDK *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ g_return_val_if_fail(inNumber>=0 && inNumber<wnck_screen_get_workspace_count(priv->screen), NULL);
+
+ /* Get wnck workspace by number */
+ wnckWorkspace=wnck_screen_get_workspace(priv->screen, inNumber);
+
+ /* Get workspace object for wnck workspace */
+ workspace=_xfdashboard_window_tracker_gdk_get_workspace_for_wnck(self, wnckWorkspace);
+ if(!workspace)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "No workspace object of type %s found for wnck workspace %s@%p named '%s'",
+ g_type_name(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK),
+ G_OBJECT_TYPE_NAME(wnckWorkspace), wnckWorkspace, wnck_workspace_get_name(wnckWorkspace));
+
+ return(NULL);
+ }
+
+ /* Return workspace object */
+ return(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE(workspace));
+}
+
+/* Determine if multiple monitors are supported */
+static gboolean _xfdashboard_window_tracker_gdk_window_tracker_supports_multiple_monitors(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ return(priv->supportsMultipleMonitors);
+}
+
+/* Get number of monitors */
+static gint _xfdashboard_window_tracker_gdk_window_tracker_get_monitors_count(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Return number of monitors */
+ return(g_list_length(priv->monitors));
+}
+
+/* Get list of monitors */
+static GList* _xfdashboard_window_tracker_gdk_window_tracker_get_monitors(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Return list of workspaces */
+ return(priv->monitors);
+}
+
+/* Get primary monitor */
+static XfdashboardWindowTrackerMonitor* _xfdashboard_window_tracker_gdk_window_tracker_get_primary_monitor(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ return(XFDASHBOARD_WINDOW_TRACKER_MONITOR(priv->primaryMonitor));
+}
+
+/* Get monitor by number */
+static XfdashboardWindowTrackerMonitor* _xfdashboard_window_tracker_gdk_window_tracker_get_monitor_by_number(XfdashboardWindowTracker *inWindowTracker,
+ gint inNumber)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ g_return_val_if_fail(inNumber>=0, NULL);
+ g_return_val_if_fail(((guint)inNumber)<g_list_length(priv->monitors), NULL);
+
+ /* Return monitor at index */
+ return(XFDASHBOARD_WINDOW_TRACKER_MONITOR(g_list_nth_data(priv->monitors, inNumber)));
+}
+
+/* Get monitor at requested position */
+static XfdashboardWindowTrackerMonitor* _xfdashboard_window_tracker_gdk_window_tracker_get_monitor_by_position(XfdashboardWindowTracker *inWindowTracker,
+ gint inX,
+ gint inY)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ GList *iter;
+ XfdashboardWindowTrackerMonitorGDK *monitor;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Iterate through monitors and return the one containing the requested position */
+ for(iter=priv->monitors; iter; iter=g_list_next(iter))
+ {
+ /* Get monitor at iterator */
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(iter->data);
+ if(!monitor) continue;
+
+ /* Check if this monitor contains the requested position. If it does
+ * then return it.
+ */
+ if(xfdashboard_window_tracker_monitor_contains(XFDASHBOARD_WINDOW_TRACKER_MONITOR(monitor), inX, inY))
+ {
+ return(XFDASHBOARD_WINDOW_TRACKER_MONITOR(monitor));
+ }
+ }
+
+ /* If we get here none of the monitors contains the requested position,
+ * so return NULL here.
+ */
+ return(NULL);
+}
+
+/* Get size of screen */
+static void _xfdashboard_window_tracker_gdk_window_tracker_get_screen_size(XfdashboardWindowTracker *inWindowTracker,
+ gint *outWidth,
+ gint *outHeight)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ gint width, height;
+#if GTK_CHECK_VERSION(3, 22, 0)
+ gint i;
+ gint numberMonitors;
+ GdkMonitor *monitor;
+ GdkRectangle monitorRect;
+ gint left, top, right, bottom;
+ gboolean forceUpdate;
+#endif
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+#if GTK_CHECK_VERSION(3, 22, 0)
+ /* Only recalculate screen size if flag is set */
+ if(priv->needScreenSizeUpdate)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS, "Screen size needs to be recalculated");
+
+ /* Get width and height of screen by iterating through all connected monitors
+ * and find the most top left and most right bottom point among all these
+ * monitors. Then calculate size of screen by these points.
+ */
+ forceUpdate=TRUE;
+ left=top=right=bottom=0;
+ numberMonitors=gdk_display_get_n_monitors(priv->gdkDisplay);
+ for(i=0; i<numberMonitors; i++)
+ {
+ monitor=gdk_display_get_monitor(priv->gdkDisplay, i);
+ gdk_monitor_get_geometry(monitor, &monitorRect);
+
+ if(forceUpdate || monitorRect.x<left) left=monitorRect.x;
+ if(forceUpdate || monitorRect.y<top) top=monitorRect.y;
+ if(forceUpdate || (monitorRect.x+monitorRect.width)>right) right=monitorRect.x+monitorRect.width;
+ if(forceUpdate || (monitorRect.y+monitorRect.height)>bottom) bottom=monitorRect.y+monitorRect.height;
+
+ /* The first monitor in list was processed so do not enforcing updating
+ * coordinates from now on except they are most-specific points.
+ */
+ forceUpdate=FALSE;
+
+ /* Debug message */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Iterating monitor %d of %d [%d,%dx%d,%d] for screen size calculation",
+ i, numberMonitors,
+ monitorRect.x, monitorRect.y,
+ monitorRect.width, monitorRect.height);
+ }
+
+ /* Calculate screen size */
+ priv->screenWidth=right-left;
+ priv->screenHeight=bottom-top;
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Screen size is %dx%d over all %d monitors covering area of [%d,%dx%d,%d]",
+ priv->screenWidth, priv->screenHeight,
+ numberMonitors,
+ left, top,
+ right, bottom);
+
+ /* Reset flag to avoid recalculation of screen size again and again */
+ priv->needScreenSizeUpdate=FALSE;
+ }
+
+ /* Get width and height of screen */
+ width=priv->screenWidth;
+ height=priv->screenHeight;
+#else
+ /* Get width and height of screen */
+ width=gdk_screen_get_width(priv->gdkScreen);
+ height=gdk_screen_get_height(priv->gdkScreen);
+#endif
+
+ /* Store result */
+ if(outWidth) *outWidth=width;
+ if(outHeight) *outHeight=height;
+}
+
+/* Get window manager name managing desktop environment */
+static const gchar* _xfdashboard_window_tracker_gdk_window_tracker_get_window_manager_name(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Get window manager name from libwnck and return */
+ return(wnck_screen_get_window_manager_name(priv->screen));
+
+}
+
+/* Get root (desktop) window */
+static XfdashboardWindowTrackerWindow* _xfdashboard_window_tracker_gdk_window_tracker_get_root_window(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerGDKPrivate *priv;
+ gulong backgroundWindowID;
+ GList *windows;
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+ priv=self->priv;
+
+ /* Find and return root window (the desktop) by known ID */
+ backgroundWindowID=wnck_screen_get_background_pixmap(priv->screen);
+ if(backgroundWindowID)
+ {
+ WnckWindow *backgroundWindow;
+
+ backgroundWindow=wnck_window_get(backgroundWindowID);
+ if(backgroundWindow)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Found desktop window %s@%p by known background pixmap ID",
+ G_OBJECT_TYPE_NAME(backgroundWindow), backgroundWindow);
+
+ /* Get or create window object for wnck background window */
+ window=_xfdashboard_window_tracker_gdk_create_window_for_wnck(self, backgroundWindow);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Resolved desktop window %s@%p to window object %s@%p",
+ G_OBJECT_TYPE_NAME(backgroundWindow), backgroundWindow,
+ G_OBJECT_TYPE_NAME(window), window);
+
+ /* Return window object found or created */
+ return(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window));
+ }
+ }
+
+ /* Either there was no known ID for the root window or the root window
+ * could not be found (happened a lot when running in daemon mode).
+ * So iterate through list of all known windows and lookup window of
+ * type 'desktop'.
+ */
+ for(windows=wnck_screen_get_windows(priv->screen); windows; windows=g_list_next(windows))
+ {
+ WnckWindow *wnckWindow;
+ WnckWindowType wnckWindowType;
+
+ wnckWindow=(WnckWindow*)windows->data;
+ wnckWindowType=wnck_window_get_window_type(wnckWindow);
+ if(wnckWindowType==WNCK_WINDOW_DESKTOP)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Desktop window %s@%p found while iterating through window list",
+ G_OBJECT_TYPE_NAME(wnckWindow), wnckWindow);
+
+ /* Get or create window object for wnck background window */
+ window=_xfdashboard_window_tracker_gdk_create_window_for_wnck(self, wnckWindow);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Resolved desktop window %s@%p to window object %s@%p",
+ G_OBJECT_TYPE_NAME(wnckWindow), wnckWindow,
+ G_OBJECT_TYPE_NAME(window), window);
+
+ /* Return window object found or created */
+ return(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window));
+ }
+ }
+
+ /* If we get here either desktop window does not exist or is not known
+ * in window list. So return NULL here.
+ */
+ XFDASHBOARD_DEBUG(self, WINDOWS, "Desktop window could not be found");
+ return(NULL);
+}
+
+/* Get window of stage */
+static XfdashboardWindowTrackerWindow* _xfdashboard_window_tracker_gdk_window_tracker_get_stage_window(XfdashboardWindowTracker *inWindowTracker,
+ ClutterStage *inStage)
+{
+ XfdashboardWindowTrackerGDK *self;
+ GdkWindow *stageGdkWindow;
+ Window stageXWindow;
+ WnckWindow *wnckWindow;
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inWindowTracker), NULL);
+ g_return_val_if_fail(CLUTTER_IS_STAGE(inStage), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inWindowTracker);
+
+ /* Get stage window and translate to needed window type */
+ stageGdkWindow=clutter_gdk_get_stage_window(inStage);
+ stageXWindow=gdk_x11_window_get_xid(stageGdkWindow);
+ wnckWindow=wnck_window_get(stageXWindow);
+
+ /* Get or create window object for wnck background window */
+ window=_xfdashboard_window_tracker_gdk_create_window_for_wnck(self, wnckWindow);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Resolved stage window %s@%p to window object %s@%p",
+ G_OBJECT_TYPE_NAME(wnckWindow), wnckWindow,
+ G_OBJECT_TYPE_NAME(window), window);
+
+ return(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window));
+}
+
+/* Interface initialization
+ * Set up default functions
+ */
+static void _xfdashboard_window_tracker_gdk_window_tracker_iface_init(XfdashboardWindowTrackerInterface *iface)
+{
+ iface->get_windows=_xfdashboard_window_tracker_gdk_window_tracker_get_windows;
+ iface->get_windows_stacked=_xfdashboard_window_tracker_gdk_window_tracker_get_windows_stacked;
+ iface->get_active_window=_xfdashboard_window_tracker_gdk_window_tracker_get_active_window;
+
+ iface->get_workspaces_count=_xfdashboard_window_tracker_gdk_window_tracker_get_workspaces_count;
+ iface->get_workspaces=_xfdashboard_window_tracker_gdk_window_tracker_get_workspaces;
+ iface->get_active_workspace=_xfdashboard_window_tracker_gdk_window_tracker_get_active_workspace;
+ iface->get_workspace_by_number=_xfdashboard_window_tracker_gdk_window_tracker_get_workspace_by_number;
+
+ iface->supports_multiple_monitors=_xfdashboard_window_tracker_gdk_window_tracker_supports_multiple_monitors;
+ iface->get_monitors_count=_xfdashboard_window_tracker_gdk_window_tracker_get_monitors_count;
+ iface->get_monitors=_xfdashboard_window_tracker_gdk_window_tracker_get_monitors;
+ iface->get_primary_monitor=_xfdashboard_window_tracker_gdk_window_tracker_get_primary_monitor;
+ iface->get_monitor_by_number=_xfdashboard_window_tracker_gdk_window_tracker_get_monitor_by_number;
+ iface->get_monitor_by_position=_xfdashboard_window_tracker_gdk_window_tracker_get_monitor_by_position;
+
+ iface->get_screen_size=_xfdashboard_window_tracker_gdk_window_tracker_get_screen_size;
+
+ iface->get_window_manager_name=_xfdashboard_window_tracker_gdk_window_tracker_get_window_manager_name;
+
+ iface->get_root_window=_xfdashboard_window_tracker_gdk_window_tracker_get_root_window;
+ iface->get_stage_window=_xfdashboard_window_tracker_gdk_window_tracker_get_stage_window;
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_tracker_gdk_dispose_free_window(gpointer inData,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inData));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inUserData));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inUserData);
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inData);
+
+ /* Unreference window */
+ _xfdashboard_window_tracker_gdk_free_window(self, window);
+}
+
+static void _xfdashboard_window_tracker_gdk_dispose_free_workspace(gpointer inData,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerWorkspaceGDK *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inData));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inUserData));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inUserData);
+ workspace=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inData);
+
+ /* Unreference workspace */
+ _xfdashboard_window_tracker_gdk_free_workspace(self, workspace);
+}
+
+static void _xfdashboard_window_tracker_gdk_dispose_free_monitor(gpointer inData,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerGDK *self;
+ XfdashboardWindowTrackerMonitorGDK *monitor;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(inData));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(inUserData));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_GDK(inUserData);
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inData);
+
+ /* Unreference monitor */
+ _xfdashboard_window_tracker_gdk_monitor_free(self, monitor);
+}
+
+static void _xfdashboard_window_tracker_gdk_dispose(GObject *inObject)
+{
+ XfdashboardWindowTrackerGDK *self=XFDASHBOARD_WINDOW_TRACKER_GDK(inObject);
+ XfdashboardWindowTrackerGDKPrivate *priv=self->priv;
+
+ /* Dispose allocated resources */
+ if(priv->suspendSignalID)
+ {
+ if(priv->application)
+ {
+ g_signal_handler_disconnect(priv->application, priv->suspendSignalID);
+ priv->application=NULL;
+ }
+
+ priv->suspendSignalID=0;
+ }
+
+ if(priv->activeWindow)
+ {
+ priv->activeWindow=NULL;
+ }
+
+ if(priv->windows)
+ {
+ g_list_foreach(priv->windows, _xfdashboard_window_tracker_gdk_dispose_free_window, self);
+ g_list_free(priv->windows);
+ priv->windows=NULL;
+ }
+
+ if(priv->windowsStacked)
+ {
+ g_list_free(priv->windowsStacked);
+ priv->windowsStacked=NULL;
+ }
+
+ if(priv->activeWorkspace)
+ {
+ priv->activeWorkspace=NULL;
+ }
+
+ if(priv->workspaces)
+ {
+ g_list_foreach(priv->workspaces, _xfdashboard_window_tracker_gdk_dispose_free_workspace, self);
+ g_list_free(priv->workspaces);
+ priv->workspaces=NULL;
+ }
+
+ if(priv->primaryMonitor)
+ {
+ priv->primaryMonitor=NULL;
+ }
+
+ if(priv->monitors)
+ {
+ g_list_foreach(priv->monitors, _xfdashboard_window_tracker_gdk_dispose_free_monitor, self);
+ g_list_free(priv->monitors);
+ priv->monitors=NULL;
+ }
+
+ if(priv->gdkScreen)
+ {
+ g_signal_handlers_disconnect_by_data(priv->gdkScreen, self);
+ priv->gdkScreen=NULL;
+ }
+
+#if GTK_CHECK_VERSION(3, 22, 0)
+ if(priv->gdkDisplay)
+ {
+ g_signal_handlers_disconnect_by_data(priv->gdkDisplay, self);
+ priv->gdkDisplay=NULL;
+ }
+#endif
+
+ if(priv->screen)
+ {
+ g_signal_handlers_disconnect_by_data(priv->screen, self);
+ priv->screen=NULL;
+ }
+
+ /* Call parent's class dispose method */
+ G_OBJECT_CLASS(xfdashboard_window_tracker_gdk_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_tracker_gdk_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ switch(inPropID)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+static void _xfdashboard_window_tracker_gdk_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerGDK *self=XFDASHBOARD_WINDOW_TRACKER_GDK(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_ACTIVE_WINDOW:
+ g_value_set_object(outValue, self->priv->activeWindow);
+ break;
+
+ case PROP_ACTIVE_WORKSPACE:
+ g_value_set_object(outValue, self->priv->activeWorkspace);
+ break;
+
+ case PROP_PRIMARY_MONITOR:
+ g_value_set_object(outValue, self->priv->primaryMonitor);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+/* Class initialization
+ * Override functions in parent classes and define properties
+ * and signals
+ */
+void xfdashboard_window_tracker_gdk_class_init(XfdashboardWindowTrackerGDKClass *klass)
+{
+ GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
+ XfdashboardWindowTracker *trackerIface;
+ GParamSpec *paramSpec;
+
+ /* Reference interface type to lookup properties etc. */
+ trackerIface=g_type_default_interface_ref(XFDASHBOARD_TYPE_WINDOW_TRACKER);
+
+ /* Override functions */
+ gobjectClass->dispose=_xfdashboard_window_tracker_gdk_dispose;
+ gobjectClass->set_property=_xfdashboard_window_tracker_gdk_set_property;
+ gobjectClass->get_property=_xfdashboard_window_tracker_gdk_get_property;
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowTrackerGDKPrivate));
+
+ /* Define properties */
+ paramSpec=g_object_interface_find_property(trackerIface, "active-window");
+ XfdashboardWindowTrackerGDKProperties[PROP_ACTIVE_WINDOW]=
+ g_param_spec_override("active-window", paramSpec);
+
+ paramSpec=g_object_interface_find_property(trackerIface, "active-workspace");
+ XfdashboardWindowTrackerGDKProperties[PROP_ACTIVE_WORKSPACE]=
+ g_param_spec_override("active-workspace", paramSpec);
+
+ paramSpec=g_object_interface_find_property(trackerIface, "primary-monitor");
+ XfdashboardWindowTrackerGDKProperties[PROP_PRIMARY_MONITOR]=
+ g_param_spec_override("primary-monitor", paramSpec);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowTrackerGDKProperties);
+
+ /* Release allocated resources */
+ g_type_default_interface_unref(trackerIface);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_window_tracker_gdk_init(XfdashboardWindowTrackerGDK *self)
+{
+ XfdashboardWindowTrackerGDKPrivate *priv;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_TRACKER_GDK_GET_PRIVATE(self);
+
+ XFDASHBOARD_DEBUG(self, WINDOWS, "Initializing window tracker");
+
+ /* Set default values */
+ priv->windows=NULL;
+ priv->windowsStacked=NULL;
+ priv->workspaces=NULL;
+ priv->monitors=NULL;
+ priv->screen=wnck_screen_get_default();
+#if GTK_CHECK_VERSION(3, 22, 0)
+ priv->gdkDisplay=gdk_display_get_default();
+ priv->gdkScreen=gdk_display_get_default_screen(priv->gdkDisplay);
+ priv->needScreenSizeUpdate=TRUE;
+ priv->screenWidth=0;
+ priv->screenHeight=0;
+#else
+ priv->gdkScreen=gdk_screen_get_default();
+#endif
+ priv->activeWindow=NULL;
+ priv->activeWorkspace=NULL;
+ priv->primaryMonitor=NULL;
+ priv->supportsMultipleMonitors=FALSE;
+
+ /* The very first call to libwnck should be setting the client type */
+ wnck_set_client_type(WNCK_CLIENT_TYPE_PAGER);
+
+ /* Connect signals to screen */
+ g_signal_connect_swapped(priv->screen,
+ "window-stacking-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_stacking_changed),
+ self);
+
+ g_signal_connect_swapped(priv->screen,
+ "window-closed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_closed),
+ self);
+ g_signal_connect_swapped(priv->screen,
+ "window-opened",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_opened),
+ self);
+ g_signal_connect_swapped(priv->screen,
+ "active-window-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_active_window_changed),
+ self);
+
+ g_signal_connect_swapped(priv->screen,
+ "workspace-destroyed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_workspace_destroyed),
+ self);
+ g_signal_connect_swapped(priv->screen,
+ "workspace-created",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_workspace_created),
+ self);
+ g_signal_connect_swapped(priv->screen,
+ "active-workspace-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_active_workspace_changed),
+ self);
+
+ g_signal_connect_swapped(priv->gdkScreen,
+ "size-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_screen_size_changed),
+ self);
+
+ g_signal_connect_swapped(priv->screen,
+ "window-manager-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_window_manager_changed),
+ self);
+
+#ifdef HAVE_XINERAMA
+ /* Check if multiple monitors are supported */
+ if(XineramaIsActive(GDK_SCREEN_XDISPLAY(priv->gdkScreen)))
+ {
+ XfdashboardWindowTrackerMonitorGDK *monitor;
+ gint numberMonitors;
+ gint i;
+
+ /* Set flag that multiple monitors are supported */
+ priv->supportsMultipleMonitors=TRUE;
+
+ /* This signal must be called at least after the default signal handler - best at last.
+ * The reason is that all other signal handler should been processed because this handler
+ * could destroy monitor instances even the one of the primary monitor if it was not
+ * handled before. So give the other signal handlers a chance ;)
+ */
+ g_signal_connect_data(priv->gdkScreen,
+ "monitors-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_monitors_changed),
+ self,
+ NULL,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+
+ /* Get monitors */
+#if GTK_CHECK_VERSION(3, 22, 0)
+ numberMonitors=gdk_display_get_n_monitors(priv->gdkDisplay);
+#else
+ numberMonitors=gdk_screen_get_n_monitors(priv->gdkScreen);
+#endif
+ for(i=0; i<numberMonitors; i++)
+ {
+ /* Create monitor object */
+ monitor=_xfdashboard_window_tracker_gdk_monitor_new(self, i);
+
+ /* Remember primary monitor */
+ if(xfdashboard_window_tracker_monitor_is_primary(XFDASHBOARD_WINDOW_TRACKER_MONITOR(monitor)))
+ {
+ priv->primaryMonitor=monitor;
+ }
+ }
+ }
+#endif
+
+ /* Handle suspension signals from application */
+ priv->application=xfdashboard_application_get_default();
+ priv->suspendSignalID=g_signal_connect_swapped(priv->application,
+ "notify::is-suspended",
+ G_CALLBACK(_xfdashboard_window_tracker_gdk_on_application_suspended_changed),
+ self);
+ priv->isAppSuspended=xfdashboard_application_is_suspended(priv->application);
+}
+
+
+/* IMPLEMENTATION: Public API */
+
+/* Get last timestamp for use in libwnck */
+guint32 xfdashboard_window_tracker_gdk_get_time(void)
+{
+ const ClutterEvent *currentClutterEvent;
+ guint32 timestamp;
+ GdkDisplay *display;
+ GdkWindow *window;
+ GdkEventMask eventMask;
+ GSList *stages, *entry;
+ ClutterStage *stage;
+
+ /* We don't use clutter_get_current_event_time as it can return
+ * a too old timestamp if there is no current event.
+ */
+ currentClutterEvent=clutter_get_current_event();
+ if(currentClutterEvent!=NULL) return(clutter_event_get_time(currentClutterEvent));
+
+ /* Next we try timestamp of last GTK+ event */
+ timestamp=gtk_get_current_event_time();
+ if(timestamp>0) return(timestamp);
+
+ /* Next we try to ask GDK for a timestamp */
+ timestamp=gdk_x11_display_get_user_time(gdk_display_get_default());
+ if(timestamp>0) return(timestamp);
+
+ /* Next we try to retrieve timestamp of last X11 event in clutter */
+ XFDASHBOARD_DEBUG(NULL, WINDOWS, "No timestamp for windows - trying timestamp of last X11 event in Clutter");
+ timestamp=(guint32)clutter_x11_get_current_event_time();
+ if(timestamp!=0)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Got timestamp %u of last X11 event in Clutter",
+ timestamp);
+ return(timestamp);
+ }
+
+ /* Last resort is to get X11 server time via stage windows */
+ XFDASHBOARD_DEBUG(NULL, WINDOWS, "No timestamp for windows - trying last resort via stage windows");
+
+ display=gdk_display_get_default();
+ if(!display)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS, "No default display found in GDK to get timestamp for windows");
+ return(0);
+ }
+
+ /* Iterate through stages, get their GDK window and try to retrieve timestamp */
+ timestamp=0;
+ stages=clutter_stage_manager_list_stages(clutter_stage_manager_get_default());
+ for(entry=stages; timestamp==0 && entry; entry=g_slist_next(entry))
+ {
+ /* Get stage */
+ stage=CLUTTER_STAGE(entry->data);
+ if(stage)
+ {
+ /* Get GDK window of stage */
+ window=clutter_gdk_get_stage_window(stage);
+ if(!window)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "No GDK window found for stage %p to get timestamp for windows",
+ stage);
+ continue;
+ }
+
+ /* Check if GDK window supports GDK_PROPERTY_CHANGE_MASK event
+ * or application (or worst X server) will hang
+ */
+ eventMask=gdk_window_get_events(window);
+ if(!(eventMask & GDK_PROPERTY_CHANGE_MASK))
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "GDK window %p for stage %p does not support GDK_PROPERTY_CHANGE_MASK to get timestamp for windows",
+ window,
+ stage);
+ continue;
+ }
+
+ timestamp=gdk_x11_get_server_time(window);
+ }
+ }
+ g_slist_free(stages);
+
+ /* Return timestamp of last resort */
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Last resort timestamp for windows %s (%u)",
+ timestamp ? "found" : "not found",
+ timestamp);
+ return(timestamp);
+}
+
+/* Find and return XfdashboardWindowTrackerWindow object for mapped wnck window */
+XfdashboardWindowTrackerWindow* xfdashboard_window_tracker_gdk_get_window_for_wnck(XfdashboardWindowTrackerGDK *self,
+ WnckWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self), NULL);
+ g_return_val_if_fail(WNCK_IS_WINDOW(inWindow), NULL);
+
+ /* Lookup window object for requested wnck window and return it */
+ window=_xfdashboard_window_tracker_gdk_get_window_for_wnck(self, inWindow);
+ return(XFDASHBOARD_WINDOW_TRACKER_WINDOW(window));
+}
+
+/* Find and return XfdashboardWindowTrackerWorkspace object for mapped wnck workspace */
+XfdashboardWindowTrackerWorkspace* xfdashboard_window_tracker_gdk_get_workspace_for_wnck(XfdashboardWindowTrackerGDK *self,
+ WnckWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_GDK(self), NULL);
+ g_return_val_if_fail(WNCK_IS_WORKSPACE(inWorkspace), NULL);
+
+ /* Lookup workspace object for requested wnck workspace and return it */
+ workspace=_xfdashboard_window_tracker_gdk_get_workspace_for_wnck(self, inWorkspace);
+ return(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE(workspace));
+}
diff --git a/libxfdashboard/gdk/window-tracker-gdk.h b/libxfdashboard/gdk/window-tracker-gdk.h
new file mode 100644
index 0000000..9e04a08
--- /dev/null
+++ b/libxfdashboard/gdk/window-tracker-gdk.h
@@ -0,0 +1,90 @@
+/*
+ * window-tracker: Tracks windows, workspaces, monitors and
+ * listens for changes. It also bundles libwnck into one
+ * class.
+ * By wrapping libwnck objects we can use a virtual
+ * stable API while the API in libwnck changes within versions.
+ * We only need to use #ifdefs in window tracker object
+ * and nowhere else in the code.
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifndef __LIBXFDASHBOARD_WINDOW_TRACKER_GDK__
+#define __LIBXFDASHBOARD_WINDOW_TRACKER_GDK__
+
+#if !defined(__LIBXFDASHBOARD_H_INSIDE__) && !defined(LIBXFDASHBOARD_COMPILATION)
+#error "Only <libxfdashboard/libxfdashboard.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+#include <libxfdashboard/window-tracker-window.h>
+#include <libxfdashboard/window-tracker-workspace.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+G_BEGIN_DECLS
+
+#define XFDASHBOARD_TYPE_WINDOW_TRACKER_GDK (xfdashboard_window_tracker_gdk_get_type())
+#define XFDASHBOARD_WINDOW_TRACKER_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_GDK, XfdashboardWindowTrackerGDK))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_GDK))
+#define XFDASHBOARD_WINDOW_TRACKER_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_GDK, XfdashboardWindowTrackerGDKClass))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_GDK))
+#define XFDASHBOARD_WINDOW_TRACKER_GDK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_GDK, XfdashboardWindowTrackerGDKClass))
+
+typedef struct _XfdashboardWindowTrackerGDK XfdashboardWindowTrackerGDK;
+typedef struct _XfdashboardWindowTrackerGDKClass XfdashboardWindowTrackerGDKClass;
+typedef struct _XfdashboardWindowTrackerGDKPrivate XfdashboardWindowTrackerGDKPrivate;
+
+struct _XfdashboardWindowTrackerGDK
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowTrackerGDKPrivate *priv;
+};
+
+struct _XfdashboardWindowTrackerGDKClass
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+};
+
+/* Public API */
+GType xfdashboard_window_tracker_gdk_get_type(void) G_GNUC_CONST;
+
+guint32 xfdashboard_window_tracker_gdk_get_time(void);
+
+XfdashboardWindowTrackerWindow* xfdashboard_window_tracker_gdk_get_window_for_wnck(XfdashboardWindowTrackerGDK *self,
+ WnckWindow *inWindow);
+XfdashboardWindowTrackerWorkspace* xfdashboard_window_tracker_gdk_get_workspace_for_wnck(XfdashboardWindowTrackerGDK *self,
+ WnckWorkspace *inWorkspace);
+
+G_END_DECLS
+
+#endif /* __LIBXFDASHBOARD_WINDOW_TRACKER_GDK__ */
diff --git a/libxfdashboard/gdk/window-tracker-monitor-gdk.c b/libxfdashboard/gdk/window-tracker-monitor-gdk.c
new file mode 100644
index 0000000..bee8e2a
--- /dev/null
+++ b/libxfdashboard/gdk/window-tracker-monitor-gdk.c
@@ -0,0 +1,425 @@
+/*
+ * window-tracker-monitor: A monitor object tracked by window tracker.
+ * It provides information about position and
+ * size of monitor within screen and also a flag
+ * if this monitor is the primary one.
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libxfdashboard/gdk/window-tracker-monitor-gdk.h>
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include <libxfdashboard/window-tracker-monitor.h>
+#include <libxfdashboard/compat.h>
+#include <libxfdashboard/debug.h>
+
+
+/* Define this class in GObject system */
+static void _xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_iface_init(XfdashboardWindowTrackerMonitorInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerMonitorGDK,
+ xfdashboard_window_tracker_monitor_gdk,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR, _xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_GDK, XfdashboardWindowTrackerMonitorGDKPrivate))
+
+struct _XfdashboardWindowTrackerMonitorGDKPrivate
+{
+ /* Properties related */
+ gint monitorIndex;
+ gboolean isPrimary;
+
+ /* Instance related */
+ GdkScreen *screen;
+ GdkRectangle geometry;
+};
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ /* Overriden properties of interface: XfdashboardWindowTrackerMonitor */
+ PROP_MONITOR_INDEX,
+ PROP_IS_PRIMARY,
+
+ PROP_LAST
+};
+
+static GParamSpec* XfdashboardWindowTrackerMonitorGDKProperties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+
+/* Set primary monitor flag */
+static void _xfdashboard_window_tracker_monitor_gdk_update_primary(XfdashboardWindowTrackerMonitorGDK *self)
+{
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv;
+ gboolean isPrimary;
+#if GTK_CHECK_VERSION(3, 22, 0)
+ GdkMonitor *primaryMonitor;
+#else
+ gint primaryMonitor;
+#endif
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR(self));
+ g_return_if_fail(self->priv->monitorIndex>=0);
+
+ priv=self->priv;
+
+ /* Get primary flag */
+#if GTK_CHECK_VERSION(3, 22, 0)
+ primaryMonitor=gdk_display_get_monitor(gdk_screen_get_display(priv->screen), priv->monitorIndex);
+ isPrimary=gdk_monitor_is_primary(primaryMonitor);
+#else
+ primaryMonitor=gdk_screen_get_primary_monitor(priv->screen);
+ if(primaryMonitor==priv->monitorIndex) isPrimary=TRUE;
+ else isPrimary=FALSE;
+#endif
+
+ /* Set value if changed */
+ if(priv->isPrimary!=isPrimary)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Monitor %d changes primary state from %s to %s",
+ priv->monitorIndex,
+ priv->isPrimary ? "yes" : "no",
+ isPrimary ? "yes" : "no");
+
+ /* Set value */
+ priv->isPrimary=isPrimary;
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerMonitorGDKProperties[PROP_IS_PRIMARY]);
+
+ /* Emit signal */
+ g_signal_emit_by_name(self, "primary-changed");
+ }
+}
+
+/* Update monitor geometry */
+static void _xfdashboard_window_tracker_monitor_gdk_update_geometry(XfdashboardWindowTrackerMonitorGDK *self)
+{
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv;
+ GdkRectangle geometry;
+ gint numberMonitors;
+#if GTK_CHECK_VERSION(3, 22, 0)
+ GdkDisplay *display;
+ GdkMonitor *monitor;
+#endif
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(self));
+ g_return_if_fail(self->priv->monitorIndex>=0);
+
+ priv=self->priv;
+
+ /* Get number of monitors */
+#if GTK_CHECK_VERSION(3, 22, 0)
+ display=gdk_screen_get_display(priv->screen);
+ numberMonitors=gdk_display_get_n_monitors(display);
+#else
+ numberMonitors=gdk_screen_get_n_monitors(priv->screen);
+#endif
+
+ /* Check if monitor is valid */
+ if(priv->monitorIndex>=numberMonitors) return;
+
+ /* Get monitor geometry */
+#if GTK_CHECK_VERSION(3, 22, 0)
+ monitor=gdk_display_get_monitor(display, priv->monitorIndex);
+ gdk_monitor_get_geometry(monitor, &geometry);
+#else
+ gdk_screen_get_monitor_geometry(priv->screen, priv->monitorIndex, &geometry);
+#endif
+
+ /* Set value if changed */
+ if(geometry.x!=priv->geometry.x ||
+ geometry.y!=priv->geometry.y ||
+ geometry.width!=priv->geometry.width ||
+ geometry.height!=priv->geometry.height)
+ {
+ /* Set value */
+ priv->geometry.x=geometry.x;
+ priv->geometry.y=geometry.y;
+ priv->geometry.width=geometry.width;
+ priv->geometry.height=geometry.height;
+
+ /* Emit signal */
+ g_signal_emit_by_name(self, "geometry-changed");
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Monitor %d moved to %d,%d and resized to %dx%d",
+ priv->monitorIndex,
+ priv->geometry.x, priv->geometry.y,
+ priv->geometry.width, priv->geometry.height);
+ }
+}
+
+/* Number of monitors, primary monitor or size of any monitor changed */
+static void _xfdashboard_window_tracker_monitor_gdk_on_monitors_changed(XfdashboardWindowTrackerMonitorGDK *self,
+ gpointer inUserData)
+{
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(self));
+ g_return_if_fail(GDK_IS_SCREEN(inUserData));
+
+ /* Update primary monitor flag */
+ _xfdashboard_window_tracker_monitor_gdk_update_primary(self);
+
+ /* Update geometry of monitor */
+ _xfdashboard_window_tracker_monitor_gdk_update_geometry(self);
+}
+
+/* Set monitor index this object belongs to and to monitor */
+static void _xfdashboard_window_tracker_monitor_gdk_set_index(XfdashboardWindowTrackerMonitorGDK *self,
+ gint inIndex)
+{
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv;
+ gint numberMonitors;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(self));
+ g_return_if_fail(inIndex>=0);
+
+ priv=self->priv;
+
+ /* Get number of monitors */
+#if GTK_CHECK_VERSION(3, 22, 0)
+ numberMonitors=gdk_display_get_n_monitors(gdk_screen_get_display(priv->screen));
+#else
+ numberMonitors=gdk_screen_get_n_monitors(priv->screen);
+#endif
+ g_return_if_fail(inIndex<numberMonitors);
+
+ /* Freeze notification */
+ g_object_freeze_notify(G_OBJECT(self));
+
+ /* Set value if changed */
+ if(priv->monitorIndex!=inIndex)
+ {
+ /* Set value */
+ priv->monitorIndex=inIndex;
+
+ /* Update primary monitor flag */
+ _xfdashboard_window_tracker_monitor_gdk_update_primary(self);
+
+ /* Update geometry of monitor */
+ _xfdashboard_window_tracker_monitor_gdk_update_geometry(self);
+
+ /* Connect signals now we have a valid monitor index set */
+ g_signal_connect_swapped(priv->screen, "monitors-changed", G_CALLBACK(_xfdashboard_window_tracker_monitor_gdk_on_monitors_changed), self);
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerMonitorGDKProperties[PROP_MONITOR_INDEX]);
+ }
+
+ /* Thaw notification */
+ g_object_thaw_notify(G_OBJECT(self));
+}
+
+
+/* IMPLEMENTATION: Interface XfdashboardWindowTrackerMonitor */
+
+/* Determine if monitor is primary one */
+static gboolean _xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_is_primary(XfdashboardWindowTrackerMonitor *inMonitor)
+{
+ XfdashboardWindowTrackerMonitorGDK *self;
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(inMonitor), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inMonitor);
+ priv=self->priv;
+
+ return(priv->isPrimary);
+}
+
+/* Get monitor index */
+static gint _xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_get_number(XfdashboardWindowTrackerMonitor *inMonitor)
+{
+ XfdashboardWindowTrackerMonitorGDK *self;
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(inMonitor), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inMonitor);
+ priv=self->priv;
+
+ return(priv->monitorIndex);
+}
+
+/* Get geometry of monitor */
+static void _xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_get_geometry(XfdashboardWindowTrackerMonitor *inMonitor,
+ gint *outX,
+ gint *outY,
+ gint *outWidth,
+ gint *outHeight)
+{
+ XfdashboardWindowTrackerMonitorGDK *self;
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(inMonitor));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inMonitor);
+ priv=self->priv;
+
+ /* Set position and size of monitor */
+ if(outX) *outX=priv->geometry.x;
+ if(outY) *outY=priv->geometry.y;
+ if(outWidth) *outWidth=priv->geometry.width;
+ if(outHeight) *outHeight=priv->geometry.height;
+}
+
+/* Interface initialization
+ * Set up default functions
+ */
+static void _xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_iface_init(XfdashboardWindowTrackerMonitorInterface *iface)
+{
+ iface->is_primary=_xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_is_primary;
+ iface->get_number=_xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_get_number;
+ iface->get_geometry=_xfdashboard_window_tracker_monitor_gdk_window_tracker_monitor_get_geometry;
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_tracker_monitor_gdk_dispose(GObject *inObject)
+{
+ XfdashboardWindowTrackerMonitorGDK *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inObject);
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv=self->priv;
+
+ /* Release allocated resources */
+ if(priv->screen)
+ {
+ g_signal_handlers_disconnect_by_data(priv->screen, self);
+ priv->screen=NULL;
+ }
+
+ /* Call parent's class dispose method */
+ G_OBJECT_CLASS(xfdashboard_window_tracker_monitor_gdk_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_tracker_monitor_gdk_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerMonitorGDK *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_MONITOR_INDEX:
+ _xfdashboard_window_tracker_monitor_gdk_set_index(self, g_value_get_int(inValue));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+static void _xfdashboard_window_tracker_monitor_gdk_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerMonitorGDK *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(inObject);
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv=self->priv;
+
+ switch(inPropID)
+ {
+ case PROP_IS_PRIMARY:
+ g_value_set_boolean(outValue, priv->isPrimary);
+ break;
+
+ case PROP_MONITOR_INDEX:
+ g_value_set_uint(outValue, priv->monitorIndex);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+/* Class initialization
+ * Override functions in parent classes and define properties
+ * and signals
+ */
+static void xfdashboard_window_tracker_monitor_gdk_class_init(XfdashboardWindowTrackerMonitorGDKClass *klass)
+{
+ GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
+ XfdashboardWindowTrackerMonitor *monitorIface;
+ GParamSpec *paramSpec;
+
+ /* Reference interface type to lookup properties etc. */
+ monitorIface=g_type_default_interface_ref(XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR);
+
+ /* Override functions */
+ gobjectClass->dispose=_xfdashboard_window_tracker_monitor_gdk_dispose;
+ gobjectClass->set_property=_xfdashboard_window_tracker_monitor_gdk_set_property;
+ gobjectClass->get_property=_xfdashboard_window_tracker_monitor_gdk_get_property;
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowTrackerMonitorGDKPrivate));
+
+ /* Define properties */
+ paramSpec=g_object_interface_find_property(monitorIface, "is-primary");
+ XfdashboardWindowTrackerMonitorGDKProperties[PROP_IS_PRIMARY]=
+ g_param_spec_override("is-primary", paramSpec);
+
+ paramSpec=g_object_interface_find_property(monitorIface, "monitor-index");
+ XfdashboardWindowTrackerMonitorGDKProperties[PROP_MONITOR_INDEX]=
+ g_param_spec_override("monitor-index", paramSpec);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowTrackerMonitorGDKProperties);
+
+ /* Release allocated resources */
+ g_type_default_interface_unref(monitorIface);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+static void xfdashboard_window_tracker_monitor_gdk_init(XfdashboardWindowTrackerMonitorGDK *self)
+{
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK_GET_PRIVATE(self);
+
+ /* Set default values */
+ priv->monitorIndex=-1;
+ priv->isPrimary=FALSE;
+ priv->screen=gdk_screen_get_default();
+ priv->geometry.x=0;
+ priv->geometry.y=0;
+ priv->geometry.width=0;
+ priv->geometry.height=0;
+}
diff --git a/libxfdashboard/gdk/window-tracker-monitor-gdk.h b/libxfdashboard/gdk/window-tracker-monitor-gdk.h
new file mode 100644
index 0000000..bd35add
--- /dev/null
+++ b/libxfdashboard/gdk/window-tracker-monitor-gdk.h
@@ -0,0 +1,76 @@
+/*
+ * window-tracker-monitor: A monitor object tracked by window tracker.
+ * It provides information about position and
+ * size of monitor within screen and also a flag
+ * if this monitor is the primary one.
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifndef __LIBXFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK__
+#define __LIBXFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK__
+
+#if !defined(__LIBXFDASHBOARD_H_INSIDE__) && !defined(LIBXFDASHBOARD_COMPILATION)
+#error "Only <libxfdashboard/libxfdashboard.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_GDK (xfdashboard_window_tracker_monitor_gdk_get_type())
+#define XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_GDK, XfdashboardWindowTrackerMonitorGDK))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_GDK))
+#define XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_GDK, XfdashboardWindowTrackerMonitorGDKClass))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_GDK))
+#define XFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_GDK, XfdashboardWindowTrackerMonitorGDKClass))
+
+typedef struct _XfdashboardWindowTrackerMonitorGDK XfdashboardWindowTrackerMonitorGDK;
+typedef struct _XfdashboardWindowTrackerMonitorGDKClass XfdashboardWindowTrackerMonitorGDKClass;
+typedef struct _XfdashboardWindowTrackerMonitorGDKPrivate XfdashboardWindowTrackerMonitorGDKPrivate;
+
+struct _XfdashboardWindowTrackerMonitorGDK
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowTrackerMonitorGDKPrivate *priv;
+};
+
+struct _XfdashboardWindowTrackerMonitorGDKClass
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+ void (*primary_changed)(XfdashboardWindowTrackerMonitorGDK *self);
+ void (*geometry_changed)(XfdashboardWindowTrackerMonitorGDK *self);
+};
+
+/* Public API */
+GType xfdashboard_window_tracker_monitor_gdk_get_type(void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __LIBXFDASHBOARD_WINDOW_TRACKER_MONITOR_GDK__ */
diff --git a/libxfdashboard/gdk/window-tracker-window-gdk.c b/libxfdashboard/gdk/window-tracker-window-gdk.c
new file mode 100644
index 0000000..62cd670
--- /dev/null
+++ b/libxfdashboard/gdk/window-tracker-window-gdk.c
@@ -0,0 +1,1890 @@
+/*
+ * window-tracker-window: A window tracked by window tracker and also
+ * a wrapper class around WnckWindow.
+ * By wrapping libwnck objects we can use a virtual
+ * stable API while the API in libwnck changes
+ * within versions. We only need to use #ifdefs in
+ * window tracker object and nowhere else in the code.
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+/**
+ * SECTION:window-tracker-window-gdk
+ * @short_description: A window used by GDK window tracker
+ * @include: xfdashboard/gdk/window-tracker-window-gdk.h
+ *
+ * This is the GDK backend of #XfdashboardWindowTrackerWindow
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libxfdashboard/gdk/window-tracker-window-gdk.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+#include <glib/gi18n-lib.h>
+#include <clutter/gdk/clutter-gdk.h>
+#include <clutter/x11/clutter-x11.h>
+#include <gtk/gtkx.h>
+#include <gdk/gdkx.h>
+#ifdef HAVE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
+#include <libxfdashboard/gdk/window-content-gdk.h>
+#include <libxfdashboard/gdk/window-tracker-workspace-gdk.h>
+#include <libxfdashboard/gdk/window-tracker-gdk.h>
+#include <libxfdashboard/window-tracker.h>
+#include <libxfdashboard/marshal.h>
+#include <libxfdashboard/compat.h>
+#include <libxfdashboard/debug.h>
+
+
+/* Define this class in GObject system */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_iface_init(XfdashboardWindowTrackerWindowInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerWindowGDK,
+ xfdashboard_window_tracker_window_gdk,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW, _xfdashboard_window_tracker_window_gdk_window_tracker_window_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK, XfdashboardWindowTrackerWindowGDKPrivate))
+
+struct _XfdashboardWindowTrackerWindowGDKPrivate
+{
+ /* Properties related */
+ WnckWindow *window;
+ XfdashboardWindowTrackerWindowState state;
+ XfdashboardWindowTrackerWindowAction actions;
+
+ /* Instance related */
+ WnckWorkspace *workspace;
+
+ gint lastGeometryX;
+ gint lastGeometryY;
+ gint lastGeometryWidth;
+ gint lastGeometryHeight;
+
+ ClutterContent *content;
+};
+
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ PROP_WINDOW,
+
+ /* Overriden properties of interface: XfdashboardWindowTrackerWindow */
+ PROP_STATE,
+ PROP_ACTIONS,
+
+ PROP_LAST
+};
+
+static GParamSpec* XfdashboardWindowTrackerWindowGDKProperties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self) \
+ g_critical(_("No wnck window wrapped at %s in called function %s"), \
+ G_OBJECT_TYPE_NAME(self), \
+ __func__);
+
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_WRONG_WINDOW(self) \
+ g_critical(_("Got signal from wrong wnck window wrapped at %s in called function %s"),\
+ G_OBJECT_TYPE_NAME(self), \
+ __func__);
+
+/* Get state of window */
+static void _xfdashboard_window_tracker_window_gdk_update_state(XfdashboardWindowTrackerWindowGDK *self)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ XfdashboardWindowTrackerWindowState newState;
+ WnckWindowState wnckState;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+
+ priv=self->priv;
+ newState=0;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ }
+ else
+ {
+ /* Get state of wnck window to determine state */
+ wnckState=wnck_window_get_state(priv->window);
+
+ /* Determine window state */
+ if(wnckState & WNCK_WINDOW_STATE_HIDDEN) newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_HIDDEN;
+
+ if(wnckState & WNCK_WINDOW_STATE_MINIMIZED)
+ {
+ newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_MINIMIZED;
+ }
+ else
+ {
+ if((wnckState & WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY) &&
+ (wnckState & WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
+ {
+ newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_MAXIMIZED;
+ }
+ }
+
+ if(wnckState & WNCK_WINDOW_STATE_FULLSCREEN) newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_FULLSCREEN;
+ if(wnckState & WNCK_WINDOW_STATE_SKIP_PAGER) newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_SKIP_PAGER;
+ if(wnckState & WNCK_WINDOW_STATE_SKIP_TASKLIST) newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_SKIP_TASKLIST;
+ if(wnckState & WNCK_WINDOW_STATE_DEMANDS_ATTENTION) newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_URGENT;
+ if(wnckState & WNCK_WINDOW_STATE_URGENT) newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_URGENT;
+
+ /* "Pin" is not a wnck window state and do not get confused with the
+ * "sticky" state as it refers only to the window's stickyness on
+ * the viewport. So we have to ask wnck if it is pinned.
+ */
+ if(wnck_window_is_pinned(priv->window)) newState|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_PINNED;
+ }
+
+ /* Set value if changed */
+ if(priv->state!=newState)
+ {
+ /* Set value */
+ priv->state=newState;
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerWindowGDKProperties[PROP_STATE]);
+ }
+}
+
+/* Get actions of window */
+static void _xfdashboard_window_tracker_window_gdk_update_actions(XfdashboardWindowTrackerWindowGDK *self)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ XfdashboardWindowTrackerWindowAction newActions;
+ WnckWindowActions wnckActions;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+
+ priv=self->priv;
+ newActions=0;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ }
+ else
+ {
+ /* Get actions of wnck window to determine state */
+ wnckActions=wnck_window_get_actions(priv->window);
+
+ /* Determine window actions */
+ if(wnckActions & WNCK_WINDOW_ACTION_CLOSE) newActions|=XFDASHBOARD_WINDOW_TRACKER_WINDOW_ACTION_CLOSE;
+ }
+
+ /* Set value if changed */
+ if(priv->actions!=newActions)
+ {
+ /* Set value */
+ priv->actions=newActions;
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerWindowGDKProperties[PROP_ACTIONS]);
+ }
+}
+
+/* Size of screen has changed so resize stage window */
+static void _xfdashboard_window_tracker_window_gdk_on_stage_screen_size_changed(XfdashboardWindowTracker *inWindowTracker,
+ gint inWidth,
+ gint inHeight,
+ gpointer inUserData)
+{
+#ifdef HAVE_XINERAMA
+ XfdashboardWindowTrackerWindowGDK *realStageWindow;
+ WnckWindow *stageWindow;
+ GdkDisplay *display;
+ GdkScreen *screen;
+ XineramaScreenInfo *monitors;
+ int monitorsCount;
+ gint top, bottom, left, right;
+ gint topIndex, bottomIndex, leftIndex, rightIndex;
+ gint i;
+ Atom atomFullscreenMonitors;
+ XEvent xEvent;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(inWindowTracker));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ realStageWindow=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ XFDASHBOARD_DEBUG(inWindowTracker, WINDOWS, "Set fullscreen across all monitors using Xinerama");
+
+ /* Get wnck window for stage window object as it is needed a lot from this
+ * point on.
+ */
+ stageWindow=xfdashboard_window_tracker_window_gdk_get_window(realStageWindow);
+
+ /* If window manager does not support fullscreen across all monitors
+ * return here.
+ */
+ if(!wnck_screen_net_wm_supports(wnck_window_get_screen(stageWindow), "_NET_WM_FULLSCREEN_MONITORS"))
+ {
+ g_warning(_("Keep window fullscreen on primary monitor because window manager does not support _NET_WM_FULLSCREEN_MONITORS."));
+ return;
+ }
+
+ /* Get display */
+ display=gdk_display_get_default();
+
+ /* Get screen */
+ screen=gdk_screen_get_default();
+
+ /* Check if Xinerama is active on display. If not try to move and resize
+ * stage window to primary monitor.
+ */
+ if(!XineramaIsActive(GDK_DISPLAY_XDISPLAY(display)))
+ {
+#if GTK_CHECK_VERSION(3, 22, 0)
+ GdkMonitor *primaryMonitor;
+#else
+ gint primaryMonitor;
+#endif
+ GdkRectangle geometry;
+
+ /* Get position and size of primary monitor and try to move and resize
+ * stage window to its position and size. Even if it fails it should
+ * resize the stage to the size of current monitor this window is
+ * fullscreened to. Tested with xfwm4.
+ */
+#if GTK_CHECK_VERSION(3, 22, 0)
+ primaryMonitor=gdk_display_get_primary_monitor(gdk_screen_get_display(screen));
+ gdk_monitor_get_geometry(primaryMonitor, &geometry);
+#else
+ primaryMonitor=gdk_screen_get_primary_monitor(screen);
+ gdk_screen_get_monitor_geometry(screen, primaryMonitor, &geometry);
+#endif
+ wnck_window_set_geometry(stageWindow,
+ WNCK_WINDOW_GRAVITY_STATIC,
+ WNCK_WINDOW_CHANGE_X | WNCK_WINDOW_CHANGE_Y | WNCK_WINDOW_CHANGE_WIDTH | WNCK_WINDOW_CHANGE_HEIGHT,
+ geometry.x, geometry.y, geometry.width, geometry.height);
+ return;
+ }
+
+ /* Get monitors from Xinerama */
+ monitors=XineramaQueryScreens(GDK_DISPLAY_XDISPLAY(display), &monitorsCount);
+ if(monitorsCount<=0 || !monitors)
+ {
+ if(monitors) XFree(monitors);
+ return;
+ }
+
+ /* Get monitor indices for each corner of screen */
+ xfdashboard_window_tracker_get_screen_size(inWindowTracker, &left, &top);
+ bottom=0;
+ right=0;
+ topIndex=bottomIndex=leftIndex=rightIndex=0;
+ for(i=0; i<monitorsCount; i++)
+ {
+ XFDASHBOARD_DEBUG(inWindowTracker, WINDOWS,
+ "Checking edges at monitor %d with upper-left at %d,%d and lower-right at %d,%d [size: %dx%d]",
+ i,
+ monitors[i].x_org,
+ monitors[i].y_org,
+ monitors[i].x_org+monitors[i].width, monitors[i].y_org+monitors[i].height,
+ monitors[i].width, monitors[i].height);
+
+ if(left>monitors[i].x_org)
+ {
+ left=monitors[i].x_org;
+ leftIndex=i;
+ }
+
+ if(right<(monitors[i].x_org+monitors[i].width))
+ {
+ right=(monitors[i].x_org+monitors[i].width);
+ rightIndex=i;
+ }
+
+ if(top>monitors[i].y_org)
+ {
+ top=monitors[i].y_org;
+ topIndex=i;
+ }
+
+ if(bottom<(monitors[i].y_org+monitors[i].height))
+ {
+ bottom=(monitors[i].y_org+monitors[i].height);
+ bottomIndex=i;
+ }
+ }
+ XFDASHBOARD_DEBUG(inWindowTracker, WINDOWS,
+ "Found edge monitors: left=%d (monitor %d), right=%d (monitor %d), top=%d (monitor %d), bottom=%d (monitor %d)",
+ left, leftIndex,
+ right, rightIndex,
+ top, topIndex,
+ bottom, bottomIndex);
+
+ /* Get X atom for fullscreen-across-all-monitors */
+ atomFullscreenMonitors=XInternAtom(GDK_DISPLAY_XDISPLAY(display),
+ "_NET_WM_FULLSCREEN_MONITORS",
+ False);
+
+ /* Send event to X to set window to fullscreen over all monitors */
+ memset(&xEvent, 0, sizeof(xEvent));
+ xEvent.type=ClientMessage;
+ xEvent.xclient.window=wnck_window_get_xid(stageWindow);
+ xEvent.xclient.display=GDK_DISPLAY_XDISPLAY(display);
+ xEvent.xclient.message_type=atomFullscreenMonitors;
+ xEvent.xclient.format=32;
+ xEvent.xclient.data.l[0]=topIndex;
+ xEvent.xclient.data.l[1]=bottomIndex;
+ xEvent.xclient.data.l[2]=leftIndex;
+ xEvent.xclient.data.l[3]=rightIndex;
+ xEvent.xclient.data.l[4]=0;
+ XSendEvent(GDK_DISPLAY_XDISPLAY(display),
+ DefaultRootWindow(GDK_DISPLAY_XDISPLAY(display)),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xEvent);
+
+ /* Release allocated resources */
+ if(monitors) XFree(monitors);
+#else
+ XfdashboardWindowTrackerWindowGDK *realStageWindow;
+ WnckWindow *stageWindow;
+ GdkScreen *screen;
+ gint primaryMonitor;
+ GdkRectangle geometry;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(inWindowTracker));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ realStageWindow=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+
+ XFDASHBOARD_DEBUG(inWindowTracker, WINDOWS, "No support for multiple monitor: Setting fullscreen on primary monitor");
+
+ /* Get wnck window for stage window object as it is needed a lot from this
+ * point on.
+ */
+ stageWindow=xfdashboard_window_tracker_window_gdk_get_window(realStageWindow);
+
+ /* Get screen */
+ screen=gdk_screen_get_default();
+
+ /* Get position and size of primary monitor and try to move and resize
+ * stage window to its position and size. Even if it fails it should
+ * resize the stage to the size of current monitor this window is
+ * fullscreened to. Tested with xfwm4.
+ */
+ primaryMonitor=gdk_screen_get_primary_monitor(screen);
+ gdk_screen_get_monitor_geometry(screen, primaryMonitor, &geometry);
+ wnck_window_set_geometry(stageWindow,
+ WNCK_WINDOW_GRAVITY_STATIC,
+ WNCK_WINDOW_CHANGE_X | WNCK_WINDOW_CHANGE_Y | WNCK_WINDOW_CHANGE_WIDTH | WNCK_WINDOW_CHANGE_HEIGHT,
+ geometry.x, geometry.y, geometry.width, geometry.height);
+
+ XFDASHBOARD_DEBUG(inWindowTracker, WINDOWS,
+ "Moving stage window to %d,%d and resize to %dx%d",
+ geometry.x, geometry.y,
+ geometry.width, geometry.height);
+#endif
+}
+
+/* State of stage window changed */
+static void _xfdashboard_window_tracker_window_gdk_on_stage_state_changed(WnckWindow *inWindow,
+ WnckWindowState inChangedMask,
+ WnckWindowState inNewValue,
+ gpointer inUserData)
+{
+ g_return_if_fail(WNCK_IS_WINDOW(inWindow));
+
+ /* Set 'skip-tasklist' if changed */
+ if((inChangedMask & WNCK_WINDOW_STATE_SKIP_TASKLIST) &&
+ !(inNewValue & WNCK_WINDOW_STATE_SKIP_TASKLIST))
+ {
+ wnck_window_set_skip_tasklist(WNCK_WINDOW(inWindow), TRUE);
+ XFDASHBOARD_DEBUG(inWindow, WINDOWS,
+ "State 'skip-tasklist' for stage window %p needs reset",
+ inWindow);
+ }
+
+ /* Set 'skip-pager' if changed */
+ if((inChangedMask & WNCK_WINDOW_STATE_SKIP_PAGER) &&
+ !(inNewValue & WNCK_WINDOW_STATE_SKIP_PAGER))
+ {
+ wnck_window_set_skip_pager(WNCK_WINDOW(inWindow), TRUE);
+ XFDASHBOARD_DEBUG(inWindow, WINDOWS,
+ "State 'skip-pager' for stage window %p needs reset",
+ inWindow);
+ }
+
+ /* Set 'make-above' if changed */
+ if((inChangedMask & WNCK_WINDOW_STATE_ABOVE) &&
+ !(inNewValue & WNCK_WINDOW_STATE_ABOVE))
+ {
+ wnck_window_make_above(WNCK_WINDOW(inWindow));
+ XFDASHBOARD_DEBUG(inWindow, WINDOWS,
+ "State 'make-above' for stage window %p needs reset",
+ inWindow);
+ }
+}
+
+/* The active window changed. Reselect stage window as active one if it is visible */
+static void _xfdashboard_window_tracker_window_gdk_on_stage_active_window_changed(WnckScreen *inScreen,
+ WnckWindow *inPreviousWindow,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindow *activeWindow;
+ gboolean reselect;
+
+ g_return_if_fail(WNCK_IS_SCREEN(inScreen));
+ g_return_if_fail(inPreviousWindow==NULL || WNCK_IS_WINDOW(inPreviousWindow));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inUserData));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inUserData);
+ priv=self->priv;
+ reselect=FALSE;
+
+ /* Reactive stage window if not hidden */
+ activeWindow=wnck_screen_get_active_window(inScreen);
+
+ if(inPreviousWindow && inPreviousWindow==priv->window) reselect=TRUE;
+ if(!activeWindow || activeWindow!=priv->window) reselect=TRUE;
+ if(!(priv->state & (XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_MINIMIZED | XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_HIDDEN))) reselect=TRUE;
+
+ if(reselect)
+ {
+ wnck_window_activate_transient(priv->window, xfdashboard_window_tracker_gdk_get_time());
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Active window changed from %p (%s) to %p (%s) but stage window %p is visible and should be active one",
+ inPreviousWindow, inPreviousWindow ? wnck_window_get_name(inPreviousWindow) : "<nil>",
+ activeWindow, activeWindow ? wnck_window_get_name(activeWindow) : "<nil>",
+ priv->window);
+ }
+}
+
+/* Proxy signal for mapped wnck window which changed name */
+static void _xfdashboard_window_tracker_window_gdk_on_wnck_name_changed(XfdashboardWindowTrackerWindowGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+ g_return_if_fail(WNCK_IS_WINDOW(inUserData));
+
+ priv=self->priv;
+ window=WNCK_WINDOW(inUserData);
+
+ /* Check that window emitting this signal is the mapped window of this object */
+ if(priv->window!=window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_WRONG_WINDOW(self);
+ return;
+ }
+
+ /* Proxy signal */
+ g_signal_emit_by_name(self, "name-changed");
+}
+
+/* Proxy signal for mapped wnck window which changed states */
+static void _xfdashboard_window_tracker_window_gdk_on_wnck_state_changed(XfdashboardWindowTrackerWindowGDK *self,
+ WnckWindowState inChangedStates,
+ WnckWindowState inNewState,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+ g_return_if_fail(WNCK_IS_WINDOW(inUserData));
+
+ priv=self->priv;
+ window=WNCK_WINDOW(inUserData);
+
+ /* Check that window emitting this signal is the mapped window of this object */
+ if(priv->window!=window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_WRONG_WINDOW(self);
+ return;
+ }
+
+ /* Update state before emitting signal */
+ _xfdashboard_window_tracker_window_gdk_update_state(self);
+
+ /* Proxy signal */
+ g_signal_emit_by_name(self, "state-changed", inChangedStates, inNewState);
+}
+
+/* Proxy signal for mapped wnck window which changed actions */
+static void _xfdashboard_window_tracker_window_gdk_on_wnck_actions_changed(XfdashboardWindowTrackerWindowGDK *self,
+ WnckWindowActions inChangedActions,
+ WnckWindowActions inNewActions,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+ g_return_if_fail(WNCK_IS_WINDOW(inUserData));
+
+ priv=self->priv;
+ window=WNCK_WINDOW(inUserData);
+
+ /* Check that window emitting this signal is the mapped window of this object */
+ if(priv->window!=window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_WRONG_WINDOW(self);
+ return;
+ }
+
+ /* Update actions before emitting signal */
+ _xfdashboard_window_tracker_window_gdk_update_actions(self);
+
+ /* Proxy signal */
+ g_signal_emit_by_name(self, "actions-changed", inChangedActions, inNewActions);
+}
+
+/* Proxy signal for mapped wnck window which changed icon */
+static void _xfdashboard_window_tracker_window_gdk_on_wnck_icon_changed(XfdashboardWindowTrackerWindowGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+ g_return_if_fail(WNCK_IS_WINDOW(inUserData));
+
+ priv=self->priv;
+ window=WNCK_WINDOW(inUserData);
+
+ /* Check that window emitting this signal is the mapped window of this object */
+ if(priv->window!=window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_WRONG_WINDOW(self);
+ return;
+ }
+
+ /* Proxy signal */
+ g_signal_emit_by_name(self, "icon-changed");
+}
+
+/* Proxy signal for mapped wnck window which changed workspace */
+static void _xfdashboard_window_tracker_window_gdk_on_wnck_workspace_changed(XfdashboardWindowTrackerWindowGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindow *window;
+ XfdashboardWindowTrackerWorkspace *oldWorkspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+ g_return_if_fail(WNCK_IS_WINDOW(inUserData));
+
+ priv=self->priv;
+ window=WNCK_WINDOW(inUserData);
+
+ /* Check that window emitting this signal is the mapped window of this object */
+ if(priv->window!=window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_WRONG_WINDOW(self);
+ return;
+ }
+
+ /* Get mapped workspace object for last known workspace of this window */
+ oldWorkspace=NULL;
+ if(priv->workspace)
+ {
+ XfdashboardWindowTracker *windowTracker;
+
+ windowTracker=xfdashboard_window_tracker_get_default();
+ oldWorkspace=xfdashboard_window_tracker_gdk_get_workspace_for_wnck(XFDASHBOARD_WINDOW_TRACKER_GDK(windowTracker), priv->workspace);
+ g_object_unref(windowTracker);
+ }
+
+ /* Proxy signal */
+ g_signal_emit_by_name(self, "workspace-changed", oldWorkspace);
+
+ /* Remember new workspace as last known workspace */
+ priv->workspace=wnck_window_get_workspace(window);
+}
+
+/* Proxy signal for mapped wnck window which changed geometry */
+static void _xfdashboard_window_tracker_window_gdk_on_wnck_geometry_changed(XfdashboardWindowTrackerWindowGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindow *window;
+ gint x, y, width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+ g_return_if_fail(WNCK_IS_WINDOW(inUserData));
+
+ priv=self->priv;
+ window=WNCK_WINDOW(inUserData);
+
+ /* Check that window emitting this signal is the mapped window of this object */
+ if(priv->window!=window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_WRONG_WINDOW(self);
+ return;
+ }
+
+ /* Get current position and size of window and check against last known
+ * position and size of window to determine if window has moved or resized.
+ */
+ wnck_window_get_geometry(priv->window, &x, &y, &width, &height);
+ if(priv->lastGeometryX!=x ||
+ priv->lastGeometryY!=y ||
+ priv->lastGeometryWidth!=width ||
+ priv->lastGeometryHeight!=height)
+ {
+ XfdashboardWindowTracker *windowTracker;
+ gint screenWidth, screenHeight;
+ XfdashboardWindowTrackerMonitor *oldMonitor;
+ XfdashboardWindowTrackerMonitor *currentMonitor;
+ gint windowMiddleX, windowMiddleY;
+
+ /* Get window tracker */
+ windowTracker=xfdashboard_window_tracker_get_default();
+
+ /* Get monitor at old position of window and the monitor at current.
+ * If they differ emit signal for window changed monitor.
+ */
+ xfdashboard_window_tracker_get_screen_size(windowTracker, &screenWidth, &screenHeight);
+
+ windowMiddleX=priv->lastGeometryX+(priv->lastGeometryWidth/2);
+ if(windowMiddleX>screenWidth) windowMiddleX=screenWidth-1;
+
+ windowMiddleY=priv->lastGeometryY+(priv->lastGeometryHeight/2);
+ if(windowMiddleY>screenHeight) windowMiddleY=screenHeight-1;
+
+ oldMonitor=xfdashboard_window_tracker_get_monitor_by_position(windowTracker, windowMiddleX, windowMiddleY);
+
+ currentMonitor=xfdashboard_window_tracker_window_get_monitor(XFDASHBOARD_WINDOW_TRACKER_WINDOW(self));
+
+ if(currentMonitor!=oldMonitor)
+ {
+ /* Emit signal */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Window '%s' moved from monitor %d (%s) to %d (%s)",
+ wnck_window_get_name(priv->window),
+ oldMonitor ? xfdashboard_window_tracker_monitor_get_number(oldMonitor) : -1,
+ (oldMonitor && xfdashboard_window_tracker_monitor_is_primary(oldMonitor)) ? "primary" : "non-primary",
+ currentMonitor ? xfdashboard_window_tracker_monitor_get_number(currentMonitor) : -1,
+ (currentMonitor && xfdashboard_window_tracker_monitor_is_primary(currentMonitor)) ? "primary" : "non-primary");
+ g_signal_emit_by_name(self, "monitor-changed", oldMonitor);
+ }
+
+ /* Remember current position and size as last known ones */
+ priv->lastGeometryX=x;
+ priv->lastGeometryY=y;
+ priv->lastGeometryWidth=width;
+ priv->lastGeometryHeight=height;
+
+ /* Release allocated resources */
+ g_object_unref(windowTracker);
+ }
+
+ /* Proxy signal */
+ g_signal_emit_by_name(self, "geometry-changed");
+}
+
+/* Set wnck window to map in this window object */
+static void _xfdashboard_window_tracker_window_gdk_set_window(XfdashboardWindowTrackerWindowGDK *self,
+ WnckWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self));
+ g_return_if_fail(!inWindow || WNCK_IS_WINDOW(inWindow));
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->window!=inWindow)
+ {
+ /* If we have created a content for this window then remove weak reference
+ * and reset content variable to NULL. First call to get window content
+ * will recreate it. Already used contents will not be affected.
+ */
+ if(priv->content)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Removing cached content with ref-count %d from %s@%p for wnck-window %p because wnck-window will change to %p",
+ G_OBJECT(priv->content)->ref_count,
+ G_OBJECT_TYPE_NAME(self), self,
+ priv->window,
+ inWindow);
+ g_object_remove_weak_pointer(G_OBJECT(priv->content), (gpointer*)&priv->content);
+ priv->content=NULL;
+ }
+
+ /* Disconnect signals to old window (if available) and reset states */
+ if(priv->window)
+ {
+ /* Remove weak reference at old window */
+ g_object_remove_weak_pointer(G_OBJECT(priv->window), (gpointer*)&priv->window);
+
+ /* Disconnect signal handlers */
+ g_signal_handlers_disconnect_by_data(priv->window, self);
+ priv->window=NULL;
+ }
+ priv->state=0;
+ priv->actions=0;
+ priv->workspace=NULL;
+
+ /* Set new value */
+ priv->window=inWindow;
+
+ /* Initialize states and connect signals if window is set */
+ if(priv->window)
+ {
+ /* Add weak reference at new window */
+ g_object_add_weak_pointer(G_OBJECT(priv->window), (gpointer*)&priv->window);
+
+ /* Initialize states */
+ _xfdashboard_window_tracker_window_gdk_update_state(self);
+ _xfdashboard_window_tracker_window_gdk_update_actions(self);
+ priv->workspace=wnck_window_get_workspace(priv->window);
+ wnck_window_get_geometry(priv->window,
+ &priv->lastGeometryX,
+ &priv->lastGeometryY,
+ &priv->lastGeometryWidth,
+ &priv->lastGeometryHeight);
+
+ /* Connect signals */
+ g_signal_connect_swapped(priv->window,
+ "name-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_wnck_name_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "state-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_wnck_state_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "actions-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_wnck_actions_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "icon-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_wnck_icon_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "workspace-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_wnck_workspace_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "geometry-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_wnck_geometry_changed),
+ self);
+ }
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerWindowGDKProperties[PROP_WINDOW]);
+ }
+}
+
+
+/* IMPLEMENTATION: Interface XfdashboardWindowTrackerWindow */
+
+/* Determine if window is visible */
+static gboolean _xfdashboard_window_tracker_window_gdk_window_tracker_window_is_visible(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* Windows are invisible if hidden but not minimized */
+ if((priv->state & XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_HIDDEN) &&
+ !(priv->state & XFDASHBOARD_WINDOW_TRACKER_WINDOW_STATE_MINIMIZED))
+ {
+ return(FALSE);
+ }
+
+ /* If we get here the window is visible */
+ return(TRUE);
+}
+
+/* Show window */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_show(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Show (unminize) window */
+ wnck_window_unminimize(priv->window, xfdashboard_window_tracker_gdk_get_time());
+}
+
+/* Show window */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_hide(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Hide (minimize) window */
+ wnck_window_minimize(priv->window);
+}
+
+/* Get parent window if this window is a child window */
+static XfdashboardWindowTrackerWindow* _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_parent(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindow *parentWindow;
+ XfdashboardWindowTracker *windowTracker;
+ XfdashboardWindowTrackerWindow *foundWindow;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Get parent window */
+ parentWindow=wnck_window_get_transient(priv->window);
+ if(!parentWindow) return(NULL);
+
+ /* Get window tracker and lookup the mapped and matching XfdashboardWindowTrackerWindow
+ * for wnck window.
+ */
+ windowTracker=xfdashboard_window_tracker_get_default();
+ foundWindow=xfdashboard_window_tracker_gdk_get_window_for_wnck(XFDASHBOARD_WINDOW_TRACKER_GDK(windowTracker), parentWindow);
+ g_object_unref(windowTracker);
+
+ /* Return found window object */
+ return(foundWindow);
+}
+
+/* Get window state */
+static XfdashboardWindowTrackerWindowState _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_state(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* Return state of window */
+ return(priv->state);
+}
+
+/* Get window actions */
+static XfdashboardWindowTrackerWindowAction _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_actions(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* Return actions of window */
+ return(priv->actions);
+}
+
+/* Get name (title) of window */
+static const gchar* _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_name(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Check if window has a name to return and return name or NULL */
+ if(!wnck_window_has_name(priv->window)) return(NULL);
+
+ return(wnck_window_get_name(priv->window));
+}
+
+/* Get icon of window */
+static GdkPixbuf* _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_icon(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Return icon as pixbuf of window */
+ return(wnck_window_get_icon(priv->window));
+}
+
+static const gchar* _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_icon_name(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Check if window has an icon name to return and return icon name or NULL */
+ if(!wnck_window_has_icon_name(priv->window)) return(NULL);
+
+ return(wnck_window_get_icon_name(priv->window));
+}
+
+/* Get workspace where window is on */
+static XfdashboardWindowTrackerWorkspace* _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_workspace(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWorkspace *wantedWorkspace;
+ XfdashboardWindowTracker *windowTracker;
+ XfdashboardWindowTrackerWorkspace *foundWorkspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Get real wnck workspace of window to lookup a mapped and matching
+ * XfdashboardWindowTrackerWorkspace object.
+ * NOTE: Workspace may be NULL. In this case return NULL immediately and
+ * do not lookup a matching workspace object.
+ */
+ wantedWorkspace=wnck_window_get_workspace(priv->window);
+ if(!wantedWorkspace) return(NULL);
+
+ /* Get window tracker and lookup the mapped and matching XfdashboardWindowTrackerWorkspace
+ * for wnck workspace.
+ */
+ windowTracker=xfdashboard_window_tracker_get_default();
+ foundWorkspace=xfdashboard_window_tracker_gdk_get_workspace_for_wnck(XFDASHBOARD_WINDOW_TRACKER_GDK(windowTracker), wantedWorkspace);
+ g_object_unref(windowTracker);
+
+ /* Return found workspace */
+ return(foundWorkspace);
+}
+
+/* Determine if window is on requested workspace */
+static gboolean _xfdashboard_window_tracker_window_gdk_window_tracker_window_is_on_workspace(XfdashboardWindowTrackerWindow *inWindow,
+ XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWorkspace *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), FALSE);
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(FALSE);
+ }
+
+ /* Get wnck workspace to check if window is on this one */
+ workspace=xfdashboard_window_tracker_workspace_gdk_get_workspace(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace));
+ if(!workspace)
+ {
+ g_critical(_("Either no wnck workspace is wrapped at %s or workspace is not available anymore when called at function %s"),
+ G_OBJECT_TYPE_NAME(inWorkspace),
+ __func__);
+ return(FALSE);
+ }
+
+ /* Check if window is on that workspace */
+ return(wnck_window_is_on_workspace(priv->window, workspace));
+}
+
+/* Get geometry (position and size) of window */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_geometry(XfdashboardWindowTrackerWindow *inWindow,
+ gint *outX,
+ gint *outY,
+ gint *outWidth,
+ gint *outHeight)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ gint x, y, width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Get window geometry */
+ wnck_window_get_client_window_geometry(priv->window, &x, &y, &width, &height);
+
+ /* Set result */
+ if(outX) *outX=x;
+ if(outX) *outY=y;
+ if(outWidth) *outWidth=width;
+ if(outHeight) *outHeight=height;
+}
+
+/* Set geometry (position and size) of window */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_set_geometry(XfdashboardWindowTrackerWindow *inWindow,
+ gint inX,
+ gint inY,
+ gint inWidth,
+ gint inHeight)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWindowMoveResizeMask flags;
+ gint contentX, contentY;
+ gint contentWidth, contentHeight;
+ gint borderX, borderY;
+ gint borderWidth, borderHeight;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Get window border size to respect it when moving window */
+ wnck_window_get_client_window_geometry(priv->window, &contentX, &contentY, &contentWidth, &contentHeight);
+ wnck_window_get_geometry(priv->window, &borderX, &borderY, &borderWidth, &borderHeight);
+
+ /* Get modification flags */
+ flags=0;
+ if(inX>=0)
+ {
+ flags|=WNCK_WINDOW_CHANGE_X;
+ inX-=(contentX-borderX);
+ }
+
+ if(inY>=0)
+ {
+ flags|=WNCK_WINDOW_CHANGE_Y;
+ inY-=(contentY-borderY);
+ }
+
+ if(inWidth>=0)
+ {
+ flags|=WNCK_WINDOW_CHANGE_WIDTH;
+ inWidth+=(borderWidth-contentWidth);
+ }
+
+ if(inHeight>=0)
+ {
+ flags|=WNCK_WINDOW_CHANGE_HEIGHT;
+ inHeight+=(borderHeight-contentHeight);
+ }
+
+ /* Set geometry */
+ wnck_window_set_geometry(priv->window,
+ WNCK_WINDOW_GRAVITY_STATIC,
+ flags,
+ inX, inY, inWidth, inHeight);
+}
+
+/* Move window */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_move(XfdashboardWindowTrackerWindow *inWindow,
+ gint inX,
+ gint inY)
+{
+ _xfdashboard_window_tracker_window_gdk_window_tracker_window_set_geometry(inWindow, inX, inY, -1, -1);
+}
+
+/* Resize window */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_resize(XfdashboardWindowTrackerWindow *inWindow,
+ gint inWidth,
+ gint inHeight)
+{
+ _xfdashboard_window_tracker_window_gdk_window_tracker_window_set_geometry(inWindow, -1, -1, inWidth, inHeight);
+}
+
+/* Move a window to another workspace */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_move_to_workspace(XfdashboardWindowTrackerWindow *inWindow,
+ XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ WnckWorkspace *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Get wnck workspace to move window to */
+ workspace=xfdashboard_window_tracker_workspace_gdk_get_workspace(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace));
+ if(!workspace)
+ {
+ g_critical(_("Either no wnck workspace is wrapped at %s or workspace is not available anymore when called at function %s"),
+ G_OBJECT_TYPE_NAME(inWorkspace),
+ __func__);
+ return;
+ }
+
+ /* Move window to workspace */
+ wnck_window_move_to_workspace(priv->window, workspace);
+}
+
+/* Activate window with its transient windows */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_activate(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Activate window */
+ wnck_window_activate_transient(priv->window, xfdashboard_window_tracker_gdk_get_time());
+}
+
+/* Close window */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_close(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Close window */
+ wnck_window_close(priv->window, xfdashboard_window_tracker_gdk_get_time());
+}
+
+/* Get process ID owning the requested window */
+static gint _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_pid(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), -1);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(-1);
+ }
+
+ /* Return PID retrieved from wnck window */
+ return(wnck_window_get_pid(priv->window));
+}
+
+/* Get all possible instance name for window, e.g. class name, instance name.
+ * Caller is responsible to free result with g_strfreev() if not NULL.
+ */
+static gchar** _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_instance_names(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ GSList *names;
+ GSList *iter;
+ const gchar *value;
+ guint numberEntries;
+ gchar **result;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+ names=NULL;
+ result=NULL;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Add class name of window to list */
+ value=wnck_window_get_class_group_name(priv->window);
+ if(value) names=g_slist_prepend(names, g_strdup(value));
+
+ /* Add instance name of window to list */
+ value=wnck_window_get_class_instance_name(priv->window);
+ if(value) names=g_slist_prepend(names, g_strdup(value));
+
+ /* Add role of window to list */
+ value=wnck_window_get_role(priv->window);
+ if(value) names=g_slist_prepend(names, g_strdup(value));
+
+ /* If nothing was added to list of name, stop here and return */
+ if(!names) return(NULL);
+
+ /* Build result list as a NULL-terminated list of strings */
+ numberEntries=g_slist_length(names);
+
+ result=g_new(gchar*, numberEntries+1);
+ result[numberEntries]=NULL;
+ for(iter=names; iter; iter=g_slist_next(iter))
+ {
+ numberEntries--;
+ result[numberEntries]=iter->data;
+ }
+
+ /* Release allocated resources */
+ g_slist_free(names);
+
+ /* Return result list */
+ return(result);
+}
+
+/* Get content for this window for use in actors.
+ * Caller is responsible to remove reference with g_object_unref().
+ */
+static ClutterContent* _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_content(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Create content for window only if no content is already available. If it
+ * is available just return it with taking an extra reference on it.
+ */
+ if(!priv->content)
+ {
+ priv->content=xfdashboard_window_content_gdk_new_for_window(self);
+ g_object_add_weak_pointer(G_OBJECT(priv->content), (gpointer*)&priv->content);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Created content %s@%p for window %s@%p (wnck-window=%p)",
+ priv->content ? G_OBJECT_TYPE_NAME(priv->content) : "<unknown>", priv->content,
+ G_OBJECT_TYPE_NAME(self), self,
+ priv->window);
+ }
+ else
+ {
+ g_object_ref(priv->content);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Using cached content %s@%p (ref-count=%d) for window %s@%p (wnck-window=%p)",
+ priv->content ? G_OBJECT_TYPE_NAME(priv->content) : "<unknown>", priv->content,
+ priv->content ? G_OBJECT(priv->content)->ref_count : 0,
+ G_OBJECT_TYPE_NAME(self), self,
+ priv->window);
+ }
+
+ /* Return content */
+ return(priv->content);
+}
+
+/* Get associated stage of window */
+static ClutterStage* _xfdashboard_window_tracker_window_gdk_window_tracker_window_get_stage(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ ClutterStage *foundStage;
+ ClutterStage *stage;
+ GdkWindow *stageGdkWindow;
+ Window stageXWindow;
+ GSList *stages, *entry;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Iterate through stages and check if stage window matches requested one */
+ foundStage=NULL;
+ stages=clutter_stage_manager_list_stages(clutter_stage_manager_get_default());
+ for(entry=stages; !foundStage && entry; entry=g_slist_next(entry))
+ {
+ stage=CLUTTER_STAGE(entry->data);
+ if(stage)
+ {
+ stageGdkWindow=clutter_gdk_get_stage_window(stage);
+ stageXWindow=gdk_x11_window_get_xid(stageGdkWindow);
+ if(stageXWindow==wnck_window_get_xid(priv->window)) foundStage=stage;
+ }
+ }
+ g_slist_free(stages);
+
+ return(foundStage);
+}
+
+/* Set up and show window for use as stage */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_show_stage(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ XfdashboardWindowTracker *windowTracker;
+ GdkWindow *stageWindow;
+ WnckScreen *screen;
+ guint signalID;
+ gulong handlerID;
+ gint width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Get stage window */
+ stageWindow=clutter_gdk_get_stage_window(_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_stage(inWindow));
+
+ /* Get screen of window */
+ screen=wnck_window_get_screen(priv->window);
+
+ /* Window of stage should always be above all other windows, pinned to all
+ * workspaces, not be listed in window pager and set to fullscreen
+ */
+ gdk_window_set_skip_taskbar_hint(stageWindow, TRUE);
+ gdk_window_set_skip_pager_hint(stageWindow, TRUE);
+ gdk_window_set_keep_above(stageWindow, TRUE);
+ gdk_window_stick(stageWindow);
+#if GTK_CHECK_VERSION(3, 8, 0)
+ gdk_window_set_fullscreen_mode(stageWindow, GDK_FULLSCREEN_ON_ALL_MONITORS);
+#endif
+ gdk_window_fullscreen(stageWindow);
+
+ /* Connect signals if not already connected */
+ signalID=g_signal_lookup("state-changed", WNCK_TYPE_WINDOW);
+ handlerID=g_signal_handler_find(priv->window,
+ G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
+ signalID,
+ 0,
+ NULL,
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_state_changed),
+ NULL);
+ if(!handlerID)
+ {
+ g_signal_connect(priv->window,
+ "state-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_state_changed),
+ NULL);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Connecting signal to 'state-changed' at window %p (wnck-window=%p)",
+ self,
+ priv->window);
+ }
+
+ signalID=g_signal_lookup("active-window-changed", WNCK_TYPE_SCREEN);
+ handlerID=g_signal_handler_find(screen,
+ G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
+ signalID,
+ 0,
+ NULL,
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_active_window_changed),
+ NULL);
+ if(!handlerID)
+ {
+ g_signal_connect(screen,
+ "active-window-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_active_window_changed),
+ self);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Connecting signal to 'active-window-changed' at screen %p of window %p (wnck-window=%p)",
+ screen,
+ self,
+ priv->window);
+ }
+
+ windowTracker=xfdashboard_window_tracker_get_default();
+ signalID=g_signal_lookup("screen-size-changed", XFDASHBOARD_TYPE_WINDOW_TRACKER);
+ handlerID=g_signal_handler_find(windowTracker,
+ G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
+ signalID,
+ 0,
+ NULL,
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_screen_size_changed),
+ NULL);
+ if(!handlerID)
+ {
+ g_signal_connect(windowTracker,
+ "screen-size-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_screen_size_changed),
+ self);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Connecting signal to 'screen-size-changed' at window %p (wnck-window=%p)",
+ self,
+ priv->window);
+ }
+ xfdashboard_window_tracker_get_screen_size(windowTracker, &width, &height);
+ _xfdashboard_window_tracker_window_gdk_on_stage_screen_size_changed(windowTracker,
+ width,
+ height,
+ self);
+ g_object_unref(windowTracker);
+
+ /* Now the window is set up and we can show it */
+ gdk_window_show(stageWindow);
+}
+
+/* Unset up and hide stage window */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_hide_stage(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowGDK *self;
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+ XfdashboardWindowTracker *windowTracker;
+ GdkWindow *stageWindow;
+ WnckScreen *screen;
+ guint signalID;
+ gulong handlerID;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Get stage window */
+ stageWindow=clutter_gdk_get_stage_window(_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_stage(inWindow));
+
+ /* First hide window before removing signals etc. */
+ gdk_window_hide(stageWindow);
+
+ /* Get screen of window */
+ screen=wnck_window_get_screen(WNCK_WINDOW(priv->window));
+
+ /* Disconnect signals */
+ signalID=g_signal_lookup("state-changed", WNCK_TYPE_WINDOW);
+ handlerID=g_signal_handler_find(priv->window,
+ G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
+ signalID,
+ 0,
+ NULL,
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_state_changed),
+ NULL);
+ if(handlerID)
+ {
+ g_signal_handler_disconnect(priv->window, handlerID);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Disconnecting handler %lu for signal 'state-changed' at window %p (wnck-window=%p)",
+ handlerID,
+ self,
+ priv->window);
+ }
+
+ signalID=g_signal_lookup("active-window-changed", WNCK_TYPE_SCREEN);
+ handlerID=g_signal_handler_find(screen,
+ G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
+ signalID,
+ 0,
+ NULL,
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_active_window_changed),
+ NULL);
+ if(handlerID)
+ {
+ g_signal_handler_disconnect(screen, handlerID);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Disconnecting handler %lu for signal 'active-window-changed' at screen %p of window %p (wnck-window=%p)",
+ handlerID,
+ screen,
+ self,
+ priv->window);
+ }
+
+ windowTracker=xfdashboard_window_tracker_get_default();
+ signalID=g_signal_lookup("screen-size-changed", XFDASHBOARD_TYPE_WINDOW_TRACKER);
+ handlerID=g_signal_handler_find(windowTracker,
+ G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
+ signalID,
+ 0,
+ NULL,
+ G_CALLBACK(_xfdashboard_window_tracker_window_gdk_on_stage_screen_size_changed),
+ NULL);
+ if(handlerID)
+ {
+ g_signal_handler_disconnect(windowTracker, handlerID);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Disconnecting handler %lu for signal 'screen-size-changed' at window %p (wnck-window=%p)",
+ handlerID,
+ self,
+ priv->window);
+ }
+ g_object_unref(windowTracker);
+}
+
+/* Interface initialization
+ * Set up default functions
+ */
+static void _xfdashboard_window_tracker_window_gdk_window_tracker_window_iface_init(XfdashboardWindowTrackerWindowInterface *iface)
+{
+ iface->is_visible=_xfdashboard_window_tracker_window_gdk_window_tracker_window_is_visible;
+ iface->show=_xfdashboard_window_tracker_window_gdk_window_tracker_window_show;
+ iface->hide=_xfdashboard_window_tracker_window_gdk_window_tracker_window_hide;
+
+ iface->get_parent=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_parent;
+
+ iface->get_state=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_state;
+ iface->get_actions=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_actions;
+
+ iface->get_name=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_name;
+
+ iface->get_icon=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_icon;
+ iface->get_icon_name=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_icon_name;
+
+ iface->get_workspace=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_workspace;
+ iface->is_on_workspace=_xfdashboard_window_tracker_window_gdk_window_tracker_window_is_on_workspace;
+
+ iface->get_geometry=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_geometry;
+ iface->set_geometry=_xfdashboard_window_tracker_window_gdk_window_tracker_window_set_geometry;
+ iface->move=_xfdashboard_window_tracker_window_gdk_window_tracker_window_move;
+ iface->resize=_xfdashboard_window_tracker_window_gdk_window_tracker_window_resize;
+ iface->move_to_workspace=_xfdashboard_window_tracker_window_gdk_window_tracker_window_move_to_workspace;
+ iface->activate=_xfdashboard_window_tracker_window_gdk_window_tracker_window_activate;
+ iface->close=_xfdashboard_window_tracker_window_gdk_window_tracker_window_close;
+
+ iface->get_pid=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_pid;
+ iface->get_instance_names=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_instance_names;
+
+ iface->get_content=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_content;
+
+ iface->get_stage=_xfdashboard_window_tracker_window_gdk_window_tracker_window_get_stage;
+ iface->show_stage=_xfdashboard_window_tracker_window_gdk_window_tracker_window_show_stage;
+ iface->hide_stage=_xfdashboard_window_tracker_window_gdk_window_tracker_window_hide_stage;
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_tracker_window_gdk_dispose(GObject *inObject)
+{
+ XfdashboardWindowTrackerWindowGDK *self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inObject);
+ XfdashboardWindowTrackerWindowGDKPrivate *priv=self->priv;
+
+ /* Dispose allocated resources */
+ if(priv->content)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Removing cached content with ref-count %d from %s@%p for wnck-window %p",
+ G_OBJECT(priv->content)->ref_count,
+ G_OBJECT_TYPE_NAME(self), self,
+ priv->window);
+ g_object_remove_weak_pointer(G_OBJECT(priv->content), (gpointer*)&priv->content);
+ priv->content=NULL;
+ }
+
+ if(priv->window)
+ {
+ /* Remove weak reference at current window */
+ g_object_remove_weak_pointer(G_OBJECT(priv->window), (gpointer*)&priv->window);
+
+ /* Disconnect signal handlers */
+ g_signal_handlers_disconnect_by_data(priv->window, self);
+ priv->window=NULL;
+ }
+
+ /* Call parent's class dispose method */
+ G_OBJECT_CLASS(xfdashboard_window_tracker_window_gdk_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_tracker_window_gdk_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerWindowGDK *self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_WINDOW:
+ _xfdashboard_window_tracker_window_gdk_set_window(self, WNCK_WINDOW(g_value_get_object(inValue)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+static void _xfdashboard_window_tracker_window_gdk_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerWindowGDK *self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_WINDOW:
+ g_value_set_object(outValue, self->priv->window);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+/* Class initialization
+ * Override functions in parent classes and define properties
+ * and signals
+ */
+void xfdashboard_window_tracker_window_gdk_class_init(XfdashboardWindowTrackerWindowGDKClass *klass)
+{
+ GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
+ XfdashboardWindowTracker *windowIface;
+ GParamSpec *paramSpec;
+
+ /* Reference interface type to lookup properties etc. */
+ windowIface=g_type_default_interface_ref(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW);
+
+ /* Override functions */
+ gobjectClass->dispose=_xfdashboard_window_tracker_window_gdk_dispose;
+ gobjectClass->set_property=_xfdashboard_window_tracker_window_gdk_set_property;
+ gobjectClass->get_property=_xfdashboard_window_tracker_window_gdk_get_property;
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowTrackerWindowGDKPrivate));
+
+ /* Define properties */
+ XfdashboardWindowTrackerWindowGDKProperties[PROP_WINDOW]=
+ g_param_spec_object("window",
+ _("Window"),
+ _("The mapped wnck window"),
+ WNCK_TYPE_WINDOW,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ paramSpec=g_object_interface_find_property(windowIface, "state");
+ XfdashboardWindowTrackerWindowGDKProperties[PROP_STATE]=
+ g_param_spec_override("state", paramSpec);
+
+ paramSpec=g_object_interface_find_property(windowIface, "actions");
+ XfdashboardWindowTrackerWindowGDKProperties[PROP_ACTIONS]=
+ g_param_spec_override("actions", paramSpec);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowTrackerWindowGDKProperties);
+
+ /* Release allocated resources */
+ g_type_default_interface_unref(windowIface);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_window_tracker_window_gdk_init(XfdashboardWindowTrackerWindowGDK *self)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_GET_PRIVATE(self);
+
+ /* Set default values */
+ priv->window=NULL;
+ priv->content=NULL;
+}
+
+
+/* IMPLEMENTATION: Public API */
+
+/**
+ * xfdashboard_window_tracker_window_gdk_get_window:
+ * @self: A #XfdashboardWindowTrackerWindowGDK
+ *
+ * Returns the wrapped window of libwnck.
+ *
+ * Return value: (transfer none): the #WnckWindow wrapped by @self. The returned
+ * #WnckWindow is owned by libwnck and must not be referenced or unreferenced.
+ */
+WnckWindow* xfdashboard_window_tracker_window_gdk_get_window(XfdashboardWindowTrackerWindowGDK *self)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self), NULL);
+
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Return wrapped libwnck window */
+ return(priv->window);
+}
+
+/**
+ * xfdashboard_window_tracker_window_gdk_get_xid:
+ * @self: A #XfdashboardWindowTrackerWindowGDK
+ *
+ * Gets the X window ID of the wrapped libwnck's window at @self.
+ *
+ * Return value: the X window ID of @self.
+ **/
+gulong xfdashboard_window_tracker_window_gdk_get_xid(XfdashboardWindowTrackerWindowGDK *self)
+{
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(self), None);
+
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_WARN_NO_WINDOW(self);
+ return(None);
+ }
+
+ /* Return X window ID */
+ return(wnck_window_get_xid(priv->window));
+}
diff --git a/libxfdashboard/gdk/window-tracker-window-gdk.h b/libxfdashboard/gdk/window-tracker-window-gdk.h
new file mode 100644
index 0000000..38cba99
--- /dev/null
+++ b/libxfdashboard/gdk/window-tracker-window-gdk.h
@@ -0,0 +1,82 @@
+/*
+ * window-tracker-window: A window tracked by window tracker and also
+ * a wrapper class around WnckWindow.
+ * By wrapping libwnck objects we can use a virtual
+ * stable API while the API in libwnck changes
+ * within versions. We only need to use #ifdefs in
+ * window tracker object and nowhere else in the code.
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifndef __LIBXFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK__
+#define __LIBXFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK__
+
+#if !defined(__LIBXFDASHBOARD_H_INSIDE__) && !defined(LIBXFDASHBOARD_COMPILATION)
+#error "Only <libxfdashboard/libxfdashboard.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+G_BEGIN_DECLS
+
+#define XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK (xfdashboard_window_tracker_window_gdk_get_type())
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK, XfdashboardWindowTrackerWindowGDK))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK))
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK, XfdashboardWindowTrackerWindowGDKClass))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK))
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_GDK, XfdashboardWindowTrackerWindowGDKClass))
+
+typedef struct _XfdashboardWindowTrackerWindowGDK XfdashboardWindowTrackerWindowGDK;
+typedef struct _XfdashboardWindowTrackerWindowGDKClass XfdashboardWindowTrackerWindowGDKClass;
+typedef struct _XfdashboardWindowTrackerWindowGDKPrivate XfdashboardWindowTrackerWindowGDKPrivate;
+
+struct _XfdashboardWindowTrackerWindowGDK
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowTrackerWindowGDKPrivate *priv;
+};
+
+struct _XfdashboardWindowTrackerWindowGDKClass
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+};
+
+/* Public API */
+GType xfdashboard_window_tracker_window_gdk_get_type(void) G_GNUC_CONST;
+
+WnckWindow* xfdashboard_window_tracker_window_gdk_get_window(XfdashboardWindowTrackerWindowGDK *self);
+gulong xfdashboard_window_tracker_window_gdk_get_xid(XfdashboardWindowTrackerWindowGDK *self);
+
+G_END_DECLS
+
+#endif /* __LIBXFDASHBOARD_WINDOW_TRACKER_WINDOW_GDK__ */
diff --git a/libxfdashboard/gdk/window-tracker-workspace-gdk.c b/libxfdashboard/gdk/window-tracker-workspace-gdk.c
new file mode 100644
index 0000000..489f449
--- /dev/null
+++ b/libxfdashboard/gdk/window-tracker-workspace-gdk.c
@@ -0,0 +1,442 @@
+/*
+ * window-tracker-workspace: A workspace tracked by window tracker and
+ * also a wrapper class around WnckWorkspace.
+ * By wrapping libwnck objects we can use a
+ * virtual stable API while the API in libwnck
+ * changes within versions. We only need to
+ * use #ifdefs in window tracker object and
+ * nowhere else in the code.
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+/**
+ * SECTION:window-tracker-workspace-gdk
+ * @short_description: A workspace used by GDK window tracker
+ * @include: xfdashboard/gdk/window-tracker-workspace-gdk.h
+ *
+ * This is the GDK backend of #XfdashboardWindowTrackerWorkspace
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libxfdashboard/gdk/window-tracker-workspace-gdk.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+#include <glib/gi18n-lib.h>
+
+#include <libxfdashboard/gdk/window-tracker-gdk.h>
+#include <libxfdashboard/window-tracker.h>
+#include <libxfdashboard/marshal.h>
+#include <libxfdashboard/compat.h>
+
+
+/* Define this class in GObject system */
+static void _xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_iface_init(XfdashboardWindowTrackerWorkspaceInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerWorkspaceGDK,
+ xfdashboard_window_tracker_workspace_gdk,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE, _xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK, XfdashboardWindowTrackerWorkspaceGDKPrivate))
+
+struct _XfdashboardWindowTrackerWorkspaceGDKPrivate
+{
+ /* Properties related */
+ WnckWorkspace *workspace;
+};
+
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ PROP_WORKSPACE,
+
+ PROP_LAST
+};
+
+static GParamSpec* XfdashboardWindowTrackerWorkspaceGDKProperties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_NO_WORKSPACE(self) \
+ g_critical(_("No wnck workspace wrapped at %s in called function %s"), \
+ G_OBJECT_TYPE_NAME(self), \
+ __func__);
+
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_WRONG_WORKSPACE(self) \
+ g_critical(_("Got signal from wrong wnck workspace wrapped at %s in called function %s"),\
+ G_OBJECT_TYPE_NAME(self), \
+ __func__);
+
+/* Proxy signal for mapped wnck window which changed name */
+static void _xfdashboard_window_tracker_workspace_gdk_on_wnck_name_changed(XfdashboardWindowTrackerWorkspaceGDK *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+ WnckWorkspace *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(self));
+ g_return_if_fail(WNCK_IS_WORKSPACE(inUserData));
+
+ priv=self->priv;
+ workspace=WNCK_WORKSPACE(inUserData);
+
+ /* Check that workspace emitting this signal is the mapped workspace of this object */
+ if(priv->workspace!=workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_WRONG_WORKSPACE(self);
+ return;
+ }
+
+ /* Proxy signal */
+ g_signal_emit_by_name(self, "name-changed");
+}
+
+/* Set wnck workspace to map in this workspace object */
+static void _xfdashboard_window_tracker_workspace_gdk_set_workspace(XfdashboardWindowTrackerWorkspaceGDK *self,
+ WnckWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(self));
+ g_return_if_fail(!inWorkspace || WNCK_IS_WORKSPACE(inWorkspace));
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->workspace!=inWorkspace)
+ {
+ /* Disconnect signals to old window (if available) and reset states */
+ if(priv->workspace)
+ {
+ /* Remove weak reference at old workspace */
+ g_object_remove_weak_pointer(G_OBJECT(priv->workspace), (gpointer*)&priv->workspace);
+
+ /* Disconnect signal handlers */
+ g_signal_handlers_disconnect_by_data(priv->workspace, self);
+ priv->workspace=NULL;
+ }
+
+ /* Set new value */
+ priv->workspace=inWorkspace;
+
+ /* Initialize states and connect signals if window is set */
+ if(priv->workspace)
+ {
+ /* Add weak reference at new workspace */
+ g_object_add_weak_pointer(G_OBJECT(priv->workspace), (gpointer*)&priv->workspace);
+
+ /* Connect signals */
+ g_signal_connect_swapped(priv->workspace,
+ "name-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_workspace_gdk_on_wnck_name_changed),
+ self);
+ }
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerWorkspaceGDKProperties[PROP_WORKSPACE]);
+ }
+}
+
+
+/* IMPLEMENTATION: Interface XfdashboardWindowTrackerWorkspace */
+
+/* Get number of workspace */
+static gint _xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_get_number(XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *self;
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace), -1);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_NO_WORKSPACE(self);
+ return(-1);
+ }
+
+ /* Return number of workspace */
+ return(wnck_workspace_get_number(priv->workspace));
+}
+
+/* Get name of workspace */
+static const gchar* _xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_get_name(XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *self;
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_NO_WORKSPACE(self);
+ return(NULL);
+ }
+
+ /* Return name of workspace */
+ return(wnck_workspace_get_name(priv->workspace));
+}
+
+/* Get size of workspace */
+static void _xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_get_size(XfdashboardWindowTrackerWorkspace *inWorkspace,
+ gint *outWidth,
+ gint *outHeight)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *self;
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+ gint width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_NO_WORKSPACE(self);
+ return;
+ }
+
+ /* Get width and height of workspace */
+ width=wnck_workspace_get_width(priv->workspace);
+ height=wnck_workspace_get_height(priv->workspace);
+
+ /* Set values */
+ if(outWidth) *outWidth=width;
+ if(outHeight) *outHeight=height;
+}
+
+/* Determine if this workspace is the active one */
+static gboolean _xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_is_active(XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *self;
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+ XfdashboardWindowTracker *windowTracker;
+ XfdashboardWindowTrackerWorkspace *activeWorkspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_NO_WORKSPACE(self);
+ return(FALSE);
+ }
+
+ /* Get current active workspace */
+ windowTracker=xfdashboard_window_tracker_get_default();
+ activeWorkspace=xfdashboard_window_tracker_get_active_workspace(windowTracker);
+ g_object_unref(windowTracker);
+
+ /* Return TRUE if current active workspace is this workspace */
+ return(xfdashboard_window_tracker_workspace_is_equal(inWorkspace, activeWorkspace));
+}
+
+/* Activate workspace */
+static void _xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_activate(XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *self;
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_NO_WORKSPACE(self);
+ return;
+ }
+
+ /* Activate workspace */
+ wnck_workspace_activate(priv->workspace, xfdashboard_window_tracker_gdk_get_time());
+}
+
+/* Interface initialization
+ * Set up default functions
+ */
+static void _xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_iface_init(XfdashboardWindowTrackerWorkspaceInterface *iface)
+{
+ iface->get_number=_xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_get_number;
+ iface->get_name=_xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_get_name;
+
+ iface->get_size=_xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_get_size;
+
+ iface->is_active=_xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_is_active;
+ iface->activate=_xfdashboard_window_tracker_workspace_gdk_window_tracker_workspace_activate;
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_tracker_workspace_gdk_dispose(GObject *inObject)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inObject);
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv=self->priv;
+
+ /* Dispose allocated resources */
+ if(priv->workspace)
+ {
+ /* Remove weak reference at current workspace */
+ g_object_remove_weak_pointer(G_OBJECT(priv->workspace), (gpointer*)&priv->workspace);
+
+ /* Disconnect signal handlers */
+ g_signal_handlers_disconnect_by_data(priv->workspace, self);
+ priv->workspace=NULL;
+ }
+
+ /* Call parent's class dispose method */
+ G_OBJECT_CLASS(xfdashboard_window_tracker_workspace_gdk_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_tracker_workspace_gdk_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_WORKSPACE:
+ _xfdashboard_window_tracker_workspace_gdk_set_workspace(self, WNCK_WORKSPACE(g_value_get_object(inValue)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+static void _xfdashboard_window_tracker_workspace_gdk_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerWorkspaceGDK *self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_WORKSPACE:
+ g_value_set_object(outValue, self->priv->workspace);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+ break;
+ }
+}
+
+/* Class initialization
+ * Override functions in parent classes and define properties
+ * and signals
+ */
+void xfdashboard_window_tracker_workspace_gdk_class_init(XfdashboardWindowTrackerWorkspaceGDKClass *klass)
+{
+ GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
+
+ /* Override functions */
+ gobjectClass->dispose=_xfdashboard_window_tracker_workspace_gdk_dispose;
+ gobjectClass->set_property=_xfdashboard_window_tracker_workspace_gdk_set_property;
+ gobjectClass->get_property=_xfdashboard_window_tracker_workspace_gdk_get_property;
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowTrackerWorkspaceGDKPrivate));
+
+ /* Define properties */
+ XfdashboardWindowTrackerWorkspaceGDKProperties[PROP_WORKSPACE]=
+ g_param_spec_object("workspace",
+ _("Window"),
+ _("The mapped wnck workspace"),
+ WNCK_TYPE_WORKSPACE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowTrackerWorkspaceGDKProperties);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_window_tracker_workspace_gdk_init(XfdashboardWindowTrackerWorkspaceGDK *self)
+{
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_GET_PRIVATE(self);
+
+ /* Set default values */
+ priv->workspace=NULL;
+}
+
+
+/* IMPLEMENTATION: Public API */
+
+/**
+ * xfdashboard_window_tracker_workspace_gdk_get_workspace:
+ * @self: A #XfdashboardWindowTrackerWorkspaceGDK
+ *
+ * Returns the wrapped workspace of libwnck.
+ *
+ * Return value: (transfer none): the #WnckWorkspace wrapped by @self. The returned
+ * #WnckWorkspace is owned by libwnck and must not be referenced or unreferenced.
+ */
+WnckWorkspace* xfdashboard_window_tracker_workspace_gdk_get_workspace(XfdashboardWindowTrackerWorkspaceGDK *self)
+{
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(self), NULL);
+
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_WARN_NO_WORKSPACE(self);
+ return(NULL);
+ }
+
+ /* Return wrapped libwnck workspace */
+ return(priv->workspace);
+}
diff --git a/libxfdashboard/gdk/window-tracker-workspace-gdk.h b/libxfdashboard/gdk/window-tracker-workspace-gdk.h
new file mode 100644
index 0000000..2d93c31
--- /dev/null
+++ b/libxfdashboard/gdk/window-tracker-workspace-gdk.h
@@ -0,0 +1,82 @@
+/*
+ * window-tracker-workspace: A workspace tracked by window tracker and
+ * also a wrapper class around WnckWorkspace.
+ * By wrapping libwnck objects we can use a
+ * virtual stable API while the API in libwnck
+ * changes within versions. We only need to
+ * use #ifdefs in window tracker object and
+ * nowhere else in the code.
+ *
+ * Copyright 2012-2017 Stephan Haller <nomad at froevel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifndef __LIBXFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK__
+#define __LIBXFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK__
+
+#if !defined(__LIBXFDASHBOARD_H_INSIDE__) && !defined(LIBXFDASHBOARD_COMPILATION)
+#error "Only <libxfdashboard/libxfdashboard.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+G_BEGIN_DECLS
+
+#define XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK (xfdashboard_window_tracker_workspace_gdk_get_type())
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK, XfdashboardWindowTrackerWorkspaceGDK))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK))
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK, XfdashboardWindowTrackerWorkspaceGDKClass))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK))
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_GDK, XfdashboardWindowTrackerWorkspaceGDKClass))
+
+typedef struct _XfdashboardWindowTrackerWorkspaceGDK XfdashboardWindowTrackerWorkspaceGDK;
+typedef struct _XfdashboardWindowTrackerWorkspaceGDKClass XfdashboardWindowTrackerWorkspaceGDKClass;
+typedef struct _XfdashboardWindowTrackerWorkspaceGDKPrivate XfdashboardWindowTrackerWorkspaceGDKPrivate;
+
+struct _XfdashboardWindowTrackerWorkspaceGDK
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowTrackerWorkspaceGDKPrivate *priv;
+};
+
+struct _XfdashboardWindowTrackerWorkspaceGDKClass
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+};
+
+/* Public API */
+GType xfdashboard_window_tracker_workspace_gdk_get_type(void) G_GNUC_CONST;
+
+WnckWorkspace* xfdashboard_window_tracker_workspace_gdk_get_workspace(XfdashboardWindowTrackerWorkspaceGDK *self);
+
+G_END_DECLS
+
+#endif /* __LIBXFDASHBOARD_WINDOW_TRACKER_WORKSPACE_GDK__ */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the Xfce4-commits
mailing list