]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/unix/displayx11.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / unix / displayx11.cpp
... / ...
CommitLineData
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
75class ScreensInfoBase
76{
77public:
78 operator const ScreenInfo *() const { return m_screens; }
79
80 unsigned GetCount() const { return static_cast<unsigned>(m_num); }
81
82protected:
83 ScreenInfo *m_screens;
84 int m_num;
85};
86
87#ifdef __WXGTK20__
88
89class ScreensInfo : public ScreensInfoBase
90{
91public:
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
117class ScreensInfo : public ScreensInfoBase
118{
119public:
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
137class WXDLLEXPORT wxDisplayImplX11 : public wxDisplayImpl
138{
139public:
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
161private:
162 wxRect m_rect;
163 int m_depth;
164
165 wxDECLARE_NO_COPY_CLASS(wxDisplayImplX11);
166};
167
168class wxDisplayFactoryX11 : public wxDisplayFactory
169{
170public:
171 wxDisplayFactoryX11() { }
172
173 virtual wxDisplayImpl *CreateDisplay(unsigned n);
174 virtual unsigned GetCount();
175 virtual int GetFromPoint(const wxPoint& pt);
176
177protected:
178 wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryX11);
179};
180
181// ============================================================================
182// wxDisplayFactoryX11 implementation
183// ============================================================================
184
185unsigned wxDisplayFactoryX11::GetCount()
186{
187 return ScreensInfo().GetCount();
188}
189
190int 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
208wxDisplayImpl *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
237wxArrayVideoModes 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
271wxVideoMode 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
281bool 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
330wxArrayVideoModes 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
351wxVideoMode wxDisplayImplX11::GetCurrentMode() const
352{
353 // Not implemented
354 return wxVideoMode();
355}
356
357bool 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
386void 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
407class wxX11Ptr
408{
409public:
410 wxX11Ptr(void *ptr = NULL) : m_ptr(ptr) { }
411 ~wxX11Ptr() { if ( m_ptr ) XFree(m_ptr); }
412
413private:
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
421void 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