Use GTK+ functions for wxDisplay implementation.
[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 #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
66 #include <X11/extensions/xf86vmode.h>
67 #endif
68 }
69
70 typedef XineramaScreenInfo ScreenInfo;
71 #endif // GTK+/Xinerama
72
73 // ----------------------------------------------------------------------------
74 // helper class storing information about all screens
75 // ----------------------------------------------------------------------------
76
77 // the base class provides access to ScreenInfo array, derived class
78 // initializes it using either GTK+ or Xinerama functions
79 class ScreensInfoBase
80 {
81 public:
82 operator const ScreenInfo *() const { return m_screens; }
83
84 unsigned GetCount() const { return static_cast<unsigned>(m_num); }
85
86 protected:
87 ScreenInfo *m_screens;
88 int m_num;
89 };
90
91 #ifdef __WXGTK20__
92
93 class ScreensInfo : public ScreensInfoBase
94 {
95 public:
96 ScreensInfo()
97 {
98 GdkScreen * const screen = gdk_screen_get_default();
99
100 m_num = gdk_screen_get_n_monitors(screen);
101 m_screens = new ScreenInfo[m_num];
102 for ( int i = 0; i < m_num; i++ )
103 {
104 GdkRectangle rect;
105 gdk_screen_get_monitor_geometry(screen, i, &rect);
106 m_screens[i].x_org = rect.x;
107 m_screens[i].y_org = rect.y;
108 m_screens[i].width = rect.width;
109 m_screens[i].height = rect.height;
110 }
111 }
112
113 ~ScreensInfo()
114 {
115 delete [] m_screens;
116 }
117 };
118
119 #else // Xinerama
120
121 class ScreensInfo : public ScreensInfoBase
122 {
123 public:
124 ScreensInfo()
125 {
126 m_screens = XineramaQueryScreens((Display *)wxGetDisplay(), &m_num);
127 }
128
129 ~ScreensInfo()
130 {
131 XFree(m_screens);
132 }
133 };
134
135 #endif // GTK+/Xinerama
136
137 // ----------------------------------------------------------------------------
138 // display and display factory classes
139 // ----------------------------------------------------------------------------
140
141 class WXDLLEXPORT wxDisplayImplX11 : public wxDisplayImpl
142 {
143 public:
144 wxDisplayImplX11(unsigned n, const ScreenInfo& info)
145 : wxDisplayImpl(n),
146 m_rect(info.x_org, info.y_org, info.width, info.height)
147 {
148 }
149
150 virtual wxRect GetGeometry() const { return m_rect; }
151 virtual wxRect GetClientArea() const
152 {
153 // we intentionally don't cache the result here because the client
154 // display area may change (e.g. the user resized or hid a panel) and
155 // we don't currently react to its changes
156 return IsPrimary() ? wxGetClientDisplayRect() : m_rect;
157 }
158
159 virtual wxString GetName() const { return wxString(); }
160
161 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
162 virtual wxVideoMode GetCurrentMode() const;
163 virtual bool ChangeMode(const wxVideoMode& mode);
164
165 private:
166 wxRect m_rect;
167 int m_depth;
168
169 wxDECLARE_NO_COPY_CLASS(wxDisplayImplX11);
170 };
171
172 class wxDisplayFactoryX11 : public wxDisplayFactory
173 {
174 public:
175 wxDisplayFactoryX11() { }
176
177 virtual wxDisplayImpl *CreateDisplay(unsigned n);
178 virtual unsigned GetCount();
179 virtual int GetFromPoint(const wxPoint& pt);
180
181 protected:
182 wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryX11);
183 };
184
185 // ============================================================================
186 // wxDisplayFactoryX11 implementation
187 // ============================================================================
188
189 unsigned wxDisplayFactoryX11::GetCount()
190 {
191 return ScreensInfo().GetCount();
192 }
193
194 int wxDisplayFactoryX11::GetFromPoint(const wxPoint& p)
195 {
196 ScreensInfo screens;
197
198 const unsigned numscreens(screens.GetCount());
199 for ( unsigned i = 0; i < numscreens; ++i )
200 {
201 const ScreenInfo& s = screens[i];
202 if ( p.x >= s.x_org && p.x < s.x_org + s.width &&
203 p.y >= s.y_org && p.y < s.y_org + s.height )
204 {
205 return i;
206 }
207 }
208
209 return wxNOT_FOUND;
210 }
211
212 wxDisplayImpl *wxDisplayFactoryX11::CreateDisplay(unsigned n)
213 {
214 ScreensInfo screens;
215
216 return n < screens.GetCount() ? new wxDisplayImplX11(n, screens[n]) : NULL;
217 }
218
219 // ============================================================================
220 // wxDisplayImplX11 implementation
221 // ============================================================================
222
223 #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
224
225 //
226 // See (http://www.xfree86.org/4.2.0/XF86VidModeDeleteModeLine.3.html) for more
227 // info about xf86 video mode extensions
228 //
229
230 //free private data common to x (usually s3) servers
231 #define wxClearXVM(vm) if(vm.privsize) XFree(vm.c_private)
232
233 // Correct res rate from GLFW
234 #define wxCRR2(v,dc) (int) (((1000.0f * (float) dc) /*PIXELS PER SECOND */) / ((float) v.htotal * v.vtotal /*PIXELS PER FRAME*/) + 0.5f)
235 #define wxCRR(v) wxCRR2(v,v.dotclock)
236 #define wxCVM2(v, dc) wxVideoMode(v.hdisplay, v.vdisplay, DefaultDepth((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay())), wxCRR2(v,dc))
237 #define wxCVM(v) wxCVM2(v, v.dotclock)
238
239 wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& mode) const
240 {
241 //Convenience...
242 Display* pDisplay = (Display*) wxGetDisplay(); //default display
243 int nScreen = DefaultScreen(pDisplay); //default screen of (default) display...
244
245 //Some variables..
246 XF86VidModeModeInfo** ppXModes; //Enumerated Modes (Don't forget XFree() :))
247 int nNumModes; //Number of modes enumerated....
248
249 wxArrayVideoModes Modes; //modes to return...
250
251 if (XF86VidModeGetAllModeLines(pDisplay, nScreen, &nNumModes, &ppXModes) == TRUE)
252 {
253 for (int i = 0; i < nNumModes; ++i)
254 {
255 if (mode == wxDefaultVideoMode || //According to display.h All modes valid if dafault mode...
256 mode.Matches(wxCVM((*ppXModes[i]))) ) //...?
257 {
258 Modes.Add(wxCVM((*ppXModes[i])));
259 }
260 wxClearXVM((*ppXModes[i]));
261 // XFree(ppXModes[i]); //supposed to free?
262 }
263 XFree(ppXModes);
264 }
265 else //OOPS!
266 {
267 wxLogSysError(_("Failed to enumerate video modes"));
268 }
269
270 return Modes;
271 }
272
273 wxVideoMode wxDisplayImplX11::GetCurrentMode() const
274 {
275 XF86VidModeModeLine VM;
276 int nDotClock;
277 XF86VidModeGetModeLine((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
278 &nDotClock, &VM);
279 wxClearXVM(VM);
280 return wxCVM2(VM, nDotClock);
281 }
282
283 bool wxDisplayImplX11::ChangeMode(const wxVideoMode& mode)
284 {
285 XF86VidModeModeInfo** ppXModes; //Enumerated Modes (Don't forget XFree() :))
286 int nNumModes; //Number of modes enumerated....
287
288 if( !XF86VidModeGetAllModeLines((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()), &nNumModes, &ppXModes) )
289 {
290 wxLogSysError(_("Failed to change video mode"));
291 return false;
292 }
293
294 bool bRet = false;
295 if (mode == wxDefaultVideoMode)
296 {
297 bRet = XF86VidModeSwitchToMode((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
298 ppXModes[0]) == TRUE;
299
300 for (int i = 0; i < nNumModes; ++i)
301 {
302 wxClearXVM((*ppXModes[i]));
303 // XFree(ppXModes[i]); //supposed to free?
304 }
305 }
306 else
307 {
308 for (int i = 0; i < nNumModes; ++i)
309 {
310 if (!bRet &&
311 ppXModes[i]->hdisplay == mode.GetWidth() &&
312 ppXModes[i]->vdisplay == mode.GetHeight() &&
313 wxCRR((*ppXModes[i])) == mode.GetRefresh())
314 {
315 //switch!
316 bRet = XF86VidModeSwitchToMode((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
317 ppXModes[i]) == TRUE;
318 }
319 wxClearXVM((*ppXModes[i]));
320 // XFree(ppXModes[i]); //supposed to free?
321 }
322 }
323
324 XFree(ppXModes);
325
326 return bRet;
327 }
328
329
330 #else // !HAVE_X11_EXTENSIONS_XF86VMODE_H
331
332 wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& modeMatch) const
333 {
334 int count_return;
335 int* depths = XListDepths((Display*)wxGetDisplay(), 0, &count_return);
336 wxArrayVideoModes modes;
337 if ( depths )
338 {
339 for ( int x = 0; x < count_return; ++x )
340 {
341 wxVideoMode mode(m_rect.GetWidth(), m_rect.GetHeight(), depths[x]);
342 if ( mode.Matches(modeMatch) )
343 {
344 modes.Add(modeMatch);
345 }
346 }
347
348 XFree(depths);
349 }
350 return modes;
351 }
352
353 wxVideoMode wxDisplayImplX11::GetCurrentMode() const
354 {
355 // Not implemented
356 return wxVideoMode();
357 }
358
359 bool wxDisplayImplX11::ChangeMode(const wxVideoMode& WXUNUSED(mode))
360 {
361 // Not implemented
362 return false;
363 }
364
365 #endif // !HAVE_X11_EXTENSIONS_XF86VMODE_H
366
367 // ============================================================================
368 // wxDisplay::CreateFactory()
369 // ============================================================================
370
371 /* static */ wxDisplayFactory *wxDisplay::CreateFactory()
372 {
373 // GTK+ screen functions are always available, no need to check for them
374 #ifndef __WXGTK20__
375 if ( !XineramaIsActive((Display*)wxGetDisplay()) )
376 return new wxDisplayFactorySingle;
377 #endif
378
379 return new wxDisplayFactoryX11;
380 }
381
382 #endif /* wxUSE_DISPLAY */
383
384 #include "wx/utils.h"
385
386 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2
387
388 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
389 {
390 // TODO: don't hardcode display size
391 if ( x )
392 *x = 0;
393 if ( y )
394 *y = 0;
395 if ( width )
396 *width = 672;
397 if ( height )
398 *height = 396;
399 }
400
401 #else // !wxUSE_LIBHILDON || !wxUSE_LIBHILDON2
402
403 #include "wx/log.h"
404
405 #include <X11/Xlib.h>
406 #include <X11/Xatom.h>
407
408 // TODO: make this a full-fledged class and move to a public header
409 class wxX11Ptr
410 {
411 public:
412 wxX11Ptr(void *ptr = NULL) : m_ptr(ptr) { }
413 ~wxX11Ptr() { if ( m_ptr ) XFree(m_ptr); }
414
415 private:
416 void *m_ptr;
417
418 wxDECLARE_NO_COPY_CLASS(wxX11Ptr);
419 };
420
421 // NB: this function is implemented using X11 and not GDK calls as it's shared
422 // by wxGTK[12], wxX11 and wxMotif ports
423 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
424 {
425 Display * const dpy = wxGetX11Display();
426 wxCHECK_RET( dpy, wxT("can't be called before initializing the GUI") );
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 return;
464 }
465
466 if ( x )
467 *x = workareas[0];
468 if ( y )
469 *y = workareas[1];
470 if ( width )
471 *width = workareas[2];
472 if ( height )
473 *height = workareas[3];
474
475 return;
476 }
477 }
478
479 // if we get here, _NET_WORKAREA is not supported so return the entire
480 // screen size as fall back
481 if (x)
482 *x = 0;
483 if (y)
484 *y = 0;
485 wxDisplaySize(width, height);
486 }
487
488 #endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON