Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

X11: replace SDL window and event handling with native xlib

  • Loading branch information...
commit 25decc32b273080fea8e47a60a09539b3f37220d 1 parent 5b6caeb
Joakim Plate authored
2  xbmc/Application.cpp
@@ -794,7 +794,7 @@ bool CApplication::CreateGUI()
794 794
795 795 uint32_t sdlFlags = 0;
796 796
797   -#if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)
  797 +#if (defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)) && !defined(HAS_GLX)
798 798 sdlFlags |= SDL_INIT_VIDEO;
799 799 #endif
800 800
4 xbmc/system.h
@@ -168,10 +168,14 @@
168 168 #ifndef HAS_SDL_OPENGL
169 169 #define HAS_SDL_OPENGL
170 170 #endif
  171 +#ifdef HAVE_X11
  172 +#define HAS_X11_WIN_EVENTS
  173 +#else
171 174 #define HAS_SDL_WIN_EVENTS
172 175 #else
173 176 #define HAS_LINUX_EVENTS
174 177 #endif
  178 +#endif
175 179 #define HAS_LINUX_NETWORK
176 180 #define HAS_LIRC
177 181 #ifdef HAVE_LIBPULSE
1  xbmc/windowing/Makefile
... ... @@ -1,6 +1,7 @@
1 1 SRCS=WinEventsSDL.cpp \
2 2 WinEventsLinux.cpp \
3 3 WinSystem.cpp \
  4 + WinEventsX11.cpp \
4 5
5 6 LIB=windowing.a
6 7
4 xbmc/windowing/WinEvents.h
@@ -58,6 +58,10 @@ class CWinEventsBase
58 58 #include "WinEventsSDL.h"
59 59 #define CWinEvents CWinEventsSDL
60 60
  61 +#elif defined(TARGET_LINUX) && defined(HAS_X11_WIN_EVENTS)
  62 +#include "WinEventsX11.h"
  63 +#define CWinEvents CWinEventsX11
  64 +
