winex11.drv: Remove XRandR 1.2 display settings handler.
[wine.git] / dlls / winex11.drv / xrandr.c
blobd111b960fa697e74986b78d984f8e6ae78208bc2
1 /*
2 * Wine X11drv Xrandr interface
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2012 Henri Verbeet for CodeWeavers
6 * Copyright 2019 Zhiyi Zhang for CodeWeavers
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #define NONAMELESSSTRUCT
27 #define NONAMELESSUNION
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
32 #ifdef HAVE_XRRGETPROVIDERRESOURCES
33 WINE_DECLARE_DEBUG_CHANNEL(winediag);
34 #endif
36 #ifdef SONAME_LIBXRANDR
38 #include <assert.h>
39 #include <X11/Xlib.h>
40 #include <X11/extensions/Xrandr.h>
41 #include "x11drv.h"
43 #define VK_NO_PROTOTYPES
44 #define WINE_VK_HOST
46 #include "wine/heap.h"
47 #include "wine/unicode.h"
48 #include "wine/vulkan.h"
49 #include "wine/vulkan_driver.h"
51 static void *xrandr_handle;
53 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
54 MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
55 MAKE_FUNCPTR(XRRConfigCurrentRate)
56 MAKE_FUNCPTR(XRRFreeScreenConfigInfo)
57 MAKE_FUNCPTR(XRRGetScreenInfo)
58 MAKE_FUNCPTR(XRRQueryExtension)
59 MAKE_FUNCPTR(XRRQueryVersion)
60 MAKE_FUNCPTR(XRRRates)
61 MAKE_FUNCPTR(XRRSetScreenConfig)
62 MAKE_FUNCPTR(XRRSetScreenConfigAndRate)
63 MAKE_FUNCPTR(XRRSizes)
65 #ifdef HAVE_XRRGETPROVIDERRESOURCES
66 MAKE_FUNCPTR(XRRFreeCrtcInfo)
67 MAKE_FUNCPTR(XRRFreeOutputInfo)
68 MAKE_FUNCPTR(XRRFreeScreenResources)
69 MAKE_FUNCPTR(XRRGetCrtcInfo)
70 MAKE_FUNCPTR(XRRGetOutputInfo)
71 MAKE_FUNCPTR(XRRGetScreenResources)
72 MAKE_FUNCPTR(XRRGetScreenResourcesCurrent)
73 MAKE_FUNCPTR(XRRGetScreenSizeRange)
74 MAKE_FUNCPTR(XRRSetCrtcConfig)
75 MAKE_FUNCPTR(XRRSetScreenSize)
76 MAKE_FUNCPTR(XRRSelectInput)
77 MAKE_FUNCPTR(XRRGetOutputPrimary)
78 MAKE_FUNCPTR(XRRGetProviderResources)
79 MAKE_FUNCPTR(XRRFreeProviderResources)
80 MAKE_FUNCPTR(XRRGetProviderInfo)
81 MAKE_FUNCPTR(XRRFreeProviderInfo)
82 #endif
84 #undef MAKE_FUNCPTR
86 static struct x11drv_mode_info *dd_modes;
87 static SizeID *xrandr10_modes;
88 static unsigned int xrandr_mode_count;
89 static int xrandr_current_mode = -1;
91 static int load_xrandr(void)
93 int r = 0;
95 if (dlopen(SONAME_LIBXRENDER, RTLD_NOW|RTLD_GLOBAL) &&
96 (xrandr_handle = dlopen(SONAME_LIBXRANDR, RTLD_NOW)))
99 #define LOAD_FUNCPTR(f) \
100 if((p##f = dlsym(xrandr_handle, #f)) == NULL) goto sym_not_found
102 LOAD_FUNCPTR(XRRConfigCurrentConfiguration);
103 LOAD_FUNCPTR(XRRConfigCurrentRate);
104 LOAD_FUNCPTR(XRRFreeScreenConfigInfo);
105 LOAD_FUNCPTR(XRRGetScreenInfo);
106 LOAD_FUNCPTR(XRRQueryExtension);
107 LOAD_FUNCPTR(XRRQueryVersion);
108 LOAD_FUNCPTR(XRRRates);
109 LOAD_FUNCPTR(XRRSetScreenConfig);
110 LOAD_FUNCPTR(XRRSetScreenConfigAndRate);
111 LOAD_FUNCPTR(XRRSizes);
112 r = 1;
114 #ifdef HAVE_XRRGETPROVIDERRESOURCES
115 LOAD_FUNCPTR(XRRFreeCrtcInfo);
116 LOAD_FUNCPTR(XRRFreeOutputInfo);
117 LOAD_FUNCPTR(XRRFreeScreenResources);
118 LOAD_FUNCPTR(XRRGetCrtcInfo);
119 LOAD_FUNCPTR(XRRGetOutputInfo);
120 LOAD_FUNCPTR(XRRGetScreenResources);
121 LOAD_FUNCPTR(XRRGetScreenResourcesCurrent);
122 LOAD_FUNCPTR(XRRGetScreenSizeRange);
123 LOAD_FUNCPTR(XRRSetCrtcConfig);
124 LOAD_FUNCPTR(XRRSetScreenSize);
125 LOAD_FUNCPTR(XRRSelectInput);
126 LOAD_FUNCPTR(XRRGetOutputPrimary);
127 LOAD_FUNCPTR(XRRGetProviderResources);
128 LOAD_FUNCPTR(XRRFreeProviderResources);
129 LOAD_FUNCPTR(XRRGetProviderInfo);
130 LOAD_FUNCPTR(XRRFreeProviderInfo);
131 r = 4;
132 #endif
134 #undef LOAD_FUNCPTR
136 sym_not_found:
137 if (!r) TRACE("Unable to load function ptrs from XRandR library\n");
139 return r;
142 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
144 return 1;
147 static int xrandr10_get_current_mode(void)
149 SizeID size;
150 Rotation rot;
151 XRRScreenConfiguration *sc;
152 short rate;
153 unsigned int i;
154 int res = -1;
156 if (xrandr_current_mode != -1)
157 return xrandr_current_mode;
159 sc = pXRRGetScreenInfo (gdi_display, DefaultRootWindow( gdi_display ));
160 size = pXRRConfigCurrentConfiguration (sc, &rot);
161 rate = pXRRConfigCurrentRate (sc);
162 pXRRFreeScreenConfigInfo(sc);
164 for (i = 0; i < xrandr_mode_count; ++i)
166 if (xrandr10_modes[i] == size && dd_modes[i].refresh_rate == rate)
168 res = i;
169 break;
172 if (res == -1)
174 ERR("In unknown mode, returning default\n");
175 return 0;
178 xrandr_current_mode = res;
179 return res;
182 static LONG xrandr10_set_current_mode( int mode )
184 SizeID size;
185 Rotation rot;
186 Window root;
187 XRRScreenConfiguration *sc;
188 Status stat;
189 short rate;
191 root = DefaultRootWindow( gdi_display );
192 sc = pXRRGetScreenInfo (gdi_display, root);
193 pXRRConfigCurrentConfiguration (sc, &rot);
194 mode = mode % xrandr_mode_count;
196 TRACE("Changing Resolution to %dx%d @%d Hz\n",
197 dd_modes[mode].width,
198 dd_modes[mode].height,
199 dd_modes[mode].refresh_rate);
201 size = xrandr10_modes[mode];
202 rate = dd_modes[mode].refresh_rate;
204 if (rate)
205 stat = pXRRSetScreenConfigAndRate( gdi_display, sc, root, size, rot, rate, CurrentTime );
206 else
207 stat = pXRRSetScreenConfig( gdi_display, sc, root, size, rot, CurrentTime );
209 pXRRFreeScreenConfigInfo(sc);
211 if (stat == RRSetConfigSuccess)
213 xrandr_current_mode = mode;
214 X11DRV_DisplayDevices_Update( TRUE );
215 return DISP_CHANGE_SUCCESSFUL;
218 ERR("Resolution change not successful -- perhaps display has changed?\n");
219 return DISP_CHANGE_FAILED;
222 static void xrandr10_init_modes(void)
224 XRRScreenSize *sizes;
225 int sizes_count;
226 int i, j, nmodes = 0;
228 sizes = pXRRSizes( gdi_display, DefaultScreen(gdi_display), &sizes_count );
229 if (sizes_count <= 0) return;
231 TRACE("XRandR: found %d sizes.\n", sizes_count);
232 for (i = 0; i < sizes_count; ++i)
234 int rates_count;
235 short *rates;
237 rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count );
238 TRACE("- at %d: %dx%d (%d rates):", i, sizes[i].width, sizes[i].height, rates_count);
239 if (rates_count)
241 nmodes += rates_count;
242 for (j = 0; j < rates_count; ++j)
244 if (j > 0)
245 TRACE(",");
246 TRACE(" %d", rates[j]);
249 else
251 ++nmodes;
252 TRACE(" <default>");
254 TRACE(" Hz\n");
257 TRACE("XRandR modes: count=%d\n", nmodes);
259 if (!(xrandr10_modes = HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr10_modes) * nmodes )))
261 ERR("Failed to allocate xrandr mode info array.\n");
262 return;
265 dd_modes = X11DRV_Settings_SetHandlers( "XRandR 1.0",
266 xrandr10_get_current_mode,
267 xrandr10_set_current_mode,
268 nmodes, 1 );
270 xrandr_mode_count = 0;
271 for (i = 0; i < sizes_count; ++i)
273 int rates_count;
274 short *rates;
276 rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count );
278 if (rates_count)
280 for (j = 0; j < rates_count; ++j)
282 X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, rates[j] );
283 xrandr10_modes[xrandr_mode_count++] = i;
286 else
288 X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, 0 );
289 xrandr10_modes[xrandr_mode_count++] = i;
293 X11DRV_Settings_AddDepthModes();
294 nmodes = X11DRV_Settings_GetModeCount();
296 TRACE("Available DD modes: count=%d\n", nmodes);
297 TRACE("Enabling XRandR\n");
300 #ifdef HAVE_XRRGETPROVIDERRESOURCES
302 static XRRScreenResources *xrandr_get_screen_resources(void)
304 XRRScreenResources *resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window );
305 if (resources && !resources->ncrtc)
307 pXRRFreeScreenResources( resources );
308 resources = pXRRGetScreenResources( gdi_display, root_window );
311 if (!resources)
312 ERR("Failed to get screen resources.\n");
313 return resources;
316 /* Some (304.64, possibly earlier) versions of the NVIDIA driver only
317 * report a DFP's native mode through RandR 1.2 / 1.3. Standard DMT modes
318 * are only listed through RandR 1.0 / 1.1. This is completely useless,
319 * but NVIDIA considers this a feature, so it's unlikely to change. The
320 * best we can do is to fall back to RandR 1.0 and encourage users to
321 * consider more cooperative driver vendors when we detect such a
322 * configuration. */
323 static BOOL is_broken_driver(void)
325 XRRScreenResources *screen_resources;
326 XRROutputInfo *output_info;
327 XRRModeInfo *first_mode;
328 INT major, event, error;
329 INT output_idx, i, j;
330 BOOL only_one_mode;
332 screen_resources = xrandr_get_screen_resources();
333 if (!screen_resources)
334 return TRUE;
336 /* Check if any output only has one native mode */
337 for (output_idx = 0; output_idx < screen_resources->noutput; ++output_idx)
339 output_info = pXRRGetOutputInfo( gdi_display, screen_resources,
340 screen_resources->outputs[output_idx] );
341 if (!output_info)
342 continue;
344 if (output_info->connection != RR_Connected)
346 pXRRFreeOutputInfo( output_info );
347 continue;
350 first_mode = NULL;
351 only_one_mode = TRUE;
352 for (i = 0; i < output_info->nmode; ++i)
354 for (j = 0; j < screen_resources->nmode; ++j)
356 if (output_info->modes[i] != screen_resources->modes[j].id)
357 continue;
359 if (!first_mode)
361 first_mode = &screen_resources->modes[j];
362 break;
365 if (first_mode->width != screen_resources->modes[j].width ||
366 first_mode->height != screen_resources->modes[j].height)
367 only_one_mode = FALSE;
369 break;
372 if (!only_one_mode)
373 break;
375 pXRRFreeOutputInfo( output_info );
377 if (!only_one_mode)
378 continue;
380 /* Check if it is NVIDIA proprietary driver */
381 if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error ))
383 ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. "
384 "Please consider using the Nouveau driver instead.\n");
385 pXRRFreeScreenResources( screen_resources );
386 return TRUE;
389 pXRRFreeScreenResources( screen_resources );
390 return FALSE;
393 static void get_screen_size( XRRScreenResources *resources, unsigned int *width, unsigned int *height )
395 int min_width = 0, min_height = 0, max_width, max_height;
396 XRRCrtcInfo *crtc_info;
397 int i;
399 pXRRGetScreenSizeRange( gdi_display, root_window, &min_width, &min_height, &max_width, &max_height );
400 *width = min_width;
401 *height = min_height;
403 for (i = 0; i < resources->ncrtc; ++i)
405 if (!(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] )))
406 continue;
408 if (crtc_info->mode != None)
410 *width = max(*width, crtc_info->x + crtc_info->width);
411 *height = max(*height, crtc_info->y + crtc_info->height);
414 pXRRFreeCrtcInfo( crtc_info );
418 static void set_screen_size( int width, int height )
420 int screen = default_visual.screen;
421 int mm_width, mm_height;
423 mm_width = width * DisplayWidthMM( gdi_display, screen ) / DisplayWidth( gdi_display, screen );
424 mm_height = height * DisplayHeightMM( gdi_display, screen ) / DisplayHeight( gdi_display, screen );
425 pXRRSetScreenSize( gdi_display, root_window, width, height, mm_width, mm_height );
428 static unsigned int get_frequency( const XRRModeInfo *mode )
430 unsigned int dots = mode->hTotal * mode->vTotal;
432 if (!dots)
433 return 0;
435 if (mode->modeFlags & RR_DoubleScan)
436 dots *= 2;
437 if (mode->modeFlags & RR_Interlace)
438 dots /= 2;
440 return (mode->dotClock + dots / 2) / dots;
443 static RECT get_primary_rect( XRRScreenResources *resources )
445 XRROutputInfo *output_info = NULL;
446 XRRCrtcInfo *crtc_info = NULL;
447 RROutput primary_output;
448 RECT primary_rect = {0};
449 RECT first_rect = {0};
450 INT i;
452 primary_output = pXRRGetOutputPrimary( gdi_display, root_window );
453 if (!primary_output)
454 goto fallback;
456 output_info = pXRRGetOutputInfo( gdi_display, resources, primary_output );
457 if (!output_info || output_info->connection != RR_Connected || !output_info->crtc)
458 goto fallback;
460 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtc );
461 if (!crtc_info || !crtc_info->mode)
462 goto fallback;
464 SetRect( &primary_rect, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
465 pXRRFreeCrtcInfo( crtc_info );
466 pXRRFreeOutputInfo( output_info );
467 return primary_rect;
469 /* Fallback when XRandR primary output is a disconnected output.
470 * Try to find a crtc with (x, y) being (0, 0). If it's found then get the primary rect from that crtc,
471 * otherwise use the first active crtc to get the primary rect */
472 fallback:
473 if (crtc_info)
474 pXRRFreeCrtcInfo( crtc_info );
475 if (output_info)
476 pXRRFreeOutputInfo( output_info );
478 WARN("Primary is set to a disconnected XRandR output.\n");
479 for (i = 0; i < resources->ncrtc; ++i)
481 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] );
482 if (!crtc_info)
483 continue;
485 if (!crtc_info->mode)
487 pXRRFreeCrtcInfo( crtc_info );
488 continue;
491 if (!crtc_info->x && !crtc_info->y)
493 SetRect( &primary_rect, 0, 0, crtc_info->width, crtc_info->height );
494 pXRRFreeCrtcInfo( crtc_info );
495 break;
498 if (IsRectEmpty( &first_rect ))
499 SetRect( &first_rect, crtc_info->x, crtc_info->y,
500 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
502 pXRRFreeCrtcInfo( crtc_info );
505 return IsRectEmpty( &primary_rect ) ? first_rect : primary_rect;
508 static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc )
510 return crtc &&
511 crtc->mode &&
512 crtc->x == primary.left &&
513 crtc->y == primary.top &&
514 crtc->x + crtc->width == primary.right &&
515 crtc->y + crtc->height == primary.bottom;
518 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
520 static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRProviderInfo *provider_info )
522 static const char *extensions[] =
524 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
525 "VK_EXT_acquire_xlib_display",
526 "VK_EXT_direct_mode_display",
528 const struct vulkan_funcs *vulkan_funcs = get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION );
529 VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
530 PFN_vkGetPhysicalDeviceProperties2 pvkGetPhysicalDeviceProperties2;
531 PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
532 uint32_t device_count, device_idx, output_idx;
533 VkPhysicalDevice *vk_physical_devices = NULL;
534 VkPhysicalDeviceProperties2 properties2;
535 VkInstanceCreateInfo create_info;
536 VkPhysicalDeviceIDProperties id;
537 VkInstance vk_instance = NULL;
538 VkDisplayKHR vk_display;
539 BOOL ret = FALSE;
540 VkResult vr;
542 if (!vulkan_funcs)
543 goto done;
545 memset( &create_info, 0, sizeof(create_info) );
546 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
547 create_info.enabledExtensionCount = ARRAY_SIZE(extensions);
548 create_info.ppEnabledExtensionNames = extensions;
550 vr = vulkan_funcs->p_vkCreateInstance( &create_info, NULL, &vk_instance );
551 if (vr != VK_SUCCESS)
553 WARN("Failed to create a Vulkan instance, vr %d.\n", vr);
554 goto done;
557 #define LOAD_VK_FUNC(f) \
558 if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \
560 WARN("Failed to load " #f ".\n"); \
561 goto done; \
564 LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
565 LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2)
566 LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
567 #undef LOAD_VK_FUNC
569 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
570 if (vr != VK_SUCCESS || !device_count)
572 WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count);
573 goto done;
576 if (!(vk_physical_devices = heap_calloc( device_count, sizeof(*vk_physical_devices) )))
577 goto done;
579 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
580 if (vr != VK_SUCCESS)
582 WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr);
583 goto done;
586 for (device_idx = 0; device_idx < device_count; ++device_idx)
588 for (output_idx = 0; output_idx < provider_info->noutputs; ++output_idx)
590 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
591 vr = pvkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
592 provider_info->outputs[output_idx], &vk_display );
593 XSync( gdi_display, FALSE );
594 if (X11DRV_check_error() || vr != VK_SUCCESS || vk_display == VK_NULL_HANDLE)
595 continue;
597 memset( &id, 0, sizeof(id) );
598 id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
599 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
600 properties2.pNext = &id;
602 pvkGetPhysicalDeviceProperties2( vk_physical_devices[device_idx], &properties2 );
603 memcpy( &gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) );
604 /* Ignore Khronos vendor IDs */
605 if (properties2.properties.vendorID < 0x10000)
607 gpu->vendor_id = properties2.properties.vendorID;
608 gpu->device_id = properties2.properties.deviceID;
610 MultiByteToWideChar( CP_UTF8, 0, properties2.properties.deviceName, -1, gpu->name, ARRAY_SIZE(gpu->name) );
611 ret = TRUE;
612 goto done;
616 done:
617 heap_free( vk_physical_devices );
618 if (vk_instance)
619 vulkan_funcs->p_vkDestroyInstance( vk_instance, NULL );
620 return ret;
623 /* Get a list of GPUs reported by XRandR 1.4. Set get_properties to FALSE if GPU properties are
624 * not needed to avoid unnecessary querying */
625 static BOOL xrandr14_get_gpus2( struct x11drv_gpu **new_gpus, int *count, BOOL get_properties )
627 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
628 struct x11drv_gpu *gpus = NULL;
629 XRRScreenResources *screen_resources = NULL;
630 XRRProviderResources *provider_resources = NULL;
631 XRRProviderInfo *provider_info = NULL;
632 XRRCrtcInfo *crtc_info = NULL;
633 INT primary_provider = -1;
634 RECT primary_rect;
635 BOOL ret = FALSE;
636 INT i, j;
638 screen_resources = xrandr_get_screen_resources();
639 if (!screen_resources)
640 goto done;
642 provider_resources = pXRRGetProviderResources( gdi_display, root_window );
643 if (!provider_resources)
644 goto done;
646 gpus = heap_calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) );
647 if (!gpus)
648 goto done;
650 /* Some XRandR implementations don't support providers.
651 * In this case, report a fake one to try searching adapters in screen resources */
652 if (!provider_resources->nproviders)
654 WARN("XRandR implementation doesn't report any providers, faking one.\n");
655 lstrcpyW( gpus[0].name, wine_adapterW );
656 *new_gpus = gpus;
657 *count = 1;
658 ret = TRUE;
659 goto done;
662 primary_rect = get_primary_rect( screen_resources );
663 for (i = 0; i < provider_resources->nproviders; ++i)
665 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, provider_resources->providers[i] );
666 if (!provider_info)
667 goto done;
669 /* Find primary provider */
670 for (j = 0; primary_provider == -1 && j < provider_info->ncrtcs; ++j)
672 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, provider_info->crtcs[j] );
673 if (!crtc_info)
674 continue;
676 if (is_crtc_primary( primary_rect, crtc_info ))
678 primary_provider = i;
679 pXRRFreeCrtcInfo( crtc_info );
680 break;
683 pXRRFreeCrtcInfo( crtc_info );
686 gpus[i].id = provider_resources->providers[i];
687 if (get_properties)
689 if (!get_gpu_properties_from_vulkan( &gpus[i], provider_info ))
690 MultiByteToWideChar( CP_UTF8, 0, provider_info->name, -1, gpus[i].name, ARRAY_SIZE(gpus[i].name) );
691 /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */
693 pXRRFreeProviderInfo( provider_info );
696 /* Make primary GPU the first */
697 if (primary_provider > 0)
699 struct x11drv_gpu tmp = gpus[0];
700 gpus[0] = gpus[primary_provider];
701 gpus[primary_provider] = tmp;
704 *new_gpus = gpus;
705 *count = provider_resources->nproviders;
706 ret = TRUE;
707 done:
708 if (provider_resources)
709 pXRRFreeProviderResources( provider_resources );
710 if (screen_resources)
711 pXRRFreeScreenResources( screen_resources );
712 if (!ret)
714 heap_free( gpus );
715 ERR("Failed to get gpus\n");
717 return ret;
720 static BOOL xrandr14_get_gpus( struct x11drv_gpu **new_gpus, int *count )
722 return xrandr14_get_gpus2( new_gpus, count, TRUE );
725 static void xrandr14_free_gpus( struct x11drv_gpu *gpus )
727 heap_free( gpus );
730 static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct x11drv_adapter **new_adapters, int *count )
732 struct x11drv_adapter *adapters = NULL;
733 XRRScreenResources *screen_resources = NULL;
734 XRRProviderInfo *provider_info = NULL;
735 XRRCrtcInfo *enum_crtc_info, *crtc_info = NULL;
736 XRROutputInfo *enum_output_info, *output_info = NULL;
737 RROutput *outputs;
738 INT crtc_count, output_count;
739 INT primary_adapter = 0;
740 INT adapter_count = 0;
741 BOOL mirrored, detached;
742 RECT primary_rect;
743 BOOL ret = FALSE;
744 INT i, j;
746 screen_resources = xrandr_get_screen_resources();
747 if (!screen_resources)
748 goto done;
750 if (gpu_id)
752 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id );
753 if (!provider_info)
754 goto done;
756 crtc_count = provider_info->ncrtcs;
757 output_count = provider_info->noutputs;
758 outputs = provider_info->outputs;
760 /* Fake provider id, search adapters in screen resources */
761 else
763 crtc_count = screen_resources->ncrtc;
764 output_count = screen_resources->noutput;
765 outputs = screen_resources->outputs;
768 /* Actual adapter count could be less */
769 adapters = heap_calloc( crtc_count, sizeof(*adapters) );
770 if (!adapters)
771 goto done;
773 primary_rect = get_primary_rect( screen_resources );
774 for (i = 0; i < output_count; ++i)
776 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, outputs[i] );
777 if (!output_info)
778 goto done;
780 /* Only connected output are considered as monitors */
781 if (output_info->connection != RR_Connected)
783 pXRRFreeOutputInfo( output_info );
784 output_info = NULL;
785 continue;
788 /* Connected output doesn't mean the output is attached to a crtc */
789 detached = FALSE;
790 if (output_info->crtc)
792 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
793 if (!crtc_info)
794 goto done;
797 if (!output_info->crtc || !crtc_info->mode)
798 detached = TRUE;
800 /* Ignore mirroring output replicas because mirrored monitors are under the same adapter */
801 mirrored = FALSE;
802 if (!detached)
804 for (j = 0; j < screen_resources->noutput; ++j)
806 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[j] );
807 if (!enum_output_info)
808 continue;
810 if (enum_output_info->connection != RR_Connected || !enum_output_info->crtc)
812 pXRRFreeOutputInfo( enum_output_info );
813 continue;
816 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
817 pXRRFreeOutputInfo( enum_output_info );
818 if (!enum_crtc_info)
819 continue;
821 /* Some outputs may have the same coordinates, aka mirrored. Choose the output with
822 * the lowest value as primary and the rest will then be replicas in a mirroring set */
823 if (crtc_info->x == enum_crtc_info->x &&
824 crtc_info->y == enum_crtc_info->y &&
825 crtc_info->width == enum_crtc_info->width &&
826 crtc_info->height == enum_crtc_info->height &&
827 outputs[i] > screen_resources->outputs[j])
829 mirrored = TRUE;
830 pXRRFreeCrtcInfo( enum_crtc_info );
831 break;
834 pXRRFreeCrtcInfo( enum_crtc_info );
838 if (!mirrored || detached)
840 /* Use RROutput as adapter id. The reason of not using RRCrtc is that we need to detect inactive but
841 * attached monitors */
842 adapters[adapter_count].id = outputs[i];
843 if (!detached)
844 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
845 if (is_crtc_primary( primary_rect, crtc_info ))
847 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
848 primary_adapter = adapter_count;
851 ++adapter_count;
854 pXRRFreeOutputInfo( output_info );
855 output_info = NULL;
856 if (crtc_info)
858 pXRRFreeCrtcInfo( crtc_info );
859 crtc_info = NULL;
863 /* Make primary adapter the first */
864 if (primary_adapter)
866 struct x11drv_adapter tmp = adapters[0];
867 adapters[0] = adapters[primary_adapter];
868 adapters[primary_adapter] = tmp;
871 *new_adapters = adapters;
872 *count = adapter_count;
873 ret = TRUE;
874 done:
875 if (screen_resources)
876 pXRRFreeScreenResources( screen_resources );
877 if (provider_info)
878 pXRRFreeProviderInfo( provider_info );
879 if (output_info)
880 pXRRFreeOutputInfo( output_info );
881 if (crtc_info)
882 pXRRFreeCrtcInfo( crtc_info );
883 if (!ret)
885 heap_free( adapters );
886 ERR("Failed to get adapters\n");
888 return ret;
891 static void xrandr14_free_adapters( struct x11drv_adapter *adapters )
893 heap_free( adapters );
896 static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct x11drv_monitor **new_monitors, int *count )
898 static const WCHAR generic_nonpnp_monitorW[] = {
899 'G','e','n','e','r','i','c',' ',
900 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
901 struct x11drv_monitor *realloc_monitors, *monitors = NULL;
902 XRRScreenResources *screen_resources = NULL;
903 XRROutputInfo *output_info = NULL, *enum_output_info = NULL;
904 XRRCrtcInfo *crtc_info = NULL, *enum_crtc_info;
905 INT primary_index = 0, monitor_count = 0, capacity;
906 RECT primary_rect;
907 BOOL ret = FALSE;
908 INT i;
910 screen_resources = xrandr_get_screen_resources();
911 if (!screen_resources)
912 goto done;
914 /* First start with a 2 monitors, should be enough for most cases */
915 capacity = 2;
916 monitors = heap_calloc( capacity, sizeof(*monitors) );
917 if (!monitors)
918 goto done;
920 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, adapter_id );
921 if (!output_info)
922 goto done;
924 if (output_info->crtc)
926 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
927 if (!crtc_info)
928 goto done;
931 /* Inactive but attached monitor, no need to check for mirrored/replica monitors */
932 if (!output_info->crtc || !crtc_info->mode)
934 lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
935 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
936 monitor_count = 1;
938 /* Active monitors, need to find other monitors with the same coordinates as mirrored */
939 else
941 primary_rect = get_primary_rect( screen_resources );
943 for (i = 0; i < screen_resources->noutput; ++i)
945 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
946 if (!enum_output_info)
947 goto done;
949 /* Detached outputs don't count */
950 if (enum_output_info->connection != RR_Connected)
952 pXRRFreeOutputInfo( enum_output_info );
953 enum_output_info = NULL;
954 continue;
957 /* Allocate more space if needed */
958 if (monitor_count >= capacity)
960 capacity *= 2;
961 realloc_monitors = heap_realloc( monitors, capacity * sizeof(*monitors) );
962 if (!realloc_monitors)
963 goto done;
964 monitors = realloc_monitors;
967 if (enum_output_info->crtc)
969 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
970 if (!enum_crtc_info)
971 goto done;
973 if (enum_crtc_info->x == crtc_info->x &&
974 enum_crtc_info->y == crtc_info->y &&
975 enum_crtc_info->width == crtc_info->width &&
976 enum_crtc_info->height == crtc_info->height)
978 /* FIXME: Read output EDID property and parse the data to get the correct name */
979 lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
981 SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y,
982 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
983 monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor );
985 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
986 if (!IsRectEmpty( &monitors[monitor_count].rc_monitor ))
987 monitors[monitor_count].state_flags |= DISPLAY_DEVICE_ACTIVE;
989 if (is_crtc_primary( primary_rect, crtc_info ))
990 primary_index = monitor_count;
991 monitor_count++;
994 pXRRFreeCrtcInfo( enum_crtc_info );
997 pXRRFreeOutputInfo( enum_output_info );
998 enum_output_info = NULL;
1001 /* Make sure the first monitor is the primary */
1002 if (primary_index)
1004 struct x11drv_monitor tmp = monitors[0];
1005 monitors[0] = monitors[primary_index];
1006 monitors[primary_index] = tmp;
1009 /* Make sure the primary monitor origin is at (0, 0) */
1010 for (i = 0; i < monitor_count; i++)
1012 OffsetRect( &monitors[i].rc_monitor, -primary_rect.left, -primary_rect.top );
1013 OffsetRect( &monitors[i].rc_work, -primary_rect.left, -primary_rect.top );
1017 *new_monitors = monitors;
1018 *count = monitor_count;
1019 ret = TRUE;
1020 done:
1021 if (screen_resources)
1022 pXRRFreeScreenResources( screen_resources );
1023 if (output_info)
1024 pXRRFreeOutputInfo( output_info);
1025 if (crtc_info)
1026 pXRRFreeCrtcInfo( crtc_info );
1027 if (enum_output_info)
1028 pXRRFreeOutputInfo( enum_output_info );
1029 if (!ret)
1031 heap_free( monitors );
1032 ERR("Failed to get monitors\n");
1034 return ret;
1037 static void xrandr14_free_monitors( struct x11drv_monitor *monitors )
1039 heap_free( monitors );
1042 static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
1044 if (hwnd == GetDesktopWindow() && GetWindowThreadProcessId( hwnd, NULL ) == GetCurrentThreadId())
1046 /* Don't send a WM_DISPLAYCHANGE message here because this event may be a result from
1047 * ChangeDisplaySettings(). Otherwise, ChangeDisplaySettings() would send multiple
1048 * WM_DISPLAYCHANGE messages instead of just one */
1049 X11DRV_DisplayDevices_Update( FALSE );
1051 return FALSE;
1054 static void xrandr14_register_event_handlers(void)
1056 Display *display = thread_init_display();
1057 int event_base, error_base;
1059 if (!pXRRQueryExtension( display, &event_base, &error_base ))
1060 return;
1062 pXRRSelectInput( display, root_window,
1063 RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RRProviderChangeNotifyMask );
1064 X11DRV_register_event_handler( event_base + RRNotify_CrtcChange, xrandr14_device_change_handler,
1065 "XRandR CrtcChange" );
1066 X11DRV_register_event_handler( event_base + RRNotify_OutputChange, xrandr14_device_change_handler,
1067 "XRandR OutputChange" );
1068 X11DRV_register_event_handler( event_base + RRNotify_ProviderChange, xrandr14_device_change_handler,
1069 "XRandR ProviderChange" );
1072 /* XRandR 1.4 display settings handler */
1073 static BOOL xrandr14_get_id( const WCHAR *device_name, ULONG_PTR *id )
1075 INT gpu_count, adapter_count, display_count = 0;
1076 INT gpu_idx, adapter_idx, display_idx;
1077 struct x11drv_adapter *adapters;
1078 struct x11drv_gpu *gpus;
1079 WCHAR *end;
1081 /* Parse \\.\DISPLAY%d */
1082 display_idx = strtolW( device_name + 11, &end, 10 ) - 1;
1083 if (*end)
1084 return FALSE;
1086 if (!xrandr14_get_gpus2( &gpus, &gpu_count, FALSE ))
1087 return FALSE;
1089 for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx)
1091 if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count ))
1093 xrandr14_free_gpus( gpus );
1094 return FALSE;
1097 adapter_idx = display_idx - display_count;
1098 if (adapter_idx < adapter_count)
1100 *id = adapters[adapter_idx].id;
1101 xrandr14_free_adapters( adapters );
1102 xrandr14_free_gpus( gpus );
1103 return TRUE;
1106 display_count += adapter_count;
1107 xrandr14_free_adapters( adapters );
1109 xrandr14_free_gpus( gpus );
1110 return FALSE;
1113 static void add_xrandr14_mode( DEVMODEW *mode, XRRModeInfo *info, DWORD depth, DWORD frequency )
1115 mode->dmSize = sizeof(*mode);
1116 mode->dmDriverExtra = sizeof(RRMode);
1117 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
1118 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
1119 if (frequency)
1121 mode->dmFields |= DM_DISPLAYFREQUENCY;
1122 mode->dmDisplayFrequency = frequency;
1124 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
1125 mode->dmBitsPerPel = depth;
1126 mode->dmPelsWidth = info->width;
1127 mode->dmPelsHeight = info->height;
1128 mode->u2.dmDisplayFlags = 0;
1129 memcpy( (BYTE *)mode + sizeof(*mode), &info->id, sizeof(info->id) );
1132 static BOOL xrandr14_get_modes( ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count )
1134 XRRScreenResources *screen_resources;
1135 XRROutputInfo *output_info = NULL;
1136 RROutput output = (RROutput)id;
1137 UINT depth_idx, mode_idx = 0;
1138 XRRModeInfo *mode_info;
1139 DEVMODEW *mode, *modes;
1140 BOOL ret = FALSE;
1141 DWORD frequency;
1142 INT i, j;
1144 screen_resources = xrandr_get_screen_resources();
1145 if (!screen_resources)
1146 goto done;
1148 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1149 if (!output_info)
1150 goto done;
1152 if (output_info->connection != RR_Connected)
1154 ret = TRUE;
1155 *new_modes = NULL;
1156 *mode_count = 0;
1157 goto done;
1160 /* Allocate space for display modes in different color depths.
1161 * Store a RRMode at the end of each DEVMODEW as private driver data */
1162 modes = heap_calloc( output_info->nmode * DEPTH_COUNT, sizeof(*modes) + sizeof(RRMode) );
1163 if (!modes)
1164 goto done;
1166 for (i = 0; i < output_info->nmode; ++i)
1168 for (j = 0; j < screen_resources->nmode; ++j)
1170 if (output_info->modes[i] != screen_resources->modes[j].id)
1171 continue;
1173 mode_info = &screen_resources->modes[j];
1174 frequency = get_frequency( mode_info );
1176 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
1178 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*modes) + sizeof(RRMode)) * mode_idx);
1179 add_xrandr14_mode( mode, mode_info, depths[depth_idx], frequency );
1180 ++mode_idx;
1183 break;
1187 ret = TRUE;
1188 *new_modes = modes;
1189 *mode_count = mode_idx;
1190 done:
1191 if (output_info)
1192 pXRRFreeOutputInfo( output_info );
1193 if (screen_resources)
1194 pXRRFreeScreenResources( screen_resources );
1195 return ret;
1198 static void xrandr14_free_modes( DEVMODEW *modes )
1200 heap_free( modes );
1203 static BOOL xrandr14_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
1205 XRRScreenResources *screen_resources;
1206 XRROutputInfo *output_info = NULL;
1207 RROutput output = (RROutput)id;
1208 XRRModeInfo *mode_info = NULL;
1209 XRRCrtcInfo *crtc_info = NULL;
1210 BOOL ret = FALSE;
1211 RECT primary;
1212 INT mode_idx;
1214 screen_resources = xrandr_get_screen_resources();
1215 if (!screen_resources)
1216 goto done;
1218 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1219 if (!output_info)
1220 goto done;
1222 if (output_info->crtc)
1224 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1225 if (!crtc_info)
1226 goto done;
1229 /* Detached */
1230 if (output_info->connection != RR_Connected || !output_info->crtc || !crtc_info->mode)
1232 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1233 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1234 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
1235 mode->dmBitsPerPel = 0;
1236 mode->dmPelsWidth = 0;
1237 mode->dmPelsHeight = 0;
1238 mode->u2.dmDisplayFlags = 0;
1239 mode->dmDisplayFrequency = 0;
1240 mode->u1.s2.dmPosition.x = 0;
1241 mode->u1.s2.dmPosition.y = 0;
1242 ret = TRUE;
1243 goto done;
1246 /* Attached */
1247 for (mode_idx = 0; mode_idx < screen_resources->nmode; ++mode_idx)
1249 if (crtc_info->mode == screen_resources->modes[mode_idx].id)
1251 mode_info = &screen_resources->modes[mode_idx];
1252 break;
1256 if (!mode_info)
1257 goto done;
1259 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1260 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1261 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
1262 mode->dmBitsPerPel = screen_bpp;
1263 mode->dmPelsWidth = mode_info->width;
1264 mode->dmPelsHeight = mode_info->height;
1265 mode->u2.dmDisplayFlags = 0;
1266 mode->dmDisplayFrequency = get_frequency( mode_info );
1267 /* Convert RandR coordinates to virtual screen coordinates */
1268 primary = get_primary_rect( screen_resources );
1269 mode->u1.s2.dmPosition.x = crtc_info->x - primary.left;
1270 mode->u1.s2.dmPosition.y = crtc_info->y - primary.top;
1271 ret = TRUE;
1272 done:
1273 if (crtc_info)
1274 pXRRFreeCrtcInfo( crtc_info );
1275 if (output_info)
1276 pXRRFreeOutputInfo( output_info );
1277 if (screen_resources)
1278 pXRRFreeScreenResources( screen_resources );
1279 return ret;
1282 static LONG xrandr14_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
1284 unsigned int screen_width, screen_height;
1285 RROutput output = (RROutput)id, *outputs;
1286 XRRScreenResources *screen_resources;
1287 XRROutputInfo *output_info = NULL;
1288 XRRCrtcInfo *crtc_info = NULL;
1289 LONG ret = DISP_CHANGE_FAILED;
1290 INT crtc_idx, output_count;
1291 Rotation rotation;
1292 RRCrtc crtc = 0;
1293 Status status;
1294 RRMode rrmode;
1296 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
1297 WARN("Cannot change screen color depth from %ubits to %ubits!\n", screen_bpp, mode->dmBitsPerPel);
1299 screen_resources = xrandr_get_screen_resources();
1300 if (!screen_resources)
1301 return ret;
1303 XGrabServer( gdi_display );
1305 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1306 if (!output_info || output_info->connection != RR_Connected)
1307 goto done;
1309 /* Attached */
1310 if (output_info->crtc)
1312 crtc = output_info->crtc;
1314 /* Detached, need to find a free CRTC */
1315 else
1317 for (crtc_idx = 0; crtc_idx < output_info->ncrtc; ++crtc_idx)
1319 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtcs[crtc_idx] );
1320 if (!crtc_info)
1321 goto done;
1323 if (!crtc_info->noutput)
1325 crtc = output_info->crtcs[crtc_idx];
1326 pXRRFreeCrtcInfo( crtc_info );
1327 crtc_info = NULL;
1328 break;
1331 pXRRFreeCrtcInfo( crtc_info );
1332 crtc_info = NULL;
1335 /* Failed to find a free CRTC */
1336 if (crtc_idx == output_info->ncrtc)
1337 goto done;
1340 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1341 if (!crtc_info)
1342 goto done;
1344 assert( mode->dmDriverExtra == sizeof(RRMode) );
1345 memcpy( &rrmode, (BYTE *)mode + sizeof(*mode), sizeof(rrmode) );
1347 if (crtc_info->noutput)
1349 outputs = crtc_info->outputs;
1350 output_count = crtc_info->noutput;
1351 rotation = crtc_info->rotation;
1353 else
1355 outputs = &output;
1356 output_count = 1;
1357 rotation = RR_Rotate_0;
1360 /* According to the RandR spec, the entire CRTC must fit inside the screen.
1361 * Since we use the union of all enabled CRTCs to determine the necessary
1362 * screen size, this might involve shrinking the screen, so we must disable
1363 * the CRTC in question first. */
1364 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime, 0, 0, None,
1365 RR_Rotate_0, NULL, 0 );
1366 if (status != RRSetConfigSuccess)
1367 goto done;
1369 get_screen_size( screen_resources, &screen_width, &screen_height );
1370 screen_width = max( screen_width, crtc_info->x + mode->dmPelsWidth );
1371 screen_height = max( screen_height, crtc_info->y + mode->dmPelsHeight );
1372 set_screen_size( screen_width, screen_height );
1374 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
1375 crtc_info->x, crtc_info->y, rrmode, rotation, outputs, output_count );
1376 if (status == RRSetConfigSuccess)
1377 ret = DISP_CHANGE_SUCCESSFUL;
1379 done:
1380 XUngrabServer( gdi_display );
1381 XFlush( gdi_display );
1382 if (crtc_info)
1383 pXRRFreeCrtcInfo( crtc_info );
1384 if (output_info)
1385 pXRRFreeOutputInfo( output_info );
1386 pXRRFreeScreenResources( screen_resources );
1387 return ret;
1390 #endif
1392 void X11DRV_XRandR_Init(void)
1394 struct x11drv_display_device_handler display_handler;
1395 struct x11drv_settings_handler settings_handler;
1396 int event_base, error_base, minor, ret;
1397 static int major;
1398 Bool ok;
1400 if (major) return; /* already initialized? */
1401 if (!usexrandr) return; /* disabled in config */
1402 if (is_virtual_desktop()) return;
1403 if (!(ret = load_xrandr())) return; /* can't load the Xrandr library */
1405 /* see if Xrandr is available */
1406 if (!pXRRQueryExtension( gdi_display, &event_base, &error_base )) return;
1407 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
1408 ok = pXRRQueryVersion( gdi_display, &major, &minor );
1409 if (X11DRV_check_error() || !ok) return;
1411 TRACE("Found XRandR %d.%d.\n", major, minor);
1413 xrandr10_init_modes();
1415 #ifdef HAVE_XRRGETPROVIDERRESOURCES
1416 if (ret >= 4 && (major > 1 || (major == 1 && minor >= 4)))
1418 display_handler.name = "XRandR 1.4";
1419 display_handler.priority = 200;
1420 display_handler.get_gpus = xrandr14_get_gpus;
1421 display_handler.get_adapters = xrandr14_get_adapters;
1422 display_handler.get_monitors = xrandr14_get_monitors;
1423 display_handler.free_gpus = xrandr14_free_gpus;
1424 display_handler.free_adapters = xrandr14_free_adapters;
1425 display_handler.free_monitors = xrandr14_free_monitors;
1426 display_handler.register_event_handlers = xrandr14_register_event_handlers;
1427 X11DRV_DisplayDevices_SetHandler( &display_handler );
1429 if (is_broken_driver())
1430 return;
1432 settings_handler.name = "XRandR 1.4";
1433 settings_handler.priority = 300;
1434 settings_handler.get_id = xrandr14_get_id;
1435 settings_handler.get_modes = xrandr14_get_modes;
1436 settings_handler.free_modes = xrandr14_free_modes;
1437 settings_handler.get_current_mode = xrandr14_get_current_mode;
1438 settings_handler.set_current_mode = xrandr14_set_current_mode;
1439 X11DRV_Settings_SetHandler( &settings_handler );
1441 #endif
1444 #else /* SONAME_LIBXRANDR */
1446 void X11DRV_XRandR_Init(void)
1448 TRACE("XRandR support not compiled in.\n");
1451 #endif /* SONAME_LIBXRANDR */