[Xfce4-commits] [apps/xfdashboard] 01/08: Add new X11 specific window tracker and window content classes
noreply at xfce.org
noreply at xfce.org
Tue Apr 4 18:41:52 CEST 2017
This is an automated email from the git hooks/post-receive script.
nomad pushed a commit to branch master
in repository apps/xfdashboard.
commit db70887e50f7cec64f45ed6a5d6924738f33a625
Author: Stephan Haller <nomad at froevel.de>
Date: Tue Apr 4 17:25:26 2017 +0200
Add new X11 specific window tracker and window content classes
---
libxfdashboard/x11/window-content-x11.c | 2701 +++++++++++++++++++++
libxfdashboard/x11/window-content-x11.h | 111 +
libxfdashboard/x11/window-tracker-monitor-x11.c | 393 +++
libxfdashboard/x11/window-tracker-monitor-x11.h | 76 +
libxfdashboard/x11/window-tracker-window-x11.c | 1811 ++++++++++++++
libxfdashboard/x11/window-tracker-window-x11.h | 82 +
libxfdashboard/x11/window-tracker-workspace-x11.c | 442 ++++
libxfdashboard/x11/window-tracker-workspace-x11.h | 82 +
libxfdashboard/x11/window-tracker-x11.c | 1890 ++++++++++++++
libxfdashboard/x11/window-tracker-x11.h | 90 +
10 files changed, 7678 insertions(+)
diff --git a/libxfdashboard/x11/window-content-x11.c b/libxfdashboard/x11/window-content-x11.c
new file mode 100644
index 0000000..81d2bcf
--- /dev/null
+++ b/libxfdashboard/x11/window-content-x11.c
@@ -0,0 +1,2701 @@
+/*
+ * 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/x11/window-content-x11.h>
+
+#include <glib/gi18n-lib.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/x11/window-tracker-window-x11.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_X11_WORKAROUND_MODE >*/
+{
+ XFDASHBOARD_WINDOW_CONTENT_X11_WORKAROUND_MODE_NONE=0,
+ XFDASHBOARD_WINDOW_CONTENT_X11_WORKAROUND_MODE_UNMINIMIZING,
+ XFDASHBOARD_WINDOW_CONTENT_X11_WORKAROUND_MODE_REMINIMIZING,
+ XFDASHBOARD_WINDOW_CONTENT_X11_WORKAROUND_MODE_DONE
+} XfdashboardWindowContentX11WorkaroundMode;
+
+/* Define this class in GObject system */
+static void _xfdashboard_window_content_clutter_content_iface_init(ClutterContentIface *iface);
+static void _xfdashboard_window_content_x11_stylable_iface_init(XfdashboardStylableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowContentX11,
+ xfdashboard_window_content_x11,
+ 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_x11_stylable_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_CONTENT_X11_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_CONTENT_X11, XfdashboardWindowContentX11Private))
+
+struct _XfdashboardWindowContentX11Private
+{
+ /* Properties related */
+ XfdashboardWindowTrackerWindowX11 *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;
+ XfdashboardWindowContentX11WorkaroundMode 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* XfdashboardWindowContentX11Properties[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_X11_CREATION_PRIORITY "immediate"
+
+struct _XfdashboardWindowContentX11PriorityMap
+{
+ const gchar *name;
+ gint priority;
+};
+typedef struct _XfdashboardWindowContentX11PriorityMap XfdashboardWindowContentX11PriorityMap;
+
+static gboolean _xfdashboard_window_content_x11_have_checked_extensions=FALSE;
+static gboolean _xfdashboard_window_content_x11_have_composite_extension=FALSE;
+static gboolean _xfdashboard_window_content_x11_have_damage_extension=FALSE;
+static int _xfdashboard_window_content_x11_damage_event_base=0;
+
+static GHashTable* _xfdashboard_window_content_x11_cache=NULL;
+static guint _xfdashboard_window_content_x11_cache_shutdown_signal_id=0;
+
+static GList* _xfdashboard_window_content_x11_resume_idle_queue=NULL;
+static guint _xfdashboard_window_content_x11_resume_idle_id=0;
+static guint _xfdashboard_window_content_x11_resume_shutdown_signal_id=0;
+
+static guint _xfdashboard_window_content_x11_xfconf_priority_notify_id=0;
+static gint _xfdashboard_window_content_x11_window_creation_priority=-1;
+static XfdashboardWindowContentX11PriorityMap _xfdashboard_window_content_x11_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_x11_window_creation_shutdown_signal_id=0;
+
+/* Forward declarations */
+static void _xfdashboard_window_content_x11_suspend(XfdashboardWindowContentX11 *self);
+static void _xfdashboard_window_content_x11_resume(XfdashboardWindowContentX11 *self);
+static gboolean _xfdashboard_window_content_x11_resume_on_idle(gpointer inUserData);
+
+/* Remove all entries from resume queue and release all allocated resources */
+static void _xfdashboard_window_content_x11_destroy_resume_queue(void)
+{
+ XfdashboardApplication *application;
+ gint queueSize;
+
+ /* Disconnect application "shutdown" signal handler */
+ if(_xfdashboard_window_content_x11_resume_shutdown_signal_id)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Disconnecting shutdown signal handler %u because of resume queue destruction",
+ _xfdashboard_window_content_x11_resume_shutdown_signal_id);
+
+ application=xfdashboard_application_get_default();
+ g_signal_handler_disconnect(application, _xfdashboard_window_content_x11_resume_shutdown_signal_id);
+ _xfdashboard_window_content_x11_resume_shutdown_signal_id=0;
+ }
+
+ /* Remove idle source if available */
+ if(_xfdashboard_window_content_x11_resume_idle_id)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Removing resume window content idle source with ID %u",
+ _xfdashboard_window_content_x11_resume_idle_id);
+
+ g_source_remove(_xfdashboard_window_content_x11_resume_idle_id);
+ _xfdashboard_window_content_x11_resume_idle_id=0;
+ }
+
+ /* Destroy resume-on-idle queue if available*/
+ if(_xfdashboard_window_content_x11_resume_idle_queue)
+ {
+ queueSize=g_list_length(_xfdashboard_window_content_x11_resume_idle_queue);
+ if(queueSize>0) g_warning(_("Destroying window content resume queue containing %d windows."), queueSize);
+#ifdef DEBUG
+ if(queueSize>0)
+ {
+ GList *iter;
+ XfdashboardWindowContentX11 *content;
+ XfdashboardWindowTrackerWindow *window;
+
+ for(iter=_xfdashboard_window_content_x11_resume_idle_queue; iter; iter=g_list_next(iter))
+ {
+ content=XFDASHBOARD_WINDOW_CONTENT_X11(iter->data);
+ window=xfdashboard_window_content_x11_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_x11_resume_idle_queue);
+ _xfdashboard_window_content_x11_resume_idle_queue=NULL;
+ }
+}
+
+/* Remove window content from resume on idle queue */
+static void _xfdashboard_window_content_x11_resume_on_idle_remove(XfdashboardWindowContentX11 *self)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self));
+
+ priv=self->priv;
+
+ /* Remove window content from queue */
+ if(_xfdashboard_window_content_x11_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_x11_resume_idle_queue, self);
+ if(queueEntry)
+ {
+ /* Remove window content from queue */
+ _xfdashboard_window_content_x11_resume_idle_queue=g_list_delete_link(_xfdashboard_window_content_x11_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_x11_resume_idle_queue &&
+ _xfdashboard_window_content_x11_resume_idle_id)
+ {
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Removing idle source with ID %u because queue is empty",
+ _xfdashboard_window_content_x11_resume_idle_id);
+
+ g_source_remove(_xfdashboard_window_content_x11_resume_idle_id);
+ _xfdashboard_window_content_x11_resume_idle_id=0;
+ }
+}
+
+/* Add window content to resume on idle queue */
+static void _xfdashboard_window_content_x11_resume_on_idle_add(XfdashboardWindowContentX11 *self)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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_x11_resume_idle_queue, self))
+ {
+ /* Queue window content for resume */
+ _xfdashboard_window_content_x11_resume_idle_queue=g_list_append(_xfdashboard_window_content_x11_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_x11_resume_idle_queue &&
+ !_xfdashboard_window_content_x11_resume_idle_id)
+ {
+ _xfdashboard_window_content_x11_resume_idle_id=clutter_threads_add_idle_full(_xfdashboard_window_content_x11_window_creation_priority,
+ _xfdashboard_window_content_x11_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_x11_resume_idle_id,
+ _xfdashboard_window_content_x11_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_x11_resume_shutdown_signal_id)
+ {
+ XfdashboardApplication *application;
+
+ application=xfdashboard_application_get_default();
+ _xfdashboard_window_content_x11_resume_shutdown_signal_id=g_signal_connect(application,
+ "shutdown-final",
+ G_CALLBACK(_xfdashboard_window_content_x11_destroy_resume_queue),
+ NULL);
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Connected to shutdown signal with handler ID %u for resume queue destruction",
+ _xfdashboard_window_content_x11_resume_shutdown_signal_id);
+ }
+}
+
+/* Value for window creation priority in xfconf has changed */
+static void _xfdashboard_window_content_x11_on_window_creation_priority_value_changed(XfconfChannel *inChannel,
+ const gchar *inProperty,
+ const GValue *inValue,
+ gpointer inUserData)
+{
+ const gchar *priorityValue;
+ XfdashboardWindowContentX11PriorityMap *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_x11_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_x11_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_x11_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_x11_on_window_creation_priority_shutdown(void)
+{
+ XfdashboardApplication *application;
+
+ /* Disconnect application "shutdown" signal handler */
+ if(_xfdashboard_window_content_x11_window_creation_shutdown_signal_id)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS,
+ "Disconnecting shutdown signal handler %u for window creation priority value change notifications",
+ _xfdashboard_window_content_x11_window_creation_shutdown_signal_id);
+
+ application=xfdashboard_application_get_default();
+ g_signal_handler_disconnect(application, _xfdashboard_window_content_x11_window_creation_shutdown_signal_id);
+ _xfdashboard_window_content_x11_window_creation_shutdown_signal_id=0;
+ }
+
+ /* Disconnect property changed signal handler */
+ if(_xfdashboard_window_content_x11_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_x11_xfconf_priority_notify_id);
+
+ xfconfChannel=xfdashboard_application_get_xfconf_channel(NULL);
+ g_signal_handler_disconnect(xfconfChannel, _xfdashboard_window_content_x11_xfconf_priority_notify_id);
+ _xfdashboard_window_content_x11_xfconf_priority_notify_id=0;
+ }
+}
+
+/* Check if we should workaround unmapped window for requested window and set up workaround */
+static void _xfdashboard_window_content_x11_on_workaround_state_changed(XfdashboardWindowContentX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowContentX11Private *priv;
+ XfdashboardWindowTrackerWindowState windowState;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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_X11_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_X11_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_X11_WORKAROUND_MODE_REMINIMIZING;
+ }
+ break;
+
+ case XFDASHBOARD_WINDOW_CONTENT_X11_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_X11_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_x11_setup_workaround(XfdashboardWindowContentX11 *self, XfdashboardWindowTrackerWindowX11 *inWindow)
+{
+ XfdashboardWindowContentX11Private *priv;
+ gboolean doWorkaround;
+ XfdashboardWindowTrackerWindowState windowState;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self));
+ g_return_if_fail(inWindow!=NULL && XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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_X11_WORKAROUND_MODE_NONE) return;
+
+ /* Set flag that workaround is (going to be) set up */
+ priv->workaroundMode=XFDASHBOARD_WINDOW_CONTENT_X11_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_x11_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_x11_check_extension(void)
+{
+ Display *display G_GNUC_UNUSED;
+#ifdef HAVE_XDAMAGE
+ int damageError=0;
+#endif
+#ifdef HAVE_XCOMPOSITE
+ int compositeMajor, compositeMinor;
+#endif
+
+ /* Check if we have already checked extensions */
+ if(_xfdashboard_window_content_x11_have_checked_extensions!=FALSE) return;
+
+ /* Mark that we have check for extensions regardless of any error*/
+ _xfdashboard_window_content_x11_have_checked_extensions=TRUE;
+
+ /* Get display */
+ display=clutter_x11_get_default_display();
+
+ /* Check for composite extenstion */
+ _xfdashboard_window_content_x11_have_composite_extension=FALSE;
+#ifdef HAVE_XCOMPOSITE
+ if(clutter_x11_has_composite_extension())
+ {
+ compositeMajor=compositeMinor=0;
+ if(XCompositeQueryVersion(display, &compositeMajor, &compositeMinor))
+ {
+ if(compositeMajor>=COMPOSITE_VERSION_MIN_MAJOR && compositeMinor>=COMPOSITE_VERSION_MIN_MINOR)
+ {
+ _xfdashboard_window_content_x11_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_x11_have_damage_extension=FALSE;
+ _xfdashboard_window_content_x11_damage_event_base=0;
+
+#ifdef HAVE_XDAMAGE
+ if(!XDamageQueryExtension(display, &_xfdashboard_window_content_x11_damage_event_base, &damageError))
+ {
+ g_warning(_("Query for X damage extension resulted in error code %d - using only still images of windows"), damageError);
+ }
+ else _xfdashboard_window_content_x11_have_damage_extension=TRUE;
+#endif
+}
+
+/* Suspension state of application changed */
+static void _xfdashboard_window_content_x11_on_application_suspended_changed(XfdashboardWindowContentX11 *self,
+ GParamSpec *inSpec,
+ gpointer inUserData)
+{
+ XfdashboardWindowContentX11Private *priv;
+ XfdashboardApplication *app;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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_x11_suspend(self);
+ }
+ /* ... otherwise resume window if it is mapped */
+ else
+ {
+ if(priv->isMapped) _xfdashboard_window_content_x11_resume(self);
+ }
+}
+
+/* Filter X events for damages */
+static ClutterX11FilterReturn _xfdashboard_window_content_x11_on_x_event(XEvent *inXEvent, ClutterEvent *inEvent, gpointer inUserData)
+{
+ XfdashboardWindowContentX11 *self;
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(inUserData), CLUTTER_X11_FILTER_CONTINUE);
+
+ self=XFDASHBOARD_WINDOW_CONTENT_X11(inUserData);
+ priv=self->priv;
+
+ /* Check for mapped, unmapped related X events as pixmap, damage, texture etc.
+ * needs to get resumed (acquired) or suspended (released)
+ */
+ if(inXEvent->xany.window==priv->xWindowID)
+ {
+ switch(inXEvent->type)
+ {
+ case MapNotify:
+ case ConfigureNotify:
+ priv->isMapped=TRUE;
+ if(!priv->isAppSuspended) _xfdashboard_window_content_x11_resume(self);
+ break;
+
+ case UnmapNotify:
+ case DestroyNotify:
+ priv->isMapped=FALSE;
+ _xfdashboard_window_content_x11_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_x11_have_damage_extension &&
+ _xfdashboard_window_content_x11_damage_event_base &&
+ inXEvent->type==(_xfdashboard_window_content_x11_damage_event_base + XDamageNotify) &&
+ ((XDamageNotifyEvent*)inXEvent)->damage==priv->damage &&
+ priv->workaroundMode==XFDASHBOARD_WINDOW_CONTENT_X11_WORKAROUND_MODE_NONE)
+ {
+ /* Update texture for live window content */
+ clutter_content_invalidate(CLUTTER_CONTENT(self));
+ }
+#endif
+
+ return(CLUTTER_X11_FILTER_CONTINUE);
+}
+
+/* Release all resources used by this instance */
+static void _xfdashboard_window_content_x11_release_resources(XfdashboardWindowContentX11 *self)
+{
+ XfdashboardWindowContentX11Private *priv;
+ Display *display;
+ gint trapError;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self));
+
+ priv=self->priv;
+
+ /* This live update will be suspended so remove it from queue */
+ _xfdashboard_window_content_x11_resume_on_idle_remove(self);
+
+ /* Get display as it used more than once ;) */
+ display=clutter_x11_get_default_display();
+
+ /* Release resources. It might be important to release them
+ * in reverse order as they were created.
+ */
+ clutter_x11_remove_filter(_xfdashboard_window_content_x11_on_x_event, (gpointer)self);
+
+ 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_x11_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), XfdashboardWindowContentX11Properties[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)),
+ self);
+ 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_x11_suspend(XfdashboardWindowContentX11 *self)
+{
+ XfdashboardWindowContentX11Private *priv;
+ Display *display;
+ gint trapError;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self));
+
+ priv=self->priv;
+
+ /* This live update will be suspended so remove it from queue */
+ _xfdashboard_window_content_x11_resume_on_idle_remove(self);
+
+ /* Get display as it used more than once ;) */
+ display=clutter_x11_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), XfdashboardWindowContentX11Properties[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_x11_resume_on_idle(gpointer inUserData)
+{
+ XfdashboardWindowContentX11 *self;
+ XfdashboardWindowContentX11Private *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_x11_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_x11_resume_idle_queue)
+ {
+ XFDASHBOARD_DEBUG(NULL, WINDOWS, "Ensuring that window content resume queue is empty");
+ g_list_free(_xfdashboard_window_content_x11_resume_idle_queue);
+ _xfdashboard_window_content_x11_resume_idle_queue=NULL;
+ }
+
+ /* Queue must be empty so remove idle source */
+ _xfdashboard_window_content_x11_resume_idle_id=0;
+ return(G_SOURCE_REMOVE);
+ }
+
+ self=XFDASHBOARD_WINDOW_CONTENT_X11(queueEntry->data);
+ priv=self->priv;
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Entering idle source with ID %u for window resume of '%s'",
+ _xfdashboard_window_content_x11_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'@%p",
+ queueEntry,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)));
+ _xfdashboard_window_content_x11_resume_idle_queue=g_list_delete_link(_xfdashboard_window_content_x11_resume_idle_queue, queueEntry);
+ if(_xfdashboard_window_content_x11_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_x11_resume_idle_id);
+
+ doContinueSource=G_SOURCE_REMOVE;
+ _xfdashboard_window_content_x11_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_x11_have_composite_extension)
+ {
+ return(doContinueSource);
+ }
+
+ /* Get display as it used more than once ;) */
+ display=clutter_x11_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_x11_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_x11_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), XfdashboardWindowContentX11Properties[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_x11_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_x11_resume(XfdashboardWindowContentX11 *self)
+{
+ XfdashboardWindowContentX11Private *priv;
+ Display *display;
+ CoglContext *context;
+ GError *error;
+ gint trapError;
+ CoglTexture *windowTexture;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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_x11_window_creation_priority>0)
+ {
+ _xfdashboard_window_content_x11_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_x11_have_composite_extension) return;
+
+ /* Get display as it used more than once ;) */
+ display=clutter_x11_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_x11_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_x11_suspend(self);
+
+ break;
+ }
+
+ /* Set up damage to get notified about changed in pixmap */
+#ifdef HAVE_XDAMAGE
+ if(_xfdashboard_window_content_x11_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_x11_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), XfdashboardWindowContentX11Properties[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_x11_get_window_frame_xid(Display *inDisplay,
+ XfdashboardWindowTrackerWindowX11 *inWindow)
+{
+ Window xWindowID;
+ Window iterXWindowID;
+ Window rootXWindowID;
+ Window foundXWindowID;
+ GdkDisplay *gdkDisplay;
+ 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_x11_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.
+ */
+ gdkDisplay=gdk_display_get_default();
+ gdkWindow=gdk_x11_window_foreign_new_for_display(gdkDisplay, xWindowID);
+ if(gdkWindow)
+ {
+ if(gdk_window_get_decorations(gdkWindow, &gdkWindowDecoration) &&
+ gdkWindowDecoration==0)
+ {
+ XFDASHBOARD_DEBUG(inWindow, WINDOWS,
+ "Window '%s' has CSD enabled and no decorations 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 but 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_x11_set_window(XfdashboardWindowContentX11 *self, XfdashboardWindowTrackerWindowX11 *inWindow)
+{
+ XfdashboardWindowContentX11Private *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_X11(self));
+ g_return_if_fail(inWindow!=NULL && XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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=clutter_x11_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_x11_get_window_frame_xid(display, priv->window);
+ }
+
+ if(!priv->xWindowID)
+ {
+ priv->xWindowID=xfdashboard_window_tracker_window_x11_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_x11_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_x11_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_x11_window_creation_priority>0)
+ {
+ priv->suspendAfterResumeOnIdle=TRUE;
+ }
+ else
+ {
+ _xfdashboard_window_content_x11_suspend(self);
+ }
+ }
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowContentX11Properties[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_x11_setup_workaround(self, inWindow);
+}
+
+/* Destroy cache hashtable */
+static void _xfdashboard_window_content_x11_destroy_cache(void)
+{
+ XfdashboardApplication *application;
+ gint cacheSize;
+
+ /* Only an existing cache can be destroyed */
+ if(!_xfdashboard_window_content_x11_cache) return;
+
+ /* Disconnect application "shutdown" signal handler */
+ application=xfdashboard_application_get_default();
+ g_signal_handler_disconnect(application, _xfdashboard_window_content_x11_cache_shutdown_signal_id);
+ _xfdashboard_window_content_x11_cache_shutdown_signal_id=0;
+
+ /* Destroy cache hashtable */
+ cacheSize=g_hash_table_size(_xfdashboard_window_content_x11_cache);
+ if(cacheSize>0) g_warning(_("Destroying window content cache still containing %d windows."), cacheSize);
+#ifdef DEBUG
+ if(cacheSize>0)
+ {
+ GHashTableIter iter;
+ gpointer key, value;
+ XfdashboardWindowContentX11 *content;
+ XfdashboardWindowTrackerWindow *window;
+
+ g_hash_table_iter_init(&iter, _xfdashboard_window_content_x11_cache);
+ while(g_hash_table_iter_next (&iter, &key, &value))
+ {
+ content=XFDASHBOARD_WINDOW_CONTENT_X11(value);
+ window=xfdashboard_window_content_x11_get_window(content);
+ g_print("Window content in cache: 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 cache hashtable");
+ g_hash_table_destroy(_xfdashboard_window_content_x11_cache);
+ _xfdashboard_window_content_x11_cache=NULL;
+}
+
+/* Create cache hashtable if not already set up */
+static void _xfdashboard_window_content_x11_create_cache(void)
+{
+ XfdashboardApplication *application;
+
+ /* Cache was already set up */
+ if(_xfdashboard_window_content_x11_cache) return;
+
+ /* Create create hashtable */
+ _xfdashboard_window_content_x11_cache=g_hash_table_new(g_direct_hash, g_direct_equal);
+ XFDASHBOARD_DEBUG(NULL, WINDOWS, "Created window content cache hashtable");
+
+ /* Connect to "shutdown" signal of application to clean up hashtable */
+ application=xfdashboard_application_get_default();
+ _xfdashboard_window_content_x11_cache_shutdown_signal_id=g_signal_connect(application,
+ "shutdown-final",
+ G_CALLBACK(_xfdashboard_window_content_x11_destroy_cache),
+ NULL);
+}
+
+/* IMPLEMENTATION: ClutterContent */
+
+/* Paint texture */
+static void _xdashboard_window_content_clutter_content_iface_paint_content(ClutterContent *inContent,
+ ClutterActor *inActor,
+ ClutterPaintNode *inRootNode)
+{
+ XfdashboardWindowContentX11 *self=XFDASHBOARD_WINDOW_CONTENT_X11(inContent);
+ XfdashboardWindowContentX11Private *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)
+{
+ XfdashboardWindowContentX11Private *priv=XFDASHBOARD_WINDOW_CONTENT_X11(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_x11_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_x11_stylable_get_classes(XfdashboardStylable *inStylable)
+{
+ /* Not implemented */
+ return(NULL);
+}
+
+static void _xfdashboard_window_content_x11_stylable_set_classes(XfdashboardStylable *inStylable, const gchar *inStyleClasses)
+{
+ /* Not implemented */
+}
+
+/* Get/set style pseudo-classes of stage */
+static const gchar* _xfdashboard_window_content_x11_stylable_get_pseudo_classes(XfdashboardStylable *inStylable)
+{
+ /* Not implemented */
+ return(NULL);
+}
+
+static void _xfdashboard_window_content_x11_stylable_set_pseudo_classes(XfdashboardStylable *inStylable, const gchar *inStylePseudoClasses)
+{
+ /* Not implemented */
+}
+
+/* Interface initialization
+ * Set up default functions
+ */
+void _xfdashboard_window_content_x11_stylable_iface_init(XfdashboardStylableInterface *iface)
+{
+ iface->get_stylable_properties=_xfdashboard_window_content_x11_stylable_get_stylable_properties;
+ iface->get_classes=_xfdashboard_window_content_x11_stylable_get_classes;
+ iface->set_classes=_xfdashboard_window_content_x11_stylable_set_classes;
+ iface->get_pseudo_classes=_xfdashboard_window_content_x11_stylable_get_pseudo_classes;
+ iface->set_pseudo_classes=_xfdashboard_window_content_x11_stylable_set_pseudo_classes;
+}
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_content_x11_dispose(GObject *inObject)
+{
+ XfdashboardWindowContentX11 *self=XFDASHBOARD_WINDOW_CONTENT_X11(inObject);
+ XfdashboardWindowContentX11Private *priv=self->priv;
+
+ /* Dispose allocated resources */
+ _xfdashboard_window_content_x11_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)
+ {
+ /* Remove from cache */
+ XFDASHBOARD_DEBUG(self, WINDOWS,
+ "Removing window content for window '%s' with ref-count %d" ,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->window)),
+ G_OBJECT(self)->ref_count);
+ g_hash_table_remove(_xfdashboard_window_content_x11_cache, 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_x11_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_content_x11_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowContentX11 *self=XFDASHBOARD_WINDOW_CONTENT_X11(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_WINDOW:
+ _xfdashboard_window_content_x11_set_window(self, XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(g_value_get_object(inValue)));
+ break;
+
+ case PROP_OUTLINE_COLOR:
+ xfdashboard_window_content_x11_set_outline_color(self, clutter_value_get_color(inValue));
+ break;
+
+ case PROP_OUTLINE_WIDTH:
+ xfdashboard_window_content_x11_set_outline_width(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_INCLUDE_WINDOW_FRAME:
+ xfdashboard_window_content_x11_set_include_window_frame(self, g_value_get_boolean(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_FILL:
+ xfdashboard_window_content_x11_set_unmapped_window_icon_x_fill(self, g_value_get_boolean(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_FILL:
+ xfdashboard_window_content_x11_set_unmapped_window_icon_y_fill(self, g_value_get_boolean(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_ALIGN:
+ xfdashboard_window_content_x11_set_unmapped_window_icon_x_align(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_ALIGN:
+ xfdashboard_window_content_x11_set_unmapped_window_icon_y_align(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_X_SCALE:
+ xfdashboard_window_content_x11_set_unmapped_window_icon_x_scale(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_Y_SCALE:
+ xfdashboard_window_content_x11_set_unmapped_window_icon_y_scale(self, g_value_get_float(inValue));
+ break;
+
+ case PROP_UNMAPPED_WINDOW_ICON_ANCHOR_POINT:
+ xfdashboard_window_content_x11_set_unmapped_window_icon_anchor_point(self, g_value_get_enum(inValue));
+ break;
+
+ case PROP_STYLE_CLASSES:
+ _xfdashboard_window_content_x11_stylable_set_classes(XFDASHBOARD_STYLABLE(self), g_value_get_string(inValue));
+ break;
+
+ case PROP_STYLE_PSEUDO_CLASSES:
+ _xfdashboard_window_content_x11_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_x11_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowContentX11 *self=XFDASHBOARD_WINDOW_CONTENT_X11(inObject);
+ XfdashboardWindowContentX11Private *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_x11_class_init(XfdashboardWindowContentX11Class *klass)
+{
+ GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
+ XfdashboardStylableInterface *stylableIface;
+ GParamSpec *paramSpec;
+
+ /* Override functions */
+ gobjectClass->dispose=_xfdashboard_window_content_x11_dispose;
+ gobjectClass->set_property=_xfdashboard_window_content_x11_set_property;
+ gobjectClass->get_property=_xfdashboard_window_content_x11_get_property;
+
+ stylableIface=g_type_default_interface_ref(XFDASHBOARD_TYPE_STYLABLE);
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowContentX11Private));
+
+ /* Define properties */
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[PROP_SUSPENDED]=
+ g_param_spec_boolean("suspended",
+ _("Suspended"),
+ _("Is this window suspended"),
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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);
+
+ XfdashboardWindowContentX11Properties[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");
+ XfdashboardWindowContentX11Properties[PROP_STYLE_CLASSES]=
+ g_param_spec_override("style-classes", paramSpec);
+
+ paramSpec=g_object_interface_find_property(stylableIface, "style-pseudo-classes");
+ XfdashboardWindowContentX11Properties[PROP_STYLE_PSEUDO_CLASSES]=
+ g_param_spec_override("style-pseudo-classes", paramSpec);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowContentX11Properties);
+
+ /* Release allocated resources */
+ g_type_default_interface_unref(stylableIface);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_window_content_x11_init(XfdashboardWindowContentX11 *self)
+{
+ XfdashboardWindowContentX11Private *priv;
+ XfdashboardApplication *app;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_CONTENT_X11_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_X11_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_x11_check_extension();
+
+ /* Add event filter for this instance */
+ clutter_x11_add_filter(_xfdashboard_window_content_x11_on_x_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_x11_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_x11_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_x11_xfconf_priority_notify_id=g_signal_connect(xfconfChannel,
+ detailedSignal,
+ G_CALLBACK(_xfdashboard_window_content_x11_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_x11_xfconf_priority_notify_id);
+
+ /* Connect to application shutdown signal for xfconf value change notification */
+ _xfdashboard_window_content_x11_window_creation_shutdown_signal_id=g_signal_connect(app,
+ "shutdown-final",
+ G_CALLBACK(_xfdashboard_window_content_x11_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_x11_window_creation_shutdown_signal_id);
+ }
+}
+
+/* IMPLEMENTATION: Public API */
+
+/* Create new instance */
+ClutterContent* xfdashboard_window_content_x11_new_for_window(XfdashboardWindowTrackerWindowX11 *inWindow)
+{
+ ClutterContent *content;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ /* If we a hash table (cache) set up lookup if window content is already cached
+ * and return a new reference to it
+ */
+ if(_xfdashboard_window_content_x11_cache &&
+ g_hash_table_contains(_xfdashboard_window_content_x11_cache, inWindow))
+ {
+ content=CLUTTER_CONTENT(g_hash_table_lookup(_xfdashboard_window_content_x11_cache, inWindow));
+ g_object_ref(content);
+ XFDASHBOARD_DEBUG(content, WINDOWS,
+ "Using cached window content for '%s' - ref-count is now %d" ,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(XFDASHBOARD_WINDOW_CONTENT_X11(content)->priv->window)),
+ G_OBJECT(content)->ref_count);
+
+ return(content);
+ }
+
+ /* Create window content */
+ content=CLUTTER_CONTENT(g_object_new(XFDASHBOARD_TYPE_WINDOW_CONTENT_X11,
+ "window", inWindow,
+ NULL));
+ g_return_val_if_fail(content, NULL);
+
+ /* Create cache if not available */
+ if(!_xfdashboard_window_content_x11_cache) _xfdashboard_window_content_x11_create_cache();
+
+ /* Store new window content into cache */
+ g_hash_table_insert(_xfdashboard_window_content_x11_cache, inWindow, content);
+ XFDASHBOARD_DEBUG(content, WINDOWS,
+ "Added window content for '%s' with ref-count %d" ,
+ xfdashboard_window_tracker_window_get_name(XFDASHBOARD_WINDOW_TRACKER_WINDOW(inWindow)),
+ G_OBJECT(content)->ref_count);
+
+ return(content);
+}
+
+/* Get window to handle and to display */
+XfdashboardWindowTrackerWindow* xfdashboard_window_content_x11_get_window(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), NULL);
+
+ return(XFDASHBOARD_WINDOW_TRACKER_WINDOW(self->priv->window));
+}
+
+/* Get state of suspension */
+gboolean xfdashboard_window_content_x11_is_suspended(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), TRUE);
+
+ return(self->priv->isSuspended);
+}
+
+/* Get/set color to draw outline with */
+const ClutterColor* xfdashboard_window_content_x11_get_outline_color(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), NULL);
+
+ return(self->priv->outlineColor);
+}
+
+void xfdashboard_window_content_x11_set_outline_color(XfdashboardWindowContentX11 *self, const ClutterColor *inColor)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_OUTLINE_COLOR]);
+ }
+}
+
+/* Get/set line width for outline */
+gfloat xfdashboard_window_content_x11_get_outline_width(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), 0.0f);
+
+ return(self->priv->outlineWidth);
+}
+
+void xfdashboard_window_content_x11_set_outline_width(XfdashboardWindowContentX11 *self, const gfloat inWidth)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_OUTLINE_WIDTH]);
+ }
+}
+
+/* Get/set flag to indicate whether to include the window frame or not */
+gboolean xfdashboard_window_content_x11_get_include_window_frame(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), TRUE);
+
+ return(self->priv->includeWindowFrame);
+}
+
+void xfdashboard_window_content_x11_set_include_window_frame(XfdashboardWindowContentX11 *self, const gboolean inIncludeFrame)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self));
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->includeWindowFrame!=inIncludeFrame)
+ {
+ /* Set value */
+ priv->includeWindowFrame=inIncludeFrame;
+
+ /* (Re-)Setup window content */
+ if(priv->window)
+ {
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ /* Re-setup window by releasing all resources first and unsetting window
+ * but remember window to set it again.
+ */
+ _xfdashboard_window_content_x11_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_x11_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), XfdashboardWindowContentX11Properties[PROP_INCLUDE_WINDOW_FRAME]);
+ }
+}
+
+/* Get/set x fill of unmapped window icon */
+gboolean xfdashboard_window_content_x11_get_unmapped_window_icon_x_fill(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), FALSE);
+
+ return(self->priv->unmappedWindowIconXFill);
+}
+
+void xfdashboard_window_content_x11_set_unmapped_window_icon_x_fill(XfdashboardWindowContentX11 *self, const gboolean inFill)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_UNMAPPED_WINDOW_ICON_X_FILL]);
+ }
+}
+
+/* Get/set y fill of unmapped window icon */
+gboolean xfdashboard_window_content_x11_get_unmapped_window_icon_y_fill(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), FALSE);
+
+ return(self->priv->unmappedWindowIconYFill);
+}
+
+void xfdashboard_window_content_x11_set_unmapped_window_icon_y_fill(XfdashboardWindowContentX11 *self, const gboolean inFill)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_UNMAPPED_WINDOW_ICON_Y_FILL]);
+ }
+}
+
+/* Get/set x align of unmapped window icon */
+gfloat xfdashboard_window_content_x11_get_unmapped_window_icon_x_align(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), 0.0f);
+
+ return(self->priv->unmappedWindowIconXAlign);
+}
+
+void xfdashboard_window_content_x11_set_unmapped_window_icon_x_align(XfdashboardWindowContentX11 *self, const gfloat inAlign)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_UNMAPPED_WINDOW_ICON_X_ALIGN]);
+ }
+}
+
+/* Get/set y align of unmapped window icon */
+gfloat xfdashboard_window_content_x11_get_unmapped_window_icon_y_align(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), 0.0f);
+
+ return(self->priv->unmappedWindowIconYAlign);
+}
+
+void xfdashboard_window_content_x11_set_unmapped_window_icon_y_align(XfdashboardWindowContentX11 *self, const gfloat inAlign)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_UNMAPPED_WINDOW_ICON_Y_ALIGN]);
+ }
+}
+
+/* Get/set x scale of unmapped window icon */
+gfloat xfdashboard_window_content_x11_get_unmapped_window_icon_x_scale(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), 0.0f);
+
+ return(self->priv->unmappedWindowIconXScale);
+}
+
+void xfdashboard_window_content_x11_set_unmapped_window_icon_x_scale(XfdashboardWindowContentX11 *self, const gfloat inScale)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_UNMAPPED_WINDOW_ICON_X_SCALE]);
+ }
+}
+
+/* Get/set y scale of unmapped window icon */
+gfloat xfdashboard_window_content_x11_get_unmapped_window_icon_y_scale(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), 0.0f);
+
+ return(self->priv->unmappedWindowIconYScale);
+}
+
+void xfdashboard_window_content_x11_set_unmapped_window_icon_y_scale(XfdashboardWindowContentX11 *self, const gfloat inScale)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_UNMAPPED_WINDOW_ICON_Y_SCALE]);
+ }
+}
+
+/* Get/set gravity (anchor point) of unmapped window icon */
+XfdashboardAnchorPoint xfdashboard_window_content_x11_get_unmapped_window_icon_anchor_point(XfdashboardWindowContentX11 *self)
+{
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(self), XFDASHBOARD_ANCHOR_POINT_NONE);
+
+ return(self->priv->unmappedWindowIconAnchorPoint);
+}
+
+void xfdashboard_window_content_x11_set_unmapped_window_icon_anchor_point(XfdashboardWindowContentX11 *self, const XfdashboardAnchorPoint inAnchorPoint)
+{
+ XfdashboardWindowContentX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_CONTENT_X11(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), XfdashboardWindowContentX11Properties[PROP_UNMAPPED_WINDOW_ICON_ANCHOR_POINT]);
+ }
+}
diff --git a/libxfdashboard/x11/window-content-x11.h b/libxfdashboard/x11/window-content-x11.h
new file mode 100644
index 0000000..1f2be66
--- /dev/null
+++ b/libxfdashboard/x11/window-content-x11.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_X11__
+#define __LIBXFDASHBOARD_WINDOW_CONTENT_X11__
+
+#if !defined(__LIBXFDASHBOARD_H_INSIDE__) && !defined(LIBXFDASHBOARD_COMPILATION)
+#error "Only <libxfdashboard/libxfdashboard.h> can be included directly."
+#endif
+
+#include <clutter/clutter.h>
+
+#include <libxfdashboard/x11/window-tracker-window-x11.h>
+#include <libxfdashboard/window-tracker-window.h>
+#include <libxfdashboard/types.h>
+
+G_BEGIN_DECLS
+
+#define XFDASHBOARD_TYPE_WINDOW_CONTENT_X11 (xfdashboard_window_content_x11_get_type())
+#define XFDASHBOARD_WINDOW_CONTENT_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_CONTENT_X11, XfdashboardWindowContentX11))
+#define XFDASHBOARD_IS_WINDOW_CONTENT_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_CONTENT_X11))
+#define XFDASHBOARD_WINDOW_CONTENT_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_CONTENT_X11, XfdashboardWindowContentX11Class))
+#define XFDASHBOARD_IS_WINDOW_CONTENT_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_CONTENT_X11))
+#define XFDASHBOARD_WINDOW_CONTENT_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_CONTENT_X11, XfdashboardWindowContentX11Class))
+
+typedef struct _XfdashboardWindowContentX11 XfdashboardWindowContentX11;
+typedef struct _XfdashboardWindowContentX11Class XfdashboardWindowContentX11Class;
+typedef struct _XfdashboardWindowContentX11Private XfdashboardWindowContentX11Private;
+
+struct _XfdashboardWindowContentX11
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowContentX11Private *priv;
+};
+
+struct _XfdashboardWindowContentX11Class
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+};
+
+/* Public API */
+GType xfdashboard_window_content_x11_get_type(void) G_GNUC_CONST;
+
+ClutterContent* xfdashboard_window_content_x11_new_for_window(XfdashboardWindowTrackerWindowX11 *inWindow);
+
+XfdashboardWindowTrackerWindow* xfdashboard_window_content_x11_get_window(XfdashboardWindowContentX11 *self);
+
+gboolean xfdashboard_window_content_x11_is_suspended(XfdashboardWindowContentX11 *self);
+
+const ClutterColor* xfdashboard_window_content_x11_get_outline_color(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_outline_color(XfdashboardWindowContentX11 *self, const ClutterColor *inColor);
+
+gfloat xfdashboard_window_content_x11_get_outline_width(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_outline_width(XfdashboardWindowContentX11 *self, const gfloat inWidth);
+
+gboolean xfdashboard_window_content_x11_get_include_window_frame(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_include_window_frame(XfdashboardWindowContentX11 *self, const gboolean inIncludeFrame);
+
+gboolean xfdashboard_window_content_x11_get_unmapped_window_icon_x_fill(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_unmapped_window_icon_x_fill(XfdashboardWindowContentX11 *self, const gboolean inFill);
+
+gboolean xfdashboard_window_content_x11_get_unmapped_window_icon_y_fill(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_unmapped_window_icon_y_fill(XfdashboardWindowContentX11 *self, const gboolean inFill);
+
+gfloat xfdashboard_window_content_x11_get_unmapped_window_icon_x_align(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_unmapped_window_icon_x_align(XfdashboardWindowContentX11 *self, const gfloat inAlign);
+
+gfloat xfdashboard_window_content_x11_get_unmapped_window_icon_y_align(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_unmapped_window_icon_y_align(XfdashboardWindowContentX11 *self, const gfloat inAlign);
+
+gfloat xfdashboard_window_content_x11_get_unmapped_window_icon_x_scale(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_unmapped_window_icon_x_scale(XfdashboardWindowContentX11 *self, const gfloat inScale);
+
+gfloat xfdashboard_window_content_x11_get_unmapped_window_icon_y_scale(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_unmapped_window_icon_y_scale(XfdashboardWindowContentX11 *self, const gfloat inScale);
+
+XfdashboardAnchorPoint xfdashboard_window_content_x11_get_unmapped_window_icon_anchor_point(XfdashboardWindowContentX11 *self);
+void xfdashboard_window_content_x11_set_unmapped_window_icon_anchor_point(XfdashboardWindowContentX11 *self, const XfdashboardAnchorPoint inAnchorPoint);
+
+G_END_DECLS
+
+#endif
diff --git a/libxfdashboard/x11/window-tracker-monitor-x11.c b/libxfdashboard/x11/window-tracker-monitor-x11.c
new file mode 100644
index 0000000..4a83bdb
--- /dev/null
+++ b/libxfdashboard/x11/window-tracker-monitor-x11.c
@@ -0,0 +1,393 @@
+/*
+ * 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/x11/window-tracker-monitor-x11.h>
+
+#include <glib/gi18n-lib.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_x11_x11_window_tracker_monitor_iface_init(XfdashboardWindowTrackerMonitorInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerMonitorX11,
+ xfdashboard_window_tracker_monitor_x11,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR, _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_X11, XfdashboardWindowTrackerMonitorX11Private))
+
+struct _XfdashboardWindowTrackerMonitorX11Private
+{
+ /* 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* XfdashboardWindowTrackerMonitorX11Properties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+
+/* Set primary monitor flag */
+static void _xfdashboard_window_tracker_monitor_x11_update_primary(XfdashboardWindowTrackerMonitorX11 *self)
+{
+ XfdashboardWindowTrackerMonitorX11Private *priv;
+ gint primaryIndex;
+ gboolean isPrimary;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR(self));
+
+ priv=self->priv;
+
+ /* Get primary flag */
+ primaryIndex=gdk_screen_get_primary_monitor(priv->screen);
+ if(primaryIndex==priv->monitorIndex) isPrimary=TRUE;
+ else isPrimary=FALSE;
+
+ /* 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), XfdashboardWindowTrackerMonitorX11Properties[PROP_IS_PRIMARY]);
+
+ /* Emit signal */
+ g_signal_emit_by_name(self, "primary-changed");
+ }
+}
+
+/* Update monitor geometry */
+static void _xfdashboard_window_tracker_monitor_x11_update_geometry(XfdashboardWindowTrackerMonitorX11 *self)
+{
+ XfdashboardWindowTrackerMonitorX11Private *priv;
+ GdkRectangle geometry;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(self));
+
+ priv=self->priv;
+
+ /* Check if monitor is valid */
+ if(priv->monitorIndex>=gdk_screen_get_n_monitors(priv->screen)) return;
+
+ /* Get monitor geometry */
+ gdk_screen_get_monitor_geometry(priv->screen, priv->monitorIndex, &geometry);
+
+ /* 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);
+ }
+}
+
+/* Set monitor index this object belongs to and to monitor */
+static void _xfdashboard_window_tracker_monitor_x11_set_index(XfdashboardWindowTrackerMonitorX11 *self,
+ gint inIndex)
+{
+ XfdashboardWindowTrackerMonitorX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(self));
+ g_return_if_fail(inIndex>=0);
+ g_return_if_fail(inIndex<gdk_screen_get_n_monitors(self->priv->screen));
+
+ priv=self->priv;
+
+ /* 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_x11_update_primary(self);
+
+ /* Update geometry of monitor */
+ _xfdashboard_window_tracker_monitor_x11_update_geometry(self);
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerMonitorX11Properties[PROP_MONITOR_INDEX]);
+ }
+
+ /* Thaw notification */
+ g_object_thaw_notify(G_OBJECT(self));
+}
+
+/* Number of monitors, primary monitor or size of any monitor changed */
+static void _xfdashboard_window_tracker_monitor_x11_on_monitors_changed(XfdashboardWindowTrackerMonitorX11 *self,
+ gpointer inUserData)
+{
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(self));
+ g_return_if_fail(GDK_IS_SCREEN(inUserData));
+
+ /* Update primary monitor flag */
+ _xfdashboard_window_tracker_monitor_x11_update_primary(self);
+
+ /* Update geometry of monitor */
+ _xfdashboard_window_tracker_monitor_x11_update_geometry(self);
+}
+
+
+/* IMPLEMENTATION: Interface XfdashboardWindowTrackerMonitor */
+
+/* Determine if monitor is primary one */
+static gboolean _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_is_primary(XfdashboardWindowTrackerMonitor *inMonitor)
+{
+ XfdashboardWindowTrackerMonitorX11 *self;
+ XfdashboardWindowTrackerMonitorX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inMonitor), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inMonitor);
+ priv=self->priv;
+
+ return(priv->isPrimary);
+}
+
+/* Get monitor index */
+static gint _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_number(XfdashboardWindowTrackerMonitor *inMonitor)
+{
+ XfdashboardWindowTrackerMonitorX11 *self;
+ XfdashboardWindowTrackerMonitorX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inMonitor), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inMonitor);
+ priv=self->priv;
+
+ return(priv->monitorIndex);
+}
+
+/* Get geometry of monitor */
+static void _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_geometry(XfdashboardWindowTrackerMonitor *inMonitor,
+ gint *outX,
+ gint *outY,
+ gint *outWidth,
+ gint *outHeight)
+{
+ XfdashboardWindowTrackerMonitorX11 *self;
+ XfdashboardWindowTrackerMonitorX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inMonitor));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(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_x11_x11_window_tracker_monitor_iface_init(XfdashboardWindowTrackerMonitorInterface *iface)
+{
+ iface->is_primary=_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_is_primary;
+ iface->get_number=_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_number;
+ iface->get_geometry=_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_geometry;
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_tracker_monitor_x11_dispose(GObject *inObject)
+{
+ XfdashboardWindowTrackerMonitorX11 *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inObject);
+ XfdashboardWindowTrackerMonitorX11Private *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_x11_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_tracker_monitor_x11_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerMonitorX11 *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_MONITOR_INDEX:
+ _xfdashboard_window_tracker_monitor_x11_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_x11_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerMonitorX11 *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inObject);
+ XfdashboardWindowTrackerMonitorX11Private *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_x11_class_init(XfdashboardWindowTrackerMonitorX11Class *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_x11_dispose;
+ gobjectClass->set_property=_xfdashboard_window_tracker_monitor_x11_set_property;
+ gobjectClass->get_property=_xfdashboard_window_tracker_monitor_x11_get_property;
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowTrackerMonitorX11Private));
+
+ /* Define properties */
+ paramSpec=g_object_interface_find_property(monitorIface, "is-primary");
+ XfdashboardWindowTrackerMonitorX11Properties[PROP_IS_PRIMARY]=
+ g_param_spec_override("is-primary", paramSpec);
+
+ paramSpec=g_object_interface_find_property(monitorIface, "monitor-index");
+ XfdashboardWindowTrackerMonitorX11Properties[PROP_MONITOR_INDEX]=
+ g_param_spec_override("monitor-index", paramSpec);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowTrackerMonitorX11Properties);
+
+ /* 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_x11_init(XfdashboardWindowTrackerMonitorX11 *self)
+{
+ XfdashboardWindowTrackerMonitorX11Private *priv;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11_GET_PRIVATE(self);
+
+ /* Set default values */
+ priv->monitorIndex=0;
+ 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;
+
+ /* Get initial primary monitor flag */
+ _xfdashboard_window_tracker_monitor_x11_update_primary(self);
+
+ /* Get initial geometry of monitor */
+ _xfdashboard_window_tracker_monitor_x11_update_geometry(self);
+
+ /* Connect signals */
+ g_signal_connect_swapped(priv->screen, "monitors-changed", G_CALLBACK(_xfdashboard_window_tracker_monitor_x11_on_monitors_changed), self);
+}
diff --git a/libxfdashboard/x11/window-tracker-monitor-x11.h b/libxfdashboard/x11/window-tracker-monitor-x11.h
new file mode 100644
index 0000000..b98afce
--- /dev/null
+++ b/libxfdashboard/x11/window-tracker-monitor-x11.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_X11__
+#define __LIBXFDASHBOARD_WINDOW_TRACKER_MONITOR_X11__
+
+#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_X11 (xfdashboard_window_tracker_monitor_x11_get_type())
+#define XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_X11, XfdashboardWindowTrackerMonitorX11))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_X11))
+#define XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_X11, XfdashboardWindowTrackerMonitorX11Class))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_X11))
+#define XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_X11, XfdashboardWindowTrackerMonitorX11Class))
+
+typedef struct _XfdashboardWindowTrackerMonitorX11 XfdashboardWindowTrackerMonitorX11;
+typedef struct _XfdashboardWindowTrackerMonitorX11Class XfdashboardWindowTrackerMonitorX11Class;
+typedef struct _XfdashboardWindowTrackerMonitorX11Private XfdashboardWindowTrackerMonitorX11Private;
+
+struct _XfdashboardWindowTrackerMonitorX11
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowTrackerMonitorX11Private *priv;
+};
+
+struct _XfdashboardWindowTrackerMonitorX11Class
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+ void (*primary_changed)(XfdashboardWindowTrackerMonitorX11 *self);
+ void (*geometry_changed)(XfdashboardWindowTrackerMonitorX11 *self);
+};
+
+/* Public API */
+GType xfdashboard_window_tracker_monitor_x11_get_type(void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __LIBXFDASHBOARD_WINDOW_TRACKER_MONITOR_X11__ */
diff --git a/libxfdashboard/x11/window-tracker-window-x11.c b/libxfdashboard/x11/window-tracker-window-x11.c
new file mode 100644
index 0000000..9337eff
--- /dev/null
+++ b/libxfdashboard/x11/window-tracker-window-x11.c
@@ -0,0 +1,1811 @@
+/*
+ * 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-x11
+ * @short_description: A window used by X11 window tracker
+ * @include: xfdashboard/x11/window-tracker-window-x11.h
+ *
+ * TODO: DESCRIPTION
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libxfdashboard/x11/window-tracker-window-x11.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+#include <glib/gi18n-lib.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/x11/window-content-x11.h>
+#include <libxfdashboard/x11/window-tracker-workspace-x11.h>
+#include <libxfdashboard/x11/window-tracker-x11.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_x11_window_tracker_window_iface_init(XfdashboardWindowTrackerWindowInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerWindowX11,
+ xfdashboard_window_tracker_window_x11,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW, _xfdashboard_window_tracker_window_x11_window_tracker_window_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_X11, XfdashboardWindowTrackerWindowX11Private))
+
+struct _XfdashboardWindowTrackerWindowX11Private
+{
+ /* Properties related */
+ WnckWindow *window;
+ XfdashboardWindowTrackerWindowState state;
+ XfdashboardWindowTrackerWindowAction actions;
+
+ /* Instance related */
+ WnckWorkspace *workspace;
+
+ gint lastGeometryX;
+ gint lastGeometryY;
+ gint lastGeometryWidth;
+ gint lastGeometryHeight;
+};
+
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ PROP_WINDOW,
+
+ /* Overriden properties of interface: XfdashboardWindowTrackerWindow */
+ PROP_STATE,
+ PROP_ACTIONS,
+
+ PROP_LAST
+};
+
+static GParamSpec* XfdashboardWindowTrackerWindowX11Properties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_X11_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_x11_update_state(XfdashboardWindowTrackerWindowX11 *self)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ XfdashboardWindowTrackerWindowState newState;
+ WnckWindowState wnckState;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(self));
+
+ priv=self->priv;
+ newState=0;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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), XfdashboardWindowTrackerWindowX11Properties[PROP_STATE]);
+ }
+}
+
+/* Get actions of window */
+static void _xfdashboard_window_tracker_window_x11_update_actions(XfdashboardWindowTrackerWindowX11 *self)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ XfdashboardWindowTrackerWindowAction newActions;
+ WnckWindowActions wnckActions;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(self));
+
+ priv=self->priv;
+ newActions=0;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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), XfdashboardWindowTrackerWindowX11Properties[PROP_ACTIONS]);
+ }
+}
+
+/* Size of screen has changed so resize stage window */
+static void _xfdashboard_window_tracker_window_x11_on_stage_screen_size_changed(XfdashboardWindowTracker *inWindowTracker,
+ gint inWidth,
+ gint inHeight,
+ gpointer inUserData)
+{
+#ifdef HAVE_XINERAMA
+ XfdashboardWindowTrackerWindowX11 *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_X11(inUserData));
+
+ realStageWindow=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_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)))
+ {
+ gint primaryMonitor;
+ 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.
+ */
+ 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);
+ 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 */
+ top=gdk_screen_get_height(screen);
+ left=gdk_screen_get_width(screen);
+ 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
+ XfdashboardWindowTrackerWindowX11 *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_X11(inUserData));
+
+ realStageWindow=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_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_x11_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_x11_on_stage_active_window_changed(WnckScreen *inScreen,
+ WnckWindow *inPreviousWindow,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *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_X11(inUserData));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_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_x11_on_wnck_name_changed(XfdashboardWindowTrackerWindowX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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_X11_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_x11_on_wnck_state_changed(XfdashboardWindowTrackerWindowX11 *self,
+ WnckWindowState inChangedStates,
+ WnckWindowState inNewState,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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_X11_WARN_WRONG_WINDOW(self);
+ return;
+ }
+
+ /* Update state before emitting signal */
+ _xfdashboard_window_tracker_window_x11_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_x11_on_wnck_actions_changed(XfdashboardWindowTrackerWindowX11 *self,
+ WnckWindowActions inChangedActions,
+ WnckWindowActions inNewActions,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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_X11_WARN_WRONG_WINDOW(self);
+ return;
+ }
+
+ /* Update actions before emitting signal */
+ _xfdashboard_window_tracker_window_x11_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_x11_on_wnck_icon_changed(XfdashboardWindowTrackerWindowX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWindow *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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_X11_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_x11_on_wnck_workspace_changed(XfdashboardWindowTrackerWindowX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWindow *window;
+ XfdashboardWindowTrackerWorkspace *oldWorkspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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_X11_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_x11_get_workspace_for_wnck(XFDASHBOARD_WINDOW_TRACKER_X11(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_x11_on_wnck_geometry_changed(XfdashboardWindowTrackerWindowX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWindow *window;
+ gint x, y, width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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_X11_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_x11_set_window(XfdashboardWindowTrackerWindowX11 *self,
+ WnckWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(self));
+ g_return_if_fail(!inWindow || WNCK_IS_WINDOW(inWindow));
+
+ priv=self->priv;
+
+ /* Set value if changed */
+ if(priv->window!=inWindow)
+ {
+ /* 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_x11_update_state(self);
+ _xfdashboard_window_tracker_window_x11_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_x11_on_wnck_name_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "state-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_x11_on_wnck_state_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "actions-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_x11_on_wnck_actions_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "icon-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_x11_on_wnck_icon_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "workspace-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_x11_on_wnck_workspace_changed),
+ self);
+ g_signal_connect_swapped(priv->window,
+ "geometry-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_x11_on_wnck_geometry_changed),
+ self);
+ }
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerWindowX11Properties[PROP_WINDOW]);
+ }
+}
+
+
+/* IMPLEMENTATION: Interface XfdashboardWindowTrackerWindow */
+
+/* Determine if window is visible */
+static gboolean _xfdashboard_window_tracker_window_x11_window_tracker_window_is_visible(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_window_tracker_window_show(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Show (unminize) window */
+ wnck_window_unminimize(priv->window, xfdashboard_window_tracker_x11_get_time());
+}
+
+/* Show window */
+static void _xfdashboard_window_tracker_window_x11_window_tracker_window_hide(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_window_tracker_window_get_parent(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWindow *parentWindow;
+ XfdashboardWindowTracker *windowTracker;
+ XfdashboardWindowTrackerWindow *foundWindow;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_get_window_for_wnck(XFDASHBOARD_WINDOW_TRACKER_X11(windowTracker), parentWindow);
+ g_object_unref(windowTracker);
+
+ /* Return found window object */
+ return(foundWindow);
+}
+
+/* Get window state */
+static XfdashboardWindowTrackerWindowState _xfdashboard_window_tracker_window_x11_window_tracker_window_get_state(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* Return state of window */
+ return(priv->state);
+}
+
+/* Get window actions */
+static XfdashboardWindowTrackerWindowAction _xfdashboard_window_tracker_window_x11_window_tracker_window_get_actions(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* Return actions of window */
+ return(priv->actions);
+}
+
+/* Get name (title) of window */
+static const gchar* _xfdashboard_window_tracker_window_x11_window_tracker_window_get_name(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_window_tracker_window_get_icon(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_window_tracker_window_get_icon_name(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_window_tracker_window_get_workspace(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWorkspace *wantedWorkspace;
+ XfdashboardWindowTracker *windowTracker;
+ XfdashboardWindowTrackerWorkspace *foundWorkspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_get_workspace_for_wnck(XFDASHBOARD_WINDOW_TRACKER_X11(windowTracker), wantedWorkspace);
+ g_object_unref(windowTracker);
+
+ /* Return found workspace */
+ return(foundWorkspace);
+}
+
+/* Determine if window is on requested workspace */
+static gboolean _xfdashboard_window_tracker_window_x11_window_tracker_window_is_on_workspace(XfdashboardWindowTrackerWindow *inWindow,
+ XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWorkspace *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), FALSE);
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return(FALSE);
+ }
+
+ /* Get wnck workspace to check if window is on this one */
+ workspace=xfdashboard_window_tracker_workspace_x11_get_workspace(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(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_x11_window_tracker_window_get_geometry(XfdashboardWindowTrackerWindow *inWindow,
+ gint *outX,
+ gint *outY,
+ gint *outWidth,
+ gint *outHeight)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ gint x, y, width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_window_tracker_window_set_geometry(XfdashboardWindowTrackerWindow *inWindow,
+ gint inX,
+ gint inY,
+ gint inWidth,
+ gint inHeight)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWindowMoveResizeMask flags;
+ gint contentX, contentY;
+ gint contentWidth, contentHeight;
+ gint borderX, borderY;
+ gint borderWidth, borderHeight;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_window_tracker_window_move(XfdashboardWindowTrackerWindow *inWindow,
+ gint inX,
+ gint inY)
+{
+ _xfdashboard_window_tracker_window_x11_window_tracker_window_set_geometry(inWindow, inX, inY, -1, -1);
+}
+
+/* Resize window */
+static void _xfdashboard_window_tracker_window_x11_window_tracker_window_resize(XfdashboardWindowTrackerWindow *inWindow,
+ gint inWidth,
+ gint inHeight)
+{
+ _xfdashboard_window_tracker_window_x11_window_tracker_window_set_geometry(inWindow, -1, -1, inWidth, inHeight);
+}
+
+/* Move a window to another workspace */
+static void _xfdashboard_window_tracker_window_x11_window_tracker_window_move_to_workspace(XfdashboardWindowTrackerWindow *inWindow,
+ XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ WnckWorkspace *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Get wnck workspace to move window to */
+ workspace=xfdashboard_window_tracker_workspace_x11_get_workspace(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(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_x11_window_tracker_window_activate(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Activate window */
+ wnck_window_activate_transient(priv->window, xfdashboard_window_tracker_x11_get_time());
+}
+
+/* Close window */
+static void _xfdashboard_window_tracker_window_x11_window_tracker_window_close(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Close window */
+ wnck_window_close(priv->window, xfdashboard_window_tracker_x11_get_time());
+}
+
+/* Get process ID owning the requested window */
+static gint _xfdashboard_window_tracker_window_x11_window_tracker_window_get_pid(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), -1);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_window_tracker_window_get_instance_names(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ GSList *names;
+ GSList *iter;
+ const gchar *value;
+ guint numberEntries;
+ gchar **result;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+ names=NULL;
+ result=NULL;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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_x11_window_tracker_window_get_content(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ ClutterContent *content;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Create content for window */
+ content=xfdashboard_window_content_x11_new_for_window(self);
+
+ /* Return content */
+ return(content);
+}
+
+/* Get associated stage of window */
+static ClutterStage* _xfdashboard_window_tracker_window_x11_window_tracker_window_get_stage(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ ClutterStage *foundStage;
+ ClutterStage *stage;
+ Window stageXWindow;
+ GSList *stages, *entry;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_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)
+ {
+ stageXWindow=clutter_x11_get_stage_window(stage);
+ if(stageXWindow==wnck_window_get_xid(priv->window)) foundStage=stage;
+ }
+ }
+ g_slist_free(stages);
+
+ return(foundStage);
+}
+
+/* Set up window for use as stage window */
+static void _xfdashboard_window_tracker_window_x11_window_tracker_window_make_stage_window(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ XfdashboardWindowTracker *windowTracker;
+ WnckScreen *screen;
+ guint signalID;
+ gulong handlerID;
+ gint width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* Window of stage should always be above all other windows, pinned to all
+ * workspaces, not be listed in window pager and set to fullscreen
+ */
+ if(!wnck_window_is_skip_tasklist(priv->window)) wnck_window_set_skip_tasklist(priv->window, TRUE);
+ if(!wnck_window_is_skip_pager(priv->window)) wnck_window_set_skip_pager(priv->window, TRUE);
+ if(!wnck_window_is_above(priv->window)) wnck_window_make_above(priv->window);
+ if(!wnck_window_is_pinned(priv->window)) wnck_window_pin(priv->window);
+
+ /* Get screen of window */
+ screen=wnck_window_get_screen(priv->window);
+
+ /* 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_x11_on_stage_state_changed),
+ NULL);
+ if(!handlerID)
+ {
+ g_signal_connect(priv->window,
+ "state-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_x11_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_x11_on_stage_active_window_changed),
+ NULL);
+ if(!handlerID)
+ {
+ g_signal_connect(screen,
+ "active-window-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_x11_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_x11_on_stage_screen_size_changed),
+ NULL);
+ if(!handlerID)
+ {
+ g_signal_connect(windowTracker,
+ "screen-size-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_window_x11_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_x11_on_stage_screen_size_changed(windowTracker,
+ width,
+ height,
+ self);
+ g_object_unref(windowTracker);
+}
+
+/* Unset up stage window (only remove connected signals) */
+static void _xfdashboard_window_tracker_window_x11_window_tracker_window_unmake_stage_window(XfdashboardWindowTrackerWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *self;
+ XfdashboardWindowTrackerWindowX11Private *priv;
+ XfdashboardWindowTracker *windowTracker;
+ WnckScreen *screen;
+ guint signalID;
+ gulong handlerID;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inWindow));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inWindow);
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return;
+ }
+
+ /* 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_x11_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_x11_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_x11_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_x11_window_tracker_window_iface_init(XfdashboardWindowTrackerWindowInterface *iface)
+{
+ iface->is_visible=_xfdashboard_window_tracker_window_x11_window_tracker_window_is_visible;
+ iface->show=_xfdashboard_window_tracker_window_x11_window_tracker_window_show;
+ iface->hide=_xfdashboard_window_tracker_window_x11_window_tracker_window_hide;
+
+ iface->get_parent=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_parent;
+
+ iface->get_state=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_state;
+ iface->get_actions=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_actions;
+
+ iface->get_name=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_name;
+
+ iface->get_icon=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_icon;
+ iface->get_icon_name=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_icon_name;
+
+ iface->get_workspace=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_workspace;
+ iface->is_on_workspace=_xfdashboard_window_tracker_window_x11_window_tracker_window_is_on_workspace;
+
+ iface->get_geometry=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_geometry;
+ iface->set_geometry=_xfdashboard_window_tracker_window_x11_window_tracker_window_set_geometry;
+ iface->move=_xfdashboard_window_tracker_window_x11_window_tracker_window_move;
+ iface->resize=_xfdashboard_window_tracker_window_x11_window_tracker_window_resize;
+ iface->move_to_workspace=_xfdashboard_window_tracker_window_x11_window_tracker_window_move_to_workspace;
+ iface->activate=_xfdashboard_window_tracker_window_x11_window_tracker_window_activate;
+ iface->close=_xfdashboard_window_tracker_window_x11_window_tracker_window_close;
+
+ iface->get_pid=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_pid;
+ iface->get_instance_names=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_instance_names;
+
+ iface->get_content=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_content;
+
+ iface->get_stage=_xfdashboard_window_tracker_window_x11_window_tracker_window_get_stage;
+ iface->make_stage_window=_xfdashboard_window_tracker_window_x11_window_tracker_window_make_stage_window;
+ iface->unmake_stage_window=_xfdashboard_window_tracker_window_x11_window_tracker_window_unmake_stage_window;
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_tracker_window_x11_dispose(GObject *inObject)
+{
+ XfdashboardWindowTrackerWindowX11 *self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inObject);
+ XfdashboardWindowTrackerWindowX11Private *priv=self->priv;
+
+ /* Dispose allocated resources */
+ 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_x11_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_tracker_window_x11_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerWindowX11 *self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_WINDOW:
+ _xfdashboard_window_tracker_window_x11_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_x11_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerWindowX11 *self=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_class_init(XfdashboardWindowTrackerWindowX11Class *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_x11_dispose;
+ gobjectClass->set_property=_xfdashboard_window_tracker_window_x11_set_property;
+ gobjectClass->get_property=_xfdashboard_window_tracker_window_x11_get_property;
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowTrackerWindowX11Private));
+
+ /* Define properties */
+ XfdashboardWindowTrackerWindowX11Properties[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");
+ XfdashboardWindowTrackerWindowX11Properties[PROP_STATE]=
+ g_param_spec_override("state", paramSpec);
+
+ paramSpec=g_object_interface_find_property(windowIface, "actions");
+ XfdashboardWindowTrackerWindowX11Properties[PROP_ACTIONS]=
+ g_param_spec_override("actions", paramSpec);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowTrackerWindowX11Properties);
+
+ /* Release allocated resources */
+ g_type_default_interface_unref(windowIface);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_window_tracker_window_x11_init(XfdashboardWindowTrackerWindowX11 *self)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_GET_PRIVATE(self);
+
+ /* Set default values */
+ priv->window=NULL;
+}
+
+
+/* IMPLEMENTATION: Public API */
+
+/**
+ * xfdashboard_window_tracker_window_x11_get_window:
+ * @self: A #XfdashboardWindowTrackerWindowX11
+ *
+ * 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_x11_get_window(XfdashboardWindowTrackerWindowX11 *self)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(self), NULL);
+
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return(NULL);
+ }
+
+ /* Return wrapped libwnck window */
+ return(self->priv->window);
+}
+
+/**
+ * xfdashboard_window_tracker_window_x11_get_xid:
+ * @self: A #XfdashboardWindowTrackerWindowX11
+ *
+ * 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_x11_get_xid(XfdashboardWindowTrackerWindowX11 *self)
+{
+ XfdashboardWindowTrackerWindowX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(self), None);
+
+ priv=self->priv;
+
+ /* A wnck window must be wrapped by this object */
+ if(!priv->window)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_WARN_NO_WINDOW(self);
+ return(None);
+ }
+
+ /* Return X window ID */
+ return(wnck_window_get_xid(priv->window));
+}
diff --git a/libxfdashboard/x11/window-tracker-window-x11.h b/libxfdashboard/x11/window-tracker-window-x11.h
new file mode 100644
index 0000000..691e318
--- /dev/null
+++ b/libxfdashboard/x11/window-tracker-window-x11.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_X11__
+#define __LIBXFDASHBOARD_WINDOW_TRACKER_WINDOW_X11__
+
+#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_X11 (xfdashboard_window_tracker_window_x11_get_type())
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_X11, XfdashboardWindowTrackerWindowX11))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_X11))
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_X11, XfdashboardWindowTrackerWindowX11Class))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_X11))
+#define XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_X11, XfdashboardWindowTrackerWindowX11Class))
+
+typedef struct _XfdashboardWindowTrackerWindowX11 XfdashboardWindowTrackerWindowX11;
+typedef struct _XfdashboardWindowTrackerWindowX11Class XfdashboardWindowTrackerWindowX11Class;
+typedef struct _XfdashboardWindowTrackerWindowX11Private XfdashboardWindowTrackerWindowX11Private;
+
+struct _XfdashboardWindowTrackerWindowX11
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowTrackerWindowX11Private *priv;
+};
+
+struct _XfdashboardWindowTrackerWindowX11Class
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+};
+
+/* Public API */
+GType xfdashboard_window_tracker_window_x11_get_type(void) G_GNUC_CONST;
+
+WnckWindow* xfdashboard_window_tracker_window_x11_get_window(XfdashboardWindowTrackerWindowX11 *self);
+gulong xfdashboard_window_tracker_window_x11_get_xid(XfdashboardWindowTrackerWindowX11 *self);
+
+G_END_DECLS
+
+#endif /* __LIBXFDASHBOARD_WINDOW_TRACKER_WINDOW_X11__ */
diff --git a/libxfdashboard/x11/window-tracker-workspace-x11.c b/libxfdashboard/x11/window-tracker-workspace-x11.c
new file mode 100644
index 0000000..32cf889
--- /dev/null
+++ b/libxfdashboard/x11/window-tracker-workspace-x11.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-x11
+ * @short_description: A workspace used by X11 window tracker
+ * @include: xfdashboard/x11/window-tracker-workspace-x11.h
+ *
+ * TODO: DESCRIPTION
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libxfdashboard/x11/window-tracker-workspace-x11.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+#include <glib/gi18n-lib.h>
+
+#include <libxfdashboard/x11/window-tracker-x11.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_x11_window_tracker_workspace_iface_init(XfdashboardWindowTrackerWorkspaceInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerWorkspaceX11,
+ xfdashboard_window_tracker_workspace_x11,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE, _xfdashboard_window_tracker_workspace_x11_window_tracker_workspace_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_X11, XfdashboardWindowTrackerWorkspaceX11Private))
+
+struct _XfdashboardWindowTrackerWorkspaceX11Private
+{
+ /* Properties related */
+ WnckWorkspace *workspace;
+};
+
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ PROP_WORKSPACE,
+
+ PROP_LAST
+};
+
+static GParamSpec* XfdashboardWindowTrackerWorkspaceX11Properties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_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_X11_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_x11_on_wnck_name_changed(XfdashboardWindowTrackerWorkspaceX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+ WnckWorkspace *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(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_X11_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_x11_set_workspace(XfdashboardWindowTrackerWorkspaceX11 *self,
+ WnckWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(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_x11_on_wnck_name_changed),
+ self);
+ }
+
+ /* Notify about property change */
+ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerWorkspaceX11Properties[PROP_WORKSPACE]);
+ }
+}
+
+
+/* IMPLEMENTATION: Interface XfdashboardWindowTrackerWorkspace */
+
+/* Get number of workspace */
+static gint _xfdashboard_window_tracker_workspace_x11_window_tracker_workspace_get_number(XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *self;
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace), -1);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_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_x11_window_tracker_workspace_get_name(XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *self;
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_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_x11_window_tracker_workspace_get_size(XfdashboardWindowTrackerWorkspace *inWorkspace,
+ gint *outWidth,
+ gint *outHeight)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *self;
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+ gint width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_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_x11_window_tracker_workspace_is_active(XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *self;
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+ XfdashboardWindowTracker *windowTracker;
+ XfdashboardWindowTrackerWorkspace *activeWorkspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_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_x11_window_tracker_workspace_activate(XfdashboardWindowTrackerWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *self;
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(inWorkspace);
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_WARN_NO_WORKSPACE(self);
+ return;
+ }
+
+ /* Activate workspace */
+ wnck_workspace_activate(priv->workspace, xfdashboard_window_tracker_x11_get_time());
+}
+
+/* Interface initialization
+ * Set up default functions
+ */
+static void _xfdashboard_window_tracker_workspace_x11_window_tracker_workspace_iface_init(XfdashboardWindowTrackerWorkspaceInterface *iface)
+{
+ iface->get_number=_xfdashboard_window_tracker_workspace_x11_window_tracker_workspace_get_number;
+ iface->get_name=_xfdashboard_window_tracker_workspace_x11_window_tracker_workspace_get_name;
+
+ iface->get_size=_xfdashboard_window_tracker_workspace_x11_window_tracker_workspace_get_size;
+
+ iface->is_active=_xfdashboard_window_tracker_workspace_x11_window_tracker_workspace_is_active;
+ iface->activate=_xfdashboard_window_tracker_workspace_x11_window_tracker_workspace_activate;
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_tracker_workspace_x11_dispose(GObject *inObject)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(inObject);
+ XfdashboardWindowTrackerWorkspaceX11Private *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_x11_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_tracker_workspace_x11_set_property(GObject *inObject,
+ guint inPropID,
+ const GValue *inValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(inObject);
+
+ switch(inPropID)
+ {
+ case PROP_WORKSPACE:
+ _xfdashboard_window_tracker_workspace_x11_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_x11_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *self=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(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_x11_class_init(XfdashboardWindowTrackerWorkspaceX11Class *klass)
+{
+ GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
+
+ /* Override functions */
+ gobjectClass->dispose=_xfdashboard_window_tracker_workspace_x11_dispose;
+ gobjectClass->set_property=_xfdashboard_window_tracker_workspace_x11_set_property;
+ gobjectClass->get_property=_xfdashboard_window_tracker_workspace_x11_get_property;
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowTrackerWorkspaceX11Private));
+
+ /* Define properties */
+ XfdashboardWindowTrackerWorkspaceX11Properties[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, XfdashboardWindowTrackerWorkspaceX11Properties);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_window_tracker_workspace_x11_init(XfdashboardWindowTrackerWorkspaceX11 *self)
+{
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_GET_PRIVATE(self);
+
+ /* Set default values */
+ priv->workspace=NULL;
+}
+
+
+/* IMPLEMENTATION: Public API */
+
+/**
+ * xfdashboard_window_tracker_workspace_x11_get_workspace:
+ * @self: A #XfdashboardWindowTrackerWorkspaceX11
+ *
+ * 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_x11_get_workspace(XfdashboardWindowTrackerWorkspaceX11 *self)
+{
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(self), NULL);
+
+ priv=self->priv;
+
+ /* A wnck workspace must be wrapped by this object */
+ if(!priv->workspace)
+ {
+ XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_WARN_NO_WORKSPACE(self);
+ return(NULL);
+ }
+
+ /* Return wrapped libwnck workspace */
+ return(self->priv->workspace);
+}
diff --git a/libxfdashboard/x11/window-tracker-workspace-x11.h b/libxfdashboard/x11/window-tracker-workspace-x11.h
new file mode 100644
index 0000000..f0f2265
--- /dev/null
+++ b/libxfdashboard/x11/window-tracker-workspace-x11.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_X11__
+#define __LIBXFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11__
+
+#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_X11 (xfdashboard_window_tracker_workspace_x11_get_type())
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_X11, XfdashboardWindowTrackerWorkspaceX11))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_X11))
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_X11, XfdashboardWindowTrackerWorkspaceX11Class))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_X11))
+#define XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_X11, XfdashboardWindowTrackerWorkspaceX11Class))
+
+typedef struct _XfdashboardWindowTrackerWorkspaceX11 XfdashboardWindowTrackerWorkspaceX11;
+typedef struct _XfdashboardWindowTrackerWorkspaceX11Class XfdashboardWindowTrackerWorkspaceX11Class;
+typedef struct _XfdashboardWindowTrackerWorkspaceX11Private XfdashboardWindowTrackerWorkspaceX11Private;
+
+struct _XfdashboardWindowTrackerWorkspaceX11
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowTrackerWorkspaceX11Private *priv;
+};
+
+struct _XfdashboardWindowTrackerWorkspaceX11Class
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+};
+
+/* Public API */
+GType xfdashboard_window_tracker_workspace_x11_get_type(void) G_GNUC_CONST;
+
+WnckWorkspace* xfdashboard_window_tracker_workspace_x11_get_workspace(XfdashboardWindowTrackerWorkspaceX11 *self);
+
+G_END_DECLS
+
+#endif /* __LIBXFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11__ */
diff --git a/libxfdashboard/x11/window-tracker-x11.c b/libxfdashboard/x11/window-tracker-x11.c
new file mode 100644
index 0000000..e333a83
--- /dev/null
+++ b/libxfdashboard/x11/window-tracker-x11.c
@@ -0,0 +1,1890 @@
+/*
+ * 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/x11/window-tracker-x11.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+#include <glib/gi18n-lib.h>
+#include <clutter/clutter.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/x11/window-tracker-monitor-x11.h>
+#include <libxfdashboard/x11/window-tracker-window-x11.h>
+#include <libxfdashboard/x11/window-tracker-workspace-x11.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_x11_window_tracker_iface_init(XfdashboardWindowTrackerInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerX11,
+ xfdashboard_window_tracker_x11,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER, _xfdashboard_window_tracker_x11_window_tracker_iface_init))
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_WINDOW_TRACKER_X11_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_X11, XfdashboardWindowTrackerX11Private))
+
+struct _XfdashboardWindowTrackerX11Private
+{
+ /* Properties related */
+ XfdashboardWindowTrackerWindowX11 *activeWindow;
+ XfdashboardWindowTrackerWorkspaceX11 *activeWorkspace;
+ XfdashboardWindowTrackerMonitorX11 *primaryMonitor;
+
+ /* Instance related */
+ GList *windows;
+ GList *workspaces;
+ GList *monitors;
+
+ XfdashboardApplication *application;
+ gboolean isAppSuspended;
+ guint suspendSignalID;
+
+ WnckScreen *screen;
+
+ gboolean supportsMultipleMonitors;
+ GdkScreen *gdkScreen;
+};
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ /* Overriden properties of interface: XfdashboardWindowTracker */
+ PROP_ACTIVE_WINDOW,
+ PROP_ACTIVE_WORKSPACE,
+ PROP_PRIMARY_MONITOR,
+
+ PROP_LAST
+};
+
+static GParamSpec* XfdashboardWindowTrackerX11Properties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+
+/* Free workspace object */
+static void _xfdashboard_window_tracker_x11_free_workspace(XfdashboardWindowTrackerX11 *self,
+ XfdashboardWindowTrackerWorkspaceX11 *inWorkspace)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ GList *iter;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(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 XfdashboardWindowTrackerWorkspaceX11* _xfdashboard_window_tracker_x11_get_workspace_for_wnck(XfdashboardWindowTrackerX11 *self,
+ WnckWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ GList *iter;
+ XfdashboardWindowTrackerWorkspaceX11 *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(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_X11(iter->data);
+ if(!workspace) continue;
+
+ /* Check if this workspace object wraps the requested wnck workspace */
+ if(xfdashboard_window_tracker_workspace_x11_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 XfdashboardWindowTrackerWorkspaceX11* _xfdashboard_window_tracker_x11_create_workspace_for_wnck(XfdashboardWindowTrackerX11 *self,
+ WnckWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ XfdashboardWindowTrackerWorkspaceX11 *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(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_x11_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_X11(g_object_new(XFDASHBOARD_TYPE_WINDOW_TRACKER_WORKSPACE_X11,
+ "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_X11),
+ 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_x11_free_window(XfdashboardWindowTrackerX11 *self,
+ XfdashboardWindowTrackerWindowX11 *inWindow)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ GList *iter;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(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 list and remove it if found */
+ iter=g_list_find(priv->windows, inWindow);
+ if(iter)
+ {
+ priv->windows=g_list_delete_link(priv->windows, iter);
+ }
+
+ /* Free window object */
+ g_object_unref(inWindow);
+}
+
+/* Get window object for requested wnck window */
+static XfdashboardWindowTrackerWindowX11* _xfdashboard_window_tracker_x11_get_window_for_wnck(XfdashboardWindowTrackerX11 *self,
+ WnckWindow *inWindow)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ GList *iter;
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(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 */
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(iter->data);
+ if(!window) continue;
+
+ /* Check if this window object wraps the requested wnck window */
+ if(xfdashboard_window_tracker_window_x11_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);
+}
+
+/* Create window object which must not exist yet */
+static XfdashboardWindowTrackerWindowX11* _xfdashboard_window_tracker_x11_create_window_for_wnck(XfdashboardWindowTrackerX11 *self,
+ WnckWindow *inWindow)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(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_x11_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_X11(g_object_new(XFDASHBOARD_TYPE_WINDOW_TRACKER_WINDOW_X11,
+ "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_X11),
+ wnck_window_get_name(inWindow));
+ return(NULL);
+ }
+
+ /* Add new window object to list of window objects */
+ priv->windows=g_list_prepend(priv->windows, window);
+
+ /* 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_x11_on_window_geometry_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_on_window_actions_changed(XfdashboardWindowTrackerX11 *self,
+ XfdashboardWindowTrackerWindowAction inChangedMask,
+ XfdashboardWindowTrackerWindowAction inNewValue,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_on_window_state_changed(XfdashboardWindowTrackerX11 *self,
+ XfdashboardWindowTrackerWindowState inChangedMask,
+ XfdashboardWindowTrackerWindowState inNewValue,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_on_window_icon_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_on_window_name_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_on_window_monitor_changed(XfdashboardWindowTrackerX11 *self,
+ XfdashboardWindowTrackerMonitor *inOldMonitor,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11 *window;
+ XfdashboardWindowTrackerMonitor *newMonitor;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(!inOldMonitor || XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inOldMonitor));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_on_window_workspace_changed(XfdashboardWindowTrackerX11 *self,
+ XfdashboardWindowTrackerWorkspace *inOldWorkspace,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWindowX11 *window;
+ XfdashboardWindowTrackerWorkspace *newWorkspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(!inOldWorkspace || XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inOldWorkspace));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inUserData));
+
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(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_x11_on_active_window_changed(XfdashboardWindowTrackerX11 *self,
+ WnckWindow *inPreviousWindow,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ WnckScreen *screen;
+ XfdashboardWindowTrackerWindowX11 *oldActiveWindow;
+ XfdashboardWindowTrackerWindowX11 *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_x11_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_X11),
+ 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_x11_on_window_closed(XfdashboardWindowTrackerX11 *self,
+ WnckWindow *inWindow,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ XfdashboardWindowTrackerWindowX11 *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_x11_get_window(priv->activeWindow)==inWindow)
+ {
+ priv->activeWindow=NULL;
+ }
+
+ /* Get window object for closed wnck window */
+ window=_xfdashboard_window_tracker_x11_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_X11),
+ 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_x11_free_window(self, window);
+}
+
+/* A new window was opened */
+static void _xfdashboard_window_tracker_x11_on_window_opened(XfdashboardWindowTrackerX11 *self,
+ WnckWindow *inWindow,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ XfdashboardWindowTrackerWindowX11 *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_x11_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_x11_on_window_actions_changed), self);
+ g_signal_connect_swapped(window, "state-changed", G_CALLBACK(_xfdashboard_window_tracker_x11_on_window_state_changed), self);
+ g_signal_connect_swapped(window, "icon-changed", G_CALLBACK(_xfdashboard_window_tracker_x11_on_window_icon_changed), self);
+ g_signal_connect_swapped(window, "name-changed", G_CALLBACK(_xfdashboard_window_tracker_x11_on_window_name_changed), self);
+ g_signal_connect_swapped(window, "monitor-changed", G_CALLBACK(_xfdashboard_window_tracker_x11_on_window_monitor_changed), self);
+ g_signal_connect_swapped(window, "workspace-changed", G_CALLBACK(_xfdashboard_window_tracker_x11_on_window_workspace_changed), self);
+ g_signal_connect_swapped(window, "geometry-changed", G_CALLBACK(_xfdashboard_window_tracker_x11_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_x11_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_x11_on_window_stacking_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(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_x11_on_workspace_name_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inUserData));
+
+ workspace=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(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_x11_on_active_workspace_changed(XfdashboardWindowTrackerX11 *self,
+ WnckWorkspace *inPreviousWorkspace,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ WnckScreen *screen;
+ XfdashboardWindowTrackerWorkspaceX11 *oldActiveWorkspace;
+ XfdashboardWindowTrackerWorkspaceX11 *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_x11_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_X11),
+ 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_x11_on_workspace_destroyed(XfdashboardWindowTrackerX11 *self,
+ WnckWorkspace *inWorkspace,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ XfdashboardWindowTrackerWorkspaceX11 *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_x11_get_workspace(priv->activeWorkspace)==inWorkspace)
+ {
+ priv->activeWorkspace=NULL;
+ }
+
+ /* Get workspace object for wnck workspace */
+ workspace=_xfdashboard_window_tracker_x11_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_X11),
+ 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_x11_free_workspace(self, workspace);
+}
+
+/* A new workspace was created */
+static void _xfdashboard_window_tracker_x11_on_workspace_created(XfdashboardWindowTrackerX11 *self,
+ WnckWorkspace *inWorkspace,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *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_x11_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_x11_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_x11_on_primary_monitor_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ XfdashboardWindowTrackerMonitorX11 *monitor;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inUserData));
+
+ priv=self->priv;
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(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)
+ {
+ XfdashboardWindowTrackerMonitorX11 *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), XfdashboardWindowTrackerX11Properties[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_x11_on_monitor_geometry_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerMonitorX11 *monitor;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inUserData));
+
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(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 XfdashboardWindowTrackerMonitorX11* _xfdashboard_window_tracker_x11_monitor_new(XfdashboardWindowTrackerX11 *self,
+ guint inMonitorIndex)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ XfdashboardWindowTrackerMonitorX11 *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_X11(g_object_new(XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR_X11,
+ "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_x11_on_primary_monitor_changed),
+ self);
+ g_signal_connect_swapped(monitor,
+ "geometry-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_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_x11_on_primary_monitor_changed(self, monitor);
+ }
+
+ /* Return newly created monitor */
+ return(monitor);
+}
+
+/* Free a monitor object */
+static void _xfdashboard_window_tracker_x11_monitor_free(XfdashboardWindowTrackerX11 *self,
+ XfdashboardWindowTrackerMonitorX11 *inMonitor)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ GList *iter;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(self));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(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_x11_on_monitors_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ GdkScreen *screen;
+ gint currentMonitorCount;
+ gint newMonitorCount;
+ gint i;
+ XfdashboardWindowTrackerMonitorX11 *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 */
+ newMonitorCount=gdk_screen_get_n_monitors(screen);
+ 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_x11_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_X11(iter->data);
+
+ /* Free monitor object */
+ _xfdashboard_window_tracker_x11_monitor_free(self, monitor);
+ }
+ }
+}
+#endif
+
+/* Total size of screen changed */
+static void _xfdashboard_window_tracker_x11_on_screen_size_changed(XfdashboardWindowTrackerX11 *self,
+ gpointer inUserData)
+{
+ GdkScreen *screen;
+ gint w, h;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(self));
+ g_return_if_fail(GDK_IS_SCREEN(inUserData));
+
+ screen=GDK_SCREEN(inUserData);
+
+ /* Get new total size of screen */
+ w=gdk_screen_get_width(screen);
+ h=gdk_screen_get_height(screen);
+
+ /* 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", w, h);
+}
+
+/* Suspension state of application changed */
+static void _xfdashboard_window_tracker_x11_on_application_suspended_changed(XfdashboardWindowTrackerX11 *self,
+ GParamSpec *inSpec,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11Private *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_x11_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_x11_on_window_geometry_changed, self);
+
+ /* Call signal handler to reflect latest changes */
+ _xfdashboard_window_tracker_x11_on_window_geometry_changed(self, window);
+ }
+ }
+}
+
+
+/* IMPLEMENTATION: Interface XfdashboardWindowTracker */
+
+/* Get list of all windows (if wanted in stack order) */
+static GList* _xfdashboard_window_tracker_x11_window_tracker_get_windows(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(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_x11_window_tracker_get_windows_stacked(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ /* Return list of window in stack order */
+ // TODO: return(wnck_screen_get_windows_stacked(priv->screen));
+ return(priv->windows);
+}
+
+/* Get active window */
+static XfdashboardWindowTrackerWindow* _xfdashboard_window_tracker_x11_window_tracker_get_active_window(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ return(XFDASHBOARD_WINDOW_TRACKER_WINDOW(priv->activeWindow));
+}
+
+/* Get number of workspaces */
+static gint _xfdashboard_window_tracker_x11_window_tracker_get_workspaces_count(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(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_x11_window_tracker_get_workspaces(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ /* Return list of workspaces */
+ return(priv->workspaces);
+}
+
+/* Get active workspace */
+static XfdashboardWindowTrackerWorkspace* _xfdashboard_window_tracker_x11_window_tracker_get_active_workspace(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ return(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE(priv->activeWorkspace));
+}
+
+/* Get workspace by number */
+static XfdashboardWindowTrackerWorkspace* _xfdashboard_window_tracker_x11_window_tracker_get_workspace_by_number(XfdashboardWindowTracker *inWindowTracker,
+ gint inNumber)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+ WnckWorkspace *wnckWorkspace;
+ XfdashboardWindowTrackerWorkspaceX11 *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(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_x11_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_X11),
+ 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_x11_window_tracker_supports_multiple_monitors(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), FALSE);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ return(priv->supportsMultipleMonitors);
+}
+
+/* Get number of monitors */
+static gint _xfdashboard_window_tracker_x11_window_tracker_get_monitors_count(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), 0);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ /* Return number of monitors */
+ return(g_list_length(priv->monitors));
+}
+
+/* Get list of monitors */
+static GList* _xfdashboard_window_tracker_x11_window_tracker_get_monitors(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ /* Return list of workspaces */
+ return(priv->monitors);
+}
+
+/* Get primary monitor */
+static XfdashboardWindowTrackerMonitor* _xfdashboard_window_tracker_x11_window_tracker_get_primary_monitor(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ return(XFDASHBOARD_WINDOW_TRACKER_MONITOR(priv->primaryMonitor));
+}
+
+/* Get monitor by number */
+static XfdashboardWindowTrackerMonitor* _xfdashboard_window_tracker_x11_window_tracker_get_monitor_by_number(XfdashboardWindowTracker *inWindowTracker,
+ gint inNumber)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(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_x11_window_tracker_get_monitor_by_position(XfdashboardWindowTracker *inWindowTracker,
+ gint inX,
+ gint inY)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+ GList *iter;
+ XfdashboardWindowTrackerMonitorX11 *monitor;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(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_X11(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_x11_window_tracker_get_screen_size(XfdashboardWindowTracker *inWindowTracker,
+ gint *outWidth,
+ gint *outHeight)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+ gint width, height;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+ priv=self->priv;
+
+ /* Get width and height of screen */
+ width=gdk_screen_get_width(priv->gdkScreen);
+ height=gdk_screen_get_height(priv->gdkScreen);
+
+ /* Store result */
+ if(outWidth) *outWidth=width;
+ if(outHeight) *outHeight=height;
+}
+
+/* Get root (desktop) window */
+static XfdashboardWindowTrackerWindow* _xfdashboard_window_tracker_x11_window_tracker_get_root_window(XfdashboardWindowTracker *inWindowTracker)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerX11Private *priv;
+ gulong backgroundWindowID;
+ GList *windows;
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(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_x11_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_x11_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_x11_window_tracker_get_stage_window(XfdashboardWindowTracker *inWindowTracker,
+ ClutterStage *inStage)
+{
+ XfdashboardWindowTrackerX11 *self;
+ Window stageXWindow;
+ WnckWindow *wnckWindow;
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inWindowTracker), NULL);
+ g_return_val_if_fail(CLUTTER_IS_STAGE(inStage), NULL);
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inWindowTracker);
+
+ /* Get stage X window and translate to needed window type */
+ stageXWindow=clutter_x11_get_stage_window(inStage);
+ wnckWindow=wnck_window_get(stageXWindow);
+
+ /* Get or create window object for wnck background window */
+ window=_xfdashboard_window_tracker_x11_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_x11_window_tracker_iface_init(XfdashboardWindowTrackerInterface *iface)
+{
+ iface->get_windows=_xfdashboard_window_tracker_x11_window_tracker_get_windows;
+ iface->get_windows_stacked=_xfdashboard_window_tracker_x11_window_tracker_get_windows_stacked;
+ iface->get_active_window=_xfdashboard_window_tracker_x11_window_tracker_get_active_window;
+
+ iface->get_workspaces_count=_xfdashboard_window_tracker_x11_window_tracker_get_workspaces_count;
+ iface->get_workspaces=_xfdashboard_window_tracker_x11_window_tracker_get_workspaces;
+ iface->get_active_workspace=_xfdashboard_window_tracker_x11_window_tracker_get_active_workspace;
+ iface->get_workspace_by_number=_xfdashboard_window_tracker_x11_window_tracker_get_workspace_by_number;
+
+ iface->supports_multiple_monitors=_xfdashboard_window_tracker_x11_window_tracker_supports_multiple_monitors;
+ iface->get_monitors_count=_xfdashboard_window_tracker_x11_window_tracker_get_monitors_count;
+ iface->get_monitors=_xfdashboard_window_tracker_x11_window_tracker_get_monitors;
+ iface->get_primary_monitor=_xfdashboard_window_tracker_x11_window_tracker_get_primary_monitor;
+ iface->get_monitor_by_number=_xfdashboard_window_tracker_x11_window_tracker_get_monitor_by_number;
+ iface->get_monitor_by_position=_xfdashboard_window_tracker_x11_window_tracker_get_monitor_by_position;
+
+ iface->get_screen_size=_xfdashboard_window_tracker_x11_window_tracker_get_screen_size;
+
+ iface->get_root_window=_xfdashboard_window_tracker_x11_window_tracker_get_root_window;
+ iface->get_stage_window=_xfdashboard_window_tracker_x11_window_tracker_get_stage_window;
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_window_tracker_x11_dispose_free_window(gpointer inData,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW_X11(inData));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inUserData));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inUserData);
+ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW_X11(inData);
+
+ /* Unreference window */
+ _xfdashboard_window_tracker_x11_free_window(self, window);
+}
+
+static void _xfdashboard_window_tracker_x11_dispose_free_workspace(gpointer inData,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerWorkspaceX11 *workspace;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WORKSPACE_X11(inData));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inUserData));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inUserData);
+ workspace=XFDASHBOARD_WINDOW_TRACKER_WORKSPACE_X11(inData);
+
+ /* Unreference workspace */
+ _xfdashboard_window_tracker_x11_free_workspace(self, workspace);
+}
+
+static void _xfdashboard_window_tracker_x11_dispose_free_monitor(gpointer inData,
+ gpointer inUserData)
+{
+ XfdashboardWindowTrackerX11 *self;
+ XfdashboardWindowTrackerMonitorX11 *monitor;
+
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inData));
+ g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(inUserData));
+
+ self=XFDASHBOARD_WINDOW_TRACKER_X11(inUserData);
+ monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inData);
+
+ /* Unreference monitor */
+ _xfdashboard_window_tracker_x11_monitor_free(self, monitor);
+}
+
+static void _xfdashboard_window_tracker_x11_dispose(GObject *inObject)
+{
+ XfdashboardWindowTrackerX11 *self=XFDASHBOARD_WINDOW_TRACKER_X11(inObject);
+ XfdashboardWindowTrackerX11Private *priv=self->priv;
+
+ /* Dispose allocated resources */
+ if(priv->suspendSignalID)
+ {
+ g_signal_handler_disconnect(xfdashboard_application_get_default(), priv->suspendSignalID);
+ priv->suspendSignalID=0;
+ }
+
+ if(priv->activeWindow)
+ {
+ priv->activeWindow=NULL;
+ }
+
+ if(priv->windows)
+ {
+ g_list_foreach(priv->windows, _xfdashboard_window_tracker_x11_dispose_free_window, self);
+ g_list_free(priv->windows);
+ priv->windows=NULL;
+ }
+
+ if(priv->activeWorkspace)
+ {
+ priv->activeWorkspace=NULL;
+ }
+
+ if(priv->workspaces)
+ {
+ g_list_foreach(priv->workspaces, _xfdashboard_window_tracker_x11_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_x11_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(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_x11_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_window_tracker_x11_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_x11_get_property(GObject *inObject,
+ guint inPropID,
+ GValue *outValue,
+ GParamSpec *inSpec)
+{
+ XfdashboardWindowTrackerX11 *self=XFDASHBOARD_WINDOW_TRACKER_X11(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_x11_class_init(XfdashboardWindowTrackerX11Class *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_x11_dispose;
+ gobjectClass->set_property=_xfdashboard_window_tracker_x11_set_property;
+ gobjectClass->get_property=_xfdashboard_window_tracker_x11_get_property;
+
+ /* Set up private structure */
+ g_type_class_add_private(klass, sizeof(XfdashboardWindowTrackerX11Private));
+
+ /* Define properties */
+ paramSpec=g_object_interface_find_property(trackerIface, "active-window");
+ XfdashboardWindowTrackerX11Properties[PROP_ACTIVE_WINDOW]=
+ g_param_spec_override("active-window", paramSpec);
+
+ paramSpec=g_object_interface_find_property(trackerIface, "active-workspace");
+ XfdashboardWindowTrackerX11Properties[PROP_ACTIVE_WORKSPACE]=
+ g_param_spec_override("active-workspace", paramSpec);
+
+ paramSpec=g_object_interface_find_property(trackerIface, "primary-monitor");
+ XfdashboardWindowTrackerX11Properties[PROP_PRIMARY_MONITOR]=
+ g_param_spec_override("primary-monitor", paramSpec);
+
+ g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowTrackerX11Properties);
+
+ /* Release allocated resources */
+ g_type_default_interface_unref(trackerIface);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_window_tracker_x11_init(XfdashboardWindowTrackerX11 *self)
+{
+ XfdashboardWindowTrackerX11Private *priv;
+ XfdashboardApplication *app;
+
+ priv=self->priv=XFDASHBOARD_WINDOW_TRACKER_X11_GET_PRIVATE(self);
+
+ XFDASHBOARD_DEBUG(self, WINDOWS, "Initializing window tracker");
+
+ /* Set default values */
+ priv->windows=NULL;
+ priv->workspaces=NULL;
+ priv->monitors=NULL;
+ priv->screen=wnck_screen_get_default();
+ priv->gdkScreen=gdk_screen_get_default();
+ 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_x11_on_window_stacking_changed),
+ self);
+
+ g_signal_connect_swapped(priv->screen,
+ "window-closed",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_on_window_closed),
+ self);
+ g_signal_connect_swapped(priv->screen,
+ "window-opened",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_on_window_opened),
+ self);
+ g_signal_connect_swapped(priv->screen,
+ "active-window-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_on_active_window_changed),
+ self);
+
+ g_signal_connect_swapped(priv->screen,
+ "workspace-destroyed",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_on_workspace_destroyed),
+ self);
+ g_signal_connect_swapped(priv->screen,
+ "workspace-created",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_on_workspace_created),
+ self);
+ g_signal_connect_swapped(priv->screen,
+ "active-workspace-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_on_active_workspace_changed),
+ self);
+
+ g_signal_connect_swapped(priv->gdkScreen,
+ "size-changed",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_on_screen_size_changed),
+ self);
+
+#ifdef HAVE_XINERAMA
+ /* Check if multiple monitors are supported */
+ if(XineramaIsActive(GDK_SCREEN_XDISPLAY(priv->gdkScreen)))
+ {
+ XfdashboardWindowTrackerMonitorX11 *monitor;
+ 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_x11_on_monitors_changed),
+ self,
+ NULL,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+
+ /* Get monitors */
+ for(i=0; i<gdk_screen_get_n_monitors(priv->gdkScreen); i++)
+ {
+ /* Create monitor object */
+ monitor=_xfdashboard_window_tracker_x11_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 */
+ app=xfdashboard_application_get_default();
+ priv->suspendSignalID=g_signal_connect_swapped(app,
+ "notify::is-suspended",
+ G_CALLBACK(_xfdashboard_window_tracker_x11_on_application_suspended_changed),
+ self);
+ priv->isAppSuspended=xfdashboard_application_is_suspended(app);
+}
+
+
+/* IMPLEMENTATION: Public API */
+
+/* Get last timestamp for use in libwnck */
+guint32 xfdashboard_window_tracker_x11_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(_xfdashboard_window_tracker_singleton, 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(_xfdashboard_window_tracker_singleton, 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(_xfdashboard_window_tracker_singleton, WINDOWS, "No timestamp for windows - trying last resort via stage windows");
+
+ display=gdk_display_get_default();
+ if(!display)
+ {
+ XFDASHBOARD_DEBUG(_xfdashboard_window_tracker_singleton, 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=gdk_x11_window_lookup_for_display(display, clutter_x11_get_stage_window(stage));
+ if(!window)
+ {
+ XFDASHBOARD_DEBUG(_xfdashboard_window_tracker_singleton, 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(_xfdashboard_window_tracker_singleton, 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(_xfdashboard_window_tracker_singleton, 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_x11_get_window_for_wnck(XfdashboardWindowTrackerX11 *self,
+ WnckWindow *inWindow)
+{
+ XfdashboardWindowTrackerWindowX11 *window;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(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_x11_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_x11_get_workspace_for_wnck(XfdashboardWindowTrackerX11 *self,
+ WnckWorkspace *inWorkspace)
+{
+ XfdashboardWindowTrackerWorkspaceX11 *workspace;
+
+ g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_X11(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_x11_get_workspace_for_wnck(self, inWorkspace);
+ return(XFDASHBOARD_WINDOW_TRACKER_WORKSPACE(workspace));
+}
diff --git a/libxfdashboard/x11/window-tracker-x11.h b/libxfdashboard/x11/window-tracker-x11.h
new file mode 100644
index 0000000..b001438
--- /dev/null
+++ b/libxfdashboard/x11/window-tracker-x11.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_X11__
+#define __LIBXFDASHBOARD_WINDOW_TRACKER_X11__
+
+#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_X11 (xfdashboard_window_tracker_x11_get_type())
+#define XFDASHBOARD_WINDOW_TRACKER_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_X11, XfdashboardWindowTrackerX11))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_X11))
+#define XFDASHBOARD_WINDOW_TRACKER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_X11, XfdashboardWindowTrackerX11Class))
+#define XFDASHBOARD_IS_WINDOW_TRACKER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_WINDOW_TRACKER_X11))
+#define XFDASHBOARD_WINDOW_TRACKER_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_WINDOW_TRACKER_X11, XfdashboardWindowTrackerX11Class))
+
+typedef struct _XfdashboardWindowTrackerX11 XfdashboardWindowTrackerX11;
+typedef struct _XfdashboardWindowTrackerX11Class XfdashboardWindowTrackerX11Class;
+typedef struct _XfdashboardWindowTrackerX11Private XfdashboardWindowTrackerX11Private;
+
+struct _XfdashboardWindowTrackerX11
+{
+ /*< private >*/
+ /* Parent instance */
+ GObject parent_instance;
+
+ /* Private structure */
+ XfdashboardWindowTrackerX11Private *priv;
+};
+
+struct _XfdashboardWindowTrackerX11Class
+{
+ /*< private >*/
+ /* Parent class */
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Virtual functions */
+};
+
+/* Public API */
+GType xfdashboard_window_tracker_x11_get_type(void) G_GNUC_CONST;
+
+guint32 xfdashboard_window_tracker_x11_get_time(void);
+
+XfdashboardWindowTrackerWindow* xfdashboard_window_tracker_x11_get_window_for_wnck(XfdashboardWindowTrackerX11 *self,
+ WnckWindow *inWindow);
+XfdashboardWindowTrackerWorkspace* xfdashboard_window_tracker_x11_get_workspace_for_wnck(XfdashboardWindowTrackerX11 *self,
+ WnckWorkspace *inWorkspace);
+
+G_END_DECLS
+
+#endif /* __LIBXFDASHBOARD_WINDOW_TRACKER_X11__ */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the Xfce4-commits
mailing list