1 /*
2 * CsScreen: An introspectable C class that establishes an event
3 * trap for the screensaver. It watches for any X events that could result
4 * in other windows showing up over our Stage, and ensures the Stage stays on
5 * top. This will only ever be other override-redirect (non-managed) X windows,
6 * such as native Firefox or Chrome notification popups.
7 *
8 */
9
10 #include "config.h"
11 #include "cs-screen.h"
12
13 #include <string.h>
14
15 #include <X11/Xlib.h>
16 #include <X11/Xutil.h>
17
18 #ifdef HAVE_SOLARIS_XINERAMA
19 #include <X11/extensions/xinerama.h>
20 #endif
21 #ifdef HAVE_XFREE_XINERAMA
22 #include <X11/extensions/Xinerama.h>
23 #endif
24 #ifdef HAVE_RANDR
25 #include <X11/extensions/Xrandr.h>
26 #endif
27
28 enum {
29 SCREEN_MONITORS_CHANGED,
30 SCREEN_SIZE_CHANGED,
31 COMPOSITED_CHANGED,
32 LAST_SIGNAL
33 };
34
35 static guint signals [LAST_SIGNAL] = { 0, };
36
37 G_DEFINE_TYPE (CsScreen, cs_screen, G_TYPE_OBJECT);
38
39 static gboolean debug_mode = FALSE;
40 #define DEBUG(...) if (debug_mode) g_printerr (__VA_ARGS__)
41
42 #define cs_XFree(p) do { if ((p)) XFree ((p)); } while (0)
43
44 #define PRIMARY_MONITOR 0
45
46 static gboolean
cs_rectangle_equal(const GdkRectangle * src1,const GdkRectangle * src2)47 cs_rectangle_equal (const GdkRectangle *src1,
48 const GdkRectangle *src2)
49 {
50 return ((src1->x == src2->x) &&
51 (src1->y == src2->y) &&
52 (src1->width == src2->width) &&
53 (src1->height == src2->height));
54 }
55
56 /* The list of monitors reported by the windowing system might include
57 * mirrored monitors with identical bounds. Since mirrored monitors
58 * shouldn't be treated as separate monitors for most purposes, we
59 * filter them out here. (We ignore the possibility of partially
60 * overlapping monitors because they are rare and it's hard to come
61 * up with any sensible interpretation.)
62 */
63 static void
filter_mirrored_monitors(CsScreen * screen)64 filter_mirrored_monitors (CsScreen *screen)
65 {
66 int i, j;
67
68 /* Currently always true and simplifies things */
69 g_assert (screen->primary_monitor_index == 0);
70
71 for (i = 1; i < screen->n_monitor_infos; i++)
72 {
73 /* In case we've filtered previous monitors */
74 screen->monitor_infos[i].number = i;
75
76 for (j = 0; j < i; j++)
77 {
78 if (cs_rectangle_equal (&screen->monitor_infos[i].rect,
79 &screen->monitor_infos[j].rect))
80 {
81 memmove (&screen->monitor_infos[i],
82 &screen->monitor_infos[i + 1],
83 (screen->n_monitor_infos - i - 1) * sizeof (CsMonitorInfo));
84 screen->n_monitor_infos--;
85 i--;
86
87 continue;
88 }
89 }
90 }
91 }
92
93 #ifdef HAVE_RANDR
94 static CsMonitorInfo *
find_monitor_with_rect(CsScreen * screen,int x,int y,int w,int h)95 find_monitor_with_rect (CsScreen *screen, int x, int y, int w, int h)
96 {
97 CsMonitorInfo *info;
98 int i;
99
100 for (i = 0; i < screen->n_monitor_infos; i++)
101 {
102 info = &screen->monitor_infos[i];
103 if (x == info->rect.x &&
104 y == info->rect.y &&
105 w == info->rect.width &&
106 h == info->rect.height)
107 {
108 return info;
109 }
110 }
111
112 return NULL;
113 }
114
115 /* In the case of multiple outputs of a single crtc (mirroring), we consider one of the
116 * outputs the "main". This is the one we consider "owning" the windows, so if
117 * the mirroring is changed to a dual monitor setup then the windows are moved to the
118 * crtc that now has that main output. If one of the outputs is the primary that is
119 * always the main, otherwise we just use the first.
120 */
121 static XID
find_main_output_for_crtc(XRRScreenResources * resources,XRRCrtcInfo * crtc,Display * xdisplay,XID xroot)122 find_main_output_for_crtc (XRRScreenResources *resources,
123 XRRCrtcInfo *crtc,
124 Display *xdisplay,
125 XID xroot)
126 {
127 XRROutputInfo *output;
128 RROutput primary_output;
129 int i;
130 XID res;
131
132 primary_output = XRRGetOutputPrimary (xdisplay, xroot);
133
134 res = None;
135 for (i = 0; i < crtc->noutput; i++)
136 {
137 output = XRRGetOutputInfo (xdisplay, resources, crtc->outputs[i]);
138 if (output->connection != RR_Disconnected &&
139 (res == None || crtc->outputs[i] == primary_output))
140 {
141 res = crtc->outputs[i];
142 }
143
144 XRRFreeOutputInfo (output);
145 }
146
147 return res;
148 }
149 #endif
150
151 static void
apply_scale_factor(CsMonitorInfo * infos,gint n_infos,gint factor)152 apply_scale_factor (CsMonitorInfo *infos,
153 gint n_infos,
154 gint factor)
155 {
156 gint i;
157
158 for (i = 0; i < n_infos; i++)
159 {
160 infos[i].rect.x /= factor;
161 infos[i].rect.y /= factor;
162 infos[i].rect.width /= factor;
163 infos[i].rect.height /= factor;
164
165 DEBUG ("Scale factor of %d applied. Monitor %d is %d,%d %d x %d\n",
166 factor,
167 infos[i].number,
168 infos[i].rect.x,
169 infos[i].rect.y,
170 infos[i].rect.width,
171 infos[i].rect.height);
172 }
173 }
174
175 #define MONITOR_WIDTH_THRESHOLD 1200
176 #define MONITOR_HEIGHT_THRESHOLD 1000
177
178 static gboolean
get_low_res_mode(CsScreen * screen,CsMonitorInfo * infos,gint n_infos)179 get_low_res_mode (CsScreen *screen,
180 CsMonitorInfo *infos,
181 gint n_infos)
182 {
183 gint i;
184 gint smallest_width, smallest_height;
185
186 smallest_width = smallest_height = G_MAXINT;
187
188 for (i = 0; i < n_infos; i++)
189 {
190 smallest_width = MIN (infos[i].rect.width, smallest_width);
191 smallest_height = MIN (infos[i].rect.height, smallest_height);
192 }
193
194 screen->smallest_width = smallest_width;
195 screen->smallest_height = smallest_height;
196
197 if (smallest_width < MONITOR_WIDTH_THRESHOLD || smallest_height < MONITOR_HEIGHT_THRESHOLD)
198 {
199 DEBUG ("Narrowest monitor width after scaling (%dx%d) is below threshold of %dx%d, applying low-res mode\n",
200 smallest_width,
201 smallest_height,
202 MONITOR_WIDTH_THRESHOLD,
203 MONITOR_HEIGHT_THRESHOLD);
204
205 return TRUE;
206 }
207
208 return FALSE;
209 }
210
211 static void
reload_monitor_infos(CsScreen * screen)212 reload_monitor_infos (CsScreen *screen)
213 {
214 GdkDisplay *gdk_display;
215 Display *xdisplay;
216 Window xroot;
217
218 gdk_display = gdk_screen_get_display (screen->gdk_screen);
219 xdisplay = gdk_x11_display_get_xdisplay (gdk_display);
220
221 xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen->gdk_screen));
222
223 /* Any previous screen->monitor_infos is freed by the caller */
224
225 screen->monitor_infos = NULL;
226 screen->n_monitor_infos = 0;
227
228 /* Xinerama doesn't have a concept of primary monitor, however XRandR
229 * does. However, the XRandR xinerama compat code always sorts the
230 * primary output first, so we rely on that here. We could use the
231 * native XRandR calls instead of xinerama, but that would be
232 * slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as
233 * that is defined in terms of xinerama monitor indexes.
234 * So, since we don't need anything in xrandr except the primary
235 * we can keep using xinerama and use the first monitor as the
236 * primary.
237 */
238
239 screen->primary_monitor_index = PRIMARY_MONITOR;
240
241
242 #ifdef HAVE_XFREE_XINERAMA
243 if (screen->n_monitor_infos == 0 &&
244 XineramaIsActive (xdisplay))
245 {
246 XineramaScreenInfo *infos;
247 int n_infos;
248 int i;
249
250 n_infos = 0;
251 infos = XineramaQueryScreens (xdisplay, &n_infos);
252
253 DEBUG ("Found %d Xinerama screens on display %s\n",
254 n_infos, gdk_display_get_name (gdk_display));
255
256 if (n_infos > 0)
257 {
258 screen->monitor_infos = g_new0 (CsMonitorInfo, n_infos);
259 screen->n_monitor_infos = n_infos;
260
261 i = 0;
262 while (i < n_infos)
263 {
264 screen->monitor_infos[i].number = infos[i].screen_number;
265 screen->monitor_infos[i].rect.x = infos[i].x_org;
266 screen->monitor_infos[i].rect.y = infos[i].y_org;
267 screen->monitor_infos[i].rect.width = infos[i].width;
268 screen->monitor_infos[i].rect.height = infos[i].height;
269
270 DEBUG ("Monitor %d is %d,%d %d x %d\n",
271 screen->monitor_infos[i].number,
272 screen->monitor_infos[i].rect.x,
273 screen->monitor_infos[i].rect.y,
274 screen->monitor_infos[i].rect.width,
275 screen->monitor_infos[i].rect.height);
276
277 ++i;
278 }
279 }
280
281 cs_XFree (infos);
282
283 #ifdef HAVE_RANDR
284 {
285 XRRScreenResources *resources;
286
287 resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);
288
289 if (resources)
290 {
291 for (i = 0; i < resources->ncrtc; i++)
292 {
293 XRRCrtcInfo *crtc;
294 CsMonitorInfo *info;
295
296 crtc = XRRGetCrtcInfo (xdisplay, resources, resources->crtcs[i]);
297 info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height);
298
299 if (info)
300 {
301 info->output = find_main_output_for_crtc (resources, crtc, xdisplay, xroot);
302 }
303
304 XRRFreeCrtcInfo (crtc);
305 }
306
307 XRRFreeScreenResources (resources);
308 }
309 }
310 #endif
311 }
312 else if (screen->n_monitor_infos > 0)
313 {
314 DEBUG ("No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
315 gdk_display_get_name (gdk_display));
316 }
317 #else
318 DEBUG ("Muffin compiled without XFree86 Xinerama support\n");
319 #endif /* HAVE_XFREE_XINERAMA */
320
321 #ifdef HAVE_SOLARIS_XINERAMA
322 /* This code from GDK, Copyright (C) 2002 Sun Microsystems */
323 if (screen->n_monitor_infos == 0 &&
324 XineramaGetState (xdisplay,
325 gdk_screen_get_number (screen->gdk_screen)))
326 {
327 XRectangle monitors[MAXFRAMEBUFFERS];
328 unsigned char hints[16];
329 int result;
330 int n_monitors;
331 int i;
332
333 n_monitors = 0;
334 result = XineramaGetInfo (xdisplay,
335 gdk_screen_get_number (screen->gdk_screen),
336 monitors, hints,
337 &n_monitors);
338 /* Yes I know it should be Success but the current implementation
339 * returns the num of monitor
340 */
341 if (result > 0)
342 {
343 g_assert (n_monitors > 0);
344
345 screen->monitor_infos = g_new0 (CsMonitorInfo, n_monitors);
346 screen->n_monitor_infos = n_monitors;
347
348 i = 0;
349 while (i < n_monitors)
350 {
351 screen->monitor_infos[i].number = i;
352 screen->monitor_infos[i].rect.x = monitors[i].x;
353 screen->monitor_infos[i].rect.y = monitors[i].y;
354 screen->monitor_infos[i].rect.width = monitors[i].width;
355 screen->monitor_infos[i].rect.height = monitors[i].height;
356
357 DEBUG ("Monitor %d is %d,%d %d x %d\n",
358 screen->monitor_infos[i].number,
359 screen->monitor_infos[i].rect.x,
360 screen->monitor_infos[i].rect.y,
361 screen->monitor_infos[i].rect.width,
362 screen->monitor_infos[i].rect.height);
363 ++i;
364 }
365 }
366 }
367 else if (screen->n_monitor_infos == 0)
368 {
369 DEBUG ("No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
370 gdk_display_get_name (gdk_display));
371 }
372 #else
373 DEBUG ("Cinnamon Screensaver compiled without Solaris Xinerama support\n");
374 #endif /* HAVE_SOLARIS_XINERAMA */
375
376 /* If no Xinerama, fill in the single screen info so
377 * we can use the field unconditionally
378 */
379 if (screen->n_monitor_infos == 0)
380 {
381 DEBUG ("No Xinerama screens, using default screen info\n");
382
383 screen->monitor_infos = g_new0 (CsMonitorInfo, 1);
384 screen->n_monitor_infos = 1;
385
386 screen->monitor_infos[0].number = 0;
387 screen->monitor_infos[0].rect = screen->rect;
388 }
389
390 filter_mirrored_monitors (screen);
391
392 screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE;
393
394 apply_scale_factor (screen->monitor_infos,
395 screen->n_monitor_infos,
396 gdk_screen_get_monitor_scale_factor (screen->gdk_screen, PRIMARY_MONITOR));
397
398 screen->low_res = get_low_res_mode (screen,
399 screen->monitor_infos,
400 screen->n_monitor_infos);
401
402 g_assert (screen->n_monitor_infos > 0);
403 g_assert (screen->monitor_infos != NULL);
404 }
405
406 static void
reload_screen_info(CsScreen * screen)407 reload_screen_info (CsScreen *screen)
408 {
409 screen->rect.x = screen->rect.y = 0;
410 screen->rect.width = gdk_screen_get_width (screen->gdk_screen);
411 screen->rect.height = gdk_screen_get_height (screen->gdk_screen);
412 }
413
414 static void
on_monitors_changed(GdkScreen * gdk_screen,gpointer user_data)415 on_monitors_changed (GdkScreen *gdk_screen, gpointer user_data)
416 {
417 CsMonitorInfo *old_monitor_infos;
418 CsScreen *screen;
419
420 screen = CS_SCREEN (user_data);
421
422 reload_screen_info (screen);
423 g_signal_emit (screen, signals[SCREEN_SIZE_CHANGED], 0);
424
425 gdk_flush ();
426
427 DEBUG ("CsScreen received 'monitors-changed' signal from GdkScreen\n");
428
429 old_monitor_infos = screen->monitor_infos;
430 reload_monitor_infos (screen);
431
432 g_free (old_monitor_infos);
433
434 g_signal_emit (screen, signals[SCREEN_MONITORS_CHANGED], 0);
435 }
436
437 static void
on_screen_changed(GdkScreen * gdk_screen,gpointer user_data)438 on_screen_changed (GdkScreen *gdk_screen, gpointer user_data)
439 {
440 CsScreen *screen;
441
442 screen = CS_SCREEN (user_data);
443
444 DEBUG ("CsScreen received 'size-changed' signal from GdkScreen\n");
445
446 reload_screen_info (screen);
447 g_signal_emit (screen, signals[SCREEN_SIZE_CHANGED], 0);
448 }
449
450 static void
on_composited_changed(GdkScreen * gdk_screen,gpointer user_data)451 on_composited_changed (GdkScreen *gdk_screen, gpointer user_data)
452 {
453 CsScreen *screen;
454
455 screen = CS_SCREEN (user_data);
456
457 DEBUG ("CsScreen received 'composited-changed' signal from GdkScreen\n");
458
459 g_signal_emit (screen, signals[COMPOSITED_CHANGED], 0);
460 }
461
462 static void
cs_screen_init(CsScreen * screen)463 cs_screen_init (CsScreen *screen)
464 {
465 screen->gdk_screen = gdk_screen_get_default ();
466
467 screen->monitors_changed_id = g_signal_connect (screen->gdk_screen,
468 "monitors-changed",
469 G_CALLBACK (on_monitors_changed),
470 screen);
471 screen->screen_size_changed_id = g_signal_connect (screen->gdk_screen,
472 "size-changed",
473 G_CALLBACK (on_screen_changed),
474 screen);
475 screen->composited_changed_id = g_signal_connect (screen->gdk_screen,
476 "composited-changed",
477 G_CALLBACK (on_composited_changed),
478 screen);
479
480 reload_screen_info (screen);
481 reload_monitor_infos (screen);
482 }
483
484 static void
cs_screen_finalize(GObject * object)485 cs_screen_finalize (GObject *object)
486 {
487 CsScreen *screen;
488
489 g_return_if_fail (object != NULL);
490 g_return_if_fail (CS_IS_SCREEN (object));
491
492 screen = CS_SCREEN (object);
493
494 if (screen->monitor_infos)
495 {
496 g_free (screen->monitor_infos);
497 }
498
499 DEBUG ("CsScreen finalize\n");
500
501 G_OBJECT_CLASS (cs_screen_parent_class)->finalize (object);
502 }
503
504 static void
cs_screen_dispose(GObject * object)505 cs_screen_dispose (GObject *object)
506 {
507 CsScreen *screen;
508
509 g_return_if_fail (object != NULL);
510 g_return_if_fail (CS_IS_SCREEN (object));
511
512 screen = CS_SCREEN (object);
513
514 if (screen->monitors_changed_id > 0)
515 {
516 g_signal_handler_disconnect (screen->gdk_screen, screen->monitors_changed_id);
517 screen->monitors_changed_id = 0;
518 }
519
520 if (screen->screen_size_changed_id > 0)
521 {
522 g_signal_handler_disconnect (screen->gdk_screen, screen->screen_size_changed_id);
523 screen->screen_size_changed_id = 0;
524 }
525
526 if (screen->composited_changed_id > 0)
527 {
528 g_signal_handler_disconnect (screen->gdk_screen, screen->composited_changed_id);
529 screen->composited_changed_id = 0;
530 }
531
532 DEBUG ("CsScreen dispose\n");
533
534 G_OBJECT_CLASS (cs_screen_parent_class)->dispose (object);
535 }
536
537 static void
cs_screen_class_init(CsScreenClass * klass)538 cs_screen_class_init (CsScreenClass *klass)
539 {
540 GObjectClass *object_class = G_OBJECT_CLASS (klass);
541
542 object_class->finalize = cs_screen_finalize;
543 object_class->dispose = cs_screen_dispose;
544
545 signals[SCREEN_MONITORS_CHANGED] = g_signal_new ("monitors-changed",
546 G_TYPE_FROM_CLASS (object_class),
547 G_SIGNAL_RUN_LAST,
548 0,
549 NULL, NULL, NULL,
550 G_TYPE_NONE, 0);
551
552 signals[SCREEN_SIZE_CHANGED] = g_signal_new ("size-changed",
553 G_TYPE_FROM_CLASS (object_class),
554 G_SIGNAL_RUN_LAST,
555 0,
556 NULL, NULL, NULL,
557 G_TYPE_NONE, 0);
558
559 signals[COMPOSITED_CHANGED] = g_signal_new ("composited-changed",
560 G_TYPE_FROM_CLASS (object_class),
561 G_SIGNAL_RUN_LAST,
562 0,
563 NULL, NULL, NULL,
564 G_TYPE_NONE, 0);
565 }
566
567 CsScreen *
cs_screen_new(gboolean debug)568 cs_screen_new (gboolean debug)
569 {
570 GObject *result;
571
572 debug_mode = debug;
573
574 result = g_object_new (CS_TYPE_SCREEN, NULL);
575
576 return CS_SCREEN (result);
577 }
578
579 /**
580 * cs_screen_get_monitor_geometry:
581 * @screen: a #CsScreen
582 * @monitor: the monitor number
583 * @geometry: (out): location to store the monitor geometry
584 *
585 * Stores the location and size of the indicated monitor in @geometry.
586 */
587 void
cs_screen_get_monitor_geometry(CsScreen * screen,gint monitor,GdkRectangle * geometry)588 cs_screen_get_monitor_geometry (CsScreen *screen,
589 gint monitor,
590 GdkRectangle *geometry)
591 {
592 g_return_if_fail (CS_IS_SCREEN (screen));
593 g_return_if_fail (monitor >= 0 && monitor < screen->n_monitor_infos);
594 g_return_if_fail (geometry != NULL);
595
596 geometry->x = screen->monitor_infos[monitor].rect.x;
597 geometry->y = screen->monitor_infos[monitor].rect.y;
598 geometry->width = screen->monitor_infos[monitor].rect.width;
599 geometry->height = screen->monitor_infos[monitor].rect.height;
600 }
601
602 /**
603 * cs_screen_get_screen_geometry:
604 * @screen: a #CsScreen
605 * @geometry: (out): location to store the screen geometry
606 *
607 * Stores the location and size of the screen in @geometry.
608 */
609 void
cs_screen_get_screen_geometry(CsScreen * screen,GdkRectangle * geometry)610 cs_screen_get_screen_geometry (CsScreen *screen,
611 GdkRectangle *geometry)
612 {
613 g_return_if_fail (CS_IS_SCREEN (screen));
614 g_return_if_fail (geometry != NULL);
615
616 geometry->x = screen->rect.x;
617 geometry->y = screen->rect.y;
618 geometry->width = screen->rect.width;
619 geometry->height = screen->rect.height;
620 }
621
622 /**
623 * cs_screen_get_primary_monitor:
624 * @screen: a #CsScreen
625 *
626 * Gets the index of the primary monitor on this @screen.
627 *
628 * Return value: a monitor index
629 */
630 gint
cs_screen_get_primary_monitor(CsScreen * screen)631 cs_screen_get_primary_monitor (CsScreen *screen)
632 {
633 g_return_val_if_fail (CS_IS_SCREEN (screen), 0);
634
635 return screen->primary_monitor_index;
636 }
637
638 /**
639 * cs_screen_get_n_monitors:
640 * @screen: a #CsScreen
641 *
642 * Gets the number of monitors that are joined together to form @screen.
643 *
644 * Return value: the number of monitors
645 */
646 gint
cs_screen_get_n_monitors(CsScreen * screen)647 cs_screen_get_n_monitors (CsScreen *screen)
648 {
649 g_return_val_if_fail (CS_IS_SCREEN (screen), 0);
650
651 return screen->n_monitor_infos;
652 }
653
654 /**
655 * cs_screen_get_mouse_monitor:
656 * @screen: a #CsScreen
657 *
658 * Gets the index of the monitor that the mouse pointer currently
659 * occupies.
660 *
661 * Return value: the monitor index for the pointer
662 */
663 gint
cs_screen_get_mouse_monitor(CsScreen * screen)664 cs_screen_get_mouse_monitor (CsScreen *screen)
665 {
666 GdkDisplay *gdk_display;
667
668 Window xroot, root_return, child_return;
669 int root_x_return, root_y_return;
670 int win_x_return, win_y_return;
671 unsigned int mask_return;
672 gint scale_factor;
673
674 gint i;
675 gint ret = 0;
676
677 g_return_val_if_fail (CS_IS_SCREEN (screen), 0);
678
679 gdk_display = gdk_screen_get_display (screen->gdk_screen);
680 xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen->gdk_screen));
681
682 gdk_error_trap_push ();
683 XQueryPointer (gdk_x11_display_get_xdisplay (gdk_display),
684 xroot,
685 &root_return,
686 &child_return,
687 &root_x_return,
688 &root_y_return,
689 &win_x_return,
690 &win_y_return,
691 &mask_return);
692 gdk_error_trap_pop_ignored ();
693
694 scale_factor = gdk_screen_get_monitor_scale_factor (screen->gdk_screen, 0);
695 root_x_return /= scale_factor;
696 root_y_return /= scale_factor;
697
698 for (i = 0; i < screen->n_monitor_infos; i++)
699 {
700 GdkRectangle iter = screen->monitor_infos[i].rect;
701
702 if (root_x_return >= iter.x && root_x_return <= iter.x + iter.width &&
703 root_y_return >= iter.y && root_y_return <= iter.y + iter.height)
704 {
705 ret = i;
706 break;
707 }
708 }
709
710 return ret;
711 }
712
713 /**
714 * cs_screen_get_low_res_mode:
715 * @screen: a #CsScreen
716 *
717 * Gets whether or not one of our monitors falls below the low res threshold (1200 wide).
718 * This lets us display certain things at smaller sizes to prevent truncating of images, etc.
719 *
720 * Returns: Whether or not to use low res mode.
721 */
722 gboolean
cs_screen_get_low_res_mode(CsScreen * screen)723 cs_screen_get_low_res_mode (CsScreen *screen)
724 {
725 g_return_val_if_fail (CS_IS_SCREEN (screen), FALSE);
726
727 return screen->low_res;
728 }
729
730 /**
731 * cs_screen_get_smallest_monitor_sizes:
732 * @screen: a #CsScreen
733 * @width: (out): width of the smallest monitor
734 * @height: (out): height of the smallest monitor
735 *
736 * Gets whether or not one of our monitors falls below the low res threshold (1200 wide).
737 * This lets us display certain things at smaller sizes to prevent truncating of images, etc.
738 *
739 * Returns: Whether or not to use low res mode.
740 */
741 void
cs_screen_get_smallest_monitor_sizes(CsScreen * screen,gint * width,gint * height)742 cs_screen_get_smallest_monitor_sizes (CsScreen *screen,
743 gint *width,
744 gint *height)
745 {
746 g_return_if_fail (CS_IS_SCREEN (screen));
747
748 if (width != NULL)
749 {
750 *width = screen->smallest_width;
751 }
752
753 if (height != NULL)
754 {
755 *height = screen->smallest_height;
756 }
757 }
758
759 /**
760 * cs_screen_center_pointer_in_primary_monitor:
761 * @screen: The #CsScreen
762 *
763 * Warps the mouse pointer to the center in x, and half again below center
764 * in y, of the primary monitor. This is used during waking to have the
765 * unlock dialog appear on the primary monitor (at least, initially).
766 */
767 void
cs_screen_place_pointer_in_primary_monitor(CsScreen * screen)768 cs_screen_place_pointer_in_primary_monitor (CsScreen *screen)
769 {
770 GdkDisplay *display;
771 GdkRectangle rect;
772 GdkSeat *seat;
773 GdkDevice *pointer;
774
775 g_return_if_fail (CS_IS_SCREEN (screen));
776
777 cs_screen_get_monitor_geometry (screen,
778 screen->primary_monitor_index,
779 &rect);
780
781 display = gdk_screen_get_display (screen->gdk_screen);
782 seat = gdk_display_get_default_seat (display);
783
784 pointer = gdk_seat_get_pointer (seat);
785
786 gdk_device_warp (pointer,
787 screen->gdk_screen,
788 rect.x + (rect.width * .5),
789 rect.y + (rect.height * .75));
790 }
791
792 /**
793 * cs_screen_reset_screensaver:
794 *
795 * Resets the screensaver idle timer. If called when the screensaver is active
796 * it will stop it.
797 *
798 */
799 void
cs_screen_reset_screensaver(void)800 cs_screen_reset_screensaver (void)
801 {
802 XResetScreenSaver (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
803 }
804
805 void
cs_screen_nuke_focus(void)806 cs_screen_nuke_focus (void)
807 {
808 Window focus = 0;
809 int rev = 0;
810
811 DEBUG ("Nuking focus\n");
812
813 gdk_error_trap_push ();
814
815 XGetInputFocus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &focus, &rev);
816 XSetInputFocus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), PointerRoot, RevertToNone, CurrentTime);
817
818 gdk_error_trap_pop_ignored ();
819 }
820