diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index 67fd2851825..155bd85d811 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -83,11 +83,6 @@ MAKE_FUNCPTR(XRRFreeProviderInfo) #undef MAKE_FUNCPTR -static struct x11drv_mode_info *dd_modes; -static SizeID *xrandr10_modes; -static unsigned int xrandr_mode_count; -static int xrandr_current_mode = -1; - static int load_xrandr(void) { int r = 0; @@ -144,157 +139,187 @@ static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg) return 1; } -static int xrandr10_get_current_mode(void) +/* XRandR 1.0 display settings handler */ +static BOOL xrandr10_get_id( const WCHAR *device_name, ULONG_PTR *id ) { - SizeID size; - Rotation rot; - XRRScreenConfiguration *sc; - short rate; - unsigned int i; - int res = -1; + WCHAR primary_adapter[CCHDEVICENAME]; - if (xrandr_current_mode != -1) - return xrandr_current_mode; + if (!get_primary_adapter( primary_adapter )) + return FALSE; - sc = pXRRGetScreenInfo (gdi_display, DefaultRootWindow( gdi_display )); - size = pXRRConfigCurrentConfiguration (sc, &rot); - rate = pXRRConfigCurrentRate (sc); - pXRRFreeScreenConfigInfo(sc); - - for (i = 0; i < xrandr_mode_count; ++i) - { - if (xrandr10_modes[i] == size && dd_modes[i].refresh_rate == rate) - { - res = i; - break; - } - } - if (res == -1) - { - ERR("In unknown mode, returning default\n"); - return 0; - } - - xrandr_current_mode = res; - return res; + /* RandR 1.0 only supports changing the primary adapter settings. + * For non-primary adapters, an id is still provided but getting + * and changing non-primary adapters' settings will be ignored. */ + *id = !lstrcmpiW( device_name, primary_adapter ) ? 1 : 0; + return TRUE; } -static LONG xrandr10_set_current_mode( int mode ) +static void add_xrandr10_mode( DEVMODEW *mode, DWORD depth, DWORD width, DWORD height, + DWORD frequency, SizeID size_id ) { - SizeID size; - Rotation rot; - Window root; - XRRScreenConfiguration *sc; - Status stat; + mode->dmSize = sizeof(*mode); + mode->dmDriverExtra = sizeof(SizeID); + mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | + DM_PELSHEIGHT | DM_DISPLAYFLAGS; + if (frequency) + { + mode->dmFields |= DM_DISPLAYFREQUENCY; + mode->dmDisplayFrequency = frequency; + } + mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT; + mode->dmBitsPerPel = depth; + mode->dmPelsWidth = width; + mode->dmPelsHeight = height; + mode->u2.dmDisplayFlags = 0; + memcpy( (BYTE *)mode + sizeof(*mode), &size_id, sizeof(size_id) ); +} + +static BOOL xrandr10_get_modes( ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *new_mode_count ) +{ + INT size_idx, depth_idx, rate_idx, mode_idx = 0; + INT size_count, rate_count, mode_count = 0; + DEVMODEW *modes, *mode; + XRRScreenSize *sizes; + short *rates; + + sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count ); + if (size_count <= 0) + return FALSE; + + for (size_idx = 0; size_idx < size_count; ++size_idx) + { + rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count ); + if (rate_count) + mode_count += rate_count; + else + ++mode_count; + } + + /* Allocate space for reported modes in three depths, and put an SizeID at the end of DEVMODEW as + * driver private data */ + modes = heap_calloc( mode_count * DEPTH_COUNT, sizeof(*modes) + sizeof(SizeID) ); + if (!modes) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + + for (size_idx = 0; size_idx < size_count; ++size_idx) + { + for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx) + { + rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count ); + if (!rate_count) + { + mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++); + add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width, + sizes[size_idx].height, 0, size_idx ); + continue; + } + + for (rate_idx = 0; rate_idx < rate_count; ++rate_idx) + { + mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++); + add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width, + sizes[size_idx].height, rates[rate_idx], size_idx ); + } + } + } + + *new_modes = modes; + *new_mode_count = mode_idx; + return TRUE; +} + +static void xrandr10_free_modes( DEVMODEW *modes ) +{ + heap_free( modes ); +} + +static BOOL xrandr10_get_current_mode( ULONG_PTR id, DEVMODEW *mode ) +{ + XRRScreenConfiguration *screen_config; + XRRScreenSize *sizes; + Rotation rotation; + SizeID size_id; + INT size_count; short rate; - root = DefaultRootWindow( gdi_display ); - sc = pXRRGetScreenInfo (gdi_display, root); - pXRRConfigCurrentConfiguration (sc, &rot); - mode = mode % xrandr_mode_count; + mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | + DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION; + mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT; + mode->u2.dmDisplayFlags = 0; + mode->u1.s2.dmPosition.x = 0; + mode->u1.s2.dmPosition.y = 0; - TRACE("Changing Resolution to %dx%d @%d Hz\n", - dd_modes[mode].width, - dd_modes[mode].height, - dd_modes[mode].refresh_rate); - - size = xrandr10_modes[mode]; - rate = dd_modes[mode].refresh_rate; - - if (rate) - stat = pXRRSetScreenConfigAndRate( gdi_display, sc, root, size, rot, rate, CurrentTime ); - else - stat = pXRRSetScreenConfig( gdi_display, sc, root, size, rot, CurrentTime ); - - pXRRFreeScreenConfigInfo(sc); - - if (stat == RRSetConfigSuccess) + if (id != 1) { - xrandr_current_mode = mode; - X11DRV_DisplayDevices_Update( TRUE ); + FIXME("Non-primary adapters are unsupported.\n"); + mode->dmBitsPerPel = 0; + mode->dmPelsWidth = 0; + mode->dmPelsHeight = 0; + mode->dmDisplayFrequency = 0; + return TRUE; + } + + sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count ); + if (size_count <= 0) + return FALSE; + + screen_config = pXRRGetScreenInfo( gdi_display, DefaultRootWindow( gdi_display ) ); + size_id = pXRRConfigCurrentConfiguration( screen_config, &rotation ); + rate = pXRRConfigCurrentRate( screen_config ); + pXRRFreeScreenConfigInfo( screen_config ); + + mode->dmBitsPerPel = screen_bpp; + mode->dmPelsWidth = sizes[size_id].width; + mode->dmPelsHeight = sizes[size_id].height; + mode->dmDisplayFrequency = rate; + return TRUE; +} + +static LONG xrandr10_set_current_mode( ULONG_PTR id, DEVMODEW *mode ) +{ + XRRScreenConfiguration *screen_config; + Rotation rotation; + SizeID size_id; + Window root; + Status stat; + + if (id != 1) + { + FIXME("Non-primary adapters are unsupported.\n"); return DISP_CHANGE_SUCCESSFUL; } - ERR("Resolution change not successful -- perhaps display has changed?\n"); - return DISP_CHANGE_FAILED; -} - -static void xrandr10_init_modes(void) -{ - XRRScreenSize *sizes; - int sizes_count; - int i, j, nmodes = 0; - - sizes = pXRRSizes( gdi_display, DefaultScreen(gdi_display), &sizes_count ); - if (sizes_count <= 0) return; - - TRACE("XRandR: found %d sizes.\n", sizes_count); - for (i = 0; i < sizes_count; ++i) + if (is_detached_mode(mode)) { - int rates_count; - short *rates; - - rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count ); - TRACE("- at %d: %dx%d (%d rates):", i, sizes[i].width, sizes[i].height, rates_count); - if (rates_count) - { - nmodes += rates_count; - for (j = 0; j < rates_count; ++j) - { - if (j > 0) - TRACE(","); - TRACE(" %d", rates[j]); - } - } - else - { - ++nmodes; - TRACE(" "); - } - TRACE(" Hz\n"); + FIXME("Detaching adapters is unsupported.\n"); + return DISP_CHANGE_SUCCESSFUL; } - TRACE("XRandR modes: count=%d\n", nmodes); + if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp) + WARN("Cannot change screen bit depth from %dbits to %dbits!\n", screen_bpp, mode->dmBitsPerPel); - if (!(xrandr10_modes = HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr10_modes) * nmodes ))) - { - ERR("Failed to allocate xrandr mode info array.\n"); - return; - } + root = DefaultRootWindow( gdi_display ); + screen_config = pXRRGetScreenInfo( gdi_display, root ); + pXRRConfigCurrentConfiguration( screen_config, &rotation ); - dd_modes = X11DRV_Settings_SetHandlers( "XRandR 1.0", - xrandr10_get_current_mode, - xrandr10_set_current_mode, - nmodes, 1 ); + assert( mode->dmDriverExtra == sizeof(SizeID) ); + memcpy( &size_id, (BYTE *)mode + sizeof(*mode), sizeof(size_id) ); - xrandr_mode_count = 0; - for (i = 0; i < sizes_count; ++i) - { - int rates_count; - short *rates; + if (mode->dmFields & DM_DISPLAYFREQUENCY && mode->dmDisplayFrequency) + stat = pXRRSetScreenConfigAndRate( gdi_display, screen_config, root, size_id, rotation, + mode->dmDisplayFrequency, CurrentTime ); + else + stat = pXRRSetScreenConfig( gdi_display, screen_config, root, size_id, rotation, CurrentTime ); + pXRRFreeScreenConfigInfo( screen_config ); - rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count ); + if (stat != RRSetConfigSuccess) + return DISP_CHANGE_FAILED; - if (rates_count) - { - for (j = 0; j < rates_count; ++j) - { - X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, rates[j] ); - xrandr10_modes[xrandr_mode_count++] = i; - } - } - else - { - X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, 0 ); - xrandr10_modes[xrandr_mode_count++] = i; - } - } - - X11DRV_Settings_AddDepthModes(); - nmodes = X11DRV_Settings_GetModeCount(); - - TRACE("Available DD modes: count=%d\n", nmodes); - TRACE("Enabling XRandR\n"); + XFlush( gdi_display ); + return DISP_CHANGE_SUCCESSFUL; } #ifdef HAVE_XRRGETPROVIDERRESOURCES @@ -1432,7 +1457,14 @@ void X11DRV_XRandR_Init(void) TRACE("Found XRandR %d.%d.\n", major, minor); - xrandr10_init_modes(); + settings_handler.name = "XRandR 1.0"; + settings_handler.priority = 200; + settings_handler.get_id = xrandr10_get_id; + settings_handler.get_modes = xrandr10_get_modes; + settings_handler.free_modes = xrandr10_free_modes; + settings_handler.get_current_mode = xrandr10_get_current_mode; + settings_handler.set_current_mode = xrandr10_set_current_mode; + X11DRV_Settings_SetHandler( &settings_handler ); #ifdef HAVE_XRRGETPROVIDERRESOURCES if (ret >= 4 && (major > 1 || (major == 1 && minor >= 4)))