Fix : invisible window when receiving call

- Process GUI events before accepting a call in order to be synchronized with Call objects
- Revert window variable naming
- Change open window order when receive call

Fix : Show Notifications while in fullscreen
Fix : show settings in fullscreen

QuickFix:
- Set Minimum Width on Tooltips
- Show full path on log folder selection
- Add Conference participant filter to show only users that are in conference
- Add test on Player to avoid crash if it cannot be instanciated before
- Window position when opening in fullscreen
This commit is contained in:
Julien Wadel 2020-06-01 15:59:39 +02:00
parent 4468c49d2e
commit bd6055227f
22 changed files with 163 additions and 125 deletions

View file

@ -398,13 +398,9 @@ QQuickWindow *App::getSettingsWindow () const {
void App::smartShowWindow (QQuickWindow *window) {
if (!window)
return;
window->setVisible(true);
if (window->visibility() == QWindow::Minimized)
window->show();
window->raise();
window->show();// Force show, maybe redundant with setVisible
window->raise();// Raise ensure to get focus on Mac
window->requestActivate();
}

View file

@ -47,7 +47,8 @@ AppController::AppController (int &argc, char *argv[]) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
// Useful to share camera on Fullscreen (other context)
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
// Do not use APPLICATION_NAME here.
// Do not use APPLICATION_NAME here.
// The EXECUTABLE_NAME will be used in qt standard paths. It's our goal.
QCoreApplication::setApplicationName(EXECUTABLE_NAME);
QApplication::setOrganizationDomain(EXECUTABLE_NAME);

View file

@ -288,7 +288,7 @@ QImage ImageProvider::requestImage (const QString &id, QSize *size, const QSize
.arg(path);
return QImage(); // Memory cannot be allocated.
}
image.fill(0x00000000);
image.fill(Qt::transparent);// Fill with transparent to set alpha channel
*size = image.size();

View file

@ -343,22 +343,22 @@ void CallModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call,
void CallModel::accept (bool withVideo) {
stopAutoAnswerTimer();
CoreManager *coreManager = CoreManager::getInstance();
shared_ptr<linphone::Core> core = coreManager->getCore();
shared_ptr<linphone::CallParams> params = core->createCallParams(mCall);
params->enableVideo(withVideo);
setRecordFile(params);
QQuickWindow *callsWindow = App::getInstance()->getCallsWindow();
if (callsWindow) {
if (coreManager->getSettingsModel()->getKeepCallsWindowInBackground()) {
if (!callsWindow->isVisible())
callsWindow->showMinimized();
callsWindow->showMinimized();
} else
App::smartShowWindow(callsWindow);
}
qApp->processEvents(); // Process GUI events before accepting in order to be synchronized with Call objects and be ready to get SDK events
shared_ptr<linphone::Core> core = coreManager->getCore();
shared_ptr<linphone::CallParams> params = core->createCallParams(mCall);
params->enableVideo(withVideo);
setRecordFile(params);
mCall->acceptWithParams(params);
}

View file

@ -52,9 +52,9 @@ ConferenceModel::ConferenceModel (QObject *parent) : QSortFilterProxyModel(paren
}
bool ConferenceModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
Q_UNUSED(sourceRow)
Q_UNUSED(sourceParent)
return true;
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const CallModel *callModel = index.data().value<CallModel *>();
return callModel->getCall()->getParams()->getLocalConferenceMode() || callModel->getCall()->getCurrentParams()->getLocalConferenceMode();
}
// -----------------------------------------------------------------------------

View file