61 65 #elif defined(TARGET_LINUX) && defined(HAS_LINUX_EVENTS)
62 66 #include "WinEventsLinux.h"
63 67 #define CWinEvents CWinEventsLinux
673 xbmc/windowing/WinEventsX11.cpp
... ... @@ -0,0 +1,673 @@
  1 +/*
  2 +* Copyright (C) 2005-2012 Team XBMC
  3 +* http://www.xbmc.org
  4 +*
  5 +* This Program is free software; you can redistribute it and/or modify
  6 +* it under the terms of the GNU General Public License as published by
  7 +* the Free Software Foundation; either version 2, or (at your option)
  8 +* any later version.
  9 +*
  10 +* This Program is distributed in the hope that it will be useful,
  11 +* but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 +* GNU General Public License for more details.
  14 +*
  15 +* You should have received a copy of the GNU General Public License
  16 +* along with XBMC; see the file COPYING. If not, write to
  17 +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18 +* http://www.gnu.org/copyleft/gpl.html
  19 +*
  20 +*/
  21 +
  22 +#include "system.h"
  23 +
  24 +#ifdef HAS_X11_WIN_EVENTS
  25 +
  26 +#include "WinEvents.h"
  27 +#include "WinEventsX11.h"
  28 +#include "Application.h"
  29 +#include <X11/Xlib.h>
  30 +#include "X11/WinSystemX11GL.h"
  31 +#include "X11/keysymdef.h"
  32 +#include "X11/XF86keysym.h"
  33 +#include "utils/log.h"
  34 +#include "utils/CharsetConverter.h"
  35 +#include "guilib/GUIWindowManager.h"
  36 +#include "input/MouseStat.h"
  37 +
  38 +CWinEventsX11* CWinEventsX11::WinEvents = 0;
  39 +
  40 +static const uint32_t SymMappingsX11[][2] =
  41 +{
  42 + {XK_BackSpace, XBMCK_BACKSPACE}
  43 +, {XK_Tab, XBMCK_TAB}
  44 +, {XK_Clear, XBMCK_CLEAR}
  45 +, {XK_Return, XBMCK_RETURN}
  46 +, {XK_Pause, XBMCK_PAUSE}
  47 +, {XK_Escape, XBMCK_ESCAPE}
  48 +, {XK_Delete, XBMCK_DELETE}
  49 +// multi-media keys
  50 +, {XF86XK_Back, XBMCK_BROWSER_BACK}
  51 +, {XF86XK_Forward, XBMCK_BROWSER_FORWARD}
  52 +, {XF86XK_Refresh, XBMCK_BROWSER_REFRESH}
  53 +, {XF86XK_Stop, XBMCK_BROWSER_STOP}
  54 +, {XF86XK_Search, XBMCK_BROWSER_SEARCH}
  55 +, {XF86XK_Favorites, XBMCK_BROWSER_FAVORITES}
  56 +, {XF86XK_HomePage, XBMCK_BROWSER_HOME}
  57 +, {XF86XK_AudioMute, XBMCK_VOLUME_MUTE}
  58 +, {XF86XK_AudioLowerVolume, XBMCK_VOLUME_DOWN}
  59 +, {XF86XK_AudioRaiseVolume, XBMCK_VOLUME_UP}
  60 +, {XF86XK_AudioNext, XBMCK_MEDIA_NEXT_TRACK}
  61 +, {XF86XK_AudioPrev, XBMCK_MEDIA_PREV_TRACK}
  62 +, {XF86XK_AudioStop, XBMCK_MEDIA_STOP}
  63 +, {XF86XK_AudioPause, XBMCK_MEDIA_PLAY_PAUSE}
  64 +, {XF86XK_Mail, XBMCK_LAUNCH_MAIL}
  65 +, {XF86XK_Select, XBMCK_LAUNCH_MEDIA_SELECT}
  66 +, {XF86XK_Launch0, XBMCK_LAUNCH_APP1}
  67 +, {XF86XK_Launch1, XBMCK_LAUNCH_APP2}
  68 +, {XF86XK_WWW, XBMCK_LAUNCH_FILE_BROWSER}
  69 +, {XF86XK_AudioMedia, XBMCK_LAUNCH_MEDIA_CENTER }
  70 + // Numeric keypad
  71 +, {XK_KP_0, XBMCK_KP0}
  72 +, {XK_KP_1, XBMCK_KP1}
  73 +, {XK_KP_2, XBMCK_KP2}
  74 +, {XK_KP_3, XBMCK_KP3}
  75 +, {XK_KP_4, XBMCK_KP4}
  76 +, {XK_KP_5, XBMCK_KP5}
  77 +, {XK_KP_6, XBMCK_KP6}
  78 +, {XK_KP_7, XBMCK_KP7}
  79 +, {XK_KP_8, XBMCK_KP8}
  80 +, {XK_KP_9, XBMCK_KP9}
  81 +, {XK_KP_Separator, XBMCK_KP_PERIOD}
  82 +, {XK_KP_Divide, XBMCK_KP_DIVIDE}
  83 +, {XK_KP_Multiply, XBMCK_KP_MULTIPLY}
  84 +, {XK_KP_Subtract, XBMCK_KP_MINUS}
  85 +, {XK_KP_Add, XBMCK_KP_PLUS}
  86 +, {XK_KP_Enter, XBMCK_KP_ENTER}
  87 +, {XK_KP_Equal, XBMCK_KP_EQUALS}
  88 + // Arrows + Home/End pad
  89 +, {XK_Up, XBMCK_UP}
  90 +, {XK_Down, XBMCK_DOWN}
  91 +, {XK_Right, XBMCK_RIGHT}
  92 +, {XK_Left, XBMCK_LEFT}
  93 +, {XK_Insert, XBMCK_INSERT}
  94 +, {XK_Home, XBMCK_HOME}
  95 +, {XK_End, XBMCK_END}
  96 +, {XK_Page_Up, XBMCK_PAGEUP}
  97 +, {XK_Page_Down, XBMCK_PAGEDOWN}
  98 + // Function keys
  99 +, {XK_F1, XBMCK_F1}
  100 +, {XK_F2, XBMCK_F2}
  101 +, {XK_F3, XBMCK_F3}
  102 +, {XK_F4, XBMCK_F4}
  103 +, {XK_F5, XBMCK_F5}
  104 +, {XK_F6, XBMCK_F6}
  105 +, {XK_F7, XBMCK_F7}
  106 +, {XK_F8, XBMCK_F8}
  107 +, {XK_F9, XBMCK_F9}
  108 +, {XK_F10, XBMCK_F10}
  109 +, {XK_F11, XBMCK_F11}
  110 +, {XK_F12, XBMCK_F12}
  111 +, {XK_F13, XBMCK_F13}
  112 +, {XK_F14, XBMCK_F14}
  113 +, {XK_F15, XBMCK_F15}
  114 + // Key state modifier keys
  115 +, {XK_Num_Lock, XBMCK_NUMLOCK}
  116 +, {XK_Caps_Lock, XBMCK_CAPSLOCK}
  117 +, {XK_Scroll_Lock, XBMCK_SCROLLOCK}
  118 +, {XK_Shift_R, XBMCK_RSHIFT}
  119 +, {XK_Shift_L, XBMCK_LSHIFT}
  120 +, {XK_Control_R, XBMCK_RCTRL}
  121 +, {XK_Control_L, XBMCK_LCTRL}
  122 +, {XK_Alt_R, XBMCK_RALT}
  123 +, {XK_Alt_L, XBMCK_LALT}
  124 +, {XK_Meta_R, XBMCK_RMETA}
  125 +, {XK_Meta_L, XBMCK_LMETA}
  126 +, {XK_Super_L, XBMCK_LSUPER}
  127 +, {XK_Super_R, XBMCK_RSUPER}
  128 +, {XK_Mode_switch, XBMCK_MODE}
  129 +, {XK_Multi_key, XBMCK_COMPOSE}
  130 + // Miscellaneous function keys
  131 +, {XK_Help, XBMCK_HELP}
  132 +, {XK_Print, XBMCK_PRINT}
  133 +//, {0, XBMCK_SYSREQ}
  134 +, {XK_Break, XBMCK_BREAK}
  135 +, {XK_Menu, XBMCK_MENU}
  136 +, {XF86XK_PowerOff, XBMCK_POWER}
  137 +, {XK_EcuSign, XBMCK_EURO}
  138 +, {XK_Undo, XBMCK_UNDO}
  139 + /* Media keys */
  140 +, {XF86XK_Eject, XBMCK_EJECT}
  141 +, {XF86XK_Stop, XBMCK_STOP}
  142 +, {XF86XK_AudioRecord, XBMCK_RECORD}
  143 +, {XF86XK_AudioRewind, XBMCK_REWIND}
  144 +, {XF86XK_Phone, XBMCK_PHONE}
  145 +, {XF86XK_AudioPlay, XBMCK_PLAY}
  146 +, {XF86XK_AudioRandomPlay, XBMCK_SHUFFLE}
  147 +, {XF86XK_AudioForward, XBMCK_FASTFORWARD}
  148 +};
  149 +
  150 +
  151 +CWinEventsX11::CWinEventsX11()
  152 +{
  153 + m_display = 0;
  154 + m_window = 0;
  155 + m_keybuf = 0;
  156 + m_keybuf_len = 0;
  157 +}
  158 +
  159 +CWinEventsX11::~CWinEventsX11()
  160 +{
  161 + free(m_keybuf);
  162 + m_keybuf = 0;
  163 +
  164 + if (m_xic)
  165 + {
  166 + XUnsetICFocus(m_xic);
  167 + XDestroyIC(m_xic);
  168 + m_xic = 0;
  169 + }
  170 +
  171 + if (m_xim)
  172 + {
  173 + XCloseIM(m_xim);
  174 + m_xim = 0;
  175 + }
  176 +
  177 + m_symLookupTable.clear();
  178 +}
  179 +
  180 +bool CWinEventsX11::Init(Display *dpy, Window win)
  181 +{
  182 + if (WinEvents)
  183 + return true;
  184 +
  185 + WinEvents = new CWinEventsX11();
  186 + WinEvents->m_display = dpy;
  187 + WinEvents->m_window = win;
  188 + WinEvents->m_keybuf_len = 32*sizeof(char);
  189 + WinEvents->m_keybuf = (char*)malloc(WinEvents->m_keybuf_len);
  190 + WinEvents->m_keymodState = 0;
  191 + WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  192 + memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
  193 +
  194 + // open input method
  195 + char *old_locale = NULL, *old_modifiers = NULL;
  196 + char res_name[8];
  197 + const char *p;
  198 +
  199 + // set resource name to xbmc, not used
  200 + strcpy(res_name, "xbmc");
  201 +
  202 + // save current locale, this should be "C"
  203 + p = setlocale(LC_ALL, NULL);
  204 + if (p)
  205 + {
  206 + old_locale = (char*)malloc(strlen(p) +1);
  207 + strcpy(old_locale, p);
  208 + }
  209 + p = XSetLocaleModifiers(NULL);
  210 + if (p)
  211 + {
  212 + old_modifiers = (char*)malloc(strlen(p) +1);
  213 + strcpy(old_modifiers, p);
  214 + }
  215 +
  216 + // set users preferences and open input method
  217 + p = setlocale(LC_ALL, "");
  218 + XSetLocaleModifiers("");
  219 + WinEvents->m_xim = XOpenIM(WinEvents->m_display, NULL, res_name, res_name);
  220 +
  221 + // restore old locale
  222 + if (old_locale)
  223 + {
  224 + setlocale(LC_ALL, old_locale);
  225 + free(old_locale);
  226 + }
  227 + if (old_modifiers)
  228 + {
  229 + XSetLocaleModifiers(old_modifiers);
  230 + free(old_modifiers);
  231 + }
  232 +
  233 + WinEvents->m_xic = NULL;
  234 + if (WinEvents->m_xim)
  235 + {
  236 + WinEvents->m_xic = XCreateIC(WinEvents->m_xim,
  237 + XNClientWindow, WinEvents->m_window,
  238 + XNFocusWindow, WinEvents->m_window,
  239 + XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
  240 + XNResourceName, res_name,
  241 + XNResourceClass, res_name,
  242 + NULL);
  243 + }
  244 +
  245 + if (!WinEvents->m_xic)
  246 + CLog::Log(LOGWARNING,"CWinEventsX11::Init - no input method found");
  247 +
  248 + // build Keysym lookup table
  249 + for (unsigned int i = 0; i < sizeof(SymMappingsX11)/(2*sizeof(uint32_t)); ++i)
  250 + {
  251 + WinEvents->m_symLookupTable[SymMappingsX11[i][0]] = SymMappingsX11[i][1];
  252 + }
  253 +
  254 + return true;
  255 +}
  256 +
  257 +void CWinEventsX11::Quit()
  258 +{
  259 + if (!WinEvents)
  260 + return;
  261 +
  262 + delete WinEvents;
  263 + WinEvents = 0;
  264 +}
  265 +
  266 +bool CWinEventsX11::MessagePump()
  267 +{
  268 + if (!WinEvents)
  269 + return false;
  270 +
  271 + bool ret = false;
  272 + XEvent xevent;
  273 +
  274 + while (WinEvents && XPending(WinEvents->m_display))
  275 + {
  276 + memset(&xevent, 0, sizeof (XEvent));
  277 + XNextEvent(WinEvents->m_display, &xevent);
  278 +
  279 + // ignore events generated by auto-repeat
  280 + if (xevent.type == KeyRelease && XPending(WinEvents->m_display))
  281 + {
  282 + XEvent peekevent;
  283 + XPeekEvent(WinEvents->m_display, &peekevent);
  284 + if ((peekevent.type == KeyPress) &&
  285 + (peekevent.xkey.keycode == xevent.xkey.keycode) &&
  286 + ((peekevent.xkey.time - xevent.xkey.time) < 2))
  287 + {
  288 + XNextEvent(WinEvents->m_display, &peekevent);
  289 + continue;
  290 + }
  291 + }
  292 +
  293 + if (XFilterEvent(&xevent, None))
  294 + continue;
  295 +
  296 + switch (xevent.type)
  297 + {
  298 + case MapNotify:
  299 + {
  300 + g_application.m_AppActive = true;
  301 + break;
  302 + }
  303 +
  304 + case UnmapNotify:
  305 + {
  306 + g_application.m_AppActive = false;
  307 + break;
  308 + }
  309 +
  310 + case FocusIn:
  311 + {
  312 + if (WinEvents->m_xic)
  313 + XSetICFocus(WinEvents->m_xic);
  314 + g_application.m_AppFocused = true;
  315 + memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
  316 + WinEvents->m_keymodState = 0;
  317 + g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
  318 + break;
  319 + }
  320 +
  321 + case FocusOut:
  322 + {
  323 + if (WinEvents->m_xic)
  324 + XUnsetICFocus(WinEvents->m_xic);
  325 + g_application.m_AppFocused = false;
  326 + memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
  327 + g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
  328 + break;
  329 + }
  330 +
  331 + case Expose:
  332 + {
  333 + g_windowManager.MarkDirty();
  334 + break;
  335 + }
  336 +
  337 + case ConfigureNotify:
  338 + {
  339 + if (xevent.xconfigure.window != WinEvents->m_window)
  340 + break;
  341 +
  342 + /* find the last configure event in the queue */
  343 + while(XCheckTypedWindowEvent(WinEvents->m_display, WinEvents->m_window, ConfigureNotify, &xevent))
  344 + ;
  345 +
  346 + /* check for resize */
  347 + if((int)g_Windowing.GetWidth() != xevent.xconfigure.width
  348 + || (int)g_Windowing.GetHeight() != xevent.xconfigure.height)
  349 + {
  350 + XBMC_Event newEvent = {0};
  351 + newEvent.type = XBMC_VIDEORESIZE;
  352 + newEvent.resize.w = xevent.xconfigure.width;
  353 + newEvent.resize.h = xevent.xconfigure.height;
  354 + ret |= g_application.OnEvent(newEvent);
  355 + }
  356 +
  357 + /* check for move */
  358 + if(g_Windowing.GetLeft() != xevent.xconfigure.x
  359 + || g_Windowing.GetTop() != xevent.xconfigure.y)
  360 + {
  361 + XBMC_Event newEvent = {0};
  362 + newEvent.type = XBMC_VIDEOMOVE;
  363 + newEvent.move.x = xevent.xconfigure.x;
  364 + newEvent.move.y = xevent.xconfigure.y;
  365 + ret |= g_application.OnEvent(newEvent);
  366 + }
  367 +
  368 +
  369 + break;
  370 + }
  371 +
  372 + case ClientMessage:
  373 + {
  374 + if ((Atom)xevent.xclient.data.l[0] == WinEvents->m_wmDeleteMessage)
  375 + if (!g_application.m_bStop) g_application.getApplicationMessenger().Quit();
  376 + break;
  377 + }
  378 +
  379 + case KeyPress:
  380 + {
  381 + XBMC_Event newEvent;
  382 + memset(&newEvent, 0, sizeof(newEvent));
  383 + newEvent.type = XBMC_KEYDOWN;
  384 + KeySym xkeysym;
  385 +
  386 + // fallback if we have no IM
  387 + if (!WinEvents->m_xic)
  388 + {
  389 + static XComposeStatus state;
  390 + char keybuf[32];
  391 + xkeysym = XLookupKeysym(&xevent.xkey, 0);
  392 + newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
  393 + newEvent.key.keysym.scancode = xevent.xkey.keycode;
  394 + newEvent.key.state = xevent.xkey.state;
  395 + newEvent.key.type = xevent.xkey.type;
  396 + if (XLookupString(&xevent.xkey, keybuf, sizeof(keybuf), NULL, &state))
  397 + {
  398 + newEvent.key.keysym.unicode = keybuf[0];
  399 + }
  400 + ret |= ProcessKey(newEvent, 500);
  401 + break;
  402 + }
  403 +
  404 + Status status;
  405 + int len;
  406 + len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
  407 + WinEvents->m_keybuf, WinEvents->m_keybuf_len,
  408 + &xkeysym, &status);
  409 + if (status == XBufferOverflow)
  410 + {
  411 + WinEvents->m_keybuf_len = len;
  412 + WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, WinEvents->m_keybuf_len);
  413 + len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
  414 + WinEvents->m_keybuf, WinEvents->m_keybuf_len,
  415 + &xkeysym, &status);
  416 + }
  417 + switch (status)
  418 + {
  419 + case XLookupNone:
  420 + break;
  421 + case XLookupChars:
  422 + case XLookupBoth:
  423 + {
  424 + CStdString data(WinEvents->m_keybuf, len);
  425 + CStdStringW keys;
  426 + g_charsetConverter.utf8ToW(data, keys, false);
  427 +
  428 + if (keys.length() == 0)
  429 + {
  430 + break;
  431 + }
  432 +
  433 + for (unsigned int i = 0; i < keys.length() - 1; i++)
  434 + {
  435 + newEvent.key.keysym.sym = XBMCK_UNKNOWN;
  436 + newEvent.key.keysym.unicode = keys[i];
  437 + newEvent.key.state = xevent.xkey.state;
  438 + newEvent.key.type = xevent.xkey.type;
  439 + ret |= ProcessKey(newEvent, 500);
  440 + }
  441 + if (keys.length() > 0)
  442 + {
  443 + newEvent.key.keysym.scancode = xevent.xkey.keycode;
  444 + xkeysym = XLookupKeysym(&xevent.xkey, 0);
  445 + newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
  446 + newEvent.key.keysym.unicode = keys[keys.length() - 1];
  447 + newEvent.key.state = xevent.xkey.state;
  448 + newEvent.key.type = xevent.xkey.type;
  449 +
  450 + ret |= ProcessKey(newEvent, 500);
  451 + }
  452 + break;
  453 + }
  454 +
  455 + case XLookupKeySym:
  456 + {
  457 + newEvent.key.keysym.scancode = xevent.xkey.keycode;
  458 + newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
  459 + newEvent.key.state = xevent.xkey.state;
  460 + newEvent.key.type = xevent.xkey.type;
  461 + ret |= ProcessKey(newEvent, 500);
  462 + break;
  463 + }
  464 +
  465 + }// switch status
  466 + break;
  467 + } //KeyPress
  468 +
  469 + case KeyRelease:
  470 + {
  471 + XBMC_Event newEvent;
  472 + KeySym xkeysym;
  473 + memset(&newEvent, 0, sizeof(newEvent));
  474 + newEvent.type = XBMC_KEYUP;
  475 + xkeysym = XLookupKeysym(&xevent.xkey, 0);
  476 + newEvent.key.keysym.scancode = xevent.xkey.keycode;
  477 + newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
  478 + newEvent.key.state = xevent.xkey.state;
  479 + newEvent.key.type = xevent.xkey.type;
  480 + ret |= ProcessKey(newEvent, 0);
  481 + break;
  482 + }
  483 +
  484 + // lose mouse coverage
  485 + case LeaveNotify:
  486 + {
  487 + g_Mouse.SetActive(false);
  488 + break;
  489 + }
  490 +
  491 + case MotionNotify:
  492 + {
  493 + XBMC_Event newEvent;
  494 + memset(&newEvent, 0, sizeof(newEvent));
  495 + newEvent.type = XBMC_MOUSEMOTION;
  496 + newEvent.motion.xrel = (int16_t)xevent.xmotion.x_root;
  497 + newEvent.motion.yrel = (int16_t)xevent.xmotion.y_root;
  498 + newEvent.motion.x = (int16_t)xevent.xmotion.x;
  499 + newEvent.motion.y = (int16_t)xevent.xmotion.y;
  500 + ret |= g_application.OnEvent(newEvent);
  501 + break;
  502 + }
  503 +
  504 + case ButtonPress:
  505 + {
  506 + XBMC_Event newEvent;
  507 + memset(&newEvent, 0, sizeof(newEvent));
  508 + newEvent.type = XBMC_MOUSEBUTTONDOWN;
  509 + newEvent.button.button = (unsigned char)xevent.xbutton.button;
  510 + newEvent.button.state = XBMC_PRESSED;
  511 + newEvent.button.x = (int16_t)xevent.xbutton.x;
  512 + newEvent.button.y = (int16_t)xevent.xbutton.y;
  513 + ret |= g_application.OnEvent(newEvent);
  514 + break;
  515 + }
  516 +
  517 + case ButtonRelease:
  518 + {
  519 + XBMC_Event newEvent;
  520 + memset(&newEvent, 0, sizeof(newEvent));
  521 + newEvent.type = XBMC_MOUSEBUTTONUP;
  522 + newEvent.button.button = (unsigned char)xevent.xbutton.button;
  523 + newEvent.button.state = XBMC_RELEASED;
  524 + newEvent.button.x = (int16_t)xevent.xbutton.x;
  525 + newEvent.button.y = (int16_t)xevent.xbutton.y;
  526 + ret |= g_application.OnEvent(newEvent);
  527 + break;
  528 + }
  529 +
  530 + default:
  531 + {
  532 + break;
  533 + }
  534 + }// switch event.type
  535 + }// while
  536 +
  537 + ret |= ProcessKeyRepeat();
  538 +
  539 + return ret;
  540 +}
  541 +
  542 +bool CWinEventsX11::ProcessKey(XBMC_Event &event, int repeatDelay)
  543 +{
  544 + if (event.type == XBMC_KEYDOWN)
  545 + {
  546 + // check key modifiers
  547 + switch(event.key.keysym.sym)
  548 + {
  549 + case XBMCK_LSHIFT:
  550 + WinEvents->m_keymodState |= XBMCKMOD_LSHIFT;
  551 + break;
  552 + case XBMCK_RSHIFT:
  553 + WinEvents->m_keymodState |= XBMCKMOD_RSHIFT;
  554 + break;
  555 + case XBMCK_LCTRL:
  556 + WinEvents->m_keymodState |= XBMCKMOD_LCTRL;
  557 + break;
  558 + case XBMCK_RCTRL:
  559 + WinEvents->m_keymodState |= XBMCKMOD_RCTRL;
  560 + break;
  561 + case XBMCK_LALT:
  562 + WinEvents->m_keymodState |= XBMCKMOD_LALT;
  563 + break;
  564 + case XBMCK_RALT:
  565 + WinEvents->m_keymodState |= XBMCKMOD_RCTRL;
  566 + break;
  567 + case XBMCK_LMETA:
  568 + WinEvents->m_keymodState |= XBMCKMOD_LMETA;
  569 + break;
  570 + case XBMCK_RMETA:
  571 + WinEvents->m_keymodState |= XBMCKMOD_RMETA;
  572 + break;
  573 + case XBMCK_MODE:
  574 + WinEvents->m_keymodState |= XBMCKMOD_MODE;
  575 + break;
  576 + default:
  577 + break;
  578 + }
  579 + event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState;
  580 + memcpy(&(WinEvents->m_lastKey), &event, sizeof(event));
  581 + WinEvents->m_repeatKeyTimeout.Set(repeatDelay);
  582 +
  583 + bool ret = ProcessShortcuts(event);
  584 + if (ret)
  585 + return ret;
  586 + }
  587 + else if (event.type == XBMC_KEYUP)
  588 + {
  589 + switch(event.key.keysym.sym)
  590 + {
  591 + case XBMCK_LSHIFT:
  592 + WinEvents->m_keymodState &= ~XBMCKMOD_LSHIFT;
  593 + break;
  594 + case XBMCK_RSHIFT:
  595 + WinEvents->m_keymodState &= ~XBMCKMOD_RSHIFT;
  596 + break;
  597 + case XBMCK_LCTRL:
  598 + WinEvents->m_keymodState &= ~XBMCKMOD_LCTRL;
  599 + break;
  600 + case XBMCK_RCTRL:
  601 + WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL;
  602 + break;
  603 + case XBMCK_LALT:
  604 + WinEvents->m_keymodState &= ~XBMCKMOD_LALT;
  605 + break;
  606 + case XBMCK_RALT:
  607 + WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL;
  608 + break;
  609 + case XBMCK_LMETA:
  610 + WinEvents->m_keymodState &= ~XBMCKMOD_LMETA;
  611 + break;
  612 + case XBMCK_RMETA:
  613 + WinEvents->m_keymodState &= ~XBMCKMOD_RMETA;
  614 + break;
  615 + case XBMCK_MODE:
  616 + WinEvents->m_keymodState &= ~XBMCKMOD_MODE;
  617 + break;
  618 + default:
  619 + break;
  620 + }
  621 + event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState;
  622 + memset(&(WinEvents->m_lastKey), 0, sizeof(event));
  623 + }
  624 +
  625 + return g_application.OnEvent(event);
  626 +}
  627 +
  628 +bool CWinEventsX11::ProcessShortcuts(XBMC_Event& event)
  629 +{
  630 + if (event.key.keysym.mod & XBMCKMOD_ALT)
  631 + {
  632 + switch(event.key.keysym.sym)
  633 + {
  634 + case XBMCK_TAB: // ALT+TAB to minimize/hide
  635 + g_application.Minimize();
  636 + return true;
  637 +
  638 + default:
  639 + return false;
  640 + }
  641 + }
  642 + return false;
  643 +}
  644 +
  645 +bool CWinEventsX11::ProcessKeyRepeat()
  646 +{
  647 + if (WinEvents && (WinEvents->m_lastKey.type == XBMC_KEYDOWN))
  648 + {
  649 + if (WinEvents->m_repeatKeyTimeout.IsTimePast())
  650 + {
  651 + return ProcessKey(WinEvents->m_lastKey, 10);
  652 + }
  653 + }
  654 + return false;
  655 +}
  656 +
  657 +XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym)
  658 +{
  659 + // try direct mapping first
  660 + std::map<uint32_t, uint32_t>::iterator it;
  661 + it = WinEvents->m_symLookupTable.find(keysym);
  662 + if (it != WinEvents->m_symLookupTable.end())
  663 + {
  664 + return (XBMCKey)(it->second);
  665 + }
  666 +
  667 + // try ascii mappings
  668 + if (keysym>>8 == 0x00)
  669 + return (XBMCKey)(keysym & 0xFF);
  670 +
  671 + return (XBMCKey)keysym;
  672 +}
  673 +#endif
