From 2015d252f02f422cd92c10c2a0aad4417ca2656e Mon Sep 17 00:00:00 2001 From: Glenn Rice Date: Mon, 15 Mar 2010 23:25:11 +0000 Subject: [PATCH] Rewrite of fullscreen toggling in linux. This goes back to using the EWMH specifications. I wasn't using it right before, but now it should work on all EWMH compliant window managers (like KDE, Metacity, Compiz, etc). Since this doesn't need an override redirect Alt-Tab works even in fullscreen mode. This also allows for some other nice things to be done. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5199 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/Core.cpp | 71 +-- Source/Core/DolphinWX/Src/Frame.cpp | 110 +++-- Source/Core/DolphinWX/Src/Frame.h | 3 + Source/Core/DolphinWX/Src/FrameTools.cpp | 21 +- Source/Core/DolphinWX/Src/Main.cpp | 2 + Source/PluginSpecs/pluginspecs_pad.h | 3 + Source/PluginSpecs/pluginspecs_video.h | 3 + Source/PluginSpecs/pluginspecs_wiimote.h | 3 + Source/Plugins/Plugin_GCPad/Src/GCPad.cpp | 8 +- Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp | 427 ++++++++++-------- Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h | 28 +- Source/Plugins/Plugin_Wiimote/Src/main.cpp | 8 +- 12 files changed, 387 insertions(+), 300 deletions(-) diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 7abb4612fd..45333463f5 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -29,11 +29,6 @@ #include "MathUtil.h" #include "MemoryUtil.h" -#if defined(HAVE_X11) && HAVE_X11 -#include -#include -#endif - #include "Console.h" #include "Core.h" #include "CPUDetect.h" @@ -252,47 +247,6 @@ void Stop() // - Hammertime! g_EmuThread = 0; } -#if defined(HAVE_X11) && HAVE_X11 -void ProcessXEvents(void) -{ - if (GetState() == CORE_PAUSE) - { - Display *dpy = (Display *)g_pWindowHandle; - XEvent event; - KeySym key; - int num_events; - for (num_events = XPending(dpy);num_events > 0;num_events--) - { - XNextEvent(dpy, &event); - switch(event.type) { - case KeyPress: - key = XLookupKeysym((XKeyEvent*)&event, 0); - if (key == XK_Escape) - Host_Message(WM_USER_PAUSE); - case ClientMessage: - if ((ulong) event.xclient.data.l[0] == XInternAtom(dpy, "WM_DELETE_WINDOW", False)) - Host_Message(WM_USER_STOP); - if ((ulong) event.xclient.data.l[0] == XInternAtom(dpy, "WINDOW_REFOCUS", False)) - XSetInputFocus(dpy, *(Window *)g_pXWindow, RevertToPointerRoot, CurrentTime); - break; - default: - break; - } - } - } -} - -THREAD_RETURN XEventThread(void *pArg) -{ - while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN) - { - ProcessXEvents(); - Common::SleepCurrentThread(200); - } - return 0; -} -#endif - // Create the CPU thread. which would be a CPU + Video thread in Single Core mode. THREAD_RETURN CpuThread(void *pArg) @@ -368,6 +322,9 @@ THREAD_RETURN EmuThread(void *pArg) VideoInitialize.pScheduleEvent_Threadsafe = CoreTiming::ScheduleEvent_Threadsafe; // This is first the m_Panel handle, then it is updated to have the new window handle VideoInitialize.pWindowHandle = _CoreParameter.hMainWindow; +#if defined(HAVE_X11) && HAVE_X11 && defined(HAVE_GTK2) && HAVE_GTK2 + VideoInitialize.pPanel = _CoreParameter.hMainWindow; +#endif VideoInitialize.pLog = Callback_VideoLog; VideoInitialize.pSysMessage = Host_SysMessage; VideoInitialize.pRequestWindowSize = NULL; //Callback_VideoRequestWindowSize; @@ -388,7 +345,7 @@ THREAD_RETURN EmuThread(void *pArg) // Under linux, this is an X11 Display, not a HWND! g_pWindowHandle = (HWND)VideoInitialize.pWindowHandle; #if defined(HAVE_X11) && HAVE_X11 - g_pXWindow = (Window *)VideoInitialize.pXWindow; + g_pXWindow = (void *)VideoInitialize.pXWindow; #endif Callback_PeekMessages = VideoInitialize.pPeekMessages; g_pUpdateFPSDisplay = VideoInitialize.pUpdateFPSDisplay; @@ -417,6 +374,9 @@ THREAD_RETURN EmuThread(void *pArg) PADInitialize.hWnd = g_pWindowHandle; #if defined(HAVE_X11) && HAVE_X11 PADInitialize.pXWindow = g_pXWindow; +#if defined(HAVE_GTK2) && HAVE_GTK2 + PADInitialize.pPanel = VideoInitialize.pPanel; +#endif #endif PADInitialize.pLog = Callback_PADLog; // This is may be needed to avoid a SDL problem @@ -429,6 +389,9 @@ THREAD_RETURN EmuThread(void *pArg) SWiimoteInitialize WiimoteInitialize; WiimoteInitialize.hWnd = g_pWindowHandle; #if defined(HAVE_X11) && HAVE_X11 +#if defined(HAVE_GTK2) && HAVE_GTK2 + WiimoteInitialize.pPanel = VideoInitialize.pPanel; +#endif WiimoteInitialize.pXWindow = g_pXWindow; #endif WiimoteInitialize.ISOId = Ascii2Hex(_CoreParameter.m_strUniqueID); @@ -459,10 +422,6 @@ THREAD_RETURN EmuThread(void *pArg) // Spawn the CPU thread Common::Thread *cpuThread = NULL; -#if defined(HAVE_X11) && HAVE_X11 - Common::Thread *xEventThread = NULL; -#endif - // ENTER THE VIDEO THREAD LOOP if (_CoreParameter.bCPUThread) { @@ -471,9 +430,6 @@ THREAD_RETURN EmuThread(void *pArg) Plugins.GetVideo()->Video_Prepare(); // wglMakeCurrent cpuThread = new Common::Thread(CpuThread, pArg); -#if defined(HAVE_X11) && HAVE_X11 - xEventThread = new Common::Thread(XEventThread, pArg); -#endif Common::SetCurrentThreadName("Video thread"); if (g_pUpdateFPSDisplay != NULL) @@ -508,9 +464,6 @@ THREAD_RETURN EmuThread(void *pArg) { if (Callback_PeekMessages) Callback_PeekMessages(); -#if defined(HAVE_X11) && HAVE_X11 - ProcessXEvents(); -#endif Common::SleepCurrentThread(20); } @@ -817,11 +770,15 @@ void Callback_KeyPress(int key, bool shift, bool control) State_UndoLoadState(); } #if defined(HAVE_X11) && HAVE_X11 + if (key == 0) + Host_Message(WM_USER_CREATE); // 0x1b == VK_ESCAPE if (key == 0x1b) Host_Message(WM_USER_STOP); if (key == 0x1c) Host_Message(WM_USER_PAUSE); + if (key == 0x1d) + Host_Message(TOGGLE_FULLSCREEN); #endif } diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index ea38e45bfa..333c5d4f46 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -523,7 +523,7 @@ void CFrame::OnQuit(wxCommandEvent& WXUNUSED (event)) } #if defined HAVE_X11 && HAVE_X11 -void X11_SendEvent(const char *message) +void CFrame::X11_SendClientEvent(const char *message) { XEvent event; Display *dpy = (Display *)Core::GetWindowHandle(); @@ -536,9 +536,24 @@ void X11_SendEvent(const char *message) // Send the event if (!XSendEvent(dpy, win, False, False, &event)) - { ERROR_LOG(VIDEO, "Failed to send message %s to the emulator window.\n", message); - } +} + +void X11_SendKeyEvent(int key) +{ + XEvent event; + Display *dpy = (Display *)Core::GetWindowHandle(); + Window win = *(Window *)Core::GetXWindow(); + + // Init X event structure for key press event + event.xkey.type = KeyPress; + // WARNING: This works for '3' to '7'. If in the future other keys are needed + // convert with InputCommon::wxCharCodeWXToX from X11InputBase.cpp. + event.xkey.keycode = XKeysymToKeycode(dpy, key); + + // Send the event + if (!XSendEvent(dpy, win, False, False, &event)) + ERROR_LOG(VIDEO, "Failed to send key press event to the emulator window.\n"); } #endif @@ -547,8 +562,13 @@ void X11_SendEvent(const char *message) void CFrame::OnActive(wxActivateEvent& event) { #if defined(HAVE_X11) && HAVE_X11 && defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) - if (event.GetActive() && (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE)) - X11_SendEvent("WINDOW_REFOCUS"); + if (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE) + { + if (event.GetActive()) + X11_SendClientEvent("FOCUSIN"); + else + X11_SendClientEvent("FOCUSOUT"); + } #endif event.Skip(); } @@ -618,7 +638,7 @@ void CFrame::OnResizeAll(wxSizeEvent& event) event.Skip(); #if defined(HAVE_X11) && HAVE_X11 && defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) if (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE) - X11_SendEvent("MAIN_RESIZED"); + X11_SendClientEvent("RESIZE"); #endif //wxWindow * Win = (wxWindow*)event.GetEventObject(); //NOTICE_LOG(CONSOLE, "OnResizeAll: %i", (HWND)Win->GetHWND()); @@ -675,11 +695,17 @@ void CFrame::OnHostMessage(wxCommandEvent& event) } break; #if defined(HAVE_X11) && HAVE_X11 + case WM_USER_CREATE: + bRenderToMain = true; + break; + case TOGGLE_FULLSCREEN: + DoFullscreen(!IsFullScreen()); + break; case WM_USER_STOP: - main_frame->DoStop(); + DoStop(); break; case WM_USER_PAUSE: - main_frame->DoPause(); + DoPause(); break; #endif } @@ -787,8 +813,14 @@ void CFrame::OnKeyDown(wxKeyEvent& event) { PostMessage((HWND)Core::GetWindowHandle(), WM_USER, WM_USER_KEYDOWN, event.GetKeyCode()); } +#elif defined(HAVE_X11) && HAVE_X11 && defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + if (event.GetKeyCode() >= '3' && event.GetKeyCode() <= '7') // Send this to the video plugin + { + X11_SendKeyEvent(event.GetKeyCode()); + } #endif + // Send the keyboard status to the Input plugin if(Core::GetState() != Core::CORE_UNINITIALIZED) CPluginManager::GetInstance().GetPad(0)->PAD_Input(event.GetKeyCode(), 1); // 1 = Down @@ -938,44 +970,46 @@ wxAuiNotebook* CFrame::CreateEmptyNotebook() void CFrame::DoFullscreen(bool bF) { -#if defined HAVE_X11 && HAVE_X11 - if ((Core::GetState() == Core::CORE_RUN)) - X11_SendEvent("TOGGLE_FULLSCREEN"); -#endif // Only switch this to fullscreen if we're rendering to main AND if we're running a game // plus if a modal dialog is open, this will still process the keyboard events, and may cause // the main window to become unresponsive, so we have to avoid that. - if ((bRenderToMain && Core::GetState() == Core::CORE_RUN)) + if ((Core::GetState() == Core::CORE_RUN) || (Core::GetState() == Core::CORE_PAUSE)) { - ShowFullScreen(bF); + if (bRenderToMain) + { + ShowFullScreen(bF); - if (bF) - { - // Save the current mode before going to fullscreen - AuiCurrent = m_Mgr->SavePerspective(); - m_Mgr->LoadPerspective(AuiFullscreen, true); - } - else - { - // Restore saved perspective - m_Mgr->LoadPerspective(AuiCurrent, true); - } + if (bF) + { + // Save the current mode before going to fullscreen + AuiCurrent = m_Mgr->SavePerspective(); + m_Mgr->LoadPerspective(AuiFullscreen, true); + } + else + { + // Restore saved perspective + m_Mgr->LoadPerspective(AuiCurrent, true); + } - // Show the cursor again, in case it was hidden - if (IsFullScreen()) - { - #ifdef _WIN32 - MSWSetCursor(true); - #endif - } - } #ifdef _WIN32 - else // Post the message to the separate rendering window which will then handle it. - { - BringWindowToTop((HWND)Core::GetWindowHandle()); - PostMessage((HWND)Core::GetWindowHandle(), WM_USER, TOGGLE_FULLSCREEN, 0); - } + // Show the cursor again, in case it was hidden + if (IsFullScreen()) + { + MSWSetCursor(true); + } #endif + } +#ifdef _WIN32 + else // Post the message to the separate rendering window which will then handle it. + { + BringWindowToTop((HWND)Core::GetWindowHandle()); + PostMessage((HWND)Core::GetWindowHandle(), WM_USER, TOGGLE_FULLSCREEN, 0); + } +#elif defined HAVE_X11 && HAVE_X11 + else // Send the event to the separate rendering window which will then handle it. + X11_SendClientEvent("TOGGLE_FULLSCREEN"); +#endif + } } // Debugging, show loose windows diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 5d0656a477..c4e21c1a06 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -303,6 +303,9 @@ class CFrame : public wxFrame void OnGameListCtrl_ItemActivated(wxListEvent& event); void DoFullscreen(bool _F); +#if defined HAVE_X11 && HAVE_X11 + void X11_SendClientEvent(const char *message); +#endif // MenuBar // File - Drive diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 50d710ed49..6c7aca9b7e 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -629,16 +629,11 @@ void CFrame::OnPlay(wxCommandEvent& WXUNUSED (event)) wxThread::Sleep(20); g_pCodeWindow->JumpToAddress(PC); g_pCodeWindow->Update(); + // Update toolbar with Play/Pause status + UpdateGUI(); } else - { - if (Core::GetState() == Core::CORE_RUN) - Core::SetState(Core::CORE_PAUSE); - else - Core::SetState(Core::CORE_RUN); - } - // Update toolbar with Play/Pause status - UpdateGUI(); + DoPause(); } else // Core is uninitialized, start the game @@ -692,9 +687,19 @@ void CFrame::OnScreenshot(wxCommandEvent& WXUNUSED (event)) void CFrame::DoPause() { if (Core::GetState() == Core::CORE_RUN) + { +#if defined(HAVE_X11) && HAVE_X11 + X11_SendClientEvent("PAUSE"); +#endif Core::SetState(Core::CORE_PAUSE); + } else + { +#if defined(HAVE_X11) && HAVE_X11 + X11_SendClientEvent("RESUME"); +#endif Core::SetState(Core::CORE_RUN); + } UpdateGUI(); } diff --git a/Source/Core/DolphinWX/Src/Main.cpp b/Source/Core/DolphinWX/Src/Main.cpp index 87ff3a7b6b..a8a9e600c0 100644 --- a/Source/Core/DolphinWX/Src/Main.cpp +++ b/Source/Core/DolphinWX/Src/Main.cpp @@ -533,6 +533,8 @@ void Host_Message(int Id) #if defined(HAVE_X11) && HAVE_X11 switch(Id) { + case WM_USER_CREATE: + case TOGGLE_FULLSCREEN: case WM_USER_STOP: case WM_USER_PAUSE: { diff --git a/Source/PluginSpecs/pluginspecs_pad.h b/Source/PluginSpecs/pluginspecs_pad.h index 4a0ef29c6a..3c6f50ba13 100644 --- a/Source/PluginSpecs/pluginspecs_pad.h +++ b/Source/PluginSpecs/pluginspecs_pad.h @@ -35,6 +35,9 @@ typedef struct { HWND hWnd; #if defined HAVE_X11 && HAVE_X11 +#if defined(HAVE_GTK2) && HAVE_GTK2 + void *pPanel; +#endif void *pXWindow; #endif TLog pLog; diff --git a/Source/PluginSpecs/pluginspecs_video.h b/Source/PluginSpecs/pluginspecs_video.h index c11b8b4db7..ab0950901f 100644 --- a/Source/PluginSpecs/pluginspecs_video.h +++ b/Source/PluginSpecs/pluginspecs_video.h @@ -72,6 +72,9 @@ typedef struct { void *pWindowHandle; #if defined(HAVE_X11) && HAVE_X11 +#if defined(HAVE_GTK2) && HAVE_GTK2 + void *pPanel; +#endif void *pXWindow; #endif diff --git a/Source/PluginSpecs/pluginspecs_wiimote.h b/Source/PluginSpecs/pluginspecs_wiimote.h index f3900afef6..b473edfca7 100644 --- a/Source/PluginSpecs/pluginspecs_wiimote.h +++ b/Source/PluginSpecs/pluginspecs_wiimote.h @@ -20,6 +20,9 @@ typedef struct { HWND hWnd; #if defined HAVE_X11 && HAVE_X11 +#if defined(HAVE_GTK2) && HAVE_GTK2 + void *pPanel; +#endif void *pXWindow; #endif u32 ISOId; diff --git a/Source/Plugins/Plugin_GCPad/Src/GCPad.cpp b/Source/Plugins/Plugin_GCPad/Src/GCPad.cpp index f583dc273c..40988afc70 100644 --- a/Source/Plugins/Plugin_GCPad/Src/GCPad.cpp +++ b/Source/Plugins/Plugin_GCPad/Src/GCPad.cpp @@ -658,12 +658,14 @@ bool IsFocus() return false; #elif defined HAVE_X11 && HAVE_X11 Window GLWin = *(Window *)g_PADInitialize->pXWindow; + bool bFocus = False; +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + bFocus = (wxPanel *)g_PADInitialize->pPanel == wxWindow::FindFocus(); +#endif Window FocusWin; int Revert; XGetInputFocus(GCdisplay, &FocusWin, &Revert); - XWindowAttributes WinAttribs; - XGetWindowAttributes (GCdisplay, GLWin, &WinAttribs); - return (GLWin != 0 && (GLWin == FocusWin || WinAttribs.override_redirect)); + return (GLWin == FocusWin || bFocus); #else return true; #endif diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp index 7a6a95b737..388aa73061 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp @@ -118,43 +118,61 @@ void UpdateFPSDisplay(const char *text) } #if defined(HAVE_X11) && HAVE_X11 +THREAD_RETURN XEventThread(void *pArg); + +void X11_EWMH_Fullscreen(int action) +{ + assert(action == _NET_WM_STATE_REMOVE || action == _NET_WM_STATE_ADD + || action == _NET_WM_STATE_TOGGLE); + + // Init X event structure for _NET_WM_STATE_FULLSCREEN client message + XEvent event; + event.xclient.type = ClientMessage; + event.xclient.message_type = XInternAtom(GLWin.dpy, "_NET_WM_STATE", False); + event.xclient.window = GLWin.win; + event.xclient.format = 32; + event.xclient.data.l[0] = action; + event.xclient.data.l[1] = XInternAtom(GLWin.dpy, "_NET_WM_STATE_FULLSCREEN", False); + + // Send the event + if (!XSendEvent(GLWin.dpy, DefaultRootWindow(GLWin.dpy), False, + SubstructureRedirectMask | SubstructureNotifyMask, &event)) + ERROR_LOG(VIDEO, "Failed to switch fullscreen/windowed mode.\n"); +} + void CreateXWindow (void) { - Atom wmProtocols[2]; - Window parent = RootWindow(GLWin.dpy, GLWin.vi->screen); - GLWin.x = 0; - GLWin.y = 0; + Atom wmProtocols[3]; + Window parent; #if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) wxMutexGuiEnter(); #endif - if (GLWin.fs) - { #if defined(HAVE_XRANDR) && HAVE_XRANDR - if (GLWin.fullSize >= 0) - XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen), - GLWin.fullSize, GLWin.screenRotation, CurrentTime); + if (GLWin.fs +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + && !g_Config.RenderToMainframe #endif - GLWin.attr.override_redirect = True; - GLWin.width = GLWin.fullWidth; - GLWin.height = GLWin.fullHeight; + ) + XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen), + GLWin.fullSize, GLWin.screenRotation, CurrentTime); +#endif +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + if (g_Config.RenderToMainframe) + { + GLWin.panel->GetSize((int *)&GLWin.width, (int *)&GLWin.height); + GLWin.panel->GetPosition(&GLWin.x, &GLWin.y); + parent = GDK_WINDOW_XID(GTK_WIDGET(GLWin.panel->GetHandle())->window); + GLWin.panel->SetFocus(); } else - { - GLWin.attr.override_redirect = False; -#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) - if (g_Config.RenderToMainframe) - { - GLWin.panel->GetSize((int *)&GLWin.width, (int *)&GLWin.height); - GLWin.panel->GetPosition(&GLWin.x, &GLWin.y); - parent = GDK_WINDOW_XID(GTK_WIDGET(GLWin.panel->GetHandle())->window); - } - else #endif - { - GLWin.width = GLWin.winWidth; - GLWin.height = GLWin.winHeight; - } + { + GLWin.x = 0; + GLWin.y = 0; + GLWin.width = GLWin.winWidth; + GLWin.height = GLWin.winHeight; + parent = RootWindow(GLWin.dpy, GLWin.vi->screen); } // Control window size and picture scaling @@ -164,28 +182,18 @@ void CreateXWindow (void) // create the window GLWin.win = XCreateWindow(GLWin.dpy, parent, GLWin.x, GLWin.y, GLWin.width, GLWin.height, 0, GLWin.vi->depth, InputOutput, GLWin.vi->visual, - CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &GLWin.attr); + CWBorderPixel | CWBackPixel | CWColormap | CWEventMask, &GLWin.attr); wmProtocols[0] = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); - wmProtocols[1] = XInternAtom(GLWin.dpy, "WM_TAKE_FOCUS", True); - XSetWMProtocols(GLWin.dpy, GLWin.win, wmProtocols, 2); + wmProtocols[1] = XInternAtom(GLWin.dpy, "_NET_WM_STATE", False); + wmProtocols[2] = XInternAtom(GLWin.dpy, "_NET_WM_STATE_FULLSCREEN", False); + XSetWMProtocols(GLWin.dpy, GLWin.win, wmProtocols, 3); XSetStandardProperties(GLWin.dpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL); XMapRaised(GLWin.dpy, GLWin.win); - if (GLWin.fs) - { - XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync, GrabModeAsync, CurrentTime); - XGrabPointer(GLWin.dpy, GLWin.win, True, NULL, - GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime); - } -#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) - if (GLWin.fs || g_Config.RenderToMainframe) -#else - if (GLWin.fs) -#endif - XSetInputFocus(GLWin.dpy, GLWin.win, RevertToPointerRoot, CurrentTime); XSync(GLWin.dpy, True); #if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) wxMutexGuiLeave(); #endif + GLWin.xEventThread = new Common::Thread(XEventThread, NULL); } void DestroyXWindow(void) @@ -200,25 +208,189 @@ void DestroyXWindow(void) /* switch back to original desktop resolution if we were in fullscreen */ if( GLWin.fs ) { - XUngrabKeyboard (GLWin.dpy, CurrentTime); - XUngrabPointer (GLWin.dpy, CurrentTime); #if defined(HAVE_XRANDR) && HAVE_XRANDR - if (GLWin.fullSize >= 0) - XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen), - GLWin.deskSize, GLWin.screenRotation, CurrentTime); + XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen), + GLWin.deskSize, GLWin.screenRotation, CurrentTime); +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + if (!g_Config.RenderToMainframe) +#endif + X11_EWMH_Fullscreen(_NET_WM_STATE_REMOVE); #endif } XUndefineCursor(GLWin.dpy, GLWin.win); XUnmapWindow(GLWin.dpy, GLWin.win); - XSync(GLWin.dpy, True); + GLWin.win = 0; } void ToggleFullscreenMode (void) { - DestroyXWindow(); GLWin.fs = !GLWin.fs; - CreateXWindow(); - OpenGL_MakeCurrent(); +#if defined(HAVE_XRANDR) && HAVE_XRANDR + if (GLWin.fs) + XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen), + GLWin.fullSize, GLWin.screenRotation, CurrentTime); + else + XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen), + GLWin.deskSize, GLWin.screenRotation, CurrentTime); +#endif +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + if (!g_Config.RenderToMainframe) +#endif + { + X11_EWMH_Fullscreen(_NET_WM_STATE_TOGGLE); + XRaiseWindow(GLWin.dpy, GLWin.win); + XSetInputFocus(GLWin.dpy, GLWin.win, RevertToPointerRoot, CurrentTime); + } + XSync(GLWin.dpy, False); +} + +THREAD_RETURN XEventThread(void *pArg) +{ + bool bPaused = False; + while (GLWin.win) + { + XEvent event; + KeySym key; + int num_events; + for (num_events = XPending(GLWin.dpy);num_events > 0;num_events--) { + XNextEvent(GLWin.dpy, &event); + switch(event.type) { + case KeyPress: + key = XLookupKeysym((XKeyEvent*)&event, 0); + switch (key) + { + case XK_F1: case XK_F2: case XK_F3: case XK_F4: case XK_F5: case XK_F6: + case XK_F7: case XK_F8: case XK_F9: case XK_F11: case XK_F12: + g_VideoInitialize.pKeyPress(key - 0xff4e, + event.xkey.state & ShiftMask, + event.xkey.state & ControlMask); + break; + case XK_Escape: + if (GLWin.fs && !bPaused) + { + printf("toggling fullscreen\n"); + ToggleFullscreenMode(); + } + g_VideoInitialize.pKeyPress(0x1c, False, False); + break; + case XK_Return: + if (event.xkey.state & Mod1Mask) + ToggleFullscreenMode(); + break; + case XK_3: + OSDChoice = 1; + // Toggle native resolution + if (!(g_Config.bNativeResolution || g_Config.b2xResolution)) + g_Config.bNativeResolution = true; + else if (g_Config.bNativeResolution && Renderer::AllowCustom()) + { g_Config.bNativeResolution = false; if (Renderer::Allow2x()) {g_Config.b2xResolution = true;} } + else if (Renderer::AllowCustom()) + g_Config.b2xResolution = false; + break; + case XK_4: + OSDChoice = 2; + // Toggle aspect ratio + g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; + break; + case XK_5: + OSDChoice = 3; + // Toggle EFB copy + if (g_Config.bEFBCopyDisable || g_Config.bCopyEFBToTexture) + { + g_Config.bEFBCopyDisable = !g_Config.bEFBCopyDisable; + g_Config.bCopyEFBToTexture = false; + } + else + { + g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture; + } + break; + case XK_6: + OSDChoice = 4; + g_Config.bDisableFog = !g_Config.bDisableFog; + break; + case XK_7: + OSDChoice = 5; + g_Config.bDisableLighting = !g_Config.bDisableLighting; + break; + default: + break; + } + break; + case FocusIn: + if (g_Config.bHideCursor && !bPaused +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + && !g_Config.RenderToMainframe +#endif + ) + XDefineCursor(GLWin.dpy, GLWin.win, GLWin.blankCursor); + break; + case FocusOut: + if (g_Config.bHideCursor && !bPaused +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + && !g_Config.RenderToMainframe +#endif + ) + XUndefineCursor(GLWin.dpy, GLWin.win); + break; + case ConfigureNotify: + Window winDummy; + unsigned int borderDummy; + XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, + &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth); + s_backbuffer_width = GLWin.width; + s_backbuffer_height = GLWin.height; + // Save windowed mode size for return from fullscreen + if (!GLWin.fs) + { + GLWin.winWidth = GLWin.width; + GLWin.winHeight = GLWin.height; + } + break; + case ClientMessage: + if ((ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", False)) + g_VideoInitialize.pKeyPress(0x1b, False, False); + if ((ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "TOGGLE_FULLSCREEN", False)) + ToggleFullscreenMode(); + if (g_Config.bHideCursor && + (ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "PAUSE", False)) + { + bPaused = True; + XUndefineCursor(GLWin.dpy, GLWin.win); + } + if (g_Config.bHideCursor && + (ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "RESUME", False)) + { + bPaused = False; + XDefineCursor(GLWin.dpy, GLWin.win, GLWin.blankCursor); + } +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + if (g_Config.RenderToMainframe && + (ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "RESIZE", False)) + { + GLWin.panel->GetSize((int *)&GLWin.width, (int *)&GLWin.height); + GLWin.panel->GetPosition(&GLWin.x, &GLWin.y); + XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y, GLWin.width, GLWin.height); + } + if (g_Config.RenderToMainframe && + (ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "FOCUSIN", False)) + { + GLWin.panel->SetFocus(); + if (g_Config.bHideCursor) + XDefineCursor(GLWin.dpy, GLWin.win, GLWin.blankCursor); + } + if (g_Config.RenderToMainframe && g_Config.bHideCursor && + (ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "FOCUSOUT", False)) + XUndefineCursor(GLWin.dpy, GLWin.win); +#endif + break; + default: + break; + } + } + Common::SleepCurrentThread(20); + } + return 0; } #endif @@ -396,7 +568,7 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight GLWin.dpy = XOpenDisplay(0); #if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) - GLWin.panel = (wxPanel *)g_VideoInitialize.pWindowHandle; + GLWin.panel = (wxPanel *)g_VideoInitialize.pPanel; #endif g_VideoInitialize.pWindowHandle = (Display *)GLWin.dpy; GLWin.screen = DefaultScreen(GLWin.dpy); @@ -426,9 +598,11 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight exit(0); // TODO: Don't bring down entire Emu } // Create a color map and set the event masks - GLWin.attr.colormap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, GLWin.vi->screen), GLWin.vi->visual, AllocNone); + GLWin.attr.colormap = XCreateColormap(GLWin.dpy, + RootWindow(GLWin.dpy, GLWin.vi->screen), GLWin.vi->visual, AllocNone); GLWin.attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask | ResizeRedirectMask; + GLWin.attr.background_pixel = BlackPixel(GLWin.dpy, GLWin.screen); GLWin.attr.border_pixel = 0; XkbSetDetectableAutoRepeat(GLWin.dpy, True, NULL); @@ -483,6 +657,11 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight GLWin.fullHeight = DisplayHeight(GLWin.dpy, GLWin.screen); #endif +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + if (g_Config.RenderToMainframe) + g_VideoInitialize.pKeyPress(0, False, False); +#endif + CreateXWindow(); g_VideoInitialize.pXWindow = (Window *) &GLWin.win; @@ -525,6 +704,19 @@ bool OpenGL_MakeCurrent() ERROR_LOG(VIDEO, "no Direct Rendering possible!"); } + if (GLWin.fs) + { +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + if (g_Config.RenderToMainframe) + { + GLWin.fs = False; + g_VideoInitialize.pKeyPress(0x1d, False, False); + } + else +#endif + X11_EWMH_Fullscreen(_NET_WM_STATE_ADD); + } + // Hide the cursor now if (g_Config.bHideCursor) XDefineCursor (GLWin.dpy, GLWin.win, GLWin.blankCursor); @@ -581,134 +773,6 @@ void OpenGL_Update() s_backbuffer_height = height; #elif defined(HAVE_X11) && HAVE_X11 - // We just check all of our events here - XEvent event; - KeySym key; - int num_events; - for (num_events = XPending(GLWin.dpy);num_events > 0;num_events--) { - XNextEvent(GLWin.dpy, &event); - switch(event.type) { - case KeyPress: - key = XLookupKeysym((XKeyEvent*)&event, 0); - switch (key) - { - case XK_F4: - if(event.xkey.state & Mod1Mask) - { - g_VideoInitialize.pKeyPress(0x1b, False, False); - break; - } - case XK_F1: case XK_F2: case XK_F3: case XK_F5: - case XK_F6: case XK_F7: case XK_F8: case XK_F9: - g_VideoInitialize.pKeyPress(key - 0xff4e, - event.xkey.state & ShiftMask, - event.xkey.state & ControlMask); - break; - case XK_Escape: - if (GLWin.fs) - { - ToggleFullscreenMode(); - #if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) - if (!g_Config.RenderToMainframe) - #endif - { - XEvent mapevent; - do { - XMaskEvent(GLWin.dpy, StructureNotifyMask, &mapevent); - } while ((mapevent.type != MapNotify) || (mapevent.xmap.event != GLWin.win)); - } - } - g_VideoInitialize.pKeyPress(0x1c, False, False); - break; - case XK_Return: - if (event.xkey.state & Mod1Mask) - ToggleFullscreenMode(); - break; - case XK_3: - OSDChoice = 1; - // Toggle native resolution - if (!(g_Config.bNativeResolution || g_Config.b2xResolution)) - g_Config.bNativeResolution = true; - else if (g_Config.bNativeResolution && Renderer::AllowCustom()) - { g_Config.bNativeResolution = false; if (Renderer::Allow2x()) {g_Config.b2xResolution = true;} } - else if (Renderer::AllowCustom()) - g_Config.b2xResolution = false; - break; - case XK_4: - OSDChoice = 2; - // Toggle aspect ratio - g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; - break; - case XK_5: - OSDChoice = 3; - // Toggle EFB copy - if (g_Config.bEFBCopyDisable || g_Config.bCopyEFBToTexture) - { - g_Config.bEFBCopyDisable = !g_Config.bEFBCopyDisable; - g_Config.bCopyEFBToTexture = false; - } - else - { - g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture; - } - break; - case XK_6: - OSDChoice = 4; - g_Config.bDisableFog = !g_Config.bDisableFog; - break; - case XK_7: - OSDChoice = 5; - g_Config.bDisableLighting = !g_Config.bDisableLighting; - break; - - default: - break; - } - break; - case FocusIn: - if (g_Config.bHideCursor) - XDefineCursor(GLWin.dpy, GLWin.win, GLWin.blankCursor); - break; - case FocusOut: - if (g_Config.bHideCursor && !GLWin.fs) - XUndefineCursor(GLWin.dpy, GLWin.win); - break; - case ConfigureNotify: - Window winDummy; - unsigned int borderDummy; - XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, - &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth); - s_backbuffer_width = GLWin.width; - s_backbuffer_height = GLWin.height; - // Save windowed mode size for return from fullscreen - if (!GLWin.fs) - { - GLWin.winWidth = GLWin.width; - GLWin.winHeight = GLWin.height; - } - break; - case ClientMessage: - if ((ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", False)) - g_VideoInitialize.pKeyPress(0x1b, False, False); - if ((ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "TOGGLE_FULLSCREEN", False)) - ToggleFullscreenMode(); -#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) - if (g_Config.RenderToMainframe && !GLWin.fs && - (ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "MAIN_RESIZED", False)) - { - GLWin.panel->GetSize((int *)&GLWin.width, (int *)&GLWin.height); - GLWin.panel->GetPosition(&GLWin.x, &GLWin.y); - XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y, GLWin.width, GLWin.height); - } - if (g_Config.RenderToMainframe && !GLWin.fs && - (ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "WINDOW_REFOCUS", False)) - XSetInputFocus(GLWin.dpy, GLWin.win, RevertToPointerRoot, CurrentTime); -#endif - break; - default: - break; - } - } #endif } @@ -748,6 +812,9 @@ void OpenGL_Shutdown() } #elif defined(HAVE_X11) && HAVE_X11 DestroyXWindow(); + if (GLWin.xEventThread) + GLWin.xEventThread->WaitForDeath(); + GLWin.xEventThread = NULL; #if defined(HAVE_XRANDR) && HAVE_XRANDR if (GLWin.fullSize >= 0) XRRFreeScreenConfigInfo(GLWin.screenConfig); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h index ddd6ec3636..921729ee60 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h @@ -31,14 +31,14 @@ #include #include -#else // linux basic definitions +#else // linux and apple basic definitions #if defined(USE_WX) && USE_WX #include #include "wx/wx.h" #include "wx/glcanvas.h" + #elif defined(HAVE_X11) && HAVE_X11 -#define I_NEED_OS2_H // HAXXOR #include #include #if defined(HAVE_GTK2) && HAVE_GTK2 // Needed for render to main @@ -46,9 +46,23 @@ #include #include #endif +#include +#include +#include +#include "Thread.h" +#if defined(HAVE_XRANDR) && HAVE_XRANDR +#include +#endif // XRANDR +// EWMH state actions, see +// http://freedesktop.org/wiki/Specifications/wm-spec?action=show&redirect=Standards%2Fwm-spec +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + #elif defined(USE_SDL) && USE_SDL #include #include + #elif defined(HAVE_COCOA) && HAVE_COCOA #include #include "cocoaGL.h" @@ -70,15 +84,6 @@ #endif #ifndef _WIN32 -#if defined(HAVE_X11) && HAVE_X11 -#include -#include -#include - -#if defined(HAVE_XRANDR) && HAVE_XRANDR -#include -#endif // XRANDR -#endif // X11 #include #include @@ -102,6 +107,7 @@ typedef struct { Bool doubleBuffered; int fullWidth, fullHeight; int winWidth, winHeight; + Common::Thread *xEventThread; #if defined(HAVE_XRANDR) && HAVE_XRANDR XRRScreenConfiguration *screenConfig; Rotation screenRotation; diff --git a/Source/Plugins/Plugin_Wiimote/Src/main.cpp b/Source/Plugins/Plugin_Wiimote/Src/main.cpp index f6b26a2f03..1ab892cda3 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/main.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/main.cpp @@ -397,12 +397,14 @@ bool IsFocus() return false; #elif defined HAVE_X11 && HAVE_X11 Window GLWin = *(Window *)g_WiimoteInitialize.pXWindow; + bool bFocus = False; +#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) + bFocus = (wxPanel *)g_WiimoteInitialize.pPanel == wxWindow::FindFocus(); +#endif Window FocusWin; int Revert; XGetInputFocus(WMdisplay, &FocusWin, &Revert); - XWindowAttributes WinAttribs; - XGetWindowAttributes (WMdisplay, GLWin, &WinAttribs); - return (GLWin != 0 && (GLWin == FocusWin || WinAttribs.override_redirect)); + return (GLWin == FocusWin || bFocus); #else return true; #endif