1 /*
2 * window-tracker-monitor: A monitor object tracked by window tracker.
3 * It provides information about position and
4 * size of monitor within screen and also a flag
5 * if this monitor is the primary one.
6 *
7 * Copyright 2012-2020 Stephan Haller <nomad@froevel.de>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * MA 02110-1301, USA.
23 *
24 *
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <libxfdashboard/x11/window-tracker-monitor-x11.h>
32
33 #include <glib/gi18n-lib.h>
34 #include <gtk/gtk.h>
35 #include <gdk/gdkx.h>
36
37 #include <libxfdashboard/window-tracker-monitor.h>
38 #include <libxfdashboard/compat.h>
39 #include <libxfdashboard/debug.h>
40
41
42 /* Define this class in GObject system */
43 static void _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_iface_init(XfdashboardWindowTrackerMonitorInterface *iface);
44
45 struct _XfdashboardWindowTrackerMonitorX11Private
46 {
47 /* Properties related */
48 gint monitorIndex;
49 gboolean isPrimary;
50
51 /* Instance related */
52 GdkScreen *screen;
53 GdkRectangle geometry;
54 };
55
56 G_DEFINE_TYPE_WITH_CODE(XfdashboardWindowTrackerMonitorX11,
57 xfdashboard_window_tracker_monitor_x11,
58 G_TYPE_OBJECT,
59 G_ADD_PRIVATE(XfdashboardWindowTrackerMonitorX11)
60 G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR, _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_iface_init))
61
62 /* Properties */
63 enum
64 {
65 PROP_0,
66
67 /* Overriden properties of interface: XfdashboardWindowTrackerMonitor */
68 PROP_MONITOR_INDEX,
69 PROP_IS_PRIMARY,
70
71 PROP_LAST
72 };
73
74 static GParamSpec* XfdashboardWindowTrackerMonitorX11Properties[PROP_LAST]={ 0, };
75
76
77 /* IMPLEMENTATION: Private variables and methods */
78
79 /* Set primary monitor flag */
_xfdashboard_window_tracker_monitor_x11_update_primary(XfdashboardWindowTrackerMonitorX11 * self)80 static void _xfdashboard_window_tracker_monitor_x11_update_primary(XfdashboardWindowTrackerMonitorX11 *self)
81 {
82 XfdashboardWindowTrackerMonitorX11Private *priv;
83 gboolean isPrimary;
84 #if GTK_CHECK_VERSION(3, 22, 0)
85 GdkMonitor *primaryMonitor;
86 #else
87 gint primaryMonitor;
88 #endif
89
90 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR(self));
91 g_return_if_fail(self->priv->monitorIndex>=0);
92
93 priv=self->priv;
94
95 /* Get primary flag */
96 #if GTK_CHECK_VERSION(3, 22, 0)
97 primaryMonitor=gdk_display_get_monitor(gdk_screen_get_display(priv->screen), priv->monitorIndex);
98 isPrimary=gdk_monitor_is_primary(primaryMonitor);
99 #else
100 primaryMonitor=gdk_screen_get_primary_monitor(priv->screen);
101 if(primaryMonitor==priv->monitorIndex) isPrimary=TRUE;
102 else isPrimary=FALSE;
103 #endif
104
105 /* Set value if changed */
106 if(priv->isPrimary!=isPrimary)
107 {
108 XFDASHBOARD_DEBUG(self, WINDOWS,
109 "Monitor %d changes primary state from %s to %s",
110 priv->monitorIndex,
111 priv->isPrimary ? "yes" : "no",
112 isPrimary ? "yes" : "no");
113
114 /* Set value */
115 priv->isPrimary=isPrimary;
116
117 /* Notify about property change */
118 g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerMonitorX11Properties[PROP_IS_PRIMARY]);
119
120 /* Emit signal */
121 g_signal_emit_by_name(self, "primary-changed");
122 }
123 }
124
125 /* Update monitor geometry */
_xfdashboard_window_tracker_monitor_x11_update_geometry(XfdashboardWindowTrackerMonitorX11 * self)126 static void _xfdashboard_window_tracker_monitor_x11_update_geometry(XfdashboardWindowTrackerMonitorX11 *self)
127 {
128 XfdashboardWindowTrackerMonitorX11Private *priv;
129 GdkRectangle geometry;
130 gint numberMonitors;
131 #if GTK_CHECK_VERSION(3, 22, 0)
132 GdkDisplay *display;
133 GdkMonitor *monitor;
134 #endif
135
136 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(self));
137 g_return_if_fail(self->priv->monitorIndex>=0);
138
139 priv=self->priv;
140
141 /* Get number of monitors */
142 #if GTK_CHECK_VERSION(3, 22, 0)
143 display=gdk_screen_get_display(priv->screen);
144 numberMonitors=gdk_display_get_n_monitors(display);
145 #else
146 numberMonitors=gdk_screen_get_n_monitors(priv->screen);
147 #endif
148
149 /* Check if monitor is valid */
150 if(priv->monitorIndex>=numberMonitors) return;
151
152 /* Get monitor geometry */
153 #if GTK_CHECK_VERSION(3, 22, 0)
154 monitor=gdk_display_get_monitor(display, priv->monitorIndex);
155 gdk_monitor_get_geometry(monitor, &geometry);
156 #else
157 gdk_screen_get_monitor_geometry(priv->screen, priv->monitorIndex, &geometry);
158 #endif
159
160 /* Set value if changed */
161 if(geometry.x!=priv->geometry.x ||
162 geometry.y!=priv->geometry.y ||
163 geometry.width!=priv->geometry.width ||
164 geometry.height!=priv->geometry.height)
165 {
166 /* Set value */
167 priv->geometry.x=geometry.x;
168 priv->geometry.y=geometry.y;
169 priv->geometry.width=geometry.width;
170 priv->geometry.height=geometry.height;
171
172 /* Emit signal */
173 g_signal_emit_by_name(self, "geometry-changed");
174 XFDASHBOARD_DEBUG(self, WINDOWS,
175 "Monitor %d moved to %d,%d and resized to %dx%d",
176 priv->monitorIndex,
177 priv->geometry.x, priv->geometry.y,
178 priv->geometry.width, priv->geometry.height);
179 }
180 }
181
182 /* Number of monitors, primary monitor or size of any monitor changed */
_xfdashboard_window_tracker_monitor_x11_on_monitors_changed(XfdashboardWindowTrackerMonitorX11 * self,gpointer inUserData)183 static void _xfdashboard_window_tracker_monitor_x11_on_monitors_changed(XfdashboardWindowTrackerMonitorX11 *self,
184 gpointer inUserData)
185 {
186 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(self));
187 g_return_if_fail(GDK_IS_SCREEN(inUserData));
188
189 /* Update primary monitor flag */
190 _xfdashboard_window_tracker_monitor_x11_update_primary(self);
191
192 /* Update geometry of monitor */
193 _xfdashboard_window_tracker_monitor_x11_update_geometry(self);
194 }
195
196 /* Set monitor index this object belongs to and to monitor */
_xfdashboard_window_tracker_monitor_x11_set_index(XfdashboardWindowTrackerMonitorX11 * self,gint inIndex)197 static void _xfdashboard_window_tracker_monitor_x11_set_index(XfdashboardWindowTrackerMonitorX11 *self,
198 gint inIndex)
199 {
200 XfdashboardWindowTrackerMonitorX11Private *priv;
201 gint numberMonitors;
202
203 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(self));
204 g_return_if_fail(inIndex>=0);
205
206 priv=self->priv;
207
208 /* Get number of monitors */
209 #if GTK_CHECK_VERSION(3, 22, 0)
210 numberMonitors=gdk_display_get_n_monitors(gdk_screen_get_display(priv->screen));
211 #else
212 numberMonitors=gdk_screen_get_n_monitors(priv->screen);
213 #endif
214 g_return_if_fail(inIndex<numberMonitors);
215
216 /* Freeze notification */
217 g_object_freeze_notify(G_OBJECT(self));
218
219 /* Set value if changed */
220 if(priv->monitorIndex!=inIndex)
221 {
222 /* Set value */
223 priv->monitorIndex=inIndex;
224
225 /* Update primary monitor flag */
226 _xfdashboard_window_tracker_monitor_x11_update_primary(self);
227
228 /* Update geometry of monitor */
229 _xfdashboard_window_tracker_monitor_x11_update_geometry(self);
230
231 /* Connect signals now we have a valid monitor index set */
232 g_signal_connect_swapped(priv->screen, "monitors-changed", G_CALLBACK(_xfdashboard_window_tracker_monitor_x11_on_monitors_changed), self);
233
234 /* Notify about property change */
235 g_object_notify_by_pspec(G_OBJECT(self), XfdashboardWindowTrackerMonitorX11Properties[PROP_MONITOR_INDEX]);
236 }
237
238 /* Thaw notification */
239 g_object_thaw_notify(G_OBJECT(self));
240 }
241
242
243 /* IMPLEMENTATION: Interface XfdashboardWindowTrackerMonitor */
244
245 /* Determine if monitor is primary one */
_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_is_primary(XfdashboardWindowTrackerMonitor * inMonitor)246 static gboolean _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_is_primary(XfdashboardWindowTrackerMonitor *inMonitor)
247 {
248 XfdashboardWindowTrackerMonitorX11 *self;
249 XfdashboardWindowTrackerMonitorX11Private *priv;
250
251 g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inMonitor), FALSE);
252
253 self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inMonitor);
254 priv=self->priv;
255
256 return(priv->isPrimary);
257 }
258
259 /* Get monitor index */
_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_number(XfdashboardWindowTrackerMonitor * inMonitor)260 static gint _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_number(XfdashboardWindowTrackerMonitor *inMonitor)
261 {
262 XfdashboardWindowTrackerMonitorX11 *self;
263 XfdashboardWindowTrackerMonitorX11Private *priv;
264
265 g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inMonitor), 0);
266
267 self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inMonitor);
268 priv=self->priv;
269
270 return(priv->monitorIndex);
271 }
272
273 /* Get geometry of monitor */
_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_geometry(XfdashboardWindowTrackerMonitor * inMonitor,gint * outX,gint * outY,gint * outWidth,gint * outHeight)274 static void _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_geometry(XfdashboardWindowTrackerMonitor *inMonitor,
275 gint *outX,
276 gint *outY,
277 gint *outWidth,
278 gint *outHeight)
279 {
280 XfdashboardWindowTrackerMonitorX11 *self;
281 XfdashboardWindowTrackerMonitorX11Private *priv;
282
283 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR_X11(inMonitor));
284
285 self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inMonitor);
286 priv=self->priv;
287
288 /* Set position and size of monitor */
289 if(outX) *outX=priv->geometry.x;
290 if(outY) *outY=priv->geometry.y;
291 if(outWidth) *outWidth=priv->geometry.width;
292 if(outHeight) *outHeight=priv->geometry.height;
293 }
294
295 /* Interface initialization
296 * Set up default functions
297 */
_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_iface_init(XfdashboardWindowTrackerMonitorInterface * iface)298 static void _xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_iface_init(XfdashboardWindowTrackerMonitorInterface *iface)
299 {
300 iface->is_primary=_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_is_primary;
301 iface->get_number=_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_number;
302 iface->get_geometry=_xfdashboard_window_tracker_monitor_x11_x11_window_tracker_monitor_get_geometry;
303 }
304
305
306 /* IMPLEMENTATION: GObject */
307
308 /* Dispose this object */
_xfdashboard_window_tracker_monitor_x11_dispose(GObject * inObject)309 static void _xfdashboard_window_tracker_monitor_x11_dispose(GObject *inObject)
310 {
311 XfdashboardWindowTrackerMonitorX11 *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inObject);
312 XfdashboardWindowTrackerMonitorX11Private *priv=self->priv;
313
314 /* Release allocated resources */
315 if(priv->screen)
316 {
317 g_signal_handlers_disconnect_by_data(priv->screen, self);
318 priv->screen=NULL;
319 }
320
321 /* Call parent's class dispose method */
322 G_OBJECT_CLASS(xfdashboard_window_tracker_monitor_x11_parent_class)->dispose(inObject);
323 }
324
325 /* Set/get properties */
_xfdashboard_window_tracker_monitor_x11_set_property(GObject * inObject,guint inPropID,const GValue * inValue,GParamSpec * inSpec)326 static void _xfdashboard_window_tracker_monitor_x11_set_property(GObject *inObject,
327 guint inPropID,
328 const GValue *inValue,
329 GParamSpec *inSpec)
330 {
331 XfdashboardWindowTrackerMonitorX11 *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inObject);
332
333 switch(inPropID)
334 {
335 case PROP_MONITOR_INDEX:
336 _xfdashboard_window_tracker_monitor_x11_set_index(self, g_value_get_int(inValue));
337 break;
338
339 default:
340 G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
341 break;
342 }
343 }
344
_xfdashboard_window_tracker_monitor_x11_get_property(GObject * inObject,guint inPropID,GValue * outValue,GParamSpec * inSpec)345 static void _xfdashboard_window_tracker_monitor_x11_get_property(GObject *inObject,
346 guint inPropID,
347 GValue *outValue,
348 GParamSpec *inSpec)
349 {
350 XfdashboardWindowTrackerMonitorX11 *self=XFDASHBOARD_WINDOW_TRACKER_MONITOR_X11(inObject);
351 XfdashboardWindowTrackerMonitorX11Private *priv=self->priv;
352
353 switch(inPropID)
354 {
355 case PROP_IS_PRIMARY:
356 g_value_set_boolean(outValue, priv->isPrimary);
357 break;
358
359 case PROP_MONITOR_INDEX:
360 g_value_set_uint(outValue, priv->monitorIndex);
361 break;
362
363 default:
364 G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
365 break;
366 }
367 }
368
369 /* Class initialization
370 * Override functions in parent classes and define properties
371 * and signals
372 */
xfdashboard_window_tracker_monitor_x11_class_init(XfdashboardWindowTrackerMonitorX11Class * klass)373 static void xfdashboard_window_tracker_monitor_x11_class_init(XfdashboardWindowTrackerMonitorX11Class *klass)
374 {
375 GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
376 XfdashboardWindowTrackerMonitor *monitorIface;
377 GParamSpec *paramSpec;
378
379 /* Reference interface type to lookup properties etc. */
380 monitorIface=g_type_default_interface_ref(XFDASHBOARD_TYPE_WINDOW_TRACKER_MONITOR);
381
382 /* Override functions */
383 gobjectClass->dispose=_xfdashboard_window_tracker_monitor_x11_dispose;
384 gobjectClass->set_property=_xfdashboard_window_tracker_monitor_x11_set_property;
385 gobjectClass->get_property=_xfdashboard_window_tracker_monitor_x11_get_property;
386
387 /* Define properties */
388 paramSpec=g_object_interface_find_property(monitorIface, "is-primary");
389 XfdashboardWindowTrackerMonitorX11Properties[PROP_IS_PRIMARY]=
390 g_param_spec_override("is-primary", paramSpec);
391
392 paramSpec=g_object_interface_find_property(monitorIface, "monitor-index");
393 XfdashboardWindowTrackerMonitorX11Properties[PROP_MONITOR_INDEX]=
394 g_param_spec_override("monitor-index", paramSpec);
395
396 g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardWindowTrackerMonitorX11Properties);
397
398 /* Release allocated resources */
399 g_type_default_interface_unref(monitorIface);
400 }
401
402 /* Object initialization
403 * Create private structure and set up default values
404 */
xfdashboard_window_tracker_monitor_x11_init(XfdashboardWindowTrackerMonitorX11 * self)405 static void xfdashboard_window_tracker_monitor_x11_init(XfdashboardWindowTrackerMonitorX11 *self)
406 {
407 XfdashboardWindowTrackerMonitorX11Private *priv;
408
409 priv=self->priv=xfdashboard_window_tracker_monitor_x11_get_instance_private(self);
410
411 /* Set default values */
412 priv->monitorIndex=-1;
413 priv->isPrimary=FALSE;
414 priv->screen=gdk_screen_get_default();
415 priv->geometry.x=0;
416 priv->geometry.y=0;
417 priv->geometry.width=0;
418 priv->geometry.height=0;
419 }
420