54 xbmc/windowing/WinEventsX11.h
... ... @@ -0,0 +1,54 @@
  1 +/*
  2 +* Copyright (C) 2005-2012 Team XBMC
  3 +* http://www.xbmc.org
  4 +*
  5 +* This Program is free software; you can redistribute it and/or modify
  6 +* it under the terms of the GNU General Public License as published by
  7 +* the Free Software Foundation; either version 2, or (at your option)
  8 +* any later version.
  9 +*
  10 +* This Program is distributed in the hope that it will be useful,
  11 +* but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 +* GNU General Public License for more details.
  14 +*
  15 +* You should have received a copy of the GNU General Public License
  16 +* along with XBMC; see the file COPYING. If not, write to
  17 +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18 +* http://www.gnu.org/copyleft/gpl.html
  19 +*
  20 +*/
  21 +#pragma once
  22 +
  23 +#include "WinEvents.h"
  24 +#include <X11/Xlib.h>
  25 +#include "threads/SystemClock.h"
  26 +#include <map>
  27 +
  28 +class CWinEventsX11 : public CWinEventsBase
  29 +{
  30 +public:
  31 + CWinEventsX11();
  32 + virtual ~CWinEventsX11();
  33 + static bool Init(Display *dpy, Window win);
  34 + static void Quit();
  35 + static bool MessagePump();
  36 +
  37 +protected:
  38 + static XBMCKey LookupXbmcKeySym(KeySym keysym);
  39 + static bool ProcessKey(XBMC_Event &event, int repeatDelay);
  40 + static bool ProcessKeyRepeat();
  41 + static bool ProcessShortcuts(XBMC_Event& event);
  42 + static CWinEventsX11 *WinEvents;
  43 + Display *m_display;
  44 + Window m_window;
  45 + Atom m_wmDeleteMessage;
  46 + char *m_keybuf;
  47 + size_t m_keybuf_len;
  48 + XIM m_xim;
  49 + XIC m_xic;
  50 + XBMC_Event m_lastKey;
  51 + XbmcThreads::EndTime m_repeatKeyTimeout;
  52 + std::map<uint32_t,uint32_t> m_symLookupTable;
  53 + int m_keymodState;
  54 +};
