diff --git a/code/Ui/Edit.cpp b/code/Ui/Edit.cpp index 7864aa2b4..c954e9bed 100644 --- a/code/Ui/Edit.cpp +++ b/code/Ui/Edit.cpp @@ -40,6 +40,7 @@ Edit::Edit() , m_acceptTab(false) , m_readOnly(false) , m_hover(false) +, m_modal(false) { } @@ -76,9 +77,7 @@ bool Edit::create(Widget* parent, const std::wstring& text, uint32_t style, cons void Edit::destroy() { - // If control is destroyed while having focus then no event is issued - // for loosing focus, so we must also enable global event handlers here. - if (getIWidget() != nullptr && hasFocus()) + if (m_modal) Application::getInstance()->enableEventHandlers< KeyDownEvent >(); Widget::destroy(); @@ -261,12 +260,14 @@ void Edit::eventFocus(FocusEvent* event) // global hooks, such as ShortcutTable, to receive events. Application::getInstance()->disableEventHandlers< KeyDownEvent >(); startTimer(500); + m_modal = true; } else { Application::getInstance()->enableEventHandlers< KeyDownEvent >(); stopTimer(); deselect(); + m_modal = false; } update(); } diff --git a/code/Ui/Edit.h b/code/Ui/Edit.h index baff2e8b3..938447341 100644 --- a/code/Ui/Edit.h +++ b/code/Ui/Edit.h @@ -79,6 +79,7 @@ class T_DLLCLASS Edit : public Widget bool m_acceptTab; bool m_readOnly; bool m_hover; + bool m_modal; void eventFocus(FocusEvent* event); diff --git a/code/Ui/EventSubject.cpp b/code/Ui/EventSubject.cpp index 46ea51fed..ad697c6af 100644 --- a/code/Ui/EventSubject.cpp +++ b/code/Ui/EventSubject.cpp @@ -7,6 +7,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include +#include "Core/Log/Log.h" #include "Ui/Event.h" #include "Ui/EventSubject.h" diff --git a/code/Ui/X11/Context.cpp b/code/Ui/X11/Context.cpp index 0c969e4a8..be15fa3aa 100644 --- a/code/Ui/X11/Context.cpp +++ b/code/Ui/X11/Context.cpp @@ -1,6 +1,6 @@ /* * TRAKTOR - * Copyright (c) 2022 Anders Pistol. + * Copyright (c) 2022-2024 Anders Pistol. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -70,9 +70,6 @@ void Context::unbind(WidgetData* widget) if (m_grabbed == widget) m_grabbed = nullptr; - - if (m_focused == widget) - m_focused = nullptr; } void Context::pushModal(WidgetData* widget) @@ -131,71 +128,16 @@ void Context::ungrab(WidgetData* widget) m_grabbed = nullptr; } -void Context::setFocus(WidgetData* widget) -{ - if (m_focused != nullptr) - { - if (m_focused == widget) - return; - - m_focused->focus = false; - - XEvent xevent = {}; - xevent.type = FocusOut; - dispatch(m_focused->window, FocusOut, true, xevent); - - m_focused = nullptr; - } - - if (widget != nullptr) - { - m_focused = widget; - m_focused->focus = true; - - XSetInputFocus(m_display, m_focused->window, RevertToNone, CurrentTime); - - XEvent xevent = {}; - xevent.type = FocusIn; - dispatch(m_focused->window, FocusIn, true, xevent); - } -} - void Context::dispatch(XEvent& xe) { switch (xe.type) { case FocusIn: - { - Window focusWindow; int revertTo; - XGetInputFocus(m_display, &focusWindow, &revertTo); - - auto b = m_bindings.find(focusWindow); - if (b == m_bindings.end()) - break; - - if (m_focused != nullptr) - { - if (m_focused->window == focusWindow) - break; - - m_focused->focus = false; - - XEvent xevent = {}; - xevent.type = FocusOut; - dispatch(m_focused->window, FocusOut, true, xevent); - - m_focused = nullptr; - } - - { - m_focused = b->second.widget; - m_focused->focus = true; + dispatch(xe.xfocus.window, FocusIn, true, xe); + break; - XEvent xevent = {}; - xevent.type = FocusIn; - dispatch(focusWindow, FocusIn, true, xevent); - } - } + case FocusOut: + dispatch(xe.xfocus.window, FocusOut, true, xe); break; case KeyPress: diff --git a/code/Ui/X11/Context.h b/code/Ui/X11/Context.h index 9c14d997e..630e860de 100644 --- a/code/Ui/X11/Context.h +++ b/code/Ui/X11/Context.h @@ -45,9 +45,6 @@ class Context : public Object //! Ungrab input. void ungrab(WidgetData* widget); - //! Set focus. - void setFocus(WidgetData* widget); - //! Dispatch event to callbacks. void dispatch(XEvent& xe); @@ -85,7 +82,6 @@ class Context : public Object SmallMap< Window, Binding > m_bindings; AlignedVector< WidgetData* > m_modal; WidgetData* m_grabbed = nullptr; - WidgetData* m_focused = nullptr; void dispatch(Window window, int32_t eventType, bool always, XEvent& xe); }; diff --git a/code/Ui/X11/TypesX11.h b/code/Ui/X11/TypesX11.h index 0662c7155..eec0b4ad5 100644 --- a/code/Ui/X11/TypesX11.h +++ b/code/Ui/X11/TypesX11.h @@ -22,7 +22,6 @@ struct WidgetData bool visible = false; bool enable = true; bool grabbed = false; - bool focus = false; }; } diff --git a/code/Ui/X11/WidgetX11Impl.h b/code/Ui/X11/WidgetX11Impl.h index cd0ff35f8..961e36556 100644 --- a/code/Ui/X11/WidgetX11Impl.h +++ b/code/Ui/X11/WidgetX11Impl.h @@ -151,6 +151,13 @@ class WidgetX11Impl } else // Becoming hidden. { + if (m_focus) + { + FocusEvent focusEvent(m_owner, false); + m_owner->raiseEvent(&focusEvent); + m_focus = false; + } + if (m_data.mapped) { XUnmapWindow(m_context->getDisplay(), m_data.window); @@ -180,12 +187,15 @@ class WidgetX11Impl virtual bool hasFocus() const override { - return m_data.focus; + Window window; + int revert; + XGetInputFocus(m_context->getDisplay(), &window, &revert); + return window == m_data.window; } virtual void setFocus() override { - m_context->setFocus(&m_data); + XSetInputFocus(m_context->getDisplay(), m_data.window, /*RevertToNone*/0, CurrentTime); } virtual bool hasCapture() const override @@ -536,6 +546,7 @@ class WidgetX11Impl int32_t m_lastMousePress = 0; int32_t m_lastMouseButton = 0; bool m_pendingExposure = false; + bool m_focus = false; bool create(IWidget* parent, int32_t style, Window window, const Rect& rect, bool visible, bool topLevel) { @@ -618,23 +629,31 @@ class WidgetX11Impl } // Focus in. - m_context->bind(&m_data, FocusIn, [this](XEvent& xe) { + m_context->bind(&m_data, FocusIn, [=, this](XEvent& xe) { if (m_xic != 0) XSetICFocus(m_xic); - FocusEvent focusEvent(m_owner, true); - m_owner->raiseEvent(&focusEvent); + if (!m_focus) + { + FocusEvent focusEvent(m_owner, true); + m_owner->raiseEvent(&focusEvent); + m_focus = true; + } }); // Focus out. - m_context->bind(&m_data, FocusOut, [this](XEvent& xe) { + m_context->bind(&m_data, FocusOut, [=, this](XEvent& xe) { if (m_xic != 0) XUnsetICFocus(m_xic); - FocusEvent focusEvent(m_owner, false); - m_owner->raiseEvent(&focusEvent); + if (m_focus) + { + FocusEvent focusEvent(m_owner, false); + m_owner->raiseEvent(&focusEvent); + m_focus = false; + } }); // Key press. - m_context->bind(&m_data, KeyPress, [this](XEvent& xe) { + m_context->bind(&m_data, KeyPress, [=, this](XEvent& xe) { T_FATAL_ASSERT (m_data.enable); int nkeysyms; @@ -671,7 +690,7 @@ class WidgetX11Impl }); // Key release. - m_context->bind(&m_data, KeyRelease, [this](XEvent& xe) { + m_context->bind(&m_data, KeyRelease, [=, this](XEvent& xe) { T_FATAL_ASSERT (m_data.enable); int nkeysyms; @@ -698,7 +717,7 @@ class WidgetX11Impl }); // Motion - m_context->bind(&m_data, MotionNotify, [this](XEvent& xe){ + m_context->bind(&m_data, MotionNotify, [=, this](XEvent& xe){ T_FATAL_ASSERT (m_data.enable); int32_t button = 0; @@ -718,19 +737,19 @@ class WidgetX11Impl }); // Enter - m_context->bind(&m_data, EnterNotify, [this](XEvent& xe){ + m_context->bind(&m_data, EnterNotify, [=, this](XEvent& xe){ MouseTrackEvent mouseTrackEvent(m_owner, true); m_owner->raiseEvent(&mouseTrackEvent); }); // Leave - m_context->bind(&m_data, LeaveNotify, [this](XEvent& xe){ + m_context->bind(&m_data, LeaveNotify, [=, this](XEvent& xe){ MouseTrackEvent mouseTrackEvent(m_owner, false); m_owner->raiseEvent(&mouseTrackEvent); }); // Button press. - m_context->bind(&m_data, ButtonPress, [this](XEvent& xe){ + m_context->bind(&m_data, ButtonPress, [=, this](XEvent& xe){ T_FATAL_ASSERT (m_data.enable); if (xe.xbutton.button == 4 || xe.xbutton.button == 5) @@ -763,7 +782,8 @@ class WidgetX11Impl return; } - setFocus(); + if ((style & WsFocus) != 0) + setFocus(); MouseButtonDownEvent mouseButtonDownEvent( m_owner, @@ -772,7 +792,7 @@ class WidgetX11Impl ); m_owner->raiseEvent(&mouseButtonDownEvent); - int32_t dbt = xe.xbutton.time - m_lastMousePress; + const int32_t dbt = xe.xbutton.time - m_lastMousePress; if (dbt <= 200 && m_lastMouseButton == button) { MouseDoubleClickEvent mouseDoubleClickEvent( @@ -868,6 +888,7 @@ class WidgetX11Impl CanvasX11 canvasImpl(m_cairo, m_context->getSystemDPI()); Canvas canvas(&canvasImpl, reinterpret_cast< Widget* >(m_owner)); + PaintEvent paintEvent( m_owner, canvas, @@ -875,6 +896,13 @@ class WidgetX11Impl ); m_owner->raiseEvent(&paintEvent); + OverlayPaintEvent overlayPaintEvent( + m_owner, + canvas, + rc != nullptr ? *rc : Rect(Point(0, 0), sz) + ); + m_owner->raiseEvent(&overlayPaintEvent); + cairo_pop_group_to_source(m_cairo); cairo_paint(m_cairo); cairo_surface_flush(m_surface);