2 * Wine X11drv Xrandr interface
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2012 Henri Verbeet for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(xrandr
);
28 #ifdef SONAME_LIBXRANDR
31 #include <X11/extensions/Xrandr.h>
34 #include "wine/library.h"
36 static void *xrandr_handle
;
38 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
39 MAKE_FUNCPTR(XRRConfigCurrentConfiguration
)
40 MAKE_FUNCPTR(XRRConfigCurrentRate
)
41 MAKE_FUNCPTR(XRRFreeScreenConfigInfo
)
42 MAKE_FUNCPTR(XRRGetScreenInfo
)
43 MAKE_FUNCPTR(XRRQueryExtension
)
44 MAKE_FUNCPTR(XRRQueryVersion
)
45 MAKE_FUNCPTR(XRRRates
)
46 MAKE_FUNCPTR(XRRSetScreenConfig
)
47 MAKE_FUNCPTR(XRRSetScreenConfigAndRate
)
48 MAKE_FUNCPTR(XRRSizes
)
50 #ifdef HAVE_XRRGETSCREENRESOURCES
51 MAKE_FUNCPTR(XRRFreeCrtcInfo
)
52 MAKE_FUNCPTR(XRRFreeOutputInfo
)
53 MAKE_FUNCPTR(XRRFreeScreenResources
)
54 MAKE_FUNCPTR(XRRGetCrtcInfo
)
55 MAKE_FUNCPTR(XRRGetOutputInfo
)
56 MAKE_FUNCPTR(XRRSetCrtcConfig
)
57 static typeof(XRRGetScreenResources
) *xrandr_get_screen_resources
;
58 static RRMode
*xrandr12_modes
;
65 static struct x11drv_mode_info
*dd_modes
;
66 static SizeID
*xrandr10_modes
;
67 static unsigned int xrandr_mode_count
;
69 static int load_xrandr(void)
73 if (wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
74 (xrandr_handle
= wine_dlopen(SONAME_LIBXRANDR
, RTLD_NOW
, NULL
, 0)))
77 #define LOAD_FUNCPTR(f) \
78 if((p##f = wine_dlsym(xrandr_handle, #f, NULL, 0)) == NULL) \
81 LOAD_FUNCPTR(XRRConfigCurrentConfiguration
)
82 LOAD_FUNCPTR(XRRConfigCurrentRate
)
83 LOAD_FUNCPTR(XRRFreeScreenConfigInfo
)
84 LOAD_FUNCPTR(XRRGetScreenInfo
)
85 LOAD_FUNCPTR(XRRQueryExtension
)
86 LOAD_FUNCPTR(XRRQueryVersion
)
87 LOAD_FUNCPTR(XRRRates
)
88 LOAD_FUNCPTR(XRRSetScreenConfig
)
89 LOAD_FUNCPTR(XRRSetScreenConfigAndRate
)
90 LOAD_FUNCPTR(XRRSizes
)
93 #ifdef HAVE_XRRGETSCREENRESOURCES
94 LOAD_FUNCPTR(XRRFreeCrtcInfo
)
95 LOAD_FUNCPTR(XRRFreeOutputInfo
)
96 LOAD_FUNCPTR(XRRFreeScreenResources
)
97 LOAD_FUNCPTR(XRRGetCrtcInfo
)
98 LOAD_FUNCPTR(XRRGetOutputInfo
)
99 LOAD_FUNCPTR(XRRSetCrtcConfig
)
105 if (!r
) TRACE("Unable to load function ptrs from XRandR library\n");
110 static int XRandRErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
115 static int xrandr10_get_current_mode(void)
120 XRRScreenConfiguration
*sc
;
126 root
= RootWindow (gdi_display
, DefaultScreen(gdi_display
));
127 sc
= pXRRGetScreenInfo (gdi_display
, root
);
128 size
= pXRRConfigCurrentConfiguration (sc
, &rot
);
129 rate
= pXRRConfigCurrentRate (sc
);
130 pXRRFreeScreenConfigInfo(sc
);
132 for (i
= 0; i
< xrandr_mode_count
; ++i
)
134 if (xrandr10_modes
[i
] == size
&& dd_modes
[i
].refresh_rate
== rate
)
142 ERR("In unknown mode, returning default\n");
148 static LONG
xrandr10_set_current_mode( int mode
)
153 XRRScreenConfiguration
*sc
;
158 root
= RootWindow (gdi_display
, DefaultScreen(gdi_display
));
159 sc
= pXRRGetScreenInfo (gdi_display
, root
);
160 size
= pXRRConfigCurrentConfiguration (sc
, &rot
);
161 mode
= mode
% xrandr_mode_count
;
163 TRACE("Changing Resolution to %dx%d @%d Hz\n",
164 dd_modes
[mode
].width
,
165 dd_modes
[mode
].height
,
166 dd_modes
[mode
].refresh_rate
);
168 size
= xrandr10_modes
[mode
];
169 rate
= dd_modes
[mode
].refresh_rate
;
172 stat
= pXRRSetScreenConfigAndRate( gdi_display
, sc
, root
, size
, rot
, rate
, CurrentTime
);
174 stat
= pXRRSetScreenConfig( gdi_display
, sc
, root
, size
, rot
, CurrentTime
);
176 pXRRFreeScreenConfigInfo(sc
);
178 if (stat
== RRSetConfigSuccess
)
180 X11DRV_resize_desktop( dd_modes
[mode
].width
, dd_modes
[mode
].height
);
181 return DISP_CHANGE_SUCCESSFUL
;
184 ERR("Resolution change not successful -- perhaps display has changed?\n");
185 return DISP_CHANGE_FAILED
;
188 static void xrandr10_init_modes(void)
190 XRRScreenSize
*sizes
;
192 int i
, j
, nmodes
= 0;
194 sizes
= pXRRSizes( gdi_display
, DefaultScreen(gdi_display
), &sizes_count
);
195 if (sizes_count
<= 0) return;
197 TRACE("XRandR: found %d sizes.\n", sizes_count
);
198 for (i
= 0; i
< sizes_count
; ++i
)
203 rates
= pXRRRates( gdi_display
, DefaultScreen(gdi_display
), i
, &rates_count
);
204 TRACE("- at %d: %dx%d (%d rates):", i
, sizes
[i
].width
, sizes
[i
].height
, rates_count
);
207 nmodes
+= rates_count
;
208 for (j
= 0; j
< rates_count
; ++j
)
212 TRACE(" %d", rates
[j
]);
223 TRACE("XRandR modes: count=%d\n", nmodes
);
225 if (!(xrandr10_modes
= HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr10_modes
) * nmodes
)))
227 ERR("Failed to allocate xrandr mode info array.\n");
231 dd_modes
= X11DRV_Settings_SetHandlers( "XRandR 1.0",
232 xrandr10_get_current_mode
,
233 xrandr10_set_current_mode
,
236 xrandr_mode_count
= 0;
237 for (i
= 0; i
< sizes_count
; ++i
)
242 rates
= pXRRRates( gdi_display
, DefaultScreen(gdi_display
), i
, &rates_count
);
246 for (j
= 0; j
< rates_count
; ++j
)
248 X11DRV_Settings_AddOneMode( sizes
[i
].width
, sizes
[i
].height
, 0, rates
[j
] );
249 xrandr10_modes
[xrandr_mode_count
++] = i
;
254 X11DRV_Settings_AddOneMode( sizes
[i
].width
, sizes
[i
].height
, 0, 0 );
255 xrandr10_modes
[xrandr_mode_count
++] = i
;
259 X11DRV_Settings_AddDepthModes();
260 nmodes
= X11DRV_Settings_GetModeCount();
262 TRACE("Available DD modes: count=%d\n", nmodes
);
263 TRACE("Enabling XRandR\n");
266 #ifdef HAVE_XRRGETSCREENRESOURCES
268 static int xrandr12_get_current_mode(void)
270 XRRScreenResources
*resources
;
271 XRRCrtcInfo
*crtc_info
;
275 if (!(resources
= xrandr_get_screen_resources( gdi_display
, root_window
)))
278 ERR("Failed to get screen resources.\n");
282 if (!resources
->ncrtc
|| !(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[0] )))
284 pXRRFreeScreenResources( resources
);
286 ERR("Failed to get CRTC info.\n");
290 TRACE("CRTC 0: mode %#lx, %ux%u+%d+%d.\n", crtc_info
->mode
,
291 crtc_info
->width
, crtc_info
->height
, crtc_info
->x
, crtc_info
->y
);
293 for (i
= 0; i
< xrandr_mode_count
; ++i
)
295 if (xrandr12_modes
[i
] == crtc_info
->mode
)
302 pXRRFreeCrtcInfo( crtc_info
);
303 pXRRFreeScreenResources( resources
);
308 ERR("Unknown mode, returning default.\n");
315 static LONG
xrandr12_set_current_mode( int mode
)
317 Status status
= RRSetConfigFailed
;
318 XRRScreenResources
*resources
;
319 XRRCrtcInfo
*crtc_info
;
321 mode
= mode
% xrandr_mode_count
;
324 if (!(resources
= xrandr_get_screen_resources( gdi_display
, root_window
)))
327 ERR("Failed to get screen resources.\n");
328 return DISP_CHANGE_FAILED
;
331 if (!resources
->ncrtc
|| !(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[0] )))
333 pXRRFreeScreenResources( resources
);
335 ERR("Failed to get CRTC info.\n");
336 return DISP_CHANGE_FAILED
;
339 TRACE("CRTC 0: mode %#lx, %ux%u+%d+%d.\n", crtc_info
->mode
,
340 crtc_info
->width
, crtc_info
->height
, crtc_info
->x
, crtc_info
->y
);
342 status
= pXRRSetCrtcConfig( gdi_display
, resources
, resources
->crtcs
[0], CurrentTime
, crtc_info
->x
,
343 crtc_info
->y
, xrandr12_modes
[mode
], crtc_info
->rotation
, crtc_info
->outputs
, crtc_info
->noutput
);
345 pXRRFreeCrtcInfo( crtc_info
);
346 pXRRFreeScreenResources( resources
);
349 if (status
!= RRSetConfigSuccess
)
351 ERR("Resolution change not successful -- perhaps display has changed?\n");
352 return DISP_CHANGE_FAILED
;
355 X11DRV_resize_desktop( dd_modes
[mode
].width
, dd_modes
[mode
].height
);
356 return DISP_CHANGE_SUCCESSFUL
;
359 static void xrandr12_init_modes(void)
361 XRRScreenResources
*resources
;
362 XRROutputInfo
*output_info
;
363 XRRCrtcInfo
*crtc_info
;
366 if (!(resources
= xrandr_get_screen_resources( gdi_display
, root_window
)))
368 ERR("Failed to get screen resources.\n");
372 if (!resources
->ncrtc
|| !(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[0] )))
374 pXRRFreeScreenResources( resources
);
375 ERR("Failed to get CRTC info.\n");
379 TRACE("CRTC 0: mode %#lx, %ux%u+%d+%d.\n", crtc_info
->mode
,
380 crtc_info
->width
, crtc_info
->height
, crtc_info
->x
, crtc_info
->y
);
382 if (!crtc_info
->noutput
|| !(output_info
= pXRRGetOutputInfo( gdi_display
, resources
, crtc_info
->outputs
[0] )))
384 pXRRFreeCrtcInfo( crtc_info
);
385 pXRRFreeScreenResources( resources
);
386 ERR("Failed to get output info.\n");
390 TRACE("OUTPUT 0: name %s.\n", debugstr_a(output_info
->name
));
392 if (!output_info
->nmode
)
394 ERR("Output has no modes.\n");
398 if (!(xrandr12_modes
= HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr12_modes
) * output_info
->nmode
)))
400 ERR("Failed to allocate xrandr mode info array.\n");
404 dd_modes
= X11DRV_Settings_SetHandlers( "XRandR 1.2",
405 xrandr12_get_current_mode
,
406 xrandr12_set_current_mode
,
407 output_info
->nmode
, 1 );
409 xrandr_mode_count
= 0;
410 for (i
= 0; i
< output_info
->nmode
; ++i
)
412 for (j
= 0; j
< resources
->nmode
; ++j
)
414 XRRModeInfo
*mode
= &resources
->modes
[j
];
416 if (mode
->id
== output_info
->modes
[i
])
418 unsigned int dots
= mode
->hTotal
* mode
->vTotal
;
419 unsigned int refresh
= dots
? (mode
->dotClock
+ dots
/ 2) / dots
: 0;
421 TRACE("Adding mode %#lx: %ux%u@%u.\n", mode
->id
, mode
->width
, mode
->height
, refresh
);
422 X11DRV_Settings_AddOneMode( mode
->width
, mode
->height
, 0, refresh
);
423 xrandr12_modes
[xrandr_mode_count
++] = mode
->id
;
429 X11DRV_Settings_AddDepthModes();
432 pXRRFreeOutputInfo( output_info
);
433 pXRRFreeCrtcInfo( crtc_info
);
434 pXRRFreeScreenResources( resources
);
437 #endif /* HAVE_XRRGETSCREENRESOURCES */
439 void X11DRV_XRandR_Init(void)
441 int event_base
, error_base
, minor
, ret
;
445 if (major
) return; /* already initialized? */
446 if (!usexrandr
) return; /* disabled in config */
447 if (root_window
!= DefaultRootWindow( gdi_display
)) return;
448 if (!(ret
= load_xrandr())) return; /* can't load the Xrandr library */
450 /* see if Xrandr is available */
452 if (!pXRRQueryExtension( gdi_display
, &event_base
, &error_base
)) goto done
;
453 X11DRV_expect_error( gdi_display
, XRandRErrorHandler
, NULL
);
454 ok
= pXRRQueryVersion( gdi_display
, &major
, &minor
);
455 if (X11DRV_check_error() || !ok
) goto done
;
457 TRACE("Found XRandR %d.%d.\n", major
, minor
);
459 #ifdef HAVE_XRRGETSCREENRESOURCES
460 if (ret
>= 2 && (major
> 1 || (major
== 1 && minor
>= 2)))
462 if (major
> 1 || (major
== 1 && minor
>= 3))
463 xrandr_get_screen_resources
= wine_dlsym( xrandr_handle
, "XRRGetScreenResourcesCurrent", NULL
, 0 );
464 if (!xrandr_get_screen_resources
)
465 xrandr_get_screen_resources
= wine_dlsym( xrandr_handle
, "XRRGetScreenResources", NULL
, 0 );
468 if (xrandr_get_screen_resources
)
469 xrandr12_init_modes();
472 xrandr10_init_modes();
478 #else /* SONAME_LIBXRANDR */
480 void X11DRV_XRandR_Init(void)
482 TRACE("XRandR support not compiled in.\n");
485 #endif /* SONAME_LIBXRANDR */