diff --git a/include/boo/IWindow.hpp b/include/boo/IWindow.hpp index ce05870..8fcb0b1 100644 --- a/include/boo/IWindow.hpp +++ b/include/boo/IWindow.hpp @@ -89,7 +89,7 @@ enum EModifierKey class IWindowCallback { -public: +public: virtual void resized(const SWindowRect& rect) {(void)rect;} virtual void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) @@ -98,6 +98,10 @@ public: {(void)coord;(void)button;(void)mods;} virtual void mouseMove(const SWindowCoord& coord) {(void)coord;} + virtual void mouseEnter(const SWindowCoord& coord) + {(void)coord;} + virtual void mouseLeave(const SWindowCoord& coord) + {(void)coord;} virtual void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) {(void)coord;(void)scroll;} @@ -119,6 +123,13 @@ public: virtual void modKeyDown(EModifierKey mod, bool isRepeat) {(void)mod;(void)isRepeat;} virtual void modKeyUp(EModifierKey mod) {(void)mod;} + virtual void focusLost() {} + virtual void focusGained() {} + virtual void windowMoved(const SWindowRect& rect) + { (void)rect; } + + virtual void destroyed() + {} }; enum ETouchType diff --git a/lib/x11/ApplicationXlib.hpp b/lib/x11/ApplicationXlib.hpp index 8bc308e..a067deb 100644 --- a/lib/x11/ApplicationXlib.hpp +++ b/lib/x11/ApplicationXlib.hpp @@ -45,20 +45,12 @@ static Window GetWindowOfEvent(XEvent* event, bool& windowEvent) return event->xconfigure.window; } case KeyPress: - { - windowEvent = true; - return event->xkey.window; - } case KeyRelease: { windowEvent = true; return event->xkey.window; } case ButtonPress: - { - windowEvent = true; - return event->xbutton.window; - } case ButtonRelease: { windowEvent = true; @@ -69,6 +61,18 @@ static Window GetWindowOfEvent(XEvent* event, bool& windowEvent) windowEvent = true; return event->xmotion.window; } + case EnterNotify: + case LeaveNotify: + { + windowEvent = true; + return event->xcrossing.window; + } + case FocusIn: + case FocusOut: + { + windowEvent = true; + return event->xfocus.window; + } case GenericEvent: { if (event->xgeneric.extension == XINPUT_OPCODE) @@ -223,12 +227,12 @@ public: return 1; /* Spawn client thread */ - int clientReturn = 0; + int clientReturn = INT_MIN; std::thread clientThread([&]() {clientReturn = m_callback.appMain(this);}); /* Begin application event loop */ - while (true) + while (clientReturn == INT_MIN) { fd_set fds; FD_ZERO(&fds); diff --git a/lib/x11/WindowXlib.cpp b/lib/x11/WindowXlib.cpp index 2674a8d..1ef5731 100644 --- a/lib/x11/WindowXlib.cpp +++ b/lib/x11/WindowXlib.cpp @@ -451,7 +451,7 @@ public: XSetWindowAttributes swa; swa.colormap = m_colormapId; swa.border_pixmap = None; - swa.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask; + swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask | LeaveWindowMask | EnterWindowMask; m_windowId = XCreateWindow(display, screen->root, x, y, w, h, 10, CopyFromParent, CopyFromParent, selectedVisual, @@ -471,16 +471,7 @@ public: /* Register netwm extension atom for window closing */ -#if 0 - xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, S_ATOMS->m_wmProtocols, - XCB_ATOM_ATOM, 32, 1, &S_ATOMS->m_wmDeleteWindow); - const xcb_atom_t wm_protocols[1] = { - S_ATOMS->m_wmDeleteWindow, - }; - xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, - S_ATOMS->m_wmProtocols, 4, - 32, 1, wm_protocols); -#endif + XSetWMProtocols(m_xDisp, m_windowId, &S_ATOMS->m_wmDeleteWindow, 1); /* Set the title of the window */ const unsigned char* c_title = (unsigned char*)title.c_str(); @@ -760,10 +751,21 @@ public: XEvent* event = (XEvent*)e; switch (event->type) { + case ClientMessage: + { + if (event->xclient.data.l[0] == S_ATOMS->m_wmDeleteWindow && m_callback) + m_callback->destroyed(); + return; + } case Expose: { - m_wx = event->xexpose.x; - m_wy = event->xexpose.y; + Window nw; + XWindowAttributes wxa; + int x, y; + XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xexpose.x, event->xexpose.y, &x, &y, &nw); + XGetWindowAttributes(m_xDisp, m_windowId, &wxa); + m_wx = x - wxa.x; + m_wy = y - wxa.y; m_ww = event->xexpose.width; m_wh = event->xexpose.height; if (m_callback) @@ -776,19 +778,21 @@ public: } case ConfigureNotify: { - if (event->xconfigure.width && event->xconfigure.height) - { - m_wx = event->xconfigure.x; - m_wy = event->xconfigure.y; - m_ww = event->xconfigure.width; - m_wh = event->xconfigure.height; + Window nw; + XWindowAttributes wxa; + int x, y; + XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xconfigure.x, event->xconfigure.y, &x, &y, &nw); + XGetWindowAttributes(m_xDisp, m_windowId, &wxa); + m_wx = x - wxa.x; + m_wy = y - wxa.y; + m_ww = event->xconfigure.width; + m_wh = event->xconfigure.height; - if (m_callback) - { - SWindowRect rect = - { {m_wx, m_wy}, {m_ww, m_wh} }; - m_callback->resized(rect); - } + if (m_callback) + { + SWindowRect rect = + { {m_wx, m_wy}, {m_ww, m_wh} }; + m_callback->windowMoved(rect); } return; } @@ -900,6 +904,18 @@ public: } return; } + case FocusIn: + { + if (m_callback) + m_callback->focusGained(); + return; + } + case FocusOut: + { + if (m_callback) + m_callback->focusLost(); + return; + } case MotionNotify: { if (m_callback) @@ -915,6 +931,36 @@ public: } return; } + case EnterNotify: + { + if (m_callback) + { + getWindowFrame(m_wx, m_wy, m_ww, m_wh); + SWindowCoord coord = + { + {(unsigned)event->xcrossing.x, (unsigned)event->xcrossing.y}, + {(unsigned)(event->xcrossing.x / m_pixelFactor), (unsigned)(event->xmotion.y / m_pixelFactor)}, + {event->xcrossing.x / (float)m_ww, event->xcrossing.y / (float)m_wh} + }; + m_callback->mouseEnter(coord); + } + return; + } + case LeaveNotify: + { + if (m_callback) + { + getWindowFrame(m_wx, m_wy, m_ww, m_wh); + SWindowCoord coord = + { + {(unsigned)event->xcrossing.x, (unsigned)event->xcrossing.y}, + {(unsigned)(event->xcrossing.x / m_pixelFactor), (unsigned)(event->xmotion.y / m_pixelFactor)}, + {event->xcrossing.x / (float)m_ww, event->xcrossing.y / (float)m_wh} + }; + m_callback->mouseLeave(coord); + } + return; + } case GenericEvent: { if (event->xgeneric.extension == XINPUT_OPCODE) diff --git a/test/main.cpp b/test/main.cpp index 7074b7c..5fa6e7a 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -128,6 +128,7 @@ struct CTestWindowCallback : IWindowCallback bool m_fullscreenToggleRequested = false; SWindowRect m_lastRect; bool m_rectDirty = false; + bool m_windowInvalid = false; void resized(const SWindowRect& rect) { @@ -148,6 +149,14 @@ struct CTestWindowCallback : IWindowCallback { fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]); } + void mouseEnter(const SWindowCoord &coord) + { + fprintf(stderr, "Mouse entered (%f,%f)\n", coord.norm[0], coord.norm[1]); + } + void mouseLeave(const SWindowCoord &coord) + { + fprintf(stderr, "Mouse left (%f,%f)\n", coord.norm[0], coord.norm[1]); + } void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) { //fprintf(stderr, "Mouse Scroll (%f,%f) (%f,%f)\n", coord.norm[0], coord.norm[1], scroll.delta[0], scroll.delta[1]); @@ -192,6 +201,16 @@ struct CTestWindowCallback : IWindowCallback } + void windowMoved(const SWindowRect& rect) + { + fprintf(stderr, "Moved %d, %d (%d, %d)\n", rect.size[0], rect.size[1], rect.location[0], rect.location[1]); + } + + void destroyed() + { + m_windowInvalid = true; + } + }; struct TestApplicationCallback : IApplicationCallback @@ -367,6 +386,12 @@ struct TestApplicationCallback : IApplicationCallback size_t lastCheck = 0; while (running) { + if (windowCallback.m_windowInvalid) + { + running = false; + break; + } + mainWindow->waitForRetrace(); if (windowCallback.m_rectDirty)