Skip to content

Commit 6121cc9

Browse files
committed
Tray workarounds backport for 2.4 #6545
* Disentangle the previous 'qdbusWorkarounds' into three different things * Make not trusting tray.isVisible() a new workaround * Introduce env vars for all workaround flags * Use the workaround flags for OSX * Determine workaround flags for KDE when the plasma integration plugin is missing (cherry picked from commit 99116ac) (cherry picked from commit ca033b9) (cherry picked from commit 8b1d979) (cherry picked from commit a0d6139)
1 parent 5d09814 commit 6121cc9

File tree

2 files changed

+127
-84
lines changed

2 files changed

+127
-84
lines changed

src/gui/owncloudgui.cpp

+117-79
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,13 @@ const char propertyAccountC[] = "oc_account";
5050
ownCloudGui::ownCloudGui(Application *parent)
5151
: QObject(parent)
5252
, _tray(0)
53-
,
5453
#if defined(Q_OS_MAC)
55-
_settingsDialog(new SettingsDialogMac(this))
56-
,
54+
, _settingsDialog(new SettingsDialogMac(this))
5755
#else
58-
_settingsDialog(new SettingsDialog(this))
59-
,
56+
, _settingsDialog(new SettingsDialog(this))
6057
#endif
61-
_logBrowser(0)
62-
, _contextMenuVisibleOsx(false)
58+
, _logBrowser(0)
6359
, _recentActionsMenu(0)
64-
, _qdbusmenuWorkaround(false)
6560
, _app(parent)
6661
{
6762
_tray = new Systray();
@@ -117,7 +112,7 @@ void ownCloudGui::slotOpenSettingsDialog()
117112

118113
void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason)
119114
{
120-
if (_qdbusmenuWorkaround) {
115+
if (_workaroundFakeDoubleClick) {
121116
static QElapsedTimer last_click;
122117
if (last_click.isValid() && last_click.elapsed() < 200) {
123118
return;
@@ -381,29 +376,31 @@ void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *men
381376

382377
void ownCloudGui::slotContextMenuAboutToShow()
383378
{
384-
// For some reason on OS X _contextMenu->isVisible returns always false
385-
_contextMenuVisibleOsx = true;
379+
_contextMenuVisibleManual = true;
386380

387381
// Update icon in sys tray, as it might change depending on the context menu state
388382
slotComputeOverallSyncStatus();
383+
384+
if (!_workaroundNoAboutToShowUpdate) {
385+
updateContextMenu();
386+
}
389387
}
390388

391389
void ownCloudGui::slotContextMenuAboutToHide()
392390
{
393-
// For some reason on OS X _contextMenu->isVisible returns always false
394-
_contextMenuVisibleOsx = false;
391+
_contextMenuVisibleManual = false;
395392

396393
// Update icon in sys tray, as it might change depending on the context menu state
397394
slotComputeOverallSyncStatus();
398395
}
399396

400397
bool ownCloudGui::contextMenuVisible() const
401398
{
402-
#ifdef Q_OS_MAC
403-
return _contextMenuVisibleOsx;
404-
#else
399+
// On some platforms isVisible doesn't work and always returns false,
400+
// elsewhere aboutToHide is unreliable.
401+
if (_workaroundManualVisibility)
402+
return _contextMenuVisibleManual;
405403
return _contextMenu->isVisible();
406-
#endif
407404
}
408405

409406
static bool minimalTrayMenu()
@@ -426,12 +423,36 @@ static bool updateWhileVisible()
426423
}
427424
}
428425

429-
static QByteArray forceQDBusTrayWorkaround()
426+
static QByteArray envForceQDBusTrayWorkaround()
430427
{
431428
static QByteArray var = qgetenv("OWNCLOUD_FORCE_QDBUS_TRAY_WORKAROUND");
432429
return var;
433430
}
434431

432+
static QByteArray envForceWorkaroundShowAndHideTray()
433+
{
434+
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_SHOW_HIDE");
435+
return var;
436+
}
437+
438+
static QByteArray envForceWorkaroundNoAboutToShowUpdate()
439+
{
440+
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_NO_ABOUT_TO_SHOW");
441+
return var;
442+
}
443+
444+
static QByteArray envForceWorkaroundFakeDoubleClick()
445+
{
446+
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_FAKE_DOUBLE_CLICK");
447+
return var;
448+
}
449+
450+
static QByteArray envForceWorkaroundManualVisibility()
451+
{
452+
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_MANUAL_VISIBILITY");
453+
return var;
454+
}
455+
435456
void ownCloudGui::setupContextMenu()
436457
{
437458
if (_contextMenu) {
@@ -454,51 +475,65 @@ void ownCloudGui::setupContextMenu()
454475
return;
455476
}
456477

457-
// Enables workarounds for bugs introduced in Qt 5.5.0
458-
// In particular QTBUG-47863 #3672 (tray menu fails to update and
459-
// becomes unresponsive) and QTBUG-48068 #3722 (click signal is
460-
// emitted several times)
461-
// The Qt version check intentionally uses 5.0.0 (where platformMenu()
462-
// was introduced) instead of 5.5.0 to avoid issues where the Qt
463-
// version used to build is different from the one used at runtime.
464-
// If we build with 5.6.1 or newer, we can skip this because the
465-
// bugs should be fixed there.
466-
#ifdef Q_OS_LINUX
467-
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(5, 6, 0))
468-
if (qVersion() == QByteArray("5.5.0")) {
469-
QObject *platformMenu = reinterpret_cast<QObject *>(_tray->contextMenu()->platformMenu());
470-
if (platformMenu
471-
&& platformMenu->metaObject()->className() == QLatin1String("QDBusPlatformMenu")) {
472-
_qdbusmenuWorkaround = true;
473-
qCWarning(lcApplication) << "Enabled QDBusPlatformMenu workaround";
474-
}
475-
}
476-
#endif
477-
#endif
478+
auto applyEnvVariable = [](bool *sw, const QByteArray &value) {
479+
if (value == "1")
480+
*sw = true;
481+
if (value == "0")
482+
*sw = false;
483+
};
478484

479-
if (forceQDBusTrayWorkaround() == "1") {
480-
_qdbusmenuWorkaround = true;
481-
} else if (forceQDBusTrayWorkaround() == "0") {
482-
_qdbusmenuWorkaround = false;
485+
// This is an old compound flag that people might still depend on
486+
bool qdbusmenuWorkarounds = false;
487+
applyEnvVariable(&qdbusmenuWorkarounds, envForceQDBusTrayWorkaround());
488+
if (qdbusmenuWorkarounds) {
489+
_workaroundFakeDoubleClick = true;
490+
_workaroundNoAboutToShowUpdate = true;
491+
_workaroundShowAndHideTray = true;
483492
}
484493

485-
// When the qdbusmenuWorkaround is necessary, we can't do on-demand updates
486-
// because the workaround is to hide and show the tray icon.
487-
if (_qdbusmenuWorkaround) {
488-
connect(&_workaroundBatchTrayUpdate, &QTimer::timeout, this, &ownCloudGui::updateContextMenu);
489-
_workaroundBatchTrayUpdate.setInterval(30 * 1000);
490-
_workaroundBatchTrayUpdate.setSingleShot(true);
491-
} else {
492-
// Update the context menu whenever we're about to show it
493-
// to the user.
494494
#ifdef Q_OS_MAC
495-
// https://bugreports.qt.io/browse/QTBUG-54633
496-
connect(_contextMenu.data(), SIGNAL(aboutToShow()), SLOT(slotContextMenuAboutToShow()));
497-
connect(_contextMenu.data(), SIGNAL(aboutToHide()), SLOT(slotContextMenuAboutToHide()));
498-
#else
499-
connect(_contextMenu.data(), &QMenu::aboutToShow, this, &ownCloudGui::updateContextMenu);
495+
// https://bugreports.qt.io/browse/QTBUG-54633
496+
_workaroundNoAboutToShowUpdate = true;
497+
_workaroundManualVisibility = true;
500498
#endif
499+
500+
#ifdef Q_OS_LINUX
501+
// For KDE sessions if the platform plugin is missing,
502+
// neither aboutToShow() updates nor the isVisible() call
503+
// work. At least aboutToHide is reliable.
504+
// https://github.com/owncloud/client/issues/6545
505+
static QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
506+
static QByteArray desktopSession = qgetenv("DESKTOP_SESSION");
507+
bool isKde =
508+
xdgCurrentDesktop.contains("KDE")
509+
|| desktopSession.contains("plasma")
510+
|| desktopSession.contains("kde");
511+
QObject *platformMenu = reinterpret_cast<QObject *>(_tray->contextMenu()->platformMenu());
512+
if (isKde && platformMenu && platformMenu->metaObject()->className() == QLatin1String("QDBusPlatformMenu")) {
513+
_workaroundManualVisibility = true;
514+
_workaroundNoAboutToShowUpdate = true;
501515
}
516+
#endif
517+
518+
applyEnvVariable(&_workaroundNoAboutToShowUpdate, envForceWorkaroundNoAboutToShowUpdate());
519+
applyEnvVariable(&_workaroundFakeDoubleClick, envForceWorkaroundFakeDoubleClick());
520+
applyEnvVariable(&_workaroundShowAndHideTray, envForceWorkaroundShowAndHideTray());
521+
applyEnvVariable(&_workaroundManualVisibility, envForceWorkaroundManualVisibility());
522+
523+
qCInfo(lcApplication) << "Tray menu workarounds:"
524+
<< "noabouttoshow:" << _workaroundNoAboutToShowUpdate
525+
<< "fakedoubleclick:" << _workaroundFakeDoubleClick
526+
<< "showhide:" << _workaroundShowAndHideTray
527+
<< "manualvisibility:" << _workaroundManualVisibility;
528+
529+
530+
connect(&_delayedTrayUpdateTimer, &QTimer::timeout, this, &ownCloudGui::updateContextMenu);
531+
_delayedTrayUpdateTimer.setInterval(2 * 1000);
532+
_delayedTrayUpdateTimer.setSingleShot(true);
533+
534+
connect(_contextMenu.data(), SIGNAL(aboutToShow()), SLOT(slotContextMenuAboutToShow()));
535+
// unfortunately aboutToHide is unreliable, it seems to work on OSX though
536+
connect(_contextMenu.data(), SIGNAL(aboutToHide()), SLOT(slotContextMenuAboutToHide()));
502537

503538
// Populate the context menu now.
504539
updateContextMenu();
@@ -510,13 +545,21 @@ void ownCloudGui::updateContextMenu()
510545
return;
511546
}
512547

513-
if (_qdbusmenuWorkaround) {
548+
// If it's visible, we can't update live, and it won't be updated lazily: reschedule
549+
if (contextMenuVisible() && !updateWhileVisible() && _workaroundNoAboutToShowUpdate) {
550+
if (!_delayedTrayUpdateTimer.isActive()) {
551+
_delayedTrayUpdateTimer.start();
552+
}
553+
return;
554+
}
555+
556+
if (_workaroundShowAndHideTray) {
514557
// To make tray menu updates work with these bugs (see setupContextMenu)
515558
// we need to hide and show the tray icon. We don't want to do that
516559
// while it's visible!
517560
if (contextMenuVisible()) {
518-
if (!_workaroundBatchTrayUpdate.isActive()) {
519-
_workaroundBatchTrayUpdate.start();
561+
if (!_delayedTrayUpdateTimer.isActive()) {
562+
_delayedTrayUpdateTimer.start();
520563
}
521564
return;
522565
}
@@ -631,35 +674,30 @@ void ownCloudGui::updateContextMenu()
631674
}
632675
_contextMenu->addAction(_actionQuit);
633676

634-
if (_qdbusmenuWorkaround) {
677+
if (_workaroundShowAndHideTray) {
635678
_tray->show();
636679
}
637680
}
638681

639682
void ownCloudGui::updateContextMenuNeeded()
640683
{
641-
// For the workaround case updating while visible is impossible. Instead
642-
// occasionally update the menu when it's invisible.
643-
if (_qdbusmenuWorkaround) {
644-
if (!_workaroundBatchTrayUpdate.isActive()) {
645-
_workaroundBatchTrayUpdate.start();
646-
}
684+
// if it's visible and we can update live: update now
685+
if (contextMenuVisible() && updateWhileVisible()) {
686+
// Note: don't update while visible on OSX
687+
// https://bugreports.qt.io/browse/QTBUG-54845
688+
updateContextMenu();
647689
return;
648690
}
649691

650-
#ifdef Q_OS_MAC
651-
// https://bugreports.qt.io/browse/QTBUG-54845
652-
// We cannot update on demand or while visible -> update when invisible.
653-
if (!contextMenuVisible()) {
654-
updateContextMenu();
692+
// if we can't lazily update: update later
693+
if (_workaroundNoAboutToShowUpdate) {
694+
// Note: don't update immediately even in the invisible case
695+
// as that can lead to extremely frequent menu updates
696+
if (!_delayedTrayUpdateTimer.isActive()) {
697+
_delayedTrayUpdateTimer.start();
698+
}
699+
return;
655700
}
656-
#else
657-
if (updateWhileVisible() && contextMenuVisible())
658-
updateContextMenu();
659-
#endif
660-
661-
// If no update was done here, we might update it on-demand due to
662-
// the aboutToShow() signal.
663701
}
664702

665703
void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg)

src/gui/owncloudgui.h

+10-5
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,19 @@ private slots:
119119
// tray's menu
120120
QScopedPointer<QMenu> _contextMenu;
121121

122-
// Manually tracking whether the context menu is visible, but only works
123-
// on OSX because aboutToHide is not reliable everywhere.
124-
bool _contextMenuVisibleOsx;
122+
// Manually tracking whether the context menu is visible via aboutToShow
123+
// and aboutToHide. Unfortunately aboutToHide isn't reliable everywhere
124+
// so this only gets used with _workaroundManualVisibility (when the tray's
125+
// isVisible() is unreliable)
126+
bool _contextMenuVisibleManual = false;
125127

126128
QMenu *_recentActionsMenu;
127129
QVector<QMenu *> _accountMenus;
128-
bool _qdbusmenuWorkaround;
129-
QTimer _workaroundBatchTrayUpdate;
130+
bool _workaroundShowAndHideTray = false;
131+
bool _workaroundNoAboutToShowUpdate = false;
132+
bool _workaroundFakeDoubleClick = false;
133+
bool _workaroundManualVisibility = false;
134+
QTimer _delayedTrayUpdateTimer;
130135
QMap<QString, QPointer<ShareDialog>> _shareDialogs;
131136

132137
QAction *_actionLogin;

0 commit comments

Comments
 (0)