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.
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.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Xinerama abstraction support for window manager.
21 * This module is all original code
22 * by Dmitry Yu. Bolkhovityanov <bolkhov@inp.nsk.su>
23 * Copyright 2001, Dmitry Bolkhovityanov
24 * You may use this code for any purpose, as long as the original
25 * copyright remains in the source code and all documentation
29 * Brief description of used concept:
31 * This code is always used by client, regardless of if Xinerama is
32 * available or not (either because -lXinerama was missing or
33 * because Xinerama extension is missing on display).
35 * If Xinerama is available, this module maintains a list of screens,
36 * from [1] to [num_screens]. screens[0] is always the "global" screen,
37 * so if Xinerama is unavailable or disabled, the module performs
38 * all checks on screens[0] instead of screens[1..num_screens].
40 * The client should first call the FScreenInit(), passing
41 * it the opened display descriptor. During this call the list of
42 * Xinerama screens is retrieved and 'dpy' is saved for future
45 * If the client wishes to hard-disable Xinerama support (e.g. if
46 * Xinerama extension is present but is broken on display), it should
47 * call FScreenDisable() *before* FScreenInit().
49 * Using real Xinerama screens info may be switched on/off "on the
50 * fly" by calling FScreenSetState(0=off/else=on).
52 * Modules with Xinerama support should listen to the XineramaEnable
53 * and XineramaDisable strings coming over the module pipe as
54 * M_CONFIG_INFO packets and call FScreenEnable() or
55 * FScreenDisable in response.
68 #include "PictureBase.h"
71 # undef FSCREEN_NEED_SCREENINFO
72 # define FScreenHaveXinerama 1
73 # ifdef HAVE_SOLARIS_XINERAMA
74 # define FScreenHaveSolarisXinerama 1
75 # ifdef HAVE_SOLARIS_XINERAMA_H
76 # include <X11/extensions/xinerama.h>
78 # define FSCREEN_NEED_SOLARIS_PROTOTYPES
80 # define FSCREEN_NEED_SCREENINFO
82 # define FScreenHaveSolarisXinerama 0
83 # include <X11/extensions/Xinerama.h>
86 # define FSCREEN_NEED_SCREENINFO
87 # define FScreenHaveXinerama 0
88 # define FScreenHaveSolarisXinerama 0
91 #ifdef FSCREEN_NEED_SCREENINFO
98 unsigned short height
;
102 #ifdef FSCREEN_NEED_SOLARIS_PROTOTYPES
103 /* Copied from Solaris 9's X11/extensions/xinerama.h */
104 Bool
XineramaGetState(Display
*, int);
105 Status
XineramaGetInfo(Display
*, int, XRectangle
*, unsigned char*, int*);
106 Status
XineramaGetCenterHint(Display
*, int, int*, int*);
109 #if FScreenHaveSolarisXinerama == 0
110 #define XineramaGetInfo(a,b,c,d,e) 0
113 #if FScreenHaveXinerama
114 # if FScreenHaveSolarisXinerama
115 # define XineramaQueryExtension(d,b,c) 1 /* Lie, for now */
116 # define XineramaIsActive(d) XineramaGetState((d),0)
117 # define XineramaQueryScreens(d,s) (*(s)) = 0, NULL
120 # define XineramaQueryExtension(da, b, c) 0
121 # define XineramaIsActive(a) 0
122 # define XineramaQueryScreens(d,s) (*(s)) = 0, NULL
125 #ifndef MAXFRAMEBUFFERS
126 #define MAXFRAMEBUFFERS 16
130 #ifdef USE_XINERAMA_EMULATION
131 #define FScreenXineramaEmulation 1
133 #define FScreenXineramaEmulation 0
138 #include <X11/Xproto.h>
139 #include <X11/extensions/Xrandr.h>
145 /* Replace with FSCREEN_GLOBAL to restore default behaviour */
146 DEFAULT_GEOMETRY_SCREEN
= FSCREEN_PRIMARY
149 /* In fact, only corners matter -- there will never be GRAV_NONE */
150 enum {GRAV_POS
= 0, GRAV_NONE
= 1, GRAV_NEG
= 2};
151 static int grav_matrix
[3][3] =
153 { NorthWestGravity
, NorthGravity
, NorthEastGravity
},
154 { WestGravity
, CenterGravity
, EastGravity
},
155 { SouthWestGravity
, SouthGravity
, SouthEastGravity
}
157 #define DEFAULT_GRAVITY NorthWestGravity
160 static Display
*disp
= NULL
;
161 static Bool is_xinerama_enabled
= DEFAULT_XINERAMA_ENABLED
;
162 static Bool is_sls_enabled
= False
;
163 static Bool have_sls_screen_list
= False
;
164 static XineramaScreenInfo
*screens
;
165 static XineramaScreenInfo
*screens_xi
;
166 static XineramaScreenInfo
*screens_sls
= NULL
;
167 /* # of Xinerama screens, *not* counting the global, 0 if disabled */
168 static int num_screens
= 0;
169 /* # of Xinerama screens, *not* counting the global */
170 static int total_screens
= 0;
171 static int total_screens_xi
= 0;
172 static int total_screens_sls
= 1;
173 static int total_sls_width
= 1;
174 static int total_sls_height
= 1;
175 static int first_to_check
= 0;
176 static int last_to_check
= 0;
177 static int default_geometry_scr
= FSCREEN_PRIMARY
;
178 /* only to be accessed vie the set/get functions! */
179 static int primary_scr
= DEFAULT_PRIMARY_SCREEN
;
183 static Bool randr_disabled
= 0;
184 static Bool randr_active
= 0;
185 static int randr_event_base
= -1;
186 static int randr_error_base
= -1;
190 static Window blank_w
, vert_w
, blank2_w
, blank3_w
;
192 static int FScreenParseScreenBit(char *arg
, char default_screen
);
193 static int FindScreenOfXY(int x
, int y
);
195 static XineramaScreenInfo
*
196 solaris_XineramaQueryScreens(Display
*d
, int *nscreens
)
198 if (FScreenHaveSolarisXinerama
)
200 XineramaScreenInfo
*screens
= NULL
;
201 XRectangle monitors
[MAXFRAMEBUFFERS
];
202 unsigned char hints
[16];
205 /* dummy instructions to keep -Wall happy */
207 result
= XineramaGetInfo(
208 d
, DefaultScreen(d
), monitors
, hints
, nscreens
);
213 /* Note, malloced area later freed by XFree() */
214 screens
= (XineramaScreenInfo
*)malloc(
215 sizeof(XineramaScreenInfo
) * (*nscreens
));
216 for (m
= 0; m
< *nscreens
; ++m
)
218 screens
[m
].screen_number
= m
;
219 screens
[m
].x_org
= monitors
[m
].x
;
220 screens
[m
].y_org
= monitors
[m
].y
;
221 screens
[m
].width
= monitors
[m
].width
;
222 screens
[m
].height
= monitors
[m
].height
;
229 "Error getting Xinerama information\n");
241 static XineramaScreenInfo
*FXineramaQueryScreens(Display
*d
, int *nscreens
)
243 if (FScreenHaveXinerama
== 0)
249 if (FScreenHaveSolarisXinerama
== 1)
251 return solaris_XineramaQueryScreens(d
, nscreens
);
255 return XineramaQueryScreens(d
, nscreens
);
259 static void GetMouseXY(XEvent
*eventp
, int *x
, int *y
)
261 if (!is_xinerama_enabled
|| last_to_check
== first_to_check
)
263 /* We use .x_org,.y_org because nothing prevents a screen to be
265 *x
= screens
[first_to_check
].x_org
;
266 *y
= screens
[first_to_check
].y_org
;
277 fev_get_evpos_or_query(
278 disp
, DefaultRootWindow(disp
), eventp
, x
, y
);
284 Bool
FScreenIsEnabled(void)
286 return (!is_xinerama_enabled
|| num_screens
== 0) ? False
: True
;
289 Bool
FScreenIsSLSEnabled(void)
291 return is_sls_enabled
;
294 static void FScreenUpdateEmulationMapState(void)
296 static Bool is_mapped
= False
;
298 if (!FScreenXineramaEmulation
)
303 if (is_xinerama_enabled
&& !is_sls_enabled
)
307 XMapRaised(disp
, blank_w
);
308 XMapRaised(disp
, blank2_w
);
309 XMapRaised(disp
, blank3_w
);
310 XMapRaised(disp
, vert_w
);
318 XUnmapWindow(disp
, blank_w
);
319 XUnmapWindow(disp
, blank2_w
);
320 XUnmapWindow(disp
, blank3_w
);
321 XUnmapWindow(disp
, vert_w
);
327 static void FScreenSetState(Bool do_enable
)
329 is_xinerama_enabled
= do_enable
;
330 if (do_enable
&& total_screens
> 0)
332 num_screens
= total_screens
;
334 last_to_check
= total_screens
;
342 FScreenUpdateEmulationMapState();
346 void FScreenInit(Display
*dpy
)
348 static Bool is_initialised
= False
;
356 is_initialised
= True
;
358 if (FScreenXineramaEmulation
)
366 XSetWindowAttributes attributes
;
368 scr
= DefaultScreen(disp
);
369 root
= RootWindow(disp
, scr
);
371 /* xinerama emulation simulates xinerama on a single screen:
374 * +---------------------+--------------+
380 * | simulated screen 1 | |
385 * +---------------------+ |
388 * +---------------------+--------------+
391 total_screens_xi
= count
;
392 screens_xi
= (XineramaScreenInfo
*)
393 safemalloc(sizeof(XineramaScreenInfo
) * (1 + count
));
394 /* calculate the faked sub screen dimensions */
395 w
= DisplayWidth(disp
, scr
);
397 h
= DisplayHeight(disp
, scr
);
398 screens_xi
[1].screen_number
= 0;
399 screens_xi
[1].x_org
= 0;
400 screens_xi
[1].y_org
= h
/ 16;
401 screens_xi
[1].width
= ws
;
402 screens_xi
[1].height
= 7 * h
/ 8;
403 screens_xi
[2].screen_number
= 1;
404 screens_xi
[2].x_org
= ws
;
405 screens_xi
[2].y_org
= 0;
406 screens_xi
[2].width
= w
- ws
;
407 screens_xi
[2].height
= 7 * h
/ 8;
409 attributes
.background_pixel
= PictureWhitePixel();
410 attributes
.override_redirect
= True
;
411 blank_w
= XCreateWindow(
412 disp
, root
, 0, screens_xi
[1].y_org
- 1,
413 screens_xi
[1].width
, 2, 0, CopyFromParent
,
414 CopyFromParent
, CopyFromParent
,
415 CWBackPixel
|CWOverrideRedirect
, &attributes
);
416 blank2_w
= XCreateWindow(
418 screens_xi
[1].y_org
+ screens_xi
[1].height
- 1,
419 screens_xi
[1].width
, 2, 0, CopyFromParent
,
420 CopyFromParent
, CopyFromParent
,
421 CWBackPixel
|CWOverrideRedirect
, &attributes
);
422 blank3_w
= XCreateWindow(
423 disp
, root
, screens_xi
[2].x_org
,
424 screens_xi
[2].height
- 1, w
- screens_xi
[2].x_org
, 2,
425 0, CopyFromParent
, CopyFromParent
, CopyFromParent
,
426 CWBackPixel
|CWOverrideRedirect
, &attributes
);
427 vert_w
= XCreateWindow(
428 disp
, root
, screens_xi
[2].x_org
- 1, 0, 2, h
, 0,
429 CopyFromParent
, CopyFromParent
, CopyFromParent
,
430 CWBackPixel
|CWOverrideRedirect
, &attributes
);
432 else if (FScreenHaveXinerama
&&
433 XineramaQueryExtension(disp
, &dummy_rc
, &dummy_rc
) &&
434 XineramaIsActive(disp
))
437 XineramaScreenInfo
*info
;
439 info
= FXineramaQueryScreens(disp
, &count
);
440 total_screens_xi
= count
;
441 screens_xi
= (XineramaScreenInfo
*)
442 safemalloc(sizeof(XineramaScreenInfo
) *
444 memcpy(screens_xi
+ 1, info
,
445 sizeof(XineramaScreenInfo
) * count
);
450 total_screens_xi
= 0;
452 (XineramaScreenInfo
*)safemalloc(
453 sizeof(XineramaScreenInfo
)*1);
455 total_screens
= total_screens_xi
;
456 screens
= screens_xi
;
458 /* Now, fill screens[0] with global screen parameters */
459 screens_xi
[0].screen_number
= -1;
460 screens_xi
[0].x_org
= 0;
461 screens_xi
[0].y_org
= 0;
462 screens_xi
[0].width
= DisplayWidth (disp
, DefaultScreen(disp
));
463 screens_xi
[0].height
= DisplayHeight(disp
, DefaultScreen(disp
));
465 /* Fill in the screen range */
466 FScreenSetState(is_xinerama_enabled
);
471 void FScreenOnOff(Bool do_enable
)
473 FScreenSetState(do_enable
);
476 void FScreenSLSOnOff(Bool do_enable
)
478 is_sls_enabled
= do_enable
;
481 total_screens
= total_screens_sls
;
484 /* Sls not configured yet, use whole screen by default
486 FScreenConfigureSLSSize(1, 1);
488 screens
= screens_sls
;
492 total_screens
= total_screens_xi
;
493 screens
= screens_xi
;
495 FScreenSetState(is_xinerama_enabled
);
498 Bool
FScreenConfigureSLSSize(int width
, int height
)
500 unsigned long scr
= DefaultScreen(disp
);
501 int w
= DisplayWidth(disp
, scr
);
502 int h
= DisplayHeight(disp
, scr
);
520 if (total_sls_width
== width
&& total_sls_height
== height
&&
530 /* calculate the screens */
536 total_screens_sls
= width
* height
;
537 total_sls_width
= width
;
538 total_sls_height
= height
;
539 ws
= w
/ total_sls_width
;
540 hs
= h
/ total_sls_height
;
541 screens_sls
= (XineramaScreenInfo
*)
542 safemalloc(sizeof(XineramaScreenInfo
) *
543 (1 + total_screens_sls
));
544 /* calculate the faked sub screen dimensions */
545 screens_sls
[0] = screens_xi
[0];
547 for (row
= 0; row
< total_sls_height
; row
++)
549 for (col
= 0; col
< total_sls_width
; col
++, sn
++)
551 screens_sls
[sn
].screen_number
= sn
- 1;
552 screens_sls
[sn
].x_org
= col
* ws
;
553 screens_sls
[sn
].y_org
= row
* hs
;
554 screens_sls
[sn
].width
= ws
;
555 screens_sls
[sn
].height
= hs
;
559 have_sls_screen_list
= False
;
560 FScreenSLSOnOff(is_sls_enabled
);
565 Bool
FScreenConfigureSLSScreens(int nscreens
, char *args
)
570 if (nscreens
== 0 || args
== NULL
)
572 return FScreenConfigureSLSSize(1, 1);
574 if (nscreens
== 1 && screens_sls
)
583 screens_sls
= (XineramaScreenInfo
*)
584 safemalloc(sizeof(XineramaScreenInfo
) * (nscreens
+ 1));
585 screens_sls
[0] = screens_xi
[0];
586 for (sn
= 1; sn
<= nscreens
; sn
++, args
= next
)
591 /* read next screen spec */
592 token
= PeekToken(args
, &next
);
597 if (XParseGeometry(token
, &val
[0], &val
[1],
598 (unsigned int *)&val
[2],
599 (unsigned int *)&val
[3]) ==
600 (XValue
|YValue
|WidthValue
|HeightValue
) ||
601 GetIntegerArguments(args
, &next
, val
, 4) == 4)
603 if (val
[0] < 0 || val
[1] < 0 || val
[2] < 1 ||
609 screens_sls
[sn
].screen_number
= sn
- 1;
610 screens_sls
[sn
].x_org
= val
[0];
611 screens_sls
[sn
].y_org
= val
[1];
612 screens_sls
[sn
].width
= val
[2];
613 screens_sls
[sn
].height
= val
[3];
621 total_screens_sls
= sn
- 1;
622 have_sls_screen_list
= True
;
623 FScreenSLSOnOff(is_sls_enabled
);
629 void FScreenDisableRandR(void)
633 fprintf(stderr
, "FScreen: WARNING: FScreenDisableRandR()"
634 " called after FScreenInit()!\n");
642 static int FScreenGetPrimaryScreen(XEvent
*ev
)
644 if (!is_xinerama_enabled
)
648 if (primary_scr
== FSCREEN_GLOBAL
)
652 else if (primary_scr
== FSCREEN_CURRENT
)
657 /* use current screen as primary screen */
658 GetMouseXY(ev
, &mx
, &my
);
659 return FindScreenOfXY(mx
, my
);
661 else if (primary_scr
< 0 || primary_scr
>= last_to_check
)
667 return primary_scr
+ 1;
670 void FScreenSetPrimaryScreen(int scr
)
675 /* Intended to be called by modules. Simply pass in the parameter from the
676 * config string sent by fvwm. */
677 void FScreenConfigureModule(char *args
)
683 n
= GetIntegerArguments(args
, &next
, val
, 4);
686 /* ignore broken line */
689 FScreenSetPrimaryScreen(val
[1]);
693 /* SLS screen coordinates follow */
694 n
= GetIntegerArguments(next
, &next
, val
+ 4, 1);
697 /* ignore broken line */
700 FScreenConfigureSLSScreens(val
[4], next
);
704 /* simple SLS line */
705 n
= GetIntegerArguments(next
, NULL
, val
+ 4, 2);
708 /* ignore broken line */
711 FScreenConfigureSLSSize(val
[4], val
[5]);
714 FScreenSLSOnOff(val
[2]);
715 FScreenOnOff(val
[0]);
720 /* Here's the function used by fvwm to generate the string which
721 * FScreenConfigureModule expects to receive back as its argument.
723 const char *FScreenGetConfiguration(void)
728 static char msg
[MAX_MODULE_INPUT_TEXT_LEN
];
732 msg
, XINERAMA_CONFIG_STRING
" %d %d %d %d",
733 FScreenIsEnabled(), primary_scr
,
734 FScreenIsSLSEnabled(), have_sls_screen_list
);
736 if (have_sls_screen_list
)
738 sprintf(msg
+ l
, " %d", total_screens_sls
);
739 for (i
= 0; i
< total_screens_sls
; i
++)
741 sprintf(buf
, " %d %d %d %d", screens_sls
[i
].x_org
,
742 screens_sls
[i
].y_org
, screens_sls
[i
].width
,
743 screens_sls
[i
].height
);
745 if (l
+ l2
> MAX_MODULE_INPUT_TEXT_LEN
)
749 strcat(msg
+ l
, buf
);
755 sprintf(msg
+ l
, " %d %d", total_sls_width
, total_sls_height
);
761 /* Sets the default screen for ...ParseGeometry if no screen spec is given.
762 * Usually this is FSCREEN_SPEC_PRIMARY, but this won't allow modules to appear
763 * under the pointer. */
764 void FScreenSetDefaultModuleScreen(char *scr_spec
)
766 default_geometry_scr
=
767 FScreenParseScreenBit(scr_spec
, FSCREEN_SPEC_PRIMARY
);
773 static int FindScreenOfXY(int x
, int y
)
777 x
= x
% screens_xi
[0].width
;
780 x
+= screens_xi
[0].width
;
782 y
= y
% screens_xi
[0].height
;
785 y
+= screens_xi
[0].height
;
787 for (i
= first_to_check
; i
<= last_to_check
; i
++)
789 if (x
>= screens
[i
].x_org
&&
790 x
< screens
[i
].x_org
+ screens
[i
].width
&&
791 y
>= screens
[i
].y_org
&&
792 y
< screens
[i
].y_org
+ screens
[i
].height
)
798 /* Ouch! A "black hole" coords? As for now, return global screen */
802 static int FindScreen(
803 fscreen_scr_arg
*arg
, fscreen_scr_t screen
)
807 if (num_screens
== 0)
809 screen
= FSCREEN_GLOBAL
;
816 case FSCREEN_PRIMARY
:
818 FScreenGetPrimaryScreen(
819 (arg
&& arg
->mouse_ev
) ? arg
->mouse_ev
: NULL
);
821 case FSCREEN_CURRENT
:
822 /* translate to xypos format */
828 GetMouseXY(arg
->mouse_ev
, &arg
->xypos
.x
, &arg
->xypos
.y
);
831 /* translate to screen number */
838 screen
= FindScreenOfXY(arg
->xypos
.x
, arg
->xypos
.y
);
841 /* screen is given counting from 0; translate to counting from
850 /* Returns the specified screens geometry rectangle. screen can be a screen
851 * number or any of the values FSCREEN_GLOBAL, FSCREEN_CURRENT,
852 * FSCREEN_PRIMARY or FSCREEN_XYPOS. The arg union only has a meaning for
853 * FSCREEN_CURRENT and FSCREEN_XYARG. For FSCREEN_CURRENT its mouse_ev member
854 * may be given. It is tried to find out the pointer position from the event
855 * first before querying the pointer. For FSCREEN_XYPOS the xpos member is used
856 * to fetch the x/y position of the point on the screen. If arg is NULL, the
857 * position 0 0 is assumed instead.
859 * Any of the arguments arg, x, y, w and h may be NULL.
861 * FSCREEN_GLOBAL: return the global screen dimensions
862 * FSCREEN_CURRENT: return dimensions of the screen with the pointer
863 * FSCREEN_PRIMARY: return the primary screen dimensions
864 * FSCREEN_XYPOS: return dimensions of the screen with the given coordinates
866 * The function returns False if the global screen was returned and more than
867 * one screen is configured. Otherwise it returns True.
869 Bool
FScreenGetScrRect(
870 fscreen_scr_arg
*arg
, fscreen_scr_t screen
, int *x
, int *y
,
873 screen
= FindScreen(arg
, screen
);
874 if (screen
< first_to_check
|| screen
> last_to_check
)
880 *x
= screens
[screen
].x_org
;
884 *y
= screens
[screen
].y_org
;
888 *w
= screens
[screen
].width
;
892 *h
= screens
[screen
].height
;
895 return !(screen
== 0 && num_screens
> 1);
898 /* returns the screen id */
899 Bool
FScreenGetScrId(
900 fscreen_scr_arg
*arg
, fscreen_scr_t screen
)
902 screen
= FindScreen(arg
, screen
);
905 screen
= FSCREEN_GLOBAL
;
911 /* Translates the coodinates *x *y from the screen specified by arg_src and
912 * screen_src to coordinates on the screen specified by arg_dest and
913 * screen_dest. (see FScreenGetScrRect for more details). */
914 void FScreenTranslateCoordinates(
915 fscreen_scr_arg
*arg_src
, fscreen_scr_t screen_src
,
916 fscreen_scr_arg
*arg_dest
, fscreen_scr_t screen_dest
,
924 FScreenGetScrRect(arg_src
, screen_src
, &x_src
, &y_src
, NULL
, NULL
);
925 FScreenGetScrRect(arg_dest
, screen_dest
, &x_dest
, &y_dest
, NULL
, NULL
);
929 *x
= *x
+ x_src
- x_dest
;
933 *y
= *y
+ y_src
- y_dest
;
939 /* Arguments work exactly like for FScreenGetScrRect() */
940 int FScreenClipToScreen(
941 fscreen_scr_arg
*arg
, fscreen_scr_t screen
, int *x
, int *y
, int w
,
948 int lx
= (x
) ? *x
: 0;
949 int ly
= (y
) ? *y
: 0;
950 int x_grav
= GRAV_POS
;
951 int y_grav
= GRAV_POS
;
953 FScreenGetScrRect(arg
, screen
, &sx
, &sy
, &sw
, &sh
);
954 if (lx
+ w
> sx
+ sw
)
959 if (ly
+ h
> sy
+ sh
)
983 return grav_matrix
[y_grav
][x_grav
];
986 /* Arguments work exactly like for FScreenGetScrRect() */
987 void FScreenCenterOnScreen(
988 fscreen_scr_arg
*arg
, fscreen_scr_t screen
, int *x
, int *y
, int w
,
998 FScreenGetScrRect(arg
, screen
, &sx
, &sy
, &sw
, &sh
);
1019 void FScreenGetResistanceRect(
1020 int wx
, int wy
, unsigned int ww
, unsigned int wh
, int *x0
, int *y0
,
1023 fscreen_scr_arg arg
;
1025 arg
.xypos
.x
= wx
+ ww
/ 2;
1026 arg
.xypos
.y
= wy
+ wh
/ 2;
1027 FScreenGetScrRect(&arg
, FSCREEN_XYPOS
, x0
, y0
, x1
, y1
);
1034 /* Arguments work exactly like for FScreenGetScrRect() */
1035 Bool
FScreenIsRectangleOnScreen(
1036 fscreen_scr_arg
*arg
, fscreen_scr_t screen
, rectangle
*rec
)
1043 FScreenGetScrRect(arg
, screen
, &sx
, &sy
, &sw
, &sh
);
1045 return (rec
->x
+ rec
->width
> sx
&& rec
->x
< sx
+ sw
&&
1046 rec
->y
+ rec
->height
> sy
&& rec
->y
< sy
+ sh
) ? True
: False
;
1049 void FScreenSpecToString(char *dest
, int space
, fscreen_scr_t screen
)
1059 case FSCREEN_GLOBAL
:
1060 strcpy(s
, "global screen");
1062 case FSCREEN_CURRENT
:
1063 strcpy(s
, "current screen");
1065 case FSCREEN_PRIMARY
:
1066 strcpy(s
, "primary screen");
1069 strcpy(s
, "screen specified by xy");
1072 sprintf(s
, "%d", screen
);
1075 strncpy(dest
, s
, space
);
1076 dest
[space
- 1] = 0;
1081 static int FScreenParseScreenBit(char *scr_spec
, char default_screen
)
1083 int scr
= default_geometry_scr
;
1086 c
= (scr_spec
) ? tolower(*scr_spec
) : tolower(default_screen
);
1087 if (c
== FSCREEN_SPEC_GLOBAL
)
1089 scr
= FSCREEN_GLOBAL
;
1091 else if (c
== FSCREEN_SPEC_CURRENT
)
1093 scr
= FSCREEN_CURRENT
;
1095 else if (c
== FSCREEN_SPEC_PRIMARY
)
1097 scr
= FSCREEN_PRIMARY
;
1099 else if (c
== FSCREEN_SPEC_WINDOW
)
1101 scr
= FSCREEN_XYPOS
;
1103 else if (isdigit(c
))
1105 scr
= atoi(scr_spec
);
1109 c
= tolower(default_screen
);
1110 if (c
== FSCREEN_SPEC_GLOBAL
)
1112 scr
= FSCREEN_GLOBAL
;
1114 else if (c
== FSCREEN_SPEC_CURRENT
)
1116 scr
= FSCREEN_CURRENT
;
1118 else if (c
== FSCREEN_SPEC_PRIMARY
)
1120 scr
= FSCREEN_PRIMARY
;
1122 else if (c
== FSCREEN_SPEC_WINDOW
)
1124 scr
= FSCREEN_XYPOS
;
1126 else if (isdigit(c
))
1128 scr
= atoi(scr_spec
);
1135 int FScreenGetScreenArgument(char *scr_spec
, fscreen_scr_spec_t default_screen
)
1137 while (scr_spec
&& isspace(*scr_spec
))
1142 return FScreenParseScreenBit(scr_spec
, default_screen
);
1146 * FScreenParseGeometry
1147 * Does the same as XParseGeometry, but handles additional "@scr".
1148 * Since it isn't safe to define "ScreenValue" constant (actual values
1149 * of other "XXXValue" are specified in Xutil.h, not by us, so there can
1150 * be a clash), the screen value is always returned, even if it wasn't
1151 * present in `parse_string' (set to default in that case).
1154 int FScreenParseGeometryWithScreen(
1155 char *parsestring
, int *x_return
, int *y_return
,
1156 unsigned int *width_return
, unsigned int *height_return
,
1165 if (parsestring
== NULL
|| *parsestring
== '\0')
1170 /* Make a local copy devoid of "@scr" */
1171 s_size
= strlen(parsestring
) + 1;
1172 copy
= safemalloc(s_size
);
1173 memcpy(copy
, parsestring
, s_size
);
1174 scr_p
= strchr(copy
, '@');
1180 /* Do the parsing */
1181 ret
= XParseGeometry(
1182 copy
, x_return
, y_return
, width_return
, height_return
);
1184 /* Parse the "@scr", if any */
1185 scr
= FScreenParseScreenBit(scr_p
, FSCREEN_SPEC_PRIMARY
);
1186 *screen_return
= scr
;
1188 /* We don't need the string any more */
1194 /* Same as above, but dump screen return value to keep compatible with the X
1196 int FScreenParseGeometry(
1197 char *parsestring
, int *x_return
, int *y_return
,
1198 unsigned int *width_return
, unsigned int *height_return
)
1205 rc
= FScreenParseGeometryWithScreen(
1206 parsestring
, x_return
, y_return
, width_return
, height_return
,
1214 case FSCREEN_GLOBAL
:
1217 case FSCREEN_CURRENT
:
1218 GetMouseXY(NULL
, &mx
, &my
);
1219 scr
= FindScreenOfXY(mx
, my
);
1221 case FSCREEN_PRIMARY
:
1222 scr
= FScreenGetPrimaryScreen(NULL
);
1228 if (scr
<= 0 || scr
> last_to_check
)
1234 /* adapt geometry to selected screen */
1241 screens
[scr
].width
-
1242 screens
[scr
].x_org
);
1246 *x_return
+= screens
[scr
].x_org
;
1254 (screens
[0].height
-
1255 screens
[scr
].height
-
1256 screens
[scr
].y_org
);
1260 *y_return
+= screens
[scr
].y_org
;
1269 /* FScreenGetGeometry
1270 * Parses the geometry in a form: XGeometry[@screen], i.e.
1271 * [=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>][@<screen>]
1272 * where <screen> is either a number or "G" (global) "C" (current)
1276 * parsestring, x_r, y_r, w_r, h_r the same as in XParseGeometry
1277 * hints window hints structure, may be NULL
1278 * flags bitmask of allowed flags (XValue, WidthValue, XNegative...)
1281 * hints->width and hints->height will be used to calc negative geometry
1282 * if width/height isn't specified in the geometry itself.
1285 * This function's behaviour is crafted to sutisfy/emulate the
1286 * FvwmWinList::MakeMeWindow()'s behaviour.
1289 * A special value of `flags' when [XY]Value are there but [XY]Negative
1290 * aren't, means that in case of negative geometry specification
1291 * x_r/y_r values will be promoted to the screen border, but w/h
1292 * wouldn't be subtracted, so that the program can do x-=w later
1293 * ([XY]Negative *will* be returned, albeit absent in `flags').
1294 * This option is supposed for proggies like FvwmButtons, which
1295 * receive geometry specification long before they are able to actually
1296 * use it (and which calculate w/h themselves).
1297 * (The same effect can't be obtained with omitting {Width,Height}Value
1298 * in the flags, since the app may wish to get the dimensions but apply
1299 * some constraints later (as FvwmButtons do, BTW...).)
1300 * This option can be also useful in cases where dimensions are
1301 * specified not in pixels but in some other units (e.g., charcells).
1303 int FScreenGetGeometry(
1304 char *parsestring
, int *x_return
, int *y_return
,
1305 int *width_return
, int *height_return
, XSizeHints
*hints
, int flags
)
1310 unsigned int w
= 0, h
= 0;
1311 int grav
, x_grav
, y_grav
;
1312 int scr
= default_geometry_scr
;
1316 /* I. Do the parsing and strip off extra bits */
1317 ret
= FScreenParseGeometryWithScreen(parsestring
, &x
, &y
, &w
, &h
, &scr
);
1318 saved
= ret
& (XNegative
| YNegative
);
1321 /* II. Get the screen rectangle */
1324 case FSCREEN_GLOBAL
:
1325 case FSCREEN_CURRENT
:
1326 case FSCREEN_PRIMARY
:
1328 FScreenGetScrRect(NULL
, scr
, &scr_x
, &scr_y
, &scr_w
, &scr_h
);
1333 if (scr
< first_to_check
|| scr
> last_to_check
)
1334 scr
= first_to_check
;
1335 scr_x
= screens
[scr
].x_org
;
1336 scr_y
= screens
[scr
].y_org
;
1337 scr_w
= screens
[scr
].width
;
1338 scr_h
= screens
[scr
].height
;
1341 /* III. Interpret and fill in the values */
1343 /* Fill in dimensions for future negative calculations if
1344 * omitted/forbidden */
1345 /* Maybe should use *x_return,*y_return if hints==NULL?
1347 if (hints
!= NULL
&& hints
->flags
& PSize
)
1349 if ((ret
& WidthValue
) == 0)
1353 if ((ret
& HeightValue
) == 0)
1360 /* This branch is required for case when size *is* specified,
1362 if ((ret
& WidthValue
) == 0)
1366 if ((ret
& HeightValue
) == 0)
1372 /* Advance coords to the screen... */
1376 /* ...and process negative geometries */
1377 if (saved
& XNegative
)
1381 if (saved
& YNegative
)
1385 if (ret
& XNegative
)
1389 if (ret
& YNegative
)
1394 /* Restore negative bits */
1397 /* Guess orientation */
1398 x_grav
= (ret
& XNegative
)? GRAV_NEG
: GRAV_POS
;
1399 y_grav
= (ret
& YNegative
)? GRAV_NEG
: GRAV_POS
;
1400 grav
= grav_matrix
[y_grav
][x_grav
];
1402 /* Return the values */
1419 if (ret
& WidthValue
)
1427 if (ret
& HeightValue
)
1435 if (1 /*flags & GravityValue*/ && grav
!= DEFAULT_GRAVITY
)
1437 if (hints
!= NULL
&& hints
->flags
& PWinGravity
)
1439 hints
->win_gravity
= grav
;
1442 if (hints
!= NULL
&& ret
& XValue
&& ret
& YValue
)
1443 hints
->flags
|= USPosition
;
1448 /* FScreenMangleScreenIntoUSPosHints
1449 * A hack to mangle the screen number into the XSizeHints structure.
1450 * If the USPosition flag is set, hints->x is set to the magic number and
1451 * hints->y is set to the screen number. If the USPosition flag is clear,
1452 * x and y are set to zero.
1454 * Note: This is a *hack* to allow modules to specify the target screen for
1455 * their windows and have the StartsOnScreen style set for them at the same
1456 * time. Do *not* rely on the mechanism described above.
1458 void FScreenMangleScreenIntoUSPosHints(fscreen_scr_t screen
, XSizeHints
*hints
)
1460 if (hints
->flags
& USPosition
)
1462 hints
->x
= FSCREEN_MANGLE_USPOS_HINTS_MAGIC
;
1463 hints
->y
= (short)screen
;
1474 /* FScreenMangleScreenIntoUSPosHints
1475 * A hack to mangle the screen number into the XSizeHints structure.
1476 * If the USPosition flag is set, hints->x is set to the magic number and
1477 * hints->y is set to the screen spec. If the USPosition flag is clear,
1478 * x and y are set to zero.
1480 * Note: This is a *hack* to allow modules to specify the target screen for
1481 * their windows and have the StartsOnScreen style set for them at the same
1482 * time. Do *not* rely on the mechanism described above.
1484 fscreen_scr_t
FScreenFetchMangledScreenFromUSPosHints(XSizeHints
*hints
)
1486 fscreen_scr_t screen
;
1488 if ((hints
->flags
& USPosition
) &&
1489 hints
->x
== FSCREEN_MANGLE_USPOS_HINTS_MAGIC
)
1491 screen
= (fscreen_scr_t
)(hints
->y
);
1495 screen
= FSCREEN_GLOBAL
;
1502 /* no rand_r for now */
1504 int FScreenGetRandrEventType(void)
1507 return randr_active
? randr_event_base
+ RRScreenChangeNotify
: 0;
1513 Bool
FScreenHandleRandrEvent(
1514 XEvent
*event
, int *old_w
, int *old_h
, int *new_w
, int *new_h
)
1519 XRRScreenChangeNotifyEvent
*ev
= (XRRScreenChangeNotifyEvent
*)event
;
1522 if (!randr_active
||
1523 event
->type
!= randr_event_base
+ RRScreenChangeNotify
)
1532 * Note1: this check is not very good, since the right way is to
1533 * obtain a list of possible rotations and ...
1535 * Note2: as to WM's point of view, I'm unsure if rotation should be
1536 * treated exactly as resizing (i.e. that it should reposition
1537 * windows in the same fashion).
1539 if (ev
->rotation
& (1<<1 | 1<<3))
1546 *old_w
= screens
[0].width
;
1547 *old_h
= screens
[0].height
;
1549 screens
[0].width
= nw
;
1551 screens
[0].height
= nh
;
1554 return (nw
!= *old_w
|| nh
!= *old_h
);