server: Fix propagation of the pixel format flag when the parent window is changed.
[wine.git] / dlls / winex11.drv / xrandr.c
blob10935411e9c457b64a6d7be0366e776bdd889a37
1 /*
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
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
28 #ifdef SONAME_LIBXRANDR
30 #include <X11/Xlib.h>
31 #include <X11/extensions/Xrandr.h>
32 #include "x11drv.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;
61 #endif
63 #undef MAKE_FUNCPTR
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)
71 int r = 0;
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) \
79 goto sym_not_found;
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)
91 r = 1;
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)
101 r = 2;
102 #endif
103 #undef LOAD_FUNCPTR
105 sym_not_found:
106 if (!r) TRACE("Unable to load function ptrs from XRandR library\n");
108 return r;
111 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
113 return 1;
116 static int xrandr10_get_current_mode(void)
118 SizeID size;
119 Rotation rot;
120 XRRScreenConfiguration *sc;
121 short rate;
122 unsigned int i;
123 int res = -1;
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)
134 res = i;
135 break;
138 if (res == -1)
140 ERR("In unknown mode, returning default\n");
141 res = 0;
143 return res;
146 static LONG xrandr10_set_current_mode( int mode )
148 SizeID size;
149 Rotation rot;
150 Window root;
151 XRRScreenConfiguration *sc;
152 Status stat;
153 short rate;
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;
168 if (rate)
169 stat = pXRRSetScreenConfigAndRate( gdi_display, sc, root, size, rot, rate, CurrentTime );
170 else
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;
188 int sizes_count;
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)
197 int rates_count;
198 short *rates;
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);
202 if (rates_count)
204 nmodes += rates_count;
205 for (j = 0; j < rates_count; ++j)
207 if (j > 0)
208 TRACE(",");
209 TRACE(" %d", rates[j]);
212 else
214 ++nmodes;
215 TRACE(" <default>");
217 TRACE(" Hz\n");
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");
225 return;
228 dd_modes = X11DRV_Settings_SetHandlers( "XRandR 1.0",
229 xrandr10_get_current_mode,
230 xrandr10_set_current_mode,
231 nmodes, 1 );
233 xrandr_mode_count = 0;
234 for (i = 0; i < sizes_count; ++i)
236 int rates_count;
237 short *rates;
239 rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count );
241 if (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;
249 else
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;
269 int i, ret = -1;
271 if (!(resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window )))
273 ERR("Failed to get screen resources.\n");
274 return 0;
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");
282 return 0;
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)
292 ret = i;
293 break;
297 pXRRFreeCrtcInfo( crtc_info );
298 pXRRFreeScreenResources( resources );
300 if (ret == -1)
302 ERR("Unknown mode, returning default.\n");
303 ret = 0;
306 return ret;
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;
354 int i;
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 );
362 continue;
365 *crtc_idx = i;
366 return crtc_info;
369 return NULL;
372 static int xrandr12_init_modes(void)
374 XRRScreenResources *resources;
375 XRROutputInfo *output_info;
376 XRRCrtcInfo *crtc_info;
377 int ret = -1;
378 int i, j;
380 if (!(resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window )))
382 ERR("Failed to get screen resources.\n");
383 return ret;
386 if (!resources->ncrtc)
388 pXRRFreeScreenResources( resources );
389 if (!(resources = pXRRGetScreenResources( gdi_display, root_window )))
391 ERR("Failed to get screen resources.\n");
392 return ret;
396 if (!(crtc_info = xrandr12_get_primary_crtc_info( resources, &primary_crtc )))
398 pXRRFreeScreenResources( resources );
399 ERR("Failed to get primary CRTC info.\n");
400 return ret;
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");
411 return ret;
414 TRACE("OUTPUT 0: name %s.\n", debugstr_a(output_info->name));
416 if (!output_info->nmode)
418 ERR("Output has no modes.\n");
419 goto done;
422 if (!(xrandr12_modes = HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr12_modes) * output_info->nmode )))
424 ERR("Failed to allocate xrandr mode info array.\n");
425 goto done;
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;
448 break;
453 X11DRV_Settings_AddDepthModes();
454 ret = 0;
456 done:
457 pXRRFreeOutputInfo( output_info );
458 pXRRFreeCrtcInfo( crtc_info );
459 pXRRFreeScreenResources( resources );
460 return ret;
463 #endif /* HAVE_XRRGETSCREENRESOURCES */
465 void X11DRV_XRandR_Init(void)
467 int event_base, error_base, minor, ret;
468 static int major;
469 Bool ok;
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)
494 #endif
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 */