Switch browser integration to use native raising of windows

This commit is contained in:
varjolintu 2018-01-25 14:21:05 +02:00 committed by Jonathan White
parent c630214915
commit 5488f1bfc3
16 changed files with 229 additions and 34 deletions

View File

@ -174,7 +174,9 @@ if(APPLE)
set(keepassx_SOURCES
${keepassx_SOURCES}
core/ScreenLockListenerMac.cpp
core/MacPasteboard.cpp)
core/MacPasteboard.cpp
gui/macutils/MacUtils.cpp
gui/macutils/AppKitImpl.mm)
endif()
if(UNIX AND NOT APPLE)
set(keepassx_SOURCES
@ -272,7 +274,7 @@ target_link_libraries(keepassx_core
${ZXCVBN_LIBRARIES})
if(APPLE)
target_link_libraries(keepassx_core "-framework Foundation")
target_link_libraries(keepassx_core "-framework Foundation -framework AppKit")
if(Qt5MacExtras_FOUND)
target_link_libraries(keepassx_core Qt5::MacExtras)
endif()

View File

@ -17,6 +17,7 @@
*/
#include "AutoTypeMac.h"
#include "gui/macutils/MacUtils.h"
#include <ApplicationServices/ApplicationServices.h>
@ -25,8 +26,7 @@
#define INVALID_KEYCODE 0xFFFF
AutoTypePlatformMac::AutoTypePlatformMac()
: m_appkit(new AppKit())
, m_hotkeyRef(nullptr)
: m_hotkeyRef(nullptr)
, m_hotkeyId({ 'kpx2', HOTKEY_ID })
{
EventTypeSpec eventSpec;
@ -79,7 +79,7 @@ QStringList AutoTypePlatformMac::windowTitles()
//
WId AutoTypePlatformMac::activeWindow()
{
return m_appkit->activeProcessId();
return macUtils()->activeWindow();
}
//
@ -159,7 +159,7 @@ AutoTypeExecutor* AutoTypePlatformMac::createExecutor()
//
bool AutoTypePlatformMac::raiseWindow(WId pid)
{
return m_appkit->activateProcess(pid);
return macUtils()->raiseWindow(pid);
}
//
@ -167,7 +167,7 @@ bool AutoTypePlatformMac::raiseWindow(WId pid)
//
bool AutoTypePlatformMac::raiseLastActiveWindow()
{
return m_appkit->activateProcess(m_appkit->lastActiveProcessId());
return macUtils()->raiseLastActiveWindow();
}
//
@ -175,7 +175,7 @@ bool AutoTypePlatformMac::raiseLastActiveWindow()
//
bool AutoTypePlatformMac::raiseOwnWindow()
{
return m_appkit->activateProcess(m_appkit->ownProcessId());
return macUtils()->raiseOwnWindow();
}
//

View File

@ -23,7 +23,6 @@
#include <QtPlugin>
#include <memory>
#include "AppKit.h"
#include "autotype/AutoTypePlatformPlugin.h"
#include "autotype/AutoTypeAction.h"
@ -55,7 +54,6 @@ signals:
void globalShortcutTriggered();
private:
std::unique_ptr<AppKit> m_appkit;
EventHotKeyRef m_hotkeyRef;
EventHotKeyID m_hotkeyId;

View File

@ -1,6 +1,8 @@
set(autotype_mac_SOURCES AutoTypeMac.cpp)
set(autotype_mac_mm_SOURCES AppKitImpl.mm)
set(autotype_mac_mm_SOURCES
${CMAKE_SOURCE_DIR}/src/gui/macutils/AppKitImpl.mm
${CMAKE_SOURCE_DIR}/src/gui/macutils/MacUtils.cpp)
add_library(keepassx-autotype-cocoa MODULE ${autotype_mac_SOURCES} ${autotype_mac_mm_SOURCES})
set_target_properties(keepassx-autotype-cocoa PROPERTIES LINK_FLAGS "-framework Foundation -framework AppKit -framework Carbon")

View File

@ -33,8 +33,12 @@
#include "core/Group.h"
#include "core/Metadata.h"
#include "core/PasswordGenerator.h"
#include "core/Tools.h"
#include "gui/MainWindow.h"
#include "gui/MessageBox.h"
#ifdef Q_OS_MACOS
#include "gui/macutils/MacUtils.h"
#endif
const char BrowserService::KEEPASSXCBROWSER_NAME[] = "KeePassXC-Browser Settings";
const char BrowserService::KEEPASSXCBROWSER_OLD_NAME[] = "keepassxc-browser Settings";
@ -50,6 +54,7 @@ BrowserService::BrowserService(DatabaseTabWidget* parent)
: m_dbTabWidget(parent)
, m_dialogActive(false)
, m_bringToFrontRequested(false)
, m_wasMinimized(false)
, m_keepassBrowserUUID(QUuid::fromRfc4122(QByteArray::fromHex("de887cc3036343b8974b5911b8816224")))
{
// Don't connect the signals when used from DatabaseSettingsWidgetBrowser (parent is nullptr)
@ -90,8 +95,9 @@ bool BrowserService::openDatabase(bool triggerUnlock)
}
if (triggerUnlock) {
getMainWindow()->bringToFront();
m_bringToFrontRequested = true;
m_wasMinimized = getMainWindow()->isMinimized();
raiseWindow(true);
}
return false;
@ -168,6 +174,7 @@ QString BrowserService::storeKey(const QString& key)
"give it a unique name to identify and accept it."));
keyDialog.setOkButtonText(tr("Save and allow access"));
keyDialog.setWindowFlags(keyDialog.windowFlags() | Qt::WindowStaysOnTopHint);
raiseWindow();
keyDialog.show();
keyDialog.activateWindow();
keyDialog.raise();
@ -176,6 +183,7 @@ QString BrowserService::storeKey(const QString& key)
id = keyDialog.textValue();
if (ok != QDialog::Accepted || id.isEmpty()) {
hideWindow();
return {};
}
@ -191,6 +199,7 @@ QString BrowserService::storeKey(const QString& key)
}
} while (contains && dialogResult == MessageBox::Cancel);
hideWindow();
db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX) + id, key);
return id;
}
@ -371,12 +380,13 @@ void BrowserService::updateEntry(const QString& id,
|| entry->password().compare(password, Qt::CaseSensitive) != 0) {
MessageBox::Button dialogResult = MessageBox::No;
if (!browserSettings()->alwaysAllowUpdate()) {
raiseWindow();
dialogResult = MessageBox::question(nullptr,
tr("KeePassXC: Update Entry"),
tr("Do you want to update the information in %1 - %2?")
.arg(QUrl(url).host(), username),
MessageBox::Save | MessageBox::Cancel,
MessageBox::Cancel);
MessageBox::Cancel, MessageBox::Raise);
}
if (browserSettings()->alwaysAllowUpdate() || dialogResult == MessageBox::Save) {
@ -385,6 +395,8 @@ void BrowserService::updateEntry(const QString& id,
entry->setPassword(password);
entry->endUpdate();
}
hideWindow();
}
}
@ -591,6 +603,11 @@ bool BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm,
accessControlDialog.setUrl(url);
accessControlDialog.setItems(pwEntriesToConfirm);
raiseWindow();
accessControlDialog.show();
accessControlDialog.activateWindow();
accessControlDialog.raise();
int res = accessControlDialog.exec();
if (accessControlDialog.remember()) {
for (Entry* entry : pwEntriesToConfirm) {
@ -614,6 +631,7 @@ bool BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm,
}
m_dialogActive = false;
hideWindow();
if (res == QDialog::Accepted) {
return true;
}
@ -909,6 +927,32 @@ bool BrowserService::checkLegacySettings()
return dialogResult == MessageBox::Yes;
}
void BrowserService::hideWindow() const
{
if (m_wasMinimized) {
getMainWindow()->showMinimized();
} else {
#ifdef Q_OS_MACOS
macUtils()->raiseLastActiveWindow();
#else
getMainWindow()->lower();
#endif
}
}
void BrowserService::raiseWindow(const bool force)
{
m_wasMinimized = getMainWindow()->isMinimized();
#ifdef Q_OS_MACOS
macUtils()->raiseOwnWindow();
Tools::wait(500);
#else
if (force) {
getMainWindow()->bringToFront();
}
#endif
}
void BrowserService::databaseLocked(DatabaseWidget* dbWidget)
{
if (dbWidget) {
@ -920,7 +964,7 @@ void BrowserService::databaseUnlocked(DatabaseWidget* dbWidget)
{
if (dbWidget) {
if (m_bringToFrontRequested) {
getMainWindow()->lower();
hideWindow();
m_bringToFrontRequested = false;
}
emit databaseUnlocked();

View File

@ -117,11 +117,14 @@ private:
bool moveSettingsToCustomData(Entry* entry, const QString& name) const;
int moveKeysToCustomData(Entry* entry, QSharedPointer<Database> db) const;
bool checkLegacySettings();
void hideWindow() const;
void raiseWindow(const bool force = false);
private:
DatabaseTabWidget* const m_dbTabWidget;
bool m_dialogActive;
bool m_bringToFrontRequested;
bool m_wasMinimized;
QUuid m_keepassBrowserUUID;
};

View File

@ -25,7 +25,11 @@ DatabaseOpenDialog::DatabaseOpenDialog(QWidget* parent)
, m_view(new DatabaseOpenWidget(this))
{
setWindowTitle(tr("Unlock Database - KeePassXC"));
#ifdef Q_OS_MACOS
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
#else
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint | Qt::ForeignWindow);
#endif
connect(m_view, SIGNAL(dialogFinished(bool)), this, SLOT(complete(bool)));
}

View File

@ -15,8 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_AUTOTYPEUNLOCKDIALOG_H
#define KEEPASSX_AUTOTYPEUNLOCKDIALOG_H
#ifndef KEEPASSX_UNLOCKDATABASEDIALOG_H
#define KEEPASSX_UNLOCKDATABASEDIALOG_H
#include "core/Global.h"
@ -37,7 +37,8 @@ public:
{
None,
AutoType,
Merge
Merge,
Browser
};
explicit DatabaseOpenDialog(QWidget* parent = nullptr);
@ -61,4 +62,4 @@ private:
Intent m_intent = Intent::None;
};
#endif // KEEPASSX_AUTOTYPEUNLOCKDIALOG_H
#endif // KEEPASSX_UNLOCKDATABASEDIALOG_H

View File

@ -39,6 +39,9 @@
#include "gui/DatabaseOpenDialog.h"
#include "gui/entry/EntryView.h"
#include "gui/group/GroupView.h"
#ifdef Q_OS_MACOS
#include "gui/macutils/MacUtils.h"
#endif
#include "gui/wizard/NewDatabaseWizard.h"
DatabaseTabWidget::DatabaseTabWidget(QWidget* parent)
@ -544,8 +547,8 @@ void DatabaseTabWidget::unlockDatabaseInDialog(DatabaseWidget* dbWidget, Databas
m_databaseOpenDialog->setFilePath(filePath);
#ifdef Q_OS_MACOS
if (intent == DatabaseOpenDialog::Intent::AutoType) {
autoType()->raiseWindow();
if (intent == DatabaseOpenDialog::Intent::AutoType || intent == DatabaseOpenDialog::Intent::Browser) {
macUtils()->raiseOwnWindow();
Tools::wait(500);
}
#endif

View File

@ -76,7 +76,8 @@ MessageBox::Button MessageBox::messageBox(QWidget* parent,
const QString& title,
const QString& text,
MessageBox::Buttons buttons,
MessageBox::Button defaultButton)
MessageBox::Button defaultButton,
MessageBox::Action action)
{
if (m_nextAnswer == MessageBox::NoButton) {
QMessageBox msgBox(parent);
@ -101,6 +102,11 @@ MessageBox::Button MessageBox::messageBox(QWidget* parent,
}
}
if (action == MessageBox::Raise) {
msgBox.setWindowFlags(Qt::WindowStaysOnTopHint);
msgBox.activateWindow();
msgBox.raise();
}
msgBox.exec();
Button returnButton = m_addedButtonLookup[msgBox.clickedButton()];
@ -118,36 +124,40 @@ MessageBox::Button MessageBox::critical(QWidget* parent,
const QString& title,
const QString& text,
MessageBox::Buttons buttons,
MessageBox::Button defaultButton)
MessageBox::Button defaultButton,
MessageBox::Action action)
{
return messageBox(parent, QMessageBox::Critical, title, text, buttons, defaultButton);
return messageBox(parent, QMessageBox::Critical, title, text, buttons, defaultButton, action);
}
MessageBox::Button MessageBox::information(QWidget* parent,
const QString& title,
const QString& text,
MessageBox::Buttons buttons,
MessageBox::Button defaultButton)
MessageBox::Button defaultButton,
MessageBox::Action action)
{
return messageBox(parent, QMessageBox::Information, title, text, buttons, defaultButton);
return messageBox(parent, QMessageBox::Information, title, text, buttons, defaultButton, action);
}
MessageBox::Button MessageBox::question(QWidget* parent,
const QString& title,
const QString& text,
MessageBox::Buttons buttons,
MessageBox::Button defaultButton)
MessageBox::Button defaultButton,
MessageBox::Action action)
{
return messageBox(parent, QMessageBox::Question, title, text, buttons, defaultButton);
return messageBox(parent, QMessageBox::Question, title, text, buttons, defaultButton, action);
}
MessageBox::Button MessageBox::warning(QWidget* parent,
const QString& title,
const QString& text,
MessageBox::Buttons buttons,
MessageBox::Button defaultButton)
MessageBox::Button defaultButton,
MessageBox::Action action)
{
return messageBox(parent, QMessageBox::Warning, title, text, buttons, defaultButton);
return messageBox(parent, QMessageBox::Warning, title, text, buttons, defaultButton, action);
}
void MessageBox::setNextAnswer(MessageBox::Button button)

