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