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
26 #ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
27 #include <X11/extensions/Xinerama.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)
67 if (!(handle
= dlopen(SONAME_LIBXINERAMA
, RTLD_NOW
)))
69 WARN( "failed to open %s\n", SONAME_LIBXINERAMA
);
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 */
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
) )))
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
;
113 #else /* SONAME_LIBXINERAMA */
115 static inline int query_screens(void)
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
) );
132 lstrcpyW( gpus
[0].name
, wine_adapterW
);
140 static void xinerama_free_gpus( struct gdi_gpu
*gpus
)
145 static BOOL
xinerama_get_adapters( ULONG_PTR gpu_id
, struct gdi_adapter
**new_adapters
, int *count
)
147 struct gdi_adapter
*adapters
= NULL
;
156 /* Being lazy, actual adapter count may be less */
157 adapters
= heap_calloc( nb_monitors
, sizeof(*adapters
) );
161 primary_index
= primary_monitor
;
162 if (primary_index
>= nb_monitors
)
165 for (i
= 0; i
< nb_monitors
; i
++)
168 for (j
= 0; j
< i
; j
++)
170 if (EqualRect( &monitors
[i
].rcMonitor
, &monitors
[j
].rcMonitor
) && !IsRectEmpty( &monitors
[j
].rcMonitor
))
177 /* Mirrored monitors share the same adapter */
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
;
193 /* Primary adapter has to be first */
196 struct gdi_adapter tmp
;
197 tmp
= adapters
[primary_index
];
198 adapters
[primary_index
] = adapters
[0];
202 *new_adapters
= adapters
;
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;
223 for (i
= first
; i
< nb_monitors
; i
++)
226 || (EqualRect( &monitors
[i
].rcMonitor
, &monitors
[first
].rcMonitor
)
227 && !IsRectEmpty( &monitors
[first
].rcMonitor
)))
231 monitor
= heap_calloc( monitor_count
, sizeof(*monitor
) );
235 for (i
= first
; i
< nb_monitors
; i
++)
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
;
255 *new_monitors
= monitor
;
256 *count
= monitor_count
;
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
;
272 if (is_virtual_desktop())
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
);
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
);