BsLinuxWindow.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Image/BsColor.h"
  4. #include "Image/BsPixelData.h"
  5. #include "BsLinuxWindow.h"
  6. #include "BsLinuxPlatform.h"
  7. #include "BsLinuxDropTarget.h"
  8. #include <X11/Xatom.h>
  9. #include <X11/extensions/Xrandr.h>
  10. #include <X11/Xutil.h>
  11. #include <X11/Xlib.h>
  12. #define _NET_WM_STATE_REMOVE 0
  13. #define _NET_WM_STATE_ADD 1
  14. #define _NET_WM_STATE_TOGGLE 2
  15. #define _NET_WM_MOVERESIZE_MOVE 8
  16. #define _NET_WM_MOVERESIZE_CANCEL 11
  17. #define WM_NormalState 1
  18. #define WM_IconicState 3
  19. namespace bs
  20. {
  21. enum class WindowState
  22. {
  23. Minimized,
  24. Maximized,
  25. Normal
  26. };
  27. struct LinuxWindow::Pimpl
  28. {
  29. ::Window xWindow = 0;
  30. INT32 x, y;
  31. UINT32 width, height;
  32. bool hasTitleBar = true;
  33. bool dragInProgress = false;
  34. bool resizeDisabled = false;
  35. WindowState state = WindowState::Normal;
  36. Vector<Rect2I> dragZones;
  37. void* userData = nullptr;
  38. };
  39. LinuxWindow::LinuxWindow(const WINDOW_DESC &desc)
  40. {
  41. m = bs_new<Pimpl>();
  42. ::Display* display = LinuxPlatform::getXDisplay();
  43. // Find the screen of the chosen monitor, as well as its current dimensions
  44. INT32 screen = XDefaultScreen(display);
  45. UINT32 outputIdx = 0;
  46. RROutput primaryOutput = XRRGetOutputPrimary(display, RootWindow(display, screen));
  47. INT32 monitorX = 0;
  48. INT32 monitorY = 0;
  49. UINT32 monitorWidth = 0;
  50. UINT32 monitorHeight = 0;
  51. INT32 screenCount = XScreenCount(display);
  52. for(INT32 i = 0; i < screenCount; i++)
  53. {
  54. XRRScreenResources* screenRes = XRRGetScreenResources(display, RootWindow(display, i));
  55. bool foundMonitor = false;
  56. for (INT32 j = 0; j < screenRes->noutput; j++)
  57. {
  58. XRROutputInfo* outputInfo = XRRGetOutputInfo(display, screenRes, screenRes->outputs[j]);
  59. if (outputInfo == nullptr || outputInfo->crtc == 0 || outputInfo->connection == RR_Disconnected)
  60. {
  61. XRRFreeOutputInfo(outputInfo);
  62. continue;
  63. }
  64. XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(display, screenRes, outputInfo->crtc);
  65. if (crtcInfo == nullptr)
  66. {
  67. XRRFreeCrtcInfo(crtcInfo);
  68. XRRFreeOutputInfo(outputInfo);
  69. continue;
  70. }
  71. if(desc.screen == (UINT32)-1)
  72. {
  73. if(screenRes->outputs[j] == primaryOutput)
  74. foundMonitor = true;
  75. }
  76. else
  77. foundMonitor = outputIdx == desc.screen;
  78. if(foundMonitor)
  79. {
  80. screen = i;
  81. monitorX = crtcInfo->x;
  82. monitorY = crtcInfo->y;
  83. monitorWidth = crtcInfo->width;
  84. monitorHeight = crtcInfo->height;
  85. foundMonitor = true;
  86. break;
  87. }
  88. }
  89. if(foundMonitor)
  90. break;
  91. }
  92. XSetWindowAttributes attributes;
  93. attributes.background_pixel = XWhitePixel(display, screen);
  94. attributes.border_pixel = XBlackPixel(display, screen);
  95. attributes.background_pixmap = 0;
  96. attributes.colormap = XCreateColormap(display,
  97. XRootWindow(display, screen),
  98. desc.visualInfo.visual,
  99. AllocNone);
  100. // If no position specified, center on the requested monitor
  101. if (desc.x == -1)
  102. m->x = monitorX + (monitorWidth - desc.width) / 2;
  103. else if (desc.screen != (UINT32)-1)
  104. m->x = monitorX + desc.x;
  105. else
  106. m->x = desc.x;
  107. if (desc.y == -1)
  108. m->y = monitorY + (monitorHeight - desc.height) / 2;
  109. else if (desc.screen != (UINT32)-1)
  110. m->y = monitorY + desc.y;
  111. else
  112. m->y = desc.y;
  113. m->width = desc.width;
  114. m->height = desc.height;
  115. m->xWindow = XCreateWindow(display,
  116. XRootWindow(display, screen),
  117. m->x, m->y,
  118. m->width, m->height,
  119. 0, desc.visualInfo.depth,
  120. InputOutput, desc.visualInfo.visual,
  121. CWBackPixel | CWBorderPixel | CWColormap | CWBackPixmap, &attributes);
  122. XStoreName(display, m->xWindow, desc.title.c_str());
  123. // Position/size might have (and usually will) get overridden by the WM, so re-apply them
  124. XSizeHints hints;
  125. hints.flags = PPosition | PSize;
  126. hints.x = m->x;
  127. hints.y = m->y;
  128. hints.width = m->width;
  129. hints.height = m->height;
  130. if(!desc.allowResize)
  131. {
  132. hints.flags |= PMinSize | PMaxSize;
  133. hints.min_height = desc.height;
  134. hints.max_height = desc.height;
  135. hints.min_width = desc.width;
  136. hints.max_width = desc.width;
  137. }
  138. XSetNormalHints(display, m->xWindow, &hints);
  139. setShowDecorations(desc.showDecorations);
  140. setIsModal(desc.modal);
  141. XClassHint* classHint = XAllocClassHint();
  142. classHint->res_class = (char*)"banshee3d";
  143. classHint->res_name = (char*)desc.title.c_str();
  144. XSetClassHint(display, m->xWindow, classHint);
  145. XFree(classHint);
  146. // Ensures the child window is always on top of the parent window
  147. if(desc.parent)
  148. XSetTransientForHint(display, m->xWindow, desc.parent);
  149. XSelectInput(display, m->xWindow,
  150. ExposureMask | FocusChangeMask |
  151. KeyPressMask | KeyReleaseMask |
  152. ButtonPressMask | ButtonReleaseMask |
  153. EnterWindowMask | LeaveWindowMask |
  154. PointerMotionMask | ButtonMotionMask |
  155. StructureNotifyMask | PropertyChangeMask
  156. );
  157. // Make sure we get the window delete message from WM, so we can clean up ourselves
  158. Atom atomDeleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", False);
  159. XSetWMProtocols(display, m->xWindow, &atomDeleteWindow, 1);
  160. // Enable drag and drop
  161. LinuxDragAndDrop::makeDNDAware(m->xWindow);
  162. // Set background image if assigned
  163. if(desc.background)
  164. {
  165. Pixmap pixmap = LinuxPlatform::createPixmap(*desc.background, (UINT32)desc.visualInfo.depth);
  166. XSetWindowBackgroundPixmap(display, m->xWindow, pixmap);
  167. XFreePixmap(display, pixmap);
  168. XSync(display, 0);
  169. }
  170. // Show the window (needs to happen after setting the background pixmap)
  171. if(!desc.hidden)
  172. XMapWindow(display, m->xWindow);
  173. if(!desc.showOnTaskBar)
  174. showOnTaskbar(false);
  175. m->hasTitleBar = desc.showDecorations;
  176. m->resizeDisabled = !desc.allowResize;
  177. LinuxPlatform::_registerWindow(m->xWindow, this);
  178. }
  179. LinuxWindow::~LinuxWindow()
  180. {
  181. if(m->xWindow != 0)
  182. _destroy();
  183. bs_delete(m);
  184. }
  185. void LinuxWindow::move(INT32 x, INT32 y)
  186. {
  187. m->x = x;
  188. m->y = y;
  189. XMoveWindow(LinuxPlatform::getXDisplay(), m->xWindow, x, y);
  190. }
  191. void LinuxWindow::resize(UINT32 width, UINT32 height)
  192. {
  193. // If resize is disabled on WM level, we need to force it
  194. if(m->resizeDisabled)
  195. {
  196. XSizeHints hints;
  197. hints.flags = PMinSize | PMaxSize;
  198. hints.min_height = height;
  199. hints.max_height = height;
  200. hints.min_width = width;
  201. hints.max_width = width;
  202. XSetNormalHints(LinuxPlatform::getXDisplay(), m->xWindow, &hints);
  203. }
  204. m->width = width;
  205. m->height = height;
  206. XResizeWindow(LinuxPlatform::getXDisplay(), m->xWindow, width, height);
  207. }
  208. void LinuxWindow::hide()
  209. {
  210. XUnmapWindow(LinuxPlatform::getXDisplay(), m->xWindow);
  211. }
  212. void LinuxWindow::show()
  213. {
  214. XMapWindow(LinuxPlatform::getXDisplay(), m->xWindow);
  215. XMoveResizeWindow(LinuxPlatform::getXDisplay(), m->xWindow, m->x, m->y, m->width, m->height);
  216. }
  217. void LinuxWindow::maximize()
  218. {
  219. maximize(true);
  220. }
  221. void LinuxWindow::minimize()
  222. {
  223. minimize(true);
  224. }
  225. void LinuxWindow::restore()
  226. {
  227. if(isMaximized())
  228. maximize(false);
  229. else if(isMinimized())
  230. minimize(false);
  231. }
  232. INT32 LinuxWindow::getLeft() const
  233. {
  234. INT32 x, y;
  235. ::Window child;
  236. XTranslateCoordinates(LinuxPlatform::getXDisplay(), m->xWindow, DefaultRootWindow(LinuxPlatform::getXDisplay()),
  237. 0, 0, &x, &y, &child);
  238. return x;
  239. }
  240. INT32 LinuxWindow::getTop() const
  241. {
  242. INT32 x, y;
  243. ::Window child;
  244. XTranslateCoordinates(LinuxPlatform::getXDisplay(), m->xWindow, DefaultRootWindow(LinuxPlatform::getXDisplay()),
  245. 0, 0, &x, &y, &child);
  246. return y;
  247. }
  248. UINT32 LinuxWindow::getWidth() const
  249. {
  250. XWindowAttributes xwa;
  251. XGetWindowAttributes(LinuxPlatform::getXDisplay(), m->xWindow, &xwa);
  252. return (UINT32)xwa.width;
  253. }
  254. UINT32 LinuxWindow::getHeight() const
  255. {
  256. XWindowAttributes xwa;
  257. XGetWindowAttributes(LinuxPlatform::getXDisplay(), m->xWindow, &xwa);
  258. return (UINT32)xwa.height;
  259. }
  260. Vector2I LinuxWindow::windowToScreenPos(const Vector2I& windowPos) const
  261. {
  262. Vector2I screenPos;
  263. ::Window child;
  264. XTranslateCoordinates(LinuxPlatform::getXDisplay(), m->xWindow, DefaultRootWindow(LinuxPlatform::getXDisplay()),
  265. windowPos.x, windowPos.y, &screenPos.x, &screenPos.y, &child);
  266. return screenPos;
  267. }
  268. Vector2I LinuxWindow::screenToWindowPos(const Vector2I& screenPos) const
  269. {
  270. Vector2I windowPos;
  271. ::Window child;
  272. XTranslateCoordinates(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), m->xWindow,
  273. screenPos.x, screenPos.y, &windowPos.x, &windowPos.y, &child);
  274. return windowPos;
  275. }
  276. void LinuxWindow::setIcon(const PixelData& data)
  277. {
  278. ::Display* display = LinuxPlatform::getXDisplay();
  279. // Set icon the old way using IconPixmapHint.
  280. Pixmap iconPixmap = LinuxPlatform::createPixmap(data, (UINT32)XDefaultDepth(display, XDefaultScreen(display)));
  281. XWMHints* hints = XAllocWMHints();
  282. hints->flags = IconPixmapHint;
  283. hints->icon_pixmap = iconPixmap;
  284. XSetWMHints(display, m->xWindow, hints);
  285. XFree(hints);
  286. XFreePixmap(display, iconPixmap);
  287. // Also try to set _NET_WM_ICON for modern window managers.
  288. // Although the property claims to use 32 bit, that actually means "long", i.e. 64 bit on 64 bit platforms.
  289. Vector<unsigned long> wmIconData(2 + data.getWidth() * data.getHeight(), 0);
  290. wmIconData[0] = data.getWidth();
  291. wmIconData[1] = data.getHeight();
  292. for (UINT32 y = 0; y < data.getHeight(); y++)
  293. for (UINT32 x = 0; x < data.getWidth(); x++)
  294. wmIconData[y * data.getWidth() + x + 2] = data.getColorAt(x, y).getAsARGB();
  295. Atom iconAtom = XInternAtom(display, "_NET_WM_ICON", False);
  296. Atom cardinalAtom = XInternAtom(display, "CARDINAL", False);
  297. XChangeProperty(display, m->xWindow, iconAtom, cardinalAtom, 32, PropModeReplace,
  298. (const unsigned char*) wmIconData.data(), wmIconData.size());
  299. XFlush(display);
  300. }
  301. void LinuxWindow::_destroy()
  302. {
  303. XUnmapWindow(LinuxPlatform::getXDisplay(), m->xWindow);
  304. XSync(LinuxPlatform::getXDisplay(), 0);
  305. XDestroyWindow(LinuxPlatform::getXDisplay(), m->xWindow);
  306. XSync(LinuxPlatform::getXDisplay(), 0);
  307. LinuxPlatform::_unregisterWindow(m->xWindow);
  308. m->xWindow = 0;
  309. }
  310. void LinuxWindow::_setDragZones(const Vector<Rect2I>& rects)
  311. {
  312. m->dragZones = rects;
  313. }
  314. void LinuxWindow::_dragStart(const XButtonEvent& event)
  315. {
  316. // Make sure to reset the flag since WM could have (and probably has) handled the drag end event, so we never
  317. // received _dragEnd() call.
  318. m->dragInProgress = false;
  319. // If window has a titlebar, custom drag zones aren't used
  320. if(m->hasTitleBar)
  321. return;
  322. for(auto& entry : m->dragZones)
  323. {
  324. if (entry.width == 0 || entry.height == 0)
  325. continue;
  326. if(entry.contains(Vector2I(event.x, event.y)))
  327. {
  328. XUngrabPointer(LinuxPlatform::getXDisplay(), 0L);
  329. XFlush(LinuxPlatform::getXDisplay());
  330. Atom wmMoveResize = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_MOVERESIZE", False);
  331. XEvent xev;
  332. memset(&xev, 0, sizeof(xev));
  333. xev.type = ClientMessage;
  334. xev.xclient.window = m->xWindow;
  335. xev.xclient.message_type = wmMoveResize;
  336. xev.xclient.format = 32;
  337. xev.xclient.data.l[0] = event.x_root;
  338. xev.xclient.data.l[1] = event.y_root;
  339. xev.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
  340. xev.xclient.data.l[3] = Button1;
  341. xev.xclient.data.l[4] = 0;
  342. XSendEvent(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), False,
  343. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  344. XSync(LinuxPlatform::getXDisplay(), 0);
  345. m->dragInProgress = true;
  346. return;
  347. }
  348. }
  349. return;
  350. }
  351. void LinuxWindow::_dragEnd()
  352. {
  353. // WM failed to end the drag, send the cancel drag event
  354. if(m->dragInProgress)
  355. {
  356. Atom wmMoveResize = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_MOVERESIZE", False);
  357. XEvent xev;
  358. memset(&xev, 0, sizeof(xev));
  359. xev.type = ClientMessage;
  360. xev.xclient.window = m->xWindow;
  361. xev.xclient.message_type = wmMoveResize;
  362. xev.xclient.format = 32;
  363. xev.xclient.data.l[0] = 0;
  364. xev.xclient.data.l[1] = 0;
  365. xev.xclient.data.l[2] = _NET_WM_MOVERESIZE_CANCEL;
  366. xev.xclient.data.l[3] = Button1;
  367. xev.xclient.data.l[4] = 0;
  368. XSendEvent(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), False,
  369. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  370. m->dragInProgress = false;
  371. }
  372. }
  373. ::Window LinuxWindow::_getXWindow() const
  374. {
  375. return m->xWindow;
  376. }
  377. void LinuxWindow::_setUserData(void* data)
  378. {
  379. m->userData = data;
  380. }
  381. void* LinuxWindow::_getUserData() const
  382. {
  383. return m->userData;
  384. }
  385. bool LinuxWindow::isMaximized() const
  386. {
  387. Atom wmState = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE", False);
  388. Atom type;
  389. INT32 format;
  390. uint64_t length;
  391. uint64_t remaining;
  392. uint8_t* data = nullptr;
  393. INT32 result = XGetWindowProperty(LinuxPlatform::getXDisplay(), m->xWindow, wmState,
  394. 0, 1024, False, XA_ATOM, &type, &format,
  395. &length, &remaining, &data);
  396. if (result == Success)
  397. {
  398. Atom* atoms = (Atom*)data;
  399. Atom wmMaxHorz = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE_MAXIMIZED_HORZ", False);
  400. Atom wmMaxVert = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE_MAXIMIZED_VERT", False);
  401. bool foundHorz = false;
  402. bool foundVert = false;
  403. for (UINT32 i = 0; i < length; i++)
  404. {
  405. if (atoms[i] == wmMaxHorz)
  406. foundHorz = true;
  407. if (atoms[i] == wmMaxVert)
  408. foundVert = true;
  409. if (foundVert && foundHorz)
  410. return true;
  411. }
  412. XFree(atoms);
  413. }
  414. return false;
  415. }
  416. bool LinuxWindow::isMinimized()
  417. {
  418. Atom wmState = XInternAtom(LinuxPlatform::getXDisplay(), "WM_STATE", True);
  419. Atom type;
  420. INT32 format;
  421. uint64_t length;
  422. uint64_t remaining;
  423. uint8_t* data = nullptr;
  424. INT32 result = XGetWindowProperty(LinuxPlatform::getXDisplay(), m->xWindow, wmState,
  425. 0, 1024, False, AnyPropertyType, &type, &format,
  426. &length, &remaining, &data);
  427. if(result == Success)
  428. {
  429. long* state = (long*) data;
  430. if(state[0] == WM_IconicState)
  431. return true;
  432. }
  433. return false;
  434. }
  435. void LinuxWindow::maximize(bool enable)
  436. {
  437. Atom wmState = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE", False);
  438. Atom wmMaxHorz = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE_MAXIMIZED_HORZ", False);
  439. Atom wmMaxVert = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE_MAXIMIZED_VERT", False);
  440. XEvent xev;
  441. memset(&xev, 0, sizeof(xev));
  442. xev.type = ClientMessage;
  443. xev.xclient.window = m->xWindow;
  444. xev.xclient.message_type = wmState;
  445. xev.xclient.format = 32;
  446. xev.xclient.data.l[0] = enable ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  447. xev.xclient.data.l[1] = wmMaxHorz;
  448. xev.xclient.data.l[2] = wmMaxVert;
  449. XSendEvent(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), False,
  450. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  451. }
  452. void LinuxWindow::minimize(bool enable)
  453. {
  454. XEvent xev;
  455. Atom wmChange = XInternAtom(LinuxPlatform::getXDisplay(), "WM_CHANGE_STATE", False);
  456. memset(&xev, 0, sizeof(xev));
  457. xev.type = ClientMessage;
  458. xev.xclient.window = m->xWindow;
  459. xev.xclient.message_type = wmChange;
  460. xev.xclient.format = 32;
  461. xev.xclient.data.l[0] = enable ? WM_IconicState : WM_NormalState;
  462. XSendEvent(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), False,
  463. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  464. }
  465. void LinuxWindow::showOnTaskbar(bool enable)
  466. {
  467. Atom wmState = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE", False);
  468. Atom wmSkipTaskbar = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", False);
  469. Atom wmSkipPager = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE_SKIP_PAGER", False);
  470. XEvent xev;
  471. memset(&xev, 0, sizeof(xev));
  472. xev.type = ClientMessage;
  473. xev.xclient.window = m->xWindow;
  474. xev.xclient.message_type = wmState;
  475. xev.xclient.format = 32;
  476. xev.xclient.data.l[0] = enable ? _NET_WM_STATE_REMOVE : _NET_WM_STATE_ADD;
  477. xev.xclient.data.l[1] = wmSkipTaskbar;
  478. XSendEvent(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), False,
  479. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  480. xev.xclient.data.l[1] = wmSkipPager;
  481. XSendEvent(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), False,
  482. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  483. XSync(LinuxPlatform::getXDisplay(), 0);
  484. }
  485. void LinuxWindow::_setFullscreen(bool fullscreen)
  486. {
  487. // Attempt to bypass compositor if switching to fullscreen
  488. if(fullscreen)
  489. {
  490. Atom wmBypassCompositor = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_BYPASS_COMPOSITOR", False);
  491. if (wmBypassCompositor)
  492. {
  493. static constexpr UINT32 enabled = 1;
  494. XChangeProperty(LinuxPlatform::getXDisplay(), m->xWindow, wmBypassCompositor,
  495. XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &enabled, 1);
  496. }
  497. }
  498. // Make the switch to fullscreen
  499. XEvent xev;
  500. Atom wmState = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE", False);
  501. Atom wmFullscreen = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE_FULLSCREEN", False);
  502. memset(&xev, 0, sizeof(xev));
  503. xev.type = ClientMessage;
  504. xev.xclient.window = m->xWindow;
  505. xev.xclient.message_type = wmState;
  506. xev.xclient.format = 32;
  507. xev.xclient.data.l[0] = fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  508. xev.xclient.data.l[1] = wmFullscreen;
  509. xev.xclient.data.l[2] = 0;
  510. XSendEvent(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), False,
  511. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  512. }
  513. void LinuxWindow::setShowDecorations(bool show)
  514. {
  515. static constexpr UINT32 MWM_HINTS_DECORATIONS = (1 << 1);
  516. struct MotifHints
  517. {
  518. UINT32 flags;
  519. UINT32 functions;
  520. UINT32 decorations;
  521. INT32 inputMode;
  522. UINT32 status;
  523. };
  524. if(show)
  525. return;
  526. MotifHints motifHints;
  527. motifHints.flags = MWM_HINTS_DECORATIONS;
  528. motifHints.decorations = 0;
  529. motifHints.functions = 0;
  530. motifHints.inputMode = 0;
  531. motifHints.status = 0;
  532. Atom wmHintsAtom = XInternAtom(LinuxPlatform::getXDisplay(), "_MOTIF_WM_HINTS", False);
  533. XChangeProperty(LinuxPlatform::getXDisplay(), m->xWindow,
  534. wmHintsAtom, wmHintsAtom,
  535. 32,
  536. PropModeReplace,
  537. (unsigned char *)&motifHints,
  538. 5);
  539. }
  540. void LinuxWindow::setIsModal(bool modal)
  541. {
  542. if(modal)
  543. {
  544. Atom wmState = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE", False);
  545. Atom wmValue = XInternAtom(LinuxPlatform::getXDisplay(), "_NET_WM_STATE_MODAL", False);
  546. XEvent xev;
  547. memset(&xev, 0, sizeof(xev));
  548. xev.type = ClientMessage;
  549. xev.xclient.window = m->xWindow;
  550. xev.xclient.message_type = wmState;
  551. xev.xclient.format = 32;
  552. xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
  553. xev.xclient.data.l[1] = wmValue;
  554. xev.xclient.data.l[2] = 0;
  555. xev.xclient.data.l[3] = 1;
  556. XSendEvent(LinuxPlatform::getXDisplay(), DefaultRootWindow(LinuxPlatform::getXDisplay()), False,
  557. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  558. }
  559. }
  560. }