Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions frame/popupwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "popupwindow.h"

#include <xcb/xcb.h>

Check warning on line 7 in frame/popupwindow.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <xcb/xcb.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

DS_BEGIN_NAMESPACE
PopupWindow::PopupWindow(QWindow *parent)
: QQuickApplicationWindow(parent)
Expand All @@ -22,6 +24,12 @@

connect(this, &QWindow::screenChanged, this, setMaximumSize);
setMaximumSize();

connect(this, &QWindow::visibleChanged, this, [this]() {
if (!isVisible()) {
setX11GrabFocusTransition(false);
}
});
}

void PopupWindow::mouseReleaseEvent(QMouseEvent *event)
Expand Down Expand Up @@ -49,4 +57,42 @@
return QQuickApplicationWindow::mouseMoveEvent(event);
}

void PopupWindow::setX11GrabFocusTransition(bool transition)
{
if (m_x11GrabFocusTransition == transition) {
return;
}

m_x11GrabFocusTransition = transition;
Q_EMIT x11GrabFocusTransitionChanged();
}

bool PopupWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
{
if (eventType == QByteArrayLiteral("xcb_generic_event_t")) {
auto *event = static_cast<xcb_generic_event_t *>(message);
if (!event) {
return QQuickApplicationWindow::nativeEvent(eventType, message, result);
}

const uint8_t responseType = event->response_type & ~0x80;
if (responseType == XCB_FOCUS_IN || responseType == XCB_FOCUS_OUT) {
auto *focusEvent = reinterpret_cast<xcb_focus_in_event_t *>(event);

Check warning on line 80 in frame/popupwindow.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Variable 'focusEvent' can be declared as pointer to const
if (focusEvent->event == static_cast<xcb_window_t>(winId())) {
if (responseType == XCB_FOCUS_OUT && focusEvent->mode == XCB_NOTIFY_MODE_GRAB) {
setX11GrabFocusTransition(true);
Q_EMIT x11FocusOutByGrab();
} else if (responseType == XCB_FOCUS_IN && focusEvent->mode == XCB_NOTIFY_MODE_UNGRAB) {
Q_EMIT x11FocusInByUngrab();
setX11GrabFocusTransition(false);
} else if (responseType == XCB_FOCUS_IN && focusEvent->mode != XCB_NOTIFY_MODE_GRAB) {
setX11GrabFocusTransition(false);
}
}
}
}

return QQuickApplicationWindow::nativeEvent(eventType, message, result);
}

DS_END_NAMESPACE
10 changes: 10 additions & 0 deletions frame/popupwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,28 @@
{
Q_OBJECT
Q_PROPERTY(QWindow *transientParent READ transientParent WRITE setTransientParent NOTIFY transientParentChanged)
Q_PROPERTY(bool x11GrabFocusTransition READ x11GrabFocusTransition NOTIFY x11GrabFocusTransitionChanged)
QML_NAMED_ELEMENT(PopupWindow)

public:
PopupWindow(QWindow *parent = nullptr);

Check warning on line 19 in frame/popupwindow.h

View workflow job for this annotation

GitHub Actions / cppcheck

Class 'PopupWindow' has a constructor with 1 argument that is not explicit. Such, so called "Converting constructors", should in general be explicit for type safety reasons as that prevents unintended implicit conversions.
bool x11GrabFocusTransition() const { return m_x11GrabFocusTransition; }

protected:
void mouseReleaseEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override;

signals:
void x11GrabFocusTransitionChanged();
void x11FocusOutByGrab();
void x11FocusInByUngrab();

private:
void setX11GrabFocusTransition(bool transition);
bool m_dragging;
bool m_pressing;
bool m_x11GrabFocusTransition = false;
};
DS_END_NAMESPACE
64 changes: 63 additions & 1 deletion frame/qml/PanelPopup.qml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Item {
property int popupX: 0
property int popupY: 0
property bool readyBinding: false
property bool grabInactivePending: false
property int grabInactiveTimeout: 200
// WM_NAME, used for kwin.
property string windowTitle: "dde-shell/panelpopup"
width: popup.childrenRect.width
Expand Down Expand Up @@ -84,8 +86,24 @@ Item {
popupWindow.requestActivate()
}
}
Timer {
id: grabInactiveTimer
interval: control.grabInactiveTimeout
repeat: false
onTriggered: {
control.grabInactivePending = false
if (!popupWindow || !readyBinding || popupWindow.currentItem !== control || !popup.visible) {
return
}
if (!popupWindow.active) {
control.close()
}
}
}
function close()
{
grabInactivePending = false
grabInactiveTimer.stop()
if (!popupWindow)
return

Expand All @@ -103,11 +121,55 @@ Item {
{
if (!popupWindow)
return
if (popupWindow.currentItem !== control || !popup.visible) {
control.grabInactivePending = false
grabInactiveTimer.stop()
return
}
if (popupWindow.active) {
control.grabInactivePending = false
grabInactiveTimer.stop()
return
}
if (control.grabInactivePending || popupWindow.x11GrabFocusTransition) {
return
}
// TODO why activeChanged is not emit.
if (popupWindow && !popupWindow.active) {
if (!popupWindow.active) {
control.close()
}
}

function onX11FocusOutByGrab()
{
if (!popupWindow || !readyBinding || !popup.visible || popupWindow.currentItem !== control) {
return
}
control.grabInactivePending = true
grabInactiveTimer.start()
}

function onX11FocusInByUngrab()
{
if (!popupWindow || popupWindow.currentItem !== control || !control.grabInactivePending) {
return
}
control.grabInactivePending = false
grabInactiveTimer.stop()

Qt.callLater(function() {
if (!popupWindow
|| !readyBinding
|| popupWindow.currentItem !== control
|| !popup.visible
|| control.grabInactivePending) {
return
}
if (!popupWindow.active) {
control.close()
}
})
}
}

Item {
Expand Down
Loading