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