Implemented case differentiation for window focus/notification on Windows and X11
This commit is contained in:
parent
c4435b8a31
commit
60c4f95795
@ -40,6 +40,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#ifdef SFML_OPENGL_ES
|
#ifdef SFML_OPENGL_ES
|
||||||
#include <SFML/Window/EglContext.hpp>
|
#include <SFML/Window/EglContext.hpp>
|
||||||
@ -54,10 +55,11 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
sf::priv::WindowImplX11* fullscreenWindow = NULL;
|
sf::priv::WindowImplX11* fullscreenWindow = NULL;
|
||||||
unsigned long eventMask = FocusChangeMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
|
std::vector<sf::priv::WindowImplX11*> allWindows;
|
||||||
PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask |
|
unsigned long eventMask = FocusChangeMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
|
||||||
EnterWindowMask | LeaveWindowMask;
|
PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask |
|
||||||
|
EnterWindowMask | LeaveWindowMask;
|
||||||
|
|
||||||
// Filter the events received by windows (only allow those matching a specific window)
|
// Filter the events received by windows (only allow those matching a specific window)
|
||||||
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
|
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
|
||||||
@ -303,6 +305,9 @@ WindowImplX11::~WindowImplX11()
|
|||||||
|
|
||||||
// Close the connection with the X server
|
// Close the connection with the X server
|
||||||
CloseDisplay(m_display);
|
CloseDisplay(m_display);
|
||||||
|
|
||||||
|
// Remove this window from the global list of windows (required for focus request)
|
||||||
|
allWindows.erase(std::find(allWindows.begin(), allWindows.end(), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -486,19 +491,50 @@ void WindowImplX11::setKeyRepeatEnabled(bool enabled)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void WindowImplX11::requestFocus()
|
void WindowImplX11::requestFocus()
|
||||||
{
|
{
|
||||||
// Ensure WM hints exist
|
// Focus is only stolen among SFML windows, not between applications
|
||||||
XWMHints* hints = XGetWMHints(m_display, m_window);
|
// Check the global list of windows to find out whether an SFML window has the focus
|
||||||
if (hints == NULL)
|
// Note: can't handle console and other non-SFML windows belonging to the application.
|
||||||
|
bool sfmlWindowFocused = false;
|
||||||
|
for (std::vector<WindowImplX11*>::iterator itr = allWindows.begin(); itr != allWindows.end(); ++itr)
|
||||||
{
|
{
|
||||||
hints = XAllocWMHints();
|
if ((*itr)->hasFocus())
|
||||||
|
{
|
||||||
|
sfmlWindowFocused = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if window is viewable (not on other desktop, ...)
|
||||||
|
// TODO: Check also if minimized
|
||||||
|
XWindowAttributes attributes;
|
||||||
|
if (XGetWindowAttributes(m_display, m_window, &attributes) == 0)
|
||||||
|
{
|
||||||
|
sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl;
|
||||||
|
return; // error getting attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
bool windowViewable = (attributes.map_state == IsViewable);
|
||||||
|
|
||||||
|
if (sfmlWindowFocused && windowViewable)
|
||||||
|
{
|
||||||
|
// Another SFML window of this application has the focus and the current window is viewable:
|
||||||
|
// steal focus (i.e. bring window to the front and give it input focus)
|
||||||
|
XRaiseWindow(m_display, m_window);
|
||||||
|
XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Add Urgency Hint flag (visual notification)
|
// Otherwise: display urgency hint (flashing application logo)
|
||||||
|
// Ensure WM hints exist, allocate if necessary
|
||||||
|
XWMHints* hints = XGetWMHints(m_display, m_window);
|
||||||
|
if (hints == NULL)
|
||||||
|
hints = XAllocWMHints();
|
||||||
|
|
||||||
|
// Add urgency (notification) flag to hints
|
||||||
hints->flags |= XUrgencyHint;
|
hints->flags |= XUrgencyHint;
|
||||||
XSetWMHints(m_display, m_window, hints);
|
XSetWMHints(m_display, m_window, hints);
|
||||||
XFree(hints);
|
XFree(hints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -598,6 +634,9 @@ void WindowImplX11::initialize()
|
|||||||
|
|
||||||
// Flush the commands queue
|
// Flush the commands queue
|
||||||
XFlush(m_display);
|
XFlush(m_display);
|
||||||
|
|
||||||
|
// Add this window to the global list of windows (required for focus request)
|
||||||
|
allWindows.push_back(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -710,6 +749,16 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
|
|||||||
Event event;
|
Event event;
|
||||||
event.type = Event::GainedFocus;
|
event.type = Event::GainedFocus;
|
||||||
pushEvent(event);
|
pushEvent(event);
|
||||||
|
|
||||||
|
// If the window has been previously marked urgent (notification) as a result of a focus request, undo that
|
||||||
|
XWMHints* hints = XGetWMHints(m_display, m_window);
|
||||||
|
if (hints != NULL)
|
||||||
|
{
|
||||||
|
// Remove urgency (notification) flag from hints
|
||||||
|
hints->flags &= ~XUrgencyHint;
|
||||||
|
XSetWMHints(m_display, m_window, hints);
|
||||||
|
XFree(hints);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +369,27 @@ void WindowImplWin32::setKeyRepeatEnabled(bool enabled)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void WindowImplWin32::requestFocus()
|
void WindowImplWin32::requestFocus()
|
||||||
{
|
{
|
||||||
SetForegroundWindow(m_handle);
|
// Allow focus stealing only within the same process; compare PIDs of current and foreground window
|
||||||
|
DWORD thisPid = GetWindowThreadProcessId(m_handle, NULL);
|
||||||
|
DWORD foregroundPid = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
|
||||||
|
|
||||||
|
if (thisPid == foregroundPid)
|
||||||
|
{
|
||||||
|
// The window requesting focus belongs to the same process as the current window: steal focus
|
||||||
|
SetForegroundWindow(m_handle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Different process: don't steal focus, but create a taskbar notification ("flash")
|
||||||
|
FLASHWINFO info;
|
||||||
|
info.cbSize = sizeof(info);
|
||||||
|
info.hwnd = m_handle;
|
||||||
|
info.dwFlags = FLASHW_TRAY;
|
||||||
|
info.dwTimeout = 0;
|
||||||
|
info.uCount = 3;
|
||||||
|
|
||||||
|
FlashWindowEx(&info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user