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