3  xbmc/windowing/WinSystem.h
@@ -91,6 +91,9 @@ class CWinSystemBase
91 91 // resolution interfaces
92 92 unsigned int GetWidth() { return m_nWidth; }
93 93 unsigned int GetHeight() { return m_nHeight; }
  94 + int GetLeft() { return m_nLeft; }
  95 + int GetTop() { return m_nTop; }
  96 +
94 97 virtual int GetNumScreens() { return 0; }
95 98 virtual int GetCurrentScreen() { return 0; }
96 99 bool IsFullScreen() { return m_bFullScreen; }
421 xbmc/windowing/X11/WinSystemX11.cpp
@@ -22,7 +22,6 @@
22 22
23 23 #ifdef HAS_GLX
24 24
25   -#include <SDL/SDL_syswm.h>
26 25 #include "WinSystemX11.h"
27 26 #include "settings/Settings.h"
28 27 #include "guilib/Texture.h"
@@ -32,6 +31,7 @@
32 31 #include <vector>
33 32 #include "threads/SingleLock.h"
34 33 #include <X11/Xlib.h>
  34 +#include <X11/Xatom.h>
35 35 #include "cores/VideoRenderers/RenderManager.h"
36 36 #include "utils/TimeUtils.h"
37 37
@@ -39,19 +39,22 @@
39 39 #include <X11/extensions/Xrandr.h>
40 40 #endif
41 41
  42 +#include "../WinEvents.h"
  43 +
