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