Merge lp:~larsu/notify-osd/always-use-workarea into lp:notify-osd

Proposed by Lars Karlitski
Status: Merged
Approved by: Sebastien Bacher
Approved revision: 486
Merged at revision: 482
Proposed branch: lp:~larsu/notify-osd/always-use-workarea
Merge into: lp:notify-osd
Diff against target: 681 lines (+45/-493)
3 files modified
src/defaults.c (+45/-437)
src/defaults.h (+0/-4)
tests/test-defaults.c (+0/-52)
To merge this branch: bzr merge lp:~larsu/notify-osd/always-use-workarea
Reviewer Review Type Date Requested Status
Mirco Müller (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Sebastien Bacher Approve
Review via email: mp+206145@code.launchpad.net

Commit message

Don't place bubbles over panels on secondary monitors

Using heuristics to find panels didn't prove to be very stable. Instead, use _NET_WORKAREA to find out about the panel size on the primary monitor and assume it's the same on every other monitor as well.

Description of the change

Don't place bubbles over panels on secondary monitors

Using heuristics to find panels didn't prove to be very stable. Instead, use _NET_WORKAREA to find out about the panel size on the primary monitor and assume it's the same on every other monitor as well.

To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote :

Nice work, works great under unity!

I've tested:
- dual monitor
- focus follow on and off
- different monitor geometries
- different configuration (left-right, top-bottom, aligned on left/right/bottom top borders)

Things worked as they should in all those scenarios, less code is good as well!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Mirco Müller (macslow) wrote :

The unit-test for the defaults class needs to be fixed/updated (run "make check").

review: Needs Fixing
Revision history for this message
Lars Karlitski (larsu) wrote :

Ah true. Thanks. I wonder why Jenkins didn't catch that.

486. By Lars Karlitski

defaults: call get_top_corner() once to initialize screen size

Revision history for this message
Sebastien Bacher (seb128) wrote :

> I wonder why Jenkins didn't catch that.

We don't run make check as part of the package build and jenkins has no knowledge of extra tests to run

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Mirco Müller (macslow) wrote :

Good to go!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/defaults.c'
2--- src/defaults.c 2012-08-29 22:05:41 +0000
3+++ src/defaults.c 2014-02-13 12:46:35 +0000
4@@ -44,12 +44,6 @@
5 enum
6 {
7 PROP_DUMMY = 0,
8- PROP_DESKTOP_WIDTH,
9- PROP_DESKTOP_HEIGHT,
10- PROP_DESKTOP_TOP,
11- PROP_DESKTOP_BOTTOM,
12- PROP_DESKTOP_LEFT,
13- PROP_DESKTOP_RIGHT,
14 PROP_DESKTOP_BOTTOM_GAP,
15 PROP_STACK_HEIGHT,
16 PROP_BUBBLE_VERT_GAP,
17@@ -335,75 +329,6 @@
18 }
19 }
20
21-void
22-defaults_refresh_screen_dimension_properties (Defaults *self)
23-{
24- Atom real_type;
25- gint result;
26- gint real_format;
27- gulong items_read;
28- gulong items_left;
29- glong* coords;
30- Atom workarea_atom;
31- Display* display;
32-
33- g_return_if_fail ((self != NULL) && IS_DEFAULTS (self));
34-
35- /* get real desktop-area without the panels */
36- workarea_atom = gdk_x11_get_xatom_by_name ("_NET_WORKAREA");
37- display = gdk_x11_display_get_xdisplay (gdk_display_get_default ());
38-
39- gdk_error_trap_push ();
40- result = XGetWindowProperty (display,
41- GDK_ROOT_WINDOW (),
42- workarea_atom,
43- 0L,
44- 4L,
45- False,
46- XA_CARDINAL,
47- &real_type,
48- &real_format,
49- &items_read,
50- &items_left,
51- (guchar **) (void*) &coords);
52- gdk_flush ();
53- gdk_error_trap_pop_ignored ();
54-
55- if (result == Success && items_read)
56- {
57- g_object_set (self,
58- "desktop-width",
59- (gint) coords[2],
60- NULL);
61- g_object_set (self,
62- "desktop-height",
63- (gint) coords[3],
64- NULL);
65- g_object_set (self,
66- "desktop-top",
67- (gint) coords[1],
68- NULL);
69- g_object_set (self,
70- "desktop-bottom",
71- (gint) coords[3],
72- NULL);
73- g_object_set (self,
74- "desktop-left",
75- (gint) coords[0],
76- NULL);
77- g_object_set (self,
78- "desktop-right",
79- (gint) coords[2],
80- NULL);
81- /* FIXME: use new upper and lower threshold/limits for stack */
82- /*g_object_set (self,
83- "stack-height",
84- (gint) coords[3] / 2,
85- NULL);*/
86- XFree (coords);
87- }
88-}
89-
90 static void
91 defaults_constructed (GObject* gobject)
92 {
93@@ -412,10 +337,13 @@
94 gdouble icon_size;
95 gdouble bubble_height;
96 gdouble new_bubble_height;
97+ GdkScreen* screen;
98+ gint x;
99+ gint y;
100
101 self = DEFAULTS (gobject);
102
103- defaults_refresh_screen_dimension_properties (self);
104+ defaults_get_top_corner (self, &screen, &x, &y);
105 defaults_refresh_bg_color_property (self);
106
107 /* grab system-wide font-face/size and DPI */
108@@ -561,30 +489,6 @@
109
110 switch (prop)
111 {
112- case PROP_DESKTOP_WIDTH:
113- g_value_set_int (value, defaults->desktop_width);
114- break;
115-
116- case PROP_DESKTOP_HEIGHT:
117- g_value_set_int (value, defaults->desktop_height);
118- break;
119-
120- case PROP_DESKTOP_TOP:
121- g_value_set_int (value, defaults->desktop_top);
122- break;
123-
124- case PROP_DESKTOP_BOTTOM:
125- g_value_set_int (value, defaults->desktop_bottom);
126- break;
127-
128- case PROP_DESKTOP_LEFT:
129- g_value_set_int (value, defaults->desktop_left);
130- break;
131-
132- case PROP_DESKTOP_RIGHT:
133- g_value_set_int (value, defaults->desktop_right);
134- break;
135-
136 case PROP_DESKTOP_BOTTOM_GAP:
137 g_value_set_double (value, defaults->desktop_bottom_gap);
138 break;
139@@ -743,30 +647,6 @@
140
141 switch (prop)
142 {
143- case PROP_DESKTOP_WIDTH:
144- defaults->desktop_width = g_value_get_int (value);
145- break;
146-
147- case PROP_DESKTOP_HEIGHT:
148- defaults->desktop_height = g_value_get_int (value);
149- break;
150-
151- case PROP_DESKTOP_TOP:
152- defaults->desktop_top = g_value_get_int (value);
153- break;
154-
155- case PROP_DESKTOP_BOTTOM:
156- defaults->desktop_bottom = g_value_get_int (value);
157- break;
158-
159- case PROP_DESKTOP_LEFT:
160- defaults->desktop_left = g_value_get_int (value);
161- break;
162-
163- case PROP_DESKTOP_RIGHT:
164- defaults->desktop_right = g_value_get_int (value);
165- break;
166-
167 case PROP_DESKTOP_BOTTOM_GAP:
168 defaults->desktop_bottom_gap = g_value_get_double (value);
169 break;
170@@ -956,13 +836,6 @@
171 {
172 GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
173
174- GdkScreen* screen = gdk_screen_get_default ();
175- GParamSpec* property_desktop_width;
176- GParamSpec* property_desktop_height;
177- GParamSpec* property_desktop_top;
178- GParamSpec* property_desktop_bottom;
179- GParamSpec* property_desktop_left;
180- GParamSpec* property_desktop_right;
181 GParamSpec* property_desktop_bottom_gap;
182 GParamSpec* property_stack_height;
183 GParamSpec* property_bubble_vert_gap;
184@@ -1025,90 +898,6 @@
185 G_TYPE_NONE,
186 0);
187
188- property_desktop_width = g_param_spec_int (
189- "desktop-width",
190- "desktop-width",
191- "Width of desktop in pixels",
192- 0,
193- G_MAXINT,
194- gdk_screen_get_width (screen),
195- G_PARAM_CONSTRUCT |
196- G_PARAM_READWRITE |
197- G_PARAM_STATIC_STRINGS);
198- g_object_class_install_property (gobject_class,
199- PROP_DESKTOP_WIDTH,
200- property_desktop_width);
201-
202- property_desktop_height = g_param_spec_int (
203- "desktop-height",
204- "desktop-height",
205- "Height of desktop in pixels",
206- 0,
207- G_MAXINT,
208- gdk_screen_get_height (screen),
209- G_PARAM_CONSTRUCT |
210- G_PARAM_READWRITE |
211- G_PARAM_STATIC_STRINGS);
212- g_object_class_install_property (gobject_class,
213- PROP_DESKTOP_HEIGHT,
214- property_desktop_height);
215-
216- property_desktop_top = g_param_spec_int (
217- "desktop-top",
218- "desktop-top",
219- "Top of desktop in pixels",
220- 0,
221- G_MAXINT,
222- 0,
223- G_PARAM_CONSTRUCT |
224- G_PARAM_READWRITE |
225- G_PARAM_STATIC_STRINGS);
226- g_object_class_install_property (gobject_class,
227- PROP_DESKTOP_TOP,
228- property_desktop_top);
229-
230- property_desktop_bottom = g_param_spec_int (
231- "desktop-bottom",
232- "desktop-bottom",
233- "Bottom of desktop in pixels",
234- 0,
235- G_MAXINT,
236- G_MAXINT,
237- G_PARAM_CONSTRUCT |
238- G_PARAM_READWRITE |
239- G_PARAM_STATIC_STRINGS);
240- g_object_class_install_property (gobject_class,
241- PROP_DESKTOP_BOTTOM,
242- property_desktop_bottom);
243-
244- property_desktop_left = g_param_spec_int (
245- "desktop-left",
246- "desktop-left",
247- "Left of desktop in pixels",
248- 0,
249- G_MAXINT,
250- 0,
251- G_PARAM_CONSTRUCT |
252- G_PARAM_READWRITE |
253- G_PARAM_STATIC_STRINGS);
254- g_object_class_install_property (gobject_class,
255- PROP_DESKTOP_LEFT,
256- property_desktop_left);
257-
258- property_desktop_right = g_param_spec_int (
259- "desktop-right",
260- "desktop-right",
261- "Right of desktop in pixels",
262- 0,
263- G_MAXINT,
264- G_MAXINT,
265- G_PARAM_CONSTRUCT |
266- G_PARAM_READWRITE |
267- G_PARAM_STATIC_STRINGS);
268- g_object_class_install_property (gobject_class,
269- PROP_DESKTOP_RIGHT,
270- property_desktop_right);
271-
272 property_desktop_bottom_gap = g_param_spec_double (
273 "desktop-bottom-gap",
274 "desktop-bottom-gap",
275@@ -1569,79 +1358,19 @@
276 gint
277 defaults_get_desktop_width (Defaults* self)
278 {
279- gint width;
280-
281 if (!self || !IS_DEFAULTS (self))
282 return 0;
283
284- g_object_get (self, "desktop-width", &width, NULL);
285-
286- return width;
287+ return self->desktop_width;
288 }
289
290 gint
291 defaults_get_desktop_height (Defaults* self)
292 {
293- gint height;
294-
295- if (!self || !IS_DEFAULTS (self))
296- return 0;
297-
298- g_object_get (self, "desktop-height", &height, NULL);
299-
300- return height;
301-}
302-
303-gint
304-defaults_get_desktop_top (Defaults* self)
305-{
306- gint top_edge;
307-
308- if (!self || !IS_DEFAULTS (self))
309- return 0;
310-
311- g_object_get (self, "desktop-top", &top_edge, NULL);
312-
313- return top_edge;
314-}
315-
316-gint
317-defaults_get_desktop_bottom (Defaults* self)
318-{
319- gint bottom_edge;
320-
321- if (!self || !IS_DEFAULTS (self))
322- return 0;
323-
324- g_object_get (self, "desktop-bottom", &bottom_edge, NULL);
325-
326- return bottom_edge;
327-}
328-
329-gint
330-defaults_get_desktop_left (Defaults* self)
331-{
332- gint left_edge;
333-
334- if (!self || !IS_DEFAULTS (self))
335- return 0;
336-
337- g_object_get (self, "desktop-left", &left_edge, NULL);
338-
339- return left_edge;
340-}
341-
342-gint
343-defaults_get_desktop_right (Defaults* self)
344-{
345- gint right_edge;
346-
347- if (!self || !IS_DEFAULTS (self))
348- return 0;
349-
350- g_object_get (self, "desktop-right", &right_edge, NULL);
351-
352- return right_edge;
353+ if (!self || !IS_DEFAULTS (self))
354+ return 0;
355+
356+ return self->desktop_height;
357 }
358
359 gdouble
360@@ -2131,94 +1860,18 @@
361 return mode;
362 }
363
364-static gboolean
365-_window_look_for_top_panel_attributes (GdkWindow *win)
366-{
367- XClassHint class_hints = {0, 0};
368- gboolean is_panel = FALSE;
369- GdkRectangle frame;
370- int result;
371-
372- if (win == NULL) return FALSE;
373-
374- gdk_error_trap_push ();
375-
376- result = XGetClassHint (gdk_x11_display_get_xdisplay (gdk_display_get_default ()),
377- GDK_WINDOW_XID (win),
378- &class_hints);
379-
380- if (! result || class_hints.res_class == NULL)
381- goto failed;
382-
383- if (g_strcmp0 (class_hints.res_name, "gnome-panel"))
384- goto failed;
385-
386- /* discard dialog windows like panel properties or the applet directory... */
387- if (wnck_window_get_window_type (wnck_window_get (GDK_WINDOW_XID (win)))
388- != WNCK_WINDOW_DOCK)
389- goto failed;
390-
391- /* select only the top panel */
392- gdk_window_get_frame_extents (win, &frame);
393- if (frame.x != 0 || frame.y != 0)
394- goto failed;
395-
396- if (frame.width < frame.height)
397- goto failed;
398-
399- is_panel = TRUE;
400-
401-failed:
402- if (class_hints.res_class)
403- XFree (class_hints.res_class);
404- if (class_hints.res_name)
405- XFree (class_hints.res_name);
406-
407- gdk_error_trap_pop_ignored ();
408-
409- return is_panel;
410-}
411-
412-static GdkWindow*
413-get_panel_window (void)
414-{
415- GdkWindow *panel_window = NULL;
416- GList *window;
417- GList *iter;
418-
419- window = gdk_screen_get_window_stack (gdk_screen_get_default ());
420-
421- for (iter = g_list_first (window);
422- iter != NULL;
423- iter = g_list_next (iter))
424- {
425- if (_window_look_for_top_panel_attributes (iter->data))
426- {
427- panel_window = iter->data;
428- break;
429- }
430- }
431-
432- g_list_free (window);
433-
434- return panel_window;
435-}
436-
437 void
438 defaults_get_top_corner (Defaults *self, GdkScreen **screen, gint *x, gint *y)
439 {
440 GdkRectangle rect;
441- GdkRectangle panel_rect = {0, 0, 0, 0};
442 GdkWindow* active_window = NULL;
443- GdkWindow* panel_window = NULL;
444 gint mx;
445 gint my;
446 gint monitor = 0;
447- gint panel_monitor = 0;
448 gint aw_monitor;
449- gboolean has_panel_window = FALSE;
450 gboolean follow_focus = defaults_multihead_does_focus_follow (self);
451 gboolean is_composited = FALSE;
452+ gint primary_monitor;
453
454 g_return_if_fail (self != NULL && IS_DEFAULTS (self));
455
456@@ -2229,23 +1882,6 @@
457 NULL);
458
459 is_composited = gdk_screen_is_composited (*screen);
460- panel_window = get_panel_window ();
461-
462- if (panel_window != NULL)
463- {
464- gdk_window_get_frame_extents (panel_window, &panel_rect);
465- panel_monitor = gdk_screen_get_monitor_at_window (*screen,
466- panel_window);
467- monitor = panel_monitor;
468- g_debug ("found panel (%d,%d) - %dx%d on monitor %d",
469- panel_rect.x,
470- panel_rect.y,
471- panel_rect.width,
472- panel_rect.height,
473- monitor);
474-
475- has_panel_window = TRUE;
476- }
477
478 if (follow_focus)
479 {
480@@ -2271,7 +1907,39 @@
481 }
482 }
483
484- gdk_screen_get_monitor_geometry (*screen, monitor, &rect);
485+ /* _NET_WORKAREA is always a rectangle spanning all monitors of
486+ * a screen. As such, it can't properly deal with monitor setups
487+ * that aren't aligned or have different resolutions.
488+ * gdk_screen_get_monitor_workarea() works around this by only
489+ * returning the workarea for the primary screen and the full
490+ * geometry for all other monitors.
491+ *
492+ * This leads to the sync bubbles sometimes overlapping the
493+ * panel on secondary monitors. To work around this, we get the
494+ * panel's height on the primary monitor and use that for all
495+ * other monitors as well.
496+ */
497+
498+ primary_monitor = gdk_screen_get_primary_monitor (*screen);
499+ if (monitor == primary_monitor)
500+ {
501+ gdk_screen_get_monitor_workarea (*screen, primary_monitor, &rect);
502+ }
503+ else
504+ {
505+ GdkRectangle workarea;
506+ GdkRectangle primary_geom;
507+ gint panel_height;
508+
509+ gdk_screen_get_monitor_workarea (*screen, primary_monitor, &workarea);
510+ gdk_screen_get_monitor_geometry (*screen, primary_monitor, &primary_geom);
511+ panel_height = workarea.y - primary_geom.y;
512+
513+ gdk_screen_get_monitor_geometry (*screen, monitor, &rect);
514+ rect.y += panel_height;
515+ rect.height -= panel_height;
516+ }
517+
518 g_debug ("selecting monitor %d at (%d,%d) - %dx%d",
519 monitor,
520 rect.x,
521@@ -2279,73 +1947,13 @@
522 rect.width,
523 rect.height);
524
525- /* Position the top left corner of the stack. */
526- if (has_panel_window &&
527- panel_monitor == monitor)
528- {
529- /* position the corner on the selected monitor */
530- rect.y += panel_rect.y + panel_rect.height;
531- } else if (! (has_panel_window || follow_focus))
532- {
533- g_debug ("no panel detetected; using workarea fallback");
534-
535- defaults_refresh_screen_dimension_properties (self);
536-
537- /* workarea rectangle */
538- g_object_get (self, "desktop-left", &rect.x, NULL);
539- g_object_get (self, "desktop-top", &rect.y, NULL);
540- g_object_get (self, "desktop-width", &rect.width, NULL);
541- g_object_get (self, "desktop-height", &rect.height, NULL);
542- }
543+ self->desktop_width = rect.width;
544+ self->desktop_height = rect.height;
545
546 *y = rect.y;
547 *y += EM2PIXELS (defaults_get_bubble_vert_gap (self), self)
548 - EM2PIXELS (defaults_get_bubble_shadow_size (self, is_composited), self);
549
550- /* correct potential offset in multi-monitor setups with two (or more)
551- * monitors side by side, all having different vertical resolutions and
552- * being aligned at the bottom edge, thus creating an "invisible" area at
553- * the top edge of the monitor with the lowest vertical resolution,
554- * LP: #716458 */
555- GdkRectangle cur_geo = {0, 0, 0, 0};
556- int num_monitors = gdk_screen_get_n_monitors (*screen);
557- int screen_width = gdk_screen_get_width (*screen);
558- int screen_height = gdk_screen_get_height (*screen);
559-
560- if (!follow_focus && num_monitors > 1)
561- {
562- int vert_offset = 0;
563-
564- if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR)
565- {
566- int right_most_monitor = 0;
567-
568- right_most_monitor = gdk_screen_get_monitor_at_point (*screen,
569- screen_width,
570- screen_height / 2);
571- gdk_screen_get_monitor_geometry (*screen,
572- right_most_monitor,
573- &cur_geo);
574- if (cur_geo.y != 0)
575- vert_offset = cur_geo.y;
576- }
577- else
578- {
579- int left_most_monitor = 0;
580-
581- left_most_monitor = gdk_screen_get_monitor_at_point (*screen,
582- 0,
583- screen_height / 2);
584- gdk_screen_get_monitor_geometry (*screen,
585- left_most_monitor,
586- &cur_geo);
587- if (cur_geo.y != 0)
588- vert_offset = cur_geo.y;
589- }
590-
591- *y += vert_offset;
592- }
593-
594 if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR)
595 {
596 *x = rect.x + rect.width;
597
598=== modified file 'src/defaults.h'
599--- src/defaults.h 2012-08-29 22:05:41 +0000
600+++ src/defaults.h 2014-02-13 12:46:35 +0000
601@@ -79,10 +79,6 @@
602 GSettings* gnome_settings;
603 gint desktop_width;
604 gint desktop_height;
605- gint desktop_top;
606- gint desktop_bottom;
607- gint desktop_left;
608- gint desktop_right;
609 gdouble desktop_bottom_gap;
610 gdouble stack_height;
611 gdouble bubble_vert_gap;
612
613=== modified file 'tests/test-defaults.c'
614--- tests/test-defaults.c 2009-09-15 12:38:22 +0000
615+++ tests/test-defaults.c 2014-02-13 12:46:35 +0000
616@@ -77,54 +77,6 @@
617
618 static
619 void
620-test_defaults_get_desktop_top ()
621-{
622- Defaults* defaults = NULL;
623-
624- defaults = defaults_new ();
625- g_assert_cmpint (defaults_get_desktop_top (defaults), <=, G_MAXINT);
626- g_assert_cmpint (defaults_get_desktop_top (defaults), >=, 0);
627- g_object_unref (defaults);
628-}
629-
630-static
631-void
632-test_defaults_get_desktop_bottom ()
633-{
634- Defaults* defaults = NULL;
635-
636- defaults = defaults_new ();
637- g_assert_cmpint (defaults_get_desktop_bottom (defaults), <=, G_MAXINT);
638- g_assert_cmpint (defaults_get_desktop_bottom (defaults), >=, 0);
639- g_object_unref (defaults);
640-}
641-
642-static
643-void
644-test_defaults_get_desktop_left ()
645-{
646- Defaults* defaults = NULL;
647-
648- defaults = defaults_new ();
649- g_assert_cmpint (defaults_get_desktop_left (defaults), <=, G_MAXINT);
650- g_assert_cmpint (defaults_get_desktop_left (defaults), >=, 0);
651- g_object_unref (defaults);
652-}
653-
654-static
655-void
656-test_defaults_get_desktop_right ()
657-{
658- Defaults* defaults = NULL;
659-
660- defaults = defaults_new ();
661- g_assert_cmpint (defaults_get_desktop_right (defaults), <=, G_MAXINT);
662- g_assert_cmpint (defaults_get_desktop_right (defaults), >=, 0);
663- g_object_unref (defaults);
664-}
665-
666-static
667-void
668 test_defaults_get_stack_height ()
669 {
670 Defaults* defaults = NULL;
671@@ -200,10 +152,6 @@
672 g_test_suite_add(ts, TC(test_defaults_del));
673 g_test_suite_add(ts, TC(test_defaults_get_desktop_width));
674 g_test_suite_add(ts, TC(test_defaults_get_desktop_height));
675- g_test_suite_add(ts, TC(test_defaults_get_desktop_top));
676- g_test_suite_add(ts, TC(test_defaults_get_desktop_bottom));
677- g_test_suite_add(ts, TC(test_defaults_get_desktop_left));
678- g_test_suite_add(ts, TC(test_defaults_get_desktop_right));
679 g_test_suite_add(ts, TC(test_defaults_get_stack_height));
680 g_test_suite_add(ts, TC(test_defaults_get_bubble_width));
681 g_test_suite_add(ts, TC(test_defaults_get_gravity));

Subscribers

People subscribed via source and target branches