42 44 using namespace std;
43 45
44 46 CWinSystemX11::CWinSystemX11() : CWinSystemBase()
45 47 {
46 48 m_eWindowSystem = WINDOW_SYSTEM_X11;
47 49 m_glContext = NULL;
48   - m_SDLSurface = NULL;
49 50 m_dpy = NULL;
  51 + m_visual = NULL;
50 52 m_glWindow = 0;
51 53 m_wmWindow = 0;
52 54 m_bWasFullScreenBeforeMinimize = false;
53 55 m_minimized = false;
54 56 m_dpyLostTime = 0;
  57 + m_invisibleCursor = 0;
55 58
56 59 XSetErrorHandler(XErrorHandler);
57 60 }
@@ -64,19 +67,11 @@ bool CWinSystemX11::InitWindowSystem()
64 67 {
65 68 if ((m_dpy = XOpenDisplay(NULL)))
66 69 {
  70 + if(!CWinSystemBase::InitWindowSystem())
  71 + return false;
67 72
68   - SDL_EnableUNICODE(1);
69   - // set repeat to 10ms to ensure repeat time < frame time
70   - // so that hold times can be reliably detected
71   - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 10);
72   -
73   - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
74   - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
75   - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
76   - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
77   - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
78   -
79   - return CWinSystemBase::InitWindowSystem();
  73 + UpdateResolutions();
  74 + return true;
80 75 }
81 76 else
82 77 CLog::Log(LOGERROR, "GLX Error: No Display found");
@@ -92,59 +87,115 @@ bool CWinSystemX11::DestroyWindowSystem()
92 87 g_xrandr.RestoreState();
93 88 #endif
94 89
95   - if (m_dpy)
  90 + if (m_visual)
