| /* | |
| * Wine X11drv Xrandr interface | |
| * | |
| * Copyright 2003 Alexander James Pasadyn | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <string.h> | |
| #include <stdio.h> | |
| #ifdef HAVE_LIBXRANDR | |
| #include <X11/Xlib.h> | |
| #include <X11/extensions/Xrandr.h> | |
| #include "x11drv.h" | |
| #include "x11ddraw.h" | |
| #include "xrandr.h" | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "ddrawi.h" | |
| #include "wine/library.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(xrandr); | |
| static void *xrandr_handle; | |
| /* some default values just in case */ | |
| #ifndef SONAME_LIBX11 | |
| #define SONAME_LIBX11 "libX11.so" | |
| #endif | |
| #ifndef SONAME_LIBXEXT | |
| #define SONAME_LIBXEXT "libXext.so" | |
| #endif | |
| #ifndef SONAME_LIBXRENDER | |
| #define SONAME_LIBXRENDER "libXrender.so" | |
| #endif | |
| #ifndef SONAME_LIBXRANDR | |
| #define SONAME_LIBXRANDR "libXrandr.so" | |
| #endif | |
| #define MAKE_FUNCPTR(f) static typeof(f) * p##f; | |
| MAKE_FUNCPTR(XRRConfigCurrentConfiguration) | |
| MAKE_FUNCPTR(XRRConfigCurrentRate) | |
| MAKE_FUNCPTR(XRRFreeScreenConfigInfo) | |
| MAKE_FUNCPTR(XRRGetScreenInfo) | |
| MAKE_FUNCPTR(XRRQueryExtension) | |
| MAKE_FUNCPTR(XRRQueryVersion) | |
| MAKE_FUNCPTR(XRRRates) | |
| MAKE_FUNCPTR(XRRSetScreenConfig) | |
| MAKE_FUNCPTR(XRRSetScreenConfigAndRate) | |
| MAKE_FUNCPTR(XRRSizes) | |
| #undef MAKE_FUNCPTR | |
| extern int usexrandr; | |
| static int xrandr_event, xrandr_error, xrandr_major, xrandr_minor; | |
| static LPDDHALMODEINFO dd_modes; | |
| static unsigned int dd_mode_count; | |
| static XRRScreenSize *real_xrandr_sizes; | |
| static short **real_xrandr_rates; | |
| static unsigned int real_xrandr_sizes_count; | |
| static int *real_xrandr_rates_count; | |
| static unsigned int real_xrandr_modes_count; | |
| int load_xrandr(void) | |
| { | |
| int r = 0; | |
| if (wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) && | |
| wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) && | |
| wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW|RTLD_GLOBAL, NULL, 0) && | |
| (xrandr_handle = wine_dlopen(SONAME_LIBXRANDR, RTLD_NOW, NULL, 0))) | |
| { | |
| #define LOAD_FUNCPTR(f) \ | |
| if((p##f = wine_dlsym(xrandr_handle, #f, NULL, 0)) == NULL) \ | |
| goto sym_not_found; | |
| LOAD_FUNCPTR(XRRConfigCurrentConfiguration) | |
| LOAD_FUNCPTR(XRRConfigCurrentRate) | |
| LOAD_FUNCPTR(XRRFreeScreenConfigInfo) | |
| LOAD_FUNCPTR(XRRGetScreenInfo) | |
| LOAD_FUNCPTR(XRRQueryExtension) | |
| LOAD_FUNCPTR(XRRQueryVersion) | |
| LOAD_FUNCPTR(XRRRates) | |
| LOAD_FUNCPTR(XRRSetScreenConfig) | |
| LOAD_FUNCPTR(XRRSetScreenConfigAndRate) | |
| LOAD_FUNCPTR(XRRSizes) | |
| #undef LOAD_FUNCPTR | |
| r = 1; /* success */ | |
| sym_not_found: | |
| if (!r) TRACE("Unable to load function ptrs from XRandR library\n"); | |
| } | |
| return r; | |
| } | |
| static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg) | |
| { | |
| return 1; | |
| } | |
| /* create the mode structures */ | |
| static void make_modes(void) | |
| { | |
| unsigned int i; | |
| int j; | |
| for (i=0; i<real_xrandr_sizes_count; i++) | |
| { | |
| if (real_xrandr_rates_count[i]) | |
| { | |
| for (j=0; j < real_xrandr_rates_count[i]; j++) | |
| { | |
| X11DRV_Settings_AddOneMode(real_xrandr_sizes[i].width, | |
| real_xrandr_sizes[i].height, | |
| 0, real_xrandr_rates[i][j]); | |
| } | |
| } | |
| else | |
| { | |
| X11DRV_Settings_AddOneMode(real_xrandr_sizes[i].width, | |
| real_xrandr_sizes[i].height, | |
| 0, 0); | |
| } | |
| } | |
| } | |
| static int X11DRV_XRandR_GetCurrentMode(void) | |
| { | |
| SizeID size; | |
| Rotation rot; | |
| Window root; | |
| XRRScreenConfiguration *sc; | |
| short rate; | |
| unsigned int i; | |
| int res = -1; | |
| wine_tsx11_lock(); | |
| root = RootWindow (gdi_display, DefaultScreen(gdi_display)); | |
| sc = pXRRGetScreenInfo (gdi_display, root); | |
| size = pXRRConfigCurrentConfiguration (sc, &rot); | |
| rate = pXRRConfigCurrentRate (sc); | |
| for (i = 0; i < real_xrandr_modes_count; i++) | |
| { | |
| if ( (dd_modes[i].dwWidth == real_xrandr_sizes[size].width ) && | |
| (dd_modes[i].dwHeight == real_xrandr_sizes[size].height) && | |
| (dd_modes[i].wRefreshRate == rate ) ) | |
| { | |
| res = i; | |
| } | |
| } | |
| pXRRFreeScreenConfigInfo(sc); | |
| wine_tsx11_unlock(); | |
| if (res == -1) | |
| { | |
| ERR("In unknown mode, returning default\n"); | |
| res = 0; | |
| } | |
| return res; | |
| } | |
| static void X11DRV_XRandR_SetCurrentMode(int mode) | |
| { | |
| SizeID size; | |
| Rotation rot; | |
| Window root; | |
| XRRScreenConfiguration *sc; | |
| Status stat = RRSetConfigSuccess; | |
| short rate; | |
| unsigned int i; | |
| int j; | |
| DWORD dwBpp = screen_depth; | |
| if (dwBpp == 24) dwBpp = 32; | |
| wine_tsx11_lock(); | |
| root = RootWindow (gdi_display, DefaultScreen(gdi_display)); | |
| sc = pXRRGetScreenInfo (gdi_display, root); | |
| size = pXRRConfigCurrentConfiguration (sc, &rot); | |
| if (dwBpp != dd_modes[mode].dwBPP) | |
| { | |
| FIXME("Cannot change screen BPP from %ld to %ld\n", dwBpp, dd_modes[mode].dwBPP); | |
| } | |
| mode = mode%real_xrandr_modes_count; | |
| for (i = 0; i < real_xrandr_sizes_count; i++) | |
| { | |
| if ( (dd_modes[mode].dwWidth == real_xrandr_sizes[i].width ) && | |
| (dd_modes[mode].dwHeight == real_xrandr_sizes[i].height) ) | |
| { | |
| size = i; | |
| if (real_xrandr_rates_count[i]) | |
| { | |
| for (j=0; j < real_xrandr_rates_count[i]; j++) | |
| { | |
| if (dd_modes[mode].wRefreshRate == real_xrandr_rates[i][j]) | |
| { | |
| rate = real_xrandr_rates[i][j]; | |
| TRACE("Resizing X display to %ldx%ld @%d Hz\n", | |
| dd_modes[mode].dwWidth, dd_modes[mode].dwHeight, rate); | |
| stat = pXRRSetScreenConfigAndRate (gdi_display, sc, root, | |
| size, rot, rate, CurrentTime); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| TRACE("Resizing X display to %ldx%ld\n", | |
| dd_modes[mode].dwWidth, dd_modes[mode].dwHeight); | |
| stat = pXRRSetScreenConfig (gdi_display, sc, root, | |
| size, rot, CurrentTime); | |
| } | |
| } | |
| } | |
| pXRRFreeScreenConfigInfo(sc); | |
| wine_tsx11_unlock(); | |
| if (stat == RRSetConfigSuccess) | |
| X11DRV_handle_desktop_resize( dd_modes[mode].dwWidth, dd_modes[mode].dwHeight ); | |
| else | |
| ERR("Resolution change not successful -- perhaps display has changed?\n"); | |
| } | |
| void X11DRV_XRandR_Init(void) | |
| { | |
| Bool ok; | |
| int nmodes = 0; | |
| unsigned int i; | |
| if (xrandr_major) return; /* already initialized? */ | |
| if (!usexrandr) return; /* disabled in config */ | |
| if (using_wine_desktop) return; /* not compatible with desktop mode */ | |
| if (!load_xrandr()) return; /* can't load the Xrandr library */ | |
| /* see if Xrandr is available */ | |
| wine_tsx11_lock(); | |
| ok = pXRRQueryExtension(gdi_display, &xrandr_event, &xrandr_error); | |
| if (ok) | |
| { | |
| X11DRV_expect_error(gdi_display, XRandRErrorHandler, NULL); | |
| ok = pXRRQueryVersion(gdi_display, &xrandr_major, &xrandr_minor); | |
| if (X11DRV_check_error()) ok = FALSE; | |
| } | |
| if (ok) | |
| { | |
| TRACE("Found XRandR - major: %d, minor: %d\n", xrandr_major, xrandr_minor); | |
| /* retrieve modes */ | |
| real_xrandr_sizes = pXRRSizes(gdi_display, DefaultScreen(gdi_display), &real_xrandr_sizes_count); | |
| ok = (real_xrandr_sizes_count>0); | |
| } | |
| if (ok) | |
| { | |
| real_xrandr_rates = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(short *) * real_xrandr_sizes_count); | |
| real_xrandr_rates_count = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(int) * real_xrandr_sizes_count); | |
| for (i=0; i < real_xrandr_sizes_count; i++) | |
| { | |
| real_xrandr_rates[i] = pXRRRates (gdi_display, DefaultScreen(gdi_display), i, &(real_xrandr_rates_count[i])); | |
| if (real_xrandr_rates_count[i]) | |
| { | |
| nmodes += real_xrandr_rates_count[i]; | |
| } | |
| else | |
| { | |
| nmodes++; | |
| } | |
| } | |
| } | |
| wine_tsx11_unlock(); | |
| if (!ok) return; | |
| real_xrandr_modes_count = nmodes; | |
| TRACE("XRandR modes: count=%d\n", nmodes); | |
| dd_modes = X11DRV_Settings_SetHandlers("XRandR", | |
| X11DRV_XRandR_GetCurrentMode, | |
| X11DRV_XRandR_SetCurrentMode, | |
| nmodes, 1); | |
| make_modes(); | |
| X11DRV_Settings_AddDepthModes(); | |
| dd_mode_count = X11DRV_Settings_GetModeCount(); | |
| X11DRV_Settings_SetDefaultMode(0); | |
| TRACE("Available DD modes: count=%d\n", dd_mode_count); | |
| TRACE("Enabling XRandR\n"); | |
| } | |
| void X11DRV_XRandR_Cleanup(void) | |
| { | |
| HeapFree(GetProcessHeap(), 0, real_xrandr_rates); | |
| real_xrandr_rates = NULL; | |
| HeapFree(GetProcessHeap(), 0, real_xrandr_rates_count); | |
| real_xrandr_rates_count = NULL; | |
| } | |
| #endif /* HAVE_LIBXRANDR */ |