@@ -59,9 +59,8 @@ ownCloudGui::ownCloudGui(Application *parent)
59
59
,
60
60
#endif
61
61
_logBrowser (0 )
62
- , _contextMenuVisibleOsx (false )
62
+ , _contextMenuVisibleManual (false )
63
63
, _recentActionsMenu(0 )
64
- , _qdbusmenuWorkaround(false )
65
64
, _app(parent)
66
65
{
67
66
_tray = new Systray ();
@@ -117,7 +116,7 @@ void ownCloudGui::slotOpenSettingsDialog()
117
116
118
117
void ownCloudGui::slotTrayClicked (QSystemTrayIcon::ActivationReason reason)
119
118
{
120
- if (_qdbusmenuWorkaround ) {
119
+ if (_workaroundFakeDoubleClick ) {
121
120
static QElapsedTimer last_click;
122
121
if (last_click.isValid () && last_click.elapsed () < 200 ) {
123
122
return ;
@@ -402,29 +401,31 @@ void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *men
402
401
403
402
void ownCloudGui::slotContextMenuAboutToShow ()
404
403
{
405
- // For some reason on OS X _contextMenu->isVisible returns always false
406
- _contextMenuVisibleOsx = true ;
404
+ _contextMenuVisibleManual = true ;
407
405
408
406
// Update icon in sys tray, as it might change depending on the context menu state
409
407
slotComputeOverallSyncStatus ();
408
+
409
+ if (!_workaroundNoAboutToShowUpdate) {
410
+ updateContextMenu ();
411
+ }
410
412
}
411
413
412
414
void ownCloudGui::slotContextMenuAboutToHide ()
413
415
{
414
- // For some reason on OS X _contextMenu->isVisible returns always false
415
- _contextMenuVisibleOsx = false ;
416
+ _contextMenuVisibleManual = false ;
416
417
417
418
// Update icon in sys tray, as it might change depending on the context menu state
418
419
slotComputeOverallSyncStatus ();
419
420
}
420
421
421
422
bool ownCloudGui::contextMenuVisible () const
422
423
{
423
- #ifdef Q_OS_MAC
424
- return _contextMenuVisibleOsx;
425
- #else
424
+ // On some platforms isVisible doesn't work and always returns false,
425
+ // elsewhere aboutToHide is unreliable.
426
+ if (_workaroundManualVisibility)
427
+ return _contextMenuVisibleManual;
426
428
return _contextMenu->isVisible ();
427
- #endif
428
429
}
429
430
430
431
static bool minimalTrayMenu ()
@@ -447,12 +448,36 @@ static bool updateWhileVisible()
447
448
}
448
449
}
449
450
450
- static QByteArray forceQDBusTrayWorkaround ()
451
+ static QByteArray envForceQDBusTrayWorkaround ()
451
452
{
452
453
static QByteArray var = qgetenv (" OWNCLOUD_FORCE_QDBUS_TRAY_WORKAROUND" );
453
454
return var;
454
455
}
455
456
457
+ static QByteArray envForceWorkaroundShowAndHideTray ()
458
+ {
459
+ static QByteArray var = qgetenv (" OWNCLOUD_FORCE_TRAY_SHOW_HIDE" );
460
+ return var;
461
+ }
462
+
463
+ static QByteArray envForceWorkaroundNoAboutToShowUpdate ()
464
+ {
465
+ static QByteArray var = qgetenv (" OWNCLOUD_FORCE_TRAY_NO_ABOUT_TO_SHOW" );
466
+ return var;
467
+ }
468
+
469
+ static QByteArray envForceWorkaroundFakeDoubleClick ()
470
+ {
471
+ static QByteArray var = qgetenv (" OWNCLOUD_FORCE_TRAY_FAKE_DOUBLE_CLICK" );
472
+ return var;
473
+ }
474
+
475
+ static QByteArray envForceWorkaroundManualVisibility ()
476
+ {
477
+ static QByteArray var = qgetenv (" OWNCLOUD_FORCE_TRAY_MANUAL_VISIBILITY" );
478
+ return var;
479
+ }
480
+
456
481
void ownCloudGui::setupContextMenu ()
457
482
{
458
483
if (_contextMenu) {
@@ -475,6 +500,8 @@ void ownCloudGui::setupContextMenu()
475
500
return ;
476
501
}
477
502
503
+ bool qdbusmenuWorkarounds = false ;
504
+
478
505
// Enables workarounds for bugs introduced in Qt 5.5.0
479
506
// In particular QTBUG-47863 #3672 (tray menu fails to update and
480
507
// becomes unresponsive) and QTBUG-48068 #3722 (click signal is
@@ -490,36 +517,70 @@ void ownCloudGui::setupContextMenu()
490
517
QObject *platformMenu = reinterpret_cast <QObject *>(_tray->contextMenu ()->platformMenu ());
491
518
if (platformMenu
492
519
&& platformMenu->metaObject ()->className () == QLatin1String (" QDBusPlatformMenu" )) {
493
- _qdbusmenuWorkaround = true ;
520
+ qdbusmenuWorkarounds = true ;
494
521
qCWarning (lcApplication) << " Enabled QDBusPlatformMenu workaround" ;
495
522
}
496
523
}
497
524
#endif
498
525
#endif
499
526
500
- if (forceQDBusTrayWorkaround () == " 1" ) {
501
- _qdbusmenuWorkaround = true ;
502
- } else if (forceQDBusTrayWorkaround () == " 0" ) {
503
- _qdbusmenuWorkaround = false ;
527
+ auto applyEnvVariable = [](bool *sw, const QByteArray &value) {
528
+ if (value == " 1" )
529
+ *sw = true ;
530
+ if (value == " 0" )
531
+ *sw = false ;
532
+ };
533
+
534
+ applyEnvVariable (&qdbusmenuWorkarounds, envForceQDBusTrayWorkaround ());
535
+ if (qdbusmenuWorkarounds) {
536
+ _workaroundFakeDoubleClick = true ;
537
+ _workaroundNoAboutToShowUpdate = true ;
538
+ _workaroundShowAndHideTray = true ;
504
539
}
505
540
506
- // When the qdbusmenuWorkaround is necessary, we can't do on-demand updates
507
- // because the workaround is to hide and show the tray icon.
508
- if (_qdbusmenuWorkaround) {
509
- connect (&_workaroundBatchTrayUpdate, &QTimer::timeout, this , &ownCloudGui::updateContextMenu);
510
- _workaroundBatchTrayUpdate.setInterval (30 * 1000 );
511
- _workaroundBatchTrayUpdate.setSingleShot (true );
512
- } else {
513
- // Update the context menu whenever we're about to show it
514
- // to the user.
515
541
#ifdef Q_OS_MAC
516
- // https://bugreports.qt.io/browse/QTBUG-54633
517
- connect (_contextMenu.data (), SIGNAL (aboutToShow ()), SLOT (slotContextMenuAboutToShow ()));
518
- connect (_contextMenu.data (), SIGNAL (aboutToHide ()), SLOT (slotContextMenuAboutToHide ()));
519
- #else
520
- connect (_contextMenu.data (), &QMenu::aboutToShow, this , &ownCloudGui::updateContextMenu);
542
+ // https://bugreports.qt.io/browse/QTBUG-54633
543
+ _workaroundNoAboutToShowUpdate = true ;
544
+ _workaroundManualVisibility = true ;
521
545
#endif
546
+
547
+ #ifdef Q_OS_LINUX
548
+ // For KDE sessions if the platform plugin is missing,
549
+ // neither aboutToShow() updates nor the isVisible() call
550
+ // work. At least aboutToHide is reliable.
551
+ // https://github.com/owncloud/client/issues/6545
552
+ static QByteArray xdgCurrentDesktop = qgetenv (" XDG_CURRENT_DESKTOP" );
553
+ static QByteArray desktopSession = qgetenv (" DESKTOP_SESSION" );
554
+ bool isKde =
555
+ xdgCurrentDesktop.contains (" KDE" )
556
+ || desktopSession.contains (" plasma" )
557
+ || desktopSession.contains (" kde" );
558
+ QObject *platformMenu = reinterpret_cast <QObject *>(_tray->contextMenu ()->platformMenu ());
559
+ if (isKde && platformMenu && platformMenu->metaObject ()->className () == QLatin1String (" QDBusPlatformMenu" )) {
560
+ _workaroundManualVisibility = true ;
561
+ _workaroundNoAboutToShowUpdate = true ;
522
562
}
563
+ #endif
564
+
565
+ applyEnvVariable (&_workaroundNoAboutToShowUpdate, envForceWorkaroundNoAboutToShowUpdate ());
566
+ applyEnvVariable (&_workaroundFakeDoubleClick, envForceWorkaroundFakeDoubleClick ());
567
+ applyEnvVariable (&_workaroundShowAndHideTray, envForceWorkaroundShowAndHideTray ());
568
+ applyEnvVariable (&_workaroundManualVisibility, envForceWorkaroundManualVisibility ());
569
+
570
+ qCDebug (lcApplication) << " Tray menu workarounds: "
571
+ << " noabouttoshow: " << _workaroundNoAboutToShowUpdate
572
+ << " fakedoubleclick: " << _workaroundFakeDoubleClick
573
+ << " showhide: " << _workaroundShowAndHideTray
574
+ << " manualvisibility: " << _workaroundManualVisibility;
575
+
576
+
577
+ connect (&_delayedTrayUpdateTimer, &QTimer::timeout, this , &ownCloudGui::updateContextMenu);
578
+ _delayedTrayUpdateTimer.setInterval (2 * 1000 );
579
+ _delayedTrayUpdateTimer.setSingleShot (true );
580
+
581
+ connect (_contextMenu.data (), SIGNAL (aboutToShow ()), SLOT (slotContextMenuAboutToShow ()));
582
+ // unfortunately aboutToHide is unreliable, it seems to work on OSX though
583
+ connect (_contextMenu.data (), SIGNAL (aboutToHide ()), SLOT (slotContextMenuAboutToHide ()));
523
584
524
585
// Populate the context menu now.
525
586
updateContextMenu ();
@@ -531,13 +592,21 @@ void ownCloudGui::updateContextMenu()
531
592
return ;
532
593
}
533
594
534
- if (_qdbusmenuWorkaround) {
595
+ // If it's visible, we can't update live, and it won't be updated lazily: reschedule
596
+ if (contextMenuVisible () && !updateWhileVisible () && _workaroundNoAboutToShowUpdate) {
597
+ if (!_delayedTrayUpdateTimer.isActive ()) {
598
+ _delayedTrayUpdateTimer.start ();
599
+ }
600
+ return ;
601
+ }
602
+
603
+ if (_workaroundShowAndHideTray) {
535
604
// To make tray menu updates work with these bugs (see setupContextMenu)
536
605
// we need to hide and show the tray icon. We don't want to do that
537
606
// while it's visible!
538
607
if (contextMenuVisible ()) {
539
- if (!_workaroundBatchTrayUpdate .isActive ()) {
540
- _workaroundBatchTrayUpdate .start ();
608
+ if (!_delayedTrayUpdateTimer .isActive ()) {
609
+ _delayedTrayUpdateTimer .start ();
541
610
}
542
611
return ;
543
612
}
@@ -652,35 +721,30 @@ void ownCloudGui::updateContextMenu()
652
721
}
653
722
_contextMenu->addAction (_actionQuit);
654
723
655
- if (_qdbusmenuWorkaround ) {
724
+ if (_workaroundShowAndHideTray ) {
656
725
_tray->show ();
657
726
}
658
727
}
659
728
660
729
void ownCloudGui::updateContextMenuNeeded ()
661
730
{
662
- // For the workaround case updating while visible is impossible. Instead
663
- // occasionally update the menu when it's invisible.
664
- if (_qdbusmenuWorkaround) {
665
- if (!_workaroundBatchTrayUpdate.isActive ()) {
666
- _workaroundBatchTrayUpdate.start ();
667
- }
731
+ // if it's visible and we can update live: update now
732
+ if (contextMenuVisible () && updateWhileVisible ()) {
733
+ // Note: don't update while visible on OSX
734
+ // https://bugreports.qt.io/browse/QTBUG-54845
735
+ updateContextMenu ();
668
736
return ;
669
737
}
670
738
671
- #ifdef Q_OS_MAC
672
- // https://bugreports.qt.io/browse/QTBUG-54845
673
- // We cannot update on demand or while visible -> update when invisible.
674
- if (!contextMenuVisible ()) {
675
- updateContextMenu ();
739
+ // if we can't lazily update: update later
740
+ if (_workaroundNoAboutToShowUpdate) {
741
+ // Note: don't update immediately even in the invisible case
742
+ // as that can lead to extremely frequent menu updates
743
+ if (!_delayedTrayUpdateTimer.isActive ()) {
744
+ _delayedTrayUpdateTimer.start ();
745
+ }
746
+ return ;
676
747
}
677
- #else
678
- if (updateWhileVisible () && contextMenuVisible ())
679
- updateContextMenu ();
680
- #endif
681
-
682
- // If no update was done here, we might update it on-demand due to
683
- // the aboutToShow() signal.
684
748
}
685
749
686
750
void ownCloudGui::slotShowTrayMessage (const QString &title, const QString &msg)
0 commit comments