Blender  V2.93
GHOST_WindowWayland.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include "GHOST_WindowWayland.h"
22 #include "GHOST_SystemWayland.h"
23 #include "GHOST_WindowManager.h"
24 
25 #include "GHOST_Event.h"
26 
27 #include "GHOST_ContextEGL.h"
28 #include "GHOST_ContextNone.h"
29 
30 #include <wayland-egl.h>
31 
32 struct window_t {
34  wl_surface *surface;
37  wl_egl_window *egl_window;
41  bool is_active;
42  bool is_dialog;
44 };
45 
46 /* -------------------------------------------------------------------- */
53 static void toplevel_configure(
54  void *data, xdg_toplevel * /*xdg_toplevel*/, int32_t width, int32_t height, wl_array *states)
55 {
56  window_t *win = static_cast<window_t *>(data);
57  win->pending_width = width;
58  win->pending_height = height;
59 
60  win->is_maximised = false;
61  win->is_fullscreen = false;
62  win->is_active = false;
63 
64  /* Note that the macro 'wl_array_for_each' would typically be used to simplify this logic,
65  * however it's not compatible with C++, so perform casts instead.
66  * If this needs to be done more often we could define our own C++ compatible macro. */
67  for (enum xdg_toplevel_state *state = static_cast<xdg_toplevel_state *>(states->data);
68  reinterpret_cast<uint8_t *>(state) < (static_cast<uint8_t *>(states->data) + states->size);
69  state++) {
70  switch (*state) {
71  case XDG_TOPLEVEL_STATE_MAXIMIZED:
72  win->is_maximised = true;
73  break;
74  case XDG_TOPLEVEL_STATE_FULLSCREEN:
75  win->is_fullscreen = true;
76  break;
77  case XDG_TOPLEVEL_STATE_ACTIVATED:
78  win->is_active = true;
79  break;
80  default:
81  break;
82  }
83  }
84 }
85 
86 static void toplevel_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
87 {
88  static_cast<window_t *>(data)->w->close();
89 }
90 
91 static const xdg_toplevel_listener toplevel_listener = {
94 };
95 
96 static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
97 {
98  window_t *win = static_cast<window_t *>(data);
99 
100  int w, h;
101  wl_egl_window_get_attached_size(win->egl_window, &w, &h);
102  if (win->pending_width != 0 && win->pending_height != 0 && win->pending_width != w &&
103  win->pending_height != h) {
104  win->width = win->pending_width;
105  win->height = win->pending_height;
106  wl_egl_window_resize(win->egl_window, win->pending_width, win->pending_height, 0, 0);
107  win->pending_width = 0;
108  win->pending_height = 0;
109  win->w->notify_size();
110  }
111 
112  if (win->is_active) {
113  win->w->activate();
114  }
115  else {
116  win->w->deactivate();
117  }
118 
119  xdg_surface_ack_configure(xdg_surface, serial);
120 }
121 
122 static const xdg_surface_listener surface_listener = {
124 };
125 
128 /* -------------------------------------------------------------------- */
135 {
136  return m_system->hasCursorShape(cursorShape);
137 }
138 
140  const char *title,
141  GHOST_TInt32 /*left*/,
142  GHOST_TInt32 /*top*/,
146  const GHOST_IWindow *parentWindow,
148  const bool is_dialog,
149  const bool stereoVisual,
150  const bool exclusive)
151  : GHOST_Window(width, height, state, stereoVisual, exclusive),
152  m_system(system),
153  w(new window_t)
154 {
155  w->w = this;
156 
157  w->width = int32_t(width);
158  w->height = int32_t(height);
159 
160  w->is_dialog = is_dialog;
161 
162  /* Window surfaces. */
163  w->surface = wl_compositor_create_surface(m_system->compositor());
164  w->egl_window = wl_egl_window_create(w->surface, int(width), int(height));
165 
166  w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface);
167  w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
168 
169  wl_surface_set_user_data(w->surface, this);
170 
171  xdg_surface_add_listener(w->xdg_surface, &surface_listener, w);
172  xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
173 
174  if (parentWindow) {
175  xdg_toplevel_set_parent(
176  w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
177  }
178 
179  /* Call top-level callbacks. */
180  wl_surface_commit(w->surface);
181  wl_display_roundtrip(m_system->display());
182 
183 #ifdef GHOST_OPENGL_ALPHA
184  setOpaque();
185 #endif
186 
187  setState(state);
188 
189  setTitle(title);
190 
191  /* EGL context. */
193  GHOST_PRINT("Failed to create EGL context" << std::endl);
194  }
195 }
196 
198 {
199  return m_system->pushEvent(
200  new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
201 }
202 
204 {
205  if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
206  return GHOST_kFailure;
207  }
208  return m_system->pushEvent(
209  new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
210 }
211 
213 {
214  m_system->getWindowManager()->setWindowInactive(this);
215  return m_system->pushEvent(
217 }
218 
220 {
221 #ifdef GHOST_OPENGL_ALPHA
222  setOpaque();
223 #endif
224 
225  return m_system->pushEvent(
226  new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
227 }
228 
230 {
231  return m_system->setCursorGrab(mode, w->surface);
232 }
233 
235 {
236  const GHOST_TSuccess ok = m_system->setCursorShape(shape);
238  return ok;
239 }
240 
242  GHOST_TUns8 *mask,
243  int sizex,
244  int sizey,
245  int hotX,
246  int hotY,
247  bool canInvertColor)
248 {
249  return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
250 }
251 
252 void GHOST_WindowWayland::setTitle(const char *title)
253 {
254  xdg_toplevel_set_title(w->xdg_toplevel, title);
255  xdg_toplevel_set_app_id(w->xdg_toplevel, title);
256  this->title = title;
257 }
258 
259 std::string GHOST_WindowWayland::getTitle() const
260 {
261  return this->title.empty() ? "untitled" : this->title;
262 }
263 
265 {
267 }
268 
270 {
271  bounds.set(0, 0, w->width, w->height);
272 }
273 
275 {
276  return setClientSize(width, GHOST_TUns32(w->height));
277 }
278 
280 {
281  return setClientSize(GHOST_TUns32(w->width), height);
282 }
283 
285 {
286  wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
287  return GHOST_kSuccess;
288 }
289 
291  GHOST_TInt32 inY,
292  GHOST_TInt32 &outX,
293  GHOST_TInt32 &outY) const
294 {
295  outX = inX;
296  outY = inY;
297 }
298 
300  GHOST_TInt32 inY,
301  GHOST_TInt32 &outX,
302  GHOST_TInt32 &outY) const
303 {
304  outX = inX;
305  outY = inY;
306 }
307 
309 {
311 
312  wl_egl_window_destroy(w->egl_window);
313  xdg_toplevel_destroy(w->xdg_toplevel);
314  xdg_surface_destroy(w->xdg_surface);
315  wl_surface_destroy(w->surface);
316 
317  delete w;
318 }
319 
321 {
322  return m_system->setCursorVisibility(visible);
323 }
324 
326 {
327  switch (state) {
329  /* Unset states. */
330  switch (getState()) {
332  xdg_toplevel_unset_maximized(w->xdg_toplevel);
333  break;
335  xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
336  break;
337  default:
338  break;
339  }
340  break;
342  xdg_toplevel_set_maximized(w->xdg_toplevel);
343  break;
345  xdg_toplevel_set_minimized(w->xdg_toplevel);
346  break;
348  xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
349  break;
351  return GHOST_kFailure;
352  }
353  return GHOST_kSuccess;
354 }
355 
357 {
358  if (w->is_fullscreen) {
360  }
361  else if (w->is_maximised) {
363  }
364  else {
366  }
367 }
368 
370 {
371  return GHOST_kSuccess;
372 }
373 
375 {
376  return GHOST_kSuccess;
377 }
378 
380 {
381  xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
382  return GHOST_kSuccess;
383 }
384 
386 {
387  xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
388  return GHOST_kSuccess;
389 }
390 
392 {
393  return w->is_dialog;
394 }
395 
396 #ifdef GHOST_OPENGL_ALPHA
397 void GHOST_WindowWayland::setOpaque() const
398 {
399  struct wl_region *region;
400 
401  /* Make the window opaque. */
402  region = wl_compositor_create_region(m_system->compositor());
403  wl_region_add(region, 0, 0, w->width, w->height);
404  wl_surface_set_opaque_region(w->surface, region);
405  wl_region_destroy(region);
406 }
407 #endif
408 
413 GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType type)
414 {
416  switch (type) {
419  break;
422  EGLNativeWindowType(w->egl_window),
423  EGLNativeDisplayType(m_system->display()),
424  EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
425  3,
426  3,
429  EGL_OPENGL_API);
430  break;
431  }
432 
433  return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr;
434 }
435 
KDTree *BLI_kdtree_nd_() new(unsigned int maxsize)
Definition: kdtree_impl.h:99
#define GHOST_OPENGL_EGL_CONTEXT_FLAGS
#define GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY
#define GHOST_PRINT(x)
Definition: GHOST_Debug.h:51
GHOST_TWindowState
Definition: GHOST_Types.h:144
@ GHOST_kWindowStateMinimized
Definition: GHOST_Types.h:147
@ GHOST_kWindowStateMaximized
Definition: GHOST_Types.h:146
@ GHOST_kWindowStateEmbedded
Definition: GHOST_Types.h:149
@ GHOST_kWindowStateNormal
Definition: GHOST_Types.h:145
@ GHOST_kWindowStateFullScreen
Definition: GHOST_Types.h:148
GHOST_TStandardCursor
Definition: GHOST_Types.h:222
@ GHOST_kStandardCursorDefault
Definition: GHOST_Types.h:224
unsigned int GHOST_TUns32
Definition: GHOST_Types.h:64
@ GHOST_kEventWindowClose
Definition: GHOST_Types.h:197
@ GHOST_kEventWindowSize
Definition: GHOST_Types.h:201
@ GHOST_kEventWindowActivate
Definition: GHOST_Types.h:198
@ GHOST_kEventWindowDeactivate
Definition: GHOST_Types.h:199
int GHOST_TInt32
Definition: GHOST_Types.h:63
GHOST_TDrawingContextType
Definition: GHOST_Types.h:156
@ GHOST_kDrawingContextTypeOpenGL
Definition: GHOST_Types.h:158
@ GHOST_kDrawingContextTypeNone
Definition: GHOST_Types.h:157
GHOST_TWindowOrder
Definition: GHOST_Types.h:154
GHOST_TSuccess
Definition: GHOST_Types.h:91
@ GHOST_kFailure
Definition: GHOST_Types.h:91
@ GHOST_kSuccess
Definition: GHOST_Types.h:91
GHOST_TGrabCursorMode
Definition: GHOST_Types.h:412
unsigned char GHOST_TUns8
Definition: GHOST_Types.h:60
static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
static const xdg_surface_listener surface_listener
static void toplevel_close(void *data, xdg_toplevel *)
static const xdg_toplevel_listener toplevel_listener
static void toplevel_configure(void *data, xdg_toplevel *, int32_t width, int32_t height, wl_array *states)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode, wl_surface *surface)
wl_compositor * compositor()
GHOST_TSuccess setCursorVisibility(bool visible)
GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape)
GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape)
GHOST_WindowManager * getWindowManager() const
Definition: GHOST_System.h:417
GHOST_TSuccess pushEvent(GHOST_IEvent *event)
virtual GHOST_TUns64 getMilliSeconds() const
GHOST_TSuccess setActiveWindow(GHOST_IWindow *window)
void setWindowInactive(const GHOST_IWindow *window)
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) override
GHOST_WindowWayland(GHOST_SystemWayland *system, const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, const GHOST_IWindow *parentWindow, GHOST_TDrawingContextType type, const bool is_dialog, const bool stereoVisual, const bool exclusive)
void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32 &outX, GHOST_TInt32 &outY) const override
GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override
GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) override
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override
GHOST_TSuccess setClientHeight(GHOST_TUns32 height) override
GHOST_TSuccess notify_size()
GHOST_TSuccess setState(GHOST_TWindowState state) override
GHOST_TSuccess setWindowCursorVisibility(bool visible) override
GHOST_TSuccess setClientWidth(GHOST_TUns32 width) override
GHOST_TWindowState getState() const override
GHOST_TSuccess beginFullScreen() const override
bool isDialog() const override
std::string getTitle() const override
GHOST_TSuccess deactivate()
void getClientBounds(GHOST_Rect &bounds) const override
GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor) override
GHOST_TSuccess endFullScreen() const override
void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32 &outX, GHOST_TInt32 &outY) const override
GHOST_TSuccess invalidate() override
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override
void setTitle(const char *title) override
void getWindowBounds(GHOST_Rect &bounds) const override
bool m_wantStereoVisual
Definition: GHOST_Window.h:396
GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type)
GHOST_TStandardCursor m_cursorShape
Definition: GHOST_Window.h:381
GHOST_TSuccess releaseNativeHandles()
static ulong state[N]
struct SELECTID_Context context
Definition: select_engine.c:47
unsigned int uint32_t
Definition: stdint.h:83
signed int int32_t
Definition: stdint.h:80
unsigned char uint8_t
Definition: stdint.h:81
wl_egl_window * egl_window
struct xdg_toplevel * xdg_toplevel
wl_surface * surface
int32_t pending_width
struct xdg_surface * xdg_surface
GHOST_WindowWayland * w
int32_t pending_height
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)