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/../version.h>
43 char mod_xrandr_ion_api_version
[]=ION_API_VERSION
;
45 WHook
*randr_screen_change_notify
=NULL
;
47 static bool hasXrandR
=FALSE
;
48 static int xrr_event_base
;
49 static int xrr_error_base
;
51 Rb_node rotations
=NULL
;
53 static int rr2scrrot(int rr
)
56 case RR_Rotate_0
: return SCREEN_ROTATION_0
;
57 case RR_Rotate_90
: return SCREEN_ROTATION_90
;
58 case RR_Rotate_180
: return SCREEN_ROTATION_180
;
59 case RR_Rotate_270
: return SCREEN_ROTATION_270
;
60 default: return SCREEN_ROTATION_0
;
65 static void insrot(int id
, int r
)
69 node
=rb_inserti(rotations
, id
, NULL
);
76 bool handle_xrandr_event(XEvent
*ev
)
78 if(hasXrandR
&& ev
->type
== xrr_event_base
+ RRScreenChangeNotify
) {
79 XRRScreenChangeNotifyEvent
*rev
=(XRRScreenChangeNotifyEvent
*)ev
;
85 screen
=XWINDOW_REGION_OF_T(rev
->root
, WScreen
);
92 r
=rr2scrrot(rev
->rotation
);
94 fp
.g
.x
=REGION_GEOM(screen
).x
;
95 fp
.g
.y
=REGION_GEOM(screen
).y
;
97 if(rev
->rotation
==RR_Rotate_90
|| rev
->rotation
==RR_Rotate_270
){
105 fp
.mode
=REGION_FIT_EXACT
;
107 node
=rb_find_ikey_n(rotations
, screen
->id
, &found
);
110 insrot(screen
->id
, r
);
111 }else if(r
!=node
->v
.ival
){
114 fp
.mode
|=REGION_FIT_ROTATE
;
116 ? SCREEN_ROTATION_0
+r
-or
117 : (SCREEN_ROTATION_270
+1)+r
-or);
121 REGION_GEOM(screen
)=fp
.g
;
123 mplex_managed_geom((WMPlex
*)screen
, &(fp
.g
));
125 mplex_do_fit_managed((WMPlex
*)screen
, &fp
);
127 hook_call_v(randr_screen_change_notify
);
137 static bool check_pivots()
140 XRRScreenConfiguration
*cfg
;
147 FOR_ALL_SCREENS(scr
){
148 Rotation rot
=RR_Rotate_90
;
149 int randr_screen_id
= XRRRootToScreen(ioncore_g
.dpy
, ((WMPlex
*) scr
)->win
.win
);
150 if (randr_screen_id
!= -1)
151 XRRRotations(ioncore_g
.dpy
, randr_screen_id
, &rot
);
153 insrot(scr
->id
, rr2scrrot(rot
));
159 #define INIT_HOOK_(NM) \
160 NM=mainloop_register_hook(#NM, create_hook()); \
161 if(NM==NULL) return FALSE
163 bool mod_xrandr_init()
166 XRRQueryExtension(ioncore_g
.dpy
,&xrr_event_base
,&xrr_error_base
);
172 XRRSelectInput(ioncore_g
.dpy
,ioncore_g
.rootwins
->dummy_win
,
173 RRScreenChangeNotifyMask
);
175 warn_obj("mod_xrandr","XRandR is not supported on this display");
178 hook_add(ioncore_handle_event_alt
,(WHookDummy
*)handle_xrandr_event
);
180 INIT_HOOK_(randr_screen_change_notify
);
182 return mod_xrandr_register_exports();
186 bool mod_xrandr_deinit()
188 hook_remove(ioncore_handle_event_alt
,
189 (WHookDummy
*)handle_xrandr_event
);
194 void add_output(ExtlTab result
, XRROutputInfo
*output_info
, XRRCrtcInfo
*crtc_info
)
196 ExtlTab details
= extl_create_table();
197 /* TODO we probably have to strdup the outputs' data here, because we free
198 * the XRROutputInfo later on. However, where can we make sure the strings
199 * get freed when the code calling mod_xrandr_get_outputs_for_geom is done
202 extl_table_sets_s(details
, "name", strdup(output_info
->name
));
203 extl_table_sets_i(details
, "x", crtc_info
->x
);
204 extl_table_sets_i(details
, "y", crtc_info
->y
);
205 extl_table_sets_i(details
, "w", (int)crtc_info
->width
);
206 extl_table_sets_i(details
, "h", (int)crtc_info
->height
);
207 extl_table_sets_t(result
, strdup(output_info
->name
), details
);
212 ExtlTab
mod_xrandr_get_all_outputs()
215 XRRScreenResources
*res
= XRRGetScreenResources(ioncore_g
.dpy
, ioncore_g
.rootwins
->dummy_win
);
216 ExtlTab result
= extl_create_table();
218 for(i
=0; i
< res
->noutput
; i
++){
221 XRROutputInfo
*output_info
= XRRGetOutputInfo(ioncore_g
.dpy
, res
, res
->outputs
[i
]);
222 if(output_info
->crtc
!= None
){
223 XRRCrtcInfo
*crtc_info
= XRRGetCrtcInfo(ioncore_g
.dpy
, res
, output_info
->crtc
);
225 add_output(result
, output_info
, crtc_info
);
227 XRRFreeCrtcInfo(crtc_info
);
229 XRRFreeOutputInfo(output_info
);
237 * Queries the RandR extension for outputs with this geometry
239 * Returns a table with the matching RandR window names as keys
243 ExtlTab
mod_xrandr_get_outputs_for_geom(ExtlTab geom
)
246 XRRScreenResources
*res
= XRRGetScreenResources(ioncore_g
.dpy
, ioncore_g
.rootwins
->dummy_win
);
247 ExtlTab result
= extl_create_table();
249 for(i
=0; i
< res
->noutput
; i
++){
252 XRROutputInfo
*output_info
= XRRGetOutputInfo(ioncore_g
.dpy
, res
, res
->outputs
[i
]);
253 if(output_info
->crtc
!= None
){
254 XRRCrtcInfo
*crtc_info
= XRRGetCrtcInfo(ioncore_g
.dpy
, res
, output_info
->crtc
);
256 extl_table_gets_i(geom
, "x", &x
);
257 extl_table_gets_i(geom
, "y", &y
);
258 extl_table_gets_i(geom
, "w", &w
);
259 extl_table_gets_i(geom
, "h", &h
);
260 if(x
==crtc_info
->x
&& y
==crtc_info
->y
261 && w
==(int)crtc_info
->width
&& h
==(int)crtc_info
->height
){
262 add_output(result
, output_info
, crtc_info
);
265 XRRFreeCrtcInfo(crtc_info
);
267 XRRFreeOutputInfo(output_info
);