@ -130,6 +130,15 @@ QObject *Notifier::createNotification (Notifier::NotificationType type, QVariant
if(allScreens.size() > 0){ // Ensure to have a screen to avoid errors
QQuickItem * previousWrapper = nullptr;
++mInstancesNumber;
bool showAsTool = false;
#ifdef Q_OS_MACOS
for(auto w : QGuiApplication::topLevelWindows()){
if( (w->windowState()&Qt::WindowFullScreen)==Qt::WindowFullScreen){
showAsTool = true;
w->raise();// Used to get focus on Mac (On Mac, A Tool is hidden if the app has not focus and the only way to rid it is to use Widget Attributes(Qt::WA_MacAlwaysShowToolWindow) that is not available)
}
}
#endif
for(int i = 0 ; i < allScreens.size() ; ++i){
QQuickView *view = new QQuickView(App::getInstance()->getEngine(), nullptr); // Use QQuickView to create a visual root object that is independant from current application Window
QScreen *screen = allScreens[i];
@ -147,13 +156,15 @@ QObject *Notifier::createNotification (Notifier::NotificationType type, QVariant
view->setScreen(screen); // Bind the visual root object to the screen
view->setProperty("flags", QVariant(Qt::BypassWindowManagerHint | Qt::WindowStaysOnBottomHint | Qt::CustomizeWindowHint | Qt::X11BypassWindowManagerHint)); // Set the visual ghost window
view->setSource(QString(NotificationsPath)+Notifier::Notifications[type].filename);
QQuickWindow *subWindow = view->findChild<QQuickWindow *>("__internalWindow");
QObject::connect(subWindow, &QObject::destroyed, view, &QObject::deleteLater); // When destroying window, detroy visual root object too
int * screenHeightOffset = &mScreenHeightOffset[screen->name()]; // Access optimization
QRect availableGeometry = screen->availableGeometry();
int heightOffset = availableGeometry.y() + (availableGeometry.height() - subWindow->height());//*screen->devicePixelRatio(); when using manual scaler
if(showAsTool)
subWindow->setProperty("showAsTool",true);
subWindow->setX(availableGeometry.x()+ (availableGeometry.width()-subWindow->property("width").toInt()));//*screen->devicePixelRatio()); when using manual scaler
subWindow->setY(heightOffset-(*screenHeightOffset % heightOffset));
@ -175,6 +186,7 @@ QObject *Notifier::createNotification (Notifier::NotificationType type, QVariant
QObject::connect(wrapperItem, &QObject::destroyed, previousWrapper, &QObject::deleteLater);
}
previousWrapper = wrapperItem; // The last one is used as a point of start when deleting and openning
view->show();
}
qInfo() << QStringLiteral("Create notifications:") << wrapperItem;

View file

@ -139,7 +139,8 @@ void SoundPlayer::buildInternalPlayer () {
mInternalPlayer = coreManager->getCore()->createLocalPlayer(
Utils::appStringToCoreString(settingsModel->getRingerDevice()), "", nullptr
);
mInternalPlayer->addListener(mHandlers);
if(mInternalPlayer)
mInternalPlayer->addListener(mHandlers);
}
void SoundPlayer::rebuildInternalPlayer () {
@ -152,7 +153,8 @@ void SoundPlayer::stop (bool force) {
return;
mForceCloseTimer->stop();
mPlaybackState = SoundPlayer::StoppedState;
mInternalPlayer->close();
if(mInternalPlayer)
mInternalPlayer->close();
emit stopped();
emit playbackStateChanged(mPlaybackState);

View file

@ -27,7 +27,7 @@ TextField {
text: {
var path = textField.selectedFile
return path.length ? Utils.basename(path) : ''
return path.length ? path : ''
}
tools: Item {

View file

@ -27,6 +27,7 @@ Item {
// ---------------------------------------------------------------------------
property alias childA: contentA.data
property alias childAItem: contentA
property alias childB: contentB.data
property bool defaultClosed: false
property bool resizeAInPriority: false

View file

@ -15,13 +15,13 @@ Item {
// ---------------------------------------------------------------------------
property alias popupX: windowId.x
property alias popupY: windowId.y
property alias popupX: window.x
property alias popupY: window.y
property bool requestActivate: false
property int flags: Qt.SplashScreen
readonly property alias popupWidth: windowId.width
readonly property alias popupHeight: windowId.height
readonly property alias popupWidth: window.width
readonly property alias popupHeight: window.height
default property alias _content: content.data
property bool _isOpen: false
@ -50,11 +50,13 @@ Item {
visible:true
Window {
id: windowId
id: window
objectName: '__internalWindow'
property bool isFrameLess : false;
// Don't use Popup for flags : it could lead to error in geometry
flags: Qt.BypassWindowManagerHint | Qt.WindowStaysOnTopHint | Qt.Window | Qt.FramelessWindowHint;
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.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint;
opacity: 1.0
height: _content[0] != null ? _content[0].height : 0
width: _content[0] != null ? _content[0].width : 0
@ -75,7 +77,7 @@ Item {
PropertyChanges {
opacity: 1.0
target: windowId
target: window
}
}
@ -86,7 +88,7 @@ Item {
ScriptAction {
script: {
if (wrapper.requestActivate) {
windowId.requestActivate()
window.requestActivate()
}
}
}
@ -95,7 +97,7 @@ Item {
from: '*'
to: ''
ScriptAction {
script: windowId.hide()
script: window.close()
}
}
]

View file

@ -15,4 +15,5 @@ QtObject {
property int margins: 8
property int padding: 4
property int radius: 4
property int minWidth: 130
}

View file

@ -33,7 +33,7 @@ MouseArea {
delay: tooltipArea.delay
parent: tooltipParent
visible: _visible || force
width: tooltipParent.width
width: tooltipParent.width>TooltipStyle.minWidth?tooltipParent.width:TooltipStyle.minWidth
timeout: -1

View file

@ -10,7 +10,7 @@ ApplicationWindow {
default property alias _content: content.data
readonly property bool virtualWindowVisible: virtualWindow.visible
readonly property bool virtualWindowVisible: virtualWindow.active
// ---------------------------------------------------------------------------

View file

@ -1,41 +1,71 @@
import QtQuick 2.7
import Common.Styles 1.0
import 'Window.js' as Logic
// =============================================================================
Item {
function setContent (object) {
object.parent = content
object.anchors.centerIn = content
visible = true
}
function unsetContent () {
visible = false
var object = content.data[0]
content.data = []
return object
}
// ---------------------------------------------------------------------------
anchors.fill: parent
visible: false
MouseArea {
Loader {
id:mainLoader
active:false
property var sourceUrl
property var sourceProperties
property var exitStatusHandler
property bool setData : false // USe this flag to update source data
anchors.fill: parent
hoverEnabled: true
onWheel: wheel.accepted = true
}
Rectangle {
id: content
function setContent (url, properties, exitStatusHandler) {
mainLoader.sourceUrl=url;
mainLoader.sourceProperties=properties;
mainLoader.exitStatusHandler=exitStatusHandler;
setData=true;
active=true;
}
anchors.fill: parent
color: WindowStyle.transientWindow.color
}
function unsetContent () {
active=false
setData=false;
}
// ---------------------------------------------------------------------------
sourceComponent:Component{
id:mainComponent
Item{
id:rootContent
property alias contentLoader:content.contentLoader
anchors.fill: parent
MouseArea {
anchors.fill: parent
hoverEnabled: true
onWheel: wheel.accepted = true
}
Rectangle {
id: content
property alias contentLoader:contentLoader
anchors.fill: parent
color: WindowStyle.transientWindow.color
Loader{
id:contentLoader
anchors.centerIn: parent
property var setSourceData : setData
onSetSourceDataChanged: if( setData) {// SetData is true : assign source with properties using QML functions
if(sourceProperties)
setSource(sourceUrl, sourceProperties);
else
setSource(sourceUrl);
}else{source=undefined}// SetData is false : clean memory
active:mainLoader.active
onLoaded:{// When loaded, attache handlers to content
item.exitStatus.connect(Logic.detachVirtualWindow)
if (exitStatusHandler) {
item.exitStatus.connect(exitStatusHandler)
}
}
}
}
}
}
}

View file

@ -31,28 +31,16 @@
//
// The exit status handler is optional.
function attachVirtualWindow (component, properties, exitStatusHandler) {
if (virtualWindow.visible) {
if (virtualWindow.active){//already loaded
return
}
var object = Utils.createObject(component, null, {
properties: properties
})
object.exitStatus.connect(detachVirtualWindow)
if (exitStatusHandler) {
object.exitStatus.connect(exitStatusHandler)
}
virtualWindow.setContent(object)
virtualWindow.setContent(component, properties, exitStatusHandler)
window.attachedVirtualWindow()
}
function detachVirtualWindow () {
var object = virtualWindow.unsetContent()
if (object) {
object.destroy()
if( virtualWindow.active){
virtualWindow.unsetContent()
window.detachedVirtualWindow()
}
}

View file

@ -10,7 +10,7 @@ Window {
default property alias _content: content.data
readonly property bool virtualWindowVisible: virtualWindow.visible
readonly property bool virtualWindowVisible: virtualWindow.active //visible
// ---------------------------------------------------------------------------

View file

@ -196,11 +196,14 @@ function openWindow (window, parent, options, fullscreen) {
options.exitHandler.bind(parent)
)
}
if(fullscreen)
object.showFullScreen()
if( runOnWindows()){
object.show() // Needed for Windows : Show the window in all case. Allow to graphically locate the window before going to fullscreen.
if(fullscreen)
object.showFullScreen()// Should be equivalent to changing visibility
}else if(fullscreen)
object.showFullScreen()// Should be equivalent to changing visibility
else
object.show()
return object
}

View file

@ -59,7 +59,7 @@ function openConferenceManager () {
}
// -----------------------------------------------------------------------------
// Used to get Component based from Call Status
function getContent () {
var call = window.call
if (call == null) {

View file

@ -1,7 +1,6 @@
import QtGraphicalEffects 1.0
import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Window 2.2
import Common 1.0
import Linphone 1.0
@ -47,8 +46,8 @@ Window {
}
function setHeight (height) {
window.height = height > Screen.desktopAvailableHeight
? Screen.desktopAvailableHeight
window.height = (Window.screen && height > Window.screen.desktopAvailableHeight)
? Winodw.screen.desktopAvailableHeight
: height
}
@ -224,6 +223,7 @@ Window {
childA: Loader {
anchors.fill: parent
sourceComponent: Logic.getContent()
onSourceComponentChanged: {rightPaned.childAItem.update()}// Force update when loading a new Content. It's just to be sure
}
childB: Loader {

View file

@ -124,7 +124,7 @@ function openCallStatistics () {
callStatistics.open()
}
function openMediaParameters (incall) {
function openMediaParameters (window, incall) {
window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/MultimediaParameters.qml'), {
call: incall.call
})
@ -139,7 +139,9 @@ function showFullscreen (position) {
properties: {
caller: incall,
x:position.x,
y:position.y
y:position.y,
width:window.width,
height:window.height
}
}, true)
}

View file

@ -32,6 +32,7 @@ Rectangle {
// ---------------------------------------------------------------------------
color: CallStyle.backgroundColor
anchors.fill:parent
// ---------------------------------------------------------------------------
@ -78,7 +79,7 @@ Rectangle {
running: true
triggeredOnStart: true
onTriggered: elapsedTime.text = Utils.formatElapsedTime(call.duration)
onTriggered: {elapsedTime.text = Utils.formatElapsedTime(call.duration);}
}
}
@ -364,7 +365,7 @@ Rectangle {
icon: 'options'
iconSize: CallStyle.actionArea.iconSize
onClicked: Logic.openMediaParameters(incall)
onClicked: Logic.openMediaParameters(window, incall)
}
}

View file

@ -17,7 +17,7 @@ import 'Incall.js' as Logic
// =============================================================================
Window {
id: windowId
id: window
// ---------------------------------------------------------------------------
@ -31,12 +31,12 @@ Window {
DesktopTools.screenSaverStatus = true
// `exit` is called by `Incall.qml`.
// The `windowId` id can be null if the windowId was closed in this view.
if (!windowId) {
// The `window` id can be null if the window was closed in this view.
if (!window) {
return
}
if(!windowId.close() && parent)
if(!window.close() && parent)
parent.close()
@ -46,16 +46,15 @@ Window {
}
// ---------------------------------------------------------------------------
visible: false
onCallChanged: if(!call) windowId.exit()
onCallChanged: if(!call) window.exit()
Component.onCompleted: {
windowId.call = caller.call
window.call = caller.call
}
// ---------------------------------------------------------------------------
Shortcut {
sequence: StandardKey.Close
onActivated: windowId.exit()
onActivated: window.exit()
}
// ---------------------------------------------------------------------------
@ -66,13 +65,13 @@ Window {
color: '#000000' // Not a style.
focus: true
Keys.onEscapePressed: windowId.exit()
Keys.onEscapePressed: window.exit()
Loader {
anchors.fill: parent
active: {
var caller = windowId.caller
var caller = window.caller
return caller && !caller.cameraActivated
}
@ -82,7 +81,7 @@ Window {
id: camera
Camera {
call: windowId.call
call: window.call
}
}
}
@ -157,13 +156,13 @@ Window {
running: true
triggeredOnStart: true
onTriggered: Logic.updateCallQualityIcon(callQuality, windowId.call)
onTriggered: Logic.updateCallQualityIcon(callQuality, window.call)
}
CallStatistics {
id: callStatistics
enabled: windowId.call
call: windowId.call
enabled: window.call
call: window.call
width: container.width
relativeTo: callQuality
@ -182,12 +181,12 @@ Window {
ActionButton {
id: callSecure
icon: windowId.call && windowId.call.isSecured ? 'call_chat_secure' : 'call_chat_unsecure'
icon: window.call && window.call.isSecured ? 'call_chat_secure' : 'call_chat_unsecure'
onClicked: zrtp.visible = (windowId.call.encryption === CallModel.CallEncryptionZrtp)
onClicked: zrtp.visible = (window.call.encryption === CallModel.CallEncryptionZrtp)
TooltipArea {
text: windowId.call?Logic.makeReadableSecuredString(windowId.call.securedString):''
text: window.call?Logic.makeReadableSecuredString(window.call.securedString):''
}
}
@ -207,7 +206,7 @@ Window {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
visible: !windowId.hideButtons
visible: !window.hideButtons
// Not a customizable style.
color: 'white'
@ -216,8 +215,8 @@ Window {
Component.onCompleted: {
var updateDuration = function () {
if(windowId.caller){
var call = windowId.caller.call
if(window.caller){
var call = window.caller.call
text = Utils.formatElapsedTime(call.duration)
Utils.setTimeout(elapsedTime, 1000, updateDuration)
}
@ -268,7 +267,7 @@ Window {
ActionButton {
icon: 'fullscreen'
onClicked: windowId.exit()
onClicked: window.exit()
}
}
@ -287,7 +286,7 @@ Window {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.margins: CallStyle.container.margins
call: windowId.call
call: window.call
visible: call && !call.isSecured && call.encryption !== CallModel.CallEncryptionNone
z: Constants.zPopup
color: CallStyle.backgroundColor
@ -366,7 +365,7 @@ Window {
iconSize: CallStyle.actionArea.iconSize
updating: call && call.updating
onClicked: windowId.exit(function () { call.videoEnabled = false })
onClicked: window.exit(function () { call.videoEnabled = false })
}
ActionButton {
@ -376,7 +375,7 @@ Window {
icon: 'options'
iconSize: CallStyle.actionArea.iconSize
onClicked: Logic.openMediaParameters(windowId)
onClicked: Logic.openMediaParameters(Window.window, window)
}
}
@ -394,13 +393,13 @@ Window {
updating: call && call.updating
visible: SettingsModel.callPauseEnabled
onClicked: windowId.exit(function () { call.pausedByUser = enabled })
onClicked: window.exit(function () { call.pausedByUser = enabled })
}
ActionButton {
icon: 'hangup'
onClicked: windowId.exit(call.terminate)
onClicked: window.exit(call.terminate)
}
}
}
@ -413,7 +412,7 @@ Window {
Loader {
active: {
var caller = windowId.caller
var caller = window.caller
return caller && !caller.cameraActivated
}
@ -426,21 +425,21 @@ Window {
property bool scale: false
function xPosition () {
return windowId.width / 2 - width / 2
return window.width / 2 - width / 2
}
function yPosition () {
return windowId.height - height
return window.height - height
}
call: windowId.call
call: window.call
isPreview: true
height: CallStyle.actionArea.userVideo.height * (scale ? 2 : 1)
width: CallStyle.actionArea.userVideo.width * (scale ? 2 : 1)
DragBox {
container: windowId
container: window
draggable: parent
xPosition: parent.xPosition
@ -459,7 +458,7 @@ Window {
TelKeypad {
id: telKeypad
call: windowId.call
call: window.call
visible: false
}
}