1 ///////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/display.cpp
3 // Author: Paul Cornett
4 // Created: 2014-04-17
5 // Copyright: (c) 2014 Paul Cornett
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8
9 #include "wx/wxprec.h"
10
11 #include "wx/private/display.h"
12 #if wxUSE_DISPLAY
13 #include "wx/window.h"
14 #endif
15
16 #include "wx/gtk/private/wrapgtk.h"
17 #ifdef GDK_WINDOWING_X11
18 #ifndef __WXGTK4__
19 #include "wx/unix/private/displayx11.h"
20
21 #define wxGTK_HAVE_X11_DISPLAY
22 #endif
23
24 #include <gdk/gdkx.h>
25 #endif
26
27 // This file is not used at all when using Win32.
28 #if !defined(GDK_WINDOWING_WIN32)
29
30 GdkWindow* wxGetTopLevelGDK();
31
32 // There are 2 quite different implementations here: one for GTK+ 4 and the
33 // other one for the previous versions.
34
35 #ifdef __WXGTK4__
36
GetDisplay()37 static inline GdkDisplay* GetDisplay()
38 {
39 return gdk_window_get_display(wxGetTopLevelGDK());
40 }
41
42 // This class is always defined as it's used for the main display even when
43 // wxUSE_DISPLAY == 0.
44 class wxDisplayImplGTK : public wxDisplayImpl
45 {
46 typedef wxDisplayImpl base_type;
47 public:
48 wxDisplayImplGTK(unsigned i);
49 virtual wxRect GetGeometry() const wxOVERRIDE;
50 virtual wxRect GetClientArea() const wxOVERRIDE;
51 virtual int GetDepth() const wxOVERRIDE;
52 virtual double GetScaleFactor() const wxOVERRIDE;
53
54 #if wxUSE_DISPLAY
55 virtual bool IsPrimary() const wxOVERRIDE;
56 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const wxOVERRIDE;
57 virtual wxVideoMode GetCurrentMode() const wxOVERRIDE;
58 virtual bool ChangeMode(const wxVideoMode& mode) wxOVERRIDE;
59 #endif // wxUSE_DISPLAY
60
61 GdkMonitor* const m_monitor;
62 };
63
64 // This class is only defined when we're built with full display support.
65 #if wxUSE_DISPLAY
66 class wxDisplayFactoryGTK: public wxDisplayFactory
67 {
68 public:
69 virtual wxDisplayImpl* CreateDisplay(unsigned n) wxOVERRIDE;
70 virtual unsigned GetCount() wxOVERRIDE;
71 virtual int GetFromPoint(const wxPoint& pt) wxOVERRIDE;
72 virtual int GetFromWindow(const wxWindow* win) wxOVERRIDE;
73 };
74
CreateDisplay(unsigned n)75 wxDisplayImpl* wxDisplayFactoryGTK::CreateDisplay(unsigned n)
76 {
77 return new wxDisplayImplGTK(n);
78 }
79
GetCount()80 unsigned wxDisplayFactoryGTK::GetCount()
81 {
82 return gdk_display_get_n_monitors(::GetDisplay());
83 }
84
GetFromPoint(const wxPoint & pt)85 int wxDisplayFactoryGTK::GetFromPoint(const wxPoint& pt)
86 {
87 GdkRectangle rect;
88 GdkDisplay* display = ::GetDisplay();
89 GdkMonitor* monitor = gdk_display_get_monitor_at_point(display, pt.x, pt.y);
90 gdk_monitor_get_geometry(monitor, &rect);
91 if (wxRect(rect.x, rect.y, rect.width, rect.height).Contains(pt))
92 {
93 for (unsigned i = gdk_display_get_n_monitors(display); i--;)
94 {
95 if (gdk_display_get_monitor(display, i) == monitor)
96 return i;
97 }
98 }
99 return wxNOT_FOUND;
100 }
101
GetFromWindow(const wxWindow * win)102 int wxDisplayFactoryGTK::GetFromWindow(const wxWindow* win)
103 {
104 if (win && win->m_widget)
105 {
106 GdkDisplay* display = gtk_widget_get_display(win->m_widget);
107 GdkMonitor* monitor;
108 if (GdkWindow* window = gtk_widget_get_window(win->m_widget))
109 monitor = gdk_display_get_monitor_at_window(display, window);
110 else
111 monitor = gdk_display_get_primary_monitor(display);
112
113 for (unsigned i = gdk_display_get_n_monitors(display); i--;)
114 {
115 if (gdk_display_get_monitor(display, i) == monitor)
116 return i;
117 }
118 }
119 return wxNOT_FOUND;
120 }
121 #endif // wxUSE_DISPLAY
122
wxDisplayImplGTK(unsigned i)123 wxDisplayImplGTK::wxDisplayImplGTK(unsigned i)
124 : base_type(i)
125 , m_monitor(gdk_display_get_monitor(GetDisplay(), i))
126 {
127 }
128
GetGeometry() const129 wxRect wxDisplayImplGTK::GetGeometry() const
130 {
131 GdkRectangle rect;
132 gdk_monitor_get_geometry(m_monitor, &rect);
133 return wxRect(rect.x, rect.y, rect.width, rect.height);
134 }
135
GetClientArea() const136 wxRect wxDisplayImplGTK::GetClientArea() const
137 {
138 GdkRectangle rect;
139 gdk_monitor_get_workarea(m_monitor, &rect);
140 return wxRect(rect.x, rect.y, rect.width, rect.height);
141 }
142
GetDepth() const143 int wxDisplayImplGTK::GetDepth() const
144 {
145 return 24;
146 }
147
GetScaleFactor() const148 double wxDisplayImplGTK::GetScaleFactor() const
149 {
150 return gdk_monitor_get_scale_factor(m_monitor);
151 }
152
153 #if wxUSE_DISPLAY
IsPrimary() const154 bool wxDisplayImplGTK::IsPrimary() const
155 {
156 return gdk_monitor_is_primary(m_monitor) != 0;
157 }
158
159 wxArrayVideoModes
GetModes(const wxVideoMode & WXUNUSED (mode)) const160 wxDisplayImplGTK::GetModes(const wxVideoMode& WXUNUSED(mode)) const
161 {
162 return wxArrayVideoModes();
163 }
164
GetCurrentMode() const165 wxVideoMode wxDisplayImplGTK::GetCurrentMode() const
166 {
167 return wxVideoMode();
168 }
169
ChangeMode(const wxVideoMode & WXUNUSED (mode))170 bool wxDisplayImplGTK::ChangeMode(const wxVideoMode& WXUNUSED(mode))
171 {
172 return false;
173 }
174 #endif // wxUSE_DISPLAY
175
176 #else // !__WXGTK4__
177
178 #if defined(__WXGTK3__) && defined(GDK_WINDOWING_X11)
179
wxIsX11GDKScreen(GdkScreen * screen)180 static inline bool wxIsX11GDKScreen(GdkScreen* screen)
181 {
182 return strcmp("GdkX11Screen", g_type_name(G_TYPE_FROM_INSTANCE(screen))) == 0;
183 }
184
185 #else // !__WXGTK3__
186
wx_gdk_screen_get_primary_monitor(GdkScreen * screen)187 static inline int wx_gdk_screen_get_primary_monitor(GdkScreen* screen)
188 {
189 int monitor = 0;
190 #if GTK_CHECK_VERSION(2,20,0)
191 if (wx_is_at_least_gtk2(20))
192 monitor = gdk_screen_get_primary_monitor(screen);
193 #endif
194 return monitor;
195 }
196 #define gdk_screen_get_primary_monitor wx_gdk_screen_get_primary_monitor
197
wxIsX11GDKScreen(GdkScreen * WXUNUSED (screen))198 static inline bool wxIsX11GDKScreen(GdkScreen* WXUNUSED(screen))
199 {
200 return true;
201 }
202
203 #endif // __WXGTK3__/!__WXGTK3__
204
205 static inline void
wx_gdk_screen_get_monitor_workarea(GdkScreen * screen,int monitor,GdkRectangle * dest)206 wx_gdk_screen_get_monitor_workarea(GdkScreen* screen, int monitor, GdkRectangle* dest)
207 {
208 wxGCC_WARNING_SUPPRESS(deprecated-declarations)
209 #if GTK_CHECK_VERSION(3,4,0)
210 if (gtk_check_version(3,4,0) == NULL)
211 gdk_screen_get_monitor_workarea(screen, monitor, dest);
212 else
213 #endif
214 {
215 gdk_screen_get_monitor_geometry(screen, monitor, dest);
216 #ifdef wxGTK_HAVE_X11_DISPLAY
217 if ( wxIsX11GDKScreen(screen) )
218 {
219 GdkRectangle rect = { 0, 0, 0, 0 };
220 wxGetWorkAreaX11(GDK_SCREEN_XSCREEN(screen),
221 rect.x, rect.y, rect.width, rect.height);
222 // in case _NET_WORKAREA result is too large
223 if (rect.width && rect.height)
224 gdk_rectangle_intersect(dest, &rect, dest);
225 }
226 #endif // wxGTK_HAVE_X11_DISPLAY
227 }
228 wxGCC_WARNING_RESTORE()
229 }
230 #define gdk_screen_get_monitor_workarea wx_gdk_screen_get_monitor_workarea
231
GetScreen()232 static inline GdkScreen* GetScreen()
233 {
234 return gdk_window_get_screen(wxGetTopLevelGDK());
235 }
236
237 class wxDisplayImplGTK : public wxDisplayImpl
238 {
239 typedef wxDisplayImpl base_type;
240 public:
241 wxDisplayImplGTK(unsigned i);
242 virtual wxRect GetGeometry() const wxOVERRIDE;
243 virtual wxRect GetClientArea() const wxOVERRIDE;
244 virtual int GetDepth() const wxOVERRIDE;
245 #if GTK_CHECK_VERSION(3,10,0)
246 virtual double GetScaleFactor() const wxOVERRIDE;
247 #endif // GTK+ 3.10
248
249 #if wxUSE_DISPLAY
250 virtual bool IsPrimary() const wxOVERRIDE;
251 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const wxOVERRIDE;
252 virtual wxVideoMode GetCurrentMode() const wxOVERRIDE;
253 virtual bool ChangeMode(const wxVideoMode& mode) wxOVERRIDE;
254 #endif // wxUSE_DISPLAY
255
256 GdkScreen* const m_screen;
257 };
258
259 #if wxUSE_DISPLAY
260 class wxDisplayFactoryGTK: public wxDisplayFactory
261 {
262 public:
263 virtual wxDisplayImpl* CreateDisplay(unsigned n) wxOVERRIDE;
264 virtual unsigned GetCount() wxOVERRIDE;
265 virtual int GetFromPoint(const wxPoint& pt) wxOVERRIDE;
266 virtual int GetFromWindow(const wxWindow* win) wxOVERRIDE;
267 };
268
269 wxGCC_WARNING_SUPPRESS(deprecated-declarations)
270
CreateDisplay(unsigned n)271 wxDisplayImpl* wxDisplayFactoryGTK::CreateDisplay(unsigned n)
272 {
273 return new wxDisplayImplGTK(n);
274 }
275
GetCount()276 unsigned wxDisplayFactoryGTK::GetCount()
277 {
278 return gdk_screen_get_n_monitors(GetScreen());
279 }
280
GetFromPoint(const wxPoint & pt)281 int wxDisplayFactoryGTK::GetFromPoint(const wxPoint& pt)
282 {
283 GdkRectangle rect;
284 GdkScreen* screen = GetScreen();
285 int monitor = gdk_screen_get_monitor_at_point(screen, pt.x, pt.y);
286 gdk_screen_get_monitor_geometry(screen, monitor, &rect);
287 if (!wxRect(rect.x, rect.y, rect.width, rect.height).Contains(pt))
288 monitor = wxNOT_FOUND;
289 return monitor;
290 }
291
GetFromWindow(const wxWindow * win)292 int wxDisplayFactoryGTK::GetFromWindow(const wxWindow* win)
293 {
294 int monitor = wxNOT_FOUND;
295 if (win && win->m_widget)
296 {
297 GdkScreen* screen = gtk_widget_get_screen(win->m_widget);
298 if (GdkWindow* window = gtk_widget_get_window(win->m_widget))
299 monitor = gdk_screen_get_monitor_at_window(screen, window);
300 else
301 monitor = gdk_screen_get_primary_monitor(screen);
302 }
303 return monitor;
304 }
305 #endif // wxUSE_DISPLAY
306
wxDisplayImplGTK(unsigned i)307 wxDisplayImplGTK::wxDisplayImplGTK(unsigned i)
308 : base_type(i)
309 , m_screen(GetScreen())
310 {
311 }
312
GetGeometry() const313 wxRect wxDisplayImplGTK::GetGeometry() const
314 {
315 GdkRectangle rect;
316 gdk_screen_get_monitor_geometry(m_screen, m_index, &rect);
317 return wxRect(rect.x, rect.y, rect.width, rect.height);
318 }
319
GetClientArea() const320 wxRect wxDisplayImplGTK::GetClientArea() const
321 {
322 GdkRectangle rect;
323 gdk_screen_get_monitor_workarea(m_screen, m_index, &rect);
324 return wxRect(rect.x, rect.y, rect.width, rect.height);
325 }
326
GetDepth() const327 int wxDisplayImplGTK::GetDepth() const
328 {
329 // TODO: How to get the depth of the specific display?
330 return gdk_visual_get_depth(gdk_window_get_visual(wxGetTopLevelGDK()));
331 }
332
333 #if GTK_CHECK_VERSION(3,10,0)
GetScaleFactor() const334 double wxDisplayImplGTK::GetScaleFactor() const
335 {
336 if ( gtk_check_version(3,10,0) == NULL )
337 return gdk_screen_get_monitor_scale_factor(m_screen, m_index);
338
339 return 1.0;
340 }
341 #endif // GTK+ 3.10
342
343 #if wxUSE_DISPLAY
IsPrimary() const344 bool wxDisplayImplGTK::IsPrimary() const
345 {
346 return gdk_screen_get_primary_monitor(m_screen) == int(m_index);
347 }
348
GetModes(const wxVideoMode & mode) const349 wxArrayVideoModes wxDisplayImplGTK::GetModes(const wxVideoMode& mode) const
350 {
351 wxArrayVideoModes modes;
352 #ifdef wxGTK_HAVE_X11_DISPLAY
353 if ( wxIsX11GDKScreen(m_screen) )
354 {
355 Display* display = GDK_DISPLAY_XDISPLAY(gdk_screen_get_display(m_screen));
356 #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
357 int nScreen = gdk_x11_screen_get_screen_number(m_screen);
358 modes = wxXF86VidMode_GetModes(mode, display, nScreen);
359 #else
360 modes = wxX11_GetModes(this, mode, display);
361 #endif
362 }
363 #else
364 wxUnusedVar(mode);
365 #endif
366 return modes;
367 }
368
GetCurrentMode() const369 wxVideoMode wxDisplayImplGTK::GetCurrentMode() const
370 {
371 wxVideoMode mode;
372 #if defined(wxGTK_HAVE_X11_DISPLAY) && defined(HAVE_X11_EXTENSIONS_XF86VMODE_H)
373 if ( wxIsX11GDKScreen(m_screen) )
374 {
375 Display* display = GDK_DISPLAY_XDISPLAY(gdk_screen_get_display(m_screen));
376 int nScreen = gdk_x11_screen_get_screen_number(m_screen);
377 mode = wxXF86VidMode_GetCurrentMode(display, nScreen);
378 }
379 #endif
380 return mode;
381 }
382
ChangeMode(const wxVideoMode & mode)383 bool wxDisplayImplGTK::ChangeMode(const wxVideoMode& mode)
384 {
385 bool success = false;
386 #if defined(wxGTK_HAVE_X11_DISPLAY) && defined(HAVE_X11_EXTENSIONS_XF86VMODE_H)
387 if ( wxIsX11GDKScreen(m_screen) )
388 {
389 Display* display = GDK_DISPLAY_XDISPLAY(gdk_screen_get_display(m_screen));
390 int nScreen = gdk_x11_screen_get_screen_number(m_screen);
391 success = wxXF86VidMode_ChangeMode(mode, display, nScreen);
392 }
393 #else
394 wxUnusedVar(mode);
395 #endif
396 return success;
397 }
398
wxGCC_WARNING_RESTORE()399 wxGCC_WARNING_RESTORE()
400
401 #endif // wxUSE_DISPLAY
402
403 #endif // __WXGTK4__/!__WXGTK4__
404
405 #if wxUSE_DISPLAY
406
407 wxDisplayFactory* wxDisplay::CreateFactory()
408 {
409 return new wxDisplayFactoryGTK;
410 }
411
412 #else // !wxUSE_DISPLAY
413
414 class wxDisplayFactorySingleGTK : public wxDisplayFactorySingle
415 {
416 protected:
417 virtual wxDisplayImpl *CreateSingleDisplay()
418 {
419 return new wxDisplayImplGTK(0);
420 }
421 };
422
423 wxDisplayFactory* wxDisplay::CreateFactory()
424 {
425 return new wxDisplayFactorySingleGTK;
426 }
427
428 #endif // wxUSE_DISPLAY/!wxUSE_DISPLAY
429
430 #endif // !defined(GDK_WINDOWING_WIN32)
431