dwrite: Avoid repeated method calls during run rendering.
[wine.git] / dlls / winex11.drv / xinerama.c
blob0419535d49447d5e774f4c4e4dc1b97011ef1273
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 RECT virtual_screen_rect;
38 static MONITORINFOEXW default_monitor =
40 sizeof(default_monitor), /* cbSize */
41 { 0, 0, 0, 0 }, /* rcMonitor */
42 { 0, 0, 0, 0 }, /* rcWork */
43 MONITORINFOF_PRIMARY, /* dwFlags */
44 { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 } /* szDevice */
47 static MONITORINFOEXW *monitors;
48 static int nb_monitors;
50 static inline MONITORINFOEXW *get_primary(void)
52 /* default to 0 if specified primary is invalid */
53 int idx = primary_monitor;
54 if (idx >= nb_monitors) idx = 0;
55 return &monitors[idx];
58 static inline HMONITOR index_to_monitor( int index )
60 return (HMONITOR)(UINT_PTR)(index + 1);
63 static inline int monitor_to_index( HMONITOR handle )
65 UINT_PTR index = (UINT_PTR)handle;
66 if (index < 1 || index > nb_monitors) return -1;
67 return index - 1;
70 static void query_work_area( RECT *rc_work )
72 Atom type;
73 int format;
74 unsigned long count, remaining;
75 long *work_area;
77 if (!XGetWindowProperty( gdi_display, DefaultRootWindow(gdi_display), x11drv_atom(_NET_WORKAREA), 0,
78 ~0, False, XA_CARDINAL, &type, &format, &count,
79 &remaining, (unsigned char **)&work_area ))
81 if (type == XA_CARDINAL && format == 32 && count >= 4)
83 SetRect( rc_work, work_area[0], work_area[1],
84 work_area[0] + work_area[2], work_area[1] + work_area[3] );
86 XFree( work_area );
90 static void query_desktop_work_area( RECT *rc_work )
92 static const WCHAR trayW[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
93 RECT rect;
94 HWND hwnd = FindWindowW( trayW, NULL );
96 if (!hwnd || !IsWindowVisible( hwnd )) return;
97 if (!GetWindowRect( hwnd, &rect )) return;
98 if (rect.top) rc_work->bottom = rect.top;
99 else rc_work->top = rect.bottom;
100 TRACE( "found tray %p %s work area %s\n", hwnd,
101 wine_dbgstr_rect( &rect ), wine_dbgstr_rect( rc_work ));
104 #ifdef SONAME_LIBXINERAMA
106 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
108 MAKE_FUNCPTR(XineramaQueryExtension);
109 MAKE_FUNCPTR(XineramaQueryScreens);
111 static void load_xinerama(void)
113 void *handle;
115 if (!(handle = wine_dlopen(SONAME_LIBXINERAMA, RTLD_NOW, NULL, 0)))
117 WARN( "failed to open %s\n", SONAME_LIBXINERAMA );
118 return;
120 pXineramaQueryExtension = wine_dlsym( handle, "XineramaQueryExtension", NULL, 0 );
121 if (!pXineramaQueryExtension) WARN( "XineramaQueryScreens not found\n" );
122 pXineramaQueryScreens = wine_dlsym( handle, "XineramaQueryScreens", NULL, 0 );
123 if (!pXineramaQueryScreens) WARN( "XineramaQueryScreens not found\n" );
126 static int query_screens(void)
128 int i, count, event_base, error_base;
129 XineramaScreenInfo *screens;
130 RECT rc_work = {0, 0, 0, 0};
132 if (!monitors) /* first time around */
133 load_xinerama();
135 query_work_area( &rc_work );
137 if (!pXineramaQueryExtension || !pXineramaQueryScreens ||
138 !pXineramaQueryExtension( gdi_display, &event_base, &error_base ) ||
139 !(screens = pXineramaQueryScreens( gdi_display, &count ))) return 0;
141 if (monitors != &default_monitor) HeapFree( GetProcessHeap(), 0, monitors );
142 if ((monitors = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*monitors) )))
144 nb_monitors = count;
145 for (i = 0; i < nb_monitors; i++)
147 monitors[i].cbSize = sizeof( monitors[i] );
148 monitors[i].rcMonitor.left = screens[i].x_org;
149 monitors[i].rcMonitor.top = screens[i].y_org;
150 monitors[i].rcMonitor.right = screens[i].x_org + screens[i].width;
151 monitors[i].rcMonitor.bottom = screens[i].y_org + screens[i].height;
152 monitors[i].dwFlags = 0;
153 if (!IntersectRect( &monitors[i].rcWork, &rc_work, &monitors[i].rcMonitor ))
154 monitors[i].rcWork = monitors[i].rcMonitor;
155 /* FIXME: using the same device name for all monitors for now */
156 lstrcpyW( monitors[i].szDevice, default_monitor.szDevice );
159 get_primary()->dwFlags |= MONITORINFOF_PRIMARY;
161 else count = 0;
163 XFree( screens );
164 return count;
167 #else /* SONAME_LIBXINERAMA */
169 static inline int query_screens(void)
171 return 0;
174 #endif /* SONAME_LIBXINERAMA */
176 POINT virtual_screen_to_root( INT x, INT y )
178 POINT pt;
179 pt.x = x - virtual_screen_rect.left;
180 pt.y = y - virtual_screen_rect.top;
181 return pt;
184 POINT root_to_virtual_screen( INT x, INT y )
186 POINT pt;
187 pt.x = x + virtual_screen_rect.left;
188 pt.y = y + virtual_screen_rect.top;
189 return pt;
192 RECT get_virtual_screen_rect(void)
194 return virtual_screen_rect;
197 RECT get_primary_monitor_rect(void)
199 return get_primary()->rcMonitor;
202 void xinerama_init( unsigned int width, unsigned int height )
204 MONITORINFOEXW *primary;
205 int i;
206 RECT rect;
208 SetRect( &rect, 0, 0, width, height );
210 if (root_window != DefaultRootWindow( gdi_display ) || !query_screens())
212 default_monitor.rcWork = default_monitor.rcMonitor = rect;
213 if (root_window == DefaultRootWindow( gdi_display ))
214 query_work_area( &default_monitor.rcWork );
215 else
216 query_desktop_work_area( &default_monitor.rcWork );
217 nb_monitors = 1;
218 monitors = &default_monitor;
221 primary = get_primary();
222 SetRectEmpty( &virtual_screen_rect );
224 /* coordinates (0,0) have to point to the primary monitor origin */
225 OffsetRect( &rect, -primary->rcMonitor.left, -primary->rcMonitor.top );
226 for (i = 0; i < nb_monitors; i++)
228 OffsetRect( &monitors[i].rcMonitor, rect.left, rect.top );
229 OffsetRect( &monitors[i].rcWork, rect.left, rect.top );
230 UnionRect( &virtual_screen_rect, &virtual_screen_rect, &monitors[i].rcMonitor );
231 TRACE( "monitor %p: %s work %s%s\n",
232 index_to_monitor(i), wine_dbgstr_rect(&monitors[i].rcMonitor),
233 wine_dbgstr_rect(&monitors[i].rcWork),
234 (monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" );
237 TRACE( "virtual size: %s primary: %s\n",
238 wine_dbgstr_rect(&virtual_screen_rect), wine_dbgstr_rect(&primary->rcMonitor) );
242 /***********************************************************************
243 * X11DRV_GetMonitorInfo (X11DRV.@)
245 BOOL CDECL X11DRV_GetMonitorInfo( HMONITOR handle, LPMONITORINFO info )
247 int i = monitor_to_index( handle );
249 if (i == -1)
251 SetLastError( ERROR_INVALID_HANDLE );
252 return FALSE;
254 info->rcMonitor = monitors[i].rcMonitor;
255 info->rcWork = monitors[i].rcWork;
256 info->dwFlags = monitors[i].dwFlags;
257 if (info->cbSize >= sizeof(MONITORINFOEXW))
258 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitors[i].szDevice );
259 return TRUE;
263 /***********************************************************************
264 * X11DRV_EnumDisplayMonitors (X11DRV.@)
266 BOOL CDECL X11DRV_EnumDisplayMonitors( HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lp )
268 int i;
270 if (hdc)
272 POINT origin;
273 RECT limit;
275 if (!GetDCOrgEx( hdc, &origin )) return FALSE;
276 if (GetClipBox( hdc, &limit ) == ERROR) return FALSE;
278 if (rect && !IntersectRect( &limit, &limit, rect )) return TRUE;
280 for (i = 0; i < nb_monitors; i++)
282 RECT monrect = monitors[i].rcMonitor;
283 OffsetRect( &monrect, -origin.x, -origin.y );
284 if (IntersectRect( &monrect, &monrect, &limit ))
285 if (!proc( index_to_monitor(i), hdc, &monrect, lp ))
286 return FALSE;
289 else
291 for (i = 0; i < nb_monitors; i++)
293 RECT unused;
294 if (!rect || IntersectRect( &unused, &monitors[i].rcMonitor, rect ))
295 if (!proc( index_to_monitor(i), 0, &monitors[i].rcMonitor, lp ))
296 return FALSE;
299 return TRUE;