Bug Summary

File:cafe-panel/panel-multimonitor.c
Warning:line 208, column 20
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name panel-multimonitor.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/cafe-panel -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/libpng16 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/ctk-3.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/cafe-desktop-2.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dconf -I /usr/include/cafe-menus -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -I . -I . -I ../cafe-panel -I ../cafe-panel/libpanel-util -D CAFELOCALEDIR="/usr/share/locale" -D PANELDATADIR="/usr/share/cafe-panel" -D PANEL_MODULES_DIR="/usr/lib/cafe-panel/modules" -D CAFEMENU_I_KNOW_THIS_IS_UNSTABLE -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/cafe-panel -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-08-06-120038-55965-1 -x c panel-multimonitor.c
1/*
2 * panel-multimonitor.c: Multi-monitor and Xinerama support for the panel.
3 *
4 * Copyright (C) 2001 George Lebl <jirka@5z.com>
5 * 2002 Sun Microsystems Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
21 *
22 * Authors: George Lebl <jirka@5z.com>,
23 * Mark McLoughlin <mark@skynet.ie>
24 */
25
26#include <config.h>
27
28#ifdef HAVE_X111
29#include <X11/Xatom.h>
30#include <X11/Xlib.h>
31#include <X11/extensions/Xrandr.h>
32#include <cdk/cdkx.h>
33#endif // HAVE_X11
34
35#include "panel-multimonitor.h"
36
37#include <string.h>
38
39// The number of logical monitors we are keeping track of
40// May be different than cdk_display_get_n_monitors()
41// (see comment in panel_multimonitor_compress_overlapping_monitors for details)
42static int monitor_count = 0;
43
44// A dynamically allocated array of monitor geometries
45// monitor_count is the length
46static CdkRectangle *geometries = NULL((void*)0);
47
48static gboolean initialized = FALSE(0);
49static gboolean have_randr = FALSE(0);
50static guint reinit_id = 0;
51
52#ifdef HAVE_X111
53#ifdef HAVE_RANDR1
54static gboolean
55_panel_multimonitor_output_should_be_first (Display *xdisplay,
56 RROutput output,
57 XRROutputInfo *info,
58 RROutput primary)
59{
60 if (primary)
61 return output == primary;
62
63 Atom connector_type_atom;
64 Atom actual_type;
65 int actual_format;
66 unsigned long nitems;
67 unsigned long bytes_after;
68 unsigned char *prop;
69 char *connector_type;
70 gboolean retval;
71
72 connector_type_atom = XInternAtom (xdisplay, "ConnectorType", False0);
73
74 if (XRRGetOutputProperty (xdisplay, output, connector_type_atom,
75 0, 100, False0, False0, None0L,
76 &actual_type, &actual_format,
77 &nitems, &bytes_after, &prop) == Success0) {
78 if (actual_type == XA_ATOM((Atom) 4) && nitems == 1 && actual_format == 32) {
79 connector_type = XGetAtomName (xdisplay, prop[0]);
80 retval = g_strcmp0 (connector_type, "Panel") == 0;
81 XFree (connector_type);
82 return retval;
83 }
84 }
85
86 /* Fallback (see https://bugs.freedesktop.org/show_bug.cgi?id=26736)
87 * "LVDS" is the oh-so-intuitive name that X gives to laptop LCDs.
88 * It can actually be LVDS0, LVDS-0, Lvds, etc.
89 */
90 return (g_ascii_strncasecmp (info->name, "LVDS", strlen ("LVDS")) == 0);
91}
92
93static gboolean
94panel_multimonitor_get_randr_monitors (int *monitors_ret,
95 CdkRectangle **geometries_ret)
96{
97 CdkDisplay *display;
98 CdkScreen *screen;
99 CdkMonitor *monitor;
100 Display *xdisplay;
101 Window xroot;
102 XRRScreenResources *resources;
103 RROutput primary;
104 GArray *geometries;
105 int scale;
106 int i;
107
108 display = cdk_display_get_default ();
109
110 g_return_val_if_fail (have_randr, FALSE)do { if ((have_randr)) { } else { g_return_if_fail_warning ((
(gchar*) 0), ((const char*) (__func__)), "have_randr"); return
((0)); } } while (0)
;
111 g_return_val_if_fail (CDK_IS_X11_DISPLAY (display), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((display)); GType __t = ((cdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning (((gchar*) 0), ((const char*
) (__func__)), "CDK_IS_X11_DISPLAY (display)"); return ((0));
} } while (0)
;
112
113 /* CTK+ 2.14.x uses the Xinerama API, instead of RANDR, to get the
114 * monitor geometries. It does this to avoid calling
115 * XRRGetScreenResources(), which is slow as it re-detects all the
116 * monitors --- note that XRRGetScreenResourcesCurrent() had not been
117 * introduced yet. Using Xinerama in CTK+ has the bad side effect that
118 * cdk_screen_get_monitor_plug_name() will return NULL, as Xinerama
119 * does not provide that information, unlike RANDR.
120 *
121 * Here we need to identify the output names, so that we can put the
122 * built-in LCD in a laptop *before* all other outputs. This is so
123 * that cafe-panel will normally prefer to appear on the "native"
124 * display rather than on an external monitor.
125 *
126 * To get the output names and geometries, we will not use
127 * cdk_screen_get_n_monitors() and friends, but rather we will call
128 * XRR*() directly.
129 *
130 * See https://bugzilla.novell.com/show_bug.cgi?id=479684 for this
131 * particular bug, and and
132 * http://bugzilla.gnome.org/show_bug.cgi?id=562944 for a more
133 * long-term solution.
134 */
135 screen = cdk_display_get_default_screen (display);
136 xdisplay = CDK_SCREEN_XDISPLAY (screen)(cdk_x11_display_get_xdisplay (cdk_screen_get_display (screen
)))
;
137 xroot = CDK_WINDOW_XID (cdk_screen_get_root_window (screen))(cdk_x11_window_get_xid (cdk_screen_get_root_window (screen))
)
;
138
139 resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);
140 if (resources->noutput == 0) {
141 /* This might happen if nothing tried to get randr
142 * resources from the server before, so we need an
143 * active probe. See comment #27 in
144 * https://bugzilla.gnome.org/show_bug.cgi?id=597101 */
145 XRRFreeScreenResources (resources);
146 resources = XRRGetScreenResources (xdisplay, xroot);
147 }
148
149 if (!resources)
150 return FALSE(0);
151
152 primary = XRRGetOutputPrimary (xdisplay, xroot);
153 monitor = cdk_display_get_primary_monitor (display);
154
155 /* Use scale factor to bring geometries down to device pixels to support HiDPI displays */
156 scale = cdk_monitor_get_scale_factor (monitor);
157
158 geometries = g_array_sized_new (FALSE(0), FALSE(0),
159 sizeof (CdkRectangle),
160 resources->noutput);
161
162 for (i = 0; i < resources->noutput; i++) {
163 XRROutputInfo *output;
164
165 output = XRRGetOutputInfo (xdisplay, resources,
166 resources->outputs[i]);
167
168 if (output->connection != RR_Disconnected1 &&
169 output->crtc != 0) {
170 XRRCrtcInfo *crtc;
171 CdkRectangle rect;
172
173 crtc = XRRGetCrtcInfo (xdisplay, resources,
174 output->crtc);
175
176 rect.x = crtc->x / scale;
177 rect.y = crtc->y / scale;
178 rect.width = crtc->width / scale;
179 rect.height = crtc->height / scale;
180
181 XRRFreeCrtcInfo (crtc);
182
183 if (_panel_multimonitor_output_should_be_first (xdisplay,
184 resources->outputs[i],
185 output, primary))
186 g_array_prepend_vals (geometries, &rect, 1);
187 else
188 g_array_append_vals (geometries, &rect, 1);
189 }
190
191 XRRFreeOutputInfo (output);
192 }
193
194 XRRFreeScreenResources (resources);
195
196 if (geometries->len == 0) {
197 /* This can happen in at least one case:
198 * https://bugzilla.novell.com/show_bug.cgi?id=543876 where all
199 * monitors appear disconnected (possibly because the screen
200 * is behing a KVM switch) -- see comment #8.
201 * There might be other cases too, so we stay on the safe side.
202 */
203 g_array_free (geometries, TRUE(!(0)));
204 return FALSE(0);
205 }
206
207 *monitors_ret = geometries->len;
208 *geometries_ret = (CdkRectangle *) g_array_free (geometries, FALSE(0));
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
209
210 return TRUE(!(0));
211}
212#endif // HAVE_RANDR
213#endif // HAVE_X11
214
215static void
216panel_multimonitor_get_cdk_monitors (int *monitors_ret,
217 CdkRectangle **geometries_ret)
218{
219 CdkDisplay *display;
220 int num_monitors;
221 CdkRectangle *geometries;
222 int i;
223
224 display = cdk_display_get_default ();
225 num_monitors = cdk_display_get_n_monitors (display);
226 geometries = g_new (CdkRectangle, num_monitors)((CdkRectangle *) g_malloc_n ((num_monitors), sizeof (CdkRectangle
)))
;
227
228 for (i = 0; i < num_monitors; i++)
229 cdk_monitor_get_geometry (cdk_display_get_monitor (display, i), &(geometries[i]));
230
231 *monitors_ret = num_monitors;
232 *geometries_ret = geometries;
233}
234
235static void
236panel_multimonitor_get_raw_monitors (int *monitors_ret,
237 CdkRectangle **geometries_ret)
238{
239 gboolean res = FALSE(0);
240
241 *monitors_ret = 0;
242 *geometries_ret = NULL((void*)0);
243
244#ifdef HAVE_X111
245#ifdef HAVE_RANDR1
246 if (CDK_IS_X11_DISPLAY (cdk_display_get_default ())(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(cdk_display_get_default ())); GType __t = ((cdk_x11_display_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
&& have_randr)
247 res = panel_multimonitor_get_randr_monitors (monitors_ret, geometries_ret);
248#endif // HAVE_RANDR
249#endif // HAVE_X11
250
251 if (res && *monitors_ret > 0)
252 return;
253
254 panel_multimonitor_get_cdk_monitors (monitors_ret, geometries_ret);
255}
256
257static inline gboolean
258rectangle_overlaps (CdkRectangle *a,
259 CdkRectangle *b)
260{
261 return cdk_rectangle_intersect (a, b, NULL((void*)0));
262}
263
264static long
265pixels_in_rectangle (CdkRectangle *r)
266{
267 return (long) (r->width * r->height);
268}
269
270static void
271panel_multimonitor_compress_overlapping_monitors (int *num_monitors_inout,
272 CdkRectangle **geometries_inout)
273{
274 int num_monitors;
275 CdkRectangle *geometries;
276 int i;
277
278 num_monitors = *num_monitors_inout;
279 geometries = *geometries_inout;
280
281 /* http://bugzilla.gnome.org/show_bug.cgi?id=530969
282 * https://bugzilla.novell.com/show_bug.cgi?id=310208
283 * and many other such bugs...
284 *
285 * RANDR sometimes gives us monitors that overlap (i.e. outputs whose
286 * bounding rectangles overlap). This is sometimes right and sometimes
287 * wrong:
288 *
289 * * Right - two 1024x768 outputs at the same offset (0, 0) that show
290 * the same thing. Think "laptop plus projector with the same
291 * resolution".
292 *
293 * * Wrong - one 1280x1024 output ("laptop internal LCD") and another
294 * 1024x768 output ("external monitor"), both at offset (0, 0).
295 * There is no way for the monitor with the small resolution to
296 * show the complete image from the laptop's LCD, unless one uses
297 * panning (but nobody wants panning, right!?).
298 *
299 * With overlapping monitors, we may end up placing the panel with
300 * respect to the "wrong" one. This is always wrong, as the panel
301 * appears "in the middle of the screen" of the monitor with the
302 * smaller resolution, instead of at the edge.
303 *
304 * Our strategy is to find the subsets of overlapping monitors, and
305 * "compress" each such set to being like if there were a single
306 * monitor with the biggest resolution of each of that set's monitors.
307 * Say we have four monitors
308 *
309 * A, B, C, D
310 *
311 * where B and D overlap. In that case, we'll generate a new list that
312 * looks like
313 *
314 * A, MAX(B, D), C
315 *
316 * with three monitors.
317 *
318 * NOTE FOR THE FUTURE: We could avoid most of this mess if we had a
319 * concept of a "primary monitor". Also, we could look at each
320 * output's name or properties to see if it is the built-in LCD in a
321 * laptop. However, with CTK+ 2.14.x we don't get output names, since
322 * it gets the list outputs from Xinerama, not RANDR (and Xinerama
323 * doesn't provide output names).
324 */
325
326 for (i = 0; i < num_monitors; i++) {
327 long max_pixels;
328 int j;
329
330 max_pixels = pixels_in_rectangle (&geometries[i]);
331
332 j = i + 1;
333
334 while (j < num_monitors) {
335 if (rectangle_overlaps (&geometries[i],
336 &geometries[j])) {
337 long pixels;
338
339 pixels = pixels_in_rectangle (&geometries[j]);
340 if (pixels > max_pixels) {
341 max_pixels = pixels;
342 /* keep the maximum */
343 geometries[i] = geometries[j];
344 }
345
346 /* Shift the remaining monitors to the left */
347 if (num_monitors - j - 1 > 0)
348 memmove (&geometries[j],
349 &geometries[j + 1],
350 sizeof (geometries[0]) * (num_monitors - j - 1));
351
352 num_monitors--;
353 g_assert (num_monitors > 0)do { if (num_monitors > 0) ; else g_assertion_message_expr
(((gchar*) 0), "panel-multimonitor.c", 353, ((const char*) (
__func__)), "num_monitors > 0"); } while (0)
;
354 } else
355 j++;
356 }
357 }
358
359 *num_monitors_inout = num_monitors;
360 *geometries_inout = geometries;
361}
362
363static gboolean
364panel_multimonitor_reinit_idle (gpointer data)
365{
366 panel_multimonitor_reinit ();
367 reinit_id = 0;
368
369 return FALSE(0);
370}
371
372static void
373panel_multimonitor_handle_screen_changed (CdkScreen *screen,
374 gpointer user_data)
375{
376 if (reinit_id)
377 return;
378
379 reinit_id = g_idle_add (panel_multimonitor_reinit_idle, NULL((void*)0));
380}
381
382static void
383panel_multimonitor_handle_monitor_changed (CdkDisplay *display,
384 CdkMonitor *monitor,
385 gpointer user_data)
386{
387 if (reinit_id)
388 return;
389
390 reinit_id = g_idle_add (panel_multimonitor_reinit_idle, NULL((void*)0));
391}
392
393static void
394panel_multimonitor_handle_monitor_invalidate (CdkMonitor *monitor,
395 gpointer user_data)
396{
397 if (reinit_id)
398 return;
399
400 reinit_id = g_idle_add (panel_multimonitor_reinit_idle, NULL((void*)0));
401}
402
403#ifdef HAVE_X111
404#ifdef HAVE_RANDR1
405static void
406panel_multimonitor_init_randr (CdkDisplay *display)
407{
408 Display *xdisplay;
409 int event_base, error_base;
410
411 g_return_if_fail (CDK_IS_X11_DISPLAY (display))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((display)); GType __t = ((cdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning (((gchar*) 0), ((const char*
) (__func__)), "CDK_IS_X11_DISPLAY (display)"); return; } } while
(0)
;
412
413 have_randr = FALSE(0);
414
415 if (!CDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((cdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
416 return;
417
418 xdisplay = CDK_DISPLAY_XDISPLAY (display)(cdk_x11_display_get_xdisplay (display));
419
420 /* We don't remember the event/error bases, as we expect to get monitor
421 * added/removed events from the display instead.
422 */
423
424 if (XRRQueryExtension (xdisplay, &event_base, &error_base)) {
425 int major, minor;
426
427 XRRQueryVersion (xdisplay, &major, &minor);
428 if ((major == 1 && minor >= 3) || major > 1)
429 have_randr = TRUE(!(0));
430 }
431}
432#endif // HAVE_RANDR
433#endif // HAVE_X11
434
435void
436panel_multimonitor_init (void)
437{
438 CdkDisplay *display;
439 CdkScreen *screen;
440 int i;
441
442 if (initialized)
443 return;
444
445 display = cdk_display_get_default ();
446 screen = cdk_display_get_default_screen (display);
447
448 have_randr = FALSE(0);
449
450#ifdef HAVE_X111
451#ifdef HAVE_RANDR1
452 if (CDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((cdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
453 panel_multimonitor_init_randr (display);
454#endif // HAVE_RANDR
455#endif // HAVE_X11
456
457 /*
458 * The screen signals probably shouldn't be needed, but sometimes on X11 they are
459 * the only ones that get fired
460 */
461
462 g_signal_handlers_disconnect_by_func (screen, panel_multimonitor_handle_screen_changed, NULL)g_signal_handlers_disconnect_matched ((screen), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (panel_multimonitor_handle_screen_changed), (((void*)0)))
;
463 g_signal_connect (screen, "size-changed",g_signal_connect_data ((screen), ("size-changed"), (((GCallback
) (panel_multimonitor_handle_screen_changed))), (((void*)0)),
((void*)0), (GConnectFlags) 0)
464 G_CALLBACK (panel_multimonitor_handle_screen_changed), NULL)g_signal_connect_data ((screen), ("size-changed"), (((GCallback
) (panel_multimonitor_handle_screen_changed))), (((void*)0)),
((void*)0), (GConnectFlags) 0)
;
465 g_signal_connect (screen, "monitors-changed",g_signal_connect_data ((screen), ("monitors-changed"), (((GCallback
) (panel_multimonitor_handle_screen_changed))), (((void*)0)),
((void*)0), (GConnectFlags) 0)
466 G_CALLBACK (panel_multimonitor_handle_screen_changed), NULL)g_signal_connect_data ((screen), ("monitors-changed"), (((GCallback
) (panel_multimonitor_handle_screen_changed))), (((void*)0)),
((void*)0), (GConnectFlags) 0)
;
467
468 g_signal_handlers_disconnect_by_func (display, panel_multimonitor_handle_monitor_changed, NULL)g_signal_handlers_disconnect_matched ((display), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (panel_multimonitor_handle_monitor_changed), (((void*)0))
)
;
469 g_signal_connect (display, "monitor-added",g_signal_connect_data ((display), ("monitor-added"), (((GCallback
) (panel_multimonitor_handle_monitor_changed))), (((void*)0))
, ((void*)0), (GConnectFlags) 0)
470 G_CALLBACK (panel_multimonitor_handle_monitor_changed), NULL)g_signal_connect_data ((display), ("monitor-added"), (((GCallback
) (panel_multimonitor_handle_monitor_changed))), (((void*)0))
, ((void*)0), (GConnectFlags) 0)
;
471 g_signal_connect (display, "monitor-removed",g_signal_connect_data ((display), ("monitor-removed"), (((GCallback
) (panel_multimonitor_handle_monitor_changed))), (((void*)0))
, ((void*)0), (GConnectFlags) 0)
472 G_CALLBACK (panel_multimonitor_handle_monitor_changed), NULL)g_signal_connect_data ((display), ("monitor-removed"), (((GCallback
) (panel_multimonitor_handle_monitor_changed))), (((void*)0))
, ((void*)0), (GConnectFlags) 0)
;
473
474 for (i = 0; i < cdk_display_get_n_monitors (display); i++) {
475 CdkMonitor *monitor;
476
477 monitor = cdk_display_get_monitor (display, i);
478 g_signal_handlers_disconnect_by_func (display, panel_multimonitor_handle_monitor_invalidate, NULL)g_signal_handlers_disconnect_matched ((display), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (panel_multimonitor_handle_monitor_invalidate), (((void*)
0)))
;
479 g_signal_connect (monitor, "invalidate",g_signal_connect_data ((monitor), ("invalidate"), (((GCallback
) (panel_multimonitor_handle_monitor_invalidate))), (((void*)
0)), ((void*)0), (GConnectFlags) 0)
480 G_CALLBACK (panel_multimonitor_handle_monitor_invalidate), NULL)g_signal_connect_data ((monitor), ("invalidate"), (((GCallback
) (panel_multimonitor_handle_monitor_invalidate))), (((void*)
0)), ((void*)0), (GConnectFlags) 0)
;
481 }
482
483 panel_multimonitor_get_raw_monitors (&monitor_count, &geometries);
484 panel_multimonitor_compress_overlapping_monitors (&monitor_count, &geometries);
485
486 initialized = TRUE(!(0));
487}
488
489void
490panel_multimonitor_reinit (void)
491{
492 GList *toplevels, *l;
493
494 if (geometries)
495 g_free (geometries);
496
497 initialized = FALSE(0);
498 panel_multimonitor_init ();
499
500 toplevels = ctk_window_list_toplevels ();
501
502 for (l = toplevels; l; l = l->next)
503 ctk_widget_queue_resize (l->data);
504
505 g_list_free (toplevels);
506}
507
508int
509panel_multimonitor_monitors ()
510{
511 return monitor_count;
512}
513
514int
515panel_multimonitor_x (int monitor)
516{
517 g_return_val_if_fail (monitor >= 0 && monitor < monitor_count, 0)do { if ((monitor >= 0 && monitor < monitor_count
)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const
char*) (__func__)), "monitor >= 0 && monitor < monitor_count"
); return (0); } } while (0)
;
518 return geometries [monitor].x;
519}
520
521int
522panel_multimonitor_y (int monitor)
523{
524 g_return_val_if_fail (monitor >= 0 && monitor < monitor_count, 0)do { if ((monitor >= 0 && monitor < monitor_count
)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const
char*) (__func__)), "monitor >= 0 && monitor < monitor_count"
); return (0); } } while (0)
;
525 return geometries [monitor].y;
526}
527
528int
529panel_multimonitor_width (int monitor)
530{
531 g_return_val_if_fail (monitor >= 0 && monitor < monitor_count, 0)do { if ((monitor >= 0 && monitor < monitor_count
)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const
char*) (__func__)), "monitor >= 0 && monitor < monitor_count"
); return (0); } } while (0)
;
532 return geometries [monitor].width;
533}
534
535int
536panel_multimonitor_height (int monitor)
537{
538 g_return_val_if_fail (monitor >= 0 && monitor < monitor_count, 0)do { if ((monitor >= 0 && monitor < monitor_count
)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const
char*) (__func__)), "monitor >= 0 && monitor < monitor_count"
); return (0); } } while (0)
;
539 return geometries [monitor].height;
540}
541
542int
543panel_multimonitor_locate_widget_monitor (CtkWidget *widget)
544{
545 CtkWidget *toplevel;
546 int retval = -1;
547
548 toplevel = ctk_widget_get_toplevel (widget);
549 if (!toplevel)
550 return -1;
551
552 g_object_get (toplevel, "monitor", &retval, NULL((void*)0));
553
554 return retval;
555}
556
557static int
558axis_distance (int p, int axis_start, int axis_size)
559{
560 if (p >= axis_start && p < axis_start + axis_size)
561 return 0;
562 else if (p < axis_start)
563 return (axis_start - p);
564 else
565 return (p - (axis_start + axis_size - 1));
566}
567
568/* The panel can't use cdk_screen_get_monitor_at_point() since it has its own
569 * view of which monitors are present. Look at get_monitors_for_screen() above
570 * to see why. */
571int
572panel_multimonitor_get_monitor_at_point (int x, int y)
573{
574 int i;
575 int min_dist_squared;
576 int closest_monitor;
577
578 min_dist_squared = G_MAXINT32((gint32) 0x7fffffff);
579 closest_monitor = 0;
580
581 for (i = 0; i < monitor_count; i++) {
582 int dist_x, dist_y;
583 int dist_squared;
584
585 dist_x = axis_distance (x, geometries[i].x, geometries[i].width);
586 dist_y = axis_distance (y, geometries[i].y, geometries[i].height);
587
588 if (dist_x == 0 && dist_y == 0)
589 return i;
590
591 dist_squared = dist_x * dist_x + dist_y * dist_y;
592
593 if (dist_squared < min_dist_squared) {
594 min_dist_squared = dist_squared;
595 closest_monitor = i;
596 }
597 }
598
599 return closest_monitor;
600}
601
602typedef struct {
603 int x0;
604 int y0;
605 int x1;
606 int y1;
607} MonitorBounds;
608
609static inline void
610get_monitor_bounds (int n_monitor,
611 MonitorBounds *bounds)
612{
613 g_return_if_fail (n_monitor >= 0 || n_monitor < monitor_count)do { if ((n_monitor >= 0 || n_monitor < monitor_count))
{ } else { g_return_if_fail_warning (((gchar*) 0), ((const char
*) (__func__)), "n_monitor >= 0 || n_monitor < monitor_count"
); return; } } while (0)
;
614 g_return_if_fail (bounds != NULL)do { if ((bounds != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "bounds != NULL")
; return; } } while (0)
;
615
616 bounds->x0 = geometries [n_monitor].x;
617 bounds->y0 = geometries [n_monitor].y;
618 bounds->x1 = bounds->x0 + geometries [n_monitor].width;
619 bounds->y1 = bounds->y0 + geometries [n_monitor].height;
620}
621
622/* determines whether a given monitor is along the visible
623 * edge of the logical screen.
624 */
625void
626panel_multimonitor_is_at_visible_extreme (int n_monitor,
627 gboolean *leftmost,
628 gboolean *rightmost,
629 gboolean *topmost,
630 gboolean *bottommost)
631{
632 MonitorBounds monitor;
633 int i;
634
635 *leftmost = TRUE(!(0));
636 *rightmost = TRUE(!(0));
637 *topmost = TRUE(!(0));
638 *bottommost = TRUE(!(0));
639
640 g_return_if_fail (n_monitor >= 0 && n_monitor < monitor_count)do { if ((n_monitor >= 0 && n_monitor < monitor_count
)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const
char*) (__func__)), "n_monitor >= 0 && n_monitor < monitor_count"
); return; } } while (0)
;
641
642 get_monitor_bounds (n_monitor, &monitor);
643
644 /* go through each monitor and try to find one either right,
645 * below, above, or left of the specified monitor
646 */
647
648 for (i = 0; i < monitor_count; i++) {
649 MonitorBounds iter;
650
651 if (i == n_monitor) continue;
652
653 get_monitor_bounds (i, &iter);
654
655 if ((iter.y0 >= monitor.y0 && iter.y0 < monitor.y1) ||
656 (iter.y1 > monitor.y0 && iter.y1 <= monitor.y1)) {
657 if (iter.x0 < monitor.x0)
658 *leftmost = FALSE(0);
659 if (iter.x1 > monitor.x1)
660 *rightmost = FALSE(0);
661 }
662
663 if ((iter.x0 >= monitor.x0 && iter.x0 < monitor.x1) ||
664 (iter.x1 > monitor.x0 && iter.x1 <= monitor.x1)) {
665 if (iter.y0 < monitor.y0)
666 *topmost = FALSE(0);
667 if (iter.y1 > monitor.y1)
668 *bottommost = FALSE(0);
669 }
670 }
671}
672
673void
674panel_multimonitor_get_bounds (CdkPoint *min,
675 CdkPoint *max)
676{
677 int i;
678
679 g_return_if_fail (monitor_count > 0)do { if ((monitor_count > 0)) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "monitor_count > 0"
); return; } } while (0)
;
680
681 min->x = min->y = INT_MAX2147483647;
682 max->x = max->y = INT_MIN(-2147483647 -1);
683
684 for (i = 0; i < monitor_count; i++) {
685 min->x = MIN (min->x, geometries[i].x)(((min->x) < (geometries[i].x)) ? (min->x) : (geometries
[i].x))
;
686 min->y = MIN (min->y, geometries[i].y)(((min->y) < (geometries[i].y)) ? (min->y) : (geometries
[i].y))
;
687 max->x = MAX (max->x, geometries[i].x + geometries[i].width)(((max->x) > (geometries[i].x + geometries[i].width)) ?
(max->x) : (geometries[i].x + geometries[i].width))
;
688 max->y = MAX (max->y, geometries[i].y + geometries[i].height)(((max->y) > (geometries[i].y + geometries[i].height)) ?
(max->y) : (geometries[i].y + geometries[i].height))
;
689 }
690}