Port QMacNativeWidget to Qt 5

Also adds examples/widgets/mac subdir for Mac specific examples,
starting with one for this feature.

Change-Id: I4cc7d84ce3d7562259d6206faa5d6996c2392a3e
Reviewed-by: Liang Qi <liang.qi@digia.com>
This commit is contained in:
Morten Johan Sørvig 2013-09-02 12:41:50 +02:00 committed by The Qt Project
parent 05cd06cff3
commit f370f77e48
7 changed files with 218 additions and 22 deletions

View File

@ -0,0 +1,5 @@
TEMPLATE = subdirs
macx {
SUBDIRS = \
qmacnativewidget
}

View File

@ -0,0 +1,142 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite 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$
**
****************************************************************************/
#import <Cocoa/Cocoa.h>
#include <QApplication>
#include <QDebug>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPainter>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QMacNativeWidget>
class RedWidget : public QWidget
{
public:
RedWidget() {
}
void resizeEvent(QResizeEvent *)
{
qDebug() << "RedWidget::resize" << size();
}
void paintEvent(QPaintEvent *event)
{
QPainter p(this);
Q_UNUSED(event);
QRect rect(QPoint(0, 0), size());
qDebug() << "Painting geometry" << rect;
p.fillRect(rect, QColor(133, 50, 50));
}
};
namespace {
int qtArgc = 0;
char **qtArgv;
QApplication *qtApp = 0;
}
@interface WindowCreator : NSObject {}
- (void)createWindow;
@end
@implementation WindowCreator
- (void)createWindow {
// Qt widgets rely on a QApplication being alive somewhere
qtApp = new QApplication(qtArgc, qtArgv);
// Create the NSWindow
NSRect frame = NSMakeRect(500, 500, 500, 500);
NSWindow* window = [[NSWindow alloc] initWithContentRect:frame
styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[window setTitle:@"NSWindow"];
// Create widget hierarchy with QPushButton and QLineEdit
QMacNativeWidget *nativeWidget = new QMacNativeWidget();
// Get the NSView for QMacNativeWidget and set it as the content view for the NSWindow
[window setContentView:nativeWidget->nativeView()];
QHBoxLayout *hlayout = new QHBoxLayout();
hlayout->addWidget(new QPushButton("Push", nativeWidget));
hlayout->addWidget(new QLineEdit(nativeWidget));
QVBoxLayout *vlayout = new QVBoxLayout();
vlayout->addLayout(hlayout);
//RedWidget * redWidget = new RedWidget;
//vlayout->addWidget(redWidget);
nativeWidget->setLayout(vlayout);
// show() must be called on nativeWiget to get the widgets int he correct state.
nativeWidget->show();
// Show the NSWindow
[window makeKeyAndOrderFront:NSApp];
}
@end
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Normally, we would use the application delegate.
// We resort to the notification mechanism for conciseness.
WindowCreator *windowCreator= [WindowCreator alloc];
[[NSNotificationCenter defaultCenter]
addObserver:windowCreator selector:@selector(createWindow)
name:NSApplicationDidFinishLaunchingNotification object:nil];
// Save these for QApplication
qtArgc = argc;
qtArgv = argv;
// Other than the few lines above, it's business as usual...
return NSApplicationMain(argc, (const char **)argv);
}

View File

@ -0,0 +1,7 @@
TEMPLATE = app
OBJECTIVE_SOURCES += main.mm
LIBS += -framework Cocoa
QT += widgets
#QT += widgets-private gui-private core-private

View File

