push b59ba84f7e04af9ef068bd4c6e96701941f0256e
[wine/hacks.git] / dlls / winex11.drv / xinerama.c
blob782c779be272346d04b149fbf09c444444e0c2c1
1 /*
2 * Xinerama support
4 * Copyright 2006 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <X11/Xlib.h>
27 #ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
28 #include <X11/extensions/Xinerama.h>
29 #endif
30 #include "wine/library.h"
31 #include "x11drv.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
36 static MONITORINFOEXW default_monitor =
38 sizeof(default_monitor), /* cbSize */
39 { 0, 0, 0, 0 }, /* rcMonitor */
40 { 0, 0, 0, 0 }, /* rcWork */
41 MONITORINFOF_PRIMARY, /* dwFlags */
42 { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 } /* szDevice */
45 static MONITORINFOEXW *monitors;
46 static int nb_monitors;
48 static inline MONITORINFOEXW *get_primary(void)
50 /* default to 0 if specified primary is invalid */
51 int idx = primary_monitor;
52 if (idx >= nb_monitors) idx = 0;
53 return &monitors[idx];
56 static inline HMONITOR index_to_monitor( int index )
58 return (HMONITOR)(UINT_PTR)(index + 1);
61 static inline int monitor_to_index( HMONITOR handle )
63 UINT_PTR index = (UINT_PTR)handle;
64 if (index < 1 || index > nb_monitors) return -1;
65 return index - 1;
69 #ifdef SONAME_LIBXINERAMA
71 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
73 MAKE_FUNCPTR(XineramaQueryExtension);
74 MAKE_FUNCPTR(XineramaQueryScreens);
76 static void load_xinerama(void)
78 void *handle;
80 if (!(handle = wine_dlopen(SONAME_LIBXINERAMA, RTLD_NOW, NULL, 0)))
82 WARN( "failed to open %s\n", SONAME_LIBXINERAMA );
83 return;
85 pXineramaQueryExtension = wine_dlsym( handle, "XineramaQueryExtension", NULL, 0 );
86 if (!pXineramaQueryExtension) WARN( "XineramaQueryScreens not found\n" );
87 pXineramaQueryScreens = wine_dlsym( handle, "XineramaQueryScreens", NULL, 0 );
88 if (!pXineramaQueryScreens) WARN( "XineramaQueryScreens not found\n" );
91 static int query_screens(void)
93 int i, count, event_base, error_base;
94 XineramaScreenInfo *screens;
96 if (!monitors) /* first time around */
97 load_xinerama();
99 if (!pXineramaQueryExtension || !pXineramaQueryScreens ||
100 !pXineramaQueryExtension( gdi_display, &event_base, &error_base ) ||
101 !(screens = pXineramaQueryScreens( gdi_display, &count ))) return 0;
103 if (monitors != &default_monitor) HeapFree( GetProcessHeap(), 0, monitors );
104 if ((monitors = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*monitors) )))
106 nb_monitors = count;
107 for (i = 0; i < nb_monitors; i++)
109 monitors[i].cbSize = sizeof( monitors[i] );
110 monitors[i].rcMonitor.left = screens[i].x_org;
111 monitors[i].rcMonitor.top = screens[i].y_org;
112 monitors[i].rcMonitor.right = screens[i].x_org + screens[i].width;
113 monitors[i].rcMonitor.bottom = screens[i].y_org + screens[i].height;
114 monitors[i].rcWork = monitors[i].rcMonitor;
115 monitors[i].dwFlags = 0;
116 /* FIXME: using the same device name for all monitors for now */
117 lstrcpyW( monitors[i].szDevice, default_monitor.szDevice );
120 get_primary()->dwFlags |= MONITORINFOF_PRIMARY;
122 else count = 0;
124 XFree( screens );
125 return count;
128 #else /* SONAME_LIBXINERAMA */
130 static inline int query_screens(void)
132 return 0;
135 #endif /* SONAME_LIBXINERAMA */
137 void xinerama_init( unsigned int width, unsigned int height )
139 MONITORINFOEXW *primary;
140 int i;
142 wine_tsx11_lock();
144 SetRect( &virtual_screen_rect, 0, 0, width, height );
146 if (root_window != DefaultRootWindow( gdi_display ) || !query_screens())
148 default_monitor.rcWork = default_monitor.rcMonitor = virtual_screen_rect;
149 nb_monitors = 1;
150 monitors = &default_monitor;
153 primary = get_primary();
155 /* coordinates (0,0) have to point to the primary monitor origin */
156 OffsetRect( &virtual_screen_rect, -primary->rcMonitor.left, -primary->rcMonitor.top );
157 for (i = 0; i < nb_monitors; i++)
159 OffsetRect( &monitors[i].rcMonitor, virtual_screen_rect.left, virtual_screen_rect.top );
160 OffsetRect( &monitors[i].rcWork, virtual_screen_rect.left, virtual_screen_rect.top );
161 TRACE( "monitor %p: %s%s\n",
162 index_to_monitor(i), wine_dbgstr_rect(&monitors[i].rcMonitor),
163 (monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" );
166 screen_width = primary->rcMonitor.right - primary->rcMonitor.left;
167 screen_height = primary->rcMonitor.bottom - primary->rcMonitor.top;
168 TRACE( "virtual size: %s primary size: %dx%d\n",
169 wine_dbgstr_rect(&virtual_screen_rect), screen_width, screen_height );
171 wine_tsx11_unlock();
172 ClipCursor( NULL ); /* reset the cursor clip rectangle */
176 /***********************************************************************
177 * X11DRV_GetMonitorInfo (X11DRV.@)
179 BOOL X11DRV_GetMonitorInfo( HMONITOR handle, LPMONITORINFO info )
181 int i = monitor_to_index( handle );
183 if (i == -1)
185 SetLastError( ERROR_INVALID_HANDLE );
186 return FALSE;
188 info->rcMonitor = monitors[i].rcMonitor;
189 info->rcWork = monitors[i].rcWork;
190 info->dwFlags = monitors[i].dwFlags;
191 if (info->cbSize >= sizeof(MONITORINFOEXW))
192 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitors[i].szDevice );
193 return TRUE;
197 /***********************************************************************
198 * X11DRV_EnumDisplayMonitors (X11DRV.@)
200 BOOL X11DRV_EnumDisplayMonitors( HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lp )
202 int i;
204 if (hdc)
206 POINT origin;
207 RECT limit;
209 if (!GetDCOrgEx( hdc, &origin )) return FALSE;
210 if (GetClipBox( hdc, &limit ) == ERROR) return FALSE;
212 if (rect && !IntersectRect( &limit, &limit, rect )) return TRUE;
214 for (i = 0; i < nb_monitors; i++)
216 RECT monrect = monitors[i].rcMonitor;
217 OffsetRect( &monrect, -origin.x, -origin.y );
218 if (IntersectRect( &monrect, &monrect, &limit ))
219 if (!proc( index_to_monitor(i), hdc, &monrect, lp )) break;
222 else
224 for (i = 0; i < nb_monitors; i++)
226 RECT unused;
227 if (!rect || IntersectRect( &unused, &monitors[i].rcMonitor, rect ))
228 if (!proc( index_to_monitor(i), 0, &monitors[i].rcMonitor, lp )) break;
231 return TRUE;