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
22 #include "wine/port.h"
27 #ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
28 #include <X11/extensions/Xinerama.h>
31 #include "wine/debug.h"
32 #include "wine/heap.h"
33 #include "wine/unicode.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(x11drv
);
37 static MONITORINFOEXW default_monitor
=
39 sizeof(default_monitor
), /* cbSize */
40 { 0, 0, 0, 0 }, /* rcMonitor */
41 { 0, 0, 0, 0 }, /* rcWork */
42 MONITORINFOF_PRIMARY
, /* dwFlags */
43 { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 } /* szDevice */
46 static MONITORINFOEXW
*monitors
;
47 static int nb_monitors
;
49 static inline MONITORINFOEXW
*get_primary(void)
51 /* default to 0 if specified primary is invalid */
52 int idx
= primary_monitor
;
53 if (idx
>= nb_monitors
) idx
= 0;
54 return &monitors
[idx
];
57 #ifdef SONAME_LIBXINERAMA
59 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
61 MAKE_FUNCPTR(XineramaQueryExtension
);
62 MAKE_FUNCPTR(XineramaQueryScreens
);
64 static void load_xinerama(void)
68 if (!(handle
= dlopen(SONAME_LIBXINERAMA
, RTLD_NOW
)))
70 WARN( "failed to open %s\n", SONAME_LIBXINERAMA
);
73 pXineramaQueryExtension
= dlsym( handle
, "XineramaQueryExtension" );
74 if (!pXineramaQueryExtension
) WARN( "XineramaQueryScreens not found\n" );
75 pXineramaQueryScreens
= dlsym( handle
, "XineramaQueryScreens" );
76 if (!pXineramaQueryScreens
) WARN( "XineramaQueryScreens not found\n" );
79 static int query_screens(void)
81 int i
, count
, event_base
, error_base
;
82 XineramaScreenInfo
*screens
;
84 if (!monitors
) /* first time around */
87 if (!pXineramaQueryExtension
|| !pXineramaQueryScreens
||
88 !pXineramaQueryExtension( gdi_display
, &event_base
, &error_base
) ||
89 !(screens
= pXineramaQueryScreens( gdi_display
, &count
))) return 0;
91 if (monitors
!= &default_monitor
) HeapFree( GetProcessHeap(), 0, monitors
);
92 if ((monitors
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*monitors
) )))
95 for (i
= 0; i
< nb_monitors
; i
++)
97 monitors
[i
].cbSize
= sizeof( monitors
[i
] );
98 monitors
[i
].rcMonitor
.left
= screens
[i
].x_org
;
99 monitors
[i
].rcMonitor
.top
= screens
[i
].y_org
;
100 monitors
[i
].rcMonitor
.right
= screens
[i
].x_org
+ screens
[i
].width
;
101 monitors
[i
].rcMonitor
.bottom
= screens
[i
].y_org
+ screens
[i
].height
;
102 monitors
[i
].dwFlags
= 0;
103 monitors
[i
].rcWork
= get_work_area( &monitors
[i
].rcMonitor
);
106 get_primary()->dwFlags
|= MONITORINFOF_PRIMARY
;
114 #else /* SONAME_LIBXINERAMA */
116 static inline int query_screens(void)
121 #endif /* SONAME_LIBXINERAMA */
123 static BOOL
xinerama_get_gpus( struct x11drv_gpu
**new_gpus
, int *count
)
125 static const WCHAR wine_adapterW
[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
126 struct x11drv_gpu
*gpus
;
128 /* Xinerama has no support for GPU, faking one */
129 gpus
= heap_calloc( 1, sizeof(*gpus
) );
133 lstrcpyW( gpus
[0].name
, wine_adapterW
);
141 static void xinerama_free_gpus( struct x11drv_gpu
*gpus
)
146 static BOOL
xinerama_get_adapters( ULONG_PTR gpu_id
, struct x11drv_adapter
**new_adapters
, int *count
)
148 struct x11drv_adapter
*adapters
= NULL
;
157 /* Being lazy, actual adapter count may be less */
158 adapters
= heap_calloc( nb_monitors
, sizeof(*adapters
) );
162 primary_index
= primary_monitor
;
163 if (primary_index
>= nb_monitors
)
166 for (i
= 0; i
< nb_monitors
; i
++)
169 for (j
= 0; j
< i
; j
++)
171 if (EqualRect( &monitors
[i
].rcMonitor
, &monitors
[j
].rcMonitor
) && !IsRectEmpty( &monitors
[j
].rcMonitor
))
178 /* Mirrored monitors share the same adapter */
182 /* Use monitor index as id */
183 adapters
[index
].id
= (ULONG_PTR
)i
;
185 if (i
== primary_index
)
186 adapters
[index
].state_flags
|= DISPLAY_DEVICE_PRIMARY_DEVICE
;
188 if (!IsRectEmpty( &monitors
[i
].rcMonitor
))
189 adapters
[index
].state_flags
|= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
;
194 /* Primary adapter has to be first */
197 struct x11drv_adapter tmp
;
198 tmp
= adapters
[primary_index
];
199 adapters
[primary_index
] = adapters
[0];
203 *new_adapters
= adapters
;
208 static void xinerama_free_adapters( struct x11drv_adapter
*adapters
)
210 heap_free( adapters
);
213 static BOOL
xinerama_get_monitors( ULONG_PTR adapter_id
, struct x11drv_monitor
**new_monitors
, int *count
)
215 static const WCHAR generic_nonpnp_monitorW
[] = {
216 'G','e','n','e','r','i','c',' ',
217 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
218 struct x11drv_monitor
*monitor
;
219 INT first
= (INT
)adapter_id
;
220 INT monitor_count
= 0;
224 for (i
= first
; i
< nb_monitors
; i
++)
227 || (EqualRect( &monitors
[i
].rcMonitor
, &monitors
[first
].rcMonitor
)
228 && !IsRectEmpty( &monitors
[first
].rcMonitor
)))
232 monitor
= heap_calloc( monitor_count
, sizeof(*monitor
) );
236 for (i
= first
; i
< nb_monitors
; i
++)
239 || (EqualRect( &monitors
[i
].rcMonitor
, &monitors
[first
].rcMonitor
)
240 && !IsRectEmpty( &monitors
[first
].rcMonitor
)))
242 lstrcpyW( monitor
[index
].name
, generic_nonpnp_monitorW
);
243 monitor
[index
].rc_monitor
= monitors
[i
].rcMonitor
;
244 monitor
[index
].rc_work
= monitors
[i
].rcWork
;
245 /* Xinerama only reports monitors already attached */
246 monitor
[index
].state_flags
= DISPLAY_DEVICE_ATTACHED
;
247 if (!IsRectEmpty( &monitors
[i
].rcMonitor
))
248 monitor
[index
].state_flags
|= DISPLAY_DEVICE_ACTIVE
;
254 *new_monitors
= monitor
;
255 *count
= monitor_count
;
259 static void xinerama_free_monitors( struct x11drv_monitor
*monitors
)
261 heap_free( monitors
);
264 void xinerama_init( unsigned int width
, unsigned int height
)
266 struct x11drv_display_device_handler handler
;
267 MONITORINFOEXW
*primary
;
271 if (is_virtual_desktop())
274 SetRect( &rect
, 0, 0, width
, height
);
275 if (!query_screens())
277 default_monitor
.rcMonitor
= rect
;
278 default_monitor
.rcWork
= get_work_area( &default_monitor
.rcMonitor
);
280 monitors
= &default_monitor
;
283 primary
= get_primary();
285 /* coordinates (0,0) have to point to the primary monitor origin */
286 OffsetRect( &rect
, -primary
->rcMonitor
.left
, -primary
->rcMonitor
.top
);
287 for (i
= 0; i
< nb_monitors
; i
++)
289 OffsetRect( &monitors
[i
].rcMonitor
, rect
.left
, rect
.top
);
290 OffsetRect( &monitors
[i
].rcWork
, rect
.left
, rect
.top
);
291 TRACE( "monitor 0x%x: %s work %s%s\n",
292 i
, wine_dbgstr_rect(&monitors
[i
].rcMonitor
),
293 wine_dbgstr_rect(&monitors
[i
].rcWork
),
294 (monitors
[i
].dwFlags
& MONITORINFOF_PRIMARY
) ? " (primary)" : "" );
297 handler
.name
= "Xinerama";
298 handler
.priority
= 100;
299 handler
.get_gpus
= xinerama_get_gpus
;
300 handler
.get_adapters
= xinerama_get_adapters
;
301 handler
.get_monitors
= xinerama_get_monitors
;
302 handler
.free_gpus
= xinerama_free_gpus
;
303 handler
.free_adapters
= xinerama_free_adapters
;
304 handler
.free_monitors
= xinerama_free_monitors
;
305 handler
.register_event_handlers
= NULL
;
306 X11DRV_DisplayDevices_SetHandler( &handler
);