/**************************************************************************** | |
** | |
** Copyright (C) 2011 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$ | |
** GNU Lesser General Public License Usage | |
** 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. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $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 | |
// qmainwindow.cpp | |
extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); | |
#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) | |
{ | |
if (!window) | |
return false; | |
if (!window->internalWinId()) | |
return true; //alien | |
return qt_isGenuineQWidget(OSViewRef(window->internalWinId())); | |
} | |
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; | |
} | |
#ifndef QT_NO_GESTURES | |
#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 | |
#endif // QT_NO_GESTURES | |
// 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; } | |
#ifndef QT_NO_GESTURES | |
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; } | |
#endif // QT_NO_GESTURES | |
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)) { | |
bool oldState = widget->testAttribute(Qt::WA_WState_ExplicitShowHide); | |
if(visible) { | |
if (!widget->testAttribute(Qt::WA_WState_ExplicitShowHide)) | |
widget->show(); | |
} else { | |
widget->hide(); | |
if(!oldState) | |
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(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 if(q->testAttribute(Qt::WA_ShowModal)) | |
wclass = kMovableModalWindowClass; | |
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; | |
} | |
} | |
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::setWindowLevel() | |
{ | |
Q_Q(QWidget); | |
const QWidget * const windowParent = q->window()->parentWidget(); | |
const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0; | |
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) { | |
// Correct modality level (NSModalPanelWindowLevel) will be | |
// set by cocoa when creating a modal session later. | |
winLevel = NSNormalWindowLevel; | |
} | |
// 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; | |
[qt_mac_window_for(q) setLevel:winLevel]; | |
} | |
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(); | |
// Tell Cocoa explicit that we wan't the view to receive key events | |
// (regardless of focus policy) because this is how it works on other | |
// platforms (and in the carbon port): | |
if (!qApp->focusWidget()) | |
[windowRef makeFirstResponder:nsview]; | |
} | |
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); | |
} | |
if (qApp->overrideCursor()) | |
[windowRef disableCursorRects]; | |
setWindowLevel(); | |
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 = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q))) { | |
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 | |
#ifdef QT_MAC_USE_COCOA | |
if (q->testAttribute(Qt::WA_NativeWindow) == false || | |
q->internalWinId() != 0) { | |
#ifdef ALIEN_DEBUG | |
qDebug() << "Skipping native widget creation for" << this; | |
#endif | |
} else | |
#endif | |
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); | |
d->aboutToDestroy(); | |
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 | |
} | |
} | |
} | |
} | |
} | |
#ifdef QT_MAC_USE_COCOA | |
void QWidgetPrivate::setSubWindowStacking(bool set) | |
{ | |
// After hitting too many unforeseen bugs trying to put Qt on top of the cocoa child | |
// window API, we have decided to revert this behaviour as much as we can. We | |
// therefore now only allow child windows to exist for children of modal dialogs. | |
static bool use_behaviour_qt473 = !qgetenv("QT_MAC_USE_CHILDWINDOWS").isEmpty(); | |
// This will set/remove a visual relationship between parent and child on screen. | |
// The reason for doing this is to ensure that a child always stacks infront of | |
// its parent. Unfortunatly is turns out that [NSWindow addChildWindow] has | |
// several unwanted side-effects, one of them being the moving of a child when | |
// moving the parent, which we choose to accept. A way tougher side-effect is | |
// that Cocoa will hide the parent if you hide the child. And in the case of | |
// a tool window, since it will normally hide when you deactivate the | |
// application, Cocoa will hide the parent upon deactivate as well. The result often | |
// being no more visible windows on screen. So, to make a long story short, we only | |
// allow parent-child relationships between windows that both are either a plain window | |
// or a dialog. | |
Q_Q(QWidget); | |
if (!q->isWindow()) | |
return; | |
NSWindow *qwin = [qt_mac_nativeview_for(q) window]; | |
if (!qwin) | |
return; | |
Qt::WindowType qtype = q->windowType(); | |
if (set && !(qtype == Qt::Window || qtype == Qt::Dialog)) | |
return; | |
if (set && ![qwin isVisible]) | |
return; | |
if (QWidget *parent = q->parentWidget()) { | |
if (NSWindow *pwin = [qt_mac_nativeview_for(parent) window]) { | |
if (set) { | |
Qt::WindowType ptype = parent->window()->windowType(); | |
if ([pwin isVisible] | |
&& (ptype == Qt::Window || ptype == Qt::Dialog) | |
&& ![qwin parentWindow] | |
&& (use_behaviour_qt473 || parent->windowModality() == Qt::ApplicationModal)) { | |
NSInteger level = [qwin level]; | |
[pwin addChildWindow:qwin ordered:NSWindowAbove]; | |
if ([qwin level] < level) | |
[qwin setLevel:level]; | |
} | |
} else { | |
[pwin removeChildWindow:qwin]; | |
} | |
} | |
} | |
// Only set-up child windows for q if q is modal: | |
if (set && !use_behaviour_qt473 && q->windowModality() != Qt::ApplicationModal) | |
return; | |
QObjectList widgets = q->children(); | |
for (int i=0; i<widgets.size(); ++i) { | |
QWidget *child = qobject_cast<QWidget *>(widgets.at(i)); | |
if (child && child->isWindow()) { | |
if (NSWindow *cwin = [qt_mac_nativeview_for(child) window]) { | |
if (set) { | |
Qt::WindowType ctype = child->window()->windowType(); | |
if ([cwin isVisible] && (ctype == Qt::Window || ctype == Qt::Dialog) && ![cwin parentWindow]) { | |
NSInteger level = [cwin level]; | |
[qwin addChildWindow:cwin ordered:NSWindowAbove]; | |
if ([cwin level] < level) | |
[cwin setLevel:level]; | |
} | |
} else { | |
[qwin removeChildWindow:qt_mac_window_for(child)]; | |
} | |
} | |
} | |
} | |
} | |
#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]; | |
if (oldToolbar) { | |
[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); | |
bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide); | |
if (wasCreated && !qt_isGenuineQWidget(q)) | |
return; | |
if (!q->testAttribute(Qt::WA_WState_WindowOpacitySet)) { | |
q->setWindowOpacity(1.0f); | |
q->setAttribute(Qt::WA_WState_WindowOpacitySet, false); | |
} | |
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, | |
// unless this is an alien widget. ) | |
const bool nonWindowWithCreatedParent = !q->isWindow() && parent->testAttribute(Qt::WA_WState_Created); | |
const bool nativeWidget = q->internalWinId() != 0; | |
if (wasCreated || nativeWidget && nonWindowWithCreatedParent) { | |
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 = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q))) { | |
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 = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q))) { | |
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) || !internalWinId()) { | |
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) || !internalWinId()) { | |
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); | |
qApp->setActiveWindow(tlw); | |
#else | |
[win makeKeyWindow]; | |
#endif | |
} 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_set_needs_display(q, QRegion()); | |
#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 | |
// Alien support: get the first native ancestor widget (will be q itself in the non-alien case), | |
// map the coordinates from q space to NSView space and invalidate the rect. | |
QWidget *nativeParent = q->internalWinId() ? q : q->nativeParentWidget(); | |
if (nativeParent == 0) | |
return; | |
QVector<QRect> rects = rgn.rects(); | |
for (int i = 0; i < rects.count(); ++i) { | |
const QRect &rect = rects.at(i); | |
const QRect nativeBoundingRect = QRect( | |
QPoint(q->mapTo(nativeParent, rect.topLeft())), | |
QSize(rect.size())); | |
[qt_mac_nativeview_for(nativeParent) setNeedsDisplayInRect:NSMakeRect(nativeBoundingRect.x(), | |
nativeBoundingRect.y(), nativeBoundingRect.width(), | |
nativeBoundingRect.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(); | |
#ifndef QT_MAC_USE_COCOA | |
if (realWindow && !q->testAttribute(Qt::WA_Moved)) { | |
if (qt_mac_is_macsheet(q)) | |
recreateMacWindow(); | |
q->createWinId(); | |
if (QWidget *p = q->parentWidget()) { | |
p->createWinId(); | |
RepositionWindow(qt_mac_window_for(q), qt_mac_window_for(p), kWindowCenterOnParentWindow); | |
} else { | |
RepositionWindow(qt_mac_window_for(q), 0, kWindowCenterOnMainScreen); | |
} | |
} | |
#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()]; | |
QWidget *top = 0; | |
if (QApplicationPrivate::tryModalHelper(q, &top)) { | |
[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(); | |
} else { | |
// The window is modally shaddowed, so we need to make | |
// sure that we don't pop in front of the modal window: | |
[window orderFront:window]; | |
if (!top->testAttribute(Qt::WA_DontShowOnScreen)) { | |
if (NSWindow *modalWin = qt_mac_window_for(top)) | |
[modalWin orderFront:window]; | |
} | |
} | |
setSubWindowStacking(true); | |
#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); | |
#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()) { | |
#ifdef QT_MAC_USE_COCOA | |
setSubWindowStacking(false); | |
#endif | |
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 | |
} | |
#ifndef QT_MAC_USE_COCOA | |
// If the window we now hide was the active window, we need | |
// to find, and activate another window on screen. NB: Cocoa takes care of this | |
// logic for us (and distinquishes between main windows and key windows) | |
if (q->isActiveWindow() && !(q->windowType() == Qt::Popup)) { | |
QWidget *w = 0; | |
if(q->parentWidget()) | |
w = q->parentWidget()->window(); | |
if(!w || (!w->isVisible() && !w->isMinimized())) { | |
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; | |
} | |
} | |
} | |
if(w && w->isVisible() && !w->isMinimized()) { | |
qt_event_request_activate(w); | |
} | |
} | |
#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()) { | |
// With the introduction of spaces it is not as simple as just raising the window. | |
// First we need to check if we are in the right space. If we are, then we just continue | |
// as usual. The problem comes when we are not in the active space. There are two main cases: | |
// 1. Our parent was moved to a new space. In this case we want the window to be raised | |
// in the same space as its parent. | |
// 2. We don't have a parent. For this case we will just raise the window and let Cocoa | |
// switch to the corresponding space. | |
// NOTICE: There are a lot of corner cases here. We are keeping this simple for now, if | |
// required we will introduce special handling for some of them. | |
if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) { | |
OSWindowRef window = qt_mac_window_for(q); | |
// isOnActiveSpace is available only from 10.6 onwards, so we need to check if it is | |
// available before calling it. | |
if([window respondsToSelector:@selector(isOnActiveSpace)]) { | |
if(![window performSelector:@selector(isOnActiveSpace)]) { | |
QWidget *parentWidget = q->parentWidget(); | |
if(parentWidget) { | |
OSWindowRef parentWindow = qt_mac_window_for(parentWidget); | |
if(parentWindow && [parentWindow isOnActiveSpace]) { | |
// The window was created in a different space. Therefore if we want | |
// to show it in the current space we need to recreate it in the new | |
// space. | |
recreateMacWindow(); | |
window = qt_mac_window_for(q); | |
} | |
} | |
} | |
} | |
[window orderFront:window]; | |
} | |
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_position(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; | |
bool isEmbeddedWindow = (q->isWindow() && topData()->embedded); | |
if (isEmbeddedWindow) { | |
#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) && !isEmbeddedWindow) { | |
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_position(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(); | |
BOOL needDisplay = realWindow ? YES : NO; | |
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 | |
if (!isMove && !q->testAttribute(Qt::WA_Moved) && !q->isVisible()) { | |
// INVARIANT: The location of the window has not yet been set. The default will | |
// instead be to center it on the desktop, or over the parent, if any. Since we now | |
// resize the window, we need to adjust the top left position to keep the window | |
// centeralized. And we need to to this now (and before show) in case the positioning | |
// of other windows (e.g. sub-windows) depend on this position: | |
if (QWidget *p = q->parentWidget()) { | |
x = p->geometry().center().x() - (w / 2); | |
y = p->geometry().center().y() - (h / 2); | |
} else { | |
QRect availGeo = QApplication::desktop()->availableGeometry(q); | |
x = availGeo.center().x() - (w / 2); | |
y = availGeo.center().y() - (h / 2); | |
} | |
} | |
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:needDisplay]; | |
} 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:needDisplay]; | |
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(); | |
// Apply size restrictions, applicable for Windows & Widgets. | |
if (QWExtra *extra = extraData()) { | |
w = qBound(extra->minw, w, extra->maxw); | |
h = qBound(extra->minh, h, extra->maxh); | |
} | |
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 | |
NSWindow *win = qt_mac_window_for(q); | |
if (on) { | |
if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaWindow) class]]) | |
[static_cast<QT_MANGLE_NAMESPACE(QCocoaWindow) *>(win) registerDragTypes]; | |
else if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaPanel) class]]) | |
[static_cast<QT_MANGLE_NAMESPACE(QCocoaPanel) *>(win) 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_set_needs_display(q, QRegion()); | |
} | |
#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){ | |
// INVARIANT: 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 { | |
// INVARIANT: 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::NonModal | |
&& primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) { | |
// INVARIANT: Our window has a parent that is application modal. | |
// This means that q is supposed to be on top of this window and | |
// not be modally shaddowed: | |
if ([windowRef isKindOfClass:[NSPanel class]]) | |
[static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES]; | |
} | |
} | |
#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 = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q)); | |
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 |