SDL_x11window.c 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. #if SDL_VIDEO_DRIVER_X11
  20. #include "SDL_assert.h"
  21. #include "SDL_hints.h"
  22. #include "../SDL_sysvideo.h"
  23. #include "../SDL_pixels_c.h"
  24. #include "../../events/SDL_keyboard_c.h"
  25. #include "../../events/SDL_mouse_c.h"
  26. #include "SDL_x11video.h"
  27. #include "SDL_x11mouse.h"
  28. #include "SDL_x11shape.h"
  29. #include "SDL_x11xinput2.h"
  30. #if SDL_VIDEO_OPENGL_EGL
  31. #include "SDL_x11opengles.h"
  32. #endif
  33. #include "SDL_timer.h"
  34. #include "SDL_syswm.h"
  35. #include "SDL_assert.h"
  36. #define _NET_WM_STATE_REMOVE 0l
  37. #define _NET_WM_STATE_ADD 1l
  38. #define _NET_WM_STATE_TOGGLE 2l
  39. static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
  40. {
  41. return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
  42. }
  43. static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
  44. {
  45. return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
  46. }
  47. static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
  48. {
  49. return ev->type == ConfigureNotify && ev->xconfigure.window == *((Window*)win);
  50. }
  51. /*
  52. static Bool
  53. X11_XIfEventTimeout(Display *display, XEvent *event_return, Bool (*predicate)(), XPointer arg, int timeoutMS)
  54. {
  55. Uint32 start = SDL_GetTicks();
  56. while (!X11_XCheckIfEvent(display, event_return, predicate, arg)) {
  57. if (SDL_TICKS_PASSED(SDL_GetTicks(), start + timeoutMS)) {
  58. return False;
  59. }
  60. }
  61. return True;
  62. }
  63. */
  64. static SDL_bool
  65. X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
  66. {
  67. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  68. return (data->fswindow != 0);
  69. }
  70. static SDL_bool
  71. X11_IsWindowMapped(_THIS, SDL_Window * window)
  72. {
  73. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  74. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  75. XWindowAttributes attr;
  76. X11_XGetWindowAttributes(videodata->display, data->xwindow, &attr);
  77. if (attr.map_state != IsUnmapped) {
  78. return SDL_TRUE;
  79. } else {
  80. return SDL_FALSE;
  81. }
  82. }
  83. #if 0
  84. static SDL_bool
  85. X11_IsActionAllowed(SDL_Window *window, Atom action)
  86. {
  87. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  88. Atom _NET_WM_ALLOWED_ACTIONS = data->videodata->_NET_WM_ALLOWED_ACTIONS;
  89. Atom type;
  90. Display *display = data->videodata->display;
  91. int form;
  92. unsigned long remain;
  93. unsigned long len, i;
  94. Atom *list;
  95. SDL_bool ret = SDL_FALSE;
  96. if (X11_XGetWindowProperty(display, data->xwindow, _NET_WM_ALLOWED_ACTIONS, 0, 1024, False, XA_ATOM, &type, &form, &len, &remain, (unsigned char **)&list) == Success)
  97. {
  98. for (i=0; i<len; ++i)
  99. {
  100. if (list[i] == action) {
  101. ret = SDL_TRUE;
  102. break;
  103. }
  104. }
  105. X11_XFree(list);
  106. }
  107. return ret;
  108. }
  109. #endif /* 0 */
  110. void
  111. X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags)
  112. {
  113. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  114. Display *display = videodata->display;
  115. Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
  116. /* Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN; */
  117. Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
  118. Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
  119. Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
  120. Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
  121. Atom atoms[5];
  122. int count = 0;
  123. /* The window manager sets this property, we shouldn't set it.
  124. If we did, this would indicate to the window manager that we don't
  125. actually want to be mapped during X11_XMapRaised(), which would be bad.
  126. *
  127. if (flags & SDL_WINDOW_HIDDEN) {
  128. atoms[count++] = _NET_WM_STATE_HIDDEN;
  129. }
  130. */
  131. if (flags & SDL_WINDOW_INPUT_FOCUS) {
  132. atoms[count++] = _NET_WM_STATE_FOCUSED;
  133. }
  134. if (flags & SDL_WINDOW_MAXIMIZED) {
  135. atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
  136. atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
  137. }
  138. if (flags & SDL_WINDOW_FULLSCREEN) {
  139. atoms[count++] = _NET_WM_STATE_FULLSCREEN;
  140. }
  141. if (count > 0) {
  142. X11_XChangeProperty(display, xwindow, _NET_WM_STATE, XA_ATOM, 32,
  143. PropModeReplace, (unsigned char *)atoms, count);
  144. } else {
  145. X11_XDeleteProperty(display, xwindow, _NET_WM_STATE);
  146. }
  147. }
  148. Uint32
  149. X11_GetNetWMState(_THIS, Window xwindow)
  150. {
  151. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  152. Display *display = videodata->display;
  153. Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
  154. Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN;
  155. Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
  156. Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
  157. Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
  158. Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
  159. Atom actualType;
  160. int actualFormat;
  161. unsigned long i, numItems, bytesAfter;
  162. unsigned char *propertyValue = NULL;
  163. long maxLength = 1024;
  164. Uint32 flags = 0;
  165. if (X11_XGetWindowProperty(display, xwindow, _NET_WM_STATE,
  166. 0l, maxLength, False, XA_ATOM, &actualType,
  167. &actualFormat, &numItems, &bytesAfter,
  168. &propertyValue) == Success) {
  169. Atom *atoms = (Atom *) propertyValue;
  170. int maximized = 0;
  171. int fullscreen = 0;
  172. for (i = 0; i < numItems; ++i) {
  173. if (atoms[i] == _NET_WM_STATE_HIDDEN) {
  174. flags |= SDL_WINDOW_HIDDEN;
  175. } else if (atoms[i] == _NET_WM_STATE_FOCUSED) {
  176. flags |= SDL_WINDOW_INPUT_FOCUS;
  177. } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
  178. maximized |= 1;
  179. } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
  180. maximized |= 2;
  181. } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
  182. fullscreen = 1;
  183. }
  184. }
  185. if (maximized == 3) {
  186. flags |= SDL_WINDOW_MAXIMIZED;
  187. } else if (fullscreen == 1) {
  188. flags |= SDL_WINDOW_FULLSCREEN;
  189. }
  190. X11_XFree(propertyValue);
  191. }
  192. /* FIXME, check the size hints for resizable */
  193. /* flags |= SDL_WINDOW_RESIZABLE; */
  194. return flags;
  195. }
  196. static int
  197. SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
  198. {
  199. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  200. SDL_WindowData *data;
  201. int numwindows = videodata->numwindows;
  202. int windowlistlength = videodata->windowlistlength;
  203. SDL_WindowData **windowlist = videodata->windowlist;
  204. /* Allocate the window data */
  205. data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
  206. if (!data) {
  207. return SDL_OutOfMemory();
  208. }
  209. data->window = window;
  210. data->xwindow = w;
  211. #ifdef X_HAVE_UTF8_STRING
  212. if (SDL_X11_HAVE_UTF8 && videodata->im) {
  213. data->ic =
  214. X11_XCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
  215. XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
  216. XNResourceName, videodata->classname, XNResourceClass,
  217. videodata->classname, NULL);
  218. }
  219. #endif
  220. data->created = created;
  221. data->videodata = videodata;
  222. /* Associate the data with the window */
  223. if (numwindows < windowlistlength) {
  224. windowlist[numwindows] = data;
  225. videodata->numwindows++;
  226. } else {
  227. windowlist =
  228. (SDL_WindowData **) SDL_realloc(windowlist,
  229. (numwindows +
  230. 1) * sizeof(*windowlist));
  231. if (!windowlist) {
  232. SDL_free(data);
  233. return SDL_OutOfMemory();
  234. }
  235. windowlist[numwindows] = data;
  236. videodata->numwindows++;
  237. videodata->windowlistlength++;
  238. videodata->windowlist = windowlist;
  239. }
  240. /* Fill in the SDL window with the window data */
  241. {
  242. XWindowAttributes attrib;
  243. X11_XGetWindowAttributes(data->videodata->display, w, &attrib);
  244. window->x = attrib.x;
  245. window->y = attrib.y;
  246. window->w = attrib.width;
  247. window->h = attrib.height;
  248. if (attrib.map_state != IsUnmapped) {
  249. window->flags |= SDL_WINDOW_SHOWN;
  250. } else {
  251. window->flags &= ~SDL_WINDOW_SHOWN;
  252. }
  253. data->visual = attrib.visual;
  254. data->colormap = attrib.colormap;
  255. }
  256. window->flags |= X11_GetNetWMState(_this, w);
  257. {
  258. Window FocalWindow;
  259. int RevertTo=0;
  260. X11_XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo);
  261. if (FocalWindow==w)
  262. {
  263. window->flags |= SDL_WINDOW_INPUT_FOCUS;
  264. }
  265. if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  266. SDL_SetKeyboardFocus(data->window);
  267. }
  268. if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
  269. /* Tell x11 to clip mouse */
  270. }
  271. }
  272. /* All done! */
  273. window->driverdata = data;
  274. return 0;
  275. }
  276. static void
  277. SetWindowBordered(Display *display, int screen, Window window, SDL_bool border)
  278. {
  279. /*
  280. * this code used to check for KWM_WIN_DECORATION, but KDE hasn't
  281. * supported it for years and years. It now respects _MOTIF_WM_HINTS.
  282. * Gnome is similar: just use the Motif atom.
  283. */
  284. Atom WM_HINTS = X11_XInternAtom(display, "_MOTIF_WM_HINTS", True);
  285. if (WM_HINTS != None) {
  286. /* Hints used by Motif compliant window managers */
  287. struct
  288. {
  289. unsigned long flags;
  290. unsigned long functions;
  291. unsigned long decorations;
  292. long input_mode;
  293. unsigned long status;
  294. } MWMHints = {
  295. (1L << 1), 0, border ? 1 : 0, 0, 0
  296. };
  297. X11_XChangeProperty(display, window, WM_HINTS, WM_HINTS, 32,
  298. PropModeReplace, (unsigned char *) &MWMHints,
  299. sizeof(MWMHints) / 4);
  300. } else { /* set the transient hints instead, if necessary */
  301. X11_XSetTransientForHint(display, window, RootWindow(display, screen));
  302. }
  303. }
  304. int
  305. X11_CreateWindow(_THIS, SDL_Window * window)
  306. {
  307. SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  308. SDL_DisplayData *displaydata =
  309. (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  310. SDL_WindowData *windowdata;
  311. Display *display = data->display;
  312. int screen = displaydata->screen;
  313. Visual *visual;
  314. int depth;
  315. XSetWindowAttributes xattr;
  316. Window w;
  317. XSizeHints *sizehints;
  318. XWMHints *wmhints;
  319. XClassHint *classhints;
  320. const long _NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1;
  321. Atom _NET_WM_BYPASS_COMPOSITOR;
  322. Atom _NET_WM_WINDOW_TYPE;
  323. Atom _NET_WM_WINDOW_TYPE_NORMAL;
  324. Atom _NET_WM_PID;
  325. Atom XdndAware, xdnd_version = 5;
  326. Uint32 fevent = 0;
  327. #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_EGL
  328. if ((window->flags & SDL_WINDOW_OPENGL) &&
  329. !SDL_getenv("SDL_VIDEO_X11_VISUALID")) {
  330. XVisualInfo *vinfo = NULL;
  331. #if SDL_VIDEO_OPENGL_EGL
  332. if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
  333. #if SDL_VIDEO_OPENGL_GLX
  334. && ( !_this->gl_data || ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile )
  335. #endif
  336. ){
  337. vinfo = X11_GLES_GetVisual(_this, display, screen);
  338. } else
  339. #endif
  340. {
  341. #if SDL_VIDEO_OPENGL_GLX
  342. vinfo = X11_GL_GetVisual(_this, display, screen);
  343. #endif
  344. }
  345. if (!vinfo) {
  346. return -1;
  347. }
  348. visual = vinfo->visual;
  349. depth = vinfo->depth;
  350. X11_XFree(vinfo);
  351. } else
  352. #endif
  353. {
  354. visual = displaydata->visual;
  355. depth = displaydata->depth;
  356. }
  357. xattr.override_redirect = False;
  358. xattr.background_pixmap = None;
  359. xattr.border_pixel = 0;
  360. if (visual->class == DirectColor) {
  361. XColor *colorcells;
  362. int i;
  363. int ncolors;
  364. int rmax, gmax, bmax;
  365. int rmask, gmask, bmask;
  366. int rshift, gshift, bshift;
  367. xattr.colormap =
  368. X11_XCreateColormap(display, RootWindow(display, screen),
  369. visual, AllocAll);
  370. /* If we can't create a colormap, then we must die */
  371. if (!xattr.colormap) {
  372. return SDL_SetError("Could not create writable colormap");
  373. }
  374. /* OK, we got a colormap, now fill it in as best as we can */
  375. colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
  376. if (!colorcells) {
  377. return SDL_OutOfMemory();
  378. }
  379. ncolors = visual->map_entries;
  380. rmax = 0xffff;
  381. gmax = 0xffff;
  382. bmax = 0xffff;
  383. rshift = 0;
  384. rmask = visual->red_mask;
  385. while (0 == (rmask & 1)) {
  386. rshift++;
  387. rmask >>= 1;
  388. }
  389. gshift = 0;
  390. gmask = visual->green_mask;
  391. while (0 == (gmask & 1)) {
  392. gshift++;
  393. gmask >>= 1;
  394. }
  395. bshift = 0;
  396. bmask = visual->blue_mask;
  397. while (0 == (bmask & 1)) {
  398. bshift++;
  399. bmask >>= 1;
  400. }
  401. /* build the color table pixel values */
  402. for (i = 0; i < ncolors; i++) {
  403. Uint32 red = (rmax * i) / (ncolors - 1);
  404. Uint32 green = (gmax * i) / (ncolors - 1);
  405. Uint32 blue = (bmax * i) / (ncolors - 1);
  406. Uint32 rbits = (rmask * i) / (ncolors - 1);
  407. Uint32 gbits = (gmask * i) / (ncolors - 1);
  408. Uint32 bbits = (bmask * i) / (ncolors - 1);
  409. Uint32 pix =
  410. (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  411. colorcells[i].pixel = pix;
  412. colorcells[i].red = red;
  413. colorcells[i].green = green;
  414. colorcells[i].blue = blue;
  415. colorcells[i].flags = DoRed | DoGreen | DoBlue;
  416. }
  417. X11_XStoreColors(display, xattr.colormap, colorcells, ncolors);
  418. SDL_free(colorcells);
  419. } else {
  420. xattr.colormap =
  421. X11_XCreateColormap(display, RootWindow(display, screen),
  422. visual, AllocNone);
  423. }
  424. w = X11_XCreateWindow(display, RootWindow(display, screen),
  425. window->x, window->y, window->w, window->h,
  426. 0, depth, InputOutput, visual,
  427. (CWOverrideRedirect | CWBackPixmap | CWBorderPixel |
  428. CWColormap), &xattr);
  429. if (!w) {
  430. return SDL_SetError("Couldn't create window");
  431. }
  432. SetWindowBordered(display, screen, w,
  433. (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  434. sizehints = X11_XAllocSizeHints();
  435. /* Setup the normal size hints */
  436. sizehints->flags = 0;
  437. if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
  438. sizehints->min_width = sizehints->max_width = window->w;
  439. sizehints->min_height = sizehints->max_height = window->h;
  440. sizehints->flags |= (PMaxSize | PMinSize);
  441. }
  442. sizehints->x = window->x;
  443. sizehints->y = window->y;
  444. sizehints->flags |= USPosition;
  445. /* Setup the input hints so we get keyboard input */
  446. wmhints = X11_XAllocWMHints();
  447. wmhints->input = True;
  448. wmhints->flags = InputHint;
  449. /* Setup the class hints so we can get an icon (AfterStep) */
  450. classhints = X11_XAllocClassHint();
  451. classhints->res_name = data->classname;
  452. classhints->res_class = data->classname;
  453. /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
  454. X11_XSetWMProperties(display, w, NULL, NULL, NULL, 0, sizehints, wmhints, classhints);
  455. X11_XFree(sizehints);
  456. X11_XFree(wmhints);
  457. X11_XFree(classhints);
  458. /* Set the PID related to the window for the given hostname, if possible */
  459. if (data->pid > 0) {
  460. _NET_WM_PID = X11_XInternAtom(display, "_NET_WM_PID", False);
  461. X11_XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
  462. (unsigned char *)&data->pid, 1);
  463. }
  464. /* Set the window manager state */
  465. X11_SetNetWMState(_this, w, window->flags);
  466. /* Let the window manager know we're a "normal" window */
  467. _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
  468. _NET_WM_WINDOW_TYPE_NORMAL = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
  469. X11_XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
  470. PropModeReplace,
  471. (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
  472. _NET_WM_BYPASS_COMPOSITOR = X11_XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False);
  473. X11_XChangeProperty(display, w, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
  474. PropModeReplace,
  475. (unsigned char *)&_NET_WM_BYPASS_COMPOSITOR_HINT_ON, 1);
  476. {
  477. Atom protocols[] = {
  478. data->WM_DELETE_WINDOW, /* Allow window to be deleted by the WM */
  479. data->_NET_WM_PING, /* Respond so WM knows we're alive */
  480. };
  481. X11_XSetWMProtocols(display, w, protocols, sizeof (protocols) / sizeof (protocols[0]));
  482. }
  483. if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
  484. X11_XDestroyWindow(display, w);
  485. return -1;
  486. }
  487. windowdata = (SDL_WindowData *) window->driverdata;
  488. #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  489. if ((window->flags & SDL_WINDOW_OPENGL) &&
  490. _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
  491. #if SDL_VIDEO_OPENGL_GLX
  492. && ( !_this->gl_data || ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile )
  493. #endif
  494. ) {
  495. #if SDL_VIDEO_OPENGL_EGL
  496. if (!_this->egl_data) {
  497. X11_XDestroyWindow(display, w);
  498. return -1;
  499. }
  500. /* Create the GLES window surface */
  501. windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) w);
  502. if (windowdata->egl_surface == EGL_NO_SURFACE) {
  503. X11_XDestroyWindow(display, w);
  504. return SDL_SetError("Could not create GLES window surface");
  505. }
  506. #else
  507. return SDL_SetError("Could not create GLES window surface (no EGL support available)");
  508. #endif /* SDL_VIDEO_OPENGL_EGL */
  509. }
  510. #endif
  511. #ifdef X_HAVE_UTF8_STRING
  512. if (SDL_X11_HAVE_UTF8 && windowdata->ic) {
  513. X11_XGetICValues(windowdata->ic, XNFilterEvents, &fevent, NULL);
  514. }
  515. #endif
  516. X11_Xinput2SelectTouch(_this, window);
  517. X11_XSelectInput(display, w,
  518. (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
  519. ExposureMask | ButtonPressMask | ButtonReleaseMask |
  520. PointerMotionMask | KeyPressMask | KeyReleaseMask |
  521. PropertyChangeMask | StructureNotifyMask |
  522. KeymapStateMask | fevent));
  523. XdndAware = X11_XInternAtom(display, "XdndAware", False);
  524. X11_XChangeProperty(display, w, XdndAware, XA_ATOM, 32,
  525. PropModeReplace,
  526. (unsigned char*)&xdnd_version, 1);
  527. X11_XFlush(display);
  528. return 0;
  529. }
  530. int
  531. X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
  532. {
  533. Window w = (Window) data;
  534. window->title = X11_GetWindowTitle(_this, w);
  535. if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
  536. return -1;
  537. }
  538. return 0;
  539. }
  540. char *
  541. X11_GetWindowTitle(_THIS, Window xwindow)
  542. {
  543. SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  544. Display *display = data->display;
  545. int status, real_format;
  546. Atom real_type;
  547. unsigned long items_read, items_left;
  548. unsigned char *propdata;
  549. char *title = NULL;
  550. status = X11_XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
  551. 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
  552. &items_read, &items_left, &propdata);
  553. if (status == Success && propdata) {
  554. title = SDL_strdup(SDL_static_cast(char*, propdata));
  555. X11_XFree(propdata);
  556. } else {
  557. status = X11_XGetWindowProperty(display, xwindow, XA_WM_NAME,
  558. 0L, 8192L, False, XA_STRING, &real_type, &real_format,
  559. &items_read, &items_left, &propdata);
  560. if (status == Success && propdata) {
  561. title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
  562. } else {
  563. title = SDL_strdup("");
  564. }
  565. }
  566. return title;
  567. }
  568. void
  569. X11_SetWindowTitle(_THIS, SDL_Window * window)
  570. {
  571. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  572. Display *display = data->videodata->display;
  573. XTextProperty titleprop, iconprop;
  574. Status status;
  575. const char *title = window->title;
  576. const char *icon = NULL;
  577. #ifdef X_HAVE_UTF8_STRING
  578. Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
  579. Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
  580. #endif
  581. if (title != NULL) {
  582. char *title_locale = SDL_iconv_utf8_locale(title);
  583. if (!title_locale) {
  584. SDL_OutOfMemory();
  585. return;
  586. }
  587. status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
  588. SDL_free(title_locale);
  589. if (status) {
  590. X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
  591. X11_XFree(titleprop.value);
  592. }
  593. #ifdef X_HAVE_UTF8_STRING
  594. if (SDL_X11_HAVE_UTF8) {
  595. status =
  596. X11_Xutf8TextListToTextProperty(display, (char **) &title, 1,
  597. XUTF8StringStyle, &titleprop);
  598. if (status == Success) {
  599. X11_XSetTextProperty(display, data->xwindow, &titleprop,
  600. _NET_WM_NAME);
  601. X11_XFree(titleprop.value);
  602. }
  603. }
  604. #endif
  605. }
  606. if (icon != NULL) {
  607. char *icon_locale = SDL_iconv_utf8_locale(icon);
  608. if (!icon_locale) {
  609. SDL_OutOfMemory();
  610. return;
  611. }
  612. status = X11_XStringListToTextProperty(&icon_locale, 1, &iconprop);
  613. SDL_free(icon_locale);
  614. if (status) {
  615. X11_XSetTextProperty(display, data->xwindow, &iconprop,
  616. XA_WM_ICON_NAME);
  617. X11_XFree(iconprop.value);
  618. }
  619. #ifdef X_HAVE_UTF8_STRING
  620. if (SDL_X11_HAVE_UTF8) {
  621. status =
  622. X11_Xutf8TextListToTextProperty(display, (char **) &icon, 1,
  623. XUTF8StringStyle, &iconprop);
  624. if (status == Success) {
  625. X11_XSetTextProperty(display, data->xwindow, &iconprop,
  626. _NET_WM_ICON_NAME);
  627. X11_XFree(iconprop.value);
  628. }
  629. }
  630. #endif
  631. }
  632. X11_XFlush(display);
  633. }
  634. void
  635. X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
  636. {
  637. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  638. Display *display = data->videodata->display;
  639. Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
  640. if (icon) {
  641. int propsize;
  642. long *propdata;
  643. /* Set the _NET_WM_ICON property */
  644. SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
  645. propsize = 2 + (icon->w * icon->h);
  646. propdata = SDL_malloc(propsize * sizeof(long));
  647. if (propdata) {
  648. int x, y;
  649. Uint32 *src;
  650. long *dst;
  651. propdata[0] = icon->w;
  652. propdata[1] = icon->h;
  653. dst = &propdata[2];
  654. for (y = 0; y < icon->h; ++y) {
  655. src = (Uint32*)((Uint8*)icon->pixels + y * icon->pitch);
  656. for (x = 0; x < icon->w; ++x) {
  657. *dst++ = *src++;
  658. }
  659. }
  660. X11_XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
  661. 32, PropModeReplace, (unsigned char *) propdata,
  662. propsize);
  663. }
  664. SDL_free(propdata);
  665. } else {
  666. X11_XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
  667. }
  668. X11_XFlush(display);
  669. }
  670. void
  671. X11_SetWindowPosition(_THIS, SDL_Window * window)
  672. {
  673. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  674. Display *display = data->videodata->display;
  675. X11_XMoveWindow(display, data->xwindow, window->x, window->y);
  676. X11_XFlush(display);
  677. }
  678. void
  679. X11_SetWindowMinimumSize(_THIS, SDL_Window * window)
  680. {
  681. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  682. Display *display = data->videodata->display;
  683. if (window->flags & SDL_WINDOW_RESIZABLE) {
  684. XSizeHints *sizehints = X11_XAllocSizeHints();
  685. long userhints;
  686. X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
  687. sizehints->min_width = window->min_w;
  688. sizehints->min_height = window->min_h;
  689. sizehints->flags |= PMinSize;
  690. X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  691. X11_XFree(sizehints);
  692. /* See comment in X11_SetWindowSize. */
  693. X11_XResizeWindow(display, data->xwindow, window->w, window->h);
  694. X11_XMoveWindow(display, data->xwindow, window->x, window->y);
  695. X11_XRaiseWindow(display, data->xwindow);
  696. }
  697. X11_XFlush(display);
  698. }
  699. void
  700. X11_SetWindowMaximumSize(_THIS, SDL_Window * window)
  701. {
  702. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  703. Display *display = data->videodata->display;
  704. if (window->flags & SDL_WINDOW_RESIZABLE) {
  705. XSizeHints *sizehints = X11_XAllocSizeHints();
  706. long userhints;
  707. X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
  708. sizehints->max_width = window->max_w;
  709. sizehints->max_height = window->max_h;
  710. sizehints->flags |= PMaxSize;
  711. X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  712. X11_XFree(sizehints);
  713. /* See comment in X11_SetWindowSize. */
  714. X11_XResizeWindow(display, data->xwindow, window->w, window->h);
  715. X11_XMoveWindow(display, data->xwindow, window->x, window->y);
  716. X11_XRaiseWindow(display, data->xwindow);
  717. }
  718. X11_XFlush(display);
  719. }
  720. void
  721. X11_SetWindowSize(_THIS, SDL_Window * window)
  722. {
  723. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  724. Display *display = data->videodata->display;
  725. if (SDL_IsShapedWindow(window)) {
  726. X11_ResizeWindowShape(window);
  727. }
  728. if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
  729. /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the X11_XResizeWindow, thus
  730. we must set the size hints to adjust the window size. */
  731. XSizeHints *sizehints = X11_XAllocSizeHints();
  732. long userhints;
  733. X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
  734. sizehints->min_width = sizehints->max_width = window->w;
  735. sizehints->min_height = sizehints->max_height = window->h;
  736. sizehints->flags |= PMinSize | PMaxSize;
  737. X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  738. X11_XFree(sizehints);
  739. /* From Pierre-Loup:
  740. WMs each have their little quirks with that. When you change the
  741. size hints, they get a ConfigureNotify event with the
  742. WM_NORMAL_SIZE_HINTS Atom. They all save the hints then, but they
  743. don't all resize the window right away to enforce the new hints.
  744. Some of them resize only after:
  745. - A user-initiated move or resize
  746. - A code-initiated move or resize
  747. - Hiding & showing window (Unmap & map)
  748. The following move & resize seems to help a lot of WMs that didn't
  749. properly update after the hints were changed. We don't do a
  750. hide/show, because there are supposedly subtle problems with doing so
  751. and transitioning from windowed to fullscreen in Unity.
  752. */
  753. X11_XResizeWindow(display, data->xwindow, window->w, window->h);
  754. X11_XMoveWindow(display, data->xwindow, window->x, window->y);
  755. X11_XRaiseWindow(display, data->xwindow);
  756. } else {
  757. X11_XResizeWindow(display, data->xwindow, window->w, window->h);
  758. }
  759. X11_XFlush(display);
  760. }
  761. void
  762. X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
  763. {
  764. const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
  765. const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
  766. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  767. SDL_DisplayData *displaydata =
  768. (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  769. Display *display = data->videodata->display;
  770. XEvent event;
  771. SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
  772. X11_XFlush(display);
  773. X11_XIfEvent(display, &event, &isConfigureNotify, (XPointer)&data->xwindow);
  774. if (visible) {
  775. XWindowAttributes attr;
  776. do {
  777. X11_XSync(display, False);
  778. X11_XGetWindowAttributes(display, data->xwindow, &attr);
  779. } while (attr.map_state != IsViewable);
  780. if (focused) {
  781. X11_XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
  782. }
  783. }
  784. /* make sure these don't make it to the real event queue if they fired here. */
  785. X11_XSync(display, False);
  786. X11_XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
  787. X11_XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
  788. }
  789. void
  790. X11_ShowWindow(_THIS, SDL_Window * window)
  791. {
  792. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  793. Display *display = data->videodata->display;
  794. XEvent event;
  795. if (!X11_IsWindowMapped(_this, window)) {
  796. X11_XMapRaised(display, data->xwindow);
  797. /* Blocking wait for "MapNotify" event.
  798. * We use X11_XIfEvent because pXWindowEvent takes a mask rather than a type,
  799. * and XCheckTypedWindowEvent doesn't block */
  800. X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
  801. X11_XFlush(display);
  802. }
  803. }
  804. void
  805. X11_HideWindow(_THIS, SDL_Window * window)
  806. {
  807. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  808. SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  809. Display *display = data->videodata->display;
  810. XEvent event;
  811. if (X11_IsWindowMapped(_this, window)) {
  812. X11_XWithdrawWindow(display, data->xwindow, displaydata->screen);
  813. /* Blocking wait for "UnmapNotify" event */
  814. X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
  815. X11_XFlush(display);
  816. }
  817. }
  818. static void
  819. SetWindowActive(_THIS, SDL_Window * window)
  820. {
  821. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  822. SDL_DisplayData *displaydata =
  823. (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  824. Display *display = data->videodata->display;
  825. Atom _NET_ACTIVE_WINDOW = data->videodata->_NET_ACTIVE_WINDOW;
  826. if (X11_IsWindowMapped(_this, window)) {
  827. XEvent e;
  828. SDL_zero(e);
  829. e.xany.type = ClientMessage;
  830. e.xclient.message_type = _NET_ACTIVE_WINDOW;
  831. e.xclient.format = 32;
  832. e.xclient.window = data->xwindow;
  833. e.xclient.data.l[0] = 1; /* source indication. 1 = application */
  834. e.xclient.data.l[1] = CurrentTime;
  835. e.xclient.data.l[2] = 0;
  836. X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  837. SubstructureNotifyMask | SubstructureRedirectMask, &e);
  838. X11_XFlush(display);
  839. }
  840. }
  841. void
  842. X11_RaiseWindow(_THIS, SDL_Window * window)
  843. {
  844. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  845. Display *display = data->videodata->display;
  846. X11_XRaiseWindow(display, data->xwindow);
  847. SetWindowActive(_this, window);
  848. X11_XFlush(display);
  849. }
  850. static void
  851. SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
  852. {
  853. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  854. SDL_DisplayData *displaydata =
  855. (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  856. Display *display = data->videodata->display;
  857. Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
  858. Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
  859. Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
  860. if (maximized) {
  861. window->flags |= SDL_WINDOW_MAXIMIZED;
  862. } else {
  863. window->flags &= ~SDL_WINDOW_MAXIMIZED;
  864. }
  865. if (X11_IsWindowMapped(_this, window)) {
  866. XEvent e;
  867. SDL_zero(e);
  868. e.xany.type = ClientMessage;
  869. e.xclient.message_type = _NET_WM_STATE;
  870. e.xclient.format = 32;
  871. e.xclient.window = data->xwindow;
  872. e.xclient.data.l[0] =
  873. maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  874. e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
  875. e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
  876. e.xclient.data.l[3] = 0l;
  877. X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  878. SubstructureNotifyMask | SubstructureRedirectMask, &e);
  879. } else {
  880. X11_SetNetWMState(_this, data->xwindow, window->flags);
  881. }
  882. X11_XFlush(display);
  883. }
  884. void
  885. X11_MaximizeWindow(_THIS, SDL_Window * window)
  886. {
  887. SetWindowMaximized(_this, window, SDL_TRUE);
  888. }
  889. void
  890. X11_MinimizeWindow(_THIS, SDL_Window * window)
  891. {
  892. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  893. SDL_DisplayData *displaydata =
  894. (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  895. Display *display = data->videodata->display;
  896. X11_XIconifyWindow(display, data->xwindow, displaydata->screen);
  897. X11_XFlush(display);
  898. }
  899. void
  900. X11_RestoreWindow(_THIS, SDL_Window * window)
  901. {
  902. SetWindowMaximized(_this, window, SDL_FALSE);
  903. X11_ShowWindow(_this, window);
  904. SetWindowActive(_this, window);
  905. }
  906. /* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */
  907. static void
  908. X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  909. {
  910. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  911. SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  912. Display *display = data->videodata->display;
  913. Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
  914. Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
  915. if (X11_IsWindowMapped(_this, window)) {
  916. XEvent e;
  917. if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
  918. /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
  919. can be resized to the fullscreen resolution (or reset so we're not resizable again) */
  920. XSizeHints *sizehints = X11_XAllocSizeHints();
  921. long flags = 0;
  922. X11_XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
  923. /* set the resize flags on */
  924. if (fullscreen) {
  925. /* we are going fullscreen so turn the flags off */
  926. sizehints->flags &= ~(PMinSize | PMaxSize);
  927. } else {
  928. /* Reset the min/max width height to make the window non-resizable again */
  929. sizehints->flags |= PMinSize | PMaxSize;
  930. sizehints->min_width = sizehints->max_width = window->windowed.w;
  931. sizehints->min_height = sizehints->max_height = window->windowed.h;
  932. }
  933. X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  934. X11_XFree(sizehints);
  935. }
  936. SDL_zero(e);
  937. e.xany.type = ClientMessage;
  938. e.xclient.message_type = _NET_WM_STATE;
  939. e.xclient.format = 32;
  940. e.xclient.window = data->xwindow;
  941. e.xclient.data.l[0] =
  942. fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  943. e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
  944. e.xclient.data.l[3] = 0l;
  945. X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  946. SubstructureNotifyMask | SubstructureRedirectMask, &e);
  947. } else {
  948. Uint32 flags;
  949. flags = window->flags;
  950. if (fullscreen) {
  951. flags |= SDL_WINDOW_FULLSCREEN;
  952. } else {
  953. flags &= ~SDL_WINDOW_FULLSCREEN;
  954. }
  955. X11_SetNetWMState(_this, data->xwindow, flags);
  956. }
  957. if (data->visual->class == DirectColor) {
  958. if ( fullscreen ) {
  959. X11_XInstallColormap(display, data->colormap);
  960. } else {
  961. X11_XUninstallColormap(display, data->colormap);
  962. }
  963. }
  964. X11_XFlush(display);
  965. }
  966. /* This handles fullscreen itself, outside the Window Manager. */
  967. static void
  968. X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  969. {
  970. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  971. SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  972. Visual *visual = data->visual;
  973. Display *display = data->videodata->display;
  974. const int screen = displaydata->screen;
  975. Window root = RootWindow(display, screen);
  976. const int def_vis = (visual == DefaultVisual(display, screen));
  977. unsigned long xattrmask = 0;
  978. XSetWindowAttributes xattr;
  979. XEvent ev;
  980. SDL_Rect rect;
  981. if ( data->fswindow ) {
  982. return; /* already fullscreen, I hope. */
  983. }
  984. X11_GetDisplayBounds(_this, _display, &rect);
  985. SDL_zero(xattr);
  986. xattr.override_redirect = True;
  987. xattrmask |= CWOverrideRedirect;
  988. xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  989. xattrmask |= CWBackPixel;
  990. xattr.border_pixel = 0;
  991. xattrmask |= CWBorderPixel;
  992. xattr.colormap = data->colormap;
  993. xattrmask |= CWColormap;
  994. data->fswindow = X11_XCreateWindow(display, root,
  995. rect.x, rect.y, rect.w, rect.h, 0,
  996. displaydata->depth, InputOutput,
  997. visual, xattrmask, &xattr);
  998. X11_XSelectInput(display, data->fswindow, StructureNotifyMask);
  999. X11_XSetWindowBackground(display, data->fswindow, 0);
  1000. X11_XInstallColormap(display, data->colormap);
  1001. X11_XClearWindow(display, data->fswindow);
  1002. X11_XMapRaised(display, data->fswindow);
  1003. /* Make sure the fswindow is in view by warping mouse to the corner */
  1004. X11_XUngrabPointer(display, CurrentTime);
  1005. X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1006. /* Wait to be mapped, filter Unmap event out if it arrives. */
  1007. X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1008. X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1009. #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1010. if ( displaydata->use_vidmode ) {
  1011. X11_XF86VidModeLockModeSwitch(display, screen, True);
  1012. }
  1013. #endif
  1014. SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1015. /* Center actual window within our cover-the-screen window. */
  1016. X11_XReparentWindow(display, data->xwindow, data->fswindow,
  1017. (rect.w - window->w) / 2, (rect.h - window->h) / 2);
  1018. /* Move the mouse to the upper left to make sure it's on-screen */
  1019. X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1020. /* Center mouse in the fullscreen window. */
  1021. rect.x += (rect.w / 2);
  1022. rect.y += (rect.h / 2);
  1023. X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1024. /* Wait to be mapped, filter Unmap event out if it arrives. */
  1025. X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1026. X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1027. SDL_UpdateWindowGrab(window);
  1028. }
  1029. static void
  1030. X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1031. {
  1032. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1033. SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1034. Display *display = data->videodata->display;
  1035. const int screen = displaydata->screen;
  1036. Window root = RootWindow(display, screen);
  1037. Window fswindow = data->fswindow;
  1038. XEvent ev;
  1039. if (!data->fswindow) {
  1040. return; /* already not fullscreen, I hope. */
  1041. }
  1042. data->fswindow = None;
  1043. #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1044. if ( displaydata->use_vidmode ) {
  1045. X11_XF86VidModeLockModeSwitch(display, screen, False);
  1046. }
  1047. #endif
  1048. SDL_UpdateWindowGrab(window);
  1049. X11_XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1050. /* flush these events so they don't confuse normal event handling */
  1051. X11_XSync(display, False);
  1052. X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1053. X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1054. SetWindowBordered(display, screen, data->xwindow,
  1055. (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1056. X11_XWithdrawWindow(display, fswindow, screen);
  1057. /* Wait to be unmapped. */
  1058. X11_XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&fswindow);
  1059. X11_XDestroyWindow(display, fswindow);
  1060. }
  1061. void
  1062. X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1063. {
  1064. /* !!! FIXME: SDL_Hint? */
  1065. SDL_bool legacy = SDL_FALSE;
  1066. const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1067. if (env) {
  1068. legacy = SDL_atoi(env);
  1069. } else {
  1070. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1071. SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1072. if ( displaydata->use_vidmode ) {
  1073. legacy = SDL_TRUE; /* the new stuff only works with XRandR. */
  1074. } else if ( !videodata->net_wm ) {
  1075. legacy = SDL_TRUE; /* The window manager doesn't support it */
  1076. } else {
  1077. /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1078. /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1079. legacy = SDL_FALSE; /* try the new way. */
  1080. }
  1081. }
  1082. if (legacy) {
  1083. if (fullscreen) {
  1084. X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1085. } else {
  1086. X11_EndWindowFullscreenLegacy(_this, window, _display);
  1087. }
  1088. } else {
  1089. X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1090. }
  1091. }
  1092. int
  1093. X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1094. {
  1095. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1096. Display *display = data->videodata->display;
  1097. Visual *visual = data->visual;
  1098. Colormap colormap = data->colormap;
  1099. XColor *colorcells;
  1100. int ncolors;
  1101. int rmask, gmask, bmask;
  1102. int rshift, gshift, bshift;
  1103. int i;
  1104. if (visual->class != DirectColor) {
  1105. return SDL_SetError("Window doesn't have DirectColor visual");
  1106. }
  1107. ncolors = visual->map_entries;
  1108. colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1109. if (!colorcells) {
  1110. return SDL_OutOfMemory();
  1111. }
  1112. rshift = 0;
  1113. rmask = visual->red_mask;
  1114. while (0 == (rmask & 1)) {
  1115. rshift++;
  1116. rmask >>= 1;
  1117. }
  1118. gshift = 0;
  1119. gmask = visual->green_mask;
  1120. while (0 == (gmask & 1)) {
  1121. gshift++;
  1122. gmask >>= 1;
  1123. }
  1124. bshift = 0;
  1125. bmask = visual->blue_mask;
  1126. while (0 == (bmask & 1)) {
  1127. bshift++;
  1128. bmask >>= 1;
  1129. }
  1130. /* build the color table pixel values */
  1131. for (i = 0; i < ncolors; i++) {
  1132. Uint32 rbits = (rmask * i) / (ncolors - 1);
  1133. Uint32 gbits = (gmask * i) / (ncolors - 1);
  1134. Uint32 bbits = (bmask * i) / (ncolors - 1);
  1135. Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1136. colorcells[i].pixel = pix;
  1137. colorcells[i].red = ramp[(0 * 256) + i];
  1138. colorcells[i].green = ramp[(1 * 256) + i];
  1139. colorcells[i].blue = ramp[(2 * 256) + i];
  1140. colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1141. }
  1142. X11_XStoreColors(display, colormap, colorcells, ncolors);
  1143. X11_XFlush(display);
  1144. SDL_free(colorcells);
  1145. return 0;
  1146. }
  1147. void
  1148. X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1149. {
  1150. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1151. Display *display = data->videodata->display;
  1152. SDL_bool oldstyle_fullscreen;
  1153. SDL_bool grab_keyboard;
  1154. const char *hint;
  1155. /* ICCCM2.0-compliant window managers can handle fullscreen windows
  1156. If we're using XVidMode to change resolution we need to confine
  1157. the cursor so we don't pan around the virtual desktop.
  1158. */
  1159. oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1160. if (oldstyle_fullscreen || grabbed) {
  1161. /* Try to grab the mouse */
  1162. for (;;) {
  1163. int result =
  1164. X11_XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1165. GrabModeAsync, data->xwindow, None, CurrentTime);
  1166. if (result == GrabSuccess) {
  1167. break;
  1168. }
  1169. SDL_Delay(50);
  1170. }
  1171. /* Raise the window if we grab the mouse */
  1172. X11_XRaiseWindow(display, data->xwindow);
  1173. /* Now grab the keyboard */
  1174. hint = SDL_GetHint(SDL_HINT_GRAB_KEYBOARD);
  1175. if (hint && SDL_atoi(hint)) {
  1176. grab_keyboard = SDL_TRUE;
  1177. } else {
  1178. /* We need to do this with the old style override_redirect
  1179. fullscreen window otherwise we won't get keyboard focus.
  1180. */
  1181. grab_keyboard = oldstyle_fullscreen;
  1182. }
  1183. if (grab_keyboard) {
  1184. X11_XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1185. GrabModeAsync, CurrentTime);
  1186. }
  1187. } else {
  1188. X11_XUngrabPointer(display, CurrentTime);
  1189. X11_XUngrabKeyboard(display, CurrentTime);
  1190. }
  1191. X11_XSync(display, False);
  1192. }
  1193. void
  1194. X11_DestroyWindow(_THIS, SDL_Window * window)
  1195. {
  1196. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1197. window->driverdata = NULL;
  1198. if (data) {
  1199. SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1200. Display *display = videodata->display;
  1201. int numwindows = videodata->numwindows;
  1202. SDL_WindowData **windowlist = videodata->windowlist;
  1203. int i;
  1204. if (windowlist) {
  1205. for (i = 0; i < numwindows; ++i) {
  1206. if (windowlist[i] && (windowlist[i]->window == window)) {
  1207. windowlist[i] = windowlist[numwindows - 1];
  1208. windowlist[numwindows - 1] = NULL;
  1209. videodata->numwindows--;
  1210. break;
  1211. }
  1212. }
  1213. }
  1214. #ifdef X_HAVE_UTF8_STRING
  1215. if (data->ic) {
  1216. X11_XDestroyIC(data->ic);
  1217. }
  1218. #endif
  1219. if (data->created) {
  1220. X11_XDestroyWindow(display, data->xwindow);
  1221. X11_XFlush(display);
  1222. }
  1223. SDL_free(data);
  1224. }
  1225. }
  1226. SDL_bool
  1227. X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1228. {
  1229. SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1230. Display *display = data->videodata->display;
  1231. if (info->version.major == SDL_MAJOR_VERSION &&
  1232. info->version.minor == SDL_MINOR_VERSION) {
  1233. info->subsystem = SDL_SYSWM_X11;
  1234. info->info.x11.display = display;
  1235. info->info.x11.window = data->xwindow;
  1236. return SDL_TRUE;
  1237. } else {
  1238. SDL_SetError("Application not compiled with SDL %d.%d\n",
  1239. SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1240. return SDL_FALSE;
  1241. }
  1242. }
  1243. #endif /* SDL_VIDEO_DRIVER_X11 */
  1244. /* vi: set ts=4 sw=4 expandtab: */