Blender V5.0
GHOST_WindowX11.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9/* For standard X11 cursors */
10#include <X11/Xatom.h>
11#include <X11/Xmd.h>
12#include <X11/Xutil.h>
13#include <X11/cursorfont.h>
14
15#include "GHOST_Debug.hh"
16#include "GHOST_IconX11.hh"
17#include "GHOST_SystemX11.hh"
18#include "GHOST_Types.h"
19#include "GHOST_WindowX11.hh"
20#include "GHOST_utildefines.hh"
21
22#ifdef WITH_XDND
23# include "GHOST_DropTargetX11.hh"
24#endif
25
26#ifdef WITH_OPENGL_BACKEND
27# include "GHOST_ContextEGL.hh"
28# include "GHOST_ContextGLX.hh"
29#endif
30#ifdef WITH_VULKAN_BACKEND
31# include "GHOST_ContextVK.hh"
32#endif
33
34/* For #XIWarpPointer. */
35#ifdef WITH_X11_XINPUT
36# include <X11/extensions/XInput2.h>
37#endif
38
39/* For DPI value. */
40#include <X11/Xresource.h>
41
42#include <cstdio>
43#include <cstring>
44
45/* For `gethostname`. */
46#include <unistd.h>
47
48#include <algorithm>
49#include <climits>
50#include <cmath>
51#include <string>
52
53/* For obscure full screen mode stuff
54 * lifted verbatim from blut. */
55
57 long flags;
61};
62
63enum {
66};
67enum {
68 MWM_FUNCTION_ALL = (1L << 0),
70 MWM_FUNCTION_MOVE = (1L << 2),
73 MWM_FUNCTION_CLOSE = (1L << 5),
74};
75
76#ifndef HOST_NAME_MAX
77# define HOST_NAME_MAX 64
78#endif
79
80// #define GHOST_X11_GRAB
81
82/*
83 * A Client can't change the window property, that is
84 * the work of the window manager. In case, we send
85 * a ClientMessage to the RootWindow with the property
86 * and the Action (WM-spec define this):
87 */
88#define _NET_WM_STATE_REMOVE 0
89#define _NET_WM_STATE_ADD 1
90// #define _NET_WM_STATE_TOGGLE 2 // UNUSED
91
92#ifdef WITH_OPENGL_BACKEND
93static XVisualInfo *get_x11_visualinfo(Display *display)
94{
95 int num_visuals;
96 XVisualInfo vinfo_template;
97 vinfo_template.screen = DefaultScreen(display);
98 return XGetVisualInfo(display, VisualScreenMask, &vinfo_template, &num_visuals);
99}
100#endif
101
103 Display *display,
104 const char *title,
106 int32_t top,
107 uint32_t width,
108 uint32_t height,
110 GHOST_WindowX11 *parent_window,
112 const bool is_dialog,
113 const GHOST_ContextParams &context_params,
114 const bool exclusive,
115 const GHOST_GPUDevice &preferred_device)
116 : GHOST_Window(width, height, state, context_params, exclusive),
117 display_(display),
118 visual_info_(nullptr),
119 fbconfig_(nullptr),
120 normal_state_(GHOST_kWindowStateNormal),
121 system_(system),
122 invalid_window_(false),
123 empty_cursor_(None),
124 custom_cursor_(None),
125 visible_cursor_(None),
126#ifdef WITH_XDND
127 drop_target_(nullptr),
128#endif
129 tablet_data_(GHOST_TABLET_DATA_NONE),
130#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
131 xic_(nullptr),
132#endif
133 valid_setup_(false),
134 preferred_device_(preferred_device)
135{
136#ifdef WITH_OPENGL_BACKEND
137 if (type == GHOST_kDrawingContextTypeOpenGL) {
138 visual_info_ = get_x11_visualinfo(display_);
139 }
140 else
141#endif
142 {
143 XVisualInfo tmp = {nullptr};
144 int n;
145 visual_info_ = XGetVisualInfo(display_, 0, &tmp, &n);
146 }
147
148 /* caller needs to check 'getValid()' */
149 if (visual_info_ == nullptr) {
150 fprintf(stderr, "initial window could not find the GLX extension\n");
151 return;
152 }
153
154 uint xattributes_valuemask = 0;
155
156 XSetWindowAttributes xattributes;
157 memset(&xattributes, 0, sizeof(xattributes));
158
159 xattributes_valuemask |= CWBorderPixel;
160 xattributes.border_pixel = 0;
161
162 /* Specify which events we are interested in hearing. */
163
164 xattributes_valuemask |= CWEventMask;
165 xattributes.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
166 EnterWindowMask | LeaveWindowMask | ButtonPressMask |
167 ButtonReleaseMask | PointerMotionMask | FocusChangeMask |
168 PropertyChangeMask | KeymapStateMask;
169
170 if (exclusive) {
171 xattributes_valuemask |= CWOverrideRedirect;
172 xattributes.override_redirect = True;
173 }
174
175 xattributes_valuemask |= CWColormap;
176 xattributes.colormap = XCreateColormap(
177 display_, RootWindow(display_, visual_info_->screen), visual_info_->visual, AllocNone);
178
179 /* create the window! */
180 window_ = XCreateWindow(display_,
181 RootWindow(display_, visual_info_->screen),
182 left,
183 top,
184 width,
185 height,
186 0, /* no border. */
187 visual_info_->depth,
188 InputOutput,
189 visual_info_->visual,
190 xattributes_valuemask,
191 &xattributes);
192
193#ifdef WITH_XDND
194 /* initialize drop target for newly created window */
195 drop_target_ = new GHOST_DropTargetX11(this, system_);
196 GHOST_PRINT("Set drop target\n");
197#endif
198
200 Atom atoms[2];
201 int count = 0;
203 atoms[count++] = system_->atom_._NET_WM_STATE_MAXIMIZED_VERT;
204 atoms[count++] = system_->atom_._NET_WM_STATE_MAXIMIZED_HORZ;
205 }
206 else {
207 atoms[count++] = system_->atom_._NET_WM_STATE_FULLSCREEN;
208 }
209
210 XChangeProperty(display_,
211 window_,
212 system_->atom_._NET_WM_STATE,
213 XA_ATOM,
214 32,
215 PropModeReplace,
216 (uchar *)atoms,
217 count);
218 post_init_ = False;
219 }
220 /*
221 * One of the problem with WM-spec is that can't set a property
222 * to a window that isn't mapped. That is why we can't "just
223 * call setState" here.
224 *
225 * To fix this, we first need know that the window is really
226 * map waiting for the MapNotify event.
227 *
228 * So, post_init_ indicate that we need wait for the MapNotify
229 * event and then set the Window state to the post_state_.
230 */
232 post_init_ = True;
234 }
235 else {
236 post_init_ = False;
238 }
239
240 if (is_dialog && parent_window) {
241 setDialogHints(parent_window);
242 }
243
244 /* Create some hints for the window manager on how
245 * we want this window treated. */
246 {
247 XSizeHints *xsizehints = XAllocSizeHints();
248 xsizehints->flags = PPosition | PSize | PMinSize | PMaxSize;
249 xsizehints->x = left;
250 xsizehints->y = top;
251 xsizehints->width = width;
252 xsizehints->height = height;
253 xsizehints->min_width = 320; /* Size hints, could be made apart of the GHOST API. */
254 xsizehints->min_height = 240; /* Limits are also arbitrary, but should not allow 1x1 window. */
255 xsizehints->max_width = 65535;
256 xsizehints->max_height = 65535;
257 XSetWMNormalHints(display_, window_, xsizehints);
258 XFree(xsizehints);
259 }
260
261 /* XClassHint, title */
262 {
263 XClassHint *xclasshint = XAllocClassHint();
264 const int len = strlen(title) + 1;
265 char *wmclass = (char *)malloc(sizeof(char) * len);
266 memcpy(wmclass, title, len * sizeof(char));
267 xclasshint->res_name = wmclass;
268 xclasshint->res_class = wmclass;
269 XSetClassHint(display_, window_, xclasshint);
270 free(wmclass);
271 XFree(xclasshint);
272 }
273
274 /* The basic for a good ICCCM "work" */
275 if (system_->atom_.WM_PROTOCOLS) {
276 Atom atoms[2];
277 int natom = 0;
278
279 if (system_->atom_.WM_DELETE_WINDOW) {
280 atoms[natom] = system_->atom_.WM_DELETE_WINDOW;
281 natom++;
282 }
283
284 if (system_->atom_.WM_TAKE_FOCUS && system_->window_focus_) {
285 atoms[natom] = system_->atom_.WM_TAKE_FOCUS;
286 natom++;
287 }
288
289 if (natom) {
290 // printf("Register atoms: %d\n", natom);
291 XSetWMProtocols(display_, window_, atoms, natom);
292 }
293 }
294
295 /* Set the window hints */
296 {
297 XWMHints *xwmhints = XAllocWMHints();
298 xwmhints->initial_state = NormalState;
299 xwmhints->input = (system_->window_focus_) ? True : False;
300 xwmhints->flags = InputHint | StateHint;
301 XSetWMHints(display, window_, xwmhints);
302 XFree(xwmhints);
303 }
304 /* Controlled via the `--no-window-frame` CLI argument and wont change at run-time.
305 * Set this once and never change. */
306 if (GHOST_ISystem::getUseWindowFrame() == false) {
307 motifShowWindowFrame(false);
308 }
309
310 /* set the icon */
311 {
312 Atom _NET_WM_ICON = XInternAtom(display_, "_NET_WM_ICON", False);
313 XChangeProperty(display_,
314 window_,
315 _NET_WM_ICON,
316 XA_CARDINAL,
317 32,
318 PropModeReplace,
321 }
322
323 /* set the process ID (_NET_WM_PID) */
324 {
325 Atom _NET_WM_PID = XInternAtom(display_, "_NET_WM_PID", False);
326 pid_t pid = getpid();
327 XChangeProperty(
328 display_, window_, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, (uchar *)&pid, 1);
329 }
330
331 /* set the hostname (WM_CLIENT_MACHINE) */
332 {
333 char hostname[HOST_NAME_MAX];
334 char *text_array[1];
335 XTextProperty text_prop;
336
337 gethostname(hostname, sizeof(hostname));
338 hostname[sizeof(hostname) - 1] = '\0';
339 text_array[0] = hostname;
340
341 XStringListToTextProperty(text_array, 1, &text_prop);
342 XSetWMClientMachine(display_, window_, &text_prop);
343 XFree(text_prop.value);
344 }
345
346#ifdef WITH_X11_XINPUT
347 refreshXInputDevices();
348#endif
349
350 /* now set up the rendering context. */
352 valid_setup_ = true;
353 GHOST_PRINT("Created window\n");
354 }
355 else {
356 const char *text =
357 "A graphics card and driver with support for OpenGL 4.3 or higher is "
358 "required.\n\nInstalling the latest driver for your graphics card might resolve the "
359 "issue.";
360 const char *help = "https://www.blender.org/download/requirements/";
361 system->showMessageBox(
362 "Unsupported hardware", text, "Learn More", "Close", help, GHOST_DialogError);
363 exit(0);
364 }
365
366 setTitle(title);
367
368 if (exclusive && system->window_focus_) {
369 XMapRaised(display_, window_);
370 }
371 else {
372 XMapWindow(display_, window_);
373
374 if (!system->window_focus_) {
375 XLowerWindow(display_, window_);
376 }
377 }
378 GHOST_PRINT("Mapped window\n");
379
380 XFlush(display_);
381}
382
383#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
384static Bool destroyICCallback(XIC /*xic*/, XPointer ptr, XPointer /*data*/)
385{
386 GHOST_PRINT("XIM input context destroyed\n");
387
388 if (ptr) {
389 *(XIC *)ptr = nullptr;
390 }
391 /* Ignored by X11. */
392 return True;
393}
394
395bool GHOST_WindowX11::createX11_XIC()
396{
397 XIM xim = system_->getX11_XIM();
398 if (!xim) {
399 return false;
400 }
401
402 XICCallback destroy;
403 destroy.callback = (XICProc)destroyICCallback;
404 destroy.client_data = (XPointer)&xic_;
405 xic_ = XCreateIC(xim,
406 XNClientWindow,
407 window_,
408 XNFocusWindow,
409 window_,
410 XNInputStyle,
411 XIMPreeditNothing | XIMStatusNothing,
412 XNResourceName,
413 GHOST_X11_RES_NAME,
414 XNResourceClass,
415 GHOST_X11_RES_CLASS,
416 XNDestroyCallback,
417 &destroy,
418 nullptr);
419 if (!xic_) {
420 return false;
421 }
422
423 ulong fevent;
424 XGetICValues(xic_, XNFilterEvents, &fevent, nullptr);
425 XSelectInput(display_,
426 window_,
427 ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
428 EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask |
429 PointerMotionMask | FocusChangeMask | PropertyChangeMask | KeymapStateMask |
430 fevent);
431 return true;
432}
433#endif
434
435#ifdef WITH_X11_XINPUT
436void GHOST_WindowX11::refreshXInputDevices()
437{
438 if (system_->xinput_version_.present) {
439 std::vector<XEventClass> xevents;
440
441 for (GHOST_SystemX11::GHOST_TabletX11 &xtablet : system_->GetXTablets()) {
442 /* With modern XInput (XLIB 1.6.2 at least and/or EVDEV 2.9.0) and some 'no-name' tablets
443 * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event,
444 * otherwise we do not get any tablet motion event once pen is pressed... See #43367.
445 */
446 XEventClass ev;
447
448 DeviceMotionNotify(xtablet.Device, xtablet.MotionEvent, ev);
449 if (ev) {
450 xevents.push_back(ev);
451 }
452 DeviceButtonPress(xtablet.Device, xtablet.PressEvent, ev);
453 if (ev) {
454 xevents.push_back(ev);
455 }
456 ProximityIn(xtablet.Device, xtablet.ProxInEvent, ev);
457 if (ev) {
458 xevents.push_back(ev);
459 }
460 ProximityOut(xtablet.Device, xtablet.ProxOutEvent, ev);
461 if (ev) {
462 xevents.push_back(ev);
463 }
464 }
465
466 XSelectExtensionEvent(display_, window_, xevents.data(), int(xevents.size()));
467 }
468}
469
470#endif /* WITH_X11_XINPUT */
471
473{
474 return window_;
475}
476
478{
479 return GHOST_Window::getValid() && valid_setup_;
480}
481
482void GHOST_WindowX11::setTitle(const char *title)
483{
484 Atom name = XInternAtom(display_, "_NET_WM_NAME", 0);
485 Atom utf8str = XInternAtom(display_, "UTF8_STRING", 0);
486 XChangeProperty(
487 display_, window_, name, utf8str, 8, PropModeReplace, (const uchar *)title, strlen(title));
488
489 /* This should convert to valid x11 string
490 * and getTitle would need matching change */
491 XStoreName(display_, window_, title);
492
493 XFlush(display_);
494}
495
496std::string GHOST_WindowX11::getTitle() const
497{
498 char *name = nullptr;
499
500 XFetchName(display_, window_, &name);
501 std::string title = name ? name : "untitled";
502 XFree(name);
503 return title;
504}
505
507{
508 /* Getting the window bounds under X11 is not
509 * really supported (nor should it be desired). */
511}
512
514{
515 Window root_return;
516 int x_return, y_return;
517 uint w_return, h_return, border_w_return, depth_return;
518 int32_t screen_x, screen_y;
519
520 XGetGeometry(display_,
521 window_,
522 &root_return,
523 &x_return,
524 &y_return,
525 &w_return,
526 &h_return,
527 &border_w_return,
528 &depth_return);
529
530 clientToScreen(0, 0, screen_x, screen_y);
531
532 bounds.l_ = screen_x;
533 bounds.r_ = bounds.l_ + w_return;
534 bounds.t_ = screen_y;
535 bounds.b_ = bounds.t_ + h_return;
536}
537
539{
540 XWindowChanges values;
541 uint value_mask = CWWidth;
542 values.width = width;
543 XConfigureWindow(display_, window_, value_mask, &values);
544
545 return GHOST_kSuccess;
546}
547
549{
550 XWindowChanges values;
551 uint value_mask = CWHeight;
552 values.height = height;
553 XConfigureWindow(display_, window_, value_mask, &values);
554 return GHOST_kSuccess;
555}
556
557GHOST_TSuccess GHOST_WindowX11::setClientSize(uint32_t width, uint32_t height)
558{
559 XWindowChanges values;
560 uint value_mask = CWWidth | CWHeight;
561 values.width = width;
562 values.height = height;
563 XConfigureWindow(display_, window_, value_mask, &values);
564 return GHOST_kSuccess;
565}
566
568{
569 int ax, ay;
570 Window temp;
571
572 /* Use (0, 0) instead of (inX, inY) to work around overflow of signed int16 in
573 * the implementation of this function. */
574 XTranslateCoordinates(
575 display_, RootWindow(display_, visual_info_->screen), window_, 0, 0, &ax, &ay, &temp);
576 outX = ax + inX;
577 outY = ay + inY;
578}
579
581{
582 int ax, ay;
583 Window temp;
584
585 XTranslateCoordinates(
586 display_, window_, RootWindow(display_, visual_info_->screen), inX, inY, &ax, &ay, &temp);
587 outX = ax;
588 outY = ay;
589}
590
592{
593
594 Atom atom_window_type = XInternAtom(display_, "_NET_WM_WINDOW_TYPE", False);
595 Atom atom_dialog = XInternAtom(display_, "_NET_WM_WINDOW_TYPE_DIALOG", False);
596 MotifWmHints hints = {0};
597
598 XChangeProperty(
599 display_, window_, atom_window_type, XA_ATOM, 32, PropModeReplace, (uchar *)&atom_dialog, 1);
600 XSetTransientForHint(display_, window_, parent_window->window_);
601
602 /* Disable minimizing of the window for now.
603 * Actually, most window managers disable minimizing and maximizing for dialogs, ignoring this.
604 * Leaving it here anyway in the hope it brings back maximizing on some window managers at least,
605 * we'd preferably have it even for dialog windows (e.g. file browser). */
609 XChangeProperty(display_,
610 window_,
611 system_->atom_._MOTIF_WM_HINTS,
612 system_->atom_._MOTIF_WM_HINTS,
613 32,
614 PropModeReplace,
615 (uchar *)&hints,
616 4);
617
618 return GHOST_kSuccess;
619}
620
621void GHOST_WindowX11::icccmSetState(int state)
622{
623 XEvent xev;
624
625 if (state != IconicState) {
626 return;
627 }
628
629 xev.xclient.type = ClientMessage;
630 xev.xclient.serial = 0;
631 xev.xclient.send_event = True;
632 xev.xclient.display = display_;
633 xev.xclient.window = window_;
634 xev.xclient.format = 32;
635 xev.xclient.message_type = system_->atom_.WM_CHANGE_STATE;
636 xev.xclient.data.l[0] = state;
637 XSendEvent(display_,
638 RootWindow(display_, visual_info_->screen),
639 False,
640 SubstructureNotifyMask | SubstructureRedirectMask,
641 &xev);
642}
643
644int GHOST_WindowX11::icccmGetState() const
645{
646 struct {
647 CARD32 state;
648 XID icon;
649 } *prop_ret;
650 ulong bytes_after, num_ret;
651 Atom type_ret;
652 int ret, format_ret;
653 CARD32 st;
654
655 prop_ret = nullptr;
656 ret = XGetWindowProperty(display_,
657 window_,
658 system_->atom_.WM_STATE,
659 0,
660 2,
661 False,
662 system_->atom_.WM_STATE,
663 &type_ret,
664 &format_ret,
665 &num_ret,
666 &bytes_after,
667 ((uchar **)&prop_ret));
668 if ((ret == Success) && (prop_ret != nullptr) && (num_ret == 2)) {
669 st = prop_ret->state;
670 }
671 else {
672 st = NormalState;
673 }
674
675 if (prop_ret) {
676 XFree(prop_ret);
677 }
678
679 return st;
680}
681
682void GHOST_WindowX11::netwmMaximized(bool set)
683{
684 XEvent xev;
685
686 xev.xclient.type = ClientMessage;
687 xev.xclient.serial = 0;
688 xev.xclient.send_event = True;
689 xev.xclient.window = window_;
690 xev.xclient.message_type = system_->atom_._NET_WM_STATE;
691 xev.xclient.format = 32;
692
693 if (set == True) {
694 xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
695 }
696 else {
697 xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
698 }
699
700 xev.xclient.data.l[1] = system_->atom_._NET_WM_STATE_MAXIMIZED_HORZ;
701 xev.xclient.data.l[2] = system_->atom_._NET_WM_STATE_MAXIMIZED_VERT;
702 xev.xclient.data.l[3] = 0;
703 xev.xclient.data.l[4] = 0;
704 XSendEvent(display_,
705 RootWindow(display_, visual_info_->screen),
706 False,
707 SubstructureRedirectMask | SubstructureNotifyMask,
708 &xev);
709}
710
711bool GHOST_WindowX11::netwmIsMaximized() const
712{
713 Atom *prop_ret;
714 ulong bytes_after, num_ret, i;
715 Atom type_ret;
716 bool st;
717 int format_ret, ret, count;
718
719 prop_ret = nullptr;
720 st = False;
721 ret = XGetWindowProperty(display_,
722 window_,
723 system_->atom_._NET_WM_STATE,
724 0,
725 INT_MAX,
726 False,
727 XA_ATOM,
728 &type_ret,
729 &format_ret,
730 &num_ret,
731 &bytes_after,
732 (uchar **)&prop_ret);
733 if ((ret == Success) && (prop_ret) && (format_ret == 32)) {
734 count = 0;
735 for (i = 0; i < num_ret; i++) {
736 if (prop_ret[i] == system_->atom_._NET_WM_STATE_MAXIMIZED_HORZ) {
737 count++;
738 }
739 if (prop_ret[i] == system_->atom_._NET_WM_STATE_MAXIMIZED_VERT) {
740 count++;
741 }
742 if (count == 2) {
743 st = True;
744 break;
745 }
746 }
747 }
748
749 if (prop_ret) {
750 XFree(prop_ret);
751 }
752 return st;
753}
754
755void GHOST_WindowX11::netwmFullScreen(bool set)
756{
757 XEvent xev;
758
759 xev.xclient.type = ClientMessage;
760 xev.xclient.serial = 0;
761 xev.xclient.send_event = True;
762 xev.xclient.window = window_;
763 xev.xclient.message_type = system_->atom_._NET_WM_STATE;
764 xev.xclient.format = 32;
765
766 if (set == True) {
767 xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
768 }
769 else {
770 xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
771 }
772
773 xev.xclient.data.l[1] = system_->atom_._NET_WM_STATE_FULLSCREEN;
774 xev.xclient.data.l[2] = 0;
775 xev.xclient.data.l[3] = 0;
776 xev.xclient.data.l[4] = 0;
777 XSendEvent(display_,
778 RootWindow(display_, visual_info_->screen),
779 False,
780 SubstructureRedirectMask | SubstructureNotifyMask,
781 &xev);
782}
783
784bool GHOST_WindowX11::netwmIsFullScreen() const
785{
786 Atom *prop_ret;
787 ulong bytes_after, num_ret, i;
788 Atom type_ret;
789 bool st;
790 int format_ret, ret;
791
792 prop_ret = nullptr;
793 st = False;
794 ret = XGetWindowProperty(display_,
795 window_,
796 system_->atom_._NET_WM_STATE,
797 0,
798 INT_MAX,
799 False,
800 XA_ATOM,
801 &type_ret,
802 &format_ret,
803 &num_ret,
804 &bytes_after,
805 (uchar **)&prop_ret);
806 if ((ret == Success) && (prop_ret) && (format_ret == 32)) {
807 for (i = 0; i < num_ret; i++) {
808 if (prop_ret[i] == system_->atom_._NET_WM_STATE_FULLSCREEN) {
809 st = True;
810 break;
811 }
812 }
813 }
814
815 if (prop_ret) {
816 XFree(prop_ret);
817 }
818 return st;
819}
820
821void GHOST_WindowX11::motifShowWindowFrame(bool set)
822{
823 MotifWmHints hints;
824
826 if (set == false) {
827 hints.decorations = 0;
828 }
829 else {
831 "Only allowed when the window frame is shown.");
832 hints.decorations = 1;
833 }
834
835 XChangeProperty(display_,
836 window_,
837 system_->atom_._MOTIF_WM_HINTS,
838 system_->atom_._MOTIF_WM_HINTS,
839 32,
840 PropModeReplace,
841 (uchar *)&hints,
842 4);
843}
844
845bool GHOST_WindowX11::motifIsShowWindowFrame() const
846{
847 MotifWmHints *prop_ret;
848 ulong bytes_after, num_ret;
849 Atom type_ret;
850 bool state;
851 int format_ret, st;
852
853 prop_ret = nullptr;
854 state = False;
855 st = XGetWindowProperty(display_,
856 window_,
857 system_->atom_._MOTIF_WM_HINTS,
858 0,
859 INT_MAX,
860 False,
861 system_->atom_._MOTIF_WM_HINTS,
862 &type_ret,
863 &format_ret,
864 &num_ret,
865 &bytes_after,
866 (uchar **)&prop_ret);
867 if ((st == Success) && prop_ret) {
868 if (prop_ret->flags & MWM_HINTS_DECORATIONS) {
869 if (!prop_ret->decorations) {
870 state = True;
871 }
872 }
873 }
874
875 if (prop_ret) {
876 XFree(prop_ret);
877 }
878 return state;
879}
880
881void GHOST_WindowX11::motifFullScreen(bool set)
882{
883 if (set == true || (GHOST_ISystem::getUseWindowFrame() == false)) {
884 motifShowWindowFrame(false);
885 }
886 else {
887 motifShowWindowFrame(true);
888 }
889}
890
891bool GHOST_WindowX11::motifIsFullScreen() const
892{
893 /* When false, the decorations can't be used to detect full-screen. */
894 if (GHOST_ISystem::getUseWindowFrame() == false) {
895 return false;
896 }
897 return motifIsShowWindowFrame();
898}
899
901{
902 GHOST_TWindowState state_ret;
903 int state;
904
905 state_ret = GHOST_kWindowStateNormal;
906 state = icccmGetState();
907 /*
908 * In the Iconic and Withdrawn state, the window
909 * is unmapped, so only need return a Minimized state.
910 */
911 if (ELEM(state, IconicState, WithdrawnState)) {
912 state_ret = GHOST_kWindowStateMinimized;
913 }
914 else if (netwmIsFullScreen() == True) {
916 }
917 else if (motifIsFullScreen() == True) {
919 }
920 else if (netwmIsMaximized() == True) {
921 state_ret = GHOST_kWindowStateMaximized;
922 }
923 return state_ret;
924}
925
927{
928 GHOST_TWindowState cur_state;
929 bool is_max, is_full, is_motif_full;
930
931 cur_state = getState();
932 if (state == int(cur_state)) {
933 return GHOST_kSuccess;
934 }
935
936 if (cur_state != GHOST_kWindowStateMinimized) {
937 /*
938 * The window don't have this property's
939 * if it's not mapped.
940 */
941 is_max = netwmIsMaximized();
942 is_full = netwmIsFullScreen();
943 }
944 else {
945 is_max = False;
946 is_full = False;
947 }
948
949 is_motif_full = motifIsFullScreen();
950
952 state = normal_state_;
953 }
954
956 if (is_max == True) {
957 netwmMaximized(False);
958 }
959 if (is_full == True) {
960 netwmFullScreen(False);
961 }
962 if (is_motif_full == True) {
963 motifFullScreen(False);
964 }
965 icccmSetState(NormalState);
966 return GHOST_kSuccess;
967 }
968
970 /*
971 * We can't change to full screen if the window
972 * isn't mapped.
973 */
974 if (cur_state == GHOST_kWindowStateMinimized) {
975 return GHOST_kFailure;
976 }
977
978 normal_state_ = cur_state;
979
980 if (is_max == True) {
981 netwmMaximized(False);
982 }
983 if (is_full == False) {
984 netwmFullScreen(True);
985 }
986 if (is_motif_full == False) {
987 motifFullScreen(True);
988 }
989 return GHOST_kSuccess;
990 }
991
993 /*
994 * We can't change to Maximized if the window
995 * isn't mapped.
996 */
997 if (cur_state == GHOST_kWindowStateMinimized) {
998 return GHOST_kFailure;
999 }
1000
1001 if (is_full == True) {
1002 netwmFullScreen(False);
1003 }
1004 if (is_motif_full == True) {
1005 motifFullScreen(False);
1006 }
1007 if (is_max == False) {
1008 netwmMaximized(True);
1009 }
1010 return GHOST_kSuccess;
1011 }
1012
1014 /*
1015 * The window manager need save the current state of
1016 * the window (maximized, full screen, etc).
1017 */
1018 icccmSetState(IconicState);
1019 return GHOST_kSuccess;
1020 }
1021
1022 return GHOST_kFailure;
1023}
1024
1026{
1027 if (order == GHOST_kWindowOrderTop) {
1028 XWindowAttributes attr;
1029 Atom atom;
1030
1031 /* We use both #XRaiseWindow and #_NET_ACTIVE_WINDOW, since some
1032 * window managers ignore the former (e.g. KWIN from KDE) and others
1033 * don't implement the latter (e.g. FLUXBOX before 0.9.9). */
1034
1035 XRaiseWindow(display_, window_);
1036
1037 atom = XInternAtom(display_, "_NET_ACTIVE_WINDOW", True);
1038
1039 if (atom != None) {
1040 Window root;
1041 XEvent xev;
1042 long eventmask;
1043
1044 xev.xclient.type = ClientMessage;
1045 xev.xclient.serial = 0;
1046 xev.xclient.send_event = True;
1047 xev.xclient.window = window_;
1048 xev.xclient.message_type = atom;
1049
1050 xev.xclient.format = 32;
1051 xev.xclient.data.l[0] = 1;
1052 xev.xclient.data.l[1] = CurrentTime;
1053 xev.xclient.data.l[2] = window_;
1054 xev.xclient.data.l[3] = 0;
1055 xev.xclient.data.l[4] = 0;
1056
1057 root = RootWindow(display_, visual_info_->screen);
1058 eventmask = SubstructureRedirectMask | SubstructureNotifyMask;
1059
1060 XSendEvent(display_, root, False, eventmask, &xev);
1061 }
1062
1063 XGetWindowAttributes(display_, window_, &attr);
1064
1065 /* Minimized windows give bad match error. */
1066 if (attr.map_state == IsViewable) {
1067 XSetInputFocus(display_, window_, RevertToPointerRoot, CurrentTime);
1068 }
1069 XFlush(display_);
1070 }
1071 else if (order == GHOST_kWindowOrderBottom) {
1072 XLowerWindow(display_, window_);
1073 XFlush(display_);
1074 }
1075 else {
1076 return GHOST_kFailure;
1077 }
1078
1079 return GHOST_kSuccess;
1080}
1081
1083{
1084 Atom atom_window_type = XInternAtom(display_, "_NET_WM_WINDOW_TYPE", False);
1085 Atom atom_dialog = XInternAtom(display_, "_NET_WM_WINDOW_TYPE_DIALOG", False);
1086
1087 Atom *prop_ret;
1088 ulong bytes_after, num_ret;
1089 Atom type_ret;
1090 bool st;
1091 int format_ret, ret;
1092
1093 prop_ret = nullptr;
1094 st = False;
1095 ret = XGetWindowProperty(display_,
1096 window_,
1097 atom_window_type,
1098 0,
1099 INT_MAX,
1100 False,
1101 XA_ATOM,
1102 &type_ret,
1103 &format_ret,
1104 &num_ret,
1105 &bytes_after,
1106 (uchar **)&prop_ret);
1107 if ((ret == Success) && (prop_ret) && (format_ret == 32)) {
1108 if (prop_ret[0] == atom_dialog) {
1109 st = True;
1110 }
1111 }
1112
1113 if (prop_ret) {
1114 XFree(prop_ret);
1115 }
1116
1117 return st;
1118}
1119
1121{
1122 /* So the idea of this function is to generate an expose event
1123 * for the window.
1124 * Unfortunately X does not handle expose events for you and
1125 * it is the client's job to refresh the dirty part of the window.
1126 * We need to queue up invalidate calls and generate GHOST events
1127 * for them in the system.
1128 *
1129 * We implement this by setting a boolean in this class to concatenate
1130 * all such calls into a single event for this window.
1131 *
1132 * At the same time we queue the dirty windows in the system class
1133 * and generate events for them at the next processEvents call. */
1134
1135 if (invalid_window_ == false) {
1136 system_->addDirtyWindow(this);
1137 invalid_window_ = true;
1138 }
1139
1140 return GHOST_kSuccess;
1141}
1142
1147
1149{
1150 invalid_window_ = false;
1151}
1152
1154{
1155 std::map<uint, Cursor>::iterator it = standard_cursors_.begin();
1156 for (; it != standard_cursors_.end(); ++it) {
1157 XFreeCursor(display_, it->second);
1158 }
1159
1160 if (empty_cursor_) {
1161 XFreeCursor(display_, empty_cursor_);
1162 }
1163 if (custom_cursor_) {
1164 XFreeCursor(display_, custom_cursor_);
1165 }
1166
1167 if (valid_setup_) {
1168 static Atom Primary_atom, Clipboard_atom;
1169 Window p_owner, c_owner;
1170 /* Change the owner of the Atoms to None if we are the owner. */
1171 Primary_atom = XInternAtom(display_, "PRIMARY", False);
1172 Clipboard_atom = XInternAtom(display_, "CLIPBOARD", False);
1173
1174 p_owner = XGetSelectionOwner(display_, Primary_atom);
1175 c_owner = XGetSelectionOwner(display_, Clipboard_atom);
1176
1177 if (p_owner == window_) {
1178 XSetSelectionOwner(display_, Primary_atom, None, CurrentTime);
1179 }
1180 if (c_owner == window_) {
1181 XSetSelectionOwner(display_, Clipboard_atom, None, CurrentTime);
1182 }
1183 }
1184
1185 if (visual_info_) {
1186 XFree(visual_info_);
1187 }
1188
1189#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
1190 if (xic_) {
1191 XDestroyIC(xic_);
1192 }
1193#endif
1194
1195#ifdef WITH_XDND
1196 delete drop_target_;
1197#endif
1198
1200
1201 if (valid_setup_) {
1202 XDestroyWindow(display_, window_);
1203 }
1204}
1205
1207{
1208 switch (type) {
1209#ifdef WITH_VULKAN_BACKEND
1210 case GHOST_kDrawingContextTypeVulkan: {
1212 GHOST_kVulkanPlatformX11,
1213 window_,
1214 display_,
1215 nullptr,
1216 nullptr,
1217 nullptr,
1218 1,
1219 2,
1220 preferred_device_,
1221 &hdr_info_);
1222 if (context->initializeDrawingContext()) {
1223 return context;
1224 }
1225 delete context;
1226 return nullptr;
1227 }
1228#endif
1229
1230#ifdef WITH_OPENGL_BACKEND
1231 case GHOST_kDrawingContextTypeOpenGL: {
1232# ifdef USE_EGL
1233 /* Try to initialize an EGL context. */
1234 for (int minor = 6; minor >= 3; --minor) {
1236 this->system_,
1238 EGLNativeWindowType(window_),
1239 EGLNativeDisplayType(display_),
1240 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
1241 4,
1242 minor,
1244 (want_context_params_.is_debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0),
1246 EGL_OPENGL_API);
1247 if (context->initializeDrawingContext()) {
1248 return context;
1249 }
1250 delete context;
1251 }
1252 /* EGL initialization failed, try to fall back to a GLX context. */
1253# endif
1254
1255 for (int minor = 6; minor >= 3; --minor) {
1256 GHOST_Context *context = new GHOST_ContextGLX(
1258 window_,
1259 display_,
1260 (GLXFBConfig)fbconfig_,
1261 GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
1262 4,
1263 minor,
1265 (want_context_params_.is_debug ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
1267 if (context->initializeDrawingContext()) {
1268 return context;
1269 }
1270 delete context;
1271 }
1272 return nullptr;
1273 }
1274#endif
1275
1276 default:
1277 /* Unsupported backend. */
1278 return nullptr;
1279 }
1280}
1281
1282GHOST_TSuccess GHOST_WindowX11::getStandardCursor(GHOST_TStandardCursor g_cursor, Cursor &xcursor)
1283{
1284 uint xcursor_id;
1285
1286 switch (g_cursor) {
1288 xcursor_id = XC_question_arrow;
1289 break;
1291 xcursor_id = XC_watch;
1292 break;
1294 xcursor_id = XC_xterm;
1295 break;
1297 xcursor_id = XC_crosshair;
1298 break;
1300 xcursor_id = XC_sb_v_double_arrow;
1301 break;
1303 xcursor_id = XC_sb_h_double_arrow;
1304 break;
1306 xcursor_id = XC_top_side;
1307 break;
1309 xcursor_id = XC_bottom_side;
1310 break;
1312 xcursor_id = XC_left_side;
1313 break;
1315 xcursor_id = XC_right_side;
1316 break;
1318 xcursor_id = XC_top_left_corner;
1319 break;
1321 xcursor_id = XC_top_right_corner;
1322 break;
1324 xcursor_id = XC_bottom_right_corner;
1325 break;
1327 xcursor_id = XC_bottom_left_corner;
1328 break;
1330 xcursor = None;
1331 return GHOST_kSuccess;
1332 default:
1333 xcursor = None;
1334 return GHOST_kFailure;
1335 }
1336
1337 xcursor = standard_cursors_[xcursor_id];
1338
1339 if (!xcursor) {
1340 xcursor = XCreateFontCursor(display_, xcursor_id);
1341
1342 standard_cursors_[xcursor_id] = xcursor;
1343 }
1344
1345 return GHOST_kSuccess;
1346}
1347
1348Cursor GHOST_WindowX11::getEmptyCursor()
1349{
1350 if (!empty_cursor_) {
1351 Pixmap blank;
1352 XColor dummy = {0};
1353 char data[1] = {0};
1354
1355 /* make a blank cursor */
1356 blank = XCreateBitmapFromData(
1357 display_, RootWindow(display_, visual_info_->screen), data, 1, 1);
1358
1359 empty_cursor_ = XCreatePixmapCursor(display_, blank, blank, &dummy, &dummy, 0, 0);
1360 XFreePixmap(display_, blank);
1361 }
1362
1363 return empty_cursor_;
1364}
1365
1367{
1368 Cursor xcursor;
1369
1370 if (visible) {
1371 if (visible_cursor_) {
1372 xcursor = visible_cursor_;
1373 }
1374 else if (getStandardCursor(getCursorShape(), xcursor) == GHOST_kFailure) {
1375 getStandardCursor(getCursorShape(), xcursor);
1376 }
1377 }
1378 else {
1379 xcursor = getEmptyCursor();
1380 }
1381
1382 XDefineCursor(display_, window_, xcursor);
1383 XFlush(display_);
1384
1385 return GHOST_kSuccess;
1386}
1387
1389{
1390 if (mode != GHOST_kGrabDisable) {
1391 if (mode != GHOST_kGrabNormal) {
1392 system_->getCursorPosition(UNPACK2(cursor_grab_init_pos_));
1393 setCursorGrabAccum(0, 0);
1394
1395 if (mode == GHOST_kGrabHide) {
1397 }
1398 }
1399#ifdef GHOST_X11_GRAB
1400 XGrabPointer(display_,
1401 window_,
1402 False,
1403 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1404 GrabModeAsync,
1405 GrabModeAsync,
1406 None,
1407 None,
1408 CurrentTime);
1409#endif
1410 }
1411 else {
1413 system_->setCursorPosition(UNPACK2(cursor_grab_init_pos_));
1414 }
1415
1417 /* use to generate a mouse move event, otherwise the last event
1418 * blender gets can be outside the screen causing menus not to show
1419 * properly unless the user moves the mouse */
1420
1421#if defined(WITH_X11_XINPUT) && defined(USE_X11_XINPUT_WARP)
1422 if ((system_->xinput_version_.present) && (system_->xinput_version_.major_version >= 2)) {
1423 int device_id;
1424 if (XIGetClientPointer(display_, None, &device_id) != False) {
1425 XIWarpPointer(display_, device_id, None, None, 0, 0, 0, 0, 0, 0);
1426 }
1427 }
1428 else
1429#endif
1430 {
1431 XWarpPointer(display_, None, None, 0, 0, 0, 0, 0, 0);
1432 }
1433 }
1434
1435 /* Perform this last so to workaround XWayland bug, see: #53004. */
1438 }
1439
1440 /* Almost works without but important
1441 * otherwise the mouse GHOST location can be incorrect on exit. */
1442 setCursorGrabAccum(0, 0);
1443 cursor_grab_bounds_.l_ = cursor_grab_bounds_.r_ = -1; /* disable */
1444#ifdef GHOST_X11_GRAB
1445 XUngrabPointer(display_, CurrentTime);
1446#endif
1447 }
1448
1449 XFlush(display_);
1450
1451 return GHOST_kSuccess;
1452}
1453
1455{
1456 Cursor xcursor;
1457 if (getStandardCursor(shape, xcursor) == GHOST_kFailure) {
1458 getStandardCursor(GHOST_kStandardCursorDefault, xcursor);
1459 }
1460
1461 visible_cursor_ = xcursor;
1462
1463 XDefineCursor(display_, window_, xcursor);
1464 XFlush(display_);
1465
1466 return GHOST_kSuccess;
1467}
1468
1470{
1471 Cursor xcursor;
1472 return getStandardCursor(shape, xcursor);
1473}
1474
1476 const uint8_t *mask,
1477 const int size[2],
1478 const int hot_spot[2],
1479 bool /*can_invert_color*/)
1480{
1481 Colormap colormap = DefaultColormap(display_, visual_info_->screen);
1482 Pixmap bitmap_pix, mask_pix;
1483 XColor fg, bg;
1484
1485 if (XAllocNamedColor(display_, colormap, "White", &fg, &fg) == 0) {
1486 return GHOST_kFailure;
1487 }
1488 if (XAllocNamedColor(display_, colormap, "Black", &bg, &bg) == 0) {
1489 return GHOST_kFailure;
1490 }
1491
1492 if (custom_cursor_) {
1493 XFreeCursor(display_, custom_cursor_);
1494 }
1495
1496 bitmap_pix = XCreateBitmapFromData(display_, window_, (char *)bitmap, size[0], size[1]);
1497 mask_pix = XCreateBitmapFromData(display_, window_, (char *)mask, size[0], size[1]);
1498
1499 custom_cursor_ = XCreatePixmapCursor(
1500 display_, bitmap_pix, mask_pix, &fg, &bg, hot_spot[0], hot_spot[1]);
1501 XDefineCursor(display_, window_, custom_cursor_);
1502 XFlush(display_);
1503
1504 visible_cursor_ = custom_cursor_;
1505
1506 XFreePixmap(display_, bitmap_pix);
1507 XFreePixmap(display_, mask_pix);
1508
1509 XFreeColors(display_, colormap, &fg.pixel, 1, 0L);
1510 XFreeColors(display_, colormap, &bg.pixel, 1, 0L);
1511
1512 return GHOST_kSuccess;
1513}
1514
1516{
1517 /* Try to read DPI setting set using xrdb */
1518 char *resMan = XResourceManagerString(display_);
1519 if (resMan) {
1520 XrmDatabase xrdb = XrmGetStringDatabase(resMan);
1521 if (xrdb) {
1522 int dpi = -1;
1523 char *type = nullptr;
1524 XrmValue val;
1525
1526 int success = XrmGetResource(xrdb, "Xft.dpi", "Xft.Dpi", &type, &val);
1527 if (success && type) {
1528 if (STREQ(type, "String")) {
1529 dpi = atoi((const char *)val.addr);
1530 }
1531 }
1532 XrmDestroyDatabase(xrdb);
1533
1534 if (dpi != -1) {
1535 return dpi;
1536 }
1537 }
1538 }
1539
1540 /* Fall back to calculating DPI using X reported DPI, set using `xrandr --dpi`. */
1541 XWindowAttributes attr;
1542 if (!XGetWindowAttributes(display_, window_, &attr)) {
1543 /* Failed to get window attributes, return X11 default DPI */
1544 return 96;
1545 }
1546
1547 Screen *screen = attr.screen;
1548 int pixelWidth = WidthOfScreen(screen);
1549 int pixelHeight = HeightOfScreen(screen);
1550 int mmWidth = WidthMMOfScreen(screen);
1551 int mmHeight = HeightMMOfScreen(screen);
1552
1553 double pixelDiagonal = sqrt((pixelWidth * pixelWidth) + (pixelHeight * pixelHeight));
1554 double mmDiagonal = sqrt((mmWidth * mmWidth) + (mmHeight * mmHeight));
1555 float inchDiagonal = mmDiagonal * 0.039f;
1556 int dpi = pixelDiagonal / inchDiagonal;
1557 return dpi;
1558}
1559
1561{
1562 return GHOST_kFailure;
1563}
1564
void BLI_kdtree_nd_ free(KDTree *tree)
unsigned char uchar
unsigned long ulong
unsigned int uint
#define UNPACK2(a)
#define ARRAY_SIZE(arr)
#define ELEM(...)
#define STREQ(a, b)
#define GHOST_OPENGL_EGL_CONTEXT_FLAGS
#define GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY
#define GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY
#define GHOST_OPENGL_GLX_CONTEXT_FLAGS
#define Window
#define Display
#define GHOST_ASSERT(x, info)
#define GHOST_PRINT(x)
static const unsigned long BLENDER_ICONS_WM_X11[]
GHOST_TWindowState
@ GHOST_kWindowStateMinimized
@ GHOST_kWindowStateMaximized
@ GHOST_kWindowStateNormal
@ GHOST_kWindowStateFullScreen
GHOST_TStandardCursor
@ GHOST_kStandardCursorBottomLeftCorner
@ GHOST_kStandardCursorHelp
@ GHOST_kStandardCursorWait
@ GHOST_kStandardCursorTopSide
@ GHOST_kStandardCursorCrosshair
@ GHOST_kStandardCursorLeftRight
@ GHOST_kStandardCursorUpDown
@ GHOST_kStandardCursorBottomSide
@ GHOST_kStandardCursorTopLeftCorner
@ GHOST_kStandardCursorBottomRightCorner
@ GHOST_kStandardCursorDefault
@ GHOST_kStandardCursorRightSide
@ GHOST_kStandardCursorTopRightCorner
@ GHOST_kStandardCursorLeftSide
@ GHOST_kStandardCursorText
static const GHOST_TabletData GHOST_TABLET_DATA_NONE
GHOST_TDrawingContextType
GHOST_TWindowOrder
@ GHOST_kWindowOrderTop
@ GHOST_kWindowOrderBottom
GHOST_TSuccess
Definition GHOST_Types.h:57
@ GHOST_kFailure
Definition GHOST_Types.h:57
@ GHOST_kSuccess
Definition GHOST_Types.h:57
GHOST_TGrabCursorMode
@ GHOST_kGrabDisable
@ GHOST_kGrabHide
@ GHOST_kGrabNormal
@ GHOST_DialogError
#define _NET_WM_STATE_REMOVE
@ MWM_HINTS_DECORATIONS
@ MWM_HINTS_FUNCTIONS
#define HOST_NAME_MAX
@ MWM_FUNCTION_MINIMIZE
@ MWM_FUNCTION_RESIZE
@ MWM_FUNCTION_MAXIMIZE
@ MWM_FUNCTION_ALL
@ MWM_FUNCTION_MOVE
@ MWM_FUNCTION_CLOSE
#define _NET_WM_STATE_ADD
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
static bool getUseWindowFrame()
GHOST_TSuccess showMessageBox(const char *title, const char *message, const char *help_label, const char *continue_label, const char *link, GHOST_DialogOptions dialog_options) const override
GHOST_Context * newDrawingContext(GHOST_TDrawingContextType type) override
GHOST_WindowX11(GHOST_SystemX11 *system, Display *display, const char *title, int32_t left, int32_t top, uint32_t width, uint32_t height, GHOST_TWindowState state, GHOST_WindowX11 *parent_window, GHOST_TDrawingContextType type, const bool is_dialog, const GHOST_ContextParams &context_params, const bool exclusive, const GHOST_GPUDevice &preferred_device)
bool getValid() const override
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override
GHOST_TSuccess setClientHeight(uint32_t height) override
void getWindowBounds(GHOST_Rect &bounds) const override
~GHOST_WindowX11() override
GHOST_TSuccess setState(GHOST_TWindowState state) override
GHOST_TSuccess endProgressBar() override
void getClientBounds(GHOST_Rect &bounds) const override
void setTitle(const char *title) override
std::string getTitle() const override
GHOST_TSuccess setClientWidth(uint32_t width) override
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override
GHOST_TSuccess setProgressBar(float progress) override
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape) override
GHOST_TSuccess setClientSize(uint32_t width, uint32_t height) override
GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override
GHOST_TSuccess setWindowCursorVisibility(bool visible) override
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override
GHOST_TSuccess setWindowCustomCursorShape(const uint8_t *bitmap, const uint8_t *mask, const int size[2], const int hot_spot[2], bool can_invert_color) override
bool isDialog() const override
uint16_t getDPIHint() override
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override
GHOST_TSuccess invalidate() override
GHOST_TWindowState post_state_
GHOST_TSuccess setDialogHints(GHOST_WindowX11 *parent_window)
GHOST_TWindowState getState() const override
GHOST_ContextParams want_context_params_
void setCursorGrabAccum(int32_t x, int32_t y)
GHOST_TStandardCursor getCursorShape() const override
GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) override
int32_t cursor_grab_init_pos_[2]
GHOST_TSuccess releaseNativeHandles()
bool getValid() const override
GHOST_Window(uint32_t width, uint32_t height, GHOST_TWindowState state, const GHOST_ContextParams &context_params, const bool exclusive=false)
GHOST_Rect cursor_grab_bounds_
GHOST_WindowHDRInfo hdr_info_
GHOST_TGrabCursorMode cursor_grab_
uint top
#define sqrt
int count
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong state[N]
static int left
#define L
const char * name
return ret
i
Definition text_draw.cc:230
uint len
PointerRNA * ptr
Definition wm_files.cc:4238