kernel32/tests/pipe: Enable compilation with long types.
[wine.git] / dlls / winex11.drv / xinerama.c
blobb707574a0ab97ec5c822cf2a53bbc2f3aa78b1d9
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"
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <X11/Xlib.h>
26 #ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
27 #include <X11/extensions/Xinerama.h>
28 #endif
29 #include <dlfcn.h>
30 #include "x11drv.h"
31 #include "wine/debug.h"
32 #include "wine/heap.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 #ifdef SONAME_LIBXINERAMA
58 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
60 MAKE_FUNCPTR(XineramaQueryExtension);
61 MAKE_FUNCPTR(XineramaQueryScreens);
63 static void load_xinerama(void)
65 void *handle;
67 if (!(handle = dlopen(SONAME_LIBXINERAMA, RTLD_NOW)))
69 WARN( "failed to open %s\n", SONAME_LIBXINERAMA );
70 return;
72 pXineramaQueryExtension = dlsym( handle, "XineramaQueryExtension" );
73 if (!pXineramaQueryExtension) WARN( "XineramaQueryScreens not found\n" );
74 pXineramaQueryScreens = dlsym( handle, "XineramaQueryScreens" );
75 if (!pXineramaQueryScreens) WARN( "XineramaQueryScreens not found\n" );
78 static int query_screens(void)
80 int i, count, event_base, error_base;
81 XineramaScreenInfo *screens;
83 if (!monitors) /* first time around */
84 load_xinerama();
86 if (!pXineramaQueryExtension || !pXineramaQueryScreens ||
87 !pXineramaQueryExtension( gdi_display, &event_base, &error_base ) ||
88 !(screens = pXineramaQueryScreens( gdi_display, &count ))) return 0;
90 if (monitors != &default_monitor) HeapFree( GetProcessHeap(), 0, monitors );
91 if ((monitors = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*monitors) )))
93 nb_monitors = count;
94 for (i = 0; i < nb_monitors; i++)
96 monitors[i].cbSize = sizeof( monitors[i] );
97 monitors[i].rcMonitor.left = screens[i].x_org;
98 monitors[i].rcMonitor.top = screens[i].y_org;
99 monitors[i].rcMonitor.right = screens[i].x_org + screens[i].width;
100 monitors[i].rcMonitor.bottom = screens[i].y_org + screens[i].height;
101 monitors[i].dwFlags = 0;
102 monitors[i].rcWork = get_work_area( &monitors[i].rcMonitor );
105 get_primary()->dwFlags |= MONITORINFOF_PRIMARY;
107 else count = 0;
109 XFree( screens );
110 return count;
113 #else /* SONAME_LIBXINERAMA */
115 static inline int query_screens(void)
117 return 0;
120 #endif /* SONAME_LIBXINERAMA */
122 static BOOL xinerama_get_gpus( struct gdi_gpu **new_gpus, int *count )
124 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
125 struct gdi_gpu *gpus;
127 /* Xinerama has no support for GPU, faking one */
128 gpus = heap_calloc( 1, sizeof(*gpus) );
129 if (!gpus)
130 return FALSE;
132 lstrcpyW( gpus[0].name, wine_adapterW );
134 *new_gpus = gpus;
135 *count = 1;
137 return TRUE;
140 static void xinerama_free_gpus( struct gdi_gpu *gpus )
142 heap_free( gpus );
145 static BOOL xinerama_get_adapters( ULONG_PTR gpu_id, struct gdi_adapter **new_adapters, int *count )
147 struct gdi_adapter *adapters = NULL;
148 INT index = 0;
149 INT i, j;
150 INT primary_index;
151 BOOL mirrored;
153 if (gpu_id)
154 return FALSE;
156 /* Being lazy, actual adapter count may be less */
157 adapters = heap_calloc( nb_monitors, sizeof(*adapters) );
158 if (!adapters)
159 return FALSE;
161 primary_index = primary_monitor;
162 if (primary_index >= nb_monitors)
163 primary_index = 0;
165 for (i = 0; i < nb_monitors; i++)
167 mirrored = FALSE;
168 for (j = 0; j < i; j++)
170 if (EqualRect( &monitors[i].rcMonitor, &monitors[j].rcMonitor) && !IsRectEmpty( &monitors[j].rcMonitor ))
172 mirrored = TRUE;
173 break;
177 /* Mirrored monitors share the same adapter */
178 if (mirrored)
179 continue;
181 /* Use monitor index as id */
182 adapters[index].id = (ULONG_PTR)i;
184 if (i == primary_index)
185 adapters[index].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
187 if (!IsRectEmpty( &monitors[i].rcMonitor ))
188 adapters[index].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
190 index++;
193 /* Primary adapter has to be first */
194 if (primary_index)
196 struct gdi_adapter tmp;
197 tmp = adapters[primary_index];
198 adapters[primary_index] = adapters[0];
199 adapters[0] = tmp;
202 *new_adapters = adapters;
203 *count = index;
204 return TRUE;
207 static void xinerama_free_adapters( struct gdi_adapter *adapters )
209 heap_free( adapters );
212 static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count )
214 static const WCHAR generic_nonpnp_monitorW[] = {
215 'G','e','n','e','r','i','c',' ',
216 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
217 struct gdi_monitor *monitor;
218 INT first = (INT)adapter_id;
219 INT monitor_count = 0;
220 INT index = 0;
221 INT i;
223 for (i = first; i < nb_monitors; i++)
225 if (i == first
226 || (EqualRect( &monitors[i].rcMonitor, &monitors[first].rcMonitor )
227 && !IsRectEmpty( &monitors[first].rcMonitor )))
228 monitor_count++;
231 monitor = heap_calloc( monitor_count, sizeof(*monitor) );
232 if (!monitor)
233 return FALSE;
235 for (i = first; i < nb_monitors; i++)
237 if (i == first
238 || (EqualRect( &monitors[i].rcMonitor, &monitors[first].rcMonitor )
239 && !IsRectEmpty( &monitors[first].rcMonitor )))
241 lstrcpyW( monitor[index].name, generic_nonpnp_monitorW );
242 monitor[index].rc_monitor = monitors[i].rcMonitor;
243 monitor[index].rc_work = monitors[i].rcWork;
244 /* Xinerama only reports monitors already attached */
245 monitor[index].state_flags = DISPLAY_DEVICE_ATTACHED;
246 monitor[index].edid_len = 0;
247 monitor[index].edid = NULL;
248 if (!IsRectEmpty( &monitors[i].rcMonitor ))
249 monitor[index].state_flags |= DISPLAY_DEVICE_ACTIVE;
251 index++;
255 *new_monitors = monitor;
256 *count = monitor_count;
257 return TRUE;
260 static void xinerama_free_monitors( struct gdi_monitor *monitors, int count )
262 heap_free( monitors );
265 void xinerama_init( unsigned int width, unsigned int height )
267 struct x11drv_display_device_handler handler;
268 MONITORINFOEXW *primary;
269 int i;
270 RECT rect;
272 if (is_virtual_desktop())
273 return;
275 SetRect( &rect, 0, 0, width, height );
276 if (!query_screens())
278 default_monitor.rcMonitor = rect;
279 default_monitor.rcWork = get_work_area( &default_monitor.rcMonitor );
280 nb_monitors = 1;
281 monitors = &default_monitor;
284 primary = get_primary();
286 /* coordinates (0,0) have to point to the primary monitor origin */
287 OffsetRect( &rect, -primary->rcMonitor.left, -primary->rcMonitor.top );
288 for (i = 0; i < nb_monitors; i++)
290 OffsetRect( &monitors[i].rcMonitor, rect.left, rect.top );
291 OffsetRect( &monitors[i].rcWork, rect.left, rect.top );
292 TRACE( "monitor 0x%x: %s work %s%s\n",
293 i, wine_dbgstr_rect(&monitors[i].rcMonitor),
294 wine_dbgstr_rect(&monitors[i].rcWork),
295 (monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" );
298 handler.name = "Xinerama";
299 handler.priority = 100;
300 handler.get_gpus = xinerama_get_gpus;
301 handler.get_adapters = xinerama_get_adapters;
302 handler.get_monitors = xinerama_get_monitors;
303 handler.free_gpus = xinerama_free_gpus;
304 handler.free_adapters = xinerama_free_adapters;
305 handler.free_monitors = xinerama_free_monitors;
306 handler.register_event_handlers = NULL;
307 X11DRV_DisplayDevices_SetHandler( &handler );