]> git.saurik.com Git - wxWidgets.git/blame - src/unix/displayx11.cpp
Trigger wxLog auto-creation when getting old logger in wxLogChain ctor.
[wxWidgets.git] / src / unix / displayx11.cpp
CommitLineData
b1b3ddd8 1///////////////////////////////////////////////////////////////////////////
ef1717a9 2// Name: src/unix/displayx11.cpp
b1b3ddd8 3// Purpose: Unix/X11 implementation of wxDisplay class
ef1717a9 4// Author: Brian Victor, Vadim Zeitlin
b1b3ddd8
JS
5// Modified by:
6// Created: 12/05/02
7// RCS-ID: $Id$
77ffb593 8// Copyright: (c) wxWidgets team
65571936 9// Licence: wxWindows licence
b1b3ddd8
JS
10/////////////////////////////////////////////////////////////////////////////
11
ef1717a9
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
b1b3ddd8
JS
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
ad9835c9 24 #pragma hdrstop
b1b3ddd8
JS
25#endif
26
ad9835c9 27#if wxUSE_DISPLAY
b1b3ddd8 28
88a7a4e1
WS
29#include "wx/display.h"
30
b1b3ddd8 31#ifndef WX_PRECOMP
ad9835c9
WS
32 #include "wx/dynarray.h"
33 #include "wx/gdicmn.h"
34 #include "wx/string.h"
35 #include "wx/utils.h"
88a7a4e1 36 #include "wx/intl.h"
e4db172a 37 #include "wx/log.h"
b1b3ddd8
JS
38#endif /* WX_PRECOMP */
39
ad9835c9 40#include "wx/display_impl.h"
b1b3ddd8 41
bfd62c8c
VZ
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>
b1b3ddd8 63
bfd62c8c 64 #include <X11/extensions/Xinerama.h>
bfd62c8c
VZ
65 }
66
67 typedef XineramaScreenInfo ScreenInfo;
68#endif // GTK+/Xinerama
b1b3ddd8 69
ef1717a9 70// ----------------------------------------------------------------------------
bfd62c8c 71// helper class storing information about all screens
ef1717a9
VZ
72// ----------------------------------------------------------------------------
73
bfd62c8c
VZ
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
b1b3ddd8 91{
ef1717a9
VZ
92public:
93 ScreensInfo()
b1b3ddd8 94 {
bfd62c8c
VZ
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 }
b1b3ddd8
JS
108 }
109
ef1717a9 110 ~ScreensInfo()
3cb98121 111 {
bfd62c8c 112 delete [] m_screens;
3cb98121 113 }
bfd62c8c 114};
3cb98121 115
bfd62c8c 116#else // Xinerama
ef1717a9 117
bfd62c8c
VZ
118class ScreensInfo : public ScreensInfoBase
119{
120public:
121 ScreensInfo()
122 {
123 m_screens = XineramaQueryScreens((Display *)wxGetDisplay(), &m_num);
124 }
ef1717a9 125
bfd62c8c
VZ
126 ~ScreensInfo()
127 {
128 XFree(m_screens);
129 }
ef1717a9
VZ
130};
131
bfd62c8c
VZ
132#endif // GTK+/Xinerama
133
ef1717a9
VZ
134// ----------------------------------------------------------------------------
135// display and display factory classes
136// ----------------------------------------------------------------------------
b1b3ddd8 137
ef1717a9 138class WXDLLEXPORT wxDisplayImplX11 : public wxDisplayImpl
b1b3ddd8 139{
ef1717a9 140public:
bfd62c8c 141 wxDisplayImplX11(unsigned n, const ScreenInfo& info)
547308b8
VZ
142 : wxDisplayImpl(n),
143 m_rect(info.x_org, info.y_org, info.width, info.height)
ef1717a9
VZ
144 {
145 }
b1b3ddd8 146
ef1717a9 147 virtual wxRect GetGeometry() const { return m_rect; }
676c8c1d
VZ
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
ef1717a9
VZ
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
c0c133e1 166 wxDECLARE_NO_COPY_CLASS(wxDisplayImplX11);
ef1717a9
VZ
167};
168
169class wxDisplayFactoryX11 : public wxDisplayFactory
b1b3ddd8 170{
ef1717a9 171public:
1003169e 172 wxDisplayFactoryX11() { }
ef1717a9 173
4e675101
PC
174 virtual wxDisplayImpl *CreateDisplay(unsigned n);
175 virtual unsigned GetCount();
ef1717a9 176 virtual int GetFromPoint(const wxPoint& pt);
b1b3ddd8 177
ef1717a9 178protected:
c0c133e1 179 wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryX11);
ef1717a9
VZ
180};
181
182// ============================================================================
183// wxDisplayFactoryX11 implementation
184// ============================================================================
185
4e675101 186unsigned wxDisplayFactoryX11::GetCount()
b1b3ddd8 187{
ef1717a9 188 return ScreensInfo().GetCount();
b1b3ddd8
JS
189}
190
ef1717a9 191int wxDisplayFactoryX11::GetFromPoint(const wxPoint& p)
b1b3ddd8 192{
ef1717a9
VZ
193 ScreensInfo screens;
194
4e675101
PC
195 const unsigned numscreens(screens.GetCount());
196 for ( unsigned i = 0; i < numscreens; ++i )
ef1717a9 197 {
bfd62c8c 198 const ScreenInfo& s = screens[i];
ef1717a9
VZ
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;
b1b3ddd8
JS
207}
208
4e675101 209wxDisplayImpl *wxDisplayFactoryX11::CreateDisplay(unsigned n)
b1b3ddd8 210{
ef1717a9
VZ
211 ScreensInfo screens;
212
547308b8 213 return n < screens.GetCount() ? new wxDisplayImplX11(n, screens[n]) : NULL;
b1b3ddd8
JS
214}
215
ef1717a9
VZ
216// ============================================================================
217// wxDisplayImplX11 implementation
218// ============================================================================
505c8ccd
VS
219
220#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
221
f84bc357
PC
222#include <X11/extensions/xf86vmode.h>
223
73b89f70
RN
224//
225// See (http://www.xfree86.org/4.2.0/XF86VidModeDeleteModeLine.3.html) for more
226// info about xf86 video mode extensions
227//
228
2980fc88
RN
229//free private data common to x (usually s3) servers
230#define wxClearXVM(vm) if(vm.privsize) XFree(vm.c_private)
231
a90bf709 232// Correct res rate from GLFW
2980fc88
RN
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)
73b89f70 237
0d5b6a40 238wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& mode) const
e07d33e7 239{
73b89f70
RN
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...
2980fc88 255 mode.Matches(wxCVM((*ppXModes[i]))) ) //...?
73b89f70 256 {
2980fc88 257 Modes.Add(wxCVM((*ppXModes[i])));
73b89f70
RN
258 }
259 wxClearXVM((*ppXModes[i]));
260 // XFree(ppXModes[i]); //supposed to free?
261 }
262 XFree(ppXModes);
263 }
264 else //OOPS!
265 {
428b6942 266 wxLogSysError(_("Failed to enumerate video modes"));
73b89f70
RN
267 }
268
269 return Modes;
e07d33e7
RN
270}
271
0d5b6a40 272wxVideoMode wxDisplayImplX11::GetCurrentMode() const
e07d33e7 273{
2980fc88
RN
274 XF86VidModeModeLine VM;
275 int nDotClock;
276 XF86VidModeGetModeLine((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
277 &nDotClock, &VM);
278 wxClearXVM(VM);
279 return wxCVM2(VM, nDotClock);
e07d33e7
RN
280}
281
0d5b6a40 282bool wxDisplayImplX11::ChangeMode(const wxVideoMode& mode)
e07d33e7 283{
a90bf709
VZ
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) )
73b89f70 288 {
a90bf709
VZ
289 wxLogSysError(_("Failed to change video mode"));
290 return false;
291 }
73b89f70 292
a90bf709
VZ
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)
73b89f70 300 {
a90bf709
VZ
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 &&
69fb24ce
RR
310 ppXModes[i]->hdisplay == mode.GetWidth() &&
311 ppXModes[i]->vdisplay == mode.GetHeight() &&
312 wxCRR((*ppXModes[i])) == mode.GetRefresh())
2980fc88 313 {
a90bf709 314 //switch!
2980fc88 315 bRet = XF86VidModeSwitchToMode((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
a90bf709 316 ppXModes[i]) == TRUE;
2980fc88 317 }
a90bf709
VZ
318 wxClearXVM((*ppXModes[i]));
319 // XFree(ppXModes[i]); //supposed to free?
73b89f70
RN
320 }
321 }
a90bf709
VZ
322
323 XFree(ppXModes);
324
325 return bRet;
e5804ce7
RN
326}
327
328
329#else // !HAVE_X11_EXTENSIONS_XF86VMODE_H
330
d5a20ebb 331wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& modeMatch) const
e5804ce7 332{
ef1717a9
VZ
333 int count_return;
334 int* depths = XListDepths((Display*)wxGetDisplay(), 0, &count_return);
335 wxArrayVideoModes modes;
336 if ( depths )
f2ebd959 337 {
ef1717a9
VZ
338 for ( int x = 0; x < count_return; ++x )
339 {
d5a20ebb
VZ
340 wxVideoMode mode(m_rect.GetWidth(), m_rect.GetHeight(), depths[x]);
341 if ( mode.Matches(modeMatch) )
342 {
343 modes.Add(modeMatch);
344 }
ef1717a9
VZ
345 }
346
347 XFree(depths);
f2ebd959 348 }
ef1717a9 349 return modes;
505c8ccd
VS
350}
351
0d5b6a40 352wxVideoMode wxDisplayImplX11::GetCurrentMode() const
505c8ccd
VS
353{
354 // Not implemented
355 return wxVideoMode();
356}
357
d5a20ebb 358bool wxDisplayImplX11::ChangeMode(const wxVideoMode& WXUNUSED(mode))
505c8ccd
VS
359{
360 // Not implemented
361 return false;
362}
363
364#endif // !HAVE_X11_EXTENSIONS_XF86VMODE_H
365
ef1717a9
VZ
366// ============================================================================
367// wxDisplay::CreateFactory()
368// ============================================================================
369
370/* static */ wxDisplayFactory *wxDisplay::CreateFactory()
371{
bfd62c8c
VZ
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
ef1717a9 377
bfd62c8c 378 return new wxDisplayFactoryX11;
ef1717a9
VZ
379}
380
505c8ccd 381#endif /* wxUSE_DISPLAY */
676c8c1d
VZ
382
383#include "wx/utils.h"
384
a73251a8 385#if wxUSE_LIBHILDON || wxUSE_LIBHILDON2 || !defined(GDK_WINDOWING_X11)
66d05130
VZ
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
426d19f1 400#else // !wxUSE_LIBHILDON || !wxUSE_LIBHILDON2
66d05130 401
562e60a0
PC
402#include "wx/log.h"
403
64bd3204 404#include <X11/Xlib.h>
676c8c1d
VZ
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
c0c133e1 417 wxDECLARE_NO_COPY_CLASS(wxX11Ptr);
676c8c1d
VZ
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();
9a83f860 425 wxCHECK_RET( dpy, wxT("can't be called before initializing the GUI") );
676c8c1d 426
dee05929
VZ
427 wxRect rectClient;
428
676c8c1d
VZ
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
f2633e54
VZ
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
676c8c1d 459 if ( actualType != XA_CARDINAL ||
f2633e54 460 format != 32 ||
676c8c1d
VZ
461 numItems != 4 )
462 {
9a83f860 463 wxLogDebug(wxT("XGetWindowProperty(\"_NET_WORKAREA\") failed"));
676c8c1d 464 }
dee05929
VZ
465 else
466 {
467 rectClient = wxRect(workareas[0], workareas[1],
468 workareas[2], workareas[3]);
469 }
470 }
471 }
676c8c1d 472
dee05929
VZ
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
676c8c1d 484
dee05929
VZ
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);
676c8c1d
VZ
494 }
495
dee05929
VZ
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;
676c8c1d
VZ
504}
505
66d05130 506#endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON