]> git.saurik.com Git - wxWidgets.git/blob - src/unix/displayx11.cpp
wxRTC: extracted XML utilities into a separate class for potential reuse.
[wxWidgets.git] / src / unix / displayx11.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/displayx11.cpp
3 // Purpose: Unix/X11 implementation of wxDisplay class
4 // Author: Brian Victor, Vadim Zeitlin
5 // Modified by:
6 // Created: 12/05/02
7 // Copyright: (c) wxWidgets team
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_DISPLAY
27
28 #include "wx/display.h"
29
30 #ifndef WX_PRECOMP
31 #include "wx/dynarray.h"
32 #include "wx/gdicmn.h"
33 #include "wx/string.h"
34 #include "wx/utils.h"
35 #include "wx/intl.h"
36 #include "wx/log.h"
37 #endif /* WX_PRECOMP */
38
39 #include "wx/display_impl.h"
40
41 #ifdef __WXGTK20__
42 #include <gdk/gdk.h>
43 #include <gdk/gdkx.h>
44
45 // define the struct with the same fields as XineramaScreenInfo (except for
46 // screen number which we don't need) but which we can use without
47 // including Xinerama headers
48 struct ScreenInfo
49 {
50 short x_org;
51 short y_org;
52 short width;
53 short height;
54 };
55 #else // use raw Xinerama functions
56 /* These must be included after the wx files. Otherwise the Data macro in
57 * Xlibint.h conflicts with a function declaration in wx/list.h. */
58 extern "C"
59 {
60 #include <X11/Xlib.h>
61 #include <X11/Xlibint.h>
62
63 #include <X11/extensions/Xinerama.h>
64 }
65
66 typedef XineramaScreenInfo ScreenInfo;
67 #endif // GTK+/Xinerama
68
69 // ----------------------------------------------------------------------------
70 // helper class storing information about all screens
71 // ----------------------------------------------------------------------------
72
73 // the base class provides access to ScreenInfo array, derived class
74 // initializes it using either GTK+ or Xinerama functions
75 class ScreensInfoBase
76 {
77 public:
78 operator const ScreenInfo *() const { return m_screens; }
79
80 unsigned GetCount() const { return static_cast<unsigned>(m_num); }
81
82 protected:
83 ScreenInfo *m_screens;
84 int m_num;
85 };
86
87 #ifdef __WXGTK20__
88
89 class ScreensInfo : public ScreensInfoBase
90 {
91 public:
92 ScreensInfo()
93 {
94 GdkScreen * const screen = gdk_screen_get_default();
95
96 m_num = gdk_screen_get_n_monitors(screen);
97 m_screens = new ScreenInfo[m_num];
98 for ( int i = 0; i < m_num; i++ )
99 {
100 GdkRectangle rect;
101 gdk_screen_get_monitor_geometry(screen, i, &rect);
102 m_screens[i].x_org = rect.x;
103 m_screens[i].y_org = rect.y;
104 m_screens[i].width = rect.width;
105 m_screens[i].height = rect.height;
106 }
107 }
108
109 ~ScreensInfo()
110 {
111 delete [] m_screens;
112 }
113 };
114
115 #else // Xinerama
116
117 class ScreensInfo : public ScreensInfoBase
118 {
119 public:
120 ScreensInfo()
121 {
122 m_screens = XineramaQueryScreens((Display *)wxGetDisplay(), &m_num);
123 }
124
125 ~ScreensInfo()
126 {
127 XFree(m_screens);
128 }
129 };
130
131 #endif // GTK+/Xinerama
132
133 // ----------------------------------------------------------------------------
134 // display and display factory classes
135 // ----------------------------------------------------------------------------
136
137 class WXDLLEXPORT wxDisplayImplX11 : public wxDisplayImpl
138 {
139 public:
140 wxDisplayImplX11(unsigned n, const ScreenInfo& info)
141 : wxDisplayImpl(n),
142 m_rect(info.x_org, info.y_org, info.width, info.height)
143 {
144 }
145
146 virtual wxRect GetGeometry() const { return m_rect; }
147 virtual wxRect GetClientArea() const
148 {
149 // we intentionally don't cache the result here because the client
150 // display area may change (e.g. the user resized or hid a panel) and
151 // we don't currently react to its changes
152 return IsPrimary() ? wxGetClientDisplayRect() : m_rect;
153 }
154
155 virtual wxString GetName() const { return wxString(); }
156
157 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
158 virtual wxVideoMode GetCurrentMode() const;
159 virtual bool ChangeMode(const wxVideoMode& mode);
160
161 private:
162 wxRect m_rect;
163 int m_depth;
164
165 wxDECLARE_NO_COPY_CLASS(wxDisplayImplX11);
166 };
167
168 class wxDisplayFactoryX11 : public wxDisplayFactory
169 {
170 public:
171 wxDisplayFactoryX11() { }
172
173 virtual wxDisplayImpl *CreateDisplay(unsigned n);
174 virtual unsigned GetCount();
175 virtual int GetFromPoint(const wxPoint& pt);
176
177 protected:
178 wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryX11);
179 };
180
181 // ============================================================================
182 // wxDisplayFactoryX11 implementation
183 // ============================================================================
184
185 unsigned wxDisplayFactoryX11::GetCount()
186 {
187 return ScreensInfo().GetCount();
188 }
189
190 int wxDisplayFactoryX11::GetFromPoint(const wxPoint& p)
191 {
192 ScreensInfo screens;
193
194 const unsigned numscreens(screens.GetCount());
195 for ( unsigned i = 0; i < numscreens; ++i )
196 {
197 const ScreenInfo& s = screens[i];
198 if ( p.x >= s.x_org && p.x < s.x_org + s.width &&
199 p.y >= s.y_org && p.y < s.y_org + s.height )
200 {
201 return i;
202 }
203 }
204
205 return wxNOT_FOUND;
206 }
207
208 wxDisplayImpl *wxDisplayFactoryX11::CreateDisplay(unsigned n)
209 {
210 ScreensInfo screens;
211
212 return n < screens.GetCount() ? new wxDisplayImplX11(n, screens[n]) : NULL;
213 }
214
215 // ============================================================================
216 // wxDisplayImplX11 implementation
217 // ============================================================================
218
219 #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
220
221 #include <X11/extensions/xf86vmode.h>
222
223 //
224 // See (http://www.xfree86.org/4.2.0/XF86VidModeDeleteModeLine.3.html) for more
225 // info about xf86 video mode extensions
226 //
227
228 //free private data common to x (usually s3) servers
229 #define wxClearXVM(vm) if(vm.privsize) XFree(vm.c_private)
230
231 // Correct res rate from GLFW
232 #define wxCRR2(v,dc) (int) (((1000.0f * (float) dc) /*PIXELS PER SECOND */) / ((float) v.htotal * v.vtotal /*PIXELS PER FRAME*/) + 0.5f)
233 #define wxCRR(v) wxCRR2(v,v.dotclock)
234 #define wxCVM2(v, dc) wxVideoMode(v.hdisplay, v.vdisplay, DefaultDepth((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay())), wxCRR2(v,dc))
235 #define wxCVM(v) wxCVM2(v, v.dotclock)
236
237 wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& mode) const
238 {
239 //Convenience...
240 Display* pDisplay = (Display*) wxGetDisplay(); //default display
241 int nScreen = DefaultScreen(pDisplay); //default screen of (default) display...
242
243 //Some variables..
244 XF86VidModeModeInfo** ppXModes; //Enumerated Modes (Don't forget XFree() :))
245 int nNumModes; //Number of modes enumerated....
246
247 wxArrayVideoModes Modes; //modes to return...
248
249 if (XF86VidModeGetAllModeLines(pDisplay, nScreen, &nNumModes, &ppXModes) == TRUE)
250 {
251 for (int i = 0; i < nNumModes; ++i)
252 {
253 if (mode == wxDefaultVideoMode || //According to display.h All modes valid if dafault mode...
254 mode.Matches(wxCVM((*ppXModes[i]))) ) //...?
255 {
256 Modes.Add(wxCVM((*ppXModes[i])));
257 }
258 wxClearXVM((*ppXModes[i]));
259 // XFree(ppXModes[i]); //supposed to free?
260 }
261 XFree(ppXModes);
262 }
263 else //OOPS!
264 {
265 wxLogSysError(_("Failed to enumerate video modes"));
266 }
267
268 return Modes;
269 }
270
271 wxVideoMode wxDisplayImplX11::GetCurrentMode() const
272 {
273 XF86VidModeModeLine VM;
274 int nDotClock;
275 XF86VidModeGetModeLine((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
276 &nDotClock, &VM);
277 wxClearXVM(VM);
278 return wxCVM2(VM, nDotClock);
279 }
280
281 bool wxDisplayImplX11::ChangeMode(const wxVideoMode& mode)
282 {
283 XF86VidModeModeInfo** ppXModes; //Enumerated Modes (Don't forget XFree() :))
284 int nNumModes; //Number of modes enumerated....
285
286 if( !XF86VidModeGetAllModeLines((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()), &nNumModes, &ppXModes) )
287 {
288 wxLogSysError(_("Failed to change video mode"));
289 return false;
290 }
291
292 bool bRet = false;
293 if (mode == wxDefaultVideoMode)
294 {
295 bRet = XF86VidModeSwitchToMode((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
296 ppXModes[0]) == TRUE;
297
298 for (int i = 0; i < nNumModes; ++i)
299 {
300 wxClearXVM((*ppXModes[i]));
301 // XFree(ppXModes[i]); //supposed to free?
302 }
303 }
304 else
305 {
306 for (int i = 0; i < nNumModes; ++i)
307 {
308 if (!bRet &&
309 ppXModes[i]->hdisplay == mode.GetWidth() &&
310 ppXModes[i]->vdisplay == mode.GetHeight() &&
311 wxCRR((*ppXModes[i])) == mode.GetRefresh())
312 {
313 //switch!
314 bRet = XF86VidModeSwitchToMode((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
315 ppXModes[i]) == TRUE;
316 }
317 wxClearXVM((*ppXModes[i]));
318 // XFree(ppXModes[i]); //supposed to free?
319 }
320 }
321
322 XFree(ppXModes);
323
324 return bRet;
325 }
326
327
328 #else // !HAVE_X11_EXTENSIONS_XF86VMODE_H
329
330 wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& modeMatch) const
331 {
332 int count_return;
333 int* depths = XListDepths((Display*)wxGetDisplay(), 0, &count_return);
334 wxArrayVideoModes modes;
335 if ( depths )
336 {
337 for ( int x = 0; x < count_return; ++x )
338 {
339 wxVideoMode mode(m_rect.GetWidth(), m_rect.GetHeight(), depths[x]);
340 if ( mode.Matches(modeMatch) )
341 {
342 modes.Add(modeMatch);
343 }
344 }
345
346 XFree(depths);
347 }
348 return modes;
349 }
350
351 wxVideoMode wxDisplayImplX11::GetCurrentMode() const
352 {
353 // Not implemented
354 return wxVideoMode();
355 }
356
357 bool wxDisplayImplX11::ChangeMode(const wxVideoMode& WXUNUSED(mode))
358 {
359 // Not implemented
360 return false;
361 }
362
363 #endif // !HAVE_X11_EXTENSIONS_XF86VMODE_H
364
365 // ============================================================================
366 // wxDisplay::CreateFactory()
367 // ============================================================================
368
369 /* static */ wxDisplayFactory *wxDisplay::CreateFactory()
370 {
371 // GTK+ screen functions are always available, no need to check for them
372 #ifndef __WXGTK20__
373 if ( !XineramaIsActive((Display*)wxGetDisplay()) )
374 return new wxDisplayFactorySingle;
375 #endif
376
377 return new wxDisplayFactoryX11;
378 }
379
380 #endif /* wxUSE_DISPLAY */
381
382 #include "wx/utils.h"
383
384 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2 || !defined(GDK_WINDOWING_X11)
385
386 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
387 {
388 // TODO: don't hardcode display size
389 if ( x )
390 *x = 0;
391 if ( y )
392 *y = 0;
393 if ( width )
394 *width = 672;
395 if ( height )
396 *height = 396;
397 }
398
399 #else // !wxUSE_LIBHILDON || !wxUSE_LIBHILDON2
400
401 #include "wx/log.h"
402
403 #include <X11/Xlib.h>
404 #include <X11/Xatom.h>
405
406 // TODO: make this a full-fledged class and move to a public header
407 class wxX11Ptr
408 {
409 public:
410 wxX11Ptr(void *ptr = NULL) : m_ptr(ptr) { }
411 ~wxX11Ptr() { if ( m_ptr ) XFree(m_ptr); }
412
413 private:
414 void *m_ptr;
415
416 wxDECLARE_NO_COPY_CLASS(wxX11Ptr);
417 };
418
419 // NB: this function is implemented using X11 and not GDK calls as it's shared
420 // by wxGTK[12], wxX11 and wxMotif ports
421 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
422 {
423 Display * const dpy = wxGetX11Display();
424 wxCHECK_RET( dpy, wxT("can't be called before initializing the GUI") );
425
426 wxRect rectClient;
427
428 const Atom atomWorkArea = XInternAtom(dpy, "_NET_WORKAREA", True);
429 if ( atomWorkArea )
430 {
431 long *workareas = NULL;
432 unsigned long numItems;
433 unsigned long bytesRemaining;
434 Atom actualType;
435 int format;
436
437 if ( XGetWindowProperty
438 (
439 dpy,
440 XDefaultRootWindow(dpy),
441 atomWorkArea,
442 0, // offset of data to retrieve
443 4, // number of items to retrieve
444 False, // don't delete property
445 XA_CARDINAL, // type of the items to get
446 &actualType,
447 &format,
448 &numItems,
449 &bytesRemaining,
450 (unsigned char **)&workareas
451 ) == Success && workareas )
452 {
453 wxX11Ptr x11ptr(workareas); // ensure it will be freed
454
455 // check that we retrieved the property of the expected type and
456 // that we did get back 4 longs (32 is the format for long), as
457 // requested
458 if ( actualType != XA_CARDINAL ||
459 format != 32 ||
460 numItems != 4 )
461 {
462 wxLogDebug(wxT("XGetWindowProperty(\"_NET_WORKAREA\") failed"));
463 }
464 else
465 {
466 rectClient = wxRect(workareas[0], workareas[1],
467 workareas[2], workareas[3]);
468 }
469 }
470 }
471
472 // Although _NET_WORKAREA is supposed to return the client size of the
473 // screen, not all implementations are conforming, apparently, see #14419,
474 // so make sure we return a subset of the primary display.
475 wxRect rectFull;
476 #if wxUSE_DISPLAY
477 ScreensInfo screens;
478 const ScreenInfo& info = screens[0];
479 rectFull = wxRect(info.x_org, info.y_org, info.width, info.height);
480 #else
481 wxDisplaySize(&rectFull.width, &rectFull.height);
482 #endif
483
484 if ( !rectClient.width || !rectClient.height )
485 {
486 // _NET_WORKAREA not available or didn't work, fall back to the total
487 // display size.
488 rectClient = rectFull;
489 }
490 else
491 {
492 rectClient = rectClient.Intersect(rectFull);
493 }
494
495 if ( x )
496 *x = rectClient.x;
497 if ( y )
498 *y = rectClient.y;
499 if ( width )
500 *width = rectClient.width;
501 if ( height )
502 *height = rectClient.height;
503 }
504
505 #endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON