fix #LINQT-1641 main window steals focus on macos

This commit is contained in:
gaelle.braud 2025-02-03 14:39:06 +01:00
parent 37a0403c01
commit a4809bbde5
5 changed files with 280 additions and 255 deletions

View file

@ -866,6 +866,15 @@ void App::setMainWindow(QQuickWindow *data) {
} }
} }
QQuickWindow *App::getLastActiveWindow() const {
return mLastActiveWindow;
}
void App::setLastActiveWindow(QQuickWindow *data) {
if (mLastActiveWindow != data) {
mLastActiveWindow = data;
}
}
QSharedPointer<AccountList> App::getAccountList() const { QSharedPointer<AccountList> App::getAccountList() const {
return mAccountList; return mAccountList;
} }
@ -1059,7 +1068,7 @@ bool App::event(QEvent *event) {
receivedMessage(0, url.toLocal8Bit()); receivedMessage(0, url.toLocal8Bit());
} else if (event->type() == QEvent::ApplicationStateChange) { } else if (event->type() == QEvent::ApplicationStateChange) {
auto state = static_cast<QApplicationStateChangeEvent *>(event); auto state = static_cast<QApplicationStateChangeEvent *>(event);
if (state->applicationState() == Qt::ApplicationActive) Utils::smartShowWindow(getMainWindow()); if (state->applicationState() == Qt::ApplicationActive) Utils::smartShowWindow(getLastActiveWindow());
} }
return SingleApplication::event(event); return SingleApplication::event(event);

View file

@ -131,6 +131,9 @@ public:
QQuickWindow *getMainWindow() const; QQuickWindow *getMainWindow() const;
void setMainWindow(QQuickWindow *data); void setMainWindow(QQuickWindow *data);
QQuickWindow *getLastActiveWindow() const;
void setLastActiveWindow(QQuickWindow *data);
QSharedPointer<AccountList> getAccountList() const; QSharedPointer<AccountList> getAccountList() const;
void setAccountList(QSharedPointer<AccountList> data); void setAccountList(QSharedPointer<AccountList> data);
Q_INVOKABLE AccountList *getAccounts() const; Q_INVOKABLE AccountList *getAccounts() const;
@ -182,6 +185,7 @@ private:
QSystemTrayIcon *mSystemTrayIcon = nullptr; QSystemTrayIcon *mSystemTrayIcon = nullptr;
QQuickWindow *mMainWindow = nullptr; QQuickWindow *mMainWindow = nullptr;
QQuickWindow *mCallsWindow = nullptr; QQuickWindow *mCallsWindow = nullptr;
QQuickWindow *mLastActiveWindow = nullptr;
QSharedPointer<SettingsCore> mSettings; QSharedPointer<SettingsCore> mSettings;
QSharedPointer<AccountList> mAccountList; QSharedPointer<AccountList> mAccountList;
QSharedPointer<CallList> mCallList; QSharedPointer<CallList> mCallList;

View file

