Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:11.1
gnome-panel
gnome-panel-bnc477845-sanitize-overlapping-moni...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File gnome-panel-bnc477845-sanitize-overlapping-monitors.diff of Package gnome-panel
bnc477845 - Panel appears in the middle of the screen when there are overlapping monitors This is also bgo530969. diff --git a/gnome-panel/panel-multiscreen.c b/gnome-panel/panel-multiscreen.c index c71eb0f..06df009 100644 --- a/gnome-panel/panel-multiscreen.c +++ b/gnome-panel/panel-multiscreen.c @@ -41,6 +41,111 @@ static int *monitors = NULL; static GdkRectangle **geometries = NULL; static gboolean initialized = FALSE; +static gboolean +overlaps (GdkRectangle *a, GdkRectangle *b) +{ + return gdk_rectangle_intersect (a, b, NULL); +} + +static long +pixels_in_rectangle (GdkRectangle *r) +{ + return (long) r->width * r->height; +} + +static void +get_monitors_for_screen (GdkScreen *screen, int *monitors_ret, GdkRectangle **geometries_ret) +{ + int num_monitors; + GdkRectangle *geometries; + int i; + + num_monitors = gdk_screen_get_n_monitors (screen); + geometries = g_new (GdkRectangle, num_monitors); + + for (i = 0; i < num_monitors; i++) + gdk_screen_get_monitor_geometry (screen, i, &(geometries[i])); + + /* http://bugzilla.gnome.org/show_bug.cgi?id=530969 + * https://bugzilla.novell.com/show_bug.cgi?id=310208 + * and many other such bugs... + * + * RANDR sometimes gives us monitors that overlap (i.e. outputs whose + * bounding rectangles overlap). This is sometimes right and sometimes + * wrong: + * + * * Right - two 1024x768 outputs at the same offset (0, 0) that show + * the same thing. Think "laptop plus projector with the same + * resolution". + * + * * Wrong - one 1280x1024 output ("laptop internal LCD") and another + * 1024x768 output ("external monitor"), both at offset (0, 0). + * There is no way for the monitor with the small resolution to show + * the complete image from the laptop's LCD, unless one uses panning + * (but nobody wants panning, right!?). + * + * With overlapping monitors, we may end up placing the panel with + * respect to the "wrong" one. This is always wrong, as the panel + * appears "in the middle of the screen" of the monitor with the smaller + * resolution, instead of at the edge. + * + * Our strategy is to find the subsets of overlapping monitors, and + * "compress" each such set to being like if there were a single monitor + * with the biggest resolution of each of that set's monitors. Say we + * have four monitors + * + * A, B, C, D + * + * where B and D overlap. In that case, we'll generate a new list that + * looks like + * + * A, MAX(B, D), C + * + * with three monitors. + * + * NOTE FOR THE FUTURE: We could avoid most of this mess if we had a + * concept of a "primary monitor". Also, we could look at each output's + * name or properties to see if it is the built-in LCD in a laptop. + * However, with GTK+ 2.14.x we don't get output names, since it gets + * the list outputs from Xinerama, not RANDR (and Xinerama doesn't + * provide output names). + */ + + for (i = 0; i < num_monitors; i++) { + long max_pixels; + int j; + + max_pixels = pixels_in_rectangle (&geometries[i]); + + j = i + 1; + + while (j < num_monitors) { + if (overlaps (&geometries[i], &geometries[j])) { + long pixels; + + pixels = pixels_in_rectangle (&geometries[j]); + if (pixels > max_pixels) { + max_pixels = pixels; + geometries[i] = geometries[j]; /* keep the maximum */ + } + + /* Shift the remaining monitors to the left */ + if (num_monitors - j - 1 > 0) + memmove (&geometries[j], + &geometries[j + 1], + sizeof (geometries[0]) * (num_monitors - j - 1)); + + num_monitors--; + g_assert (num_monitors > 0); + } else + j++; + } + } + + *monitors_ret = num_monitors; + *geometries_ret = geometries; +} + void panel_multiscreen_init (void) { @@ -58,19 +163,13 @@ panel_multiscreen_init (void) for (i = 0; i < screens; i++) { GdkScreen *screen; - int j; screen = gdk_display_get_screen (display, i); g_signal_connect (screen, "size-changed", G_CALLBACK (panel_multiscreen_reinit), NULL); - monitors [i] = gdk_screen_get_n_monitors (screen); - geometries [i] = g_new0 (GdkRectangle, monitors [i]); - - for (j = 0; j < monitors [i]; j++) - gdk_screen_get_monitor_geometry ( - screen, j, &geometries [i][j]); + get_monitors_for_screen (screen, &(monitors[i]), &(geometries[i])); } initialized = TRUE; @@ -209,6 +308,61 @@ panel_multiscreen_locate_widget_monitor (GtkWidget *widget) return retval; } +static int +axis_distance (int p, int axis_start, int axis_size) +{ + if (p >= axis_start && p < axis_start + axis_size) + return 0; + else if (p < axis_start) + return axis_start - p; + else + return p - (axis_start + axis_size - 1); +} + +/* The panel can't use gdk_screen_get_monitor_at_point() since it has its own view of which + * monitors are present. Look at get_monitors_for_screen() above to see why. + */ +int +panel_multiscreen_get_monitor_at_point (GdkScreen *screen, int x, int y) +{ + int n_screen; + int i; + int n_monitors; + GdkRectangle *geoms; + int min_dist_squared; + int closest_monitor; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); /* not -1 as callers expect a real monitor */ + + n_screen = gdk_screen_get_number (screen); + + n_monitors = monitors[n_screen]; + geoms = geometries[n_screen]; + + min_dist_squared = G_MAXINT32; + closest_monitor = 0; + + for (i = 0; i < n_monitors; i++) { + int dist_x, dist_y; + int dist_squared; + + dist_x = axis_distance (x, geoms[i].x, geoms[i].width); + dist_y = axis_distance (y, geoms[i].y, geoms[i].height); + + if (dist_x == 0 && dist_y == 0) + return i; + + dist_squared = dist_x * dist_x + dist_y * dist_y; + + if (dist_squared < min_dist_squared) { + min_dist_squared = dist_squared; + closest_monitor = i; + } + } + + return closest_monitor; +} + typedef struct { int x0; int y0; diff --git a/gnome-panel/panel-multiscreen.h b/gnome-panel/panel-multiscreen.h index ba5fe2c..dd31b89 100644 --- a/gnome-panel/panel-multiscreen.h +++ b/gnome-panel/panel-multiscreen.h @@ -43,6 +43,9 @@ int panel_multiscreen_width (GdkScreen *screen, int panel_multiscreen_height (GdkScreen *screen, int monitor); int panel_multiscreen_locate_widget_monitor (GtkWidget *widget); +int panel_multiscreen_get_monitor_at_point (GdkScreen *screen, + int x, + int y); void panel_multiscreen_is_at_visible_extreme (GdkScreen *screen, int monitor, gboolean *leftmost, diff --git a/gnome-panel/panel-toplevel.c b/gnome-panel/panel-toplevel.c index 22694fe..5c9824b 100644 --- a/gnome-panel/panel-toplevel.c +++ b/gnome-panel/panel-toplevel.c @@ -615,7 +615,7 @@ panel_toplevel_calc_new_orientation (PanelToplevel *toplevel, screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); - monitor = gdk_screen_get_monitor_at_point (screen, pointer_x, pointer_y); + monitor = panel_multiscreen_get_monitor_at_point (screen, pointer_x, pointer_y); if (toplevel->priv->geometry.height < toplevel->priv->geometry.width) vborder = hborder = (3 * toplevel->priv->geometry.height) >> 1; @@ -727,7 +727,7 @@ panel_toplevel_move_to (PanelToplevel *toplevel, toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) new_orientation = PANEL_ORIENTATION_BOTTOM; - new_monitor = gdk_screen_get_monitor_at_point (screen, new_x, new_y); + new_monitor = panel_multiscreen_get_monitor_at_point (screen, new_x, new_y); panel_toplevel_get_monitor_geometry ( toplevel, NULL, NULL, &monitor_width, &monitor_height); @@ -2091,7 +2091,7 @@ panel_toplevel_update_expanded_position (PanelToplevel *toplevel) break; } - monitor = gdk_screen_get_monitor_at_point (screen, x, y); + monitor = panel_multiscreen_get_monitor_at_point (screen, x, y); panel_toplevel_set_monitor (toplevel, monitor);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor