1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, see: <http://www.gnu.org/licenses/>
14 */
15
16 /*
17 * FScreen.c
18 * Xinerama abstraction support for window manager.
19 *
20 * This module is all original code
21 * by Dmitry Yu. Bolkhovityanov <bolkhov@inp.nsk.su>
22 * Copyright 2001, Dmitry Bolkhovityanov
23 * You may use this code for any purpose, as long as the original
24 * copyright remains in the source code and all documentation
25 */
26
27 /*
28 * Brief description of used concept:
29 *
30 * This code is always used by client, regardless of if Xinerama is
31 * available or not (either because -lXinerama was missing or
32 * because Xinerama extension is missing on display).
33 *
34 * If Xinerama is available, this module maintains a list of screens,
35 * from [1] to [num_screens]. screens[0] is always the "global" screen,
36 * so if Xinerama is unavailable or disabled, the module performs
37 * all checks on screens[0] instead of screens[1..num_screens].
38 *
39 * The client should first call the FScreenInit(), passing
40 * it the opened display descriptor. During this call the list of
41 * Xinerama screens is retrieved and 'dpy' is saved for future
42 * reference.
43 *
44 * If the client wishes to hard-disable Xinerama support (e.g. if
45 * Xinerama extension is present but is broken on display), it should
46 * call FScreenDisable() *before* FScreenInit().
47 *
48 * Using real Xinerama screens info may be switched on/off "on the
49 * fly" by calling FScreenSetState(0=off/else=on).
50 *
51 * Modules with Xinerama support should listen to the XineramaEnable
52 * and XineramaDisable strings coming over the module pipe as
53 * M_CONFIG_INFO packets and call FScreenEnable() or
54 * FScreenDisable in response.
55 *
56 */
57
58 #include "config.h"
59
60 #include <stdio.h>
61 #include <ctype.h>
62
63 #include "defaults.h"
64 #include "fvwmlib.h"
65 #include "Parse.h"
66 #include "FScreen.h"
67 #include "PictureBase.h"
68
69 #ifdef HAVE_XINERAMA
70 # undef FSCREEN_NEED_SCREENINFO
71 # define FScreenHaveXinerama 1
72 # ifdef HAVE_SOLARIS_XINERAMA
73 # define FScreenHaveSolarisXinerama 1
74 # ifdef HAVE_SOLARIS_XINERAMA_H
75 # include <X11/extensions/xinerama.h>
76 # else
77 # define FSCREEN_NEED_SOLARIS_PROTOTYPES
78 # endif
79 # define FSCREEN_NEED_SCREENINFO
80 # else
81 # define FScreenHaveSolarisXinerama 0
82 # include <X11/extensions/Xinerama.h>
83 # endif
84 #else
85 # define FSCREEN_NEED_SCREENINFO
86 # define FScreenHaveXinerama 0
87 # define FScreenHaveSolarisXinerama 0
88 #endif
89
90 #ifdef FSCREEN_NEED_SCREENINFO
91 typedef struct
92 {
93 int screen_number;
94 short x_org;
95 short y_org;
96 unsigned short width;
97 unsigned short height;
98 } XineramaScreenInfo;
99 #endif
100
101 #ifdef FSCREEN_NEED_SOLARIS_PROTOTYPES
102 /* Copied from Solaris 9's X11/extensions/xinerama.h */
103 Bool XineramaGetState(Display*, int);
104 Status XineramaGetInfo(Display*, int, XRectangle*, unsigned char*, int*);
105 Status XineramaGetCenterHint(Display*, int, int*, int*);
106 #endif
107
108 #if FScreenHaveSolarisXinerama == 0
109 #define XineramaGetInfo(a,b,c,d,e) 0
110 #endif
111
112 #if FScreenHaveXinerama
113 # if FScreenHaveSolarisXinerama
114 # define XineramaQueryExtension(d,b,c) 1 /* Lie, for now */
115 # define XineramaIsActive(d) XineramaGetState((d),0)
116 # define XineramaQueryScreens(d,s) (*(s)) = 0, NULL
117 # endif
118 #else
119 # define XineramaQueryExtension(da, b, c) 0
120 # define XineramaIsActive(a) 0
121 # define XineramaQueryScreens(d,s) (*(s)) = 0, NULL
122 #endif
123
124 #ifndef MAXFRAMEBUFFERS
125 #define MAXFRAMEBUFFERS 16
126 #endif
127
128
129 #ifdef USE_XINERAMA_EMULATION
130 #define FScreenXineramaEmulation 1
131 #else
132 #define FScreenXineramaEmulation 0
133 #endif
134
135 #if 0
136 #ifdef HAVE_RANDR
137 #include <X11/Xproto.h>
138 #include <X11/extensions/Xrandr.h>
139 #endif
140 #endif
141
142 enum
143 {
144 /* Replace with FSCREEN_GLOBAL to restore default behaviour */
145 DEFAULT_GEOMETRY_SCREEN = FSCREEN_PRIMARY
146 };
147
148 /* In fact, only corners matter -- there will never be GRAV_NONE */
149 enum {GRAV_POS = 0, GRAV_NONE = 1, GRAV_NEG = 2};
150 static int grav_matrix[3][3] =
151 {
152 { NorthWestGravity, NorthGravity, NorthEastGravity },
153 { WestGravity, CenterGravity, EastGravity },
154 { SouthWestGravity, SouthGravity, SouthEastGravity }
155 };
156 #define DEFAULT_GRAVITY NorthWestGravity
157
158
159 static Display *disp = NULL;
160 static Bool is_xinerama_enabled = DEFAULT_XINERAMA_ENABLED;
161 static Bool is_sls_enabled = False;
162 static Bool have_sls_screen_list = False;
163 static XineramaScreenInfo *screens;
164 static XineramaScreenInfo *screens_xi;
165 static XineramaScreenInfo *screens_sls = NULL;
166 /* # of Xinerama screens, *not* counting the global, 0 if disabled */
167 static int num_screens = 0;
168 /* # of Xinerama screens, *not* counting the global */
169 static int total_screens = 0;
170 static int total_screens_xi = 0;
171 static int total_screens_sls = 1;
172 static int total_sls_width = 1;
173 static int total_sls_height = 1;
174 static int first_to_check = 0;
175 static int last_to_check = 0;
176 static int default_geometry_scr = FSCREEN_PRIMARY;
177 /* only to be accessed vie the set/get functions! */
178 static int primary_scr = DEFAULT_PRIMARY_SCREEN;
179
180 #if 0
181 #ifdef HAVE_RANDR
182 static Bool randr_disabled = 0;
183 static Bool randr_active = 0;
184 static int randr_event_base = -1;
185 static int randr_error_base = -1;
186 #endif
187 #endif
188
189 static Window blank_w, vert_w, blank2_w, blank3_w;
190
191 static int FScreenParseScreenBit(char *arg, char default_screen);
192 static int FindScreenOfXY(int x, int y);
193
194 static XineramaScreenInfo *
solaris_XineramaQueryScreens(Display * d,int * nscreens)195 solaris_XineramaQueryScreens(Display *d, int *nscreens)
196 {
197 if (FScreenHaveSolarisXinerama)
198 {
199 XineramaScreenInfo *screens = NULL;
200 XRectangle monitors[MAXFRAMEBUFFERS];
201 unsigned char hints[16];
202 int result;
203
204 /* dummy instructions to keep -Wall happy */
205 hints[0] = hints[0];
206 result = XineramaGetInfo(
207 d, DefaultScreen(d), monitors, hints, nscreens);
208 if (result)
209 {
210 int m;
211
212 /* Note, malloced area later freed by XFree() */
213 screens = (XineramaScreenInfo *)malloc(
214 sizeof(XineramaScreenInfo) * (*nscreens));
215 for (m = 0; m < *nscreens; ++m)
216 {
217 screens[m].screen_number = m;
218 screens[m].x_org = monitors[m].x;
219 screens[m].y_org = monitors[m].y;
220 screens[m].width = monitors[m].width;
221 screens[m].height = monitors[m].height;
222 }
223 }
224 else
225 {
226 fprintf(
227 stderr,
228 "Error getting Xinerama information\n");
229 *nscreens = 0;
230 }
231
232 return screens;
233 }
234 else
235 {
236 return NULL;
237 }
238 }
239
FXineramaQueryScreens(Display * d,int * nscreens)240 static XineramaScreenInfo *FXineramaQueryScreens(Display *d, int *nscreens)
241 {
242 if (FScreenHaveXinerama == 0)
243 {
244 *nscreens = 0;
245
246 return NULL;
247 }
248 if (FScreenHaveSolarisXinerama == 1)
249 {
250 return solaris_XineramaQueryScreens(d, nscreens);
251 }
252 else
253 {
254 return XineramaQueryScreens(d, nscreens);
255 }
256 }
257
GetMouseXY(XEvent * eventp,int * x,int * y)258 static void GetMouseXY(XEvent *eventp, int *x, int *y)
259 {
260 if (!is_xinerama_enabled || last_to_check == first_to_check)
261 {
262 /* We use .x_org,.y_org because nothing prevents a screen to be
263 * not at (0,0) */
264 *x = screens[first_to_check].x_org;
265 *y = screens[first_to_check].y_org;
266 }
267 else
268 {
269 XEvent e;
270
271 if (eventp == NULL)
272 {
273 eventp = &e;
274 e.type = 0;
275 }
276 fev_get_evpos_or_query(
277 disp, DefaultRootWindow(disp), eventp, x, y);
278 }
279
280 return;
281 }
282
FScreenIsEnabled(void)283 Bool FScreenIsEnabled(void)
284 {
285 return (!is_xinerama_enabled || num_screens == 0) ? False : True;
286 }
287
FScreenIsSLSEnabled(void)288 Bool FScreenIsSLSEnabled(void)
289 {
290 return is_sls_enabled;
291 }
292
FScreenUpdateEmulationMapState(void)293 static void FScreenUpdateEmulationMapState(void)
294 {
295 static Bool is_mapped = False;
296
297 if (!FScreenXineramaEmulation)
298 {
299 return;
300 }
301
302 if (is_xinerama_enabled && !is_sls_enabled)
303 {
304 if (!is_mapped)
305 {
306 XMapRaised(disp, blank_w);
307 XMapRaised(disp, blank2_w);
308 XMapRaised(disp, blank3_w);
309 XMapRaised(disp, vert_w);
310 is_mapped = True;
311 }
312 }
313 else
314 {
315 if (is_mapped)
316 {
317 XUnmapWindow(disp, blank_w);
318 XUnmapWindow(disp, blank2_w);
319 XUnmapWindow(disp, blank3_w);
320 XUnmapWindow(disp, vert_w);
321 is_mapped = False;
322 }
323 }
324 }
325
FScreenSetState(Bool do_enable)326 static void FScreenSetState(Bool do_enable)
327 {
328 is_xinerama_enabled = do_enable;
329 if (do_enable && total_screens > 0)
330 {
331 num_screens = total_screens;
332 first_to_check = 1;
333 last_to_check = total_screens;
334 }
335 else
336 {
337 num_screens = 0;
338 first_to_check = 0;
339 last_to_check = 0;
340 }
341 FScreenUpdateEmulationMapState();
342 }
343
344
FScreenInit(Display * dpy)345 void FScreenInit(Display *dpy)
346 {
347 static Bool is_initialised = False;
348 int dummy_rc;
349
350 SUPPRESS_UNUSED_VAR_WARNING(dummy_rc);
351 if (is_initialised)
352 {
353 return;
354 }
355 is_initialised = True;
356 disp = dpy;
357 if (FScreenXineramaEmulation)
358 {
359 int count;
360 int w;
361 int h;
362 int ws;
363 unsigned long scr;
364 Window root;
365 XSetWindowAttributes attributes;
366
367 scr = DefaultScreen(disp);
368 root = RootWindow(disp, scr);
369
370 /* xinerama emulation simulates xinerama on a single screen:
371 *
372 * actual screen
373 * +---------------------+--------------+
374 * | | |
375 * | | |
376 * | | |
377 * | | simulated |
378 * | | screen 2 |
379 * | simulated screen 1 | |
380 * | | |
381 * | | |
382 * | | |
383 * | | |
384 * +---------------------+ |
385 * | blank area | |
386 * | | |
387 * +---------------------+--------------+
388 */
389 count = 2;
390 total_screens_xi = count;
391 screens_xi = (XineramaScreenInfo *)
392 safemalloc(sizeof(XineramaScreenInfo) * (1 + count));
393 /* calculate the faked sub screen dimensions */
394 w = DisplayWidth(disp, scr);
395 ws = 3 * w / 5;
396 h = DisplayHeight(disp, scr);
397 screens_xi[1].screen_number = 0;
398 screens_xi[1].x_org = 0;
399 screens_xi[1].y_org = h / 16;
400 screens_xi[1].width = ws;
401 screens_xi[1].height = 7 * h / 8;
402 screens_xi[2].screen_number = 1;
403 screens_xi[2].x_org = ws;
404 screens_xi[2].y_org = 0;
405 screens_xi[2].width = w - ws;
406 screens_xi[2].height = 7 * h / 8;
407 /* add delimiter */
408 attributes.background_pixel = PictureWhitePixel();
409 attributes.override_redirect = True;
410 blank_w = XCreateWindow(
411 disp, root, 0, screens_xi[1].y_org - 1,
412 screens_xi[1].width, 2, 0, CopyFromParent,
413 CopyFromParent, CopyFromParent,
414 CWBackPixel|CWOverrideRedirect, &attributes);
415 blank2_w = XCreateWindow(
416 disp, root, 0,
417 screens_xi[1].y_org + screens_xi[1].height - 1,
418 screens_xi[1].width, 2, 0, CopyFromParent,
419 CopyFromParent, CopyFromParent,
420 CWBackPixel|CWOverrideRedirect, &attributes);
421 blank3_w = XCreateWindow(
422 disp, root, screens_xi[2].x_org,
423 screens_xi[2].height - 1, w - screens_xi[2].x_org, 2,
424 0, CopyFromParent, CopyFromParent, CopyFromParent,
425 CWBackPixel|CWOverrideRedirect, &attributes);
426 vert_w = XCreateWindow(
427 disp, root, screens_xi[2].x_org - 1, 0, 2, h, 0,
428 CopyFromParent, CopyFromParent, CopyFromParent,
429 CWBackPixel|CWOverrideRedirect, &attributes);
430 }
431 else if (FScreenHaveXinerama &&
432 XineramaQueryExtension(disp, &dummy_rc, &dummy_rc) &&
433 XineramaIsActive(disp))
434 {
435 int count;
436 XineramaScreenInfo *info;
437
438 info = FXineramaQueryScreens(disp, &count);
439 total_screens_xi = count;
440 screens_xi = (XineramaScreenInfo *)
441 safemalloc(sizeof(XineramaScreenInfo) *
442 (1 + count));
443 memcpy(screens_xi + 1, info,
444 sizeof(XineramaScreenInfo) * count);
445 XFree(info);
446 }
447 else
448 {
449 total_screens_xi = 0;
450 screens_xi =
451 (XineramaScreenInfo *)safemalloc(
452 sizeof(XineramaScreenInfo)*1);
453 }
454 total_screens = total_screens_xi;
455 screens = screens_xi;
456
457 /* Now, fill screens[0] with global screen parameters */
458 screens_xi[0].screen_number = -1;
459 screens_xi[0].x_org = 0;
460 screens_xi[0].y_org = 0;
461 screens_xi[0].width = DisplayWidth (disp, DefaultScreen(disp));
462 screens_xi[0].height = DisplayHeight(disp, DefaultScreen(disp));
463
464 /* Fill in the screen range */
465 FScreenSetState(is_xinerama_enabled);
466
467 return;
468 }
469
FScreenOnOff(Bool do_enable)470 void FScreenOnOff(Bool do_enable)
471 {
472 FScreenSetState(do_enable);
473 }
474
FScreenSLSOnOff(Bool do_enable)475 void FScreenSLSOnOff(Bool do_enable)
476 {
477 is_sls_enabled = do_enable;
478 if (do_enable)
479 {
480 total_screens = total_screens_sls;
481 if (!screens_sls)
482 {
483 /* Sls not configured yet, use whole screen by default
484 */
485 FScreenConfigureSLSSize(1, 1);
486 }
487 screens = screens_sls;
488 }
489 else
490 {
491 total_screens = total_screens_xi;
492 screens = screens_xi;
493 }
494 FScreenSetState(is_xinerama_enabled);
495 }
496
FScreenConfigureSLSSize(int width,int height)497 Bool FScreenConfigureSLSSize(int width, int height)
498 {
499 unsigned long scr = DefaultScreen(disp);
500 int w = DisplayWidth(disp, scr);
501 int h = DisplayHeight(disp, scr);
502
503 if (width <= 1)
504 {
505 width = 1;
506 }
507 else if (width > w)
508 {
509 width = w;
510 }
511 if (height <= 1)
512 {
513 height = 1;
514 }
515 else if (height > h)
516 {
517 height = h;
518 }
519 if (total_sls_width == width && total_sls_height == height &&
520 screens_sls)
521 {
522 return False;
523 }
524 if (screens_sls)
525 {
526 free(screens_sls);
527 screens_sls = NULL;
528 }
529 /* calculate the screens */
530 {
531 int row, col, sn;
532 int ws;
533 int hs;
534
535 total_screens_sls = width * height;
536 total_sls_width = width;
537 total_sls_height = height;
538 ws = w / total_sls_width;
539 hs = h / total_sls_height;
540 screens_sls = (XineramaScreenInfo *)
541 safemalloc(sizeof(XineramaScreenInfo) *
542 (1 + total_screens_sls));
543 /* calculate the faked sub screen dimensions */
544 screens_sls[0] = screens_xi[0];
545 sn = 1;
546 for (row = 0; row < total_sls_height; row++)
547 {
548 for (col = 0; col < total_sls_width; col++, sn++)
549 {
550 screens_sls[sn].screen_number = sn - 1;
551 screens_sls[sn].x_org = col * ws;
552 screens_sls[sn].y_org = row * hs;
553 screens_sls[sn].width = ws;
554 screens_sls[sn].height = hs;
555 }
556 }
557 }
558 have_sls_screen_list = False;
559 FScreenSLSOnOff(is_sls_enabled);
560
561 return True;
562 }
563
FScreenConfigureSLSScreens(int nscreens,char * args)564 Bool FScreenConfigureSLSScreens(int nscreens, char *args)
565 {
566 int sn;
567 char *next;
568
569 if (nscreens == 0 || args == NULL)
570 {
571 return FScreenConfigureSLSSize(1, 1);
572 }
573 if (nscreens == 1 && screens_sls)
574 {
575 return False;
576 }
577 if (screens_sls)
578 {
579 free(screens_sls);
580 screens_sls = NULL;
581 }
582 screens_sls = (XineramaScreenInfo *)
583 safemalloc(sizeof(XineramaScreenInfo) * (nscreens + 1));
584 screens_sls[0] = screens_xi[0];
585 for (sn = 1; sn <= nscreens; sn++, args = next)
586 {
587 char *token;
588 int val[4];
589
590 /* read next screen spec */
591 token = PeekToken(args, &next);
592 if (!token)
593 {
594 break;
595 }
596 if (XParseGeometry(token, &val[0], &val[1],
597 (unsigned int *)&val[2],
598 (unsigned int *)&val[3]) ==
599 (XValue|YValue|WidthValue|HeightValue) ||
600 GetIntegerArguments(args, &next, val, 4) == 4)
601 {
602 if (val[0] < 0 || val[1] < 0 || val[2] < 1 ||
603 val[3] < 1)
604 {
605 /* illegal spec */
606 break;
607 }
608 screens_sls[sn].screen_number = sn - 1;
609 screens_sls[sn].x_org = val[0];
610 screens_sls[sn].y_org = val[1];
611 screens_sls[sn].width = val[2];
612 screens_sls[sn].height = val[3];
613 }
614 else
615 {
616 /* illegal spec */
617 break;
618 }
619 }
620 total_screens_sls = sn - 1;
621 have_sls_screen_list = True;
622 FScreenSLSOnOff(is_sls_enabled);
623
624 return True;
625 }
626
627 #if 0
628 void FScreenDisableRandR(void)
629 {
630 if (disp != NULL)
631 {
632 fprintf(stderr, "FScreen: WARNING: FScreenDisableRandR()"
633 " called after FScreenInit()!\n");
634 }
635 randr_disabled = 1;
636
637 return;
638 }
639 #endif
640
FScreenGetPrimaryScreen(XEvent * ev)641 static int FScreenGetPrimaryScreen(XEvent *ev)
642 {
643 if (!is_xinerama_enabled)
644 {
645 return 0;
646 }
647 if (primary_scr == FSCREEN_GLOBAL)
648 {
649 return 0;
650 }
651 else if (primary_scr == FSCREEN_CURRENT)
652 {
653 int mx;
654 int my;
655
656 /* use current screen as primary screen */
657 GetMouseXY(ev, &mx, &my);
658 return FindScreenOfXY(mx, my);
659 }
660 else if (primary_scr < 0 || primary_scr >= last_to_check)
661 {
662 /* out of range */
663 return 0;
664 }
665
666 return primary_scr + 1;
667 }
668
FScreenSetPrimaryScreen(int scr)669 void FScreenSetPrimaryScreen(int scr)
670 {
671 primary_scr = scr;
672 }
673
674 /* Intended to be called by modules. Simply pass in the parameter from the
675 * config string sent by fvwm. */
FScreenConfigureModule(char * args)676 void FScreenConfigureModule(char *args)
677 {
678 int val[6];
679 int n;
680 char *next;
681
682 n = GetIntegerArguments(args, &next, val, 4);
683 if (n != 4)
684 {
685 /* ignore broken line */
686 return;
687 }
688 FScreenSetPrimaryScreen(val[1]);
689
690 if (val[3])
691 {
692 /* SLS screen coordinates follow */
693 n = GetIntegerArguments(next, &next, val + 4, 1);
694 if (n != 1)
695 {
696 /* ignore broken line */
697 return;
698 }
699 FScreenConfigureSLSScreens(val[4], next);
700 }
701 else
702 {
703 /* simple SLS line */
704 n = GetIntegerArguments(next, NULL, val + 4, 2);
705 if (n != 2)
706 {
707 /* ignore broken line */
708 return;
709 }
710 FScreenConfigureSLSSize(val[4], val[5]);
711 }
712
713 FScreenSLSOnOff(val[2]);
714 FScreenOnOff(val[0]);
715
716 return;
717 }
718
719 /* Here's the function used by fvwm to generate the string which
720 * FScreenConfigureModule expects to receive back as its argument.
721 */
FScreenGetConfiguration(void)722 const char *FScreenGetConfiguration(void)
723 {
724 int i;
725 int l;
726 int l2;
727 static char msg[MAX_MODULE_INPUT_TEXT_LEN];
728 char buf[64];
729
730 sprintf(
731 msg, XINERAMA_CONFIG_STRING" %d %d %d %d",
732 FScreenIsEnabled(), primary_scr,
733 FScreenIsSLSEnabled(), have_sls_screen_list);
734 l = strlen(msg);
735 if (have_sls_screen_list)
736 {
737 sprintf(msg + l, " %d", total_screens_sls);
738 for (i = 0; i < total_screens_sls; i++)
739 {
740 sprintf(buf, " %d %d %d %d", screens_sls[i].x_org,
741 screens_sls[i].y_org, screens_sls[i].width,
742 screens_sls[i].height);
743 l2 = strlen(buf);
744 if (l + l2 > MAX_MODULE_INPUT_TEXT_LEN)
745 {
746 break;
747 }
748 strcat(msg + l, buf);
749 l += l2;
750 }
751 }
752 else
753 {
754 sprintf(msg + l, " %d %d", total_sls_width, total_sls_height);
755 }
756
757 return msg;
758 }
759
760 /* Sets the default screen for ...ParseGeometry if no screen spec is given.
761 * Usually this is FSCREEN_SPEC_PRIMARY, but this won't allow modules to appear
762 * under the pointer. */
FScreenSetDefaultModuleScreen(char * scr_spec)763 void FScreenSetDefaultModuleScreen(char *scr_spec)
764 {
765 default_geometry_scr =
766 FScreenParseScreenBit(scr_spec, FSCREEN_SPEC_PRIMARY);
767
768 return;
769 }
770
771
FindScreenOfXY(int x,int y)772 static int FindScreenOfXY(int x, int y)
773 {
774 int i;
775
776 x = x % screens_xi[0].width;
777 while (x < 0)
778 {
779 x += screens_xi[0].width;
780 }
781 y = y % screens_xi[0].height;
782 while (y < 0)
783 {
784 y += screens_xi[0].height;
785 }
786 for (i = first_to_check; i <= last_to_check; i++)
787 {
788 if (x >= screens[i].x_org &&
789 x < screens[i].x_org + screens[i].width &&
790 y >= screens[i].y_org &&
791 y < screens[i].y_org + screens[i].height)
792 {
793 return i;
794 }
795 }
796
797 /* Ouch! A "black hole" coords? As for now, return global screen */
798 return 0;
799 }
800
FindScreen(fscreen_scr_arg * arg,fscreen_scr_t screen)801 static int FindScreen(
802 fscreen_scr_arg *arg, fscreen_scr_t screen)
803 {
804 fscreen_scr_arg tmp;
805
806 if (num_screens == 0)
807 {
808 screen = FSCREEN_GLOBAL;
809 }
810 switch (screen)
811 {
812 case FSCREEN_GLOBAL:
813 screen = 0;
814 break;
815 case FSCREEN_PRIMARY:
816 screen =
817 FScreenGetPrimaryScreen(
818 (arg && arg->mouse_ev) ? arg->mouse_ev : NULL);
819 break;
820 case FSCREEN_CURRENT:
821 /* translate to xypos format */
822 if (!arg)
823 {
824 tmp.mouse_ev = NULL;
825 arg = &tmp;
826 }
827 GetMouseXY(arg->mouse_ev, &arg->xypos.x, &arg->xypos.y);
828 /* fall through */
829 case FSCREEN_XYPOS:
830 /* translate to screen number */
831 if (!arg)
832 {
833 tmp.xypos.x = 0;
834 tmp.xypos.y = 0;
835 arg = &tmp;
836 }
837 screen = FindScreenOfXY(arg->xypos.x, arg->xypos.y);
838 break;
839 default:
840 /* screen is given counting from 0; translate to counting from
841 * 1 */
842 screen++;
843 break;
844 }
845
846 return screen;
847 }
848
849 /* Given pointer coordinates, return the screen the pointer is on.
850 *
851 * Perhaps most useful with $[pointer.screen]
852 */
FScreenOfPointerXY(int x,int y)853 int FScreenOfPointerXY(int x, int y)
854 {
855 int pscreen;
856
857 pscreen = FindScreenOfXY(x, y);
858
859 return (pscreen > 0) ? --pscreen : pscreen;
860 }
861
862 /* Returns the specified screens geometry rectangle. screen can be a screen
863 * number or any of the values FSCREEN_GLOBAL, FSCREEN_CURRENT,
864 * FSCREEN_PRIMARY or FSCREEN_XYPOS. The arg union only has a meaning for
865 * FSCREEN_CURRENT and FSCREEN_XYARG. For FSCREEN_CURRENT its mouse_ev member
866 * may be given. It is tried to find out the pointer position from the event
867 * first before querying the pointer. For FSCREEN_XYPOS the xpos member is used
868 * to fetch the x/y position of the point on the screen. If arg is NULL, the
869 * position 0 0 is assumed instead.
870 *
871 * Any of the arguments arg, x, y, w and h may be NULL.
872 *
873 * FSCREEN_GLOBAL: return the global screen dimensions
874 * FSCREEN_CURRENT: return dimensions of the screen with the pointer
875 * FSCREEN_PRIMARY: return the primary screen dimensions
876 * FSCREEN_XYPOS: return dimensions of the screen with the given coordinates
877 *
878 * The function returns False if the global screen was returned and more than
879 * one screen is configured. Otherwise it returns True.
880 */
FScreenGetScrRect(fscreen_scr_arg * arg,fscreen_scr_t screen,int * x,int * y,int * w,int * h)881 Bool FScreenGetScrRect(
882 fscreen_scr_arg *arg, fscreen_scr_t screen, int *x, int *y,
883 int *w, int *h)
884 {
885 screen = FindScreen(arg, screen);
886 if (screen < first_to_check || screen > last_to_check)
887 {
888 screen = 0;
889 }
890 if (x)
891 {
892 *x = screens[screen].x_org;
893 }
894 if (y)
895 {
896 *y = screens[screen].y_org;
897 }
898 if (w)
899 {
900 *w = screens[screen].width;
901 }
902 if (h)
903 {
904 *h = screens[screen].height;
905 }
906
907 return !(screen == 0 && num_screens > 1);
908 }
909
910 /* returns the screen id */
FScreenGetScrId(fscreen_scr_arg * arg,fscreen_scr_t screen)911 Bool FScreenGetScrId(
912 fscreen_scr_arg *arg, fscreen_scr_t screen)
913 {
914 screen = FindScreen(arg, screen);
915 if (screen < 0)
916 {
917 screen = FSCREEN_GLOBAL;
918 }
919
920 return screen;
921 }
922
923 /* Translates the coodinates *x *y from the screen specified by arg_src and
924 * screen_src to coordinates on the screen specified by arg_dest and
925 * screen_dest. (see FScreenGetScrRect for more details). */
FScreenTranslateCoordinates(fscreen_scr_arg * arg_src,fscreen_scr_t screen_src,fscreen_scr_arg * arg_dest,fscreen_scr_t screen_dest,int * x,int * y)926 void FScreenTranslateCoordinates(
927 fscreen_scr_arg *arg_src, fscreen_scr_t screen_src,
928 fscreen_scr_arg *arg_dest, fscreen_scr_t screen_dest,
929 int *x, int *y)
930 {
931 int x_src;
932 int y_src;
933 int x_dest;
934 int y_dest;
935
936 FScreenGetScrRect(arg_src, screen_src, &x_src, &y_src, NULL, NULL);
937 FScreenGetScrRect(arg_dest, screen_dest, &x_dest, &y_dest, NULL, NULL);
938
939 if (x)
940 {
941 *x = *x + x_src - x_dest;
942 }
943 if (y)
944 {
945 *y = *y + y_src - y_dest;
946 }
947
948 return;
949 }
950
951 /* Arguments work exactly like for FScreenGetScrRect() */
FScreenClipToScreen(fscreen_scr_arg * arg,fscreen_scr_t screen,int * x,int * y,int w,int h)952 int FScreenClipToScreen(
953 fscreen_scr_arg *arg, fscreen_scr_t screen, int *x, int *y, int w,
954 int h)
955 {
956 int sx;
957 int sy;
958 int sw;
959 int sh;
960 int lx = (x) ? *x : 0;
961 int ly = (y) ? *y : 0;
962 int x_grav = GRAV_POS;
963 int y_grav = GRAV_POS;
964
965 FScreenGetScrRect(arg, screen, &sx, &sy, &sw, &sh);
966 if (lx + w > sx + sw)
967 {
968 lx = sx + sw - w;
969 x_grav = GRAV_NEG;
970 }
971 if (ly + h > sy + sh)
972 {
973 ly = sy + sh - h;
974 y_grav = GRAV_NEG;
975 }
976 if (lx < sx)
977 {
978 lx = sx;
979 x_grav = GRAV_POS;
980 }
981 if (ly < sy)
982 {
983 ly = sy;
984 y_grav = GRAV_POS;
985 }
986 if (x)
987 {
988 *x = lx;
989 }
990 if (y)
991 {
992 *y = ly;
993 }
994
995 return grav_matrix[y_grav][x_grav];
996 }
997
998 /* Arguments work exactly like for FScreenGetScrRect() */
FScreenCenterOnScreen(fscreen_scr_arg * arg,fscreen_scr_t screen,int * x,int * y,int w,int h)999 void FScreenCenterOnScreen(
1000 fscreen_scr_arg *arg, fscreen_scr_t screen, int *x, int *y, int w,
1001 int h)
1002 {
1003 int sx;
1004 int sy;
1005 int sw;
1006 int sh;
1007 int lx;
1008 int ly;
1009
1010 FScreenGetScrRect(arg, screen, &sx, &sy, &sw, &sh);
1011 lx = (sw - w) / 2;
1012 ly = (sh - h) / 2;
1013 if (lx < 0)
1014 lx = 0;
1015 if (ly < 0)
1016 ly = 0;
1017 lx += sx;
1018 ly += sy;
1019 if (x)
1020 {
1021 *x = lx;
1022 }
1023 if (y)
1024 {
1025 *y = ly;
1026 }
1027
1028 return;
1029 }
1030
FScreenGetResistanceRect(int wx,int wy,unsigned int ww,unsigned int wh,int * x0,int * y0,int * x1,int * y1)1031 void FScreenGetResistanceRect(
1032 int wx, int wy, unsigned int ww, unsigned int wh, int *x0, int *y0,
1033 int *x1, int *y1)
1034 {
1035 fscreen_scr_arg arg;
1036
1037 arg.xypos.x = wx + ww / 2;
1038 arg.xypos.y = wy + wh / 2;
1039 FScreenGetScrRect(&arg, FSCREEN_XYPOS, x0, y0, x1, y1);
1040 *x1 += *x0;
1041 *y1 += *y0;
1042
1043 return;
1044 }
1045
1046 /* Arguments work exactly like for FScreenGetScrRect() */
FScreenIsRectangleOnScreen(fscreen_scr_arg * arg,fscreen_scr_t screen,rectangle * rec)1047 Bool FScreenIsRectangleOnScreen(
1048 fscreen_scr_arg *arg, fscreen_scr_t screen, rectangle *rec)
1049 {
1050 int sx;
1051 int sy;
1052 int sw;
1053 int sh;
1054
1055 FScreenGetScrRect(arg, screen, &sx, &sy, &sw, &sh);
1056
1057 return (rec->x + rec->width > sx && rec->x < sx + sw &&
1058 rec->y + rec->height > sy && rec->y < sy + sh) ? True : False;
1059 }
1060
FScreenSpecToString(char * dest,int space,fscreen_scr_t screen)1061 void FScreenSpecToString(char *dest, int space, fscreen_scr_t screen)
1062 {
1063 char s[32];
1064
1065 if (space <= 0)
1066 {
1067 return;
1068 }
1069 switch (screen)
1070 {
1071 case FSCREEN_GLOBAL:
1072 strcpy(s, "global screen");
1073 break;
1074 case FSCREEN_CURRENT:
1075 strcpy(s, "current screen");
1076 break;
1077 case FSCREEN_PRIMARY:
1078 strcpy(s, "primary screen");
1079 break;
1080 case FSCREEN_XYPOS:
1081 strcpy(s, "screen specified by xy");
1082 break;
1083 default:
1084 sprintf(s, "%d", screen);
1085 break;
1086 }
1087 strncpy(dest, s, space);
1088 dest[space - 1] = 0;
1089
1090 return;
1091 }
1092
FScreenParseScreenBit(char * scr_spec,char default_screen)1093 static int FScreenParseScreenBit(char *scr_spec, char default_screen)
1094 {
1095 int scr = default_geometry_scr;
1096 char c;
1097
1098 c = (scr_spec) ? tolower(*scr_spec) : tolower(default_screen);
1099 if (c == FSCREEN_SPEC_GLOBAL)
1100 {
1101 scr = FSCREEN_GLOBAL;
1102 }
1103 else if (c == FSCREEN_SPEC_CURRENT)
1104 {
1105 scr = FSCREEN_CURRENT;
1106 }
1107 else if (c == FSCREEN_SPEC_PRIMARY)
1108 {
1109 scr = FSCREEN_PRIMARY;
1110 }
1111 else if (c == FSCREEN_SPEC_WINDOW)
1112 {
1113 scr = FSCREEN_XYPOS;
1114 }
1115 else if (isdigit(c))
1116 {
1117 scr = atoi(scr_spec);
1118 }
1119 else
1120 {
1121 c = tolower(default_screen);
1122 if (c == FSCREEN_SPEC_GLOBAL)
1123 {
1124 scr = FSCREEN_GLOBAL;
1125 }
1126 else if (c == FSCREEN_SPEC_CURRENT)
1127 {
1128 scr = FSCREEN_CURRENT;
1129 }
1130 else if (c == FSCREEN_SPEC_PRIMARY)
1131 {
1132 scr = FSCREEN_PRIMARY;
1133 }
1134 else if (c == FSCREEN_SPEC_WINDOW)
1135 {
1136 scr = FSCREEN_XYPOS;
1137 }
1138 else if (isdigit(c))
1139 {
1140 scr = atoi(scr_spec);
1141 }
1142 }
1143
1144 return scr;
1145 }
1146
FScreenGetScreenArgument(char * scr_spec,fscreen_scr_spec_t default_screen)1147 int FScreenGetScreenArgument(char *scr_spec, fscreen_scr_spec_t default_screen)
1148 {
1149 while (scr_spec && isspace(*scr_spec))
1150 {
1151 scr_spec++;
1152 }
1153
1154 return FScreenParseScreenBit(scr_spec, default_screen);
1155 }
1156
1157 /*
1158 * FScreenParseGeometry
1159 * Does the same as XParseGeometry, but handles additional "@scr".
1160 * Since it isn't safe to define "ScreenValue" constant (actual values
1161 * of other "XXXValue" are specified in Xutil.h, not by us, so there can
1162 * be a clash), the screen value is always returned, even if it wasn't
1163 * present in `parse_string' (set to default in that case).
1164 *
1165 */
FScreenParseGeometryWithScreen(char * parsestring,int * x_return,int * y_return,unsigned int * width_return,unsigned int * height_return,int * screen_return)1166 int FScreenParseGeometryWithScreen(
1167 char *parsestring, int *x_return, int *y_return,
1168 unsigned int *width_return, unsigned int *height_return,
1169 int *screen_return)
1170 {
1171 int ret;
1172 char *copy, *scr_p;
1173 int s_size;
1174 int scr;
1175
1176 /* Safety net */
1177 if (parsestring == NULL || *parsestring == '\0')
1178 {
1179 return 0;
1180 }
1181
1182 /* Make a local copy devoid of "@scr" */
1183 s_size = strlen(parsestring) + 1;
1184 copy = safemalloc(s_size);
1185 memcpy(copy, parsestring, s_size);
1186 scr_p = strchr(copy, '@');
1187 if (scr_p != NULL)
1188 {
1189 *scr_p++ = '\0';
1190 }
1191
1192 /* Do the parsing */
1193 ret = XParseGeometry(
1194 copy, x_return, y_return, width_return, height_return);
1195
1196 /* Parse the "@scr", if any */
1197 scr = FScreenParseScreenBit(scr_p, FSCREEN_SPEC_PRIMARY);
1198 *screen_return = scr;
1199
1200 /* We don't need the string any more */
1201 free(copy);
1202
1203 return ret;
1204 }
1205
1206 /* Same as above, but dump screen return value to keep compatible with the X
1207 * function. */
FScreenParseGeometry(char * parsestring,int * x_return,int * y_return,unsigned int * width_return,unsigned int * height_return)1208 int FScreenParseGeometry(
1209 char *parsestring, int *x_return, int *y_return,
1210 unsigned int *width_return, unsigned int *height_return)
1211 {
1212 int scr;
1213 int rc;
1214 int mx;
1215 int my;
1216
1217 rc = FScreenParseGeometryWithScreen(
1218 parsestring, x_return, y_return, width_return, height_return,
1219 &scr);
1220 if (rc == 0)
1221 {
1222 return 0;
1223 }
1224 switch (scr)
1225 {
1226 case FSCREEN_GLOBAL:
1227 scr = 0;
1228 break;
1229 case FSCREEN_CURRENT:
1230 GetMouseXY(NULL, &mx, &my);
1231 scr = FindScreenOfXY(mx, my);
1232 break;
1233 case FSCREEN_PRIMARY:
1234 scr = FScreenGetPrimaryScreen(NULL);
1235 break;
1236 default:
1237 scr++;
1238 break;
1239 }
1240 if (scr <= 0 || scr > last_to_check)
1241 {
1242 scr = 0;
1243 }
1244 else
1245 {
1246 /* adapt geometry to selected screen */
1247 if (rc & XValue)
1248 {
1249 if (rc & XNegative)
1250 {
1251 *x_return -=
1252 (screens[0].width -
1253 screens[scr].width -
1254 screens[scr].x_org);
1255 }
1256 else
1257 {
1258 *x_return += screens[scr].x_org;
1259 }
1260 }
1261 if (rc & YValue)
1262 {
1263 if (rc & YNegative)
1264 {
1265 *y_return -=
1266 (screens[0].height -
1267 screens[scr].height -
1268 screens[scr].y_org);
1269 }
1270 else
1271 {
1272 *y_return += screens[scr].y_org;
1273 }
1274 }
1275 }
1276
1277 return rc;
1278 }
1279
1280
1281 /* FScreenGetGeometry
1282 * Parses the geometry in a form: XGeometry[@screen], i.e.
1283 * [=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>][@<screen>]
1284 * where <screen> is either a number or "G" (global) "C" (current)
1285 * or "P" (primary)
1286 *
1287 * Args:
1288 * parsestring, x_r, y_r, w_r, h_r the same as in XParseGeometry
1289 * hints window hints structure, may be NULL
1290 * flags bitmask of allowed flags (XValue, WidthValue, XNegative...)
1291 *
1292 * Note1:
1293 * hints->width and hints->height will be used to calc negative geometry
1294 * if width/height isn't specified in the geometry itself.
1295 *
1296 * Note2:
1297 * This function's behaviour is crafted to sutisfy/emulate the
1298 * FvwmWinList::MakeMeWindow()'s behaviour.
1299 *
1300 * Note3:
1301 * A special value of `flags' when [XY]Value are there but [XY]Negative
1302 * aren't, means that in case of negative geometry specification
1303 * x_r/y_r values will be promoted to the screen border, but w/h
1304 * wouldn't be subtracted, so that the program can do x-=w later
1305 * ([XY]Negative *will* be returned, albeit absent in `flags').
1306 * This option is supposed for proggies like FvwmButtons, which
1307 * receive geometry specification long before they are able to actually
1308 * use it (and which calculate w/h themselves).
1309 * (The same effect can't be obtained with omitting {Width,Height}Value
1310 * in the flags, since the app may wish to get the dimensions but apply
1311 * some constraints later (as FvwmButtons do, BTW...).)
1312 * This option can be also useful in cases where dimensions are
1313 * specified not in pixels but in some other units (e.g., charcells).
1314 */
FScreenGetGeometry(char * parsestring,int * x_return,int * y_return,int * width_return,int * height_return,XSizeHints * hints,int flags)1315 int FScreenGetGeometry(
1316 char *parsestring, int *x_return, int *y_return,
1317 int *width_return, int *height_return, XSizeHints *hints, int flags)
1318 {
1319 int ret;
1320 int saved;
1321 int x, y;
1322 unsigned int w = 0, h = 0;
1323 int grav, x_grav, y_grav;
1324 int scr = default_geometry_scr;
1325 int scr_x, scr_y;
1326 int scr_w, scr_h;
1327
1328 /* I. Do the parsing and strip off extra bits */
1329 ret = FScreenParseGeometryWithScreen(parsestring, &x, &y, &w, &h, &scr);
1330 saved = ret & (XNegative | YNegative);
1331 ret &= flags;
1332
1333 /* II. Get the screen rectangle */
1334 switch (scr)
1335 {
1336 case FSCREEN_GLOBAL:
1337 case FSCREEN_CURRENT:
1338 case FSCREEN_PRIMARY:
1339 case FSCREEN_XYPOS:
1340 FScreenGetScrRect(NULL, scr, &scr_x, &scr_y, &scr_w, &scr_h);
1341 break;
1342
1343 default:
1344 scr++;
1345 if (scr < first_to_check || scr > last_to_check)
1346 scr = first_to_check;
1347 scr_x = screens[scr].x_org;
1348 scr_y = screens[scr].y_org;
1349 scr_w = screens[scr].width;
1350 scr_h = screens[scr].height;
1351 }
1352
1353 /* III. Interpret and fill in the values */
1354
1355 /* Fill in dimensions for future negative calculations if
1356 * omitted/forbidden */
1357 /* Maybe should use *x_return,*y_return if hints==NULL?
1358 * Unreliable... */
1359 if (hints != NULL && hints->flags & PSize)
1360 {
1361 if ((ret & WidthValue) == 0)
1362 {
1363 w = hints->width;
1364 }
1365 if ((ret & HeightValue) == 0)
1366 {
1367 h = hints->height;
1368 }
1369 }
1370 else
1371 {
1372 /* This branch is required for case when size *is* specified,
1373 * but masked off */
1374 if ((ret & WidthValue) == 0)
1375 {
1376 w = 0;
1377 }
1378 if ((ret & HeightValue) == 0)
1379 {
1380 h = 0;
1381 }
1382 }
1383
1384 /* Advance coords to the screen... */
1385 x += scr_x;
1386 y += scr_y;
1387
1388 /* ...and process negative geometries */
1389 if (saved & XNegative)
1390 {
1391 x += scr_w;
1392 }
1393 if (saved & YNegative)
1394 {
1395 y += scr_h;
1396 }
1397 if (ret & XNegative)
1398 {
1399 x -= w;
1400 }
1401 if (ret & YNegative)
1402 {
1403 y -= h;
1404 }
1405
1406 /* Restore negative bits */
1407 ret |= saved;
1408
1409 /* Guess orientation */
1410 x_grav = (ret & XNegative)? GRAV_NEG : GRAV_POS;
1411 y_grav = (ret & YNegative)? GRAV_NEG : GRAV_POS;
1412 grav = grav_matrix[y_grav][x_grav];
1413
1414 /* Return the values */
1415 if (ret & XValue)
1416 {
1417 *x_return = x;
1418 if (hints != NULL)
1419 {
1420 hints->x = x;
1421 }
1422 }
1423 if (ret & YValue)
1424 {
1425 *y_return = y;
1426 if (hints != NULL)
1427 {
1428 hints->y = y;
1429 }
1430 }
1431 if (ret & WidthValue)
1432 {
1433 *width_return = w;
1434 if (hints != NULL)
1435 {
1436 hints->width = w;
1437 }
1438 }
1439 if (ret & HeightValue)
1440 {
1441 *height_return = h;
1442 if (hints != NULL)
1443 {
1444 hints->height = h;
1445 }
1446 }
1447 if (1 /*flags & GravityValue*/ && grav != DEFAULT_GRAVITY)
1448 {
1449 if (hints != NULL && hints->flags & PWinGravity)
1450 {
1451 hints->win_gravity = grav;
1452 }
1453 }
1454 if (hints != NULL && ret & XValue && ret & YValue)
1455 hints->flags |= USPosition;
1456
1457 return ret;
1458 }
1459
1460 /* FScreenMangleScreenIntoUSPosHints
1461 * A hack to mangle the screen number into the XSizeHints structure.
1462 * If the USPosition flag is set, hints->x is set to the magic number and
1463 * hints->y is set to the screen number. If the USPosition flag is clear,
1464 * x and y are set to zero.
1465 *
1466 * Note: This is a *hack* to allow modules to specify the target screen for
1467 * their windows and have the StartsOnScreen style set for them at the same
1468 * time. Do *not* rely on the mechanism described above.
1469 */
FScreenMangleScreenIntoUSPosHints(fscreen_scr_t screen,XSizeHints * hints)1470 void FScreenMangleScreenIntoUSPosHints(fscreen_scr_t screen, XSizeHints *hints)
1471 {
1472 if (hints->flags & USPosition)
1473 {
1474 hints->x = FSCREEN_MANGLE_USPOS_HINTS_MAGIC;
1475 hints->y = (short)screen;
1476 }
1477 else
1478 {
1479 hints->x = 0;
1480 hints->y = 0;
1481 }
1482
1483 return;
1484 }
1485
1486 /* FScreenMangleScreenIntoUSPosHints
1487 * A hack to mangle the screen number into the XSizeHints structure.
1488 * If the USPosition flag is set, hints->x is set to the magic number and
1489 * hints->y is set to the screen spec. If the USPosition flag is clear,
1490 * x and y are set to zero.
1491 *
1492 * Note: This is a *hack* to allow modules to specify the target screen for
1493 * their windows and have the StartsOnScreen style set for them at the same
1494 * time. Do *not* rely on the mechanism described above.
1495 */
FScreenFetchMangledScreenFromUSPosHints(XSizeHints * hints)1496 fscreen_scr_t FScreenFetchMangledScreenFromUSPosHints(XSizeHints *hints)
1497 {
1498 fscreen_scr_t screen;
1499
1500 if ((hints->flags & USPosition) &&
1501 hints->x == FSCREEN_MANGLE_USPOS_HINTS_MAGIC)
1502 {
1503 screen = (fscreen_scr_t)(hints->y);
1504 }
1505 else
1506 {
1507 screen = FSCREEN_GLOBAL;
1508 }
1509
1510 return screen;
1511 }
1512
1513
1514 /* no rand_r for now */
1515 # if 0
1516 int FScreenGetRandrEventType(void)
1517 {
1518 #ifdef HAVE_RANDR
1519 return randr_active? randr_event_base + RRScreenChangeNotify : 0;
1520 #else
1521 return 0;
1522 #endif
1523 }
1524
1525 Bool FScreenHandleRandrEvent(
1526 XEvent *event, int *old_w, int *old_h, int *new_w, int *new_h)
1527 {
1528 #ifndef HAVE_RANDR
1529 return 0;
1530 #else
1531 XRRScreenChangeNotifyEvent *ev = (XRRScreenChangeNotifyEvent *)event;
1532 int nw, nh, tmp;
1533
1534 if (!randr_active ||
1535 event->type != randr_event_base + RRScreenChangeNotify)
1536 {
1537 return 0;
1538 }
1539
1540 nw = ev->width;
1541 nh = ev->height;
1542
1543 /*
1544 * Note1: this check is not very good, since the right way is to
1545 * obtain a list of possible rotations and ...
1546 *
1547 * Note2: as to WM's point of view, I'm unsure if rotation should be
1548 * treated exactly as resizing (i.e. that it should reposition
1549 * windows in the same fashion).
1550 */
1551 if (ev->rotation & (1<<1 | 1<<3))
1552 {
1553 tmp = nw;
1554 nw = nh;
1555 nh = tmp;
1556 }
1557
1558 *old_w = screens[0].width;
1559 *old_h = screens[0].height;
1560
1561 screens[0].width = nw;
1562 *new_w = nw;
1563 screens[0].height = nh;
1564 *new_h = nh;
1565
1566 return (nw != *old_w || nh != *old_h);
1567 #endif
1568 }
1569 #endif
1570