From 16aaa1b0500f703ca8c84dec09bd8a6a73ae5f21 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Thu, 5 Jan 2023 17:06:21 +0100 Subject: [PATCH] GODT-2010: add Cocoa app delegate handler for second application instance. --- .../bridge-gui/bridge-gui/CMakeLists.txt | 12 +++- .../{DockIcon => MacOS}/DockIcon.cpp | 0 .../bridge-gui/{DockIcon => MacOS}/DockIcon.h | 0 .../{DockIcon => MacOS}/DockIcon.mm | 0 .../bridge-gui/MacOS/SecondInstance.h | 28 +++++++++ .../bridge-gui/MacOS/SecondInstance.mm | 63 +++++++++++++++++++ .../bridge-gui/bridge-gui/QMLBackend.h | 2 +- .../frontend/bridge-gui/bridge-gui/main.cpp | 10 ++- 8 files changed, 110 insertions(+), 5 deletions(-) rename internal/frontend/bridge-gui/bridge-gui/{DockIcon => MacOS}/DockIcon.cpp (100%) rename internal/frontend/bridge-gui/bridge-gui/{DockIcon => MacOS}/DockIcon.h (100%) rename internal/frontend/bridge-gui/bridge-gui/{DockIcon => MacOS}/DockIcon.mm (100%) create mode 100644 internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.h create mode 100644 internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.mm diff --git a/internal/frontend/bridge-gui/bridge-gui/CMakeLists.txt b/internal/frontend/bridge-gui/bridge-gui/CMakeLists.txt index 9d12c5f8..a5f9b03c 100644 --- a/internal/frontend/bridge-gui/bridge-gui/CMakeLists.txt +++ b/internal/frontend/bridge-gui/bridge-gui/CMakeLists.txt @@ -105,9 +105,9 @@ if (NOT TARGET bridgepp) endif() if (APPLE) - set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.mm) + set(DOCK_ICON_SRC_FILE MacOS/DockIcon.mm) else() - set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.cpp) + set(DOCK_ICON_SRC_FILE MacOS/DockIcon.cpp) endif() if(UNIX) @@ -125,9 +125,15 @@ add_executable(bridge-gui QMLBackend.cpp QMLBackend.h UserList.cpp UserList.h SentryUtils.cpp SentryUtils.h - ${DOCK_ICON_SRC_FILE} DockIcon/DockIcon.h + ${DOCK_ICON_SRC_FILE} MacOS/DockIcon.h ) + +if (APPLE) + target_sources(bridge-gui PRIVATE MacOS/SecondInstance.mm MacOS/SecondInstance.h) +endif(APPLE) + + if (WIN32) # on Windows, we add a (non-Qt) resource file that contains the application icon and version information. string(TIMESTAMP BRIDGE_BUILD_YEAR "%Y") set(REGEX_NUMBER "[0123456789]") # CMake matches does not support \d. diff --git a/internal/frontend/bridge-gui/bridge-gui/DockIcon/DockIcon.cpp b/internal/frontend/bridge-gui/bridge-gui/MacOS/DockIcon.cpp similarity index 100% rename from internal/frontend/bridge-gui/bridge-gui/DockIcon/DockIcon.cpp rename to internal/frontend/bridge-gui/bridge-gui/MacOS/DockIcon.cpp diff --git a/internal/frontend/bridge-gui/bridge-gui/DockIcon/DockIcon.h b/internal/frontend/bridge-gui/bridge-gui/MacOS/DockIcon.h similarity index 100% rename from internal/frontend/bridge-gui/bridge-gui/DockIcon/DockIcon.h rename to internal/frontend/bridge-gui/bridge-gui/MacOS/DockIcon.h diff --git a/internal/frontend/bridge-gui/bridge-gui/DockIcon/DockIcon.mm b/internal/frontend/bridge-gui/bridge-gui/MacOS/DockIcon.mm similarity index 100% rename from internal/frontend/bridge-gui/bridge-gui/DockIcon/DockIcon.mm rename to internal/frontend/bridge-gui/bridge-gui/MacOS/DockIcon.mm diff --git a/internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.h b/internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.h new file mode 100644 index 00000000..1fc4708a --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.h @@ -0,0 +1,28 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail Bridge. +// +// Proton Mail Bridge 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 3 of the License, or +// (at your option) any later version. +// +// Proton Mail Bridge 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 Proton Mail Bridge. If not, see . + + +#ifndef BRIDGE_GUI_APP_DELEGATE_H +#define BRIDGE_GUI_APP_DELEGATE_H +#ifdef Q_OS_MACOS + + +void registerSecondInstanceHandler(); + + +#endif // Q_OS_MACOS +#endif //BRIDGE_GUI_APP_DELEGATE_H diff --git a/internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.mm b/internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.mm new file mode 100644 index 00000000..2d8449b8 --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.mm @@ -0,0 +1,63 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail Bridge. +// +// Proton Mail Bridge 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 3 of the License, or +// (at your option) any later version. +// +// Proton Mail Bridge 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 Proton Mail Bridge. If not, see . + + +#include "SecondInstance.h" +#include "QMLBackend.h" +#include +#import +#import + + +using namespace bridgepp; + + +#ifdef Q_OS_MACOS + + +//**************************************************************************************************************************************************** +/// \brief handle notification of attempt to re-open the application. +//**************************************************************************************************************************************************** +void applicationShouldHandleReopen(id, SEL) { + app().backend().showMainWindow(); +} + + +//**************************************************************************************************************************************************** +/// \brief Register our handler for the NSApplicationDelegate applicationShouldHandleReopen:hasVisibleWindows: method that is called when the user +/// tries to open a second instance of an application. +/// +/// Objective-C(++) lets you add or replace selector within a class at runtime. we use it to implement our handler for the +/// applicationShouldHandleReopen:hasVisibleWindows: selector of the Cocoa application delegate. +//**************************************************************************************************************************************************** +void registerSecondInstanceHandler() { + try { + Class cls = [[[NSApplication sharedApplication] delegate] class]; + if (!cls) { + throw Exception("Could not retrieve Cocoa NSApplicationDelegate instance"); + } + + if (!class_replaceMethod(cls, @selector(applicationShouldHandleReopen:hasVisibleWindows:), (IMP) applicationShouldHandleReopen, "v@:")) { + throw Exception("Could not register second application instance handler"); + } + } catch (Exception const &e) { + app().log().error(e.qwhat()); + } +} + + +#endif // Q_OS_MACOS diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h index 1494f275..0b63f8a4 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h @@ -20,7 +20,7 @@ #define BRIDGE_GUI_QML_BACKEND_H -#include "DockIcon/DockIcon.h" +#include "MacOS/DockIcon.h" #include "Version.h" #include "UserList.h" #include diff --git a/internal/frontend/bridge-gui/bridge-gui/main.cpp b/internal/frontend/bridge-gui/bridge-gui/main.cpp index 42b38a7a..8db99349 100644 --- a/internal/frontend/bridge-gui/bridge-gui/main.cpp +++ b/internal/frontend/bridge-gui/bridge-gui/main.cpp @@ -30,9 +30,16 @@ #include -using namespace bridgepp; +#ifdef Q_OS_MACOS +#include "MacOS/SecondInstance.h" + + +#endif + +using namespace bridgepp; + namespace { /// \brief The file extension for the bridge executable file. @@ -320,6 +327,7 @@ int main(int argc, char *argv[]) { CommandLineOptions const cliOptions = parseCommandLine(argc, argv); #ifdef Q_OS_MACOS + registerSecondInstanceHandler(); setDockIconVisibleState(!cliOptions.noWindow); #endif