@@ -50,18 +50,13 @@ const char propertyAccountC[] = "oc_account";
50
50
ownCloudGui::ownCloudGui (Application *parent)
51
51
: QObject(parent)
52
52
, _tray(0 )
53
- ,
54
53
#if defined(Q_OS_MAC)
55
- _settingsDialog (new SettingsDialogMac(this ))
56
- ,
54
+ , _settingsDialog(new SettingsDialogMac(this ))
57
55
#else
58
- _settingsDialog (new SettingsDialog(this ))
59
- ,
56
+ , _settingsDialog(new SettingsDialog(this ))
60
57
#endif
61
- _logBrowser (0 )
62
- , _contextMenuVisibleOsx(false )
58
+ , _logBrowser(0 )
63
59
, _recentActionsMenu(0 )
64
- , _qdbusmenuWorkaround(false )
65
60
, _app(parent)
66
61
{
67
62
_tray = new Systray ();
@@ -117,7 +112,7 @@ void ownCloudGui::slotOpenSettingsDialog()
117
112
118
113
void ownCloudGui::slotTrayClicked (QSystemTrayIcon::ActivationReason reason)
119
114
{
120
- if (_qdbusmenuWorkaround ) {
115
+ if (_workaroundFakeDoubleClick ) {
121
116
static QElapsedTimer last_click;
122
117
if (last_click.isValid () && last_click.elapsed () < 200 ) {
123
118
return ;
@@ -381,29 +376,31 @@ void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *men
381
376
382
377
void ownCloudGui::slotContextMenuAboutToShow ()
383
378
{
384
- // For some reason on OS X _contextMenu->isVisible returns always false
385
- _contextMenuVisibleOsx = true ;
379
+ _contextMenuVisibleManual = true ;
386
380
387
381
// Update icon in sys tray, as it might change depending on the context menu state
388
382
slotComputeOverallSyncStatus ();
383
+
384
+ if (!_workaroundNoAboutToShowUpdate) {
385
+ updateContextMenu ();
386
+ }
389
387
}
390
388
391
389
void ownCloudGui::slotContextMenuAboutToHide ()
392
390
{
393
- // For some reason on OS X _contextMenu->isVisible returns always false
394
- _contextMenuVisibleOsx = false ;
391
+ _contextMenuVisibleManual = false ;
395
392
396
393
// Update icon in sys tray, as it might change depending on the context menu state
397
394
slotComputeOverallSyncStatus ();
398
395
}
399
396
400
397
bool ownCloudGui::contextMenuVisible () const
401
398
{
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;
405
403
return _contextMenu->isVisible ();
406
- #endif
407
404
}
408
405
409
406
static bool minimalTrayMenu ()
@@ -426,12 +423,36 @@ static bool updateWhileVisible()
426
423
}
427
424
}
428
425
429
- static QByteArray forceQDBusTrayWorkaround ()
426
+ static QByteArray envForceQDBusTrayWorkaround ()
430
427
{
431
428
static QByteArray var = qgetenv (" OWNCLOUD_FORCE_QDBUS_TRAY_WORKAROUND" );
432
429
return var;
433
430
}
434
431
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
+
435
456
void ownCloudGui::setupContextMenu ()
436
457
{
437
458
if (_contextMenu) {
@@ -454,51 +475,65 @@ void ownCloudGui::setupContextMenu()
454
475
return ;
455
476
}
456
477
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
+ };
478
484
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 ;
483
492
}
484
493
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.
494
494
#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 ;
500
498
#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 ;
501
515
}
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 ()));
502
537
503
538
// Populate the context menu now.
504
539
updateContextMenu ();
@@ -510,13 +545,21 @@ void ownCloudGui::updateContextMenu()
510
545
return ;
511
546
}
512
547
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) {
514
557
// To make tray menu updates work with these bugs (see setupContextMenu)
515
558
// we need to hide and show the tray icon. We don't want to do that
516
559
// while it's visible!
517
560
if (contextMenuVisible ()) {
518
- if (!_workaroundBatchTrayUpdate .isActive ()) {
519
- _workaroundBatchTrayUpdate .start ();
561
+ if (!_delayedTrayUpdateTimer .isActive ()) {
562
+ _delayedTrayUpdateTimer .start ();
520
563
}
521
564
return ;
522
565
}
@@ -631,35 +674,30 @@ void ownCloudGui::updateContextMenu()
631
674
}
632
675
_contextMenu->addAction (_actionQuit);
633
676
634
- if (_qdbusmenuWorkaround ) {
677
+ if (_workaroundShowAndHideTray ) {
635
678
_tray->show ();
636
679
}
637
680
}
638
681
639
682
void ownCloudGui::updateContextMenuNeeded ()
640
683
{
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 ();
647
689
return ;
648
690
}
649
691
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 ;
655
700
}
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.
663
701
}
664
702
665
703
void ownCloudGui::slotShowTrayMessage (const QString &title, const QString &msg)
0 commit comments