]> git.saurik.com Git - wxWidgets.git/blob - src/unix/displayx11.cpp
avoid multiple mouse moved events, refs #15072
[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 // 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
76 class ScreensInfoBase
77 {
78 public:
79 operator const ScreenInfo *() const { return m_screens; }
80
81 unsigned GetCount() const { return static_cast<unsigned>(m_num); }
82
83 protected:
84 ScreenInfo *m_screens;
85 int m_num;
86 };
87
88 #ifdef __WXGTK20__
89
90 class ScreensInfo : public ScreensInfoBase
91 {
92 public:
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
118 class ScreensInfo : public ScreensInfoBase
119 {
120 public:
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
138 class WXDLLEXPORT wxDisplayImplX11 : public wxDisplayImpl
139 {
140 public:
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
162 private:
163 wxRect m_rect;
164 int m_depth;
165
166 wxDECLARE_NO_COPY_CLASS(wxDisplayImplX11);
167 };
168
169 class wxDisplayFactoryX11 : public wxDisplayFactory
170 {
171 public:
172 wxDisplayFactoryX11() { }
173
174 virtual wxDisplayImpl *CreateDisplay(unsigned n);
175 virtual unsigned GetCount();
176 virtual int GetFromPoint(const wxPoint& pt);
177
178 protected:
179 wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryX11);
180 };
181
182 // ============================================================================
183 // wxDisplayFactoryX11 implementation
184 // ============================================================================
185
186 unsigned wxDisplayFactoryX11::GetCount()
187 {
188 return ScreensInfo().GetCount();
189 }
190
191 int 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
209 wxDisplayImpl *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
238 wxArrayVideoModes 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
272 wxVideoMode 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
282 bool 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
331 wxArrayVideoModes 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
352 wxVideoMode wxDisplayImplX11::GetCurrentMode() const
353 {
354 // Not implemented
355 return wxVideoMode();
356 }
357
358 bool 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
387 void 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
408 class wxX11Ptr
409 {
410 public:
411 wxX11Ptr(void *ptr = NULL) : m_ptr(ptr) { }
412 ~wxX11Ptr() { if ( m_ptr ) XFree(m_ptr); }
413
414 private:
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
422 void 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