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(XRRGetScreenResources
)
57 MAKE_FUNCPTR(XRRSetCrtcConfig
)
58 static typeof(XRRGetScreenResources
) *pXRRGetScreenResourcesCurrent
;
59 static RRMode
*xrandr12_modes
;
60 static int primary_crtc
;
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(XRRGetScreenResources
)
100 LOAD_FUNCPTR(XRRSetCrtcConfig
)
106 if (!r
) TRACE("Unable to load function ptrs from XRandR library\n");
111 static int XRandRErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
116 static int xrandr10_get_current_mode(void)
120 XRRScreenConfiguration
*sc
;
125 sc
= pXRRGetScreenInfo (gdi_display
, DefaultRootWindow( gdi_display
));
126 size
= pXRRConfigCurrentConfiguration (sc
, &rot
);
127 rate
= pXRRConfigCurrentRate (sc
);
128 pXRRFreeScreenConfigInfo(sc
);
130 for (i
= 0; i
< xrandr_mode_count
; ++i
)
132 if (xrandr10_modes
[i
] == size
&& dd_modes
[i
].refresh_rate
== rate
)
140 ERR("In unknown mode, returning default\n");
146 static LONG
xrandr10_set_current_mode( int mode
)
151 XRRScreenConfiguration
*sc
;
155 root
= DefaultRootWindow( gdi_display
);
156 sc
= pXRRGetScreenInfo (gdi_display
, root
);
157 size
= pXRRConfigCurrentConfiguration (sc
, &rot
);
158 mode
= mode
% xrandr_mode_count
;
160 TRACE("Changing Resolution to %dx%d @%d Hz\n",
161 dd_modes
[mode
].width
,
162 dd_modes
[mode
].height
,
163 dd_modes
[mode
].refresh_rate
);
165 size
= xrandr10_modes
[mode
];
166 rate
= dd_modes
[mode
].refresh_rate
;
169 stat
= pXRRSetScreenConfigAndRate( gdi_display
, sc
, root
, size
, rot
, rate
, CurrentTime
);
171 stat
= pXRRSetScreenConfig( gdi_display
, sc
, root
, size
, rot
, CurrentTime
);
173 pXRRFreeScreenConfigInfo(sc
);
175 if (stat
== RRSetConfigSuccess
)
177 X11DRV_resize_desktop( dd_modes
[mode
].width
, dd_modes
[mode
].height
);
178 return DISP_CHANGE_SUCCESSFUL
;
181 ERR("Resolution change not successful -- perhaps display has changed?\n");
182 return DISP_CHANGE_FAILED
;
185 static void xrandr10_init_modes(void)
187 XRRScreenSize
*sizes
;
189 int i
, j
, nmodes
= 0;
191 sizes
= pXRRSizes( gdi_display
, DefaultScreen(gdi_display
), &sizes_count
);
192 if (sizes_count
<= 0) return;
194 TRACE("XRandR: found %d sizes.\n", sizes_count
);
195 for (i
= 0; i
< sizes_count
; ++i
)
200 rates
= pXRRRates( gdi_display
, DefaultScreen(gdi_display
), i
, &rates_count
);
201 TRACE("- at %d: %dx%d (%d rates):", i
, sizes
[i
].width
, sizes
[i
].height
, rates_count
);
204 nmodes
+= rates_count
;
205 for (j
= 0; j
< rates_count
; ++j
)
209 TRACE(" %d", rates
[j
]);
220 TRACE("XRandR modes: count=%d\n", nmodes
);
222 if (!(xrandr10_modes
= HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr10_modes
) * nmodes
)))
224 ERR("Failed to allocate xrandr mode info array.\n");
228 dd_modes
= X11DRV_Settings_SetHandlers( "XRandR 1.0",
229 xrandr10_get_current_mode
,
230 xrandr10_set_current_mode
,
233 xrandr_mode_count
= 0;
234 for (i
= 0; i
< sizes_count
; ++i
)
239 rates
= pXRRRates( gdi_display
, DefaultScreen(gdi_display
), i
, &rates_count
);
243 for (j
= 0; j
< rates_count
; ++j
)
245 X11DRV_Settings_AddOneMode( sizes
[i
].width
, sizes
[i
].height
, 0, rates
[j
] );
246 xrandr10_modes
[xrandr_mode_count
++] = i
;
251 X11DRV_Settings_AddOneMode( sizes
[i
].width
, sizes
[i
].height
, 0, 0 );
252 xrandr10_modes
[xrandr_mode_count
++] = i
;
256 X11DRV_Settings_AddDepthModes();
257 nmodes
= X11DRV_Settings_GetModeCount();
259 TRACE("Available DD modes: count=%d\n", nmodes
);
260 TRACE("Enabling XRandR\n");
263 #ifdef HAVE_XRRGETSCREENRESOURCES
265 static int xrandr12_get_current_mode(void)
267 XRRScreenResources
*resources
;
268 XRRCrtcInfo
*crtc_info
;
271 if (!(resources
= pXRRGetScreenResourcesCurrent( gdi_display
, root_window
)))
273 ERR("Failed to get screen resources.\n");
277 if (resources
->ncrtc
<= primary_crtc
||
278 !(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[primary_crtc
] )))
280 pXRRFreeScreenResources( resources
);
281 ERR("Failed to get CRTC info.\n");
285 TRACE("CRTC %d: mode %#lx, %ux%u+%d+%d.\n", primary_crtc
, crtc_info
->mode
,
286 crtc_info
->width
, crtc_info
->height
, crtc_info
->x
, crtc_info
->y
);
288 for (i
= 0; i
< xrandr_mode_count
; ++i
)
290 if (xrandr12_modes
[i
] == crtc_info
->mode
)
297 pXRRFreeCrtcInfo( crtc_info
);
298 pXRRFreeScreenResources( resources
);
302 ERR("Unknown mode, returning default.\n");
309 static LONG
xrandr12_set_current_mode( int mode
)
311 Status status
= RRSetConfigFailed
;
312 XRRScreenResources
*resources
;
313 XRRCrtcInfo
*crtc_info
;
315 mode
= mode
% xrandr_mode_count
;
317 if (!(resources
= pXRRGetScreenResourcesCurrent( gdi_display
, root_window
)))
319 ERR("Failed to get screen resources.\n");
320 return DISP_CHANGE_FAILED
;
323 if (resources
->ncrtc
<= primary_crtc
||
324 !(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[primary_crtc
] )))
326 pXRRFreeScreenResources( resources
);
327 ERR("Failed to get CRTC info.\n");
328 return DISP_CHANGE_FAILED
;
331 TRACE("CRTC %d: mode %#lx, %ux%u+%d+%d.\n", primary_crtc
, crtc_info
->mode
,
332 crtc_info
->width
, crtc_info
->height
, crtc_info
->x
, crtc_info
->y
);
334 status
= pXRRSetCrtcConfig( gdi_display
, resources
, resources
->crtcs
[primary_crtc
],
335 CurrentTime
, crtc_info
->x
, crtc_info
->y
, xrandr12_modes
[mode
],
336 crtc_info
->rotation
, crtc_info
->outputs
, crtc_info
->noutput
);
338 pXRRFreeCrtcInfo( crtc_info
);
339 pXRRFreeScreenResources( resources
);
341 if (status
!= RRSetConfigSuccess
)
343 ERR("Resolution change not successful -- perhaps display has changed?\n");
344 return DISP_CHANGE_FAILED
;
347 X11DRV_resize_desktop( dd_modes
[mode
].width
, dd_modes
[mode
].height
);
348 return DISP_CHANGE_SUCCESSFUL
;
351 static XRRCrtcInfo
*xrandr12_get_primary_crtc_info( XRRScreenResources
*resources
, int *crtc_idx
)
353 XRRCrtcInfo
*crtc_info
;
356 for (i
= 0; i
< resources
->ncrtc
; ++i
)
358 crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[i
] );
359 if (!crtc_info
|| crtc_info
->mode
== None
)
361 pXRRFreeCrtcInfo( crtc_info
);
372 static int xrandr12_init_modes(void)
374 XRRScreenResources
*resources
;
375 XRROutputInfo
*output_info
;
376 XRRCrtcInfo
*crtc_info
;
380 if (!(resources
= pXRRGetScreenResourcesCurrent( gdi_display
, root_window
)))
382 ERR("Failed to get screen resources.\n");
386 if (!resources
->ncrtc
)
388 pXRRFreeScreenResources( resources
);
389 if (!(resources
= pXRRGetScreenResources( gdi_display
, root_window
)))
391 ERR("Failed to get screen resources.\n");
396 if (!(crtc_info
= xrandr12_get_primary_crtc_info( resources
, &primary_crtc
)))
398 pXRRFreeScreenResources( resources
);
399 ERR("Failed to get primary CRTC info.\n");
403 TRACE("CRTC %d: mode %#lx, %ux%u+%d+%d.\n", primary_crtc
, crtc_info
->mode
,
404 crtc_info
->width
, crtc_info
->height
, crtc_info
->x
, crtc_info
->y
);
406 if (!crtc_info
->noutput
|| !(output_info
= pXRRGetOutputInfo( gdi_display
, resources
, crtc_info
->outputs
[0] )))
408 pXRRFreeCrtcInfo( crtc_info
);
409 pXRRFreeScreenResources( resources
);
410 ERR("Failed to get output info.\n");
414 TRACE("OUTPUT 0: name %s.\n", debugstr_a(output_info
->name
));
416 if (!output_info
->nmode
)
418 ERR("Output has no modes.\n");
422 if (!(xrandr12_modes
= HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr12_modes
) * output_info
->nmode
)))
424 ERR("Failed to allocate xrandr mode info array.\n");
428 dd_modes
= X11DRV_Settings_SetHandlers( "XRandR 1.2",
429 xrandr12_get_current_mode
,
430 xrandr12_set_current_mode
,
431 output_info
->nmode
, 1 );
433 xrandr_mode_count
= 0;
434 for (i
= 0; i
< output_info
->nmode
; ++i
)
436 for (j
= 0; j
< resources
->nmode
; ++j
)
438 XRRModeInfo
*mode
= &resources
->modes
[j
];
440 if (mode
->id
== output_info
->modes
[i
])
442 unsigned int dots
= mode
->hTotal
* mode
->vTotal
;
443 unsigned int refresh
= dots
? (mode
->dotClock
+ dots
/ 2) / dots
: 0;
445 TRACE("Adding mode %#lx: %ux%u@%u.\n", mode
->id
, mode
->width
, mode
->height
, refresh
);
446 X11DRV_Settings_AddOneMode( mode
->width
, mode
->height
, 0, refresh
);
447 xrandr12_modes
[xrandr_mode_count
++] = mode
->id
;
453 X11DRV_Settings_AddDepthModes();
457 pXRRFreeOutputInfo( output_info
);
458 pXRRFreeCrtcInfo( crtc_info
);
459 pXRRFreeScreenResources( resources
);
463 #endif /* HAVE_XRRGETSCREENRESOURCES */
465 void X11DRV_XRandR_Init(void)
467 int event_base
, error_base
, minor
, ret
;
471 if (major
) return; /* already initialized? */
472 if (!usexrandr
) return; /* disabled in config */
473 if (root_window
!= DefaultRootWindow( gdi_display
)) return;
474 if (!(ret
= load_xrandr())) return; /* can't load the Xrandr library */
476 /* see if Xrandr is available */
477 if (!pXRRQueryExtension( gdi_display
, &event_base
, &error_base
)) return;
478 X11DRV_expect_error( gdi_display
, XRandRErrorHandler
, NULL
);
479 ok
= pXRRQueryVersion( gdi_display
, &major
, &minor
);
480 if (X11DRV_check_error() || !ok
) return;
482 TRACE("Found XRandR %d.%d.\n", major
, minor
);
484 #ifdef HAVE_XRRGETSCREENRESOURCES
485 if (ret
>= 2 && (major
> 1 || (major
== 1 && minor
>= 2)))
487 if (major
> 1 || (major
== 1 && minor
>= 3))
488 pXRRGetScreenResourcesCurrent
= wine_dlsym( xrandr_handle
, "XRRGetScreenResourcesCurrent", NULL
, 0 );
489 if (!pXRRGetScreenResourcesCurrent
)
490 pXRRGetScreenResourcesCurrent
= pXRRGetScreenResources
;
493 if (!pXRRGetScreenResourcesCurrent
|| xrandr12_init_modes() < 0)
495 xrandr10_init_modes();
498 #else /* SONAME_LIBXRANDR */
500 void X11DRV_XRandR_Init(void)
502 TRACE("XRandR support not compiled in.\n");
505 #endif /* SONAME_LIBXRANDR */