@ -28,3 +28,4 @@ contains(QT_CONFIG, opengl(es1|es2)?) {
!contains(QT_CONFIG, opengl(es1|es2)?): SUBDIRS -= windowcontainer !contains(QT_CONFIG, opengl(es1|es2)?): SUBDIRS -= windowcontainer
contains(DEFINES, QT_NO_CURSOR): SUBDIRS -= mainwindows contains(DEFINES, QT_NO_CURSOR): SUBDIRS -= mainwindows
contains(DEFINES, QT_NO_DRAGANDDROP): SUBDIRS -= draganddrop contains(DEFINES, QT_NO_DRAGANDDROP): SUBDIRS -= draganddrop
mac:SUBDIRS += mac

View File

@ -44,20 +44,23 @@
#include <QtWidgets/QWidget> #include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE Q_FORWARD_DECLARE_OBJC_CLASS(NSView);
QT_BEGIN_NAMESPACE
class QMacNativeWidgetPrivate; class QMacNativeWidgetPrivate;
class Q_WIDGETS_EXPORT QMacNativeWidget : public QWidget class Q_WIDGETS_EXPORT QMacNativeWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
QMacNativeWidget(void *parentRef = 0); QMacNativeWidget(NSView *parentView = 0);
~QMacNativeWidget(); ~QMacNativeWidget();
QSize sizeHint() const; QSize sizeHint() const;
NSView *nativeView() const;
protected: protected:
void init(NSView *parentView);
bool event(QEvent *ev); bool event(QEvent *ev);
private: private:

View File

@ -40,15 +40,18 @@
****************************************************************************/ ****************************************************************************/
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import <private/qcocoaview_mac_p.h>
#include "qmacnativewidget_mac.h" #include "qmacnativewidget_mac.h"
#include <private/qwidget_p.h>
#include <QtCore/qdebug.h>
#include <QtGui/qwindow.h>
#include <QtGui/qguiapplication.h>
#include <qpa/qplatformnativeinterface.h>
/*! /*!
\class QMacNativeWidget \class QMacNativeWidget
\since 4.5 \since 4.5
\brief The QMacNativeWidget class provides a widget for Mac OS X that provides a way to put Qt widgets into Carbon \brief The QMacNativeWidget class provides a widget for Mac OS X that provides
or Cocoa hierarchies depending on how Qt was configured. a way to put Qt widgets into Cocoa hierarchies.
\ingroup advanced \ingroup advanced
\inmodule QtWidgets \inmodule QtWidgets
@ -80,26 +83,47 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QMacNativeWidgetPrivate : public QWidgetPrivate namespace {
// TODO use QtMacExtras copy of this function when available.
inline QPlatformNativeInterface::NativeResourceForIntegrationFunction resolvePlatformFunction(const QByteArray &functionName)
{ {
}; QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
QPlatformNativeInterface::NativeResourceForIntegrationFunction function =
nativeInterface->nativeResourceFunctionForIntegration(functionName);
if (!function)
qWarning() << "Qt could not resolve function" << functionName
<< "from QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration()";
return function;
}
} //namespsace
extern OSViewRef qt_mac_create_widget(QWidget *widget, QWidgetPrivate *widgetPrivate, OSViewRef parent); NSView *getEmbeddableView(QWindow *qtWindow)
{
// Make sure the platform window is created
qtWindow->create();
// Inform the window that it's a subwindow of a non-Qt window. This must be
// done after create() because we need to have a QPlatformWindow instance.
// The corresponding NSWindow will not be shown and can be deleted later.
typedef void (*SetEmbeddedInForeignViewFunction)(QPlatformWindow *window, bool embedded);
reinterpret_cast<SetEmbeddedInForeignViewFunction>(resolvePlatformFunction("setEmbeddedInForeignView"))(qtWindow->handle(), true);
// Get the Qt content NSView for the QWindow from the Qt platform plugin
QPlatformNativeInterface *platformNativeInterface = QGuiApplication::platformNativeInterface();
NSView *qtView = (NSView *)platformNativeInterface->nativeResourceForWindow("nsview", qtWindow);
return qtView; // qtView is ready for use.
}
/*! /*!
Create a QMacNativeWidget with \a parentView as its "superview" (i.e., Create a QMacNativeWidget with \a parentView as its "superview" (i.e.,
parent). The \a parentView is either an HIViewRef if Qt is using Carbon or parent). The \a parentView is a NSView pointer.
a NSView pointer if Qt is using Cocoa.
*/ */
QMacNativeWidget::QMacNativeWidget(void *parentView) QMacNativeWidget::QMacNativeWidget(NSView *parentView)
: QWidget(*new QMacNativeWidgetPrivate, 0, Qt::Window) : QWidget(0)
{ {
Q_D(QMacNativeWidget); Q_UNUSED(parentView);
OSViewRef myView = qt_mac_create_widget(this, d, OSViewRef(parentView));
d->topData()->embedded = true; //d_func()->topData()->embedded = true;
create(WId(myView), false, false);
setPalette(QPalette(Qt::transparent)); setPalette(QPalette(Qt::transparent));
setAttribute(Qt::WA_SetPalette, false); setAttribute(Qt::WA_SetPalette, false);
setAttribute(Qt::WA_LayoutUsesWidgetRect); setAttribute(Qt::WA_LayoutUsesWidgetRect);
@ -117,8 +141,19 @@ QMacNativeWidget::~QMacNativeWidget()
*/ */
QSize QMacNativeWidget::sizeHint() const QSize QMacNativeWidget::sizeHint() const
{ {
return QSize(200, 200); // QMacNativeWidget really does not have any other choice
// than to fill its designated area.
if (windowHandle())
return windowHandle()->size();
return QWidget::sizeHint();
} }
NSView *QMacNativeWidget::nativeView() const
{
winId();
return getEmbeddableView(windowHandle());
}
/*! /*!
\reimp \reimp
*/ */

View File

@ -142,20 +142,23 @@ SOURCES += \
widgets/qplaintextedit.cpp widgets/qplaintextedit.cpp
macx { macx {
HEADERS += \
widgets/qmacnativewidget_mac.h
OBJECTIVE_SOURCES += \ OBJECTIVE_SOURCES += \
widgets/qmenu_mac.mm widgets/qmenu_mac.mm \
widgets/qmacnativewidget_mac.mm
} }
# TODO # TODO
false:mac { false:mac {
HEADERS += widgets/qmacnativewidget_mac.h \ HEADERS += widgets/qmaccocoaviewcontainer_mac.h
widgets/qmaccocoaviewcontainer_mac.h
OBJECTIVE_HEADERS += widgets/qcocoatoolbardelegate_mac_p.h \ OBJECTIVE_HEADERS += widgets/qcocoatoolbardelegate_mac_p.h \
widgets/qcocoamenu_mac_p.h widgets/qcocoamenu_mac_p.h
OBJECTIVE_SOURCES += widgets/qmaccocoaviewcontainer_mac.mm \ OBJECTIVE_SOURCES += widgets/qmaccocoaviewcontainer_mac.mm \
widgets/qcocoatoolbardelegate_mac.mm \ widgets/qcocoatoolbardelegate_mac.mm \
widgets/qmainwindowlayout_mac.mm \ widgets/qmainwindowlayout_mac.mm \
widgets/qmacnativewidget_mac.mm \
} }
wince*: { wince*: {