diff options
-rw-r--r-- | src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp | 232 | ||||
-rw-r--r-- | src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h (renamed from src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.h) | 29 | ||||
-rw-r--r-- | src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp | 204 | ||||
-rw-r--r-- | src/plugins/platforms/winrt/qwinrttheme.cpp | 9 | ||||
-rw-r--r-- | src/plugins/platforms/winrt/winrt.pro | 6 |
5 files changed, 259 insertions, 221 deletions
diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp new file mode 100644 index 0000000000..6de90ba1ec --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinrtmessagedialoghelper.h" +#include "qwinrttheme.h" + +#include <QtCore/qfunctions_winrt.h> + +#include <windows.ui.popups.h> +#include <windows.foundation.h> +#include <windows.foundation.collections.h> +#include <wrl.h> + +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Popups; +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +typedef IAsyncOperationCompletedHandler<IUICommand *> DialogCompletedHandler; + +QT_BEGIN_NAMESPACE + +class CommandId : public RuntimeClass<IInspectable> +{ +public: + CommandId(QPlatformDialogHelper::StandardButton button) + : button(button) { } + QPlatformDialogHelper::StandardButton button; +}; + +class QWinRTMessageDialogHelperPrivate +{ +public: + const QWinRTTheme *theme; + bool shown; + ComPtr<IAsyncInfo> info; + QEventLoop loop; +}; + +QWinRTMessageDialogHelper::QWinRTMessageDialogHelper(const QWinRTTheme *theme) + : QPlatformMessageDialogHelper(), d_ptr(new QWinRTMessageDialogHelperPrivate) +{ + Q_D(QWinRTMessageDialogHelper); + + d->theme = theme; + d->shown = false; +} + +QWinRTMessageDialogHelper::~QWinRTMessageDialogHelper() +{ + Q_D(QWinRTMessageDialogHelper); + + if (d->shown) + hide(); +} + +void QWinRTMessageDialogHelper::exec() +{ + Q_D(QWinRTMessageDialogHelper); + + if (!d->shown) + show(Qt::Dialog, Qt::ApplicationModal, 0); + d->loop.exec(); +} + +bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) +{ + Q_UNUSED(windowFlags) + Q_UNUSED(windowModality) + Q_UNUSED(parent) + Q_D(QWinRTMessageDialogHelper); + + QSharedPointer<QMessageDialogOptions> options = this->options(); + const QString informativeText = options->informativeText(); + const QString title = options->windowTitle(); + const QString text = informativeText.isEmpty() ? options->text() : (options->text() + QLatin1Char('\n') + informativeText); + + HRESULT hr; + ComPtr<IMessageDialogFactory> dialogFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_MessageDialog).Get(), + IID_PPV_ARGS(&dialogFactory)); + RETURN_FALSE_IF_FAILED("Failed to create dialog factory"); + + ComPtr<IUICommandFactory> commandFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_UICommand).Get(), + IID_PPV_ARGS(&commandFactory)); + RETURN_FALSE_IF_FAILED("Failed to create command factory"); + + ComPtr<IMessageDialog> dialog; + HStringReference nativeText(reinterpret_cast<LPCWSTR>(text.utf16()), text.size()); + if (!title.isEmpty()) { + HStringReference nativeTitle(reinterpret_cast<LPCWSTR>(title.utf16()), title.size()); + hr = dialogFactory->CreateWithTitle(nativeText.Get(), nativeTitle.Get(), &dialog); + RETURN_FALSE_IF_FAILED("Failed to create dialog with title"); + } else { + hr = dialogFactory->Create(nativeText.Get(), &dialog); + RETURN_FALSE_IF_FAILED("Failed to create dialog"); + } + + // Add Buttons + ComPtr<IVector<IUICommand *>> dialogCommands; + hr = dialog->get_Commands(&dialogCommands); + RETURN_FALSE_IF_FAILED("Failed to get dialog commands"); + + // If no button is specified we need to create one to get close notification + int buttons = options->standardButtons(); + if (buttons == 0) + buttons = Ok; + + for (int i = FirstButton; i < LastButton; i<<=1) { + if (!(buttons & i)) + continue; + // Add native command + const QString label = d->theme->standardButtonText(i); + HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()), label.size()); + ComPtr<IUICommand> command; + hr = commandFactory->Create(nativeLabel.Get(), &command); + RETURN_FALSE_IF_FAILED("Failed to create message box command"); + ComPtr<IInspectable> id = Make<CommandId>(static_cast<StandardButton>(i)); + hr = command->put_Id(id.Get()); + RETURN_FALSE_IF_FAILED("Failed to set command ID"); + hr = dialogCommands->Append(command.Get()); + if (hr == E_BOUNDS) { + qErrnoWarning(hr, "The WinRT message dialog supports a maximum of three buttons"); + continue; + } + RETURN_FALSE_IF_FAILED("Failed to append message box command"); + if (i == Abort || i == Cancel || i == Close) { + quint32 size; + hr = dialogCommands->get_Size(&size); + RETURN_FALSE_IF_FAILED("Failed to get command list size"); + hr = dialog->put_CancelCommandIndex(size - 1); + RETURN_FALSE_IF_FAILED("Failed to set cancel index"); + } + } + + ComPtr<IAsyncOperation<IUICommand *>> op; + hr = dialog->ShowAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to show dialog"); + hr = op->put_Completed(Callback<DialogCompletedHandler>(this, &QWinRTMessageDialogHelper::onCompleted).Get()); + RETURN_FALSE_IF_FAILED("Failed to set dialog callback"); + + d->shown = true; + hr = op.As(&d->info); + RETURN_FALSE_IF_FAILED("Failed to acquire AsyncInfo for MessageDialog"); + + return true; +} + +void QWinRTMessageDialogHelper::hide() +{ + Q_D(QWinRTMessageDialogHelper); + + if (!d->shown) + return; + + HRESULT hr = d->info->Cancel(); + if (FAILED(hr)) + qErrnoWarning(hr, "Failed to cancel dialog operation"); + + d->shown = false; +} + +HRESULT QWinRTMessageDialogHelper::onCompleted(IAsyncOperation<IUICommand *> *asyncInfo, AsyncStatus status) +{ + Q_UNUSED(status); + Q_D(QWinRTMessageDialogHelper); + + if (d->loop.isRunning()) + d->loop.exit(); + + d->shown = false; + + if (status == Canceled) { + emit reject(); + return S_OK; + } + + HRESULT hr; + ComPtr<IUICommand> command; + hr = asyncInfo->GetResults(&command); + RETURN_OK_IF_FAILED("Failed to get command"); + + ComPtr<CommandId> id; + hr = command->get_Id(&id); + RETURN_OK_IF_FAILED("Failed to get command ID"); + + ButtonRole role = buttonRole(id->button); + emit clicked(id->button, role); + return S_OK; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.h b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h index fbb21ed69c..25199e569c 100644 --- a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h @@ -39,11 +39,10 @@ ** ****************************************************************************/ -#ifndef QWINRTPLATFORMMESSAGEDIALOGHELPER_H -#define QWINRTPLATFORMMESSAGEDIALOGHELPER_H +#ifndef QWINRTMESSAGEDIALOGHELPER_H +#define QWINRTMESSAGEDIALOGHELPER_H #include <qpa/qplatformdialoghelper.h> -#include <QtCore/QEventLoop> #include <QtCore/qt_windows.h> namespace ABI { @@ -53,19 +52,24 @@ namespace ABI { struct IUICommand; } } + namespace Foundation { + enum class AsyncStatus; + template <typename T> struct IAsyncOperation; + } } } QT_BEGIN_NAMESPACE -struct QWinRTPlatformMessageDialogInfo; +class QWinRTTheme; -class QWinRTPlatformMessageDialogHelper : public QPlatformMessageDialogHelper +class QWinRTMessageDialogHelperPrivate; +class QWinRTMessageDialogHelper : public QPlatformMessageDialogHelper { Q_OBJECT public: - explicit QWinRTPlatformMessageDialogHelper(); - ~QWinRTPlatformMessageDialogHelper(); + explicit QWinRTMessageDialogHelper(const QWinRTTheme *theme); + ~QWinRTMessageDialogHelper(); void exec(); bool show(Qt::WindowFlags windowFlags, @@ -73,13 +77,14 @@ public: QWindow *parent); void hide(); - HRESULT onInvoked(ABI::Windows::UI::Popups::IUICommand *command); private: - QWinRTPlatformMessageDialogInfo *m_info; - QEventLoop m_loop; - bool m_shown; + HRESULT onCompleted(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand *> *asyncInfo, + ABI::Windows::Foundation::AsyncStatus status); + + QScopedPointer<QWinRTMessageDialogHelperPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTMessageDialogHelper) }; QT_END_NAMESPACE -#endif // QWINRTPLATFORMMESSAGEDIALOGHELPER_H +#endif // QWINRTMESSAGEDIALOGHELPER_H diff --git a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp deleted file mode 100644 index c2f884055d..0000000000 --- a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwinrtplatformmessagedialoghelper.h" - -#include <QtGui/QGuiApplication> -#include <private/qguiapplication_p.h> -#include <qpa/qplatformtheme.h> - -#include <asyncinfo.h> -#include <windows.ui.popups.h> -#include <windows.foundation.h> -#include <windows.foundation.collections.h> -#include <wrl.h> - -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Foundation::Collections; -using namespace ABI::Windows::UI::Popups; -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; - -QT_BEGIN_NAMESPACE - -struct QWinRTPlatformMessageDialogInfo -{ - ComPtr<IAsyncInfo> info; -}; - -QWinRTPlatformMessageDialogHelper::QWinRTPlatformMessageDialogHelper() : - QPlatformMessageDialogHelper(), - m_info(new QWinRTPlatformMessageDialogInfo), - m_shown(false) -{ -} - -QWinRTPlatformMessageDialogHelper::~QWinRTPlatformMessageDialogHelper() -{ - if (m_shown) - hide(); - delete m_info; -} - -void QWinRTPlatformMessageDialogHelper::exec() -{ - if (!m_shown) - show(Qt::Dialog, Qt::ApplicationModal, 0); - m_loop.exec(); -} - -bool QWinRTPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) -{ - Q_UNUSED(windowFlags) - Q_UNUSED(windowModality) - Q_UNUSED(parent) - - QSharedPointer<QMessageDialogOptions> options = this->options(); - - const QString informativeText = options->informativeText(); - const QString title = options->windowTitle(); - const QString text = informativeText.isEmpty() ? options->text() : (options->text() + QLatin1Char('\n') + informativeText); - - - ComPtr<IMessageDialogFactory> dialogFactory; - if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_MessageDialog).Get(), &dialogFactory))) - return false; - - ComPtr<IUICommandFactory> commandFactory; - if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_UICommand).Get(), &commandFactory))) - return false; - - HString nativeText; - nativeText.Set(reinterpret_cast<LPCWSTR>(text.utf16()), text.size()); - ComPtr<IMessageDialog> dialog; - - if (!title.isEmpty()) { - HString nativeTitle; - nativeTitle.Set(reinterpret_cast<LPCWSTR>(title.utf16()), title.size()); - if (FAILED(dialogFactory->CreateWithTitle(nativeText.Get(), nativeTitle.Get(), &dialog))) - return false; - } else { - if (FAILED(dialogFactory->Create(nativeText.Get(), &dialog))) - return false; - } - - // Add Buttons - ComPtr<IVector<IUICommand*> > dialogCommands; - if (FAILED(dialog->get_Commands(&dialogCommands))) - return false; - - // If no button is specified we need to create one to get close notification - int buttons = options->standardButtons(); - if (buttons == 0) - buttons = QPlatformDialogHelper::Ok; - - for (int i = QPlatformDialogHelper::FirstButton; i < QPlatformDialogHelper::LastButton; i<<=1) { - if (buttons & i) { - // Add native command - const QString label = QGuiApplicationPrivate::platformTheme()->standardButtonText(i); - - HString hLabel; - hLabel.Set(reinterpret_cast<LPCWSTR>(label.utf16()), label.size()); - - ABI::Windows::UI::Popups::IUICommand *command; - if (FAILED(commandFactory->CreateWithHandler(hLabel.Get(), - Callback<IUICommandInvokedHandler>(this, &QWinRTPlatformMessageDialogHelper::onInvoked).Get(), - &command))) - return false; - dialogCommands->Append(command); - } - } - - ComPtr<IAsyncOperation<IUICommand*> > op; - if (FAILED(dialog->ShowAsync(&op))) - return false; - - m_shown = true; - if (FAILED(op.As(&m_info->info))) { - m_shown = false; - // The dialog is shown already, so we cannot return false - qWarning("Failed to acquire AsyncInfo for MessageDialog"); - } - return true; -} - -void QWinRTPlatformMessageDialogHelper::hide() -{ - if (!m_shown) - return; - - m_info->info->Cancel(); - m_shown = false; -} - -HRESULT QWinRTPlatformMessageDialogHelper::onInvoked(ABI::Windows::UI::Popups::IUICommand *command) -{ - HString hLabel; - UINT32 labelLength; - command->get_Label(hLabel.GetAddressOf()); - PCWSTR rawString = hLabel.GetRawBuffer(&labelLength); - QString label = QString::fromWCharArray(rawString, labelLength); - int buttonId = -1; - for (int i = QPlatformDialogHelper::FirstButton; i < QPlatformDialogHelper::LastButton; i<<=1) { - if ( options()->standardButtons() & i ) { - if (QGuiApplicationPrivate::platformTheme()->standardButtonText(i) == label) { - buttonId = i; - break; - } - } - } - if (m_loop.isRunning()) - m_loop.exit(); - - m_shown = false; - - if (buttonId < 0) { - emit reject(); - return S_OK; - } - - QPlatformDialogHelper::StandardButton standardButton = static_cast<QPlatformDialogHelper::StandardButton>(buttonId); - QPlatformDialogHelper::ButtonRole role = QPlatformDialogHelper::buttonRole(standardButton); - emit clicked(standardButton, role); - return S_OK; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp index 65ed9440b2..f9c2e21676 100644 --- a/src/plugins/platforms/winrt/qwinrttheme.cpp +++ b/src/plugins/platforms/winrt/qwinrttheme.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include "qwinrttheme.h" -#include "qwinrtplatformmessagedialoghelper.h" +#include "qwinrtmessagedialoghelper.h" #include <QtCore/qfunctions_winrt.h> #include <QtGui/QPalette> @@ -131,8 +131,11 @@ QWinRTTheme::QWinRTTheme() bool QWinRTTheme::usePlatformNativeDialog(DialogType type) const { + static bool useNativeDialogs = qEnvironmentVariableIsSet("QT_USE_WINRT_NATIVE_DIALOGS") + ? qgetenv("QT_USE_WINRT_NATIVE_DIALOGS").toInt() : true; + if (type == MessageDialog) - return true; + return useNativeDialogs; return false; } @@ -140,7 +143,7 @@ QPlatformDialogHelper *QWinRTTheme::createPlatformDialogHelper(DialogType type) { switch (type) { case MessageDialog: - return new QWinRTPlatformMessageDialogHelper; + return new QWinRTMessageDialogHelper(this); default: break; } diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 5460a7b18c..427920a670 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -35,12 +35,13 @@ SOURCES = \ qwinrtfontdatabase.cpp \ qwinrtinputcontext.cpp \ qwinrtintegration.cpp \ - qwinrtplatformmessagedialoghelper.cpp \ + qwinrtmessagedialoghelper.cpp \ qwinrtscreen.cpp \ qwinrtservices.cpp \ qwinrttheme.cpp \ qwinrtwindow.cpp + HEADERS = \ qwinrtbackingstore.h \ qwinrtcursor.h \ @@ -49,12 +50,13 @@ HEADERS = \ qwinrtfontdatabase.h \ qwinrtinputcontext.h \ qwinrtintegration.h \ - qwinrtplatformmessagedialoghelper.h \ + qwinrtmessagedialoghelper.h \ qwinrtscreen.h \ qwinrtservices.h \ qwinrttheme.h \ qwinrtwindow.h + BLIT_INPUT = $$PWD/blit.hlsl fxc_blitps.commands = fxc.exe /nologo /T ps_4_0_level_9_1 /E blitps /Vn q_blitps /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} fxc_blitps.output = $$OUT_PWD/blitps.h |