From 3c305f9db9f8f00eba261e2c028368c2f27f5281 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 23 Oct 2006 14:37:17 +0200 Subject: [PATCH] winex11.drv: Preliminary support for Xinerama. --- dlls/winex11.drv/Makefile.in | 1 + dlls/winex11.drv/bitblt.c | 2 +- dlls/winex11.drv/desktop.c | 1 + dlls/winex11.drv/window.c | 14 +-- dlls/winex11.drv/winpos.c | 3 +- dlls/winex11.drv/x11drv.h | 3 + dlls/winex11.drv/x11drv_main.c | 6 ++ dlls/winex11.drv/xinerama.c | 156 +++++++++++++++++++++++++++++++++ 8 files changed, 178 insertions(+), 8 deletions(-) create mode 100644 dlls/winex11.drv/xinerama.c diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index 3c19dd10b36..5cf7dac130e 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -39,6 +39,7 @@ C_SRCS = \ xdnd.c \ xfont.c \ xim.c \ + xinerama.c \ xrandr.c \ xrender.c \ xvidmode.c diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 94a65ac4043..61a3ad69637 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1154,7 +1154,7 @@ static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT y GetObjectW( physDevSrc->bitmap->hbitmap, sizeof(bm), &bm ); SetRect( &clipRect, 0, 0, bm.bmWidth, bm.bmHeight ); } - else SetRect( &clipRect, 0, 0, screen_width, screen_height ); + else clipRect = virtual_screen_rect; if (!IntersectRect( visRectSrc, &rect, &clipRect )) return FALSE; diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index 614b3358aaf..88634726b63 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -141,6 +141,7 @@ void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height ) max_height = screen_height; screen_width = width; screen_height = height; + xinerama_init(); /* initialize the available resolutions */ dd_modes = X11DRV_Settings_SetHandlers("desktop", diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 3992ffb8fcf..39c58c9cfb3 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -110,8 +110,11 @@ BOOL X11DRV_is_window_rect_mapped( const RECT *rect ) if (IsRectEmpty( rect )) return FALSE; /* don't map if rect is off-screen */ - if (rect->left >= (int)screen_width || rect->top >= (int)screen_height) return FALSE; - if (rect->right < 0 || rect->bottom < 0) return FALSE; + if (rect->left >= virtual_screen_rect.right || + rect->top >= virtual_screen_rect.bottom || + rect->right <= virtual_screen_rect.left || + rect->bottom <= virtual_screen_rect.top) + return FALSE; return TRUE; } @@ -335,7 +338,7 @@ static void systray_dock_window( Display *display, struct x11drv_win_data *data * For more information on this problem, see * http://standards.freedesktop.org/xembed-spec/latest/ar01s04.html */ - SetWindowPos( data->hwnd, NULL, screen_width + 1, screen_height + 1, + SetWindowPos( data->hwnd, NULL, virtual_screen_rect.right + 1, virtual_screen_rect.bottom + 1, 0, 0, SWP_NOZORDER | SWP_NOSIZE ); /* set XEMBED protocol data on the window */ @@ -938,7 +941,6 @@ static struct x11drv_win_data *alloc_win_data( Display *display, HWND hwnd ) /* fill in the desktop X window id in the x11drv_win_data structure */ static void get_desktop_xwin( Display *display, struct x11drv_win_data *data ) { - RECT rect; Window win = (Window)GetPropA( data->hwnd, whole_window_prop ); if (win) @@ -967,8 +969,8 @@ static void get_desktop_xwin( Display *display, struct x11drv_win_data *data ) SetPropA( data->hwnd, whole_window_prop, (HANDLE)root_window ); SetPropA( data->hwnd, visual_id_prop, (HANDLE)visualid ); data->whole_window = root_window; - SetRect( &rect, 0, 0, screen_width, screen_height ); - X11DRV_set_window_pos( data->hwnd, 0, &rect, &rect, SWP_NOZORDER, NULL ); + X11DRV_set_window_pos( data->hwnd, 0, &virtual_screen_rect, &virtual_screen_rect, + SWP_NOZORDER, NULL ); if (root_window != DefaultRootWindow( display )) { data->managed = TRUE; diff --git a/dlls/winex11.drv/winpos.c b/dlls/winex11.drv/winpos.c index 2f4ad51d5c6..3215f7c5d0c 100644 --- a/dlls/winex11.drv/winpos.c +++ b/dlls/winex11.drv/winpos.c @@ -1253,6 +1253,7 @@ void X11DRV_handle_desktop_resize( unsigned int width, unsigned int height ) screen_width = width; screen_height = height; + xinerama_init(); TRACE("desktop %p change to (%dx%d)\n", hwnd, width, height); SetRect( &rect, 0, 0, width, height ); data->lock_changes++; @@ -1665,7 +1666,7 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) else { parent = 0; - SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); + mouseRect = virtual_screen_rect; } origRect = sizingRect; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 1059e8f5c18..97eaefab1dc 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -526,12 +526,14 @@ extern Window root_window; extern unsigned int screen_width; extern unsigned int screen_height; extern unsigned int screen_depth; +extern RECT virtual_screen_rect; extern unsigned int text_caps; extern int use_xkb; extern int use_take_focus; extern int use_primary_selection; extern int managed_mode; extern int private_color_map; +extern int primary_monitor; extern int copy_default_colors; extern int alloc_system_colors; extern int xrender_error_base; @@ -686,6 +688,7 @@ extern void X11DRV_sync_window_position( Display *display, struct x11drv_win_dat extern BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow, const RECT *rectClient, UINT swp_flags, const RECT *validRects ); extern void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data ); +extern void xinerama_init(void); extern void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height ); extern void X11DRV_handle_desktop_resize(unsigned int width, unsigned int height); diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 068db14b712..979b7f127df 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -69,6 +69,7 @@ Visual *visual; unsigned int screen_width; unsigned int screen_height; unsigned int screen_depth; +RECT virtual_screen_rect; Window root_window; int dxgrab = 0; int usexvidmode = 1; @@ -78,6 +79,7 @@ int use_take_focus = 1; int use_primary_selection = 0; int managed_mode = 1; int private_color_map = 0; +int primary_monitor = 0; int client_side_with_core = 1; int client_side_with_render = 1; int client_side_antialias_with_core = 1; @@ -358,6 +360,9 @@ static void setup_options(void) if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) )) private_color_map = IS_OPTION_TRUE( buffer[0] ); + if (!get_config_key( hkey, appkey, "PrimaryMonitor", buffer, sizeof(buffer) )) + primary_monitor = atoi( buffer ); + if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) )) copy_default_colors = atoi(buffer); @@ -429,6 +434,7 @@ static BOOL process_attach(void) screen_width = WidthOfScreen( screen ); screen_height = HeightOfScreen( screen ); + xinerama_init(); X11DRV_Settings_Init(); #ifdef HAVE_LIBXXF86VM diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c new file mode 100644 index 00000000000..97108db134c --- /dev/null +++ b/dlls/winex11.drv/xinerama.c @@ -0,0 +1,156 @@ +/* + * Xinerama support + * + * Copyright 2006 Alexandre Julliard + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H +#include +#endif +#include "wine/library.h" +#include "x11drv.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(x11drv); + +static MONITORINFOEXW default_monitor = +{ + sizeof(default_monitor), /* cbSize */ + { 0, 0, 0, 0 }, /* rcMonitor */ + { 0, 0, 0, 0 }, /* rcWork */ + MONITORINFOF_PRIMARY, /* dwFlags */ + { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 } /* szDevice */ +}; + +static MONITORINFOEXW *monitors; +static int nb_monitors; + +static inline MONITORINFOEXW *get_primary(void) +{ + /* default to 0 if specified primary is invalid */ + int idx = primary_monitor; + if (idx >= nb_monitors) idx = 0; + return &monitors[idx]; +} + +#ifdef HAVE_LIBXINERAMA + +#define MAKE_FUNCPTR(f) static typeof(f) * p##f + +MAKE_FUNCPTR(XineramaQueryExtension); +MAKE_FUNCPTR(XineramaQueryScreens); + +static void load_xinerama(void) +{ + void *handle; + + if (!(handle = wine_dlopen(SONAME_LIBXINERAMA, RTLD_NOW, NULL, 0))) + { + WARN( "failed to open %s\n", SONAME_LIBXINERAMA ); + return; + } + pXineramaQueryExtension = wine_dlsym( handle, "XineramaQueryExtension", NULL, 0 ); + if (!pXineramaQueryExtension) WARN( "XineramaQueryScreens not found\n" ); + pXineramaQueryScreens = wine_dlsym( handle, "XineramaQueryScreens", NULL, 0 ); + if (!pXineramaQueryScreens) WARN( "XineramaQueryScreens not found\n" ); +} + +static int query_screens(void) +{ + int i, count, event_base, error_base; + XineramaScreenInfo *screens; + + if (!monitors) /* first time around */ + load_xinerama(); + + if (!pXineramaQueryExtension || !pXineramaQueryScreens || + !pXineramaQueryExtension( gdi_display, &event_base, &error_base ) || + !(screens = pXineramaQueryScreens( gdi_display, &count ))) return 0; + + if (monitors != &default_monitor) HeapFree( GetProcessHeap(), 0, monitors ); + if ((monitors = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*monitors) ))) + { + nb_monitors = count; + for (i = 0; i < nb_monitors; i++) + { + /* FIXME: for now, force primary to be the screen that starts at (0,0) origin */ + if (!screens[i].x_org && !screens[i].y_org) primary_monitor = i; + + monitors[i].cbSize = sizeof( monitors[i] ); + monitors[i].rcMonitor.left = screens[i].x_org; + monitors[i].rcMonitor.top = screens[i].y_org; + monitors[i].rcMonitor.right = screens[i].x_org + screens[i].width; + monitors[i].rcMonitor.bottom = screens[i].y_org + screens[i].height; + monitors[i].rcWork = monitors[i].rcMonitor; + monitors[i].dwFlags = 0; + /* FIXME: using the same device name for all monitors for now */ + lstrcpyW( monitors[i].szDevice, default_monitor.szDevice ); + } + + get_primary()->dwFlags |= MONITORINFOF_PRIMARY; + + for (i = 0; i < nb_monitors; i++) + TRACE( "monitor %d: %s%s\n", + i, wine_dbgstr_rect(&monitors[i].rcMonitor), + (monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" ); + } + else count = 0; + + XFree( screens ); + return count; +} + +#else /* HAVE_LIBXINERAMA */ + +static inline int query_screens(void) +{ + return 0; +} + +#endif /* HAVE_LIBXINERAMA */ + +void xinerama_init(void) +{ + MONITORINFOEXW *primary; + + wine_tsx11_lock(); + + SetRect( &virtual_screen_rect, 0, 0, screen_width, screen_height ); + + if (root_window != DefaultRootWindow( gdi_display ) || !query_screens()) + { + default_monitor.rcWork = default_monitor.rcMonitor = virtual_screen_rect; + nb_monitors = 1; + monitors = &default_monitor; + } + + primary = get_primary(); + /* coordinates (0,0) have to point to the primary monitor origin */ + OffsetRect( &virtual_screen_rect, -primary->rcMonitor.left, -primary->rcMonitor.top ); + screen_width = primary->rcMonitor.right - primary->rcMonitor.left; + screen_height = primary->rcMonitor.bottom - primary->rcMonitor.top; + TRACE( "virtual size: %s primary size: %dx%d\n", + wine_dbgstr_rect(&virtual_screen_rect), screen_width, screen_height ); + + wine_tsx11_unlock(); +}