Fixed freezes in macOS clipboard requests.

Sometimes QClipboard::text() unexpectedly freezes on macOS, no known
causes for that. But before we were requesting the clipboard text after
each change in any text field to update macOS global menu items.

Now we use Cocoa API directly to find out if there were any changes to
the clipboard content and query text through Qt only if we have changes.

That way it should almost never freeze (at least) or even really never.
This commit is contained in:
John Preston 2017-03-05 23:18:27 +03:00
parent 31009b19c6
commit e88305d984

View File

@ -67,6 +67,8 @@ public:
void initCustomTitle(NSWindow *window, NSView *view);
bool clipboardHasText();
~Private();
private:
@ -74,6 +76,9 @@ private:
friend class MainWindow;
MainWindowObserver *_observer;
NSPasteboard *_generalPasteboard = nullptr;
int _generalPasteboardChangeCount = -1;
bool _generalPasteboardHasText = false;
};
@ -127,6 +132,8 @@ namespace Platform {
MainWindow::Private::Private(MainWindow *window)
: _public(window)
, _observer([[MainWindowObserver alloc] init:this]) {
_generalPasteboard = [NSPasteboard generalPasteboard];
@autoreleasepool {
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:_observer selector:@selector(activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
@ -167,6 +174,15 @@ void MainWindow::Private::initCustomTitle(NSWindow *window, NSView *view) {
#endif // !OS_MAC_OLD
}
bool MainWindow::Private::clipboardHasText() {
auto currentChangeCount = static_cast<int>([_generalPasteboard changeCount]);
if (_generalPasteboardChangeCount != currentChangeCount) {
_generalPasteboardChangeCount = currentChangeCount;
_generalPasteboardHasText = !Application::clipboard()->text().isEmpty();
}
return _generalPasteboardHasText;
}
void MainWindow::Private::willEnterFullScreen() {
_public->setTitleVisible(false);
}
@ -503,18 +519,19 @@ void MainWindow::updateGlobalMenuHook() {
auto focused = QApplication::focusWidget();
bool isLogged = !!App::self(), canUndo = false, canRedo = false, canCut = false, canCopy = false, canPaste = false, canDelete = false, canSelectAll = false;
auto clipboardHasText = _private->clipboardHasText();
if (auto edit = qobject_cast<QLineEdit*>(focused)) {
canCut = canCopy = canDelete = edit->hasSelectedText();
canSelectAll = !edit->text().isEmpty();
canUndo = edit->isUndoAvailable();
canRedo = edit->isRedoAvailable();
canPaste = !Application::clipboard()->text().isEmpty();
canPaste = clipboardHasText;
} else if (auto edit = qobject_cast<QTextEdit*>(focused)) {
canCut = canCopy = canDelete = edit->textCursor().hasSelection();
canSelectAll = !edit->document()->isEmpty();
canUndo = edit->document()->isUndoAvailable();
canRedo = edit->document()->isRedoAvailable();
canPaste = !Application::clipboard()->text().isEmpty();
canPaste = clipboardHasText;
} else if (auto list = qobject_cast<HistoryInner*>(focused)) {
canCopy = list->canCopySelected();
canDelete = list->canDeleteSelected();