3 * Copyright (C) 2004 Ragnar Rova
4 * 2005-2007 Tuomo Valkonen
6 * by Ragnar Rova <rr@mima.x.se>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License,or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not,write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <X11/Xatom.h>
28 #include <X11/Xutil.h>
29 #include <X11/extensions/Xrandr.h>
33 #include <ioncore/common.h>
34 #include <ioncore/eventh.h>
35 #include <ioncore/global.h>
36 #include <ioncore/event.h>
37 #include <ioncore/mplex.h>
38 #include <ioncore/xwindow.h>
39 #include <ioncore/log.h>
40 #include <ioncore/../version.h>
44 char mod_xrandr_ion_api_version
[]=ION_API_VERSION
;
46 WHook
*randr_screen_change_notify
=NULL
;
48 static bool hasXrandR
=FALSE
;
49 static int xrr_event_base
;
50 static int xrr_error_base
;
52 Rb_node rotations
=NULL
;
54 static int rr2scrrot(int rr
)
57 case RR_Rotate_0
: return SCREEN_ROTATION_0
;
58 case RR_Rotate_90
: return SCREEN_ROTATION_90
;
59 case RR_Rotate_180
: return SCREEN_ROTATION_180
;
60 case RR_Rotate_270
: return SCREEN_ROTATION_270
;
61 default: return SCREEN_ROTATION_0
;
66 static void insrot(int id
, int r
)
70 node
=rb_inserti(rotations
, id
, NULL
);
77 bool handle_xrandr_event(XEvent
*ev
)
79 if(hasXrandR
&& ev
->type
== xrr_event_base
+ RRScreenChangeNotify
) {
80 XRRScreenChangeNotifyEvent
*rev
=(XRRScreenChangeNotifyEvent
*)ev
;
84 LOG(DEBUG
, RANDR
, "XRRScreenChangeNotifyEvent size %dx%d (%dx%d mm)",
85 rev
->width
, rev
->height
, rev
->mwidth
, rev
->mheight
);
87 screen
=XWINDOW_REGION_OF_T(rev
->root
, WScreen
);
94 r
=rr2scrrot(rev
->rotation
);
96 fp
.g
.x
=REGION_GEOM(screen
).x
;
97 fp
.g
.y
=REGION_GEOM(screen
).y
;
99 if(rev
->rotation
==RR_Rotate_90
|| rev
->rotation
==RR_Rotate_270
){
107 fp
.mode
=REGION_FIT_EXACT
;
109 node
=rb_find_ikey_n(rotations
, screen
->id
, &found
);
112 insrot(screen
->id
, r
);
113 }else if(r
!=node
->v
.ival
){
116 fp
.mode
|=REGION_FIT_ROTATE
;
118 ? SCREEN_ROTATION_0
+r
-or
119 : (SCREEN_ROTATION_270
+1)+r
-or);
123 REGION_GEOM(screen
)=fp
.g
;
125 mplex_managed_geom((WMPlex
*)screen
, &(fp
.g
));
127 mplex_do_fit_managed((WMPlex
*)screen
, &fp
);
129 hook_call_v(randr_screen_change_notify
);
139 static bool check_pivots()
148 FOR_ALL_SCREENS(scr
){
149 Rotation rot
=RR_Rotate_90
;
150 int randr_screen_id
= XRRRootToScreen(ioncore_g
.dpy
, ((WMPlex
*) scr
)->win
.win
);
151 if (randr_screen_id
!= -1)
152 XRRRotations(ioncore_g
.dpy
, randr_screen_id
, &rot
);
154 insrot(scr
->id
, rr2scrrot(rot
));
160 #define INIT_HOOK_(NM) \
161 NM=mainloop_register_hook(#NM, create_hook()); \
162 if(NM==NULL) return FALSE
164 bool mod_xrandr_init()
167 XRRQueryExtension(ioncore_g
.dpy
,&xrr_event_base
,&xrr_error_base
);
173 XRRSelectInput(ioncore_g
.dpy
,ioncore_g
.rootwins
->dummy_win
,
174 RRScreenChangeNotifyMask
);
176 warn_obj("mod_xrandr","XRandR is not supported on this display");
179 hook_add(ioncore_handle_event_alt
,(WHookDummy
*)handle_xrandr_event
);
181 INIT_HOOK_(randr_screen_change_notify
);
183 return mod_xrandr_register_exports();
187 bool mod_xrandr_deinit()
189 hook_remove(ioncore_handle_event_alt
,
190 (WHookDummy
*)handle_xrandr_event
);
195 void add_output(ExtlTab result
, XRROutputInfo
*output_info
, XRRCrtcInfo
*crtc_info
)
197 ExtlTab details
= extl_create_table();
198 /* TODO we probably have to strdup the outputs' data here, because we free
199 * the XRROutputInfo later on. However, where can we make sure the strings
200 * get freed when the code calling mod_xrandr_get_outputs_for_geom is done
203 extl_table_sets_s(details
, "name", strdup(output_info
->name
));
204 extl_table_sets_i(details
, "x", crtc_info
->x
);
205 extl_table_sets_i(details
, "y", crtc_info
->y
);
206 extl_table_sets_i(details
, "w", (int)crtc_info
->width
);
207 extl_table_sets_i(details
, "h", (int)crtc_info
->height
);
208 extl_table_sets_t(result
, strdup(output_info
->name
), details
);
213 ExtlTab
mod_xrandr_get_all_outputs()
216 XRRScreenResources
*res
= XRRGetScreenResources(ioncore_g
.dpy
, ioncore_g
.rootwins
->dummy_win
);
217 ExtlTab result
= extl_create_table();
219 for(i
=0; i
< res
->noutput
; i
++){
220 XRROutputInfo
*output_info
= XRRGetOutputInfo(ioncore_g
.dpy
, res
, res
->outputs
[i
]);
221 if(output_info
->crtc
!= None
){
222 XRRCrtcInfo
*crtc_info
= XRRGetCrtcInfo(ioncore_g
.dpy
, res
, output_info
->crtc
);
224 add_output(result
, output_info
, crtc_info
);
226 XRRFreeCrtcInfo(crtc_info
);
228 XRRFreeOutputInfo(output_info
);
236 * Queries the RandR extension for outputs with this geometry
238 * Returns a table with the matching RandR window names as keys
242 ExtlTab
mod_xrandr_get_outputs_for_geom(ExtlTab geom
)
245 XRRScreenResources
*res
= XRRGetScreenResources(ioncore_g
.dpy
, ioncore_g
.rootwins
->dummy_win
);
246 ExtlTab result
= extl_create_table();
248 for(i
=0; i
< res
->noutput
; i
++){
251 XRROutputInfo
*output_info
= XRRGetOutputInfo(ioncore_g
.dpy
, res
, res
->outputs
[i
]);
252 if(output_info
->crtc
!= None
){
253 XRRCrtcInfo
*crtc_info
= XRRGetCrtcInfo(ioncore_g
.dpy
, res
, output_info
->crtc
);
255 extl_table_gets_i(geom
, "x", &x
);
256 extl_table_gets_i(geom
, "y", &y
);
257 extl_table_gets_i(geom
, "w", &w
);
258 extl_table_gets_i(geom
, "h", &h
);
259 if(x
==crtc_info
->x
&& y
==crtc_info
->y
260 && w
==(int)crtc_info
->width
&& h
==(int)crtc_info
->height
){
261 add_output(result
, output_info
, crtc_info
);
264 XRRFreeCrtcInfo(crtc_info
);
266 XRRFreeOutputInfo(output_info
);