Bug Summary

File:cafe-panel/panel-multimonitor.c
Warning:line 209, 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 -fdebug-compilation-dir=/rootdir/cafe-panel -fcoverage-compilation-dir=/rootdir/cafe-panel -resource-dir /usr/lib/llvm-19/lib/clang/19 -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-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -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.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/2025-03-30-180740-54439-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 gboolean retval;
70
71 connector_type_atom = XInternAtom (xdisplay, "ConnectorType", False0);
72
73 if (XRRGetOutputProperty (xdisplay, output, connector_type_atom,
74 0, 100, False0, False0, None0L,
75 &actual_type, &actual_format,
76 &nitems, &bytes_after, &prop) == Success0) {
77 if (actual_type == XA_ATOM((Atom) 4) && nitems == 1 && actual_format == 32) {
78 char *connector_type;
79
80 connector_type = XGetAtomName (xdisplay, prop[0]);
81 retval = g_strcmp0 (connector_type, "Panel") == 0;
82 XFree (connector_type);
83 return retval;
84 }
85 }
86
87 /* Fallback (see https://bugs.freedesktop.org/show_bug.cgi?id=26736)
88 * "LVDS" is the oh-so-intuitive name that X gives to laptop LCDs.
89 * It can actually be LVDS0, LVDS-0, Lvds, etc.
90 */
91 return (g_ascii_strncasecmp (info->name, "LVDS", strlen ("LVDS")) == 0);
92}
93
94static gboolean
95panel_multimonitor_get_randr_monitors (int *monitors_ret,
96 CdkRectangle **geometries_ret)
97{
98 CdkDisplay *display;
99 CdkScreen *screen;
100 CdkMonitor *monitor;
101 Display *xdisplay;
102 Window xroot;
103 XRRScreenResources *resources;
104 RROutput primary;
105 GArray *geometries;
106 int scale;
107 int i;
108
109 display = cdk_display_get_default ();
110
111 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)
;
112 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)
;
113
114 /* CTK+ 2.14.x uses the Xinerama API, instead of RANDR, to get the
115 * monitor geometries. It does this to avoid calling
116 * XRRGetScreenResources(), which is slow as it re-detects all the
117 * monitors --- note that XRRGetScreenResourcesCurrent() had not been
118 * introduced yet. Using Xinerama in CTK+ has the bad side effect that
119 * cdk_screen_get_monitor_plug_name() will return NULL, as Xinerama
120 * does not provide that information, unlike RANDR.
121 *
122 * Here we need to identify the output names, so that we can put the
123 * built-in LCD in a laptop *before* all other outputs. This is so
124 * that cafe-panel will normally prefer to appear on the "native"
125 * display rather than on an external monitor.
126 *
127 * To get the output names and geometries, we will not use
128 * cdk_screen_get_n_monitors() and friends, but rather we will call
129 * XRR*() directly.
130 *
131 * See https://bugzilla.novell.com/show_bug.cgi?id=479684 for this
132 * particular bug, and and
133 * http://bugzilla.gnome.org/show_bug.cgi?id=562944 for a more
134 * long-term solution.
135 */
136 screen = cdk_display_get_default_screen (display);
137 xdisplay = CDK_SCREEN_XDISPLAY (screen)(cdk_x11_display_get_xdisplay (cdk_screen_get_display (screen
)))
;
138 xroot = CDK_WINDOW_XID (cdk_screen_get_root_window (screen))(cdk_x11_window_get_xid (cdk_screen_get_root_window (screen))
)
;
139
140 resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);
141 if (resources->noutput == 0) {
142 /* This might happen if nothing tried to get randr
143 * resources from the server before, so we need an
144 * active probe. See comment #27 in
145 * https://bugzilla.gnome.org/show_bug.cgi?id=597101 */
146 XRRFreeScreenResources (resources);
147 resources = XRRGetScreenResources (xdisplay, xroot);
148 }
149
150 if (!resources)
151 return FALSE(0);
152
153 primary = XRRGetOutputPrimary (xdisplay, xroot);
154 monitor = cdk_display_get_primary_monitor (display);
155
156 /* Use scale factor to bring geometries down to device pixels to support HiDPI displays */
157 scale = cdk_monitor_get_scale_factor (monitor);
158
159 geometries = g_array_sized_new (FALSE(0), FALSE(0),
160 sizeof (CdkRectangle),
161 resources->noutput);
162
163 for (i = 0; i < resources->noutput; i++) {
164 XRROutputInfo *output;
165
166 output = XRRGetOutputInfo (xdisplay, resources,
167 resources->outputs[i]);
168
169 if (output->connection != RR_Disconnected1 &&
170 output->crtc != 0) {
171 XRRCrtcInfo *crtc;
172 CdkRectangle rect;
173
174 crtc = XRRGetCrtcInfo (xdisplay, resources,
175 output->crtc);
176
177 rect.x = crtc->x / scale;
178 rect.y = crtc->y / scale;
179 rect.width = crtc->width / scale;
180 rect.height = crtc->height / scale;
181
182 XRRFreeCrtcInfo (crtc);
183
184 if (_panel_multimonitor_output_should_be_first (xdisplay,
185 resources->outputs[i],
186 output, primary))
187 g_array_prepend_vals (geometries, &rect, 1);
188 else
189 g_array_append_vals (geometries, &rect, 1);
190 }
191
192 XRRFreeOutputInfo (output);
193 }
194
195 XRRFreeScreenResources (resources);
196
197 if (geometries->len == 0) {
198 /* This can happen in at least one case:
199 * https://bugzilla.novell.com/show_bug.cgi?id=543876 where all
200 * monitors appear disconnected (possibly because the screen
201 * is behing a KVM switch) -- see comment #8.
202 * There might be other cases too, so we stay on the safe side.
203 */
204 g_array_free (geometries, TRUE(!(0)));
205 return FALSE(0);
206 }
207
208 *monitors_ret = geometries->len;
209 *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
210
211 return TRUE(!(0));
212}
213#endif // HAVE_RANDR
214#endif // HAVE_X11
215
216static void
217panel_multimonitor_get_cdk_monitors (int *monitors_ret,
218 CdkRectangle **geometries_ret)
219{
220 CdkDisplay *display;
221 int num_monitors;
222 CdkRectangle *geometries;
223 int i;
224
225 display = cdk_display_get_default ();
226 num_monitors = cdk_display_get_n_monitors (display);
227 geometries = g_new (CdkRectangle, num_monitors)((CdkRectangle *) g_malloc_n ((num_monitors), sizeof (CdkRectangle
)))
;
228
229 for (i = 0; i < num_monitors; i++)
230 cdk_monitor_get_geometry (cdk_display_get_monitor (display, i), &(geometries[i]));
231
232 *monitors_ret = num_monitors;
233 *geometries_ret = geometries;
234}
235
236static void
237panel_multimonitor_get_raw_monitors (int *monitors_ret,
238 CdkRectangle **geometries_ret)
239{
240 gboolean res = FALSE(0);
241
242 *monitors_ret = 0;
243 *geometries_ret = NULL((void*)0);
244
245#ifdef HAVE_X111
246#ifdef HAVE_RANDR1
247 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)
248 res = panel_multimonitor_get_randr_monitors (monitors_ret, geometries_ret);
249#endif // HAVE_RANDR
250#endif // HAVE_X11
251
252 if (res && *monitors_ret > 0)
253 return;
254
255 panel_multimonitor_get_cdk_monitors (monitors_ret, geometries_ret);
256}
257
258static inline gboolean
259rectangle_overlaps (CdkRectangle *a,
260 CdkRectangle *b)
261{
262 return cdk_rectangle_intersect (a, b, NULL((void*)0));
263}
264
265static long
266pixels_in_rectangle (CdkRectangle *r)
267{
268 return (long) (r->width * r->height);
269}
270
271static void
272panel_multimonitor_compress_overlapping_monitors (int *num_monitors_inout,
273 CdkRectangle **geometries_inout)
274{
275 int num_monitors;
276 CdkRectangle *geometries;
277 int i;
278
279 num_monitors = *num_monitors_inout;
280 geometries = *geometries_inout;
281
282 /* http://bugzilla.gnome.org/show_bug.cgi?id=530969
283 * https://bugzilla.novell.com/show_bug.cgi?id=310208
284 * and many other such bugs...
285 *
286 * RANDR sometimes gives us monitors that overlap (i.e. outputs whose
287 * bounding rectangles overlap). This is sometimes right and sometimes
288 * wrong:
289 *
290 * * Right - two 1024x768 outputs at the same offset (0, 0) that show
291 * the same thing. Think "laptop plus projector with the same
292 * resolution".
293 *
294 * * Wrong - one 1280x1024 output ("laptop internal LCD") and another
295 * 1024x768 output ("external monitor"), both at offset (0, 0).
296 * There is no way for the monitor with the small resolution to
297 * show the complete image from the laptop's LCD, unless one uses
298 * panning (but nobody wants panning, right!?).
299 *
300 * With overlapping monitors, we may end up placing the panel with
301 * respect to the "wrong" one. This is always wrong, as the panel
302 * appears "in the middle of the screen" of the monitor with the
303 * smaller resolution, instead of at the edge.
304 *
305 * Our strategy is to find the subsets of overlapping monitors, and
306 * "compress" each such set to being like if there were a single
307 * monitor with the biggest resolution of each of that set's monitors.
308 * Say we have four monitors
309 *
310 * A, B, C, D
311 *
312 * where B and D overlap. In that case, we'll generate a new list that
313 * looks like
314 *
315 * A, MAX(B, D), C
316 *
317 * with three monitors.
318 *
319 * NOTE FOR THE FUTURE: We could avoid most of this mess if we had a
320 * concept of a "primary monitor". Also, we could look at each
321 * output's name or properties to see if it is the built-in LCD in a
322 * laptop. However, with CTK+ 2.14.x we don't get output names, since
323 * it gets the list outputs from Xinerama, not RANDR (and Xinerama
324 * doesn't provide output names).
325 */
326
327 for (i = 0; i < num_monitors; i++) {
328 long max_pixels;
329 int j;
330
331 max_pixels = pixels_in_rectangle (&geometries[i]);
332
333 j = i + 1;
334
335 while (j < num_monitors) {
336 if (rectangle_overlaps (&geometries[i],
337 &geometries[j])) {
338 long pixels;
339
340 pixels = pixels_in_rectangle (&geometries[j]);
341 if (pixels > max_pixels) {
342 max_pixels = pixels;
343 /* keep the maximum */
344 geometries[i] = geometries[j];
345 }
346
347 /* Shift the remaining monitors to the left */
348 if (num_monitors - j - 1 > 0)
349 memmove (&geometries[j],
350 &geometries[j + 1],
351 sizeof (geometries[0]) * (num_monitors - j - 1));
352
353 num_monitors--;
354 g_assert (num_monitors > 0)do { if (num_monitors > 0) ; else g_assertion_message_expr
(((gchar*) 0), "panel-multimonitor.c", 354, ((const char*) (
__func__)), "num_monitors > 0"); } while (0)
;
355 } else
356 j++;
357 }
358 }
359
360 *num_monitors_inout = num_monitors;
361 *geometries_inout = geometries;
362}
363
364static gboolean
365panel_multimonitor_reinit_idle (gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
366{
367 panel_multimonitor_reinit ();
368 reinit_id = 0;
369
370 return FALSE(0);
371}
372
373static void
374panel_multimonitor_handle_screen_changed (CdkScreen *screen G_GNUC_UNUSED__attribute__ ((__unused__)),
375 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
376{
377 if (reinit_id)
378 return;
379
380 reinit_id = g_idle_add (panel_multimonitor_reinit_idle, NULL((void*)0));
381}
382
383static void
384panel_multimonitor_handle_monitor_changed (CdkDisplay *display G_GNUC_UNUSED__attribute__ ((__unused__)),
385 CdkMonitor *monitor G_GNUC_UNUSED__attribute__ ((__unused__)),
386 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
387{
388 if (reinit_id)
389 return;
390
391 reinit_id = g_idle_add (panel_multimonitor_reinit_idle, NULL((void*)0));
392}
393
394static void
395panel_multimonitor_handle_monitor_invalidate (CdkMonitor *monitor G_GNUC_UNUSED__attribute__ ((__unused__)),
396 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
397{
398 if (reinit_id)
399 return;
400
401 reinit_id = g_idle_add (panel_multimonitor_reinit_idle, NULL((void*)0));
402}
403
404#ifdef HAVE_X111
405#ifdef HAVE_RANDR1
406static void
407panel_multimonitor_init_randr (CdkDisplay *display)
408{
409 Display *xdisplay;
410 int event_base, error_base;
411
412 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)
;
413
414 have_randr = FALSE(0);
415
416 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; }))))
)
417 return;
418
419 xdisplay = CDK_DISPLAY_XDISPLAY (display)(cdk_x11_display_get_xdisplay (display));
420
421 /* We don't remember the event/error bases, as we expect to get monitor
422 * added/removed events from the display instead.
423 */
424
425 if (XRRQueryExtension (xdisplay, &event_base, &error_base)) {
426 int major, minor;
427
428 XRRQueryVersion (xdisplay, &major, &minor);
429 if ((major == 1 && minor >= 3) || major > 1)
430 have_randr = TRUE(!(0));
431 }
432}
433#endif // HAVE_RANDR
434#endif // HAVE_X11
435
436void
437panel_multimonitor_init (void)
438{
439 CdkDisplay *display;
440 CdkScreen *screen;
441 int i;
442
443 if (initialized)
444 return;
445
446 display = cdk_display_get_default ();
447 screen = cdk_display_get_default_screen (display);
448
449 have_randr = FALSE(0);
450
451#ifdef HAVE_X111
452#ifdef HAVE_RANDR1
453 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; }))))
)
454 panel_multimonitor_init_randr (display);
455#endif // HAVE_RANDR
456#endif // HAVE_X11
457
458 /*
459 * The screen signals probably shouldn't be needed, but sometimes on X11 they are
460 * the only ones that get fired
461 */
462
463 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)))
;
464 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)
465 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)
;
466 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)
467 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)
;
468
469 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))
)
;
470 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)
471 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)
;
472 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)
473 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)
;
474
475 for (i = 0; i < cdk_display_get_n_monitors (display); i++) {
476 CdkMonitor *monitor;
477
478 monitor = cdk_display_get_monitor (display, i);
479 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)))
;
480 g_signal_connect (monitor, "invalidate",g_signal_connect_data ((monitor), ("invalidate"), (((GCallback
) (panel_multimonitor_handle_monitor_invalidate))), (((void*)
0)), ((void*)0), (GConnectFlags) 0)
481 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)
;
482 }
483
484 panel_multimonitor_get_raw_monitors (&monitor_count, &geometries);
485 panel_multimonitor_compress_overlapping_monitors (&monitor_count, &geometries);
486
487 initialized = TRUE(!(0));
488}
489
490void
491panel_multimonitor_reinit (void)
492{
493 GList *toplevels, *l;
494
495 if (geometries)
496 g_free (geometries);
497
498 initialized = FALSE(0);
499 panel_multimonitor_init ();
500
501 toplevels = ctk_window_list_toplevels ();
502
503 for (l = toplevels; l; l = l->next)
504 ctk_widget_queue_resize (l->data);
505
506 g_list_free (toplevels);
507}
508
509int
510panel_multimonitor_monitors ()
511{
512 return monitor_count;
513}
514
515int
516panel_multimonitor_x (int monitor)
517{
518 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)
;
519 return geometries [monitor].x;
520}
521
522int
523panel_multimonitor_y (int monitor)
524{
525 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)
;
526 return geometries [monitor].y;
527}
528
529int
530panel_multimonitor_width (int monitor)
531{
532 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)
;
533 return geometries [monitor].width;
534}
535
536int
537panel_multimonitor_height (int monitor)
538{
539 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)
;
540 return geometries [monitor].height;
541}
542
543int
544panel_multimonitor_locate_widget_monitor (CtkWidget *widget)
545{
546 CtkWidget *toplevel;
547 int retval = -1;
548
549 toplevel = ctk_widget_get_toplevel (widget);
550 if (!toplevel)
551 return -1;
552
553 g_object_get (toplevel, "monitor", &retval, NULL((void*)0));
554
555 return retval;
556}
557
558static int
559axis_distance (int p, int axis_start, int axis_size)
560{
561 if (p >= axis_start && p < axis_start + axis_size)
562 return 0;
563 else if (p < axis_start)
564 return (axis_start - p);
565 else
566 return (p - (axis_start + axis_size - 1));
567}
568
569/* The panel can't use cdk_screen_get_monitor_at_point() since it has its own
570 * view of which monitors are present. Look at get_monitors_for_screen() above
571 * to see why. */
572int
573panel_multimonitor_get_monitor_at_point (int x, int y)
574{
575 int i;
576 int min_dist_squared;
577 int closest_monitor;
578
579 min_dist_squared = G_MAXINT32((gint32) 0x7fffffff);
580 closest_monitor = 0;
581
582 for (i = 0; i < monitor_count; i++) {
583 int dist_x, dist_y;
584 int dist_squared;
585
586 dist_x = axis_distance (x, geometries[i].x, geometries[i].width);
587 dist_y = axis_distance (y, geometries[i].y, geometries[i].height);
588
589 if (dist_x == 0 && dist_y == 0)
590 return i;
591
592 dist_squared = dist_x * dist_x + dist_y * dist_y;
593
594 if (dist_squared < min_dist_squared) {
595 min_dist_squared = dist_squared;
596 closest_monitor = i;
597 }
598 }
599
600 return closest_monitor;
601}
602
603typedef struct {
604 int x0;
605 int y0;
606 int x1;
607 int y1;
608} MonitorBounds;
609
610static inline void
611get_monitor_bounds (int n_monitor,
612 MonitorBounds *bounds)
613{
614 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)
;
615 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)
;
616
617 bounds->x0 = geometries [n_monitor].x;
618 bounds->y0 = geometries [n_monitor].y;
619 bounds->x1 = bounds->x0 + geometries [n_monitor].width;
620 bounds->y1 = bounds->y0 + geometries [n_monitor].height;
621}
622
623/* determines whether a given monitor is along the visible
624 * edge of the logical screen.
625 */
626void
627panel_multimonitor_is_at_visible_extreme (int n_monitor,
628 gboolean *leftmost,
629 gboolean *rightmost,
630 gboolean *topmost,
631 gboolean *bottommost)
632{
633 MonitorBounds monitor;
634 int i;
635
636 *leftmost = TRUE(!(0));
637 *rightmost = TRUE(!(0));
638 *topmost = TRUE(!(0));
639 *bottommost = TRUE(!(0));
640
641 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)
;
642
643 get_monitor_bounds (n_monitor, &monitor);
644
645 /* go through each monitor and try to find one either right,
646 * below, above, or left of the specified monitor
647 */
648
649 for (i = 0; i < monitor_count; i++) {
650 MonitorBounds iter;
651
652 if (i == n_monitor) continue;
653
654 get_monitor_bounds (i, &iter);
655
656 if ((iter.y0 >= monitor.y0 && iter.y0 < monitor.y1) ||
657 (iter.y1 > monitor.y0 && iter.y1 <= monitor.y1)) {
658 if (iter.x0 < monitor.x0)
659 *leftmost = FALSE(0);
660 if (iter.x1 > monitor.x1)
661 *rightmost = FALSE(0);
662 }
663
664 if ((iter.x0 >= monitor.x0 && iter.x0 < monitor.x1) ||
665 (iter.x1 > monitor.x0 && iter.x1 <= monitor.x1)) {
666 if (iter.y0 < monitor.y0)
667 *topmost = FALSE(0);
668 if (iter.y1 > monitor.y1)
669 *bottommost = FALSE(0);
670 }
671 }
672}
673
674void
675panel_multimonitor_get_bounds (CdkPoint *min,
676 CdkPoint *max)
677{
678 int i;
679
680 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)
;
681
682 min->x = min->y = INT_MAX2147483647;
683 max->x = max->y = INT_MIN(-2147483647 -1);
684
685 for (i = 0; i < monitor_count; i++) {
686 min->x = MIN (min->x, geometries[i].x)(((min->x) < (geometries[i].x)) ? (min->x) : (geometries
[i].x))
;
687 min->y = MIN (min->y, geometries[i].y)(((min->y) < (geometries[i].y)) ? (min->y) : (geometries
[i].y))
;
688 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))
;
689 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))
;
690 }
691}