View File

@ -63,6 +63,11 @@ public:
Last = Merge,
};
enum Action {
None = 0,
Raise = 1,
};
typedef uint64_t Buttons;
static void initializeButtonDefs();
@ -72,22 +77,26 @@ public:
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
Button defaultButton = MessageBox::NoButton,
Action action = MessageBox::None);
static Button information(QWidget* parent,
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
Button defaultButton = MessageBox::NoButton,
Action action = MessageBox::None);
static Button question(QWidget* parent,
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
Button defaultButton = MessageBox::NoButton,
Action action = MessageBox::None);
static Button warning(QWidget* parent,
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
Button defaultButton = MessageBox::NoButton,
Action action = MessageBox::None);
private:
static Button m_nextAnswer;
@ -99,7 +108,8 @@ private:
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
Button defaultButton = MessageBox::NoButton,
Action action = MessageBox::None);
static QString stdButtonText(QMessageBox::StandardButton button);

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MacUtils.h"
#include <QApplication>
MacUtils* MacUtils::m_instance = nullptr;
MacUtils::MacUtils(QObject* parent) : QObject(parent)
, m_appkit(new AppKit())
{
}
MacUtils::~MacUtils()
{
}
MacUtils* MacUtils::instance()
{
if (!m_instance) {
m_instance = new MacUtils(qApp);
}
return m_instance;
}
WId MacUtils::activeWindow()
{
return m_appkit->activeProcessId();
}
bool MacUtils::raiseWindow(WId pid)
{
return m_appkit->activateProcess(pid);
}
bool MacUtils::raiseOwnWindow()
{
return m_appkit->activateProcess(m_appkit->ownProcessId());
}
bool MacUtils::raiseLastActiveWindow()
{
return m_appkit->activateProcess(m_appkit->lastActiveProcessId());
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_MACUTILS_H
#define KEEPASSXC_MACUTILS_H
#include <QObject>
#include <QWidget>
#include "AppKit.h"
class MacUtils : public QObject
{
Q_OBJECT
public:
static MacUtils* instance();
static void createTestInstance();
WId activeWindow();
bool raiseWindow(WId pid);
bool raiseLastActiveWindow();
bool raiseOwnWindow();
private:
explicit MacUtils(QObject* parent = nullptr);
~MacUtils();
private:
std::unique_ptr<AppKit> m_appkit;
static MacUtils* m_instance;
void* self;
Q_DISABLE_COPY(MacUtils)
};
inline MacUtils* macUtils()
{
return MacUtils::instance();
}
#endif // KEEPASSXC_MACUTILS_H