96 91 {
97   - if (m_glContext)
98   - {
99   - glXMakeCurrent(m_dpy, None, NULL);
100   - glXDestroyContext(m_dpy, m_glContext);
101   - }
102   -
103   - m_glContext = 0;
104   -
105   - //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy
106   - //so instead we just let m_dpy die on exit
  92 + XFree(m_visual);
  93 + m_visual = NULL;
107 94 }
108 95
109   - // m_SDLSurface is free()'d by SDL_Quit().
  96 + if (m_dpy)
  97 + {
  98 + XCloseDisplay(m_dpy);
  99 + m_dpy = NULL;
  100 + }
110 101
111 102 return true;
112 103 }
113 104
  105 +/**
  106 + * @brief Allocate a cursor that won't be visible on the window
  107 + */
  108 +static Cursor AllocateInvisibleCursor(Display* dpy, Window wnd)
  109 +{
  110 + Pixmap bitmap;
  111 + XColor black = {0};
  112 + Cursor cursor;
  113 + static char data[] = { 0,0,0,0,0,0,0,0 };
  114 +
  115 + bitmap = XCreateBitmapFromData(dpy, wnd, data, 8, 8);
  116 + cursor = XCreatePixmapCursor(dpy, bitmap, bitmap,
  117 + &black, &black, 0, 0);
  118 + XFreePixmap(dpy, bitmap);
  119 + return cursor;
  120 +}
  121 +
  122 +
