Improve behavior under Wayland

* Add workaround for using QCursor::pos()
* Set window flags and parent of TrayMenu to it is shown
  like a context menu
This commit is contained in:
Martchus 2019-06-22 17:28:09 +02:00
parent 9f9b9124a4
commit 1bdba31c70
11 changed files with 207 additions and 53 deletions

View File

@ -111,7 +111,7 @@ void trigger(bool tray, bool webUi)
trayWidget->showWebUi();
}
if (tray) {
trayWidget->showAtCursor();
trayWidget->showUsingPositioningSettings();
}
}

View File

@ -35,7 +35,7 @@ namespace QtGui {
*/
TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
: QSystemTrayIcon(parent)
, m_trayMenu(this)
, m_trayMenu(new TrayMenu(this, &m_parentWidget))
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
, m_dbusNotificationsEnabled(Settings::values().dbusNotifications)
#endif
@ -43,7 +43,7 @@ TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
, m_messageClickedAction(TrayIconMessageClickedAction::None)
{
// get widget, connection and notifier
const auto &widget(m_trayMenu.widget());
const auto &widget(trayMenu().widget());
const auto &connection(widget.connection());
const auto &notifier(widget.notifier());
@ -71,7 +71,7 @@ TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
tr("Show internal errors"));
m_errorsAction->setVisible(false);
connect(m_errorsAction, &QAction::triggered, this, &TrayIcon::showInternalErrorsDialog);
m_contextMenu.addMenu(m_trayMenu.widget().connectionsMenu());
m_contextMenu.addMenu(trayMenu().widget().connectionsMenu());
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("help-about"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/help-about.svg"))), tr("About")),
&QAction::triggered, &widget, &TrayWidget::showAboutDialog);
@ -109,7 +109,7 @@ TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
// apply settings, this also establishes the connection to Syncthing (according to settings)
// note: it is important to apply settings after all Signals & Slots have been connected (eg. to handle SyncthingConnection::error())
m_trayMenu.widget().applySettings(connectionConfig);
trayMenu().widget().applySettings(connectionConfig);
}
/*!
@ -136,10 +136,10 @@ void TrayIcon::handleActivated(QSystemTrayIcon::ActivationReason reason)
// can't catch that event on Plasma 5 anyways
break;
case QSystemTrayIcon::MiddleClick:
m_trayMenu.widget().showWebUi();
trayMenu().widget().showWebUi();
break;
case QSystemTrayIcon::Trigger: {
m_trayMenu.showAtCursor();
trayMenu().showUsingPositioningSettings();
break;
}
default:;
@ -152,13 +152,13 @@ void TrayIcon::handleMessageClicked()
case TrayIconMessageClickedAction::None:
return;
case TrayIconMessageClickedAction::DismissNotification:
m_trayMenu.widget().dismissNotifications();
trayMenu().widget().dismissNotifications();
break;
case TrayIconMessageClickedAction::ShowInternalErrors:
showInternalErrorsDialog();
break;
case TrayIconMessageClickedAction::ShowWebUi:
m_trayMenu.widget().showWebUi();
trayMenu().widget().showWebUi();
break;
}
}
@ -199,7 +199,7 @@ void TrayIcon::handleErrorsCleared()
void TrayIcon::showInternalError(
const QString &errorMessage, SyncthingErrorCategory category, int networkError, const QNetworkRequest &request, const QByteArray &response)
{
if (!InternalError::isRelevant(m_trayMenu.widget().connection(), category, networkError)) {
if (!InternalError::isRelevant(trayMenu().widget().connection(), category, networkError)) {
return;
}
InternalError error(errorMessage, request.url(), response);

View File

@ -49,7 +49,8 @@ private slots:
void handleErrorsCleared();
private:
TrayMenu m_trayMenu;
QWidget m_parentWidget;
TrayMenu *m_trayMenu;
#ifndef SYNCTHINGTRAY_UNIFY_TRAY_MENUS
QMenu m_contextMenu;
QAction *m_errorsAction;
@ -64,7 +65,7 @@ private:
inline TrayMenu &TrayIcon::trayMenu()
{
return m_trayMenu;
return *m_trayMenu;
}
} // namespace QtGui

View File

@ -7,7 +7,6 @@
#include <qtutilities/misc/dialogutils.h>
#include <QApplication>
#include <QCursor>
#include <QDesktopWidget>
#include <QHBoxLayout>
@ -25,6 +24,7 @@ TrayMenu::TrayMenu(TrayIcon *trayIcon, QWidget *parent)
menuLayout->addWidget(m_trayWidget = new TrayWidget(this));
setLayout(menuLayout);
setPlatformMenu(nullptr);
setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::Popup);
}
QSize TrayMenu::sizeHint() const
@ -50,10 +50,10 @@ void moveInside(QPoint &point, const QSize &innerRect, const QRect &outerRect)
}
}
void TrayMenu::showAtCursor()
void TrayMenu::showUsingPositioningSettings()
{
resize(sizeHint());
QPoint pos(QCursor::pos());
auto pos = Settings::values().appearance.positioning.positionToUse();
moveInside(pos, size(), availableScreenGeometryAtPoint(pos));
popup(pos);
}

View File

@ -20,7 +20,7 @@ public:
TrayIcon *icon();
public slots:
void showAtCursor();
void showUsingPositioningSettings();
private:
TrayWidget *m_trayWidget;

View File

@ -36,7 +36,6 @@
#include <QClipboard>
#include <QCoreApplication>
#include <QCursor>
#include <QDesktopServices>
#include <QDir>
#include <QFontDatabase>
@ -278,12 +277,12 @@ void TrayWidget::showNotifications()
dismissNotifications();
}
void TrayWidget::showAtCursor()
void TrayWidget::showUsingPositioningSettings()
{
if (m_menu) {
m_menu->showAtCursor();
m_menu->showUsingPositioningSettings();
} else {
move(QCursor::pos());
move(Settings::values().appearance.positioning.positionToUse());
show();
}
}

View File

@ -60,7 +60,7 @@ public slots:
void showOwnDeviceId();
void showLog();
void showNotifications();
void showAtCursor();
void showUsingPositioningSettings();
#ifdef SYNCTHINGTRAY_UNIFY_TRAY_MENUS
void showInternalErrorsButton();
void showInternalErrorsDialog();

View File

@ -20,24 +20,13 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="guiElementsLabel">
<property name="text">
<string>Optional GUI elements</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="showTrafficCheckBox">
<property name="text">
<string>Traffic statistics</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="menuSizeHorizontalLayout">
<item>
<widget class="QSpinBox" name="widthSpinBox">
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>150</number>
</property>
@ -67,6 +56,9 @@
</item>
<item>
<widget class="QSpinBox" name="heightSpinBox">
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>150</number>
</property>
@ -79,17 +71,37 @@
</widget>
</item>
<item>
<widget class="QLabel" name="sizePxLabel">
<property name="text">
<string> px</string>
<spacer name="sizeHorizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="guiElementsLabel">
<property name="text">
<string>Optional GUI elements</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="showTrafficCheckBox">
<property name="text">
<string>Traffic statistics</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="frameShapeLabel">
<property name="text">
@ -97,13 +109,6 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="frameShadowLabel">
<property name="text">
<string>Frame shadow</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="frameShapeComboBox">
<item>
@ -128,6 +133,13 @@
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="frameShadowLabel">
<property name="text">
<string>Frame shadow</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="frameShadowComboBox">
<item>
@ -147,14 +159,14 @@
</item>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="tabPosLabel">
<property name="text">
<string>Tab position</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QComboBox" name="tabPosComboBox">
<item>
<property name="text">
@ -178,20 +190,129 @@
</item>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="colorsLabel">
<property name="text">
<string>Colors</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="7" column="1">
<widget class="QCheckBox" name="brightTextColorsCheckBox">
<property name="text">
<string>Bright custom text colors (use for dark color scheme)</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="positioningLabel">
<property name="text">
<string>Positioning</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="8" column="1">
<layout class="QVBoxLayout" name="positioningVerticalLayout">
<item>
<widget class="QCheckBox" name="useCursorPosCheckBox">
<property name="text">
<string>Use cursor position</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="assumeIconPosLabel">
<property name="text">
<string>Otherwise assume tray icon coordinates to be:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="positioningHorizontalLayout">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="xPosLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>x:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="xPosSpinBox">
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>-10000</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="yPosLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>y:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="yPosSpinBox">
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>-10000</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
<item>
<spacer name="positioningHorizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>

View File

@ -19,6 +19,7 @@
#endif
#include <QApplication>
#include <QCursor>
#include <QFile>
#include <QMessageBox>
#include <QSettings>
@ -51,6 +52,14 @@ namespace Settings {
*/
constexpr auto minActiveTimeInSeconds = 5;
/*!
* \brief Returns the position to use.
*/
QPoint Appearance::Positioning::positionToUse() const
{
return useCursorPosition ? QCursor::pos() : assumedIconPosition;
}
/*!
* \brief Contains the processes for launching extra tools.
* \remarks Using std::unordered_map instead of QHash because SyncthingProcess can not be copied.
@ -245,6 +254,11 @@ void restore()
appearance.tabPosition = settings.value(QStringLiteral("tabPos"), appearance.tabPosition).toInt();
appearance.brightTextColors = settings.value(QStringLiteral("brightTextColors"), appearance.brightTextColors).toBool();
v.statusIcons = StatusIconSettings(settings.value(QStringLiteral("statusIcons")).toString());
settings.beginGroup(QStringLiteral("positioning"));
auto &positioning = appearance.positioning;
positioning.useCursorPosition = settings.value(QStringLiteral("useCursorPos"), positioning.useCursorPosition).toBool();
positioning.assumedIconPosition = settings.value(QStringLiteral("assumedIconPos"), positioning.assumedIconPosition).toPoint();
settings.endGroup();
settings.endGroup();
settings.beginGroup(QStringLiteral("startup"));
@ -336,6 +350,10 @@ void save()
settings.setValue(QStringLiteral("tabPos"), appearance.tabPosition);
settings.setValue(QStringLiteral("brightTextColors"), appearance.brightTextColors);
settings.setValue(QStringLiteral("statusIcons"), v.statusIcons.toString());
settings.beginGroup(QStringLiteral("positioning"));
settings.setValue(QStringLiteral("useCursorPos"), appearance.positioning.useCursorPosition);
settings.setValue(QStringLiteral("assumedIconPos"), appearance.positioning.assumedIconPosition);
settings.endGroup();
settings.endGroup();
settings.beginGroup(QStringLiteral("startup"));
@ -469,6 +487,7 @@ Systemd::ServiceStatus Systemd::status(SyncthingConnection &connection) const
const auto isRelevant = service->isSystemdAvailable() && connection.isLocal();
return ServiceStatus{ isRelevant, service->isRunning(), considerForReconnect && isRelevant, showButton && isRelevant };
}
#endif
} // namespace Settings

View File

@ -10,6 +10,7 @@
#include <QByteArray>
#include <QFrame>
#include <QHash>
#include <QPoint>
#include <QSize>
#include <QString>
#include <QTabWidget>
@ -51,6 +52,11 @@ struct SYNCTHINGWIDGETS_EXPORT Appearance {
int frameStyle = QFrame::NoFrame | QFrame::Plain;
int tabPosition = QTabWidget::South;
bool brightTextColors = false;
struct Positioning {
QPoint assumedIconPosition;
bool useCursorPosition = true;
QPoint positionToUse() const;
} positioning;
};
struct SYNCTHINGWIDGETS_EXPORT ToolParameter {

View File

@ -457,6 +457,9 @@ bool AppearanceOptionPage::apply()
settings.tabPosition = ui()->tabPosComboBox->currentIndex();
settings.brightTextColors = ui()->brightTextColorsCheckBox->isChecked();
settings.positioning.useCursorPosition = ui()->useCursorPosCheckBox->isChecked();
settings.positioning.assumedIconPosition = QPoint(ui()->xPosSpinBox->value(), ui()->yPosSpinBox->value());
return true;
}
@ -493,7 +496,12 @@ void AppearanceOptionPage::reset()
}
ui()->frameShadowComboBox->setCurrentIndex(index);
ui()->tabPosComboBox->setCurrentIndex(settings.tabPosition);
ui()->brightTextColorsCheckBox->setChecked(settings.brightTextColors);
ui()->useCursorPosCheckBox->setChecked(settings.positioning.useCursorPosition);
ui()->xPosSpinBox->setValue(settings.positioning.assumedIconPosition.x());
ui()->yPosSpinBox->setValue(settings.positioning.assumedIconPosition.y());
}
// IconsOptionPage