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>
30 #include "wine/library.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;
70 static void query_work_area( RECT
*rc_work
)
74 unsigned long count
, remaining
;
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] );
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};
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)
115 if (!(handle
= wine_dlopen(SONAME_LIBXINERAMA
, RTLD_NOW
, NULL
, 0)))
117 WARN( "failed to open %s\n", SONAME_LIBXINERAMA
);
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 */
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
) )))
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
;
167 #else /* SONAME_LIBXINERAMA */
169 static inline int query_screens(void)
174 #endif /* SONAME_LIBXINERAMA */
176 POINT
virtual_screen_to_root( INT x
, INT y
)
179 pt
.x
= x
- virtual_screen_rect
.left
;
180 pt
.y
= y
- virtual_screen_rect
.top
;
184 POINT
root_to_virtual_screen( INT x
, INT y
)
187 pt
.x
= x
+ virtual_screen_rect
.left
;
188 pt
.y
= y
+ virtual_screen_rect
.top
;
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
;
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
);
216 query_desktop_work_area( &default_monitor
.rcWork
);
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
);
251 SetLastError( ERROR_INVALID_HANDLE
);
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
);
263 /***********************************************************************
264 * X11DRV_EnumDisplayMonitors (X11DRV.@)
266 BOOL CDECL
X11DRV_EnumDisplayMonitors( HDC hdc
, LPRECT rect
, MONITORENUMPROC proc
, LPARAM lp
)
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
))
291 for (i
= 0; i
< nb_monitors
; i
++)
294 if (!rect
|| IntersectRect( &unused
, &monitors
[i
].rcMonitor
, rect
))
295 if (!proc( index_to_monitor(i
), 0, &monitors
[i
].rcMonitor
, lp
))