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
;
66 static struct x11drv_mode_info
*dd_modes
;
67 static SizeID
*xrandr10_modes
;
68 static unsigned int xrandr_mode_count
;
70 static int load_xrandr(void)
74 if (wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
75 (xrandr_handle
= wine_dlopen(SONAME_LIBXRANDR
, RTLD_NOW
, NULL
, 0)))
78 #define LOAD_FUNCPTR(f) \
79 if((p##f = wine_dlsym(xrandr_handle, #f, NULL, 0)) == NULL) \
82 LOAD_FUNCPTR(XRRConfigCurrentConfiguration
)
83 LOAD_FUNCPTR(XRRConfigCurrentRate
)
84 LOAD_FUNCPTR(XRRFreeScreenConfigInfo
)
85 LOAD_FUNCPTR(XRRGetScreenInfo
)
86 LOAD_FUNCPTR(XRRQueryExtension
)
87 LOAD_FUNCPTR(XRRQueryVersion
)
88 LOAD_FUNCPTR(XRRRates
)
89 LOAD_FUNCPTR(XRRSetScreenConfig
)
90 LOAD_FUNCPTR(XRRSetScreenConfigAndRate
)
91 LOAD_FUNCPTR(XRRSizes
)
94 #ifdef HAVE_XRRGETSCREENRESOURCES
95 LOAD_FUNCPTR(XRRFreeCrtcInfo
)
96 LOAD_FUNCPTR(XRRFreeOutputInfo
)
97 LOAD_FUNCPTR(XRRFreeScreenResources
)
98 LOAD_FUNCPTR(XRRGetCrtcInfo
)
99 LOAD_FUNCPTR(XRRGetOutputInfo
)
100 LOAD_FUNCPTR(XRRGetScreenResources
)
101 LOAD_FUNCPTR(XRRSetCrtcConfig
)
107 if (!r
) TRACE("Unable to load function ptrs from XRandR library\n");
112 static int XRandRErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
117 static int xrandr10_get_current_mode(void)
121 XRRScreenConfiguration
*sc
;
126 sc
= pXRRGetScreenInfo (gdi_display
, DefaultRootWindow( gdi_display
));
127 size
= pXRRConfigCurrentConfiguration (sc
, &rot
);
128 rate
= pXRRConfigCurrentRate (sc
);
129 pXRRFreeScreenConfigInfo(sc
);
131 for (i
= 0; i
< xrandr_mode_count
; ++i
)
133 if (xrandr10_modes
[i
] == size
&& dd_modes
[i
].refresh_rate
== rate
)
141 ERR("In unknown mode, returning default\n");
147 static LONG
xrandr10_set_current_mode( int mode
)
152 XRRScreenConfiguration
*sc
;
156 root
= DefaultRootWindow( gdi_display
);
157 sc
= pXRRGetScreenInfo (gdi_display
, root
);
158 size
= pXRRConfigCurrentConfiguration (sc
, &rot
);
159 mode
= mode
% xrandr_mode_count
;
161 TRACE("Changing Resolution to %dx%d @%d Hz\n",
162 dd_modes
[mode
].width
,
163 dd_modes
[mode
].height
,
164 dd_modes
[mode
].refresh_rate
);
166 size
= xrandr10_modes
[mode
];
167 rate
= dd_modes
[mode
].refresh_rate
;
170 stat
= pXRRSetScreenConfigAndRate( gdi_display
, sc
, root
, size
, rot
, rate
, CurrentTime
);
172 stat
= pXRRSetScreenConfig( gdi_display
, sc
, root
, size
, rot
, CurrentTime
);
174 pXRRFreeScreenConfigInfo(sc
);
176 if (stat
== RRSetConfigSuccess
)
178 X11DRV_resize_desktop( dd_modes
[mode
].width
, dd_modes
[mode
].height
);
179 return DISP_CHANGE_SUCCESSFUL
;
182 ERR("Resolution change not successful -- perhaps display has changed?\n");
183 return DISP_CHANGE_FAILED
;
186 static void xrandr10_init_modes(void)
188 XRRScreenSize
*sizes
;
190 int i
, j
, nmodes
= 0;
192 sizes
= pXRRSizes( gdi_display
, DefaultScreen(gdi_display
), &sizes_count
);
193 if (sizes_count
<= 0) return;
195 TRACE("XRandR: found %d sizes.\n", sizes_count
);
196 for (i
= 0; i
< sizes_count
; ++i
)
201 rates
= pXRRRates( gdi_display
, DefaultScreen(gdi_display
), i
, &rates_count
);
202 TRACE("- at %d: %dx%d (%d rates):", i
, sizes
[i
].width
, sizes
[i
].height
, rates_count
);
205 nmodes
+= rates_count
;
206 for (j
= 0; j
< rates_count
; ++j
)
210 TRACE(" %d", rates
[j
]);
221 TRACE("XRandR modes: count=%d\n", nmodes
);
223 if (!(xrandr10_modes
= HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr10_modes
) * nmodes
)))
225 ERR("Failed to allocate xrandr mode info array.\n");
229 dd_modes
= X11DRV_Settings_SetHandlers( "XRandR 1.0",
230 xrandr10_get_current_mode
,
231 xrandr10_set_current_mode
,
234 xrandr_mode_count
= 0;
235 for (i
= 0; i
< sizes_count
; ++i
)
240 rates
= pXRRRates( gdi_display
, DefaultScreen(gdi_display
), i
, &rates_count
);
244 for (j
= 0; j
< rates_count
; ++j
)
246 X11DRV_Settings_AddOneMode( sizes
[i
].width
, sizes
[i
].height
, 0, rates
[j
] );
247 xrandr10_modes
[xrandr_mode_count
++] = i
;
252 X11DRV_Settings_AddOneMode( sizes
[i
].width
, sizes
[i
].height
, 0, 0 );
253 xrandr10_modes
[xrandr_mode_count
++] = i
;
257 X11DRV_Settings_AddDepthModes();
258 nmodes
= X11DRV_Settings_GetModeCount();
260 TRACE("Available DD modes: count=%d\n", nmodes
);
261 TRACE("Enabling XRandR\n");
264 #ifdef HAVE_XRRGETSCREENRESOURCES
266 static int xrandr12_get_current_mode(void)
268 XRRScreenResources
*resources
;
269 XRRCrtcInfo
*crtc_info
;
272 if (!(resources
= pXRRGetScreenResourcesCurrent( gdi_display
, root_window
)))
274 ERR("Failed to get screen resources.\n");
278 if (!resources
->ncrtc
|| !(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[0] )))
280 pXRRFreeScreenResources( resources
);
281 ERR("Failed to get CRTC info.\n");
285 TRACE("CRTC 0: mode %#lx, %ux%u+%d+%d.\n", 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
|| !(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[0] )))
325 pXRRFreeScreenResources( resources
);
326 ERR("Failed to get CRTC info.\n");
327 return DISP_CHANGE_FAILED
;
330 TRACE("CRTC 0: mode %#lx, %ux%u+%d+%d.\n", crtc_info
->mode
,
331 crtc_info
->width
, crtc_info
->height
, crtc_info
->x
, crtc_info
->y
);
333 status
= pXRRSetCrtcConfig( gdi_display
, resources
, resources
->crtcs
[0], CurrentTime
, crtc_info
->x
,
334 crtc_info
->y
, xrandr12_modes
[mode
], crtc_info
->rotation
, crtc_info
->outputs
, crtc_info
->noutput
);
336 pXRRFreeCrtcInfo( crtc_info
);
337 pXRRFreeScreenResources( resources
);
339 if (status
!= RRSetConfigSuccess
)
341 ERR("Resolution change not successful -- perhaps display has changed?\n");
342 return DISP_CHANGE_FAILED
;
345 X11DRV_resize_desktop( dd_modes
[mode
].width
, dd_modes
[mode
].height
);
346 return DISP_CHANGE_SUCCESSFUL
;
349 static int xrandr12_init_modes(void)
351 XRRScreenResources
*resources
;
352 XRROutputInfo
*output_info
;
353 XRRCrtcInfo
*crtc_info
;
357 if (!(resources
= pXRRGetScreenResourcesCurrent( gdi_display
, root_window
)))
359 ERR("Failed to get screen resources.\n");
363 if (!resources
->ncrtc
)
365 pXRRFreeScreenResources( resources
);
366 if (!(resources
= pXRRGetScreenResources( gdi_display
, root_window
)))
368 ERR("Failed to get screen resources.\n");
373 if (!resources
->ncrtc
|| !(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[0] )))
375 pXRRFreeScreenResources( resources
);
376 ERR("Failed to get CRTC info.\n");
380 TRACE("CRTC 0: mode %#lx, %ux%u+%d+%d.\n", crtc_info
->mode
,
381 crtc_info
->width
, crtc_info
->height
, crtc_info
->x
, crtc_info
->y
);
383 if (!crtc_info
->noutput
|| !(output_info
= pXRRGetOutputInfo( gdi_display
, resources
, crtc_info
->outputs
[0] )))
385 pXRRFreeCrtcInfo( crtc_info
);
386 pXRRFreeScreenResources( resources
);
387 ERR("Failed to get output info.\n");
391 TRACE("OUTPUT 0: name %s.\n", debugstr_a(output_info
->name
));
393 if (!output_info
->nmode
)
395 ERR("Output has no modes.\n");
399 if (!(xrandr12_modes
= HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr12_modes
) * output_info
->nmode
)))
401 ERR("Failed to allocate xrandr mode info array.\n");
405 dd_modes
= X11DRV_Settings_SetHandlers( "XRandR 1.2",
406 xrandr12_get_current_mode
,
407 xrandr12_set_current_mode
,
408 output_info
->nmode
, 1 );
410 xrandr_mode_count
= 0;
411 for (i
= 0; i
< output_info
->nmode
; ++i
)
413 for (j
= 0; j
< resources
->nmode
; ++j
)
415 XRRModeInfo
*mode
= &resources
->modes
[j
];
417 if (mode
->id
== output_info
->modes
[i
])
419 unsigned int dots
= mode
->hTotal
* mode
->vTotal
;
420 unsigned int refresh
= dots
? (mode
->dotClock
+ dots
/ 2) / dots
: 0;
422 TRACE("Adding mode %#lx: %ux%u@%u.\n", mode
->id
, mode
->width
, mode
->height
, refresh
);
423 X11DRV_Settings_AddOneMode( mode
->width
, mode
->height
, 0, refresh
);
424 xrandr12_modes
[xrandr_mode_count
++] = mode
->id
;
430 X11DRV_Settings_AddDepthModes();
434 pXRRFreeOutputInfo( output_info
);
435 pXRRFreeCrtcInfo( crtc_info
);
436 pXRRFreeScreenResources( resources
);
440 #endif /* HAVE_XRRGETSCREENRESOURCES */
442 void X11DRV_XRandR_Init(void)
444 int event_base
, error_base
, minor
, ret
;
448 if (major
) return; /* already initialized? */
449 if (!usexrandr
) return; /* disabled in config */
450 if (root_window
!= DefaultRootWindow( gdi_display
)) return;
451 if (!(ret
= load_xrandr())) return; /* can't load the Xrandr library */
453 /* see if Xrandr is available */
454 if (!pXRRQueryExtension( gdi_display
, &event_base
, &error_base
)) return;
455 X11DRV_expect_error( gdi_display
, XRandRErrorHandler
, NULL
);
456 ok
= pXRRQueryVersion( gdi_display
, &major
, &minor
);
457 if (X11DRV_check_error() || !ok
) return;
459 TRACE("Found XRandR %d.%d.\n", major
, minor
);
461 #ifdef HAVE_XRRGETSCREENRESOURCES
462 if (ret
>= 2 && (major
> 1 || (major
== 1 && minor
>= 2)))
464 if (major
> 1 || (major
== 1 && minor
>= 3))
465 pXRRGetScreenResourcesCurrent
= wine_dlsym( xrandr_handle
, "XRRGetScreenResourcesCurrent", NULL
, 0 );
466 if (!pXRRGetScreenResourcesCurrent
)
467 pXRRGetScreenResourcesCurrent
= pXRRGetScreenResources
;
470 if (!pXRRGetScreenResourcesCurrent
|| xrandr12_init_modes() < 0)
472 xrandr10_init_modes();
475 #else /* SONAME_LIBXRANDR */
477 void X11DRV_XRandR_Init(void)
479 TRACE("XRandR support not compiled in.\n");
482 #endif /* SONAME_LIBXRANDR */