Skip to content

Commit

Permalink
Traktor: More robust handling of focus in X11 UI.
Browse files Browse the repository at this point in the history
  • Loading branch information
apistol78 committed Jun 6, 2024
1 parent d5161f8 commit a6f6424
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 87 deletions.
7 changes: 4 additions & 3 deletions code/Ui/Edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Edit::Edit()
, m_acceptTab(false)
, m_readOnly(false)
, m_hover(false)
, m_modal(false)
{
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
}
Expand Down
1 change: 1 addition & 0 deletions code/Ui/Edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions code/Ui/EventSubject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <algorithm>
#include "Core/Log/Log.h"
#include "Ui/Event.h"
#include "Ui/EventSubject.h"

Expand Down
68 changes: 5 additions & 63 deletions code/Ui/X11/Context.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 0 additions & 4 deletions code/Ui/X11/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
};
Expand Down
1 change: 0 additions & 1 deletion code/Ui/X11/TypesX11.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ struct WidgetData
bool visible = false;
bool enable = true;
bool grabbed = false;
bool focus = false;
};

}
60 changes: 44 additions & 16 deletions code/Ui/X11/WidgetX11Impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -763,7 +782,8 @@ class WidgetX11Impl
return;
}

setFocus();
if ((style & WsFocus) != 0)
setFocus();

MouseButtonDownEvent mouseButtonDownEvent(
m_owner,
Expand All @@ -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(
Expand Down Expand Up @@ -868,13 +888,21 @@ class WidgetX11Impl

CanvasX11 canvasImpl(m_cairo, m_context->getSystemDPI());
Canvas canvas(&canvasImpl, reinterpret_cast< Widget* >(m_owner));

PaintEvent paintEvent(
m_owner,
canvas,
rc != nullptr ? *rc : Rect(Point(0, 0), sz)
);
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);
Expand Down

0 comments on commit a6f6424

Please sign in to comment.