configure: Don't use a default soname if a library is not found, leave it undefined.
[wine] / dlls / winex11.drv / xinerama.c
1 /*
2  * Xinerama support
3  *
4  * Copyright 2006 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
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"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
35
36 static MONITORINFOEXW default_monitor =
37 {
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 */
43 };
44
45 static MONITORINFOEXW *monitors;
46 static int nb_monitors;
47
48 static inline MONITORINFOEXW *get_primary(void)
49 {
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];
54 }
55
56 static inline HMONITOR index_to_monitor( int index )
57 {
58     return (HMONITOR)(UINT_PTR)(index + 1);
59 }
60
61 static inline int monitor_to_index( HMONITOR handle )
62 {
63     UINT_PTR index = (UINT_PTR)handle;
64     if (index < 1 || index > nb_monitors) return -1;
65     return index - 1;
66 }
67
68
69 #ifdef HAVE_LIBXINERAMA
70
71 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
72
73 MAKE_FUNCPTR(XineramaQueryExtension);
74 MAKE_FUNCPTR(XineramaQueryScreens);
75
76 #ifndef SONAME_LIBXINERAMA
77 #define SONAME_LIBXINERAMA "libXinerama" SONAME_EXT
78 #endif
79
80 static void load_xinerama(void)
81 {
82     void *handle;
83
84     if (!(handle = wine_dlopen(SONAME_LIBXINERAMA, RTLD_NOW, NULL, 0)))
85     {
86         WARN( "failed to open %s\n", SONAME_LIBXINERAMA );
87         return;
88     }
89     pXineramaQueryExtension = wine_dlsym( handle, "XineramaQueryExtension", NULL, 0 );
90     if (!pXineramaQueryExtension) WARN( "XineramaQueryScreens not found\n" );
91     pXineramaQueryScreens = wine_dlsym( handle, "XineramaQueryScreens", NULL, 0 );
92     if (!pXineramaQueryScreens) WARN( "XineramaQueryScreens not found\n" );
93 }
94
95 static int query_screens(void)
96 {
97     int i, count, event_base, error_base;
98     XineramaScreenInfo *screens;
99
100     if (!monitors)  /* first time around */
101         load_xinerama();
102
103     if (!pXineramaQueryExtension || !pXineramaQueryScreens ||
104         !pXineramaQueryExtension( gdi_display, &event_base, &error_base ) ||
105         !(screens = pXineramaQueryScreens( gdi_display, &count ))) return 0;
106
107     if (monitors != &default_monitor) HeapFree( GetProcessHeap(), 0, monitors );
108     if ((monitors = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*monitors) )))
109     {
110         nb_monitors = count;
111         for (i = 0; i < nb_monitors; i++)
112         {
113             monitors[i].cbSize = sizeof( monitors[i] );
114             monitors[i].rcMonitor.left   = screens[i].x_org;
115             monitors[i].rcMonitor.top    = screens[i].y_org;
116             monitors[i].rcMonitor.right  = screens[i].x_org + screens[i].width;
117             monitors[i].rcMonitor.bottom = screens[i].y_org + screens[i].height;
118             monitors[i].rcWork           = monitors[i].rcMonitor;
119             monitors[i].dwFlags          = 0;
120             /* FIXME: using the same device name for all monitors for now */
121             lstrcpyW( monitors[i].szDevice, default_monitor.szDevice );
122         }
123
124         get_primary()->dwFlags |= MONITORINFOF_PRIMARY;
125     }
126     else count = 0;
127
128     XFree( screens );
129     return count;
130 }
131
132 #else  /* HAVE_LIBXINERAMA */
133
134 static inline int query_screens(void)
135 {
136     return 0;
137 }
138
139 #endif  /* HAVE_LIBXINERAMA */
140
141 void xinerama_init(void)
142 {
143     MONITORINFOEXW *primary;
144     int i;
145
146     wine_tsx11_lock();
147
148     SetRect( &virtual_screen_rect, 0, 0, screen_width, screen_height );
149
150     if (root_window != DefaultRootWindow( gdi_display ) || !query_screens())
151     {
152         default_monitor.rcWork = default_monitor.rcMonitor = virtual_screen_rect;
153         nb_monitors = 1;
154         monitors = &default_monitor;
155     }
156
157     primary = get_primary();
158
159     /* coordinates (0,0) have to point to the primary monitor origin */
160     OffsetRect( &virtual_screen_rect, -primary->rcMonitor.left, -primary->rcMonitor.top );
161     for (i = 0; i < nb_monitors; i++)
162     {
163         OffsetRect( &monitors[i].rcMonitor, virtual_screen_rect.left, virtual_screen_rect.top );
164         OffsetRect( &monitors[i].rcWork, virtual_screen_rect.left, virtual_screen_rect.top );
165         TRACE( "monitor %p: %s%s\n",
166                index_to_monitor(i), wine_dbgstr_rect(&monitors[i].rcMonitor),
167                (monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" );
168     }
169
170     screen_width = primary->rcMonitor.right - primary->rcMonitor.left;
171     screen_height = primary->rcMonitor.bottom - primary->rcMonitor.top;
172     TRACE( "virtual size: %s primary size: %dx%d\n",
173            wine_dbgstr_rect(&virtual_screen_rect), screen_width, screen_height );
174
175     wine_tsx11_unlock();
176 }
177
178
179 /***********************************************************************
180  *              X11DRV_GetMonitorInfo  (X11DRV.@)
181  */
182 BOOL X11DRV_GetMonitorInfo( HMONITOR handle, LPMONITORINFO info )
183 {
184     int i = monitor_to_index( handle );
185
186     if (i == -1)
187     {
188         SetLastError( ERROR_INVALID_HANDLE );
189         return FALSE;
190     }
191     info->rcMonitor = monitors[i].rcMonitor;
192     info->rcWork = monitors[i].rcWork;
193     info->dwFlags = monitors[i].dwFlags;
194     if (info->cbSize >= sizeof(MONITORINFOEXW))
195         lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitors[i].szDevice );
196     return TRUE;
197 }
198
199
200 /***********************************************************************
201  *              X11DRV_EnumDisplayMonitors  (X11DRV.@)
202  */
203 BOOL X11DRV_EnumDisplayMonitors( HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lp )
204 {
205     int i;
206
207     if (hdc)
208     {
209         POINT origin;
210         RECT limit;
211
212         if (!GetDCOrgEx( hdc, &origin )) return FALSE;
213         if (GetClipBox( hdc, &limit ) == ERROR) return FALSE;
214
215         if (rect && !IntersectRect( &limit, &limit, rect )) return TRUE;
216
217         for (i = 0; i < nb_monitors; i++)
218         {
219             RECT monrect = monitors[i].rcMonitor;
220             OffsetRect( &monrect, -origin.x, -origin.y );
221             if (IntersectRect( &monrect, &monrect, &limit ))
222                 if (!proc( index_to_monitor(i), hdc, &monrect, lp )) break;
223         }
224     }
225     else
226     {
227         for (i = 0; i < nb_monitors; i++)
228         {
229             RECT unused;
230             if (!rect || IntersectRect( &unused, &monitors[i].rcMonitor, rect ))
231                 if (!proc( index_to_monitor(i), 0, &monitors[i].rcMonitor, lp )) break;
232         }
233     }
234     return TRUE;
235 }