/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/****************************************************************************
**
** Copyright (c) 2007-2008, Apple, Inc.
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice,
** this list of conditions and the following disclaimer.
**
** * Redistributions in binary form must reproduce the above copyright notice,
** this list of conditions and the following disclaimer in the documentation
** and/or other materials provided with the distribution.
**
** * Neither the name of Apple, Inc. nor the names of its contributors
** may be used to endorse or promote products derived from this software
** without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
****************************************************************************/
#include <private/qt_mac_p.h>
#include <private/qeventdispatcher_mac_p.h>
#include "qapplication.h"
#include "qapplication_p.h"
#include "qbitmap.h"
#include "qcursor.h"
#include "qdesktopwidget.h"
#include "qevent.h"
#include "qfileinfo.h"
#include "qimage.h"
#include "qlayout.h"
#include "qmenubar.h"
#include <private/qbackingstore_p.h>
#include <private/qwindowsurface_mac_p.h>
#include <private/qpaintengine_mac_p.h>
#include "qpainter.h"
#include "qstyle.h"
#include "qtimer.h"
#include "qfocusframe.h"
#include "qdebug.h"
#include <private/qmainwindowlayout_p.h>
#include <private/qabstractscrollarea_p.h>
#include <qabstractscrollarea.h>
#include <ApplicationServices/ApplicationServices.h>
#include <limits.h>
#include <private/qt_cocoa_helpers_mac_p.h>
#include <private/qcocoaview_mac_p.h>
#include <private/qcocoawindow_mac_p.h>
#include <private/qcocoawindowdelegate_mac_p.h>
#include <private/qcocoapanel_mac_p.h>
#include "qwidget_p.h"
#include "qevent_p.h"
#include "qdnd_p.h"
#include <QtGui/qgraphicsproxywidget.h>
#include "qmainwindow.h"
QT_BEGIN_NAMESPACE
#define XCOORD_MAX 16383
#define WRECT_MAX 8191
#ifndef QT_MAC_USE_COCOA
extern "C" {
extern OSStatus _HIViewScrollRectWithOptions(HIViewRef, const HIRect *, CGFloat, CGFloat,
OptionBits) __attribute__ ((weak));
}
#define kHIViewScrollRectAdjustInvalid 1
#define kHIViewScrollRectDontInvalidateRevealedArea 2
#endif
/*****************************************************************************
QWidget debug facilities
*****************************************************************************/
//#define DEBUG_WINDOW_RGNS
//#define DEBUG_WINDOW_CREATE
//#define DEBUG_WINDOW_STATE
//#define DEBUG_WIDGET_PAINT
/*****************************************************************************
QWidget globals
*****************************************************************************/
#ifndef QT_MAC_USE_COCOA
typedef QHash<Qt::WindowFlags, WindowGroupRef> WindowGroupHash;
Q_GLOBAL_STATIC(WindowGroupHash, qt_mac_window_groups)
const UInt32 kWidgetCreatorQt = kEventClassQt;
enum {
kWidgetPropertyQWidget = 'QWId' //QWidget *
};
#endif
static bool qt_mac_raise_process = true;
static OSWindowRef qt_root_win = 0;
QWidget *mac_mouse_grabber = 0;
QWidget *mac_keyboard_grabber = 0;
extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
#ifndef QT_MAC_USE_COCOA
#ifdef QT_NAMESPACE
// produce the string "com.trolltech.qt-namespace.widget", where "namespace" is the contents of QT_NAMESPACE.
#define SS(x) #x
#define S0(x) SS(x)
#define S "com.trolltech.qt-" S0(QT_NAMESPACE) ".widget"
static CFStringRef kObjectQWidget = CFSTR(S);
#undef SS
#undef S0
#undef S
#else
static CFStringRef kObjectQWidget = CFSTR("com.trolltech.qt.widget");
#endif // QT_NAMESPACE
#endif // QT_MAC_USE_COCOA
/*****************************************************************************
Externals
*****************************************************************************/
extern QWidget *qt_mac_modal_blocked(QWidget *); //qapplication_mac.mm
extern void qt_event_request_activate(QWidget *); //qapplication_mac.mm
extern bool qt_event_remove_activate(); //qapplication_mac.mm
extern void qt_mac_event_release(QWidget *w); //qapplication_mac.mm
extern void qt_event_request_showsheet(QWidget *); //qapplication_mac.mm
extern void qt_event_request_window_change(QWidget *); //qapplication_mac.mm
extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
extern IconRef qt_mac_create_iconref(const QPixmap &); //qpixmap_mac.cpp
extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.mm
extern void qt_mac_update_cursor(); //qcursor_mac.mm
extern bool qt_nograb();
extern CGImageRef qt_mac_create_cgimage(const QPixmap &, bool); //qpixmap_mac.cpp
extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
extern QRegion qt_mac_convert_mac_region(RgnHandle rgn); //qregion_mac.cpp
/*****************************************************************************
QWidget utility functions
*****************************************************************************/
void Q_GUI_EXPORT qt_mac_set_raise_process(bool b) { qt_mac_raise_process = b; }
static QSize qt_mac_desktopSize()
{
int w = 0, h = 0;
CGDisplayCount cg_count;
CGGetActiveDisplayList(0, 0, &cg_count);
QVector<CGDirectDisplayID> displays(cg_count);
CGGetActiveDisplayList(cg_count, displays.data(), &cg_count);
Q_ASSERT(cg_count == (CGDisplayCount)displays.size());
for(int i = 0; i < (int)cg_count; ++i) {
CGRect r = CGDisplayBounds(displays.at(i));
w = qMax<int>(w, qRound(r.origin.x + r.size.width));
h = qMax<int>(h, qRound(r.origin.y + r.size.height));
}
return QSize(w, h);
}
#ifdef QT_MAC_USE_COCOA
static NSDrawer *qt_mac_drawer_for(const QWidget *widget)
{
// This only goes one level below the content view so start with the window.
// This works fine for straight Qt stuff, but runs into problems if we are
// embedding, but if that's the case, they probably want to be using
// NSDrawer directly.
NSView *widgetView = reinterpret_cast<NSView *>(widget->window()->winId());
NSArray *windows = [NSApp windows];
for (NSWindow *window in windows) {
NSArray *drawers = [window drawers];
for (NSDrawer *drawer in drawers) {
NSArray *views = [[drawer contentView] subviews];
for (NSView *view in views) {
if (view == widgetView)
return drawer;
}
}
}
return 0;
}
#endif
static void qt_mac_destructView(OSViewRef view)
{
#ifdef QT_MAC_USE_COCOA
[view removeFromSuperview];
[view release];
#else
HIViewRemoveFromSuperview(view);
CFRelease(view);
#endif
}
static void qt_mac_destructWindow(OSWindowRef window)
{
#ifdef QT_MAC_USE_COCOA
if ([window isVisible] && [window isSheet]){
[NSApp endSheet:window];
[window orderOut:window];
}
[[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] resignDelegateForWindow:window];
[window release];
#else
// Remove property to clean up memory:
RemoveWindowProperty(window, kWidgetCreatorQt, kWidgetPropertyQWidget);
CFRelease(window);
#endif
}
static void qt_mac_destructDrawer(NSDrawer *drawer)
{
#ifdef QT_MAC_USE_COCOA
[[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] resignDelegateForDrawer:drawer];
[drawer release];
#else
Q_UNUSED(drawer);
#endif
}
bool qt_mac_can_clickThrough(const QWidget *w)
{
static int qt_mac_carbon_clickthrough = -1;
if (qt_mac_carbon_clickthrough < 0)
qt_mac_carbon_clickthrough = !qgetenv("QT_MAC_NO_COCOA_CLICKTHROUGH").isEmpty();
bool ret = !qt_mac_carbon_clickthrough;
for ( ; w; w = w->parentWidget()) {
if (w->testAttribute(Qt::WA_MacNoClickThrough)) {
ret = false;
break;
}
}
return ret;
}
bool qt_mac_is_macsheet(const QWidget *w)
{
if (!w)
return false;
Qt::WindowModality modality = w->windowModality();
if (modality == Qt::ApplicationModal)
return false;
return w->parentWidget() && (modality == Qt::WindowModal || w->windowType() == Qt::Sheet);
}
bool qt_mac_is_macdrawer(const QWidget *w)
{
return (w && w->parentWidget() && w->windowType() == Qt::Drawer);
}
bool qt_mac_insideKeyWindow(const QWidget *w)
{
#ifdef QT_MAC_USE_COCOA
return [[reinterpret_cast<NSView *>(w->winId()) window] isKeyWindow];
#else
Q_UNUSED(w);
#endif
return false;
}
bool qt_mac_set_drawer_preferred_edge(QWidget *w, Qt::DockWidgetArea where) //users of Qt for Mac OS X can use this..
{
if(!qt_mac_is_macdrawer(w))
return false;
#if QT_MAC_USE_COCOA
NSDrawer *drawer = qt_mac_drawer_for(w);
if (!drawer)
return false;
NSRectEdge edge;
if (where & Qt::LeftDockWidgetArea)
edge = NSMinXEdge;
else if (where & Qt::RightDockWidgetArea)
edge = NSMaxXEdge;
else if (where & Qt::TopDockWidgetArea)
edge = NSMaxYEdge;
else if (where & Qt::BottomDockWidgetArea)
edge = NSMinYEdge;
else
return false;
if (edge == [drawer preferredEdge]) //no-op
return false;
if (w->isVisible()) {
[drawer close];
[drawer openOnEdge:edge];
}
[drawer setPreferredEdge:edge];
#else
OSWindowRef window = qt_mac_window_for(w);
OptionBits edge;
if(where & Qt::LeftDockWidgetArea)
edge = kWindowEdgeLeft;
else if(where & Qt::RightDockWidgetArea)
edge = kWindowEdgeRight;
else if(where & Qt::TopDockWidgetArea)
edge = kWindowEdgeTop;
else if(where & Qt::BottomDockWidgetArea)
edge = kWindowEdgeBottom;
else
return false;
if(edge == GetDrawerPreferredEdge(window)) //no-op
return false;
//do it
SetDrawerPreferredEdge(window, edge);
if(w->isVisible()) {
CloseDrawer(window, false);
OpenDrawer(window, edge, true);
}
#endif
return true;
}
#ifndef QT_MAC_USE_COCOA
Q_GUI_EXPORT
#endif
QPoint qt_mac_posInWindow(const QWidget *w)
{
QPoint ret = w->data->wrect.topLeft();
while(w && !w->isWindow()) {
ret += w->pos();
w = w->parentWidget();
}
return ret;
}
//find a QWidget from a OSWindowRef
QWidget *qt_mac_find_window(OSWindowRef window)
{
#ifdef QT_MAC_USE_COCOA
return [window QT_MANGLE_NAMESPACE(qt_qwidget)];
#else
if(!window)
return 0;
QWidget *ret;
if(GetWindowProperty(window, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(ret), 0, &ret) == noErr)
return ret;
return 0;
#endif
}
inline static void qt_mac_set_fullscreen_mode(bool b)
{
extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
if(qt_mac_app_fullscreen == b)
return;
qt_mac_app_fullscreen = b;
if (b) {
SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
} else {
SetSystemUIMode(kUIModeNormal, 0);
}
}
Q_GUI_EXPORT OSViewRef qt_mac_nativeview_for(const QWidget *w)
{
return reinterpret_cast<OSViewRef>(w->data->winid);
}
Q_GUI_EXPORT OSViewRef qt_mac_get_contentview_for(OSWindowRef w)
{
#ifdef QT_MAC_USE_COCOA
return [w contentView];
#else
HIViewRef contentView = 0;
OSStatus err = GetRootControl(w, &contentView); // Returns the window's content view (Apple QA1214)
if (err == errUnknownControl) {
contentView = HIViewGetRoot(w);
} else if (err != noErr) {
qWarning("Qt:Could not get content or root view of window! %s:%d [%ld]",
__FILE__, __LINE__, err);
}
return contentView;
#endif
}
bool qt_mac_sendMacEventToWidget(QWidget *widget, EventRef ref)
{
return widget->macEvent(0, ref);
}
Q_GUI_EXPORT OSWindowRef qt_mac_window_for(OSViewRef view)
{
#ifdef QT_MAC_USE_COCOA
if (view)
return [view window];
return 0;
#else
return HIViewGetWindow(view);
#endif
}
static bool qt_isGenuineQWidget(OSViewRef ref)
{
#ifdef QT_MAC_USE_COCOA
return [ref isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]];
#else
return HIObjectIsOfClass(HIObjectRef(ref), kObjectQWidget);
#endif
}
bool qt_isGenuineQWidget(const QWidget *window)
{
return window && qt_isGenuineQWidget(OSViewRef(window->winId()));
}
Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget *w)
{
OSViewRef hiview = qt_mac_nativeview_for(w);
if (hiview){
OSWindowRef window = qt_mac_window_for(hiview);
if (!window && qt_isGenuineQWidget(hiview)) {
QWidget *myWindow = w->window();
// This is a workaround for NSToolbar. When a widget is hidden
// by clicking the toolbar button, Cocoa reparents the widgets
// to another window (but Qt doesn't know about it).
// When we start showing them, it reparents back,
// but at this point it's window is nil, but the window it's being brought
// into (the Qt one) is for sure created.
// This stops the hierarchy moving under our feet.
if (myWindow != w && qt_mac_window_for(qt_mac_nativeview_for(myWindow)))
return qt_mac_window_for(qt_mac_nativeview_for(myWindow));
myWindow->d_func()->createWindow_sys();
// Reget the hiview since the "create window could potentially move the view (I guess).
hiview = qt_mac_nativeview_for(w);
window = qt_mac_window_for(hiview);
}
return window;
}
return 0;
}
#ifndef QT_MAC_USE_COCOA
/* Checks if the current group is a 'stay on top' group. If so, the
group gets removed from the hash table */
static void qt_mac_release_stays_on_top_group(WindowGroupRef group)
{
for (WindowGroupHash::iterator it = qt_mac_window_groups()->begin(); it != qt_mac_window_groups()->end(); ++it) {
if (it.value() == group) {
qt_mac_window_groups()->remove(it.key());
return;
}
}
}
/* Use this function instead of ReleaseWindowGroup, this will be sure to release the
stays on top window group (created with qt_mac_get_stays_on_top_group below) */
static void qt_mac_release_window_group(WindowGroupRef group)
{
ReleaseWindowGroup(group);
if (GetWindowGroupRetainCount(group) == 0)
qt_mac_release_stays_on_top_group(group);
}
#define ReleaseWindowGroup(x) Are you sure you wanted to do that? (you wanted qt_mac_release_window_group)
SInt32 qt_mac_get_group_level(WindowClass wclass)
{
SInt32 group_level;
CGWindowLevel tmpLevel;
GetWindowGroupLevelOfType(GetWindowGroupOfClass(wclass), kWindowGroupLevelActive, &tmpLevel);
group_level = tmpLevel;
return group_level;
}
#endif
#ifndef QT_MAC_USE_COCOA
static void qt_mac_set_window_group(OSWindowRef window, Qt::WindowFlags flags, int level)
{
WindowGroupRef group = 0;
if (qt_mac_window_groups()->contains(flags)) {
group = qt_mac_window_groups()->value(flags);
RetainWindowGroup(group);
} else {
CreateWindowGroup(kWindowActivationScopeNone, &group);
SetWindowGroupLevel(group, level);
SetWindowGroupParent(group, GetWindowGroupOfClass(kAllWindowClasses));
qt_mac_window_groups()->insert(flags, group);
}
SetWindowGroup(window, group);
}
inline static void qt_mac_set_window_group_to_stays_on_top(OSWindowRef window, Qt::WindowType type)
{
// We create one static stays on top window group so that
// all stays on top (aka popups) will fall into the same
// group and be able to be raise()'d with releation to one another (from
// within the same window group).
qt_mac_set_window_group(window, type|Qt::WindowStaysOnTopHint, qt_mac_get_group_level(kOverlayWindowClass));
}
inline static void qt_mac_set_window_group_to_tooltip(OSWindowRef window)
{
// Since new groups are created for 'stays on top' windows, the
// same must be done for tooltips. Otherwise, tooltips would be drawn
// below 'stays on top' widgets even tough they are on the same level.
// Also, add 'two' to the group level to make sure they also get on top of popups.
qt_mac_set_window_group(window, Qt::ToolTip, qt_mac_get_group_level(kHelpWindowClass)+2);
}
inline static void qt_mac_set_window_group_to_popup(OSWindowRef window)
{
// In Qt, a popup is seen as a 'stay on top' window.
// Since new groups are created for 'stays on top' windows, the
// same must be done for popups. Otherwise, popups would be drawn
// below 'stays on top' windows. Add 1 to get above pure stay-on-top windows.
qt_mac_set_window_group(window, Qt::Popup, qt_mac_get_group_level(kOverlayWindowClass)+1);
}
#endif
#ifdef QT_MAC_USE_COCOA
void qt_mac_set_needs_display(QWidget *widget, QRegion region)
{
NSView *theNSView = qt_mac_nativeview_for(widget);
if (region.isEmpty()) {
[theNSView setNeedsDisplay:YES];
return;
}
QVector<QRect> rects = region.rects();
for (int i = 0; i<rects.count(); ++i) {
const QRect &rect = rects.at(i);
NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
[theNSView setNeedsDisplayInRect:nsrect];
}
}
#endif
inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRect &rect)
{
if (!widget)
return false;
#ifndef QT_NO_GRAPHICSVIEW
QWidget *tlw = widget->window();
QWExtra *extra = qt_widget_private(tlw)->extra;
if (extra && extra->proxyWidget) {
extra->proxyWidget->update(rect.translated(widget->mapTo(tlw, QPoint())));
return true;
}
#endif
return false;
}
inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRegion &rgn)
{
if (!widget)
return false;
#ifndef QT_NO_GRAPHICSVIEW
QWidget *tlw = widget->window();
QWExtra *extra = qt_widget_private(tlw)->extra;
if (extra && extra->proxyWidget) {
const QPoint offset(widget->mapTo(tlw, QPoint()));
const QVector<QRect> rects = rgn.rects();
for (int i = 0; i < rects.size(); ++i)
extra->proxyWidget->update(rects.at(i).translated(offset));
return true;
}
#endif
return false;
}
void QWidgetPrivate::macUpdateIsOpaque()
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created))
return;
#ifndef QT_MAC_USE_COCOA
HIViewFeatures bits;
HIViewRef hiview = qt_mac_nativeview_for(q);
HIViewGetFeatures(hiview, &bits);
if ((bits & kHIViewIsOpaque) == isOpaque)
return;
if (isOpaque) {
HIViewChangeFeatures(hiview, kHIViewIsOpaque, 0);
} else {
HIViewChangeFeatures(hiview, 0, kHIViewIsOpaque);
}
if (q->isVisible())
HIViewReshapeStructure(qt_mac_nativeview_for(q));
#else
if (isRealWindow() && !q->testAttribute(Qt::WA_MacBrushedMetal)) {
bool opaque = isOpaque;
if (extra && extra->imageMask)
opaque = false; // we are never opaque when we have a mask.
[qt_mac_window_for(q) setOpaque:opaque];
}
#endif
}
#ifdef QT_MAC_USE_COCOA
static OSWindowRef qt_mac_create_window(QWidget *widget, WindowClass wclass,
NSUInteger wattr, const QRect &crect)
{
// Determine if we need to add in our "custom window" attribute. Cocoa is rather clever
// in deciding if we need the maximize button or not (i.e., it's resizeable, so you
// must need a maximize button). So, the only buttons we have control over are the
// close and minimize buttons. If someone wants to customize and NOT have the maximize
// button, then we have to do our hack. We only do it for these cases because otherwise
// the window looks different when activated. This "QtMacCustomizeWindow" attribute is
// intruding on a public space and WILL BREAK in the future.
// One can hope that there is a more public API available by that time.
Qt::WindowFlags flags = widget ? widget->windowFlags() : Qt::WindowFlags(0);
if ((flags & Qt::CustomizeWindowHint)) {
if ((flags & (Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint
| Qt::WindowMinimizeButtonHint | Qt::WindowTitleHint))
&& !(flags & Qt::WindowMaximizeButtonHint))
wattr |= QtMacCustomizeWindow;
}
// If we haven't created the desktop widget, you have to pass the rectangle
// in "cocoa coordinates" (i.e., top points to the lower left coordinate).
// Otherwise, we do the conversion for you. Since we are the only ones that
// create the desktop widget, this is OK (but confusing).
NSRect geo = NSMakeRect(crect.left(),
(qt_root_win != 0) ? flipYCoordinate(crect.bottom() + 1) : crect.top(),
crect.width(), crect.height());
QMacCocoaAutoReleasePool pool;
OSWindowRef window;
switch (wclass) {
case kMovableModalWindowClass:
case kModalWindowClass:
case kSheetWindowClass:
case kFloatingWindowClass:
case kOverlayWindowClass:
case kHelpWindowClass: {
NSPanel *panel;
BOOL needFloating = NO;
BOOL worksWhenModal = widget && (widget->windowType() == Qt::Popup);
// Add in the extra flags if necessary.
switch (wclass) {
case kSheetWindowClass:
wattr |= NSDocModalWindowMask;
break;
case kFloatingWindowClass:
case kHelpWindowClass:
needFloating = YES;
wattr |= NSUtilityWindowMask;
break;
default:
break;
}
panel = [[QT_MANGLE_NAMESPACE(QCocoaPanel) alloc] QT_MANGLE_NAMESPACE(qt_initWithQWidget):widget contentRect:geo styleMask:wattr];
[panel setFloatingPanel:needFloating];
[panel setWorksWhenModal:worksWhenModal];
window = panel;
break;
}
case kDrawerWindowClass: {
NSDrawer *drawer = [[NSDrawer alloc] initWithContentSize:geo.size preferredEdge:NSMinXEdge];
[[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] becomeDelegateForDrawer:drawer widget:widget];
QWidget *parentWidget = widget->parentWidget();
if (parentWidget)
[drawer setParentWindow:qt_mac_window_for(parentWidget)];
[drawer setLeadingOffset:0.0];
[drawer setTrailingOffset:25.0];
window = [[drawer contentView] window]; // Just to make sure we actually return a window
break;
}
default:
window = [[QT_MANGLE_NAMESPACE(QCocoaWindow) alloc] QT_MANGLE_NAMESPACE(qt_initWithQWidget):widget contentRect:geo styleMask:wattr];
break;
}
qt_syncCocoaTitleBarButtons(window, widget);
return window;
}
#else
static OSWindowRef qt_mac_create_window(QWidget *, WindowClass wclass, WindowAttributes wattr,
const QRect &crect)
{
OSWindowRef window;
Rect geo;
SetRect(&geo, crect.left(), crect.top(), crect.right() + 1, crect.bottom() + 1);
OSStatus err;
if(geo.right <= geo.left) geo.right = geo.left + 1;
if(geo.bottom <= geo.top) geo.bottom = geo.top + 1;
Rect null_rect;
SetRect(&null_rect, 0, 0, 1, 1);
err = CreateNewWindow(wclass, wattr, &null_rect, &window);
if(err == noErr) {
err = SetWindowBounds(window, kWindowContentRgn, &geo);
if(err != noErr)
qWarning("QWidget: Internal error (%s:%d)", __FILE__, __LINE__);
}
return window;
}
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
/* We build the release package against the 10.4 SDK.
So, to enable gestures for applications running on
10.6+, we define the missing constants here: */
enum {
kEventClassGesture = 'gest',
kEventGestureStarted = 1,
kEventGestureEnded = 2,
kEventGestureMagnify = 4,
kEventGestureSwipe = 5,
kEventGestureRotate = 6,
kEventParamRotationAmount = 'rota',
kEventParamSwipeDirection = 'swip',
kEventParamMagnificationAmount = 'magn'
};
#endif
// window events
static EventTypeSpec window_events[] = {
{ kEventClassWindow, kEventWindowClose },
{ kEventClassWindow, kEventWindowExpanded },
{ kEventClassWindow, kEventWindowHidden },
{ kEventClassWindow, kEventWindowZoom },
{ kEventClassWindow, kEventWindowZoomed },
{ kEventClassWindow, kEventWindowCollapsed },
{ kEventClassWindow, kEventWindowToolbarSwitchMode },
{ kEventClassWindow, kEventWindowProxyBeginDrag },
{ kEventClassWindow, kEventWindowProxyEndDrag },
{ kEventClassWindow, kEventWindowResizeCompleted },
{ kEventClassWindow, kEventWindowBoundsChanging },
{ kEventClassWindow, kEventWindowGetRegion },
{ kEventClassWindow, kEventWindowGetClickModality },
{ kEventClassWindow, kEventWindowTransitionCompleted },
{ kEventClassGesture, kEventGestureStarted },
{ kEventClassGesture, kEventGestureEnded },
{ kEventClassGesture, kEventGestureMagnify },
{ kEventClassGesture, kEventGestureSwipe },
{ kEventClassGesture, kEventGestureRotate },
{ kEventClassMouse, kEventMouseDown }
};
static EventHandlerUPP mac_win_eventUPP = 0;
static void cleanup_win_eventUPP()
{
DisposeEventHandlerUPP(mac_win_eventUPP);
mac_win_eventUPP = 0;
}
static const EventHandlerUPP make_win_eventUPP()
{
if(mac_win_eventUPP)
return mac_win_eventUPP;
qAddPostRoutine(cleanup_win_eventUPP);
return mac_win_eventUPP = NewEventHandlerUPP(QWidgetPrivate::qt_window_event);
}
OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, void *)
{
QScopedLoopLevelCounter loopLevelCounter(qApp->d_func()->threadData);
bool handled_event = true;
UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event);
switch(eclass) {
case kEventClassWindow: {
WindowRef wid = 0;
GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0,
sizeof(WindowRef), 0, &wid);
QWidget *widget = qt_mac_find_window(wid);
if(!widget) {
handled_event = false;
} else if(ekind == kEventWindowGetClickModality) {
// Carbon will send us kEventWindowGetClickModality before every
// mouse press / release event. By returning 'true', we tell Carbon
// that we would like the event target to receive the mouse event even
// if the target is modally shaddowed. In Qt, this makes sense when we
// e.g. have a popup showing, as the popup will grab the event
// and perhaps use it to close itself.
// By also setting the current modal window back into the event, we
// help Carbon determining which window is supposed to be raised.
handled_event = qApp->activePopupWidget() ? true : false;
} else if(ekind == kEventWindowClose) {
widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
QMenuBar::macUpdateMenuBar();
} else if (ekind == kEventWindowTransitionCompleted) {
WindowTransitionAction transitionAction;
GetEventParameter(event, kEventParamWindowTransitionAction, typeWindowTransitionAction,
0, sizeof(transitionAction), 0, &transitionAction);
if (transitionAction == kWindowHideTransitionAction)
widget->hide();
} else if(ekind == kEventWindowExpanded) {
Qt::WindowStates currState = Qt::WindowStates(widget->data->window_state);
Qt::WindowStates newState = currState;
if (currState & Qt::WindowMinimized)
newState &= ~Qt::WindowMinimized;
if (!(currState & Qt::WindowActive))
newState |= Qt::WindowActive;
if (newState != currState) {
// newState will differ from currState if the window
// was expanded after clicking on the jewels (as opposed
// to calling QWidget::setWindowState)
widget->data->window_state = newState;
QWindowStateChangeEvent e(currState);
QApplication::sendSpontaneousEvent(widget, &e);
}
QShowEvent qse;
QApplication::sendSpontaneousEvent(widget, &qse);
} else if(ekind == kEventWindowZoom) {
widget->d_func()->topData()->normalGeometry = widget->geometry();
handled_event = false;
} else if(ekind == kEventWindowZoomed) {
WindowPartCode windowPart;
GetEventParameter(event, kEventParamWindowPartCode,
typeWindowPartCode, 0, sizeof(windowPart), 0, &windowPart);
if(windowPart == inZoomIn && widget->isMaximized()) {
widget->data->window_state = widget->data->window_state & ~Qt::WindowMaximized;
QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state | Qt::WindowMaximized));
QApplication::sendSpontaneousEvent(widget, &e);
} else if(windowPart == inZoomOut && !widget->isMaximized()) {
widget->data->window_state = widget->data->window_state | Qt::WindowMaximized;
QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state
& ~Qt::WindowMaximized));
QApplication::sendSpontaneousEvent(widget, &e);
}
qt_button_down = 0;
} else if(ekind == kEventWindowCollapsed) {
if (!widget->isMinimized()) {
widget->data->window_state = widget->data->window_state | Qt::WindowMinimized;
QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state & ~Qt::WindowMinimized));
QApplication::sendSpontaneousEvent(widget, &e);
}
// Deactivate this window:
if (widget->isActiveWindow() && !(widget->windowType() == Qt::Popup)) {
QWidget *w = 0;
if (widget->parentWidget())
w = widget->parentWidget()->window();
if (!w || (!w->isVisible() && !w->isMinimized())) {
for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true);
wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) {
if ((w = qt_mac_find_window(wp)))
break;
}
}
if(!(w && w->isVisible() && !w->isMinimized()))
qApp->setActiveWindow(0);
}
//we send a hide to be like X11/Windows
QEvent e(QEvent::Hide);
QApplication::sendSpontaneousEvent(widget, &e);
qt_button_down = 0;
} else if(ekind == kEventWindowToolbarSwitchMode) {
macSendToolbarChangeEvent(widget);
HIToolbarRef toolbar;
if (GetWindowToolbar(wid, &toolbar) == noErr) {
if (toolbar) {
// Let HIToolbar do its thang, but things like the OpenGL context
// needs to know about it.
CallNextEventHandler(er, event);
qt_event_request_window_change(widget);
widget->data->fstrut_dirty = true;
}
}
} else if(ekind == kEventWindowGetRegion) {
WindowRef window;
GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0,
sizeof(window), 0, &window);
WindowRegionCode wcode;
GetEventParameter(event, kEventParamWindowRegionCode, typeWindowRegionCode, 0,
sizeof(wcode), 0, &wcode);
if (wcode != kWindowOpaqueRgn){
// If the region is kWindowOpaqueRgn, don't call next
// event handler cause this will make the shadow of
// masked windows become offset. Unfortunately, we're not sure why.
CallNextEventHandler(er, event);
}
RgnHandle rgn;
GetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, 0,
sizeof(rgn), 0, &rgn);
if(QWidgetPrivate::qt_widget_rgn(qt_mac_find_window(window), wcode, rgn, false))
SetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, sizeof(rgn), &rgn);
} else if(ekind == kEventWindowProxyBeginDrag) {
QIconDragEvent e;
QApplication::sendSpontaneousEvent(widget, &e);
} else if(ekind == kEventWindowResizeCompleted) {
// Create a mouse up event, since such an event is not send by carbon to the
// application event handler (while a mouse down <b>is</b> on kEventWindowResizeStarted)
EventRef mouseUpEvent;
CreateEvent(0, kEventClassMouse, kEventMouseUp, 0, kEventAttributeUserEvent, &mouseUpEvent);
UInt16 mbutton = kEventMouseButtonPrimary;
SetEventParameter(mouseUpEvent, kEventParamMouseButton, typeMouseButton, sizeof(mbutton), &mbutton);
WindowRef window;
GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0, sizeof(window), 0, &window);
Rect dragRect;
GetWindowBounds(window, kWindowGrowRgn, &dragRect);
Point pos = {dragRect.bottom, dragRect.right};
SetEventParameter(mouseUpEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pos), &pos);
SendEventToApplication(mouseUpEvent);
ReleaseEvent(mouseUpEvent);
} else if(ekind == kEventWindowBoundsChanging) {
UInt32 flags = 0;
GetEventParameter(event, kEventParamAttributes, typeUInt32, 0,
sizeof(flags), 0, &flags);
Rect nr;
GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, 0,
sizeof(nr), 0, &nr);
QRect newRect(nr.left, nr.top, nr.right - nr.left, nr.bottom - nr.top);
QTLWExtra * const tlwExtra = widget->d_func()->maybeTopData();
if (tlwExtra && tlwExtra->isSetGeometry == 1) {
widget->d_func()->setGeometry_sys_helper(newRect.left(), newRect.top(), newRect.width(), newRect.height(), tlwExtra->isMove);
} else {
//implicitly removes the maximized bit
if((widget->data->window_state & Qt::WindowMaximized) &&
IsWindowInStandardState(wid, 0, 0)) {
widget->data->window_state &= ~Qt::WindowMaximized;
QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state
| Qt::WindowMaximized));
QApplication::sendSpontaneousEvent(widget, &e);
}
handled_event = false;
const QRect oldRect = widget->data->crect;
if((flags & kWindowBoundsChangeOriginChanged)) {
if(nr.left != oldRect.x() || nr.top != oldRect.y()) {
widget->data->crect.moveTo(nr.left, nr.top);
QMoveEvent qme(widget->data->crect.topLeft(), oldRect.topLeft());
QApplication::sendSpontaneousEvent(widget, &qme);
}
}
if((flags & kWindowBoundsChangeSizeChanged)) {
if (widget->isWindow()) {
QSize newSize = QLayout::closestAcceptableSize(widget, newRect.size());
int dh = newSize.height() - newRect.height();
int dw = newSize.width() - newRect.width();
if (dw != 0 || dh != 0) {
handled_event = true; // We want to change the bounds, so we handle the event
// set the rect, so we can also do the resize down below (yes, we need to resize).
newRect.setBottom(newRect.bottom() + dh);
newRect.setRight(newRect.right() + dw);
nr.left = newRect.x();
nr.top = newRect.y();
nr.right = nr.left + newRect.width();
nr.bottom = nr.top + newRect.height();
SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), &nr);
}
}
if (oldRect.width() != newRect.width() || oldRect.height() != newRect.height()) {
widget->data->crect.setSize(newRect.size());
HIRect bounds = CGRectMake(0, 0, newRect.width(), newRect.height());
// If the WA_StaticContents attribute is set we can optimize the resize
// by only repainting the newly exposed area. We do this by disabling
// painting when setting the size of the view. The OS will invalidate
// the newly exposed area for us.
const bool staticContents = widget->testAttribute(Qt::WA_StaticContents);
const HIViewRef view = qt_mac_nativeview_for(widget);
if (staticContents)
HIViewSetDrawingEnabled(view, false);
HIViewSetFrame(view, &bounds);
if (staticContents)
HIViewSetDrawingEnabled(view, true);
QResizeEvent qre(newRect.size(), oldRect.size());
QApplication::sendSpontaneousEvent(widget, &qre);
qt_event_request_window_change(widget);
}
}
}
} else if (ekind == kEventWindowHidden) {
// Make sure that we also hide any visible sheets on our window.
// Cocoa does the right thing for us.
const QObjectList children = widget->children();
const int childCount = children.count();
for (int i = 0; i < childCount; ++i) {
QObject *obj = children.at(i);
if (obj->isWidgetType()) {
QWidget *widget = static_cast<QWidget *>(obj);
if (qt_mac_is_macsheet(widget) && widget->isVisible())
widget->hide();
}
}
} else {
handled_event = false;
}
break; }
case kEventClassMouse: {
#if 0
return SendEventToApplication(event);
#endif
bool send_to_app = false;
{
WindowPartCode wpc;
if (GetEventParameter(event, kEventParamWindowPartCode, typeWindowPartCode, 0,
sizeof(wpc), 0, &wpc) == noErr && wpc != inContent)
send_to_app = true;
}
if(!send_to_app) {
WindowRef window;
if(GetEventParameter(event, kEventParamWindowRef, typeWindowRef, 0,
sizeof(window), 0, &window) == noErr) {
HIViewRef hiview;
if(HIViewGetViewForMouseEvent(HIViewGetRoot(window), event, &hiview) == noErr) {
if(QWidget *w = QWidget::find((WId)hiview)) {
#if 0
send_to_app = !w->isActiveWindow();
#else
Q_UNUSED(w);
send_to_app = true;
#endif
}
}
}
}
if(send_to_app)
return SendEventToApplication(event);
handled_event = false;
break; }
case kEventClassGesture: {
// First, find the widget that was under
// the mouse when the gesture happened:
HIPoint screenLocation;
if (GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, 0,
sizeof(screenLocation), 0, &screenLocation) != noErr) {
handled_event = false;
break;
}
QWidget *widget = QApplication::widgetAt(screenLocation.x, screenLocation.y);
if (!widget) {
handled_event = false;
break;
}
QNativeGestureEvent qNGEvent;
qNGEvent.position = QPoint(screenLocation.x, screenLocation.y);
switch (ekind) {
case kEventGestureStarted:
qNGEvent.gestureType = QNativeGestureEvent::GestureBegin;
break;
case kEventGestureEnded:
qNGEvent.gestureType = QNativeGestureEvent::GestureEnd;
break;
case kEventGestureRotate: {
CGFloat amount;
if (GetEventParameter(event, kEventParamRotationAmount, 'cgfl', 0,
sizeof(amount), 0, &amount) != noErr) {
handled_event = false;
break;
}
qNGEvent.gestureType = QNativeGestureEvent::Rotate;
qNGEvent.percentage = float(-amount);
break; }
case kEventGestureSwipe: {
HIPoint swipeDirection;
if (GetEventParameter(event, kEventParamSwipeDirection, typeHIPoint, 0,
sizeof(swipeDirection), 0, &swipeDirection) != noErr) {
handled_event = false;
break;
}
qNGEvent.gestureType = QNativeGestureEvent::Swipe;
if (swipeDirection.x == 1)
qNGEvent.angle = 180.0f;
else if (swipeDirection.x == -1)
qNGEvent.angle = 0.0f;
else if (swipeDirection.y == 1)
qNGEvent.angle = 90.0f;
else if (swipeDirection.y == -1)
qNGEvent.angle = 270.0f;
break; }
case kEventGestureMagnify: {
CGFloat amount;
if (GetEventParameter(event, kEventParamMagnificationAmount, 'cgfl', 0,
sizeof(amount), 0, &amount) != noErr) {
handled_event = false;
break;
}
qNGEvent.gestureType = QNativeGestureEvent::Zoom;
qNGEvent.percentage = float(amount);
break; }
}
QApplication::sendSpontaneousEvent(widget, &qNGEvent);
break; }
default:
handled_event = false;
}
if(!handled_event) //let the event go through
return eventNotHandledErr;
return noErr; //we eat the event
}
// widget events
static HIObjectClassRef widget_class = 0;
static EventTypeSpec widget_events[] = {
{ kEventClassHIObject, kEventHIObjectConstruct },
{ kEventClassHIObject, kEventHIObjectDestruct },
{ kEventClassControl, kEventControlDraw },
{ kEventClassControl, kEventControlInitialize },
{ kEventClassControl, kEventControlGetPartRegion },
{ kEventClassControl, kEventControlGetClickActivation },
{ kEventClassControl, kEventControlSetFocusPart },
{ kEventClassControl, kEventControlDragEnter },
{ kEventClassControl, kEventControlDragWithin },
{ kEventClassControl, kEventControlDragLeave },
{ kEventClassControl, kEventControlDragReceive },
{ kEventClassControl, kEventControlOwningWindowChanged },
{ kEventClassControl, kEventControlBoundsChanged },
{ kEventClassControl, kEventControlGetSizeConstraints },
{ kEventClassControl, kEventControlVisibilityChanged },
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseDragged }
};
static EventHandlerUPP mac_widget_eventUPP = 0;
static void cleanup_widget_eventUPP()
{
DisposeEventHandlerUPP(mac_widget_eventUPP);
mac_widget_eventUPP = 0;
}
static const EventHandlerUPP make_widget_eventUPP()
{
if(mac_widget_eventUPP)
return mac_widget_eventUPP;
qAddPostRoutine(cleanup_widget_eventUPP);
return mac_widget_eventUPP = NewEventHandlerUPP(QWidgetPrivate::qt_widget_event);
}
OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, void *)
{
QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData);
bool handled_event = true;
UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event);
switch(eclass) {
case kEventClassHIObject: {
HIViewRef view = 0;
GetEventParameter(event, kEventParamHIObjectInstance, typeHIObjectRef,
0, sizeof(view), 0, &view);
if(ekind == kEventHIObjectConstruct) {
if(view) {
HIViewChangeFeatures(view, kHIViewAllowsSubviews, 0);
SetEventParameter(event, kEventParamHIObjectInstance,
typeVoidPtr, sizeof(view), &view);
}
} else if(ekind == kEventHIObjectDestruct) {
//nothing to really do.. or is there?
} else {
handled_event = false;
}
break; }
case kEventClassControl: {
QWidget *widget = 0;
HIViewRef hiview = 0;
if(GetEventParameter(event, kEventParamDirectObject, typeControlRef,
0, sizeof(hiview), 0, &hiview) == noErr)
widget = QWidget::find((WId)hiview);
if (widget && widget->macEvent(er, event))
return noErr;
if(ekind == kEventControlDraw) {
if(widget && qt_isGenuineQWidget(hiview)) {
// if there is a window change event pending for any gl child wigets,
// send it immediately. (required for flicker-free resizing)
extern void qt_mac_send_posted_gl_updates(QWidget *widget);
qt_mac_send_posted_gl_updates(widget);
if (QApplicationPrivate::graphicsSystem() && !widget->d_func()->paintOnScreen()) {
widget->d_func()->syncBackingStore();
widget->d_func()->dirtyOnWidget = QRegion();
return noErr;
}
//requested rgn
RgnHandle rgn;
GetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, 0, sizeof(rgn), 0, &rgn);
QRegion qrgn(qt_mac_convert_mac_region(rgn));
//update handles
GrafPtr qd = 0;
CGContextRef cg = 0;
if(GetEventParameter(event, kEventParamCGContextRef, typeCGContextRef, 0, sizeof(cg), 0, &cg) != noErr) {
Q_ASSERT(false);
}
widget->d_func()->hd = cg;
widget->d_func()->qd_hd = qd;
CGContextSaveGState(cg);
#ifdef DEBUG_WIDGET_PAINT
const bool doDebug = true;
if(doDebug) {
qDebug("asked to draw %p[%p] [%s::%s] %p[%p] [%d] [%dx%d]", widget, hiview, widget->metaObject()->className(),
widget->objectName().local8Bit().data(), widget->parentWidget(),
(HIViewRef)(widget->parentWidget() ? qt_mac_nativeview_for(widget->parentWidget()) : (HIViewRef)0),
HIViewIsCompositingEnabled(hiview), qt_mac_posInWindow(widget).x(), qt_mac_posInWindow(widget).y());
#if 0
QVector<QRect> region_rects = qrgn.rects();
qDebug("Region! %d", region_rects.count());
for(int i = 0; i < region_rects.count(); i++)
qDebug("%d %d %d %d", region_rects[i].x(), region_rects[i].y(),
region_rects[i].width(), region_rects[i].height());
region_rects = widget->d_func()->clp.rects();
qDebug("Widget Region! %d", region_rects.count());
for(int i = 0; i < region_rects.count(); i++)
qDebug("%d %d %d %d", region_rects[i].x(), region_rects[i].y(),
region_rects[i].width(), region_rects[i].height());
#endif
}
#endif
if (widget->isVisible() && widget->updatesEnabled()) { //process the actual paint event.
if(widget->testAttribute(Qt::WA_WState_InPaintEvent))
qWarning("QWidget::repaint: Recursive repaint detected");
if (widget->isWindow() && !widget->d_func()->isOpaque
&& !widget->testAttribute(Qt::WA_MacBrushedMetal)) {
QRect qrgnRect = qrgn.boundingRect();
CGContextClearRect(cg, CGRectMake(qrgnRect.x(), qrgnRect.y(), qrgnRect.width(), qrgnRect.height()));
}
QPoint redirectionOffset(0, 0);
QWidget *tl = widget->window();
if (tl) {
Qt::WindowFlags flags = tl->windowFlags();
if (flags & Qt::FramelessWindowHint
|| (flags & Qt::CustomizeWindowHint && !(flags & Qt::WindowTitleHint))) {
if(tl->d_func()->extra && !tl->d_func()->extra->mask.isEmpty())
redirectionOffset += tl->d_func()->extra->mask.boundingRect().topLeft();
}
}
//setup the context
widget->setAttribute(Qt::WA_WState_InPaintEvent);
QPaintEngine *engine = widget->paintEngine();
if (engine)
engine->setSystemClip(qrgn);
//handle the erase
if (engine && (!widget->testAttribute(Qt::WA_NoSystemBackground)
&& (widget->isWindow() || widget->autoFillBackground())
|| widget->testAttribute(Qt::WA_TintedBackground)
|| widget->testAttribute(Qt::WA_StyledBackground))) {
#ifdef DEBUG_WIDGET_PAINT
if(doDebug)
qDebug(" Handling erase for [%s::%s]", widget->metaObject()->className(),
widget->objectName().local8Bit().data());
#endif
if (!redirectionOffset.isNull())
widget->d_func()->setRedirected(widget, redirectionOffset);
bool was_unclipped = widget->testAttribute(Qt::WA_PaintUnclipped);
widget->setAttribute(Qt::WA_PaintUnclipped, false);
QPainter p(widget);
p.setClipping(false);
if(was_unclipped)
widget->setAttribute(Qt::WA_PaintUnclipped);
widget->d_func()->paintBackground(&p, qrgn, widget->isWindow() ? DrawAsRoot : 0);
if (widget->testAttribute(Qt::WA_TintedBackground)) {
QColor tint = widget->palette().window().color();
tint.setAlphaF(.6);
const QVector<QRect> &rects = qrgn.rects();
for (int i = 0; i < rects.size(); ++i)
p.fillRect(rects.at(i), tint);
}
p.end();
if (!redirectionOffset.isNull())
widget->d_func()->restoreRedirected();
}
if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget))
CallNextEventHandler(er, event);
//send the paint
redirectionOffset += widget->data->wrect.topLeft(); // Map from system to qt coordinates
if (!redirectionOffset.isNull())
widget->d_func()->setRedirected(widget, redirectionOffset);
qrgn.translate(redirectionOffset);
QPaintEvent e(qrgn);
widget->d_func()->dirtyOnWidget = QRegion();
#ifdef QT3_SUPPORT
e.setErased(true);
#endif
QApplication::sendSpontaneousEvent(widget, &e);
if (!redirectionOffset.isNull())
widget->d_func()->restoreRedirected();
//cleanup
if (engine)
engine->setSystemClip(QRegion());
widget->setAttribute(Qt::WA_WState_InPaintEvent, false);
if(!widget->testAttribute(Qt::WA_PaintOutsidePaintEvent) && widget->paintingActive())
qWarning("QWidget: It is dangerous to leave painters active on a widget outside of the PaintEvent");
}
widget->d_func()->hd = 0;
widget->d_func()->qd_hd = 0;
CGContextRestoreGState(cg);
} else if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) {
CallNextEventHandler(er, event);
}
} else if(ekind == kEventControlInitialize) {
if(HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) {
UInt32 features = kControlSupportsDragAndDrop | kControlSupportsClickActivation | kControlSupportsFocus;
SetEventParameter(event, kEventParamControlFeatures, typeUInt32, sizeof(features), &features);
} else {
handled_event = false;
}
} else if(ekind == kEventControlSetFocusPart) {
if(widget) {
ControlPartCode part;
GetEventParameter(event, kEventParamControlPart, typeControlPartCode, 0,
sizeof(part), 0, &part);
if(part == kControlFocusNoPart){
if (widget->hasFocus())
QApplicationPrivate::setFocusWidget(0, Qt::OtherFocusReason);
} else
widget->setFocus();
}
if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget))
CallNextEventHandler(er, event);
} else if(ekind == kEventControlGetClickActivation) {
ClickActivationResult clickT = kActivateAndIgnoreClick;
SetEventParameter(event, kEventParamClickActivation, typeClickActivationResult,
sizeof(clickT), &clickT);
} else if(ekind == kEventControlGetPartRegion) {
handled_event = false;
if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget) && CallNextEventHandler(er, event) == noErr) {
handled_event = true;
break;
}
if(widget && !widget->isWindow()) {
ControlPartCode part;
GetEventParameter(event, kEventParamControlPart, typeControlPartCode, 0,
sizeof(part), 0, &part);
if(part == kControlClickableMetaPart && widget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
RgnHandle rgn;
GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0,
sizeof(rgn), 0, &rgn);
SetEmptyRgn(rgn);
handled_event = true;
} else if(part == kControlStructureMetaPart || part == kControlClickableMetaPart) {
RgnHandle rgn;
GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0,
sizeof(rgn), 0, &rgn);
SetRectRgn(rgn, 0, 0, widget->width(), widget->height());
if(QWidgetPrivate::qt_widget_rgn(widget, kWindowStructureRgn, rgn, false))
handled_event = true;
} else if(part == kControlOpaqueMetaPart) {
if(widget->d_func()->isOpaque) {
RgnHandle rgn;
GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0,
sizeof(RgnHandle), 0, &rgn);
SetRectRgn(rgn, 0, 0, widget->width(), widget->height());
QWidgetPrivate::qt_widget_rgn(widget, kWindowStructureRgn, rgn, false);
SetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle,
sizeof(RgnHandle), &rgn);
handled_event = true;
}
}
}
} else if(ekind == kEventControlOwningWindowChanged) {
if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget))
CallNextEventHandler(er, event);
if(widget && qt_mac_window_for(hiview)) {
WindowRef foo = 0;
GetEventParameter(event, kEventParamControlCurrentOwningWindow, typeWindowRef, 0,
sizeof(foo), 0, &foo);
widget->d_func()->initWindowPtr();
}
if (widget)
qt_event_request_window_change(widget);
} else if(ekind == kEventControlDragEnter || ekind == kEventControlDragWithin ||
ekind == kEventControlDragLeave || ekind == kEventControlDragReceive) {
// dnd are really handled in qdnd_mac.cpp,
// just modularize the code a little...
DragRef drag;
GetEventParameter(event, kEventParamDragRef, typeDragRef, 0, sizeof(drag), 0, &drag);
handled_event = false;
bool drag_allowed = false;
QWidget *dropWidget = widget;
if (qobject_cast<QFocusFrame *>(widget)){
// We might shadow widgets underneath the focus
// frame, so stay interrested, and let the dnd through
drag_allowed = true;
handled_event = true;
Point where;
GetDragMouse(drag, &where, 0);
dropWidget = QApplication::widgetAt(QPoint(where.h, where.v));
if (dropWidget != QDragManager::self()->currentTarget()) {
// We have to 'fake' enter and leave events for the shaddowed widgets:
if (ekind == kEventControlDragEnter) {
if (QDragManager::self()->currentTarget())
QDragManager::self()->currentTarget()->d_func()->qt_mac_dnd_event(kEventControlDragLeave, drag);
if (dropWidget) {
dropWidget->d_func()->qt_mac_dnd_event(kEventControlDragEnter, drag);
}
// Set dropWidget to zero, so qt_mac_dnd_event
// doesn't get called a second time below:
dropWidget = 0;
} else if (ekind == kEventControlDragLeave) {
dropWidget = QDragManager::self()->currentTarget();
if (dropWidget) {
dropWidget->d_func()->qt_mac_dnd_event(kEventControlDragLeave, drag);
}
// Set dropWidget to zero, so qt_mac_dnd_event
// doesn't get called a second time below:
dropWidget = 0;
}
}
}
// Send the dnd event to the widget:
if (dropWidget && dropWidget->d_func()->qt_mac_dnd_event(ekind, drag)) {
drag_allowed = true;
handled_event = true;
}
if (ekind == kEventControlDragEnter) {
// If we don't accept the enter event, we will
// receive no more drag events for this widget
const Boolean wouldAccept = drag_allowed ? true : false;
SetEventParameter(event, kEventParamControlWouldAcceptDrop, typeBoolean,
sizeof(wouldAccept), &wouldAccept);
}
} else if (ekind == kEventControlBoundsChanged) {
if (!widget || widget->isWindow() || widget->testAttribute(Qt::WA_Moved) || widget->testAttribute(Qt::WA_Resized)) {
handled_event = false;
} else {
// Sync our view in case some other (non-Qt) view is controlling us.
handled_event = true;
Rect newBounds;
GetEventParameter(event, kEventParamCurrentBounds,
typeQDRectangle, 0, sizeof(Rect), 0, &newBounds);
QRect rect(newBounds.left, newBounds.top,
newBounds.right - newBounds.left, newBounds.bottom - newBounds.top);
bool moved = widget->testAttribute(Qt::WA_Moved);
bool resized = widget->testAttribute(Qt::WA_Resized);
widget->setGeometry(rect);
widget->setAttribute(Qt::WA_Moved, moved);
widget->setAttribute(Qt::WA_Resized, resized);
qt_event_request_window_change(widget);
}
} else if (ekind == kEventControlGetSizeConstraints) {
if (!widget || !qt_isGenuineQWidget(widget)) {
handled_event = false;
} else {
handled_event = true;
QWidgetItem item(widget);
QSize size = item.minimumSize();
HISize hisize = { size.width(), size.height() };
SetEventParameter(event, kEventParamMinimumSize, typeHISize, sizeof(HISize), &hisize);
size = item.maximumSize();
hisize.width = size.width() + 2; // ### shouldn't have to add 2 (but it works).
hisize.height = size.height();
SetEventParameter(event, kEventParamMaximumSize, typeHISize, sizeof(HISize), &hisize);
}
} else if (ekind == kEventControlVisibilityChanged) {
handled_event = false;
if (widget) {
qt_event_request_window_change(widget);
if (!HIViewIsVisible(HIViewRef(widget->winId()))) {
if (widget == qt_button_down)
qt_button_down = 0;
}
}
}
break; }
case kEventClassMouse: {
bool send_to_app = false;
if(qt_button_down)
send_to_app = true;
if(send_to_app) {
OSStatus err = SendEventToApplication(event);
if(err != noErr)
handled_event = false;
} else {
CallNextEventHandler(er, event);
}
break; }
default:
handled_event = false;
break;
}
if(!handled_event) //let the event go through
return eventNotHandledErr;
return noErr; //we eat the event
}
#endif
OSViewRef qt_mac_create_widget(QWidget *widget, QWidgetPrivate *widgetPrivate, OSViewRef parent)
{
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
QT_MANGLE_NAMESPACE(QCocoaView) *view = [[QT_MANGLE_NAMESPACE(QCocoaView) alloc] initWithQWidget:widget widgetPrivate:widgetPrivate];
if (view && parent)
[parent addSubview:view];
return view;
#else
Q_UNUSED(widget);
Q_UNUSED(widgetPrivate);
if(!widget_class) {
OSStatus err = HIObjectRegisterSubclass(kObjectQWidget, kHIViewClassID, 0, make_widget_eventUPP(),
GetEventTypeCount(widget_events), widget_events,
0, &widget_class);
if (err && err != hiObjectClassExistsErr)
qWarning("QWidget: Internal error (%d)", __LINE__);
}
HIViewRef ret = 0;
if(HIObjectCreate(kObjectQWidget, 0, (HIObjectRef*)&ret) != noErr)
qWarning("QWidget: Internal error (%d)", __LINE__);
if(ret && parent)
HIViewAddSubview(parent, ret);
return ret;
#endif
}
void qt_mac_unregister_widget()
{
#ifndef QT_MAC_USE_COCOA
HIObjectUnregisterClass(widget_class);
widget_class = 0;
#endif
}
void QWidgetPrivate::toggleDrawers(bool visible)
{
for (int i = 0; i < children.size(); ++i) {
register QObject *object = children.at(i);
if (!object->isWidgetType())
continue;
QWidget *widget = static_cast<QWidget*>(object);
if(qt_mac_is_macdrawer(widget)) {
if(visible) {
if (!widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
widget->show();
} else {
widget->hide();
widget->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
}
}
}
}
/*****************************************************************************
QWidgetPrivate member functions
*****************************************************************************/
bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
{
// I'm not sure what "up" is
if(!w || !w->isWindow())
return false;
QTLWExtra *topData = w->d_func()->topData();
QWExtra *extraData = w->d_func()->extraData();
// topData->resizer is only 4 bits, so subtracting -1 from zero causes bad stuff
// to happen, prevent that here (you really want the thing hidden).
if (up >= 0 || topData->resizer != 0)
topData->resizer += up;
OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->winId()));
{
#ifndef QT_MAC_USE_COCOA
WindowClass wclass;
GetWindowClass(windowRef, &wclass);
if(!(GetAvailableWindowAttributes(wclass) & kWindowResizableAttribute))
return true;
#endif
}
bool remove_grip = (topData->resizer || (w->windowFlags() & Qt::FramelessWindowHint)
|| (extraData->maxw && extraData->maxh &&
extraData->maxw == extraData->minw && extraData->maxh == extraData->minh));
#ifndef QT_MAC_USE_COCOA
WindowAttributes attr;
GetWindowAttributes(windowRef, &attr);
if(remove_grip) {
if(attr & kWindowResizableAttribute) {
ChangeWindowAttributes(qt_mac_window_for(w), kWindowNoAttributes,
kWindowResizableAttribute);
ReshapeCustomWindow(qt_mac_window_for(w));
}
} else if(!(attr & kWindowResizableAttribute)) {
ChangeWindowAttributes(windowRef, kWindowResizableAttribute,
kWindowNoAttributes);
ReshapeCustomWindow(windowRef);
}
#else
[windowRef setShowsResizeIndicator:!remove_grip];
#endif
return true;
}
void QWidgetPrivate::qt_clean_root_win()
{
#ifdef QT_MAC_USE_COCOA
[qt_root_win release];
#else
if(!qt_root_win)
return;
CFRelease(qt_root_win);
#endif
qt_root_win = 0;
}
bool QWidgetPrivate::qt_create_root_win()
{
if(qt_root_win)
return false;
const QSize desktopSize = qt_mac_desktopSize();
QRect desktopRect(QPoint(0, 0), desktopSize);
#ifdef QT_MAC_USE_COCOA
qt_root_win = qt_mac_create_window(0, kOverlayWindowClass, NSBorderlessWindowMask, desktopRect);
#else
WindowAttributes wattr = (kWindowCompositingAttribute | kWindowStandardHandlerAttribute);
qt_root_win = qt_mac_create_window(0, kOverlayWindowClass, wattr, desktopRect);
#endif
if(!qt_root_win)
return false;
qAddPostRoutine(qt_clean_root_win);
return true;
}
bool QWidgetPrivate::qt_widget_rgn(QWidget *widget, short wcode, RgnHandle rgn, bool force = false)
{
bool ret = false;
#ifndef QT_MAC_USE_COCOA
switch(wcode) {
case kWindowStructureRgn: {
if(widget) {
if(widget->d_func()->extra && !widget->d_func()->extra->mask.isEmpty()) {
QRegion rin = qt_mac_convert_mac_region(rgn);
if(!rin.isEmpty()) {
QPoint rin_tl = rin.boundingRect().topLeft(); //in offset
rin.translate(-rin_tl.x(), -rin_tl.y()); //bring into same space as below
QRegion mask = widget->d_func()->extra->mask;
Qt::WindowFlags flags = widget->windowFlags();
if(widget->isWindow()
&& !(flags & Qt::FramelessWindowHint
|| (flags & Qt::CustomizeWindowHint && !(flags & Qt::WindowTitleHint)))) {
QRegion title;
{
QMacSmartQuickDrawRegion rgn(qt_mac_get_rgn());
GetWindowRegion(qt_mac_window_for(widget), kWindowTitleBarRgn, rgn);
title = qt_mac_convert_mac_region(rgn);
}
QRect br = title.boundingRect();
mask.translate(0, br.height()); //put the mask 'under' the title bar..
title.translate(-br.x(), -br.y());
mask += title;
}
QRegion cr = rin & mask;
cr.translate(rin_tl.x(), rin_tl.y()); //translate back to incoming space
CopyRgn(QMacSmartQuickDrawRegion(cr.toQDRgn()), rgn);
}
ret = true;
} else if(force) {
QRegion cr(widget->geometry());
CopyRgn(QMacSmartQuickDrawRegion(cr.toQDRgn()), rgn);
ret = true;
}
}
break; }
default: break;
}
//qDebug() << widget << ret << wcode << qt_mac_convert_mac_region(rgn);
#else
Q_UNUSED(widget);
Q_UNUSED(wcode);
Q_UNUSED(rgn);
Q_UNUSED(force);
#endif
return ret;
}
/*****************************************************************************
QWidget member functions
*****************************************************************************/
void QWidgetPrivate::determineWindowClass()
{
Q_Q(QWidget);
#if !defined(QT_NO_MAINWINDOW) && !defined(QT_NO_TOOLBAR)
// Make sure that QMainWindow has the MacWindowToolBarButtonHint when the
// unifiedTitleAndToolBarOnMac property is ON. This is to avoid reentry of
// setParent() triggered by the QToolBar::event(QEvent::ParentChange).
QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q);
if (mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()) {
data.window_flags |= Qt::MacWindowToolBarButtonHint;
}
#endif
#ifndef QT_MAC_USE_COCOA
// ### COCOA:Interleave these better!
const Qt::WindowType type = q->windowType();
Qt::WindowFlags &flags = data.window_flags;
const bool popup = (type == Qt::Popup);
if (type == Qt::ToolTip || type == Qt::SplashScreen || popup)
flags |= Qt::FramelessWindowHint;
WindowClass wclass = kSheetWindowClass;
if(qt_mac_is_macdrawer(q))
wclass = kDrawerWindowClass;
else if (q->testAttribute(Qt::WA_ShowModal) && flags & Qt::CustomizeWindowHint)
wclass = kDocumentWindowClass;
else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen))
wclass = kModalWindowClass;
else if(q->testAttribute(Qt::WA_ShowModal))
wclass = kMovableModalWindowClass;
else if(type == Qt::ToolTip)
wclass = kHelpWindowClass;
else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5
&& type == Qt::SplashScreen))
wclass = kFloatingWindowClass;
else
wclass = kDocumentWindowClass;
WindowGroupRef grp = 0;
WindowAttributes wattr = (kWindowCompositingAttribute | kWindowStandardHandlerAttribute);
if (q->testAttribute(Qt::WA_MacFrameworkScaled))
wattr |= kWindowFrameworkScaledAttribute;
if(qt_mac_is_macsheet(q)) {
//grp = GetWindowGroupOfClass(kMovableModalWindowClass);
wclass = kSheetWindowClass;
} else {
grp = GetWindowGroupOfClass(wclass);
// Shift things around a bit to get the correct window class based on the presence
// (or lack) of the border.
bool customize = flags & Qt::CustomizeWindowHint;
bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint)));
if (framelessWindow) {
if(wclass == kDocumentWindowClass) {
wattr |= kWindowNoTitleBarAttribute;
} else if(wclass == kFloatingWindowClass) {
wattr |= kWindowNoTitleBarAttribute;
} else if (wclass == kMovableModalWindowClass) {
wclass = kModalWindowClass;
}
} else {
if(wclass != kModalWindowClass)
wattr |= kWindowResizableAttribute;
}
// Only add extra decorations (well, buttons) for widgets that can have them
// and have an actual border we can put them on.
if(wclass != kModalWindowClass && wclass != kMovableModalWindowClass
&& wclass != kSheetWindowClass && wclass != kPlainWindowClass
&& !framelessWindow && wclass != kDrawerWindowClass
&& wclass != kHelpWindowClass) {
if (flags & Qt::WindowMaximizeButtonHint)
wattr |= kWindowFullZoomAttribute;
if (flags & Qt::WindowMinimizeButtonHint)
wattr |= kWindowCollapseBoxAttribute;
if (flags & Qt::WindowSystemMenuHint || flags & Qt::WindowCloseButtonHint)
wattr |= kWindowCloseBoxAttribute;
if (flags & Qt::MacWindowToolBarButtonHint)
wattr |= kWindowToolbarButtonAttribute;
} else {
// Clear these hints so that we aren't call them on invalid windows
flags &= ~(Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint
| Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint);
}
}
if((popup || type == Qt::Tool) && !q->isModal())
wattr |= kWindowHideOnSuspendAttribute;
wattr |= kWindowLiveResizeAttribute;
#ifdef DEBUG_WINDOW_CREATE
#define ADD_DEBUG_WINDOW_NAME(x) { x, #x }
struct {
UInt32 tag;
const char *name;
} known_attribs[] = {
ADD_DEBUG_WINDOW_NAME(kWindowCompositingAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowMetalAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowCollapseBoxAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowHorizontalZoomAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowVerticalZoomAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowResizableAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowNoActivatesAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowNoUpdatesAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowOpaqueForEventsAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowLiveResizeAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowCloseBoxAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
{ 0, 0 }
}, known_classes[] = {
ADD_DEBUG_WINDOW_NAME(kHelpWindowClass),
ADD_DEBUG_WINDOW_NAME(kPlainWindowClass),
ADD_DEBUG_WINDOW_NAME(kDrawerWindowClass),
ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
ADD_DEBUG_WINDOW_NAME(kSheetWindowClass),
ADD_DEBUG_WINDOW_NAME(kFloatingWindowClass),
ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
ADD_DEBUG_WINDOW_NAME(kDocumentWindowClass),
ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
ADD_DEBUG_WINDOW_NAME(kMovableModalWindowClass),
ADD_DEBUG_WINDOW_NAME(kModalWindowClass),
{ 0, 0 }
};
qDebug("Qt: internal: ************* Creating new window %p (%s::%s)", q, q->metaObject()->className(),
q->objectName().toLocal8Bit().constData());
bool found_class = false;
for(int i = 0; known_classes[i].name; i++) {
if(wclass == known_classes[i].tag) {
found_class = true;
qDebug("Qt: internal: ** Class: %s", known_classes[i].name);
break;
}
}
if(!found_class)
qDebug("Qt: internal: !! Class: Unknown! (%d)", (int)wclass);
if(wattr) {
WindowAttributes tmp_wattr = wattr;
qDebug("Qt: internal: ** Attributes:");
for(int i = 0; tmp_wattr && known_attribs[i].name; i++) {
if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) {
tmp_wattr ^= known_attribs[i].tag;
qDebug("Qt: internal: * %s %s", known_attribs[i].name,
(GetAvailableWindowAttributes(wclass) & known_attribs[i].tag) ? "" : "(*)");
}
}
if(tmp_wattr)
qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)tmp_wattr);
}
#endif
/* Just to be extra careful we will change to the kUtilityWindowClass if the
requested attributes cannot be used */
if((GetAvailableWindowAttributes(wclass) & wattr) != wattr) {
WindowClass tmp_class = wclass;
if(wclass == kToolbarWindowClass || wclass == kUtilityWindowClass)
wclass = kFloatingWindowClass;
if(tmp_class != wclass) {
if(!grp)
grp = GetWindowGroupOfClass(wclass);
wclass = tmp_class;
}
}
topData()->wclass = wclass;
topData()->wattr = wattr;
#else
const Qt::WindowType type = q->windowType();
Qt::WindowFlags &flags = data.window_flags;
const bool popup = (type == Qt::Popup);
if (type == Qt::ToolTip || type == Qt::SplashScreen || popup)
flags |= Qt::FramelessWindowHint;
WindowClass wclass = kSheetWindowClass;
if(qt_mac_is_macdrawer(q))
wclass = kDrawerWindowClass;
else if (q->testAttribute(Qt::WA_ShowModal) && flags & Qt::CustomizeWindowHint)
wclass = kDocumentWindowClass;
else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen))
wclass = kModalWindowClass;
else if(q->testAttribute(Qt::WA_ShowModal) || type == Qt::Dialog)
wclass = kMovableModalWindowClass;
else if(type == Qt::ToolTip)
wclass = kHelpWindowClass;
else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5
&& type == Qt::SplashScreen))
wclass = kFloatingWindowClass;
else
wclass = kDocumentWindowClass;
WindowAttributes wattr = NSBorderlessWindowMask;
if(qt_mac_is_macsheet(q)) {
//grp = GetWindowGroupOfClass(kMovableModalWindowClass);
wclass = kSheetWindowClass;
wattr = NSTitledWindowMask | NSResizableWindowMask;
} else {
#ifndef QT_MAC_USE_COCOA
grp = GetWindowGroupOfClass(wclass);
#endif
// Shift things around a bit to get the correct window class based on the presence
// (or lack) of the border.
bool customize = flags & Qt::CustomizeWindowHint;
bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint)));
if (framelessWindow) {
if (wclass == kDocumentWindowClass) {
wclass = kSimpleWindowClass;
} else if (wclass == kFloatingWindowClass) {
wclass = kToolbarWindowClass;
} else if (wclass == kMovableModalWindowClass) {
wclass = kModalWindowClass;
}
} else {
wattr |= NSTitledWindowMask;
if (wclass != kModalWindowClass)
wattr |= NSResizableWindowMask;
}
// Only add extra decorations (well, buttons) for widgets that can have them
// and have an actual border we can put them on.
if (wclass != kModalWindowClass
&& wclass != kSheetWindowClass && wclass != kPlainWindowClass
&& !framelessWindow && wclass != kDrawerWindowClass
&& wclass != kHelpWindowClass) {
if (flags & Qt::WindowMinimizeButtonHint)
wattr |= NSMiniaturizableWindowMask;
if (flags & Qt::WindowSystemMenuHint || flags & Qt::WindowCloseButtonHint)
wattr |= NSClosableWindowMask;
} else {
// Clear these hints so that we aren't call them on invalid windows
flags &= ~(Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint
| Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint);
}
}
if (q->testAttribute(Qt::WA_MacBrushedMetal))
wattr |= NSTexturedBackgroundWindowMask;
#ifdef DEBUG_WINDOW_CREATE
#define ADD_DEBUG_WINDOW_NAME(x) { x, #x }
struct {
UInt32 tag;
const char *name;
} known_attribs[] = {
ADD_DEBUG_WINDOW_NAME(kWindowCompositingAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowMetalAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowCollapseBoxAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowHorizontalZoomAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowVerticalZoomAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowResizableAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowNoActivatesAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowNoUpdatesAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowOpaqueForEventsAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowLiveResizeAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowCloseBoxAttribute),
ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
{ 0, 0 }
}, known_classes[] = {
ADD_DEBUG_WINDOW_NAME(kHelpWindowClass),
ADD_DEBUG_WINDOW_NAME(kPlainWindowClass),
ADD_DEBUG_WINDOW_NAME(kDrawerWindowClass),
ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
ADD_DEBUG_WINDOW_NAME(kSheetWindowClass),
ADD_DEBUG_WINDOW_NAME(kFloatingWindowClass),
ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
ADD_DEBUG_WINDOW_NAME(kDocumentWindowClass),
ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
ADD_DEBUG_WINDOW_NAME(kMovableModalWindowClass),
ADD_DEBUG_WINDOW_NAME(kModalWindowClass),
{ 0, 0 }
};
qDebug("Qt: internal: ************* Creating new window %p (%s::%s)", q, q->metaObject()->className(),
q->objectName().toLocal8Bit().constData());
bool found_class = false;
for(int i = 0; known_classes[i].name; i++) {
if(wclass == known_classes[i].tag) {
found_class = true;
qDebug("Qt: internal: ** Class: %s", known_classes[i].name);
break;
}
}
if(!found_class)
qDebug("Qt: internal: !! Class: Unknown! (%d)", (int)wclass);
if(wattr) {
WindowAttributes tmp_wattr = wattr;
qDebug("Qt: internal: ** Attributes:");
for(int i = 0; tmp_wattr && known_attribs[i].name; i++) {
if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) {
tmp_wattr ^= known_attribs[i].tag;
qDebug("Qt: internal: * %s %s", known_attribs[i].name,
(GetAvailableWindowAttributes(wclass) & known_attribs[i].tag) ? "" : "(*)");
}
}
if(tmp_wattr)
qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)tmp_wattr);
}
#endif
#ifndef QT_MAC_USE_COCOA
/* Just to be extra careful we will change to the kUtilityWindowClass if the
requested attributes cannot be used */
if((GetAvailableWindowAttributes(wclass) & wattr) != wattr) {
WindowClass tmp_class = wclass;
if(wclass == kToolbarWindowClass || wclass == kUtilityWindowClass)
wclass = kFloatingWindowClass;
if(tmp_class != wclass) {
if(!grp)
grp = GetWindowGroupOfClass(wclass);
wclass = tmp_class;
}
}
#endif
#endif
topData()->wclass = wclass;
topData()->wattr = wattr;
}
#ifndef QT_MAC_USE_COCOA // This is handled in Cocoa via our category.
void QWidgetPrivate::initWindowPtr()
{
Q_Q(QWidget);
OSWindowRef windowRef = qt_mac_window_for(qt_mac_nativeview_for(q)); //do not create!
if(!windowRef)
return;
QWidget *window = q->window(), *oldWindow = 0;
if(GetWindowProperty(windowRef, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(oldWindow), 0, &oldWindow) == noErr) {
Q_ASSERT(window == oldWindow);
return;
}
if(SetWindowProperty(windowRef, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(window), &window) != noErr)
qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__); //no real way to recover
if(!q->windowType() != Qt::Desktop) { //setup an event callback handler on the window
InstallWindowEventHandler(windowRef, make_win_eventUPP(), GetEventTypeCount(window_events),
window_events, static_cast<void *>(qApp), &window_event);
}
}
void QWidgetPrivate::finishCreateWindow_sys_Carbon(OSWindowRef windowRef)
{
Q_Q(QWidget);
const Qt::WindowType type = q->windowType();
Qt::WindowFlags &flags = data.window_flags;
QWidget *parentWidget = q->parentWidget();
const bool desktop = (type == Qt::Desktop);
const bool dialog = (type == Qt::Dialog
|| type == Qt::Sheet
|| type == Qt::Drawer
|| (flags & Qt::MSWindowsFixedSizeDialogHint));
QTLWExtra *topExtra = topData();
quint32 wattr = topExtra->wattr;
if (!desktop)
SetAutomaticControlDragTrackingEnabledForWindow(windowRef, true);
HIWindowChangeFeatures(windowRef, kWindowCanCollapse, 0);
if (wattr & kWindowHideOnSuspendAttribute)
HIWindowChangeAvailability(windowRef, kHIWindowExposeHidden, 0);
else
HIWindowChangeAvailability(windowRef, 0, kHIWindowExposeHidden);
if ((flags & Qt::WindowStaysOnTopHint))
ChangeWindowAttributes(windowRef, kWindowNoAttributes, kWindowHideOnSuspendAttribute);
if (qt_mac_is_macdrawer(q) && parentWidget)
SetDrawerParent(windowRef, qt_mac_window_for (parentWidget));
if (topExtra->group) {
qt_mac_release_window_group(topExtra->group);
topExtra->group = 0;
}
if (type == Qt::ToolTip)
qt_mac_set_window_group_to_tooltip(windowRef);
else if (type == Qt::Popup && (flags & Qt::WindowStaysOnTopHint))
qt_mac_set_window_group_to_popup(windowRef);
else if (flags & Qt::WindowStaysOnTopHint)
qt_mac_set_window_group_to_stays_on_top(windowRef, type);
else if (dialog)
SetWindowGroup(windowRef, GetWindowGroupOfClass(kMovableModalWindowClass));
#ifdef DEBUG_WINDOW_CREATE
if (WindowGroupRef grpf = GetWindowGroup(windowRef)) {
QCFString cfname;
CopyWindowGroupName(grpf, &cfname);
SInt32 lvl;
GetWindowGroupLevel(grpf, &lvl);
const char *from = "Default";
if (topExtra && grpf == topData()->group)
from = "Created";
else if (grpf == grp)
from = "Copied";
qDebug("Qt: internal: With window group '%s' [%p] @ %d: %s",
static_cast<QString>(cfname).toLatin1().constData(), grpf, (int)lvl, from);
} else {
qDebug("Qt: internal: No window group!!!");
}
HIWindowAvailability hi_avail = 0;
if (HIWindowGetAvailability(windowRef, &hi_avail) == noErr) {
struct {
UInt32 tag;
const char *name;
} known_avail[] = {
ADD_DEBUG_WINDOW_NAME(kHIWindowExposeHidden),
{ 0, 0 }
};
qDebug("Qt: internal: ** HIWindowAvailibility:");
for (int i = 0; hi_avail && known_avail[i].name; i++) {
if ((hi_avail & known_avail[i].tag) == known_avail[i].tag) {
hi_avail ^= known_avail[i].tag;
qDebug("Qt: internal: * %s", known_avail[i].name);
}
}
if (hi_avail)
qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)hi_avail);
}
#undef ADD_DEBUG_WINDOW_NAME
#endif
if (extra && !extra->mask.isEmpty())
ReshapeCustomWindow(windowRef);
SetWindowModality(windowRef, kWindowModalityNone, 0);
if (qt_mac_is_macdrawer(q))
SetDrawerOffsets(windowRef, 0.0, 25.0);
data.fstrut_dirty = true; // when we create a toplevel widget, the frame strut should be dirty
HIViewRef hiview = (HIViewRef)data.winid;
HIViewRef window_hiview = qt_mac_get_contentview_for(windowRef);
if(!hiview) {
hiview = qt_mac_create_widget(q, this, window_hiview);
setWinId((WId)hiview);
} else {
HIViewAddSubview(window_hiview, hiview);
}
if (hiview) {
Rect win_rect;
GetWindowBounds(qt_mac_window_for (window_hiview), kWindowContentRgn, &win_rect);
HIRect bounds = CGRectMake(0, 0, win_rect.right-win_rect.left, win_rect.bottom-win_rect.top);
HIViewSetFrame(hiview, &bounds);
HIViewSetVisible(hiview, true);
if (q->testAttribute(Qt::WA_DropSiteRegistered))
registerDropSite(true);
transferChildren();
}
initWindowPtr();
if (topExtra->posFromMove) {
updateFrameStrut();
const QRect &fStrut = frameStrut();
Rect r;
SetRect(&r, data.crect.left(), data.crect.top(), data.crect.right() + 1, data.crect.bottom() + 1);
SetRect(&r, r.left + fStrut.left(), r.top + fStrut.top(),
(r.left + fStrut.left() + data.crect.width()) - fStrut.right(),
(r.top + fStrut.top() + data.crect.height()) - fStrut.bottom());
SetWindowBounds(windowRef, kWindowContentRgn, &r);
topExtra->posFromMove = false;
}
if (q->testAttribute(Qt::WA_WState_WindowOpacitySet)){
q->setWindowOpacity(topExtra->opacity / 255.0f);
} else if (qt_mac_is_macsheet(q)){
SetThemeWindowBackground(qt_mac_window_for(q), kThemeBrushSheetBackgroundTransparent, true);
CGFloat alpha = 0;
GetWindowAlpha(qt_mac_window_for(q), &alpha);
if (alpha == 1){
// For some reason the 'SetThemeWindowBackground' does not seem
// to work. So we do this little hack until it hopefully starts to
// work in newer versions of mac OS.
q->setWindowOpacity(0.95f);
q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
}
} else{
// If the window has been recreated after beeing e.g. a sheet,
// make sure that we don't report a faulty opacity:
q->setWindowOpacity(1.0f);
q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
}
// Since we only now have a window, sync our state.
macUpdateHideOnSuspend();
macUpdateOpaqueSizeGrip();
macUpdateMetalAttribute();
macUpdateIgnoreMouseEvents();
setWindowTitle_helper(extra->topextra->caption);
setWindowIconText_helper(extra->topextra->iconText);
setWindowFilePath_helper(extra->topextra->filePath);
setWindowModified_sys(q->isWindowModified());
updateFrameStrut();
qt_mac_update_sizer(q);
applyMaxAndMinSizeOnWindow();
}
#else // QT_MAC_USE_COCOA
void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWindowRef)
{
Q_Q(QWidget);
QMacCocoaAutoReleasePool pool;
NSWindow *windowRef = static_cast<NSWindow *>(voidWindowRef);
const Qt::WindowType type = q->windowType();
Qt::WindowFlags &flags = data.window_flags;
QWidget *parentWidget = q->parentWidget();
const bool popup = (type == Qt::Popup);
const bool dialog = (type == Qt::Dialog
|| type == Qt::Sheet
|| type == Qt::Drawer
|| (flags & Qt::MSWindowsFixedSizeDialogHint));
QTLWExtra *topExtra = topData();
if ((popup || type == Qt::Tool || type == Qt::ToolTip) && !q->isModal()) {
[windowRef setHidesOnDeactivate:YES];
} else {
[windowRef setHidesOnDeactivate:NO];
}
[windowRef setHasShadow:YES];
Q_UNUSED(parentWidget);
Q_UNUSED(dialog);
data.fstrut_dirty = true; // when we create a toplevel widget, the frame strut should be dirty
OSViewRef nsview = (OSViewRef)data.winid;
OSViewRef window_contentview = qt_mac_get_contentview_for(windowRef);
if (!nsview) {
nsview = qt_mac_create_widget(q, this, window_contentview);
setWinId(WId(nsview));
} else {
[window_contentview addSubview:nsview];
}
if (nsview) {
NSRect bounds = [window_contentview bounds];
[nsview setFrame:bounds];
[nsview setHidden:NO];
if (q->testAttribute(Qt::WA_DropSiteRegistered))
registerDropSite(true);
transferChildren();
}
if (topExtra->posFromMove) {
updateFrameStrut();
const QRect &fStrut = frameStrut();
const QRect &crect = data.crect;
const QRect frameRect(QPoint(crect.left(), crect.top()),
QSize(fStrut.left() + fStrut.right() + crect.width(),
fStrut.top() + fStrut.bottom() + crect.height()));
NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1),
frameRect.width(), frameRect.height());
[windowRef setFrame:cocoaFrameRect display:NO];
topExtra->posFromMove = false;
}
if (q->testAttribute(Qt::WA_WState_WindowOpacitySet)){
q->setWindowOpacity(topExtra->opacity / 255.0f);
} else if (qt_mac_is_macsheet(q)){
CGFloat alpha = [qt_mac_window_for(q) alphaValue];
if (alpha >= 1.0) {
q->setWindowOpacity(0.95f);
q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
}
} else{
// If the window has been recreated after beeing e.g. a sheet,
// make sure that we don't report a faulty opacity:
q->setWindowOpacity(1.0f);
q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
}
macUpdateHideOnSuspend();
macUpdateOpaqueSizeGrip();
macUpdateIgnoreMouseEvents();
setWindowTitle_helper(extra->topextra->caption);
setWindowIconText_helper(extra->topextra->iconText);
setWindowModified_sys(q->isWindowModified());
updateFrameStrut();
syncCocoaMask();
macUpdateIsOpaque();
qt_mac_update_sizer(q);
applyMaxAndMinSizeOnWindow();
}
#endif // QT_MAC_USE_COCOA
/*
Recreates widget window. Useful if immutable
properties for it has changed.
*/
void QWidgetPrivate::recreateMacWindow()
{
Q_Q(QWidget);
OSViewRef myView = qt_mac_nativeview_for(q);
OSWindowRef oldWindow = qt_mac_window_for(myView);
#ifndef QT_MAC_USE_COCOA
HIViewRemoveFromSuperview(myView);
determineWindowClass();
createWindow_sys();
if (QMainWindowLayout *mwl = qobject_cast<QMainWindowLayout *>(q->layout())) {
mwl->updateHIToolBarStatus();
}
if (IsWindowVisible(oldWindow))
show_sys();
#else
QMacCocoaAutoReleasePool pool;
[myView removeFromSuperview];
determineWindowClass();
createWindow_sys();
if (NSToolbar *toolbar = [oldWindow toolbar]) {
OSWindowRef newWindow = qt_mac_window_for(myView);
[newWindow setToolbar:toolbar];
[toolbar setVisible:[toolbar isVisible]];
}
if ([oldWindow isVisible]){
if ([oldWindow isSheet])
[NSApp endSheet:oldWindow];
[oldWindow orderOut:oldWindow];
show_sys();
}
#endif // QT_MAC_USE_COCOA
// Release the window after creating the new window, because releasing it early
// may cause the app to quit ("close on last window closed attribute")
qt_mac_destructWindow(oldWindow);
}
void QWidgetPrivate::createWindow_sys()
{
Q_Q(QWidget);
Qt::WindowFlags &flags = data.window_flags;
QWidget *parentWidget = q->parentWidget();
QTLWExtra *topExtra = topData();
if (topExtra->embedded)
return; // Simply return because this view "is" the top window.
quint32 wattr = topExtra->wattr;
if(parentWidget && (parentWidget->window()->windowFlags() & Qt::WindowStaysOnTopHint)) // If our parent has Qt::WStyle_StaysOnTop, so must we
flags |= Qt::WindowStaysOnTopHint;
data.fstrut_dirty = true;
OSWindowRef windowRef = qt_mac_create_window(q, topExtra->wclass, wattr, data.crect);
if (windowRef == 0)
qWarning("QWidget: Internal error: %s:%d: If you reach this error please contact Qt Support and include the\n"
" WidgetFlags used in creating the widget.", __FILE__, __LINE__);
#ifndef QT_MAC_USE_COCOA
finishCreateWindow_sys_Carbon(windowRef);
#else
finishCreateWindow_sys_Cocoa(windowRef);
#endif
}
void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
{
Q_Q(QWidget);
OSViewRef destroyid = 0;
#ifndef QT_MAC_USE_COCOA
window_event = 0;
#endif
Qt::WindowType type = q->windowType();
Qt::WindowFlags flags = data.window_flags;
QWidget *parentWidget = q->parentWidget();
bool topLevel = (flags & Qt::Window);
bool popup = (type == Qt::Popup);
bool dialog = (type == Qt::Dialog
|| type == Qt::Sheet
|| type == Qt::Drawer
|| (flags & Qt::MSWindowsFixedSizeDialogHint));
bool desktop = (type == Qt::Desktop);
// Determine this early for top-levels so, we can use it later.
if (topLevel)
determineWindowClass();
if (desktop) {
QSize desktopSize = qt_mac_desktopSize();
q->setAttribute(Qt::WA_WState_Visible);
data.crect.setRect(0, 0, desktopSize.width(), desktopSize.height());
dialog = popup = false; // force these flags off
} else {
q->setAttribute(Qt::WA_WState_Visible, false);
if (topLevel && (type != Qt::Drawer)) {
if (QDesktopWidget *dsk = QApplication::desktop()) { // calc pos/size from screen
const bool wasResized = q->testAttribute(Qt::WA_Resized);
const bool wasMoved = q->testAttribute(Qt::WA_Moved);
int deskn = dsk->primaryScreen();
if (parentWidget && parentWidget->windowType() != Qt::Desktop)
deskn = dsk->screenNumber(parentWidget);
QRect screenGeo = dsk->screenGeometry(deskn);
if (!wasResized) {
#ifndef QT_MAC_USE_COCOA
data.crect.setSize(QSize(screenGeo.width()/2, 4*screenGeo.height()/10));
#else
NSRect newRect = [NSWindow frameRectForContentRect:NSMakeRect(0, 0,
screenGeo.width() / 2.,
4 * screenGeo.height() / 10.)
styleMask:topData()->wattr];
data.crect.setSize(QSize(newRect.size.width, newRect.size.height));
#endif
// Constrain to minimums and maximums we've set
if (extra->minw > 0)
data.crect.setWidth(qMax(extra->minw, data.crect.width()));
if (extra->minh > 0)
data.crect.setHeight(qMax(extra->minh, data.crect.height()));
if (extra->maxw > 0)
data.crect.setWidth(qMin(extra->maxw, data.crect.width()));
if (extra->maxh > 0)
data.crect.setHeight(qMin(extra->maxh, data.crect.height()));
}
if (!wasMoved && !q->testAttribute(Qt::WA_DontShowOnScreen))
data.crect.moveTopLeft(QPoint(screenGeo.width()/4,
3 * screenGeo.height() / 10));
}
}
}
if(!window) // always initialize
initializeWindow=true;
hd = 0;
if(window) { // override the old window (with a new NSView)
OSViewRef nativeView = OSViewRef(window);
OSViewRef parent = 0;
#ifndef QT_MAC_USE_COCOA
CFRetain(nativeView);
#else
[nativeView retain];
#endif
if (destroyOldWindow)
destroyid = qt_mac_nativeview_for(q);
bool transfer = false;
setWinId((WId)nativeView);
#ifndef QT_MAC_USE_COCOA
#ifndef HIViewInstallEventHandler
// Macro taken from the CarbonEvents Header on Tiger
#define HIViewInstallEventHandler( target, handler, numTypes, list, userData, outHandlerRef ) \
InstallEventHandler( HIObjectGetEventTarget( (HIObjectRef) (target) ), (handler), (numTypes), (list), (userData), (outHandlerRef) )
#endif
HIViewInstallEventHandler(nativeView, make_widget_eventUPP(), GetEventTypeCount(widget_events), widget_events, 0, 0);
#endif
if(topLevel) {
for(int i = 0; i < 2; ++i) {
if(i == 1) {
if(!initializeWindow)
break;
createWindow_sys();
}
if(OSWindowRef windowref = qt_mac_window_for(nativeView)) {
#ifndef QT_MAC_USE_COCOA
CFRetain(windowref);
#else
[windowref retain];
#endif
if (initializeWindow) {
parent = qt_mac_get_contentview_for(windowref);
} else {
#ifndef QT_MAC_USE_COCOA
parent = HIViewGetSuperview(nativeView);
#else
parent = [nativeView superview];
#endif
}
break;
}
}
if(!parent)
transfer = true;
} else if (parentWidget) {
// I need to be added to my parent, therefore my parent needs an NSView
parentWidget->createWinId();
parent = qt_mac_nativeview_for(parentWidget);
}
if(parent != nativeView && parent) {
#ifndef QT_MAC_USE_COCOA
HIViewAddSubview(parent, nativeView);
#else
[parent addSubview:nativeView];
#endif
}
if(transfer)
transferChildren();
data.fstrut_dirty = true; // we'll re calculate this later
q->setAttribute(Qt::WA_WState_Visible,
#ifndef QT_MAC_USE_COCOA
HIViewIsVisible(nativeView)
#else
![nativeView isHidden]
#endif
);
if(initializeWindow) {
#ifndef QT_MAC_USE_COCOA
HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
HIViewSetFrame(nativeView, &bounds);
q->setAttribute(Qt::WA_WState_Visible, HIViewIsVisible(nativeView));
#else
NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
[nativeView setFrame:bounds];
q->setAttribute(Qt::WA_WState_Visible, [nativeView isHidden]);
#endif
}
#ifndef QT_MAC_USE_COCOA
initWindowPtr();
#endif
} else if (desktop) { // desktop widget
if (!qt_root_win)
QWidgetPrivate::qt_create_root_win();
Q_ASSERT(qt_root_win);
WId rootWinID = 0;
#ifndef QT_MAC_USE_COCOA
CFRetain(qt_root_win);
if(HIViewRef rootContentView = HIViewGetRoot(qt_root_win)) {
rootWinID = (WId)rootContentView;
CFRetain(rootContentView);
}
#else
[qt_root_win retain];
if (OSViewRef rootContentView = [qt_root_win contentView]) {
rootWinID = (WId)rootContentView;
[rootContentView retain];
}
#endif
setWinId(rootWinID);
} else if (topLevel) {
determineWindowClass();
if(OSViewRef osview = qt_mac_create_widget(q, this, 0)) {
#ifndef QT_MAC_USE_COCOA
HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(),
data.crect.width(), data.crect.height());
HIViewSetFrame(osview, &bounds);
#else
NSRect bounds = NSMakeRect(data.crect.x(), flipYCoordinate(data.crect.y()),
data.crect.width(), data.crect.height());
[osview setFrame:bounds];
#endif
setWinId((WId)osview);
}
} else {
data.fstrut_dirty = false; // non-toplevel widgets don't have a frame, so no need to update the strut
if(OSViewRef osview = qt_mac_create_widget(q, this, qt_mac_nativeview_for(parentWidget))) {
#ifndef QT_MAC_USE_COCOA
HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
HIViewSetFrame(osview, &bounds);
setWinId((WId)osview);
#else
NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
[osview setFrame:bounds];
setWinId((WId)osview);
#endif
if (q->testAttribute(Qt::WA_DropSiteRegistered))
registerDropSite(true);
}
}
updateIsOpaque();
if (q->hasFocus())
setFocus_sys();
if (!topLevel && initializeWindow)
setWSGeometry();
if (destroyid)
qt_mac_destructView(destroyid);
if (q->testAttribute(Qt::WA_AcceptTouchEvents))
registerTouchWindow();
}
/*!
Returns the QuickDraw handle of the widget. Use of this function is not
portable. This function will return 0 if QuickDraw is not supported, or
if the handle could not be created.
\warning This function is only available on Mac OS X.
*/
Qt::HANDLE
QWidget::macQDHandle() const
{
#ifndef QT_MAC_USE_COCOA
return d_func()->qd_hd;
#else
return 0;
#endif
}
/*!
Returns the CoreGraphics handle of the widget. Use of this function is
not portable. This function will return 0 if no painter context can be
established, or if the handle could not be created.
\warning This function is only available on Mac OS X.
*/
Qt::HANDLE
QWidget::macCGHandle() const
{
return handle();
}
void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
Q_D(QWidget);
if (!isWindow() && parentWidget())
parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
d->deactivateWidgetCleanup();
qt_mac_event_release(this);
if(testAttribute(Qt::WA_WState_Created)) {
QMacCocoaAutoReleasePool pool;
setAttribute(Qt::WA_WState_Created, false);
QObjectList chldrn = children();
for(int i = 0; i < chldrn.size(); i++) { // destroy all widget children
QObject *obj = chldrn.at(i);
if(obj->isWidgetType())
static_cast<QWidget*>(obj)->destroy(destroySubWindows, destroySubWindows);
}
if(mac_mouse_grabber == this)
releaseMouse();
if(mac_keyboard_grabber == this)
releaseKeyboard();
if(testAttribute(Qt::WA_ShowModal)) // just be sure we leave modal
QApplicationPrivate::leaveModal(this);
else if((windowType() == Qt::Popup))
qApp->d_func()->closePopup(this);
if (destroyWindow) {
if(OSViewRef hiview = qt_mac_nativeview_for(this)) {
OSWindowRef window = 0;
NSDrawer *drawer = nil;
#ifdef QT_MAC_USE_COCOA
if (qt_mac_is_macdrawer(this)) {
drawer = qt_mac_drawer_for(this);
} else
#endif
if (isWindow())
window = qt_mac_window_for(hiview);
// Because of how "destruct" works, we have to do just a normal release for the root_win.
if (window && window == qt_root_win) {
#ifndef QT_MAC_USE_COCOA
CFRelease(hiview);
#else
[hiview release];
#endif
} else {
qt_mac_destructView(hiview);
}
if (drawer)
qt_mac_destructDrawer(drawer);
if (window)
qt_mac_destructWindow(window);
}
}
QT_TRY {
d->setWinId(0);
} QT_CATCH (const std::bad_alloc &) {
// swallow - destructors must not throw
}
}
}
void QWidgetPrivate::transferChildren()
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created))
return; // Can't add any views anyway
QObjectList chlist = q->children();
for (int i = 0; i < chlist.size(); ++i) {
QObject *obj = chlist.at(i);
if (obj->isWidgetType()) {
QWidget *w = (QWidget *)obj;
if (!w->isWindow()) {
// This seems weird, no need to call it in a loop right?
if (!topData()->caption.isEmpty())
setWindowTitle_helper(extra->topextra->caption);
if (w->testAttribute(Qt::WA_WState_Created)) {
#ifndef QT_MAC_USE_COCOA
HIViewAddSubview(qt_mac_nativeview_for(q), qt_mac_nativeview_for(w));
#else
// New NSWindows get an extra reference when drops are
// registered (at least in 10.5) which means that we may
// access the window later and get a crash (becasue our
// widget is dead). Work around this be having the drop
// site disabled until it is part of the new hierarchy.
bool oldRegistered = w->testAttribute(Qt::WA_DropSiteRegistered);
w->setAttribute(Qt::WA_DropSiteRegistered, false);
[qt_mac_nativeview_for(w) retain];
[qt_mac_nativeview_for(w) removeFromSuperview];
[qt_mac_nativeview_for(q) addSubview:qt_mac_nativeview_for(w)];
[qt_mac_nativeview_for(w) release];
w->setAttribute(Qt::WA_DropSiteRegistered, oldRegistered);
#endif
}
}
}
}
}
void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
{
Q_Q(QWidget);
QMacCocoaAutoReleasePool pool;
QTLWExtra *topData = maybeTopData();
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
#ifdef QT_MAC_USE_COCOA
bool wasWindow = q->isWindow();
#endif
OSViewRef old_id = 0;
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
// Maintain the glWidgets list on parent change: remove "our" gl widgets
// from the list on the old parent and grandparents.
if (glWidgets.isEmpty() == false) {
QWidget *current = q->parentWidget();
while (current) {
for (QList<QWidgetPrivate::GlWidgetInfo>::const_iterator it = glWidgets.constBegin();
it != glWidgets.constEnd(); ++it)
current->d_func()->glWidgets.removeAll(*it);
if (current->isWindow())
break;
current = current->parentWidget();
}
}
#ifndef QT_MAC_USE_COCOA
EventHandlerRef old_window_event = 0;
#else
bool oldToolbarVisible = false;
NSDrawer *oldDrawer = nil;
NSToolbar *oldToolbar = 0;
#endif
if (wasCreated && !(q->windowType() == Qt::Desktop)) {
old_id = qt_mac_nativeview_for(q);
#ifndef QT_MAC_USE_COCOA
old_window_event = window_event;
#else
OSWindowRef oldWindow = qt_mac_window_for(old_id);
if (qt_mac_is_macdrawer(q)) {
oldDrawer = qt_mac_drawer_for(q);
}
if (wasWindow) {
oldToolbar = [oldWindow toolbar];
[oldToolbar retain];
oldToolbarVisible = [oldToolbar isVisible];
[oldWindow setToolbar:nil];
}
#endif
}
QWidget* oldtlw = q->window();
if (q->testAttribute(Qt::WA_DropSiteRegistered))
q->setAttribute(Qt::WA_DropSiteRegistered, false);
//recreate and setup flags
QObjectPrivate::setParent_helper(parent);
QPoint pt = q->pos();
bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
if (wasCreated && !qt_isGenuineQWidget(q))
return;
if ((data.window_flags & Qt::Sheet) && topData && topData->opacity == 242)
q->setWindowOpacity(1.0f);
setWinId(0); //do after the above because they may want the id
data.window_flags = f;
q->setAttribute(Qt::WA_WState_Created, false);
q->setAttribute(Qt::WA_WState_Visible, false);
q->setAttribute(Qt::WA_WState_Hidden, false);
adjustFlags(data.window_flags, q);
// keep compatibility with previous versions, we need to preserve the created state
// (but we recreate the winId for the widget being reparented, again for compatibility)
if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created))) {
createWinId();
if (q->isWindow()) {
#ifndef QT_MAC_USE_COCOA
// We do this down below for wasCreated, so avoid doing this twice
// (only for performance, it gets called a lot anyway).
if (!wasCreated) {
if (QMainWindowLayout *mwl = qobject_cast<QMainWindowLayout *>(q->layout())) {
mwl->updateHIToolBarStatus();
}
}
#else
// Simply transfer our toolbar over. Everything should stay put, unlike in Carbon.
if (oldToolbar && !(f & Qt::FramelessWindowHint)) {
OSWindowRef newWindow = qt_mac_window_for(q);
[newWindow setToolbar:oldToolbar];
[oldToolbar release];
[oldToolbar setVisible:oldToolbarVisible];
}
#endif
}
}
if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
q->setAttribute(Qt::WA_WState_Hidden);
q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
if (wasCreated) {
transferChildren();
#ifndef QT_MAC_USE_COCOA
// If we were a unified window, We just transfered our toolbars out of the unified toolbar.
// So redo the status one more time. It apparently is not an issue with Cocoa.
if (q->isWindow()) {
if (QMainWindowLayout *mwl = qobject_cast<QMainWindowLayout *>(q->layout())) {
mwl->updateHIToolBarStatus();
}
}
#endif
if (topData &&
(!topData->caption.isEmpty() || !topData->filePath.isEmpty()))
setWindowTitle_helper(q->windowTitle());
}
if (q->testAttribute(Qt::WA_AcceptDrops)
|| (!q->isWindow() && q->parentWidget()
&& q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
q->setAttribute(Qt::WA_DropSiteRegistered, true);
//cleanup
#ifndef QT_MAC_USE_COCOA
if (old_window_event)
RemoveEventHandler(old_window_event);
#endif
if (old_id) { //don't need old window anymore
OSWindowRef window = (oldtlw == q) ? qt_mac_window_for(old_id) : 0;
qt_mac_destructView(old_id);
#ifdef QT_MAC_USE_COCOA
if (oldDrawer) {
qt_mac_destructDrawer(oldDrawer);
} else
#endif
if (window)
qt_mac_destructWindow(window);
}
// Maintain the glWidgets list on parent change: add "our" gl widgets
// to the list on the new parent and grandparents.
if (glWidgets.isEmpty() == false) {
QWidget *current = q->parentWidget();
while (current) {
current->d_func()->glWidgets += glWidgets;
if (current->isWindow())
break;
current = current->parentWidget();
}
}
invalidateBuffer(q->rect());
qt_event_request_window_change(q);
}
QPoint QWidget::mapToGlobal(const QPoint &pos) const
{
Q_D(const QWidget);
if (!testAttribute(Qt::WA_WState_Created)) {
QPoint p = pos + data->crect.topLeft();
return isWindow() ? p : parentWidget()->mapToGlobal(p);
}
#ifndef QT_MAC_USE_COCOA
QPoint tmp = d->mapToWS(pos);
HIPoint hi_pos = CGPointMake(tmp.x(), tmp.y());
HIViewConvertPoint(&hi_pos, qt_mac_nativeview_for(this), 0);
Rect win_rect;
GetWindowBounds(qt_mac_window_for(this), kWindowStructureRgn, &win_rect);
return QPoint((int)hi_pos.x+win_rect.left, (int)hi_pos.y+win_rect.top);
#else
QPoint tmp = d->mapToWS(pos);
NSPoint hi_pos = NSMakePoint(tmp.x(), tmp.y());
hi_pos = [qt_mac_nativeview_for(this) convertPoint:hi_pos toView:nil];
NSRect win_rect = [qt_mac_window_for(this) frame];
hi_pos.x += win_rect.origin.x;
hi_pos.y += win_rect.origin.y;
// If we aren't the desktop we need to flip, if you flip the desktop on itself, you get the other problem.
return ((window()->windowFlags() & Qt::Desktop) == Qt::Desktop) ? QPointF(hi_pos.x, hi_pos.y).toPoint()
: flipPoint(hi_pos).toPoint();
#endif
}
QPoint QWidget::mapFromGlobal(const QPoint &pos) const
{
Q_D(const QWidget);
if (!testAttribute(Qt::WA_WState_Created)) {
QPoint p = isWindow() ? pos : parentWidget()->mapFromGlobal(pos);
return p - data->crect.topLeft();
}
#ifndef QT_MAC_USE_COCOA
Rect win_rect;
GetWindowBounds(qt_mac_window_for(this), kWindowStructureRgn, &win_rect);
HIPoint hi_pos = CGPointMake(pos.x()-win_rect.left, pos.y()-win_rect.top);
HIViewConvertPoint(&hi_pos, 0, qt_mac_nativeview_for(this));
return d->mapFromWS(QPoint((int)hi_pos.x, (int)hi_pos.y));
#else
NSRect win_rect = [qt_mac_window_for(this) frame];
// The Window point is in "Cocoa coordinates," but the view is in "Qt coordinates"
// so make sure to keep them in sync.
NSPoint hi_pos = NSMakePoint(pos.x()-win_rect.origin.x,
flipYCoordinate(pos.y())-win_rect.origin.y);
hi_pos = [qt_mac_nativeview_for(this) convertPoint:hi_pos fromView:0];
return d->mapFromWS(QPoint(qRound(hi_pos.x), qRound(hi_pos.y)));
#endif
}
void QWidgetPrivate::updateSystemBackground()
{
}
void QWidgetPrivate::setCursor_sys(const QCursor &)
{
#ifndef QT_MAC_USE_COCOA
qt_mac_update_cursor();
#else
Q_Q(QWidget);
if (q->testAttribute(Qt::WA_WState_Created)) {
QMacCocoaAutoReleasePool pool;
[qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)];
}
#endif
}
void QWidgetPrivate::unsetCursor_sys()
{
#ifndef QT_MAC_USE_COCOA
qt_mac_update_cursor();
#else
Q_Q(QWidget);
if (q->testAttribute(Qt::WA_WState_Created)) {
QMacCocoaAutoReleasePool pool;
[qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)];
}
#endif
}
void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
{
Q_Q(QWidget);
if (q->isWindow()) {
#ifndef QT_MAC_USE_COCOA
SetWindowTitleWithCFString(qt_mac_window_for(q), QCFString(caption));
#else
QMacCocoaAutoReleasePool pool;
[qt_mac_window_for(q) setTitle:qt_mac_QStringToNSString(caption)];
#endif
}
}
void QWidgetPrivate::setWindowModified_sys(bool mod)
{
Q_Q(QWidget);
if (q->isWindow() && q->testAttribute(Qt::WA_WState_Created)) {
#ifndef QT_MAC_USE_COCOA
SetWindowModified(qt_mac_window_for(q), mod);
#else
[qt_mac_window_for(q) setDocumentEdited:mod];
#endif
}
}
void QWidgetPrivate::setWindowFilePath_sys(const QString &filePath)
{
Q_Q(QWidget);
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
QFileInfo fi(filePath);
[qt_mac_window_for(q) setRepresentedFilename:fi.exists() ? qt_mac_QStringToNSString(filePath) : @""];
#else
bool validRef = false;
FSRef ref;
bzero(&ref, sizeof(ref));
OSStatus status;
if (!filePath.isEmpty()) {
status = FSPathMakeRef(reinterpret_cast<const UInt8 *>(filePath.toUtf8().constData()), &ref, 0);
validRef = (status == noErr);
}
// Set the proxy regardless, since this is our way of clearing it as well, but ignore the
// return value as well.
if (validRef) {
status = HIWindowSetProxyFSRef(qt_mac_window_for(q), &ref);
} else {
status = RemoveWindowProxy(qt_mac_window_for(q));
}
if (status != noErr)
qWarning("QWidget::setWindowFilePath: Error setting proxyicon for path (%s):%ld",
qPrintable(filePath), status);
#endif
}
void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created))
return;
QTLWExtra *topData = this->topData();
if (topData->iconPixmap && !forceReset) // already set
return;
QIcon icon = q->windowIcon();
QPixmap *pm = 0;
if (!icon.isNull()) {
// now create the extra
if (!topData->iconPixmap) {
pm = new QPixmap(icon.pixmap(QSize(22, 22)));
topData->iconPixmap = pm;
} else {
pm = topData->iconPixmap;
}
}
if (q->isWindow()) {
#ifndef QT_MAC_USE_COCOA
IconRef previousIcon = 0;
if (icon.isNull()) {
RemoveWindowProxy(qt_mac_window_for(q));
previousIcon = topData->windowIcon;
topData->windowIcon = 0;
} else {
WindowClass wclass;
GetWindowClass(qt_mac_window_for(q), &wclass);
if (wclass == kDocumentWindowClass) {
IconRef newIcon = qt_mac_create_iconref(*pm);
previousIcon = topData->windowIcon;
topData->windowIcon = newIcon;
SetWindowProxyIcon(qt_mac_window_for(q), newIcon);
}
}
// Release the previous icon if it was set by this function.
if (previousIcon != 0)
ReleaseIconRef(previousIcon);
#else
QMacCocoaAutoReleasePool pool;
NSButton *iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
if (iconButton == nil) {
QCFString string(q->windowTitle());
const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
[qt_mac_window_for(q) setRepresentedURL:[NSURL fileURLWithPath:tmpString]];
iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
}
if (icon.isNull()) {
[iconButton setImage:nil];
} else {
QPixmap scaled = pm->scaled(QSize(16,16), Qt::KeepAspectRatio, Qt::SmoothTransformation);
NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(scaled));
[iconButton setImage:image];
[image release];
}
#endif
}
}
void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
{
Q_Q(QWidget);
if(q->isWindow() && !iconText.isEmpty()) {
#ifndef QT_MAC_USE_COCOA
SetWindowAlternateTitle(qt_mac_window_for(q), QCFString(iconText));
#else
QMacCocoaAutoReleasePool pool;
[qt_mac_window_for(q) setMiniwindowTitle:qt_mac_QStringToNSString(iconText)];
#endif
}
}
void QWidget::grabMouse()
{
if(isVisible() && !qt_nograb()) {
if(mac_mouse_grabber)
mac_mouse_grabber->releaseMouse();
mac_mouse_grabber=this;
}
}
#ifndef QT_NO_CURSOR
void QWidget::grabMouse(const QCursor &)
{
if(isVisible() && !qt_nograb()) {
if(mac_mouse_grabber)
mac_mouse_grabber->releaseMouse();
mac_mouse_grabber=this;
}
}
#endif
void QWidget::releaseMouse()
{
if(!qt_nograb() && mac_mouse_grabber == this)
mac_mouse_grabber = 0;
}
void QWidget::grabKeyboard()
{
if(!qt_nograb()) {
if(mac_keyboard_grabber)
mac_keyboard_grabber->releaseKeyboard();
mac_keyboard_grabber = this;
}
}
void QWidget::releaseKeyboard()
{
if(!qt_nograb() && mac_keyboard_grabber == this)
mac_keyboard_grabber = 0;
}
QWidget *QWidget::mouseGrabber()
{
return mac_mouse_grabber;
}
QWidget *QWidget::keyboardGrabber()
{
return mac_keyboard_grabber;
}
void QWidget::activateWindow()
{
QWidget *tlw = window();
if(!tlw->isVisible() || !tlw->isWindow() || (tlw->windowType() == Qt::Desktop))
return;
qt_event_remove_activate();
QWidget *fullScreenWidget = tlw;
QWidget *parentW = tlw;
// Find the oldest parent or the parent with fullscreen, whichever comes first.
while (parentW) {
fullScreenWidget = parentW->window();
if (fullScreenWidget->windowState() & Qt::WindowFullScreen)
break;
parentW = fullScreenWidget->parentWidget();
}
if (fullScreenWidget->windowType() != Qt::ToolTip) {
qt_mac_set_fullscreen_mode((fullScreenWidget->windowState() & Qt::WindowFullScreen) &&
qApp->desktop()->screenNumber(this) == 0);
}
bool windowActive;
OSWindowRef win = qt_mac_window_for(tlw);
#ifndef QT_MAC_USE_COCOA
windowActive = IsWindowActive(win);
#else
QMacCocoaAutoReleasePool pool;
windowActive = [win isKeyWindow];
#endif
if ((tlw->windowType() == Qt::Popup)
|| (tlw->windowType() == Qt::Tool)
|| qt_mac_is_macdrawer(tlw)
|| windowActive) {
#ifndef QT_MAC_USE_COCOA
ActivateWindow(win, true);
#else
[win makeKeyWindow];
#endif
qApp->setActiveWindow(tlw);
} else if(!isMinimized()) {
#ifndef QT_MAC_USE_COCOA
SelectWindow(win);
#else
[win makeKeyAndOrderFront:win];
#endif
}
}
QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
{
return new QMacWindowSurface(q_func());
}
void QWidgetPrivate::update_sys(const QRect &r)
{
Q_Q(QWidget);
if (r == q->rect()) {
if (updateRedirectedToGraphicsProxyWidget(q, r))
return;
dirtyOnWidget += r;
#ifndef QT_MAC_USE_COCOA
HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true);
#else
[qt_mac_nativeview_for(q) setNeedsDisplay:YES];
#endif
return;
}
int x = r.x(), y = r.y(), w = r.width(), h = r.height();
if (w < 0)
w = q->data->crect.width() - x;
if (h < 0)
h = q->data->crect.height() - y;
if (w && h) {
const QRect updateRect = QRect(x, y, w, h);
if (updateRedirectedToGraphicsProxyWidget(q, updateRect))
return;
#ifndef QT_MAC_USE_COCOA
dirtyOnWidget += updateRect;
HIRect r = CGRectMake(x, y, w, h);
HIViewSetNeedsDisplayInRect(qt_mac_nativeview_for(q), &r, true);
#else
[qt_mac_nativeview_for(q) setNeedsDisplayInRect:NSMakeRect(x, y, w, h)];
#endif
}
}
void QWidgetPrivate::update_sys(const QRegion &rgn)
{
Q_Q(QWidget);
if (updateRedirectedToGraphicsProxyWidget(q, rgn))
return;
dirtyOnWidget += rgn;
#ifndef QT_MAC_USE_COCOA
RgnHandle rgnHandle = rgn.toQDRgnForUpdate_sys();
if (rgnHandle)
HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true);
else {
HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow.
}
#else
// Cocoa doesn't do regions, it seems more efficient to just update the bounding rect instead of a potential number of message passes for each rect.
const QRect &boundingRect = rgn.boundingRect();
[qt_mac_nativeview_for(q) setNeedsDisplayInRect:NSMakeRect(boundingRect.x(),
boundingRect.y(), boundingRect.width(),
boundingRect.height())];
#endif
}
bool QWidgetPrivate::isRealWindow() const
{
return q_func()->isWindow() && !topData()->embedded;
}
void QWidgetPrivate::show_sys()
{
Q_Q(QWidget);
if ((q->windowType() == Qt::Desktop)) //desktop is always visible
return;
invalidateBuffer(q->rect());
if (q->testAttribute(Qt::WA_OutsideWSRange))
return;
QMacCocoaAutoReleasePool pool;
q->setAttribute(Qt::WA_Mapped);
if (q->testAttribute(Qt::WA_DontShowOnScreen))
return;
bool realWindow = isRealWindow();
if (realWindow && !q->testAttribute(Qt::WA_Moved)) {
q->createWinId();
if (QWidget *p = q->parentWidget()) {
p->createWinId();
#ifndef QT_MAC_USE_COCOA
RepositionWindow(qt_mac_window_for(q), qt_mac_window_for(p), kWindowCenterOnParentWindow);
#else
CGRect parentFrame = NSRectToCGRect([qt_mac_window_for(p) frame]);
OSWindowRef windowRef = qt_mac_window_for(q);
NSRect windowFrame = [windowRef frame];
NSPoint parentCenter = NSMakePoint(CGRectGetMidX(parentFrame), CGRectGetMidY(parentFrame));
[windowRef setFrameTopLeftPoint:NSMakePoint(parentCenter.x - (windowFrame.size.width / 2),
(parentCenter.y + (windowFrame.size.height / 2)))];
#endif
} else {
#ifndef QT_MAC_USE_COCOA
RepositionWindow(qt_mac_window_for(q), 0, kWindowCenterOnMainScreen);
#else
// Ideally we would do a "center" here, but NSWindow's center is more equivalent to
// kWindowAlertPositionOnMainScreen instead of kWindowCenterOnMainScreen.
QRect availGeo = QApplication::desktop()->availableGeometry(q);
// Center the content only.
data.crect.moveCenter(availGeo.center());
QRect fStrut = frameStrut();
QRect frameRect(data.crect.x() - fStrut.left(), data.crect.y() - fStrut.top(),
fStrut.left() + fStrut.right() + data.crect.width(),
fStrut.top() + fStrut.bottom() + data.crect.height());
NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1), frameRect.width(), frameRect.height());
[qt_mac_window_for(q) setFrame:cocoaFrameRect display:NO];
#endif
}
}
data.fstrut_dirty = true;
if (realWindow) {
// Delegates can change window state, so record some things earlier.
bool isCurrentlyMinimized = (q->windowState() & Qt::WindowMinimized);
setModal_sys();
OSWindowRef window = qt_mac_window_for(q);
#ifndef QT_MAC_USE_COCOA
SizeWindow(window, q->width(), q->height(), true);
#endif
#ifdef QT_MAC_USE_COCOA
// Make sure that we end up sending a repaint event to
// the widget if the window has been visible one before:
[qt_mac_get_contentview_for(window) setNeedsDisplay:YES];
#endif
if(qt_mac_is_macsheet(q)) {
qt_event_request_showsheet(q);
} else if(qt_mac_is_macdrawer(q)) {
#ifndef QT_MAC_USE_COCOA
OpenDrawer(window, kWindowEdgeDefault, false);
#else
NSDrawer *drawer = qt_mac_drawer_for(q);
[drawer openOnEdge:[drawer preferredEdge]];
#endif
} else {
#ifndef QT_MAC_USE_COCOA
ShowHide(window, true);
#else
// sync the opacity value back (in case of a fade).
[window setAlphaValue:q->windowOpacity()];
[window makeKeyAndOrderFront:window];
// If this window is app modal, we need to start spinning
// a modal session for it. Interrupting
// the event dispatcher will make this happend:
if (data.window_modality == Qt::ApplicationModal)
QEventDispatcherMac::instance()->interrupt();
#endif
if (q->windowType() == Qt::Popup) {
if (q->focusWidget())
q->focusWidget()->d_func()->setFocus_sys();
else
setFocus_sys();
}
toggleDrawers(true);
}
if (isCurrentlyMinimized) { //show in collapsed state
#ifndef QT_MAC_USE_COCOA
CollapseWindow(window, true);
#else
[window miniaturize:window];
#endif
} else if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) {
#ifndef QT_MAC_USE_COCOA
qt_event_request_activate(q);
#else
[qt_mac_window_for(q) makeKeyWindow];
#endif
}
} else if(topData()->embedded || !q->parentWidget() || q->parentWidget()->isVisible()) {
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
[qt_mac_nativeview_for(q) setHidden:NO];
#endif
}
if (!QWidget::mouseGrabber()){
QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
qt_mouseover = enterWidget;
}
qt_event_request_window_change(q);
}
QPoint qt_mac_nativeMapFromParent(const QWidget *child, const QPoint &pt)
{
#ifndef QT_MAC_USE_COCOA
CGPoint nativePoint = CGPointMake(pt.x(), pt.y());
HIViewConvertPoint(&nativePoint, qt_mac_nativeview_for(child->parentWidget()),
qt_mac_nativeview_for(child));
#else
NSPoint nativePoint = [qt_mac_nativeview_for(child) convertPoint:NSMakePoint(pt.x(), pt.y()) fromView:qt_mac_nativeview_for(child->parentWidget())];
#endif
return QPoint(nativePoint.x, nativePoint.y);
}
void QWidgetPrivate::hide_sys()
{
Q_Q(QWidget);
if((q->windowType() == Qt::Desktop)) //you can't hide the desktop!
return;
QMacCocoaAutoReleasePool pool;
if(q->isWindow()) {
OSWindowRef window = qt_mac_window_for(q);
if(qt_mac_is_macsheet(q)) {
#ifndef QT_MAC_USE_COCOA
WindowRef parent = 0;
if(GetSheetWindowParent(window, &parent) != noErr || !parent)
ShowHide(window, false);
else
HideSheetWindow(window);
#else
[NSApp endSheet:window];
[window orderOut:window];
#endif
} else if(qt_mac_is_macdrawer(q)) {
#ifndef QT_MAC_USE_COCOA
CloseDrawer(window, false);
#else
[qt_mac_drawer_for(q) close];
#endif
} else {
#ifndef QT_MAC_USE_COCOA
ShowHide(window, false);
#else
[window orderOut:window];
// Unfortunately it is not as easy as just hiding the window, we need
// to find out if we were in full screen mode. If we were and this is
// the last window in full screen mode then we need to unset the full screen
// mode. If this is not the last visible window in full screen mode then we
// don't change the full screen mode.
if(q->isFullScreen())
{
bool keepFullScreen = false;
QWidgetList windowList = qApp->topLevelWidgets();
int windowCount = windowList.count();
for(int i = 0; i < windowCount; i++)
{
QWidget *w = windowList[i];
// If it is the same window, we don't need to check :-)
if(q == w)
continue;
// If they are not visible or if they are minimized then
// we just ignore them.
if(!w->isVisible() || w->isMinimized())
continue;
// Is it full screen?
// Notice that if there is one window in full screen mode then we
// cannot switch the full screen mode off, therefore we just abort.
if(w->isFullScreen()) {
keepFullScreen = true;
break;
}
}
// No windows in full screen mode, so let just unset that flag.
if(!keepFullScreen)
qt_mac_set_fullscreen_mode(false);
}
#endif
toggleDrawers(false);
#ifndef QT_MAC_USE_COCOA
// Clear modality (because it seems something that we've always done).
if (data.window_modality != Qt::NonModal) {
SetWindowModality(window, kWindowModalityNone,
q->parentWidget() ? qt_mac_window_for(q->parentWidget()->window()) : 0);
}
#endif
}
if(q->isActiveWindow() && !(q->windowType() == Qt::Popup)) {
QWidget *w = 0;
if(q->parentWidget())
w = q->parentWidget()->window();
if(!w || (!w->isVisible() && !w->isMinimized())) {
#ifndef QT_MAC_USE_COCOA
for (WindowPtr wp = GetFrontWindowOfClass(kMovableModalWindowClass, true);
wp; wp = GetNextWindowOfClass(wp, kMovableModalWindowClass, true)) {
if((w = qt_mac_find_window(wp)))
break;
}
if (!w){
for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true);
wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) {
if((w = qt_mac_find_window(wp)))
break;
}
}
if (!w){
for(WindowPtr wp = GetFrontWindowOfClass(kSimpleWindowClass, true);
wp; wp = GetNextWindowOfClass(wp, kSimpleWindowClass, true)) {
if((w = qt_mac_find_window(wp)))
break;
}
}
#else
NSArray *windows = [NSApp windows];
NSUInteger totalWindows = [windows count];
for (NSUInteger i = 0; i < totalWindows; ++i) {
OSWindowRef wp = [windows objectAtIndex:i];
if ((w = qt_mac_find_window(wp)))
break;
}
#endif
}
if(w && w->isVisible() && !w->isMinimized()) {
#ifndef QT_MAC_USE_COCOA
qt_event_request_activate(w);
#else
[qt_mac_window_for(w) makeKeyWindow];
#endif
}
}
} else {
invalidateBuffer(q->rect());
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), false);
#else
[qt_mac_nativeview_for(q) setHidden:YES];
#endif
}
if (!QWidget::mouseGrabber()){
QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
if (enterWidget && enterWidget->data->in_destructor)
enterWidget = 0;
QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
qt_mouseover = enterWidget;
}
qt_event_request_window_change(q);
deactivateWidgetCleanup();
qt_mac_event_release(q);
}
void QWidget::setWindowState(Qt::WindowStates newstate)
{
Q_D(QWidget);
bool needShow = false;
Qt::WindowStates oldstate = windowState();
if (oldstate == newstate)
return;
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
#endif
bool needSendStateChange = true;
if(isWindow()) {
if((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
if(newstate & Qt::WindowFullScreen) {
if(QTLWExtra *tlextra = d->topData()) {
if(tlextra->normalGeometry.width() < 0) {
if(!testAttribute(Qt::WA_Resized))
adjustSize();
tlextra->normalGeometry = geometry();
}
tlextra->savedFlags = windowFlags();
}
needShow = isVisible();
const QRect fullscreen(qApp->desktop()->screenGeometry(qApp->desktop()->screenNumber(this)));
setParent(parentWidget(), Qt::Window | Qt::FramelessWindowHint | (windowFlags() & 0xffff0000)); //save
setGeometry(fullscreen);
if(!qApp->desktop()->screenNumber(this))
qt_mac_set_fullscreen_mode(true);
} else {
needShow = isVisible();
if(!qApp->desktop()->screenNumber(this))
qt_mac_set_fullscreen_mode(false);
setParent(parentWidget(), d->topData()->savedFlags);
setGeometry(d->topData()->normalGeometry);
d->topData()->normalGeometry.setRect(0, 0, -1, -1);
}
}
d->createWinId();
OSWindowRef window = qt_mac_window_for(this);
if((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
if (newstate & Qt::WindowMinimized) {
#ifndef QT_MAC_USE_COCOA
CollapseWindow(window, true);
#else
[window miniaturize:window];
#endif
} else {
#ifndef QT_MAC_USE_COCOA
CollapseWindow(window, false);
#else
[window deminiaturize:window];
#endif
}
needSendStateChange = oldstate == windowState(); // Collapse didn't change our flags.
}
if((newstate & Qt::WindowMaximized) && !((newstate & Qt::WindowFullScreen))) {
if(QTLWExtra *tlextra = d->topData()) {
if(tlextra->normalGeometry.width() < 0) {
if(!testAttribute(Qt::WA_Resized))
adjustSize();
tlextra->normalGeometry = geometry();
}
}
} else if(!(newstate & Qt::WindowFullScreen)) {
// d->topData()->normalGeometry = QRect(0, 0, -1, -1);
}
#ifdef DEBUG_WINDOW_STATE
#define WSTATE(x) qDebug("%s -- %s --> %s", #x, (oldstate & x) ? "true" : "false", (newstate & x) ? "true" : "false")
WSTATE(Qt::WindowMinimized);
WSTATE(Qt::WindowMaximized);
WSTATE(Qt::WindowFullScreen);
#undef WSTATE
#endif
if(!(newstate & (Qt::WindowMinimized|Qt::WindowFullScreen)) &&
((oldstate & Qt::WindowFullScreen) || (oldstate & Qt::WindowMinimized) ||
(oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized))) {
if(newstate & Qt::WindowMaximized) {
data->fstrut_dirty = true;
#ifndef QT_MAC_USE_COCOA
HIToolbarRef toolbarRef;
if (GetWindowToolbar(window, &toolbarRef) == noErr && toolbarRef
&& !isVisible() && !IsWindowToolbarVisible(window)) {
// HIToolbar, needs to be shown so that it's in the structure window
// Typically this is part of a main window and will get shown
// during the show, but it's will make the maximize all wrong.
ShowHideWindowToolbar(window, true, false);
d->updateFrameStrut(); // In theory the dirty would work, but it's optimized out if the window is not visible :(
}
Rect bounds;
QDesktopWidget *dsk = QApplication::desktop();
QRect avail = dsk->availableGeometry(dsk->screenNumber(this));
SetRect(&bounds, avail.x(), avail.y(), avail.x() + avail.width(), avail.y() + avail.height());
if(QWExtra *extra = d->extraData()) {
if(bounds.right - bounds.left > extra->maxw)
bounds.right = bounds.left + extra->maxw;
if(bounds.bottom - bounds.top > extra->maxh)
bounds.bottom = bounds.top + extra->maxh;
}
if(d->topData()) {
QRect fs = d->frameStrut();
bounds.left += fs.left();
if(bounds.right < avail.x()+avail.width())
bounds.right = qMin<short>((uint)avail.x()+avail.width(), bounds.right+fs.left());
if(bounds.bottom < avail.y()+avail.height())
bounds.bottom = qMin<short>((uint)avail.y()+avail.height(), bounds.bottom+fs.top());
bounds.top += fs.top();
bounds.right -= fs.right();
bounds.bottom -= fs.bottom();
}
QRect orect(geometry().x(), geometry().y(), width(), height()),
nrect(bounds.left, bounds.top, bounds.right - bounds.left,
bounds.bottom - bounds.top);
if(orect != nrect) { // the new rect differ from the old
Point idealSize = { nrect.height(), nrect.width() };
ZoomWindowIdeal(window, inZoomOut, &idealSize);
}
#else
NSToolbar *toolbarRef = [window toolbar];
if (toolbarRef && !isVisible() && ![toolbarRef isVisible]) {
// HIToolbar, needs to be shown so that it's in the structure window
// Typically this is part of a main window and will get shown
// during the show, but it's will make the maximize all wrong.
// ### Not sure this is right for NSToolbar...
[toolbarRef setVisible:true];
// ShowHideWindowToolbar(window, true, false);
d->updateFrameStrut(); // In theory the dirty would work, but it's optimized out if the window is not visible :(
}
// Everything should be handled by Cocoa.
[window zoom:window];
#endif
needSendStateChange = oldstate == windowState(); // Zoom didn't change flags.
} else if(oldstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen)) {
#ifndef QT_MAC_USE_COCOA
Point idealSize;
ZoomWindowIdeal(window, inZoomIn, &idealSize);
#else
[window zoom:window];
#endif
if(QTLWExtra *tlextra = d->topData()) {
setGeometry(tlextra->normalGeometry);
tlextra->normalGeometry.setRect(0, 0, -1, -1);
}
}
}
}
data->window_state = newstate;
if(needShow)
show();
if(newstate & Qt::WindowActive)
activateWindow();
qt_event_request_window_change(this);
if (needSendStateChange) {
QWindowStateChangeEvent e(oldstate);
QApplication::sendEvent(this, &e);
}
}
void QWidgetPrivate::setFocus_sys()
{
Q_Q(QWidget);
if (q->testAttribute(Qt::WA_WState_Created)) {
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
NSView *view = qt_mac_nativeview_for(q);
[[view window] makeFirstResponder:view];
#else
SetKeyboardFocus(qt_mac_window_for(q), qt_mac_nativeview_for(q), 1);
#endif
}
}
NSComparisonResult compareViews2Raise(id view1, id view2, void *context)
{
id topView = reinterpret_cast<id>(context);
if (view1 == topView)
return NSOrderedDescending;
if (view2 == topView)
return NSOrderedAscending;
return NSOrderedSame;
}
void QWidgetPrivate::raise_sys()
{
Q_Q(QWidget);
if((q->windowType() == Qt::Desktop))
return;
#if QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
if (isRealWindow()) {
// Calling orderFront shows the window on Cocoa too.
if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) {
[qt_mac_window_for(q) orderFront:qt_mac_window_for(q)];
}
if (qt_mac_raise_process) { //we get to be the active process now
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly);
}
} else {
NSView *view = qt_mac_nativeview_for(q);
NSView *parentView = [view superview];
[parentView sortSubviewsUsingFunction:compareViews2Raise context:reinterpret_cast<void *>(view)];
}
#else
if(q->isWindow()) {
//raise this window
BringToFront(qt_mac_window_for(q));
if(qt_mac_raise_process) { //we get to be the active process now
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly);
}
} else if(q->parentWidget()) {
HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderAbove, 0);
qt_event_request_window_change(q);
}
#endif
}
NSComparisonResult compareViews2Lower(id view1, id view2, void *context)
{
id topView = reinterpret_cast<id>(context);
if (view1 == topView)
return NSOrderedAscending;
if (view2 == topView)
return NSOrderedDescending;
return NSOrderedSame;
}
void QWidgetPrivate::lower_sys()
{
Q_Q(QWidget);
if((q->windowType() == Qt::Desktop))
return;
#ifdef QT_MAC_USE_COCOA
if (isRealWindow()) {
OSWindowRef window = qt_mac_window_for(q);
[window orderBack:window];
} else {
NSView *view = qt_mac_nativeview_for(q);
NSView *parentView = [view superview];
[parentView sortSubviewsUsingFunction:compareViews2Lower context:reinterpret_cast<void *>(view)];
}
#else
if(q->isWindow()) {
SendBehind(qt_mac_window_for(q), 0);
} else if(q->parentWidget()) {
invalidateBuffer(q->rect());
HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderBelow, 0);
qt_event_request_window_change(q);
}
#endif
}
NSComparisonResult compareViews2StackUnder(id view1, id view2, void *context)
{
const QHash<NSView *, int> &viewOrder = *reinterpret_cast<QHash<NSView *, int> *>(context);
if (viewOrder[view1] < viewOrder[view2])
return NSOrderedAscending;
if (viewOrder[view1] > viewOrder[view2])
return NSOrderedDescending;
return NSOrderedSame;
}
void QWidgetPrivate::stackUnder_sys(QWidget *w)
{
// stackUnder
Q_Q(QWidget);
if(!w || q->isWindow() || (q->windowType() == Qt::Desktop))
return;
#ifdef QT_MAC_USE_COCOA
// Do the same trick as lower_sys() and put this widget before the widget passed in.
NSView *myView = qt_mac_nativeview_for(q);
NSView *wView = qt_mac_nativeview_for(w);
QHash<NSView *, int> viewOrder;
NSView *parentView = [myView superview];
NSArray *subviews = [parentView subviews];
NSUInteger index = 1;
// make a hash of view->zorderindex and make sure z-value is always odd,
// so that when we modify the order we create a new (even) z-value which
// will not interfere with others.
for (NSView *subview in subviews) {
viewOrder.insert(subview, index * 2);
++index;
}
viewOrder[myView] = viewOrder[wView] - 1;
[parentView sortSubviewsUsingFunction:compareViews2StackUnder context:reinterpret_cast<void *>(&viewOrder)];
#else
QWidget *p = q->parentWidget();
if(!p || p != w->parentWidget())
return;
invalidateBuffer(q->rect());
HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderBelow, qt_mac_nativeview_for(w));
qt_event_request_window_change(q);
#endif
}
/*
Modifies the bounds for a widgets backing HIView during moves and resizes. Also updates the
widget, either by scrolling its contents or repainting, depending on the WA_StaticContents
flag
*/
static void qt_mac_update_widget_posisiton(QWidget *q, QRect oldRect, QRect newRect)
{
#ifndef QT_MAC_USE_COCOA
HIRect bounds = CGRectMake(newRect.x(), newRect.y(),
newRect.width(), newRect.height());
const HIViewRef view = qt_mac_nativeview_for(q);
const bool isMove = (oldRect.topLeft() != newRect.topLeft());
const bool isResize = (oldRect.size() != newRect.size());
// qDebug() << oldRect << newRect << isMove << isResize << q->testAttribute(Qt::WA_OpaquePaintEvent) << q->testAttribute(Qt::WA_StaticContents);
QWidgetPrivate *qd = qt_widget_private(q);
// Perform a normal (complete repaint) update in some cases:
if (
// always repaint on move.
(isMove) ||
// limited update on resize requires WA_StaticContents.
(isResize && q->testAttribute(Qt::WA_StaticContents) == false) ||
// one of the rects are invalid
(oldRect.isValid() == false || newRect.isValid() == false) ||
// the position update is a part of a drag-and-drop operation
QDragManager::self()->object ||
// we are on Panther (no HIViewSetNeedsDisplayInRect)
QSysInfo::MacintoshVersion < QSysInfo::MV_10_4
){
HIViewSetFrame(view, &bounds);
return;
}
const int dx = newRect.x() - oldRect.x();
const int dy = newRect.y() - oldRect.y();
if (isMove) {
// HIViewScrollRect silently fails if we try to scroll anything under the grow box.
// Check if there's one present within the widget rect, and if there is fall back
// to repainting the entire widget.
QWidget const * const parentWidget = q->parentWidget();
const HIViewRef parentView = qt_mac_nativeview_for(parentWidget);
HIViewRef nativeSizeGrip = 0;
if (q->testAttribute(Qt::WA_WState_Created))
HIViewFindByID(HIViewGetRoot(HIViewGetWindow(HIViewRef(q->winId()))), kHIViewWindowGrowBoxID, &nativeSizeGrip);
if (nativeSizeGrip) {
QWidget * const window = q->window();
const int sizeGripSize = 20;
const QRect oldWidgetRect = QRect(q->mapTo(window, QPoint(0, 0)), QSize(oldRect.width(), oldRect.height()));
const QRect newWidgetRect = QRect(q->mapTo(window, QPoint(0, 0)), QSize(newRect.width(), newRect.height()));
const QRect sizeGripRect = QRect(window->rect().bottomRight() - QPoint(sizeGripSize, sizeGripSize),
window->rect().bottomRight());
if (sizeGripRect.intersects(oldWidgetRect) || sizeGripRect.intersects(newWidgetRect)) {
HIViewSetFrame(view, &bounds);
return;
}
}
// Don't scroll anything outside the parent widget rect.
const QRect scrollRect = (oldRect | newRect) & parentWidget->rect();
const HIRect scrollBounds =
CGRectMake(scrollRect.x(), scrollRect.y(), scrollRect.width(), scrollRect.height());
// We cannot scroll when the widget has a mask as that would
// scroll the masked out areas too
if (qd->extra && qd->extra->hasMask) {
HIViewMoveBy(view, dx, dy);
return;
}
OSStatus err = HIViewScrollRect(parentView, &scrollBounds, dx, dy);
if (err != noErr) {
HIViewSetNeedsDisplay(view, true);
qWarning("QWidget: Internal error (%s:%d)", __FILE__, __LINE__);
}
}
// Set the view bounds with drawing disabled to prevent repaints.
HIViewSetDrawingEnabled(view, false);
HIViewSetFrame(view, &bounds);
HIViewSetDrawingEnabled(view, true);
// Update any newly exposed areas due to resizing.
const int startx = oldRect.width();
const int stopx = newRect.width();
const int starty = oldRect.height();
const int stopy = newRect.height();
const HIRect verticalSlice = CGRectMake(startx, 0, stopx , stopy);
HIViewSetNeedsDisplayInRect(view, &verticalSlice, true);
const HIRect horizontalSlice = CGRectMake(0, starty, startx, stopy);
HIViewSetNeedsDisplayInRect(view, &horizontalSlice, true);
#else
Q_UNUSED(oldRect);
NSRect bounds = NSMakeRect(newRect.x(), newRect.y(),
newRect.width(), newRect.height());
[qt_mac_nativeview_for(q) setFrame:bounds];
#endif
}
/*
Helper function for non-toplevel widgets. Helps to map Qt's 32bit
coordinate system to OS X's 16bit coordinate system.
Sets the geometry of the widget to data.crect, but clipped to sizes
that OS X can handle. Unmaps widgets that are completely outside the
valid range.
Maintains data.wrect, which is the geometry of the OS X widget,
measured in this widget's coordinate system.
if the parent is not clipped, parentWRect is empty, otherwise
parentWRect is the geometry of the parent's OS X rect, measured in
parent's coord sys
*/
void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
{
Q_Q(QWidget);
Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
Q_UNUSED(oldRect);
/*
There are up to four different coordinate systems here:
Qt coordinate system for this widget.
X coordinate system for this widget (relative to wrect).
Qt coordinate system for parent
X coordinate system for parent (relative to parent's wrect).
*/
QRect wrect;
//xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys)
QRect xrect = data.crect;
QRect parentWRect;
if (q->isWindow() && topData()->embedded) {
#ifndef QT_MAC_USE_COCOA
HIViewRef parentView = HIViewGetSuperview(qt_mac_nativeview_for(q));
#else
NSView *parentView = [qt_mac_nativeview_for(q) superview];
#endif
if (parentView) {
#ifndef QT_MAC_USE_COCOA
HIRect tmpRect;
HIViewGetFrame(parentView, &tmpRect);
#else
NSRect tmpRect = [parentView frame];
#endif
parentWRect = QRect(tmpRect.origin.x, tmpRect.origin.y,
tmpRect.size.width, tmpRect.size.height);
} else {
const QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
parentWRect = wrectRange;
}
} else {
parentWRect = q->parentWidget()->data->wrect;
}
if (parentWRect.isValid()) {
// parent is clipped, and we have to clip to the same limit as parent
if (!parentWRect.contains(xrect)) {
xrect &= parentWRect;
wrect = xrect;
//translate from parent's to my Qt coord sys
wrect.translate(-data.crect.topLeft());
}
//translate from parent's Qt coords to parent's X coords
xrect.translate(-parentWRect.topLeft());
} else {
// parent is not clipped, we may or may not have to clip
if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
// This is where the main optimization is: we are already
// clipped, and if our clip is still valid, we can just
// move our window, and do not need to move or clip
// children
QRect vrect = xrect & q->parentWidget()->rect();
vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
if (data.wrect.contains(vrect)) {
xrect = data.wrect;
xrect.translate(data.crect.topLeft());
#ifndef QT_MAC_USE_COCOA
HIRect bounds = CGRectMake(xrect.x(), xrect.y(),
xrect.width(), xrect.height());
HIViewSetFrame(qt_mac_nativeview_for(q), &bounds);
#else
NSRect bounds = NSMakeRect(xrect.x(), xrect.y(),
xrect.width(), xrect.height());
[qt_mac_nativeview_for(q) setFrame:bounds];
#endif
if (q->testAttribute(Qt::WA_OutsideWSRange)) {
q->setAttribute(Qt::WA_OutsideWSRange, false);
if (!dontShow) {
q->setAttribute(Qt::WA_Mapped);
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
[qt_mac_nativeview_for(q) setHidden:NO];
#endif
}
}
return;
}
}
const QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
if (!validRange.contains(xrect)) {
// we are too big, and must clip
QPoint screenOffset(0, 0); // offset of the part being on screen
const QWidget *parentWidget = q->parentWidget();
while (parentWidget && !parentWidget->isWindow()) {
screenOffset -= parentWidget->data->crect.topLeft();
parentWidget = parentWidget->parentWidget();
}
QRect cropRect(screenOffset.x() - WRECT_MAX,
screenOffset.y() - WRECT_MAX,
2*WRECT_MAX,
2*WRECT_MAX);
xrect &=cropRect;
wrect = xrect;
wrect.translate(-data.crect.topLeft()); // translate wrect in my Qt coordinates
}
}
// unmap if we are outside the valid window system coord system
bool outsideRange = !xrect.isValid();
bool mapWindow = false;
if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
if (outsideRange) {
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), false);
#else
[qt_mac_nativeview_for(q) setHidden:YES];
#endif
q->setAttribute(Qt::WA_Mapped, false);
} else if (!q->isHidden()) {
mapWindow = true;
}
}
if (outsideRange)
return;
bool jump = (data.wrect != wrect);
data.wrect = wrect;
// and now recursively for all children...
// ### can be optimized
for (int i = 0; i < children.size(); ++i) {
QObject *object = children.at(i);
if (object->isWidgetType()) {
QWidget *w = static_cast<QWidget *>(object);
if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
w->d_func()->setWSGeometry();
}
}
qt_mac_update_widget_posisiton(q, oldRect, xrect);
if (jump)
q->update();
if (mapWindow && !dontShow) {
q->setAttribute(Qt::WA_Mapped);
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
[qt_mac_nativeview_for(q) setHidden:NO];
#endif
}
}
void QWidgetPrivate::adjustWithinMaxAndMinSize(int &w, int &h)
{
if (QWExtra *extra = extraData()) {
w = qMin(w, extra->maxw);
h = qMin(h, extra->maxh);
w = qMax(w, extra->minw);
h = qMax(h, extra->minh);
// Deal with size increment
if (QTLWExtra *top = topData()) {
if(top->incw) {
w = w/top->incw;
w *= top->incw;
}
if(top->inch) {
h = h/top->inch;
h *= top->inch;
}
}
}
if (isRealWindow()) {
w = qMax(0, w);
h = qMax(0, h);
}
}
void QWidgetPrivate::applyMaxAndMinSizeOnWindow()
{
Q_Q(QWidget);
const float max_f(20000);
#ifndef QT_MAC_USE_COCOA
#define SF(x) ((x > max_f) ? max_f : x)
HISize max = CGSizeMake(SF(extra->maxw), SF(extra->maxh));
HISize min = CGSizeMake(SF(extra->minw), SF(extra->minh));
#undef SF
SetWindowResizeLimits(qt_mac_window_for(q), &min, &max);
#else
#define SF(x) ((x > max_f) ? max_f : x)
NSSize max = NSMakeSize(SF(extra->maxw), SF(extra->maxh));
NSSize min = NSMakeSize(SF(extra->minw), SF(extra->minh));
#undef SF
[qt_mac_window_for(q) setContentMinSize:min];
[qt_mac_window_for(q) setContentMaxSize:max];
#endif
}
void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
{
Q_Q(QWidget);
Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
if(q->windowType() == Qt::Desktop)
return;
QMacCocoaAutoReleasePool pool;
bool realWindow = isRealWindow();
if (realWindow && !q->testAttribute(Qt::WA_DontShowOnScreen)){
adjustWithinMaxAndMinSize(w, h);
#ifndef QT_MAC_USE_COCOA
if (w != 0 && h != 0) {
topData()->isSetGeometry = 1;
topData()->isMove = isMove;
Rect r; SetRect(&r, x, y, x + w, y + h);
SetWindowBounds(qt_mac_window_for(q), kWindowContentRgn, &r);
topData()->isSetGeometry = 0;
} else {
setGeometry_sys_helper(x, y, w, h, isMove);
}
#else
QSize olds = q->size();
const bool isResize = (olds != QSize(w, h));
NSWindow *window = qt_mac_window_for(q);
const QRect &fStrut = frameStrut();
const QRect frameRect(QPoint(x - fStrut.left(), y - fStrut.top()),
QSize(fStrut.left() + fStrut.right() + w,
fStrut.top() + fStrut.bottom() + h));
NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1),
frameRect.width(), frameRect.height());
// The setFrame call will trigger a 'windowDidResize' notification for the corresponding
// NSWindow. The pending flag is set, so that the resize event can be send as non-spontaneous.
if (isResize)
q->setAttribute(Qt::WA_PendingResizeEvent);
QPoint currTopLeft = data.crect.topLeft();
if (currTopLeft.x() == x && currTopLeft.y() == y
&& cocoaFrameRect.size.width != 0
&& cocoaFrameRect.size.height != 0) {
[window setFrame:cocoaFrameRect display:NO];
} else {
// The window is moved and resized (or resized to zero).
// Since Cocoa usually only sends us a resize callback after
// setting a window frame, we issue an explicit move as
// well. To stop Cocoa from optimize away the move (since the move
// would have the same origin as the setFrame call) we shift the
// window back and forth inbetween.
cocoaFrameRect.origin.y += 1;
[window setFrame:cocoaFrameRect display:NO];
cocoaFrameRect.origin.y -= 1;
[window setFrameOrigin:cocoaFrameRect.origin];
}
#endif
} else {
setGeometry_sys_helper(x, y, w, h, isMove);
}
}
void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isMove)
{
Q_Q(QWidget);
bool realWindow = isRealWindow();
QPoint oldp = q->pos();
QSize olds = q->size();
const bool isResize = (olds != QSize(w, h));
if (!realWindow && !isResize && QPoint(x, y) == oldp)
return;
if (isResize)
data.window_state = data.window_state & ~Qt::WindowMaximized;
const bool visible = q->isVisible();
data.crect = QRect(x, y, w, h);
if (realWindow) {
adjustWithinMaxAndMinSize(w, h);
qt_mac_update_sizer(q);
#ifndef QT_MAC_USE_COCOA
if (q->windowFlags() & Qt::WindowMaximizeButtonHint) {
OSWindowRef window = qt_mac_window_for(q);
if (extra->maxw && extra->maxh && extra->maxw == extra->minw
&& extra->maxh == extra->minh) {
ChangeWindowAttributes(window, kWindowNoAttributes, kWindowFullZoomAttribute);
} else {
ChangeWindowAttributes(window, kWindowFullZoomAttribute, kWindowNoAttributes);
}
}
HIRect bounds = CGRectMake(0, 0, w, h);
HIViewSetFrame(qt_mac_nativeview_for(q), &bounds);
#else
[qt_mac_nativeview_for(q) setFrame:NSMakeRect(0, 0, w, h)];
#endif
} else {
const QRect oldRect(oldp, olds);
if (!isResize && QApplicationPrivate::graphicsSystem())
moveRect(oldRect, x - oldp.x(), y - oldp.y());
setWSGeometry(false, oldRect);
if (isResize && QApplicationPrivate::graphicsSystem()) {
invalidateBuffer(q->rect());
if (extra && !graphicsEffect && !extra->mask.isEmpty()) {
QRegion oldRegion(extra->mask.translated(oldp));
oldRegion &= oldRect;
q->parentWidget()->d_func()->invalidateBuffer(oldRegion);
} else {
q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(oldRect));
}
}
}
if(isMove || isResize) {
if(!visible) {
if(isMove && q->pos() != oldp)
q->setAttribute(Qt::WA_PendingMoveEvent, true);
if(isResize)
q->setAttribute(Qt::WA_PendingResizeEvent, true);
} else {
if(isResize) { //send the resize event..
QResizeEvent e(q->size(), olds);
QApplication::sendEvent(q, &e);
}
if(isMove && q->pos() != oldp) { //send the move event..
QMoveEvent e(q->pos(), oldp);
QApplication::sendEvent(q, &e);
}
}
}
qt_event_request_window_change(q);
}
void QWidgetPrivate::setConstraints_sys()
{
updateMaximizeButton_sys();
applyMaxAndMinSizeOnWindow();
}
void QWidgetPrivate::updateMaximizeButton_sys()
{
Q_Q(QWidget);
if (q->data->window_flags & Qt::CustomizeWindowHint)
return;
OSWindowRef window = qt_mac_window_for(q);
QTLWExtra * tlwExtra = topData();
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
NSButton *maximizeButton = [window standardWindowButton:NSWindowZoomButton];
#endif
if (extra->maxw && extra->maxh
&& extra->maxw == extra->minw
&& extra->maxh == extra->minh) {
// The window has a fixed size, so gray out the maximize button:
if (!tlwExtra->savedWindowAttributesFromMaximized) {
#ifndef QT_MAC_USE_COCOA
GetWindowAttributes(window,
(WindowAttributes*)&extra->topextra->savedWindowAttributesFromMaximized);
#else
tlwExtra->savedWindowAttributesFromMaximized = (![maximizeButton isHidden] && [maximizeButton isEnabled]);
#endif
}
#ifndef QT_MAC_USE_COCOA
ChangeWindowAttributes(window, kWindowNoAttributes, kWindowFullZoomAttribute);
#else
[maximizeButton setEnabled:NO];
#endif
} else {
if (tlwExtra->savedWindowAttributesFromMaximized) {
#ifndef QT_MAC_USE_COCOA
ChangeWindowAttributes(window,
extra->topextra->savedWindowAttributesFromMaximized,
kWindowNoAttributes);
#else
[maximizeButton setEnabled:YES];
#endif
tlwExtra->savedWindowAttributesFromMaximized = 0;
}
}
}
void QWidgetPrivate::scroll_sys(int dx, int dy)
{
if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
scrollChildren(dx, dy);
scrollRect(q_func()->rect(), dx, dy);
} else {
scroll_sys(dx, dy, QRect());
}
}
void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
{
Q_Q(QWidget);
if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
scrollRect(r, dx, dy);
return;
}
const bool valid_rect = r.isValid();
if (!q->updatesEnabled() && (valid_rect || q->children().isEmpty()))
return;
qt_event_request_window_change(q);
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
#endif
if(!valid_rect) { // scroll children
QPoint pd(dx, dy);
QWidgetList moved;
QObjectList chldrn = q->children();
for(int i = 0; i < chldrn.size(); i++) { //first move all children
QObject *obj = chldrn.at(i);
if(obj->isWidgetType()) {
QWidget *w = (QWidget*)obj;
if(!w->isWindow()) {
w->data->crect = QRect(w->pos() + pd, w->size());
if (w->testAttribute(Qt::WA_WState_Created)) {
#ifndef QT_MAC_USE_COCOA
HIRect bounds = CGRectMake(w->data->crect.x(), w->data->crect.y(),
w->data->crect.width(), w->data->crect.height());
HIViewRef hiview = qt_mac_nativeview_for(w);
const bool opaque = q->testAttribute(Qt::WA_OpaquePaintEvent);
if (opaque)
HIViewSetDrawingEnabled(hiview, false);
HIViewSetFrame(hiview, &bounds);
if (opaque)
HIViewSetDrawingEnabled(hiview, true);
#else
[qt_mac_nativeview_for(w)
setFrame:NSMakeRect(w->data->crect.x(), w->data->crect.y(),
w->data->crect.width(), w->data->crect.height())];
#endif
}
moved.append(w);
}
}
}
//now send move events (do not do this in the above loop, breaks QAquaFocusWidget)
for(int i = 0; i < moved.size(); i++) {
QWidget *w = moved.at(i);
QMoveEvent e(w->pos(), w->pos() - pd);
QApplication::sendEvent(w, &e);
}
}
if (!q->testAttribute(Qt::WA_WState_Created) || !q->isVisible())
return;
OSViewRef view = qt_mac_nativeview_for(q);
#ifndef QT_MAC_USE_COCOA
HIRect scrollrect = CGRectMake(r.x(), r.y(), r.width(), r.height());
OSStatus err = _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
if (err) {
// The only parameter that can go wrong, is the rect.
qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect");
scrollrect = CGRectMake(qMax(r.x(), 0), qMax(r.y(), 0),
qMin(r.width(), q->width()), qMin(r.height(), q->height()));
_HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
}
#else
NSRect scrollRect = valid_rect ? NSMakeRect(r.x(), r.y(), r.width(), r.height())
: NSMakeRect(0, 0, q->width(), q->height());
// calc the updateRect
NSRect deltaXRect = { {0, 0}, {0, 0} };
NSRect deltaYRect = { {0, 0}, {0, 0} };
if (dy != 0) {
deltaYRect.size.width = scrollRect.size.width;
if (dy > 0) {
deltaYRect.size.height = dy;
} else {
deltaYRect.size.height = -dy;
deltaYRect.origin.y = scrollRect.size.height + dy;
}
}
if (dx != 0) {
deltaXRect.size.height = scrollRect.size.height;
if (dx > 0) {
deltaXRect.size.width = dx;
} else {
deltaXRect.size.width = -dx;
deltaXRect.origin.x = scrollRect.size.width + dx;
}
}
// ### Scroll the dirty regions as well, the following is not correct.
QRegion displayRegion = r.isNull() ? dirtyOnWidget : (dirtyOnWidget & r);
const QVector<QRect> &rects = dirtyOnWidget.rects();
const QVector<QRect>::const_iterator end = rects.end();
QVector<QRect>::const_iterator it = rects.begin();
while (it != end) {
const QRect rect = *it;
const NSRect dirtyRect = NSMakeRect(rect.x() + dx, rect.y() + dy,
rect.width(), rect.height());
[view setNeedsDisplayInRect:dirtyRect];
++it;
}
NSSize deltaSize = NSMakeSize(dx, dy);
[view scrollRect:scrollRect by:deltaSize];
[view setNeedsDisplayInRect:deltaXRect];
[view setNeedsDisplayInRect:deltaYRect];
#endif // QT_MAC_USE_COCOA
}
int QWidget::metric(PaintDeviceMetric m) const
{
switch(m) {
case PdmHeightMM:
return qRound(metric(PdmHeight) * 25.4 / qreal(metric(PdmDpiY)));
case PdmWidthMM:
return qRound(metric(PdmWidth) * 25.4 / qreal(metric(PdmDpiX)));
case PdmHeight:
case PdmWidth: {
#ifndef QT_MAC_USE_COCOA
HIRect rect;
HIViewGetFrame(qt_mac_nativeview_for(this), &rect);
#else
NSRect rect = [qt_mac_nativeview_for(this) frame];
#endif
if(m == PdmWidth)
return (int)rect.size.width;
return (int)rect.size.height; }
case PdmDepth:
return 32;
case PdmNumColors:
return INT_MAX;
case PdmDpiX:
case PdmPhysicalDpiX: {
Q_D(const QWidget);
if (d->extra && d->extra->customDpiX)
return d->extra->customDpiX;
else if (d->parent)
return static_cast<QWidget *>(d->parent)->metric(m);
extern float qt_mac_defaultDpi_x(); //qpaintdevice_mac.cpp
return int(qt_mac_defaultDpi_x()); }
case PdmDpiY:
case PdmPhysicalDpiY: {
Q_D(const QWidget);
if (d->extra && d->extra->customDpiY)
return d->extra->customDpiY;
else if (d->parent)
return static_cast<QWidget *>(d->parent)->metric(m);
extern float qt_mac_defaultDpi_y(); //qpaintdevice_mac.cpp
return int(qt_mac_defaultDpi_y()); }
default: //leave this so the compiler complains when new ones are added
qWarning("QWidget::metric: Unhandled parameter %d", m);
return QPaintDevice::metric(m);
}
return 0;
}
void QWidgetPrivate::createSysExtra()
{
#ifdef QT_MAC_USE_COCOA
extra->imageMask = 0;
#endif
}
void QWidgetPrivate::deleteSysExtra()
{
#ifdef QT_MAC_USE_COCOA
if (extra->imageMask)
CFRelease(extra->imageMask);
#endif
}
void QWidgetPrivate::createTLSysExtra()
{
extra->topextra->resizer = 0;
extra->topextra->isSetGeometry = 0;
extra->topextra->isMove = 0;
extra->topextra->wattr = 0;
extra->topextra->wclass = 0;
extra->topextra->group = 0;
extra->topextra->windowIcon = 0;
extra->topextra->savedWindowAttributesFromMaximized = 0;
}
void QWidgetPrivate::deleteTLSysExtra()
{
#ifndef QT_MAC_USE_COCOA
if (extra->topextra->group) {
qt_mac_release_window_group(extra->topextra->group);
extra->topextra->group = 0;
}
if (extra->topextra->windowIcon) {
ReleaseIconRef(extra->topextra->windowIcon);
extra->topextra->windowIcon = 0;
}
#endif
}
void QWidgetPrivate::updateFrameStrut()
{
Q_Q(QWidget);
QWidgetPrivate *that = const_cast<QWidgetPrivate*>(this);
that->data.fstrut_dirty = false;
QTLWExtra *top = that->topData();
#if QT_MAC_USE_COCOA
// 1 Get the window frame
OSWindowRef oswnd = qt_mac_window_for(q);
NSRect frameW = [oswnd frame];
// 2 Get the content frame - so now
NSRect frameC = [oswnd contentRectForFrameRect:frameW];
top->frameStrut.setCoords(frameC.origin.x - frameW.origin.x,
(frameW.origin.y + frameW.size.height) - (frameC.origin.y + frameC.size.height),
(frameW.origin.x + frameW.size.width) - (frameC.origin.x + frameC.size.width),
frameC.origin.y - frameW.origin.y);
#else
Rect window_r;
GetWindowStructureWidths(qt_mac_window_for(q), &window_r);
top->frameStrut.setCoords(window_r.left, window_r.top, window_r.right, window_r.bottom);
#endif
}
void QWidgetPrivate::registerDropSite(bool on)
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created))
return;
#ifndef QT_MAC_USE_COCOA
SetControlDragTrackingEnabled(qt_mac_nativeview_for(q), on);
#else
NSView *view = qt_mac_nativeview_for(q);
if (on && [view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
[static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) registerDragTypes];
}
#endif
}
void QWidgetPrivate::registerTouchWindow()
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6)
return;
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created))
return;
#ifndef QT_MAC_USE_COCOA
// Needs implementation!
#else
NSView *view = qt_mac_nativeview_for(q);
[view setAcceptsTouchEvents:YES];
#endif
#endif
}
void QWidgetPrivate::setMask_sys(const QRegion ®ion)
{
Q_UNUSED(region);
#ifndef QT_MAC_USE_COCOA
Q_Q(QWidget);
if (q->isWindow())
ReshapeCustomWindow(qt_mac_window_for(q));
else
HIViewReshapeStructure(qt_mac_nativeview_for(q));
#else
if (extra->mask.isEmpty()) {
extra->maskBits = QImage();
finishCocoaMaskSetup();
} else {
syncCocoaMask();
}
#endif
}
void QWidgetPrivate::setWindowOpacity_sys(qreal level)
{
Q_Q(QWidget);
if (!q->isWindow())
return;
level = qBound(0.0, level, 1.0);
topData()->opacity = (uchar)(level * 255);
if (!q->testAttribute(Qt::WA_WState_Created))
return;
OSWindowRef oswindow = qt_mac_window_for(q);
#if QT_MAC_USE_COCOA
[oswindow setAlphaValue:level];
#else
SetWindowAlpha(oswindow, level);
#endif
}
#ifdef QT_MAC_USE_COCOA
void QWidgetPrivate::syncCocoaMask()
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created) || !extra)
return;
if (extra->hasMask) {
if(extra->maskBits.size() != q->size()) {
extra->maskBits = QImage(q->size(), QImage::Format_Mono);
}
extra->maskBits.fill(QColor(Qt::color1).rgba());
extra->maskBits.setNumColors(2);
extra->maskBits.setColor(0, QColor(Qt::color0).rgba());
extra->maskBits.setColor(1, QColor(Qt::color1).rgba());
QPainter painter(&extra->maskBits);
painter.setBrush(Qt::color1);
painter.setPen(Qt::NoPen);
painter.drawRects(extra->mask.rects());
painter.end();
finishCocoaMaskSetup();
}
}
void QWidgetPrivate::finishCocoaMaskSetup()
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created) || !extra)
return;
// Technically this is too late to release, because the data behind the image
// has already been released. But it's more tidy to do it here.
// If you are seeing a crash, consider doing a CFRelease before changing extra->maskBits.
if (extra->imageMask) {
CFRelease(extra->imageMask);
extra->imageMask = 0;
}
if (!extra->maskBits.isNull()) {
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(0,
extra->maskBits.bits(),
extra->maskBits.numBytes(),
0); // shouldn't need to release.
CGFloat decode[2] = {1, 0};
extra->imageMask = CGImageMaskCreate(extra->maskBits.width(), extra->maskBits.height(),
1, 1, extra->maskBits.bytesPerLine(), dataProvider,
decode, false);
}
if (q->isWindow()) {
NSWindow *window = qt_mac_window_for(q);
[window setOpaque:(extra->imageMask == 0)];
[window invalidateShadow];
}
[qt_mac_nativeview_for(q) setNeedsDisplay:YES];
}
#endif
struct QPaintEngineCleanupHandler
{
inline QPaintEngineCleanupHandler() : engine(0) {}
inline ~QPaintEngineCleanupHandler() { delete engine; }
QPaintEngine *engine;
};
Q_GLOBAL_STATIC(QPaintEngineCleanupHandler, engineHandler)
QPaintEngine *QWidget::paintEngine() const
{
QPaintEngine *&pe = engineHandler()->engine;
if (!pe)
pe = new QCoreGraphicsPaintEngine();
if (pe->isActive()) {
QPaintEngine *engine = new QCoreGraphicsPaintEngine();
engine->setAutoDestruct(true);
return engine;
}
return pe;
}
void QWidgetPrivate::setModal_sys()
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
return;
const QWidget * const windowParent = q->window()->parentWidget();
const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0;
OSWindowRef windowRef = qt_mac_window_for(q);
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
bool alreadySheet = [windowRef styleMask] & NSDocModalWindowMask;
if (windowParent && q->windowModality() == Qt::WindowModal){
// Window should be window-modal, which implies a sheet.
if (!alreadySheet) {
// NB: the following call will call setModal_sys recursivly:
recreateMacWindow();
windowRef = qt_mac_window_for(q);
}
if ([windowRef isKindOfClass:[NSPanel class]]){
// If the primary window of the sheet parent is a child of a modal dialog,
// the sheet parent should not be modally shaddowed.
// This goes for the sheet as well:
OSWindowRef ref = primaryWindow ? qt_mac_window_for(primaryWindow) : 0;
bool isDialog = ref ? [ref isKindOfClass:[NSPanel class]] : false;
bool worksWhenModal = isDialog ? [static_cast<NSPanel *>(ref) worksWhenModal] : false;
if (worksWhenModal)
[static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES];
}
} else {
// Window shold not be window-modal, and as such, not a sheet.
if (alreadySheet){
// NB: the following call will call setModal_sys recursivly:
recreateMacWindow();
windowRef = qt_mac_window_for(q);
}
if (q->windowModality() == Qt::ApplicationModal) {
[windowRef setLevel:NSModalPanelWindowLevel];
} else if (primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) {
// INVARIANT: Our window is a dialog that has a dialog parent that is
// application modal, or . This means that q is supposed to be on top of this
// dialog and not be modally shaddowed:
[windowRef setLevel:NSModalPanelWindowLevel];
if ([windowRef isKindOfClass:[NSPanel class]])
[static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES];
} else {
// INVARIANT: q should not be modal.
NSInteger winLevel = -1;
if (q->windowType() == Qt::Popup) {
winLevel = NSPopUpMenuWindowLevel;
// Popup should be in at least the same level as its parent.
if (primaryWindow) {
OSWindowRef parentRef = qt_mac_window_for(primaryWindow);
winLevel = qMax([parentRef level], winLevel);
}
} else if (q->windowType() == Qt::Tool) {
winLevel = NSFloatingWindowLevel;
} else if (q->windowType() == Qt::Dialog) {
winLevel = NSModalPanelWindowLevel;
}
// StayOnTop window should appear above Tool windows.
if (data.window_flags & Qt::WindowStaysOnTopHint)
winLevel = NSPopUpMenuWindowLevel;
// Tooltips should appear above StayOnTop windows.
if (q->windowType() == Qt::ToolTip)
winLevel = NSScreenSaverWindowLevel;
// All other types are Normal level.
if (winLevel == -1)
winLevel = NSNormalWindowLevel;
[windowRef setLevel:winLevel];
}
}
#else
const bool primaryWindowModal = primaryWindow ? primaryWindow->testAttribute(Qt::WA_ShowModal) : false;
const bool modal = q->testAttribute(Qt::WA_ShowModal);
WindowClass old_wclass;
GetWindowClass(windowRef, &old_wclass);
if (modal || primaryWindowModal) {
if (q->windowModality() == Qt::WindowModal
|| (primaryWindow && primaryWindow->windowModality() == Qt::WindowModal)){
// Window should be window-modal (which implies a sheet).
if (old_wclass != kSheetWindowClass){
// We cannot convert a created window to a sheet.
// So we recreate the window:
recreateMacWindow();
return;
}
} else {
// Window should be application-modal (which implies NOT using a sheet).
if (old_wclass == kSheetWindowClass){
// We cannot convert a sheet to a window.
// So we recreate the window:
recreateMacWindow();
return;
} else if (!(q->data->window_flags & Qt::CustomizeWindowHint)) {
if (old_wclass == kDocumentWindowClass || old_wclass == kFloatingWindowClass || old_wclass == kUtilityWindowClass){
// Only change the class to kMovableModalWindowClass if the no explicit jewels
// are set (kMovableModalWindowClass can't contain them), and the current window class
// can be converted to modal (according to carbon doc). Mind the order of
// HIWindowChangeClass and ChangeWindowAttributes.
WindowGroupRef group = GetWindowGroup(windowRef);
HIWindowChangeClass(windowRef, kMovableModalWindowClass);
quint32 tmpWattr = kWindowCloseBoxAttribute | kWindowHorizontalZoomAttribute;
ChangeWindowAttributes(windowRef, tmpWattr, kWindowNoAttributes);
ChangeWindowAttributes(windowRef, kWindowNoAttributes, tmpWattr);
// If the window belongs to a qt-created group, set that group once more:
if (data.window_flags & Qt::WindowStaysOnTopHint
|| q->windowType() == Qt::Popup
|| q->windowType() == Qt::ToolTip)
SetWindowGroup(windowRef, group);
}
// Popups are usually handled "special" and are never modal.
Qt::WindowType winType = q->windowType();
if (winType != Qt::Popup && winType != Qt::ToolTip)
SetWindowModality(windowRef, kWindowModalityAppModal, 0);
}
}
} else if (windowRef) {
if (old_wclass == kSheetWindowClass){
// Converting a sheet to a window is complex. It's easier to recreate:
recreateMacWindow();
return;
}
SetWindowModality(windowRef, kWindowModalityNone, 0);
if (!(q->data->window_flags & Qt::CustomizeWindowHint)) {
if (q->window()->d_func()->topData()->wattr |= kWindowCloseBoxAttribute)
ChangeWindowAttributes(windowRef, kWindowCloseBoxAttribute, kWindowNoAttributes);
if (q->window()->d_func()->topData()->wattr |= kWindowHorizontalZoomAttribute)
ChangeWindowAttributes(windowRef, kWindowHorizontalZoomAttribute, kWindowNoAttributes);
if (q->window()->d_func()->topData()->wattr |= kWindowCollapseBoxAttribute)
ChangeWindowAttributes(windowRef, kWindowCollapseBoxAttribute, kWindowNoAttributes);
}
WindowClass newClass = q->window()->d_func()->topData()->wclass;
if (old_wclass != newClass && newClass != 0){
WindowGroupRef group = GetWindowGroup(windowRef);
HIWindowChangeClass(windowRef, newClass);
// If the window belongs to a qt-created group, set that group once more:
if (data.window_flags & Qt::WindowStaysOnTopHint
|| q->windowType() == Qt::Popup
|| q->windowType() == Qt::ToolTip)
SetWindowGroup(windowRef, group);
}
}
// Make sure that HIWindowChangeClass didn't remove drag support
// or reset the opaque size grip setting:
SetAutomaticControlDragTrackingEnabledForWindow(windowRef, true);
macUpdateOpaqueSizeGrip();
#endif
}
void QWidgetPrivate::macUpdateHideOnSuspend()
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() || q->windowType() != Qt::Tool)
return;
#ifndef QT_MAC_USE_COCOA
if(q->testAttribute(Qt::WA_MacAlwaysShowToolWindow))
ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowHideOnSuspendAttribute);
else
ChangeWindowAttributes(qt_mac_window_for(q), kWindowHideOnSuspendAttribute, 0);
#else
if(q->testAttribute(Qt::WA_MacAlwaysShowToolWindow))
[qt_mac_window_for(q) setHidesOnDeactivate:NO];
else
[qt_mac_window_for(q) setHidesOnDeactivate:YES];
#endif
}
void QWidgetPrivate::macUpdateOpaqueSizeGrip()
{
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
return;
#ifndef QT_MAC_USE_COCOA // Growbox is always transparent on Cocoa. Can emulate with setting a QSizeGrip
HIViewRef growBox;
HIViewFindByID(HIViewGetRoot(qt_mac_window_for(q)), kHIViewWindowGrowBoxID, &growBox);
if (!growBox)
return;
HIGrowBoxViewSetTransparent(growBox, !q->testAttribute(Qt::WA_MacOpaqueSizeGrip));
#endif
}
void QWidgetPrivate::macUpdateSizeAttribute()
{
Q_Q(QWidget);
QEvent event(QEvent::MacSizeChange);
QApplication::sendEvent(q, &event);
for (int i = 0; i < children.size(); ++i) {
QWidget *w = qobject_cast<QWidget *>(children.at(i));
if (w && (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
&& !q->testAttribute(Qt::WA_MacMiniSize) // no attribute set? inherit from parent
&& !w->testAttribute(Qt::WA_MacSmallSize)
&& !w->testAttribute(Qt::WA_MacNormalSize))
w->d_func()->macUpdateSizeAttribute();
}
resolveFont();
}
void QWidgetPrivate::macUpdateIgnoreMouseEvents()
{
#ifndef QT_MAC_USE_COCOA // This is handled inside the mouse handler on Cocoa.
Q_Q(QWidget);
if (!q->testAttribute(Qt::WA_WState_Created))
return;
if(q->isWindow())
{
if(q->testAttribute(Qt::WA_TransparentForMouseEvents))
ChangeWindowAttributes(qt_mac_window_for(q), kWindowIgnoreClicksAttribute, 0);
else
ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowIgnoreClicksAttribute);
ReshapeCustomWindow(qt_mac_window_for(q));
} else {
#ifndef kHIViewFeatureIgnoresClicks
#define kHIViewFeatureIgnoresClicks kHIViewIgnoresClicks
#endif
if(q->testAttribute(Qt::WA_TransparentForMouseEvents))
HIViewChangeFeatures(qt_mac_nativeview_for(q), kHIViewFeatureIgnoresClicks, 0);
else
HIViewChangeFeatures(qt_mac_nativeview_for(q), 0, kHIViewFeatureIgnoresClicks);
HIViewReshapeStructure(qt_mac_nativeview_for(q));
}
#endif
}
void QWidgetPrivate::macUpdateMetalAttribute()
{
Q_Q(QWidget);
bool realWindow = isRealWindow();
if (!q->testAttribute(Qt::WA_WState_Created) || !realWindow)
return;
if (realWindow) {
#if QT_MAC_USE_COCOA
// Cocoa doesn't let us change the style mask once it's been changed
// So, that means we need to recreate the window.
OSWindowRef cocoaWindow = qt_mac_window_for(q);
if ([cocoaWindow styleMask] & NSTexturedBackgroundWindowMask)
return;
recreateMacWindow();
#else
QMainWindowLayout *layout = qobject_cast<QMainWindowLayout *>(q->layout());
if (q->testAttribute(Qt::WA_MacBrushedMetal)) {
if (layout)
layout->updateHIToolBarStatus();
ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalAttribute, 0);
ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalNoContentSeparatorAttribute, 0);
} else {
ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalNoContentSeparatorAttribute);
ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalAttribute);
if (layout)
layout->updateHIToolBarStatus();
}
#endif
}
}
void QWidgetPrivate::setEnabled_helper_sys(bool enable)
{
#ifdef QT_MAC_USE_COCOA
Q_Q(QWidget);
NSView *view = qt_mac_nativeview_for(q);
if ([view isKindOfClass:[NSControl class]])
[static_cast<NSControl *>(view) setEnabled:enable];
#else
Q_UNUSED(enable);
#endif
}
QT_END_NAMESPACE