114 123 bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
115 124 {
116   - RESOLUTION_INFO& desktop = g_settings.m_ResInfo[RES_DESKTOP];
117 125
118   - if (fullScreen &&
119   - (res.iWidth != desktop.iWidth || res.iHeight != desktop.iHeight ||
120   - res.fRefreshRate != desktop.fRefreshRate || res.iScreen != desktop.iScreen))
  126 + if (m_wmWindow)
121 127 {
122   - //on the first call to SDL_SetVideoMode, SDL stores the current displaymode
123   - //SDL restores the displaymode on SDL_QUIT(), if we change the displaymode
124   - //before the first call to SDL_SetVideoMode, SDL changes the displaymode back
125   - //to the wrong mode on exit
126   -
127   - CLog::Log(LOGINFO, "CWinSystemX11::CreateNewWindow initializing to desktop resolution first");
128   - if (!SetFullScreen(true, desktop, false))
129   - return false;
  128 + OnLostDevice();
  129 + DestroyWindow();
130 130 }
131 131
132   - if(!SetFullScreen(fullScreen, res, false))
  132 + /* higher layer should have set m_visual */
  133 + if(m_visual == NULL)
  134 + {
  135 + CLog::Log(LOGERROR, "CWinSystemX11::CreateNewWindow - no visual setup");
133 136 return false;
  137 + }
134 138
135   - CBaseTexture* iconTexture = CTexture::LoadFromFile("special://xbmc/media/icon.png");
  139 + XSetWindowAttributes swa = {0};
136 140
137   - if (iconTexture)
138   - SDL_WM_SetIcon(SDL_CreateRGBSurfaceFrom(iconTexture->GetPixels(), iconTexture->GetWidth(), iconTexture->GetHeight(), 32, iconTexture->GetPitch(), 0xff0000, 0x00ff00, 0x0000ff, 0xff000000L), NULL);
139   - SDL_WM_SetCaption("XBMC Media Center", NULL);
140   - delete iconTexture;
  141 + swa.override_redirect = False;
  142 + swa.border_pixel = fullScreen ? 0 : 5;
141 143
142   - // register XRandR Events
143   -#if defined(HAS_XRANDR)
144   - int iReturn;
145   - XRRQueryExtension(m_dpy, &m_RREventBase, &iReturn);
146   - XRRSelectInput(m_dpy, m_wmWindow, RRScreenChangeNotifyMask);
147   -#endif
  144 + if(m_visual->visual == DefaultVisual(m_dpy, m_visual->screen))
  145 + swa.background_pixel = BlackPixel(m_dpy, m_visual->screen);
  146 +
  147 + swa.colormap = XCreateColormap(m_dpy, RootWindow(m_dpy, m_visual->screen), m_visual->visual, AllocNone);
  148 + swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask |
  149 + ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
  150 + PropertyChangeMask | StructureNotifyMask | KeymapStateMask |
  151 + EnterWindowMask | LeaveWindowMask | ExposureMask;
  152 +
  153 + m_wmWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, m_visual->screen),
  154 + 0, 0,
  155 + res.iWidth, res.iHeight,
  156 + 0, m_visual->depth,
  157 + InputOutput, m_visual->visual,
  158 + CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask,
  159 + &swa);
  160 +
  161 + if (fullScreen)
  162 + {
  163 + Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", False);
  164 + XChangeProperty(m_dpy, m_wmWindow, XInternAtom(m_dpy, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1);
  165 + }
  166 + else
  167 + XDeleteProperty(m_dpy, m_wmWindow, XInternAtom(m_dpy, "_NET_WM_STATE", False));
  168 +
  169 + m_invisibleCursor = AllocateInvisibleCursor(m_dpy, m_wmWindow);
  170 + XDefineCursor(m_dpy, m_wmWindow, m_invisibleCursor);
  171 +
  172 +
  173 + XWMHints wm_hints;
  174 + XTextProperty windowName, iconName;
  175 + const char* title = "XBMC Media Center";
  176 +
  177 + XStringListToTextProperty((char**)&title, 1, &windowName);
  178 + XStringListToTextProperty((char**)&title, 1, &iconName);
  179 + wm_hints.initial_state = NormalState;
  180 + wm_hints.input = True;
  181 + wm_hints.icon_pixmap = None;
  182 + wm_hints.flags = StateHint | IconPixmapHint | InputHint;
  183 +
  184 + XSetWMProperties(m_dpy, m_wmWindow, &windowName, &iconName,
  185 + NULL, 0, NULL, &wm_hints,
  186 + NULL);
  187 +
  188 + // register interest in the delete window message
  189 + Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False);
  190 + XSetWMProtocols(m_dpy, m_wmWindow, &wmDeleteMessage, 1);
  191 +
  192 + XMapRaised(m_dpy, m_wmWindow);
  193 + XSync(m_dpy, True);
  194 +
  195 + RefreshWindowState();
  196 +
  197 + //init X11 events
  198 + CWinEvents::Init(m_dpy, m_wmWindow);
