Blender  V3.3
GHOST_WindowWayland.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "GHOST_WindowWayland.h"
8 #include "GHOST_SystemWayland.h"
9 #include "GHOST_WaylandUtils.h"
10 #include "GHOST_WindowManager.h"
11 #include "GHOST_utildefines.h"
12 
13 #include "GHOST_Event.h"
14 
15 #include "GHOST_ContextEGL.h"
16 #include "GHOST_ContextNone.h"
17 
18 #include <wayland-client-protocol.h>
19 
20 #ifdef WITH_GHOST_WAYLAND_DYNLOAD
21 # include <wayland_dynload_egl.h>
22 #endif
23 #include <wayland-egl.h>
24 
25 #include <algorithm> /* For `std::find`. */
26 
27 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
28 # ifdef WITH_GHOST_WAYLAND_DYNLOAD
30 # endif
31 # include <libdecor.h>
32 #endif
33 
34 /* Logging, use `ghost.wl.*` prefix. */
35 #include "CLG_log.h"
36 
37 static constexpr size_t base_dpi = 96;
38 
40 
41 struct window_t {
42  GHOST_WindowWayland *w = nullptr;
43  struct wl_surface *wl_surface = nullptr;
50  std::vector<output_t *> outputs;
51 
53  int scale = 0;
61 
62 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
63  struct libdecor_frame *decor_frame = nullptr;
64  bool decor_configured = false;
65 #else
66  struct xdg_surface *xdg_surface = nullptr;
67  struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr;
68  struct xdg_toplevel *xdg_toplevel = nullptr;
69 
70  enum zxdg_toplevel_decoration_v1_mode decoration_mode = (enum zxdg_toplevel_decoration_v1_mode)0;
71 #endif
72 
73  wl_egl_window *egl_window = nullptr;
74  bool is_maximised = false;
75  bool is_fullscreen = false;
76  bool is_active = false;
77  bool is_dialog = false;
78 
79  int32_t size[2] = {0, 0};
80  int32_t size_pending[2] = {0, 0};
81 };
82 
83 /* -------------------------------------------------------------------- */
90 static int output_scale_cmp(const output_t *output_a, const output_t *output_b)
91 {
92  if (output_a->scale < output_b->scale) {
93  return -1;
94  }
95  if (output_a->scale > output_b->scale) {
96  return 1;
97  }
98  if (output_a->has_scale_fractional || output_b->has_scale_fractional) {
99  const wl_fixed_t scale_fractional_a = output_a->has_scale_fractional ?
100  output_a->scale_fractional :
101  wl_fixed_from_int(output_a->scale);
102  const wl_fixed_t scale_fractional_b = output_b->has_scale_fractional ?
103  output_b->scale_fractional :
104  wl_fixed_from_int(output_b->scale);
105  if (scale_fractional_a < scale_fractional_b) {
106  return -1;
107  }
108  if (scale_fractional_a > scale_fractional_b) {
109  return 1;
110  }
111  }
112  return 0;
113 }
114 
115 static int outputs_max_scale_or_default(const std::vector<output_t *> &outputs,
116  const int32_t scale_default,
117  uint32_t *r_dpi)
118 {
119  const output_t *output_max = nullptr;
120  for (const output_t *reg_output : outputs) {
121  if (!output_max || (output_scale_cmp(output_max, reg_output) == -1)) {
122  output_max = reg_output;
123  }
124  }
125 
126  if (output_max) {
127  if (r_dpi) {
128  *r_dpi = output_max->has_scale_fractional ?
129  /* Fractional DPI. */
130  wl_fixed_to_int(output_max->scale_fractional * base_dpi) :
131  /* Simple non-fractional DPI. */
132  (output_max->scale * base_dpi);
133  }
134  return output_max->scale;
135  }
136 
137  if (r_dpi) {
138  *r_dpi = scale_default * base_dpi;
139  }
140  return scale_default;
141 }
142 
145 /* -------------------------------------------------------------------- */
149 #ifndef WITH_GHOST_WAYLAND_LIBDECOR
150 
151 static CLG_LogRef LOG_WL_XDG_TOPLEVEL = {"ghost.wl.handle.xdg_toplevel"};
152 # define LOG (&LOG_WL_XDG_TOPLEVEL)
153 
155  xdg_toplevel * /*xdg_toplevel*/,
156  const int32_t width,
157  const int32_t height,
158  wl_array *states)
159 {
160  /* TODO: log `states`, not urgent. */
161  CLOG_INFO(LOG, 2, "configure (size=[%d, %d])", width, height);
162 
163  window_t *win = static_cast<window_t *>(data);
164  win->size_pending[0] = win->scale * width;
165  win->size_pending[1] = win->scale * height;
166 
167  win->is_maximised = false;
168  win->is_fullscreen = false;
169  win->is_active = false;
170 
171  enum xdg_toplevel_state *state;
172  WL_ARRAY_FOR_EACH (state, states) {
173  switch (*state) {
174  case XDG_TOPLEVEL_STATE_MAXIMIZED:
175  win->is_maximised = true;
176  break;
177  case XDG_TOPLEVEL_STATE_FULLSCREEN:
178  win->is_fullscreen = true;
179  break;
180  case XDG_TOPLEVEL_STATE_ACTIVATED:
181  win->is_active = true;
182  break;
183  default:
184  break;
185  }
186  }
187 }
188 
189 static void xdg_toplevel_handle_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
190 {
191  CLOG_INFO(LOG, 2, "close");
192  static_cast<window_t *>(data)->w->close();
193 }
194 
195 static const xdg_toplevel_listener toplevel_listener = {
198 };
199 
200 # undef LOG
201 
202 #endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
203 
206 /* -------------------------------------------------------------------- */
210 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
211 
212 static CLG_LogRef LOG_WL_LIBDECOR_FRAME = {"ghost.wl.handle.libdecor_frame"};
213 # define LOG (&LOG_WL_LIBDECOR_FRAME)
214 
215 static void frame_handle_configure(struct libdecor_frame *frame,
216  struct libdecor_configuration *configuration,
217  void *data)
218 {
219  CLOG_INFO(LOG, 2, "configure");
220 
221  window_t *win = static_cast<window_t *>(data);
222 
223  int size_next[2];
224  enum libdecor_window_state window_state;
225  struct libdecor_state *state;
226 
228  configuration, frame, &size_next[0], &size_next[1])) {
229  size_next[0] = win->size[0] / win->scale;
230  size_next[1] = win->size[1] / win->scale;
231  }
232 
233  win->size[0] = win->scale * size_next[0];
234  win->size[1] = win->scale * size_next[1];
235 
236  wl_egl_window_resize(win->egl_window, UNPACK2(win->size), 0, 0);
237  win->w->notify_size();
238 
239  if (!libdecor_configuration_get_window_state(configuration, &window_state)) {
240  window_state = LIBDECOR_WINDOW_STATE_NONE;
241  }
242 
243  win->is_maximised = window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED;
244  win->is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
245  win->is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
246 
247  win->is_active ? win->w->activate() : win->w->deactivate();
248 
249  state = libdecor_state_new(UNPACK2(size_next));
250  libdecor_frame_commit(frame, state, configuration);
252 
253  win->decor_configured = true;
254 }
255 
256 static void frame_handle_close(struct libdecor_frame * /*frame*/, void *data)
257 {
258  CLOG_INFO(LOG, 2, "close");
259 
260  static_cast<window_t *>(data)->w->close();
261 }
262 
263 static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data)
264 {
265  CLOG_INFO(LOG, 2, "commit");
266 
267  /* We have to swap twice to keep any pop-up menus alive. */
268  static_cast<window_t *>(data)->w->swapBuffers();
269  static_cast<window_t *>(data)->w->swapBuffers();
270 }
271 
272 static struct libdecor_frame_interface libdecor_frame_iface = {
273  frame_handle_configure,
274  frame_handle_close,
275  frame_handle_commit,
276 };
277 
278 # undef LOG
279 
280 #endif /* WITH_GHOST_WAYLAND_LIBDECOR. */
281 
284 /* -------------------------------------------------------------------- */
288 #ifndef WITH_GHOST_WAYLAND_LIBDECOR
289 
290 static CLG_LogRef LOG_WL_XDG_TOPLEVEL_DECORATION = {"ghost.wl.handle.xdg_toplevel_decoration"};
291 # define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION)
292 
294  void *data,
295  struct zxdg_toplevel_decoration_v1 * /*zxdg_toplevel_decoration_v1*/,
296  const uint32_t mode)
297 {
298  CLOG_INFO(LOG, 2, "configure (mode=%u)", mode);
299  static_cast<window_t *>(data)->decoration_mode = (zxdg_toplevel_decoration_v1_mode)mode;
300 }
301 
302 static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = {
304 };
305 
306 # undef LOG
307 
308 #endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
309 
312 /* -------------------------------------------------------------------- */
316 #ifndef WITH_GHOST_WAYLAND_LIBDECOR
317 
318 static CLG_LogRef LOG_WL_XDG_SURFACE = {"ghost.wl.handle.xdg_surface"};
319 # define LOG (&LOG_WL_XDG_SURFACE)
320 
322  xdg_surface *xdg_surface,
323  const uint32_t serial)
324 {
325  window_t *win = static_cast<window_t *>(data);
326 
327  if (win->xdg_surface != xdg_surface) {
328  CLOG_INFO(LOG, 2, "configure (skipped)");
329  return;
330  }
331  const bool do_resize = win->size_pending[0] != 0 && win->size_pending[1] != 0;
332  CLOG_INFO(LOG, 2, "configure (do_resize=%d)", do_resize);
333 
334  if (do_resize) {
335  win->size[0] = win->size_pending[0];
336  win->size[1] = win->size_pending[1];
337  wl_egl_window_resize(win->egl_window, UNPACK2(win->size), 0, 0);
338  win->size_pending[0] = 0;
339  win->size_pending[1] = 0;
340  win->w->notify_size();
341  }
342 
343  if (win->is_active) {
344  win->w->activate();
345  }
346  else {
347  win->w->deactivate();
348  }
349 
350  xdg_surface_ack_configure(xdg_surface, serial);
351 }
352 
355 };
356 
357 # undef LOG
358 
359 #endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
360 
363 /* -------------------------------------------------------------------- */
367 static CLG_LogRef LOG_WL_SURFACE = {"ghost.wl.handle.surface"};
368 #define LOG (&LOG_WL_SURFACE)
369 
370 static void surface_handle_enter(void *data,
371  struct wl_surface * /*wl_surface*/,
372  struct wl_output *output)
373 {
374  if (!ghost_wl_output_own(output)) {
375  CLOG_INFO(LOG, 2, "enter (skipped)");
376  return;
377  }
378  CLOG_INFO(LOG, 2, "enter");
379 
381  GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(data);
382  if (win->outputs_enter(reg_output)) {
384  }
385 }
386 
387 static void surface_handle_leave(void *data,
388  struct wl_surface * /*wl_surface*/,
389  struct wl_output *output)
390 {
391  if (!ghost_wl_output_own(output)) {
392  CLOG_INFO(LOG, 2, "leave (skipped)");
393  return;
394  }
395  CLOG_INFO(LOG, 2, "leave");
396 
398  GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(data);
399  if (win->outputs_leave(reg_output)) {
401  }
402 }
403 
407 };
408 
409 #undef LOG
410 
413 /* -------------------------------------------------------------------- */
420 {
421  return m_system->hasCursorShape(cursorShape);
422 }
423 
425  const char *title,
426  const int32_t /*left*/,
427  const int32_t /*top*/,
428  const uint32_t width,
429  const uint32_t height,
431  const GHOST_IWindow *parentWindow,
433  const bool is_dialog,
434  const bool stereoVisual,
435  const bool exclusive)
436  : GHOST_Window(width, height, state, stereoVisual, exclusive),
437  m_system(system),
438  w(new window_t)
439 {
440  /* Globally store pointer to window manager. */
441  if (!window_manager) {
442  window_manager = m_system->getWindowManager();
443  }
444 
445  w->w = this;
446 
447  w->size[0] = int32_t(width);
448  w->size[1] = int32_t(height);
449 
450  w->is_dialog = is_dialog;
451 
452  /* NOTE(@campbellbarton): The scale set here to avoid flickering on startup.
453  * When all monitors use the same scale (which is quite common) there aren't any problems.
454  *
455  * When monitors have different scales there may still be a visible window resize on startup.
456  * Ideally it would be possible to know the scale this window will use however that's only
457  * known once #surface_enter callback runs (which isn't guaranteed to run at all).
458  *
459  * Using the maximum scale is best as it results in the window first being smaller,
460  * avoiding a large window flashing before it's made smaller. */
461  w->scale = outputs_max_scale_or_default(this->m_system->outputs(), 1, &w->dpi);
462 
463  /* Window surfaces. */
464  w->wl_surface = wl_compositor_create_surface(m_system->compositor());
465  ghost_wl_surface_tag(w->wl_surface);
466 
467  wl_surface_set_buffer_scale(w->wl_surface, w->scale);
468 
469  wl_surface_add_listener(w->wl_surface, &wl_surface_listener, this);
470 
471  w->egl_window = wl_egl_window_create(w->wl_surface, int(w->size[0]), int(w->size[1]));
472 
473  /* NOTE: The limit is in points (not pixels) so Hi-DPI will limit to larger number of pixels.
474  * This has the advantage that the size limit is the same when moving the window between monitors
475  * with different scales set. If it was important to limit in pixels it could be re-calculated
476  * when the `w->scale` changed. */
477  const int32_t size_min[2] = {320, 240};
478 
479 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
480  /* create window decorations */
481  w->decor_frame = libdecor_decorate(
482  m_system->decor_context(), w->wl_surface, &libdecor_frame_iface, w);
483  libdecor_frame_map(w->decor_frame);
484 
485  libdecor_frame_set_min_content_size(w->decor_frame, UNPACK2(size_min));
486 
487  if (parentWindow) {
489  w->decor_frame, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->decor_frame);
490  }
491 #else
492  w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->xdg_shell(), w->wl_surface);
493  w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
494 
495  xdg_toplevel_set_min_size(w->xdg_toplevel, UNPACK2(size_min));
496 
497  if (m_system->xdg_decoration_manager()) {
498  w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
499  m_system->xdg_decoration_manager(), w->xdg_toplevel);
500  zxdg_toplevel_decoration_v1_add_listener(
501  w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w);
502  zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration,
503  ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
504  }
505 
506  xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
507  xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
508 
509  if (parentWindow && is_dialog) {
510  xdg_toplevel_set_parent(
511  w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
512  }
513 
514 #endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
515 
516  setTitle(title);
517 
518  wl_surface_set_user_data(w->wl_surface, this);
519 
520  /* Call top-level callbacks. */
521  wl_surface_commit(w->wl_surface);
522  wl_display_roundtrip(m_system->display());
523 
524 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
525  /* It's important not to return until the window is configured or
526  * calls to `setState` from Blender will crash `libdecor`. */
527  while (!w->decor_configured) {
528  if (libdecor_dispatch(m_system->decor_context(), 0) < 0) {
529  break;
530  }
531  }
532 #endif
533 
534 #ifdef GHOST_OPENGL_ALPHA
535  setOpaque();
536 #endif
537 
538 #ifndef WITH_GHOST_WAYLAND_LIBDECOR /* Causes a glitch with `libdecor` for some reason. */
539  setState(state);
540 #endif
541 
542  /* EGL context. */
544  GHOST_PRINT("Failed to create EGL context" << std::endl);
545  }
546 
547  /* Set swap interval to 0 to prevent blocking. */
548  setSwapInterval(0);
549 }
550 
552 {
553  GHOST_Rect bounds_buf;
554  GHOST_Rect *bounds = nullptr;
555  if (m_cursorGrab == GHOST_kGrabWrap) {
556  if (getCursorGrabBounds(bounds_buf) == GHOST_kFailure) {
557  getClientBounds(bounds_buf);
558  }
559  bounds = &bounds_buf;
560  }
561  if (m_system->window_cursor_grab_set(mode,
562  m_cursorGrab,
564  bounds,
566  w->wl_surface,
567  w->scale)) {
568  return GHOST_kSuccess;
569  }
570  return GHOST_kFailure;
571 }
572 
574 {
575  const GHOST_TSuccess ok = m_system->setCursorShape(shape);
577  return ok;
578 }
579 
581 {
583 }
584 
586  uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
587 {
588  return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
589 }
590 
592 {
593  return m_system->getCursorBitmap(bitmap);
594 }
595 
596 void GHOST_WindowWayland::setTitle(const char *title)
597 {
598 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
599  libdecor_frame_set_app_id(w->decor_frame, title);
600  libdecor_frame_set_title(w->decor_frame, title);
601 #else
602  xdg_toplevel_set_title(w->xdg_toplevel, title);
603  xdg_toplevel_set_app_id(w->xdg_toplevel, title);
604 #endif
605 
606  this->title = title;
607 }
608 
609 std::string GHOST_WindowWayland::getTitle() const
610 {
611  return this->title.empty() ? "untitled" : this->title;
612 }
613 
615 {
617 }
618 
620 {
621  bounds.set(0, 0, UNPACK2(w->size));
622 }
623 
625 {
626  return setClientSize(width, uint32_t(w->size[1]));
627 }
628 
630 {
631  return setClientSize(uint32_t(w->size[0]), height);
632 }
633 
635 {
636  wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
637 
638  /* Override any pending size that may be set. */
639  w->size_pending[0] = 0;
640  w->size_pending[1] = 0;
641 
642  w->size[0] = width;
643  w->size[1] = height;
644 
645  notify_size();
646 
647  return GHOST_kSuccess;
648 }
649 
651  int32_t inY,
652  int32_t &outX,
653  int32_t &outY) const
654 {
655  outX = inX;
656  outY = inY;
657 }
658 
660  int32_t inY,
661  int32_t &outX,
662  int32_t &outY) const
663 {
664  outX = inX;
665  outY = inY;
666 }
667 
669 {
671 
672  wl_egl_window_destroy(w->egl_window);
673 
674 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
675  libdecor_frame_unref(w->decor_frame);
676 #else
677  if (w->xdg_toplevel_decoration) {
678  zxdg_toplevel_decoration_v1_destroy(w->xdg_toplevel_decoration);
679  }
680  xdg_toplevel_destroy(w->xdg_toplevel);
681  xdg_surface_destroy(w->xdg_surface);
682 #endif
683 
684  /* Clear any pointers to this window. This is needed because there are no guarantees
685  * that flushing the display will the "leave" handlers before handling events. */
686  m_system->window_surface_unref(w->wl_surface);
687 
688  wl_surface_destroy(w->wl_surface);
689 
690  /* NOTE(@campbellbarton): Flushing will often run the appropriate handlers event
691  * (#wl_surface_listener.leave in particular) to avoid attempted access to the freed surfaces.
692  * This is not fool-proof though, hence the call to #window_surface_unref, see: T99078. */
693  wl_display_flush(m_system->display());
694 
695  delete w;
696 }
697 
699 {
700  return w->dpi;
701 }
702 
704 {
705  return m_system->setCursorVisibility(visible);
706 }
707 
709 {
710  switch (state) {
712  /* Unset states. */
713  switch (getState()) {
715 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
716  libdecor_frame_unset_maximized(w->decor_frame);
717 #else
718  xdg_toplevel_unset_maximized(w->xdg_toplevel);
719 #endif
720  break;
722 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
723  libdecor_frame_unset_fullscreen(w->decor_frame);
724 #else
725  xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
726 #endif
727  break;
728  default:
729  break;
730  }
731  break;
733 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
734  libdecor_frame_set_maximized(w->decor_frame);
735 #else
736  xdg_toplevel_set_maximized(w->xdg_toplevel);
737 #endif
738  break;
740 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
741  libdecor_frame_set_minimized(w->decor_frame);
742 #else
743  xdg_toplevel_set_minimized(w->xdg_toplevel);
744 #endif
745  break;
747 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
748  libdecor_frame_set_fullscreen(w->decor_frame, nullptr);
749 #else
750  xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
751 #endif
752  break;
754  return GHOST_kFailure;
755  }
756  return GHOST_kSuccess;
757 }
758 
760 {
761  if (w->is_fullscreen) {
763  }
764  if (w->is_maximised) {
766  }
768 }
769 
771 {
772  return GHOST_kSuccess;
773 }
774 
776 {
777  return GHOST_kSuccess;
778 }
779 
781 {
782 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
783  libdecor_frame_set_fullscreen(w->decor_frame, nullptr);
784 #else
785  xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
786 #endif
787  return GHOST_kSuccess;
788 }
789 
791 {
792 #ifdef WITH_GHOST_WAYLAND_LIBDECOR
793  libdecor_frame_unset_fullscreen(w->decor_frame);
794 #else
795  xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
796 #endif
797  return GHOST_kSuccess;
798 }
799 
801 {
802  return w->is_dialog;
803 }
804 
805 #ifdef GHOST_OPENGL_ALPHA
806 void GHOST_WindowWayland::setOpaque() const
807 {
808  struct wl_region *region;
809 
810  /* Make the window opaque. */
811  region = wl_compositor_create_region(m_system->compositor());
812  wl_region_add(region, 0, 0, UNPACK2(w->size));
813  wl_surface_set_opaque_region(w->surface, region);
814  wl_region_destroy(region);
815 }
816 #endif
817 
822 GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType type)
823 {
825  switch (type) {
828  break;
830  for (int minor = 6; minor >= 0; --minor) {
831  context = new GHOST_ContextEGL(this->m_system,
833  EGLNativeWindowType(w->egl_window),
834  EGLNativeDisplayType(m_system->display()),
835  EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
836  4,
837  minor,
840  EGL_OPENGL_API);
841 
842  if (context->initializeDrawingContext()) {
843  return context;
844  }
845  delete context;
846  }
847  context = new GHOST_ContextEGL(this->m_system,
849  EGLNativeWindowType(w->egl_window),
850  EGLNativeDisplayType(m_system->display()),
851  EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
852  3,
853  3,
856  EGL_OPENGL_API);
857  }
858 
859  return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr;
860 }
861 
864 /* -------------------------------------------------------------------- */
871 {
872  return w->dpi;
873 }
874 
876 {
877  return w->scale;
878 }
879 
880 wl_surface *GHOST_WindowWayland::surface() const
881 {
882  return w->wl_surface;
883 }
884 
885 const std::vector<output_t *> &GHOST_WindowWayland::outputs()
886 {
887  return w->outputs;
888 }
889 
892 /* -------------------------------------------------------------------- */
899 {
900  return m_system->pushEvent(
901  new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
902 }
903 
905 {
906  if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
907  return GHOST_kFailure;
908  }
909  return m_system->pushEvent(
910  new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
911 }
912 
914 {
915  m_system->getWindowManager()->setWindowInactive(this);
916  return m_system->pushEvent(
918 }
919 
921 {
922 #ifdef GHOST_OPENGL_ALPHA
923  setOpaque();
924 #endif
925 
926  return m_system->pushEvent(
927  new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
928 }
929 
932 /* -------------------------------------------------------------------- */
939 {
940  uint32_t dpi_next;
941  const int scale_next = outputs_max_scale_or_default(this->outputs(), 0, &dpi_next);
942  if (UNLIKELY(scale_next == 0)) {
943  return false;
944  }
945 
946  window_t *win = this->w;
947  const uint32_t dpi_curr = win->dpi;
948  const int scale_curr = win->scale;
949  bool changed = false;
950 
951  if (scale_next != scale_curr) {
952  /* Unlikely but possible there is a pending size change is set. */
953  win->size_pending[0] = (win->size_pending[0] / scale_curr) * scale_next;
954  win->size_pending[1] = (win->size_pending[1] / scale_curr) * scale_next;
955 
956  win->scale = scale_next;
957  wl_surface_set_buffer_scale(w->wl_surface, scale_next);
958  changed = true;
959  }
960 
961  if (dpi_next != dpi_curr) {
962  /* Using the real DPI will cause wrong scaling of the UI
963  * use a multiplier for the default DPI as workaround. */
964  win->dpi = dpi_next;
965  changed = true;
966  }
967 
968  return changed;
969 }
970 
972 {
973  std::vector<output_t *> &outputs = w->outputs;
974  auto it = std::find(outputs.begin(), outputs.end(), reg_output);
975  if (it != outputs.end()) {
976  return false;
977  }
978  outputs.push_back(reg_output);
979  return true;
980 }
981 
983 {
984  std::vector<output_t *> &outputs = w->outputs;
985  auto it = std::find(outputs.begin(), outputs.end(), reg_output);
986  if (it == outputs.end()) {
987  return false;
988  }
989  outputs.erase(it);
990  return true;
991 }
992 
KDTree *BLI_kdtree_nd_() new(unsigned int maxsize)
Definition: kdtree_impl.h:85
#define UNPACK2(a)
#define UNLIKELY(x)
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:187
#define GHOST_OPENGL_EGL_CONTEXT_FLAGS
#define GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY
#define GHOST_PRINT(x)
Definition: GHOST_Debug.h:35
void ghost_wl_surface_tag(struct wl_surface *surface)
struct output_t * ghost_wl_output_user_data(struct wl_output *wl_output)
bool ghost_wl_output_own(const struct wl_output *output)
GHOST_TWindowState
Definition: GHOST_Types.h:129
@ GHOST_kWindowStateMinimized
Definition: GHOST_Types.h:132
@ GHOST_kWindowStateMaximized
Definition: GHOST_Types.h:131
@ GHOST_kWindowStateEmbedded
Definition: GHOST_Types.h:134
@ GHOST_kWindowStateNormal
Definition: GHOST_Types.h:130
@ GHOST_kWindowStateFullScreen
Definition: GHOST_Types.h:133
GHOST_TStandardCursor
Definition: GHOST_Types.h:214
@ GHOST_kStandardCursorDefault
Definition: GHOST_Types.h:216
@ GHOST_kEventWindowClose
Definition: GHOST_Types.h:189
@ GHOST_kEventWindowSize
Definition: GHOST_Types.h:193
@ GHOST_kEventWindowActivate
Definition: GHOST_Types.h:190
@ GHOST_kEventWindowDeactivate
Definition: GHOST_Types.h:191
GHOST_TDrawingContextType
Definition: GHOST_Types.h:148
@ GHOST_kDrawingContextTypeOpenGL
Definition: GHOST_Types.h:150
@ GHOST_kDrawingContextTypeNone
Definition: GHOST_Types.h:149
GHOST_TWindowOrder
Definition: GHOST_Types.h:146
GHOST_TSuccess
Definition: GHOST_Types.h:74
@ GHOST_kFailure
Definition: GHOST_Types.h:74
@ GHOST_kSuccess
Definition: GHOST_Types.h:74
GHOST_TGrabCursorMode
Definition: GHOST_Types.h:404
@ GHOST_kGrabWrap
Definition: GHOST_Types.h:410
static void surface_handle_leave(void *data, struct wl_surface *, struct wl_output *output)
static GHOST_WindowManager * window_manager
#define LOG
static CLG_LogRef LOG_WL_XDG_TOPLEVEL_DECORATION
static void xdg_toplevel_handle_configure(void *data, xdg_toplevel *, const int32_t width, const int32_t height, wl_array *states)
static CLG_LogRef LOG_WL_XDG_SURFACE
static void xdg_surface_handle_configure(void *data, xdg_surface *xdg_surface, const uint32_t serial)
static void surface_handle_enter(void *data, struct wl_surface *, struct wl_output *output)
static CLG_LogRef LOG_WL_SURFACE
static int outputs_max_scale_or_default(const std::vector< output_t * > &outputs, const int32_t scale_default, uint32_t *r_dpi)
static void xdg_toplevel_decoration_handle_configure(void *data, struct zxdg_toplevel_decoration_v1 *, const uint32_t mode)
static const xdg_toplevel_listener toplevel_listener
static int output_scale_cmp(const output_t *output_a, const output_t *output_b)
static constexpr size_t base_dpi
static const xdg_surface_listener xdg_surface_listener
static CLG_LogRef LOG_WL_XDG_TOPLEVEL
static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener
static struct wl_surface_listener wl_surface_listener
static void xdg_toplevel_handle_close(void *data, xdg_toplevel *)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_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 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
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
zxdg_decoration_manager_v1 * xdg_decoration_manager()
void window_surface_unref(const wl_surface *surface)
wl_compositor * compositor()
GHOST_TSuccess setCursorVisibility(bool visible)
bool window_cursor_grab_set(const GHOST_TGrabCursorMode mode, const GHOST_TGrabCursorMode mode_current, int32_t init_grab_xy[2], const GHOST_Rect *wrap_bounds, GHOST_TAxisFlag wrap_axis, wl_surface *surface, int scale)
const std::vector< output_t * > & outputs() const
GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape)
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape)
GHOST_TSuccess setCustomCursorShape(uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
bool getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode)
virtual uint64_t getMilliSeconds() const
GHOST_WindowManager * getWindowManager() const
Definition: GHOST_System.h:432
GHOST_TSuccess pushEvent(GHOST_IEvent *event)
GHOST_TSuccess setActiveWindow(GHOST_IWindow *window)
void setWindowInactive(const GHOST_IWindow *window)
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) override
GHOST_TSuccess setClientSize(uint32_t width, uint32_t height) override
GHOST_TSuccess setClientWidth(uint32_t width) override
bool outputs_leave(output_t *reg_output)
GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override
bool outputs_enter(output_t *reg_output)
GHOST_TSuccess notify_size()
GHOST_TSuccess setState(GHOST_TWindowState state) override
GHOST_TSuccess setWindowCursorVisibility(bool visible) override
GHOST_TWindowState getState() const override
bool getCursorGrabUseSoftwareDisplay() override
GHOST_TSuccess beginFullScreen() const override
bool isDialog() const override
struct wl_surface * surface() const
std::string getTitle() const override
GHOST_TSuccess deactivate()
void getClientBounds(GHOST_Rect &bounds) const override
uint16_t getDPIHint() override
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override
GHOST_TSuccess endFullScreen() const override
GHOST_TSuccess setClientHeight(uint32_t height) override
GHOST_WindowWayland(GHOST_SystemWayland *system, const char *title, int32_t left, int32_t top, uint32_t width, uint32_t height, GHOST_TWindowState state, const GHOST_IWindow *parentWindow, GHOST_TDrawingContextType type, const bool is_dialog, const bool stereoVisual, const bool exclusive)
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override
const std::vector< output_t * > & outputs()
GHOST_TSuccess invalidate() override
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override
void setTitle(const char *title) override
GHOST_TSuccess setWindowCustomCursorShape(uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor) override
void getWindowBounds(GHOST_Rect &bounds) const override
GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) override
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds)
GHOST_TGrabCursorMode m_cursorGrab
Definition: GHOST_Window.h:359
bool m_wantStereoVisual
Definition: GHOST_Window.h:389
int32_t m_cursorGrabInitPos[2]
Definition: GHOST_Window.h:365
GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type)
GHOST_TStandardCursor m_cursorShape
Definition: GHOST_Window.h:374
GHOST_TSuccess releaseNativeHandles()
GHOST_TAxisFlag m_cursorGrabAxis
Definition: GHOST_Window.h:362
GHOST_TSuccess setSwapInterval(int interval)
ccl_global KernelShaderEvalInput ccl_global float * output
const int state
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static bNodeSocketTemplate outputs[]
unsigned short uint16_t
Definition: stdint.h:79
unsigned int uint32_t
Definition: stdint.h:80
signed int int32_t
Definition: stdint.h:77
unsigned char uint8_t
Definition: stdint.h:78
wl_fixed_t scale_fractional
bool has_scale_fractional
int32_t size_pending[2]
enum zxdg_toplevel_decoration_v1_mode decoration_mode
wl_egl_window * egl_window
int32_t size[2]
struct xdg_toplevel * xdg_toplevel
struct zxdg_toplevel_decoration_v1 * xdg_toplevel_decoration
struct wl_surface * wl_surface
struct xdg_surface * xdg_surface
GHOST_WindowWayland * w
std::vector< output_t * > outputs
#define wl_display_flush(...)
#define wl_display_roundtrip(...)
#define wl_egl_window_resize(...)
#define wl_egl_window_create(...)
#define wl_egl_window_destroy(...)
#define libdecor_frame_set_fullscreen(...)
#define libdecor_frame_map(...)
#define libdecor_state_new(...)
#define libdecor_frame_unset_fullscreen(...)
#define libdecor_configuration_get_content_size(...)
#define libdecor_dispatch(...)
#define libdecor_state_free(...)
#define libdecor_configuration_get_window_state(...)
#define libdecor_frame_unref(...)
#define libdecor_frame_unset_maximized(...)
#define libdecor_frame_set_app_id(...)
#define libdecor_frame_set_min_content_size(...)
#define libdecor_frame_set_parent(...)
#define libdecor_frame_set_title(...)
#define libdecor_frame_set_minimized(...)
#define libdecor_frame_commit(...)
#define libdecor_decorate(...)
#define libdecor_frame_set_maximized(...)