@ -212,6 +212,13 @@ QQuickWindow *Utils::getMainWindow() {
return win; return win;
} }
QQuickWindow *Utils::getLastActiveWindow() {
return App::getInstance()->getLastActiveWindow();
}
void Utils::setLastActiveWindow(QQuickWindow *data) {
App::getInstance()->setLastActiveWindow(data);
}
void Utils::showInformationPopup(const QString &title, void Utils::showInformationPopup(const QString &title,
const QString &description, const QString &description,
bool isSuccess, bool isSuccess,
@ -239,6 +246,7 @@ void Utils::smartShowWindow(QQuickWindow *window) {
if (window->visibility() == QWindow::Maximized) // Avoid to change visibility mode if (window->visibility() == QWindow::Maximized) // Avoid to change visibility mode
window->showNormal(); window->showNormal();
else window->show(); else window->show();
App::getInstance()->setLastActiveWindow(window);
window->raise(); // Raise ensure to get focus on Mac window->raise(); // Raise ensure to get focus on Mac
window->requestActivate(); window->requestActivate();
} }

View file

@ -75,6 +75,8 @@ public:
Q_INVOKABLE static void setupConference(ConferenceInfoGui *confGui); Q_INVOKABLE static void setupConference(ConferenceInfoGui *confGui);
Q_INVOKABLE static QQuickWindow *getMainWindow(); Q_INVOKABLE static QQuickWindow *getMainWindow();
Q_INVOKABLE static void openCallsWindow(CallGui *call); Q_INVOKABLE static void openCallsWindow(CallGui *call);
Q_INVOKABLE static QQuickWindow *getLastActiveWindow();
Q_INVOKABLE static void setLastActiveWindow(QQuickWindow *data);
Q_INVOKABLE static void showInformationPopup(const QString &title, Q_INVOKABLE static void showInformationPopup(const QString &title,
const QString &description, const QString &description,
bool isSuccess = true, bool isSuccess = true,

View file

@ -9,269 +9,271 @@ import DesktopToolsCpp
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
ApplicationWindow { ApplicationWindow {
id: mainWindow id: mainWindow
x: 0 x: 0
y: 0 y: 0
width: Math.min(1512 * DefaultStyle.dp, Screen.desktopAvailableWidth) width: Math.min(1512 * DefaultStyle.dp, Screen.desktopAvailableWidth)
height: Math.min(982 * DefaultStyle.dp, Screen.desktopAvailableHeight) height: Math.min(982 * DefaultStyle.dp, Screen.desktopAvailableHeight)
property bool isFullscreen: visibility == Window.FullScreen
onIsFullscreenChanged: DesktopToolsCpp.screenSaverStatus = !isFullscreen
MouseArea { onActiveChanged: UtilsCpp.setLastActiveWindow(this)
anchors.fill: parent
onClicked: mainWindow.contentItem.forceActiveFocus()
}
Component { property bool isFullscreen: visibility == Window.FullScreen
id: popupComp onIsFullscreenChanged: DesktopToolsCpp.screenSaverStatus = !isFullscreen
InformationPopup{}
}
Component{
id: confirmPopupComp
Dialog {
property var requestDialog
property int index
property var callback: requestDialog?.result
signal closePopup(int index)
onClosed: closePopup(index)
text: requestDialog?.message
details: requestDialog?.details
firstButtonAccept: title.length === 0
secondButtonAccept: title.length !== 0
Component.onCompleted: if (details.length != 0) radius = 0
// For C++, requestDialog need to be call directly
onAccepted: requestDialog ? requestDialog.result(1) : callback(1)
onRejected: requestDialog ? requestDialog.result(0) : callback(0)
width: title.length === 0 ? 278 * DefaultStyle.dp : 637 * DefaultStyle.dp
}
}
Popup { MouseArea {
id: startCallPopup anchors.fill: parent
property FriendGui contact onClicked: mainWindow.contentItem.forceActiveFocus()
property bool videoEnabled }
// if currentCall, transfer call to contact
property CallGui currentCall
onContactChanged: {
console.log("contact changed", contact)
}
underlineColor: DefaultStyle.main1_500_main
anchors.centerIn: parent
width: 370 * DefaultStyle.dp
modal: true
leftPadding: 15 * DefaultStyle.dp
rightPadding: 15 * DefaultStyle.dp
topPadding: 20 * DefaultStyle.dp
bottomPadding: 25 * DefaultStyle.dp
contentItem: ColumnLayout {
spacing: 16 * DefaultStyle.dp
RowLayout {
spacing: 5 * DefaultStyle.dp
width: startCallPopup.width
Text {
text: qsTr("Quelle addresse souhaitez-vous appeler ?")
wrapMode: Text.Wrap
Layout.fillWidth: true
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
RoundButton {
Layout.alignment: Qt.AlignVCenter
style: ButtonStyle.noBackground
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
icon.source:AppIcons.closeX
onClicked: startCallPopup.close()
}
}
ListView {
id: popuplist
model: VariantList {
model: startCallPopup.contact && startCallPopup.contact.core.allAddresses || []
}
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
spacing: 10 * DefaultStyle.dp
delegate: Item {
width: popuplist.width
height: 56 * DefaultStyle.dp
ColumnLayout {
width: popuplist.width
anchors.verticalCenter: parent.verticalCenter
spacing: 10 * DefaultStyle.dp
ColumnLayout {
spacing: 7 * DefaultStyle.dp
Text {
Layout.leftMargin: 5 * DefaultStyle.dp
text: modelData.label + " :"
font {
pixelSize: 13 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
Text {
Layout.leftMargin: 5 * DefaultStyle.dp
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(modelData.address) : modelData.address
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
}
}
Rectangle {
visible: index != popuplist.model.count - 1
Layout.fillWidth: true
Layout.preferredHeight: 1 * DefaultStyle.dp
color: DefaultStyle.main2_200
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (startCallPopup.currentCall) startCallPopup.currentCall.core.lTransferCall(modelData.address)
else UtilsCpp.createCall(modelData.address, {'localVideoEnabled': startCallPopup.videoEnabled})
startCallPopup.close()
}
}
}
}
}
}
function startCallWithContact(contact, videoEnabled, parentItem) { Component {
if (parentItem == undefined) parentItem = mainWindow.contentItem id: popupComp
startCallPopup.parent = parentItem InformationPopup{}
if (contact) { }
console.log("START CALL WITH", contact.core.fullName, "addresses count", contact.core.allAddresses.length)
if (contact.core.allAddresses.length > 1) {
startCallPopup.contact = contact
startCallPopup.videoEnabled = videoEnabled
startCallPopup.open()
} else { Component{
var addressToCall = contact.core.defaultAddress.length === 0 id: confirmPopupComp
? contact.core.phoneNumbers.length === 0 Dialog {
? "" property var requestDialog
: contact.core.phoneNumbers[0].address property int index
: contact.core.defaultAddress property var callback: requestDialog?.result
if (addressToCall.length != 0) UtilsCpp.createCall(addressToCall, {'localVideoEnabled':videoEnabled}) signal closePopup(int index)
} onClosed: closePopup(index)
} text: requestDialog?.message
} details: requestDialog?.details
firstButtonAccept: title.length === 0
secondButtonAccept: title.length !== 0
Component.onCompleted: if (details.length != 0) radius = 0
// For C++, requestDialog need to be call directly
onAccepted: requestDialog ? requestDialog.result(1) : callback(1)
onRejected: requestDialog ? requestDialog.result(0) : callback(0)
width: title.length === 0 ? 278 * DefaultStyle.dp : 637 * DefaultStyle.dp
}
}
function transferCallToContact(call, contact, parentItem) { Popup {
if (!call || !contact) return id: startCallPopup
if (parentItem == undefined) parentItem = mainWindow.contentItem property FriendGui contact
startCallPopup.parent = parentItem property bool videoEnabled
if (contact) { // if currentCall, transfer call to contact
console.log("[AbstractWindow] Transfer call to", contact.core.fullName, "addresses count", contact.core.allAddresses.length, call) property CallGui currentCall
if (contact.core.allAddresses.length > 1) { onContactChanged: {
startCallPopup.contact = contact console.log("contact changed", contact)
startCallPopup.currentCall = call }
startCallPopup.open() underlineColor: DefaultStyle.main1_500_main
anchors.centerIn: parent
width: 370 * DefaultStyle.dp
modal: true
leftPadding: 15 * DefaultStyle.dp
rightPadding: 15 * DefaultStyle.dp
topPadding: 20 * DefaultStyle.dp
bottomPadding: 25 * DefaultStyle.dp
contentItem: ColumnLayout {
spacing: 16 * DefaultStyle.dp
RowLayout {
spacing: 5 * DefaultStyle.dp
width: startCallPopup.width
Text {
text: qsTr("Quelle addresse souhaitez-vous appeler ?")
wrapMode: Text.Wrap
Layout.fillWidth: true
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
RoundButton {
Layout.alignment: Qt.AlignVCenter
style: ButtonStyle.noBackground
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
icon.source:AppIcons.closeX
onClicked: startCallPopup.close()
}
}
ListView {
id: popuplist
model: VariantList {
model: startCallPopup.contact && startCallPopup.contact.core.allAddresses || []
}
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
spacing: 10 * DefaultStyle.dp
delegate: Item {
width: popuplist.width
height: 56 * DefaultStyle.dp
ColumnLayout {
width: popuplist.width
anchors.verticalCenter: parent.verticalCenter
spacing: 10 * DefaultStyle.dp
ColumnLayout {
spacing: 7 * DefaultStyle.dp
Text {
Layout.leftMargin: 5 * DefaultStyle.dp
text: modelData.label + " :"
font {
pixelSize: 13 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
Text {
Layout.leftMargin: 5 * DefaultStyle.dp
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(modelData.address) : modelData.address
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
}
}
Rectangle {
visible: index != popuplist.model.count - 1
Layout.fillWidth: true
Layout.preferredHeight: 1 * DefaultStyle.dp
color: DefaultStyle.main2_200
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (startCallPopup.currentCall) startCallPopup.currentCall.core.lTransferCall(modelData.address)
else UtilsCpp.createCall(modelData.address, {'localVideoEnabled': startCallPopup.videoEnabled})
startCallPopup.close()
}
}
}
}
}
}
} else { function startCallWithContact(contact, videoEnabled, parentItem) {
var addressToCall = contact.core.defaultAddress.length === 0 if (parentItem == undefined) parentItem = mainWindow.contentItem
? contact.core.phoneNumbers.length === 0 startCallPopup.parent = parentItem
? "" if (contact) {
: contact.core.phoneNumbers[0].address console.log("START CALL WITH", contact.core.fullName, "addresses count", contact.core.allAddresses.length)
: contact.core.defaultAddress if (contact.core.allAddresses.length > 1) {
if (addressToCall.length != 0) call.core.lTransferCall(addressToCall) startCallPopup.contact = contact
} startCallPopup.videoEnabled = videoEnabled
} startCallPopup.open()
}
function removeFromPopupLayout(index) { } else {
popupLayout.popupList.splice(index, 1) var addressToCall = contact.core.defaultAddress.length === 0
} ? contact.core.phoneNumbers.length === 0
function showInformationPopup(title, description, isSuccess) { ? ""
if (isSuccess == undefined) isSuccess = true : contact.core.phoneNumbers[0].address
var infoPopup = popupComp.createObject(popupLayout, {"title": title, "description": description, "isSuccess": isSuccess}) : contact.core.defaultAddress
infoPopup.index = popupLayout.popupList.length if (addressToCall.length != 0) UtilsCpp.createCall(addressToCall, {'localVideoEnabled':videoEnabled})
popupLayout.popupList.push(infoPopup) }
infoPopup.open() }
infoPopup.closePopup.connect(removeFromPopupLayout) }
}
function showLoadingPopup(text, cancelButtonVisible, callback) {
if (cancelButtonVisible == undefined) cancelButtonVisible = false
loadingPopup.text = text
loadingPopup.callback = callback
loadingPopup.cancelButtonVisible = cancelButtonVisible
loadingPopup.open()
}
function closeLoadingPopup() {
loadingPopup.close()
}
function showConfirmationPopup(requestDialog){ function transferCallToContact(call, contact, parentItem) {
console.log("Showing confirmation popup") if (!call || !contact) return
var popup = confirmPopupComp.createObject(popupLayout, {"requestDialog": requestDialog}) if (parentItem == undefined) parentItem = mainWindow.contentItem
popup.open() startCallPopup.parent = parentItem
popup.closePopup.connect(removeFromPopupLayout) if (contact) {
} console.log("[AbstractWindow] Transfer call to", contact.core.fullName, "addresses count", contact.core.allAddresses.length, call)
if (contact.core.allAddresses.length > 1) {
function showConfirmationLambdaPopup(title,text, details, callback, firstButtonText, secondButtonText, customContent){ startCallPopup.contact = contact
console.log("Showing confirmation lambda popup") startCallPopup.currentCall = call
var popup = confirmPopupComp.createObject(popupLayout, {"title": title, "text": text, "details":details,"callback":callback}) startCallPopup.open()
if (firstButtonText != undefined) popup.firstButtonText = firstButtonText
if (secondButtonText != undefined) popup.secondButtonText = secondButtonText
if (customContent != undefined) popup.content = customContent
popup.titleColor = DefaultStyle.main1_500_main
popup.open()
popup.closePopup.connect(removeFromPopupLayout)
}
ColumnLayout {
id: popupLayout
anchors.fill: parent
Layout.alignment: Qt.AlignBottom
property int nextY: mainWindow.height
property list<InformationPopup> popupList
property int popupCount: popupList.length
spacing: 15 * DefaultStyle.dp
onPopupCountChanged: {
nextY = mainWindow.height
for(var i = 0; i < popupCount; ++i) {
var popupItem = popupList[i]
if( popupItem ){
popupItem.y = nextY - popupItem.height
popupItem.index = i
nextY = nextY - popupItem.height - 15
}
}
}
}
LoadingPopup { } else {
id: loadingPopup var addressToCall = contact.core.defaultAddress.length === 0
modal: true ? contact.core.phoneNumbers.length === 0
closePolicy: Popup.NoAutoClose ? ""
anchors.centerIn: parent : contact.core.phoneNumbers[0].address
padding: 20 * DefaultStyle.dp : contact.core.defaultAddress
underlineColor: DefaultStyle.main1_500_main if (addressToCall.length != 0) call.core.lTransferCall(addressToCall)
radius: 15 * DefaultStyle.dp }
} }
FPSCounter{ }
anchors.top: parent.top
anchors.left: parent.left function removeFromPopupLayout(index) {
height: 50 popupLayout.popupList.splice(index, 1)
width: fpsText.implicitWidth }
z: 100 function showInformationPopup(title, description, isSuccess) {
visible: !SettingsCpp.hideFps if (isSuccess == undefined) isSuccess = true
Text{ var infoPopup = popupComp.createObject(popupLayout, {"title": title, "description": description, "isSuccess": isSuccess})
id: fpsText infoPopup.index = popupLayout.popupList.length
font.bold: true popupLayout.popupList.push(infoPopup)
font.italic: true infoPopup.open()
font.pixelSize: 14 * DefaultStyle.dp infoPopup.closePopup.connect(removeFromPopupLayout)
text: parent.fps + " FPS" }
color: parent.fps < 30 ? DefaultStyle.danger_500main : DefaultStyle.main2_900 function showLoadingPopup(text, cancelButtonVisible, callback) {
} if (cancelButtonVisible == undefined) cancelButtonVisible = false
} loadingPopup.text = text
loadingPopup.callback = callback
loadingPopup.cancelButtonVisible = cancelButtonVisible
loadingPopup.open()
}
function closeLoadingPopup() {
loadingPopup.close()
}
function showConfirmationPopup(requestDialog){
console.log("Showing confirmation popup")
var popup = confirmPopupComp.createObject(popupLayout, {"requestDialog": requestDialog})
popup.open()
popup.closePopup.connect(removeFromPopupLayout)
}
function showConfirmationLambdaPopup(title,text, details, callback, firstButtonText, secondButtonText, customContent){
console.log("Showing confirmation lambda popup")
var popup = confirmPopupComp.createObject(popupLayout, {"title": title, "text": text, "details":details,"callback":callback})
if (firstButtonText != undefined) popup.firstButtonText = firstButtonText
if (secondButtonText != undefined) popup.secondButtonText = secondButtonText
if (customContent != undefined) popup.content = customContent
popup.titleColor = DefaultStyle.main1_500_main
popup.open()
popup.closePopup.connect(removeFromPopupLayout)
}
ColumnLayout {
id: popupLayout
anchors.fill: parent
Layout.alignment: Qt.AlignBottom
property int nextY: mainWindow.height
property list<InformationPopup> popupList
property int popupCount: popupList.length
spacing: 15 * DefaultStyle.dp
onPopupCountChanged: {
nextY = mainWindow.height
for(var i = 0; i < popupCount; ++i) {
var popupItem = popupList[i]
if( popupItem ){
popupItem.y = nextY - popupItem.height
popupItem.index = i
nextY = nextY - popupItem.height - 15
}
}
}
}
LoadingPopup {
id: loadingPopup
modal: true
closePolicy: Popup.NoAutoClose
anchors.centerIn: parent
padding: 20 * DefaultStyle.dp
underlineColor: DefaultStyle.main1_500_main
radius: 15 * DefaultStyle.dp
}
FPSCounter{
anchors.top: parent.top
anchors.left: parent.left
height: 50
width: fpsText.implicitWidth
z: 100
visible: !SettingsCpp.hideFps
Text{
id: fpsText
font.bold: true
font.italic: true
font.pixelSize: 14 * DefaultStyle.dp
text: parent.fps + " FPS"
color: parent.fps < 30 ? DefaultStyle.danger_500main : DefaultStyle.main2_900
}
}
} }