Skip to content
Browse files

X11: replace SDL window and event handling with native xlib

  • Loading branch information...
1 parent 5b6caeb commit 25decc32b273080fea8e47a60a09539b3f37220d @elupus committed Jul 17, 2012
View
2 xbmc/Application.cpp
@@ -794,7 +794,7 @@ bool CApplication::CreateGUI()
uint32_t sdlFlags = 0;
-#if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)
+#if (defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)) && !defined(HAS_GLX)
sdlFlags |= SDL_INIT_VIDEO;
#endif
View
4 xbmc/system.h
@@ -168,10 +168,14 @@
#ifndef HAS_SDL_OPENGL
#define HAS_SDL_OPENGL
#endif
+#ifdef HAVE_X11
+#define HAS_X11_WIN_EVENTS
+#else
#define HAS_SDL_WIN_EVENTS
#else
#define HAS_LINUX_EVENTS
#endif
+#endif
#define HAS_LINUX_NETWORK
#define HAS_LIRC
#ifdef HAVE_LIBPULSE
View
1 xbmc/windowing/Makefile
@@ -1,6 +1,7 @@
SRCS=WinEventsSDL.cpp \
WinEventsLinux.cpp \
WinSystem.cpp \
+ WinEventsX11.cpp \
LIB=windowing.a
View
4 xbmc/windowing/WinEvents.h
@@ -58,6 +58,10 @@ class CWinEventsBase
#include "WinEventsSDL.h"
#define CWinEvents CWinEventsSDL
+#elif defined(TARGET_LINUX) && defined(HAS_X11_WIN_EVENTS)
+#include "WinEventsX11.h"
+#define CWinEvents CWinEventsX11
+
#elif defined(TARGET_LINUX) && defined(HAS_LINUX_EVENTS)
#include "WinEventsLinux.h"
#define CWinEvents CWinEventsLinux
View
673 xbmc/windowing/WinEventsX11.cpp
@@ -0,0 +1,673 @@
+/*
+* Copyright (C) 2005-2012 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#include "system.h"
+
+#ifdef HAS_X11_WIN_EVENTS
+
+#include "WinEvents.h"
+#include "WinEventsX11.h"
+#include "Application.h"
+#include <X11/Xlib.h>
+#include "X11/WinSystemX11GL.h"
+#include "X11/keysymdef.h"
+#include "X11/XF86keysym.h"
+#include "utils/log.h"
+#include "utils/CharsetConverter.h"
+#include "guilib/GUIWindowManager.h"
+#include "input/MouseStat.h"
+
+CWinEventsX11* CWinEventsX11::WinEvents = 0;
+
+static const uint32_t SymMappingsX11[][2] =
+{
+ {XK_BackSpace, XBMCK_BACKSPACE}
+, {XK_Tab, XBMCK_TAB}
+, {XK_Clear, XBMCK_CLEAR}
+, {XK_Return, XBMCK_RETURN}
+, {XK_Pause, XBMCK_PAUSE}
+, {XK_Escape, XBMCK_ESCAPE}
+, {XK_Delete, XBMCK_DELETE}
+// multi-media keys
+, {XF86XK_Back, XBMCK_BROWSER_BACK}
+, {XF86XK_Forward, XBMCK_BROWSER_FORWARD}
+, {XF86XK_Refresh, XBMCK_BROWSER_REFRESH}
+, {XF86XK_Stop, XBMCK_BROWSER_STOP}
+, {XF86XK_Search, XBMCK_BROWSER_SEARCH}
+, {XF86XK_Favorites, XBMCK_BROWSER_FAVORITES}
+, {XF86XK_HomePage, XBMCK_BROWSER_HOME}
+, {XF86XK_AudioMute, XBMCK_VOLUME_MUTE}
+, {XF86XK_AudioLowerVolume, XBMCK_VOLUME_DOWN}
+, {XF86XK_AudioRaiseVolume, XBMCK_VOLUME_UP}
+, {XF86XK_AudioNext, XBMCK_MEDIA_NEXT_TRACK}
+, {XF86XK_AudioPrev, XBMCK_MEDIA_PREV_TRACK}
+, {XF86XK_AudioStop, XBMCK_MEDIA_STOP}
+, {XF86XK_AudioPause, XBMCK_MEDIA_PLAY_PAUSE}
+, {XF86XK_Mail, XBMCK_LAUNCH_MAIL}
+, {XF86XK_Select, XBMCK_LAUNCH_MEDIA_SELECT}
+, {XF86XK_Launch0, XBMCK_LAUNCH_APP1}
+, {XF86XK_Launch1, XBMCK_LAUNCH_APP2}
+, {XF86XK_WWW, XBMCK_LAUNCH_FILE_BROWSER}
+, {XF86XK_AudioMedia, XBMCK_LAUNCH_MEDIA_CENTER }
+ // Numeric keypad
+, {XK_KP_0, XBMCK_KP0}
+, {XK_KP_1, XBMCK_KP1}
+, {XK_KP_2, XBMCK_KP2}
+, {XK_KP_3, XBMCK_KP3}
+, {XK_KP_4, XBMCK_KP4}
+, {XK_KP_5, XBMCK_KP5}
+, {XK_KP_6, XBMCK_KP6}
+, {XK_KP_7, XBMCK_KP7}
+, {XK_KP_8, XBMCK_KP8}
+, {XK_KP_9, XBMCK_KP9}
+, {XK_KP_Separator, XBMCK_KP_PERIOD}
+, {XK_KP_Divide, XBMCK_KP_DIVIDE}
+, {XK_KP_Multiply, XBMCK_KP_MULTIPLY}
+, {XK_KP_Subtract, XBMCK_KP_MINUS}
+, {XK_KP_Add, XBMCK_KP_PLUS}
+, {XK_KP_Enter, XBMCK_KP_ENTER}
+, {XK_KP_Equal, XBMCK_KP_EQUALS}
+ // Arrows + Home/End pad
+, {XK_Up, XBMCK_UP}
+, {XK_Down, XBMCK_DOWN}
+, {XK_Right, XBMCK_RIGHT}
+, {XK_Left, XBMCK_LEFT}
+, {XK_Insert, XBMCK_INSERT}
+, {XK_Home, XBMCK_HOME}
+, {XK_End, XBMCK_END}
+, {XK_Page_Up, XBMCK_PAGEUP}
+, {XK_Page_Down, XBMCK_PAGEDOWN}
+ // Function keys
+, {XK_F1, XBMCK_F1}
+, {XK_F2, XBMCK_F2}
+, {XK_F3, XBMCK_F3}
+, {XK_F4, XBMCK_F4}
+, {XK_F5, XBMCK_F5}
+, {XK_F6, XBMCK_F6}
+, {XK_F7, XBMCK_F7}
+, {XK_F8, XBMCK_F8}
+, {XK_F9, XBMCK_F9}
+, {XK_F10, XBMCK_F10}
+, {XK_F11, XBMCK_F11}
+, {XK_F12, XBMCK_F12}
+, {XK_F13, XBMCK_F13}
+, {XK_F14, XBMCK_F14}
+, {XK_F15, XBMCK_F15}
+ // Key state modifier keys
+, {XK_Num_Lock, XBMCK_NUMLOCK}
+, {XK_Caps_Lock, XBMCK_CAPSLOCK}
+, {XK_Scroll_Lock, XBMCK_SCROLLOCK}
+, {XK_Shift_R, XBMCK_RSHIFT}
+, {XK_Shift_L, XBMCK_LSHIFT}
+, {XK_Control_R, XBMCK_RCTRL}
+, {XK_Control_L, XBMCK_LCTRL}
+, {XK_Alt_R, XBMCK_RALT}
+, {XK_Alt_L, XBMCK_LALT}
+, {XK_Meta_R, XBMCK_RMETA}
+, {XK_Meta_L, XBMCK_LMETA}
+, {XK_Super_L, XBMCK_LSUPER}
+, {XK_Super_R, XBMCK_RSUPER}
+, {XK_Mode_switch, XBMCK_MODE}
+, {XK_Multi_key, XBMCK_COMPOSE}
+ // Miscellaneous function keys
+, {XK_Help, XBMCK_HELP}
+, {XK_Print, XBMCK_PRINT}
+//, {0, XBMCK_SYSREQ}
+, {XK_Break, XBMCK_BREAK}
+, {XK_Menu, XBMCK_MENU}
+, {XF86XK_PowerOff, XBMCK_POWER}
+, {XK_EcuSign, XBMCK_EURO}
+, {XK_Undo, XBMCK_UNDO}
+ /* Media keys */
+, {XF86XK_Eject, XBMCK_EJECT}
+, {XF86XK_Stop, XBMCK_STOP}
+, {XF86XK_AudioRecord, XBMCK_RECORD}
+, {XF86XK_AudioRewind, XBMCK_REWIND}
+, {XF86XK_Phone, XBMCK_PHONE}
+, {XF86XK_AudioPlay, XBMCK_PLAY}
+, {XF86XK_AudioRandomPlay, XBMCK_SHUFFLE}
+, {XF86XK_AudioForward, XBMCK_FASTFORWARD}
+};
+
+
+CWinEventsX11::CWinEventsX11()
+{
+ m_display = 0;
+ m_window = 0;
+ m_keybuf = 0;
+ m_keybuf_len = 0;
+}
+
+CWinEventsX11::~CWinEventsX11()
+{
+ free(m_keybuf);
+ m_keybuf = 0;
+
+ if (m_xic)
+ {
+ XUnsetICFocus(m_xic);
+ XDestroyIC(m_xic);
+ m_xic = 0;
+ }
+
+ if (m_xim)
+ {
+ XCloseIM(m_xim);
+ m_xim = 0;
+ }
+
+ m_symLookupTable.clear();
+}
+
+bool CWinEventsX11::Init(Display *dpy, Window win)
+{
+ if (WinEvents)
+ return true;
+
+ WinEvents = new CWinEventsX11();
+ WinEvents->m_display = dpy;
+ WinEvents->m_window = win;
+ WinEvents->m_keybuf_len = 32*sizeof(char);
+ WinEvents->m_keybuf = (char*)malloc(WinEvents->m_keybuf_len);
+ WinEvents->m_keymodState = 0;
+ WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
+
+ // open input method
+ char *old_locale = NULL, *old_modifiers = NULL;
+ char res_name[8];
+ const char *p;
+
+ // set resource name to xbmc, not used
+ strcpy(res_name, "xbmc");
+
+ // save current locale, this should be "C"
+ p = setlocale(LC_ALL, NULL);
+ if (p)
+ {
+ old_locale = (char*)malloc(strlen(p) +1);
+ strcpy(old_locale, p);
+ }
+ p = XSetLocaleModifiers(NULL);
+ if (p)
+ {
+ old_modifiers = (char*)malloc(strlen(p) +1);
+ strcpy(old_modifiers, p);
+ }
+
+ // set users preferences and open input method
+ p = setlocale(LC_ALL, "");
+ XSetLocaleModifiers("");
+ WinEvents->m_xim = XOpenIM(WinEvents->m_display, NULL, res_name, res_name);
+
+ // restore old locale
+ if (old_locale)
+ {
+ setlocale(LC_ALL, old_locale);
+ free(old_locale);
+ }
+ if (old_modifiers)
+ {
+ XSetLocaleModifiers(old_modifiers);
+ free(old_modifiers);
+ }
+
+ WinEvents->m_xic = NULL;
+ if (WinEvents->m_xim)
+ {
+ WinEvents->m_xic = XCreateIC(WinEvents->m_xim,
+ XNClientWindow, WinEvents->m_window,
+ XNFocusWindow, WinEvents->m_window,
+ XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
+ XNResourceName, res_name,
+ XNResourceClass, res_name,
+ NULL);
+ }
+
+ if (!WinEvents->m_xic)
+ CLog::Log(LOGWARNING,"CWinEventsX11::Init - no input method found");
+
+ // build Keysym lookup table
+ for (unsigned int i = 0; i < sizeof(SymMappingsX11)/(2*sizeof(uint32_t)); ++i)
+ {
+ WinEvents->m_symLookupTable[SymMappingsX11[i][0]] = SymMappingsX11[i][1];
+ }
+
+ return true;
+}
+
+void CWinEventsX11::Quit()
+{
+ if (!WinEvents)
+ return;
+
+ delete WinEvents;
+ WinEvents = 0;
+}
+
+bool CWinEventsX11::MessagePump()
+{
+ if (!WinEvents)
+ return false;
+
+ bool ret = false;
+ XEvent xevent;
+
+ while (WinEvents && XPending(WinEvents->m_display))
+ {
+ memset(&xevent, 0, sizeof (XEvent));
+ XNextEvent(WinEvents->m_display, &xevent);
+
+ // ignore events generated by auto-repeat
+ if (xevent.type == KeyRelease && XPending(WinEvents->m_display))
+ {
+ XEvent peekevent;
+ XPeekEvent(WinEvents->m_display, &peekevent);
+ if ((peekevent.type == KeyPress) &&
+ (peekevent.xkey.keycode == xevent.xkey.keycode) &&
+ ((peekevent.xkey.time - xevent.xkey.time) < 2))
+ {
+ XNextEvent(WinEvents->m_display, &peekevent);
+ continue;
+ }
+ }
+
+ if (XFilterEvent(&xevent, None))
+ continue;
+
+ switch (xevent.type)
+ {
+ case MapNotify:
+ {
+ g_application.m_AppActive = true;
+ break;
+ }
+
+ case UnmapNotify:
+ {
+ g_application.m_AppActive = false;
+ break;
+ }
+
+ case FocusIn:
+ {
+ if (WinEvents->m_xic)
+ XSetICFocus(WinEvents->m_xic);
+ g_application.m_AppFocused = true;
+ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
+ WinEvents->m_keymodState = 0;
+ g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
+ break;
+ }
+
+ case FocusOut:
+ {
+ if (WinEvents->m_xic)
+ XUnsetICFocus(WinEvents->m_xic);
+ g_application.m_AppFocused = false;
+ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
+ g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
+ break;
+ }
+
+ case Expose:
+ {
+ g_windowManager.MarkDirty();
+ break;
+ }
+
+ case ConfigureNotify:
+ {
+ if (xevent.xconfigure.window != WinEvents->m_window)
+ break;
+
+ /* find the last configure event in the queue */
+ while(XCheckTypedWindowEvent(WinEvents->m_display, WinEvents->m_window, ConfigureNotify, &xevent))
+ ;
+
+ /* check for resize */
+ if((int)g_Windowing.GetWidth() != xevent.xconfigure.width
+ || (int)g_Windowing.GetHeight() != xevent.xconfigure.height)
+ {
+ XBMC_Event newEvent = {0};
+ newEvent.type = XBMC_VIDEORESIZE;
+ newEvent.resize.w = xevent.xconfigure.width;
+ newEvent.resize.h = xevent.xconfigure.height;
+ ret |= g_application.OnEvent(newEvent);
+ }
+
+ /* check for move */
+ if(g_Windowing.GetLeft() != xevent.xconfigure.x
+ || g_Windowing.GetTop() != xevent.xconfigure.y)
+ {
+ XBMC_Event newEvent = {0};
+ newEvent.type = XBMC_VIDEOMOVE;
+ newEvent.move.x = xevent.xconfigure.x;
+ newEvent.move.y = xevent.xconfigure.y;
+ ret |= g_application.OnEvent(newEvent);
+ }
+
+
+ break;
+ }
+
+ case ClientMessage:
+ {
+ if ((Atom)xevent.xclient.data.l[0] == WinEvents->m_wmDeleteMessage)
+ if (!g_application.m_bStop) g_application.getApplicationMessenger().Quit();
+ break;
+ }
+
+ case KeyPress:
+ {
+ XBMC_Event newEvent;
+ memset(&newEvent, 0, sizeof(newEvent));
+ newEvent.type = XBMC_KEYDOWN;
+ KeySym xkeysym;
+
+ // fallback if we have no IM
+ if (!WinEvents->m_xic)
+ {
+ static XComposeStatus state;
+ char keybuf[32];
+ xkeysym = XLookupKeysym(&xevent.xkey, 0);
+ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
+ newEvent.key.keysym.scancode = xevent.xkey.keycode;
+ newEvent.key.state = xevent.xkey.state;
+ newEvent.key.type = xevent.xkey.type;
+ if (XLookupString(&xevent.xkey, keybuf, sizeof(keybuf), NULL, &state))
+ {
+ newEvent.key.keysym.unicode = keybuf[0];
+ }
+ ret |= ProcessKey(newEvent, 500);
+ break;
+ }
+
+ Status status;
+ int len;
+ len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
+ WinEvents->m_keybuf, WinEvents->m_keybuf_len,
+ &xkeysym, &status);
+ if (status == XBufferOverflow)
+ {
+ WinEvents->m_keybuf_len = len;
+ WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, WinEvents->m_keybuf_len);
+ len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
+ WinEvents->m_keybuf, WinEvents->m_keybuf_len,
+ &xkeysym, &status);
+ }
+ switch (status)
+ {
+ case XLookupNone:
+ break;
+ case XLookupChars:
+ case XLookupBoth:
+ {
+ CStdString data(WinEvents->m_keybuf, len);
+ CStdStringW keys;
+ g_charsetConverter.utf8ToW(data, keys, false);
+
+ if (keys.length() == 0)
+ {
+ break;
+ }
+
+ for (unsigned int i = 0; i < keys.length() - 1; i++)
+ {
+ newEvent.key.keysym.sym = XBMCK_UNKNOWN;
+ newEvent.key.keysym.unicode = keys[i];
+ newEvent.key.state = xevent.xkey.state;
+ newEvent.key.type = xevent.xkey.type;
+ ret |= ProcessKey(newEvent, 500);
+ }
+ if (keys.length() > 0)
+ {
+ newEvent.key.keysym.scancode = xevent.xkey.keycode;
+ xkeysym = XLookupKeysym(&xevent.xkey, 0);
+ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
+ newEvent.key.keysym.unicode = keys[keys.length() - 1];
+ newEvent.key.state = xevent.xkey.state;
+ newEvent.key.type = xevent.xkey.type;
+
+ ret |= ProcessKey(newEvent, 500);
+ }
+ break;
+ }
+
+ case XLookupKeySym:
+ {
+ newEvent.key.keysym.scancode = xevent.xkey.keycode;
+ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
+ newEvent.key.state = xevent.xkey.state;
+ newEvent.key.type = xevent.xkey.type;
+ ret |= ProcessKey(newEvent, 500);
+ break;
+ }
+
+ }// switch status
+ break;
+ } //KeyPress
+
+ case KeyRelease:
+ {
+ XBMC_Event newEvent;
+ KeySym xkeysym;
+ memset(&newEvent, 0, sizeof(newEvent));
+ newEvent.type = XBMC_KEYUP;
+ xkeysym = XLookupKeysym(&xevent.xkey, 0);
+ newEvent.key.keysym.scancode = xevent.xkey.keycode;
+ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
+ newEvent.key.state = xevent.xkey.state;
+ newEvent.key.type = xevent.xkey.type;
+ ret |= ProcessKey(newEvent, 0);
+ break;
+ }
+
+ // lose mouse coverage
+ case LeaveNotify:
+ {
+ g_Mouse.SetActive(false);
+ break;
+ }
+
+ case MotionNotify:
+ {
+ XBMC_Event newEvent;
+ memset(&newEvent, 0, sizeof(newEvent));
+ newEvent.type = XBMC_MOUSEMOTION;
+ newEvent.motion.xrel = (int16_t)xevent.xmotion.x_root;
+ newEvent.motion.yrel = (int16_t)xevent.xmotion.y_root;
+ newEvent.motion.x = (int16_t)xevent.xmotion.x;
+ newEvent.motion.y = (int16_t)xevent.xmotion.y;
+ ret |= g_application.OnEvent(newEvent);
+ break;
+ }
+
+ case ButtonPress:
+ {
+ XBMC_Event newEvent;
+ memset(&newEvent, 0, sizeof(newEvent));
+ newEvent.type = XBMC_MOUSEBUTTONDOWN;
+ newEvent.button.button = (unsigned char)xevent.xbutton.button;
+ newEvent.button.state = XBMC_PRESSED;
+ newEvent.button.x = (int16_t)xevent.xbutton.x;
+ newEvent.button.y = (int16_t)xevent.xbutton.y;
+ ret |= g_application.OnEvent(newEvent);
+ break;
+ }
+
+ case ButtonRelease:
+ {
+ XBMC_Event newEvent;
+ memset(&newEvent, 0, sizeof(newEvent));
+ newEvent.type = XBMC_MOUSEBUTTONUP;
+ newEvent.button.button = (unsigned char)xevent.xbutton.button;
+ newEvent.button.state = XBMC_RELEASED;
+ newEvent.button.x = (int16_t)xevent.xbutton.x;
+ newEvent.button.y = (int16_t)xevent.xbutton.y;
+ ret |= g_application.OnEvent(newEvent);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }// switch event.type
+ }// while
+
+ ret |= ProcessKeyRepeat();
+
+ return ret;
+}
+
+bool CWinEventsX11::ProcessKey(XBMC_Event &event, int repeatDelay)
+{
+ if (event.type == XBMC_KEYDOWN)
+ {
+ // check key modifiers
+ switch(event.key.keysym.sym)
+ {
+ case XBMCK_LSHIFT:
+ WinEvents->m_keymodState |= XBMCKMOD_LSHIFT;
+ break;
+ case XBMCK_RSHIFT:
+ WinEvents->m_keymodState |= XBMCKMOD_RSHIFT;
+ break;
+ case XBMCK_LCTRL:
+ WinEvents->m_keymodState |= XBMCKMOD_LCTRL;
+ break;
+ case XBMCK_RCTRL:
+ WinEvents->m_keymodState |= XBMCKMOD_RCTRL;
+ break;
+ case XBMCK_LALT:
+ WinEvents->m_keymodState |= XBMCKMOD_LALT;
+ break;
+ case XBMCK_RALT:
+ WinEvents->m_keymodState |= XBMCKMOD_RCTRL;
+ break;
+ case XBMCK_LMETA:
+ WinEvents->m_keymodState |= XBMCKMOD_LMETA;
+ break;
+ case XBMCK_RMETA:
+ WinEvents->m_keymodState |= XBMCKMOD_RMETA;
+ break;
+ case XBMCK_MODE:
+ WinEvents->m_keymodState |= XBMCKMOD_MODE;
+ break;
+ default:
+ break;
+ }
+ event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState;
+ memcpy(&(WinEvents->m_lastKey), &event, sizeof(event));
+ WinEvents->m_repeatKeyTimeout.Set(repeatDelay);
+
+ bool ret = ProcessShortcuts(event);
+ if (ret)
+ return ret;
+ }
+ else if (event.type == XBMC_KEYUP)
+ {
+ switch(event.key.keysym.sym)
+ {
+ case XBMCK_LSHIFT:
+ WinEvents->m_keymodState &= ~XBMCKMOD_LSHIFT;
+ break;
+ case XBMCK_RSHIFT:
+ WinEvents->m_keymodState &= ~XBMCKMOD_RSHIFT;
+ break;
+ case XBMCK_LCTRL:
+ WinEvents->m_keymodState &= ~XBMCKMOD_LCTRL;
+ break;
+ case XBMCK_RCTRL:
+ WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL;
+ break;
+ case XBMCK_LALT:
+ WinEvents->m_keymodState &= ~XBMCKMOD_LALT;
+ break;
+ case XBMCK_RALT:
+ WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL;
+ break;
+ case XBMCK_LMETA:
+ WinEvents->m_keymodState &= ~XBMCKMOD_LMETA;
+ break;
+ case XBMCK_RMETA:
+ WinEvents->m_keymodState &= ~XBMCKMOD_RMETA;
+ break;
+ case XBMCK_MODE:
+ WinEvents->m_keymodState &= ~XBMCKMOD_MODE;
+ break;
+ default:
+ break;
+ }
+ event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState;
+ memset(&(WinEvents->m_lastKey), 0, sizeof(event));
+ }
+
+ return g_application.OnEvent(event);
+}
+
+bool CWinEventsX11::ProcessShortcuts(XBMC_Event& event)
+{
+ if (event.key.keysym.mod & XBMCKMOD_ALT)
+ {
+ switch(event.key.keysym.sym)
+ {
+ case XBMCK_TAB: // ALT+TAB to minimize/hide
+ g_application.Minimize();
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+bool CWinEventsX11::ProcessKeyRepeat()
+{
+ if (WinEvents && (WinEvents->m_lastKey.type == XBMC_KEYDOWN))
+ {
+ if (WinEvents->m_repeatKeyTimeout.IsTimePast())
+ {
+ return ProcessKey(WinEvents->m_lastKey, 10);
+ }
+ }
+ return false;
+}
+
+XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym)
+{
+ // try direct mapping first
+ std::map<uint32_t, uint32_t>::iterator it;
+ it = WinEvents->m_symLookupTable.find(keysym);
+ if (it != WinEvents->m_symLookupTable.end())
+ {
+ return (XBMCKey)(it->second);
+ }
+
+ // try ascii mappings
+ if (keysym>>8 == 0x00)
+ return (XBMCKey)(keysym & 0xFF);
+
+ return (XBMCKey)keysym;
+}
+#endif
View
54 xbmc/windowing/WinEventsX11.h
@@ -0,0 +1,54 @@
+/*
+* Copyright (C) 2005-2012 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+#pragma once
+
+#include "WinEvents.h"
+#include <X11/Xlib.h>
+#include "threads/SystemClock.h"
+#include <map>
+
+class CWinEventsX11 : public CWinEventsBase
+{
+public:
+ CWinEventsX11();
+ virtual ~CWinEventsX11();
+ static bool Init(Display *dpy, Window win);
+ static void Quit();
+ static bool MessagePump();
+
+protected:
+ static XBMCKey LookupXbmcKeySym(KeySym keysym);
+ static bool ProcessKey(XBMC_Event &event, int repeatDelay);
+ static bool ProcessKeyRepeat();
+ static bool ProcessShortcuts(XBMC_Event& event);
+ static CWinEventsX11 *WinEvents;
+ Display *m_display;
+ Window m_window;
+ Atom m_wmDeleteMessage;
+ char *m_keybuf;
+ size_t m_keybuf_len;
+ XIM m_xim;
+ XIC m_xic;
+ XBMC_Event m_lastKey;
+ XbmcThreads::EndTime m_repeatKeyTimeout;
+ std::map<uint32_t,uint32_t> m_symLookupTable;
+ int m_keymodState;
+};
View
3 xbmc/windowing/WinSystem.h
@@ -91,6 +91,9 @@ class CWinSystemBase
// resolution interfaces
unsigned int GetWidth() { return m_nWidth; }
unsigned int GetHeight() { return m_nHeight; }
+ int GetLeft() { return m_nLeft; }
+ int GetTop() { return m_nTop; }
+
virtual int GetNumScreens() { return 0; }
virtual int GetCurrentScreen() { return 0; }
bool IsFullScreen() { return m_bFullScreen; }
View
421 xbmc/windowing/X11/WinSystemX11.cpp
@@ -22,7 +22,6 @@
#ifdef HAS_GLX
-#include <SDL/SDL_syswm.h>
#include "WinSystemX11.h"
#include "settings/Settings.h"
#include "guilib/Texture.h"
@@ -32,26 +31,30 @@
#include <vector>
#include "threads/SingleLock.h"
#include <X11/Xlib.h>
+#include <X11/Xatom.h>
#include "cores/VideoRenderers/RenderManager.h"
#include "utils/TimeUtils.h"
#if defined(HAS_XRANDR)
#include <X11/extensions/Xrandr.h>
#endif
+#include "../WinEvents.h"
+
using namespace std;
CWinSystemX11::CWinSystemX11() : CWinSystemBase()
{
m_eWindowSystem = WINDOW_SYSTEM_X11;
m_glContext = NULL;
- m_SDLSurface = NULL;
m_dpy = NULL;
+ m_visual = NULL;
m_glWindow = 0;
m_wmWindow = 0;
m_bWasFullScreenBeforeMinimize = false;
m_minimized = false;
m_dpyLostTime = 0;
+ m_invisibleCursor = 0;
XSetErrorHandler(XErrorHandler);
}
@@ -64,19 +67,11 @@ bool CWinSystemX11::InitWindowSystem()
{
if ((m_dpy = XOpenDisplay(NULL)))
{
+ if(!CWinSystemBase::InitWindowSystem())
+ return false;
- SDL_EnableUNICODE(1);
- // set repeat to 10ms to ensure repeat time < frame time
- // so that hold times can be reliably detected
- SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 10);
-
- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-
- return CWinSystemBase::InitWindowSystem();
+ UpdateResolutions();
+ return true;
}
else
CLog::Log(LOGERROR, "GLX Error: No Display found");
@@ -92,98 +87,171 @@ bool CWinSystemX11::DestroyWindowSystem()
g_xrandr.RestoreState();
#endif
- if (m_dpy)
+ if (m_visual)
{
- if (m_glContext)
- {
- glXMakeCurrent(m_dpy, None, NULL);
- glXDestroyContext(m_dpy, m_glContext);
- }
-
- m_glContext = 0;
-
- //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy
- //so instead we just let m_dpy die on exit
+ XFree(m_visual);
+ m_visual = NULL;
}
- // m_SDLSurface is free()'d by SDL_Quit().
+ if (m_dpy)
+ {
+ XCloseDisplay(m_dpy);
+ m_dpy = NULL;
+ }
return true;
}
+/**
+ * @brief Allocate a cursor that won't be visible on the window
+ */
+static Cursor AllocateInvisibleCursor(Display* dpy, Window wnd)
+{
+ Pixmap bitmap;
+ XColor black = {0};
+ Cursor cursor;
+ static char data[] = { 0,0,0,0,0,0,0,0 };
+
+ bitmap = XCreateBitmapFromData(dpy, wnd, data, 8, 8);
+ cursor = XCreatePixmapCursor(dpy, bitmap, bitmap,
+ &black, &black, 0, 0);
+ XFreePixmap(dpy, bitmap);
+ return cursor;
+}
+
+
bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
{
- RESOLUTION_INFO& desktop = g_settings.m_ResInfo[RES_DESKTOP];
- if (fullScreen &&
- (res.iWidth != desktop.iWidth || res.iHeight != desktop.iHeight ||
- res.fRefreshRate != desktop.fRefreshRate || res.iScreen != desktop.iScreen))
+ if (m_wmWindow)
{
- //on the first call to SDL_SetVideoMode, SDL stores the current displaymode
- //SDL restores the displaymode on SDL_QUIT(), if we change the displaymode
- //before the first call to SDL_SetVideoMode, SDL changes the displaymode back
- //to the wrong mode on exit
-
- CLog::Log(LOGINFO, "CWinSystemX11::CreateNewWindow initializing to desktop resolution first");
- if (!SetFullScreen(true, desktop, false))
- return false;
+ OnLostDevice();
+ DestroyWindow();
}
- if(!SetFullScreen(fullScreen, res, false))
+ /* higher layer should have set m_visual */
+ if(m_visual == NULL)
+ {
+ CLog::Log(LOGERROR, "CWinSystemX11::CreateNewWindow - no visual setup");
return false;
+ }
- CBaseTexture* iconTexture = CTexture::LoadFromFile("special://xbmc/media/icon.png");
+ XSetWindowAttributes swa = {0};
- if (iconTexture)
- SDL_WM_SetIcon(SDL_CreateRGBSurfaceFrom(iconTexture->GetPixels(), iconTexture->GetWidth(), iconTexture->GetHeight(), 32, iconTexture->GetPitch(), 0xff0000, 0x00ff00, 0x0000ff, 0xff000000L), NULL);
- SDL_WM_SetCaption("XBMC Media Center", NULL);
- delete iconTexture;
+ swa.override_redirect = False;
+ swa.border_pixel = fullScreen ? 0 : 5;
- // register XRandR Events
-#if defined(HAS_XRANDR)
- int iReturn;
- XRRQueryExtension(m_dpy, &m_RREventBase, &iReturn);
- XRRSelectInput(m_dpy, m_wmWindow, RRScreenChangeNotifyMask);
-#endif
+ if(m_visual->visual == DefaultVisual(m_dpy, m_visual->screen))
+ swa.background_pixel = BlackPixel(m_dpy, m_visual->screen);
+
+ swa.colormap = XCreateColormap(m_dpy, RootWindow(m_dpy, m_visual->screen), m_visual->visual, AllocNone);
+ swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
+ PropertyChangeMask | StructureNotifyMask | KeymapStateMask |
+ EnterWindowMask | LeaveWindowMask | ExposureMask;
+
+ m_wmWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, m_visual->screen),
+ 0, 0,
+ res.iWidth, res.iHeight,
+ 0, m_visual->depth,
+ InputOutput, m_visual->visual,
+ CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask,
+ &swa);
+
+ if (fullScreen)
+ {
+ Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ XChangeProperty(m_dpy, m_wmWindow, XInternAtom(m_dpy, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1);
+ }
+ else
+ XDeleteProperty(m_dpy, m_wmWindow, XInternAtom(m_dpy, "_NET_WM_STATE", False));
+
+ m_invisibleCursor = AllocateInvisibleCursor(m_dpy, m_wmWindow);
+ XDefineCursor(m_dpy, m_wmWindow, m_invisibleCursor);
+
+
+ XWMHints wm_hints;
+ XTextProperty windowName, iconName;
+ const char* title = "XBMC Media Center";
+
+ XStringListToTextProperty((char**)&title, 1, &windowName);
+ XStringListToTextProperty((char**)&title, 1, &iconName);
+ wm_hints.initial_state = NormalState;
+ wm_hints.input = True;
+ wm_hints.icon_pixmap = None;
+ wm_hints.flags = StateHint | IconPixmapHint | InputHint;
+
+ XSetWMProperties(m_dpy, m_wmWindow, &windowName, &iconName,
+ NULL, 0, NULL, &wm_hints,
+ NULL);
+
+ // register interest in the delete window message
+ Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(m_dpy, m_wmWindow, &wmDeleteMessage, 1);
+
+ XMapRaised(m_dpy, m_wmWindow);
+ XSync(m_dpy, True);
+
+ RefreshWindowState();
+
+ //init X11 events
+ CWinEvents::Init(m_dpy, m_wmWindow);
m_bWindowCreated = true;
return true;
}
bool CWinSystemX11::DestroyWindow()
{
+ if (m_glContext)
+ {
+ glFinish();
+ glXMakeCurrent(m_dpy, None, NULL);
+ }
+
+ if (m_invisibleCursor)
+ {
+ XUndefineCursor(m_dpy, m_wmWindow);
+ XFreeCursor(m_dpy, m_invisibleCursor);
+ m_invisibleCursor = 0;
+ }
+
+ CWinEvents::Quit();
+
+ if(m_wmWindow)
+ {
+ XUnmapWindow(m_dpy, m_wmWindow);
+ XSync(m_dpy, True);
+ XDestroyWindow(m_dpy, m_wmWindow);
+ m_wmWindow = 0;
+ }
+
return true;
}
bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
{
- if(m_nWidth == newWidth
- && m_nHeight == newHeight)
- return true;
+ RefreshWindowState();
- m_nWidth = newWidth;
- m_nHeight = newHeight;
+ if(newLeft < 0) newLeft = m_nLeft;
+ if(newTop < 0) newTop = m_nTop;
- int options = SDL_OPENGL;
- if (m_bFullScreen)
- options |= SDL_FULLSCREEN;
- else
- options |= SDL_RESIZABLE;
-
- if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options)))
+ /* check if we are already correct */
+ if(m_nWidth != newWidth
+ && m_nHeight != newHeight
+ && m_nLeft != newLeft
+ && m_nTop != newTop)
{
- RefreshGlxContext();
- return true;
+ XMoveResizeWindow(m_dpy, m_wmWindow, newLeft, newTop, newWidth, newHeight);
+ XSync(m_dpy, False);
+ RefreshWindowState();
}
- return false;
+ return true;
}
bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
{
- m_nWidth = res.iWidth;
- m_nHeight = res.iHeight;
- m_bFullScreen = fullScreen;
#if defined(HAS_XRANDR)
XOutput out;
@@ -203,23 +271,70 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
g_xrandr.RestoreState();
#endif
- int options = SDL_OPENGL;
- if (m_bFullScreen)
- options |= SDL_FULLSCREEN;
+
+ XSetWindowAttributes attr = {0};
+ if(fullScreen)
+ attr.border_pixel = 0;
else
- options |= SDL_RESIZABLE;
+ attr.border_pixel = 5;
+ XChangeWindowAttributes(m_dpy, m_wmWindow, CWBorderPixel, &attr);
- if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options)))
- {
- if ((m_SDLSurface->flags & SDL_OPENGL) != SDL_OPENGL)
- CLog::Log(LOGERROR, "CWinSystemX11::SetFullScreen SDL_OPENGL not set, SDL_GetError:%s", SDL_GetError());
+ int x = 0, y = 0;
- RefreshGlxContext();
+ XWindowAttributes attr2;
+ XGetWindowAttributes(m_dpy, m_wmWindow, &attr2);
- return true;
+ Atom m_NET_WM_STATE = XInternAtom(m_dpy, "_NET_WM_STATE", False);
+ Atom m_NET_WM_STATE_FULLSCREEN = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True);
+ Atom m_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(m_dpy, "_NET_WM_STATE_MAXIMIZED_VERT", True);
+ Atom m_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(m_dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", True);
+
+ if(m_NET_WM_STATE_FULLSCREEN)
+ {
+ if(attr2.map_state == IsUnmapped)
+ {
+ if(fullScreen)
+ XChangeProperty(m_dpy, m_wmWindow, m_NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *) &m_NET_WM_STATE_FULLSCREEN, 1);
+ else
+ XDeleteProperty(m_dpy, m_wmWindow, m_NET_WM_STATE);
+ }
+ else
+ {
+ XEvent e = {0};
+ e.xany.type = ClientMessage;
+ e.xclient.message_type = m_NET_WM_STATE;
+ e.xclient.display = m_dpy;
+ e.xclient.window = m_wmWindow;
+ e.xclient.format = 32;
+ if(fullScreen)
+ {
+ e.xclient.data.l[0] = 1; /* _NET_WM_STATE_ADD */
+ e.xclient.data.l[1] = m_NET_WM_STATE_FULLSCREEN;
+ }
+ else
+ {
+ e.xclient.data.l[0] = 0; /* _NET_WM_STATE_REMOVE */
+ e.xclient.data.l[1] = m_NET_WM_STATE_FULLSCREEN;
+ e.xclient.data.l[2] = m_NET_WM_STATE_MAXIMIZED_VERT;
+ e.xclient.data.l[3] = m_NET_WM_STATE_MAXIMIZED_HORZ;
+ }
+
+ XSendEvent(m_dpy, RootWindow(m_dpy, m_visual->screen), False,
+ SubstructureNotifyMask | SubstructureRedirectMask, &e);
+ }
+ XSync(m_dpy, False);
}
- return false;
+ if(fullScreen)
+ XMoveResizeWindow(m_dpy, m_wmWindow, x, y, res.iWidth, res.iHeight);
+ else
+ XResizeWindow(m_dpy, m_wmWindow, res.iWidth, res.iHeight);
+ XSync(m_dpy, False);
+
+ RefreshWindowState();
+
+ m_bFullScreen = fullScreen;
+ return true;
}
void CWinSystemX11::UpdateResolutions()
@@ -296,124 +411,25 @@ void CWinSystemX11::UpdateResolutions()
}
-bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo)
+void CWinSystemX11::RefreshWindowState()
{
- int value;
- if (glXGetConfig(m_dpy, vInfo, GLX_RGBA, &value) || !value)
- return false;
- if (glXGetConfig(m_dpy, vInfo, GLX_DOUBLEBUFFER, &value) || !value)
- return false;
- if (glXGetConfig(m_dpy, vInfo, GLX_RED_SIZE, &value) || value < 8)
- return false;
- if (glXGetConfig(m_dpy, vInfo, GLX_GREEN_SIZE, &value) || value < 8)
- return false;
- if (glXGetConfig(m_dpy, vInfo, GLX_BLUE_SIZE, &value) || value < 8)
- return false;
- if (glXGetConfig(m_dpy, vInfo, GLX_ALPHA_SIZE, &value) || value < 8)
- return false;
- if (glXGetConfig(m_dpy, vInfo, GLX_DEPTH_SIZE, &value) || value < 8)
- return false;
- return true;
-}
-
-bool CWinSystemX11::RefreshGlxContext()
-{
- bool retVal = false;
- SDL_SysWMinfo info;
- SDL_VERSION(&info.version);
- if (SDL_GetWMInfo(&info) <= 0)
- {
- CLog::Log(LOGERROR, "Failed to get window manager info from SDL");
- return false;
- }
-
- if(m_glWindow == info.info.x11.window && m_glContext)
- {
- CLog::Log(LOGERROR, "GLX: Same window as before, refreshing context");
- glXMakeCurrent(m_dpy, None, NULL);
- glXMakeCurrent(m_dpy, m_glWindow, m_glContext);
- return true;
- }
-
- XVisualInfo vMask;
- XVisualInfo *visuals;
- XVisualInfo *vInfo = NULL;
- int availableVisuals = 0;
- vMask.screen = DefaultScreen(m_dpy);
- XWindowAttributes winAttr;
- m_glWindow = info.info.x11.window;
- m_wmWindow = info.info.x11.wmwindow;
-
- /* Assume a depth of 24 in case the below calls to XGetWindowAttributes()
- or XGetVisualInfo() fail. That shouldn't happen unless something is
- fatally wrong, but lets prepare for everything. */
- vMask.depth = 24;
-
- if (XGetWindowAttributes(m_dpy, m_glWindow, &winAttr))
- {
- vMask.visualid = XVisualIDFromVisual(winAttr.visual);
- vInfo = XGetVisualInfo(m_dpy, VisualScreenMask | VisualIDMask, &vMask, &availableVisuals);
- if (!vInfo)
- CLog::Log(LOGWARNING, "Failed to get VisualInfo of SDL visual 0x%x", (unsigned) vMask.visualid);
- else if(!IsSuitableVisual(vInfo))
- {
- CLog::Log(LOGWARNING, "Visual 0x%x of the SDL window is not suitable, looking for another one...",
- (unsigned) vInfo->visualid);
- vMask.depth = vInfo->depth;
- XFree(vInfo);
- vInfo = NULL;
- }
- }
- else
- CLog::Log(LOGWARNING, "Failed to get SDL window attributes");
-
- /* As per glXMakeCurrent documentation, we have to use the same visual as
- m_glWindow. Since that was not suitable for use, we try to use another
- one with the same depth and hope that the used implementation is less
- strict than the documentation. */
- if (!vInfo)
- {
- visuals = XGetVisualInfo(m_dpy, VisualScreenMask | VisualDepthMask, &vMask, &availableVisuals);
- for (int i = 0; i < availableVisuals; i++)
- {
- if (IsSuitableVisual(&visuals[i]))
- {
- vMask.visualid = visuals[i].visualid;
- vInfo = XGetVisualInfo(m_dpy, VisualScreenMask | VisualIDMask, &vMask, &availableVisuals);
- break;
- }
- }
- XFree(visuals);
- }
-
- if (vInfo)
- {
- CLog::Log(LOGNOTICE, "Using visual 0x%x", (unsigned) vInfo->visualid);
- if (m_glContext)
- {
- glXMakeCurrent(m_dpy, None, NULL);
- glXDestroyContext(m_dpy, m_glContext);
- }
-
- if ((m_glContext = glXCreateContext(m_dpy, vInfo, NULL, True)))
- {
- // make this context current
- glXMakeCurrent(m_dpy, m_glWindow, m_glContext);
- retVal = true;
- }
- else
- CLog::Log(LOGERROR, "GLX Error: Could not create context");
- XFree(vInfo);
- }
- else
- CLog::Log(LOGERROR, "GLX Error: vInfo is NULL!");
-
- return retVal;
+ XWindowAttributes attr;
+ Window child;
+ XGetWindowAttributes(m_dpy, m_wmWindow, &attr);
+ XTranslateCoordinates(m_dpy, m_wmWindow, attr.root, -attr.border_width, -attr.border_width, &attr.x, &attr.y, &child);
+
+ m_nWidth = attr.width;
+ m_nHeight = attr.height;
+ m_nLeft = attr.x;
+ m_nTop = attr.y;
}
void CWinSystemX11::ShowOSMouse(bool show)
{
- SDL_ShowCursor(show ? 1 : 0);
+ if (show)
+ XUndefineCursor(m_dpy,m_wmWindow);
+ else if (m_invisibleCursor)
+ XDefineCursor(m_dpy,m_wmWindow, m_invisibleCursor);
}
void CWinSystemX11::ResetOSScreensaver()
@@ -427,8 +443,6 @@ void CWinSystemX11::ResetOSScreensaver()
{
m_screensaverReset.StartZero();
XResetScreenSaver(m_dpy);
- //need to flush the output buffer, since we don't check for events on m_dpy
- XFlush(m_dpy);
}
}
else
@@ -437,36 +451,47 @@ void CWinSystemX11::ResetOSScreensaver()
}
}
-void CWinSystemX11::NotifyAppActiveChange(bool bActivated)
+void CWinSystemX11::NotifyAppFocusChange(bool bActivated)
{
if (bActivated && m_bWasFullScreenBeforeMinimize && !g_graphicsContext.IsFullScreenRoot())
g_graphicsContext.ToggleFullScreenRoot();
m_minimized = !bActivated;
+ if(bActivated)
+ m_bWasFullScreenBeforeMinimize = false;
}
+
bool CWinSystemX11::Minimize()
{
m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot();
if (m_bWasFullScreenBeforeMinimize)
g_graphicsContext.ToggleFullScreenRoot();
- SDL_WM_IconifyWindow();
m_minimized = true;
+ XIconifyWindow(m_dpy, m_wmWindow, m_visual->screen);
+
return true;
}
+
bool CWinSystemX11::Restore()
{
- return false;
+ return Show(true);
}
+
bool CWinSystemX11::Hide()
{
XUnmapWindow(m_dpy, m_wmWindow);
XSync(m_dpy, False);
return true;
}
+
bool CWinSystemX11::Show(bool raise)
{
- XMapWindow(m_dpy, m_wmWindow);
+ if(raise)
+ XMapRaised(m_dpy, m_wmWindow);
+ else
+ XMapWindow(m_dpy, m_wmWindow);
+
XSync(m_dpy, False);
m_minimized = false;
return true;
View
17 xbmc/windowing/X11/WinSystemX11.h
@@ -51,7 +51,16 @@ class CWinSystemX11 : public CWinSystemBase
virtual void ResetOSScreensaver();
virtual bool EnableFrameLimiter();
- virtual void NotifyAppActiveChange(bool bActivated);
+ virtual void OnMove(int x, int y)
+ {
+ if(!m_bFullScreen)
+ {
+ m_nLeft = x;
+ m_nTop = y;
+ }
+ }
+
+ virtual void NotifyAppFocusChange(bool bGaining);
virtual bool Minimize();
virtual bool Restore() ;
@@ -65,16 +74,18 @@ class CWinSystemX11 : public CWinSystemBase
GLXWindow GetWindow() { return m_glWindow; }
protected:
- bool RefreshGlxContext();
+ void RefreshWindowState();
void CheckDisplayEvents();
void OnLostDevice();
void OnResetDevice();
- SDL_Surface* m_SDLSurface;
+ XVisualInfo* m_visual;
GLXContext m_glContext;
GLXWindow m_glWindow;
Window m_wmWindow;
Display* m_dpy;
+
+ Cursor m_invisibleCursor;
bool m_bWasFullScreenBeforeMinimize;
bool m_minimized;
int m_RREventBase;
View
63 xbmc/windowing/X11/WinSystemX11GL.cpp
@@ -40,6 +40,18 @@ CWinSystemX11GL::~CWinSystemX11GL()
{
}
+bool CWinSystemX11GL::DestroyWindowSystem()
+{
+ if (m_glContext)
+ {
+ glFinish();
+ glXMakeCurrent(m_dpy, None, NULL);
+ glXDestroyContext(m_dpy, m_glContext);
+ m_glContext = None;
+ }
+ return CWinSystemX11::DestroyWindowSystem();
+}
+
bool CWinSystemX11GL::PresentRenderImpl(const CDirtyRegionList& dirty)
{
CheckDisplayEvents();
@@ -197,11 +209,60 @@ bool CWinSystemX11GL::IsExtSupported(const char* extension)
return m_glxext.find(name) != std::string::npos;
}
+bool CWinSystemX11GL::DestroyWindow()
+{
+ if(m_glContext)
+ {
+ glFinish();
+ glXMakeCurrent(m_dpy, None, NULL);
+ glXDestroyContext(m_dpy, m_glContext);
+ m_glContext = None;
+ }
+ return CWinSystemX11::DestroyWindow();
+}
+
bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
{
+ GLint att[] =
+ {
+ GLX_RGBA,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, 8,
+ GLX_DEPTH_SIZE, 24,
+ GLX_DOUBLEBUFFER,
+ None
+ };
+
+ DestroyWindow();
+
+ m_visual = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att);
+ if(m_visual == NULL)
+ {
+ CLog::Log(LOGERROR, "CWinSystemX11GL::CreateNewWindow - failed to create visual");
+ return false;
+ }
+
+
if(!CWinSystemX11::CreateNewWindow(name, fullScreen, res, userFunction))
return false;
+ m_glContext = glXCreateContext(m_dpy, m_visual, NULL, True);
+ if (m_glContext == NULL)
+ {
+ CLog::Log(LOGERROR, "CWinSystemX11GL::CreateNewWindow - failed to create context");
+ return false;
+ }
+
+ if(glXMakeCurrent(m_dpy, m_wmWindow, m_glContext) == False)
+ {
+ CLog::Log(LOGERROR, "CWinSystemX11GL::CreateNewWindow - failed to make context current");
+ return false;
+ }
+
+ m_glWindow = m_wmWindow;
+
m_glxext = " ";
m_glxext += (const char*)glXQueryExtensionsString(m_dpy, DefaultScreen(m_dpy));
m_glxext += " ";
@@ -240,6 +301,8 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R
m_glXSwapIntervalMESA = NULL;
+ OnResetDevice();
+
return true;
}
View
2 xbmc/windowing/X11/WinSystemX11GL.h
@@ -31,6 +31,8 @@ class CWinSystemX11GL : public CWinSystemX11, public CRenderSystemGL
public:
CWinSystemX11GL();
virtual ~CWinSystemX11GL();
+ virtual bool DestroyWindowSystem();
+ virtual bool DestroyWindow();
virtual bool CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction);
virtual bool ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop);
virtual bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays);

0 comments on commit 25decc3

Please sign in to comment.
Something went wrong with that request. Please try again.