diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index 1a11ef697..3058801b6 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -1052,6 +1052,10 @@ void App::initFonts() { void App::clean() { mDateUpdateTimer.stop(); +#ifdef Q_OS_WIN + removeNativeEventFilter(mLockEventFilter); + delete mLockEventFilter; +#endif if (mEngine) { mEngine->clearComponentCache(); mEngine->clearSingletons(); @@ -1309,11 +1313,20 @@ QQuickWindow *App::getMainWindow() const { } void App::setMainWindow(QQuickWindow *data) { - if (mMainWindow) disconnect(mMainWindow, &QQuickWindow::activeChanged, this, nullptr); + if (mMainWindow) { + disconnect(mMainWindow, &QQuickWindow::activeChanged, this, nullptr); + } if (mMainWindow != data) { mMainWindow = data; connect(mMainWindow, &QQuickWindow::activeChanged, this, &App::handleAppActivity); handleAppActivity(); + + mMainWindow->winId(); + +#ifdef Q_OS_WIN + WTSRegisterSessionNotification(reinterpret_cast(mMainWindow->winId()), NOTIFY_FOR_THIS_SESSION); +#endif + emit mainWindowChanged(); } } @@ -1592,7 +1605,6 @@ void App::setSysTrayIcon() { (mSystemTrayIcon ? mSystemTrayIcon : new QSystemTrayIcon(nullptr)); // Workaround : QSystemTrayIcon cannot be deleted because // of setContextMenu (indirectly) - // trayIcon: Right click actions. QAction *restoreAction = nullptr; if (mSettings && !mSettings->getExitOnClose()) { @@ -1654,6 +1666,13 @@ void App::setSysTrayIcon() { systemTrayIcon->show(); if (!mSystemTrayIcon) mSystemTrayIcon = systemTrayIcon; if (!QSystemTrayIcon::isSystemTrayAvailable()) qInfo() << "System tray is not available"; + +// +#ifdef Q_OS_WIN + if (!mLockEventFilter) mLockEventFilter = new LockEventFilter(); + connect(mLockEventFilter, &LockEventFilter::sessionUnlocked, this, [this] { emit sessionUnlocked(); }); + installNativeEventFilter(mLockEventFilter); +#endif } //----------------------------------------------------------- diff --git a/Linphone/core/App.hpp b/Linphone/core/App.hpp index 1047a1405..0681e9028 100644 --- a/Linphone/core/App.hpp +++ b/Linphone/core/App.hpp @@ -29,6 +29,7 @@ #include "core/chat/ChatGui.hpp" #include "core/chat/ChatList.hpp" #include "core/conference/ConferenceInfoList.hpp" +#include "core/event-filter/LockEventFilter.hpp" #include "core/setting/SettingsCore.hpp" #include "core/singleapplication/singleapplication.h" #include "model/cli/CliModel.hpp" @@ -231,6 +232,9 @@ signals: void lForceOidcTimeout(); void remainingTimeBeforeOidcTimeoutChanged(); void currentAccountChanged(); +#ifdef Q_OS_WIN + void sessionUnlocked(); +#endif // void executeCommand(QString command); private: @@ -248,6 +252,9 @@ private: QQuickWindow *mMainWindow = nullptr; QQuickWindow *mCallsWindow = nullptr; QQuickWindow *mLastActiveWindow = nullptr; +#ifdef Q_OS_WIN + LockEventFilter *mLockEventFilter = nullptr; +#endif // Holds the current chat displayed in the view // to know if we need to display the notification ChatGui *mCurrentChat = nullptr; diff --git a/Linphone/core/CMakeLists.txt b/Linphone/core/CMakeLists.txt index a3e4c34f4..39a3d54f5 100644 --- a/Linphone/core/CMakeLists.txt +++ b/Linphone/core/CMakeLists.txt @@ -40,6 +40,7 @@ list(APPEND _LINPHONEAPP_SOURCES core/emoji/EmojiModel.cpp core/emoji/EmojiProxy.cpp core/event-count-notifier/AbstractEventCountNotifier.cpp + core/event-filter/LockEventFilter.cpp core/fps-counter/FPSCounter.cpp core/friend/FriendCore.cpp core/friend/FriendGui.cpp diff --git a/Linphone/core/event-filter/LockEventFilter.cpp b/Linphone/core/event-filter/LockEventFilter.cpp new file mode 100644 index 000000000..bbbeddcec --- /dev/null +++ b/Linphone/core/event-filter/LockEventFilter.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010-2026 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.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 3 of the License, or + * (at your option) any later version. + * + * 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 . + */ + +#include "LockEventFilter.hpp" + +LockEventFilter::LockEventFilter(QObject *parent) : QObject(parent) { +} + +bool LockEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) { +#ifdef Q_OS_WIN + MSG *msg = static_cast(message); + if (msg->message == WM_WTSSESSION_CHANGE) { + if (msg->wParam == WTS_SESSION_LOCK) { + return true; + } else { + emit sessionUnlocked(); + return true; + } + } +#endif + + return false; +} diff --git a/Linphone/core/event-filter/LockEventFilter.hpp b/Linphone/core/event-filter/LockEventFilter.hpp new file mode 100644 index 000000000..e6d2bd4d1 --- /dev/null +++ b/Linphone/core/event-filter/LockEventFilter.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010-2026 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.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 3 of the License, or + * (at your option) any later version. + * + * 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 . + */ + +#ifndef LOCKEVENTFILTER_H +#define LOCKEVENTFILTER_H + +#include "tool/Utils.hpp" +#include + +#ifdef Q_OS_WIN +#include +#include +#include +#pragma comment(lib, "Wtsapi32.lib") +#endif + +class LockEventFilter : public QObject, public QAbstractNativeEventFilter { + Q_OBJECT +public: + LockEventFilter(QObject *parent = nullptr); + // virtual bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; + + virtual bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; + +signals: + void sessionUnlocked(); +}; + +#endif // LOCKEVENTFILTER_H diff --git a/Linphone/core/notifier/Notifier.cpp b/Linphone/core/notifier/Notifier.cpp index 58c3289f1..4620f2e09 100644 --- a/Linphone/core/notifier/Notifier.cpp +++ b/Linphone/core/notifier/Notifier.cpp @@ -207,12 +207,23 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d // ----------------------------------------------------------------------------- -void Notifier::showNotification(QObject *notification, int timeout) { +void Notifier::showNotification(QQuickWindow *notification, int timeout) { // Display notification. QTimer *timer = new QTimer(notification); timer->setInterval(timeout); timer->setSingleShot(true); notification->setProperty(NotificationPropertyTimer, QVariant::fromValue(timer)); +#ifdef Q_OS_WIN + QObject::connect(App::getInstance(), &App::sessionUnlocked, notification, [this, notification] { + lInfo() << log().arg("Windows : screen unlocked, force raising notification"); + notification->show(); + notification->raise(); + notification->requestActivate(); + }); +#endif + notification->show(); + notification->raise(); + notification->requestActivate(); // Destroy it after timeout. QObject::connect(timer, &QTimer::timeout, this, diff --git a/Linphone/core/notifier/Notifier.hpp b/Linphone/core/notifier/Notifier.hpp index 088c9de0b..e64c0d2bc 100644 --- a/Linphone/core/notifier/Notifier.hpp +++ b/Linphone/core/notifier/Notifier.hpp @@ -90,7 +90,7 @@ private: }; bool createNotification(NotificationType type, QVariantMap data); - void showNotification(QObject *notification, int timeout); + void showNotification(QQuickWindow *notification, int timeout); QHash mScreenHeightOffset; int mInstancesNumber = 0; diff --git a/Linphone/data/languages/de.ts b/Linphone/data/languages/de.ts index 4000ae031..e121bc232 100644 --- a/Linphone/data/languages/de.ts +++ b/Linphone/data/languages/de.ts @@ -678,14 +678,14 @@ - + info_popup_error_title Error Fehler - + info_popup_configuration_failed_message Remote provisioning failed : %1 @@ -725,86 +725,86 @@ - + configuration_error_detail not reachable - + application_description "A free and open source SIP video-phone." Ein kostenloses Open-Source SIP Video-Telefon. - + command_line_arg_order "Send an order to the application towards a command line" Kommandozeilen-Befehl an die Anwendung schicken - + command_line_option_show_help Zeige Hilfe - + command_line_option_show_app_version App-Version anzeigen - + command_line_option_config_to_fetch "Specify the linphone configuration file to be fetched. It will be merged with the current configuration." Abzurufende Linphone-Konfigurationsdatei angeben. Sie wird mit der aktuellen Konfiguration zusammengeführt. - + command_line_option_config_to_fetch_arg "URL, path or file" URL, Pfad oder Datei - + command_line_option_minimized - + command_line_option_log_to_stdout Debug-Informationen auf der Standardausgabe ausgeben - + command_line_option_print_app_logs_only "Print only logs from the application" Nur Anwendungs-Logs ausgeben - + hide_action "Cacher" "Afficher" Ausblenden - + show_action Zeigen - + quit_action "Quitter" Beenden - + check_for_update Check for update - + mark_all_read_action @@ -2071,13 +2071,13 @@ ChatCore - + info_toast_deleted_title Deleted - + info_toast_deleted_message_history Message history has been deleted @@ -4726,19 +4726,19 @@ Error MeetingListView - + meeting_info_cancelled "Réunion annulée" Besprechung abgesagt - + meetings_list_no_meeting_for_today "Aucune réunion aujourd'hui" Heute keine Besprechungen - + meeting_info_delete "Supprimer la réunion" Besprechung löschen @@ -5135,42 +5135,42 @@ Error Notifier - + new_call_alert_accessible_name New call from %1 - + new_voice_message 'Voice message received!' : message to warn the user in a notification for voice messages. - + new_file_message - + new_conference_invitation 'Conference invitation received!' : Notification about receiving an invitation to a conference. - + new_chat_room_message 'New message received!' Notification that warn the user of a new message. - + new_chat_room_messages 'New messages received!' Notification that warn the user of new messages. - + new_message_alert_accessible_name New message on chatroom %1 diff --git a/Linphone/data/languages/en.ts b/Linphone/data/languages/en.ts index 07b299443..5bf329c75 100644 --- a/Linphone/data/languages/en.ts +++ b/Linphone/data/languages/en.ts @@ -669,14 +669,14 @@ - + info_popup_error_title Error Error - + info_popup_configuration_failed_message Remote provisioning failed : %1 Remote provisioning failed : %1 @@ -716,86 +716,86 @@ Up to date Your version is up to date - + configuration_error_detail not reachable not reachable - + application_description "A free and open source SIP video-phone." A free and open source SIP video-phone. - + command_line_arg_order "Send an order to the application towards a command line" Send an order to the application towards a command line - + command_line_option_show_help Show this help - + command_line_option_show_app_version Show app version - + command_line_option_config_to_fetch "Specify the linphone configuration file to be fetched. It will be merged with the current configuration." Specify the linphone configuration file to be fetched. It will be merged with the current configuration. - + command_line_option_config_to_fetch_arg "URL, path or file" URL, path or file - + command_line_option_minimized Minimize - + command_line_option_log_to_stdout Log to stdout some debug information while running - + command_line_option_print_app_logs_only "Print only logs from the application" Print only logs from the application - + hide_action "Cacher" "Afficher" Hide - + show_action Show - + quit_action "Quitter" Quit - + check_for_update Check for update Check for update - + mark_all_read_action Marquer tout comme lu @@ -2064,13 +2064,13 @@ ChatCore - + info_toast_deleted_title Deleted Deleted - + info_toast_deleted_message_history Message history has been deleted Message history has been deleted @@ -4658,19 +4658,19 @@ Expiration : %1 MeetingListView - + meeting_info_cancelled "Réunion annulée" Meeting canceled - + meetings_list_no_meeting_for_today "Aucune réunion aujourd'hui" No meeting for today - + meeting_info_delete "Supprimer la réunion" Delete meeting @@ -5058,42 +5058,42 @@ Expiration : %1 Notifier - + new_call_alert_accessible_name New call from %1 New call from %1 - + new_voice_message 'Voice message received!' : message to warn the user in a notification for voice messages. Voice message received! - + new_file_message File received! - + new_conference_invitation 'Conference invitation received!' : Notification about receiving an invitation to a conference. Conference invitation received ! - + new_chat_room_message 'New message received!' Notification that warn the user of a new message. New message received! - + new_chat_room_messages 'New messages received!' Notification that warn the user of new messages. New messages received ! - + new_message_alert_accessible_name New message on chatroom %1 New message on chatroom %1 diff --git a/Linphone/data/languages/fr.ts b/Linphone/data/languages/fr.ts index a8bc22b45..820d01a4a 100644 --- a/Linphone/data/languages/fr.ts +++ b/Linphone/data/languages/fr.ts @@ -664,14 +664,14 @@ - + info_popup_error_title Error Erreur - + info_popup_configuration_failed_message Remote provisioning failed : %1 La configuration distante a échoué : %1 @@ -711,86 +711,86 @@ Votre version est à jour - + configuration_error_detail not reachable indisponible - + application_description "A free and open source SIP video-phone." A free and open source SIP video-phone. - + command_line_arg_order "Send an order to the application towards a command line" Send an order to the application towards a command line - + command_line_option_show_help Show this help - + command_line_option_show_app_version Afficher la version de l'application - + command_line_option_config_to_fetch "Specify the linphone configuration file to be fetched. It will be merged with the current configuration." Specify the linphone configuration file to be fetched. It will be merged with the current configuration. - + command_line_option_config_to_fetch_arg "URL, path or file" URL, path or file - + command_line_option_minimized Minimiser - + command_line_option_log_to_stdout Log to stdout some debug information while running - + command_line_option_print_app_logs_only "Print only logs from the application" Print only logs from the application - + hide_action "Cacher" "Afficher" Cacher - + show_action Afficher - + quit_action "Quitter" Quitter - + check_for_update Check for update Rechercher une mise à jour - + mark_all_read_action Marquer tout comme lu @@ -2039,13 +2039,13 @@ ChatCore - + info_toast_deleted_title Deleted Supprimé - + info_toast_deleted_message_history Message history has been deleted L'historique des messages a été supprimé @@ -4629,19 +4629,19 @@ Expiration : %1 MeetingListView - + meeting_info_cancelled "Réunion annulée" Réunion annulée - + meetings_list_no_meeting_for_today "Aucune réunion aujourd'hui" Aucune réunion aujourd'hui - + meeting_info_delete "Supprimer la réunion" Supprimer la réunion @@ -5029,42 +5029,42 @@ Expiration : %1 Notifier - + new_call_alert_accessible_name New call from %1 Nouvel appel de %1 - + new_voice_message 'Voice message received!' : message to warn the user in a notification for voice messages. Message vocal reçu ! - + new_file_message Fichier reçu ! - + new_conference_invitation 'Conference invitation received!' : Notification about receiving an invitation to a conference. Nouvelle invitation à une conférence ! - + new_chat_room_message 'New message received!' Notification that warn the user of a new message. Nouveau message reçu ! - + new_chat_room_messages 'New messages received!' Notification that warn the user of new messages. Nouveaux messages reçus ! - + new_message_alert_accessible_name New message on chatroom %1 Nouveau message sur la conversation %1 diff --git a/Linphone/view/Control/Popup/DesktopPopup.qml b/Linphone/view/Control/Popup/DesktopPopup.qml index 165c8aee4..4485f6eee 100644 --- a/Linphone/view/Control/Popup/DesktopPopup.qml +++ b/Linphone/view/Control/Popup/DesktopPopup.qml @@ -40,7 +40,7 @@ Window { property bool showAsTool : false // Don't use Popup for flags : it could lead to error in geometry. On Mac, Using Tool ensure to have the Window on Top and fullscreen independant // flags: Qt.WindowDoesNotAcceptFocus | Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint; - flags: Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.FramelessWindowHint + flags: Qt.SplashScreen | Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint opacity: 1.0 height: _content[0] != null ? _content[0].height : 0 width: _content[0] != null ? _content[0].width : 0