148 199
149 200 m_bWindowCreated = true;
150 201 return true;
@@ -152,38 +203,55 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
152 203
153 204 bool CWinSystemX11::DestroyWindow()
154 205 {
  206 + if (m_glContext)
  207 + {
  208 + glFinish();
  209 + glXMakeCurrent(m_dpy, None, NULL);
  210 + }
  211 +
  212 + if (m_invisibleCursor)
  213 + {
  214 + XUndefineCursor(m_dpy, m_wmWindow);
  215 + XFreeCursor(m_dpy, m_invisibleCursor);
  216 + m_invisibleCursor = 0;
  217 + }
  218 +
  219 + CWinEvents::Quit();
  220 +
  221 + if(m_wmWindow)
  222 + {
  223 + XUnmapWindow(m_dpy, m_wmWindow);
  224 + XSync(m_dpy, True);
  225 + XDestroyWindow(m_dpy, m_wmWindow);
  226 + m_wmWindow = 0;
  227 + }
  228 +
155 229 return true;
156 230 }
157 231
158 232 bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
159 233 {
160   - if(m_nWidth == newWidth
161   - && m_nHeight == newHeight)
162   - return true;
  234 + RefreshWindowState();
163 235
164   - m_nWidth = newWidth;
165   - m_nHeight = newHeight;
  236 + if(newLeft < 0) newLeft = m_nLeft;
  237 + if(newTop < 0) newTop = m_nTop;
166 238
167   - int options = SDL_OPENGL;
168   - if (m_bFullScreen)
169   - options |= SDL_FULLSCREEN;
170   - else
171   - options |= SDL_RESIZABLE;
172   -
173   - if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options)))
  239 + /* check if we are already correct */
  240 + if(m_nWidth != newWidth
  241 + && m_nHeight != newHeight
  242 + && m_nLeft != newLeft
  243 + && m_nTop != newTop)
174 244 {
175   - RefreshGlxContext();
176   - return true;
  245 + XMoveResizeWindow(m_dpy, m_wmWindow, newLeft, newTop, newWidth, newHeight);
  246 + XSync(m_dpy, False);
  247 + RefreshWindowState();
177 248 }
178 249
179   - return false;
  250 + return true;
180 251 }
181 252
182 253 bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
183 254 {
184   - m_nWidth = res.iWidth;
185   - m_nHeight = res.iHeight;
186   - m_bFullScreen = fullScreen;
187 255
188 256 #if defined(HAS_XRANDR)
189 257 XOutput out;
@@ -203,23 +271,70 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
203 271 g_xrandr.RestoreState();
204 272 #endif
205 273
206   - int options = SDL_OPENGL;
207   - if (m_bFullScreen)
208   - options |= SDL_FULLSCREEN;
  274 +
  275 + XSetWindowAttributes attr = {0};
  276 + if(fullScreen)
  277 + attr.border_pixel = 0;
209 278 else
210   - options |= SDL_RESIZABLE;
  279 + attr.border_pixel = 5;
  280 + XChangeWindowAttributes(m_dpy, m_wmWindow, CWBorderPixel, &attr);
211 281
212   - if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options)))
213   - {
214   - if ((m_SDLSurface->flags & SDL_OPENGL) != SDL_OPENGL)
215   - CLog::Log(LOGERROR, "CWinSystemX11::SetFullScreen SDL_OPENGL not set, SDL_GetError:%s", SDL_GetError());
  282 + int x = 0, y = 0;
216 283
217   - RefreshGlxContext();
  284 + XWindowAttributes attr2;
  285 + XGetWindowAttributes(m_dpy, m_wmWindow, &attr2);
218 286
219   - return true;
  287 + Atom m_NET_WM_STATE = XInternAtom(m_dpy, "_NET_WM_STATE", False);
  288 + Atom m_NET_WM_STATE_FULLSCREEN = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True);
  289 + Atom m_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(m_dpy, "_NET_WM_STATE_MAXIMIZED_VERT", True);
  290 + Atom m_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(m_dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", True);
  291 +
  292 + if(m_NET_WM_STATE_FULLSCREEN)
  293 + {
  294 + if(attr2.map_state == IsUnmapped)
  295 + {
  296 + if(fullScreen)
  297 + XChangeProperty(m_dpy, m_wmWindow, m_NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *) &m_NET_WM_STATE_FULLSCREEN, 1);
  298 + else
  299 + XDeleteProperty(m_dpy, m_wmWindow, m_NET_WM_STATE);
  300 + }
  301 + else
  302 + {
  303 + XEvent e = {0};
  304 + e.xany.type = ClientMessage;
  305 + e.xclient.message_type = m_NET_WM_STATE;
  306 + e.xclient.display = m_dpy;
  307 + e.xclient.window = m_wmWindow;
  308 + e.xclient.format = 32;
  309 + if(fullScreen)
  310 + {
  311 + e.xclient.data.l[0] = 1; /* _NET_WM_STATE_ADD */
  312 + e.xclient.data.l[1] = m_NET_WM_STATE_FULLSCREEN;
  313 + }
  314 + else
  315 + {
  316 + e.xclient.data.l[0] = 0; /* _NET_WM_STATE_REMOVE */
  317 + e.xclient.data.l[1] = m_NET_WM_STATE_FULLSCREEN;
  318 + e.xclient.data.l[2] = m_NET_WM_STATE_MAXIMIZED_VERT;
  319 + e.xclient.data.l[3] = m_NET_WM_STATE_MAXIMIZED_HORZ;
  320 + }
  321 +
  322 + XSendEvent(m_dpy, RootWindow(m_dpy, m_visual->screen), False,
  323 + SubstructureNotifyMask | SubstructureRedirectMask, &e);
  324 + }
  325 + XSync(m_dpy, False);
220 326 }
221 327
222   - return false;
  328 + if(fullScreen)
  329 + XMoveResizeWindow(m_dpy, m_wmWindow, x, y, res.iWidth, res.iHeight);
  330 + else
  331 + XResizeWindow(m_dpy, m_wmWindow, res.iWidth, res.iHeight);
  332 + XSync(m_dpy, False);
  333 +
  334 + RefreshWindowState();
  335 +
  336 + m_bFullScreen = fullScreen;
  337 + return true;
223 338 }
224 339
225 340 void CWinSystemX11::UpdateResolutions()
@@ -296,124 +411,25 @@ void CWinSystemX11::UpdateResolutions()
296 411
297 412 }
298 413
299   -bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo)
  414 +void CWinSystemX11::RefreshWindowState()
300 415 {
301   - int value;
302   - if (glXGetConfig(m_dpy, vInfo, GLX_RGBA, &value) || !value)
303   - return false;
304   - if (glXGetConfig(m_dpy, vInfo, GLX_DOUBLEBUFFER, &value) || !value)
305   - return false;
306   - if (glXGetConfig(m_dpy, vInfo, GLX_RED_SIZE, &value) || value < 8)