BsLinuxWindow.cpp 18 KB

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