source: trunk/src/gui/kernel/qt_cocoa_helpers_mac.mm@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 47.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/****************************************************************************
43**
44** Copyright (c) 2007-2008, Apple, Inc.
45**
46** All rights reserved.
47**
48** Redistribution and use in source and binary forms, with or without
49** modification, are permitted provided that the following conditions are met:
50**
51** * Redistributions of source code must retain the above copyright notice,
52** this list of conditions and the following disclaimer.
53**
54** * Redistributions in binary form must reproduce the above copyright notice,
55** this list of conditions and the following disclaimer in the documentation
56** and/or other materials provided with the distribution.
57**
58** * Neither the name of Apple, Inc. nor the names of its contributors
59** may be used to endorse or promote products derived from this software
60** without specific prior written permission.
61**
62** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
63** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
64** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
65** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
66** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
67** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
68** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
69** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
70** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
71** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
72** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73**
74****************************************************************************/
75
76#include <private/qcore_mac_p.h>
77#include <qaction.h>
78#include <qwidget.h>
79#include <qdesktopwidget.h>
80#include <qevent.h>
81#include <qpixmapcache.h>
82#include <private/qevent_p.h>
83#include <private/qt_cocoa_helpers_mac_p.h>
84#include <private/qt_mac_p.h>
85#include <private/qapplication_p.h>
86#include <private/qcocoawindow_mac_p.h>
87#include <private/qcocoaview_mac_p.h>
88#include <private/qkeymapper_p.h>
89#include <private/qwidget_p.h>
90
91QT_BEGIN_NAMESPACE
92
93Q_GLOBAL_STATIC(QMacWindowFader, macwindowFader);
94
95QMacWindowFader::QMacWindowFader()
96 : m_duration(0.250)
97{
98}
99
100QMacWindowFader *QMacWindowFader::currentFader()
101{
102 return macwindowFader();
103}
104
105void QMacWindowFader::registerWindowToFade(QWidget *window)
106{
107 m_windowsToFade.append(window);
108}
109
110void QMacWindowFader::performFade()
111{
112 const QWidgetList myWidgetsToFade = m_windowsToFade;
113 const int widgetCount = myWidgetsToFade.count();
114#if QT_MAC_USE_COCOA
115 QMacCocoaAutoReleasePool pool;
116 [NSAnimationContext beginGrouping];
117 [[NSAnimationContext currentContext] setDuration:NSTimeInterval(m_duration)];
118#endif
119
120 for (int i = 0; i < widgetCount; ++i) {
121 QWidget *widget = m_windowsToFade.at(i);
122 OSWindowRef window = qt_mac_window_for(widget);
123#if QT_MAC_USE_COCOA
124 [[window animator] setAlphaValue:0.0];
125 QTimer::singleShot(qRound(m_duration * 1000), widget, SLOT(hide()));
126#else
127 TransitionWindowOptions options = {0, m_duration, 0, 0};
128 TransitionWindowWithOptions(window, kWindowFadeTransitionEffect, kWindowHideTransitionAction,
129 0, 1, &options);
130#endif
131 }
132#if QT_MAC_USE_COCOA
133 [NSAnimationContext endGrouping];
134#endif
135 m_duration = 0.250;
136 m_windowsToFade.clear();
137}
138
139extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); // qapplication.cpp;
140extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm
141extern QWidget * mac_mouse_grabber;
142extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
143
144void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds)
145{
146#ifdef QT_MAC_USE_COCOA
147 QMacCocoaAutoReleasePool pool;
148#endif
149 OSWindowRef wnd = static_cast<OSWindowRef>(window);
150 if (wnd) {
151 QWidget *widget;
152#if QT_MAC_USE_COCOA
153 widget = [wnd QT_MANGLE_NAMESPACE(qt_qwidget)];
154#else
155 const UInt32 kWidgetCreatorQt = kEventClassQt;
156 enum {
157 kWidgetPropertyQWidget = 'QWId' //QWidget *
158 };
159 if (GetWindowProperty(static_cast<WindowRef>(window), kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(widget), 0, &widget) != noErr)
160 widget = 0;
161#endif
162 if (widget) {
163 QMacWindowFader::currentFader()->setFadeDuration(durationSeconds);
164 QMacWindowFader::currentFader()->registerWindowToFade(widget);
165 QMacWindowFader::currentFader()->performFade();
166 }
167 }
168}
169
170bool macWindowIsTextured( void * /*OSWindowRef*/ window )
171{
172 OSWindowRef wnd = static_cast<OSWindowRef>(window);
173#if QT_MAC_USE_COCOA
174 return ( [wnd styleMask] & NSTexturedBackgroundWindowMask ) ? true : false;
175#else
176 WindowAttributes currentAttributes;
177 GetWindowAttributes(wnd, &currentAttributes);
178 return (currentAttributes & kWindowMetalAttribute) ? true : false;
179#endif
180}
181
182void macWindowToolbarShow(const QWidget *widget, bool show )
183{
184 OSWindowRef wnd = qt_mac_window_for(widget);
185#if QT_MAC_USE_COCOA
186 if (NSToolbar *toolbar = [wnd toolbar]) {
187 QMacCocoaAutoReleasePool pool;
188 if (show != [toolbar isVisible]) {
189 [toolbar setVisible:show];
190 } else {
191 // The toolbar may be in sync, but we are not, update our framestrut.
192 qt_widget_private(const_cast<QWidget *>(widget))->updateFrameStrut();
193 }
194 }
195#else
196 ShowHideWindowToolbar(wnd, show, false);
197#endif
198}
199
200
201void macWindowToolbarSet( void * /*OSWindowRef*/ window, void *toolbarRef )
202{
203 OSWindowRef wnd = static_cast<OSWindowRef>(window);
204#if QT_MAC_USE_COCOA
205 [wnd setToolbar:static_cast<NSToolbar *>(toolbarRef)];
206#else
207 SetWindowToolbar(wnd, static_cast<HIToolbarRef>(toolbarRef));
208#endif
209}
210
211bool macWindowToolbarIsVisible( void * /*OSWindowRef*/ window )
212{
213 OSWindowRef wnd = static_cast<OSWindowRef>(window);
214#if QT_MAC_USE_COCOA
215 if (NSToolbar *toolbar = [wnd toolbar])
216 return [toolbar isVisible];
217 return false;
218#else
219 return IsWindowToolbarVisible(wnd);
220#endif
221}
222
223void macWindowSetHasShadow( void * /*OSWindowRef*/ window, bool hasShadow )
224{
225 OSWindowRef wnd = static_cast<OSWindowRef>(window);
226#if QT_MAC_USE_COCOA
227 [wnd setHasShadow:BOOL(hasShadow)];
228#else
229 if (hasShadow)
230 ChangeWindowAttributes(wnd, 0, kWindowNoShadowAttribute);
231 else
232 ChangeWindowAttributes(wnd, kWindowNoShadowAttribute, 0);
233#endif
234}
235
236void macWindowFlush(void * /*OSWindowRef*/ window)
237{
238 OSWindowRef wnd = static_cast<OSWindowRef>(window);
239#if QT_MAC_USE_COCOA
240 [wnd flushWindowIfNeeded];
241#else
242 HIWindowFlush(wnd);
243#endif
244}
245
246void * /*NSImage */qt_mac_create_nsimage(const QPixmap &pm)
247{
248 QMacCocoaAutoReleasePool pool;
249 if(QCFType<CGImageRef> image = pm.toMacCGImageRef()) {
250 NSImage *newImage = 0;
251 NSRect imageRect = NSMakeRect(0.0, 0.0, CGImageGetWidth(image), CGImageGetHeight(image));
252 newImage = [[NSImage alloc] initWithSize:imageRect.size];
253 [newImage lockFocus];
254 {
255 CGContextRef imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
256 CGContextDrawImage(imageContext, *(CGRect*)&imageRect, image);
257 }
258 [newImage unlockFocus];
259 return newImage;
260 }
261 return 0;
262}
263
264void qt_mac_update_mouseTracking(QWidget *widget)
265{
266#ifdef QT_MAC_USE_COCOA
267 [qt_mac_nativeview_for(widget) updateTrackingAreas];
268#else
269 Q_UNUSED(widget);
270#endif
271}
272
273OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage)
274{
275 // Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev)
276 OSStatus err = noErr;
277
278 require_action(inContext != NULL, InvalidContext, err = paramErr);
279 require_action(inBounds != NULL, InvalidBounds, err = paramErr);
280 require_action(inImage != NULL, InvalidImage, err = paramErr);
281
282 CGContextSaveGState( inContext );
283 CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds));
284 CGContextScaleCTM(inContext, 1, -1);
285
286 CGContextDrawImage(inContext, *inBounds, inImage);
287
288 CGContextRestoreGState(inContext);
289InvalidImage:
290InvalidBounds:
291InvalidContext:
292 return err;
293}
294
295bool qt_mac_checkForNativeSizeGrip(const QWidget *widget)
296{
297#ifndef QT_MAC_USE_COCOA
298 OSViewRef nativeSizeGrip = 0;
299 HIViewFindByID(HIViewGetRoot(HIViewGetWindow(HIViewRef(widget->winId()))), kHIViewWindowGrowBoxID, &nativeSizeGrip);
300 return (nativeSizeGrip != 0);
301#else
302 return [[reinterpret_cast<NSView *>(widget->winId()) window] showsResizeIndicator];
303#endif
304}
305struct qt_mac_enum_mapper
306{
307 int mac_code;
308 int qt_code;
309#if defined(DEBUG_MOUSE_MAPS)
310# define QT_MAC_MAP_ENUM(x) x, #x
311 const char *desc;
312#else
313# define QT_MAC_MAP_ENUM(x) x
314#endif
315};
316
317//mouse buttons
318static qt_mac_enum_mapper qt_mac_mouse_symbols[] = {
319{ kEventMouseButtonPrimary, QT_MAC_MAP_ENUM(Qt::LeftButton) },
320{ kEventMouseButtonSecondary, QT_MAC_MAP_ENUM(Qt::RightButton) },
321{ kEventMouseButtonTertiary, QT_MAC_MAP_ENUM(Qt::MidButton) },
322{ 4, QT_MAC_MAP_ENUM(Qt::XButton1) },
323{ 5, QT_MAC_MAP_ENUM(Qt::XButton2) },
324{ 0, QT_MAC_MAP_ENUM(0) }
325};
326Qt::MouseButtons qt_mac_get_buttons(int buttons)
327{
328#ifdef DEBUG_MOUSE_MAPS
329 qDebug("Qt: internal: **Mapping buttons: %d (0x%04x)", buttons, buttons);
330#endif
331 Qt::MouseButtons ret = Qt::NoButton;
332 for(int i = 0; qt_mac_mouse_symbols[i].qt_code; i++) {
333 if (buttons & (0x01<<(qt_mac_mouse_symbols[i].mac_code-1))) {
334#ifdef DEBUG_MOUSE_MAPS
335 qDebug("Qt: internal: got button: %s", qt_mac_mouse_symbols[i].desc);
336#endif
337 ret |= Qt::MouseButtons(qt_mac_mouse_symbols[i].qt_code);
338 }
339 }
340 return ret;
341}
342Qt::MouseButton qt_mac_get_button(EventMouseButton button)
343{
344#ifdef DEBUG_MOUSE_MAPS
345 qDebug("Qt: internal: **Mapping button: %d (0x%04x)", button, button);
346#endif
347 Qt::MouseButtons ret = 0;
348 for(int i = 0; qt_mac_mouse_symbols[i].qt_code; i++) {
349 if (button == qt_mac_mouse_symbols[i].mac_code) {
350#ifdef DEBUG_MOUSE_MAPS
351 qDebug("Qt: internal: got button: %s", qt_mac_mouse_symbols[i].desc);
352#endif
353 return Qt::MouseButton(qt_mac_mouse_symbols[i].qt_code);
354 }
355 }
356 return Qt::NoButton;
357}
358
359void macSendToolbarChangeEvent(QWidget *widget)
360{
361 QToolBarChangeEvent ev(!(GetCurrentKeyModifiers() & cmdKey));
362 qt_sendSpontaneousEvent(widget, &ev);
363}
364
365Q_GLOBAL_STATIC(QMacTabletHash, tablet_hash)
366QMacTabletHash *qt_mac_tablet_hash()
367{
368 return tablet_hash();
369}
370
371#ifdef QT_MAC_USE_COCOA
372void qt_dispatchTabletProximityEvent(void * /*NSEvent * */ tabletEvent)
373{
374 NSEvent *proximityEvent = static_cast<NSEvent *>(tabletEvent);
375 // simply construct a Carbon proximity record and handle it all in one spot.
376 TabletProximityRec carbonProximityRec = { [proximityEvent vendorID],
377 [proximityEvent tabletID],
378 [proximityEvent pointingDeviceID],
379 [proximityEvent deviceID],
380 [proximityEvent systemTabletID],
381 [proximityEvent vendorPointingDeviceType],
382 [proximityEvent pointingDeviceSerialNumber],
383 [proximityEvent uniqueID],
384 [proximityEvent capabilityMask],
385 [proximityEvent pointingDeviceType],
386 [proximityEvent isEnteringProximity] };
387 qt_dispatchTabletProximityEvent(carbonProximityRec);
388}
389#endif // QT_MAC_USE_COCOA
390
391void qt_dispatchTabletProximityEvent(const ::TabletProximityRec &proxRec)
392{
393 QTabletDeviceData proximityDevice;
394 proximityDevice.tabletUniqueID = proxRec.uniqueID;
395 proximityDevice.capabilityMask = proxRec.capabilityMask;
396
397 switch (proxRec.pointerType) {
398 case NSUnknownPointingDevice:
399 default:
400 proximityDevice.tabletPointerType = QTabletEvent::UnknownPointer;
401 break;
402 case NSPenPointingDevice:
403 proximityDevice.tabletPointerType = QTabletEvent::Pen;
404 break;
405 case NSCursorPointingDevice:
406 proximityDevice.tabletPointerType = QTabletEvent::Cursor;
407 break;
408 case NSEraserPointingDevice:
409 proximityDevice.tabletPointerType = QTabletEvent::Eraser;
410 break;
411 }
412 uint bits = proxRec.vendorPointerType;
413 if (bits == 0 && proximityDevice.tabletUniqueID != 0) {
414 // Fallback. It seems that the driver doesn't always include all the information.
415 // High-End Wacom devices store their "type" in the uper bits of the Unique ID.
416 // I'm not sure how to handle it for consumer devices, but I'll test that in a bit.
417 bits = proximityDevice.tabletUniqueID >> 32;
418 }
419 // Defined in the "EN0056-NxtGenImpGuideX"
420 // on Wacom's Developer Website (www.wacomeng.com)
421 if (((bits & 0x0006) == 0x0002) && ((bits & 0x0F06) != 0x0902)) {
422 proximityDevice.tabletDeviceType = QTabletEvent::Stylus;
423 } else {
424 switch (bits & 0x0F06) {
425 case 0x0802:
426 proximityDevice.tabletDeviceType = QTabletEvent::Stylus;
427 break;
428 case 0x0902:
429 proximityDevice.tabletDeviceType = QTabletEvent::Airbrush;
430 break;
431 case 0x0004:
432 proximityDevice.tabletDeviceType = QTabletEvent::FourDMouse;
433 break;
434 case 0x0006:
435 proximityDevice.tabletDeviceType = QTabletEvent::Puck;
436 break;
437 case 0x0804:
438 proximityDevice.tabletDeviceType = QTabletEvent::RotationStylus;
439 break;
440 default:
441 proximityDevice.tabletDeviceType = QTabletEvent::NoDevice;
442 }
443 }
444 // The deviceID is "unique" while in the proximity, it's a key that we can use for
445 // linking up TabletDeviceData to an event (especially if there are two devices in action).
446 bool entering = proxRec.enterProximity;
447 if (entering) {
448 qt_mac_tablet_hash()->insert(proxRec.deviceID, proximityDevice);
449 } else {
450 qt_mac_tablet_hash()->remove(proxRec.deviceID);
451 }
452
453 QTabletEvent qtabletProximity(entering ? QEvent::TabletEnterProximity
454 : QEvent::TabletLeaveProximity,
455 QPoint(), QPoint(), QPointF(), proximityDevice.tabletDeviceType,
456 proximityDevice.tabletPointerType, 0., 0, 0, 0., 0., 0, 0,
457 proximityDevice.tabletUniqueID);
458
459 qt_sendSpontaneousEvent(qApp, &qtabletProximity);
460}
461
462#ifdef QT_MAC_USE_COCOA
463// Use this method to keep all the information in the TextSegment. As long as it is ordered
464// we are in OK shape, and we can influence that ourselves.
465struct KeyPair
466{
467 QChar cocoaKey;
468 Qt::Key qtKey;
469};
470
471bool operator==(const KeyPair &entry, QChar qchar)
472{
473 return entry.cocoaKey == qchar;
474}
475
476bool operator<(const KeyPair &entry, QChar qchar)
477{
478 return entry.cocoaKey < qchar;
479}
480
481bool operator<(QChar qchar, const KeyPair &entry)
482{
483 return qchar < entry.cocoaKey;
484}
485
486static Qt::Key cocoaKey2QtKey(QChar keyCode)
487{
488 static const int NumEntries = 57;
489 static const KeyPair entries[NumEntries] = {
490 { NSEnterCharacter, Qt::Key_Enter },
491 { NSTabCharacter, Qt::Key_Tab },
492 { NSCarriageReturnCharacter, Qt::Key_Return },
493 { NSBackTabCharacter, Qt::Key_Backtab },
494 { kEscapeCharCode, Qt::Key_Escape },
495 { NSDeleteCharacter, Qt::Key_Backspace },
496 { NSUpArrowFunctionKey, Qt::Key_Up },
497 { NSDownArrowFunctionKey, Qt::Key_Down },
498 { NSLeftArrowFunctionKey, Qt::Key_Left },
499 { NSRightArrowFunctionKey, Qt::Key_Right },
500 { NSF1FunctionKey, Qt::Key_F1 },
501 { NSF2FunctionKey, Qt::Key_F2 },
502 { NSF3FunctionKey, Qt::Key_F3 },
503 { NSF4FunctionKey, Qt::Key_F4 },
504 { NSF5FunctionKey, Qt::Key_F5 },
505 { NSF6FunctionKey, Qt::Key_F6 },
506 { NSF7FunctionKey, Qt::Key_F7 },
507 { NSF8FunctionKey, Qt::Key_F8 },
508 { NSF9FunctionKey, Qt::Key_F8 },
509 { NSF10FunctionKey, Qt::Key_F10 },
510 { NSF11FunctionKey, Qt::Key_F11 },
511 { NSF12FunctionKey, Qt::Key_F12 },
512 { NSF13FunctionKey, Qt::Key_F13 },
513 { NSF14FunctionKey, Qt::Key_F14 },
514 { NSF15FunctionKey, Qt::Key_F15 },
515 { NSF16FunctionKey, Qt::Key_F16 },
516 { NSF17FunctionKey, Qt::Key_F17 },
517 { NSF18FunctionKey, Qt::Key_F18 },
518 { NSF19FunctionKey, Qt::Key_F19 },
519 { NSF20FunctionKey, Qt::Key_F20 },
520 { NSF21FunctionKey, Qt::Key_F21 },
521 { NSF22FunctionKey, Qt::Key_F22 },
522 { NSF23FunctionKey, Qt::Key_F23 },
523 { NSF24FunctionKey, Qt::Key_F24 },
524 { NSF25FunctionKey, Qt::Key_F25 },
525 { NSF26FunctionKey, Qt::Key_F26 },
526 { NSF27FunctionKey, Qt::Key_F27 },
527 { NSF28FunctionKey, Qt::Key_F28 },
528 { NSF29FunctionKey, Qt::Key_F29 },
529 { NSF30FunctionKey, Qt::Key_F30 },
530 { NSF31FunctionKey, Qt::Key_F31 },
531 { NSF32FunctionKey, Qt::Key_F32 },
532 { NSF33FunctionKey, Qt::Key_F33 },
533 { NSF34FunctionKey, Qt::Key_F34 },
534 { NSF35FunctionKey, Qt::Key_F35 },
535 { NSInsertFunctionKey, Qt::Key_Insert },
536 { NSDeleteFunctionKey, Qt::Key_Delete },
537 { NSHomeFunctionKey, Qt::Key_Home },
538 { NSEndFunctionKey, Qt::Key_End },
539 { NSPageUpFunctionKey, Qt::Key_PageUp },
540 { NSPageDownFunctionKey, Qt::Key_PageDown },
541 { NSPrintScreenFunctionKey, Qt::Key_Print },
542 { NSScrollLockFunctionKey, Qt::Key_ScrollLock },
543 { NSPauseFunctionKey, Qt::Key_Pause },
544 { NSSysReqFunctionKey, Qt::Key_SysReq },
545 { NSMenuFunctionKey, Qt::Key_Menu },
546 { NSHelpFunctionKey, Qt::Key_Help },
547 };
548 static const KeyPair * const end = entries + NumEntries;
549 const KeyPair *i = qBinaryFind(entries, end, keyCode);
550 if (i == end)
551 return Qt::Key(keyCode.unicode());
552 return i->qtKey;
553}
554
555Qt::KeyboardModifiers qt_cocoaModifiers2QtModifiers(ulong modifierFlags)
556{
557 Qt::KeyboardModifiers qtMods =Qt::NoModifier;
558 if (modifierFlags & NSShiftKeyMask)
559 qtMods |= Qt::ShiftModifier;
560 if (modifierFlags & NSControlKeyMask)
561 qtMods |= Qt::MetaModifier;
562 if (modifierFlags & NSAlternateKeyMask)
563 qtMods |= Qt::AltModifier;
564 if (modifierFlags & NSCommandKeyMask)
565 qtMods |= Qt::ControlModifier;
566 if (modifierFlags & NSNumericPadKeyMask)
567 qtMods |= Qt::KeypadModifier;
568 return qtMods;
569}
570
571Qt::KeyboardModifiers qt_cocoaDragOperation2QtModifiers(uint dragOperations)
572{
573 Qt::KeyboardModifiers qtMods =Qt::NoModifier;
574 if (dragOperations & NSDragOperationLink)
575 qtMods |= Qt::MetaModifier;
576 if (dragOperations & NSDragOperationGeneric)
577 qtMods |= Qt::ControlModifier;
578 if (dragOperations & NSDragOperationCopy)
579 qtMods |= Qt::AltModifier;
580 return qtMods;
581}
582
583static inline QEvent::Type cocoaEvent2QtEvent(NSUInteger eventType)
584{
585 // Handle the trivial cases that can be determined from the type.
586 switch (eventType) {
587 case NSKeyDown:
588 return QEvent::KeyPress;
589 case NSKeyUp:
590 return QEvent::KeyRelease;
591 case NSLeftMouseDown:
592 case NSRightMouseDown:
593 case NSOtherMouseDown:
594 return QEvent::MouseButtonPress;
595 case NSLeftMouseUp:
596 case NSRightMouseUp:
597 case NSOtherMouseUp:
598 return QEvent::MouseButtonRelease;
599 case NSMouseMoved:
600 case NSLeftMouseDragged:
601 case NSRightMouseDragged:
602 case NSOtherMouseDragged:
603 return QEvent::MouseMove;
604 case NSScrollWheel:
605 return QEvent::Wheel;
606 }
607 return QEvent::None;
608}
609
610static bool mustUseCocoaKeyEvent()
611{
612 QCFType<TISInputSourceRef> source = TISCopyCurrentKeyboardInputSource();
613 return TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData) == 0;
614}
615
616bool qt_dispatchKeyEventWithCocoa(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent)
617{
618 NSEvent *event = static_cast<NSEvent *>(keyEvent);
619 NSString *keyChars = [event charactersIgnoringModifiers];
620 int keyLength = [keyChars length];
621 if (keyLength == 0)
622 return false; // Dead Key, nothing to do!
623 bool ignoreText = false;
624 Qt::Key qtKey = Qt::Key_unknown;
625 if (keyLength == 1) {
626 QChar ch([keyChars characterAtIndex:0]);
627 if (ch.isLower())
628 ch = ch.toUpper();
629 qtKey = cocoaKey2QtKey(ch);
630 // Do not set the text for Function-Key Unicodes characters (0xF700–0xF8FF).
631 ignoreText = (ch.unicode() >= 0xF700 && ch.unicode() <= 0xF8FF);
632 }
633 Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([event modifierFlags]);
634 QString text;
635
636 // To quote from the Carbon port: This is actually wrong--but it is the best that
637 // can be done for now because of the Control/Meta mapping issues
638 // (we always get text on the Mac)
639 if (!ignoreText && !(keyMods & (Qt::ControlModifier | Qt::MetaModifier)))
640 text = QCFString::toQString(reinterpret_cast<CFStringRef>(keyChars));
641
642 UInt32 macScanCode = 1;
643 QKeyEventEx ke(cocoaEvent2QtEvent([event type]), qtKey, keyMods, text, [event isARepeat], qMax(1, keyLength),
644 macScanCode, [event keyCode], [event modifierFlags]);
645 qt_sendSpontaneousEvent(widgetToGetEvent, &ke);
646 return ke.isAccepted();
647}
648#endif
649
650// Helper to share code between QCocoaWindow and QCocoaView
651bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent)
652{
653#ifndef QT_MAC_USE_COCOA
654 Q_UNUSED(keyEvent);
655 Q_UNUSED(widgetToGetEvent);
656 return false;
657#else
658 NSEvent *event = static_cast<NSEvent *>(keyEvent);
659 EventRef key_event = static_cast<EventRef>(const_cast<void *>([event eventRef]));
660 Q_ASSERT(key_event);
661 if ([event type] == NSKeyDown) {
662 qt_keymapper_private()->updateKeyMap(0, key_event, 0);
663 }
664 if (widgetToGetEvent == 0)
665 return false;
666
667 if (qt_mac_sendMacEventToWidget(widgetToGetEvent, key_event))
668 return true;
669
670 if (mustUseCocoaKeyEvent())
671 return qt_dispatchKeyEventWithCocoa(keyEvent, widgetToGetEvent);
672 bool isAccepted;
673 qt_keymapper_private()->translateKeyEvent(widgetToGetEvent, 0, key_event, &isAccepted, true);
674 return isAccepted;
675#endif
676}
677
678void qt_dispatchModifiersChanged(void * /*NSEvent * */flagsChangedEvent, QWidget *widgetToGetEvent)
679{
680#ifndef QT_MAC_USE_COCOA
681 Q_UNUSED(flagsChangedEvent);
682 Q_UNUSED(widgetToGetEvent);
683#else
684 UInt32 modifiers = 0;
685 // Sync modifiers with Qt
686 NSEvent *event = static_cast<NSEvent *>(flagsChangedEvent);
687 EventRef key_event = static_cast<EventRef>(const_cast<void *>([event eventRef]));
688 Q_ASSERT(key_event);
689 GetEventParameter(key_event, kEventParamKeyModifiers, typeUInt32, 0,
690 sizeof(modifiers), 0, &modifiers);
691 extern void qt_mac_send_modifiers_changed(quint32 modifiers, QObject *object);
692 qt_mac_send_modifiers_changed(modifiers, widgetToGetEvent);
693#endif
694}
695
696
697QPointF flipPoint(const NSPoint &p)
698{
699 return QPointF(p.x, flipYCoordinate(p.y));
700}
701
702NSPoint flipPoint(const QPoint &p)
703{
704 return NSMakePoint(p.x(), flipYCoordinate(p.y()));
705}
706
707NSPoint flipPoint(const QPointF &p)
708{
709 return NSMakePoint(p.x(), flipYCoordinate(p.y()));
710}
711
712void qt_mac_dispatchNCMouseMessage(void * /* NSWindow* */eventWindow, void * /* NSEvent* */mouseEvent,
713 QWidget *widgetToGetEvent, bool &leftButtonIsRightButton)
714{
715#ifndef QT_MAC_USE_COCOA
716 Q_UNUSED(eventWindow);
717 Q_UNUSED(mouseEvent);
718 Q_UNUSED(widgetToGetEvent);
719 Q_UNUSED(leftButtonIsRightButton);
720#else
721 if (widgetToGetEvent == 0)
722 return;
723 NSWindow *window = static_cast<NSWindow *>(eventWindow);
724 NSEvent *event = static_cast<NSEvent *>(mouseEvent);
725 NSEventType evtType = [event type];
726
727 QPoint qlocalPoint;
728 QPoint qglobalPoint;
729 bool processThisEvent = false;
730 bool fakeNCEvents = false;
731 bool fakeMouseEvents = false;
732
733 // Check if this is a mouse event.
734 if (evtType == NSLeftMouseDown || evtType == NSLeftMouseUp
735 || evtType == NSRightMouseDown || evtType == NSRightMouseUp
736 || evtType == NSOtherMouseDown || evtType == NSOtherMouseUp
737 || evtType == NSMouseMoved || evtType == NSLeftMouseDragged
738 || evtType == NSRightMouseDragged || evtType == NSOtherMouseDragged) {
739 // Check if we want to pass this message to another window
740 if (mac_mouse_grabber && mac_mouse_grabber != widgetToGetEvent) {
741 NSWindow *grabWindow = static_cast<NSWindow *>(qt_mac_window_for(mac_mouse_grabber));
742 if (window != grabWindow) {
743 window = grabWindow;
744 widgetToGetEvent = mac_mouse_grabber;
745 fakeNCEvents = true;
746 }
747 }
748 // Dont generate normal NC mouse events for Left Button dragged
749 if(evtType != NSLeftMouseDragged || fakeNCEvents) {
750 NSPoint windowPoint = [event locationInWindow];
751 NSPoint globalPoint = [[event window] convertBaseToScreen:windowPoint];
752 NSRect frameRect = [window frame];
753 if (fakeNCEvents || NSMouseInRect(globalPoint, frameRect, NO)) {
754 NSRect contentRect = [window contentRectForFrameRect:frameRect];
755 qglobalPoint = QPoint(flipPoint(globalPoint).toPoint());
756 QWidget *w = widgetToGetEvent->childAt(widgetToGetEvent->mapFromGlobal(qglobalPoint));
757 // check that the mouse pointer is on the non-client area and
758 // there are not widgets in it.
759 if (fakeNCEvents || (!NSMouseInRect(globalPoint, contentRect, NO) && !w)) {
760 qglobalPoint = QPoint(flipPoint(globalPoint).toPoint());
761 qlocalPoint = widgetToGetEvent->mapFromGlobal(qglobalPoint);
762 processThisEvent = true;
763 }
764 }
765 }
766 }
767 // This is not an NC area mouse message.
768 if (!processThisEvent)
769 return;
770
771 // If the window is frame less, generate fake mouse events instead. (floating QToolBar)
772 // or if someone already got an explicit or implicit grab
773 if (mac_mouse_grabber || qt_button_down ||
774 (fakeNCEvents && (widgetToGetEvent->window()->windowFlags() & Qt::FramelessWindowHint)))
775 fakeMouseEvents = true;
776
777 Qt::MouseButton button;
778 QEvent::Type eventType;
779 // Convert to Qt::Event type
780 switch (evtType) {
781 case NSLeftMouseDown:
782 button = Qt::LeftButton;
783 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonPress
784 : QEvent::MouseButtonPress;
785 break;
786 case NSLeftMouseUp:
787 button = Qt::LeftButton;
788 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonRelease
789 : QEvent::MouseButtonRelease;
790 break;
791 case NSRightMouseDown:
792 button = Qt::RightButton;
793 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonPress
794 : QEvent::MouseButtonPress;
795 break;
796 case NSRightMouseUp:
797 button = Qt::RightButton;
798 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonRelease
799 : QEvent::MouseButtonRelease;
800 break;
801 case NSOtherMouseDown:
802 button = cocoaButton2QtButton([event buttonNumber]);
803 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonPress
804 : QEvent::MouseButtonPress;
805 break;
806 case NSOtherMouseUp:
807 button = cocoaButton2QtButton([event buttonNumber]);
808 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonRelease
809 : QEvent::MouseButtonRelease;
810 break;
811 case NSMouseMoved:
812 button = Qt::NoButton;
813 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseMove
814 : QEvent::MouseMove;
815 break;
816 case NSLeftMouseDragged:
817 button = Qt::LeftButton;
818 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseMove
819 : QEvent::MouseMove;
820 break;
821 case NSRightMouseDragged:
822 button = Qt::RightButton;
823 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseMove
824 : QEvent::MouseMove;
825 break;
826 case NSOtherMouseDragged:
827 button = cocoaButton2QtButton([event buttonNumber]);
828 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseMove
829 : QEvent::MouseMove;
830 break;
831 default:
832 qWarning("not handled! Non client area mouse message");
833 return;
834 }
835
836 Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([event modifierFlags]);
837 if (eventType == QEvent::NonClientAreaMouseButtonPress || eventType == QEvent::MouseButtonPress) {
838 NSInteger clickCount = [event clickCount];
839 if (clickCount % 2 == 0)
840 eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonDblClick
841 : QEvent::MouseButtonDblClick;
842 if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) {
843 button = Qt::RightButton;
844 leftButtonIsRightButton = true;
845 }
846 } else if (eventType == QEvent::NonClientAreaMouseButtonRelease || eventType == QEvent::MouseButtonRelease) {
847 if (button == Qt::LeftButton && leftButtonIsRightButton) {
848 button = Qt::RightButton;
849 leftButtonIsRightButton = false;
850 }
851 }
852
853 QMouseEvent qme(eventType, qlocalPoint, qglobalPoint, button, button, keyMods);
854 qt_sendSpontaneousEvent(widgetToGetEvent, &qme);
855
856 // We don't need to set the implicit grab widget here because we won't
857 // reach this point if then event type is Press over a Qt widget.
858 // However we might need to unset it if the event is Release.
859 if (eventType == QEvent::MouseButtonRelease)
860 qt_button_down = 0;
861#endif
862}
863
864bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */event, QEvent::Type eventType, Qt::MouseButton button)
865{
866#ifndef QT_MAC_USE_COCOA
867 Q_UNUSED(view);
868 Q_UNUSED(event);
869 Q_UNUSED(eventType);
870 Q_UNUSED(button);
871 return false;
872#else
873 QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
874 NSEvent *theEvent = static_cast<NSEvent *>(event);
875
876 // Give the Input Manager a chance to process the mouse events.
877 NSInputManager *currentIManager = [NSInputManager currentInputManager];
878 if (currentIManager && [currentIManager wantsToHandleMouseEvents]) {
879 [currentIManager handleMouseEvent:theEvent];
880 }
881
882 // Handle tablet events (if any) first.
883 if (qt_mac_handleTabletEvent(theView, theEvent)) {
884 // Tablet event was handled. In Qt we aren't supposed to send the mouse event.
885 return true;
886 }
887
888 NSPoint windowPoint = [theEvent locationInWindow];
889 NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint];
890
891 // Find the widget that *should* get the event (e.g., maybe it was a pop-up,
892 // they always get the mouse event).
893 QWidget *qwidget = [theView qt_qwidget];
894 QWidget *widgetToGetMouse = 0;
895 NSView *tmpView = 0;
896 QWidget *popup = qAppInstance()->activePopupWidget();
897 QPoint qglobalPoint(flipPoint(globalPoint).toPoint());
898
899 if (popup) {
900 widgetToGetMouse = popup;
901 tmpView = qt_mac_nativeview_for(popup);
902 windowPoint = [[tmpView window] convertScreenToBase:globalPoint];
903
904 QPoint qWindowPoint(windowPoint.x, windowPoint.y);
905 if (widgetToGetMouse->rect().contains(qWindowPoint)) {
906 // Keeping the mouse pressed on a combobox button will make
907 // the popup pop in front of the mouse. But all mouse events
908 // will be sendt to the button. Since we want mouse events
909 // to be sendt to widgets inside the popup, we search for the
910 // widget in front of the mouse:
911 tmpView = [tmpView hitTest:windowPoint];
912 if (!tmpView)
913 return false;
914 widgetToGetMouse =
915 [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(tmpView) qt_qwidget];
916 }
917 } else {
918 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
919 QPoint pos;
920 widgetToGetMouse = QApplicationPrivate::pickMouseReceiver(qwidget, qglobalPoint,
921 pos, eventType,
922 button, qt_button_down, 0);
923 if (widgetToGetMouse)
924 tmpView = qt_mac_nativeview_for(widgetToGetMouse);
925 }
926 if (!widgetToGetMouse)
927 return false;
928
929 NSPoint localPoint = [tmpView convertPoint:windowPoint fromView:nil];
930 QPoint qlocalPoint(localPoint.x, localPoint.y);
931
932 EventRef carbonEvent = static_cast<EventRef>(const_cast<void *>([theEvent eventRef]));
933 if (qt_mac_sendMacEventToWidget(widgetToGetMouse, carbonEvent))
934 return true;
935
936 // Yay! All the special cases are handled, it really is just a normal mouse event.
937 Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]);
938 NSInteger clickCount = [theEvent clickCount];
939 Qt::MouseButtons buttons = 0;
940 {
941 UInt32 mac_buttons;
942 if (GetEventParameter(carbonEvent, kEventParamMouseChord, typeUInt32, 0,
943 sizeof(mac_buttons), 0, &mac_buttons) == noErr)
944 buttons = qt_mac_get_buttons(mac_buttons);
945 }
946 switch (eventType) {
947 default:
948 qWarning("not handled! %d", eventType);
949 break;
950 case QEvent::MouseMove:
951 break;
952 case QEvent::MouseButtonPress:
953 [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->view = theView;
954 [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->theEvent = theEvent;
955#ifndef QT_NAMESPACE
956 Q_ASSERT(clickCount > 0);
957#endif
958 if (clickCount % 2 == 0)
959 eventType = QEvent::MouseButtonDblClick;
960 if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) {
961 button = Qt::RightButton;
962 [theView qt_setLeftButtonIsRightButton: true];
963 }
964 break;
965 case QEvent::MouseButtonRelease:
966 if (button == Qt::LeftButton && [theView qt_leftButtonIsRightButton]) {
967 button = Qt::RightButton;
968 [theView qt_setLeftButtonIsRightButton: false];
969 }
970 break;
971 }
972 [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->localPoint = localPoint;
973 QMouseEvent qme(eventType, qlocalPoint, qglobalPoint, button, buttons, keyMods);
974 qt_sendSpontaneousEvent(widgetToGetMouse, &qme);
975 if (eventType == QEvent::MouseButtonPress && button == Qt::RightButton) {
976 QContextMenuEvent qcme(QContextMenuEvent::Mouse, qlocalPoint, qglobalPoint, keyMods);
977 qt_sendSpontaneousEvent(widgetToGetMouse, &qcme);
978 }
979 return true;
980#endif
981}
982
983bool qt_mac_handleTabletEvent(void * /*QCocoaView * */view, void * /*NSEvent * */tabletEvent)
984{
985#ifndef QT_MAC_USE_COCOA
986 Q_UNUSED(view);
987 Q_UNUSED(tabletEvent);
988 return false;
989#else
990 QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
991 NSView *theNSView = static_cast<NSView *>(view);
992 NSEvent *theTabletEvent = static_cast<NSEvent *>(tabletEvent);
993
994 NSEventType eventType = [theTabletEvent type];
995 if (eventType != NSTabletPoint && [theTabletEvent subtype] != NSTabletPointEventSubtype)
996 return false; // Not a tablet event.
997
998 NSPoint windowPoint = [theTabletEvent locationInWindow];
999 NSPoint globalPoint = [[theTabletEvent window] convertBaseToScreen:windowPoint];
1000
1001 QWidget *qwidget = [theView qt_qwidget];
1002 QWidget *widgetToGetMouse = qwidget;
1003 QWidget *popup = qAppInstance()->activePopupWidget();
1004 if (popup && popup != qwidget->window())
1005 widgetToGetMouse = popup;
1006
1007 if (qt_mac_sendMacEventToWidget(widgetToGetMouse,
1008 static_cast<EventRef>(const_cast<void *>([theTabletEvent eventRef]))))
1009 return true;
1010 if (widgetToGetMouse != qwidget) {
1011 theNSView = qt_mac_nativeview_for(widgetToGetMouse);
1012 windowPoint = [[theNSView window] convertScreenToBase:globalPoint];
1013 }
1014 NSPoint localPoint = [theNSView convertPoint:windowPoint fromView:nil];
1015 // Tablet events do not handle WA_TransparentForMouseEvents ATM
1016 // In theory, people who set the WA_TransparentForMouseEvents attribute won't handle
1017 // tablet events either in which case they will fall into the mouse event case and get
1018 // them passed on. This will NOT handle the raw events, but that might not be a big problem.
1019
1020 const QMacTabletHash *tabletHash = qt_mac_tablet_hash();
1021 if (!tabletHash->contains([theTabletEvent deviceID])) {
1022 qWarning("QCocoaView handleTabletEvent: This tablet device is unknown"
1023 " (received no proximity event for it). Discarding event.");
1024 return false;
1025 }
1026 const QTabletDeviceData &deviceData = tabletHash->value([theTabletEvent deviceID]);
1027
1028
1029 QEvent::Type qType;
1030 switch (eventType) {
1031 case NSLeftMouseDown:
1032 case NSRightMouseDown:
1033 qType = QEvent::TabletPress;
1034 break;
1035 case NSLeftMouseUp:
1036 case NSRightMouseUp:
1037 qType = QEvent::TabletRelease;
1038 break;
1039 case NSMouseMoved:
1040 case NSTabletPoint:
1041 case NSLeftMouseDragged:
1042 case NSRightMouseDragged:
1043 default:
1044 qType = QEvent::TabletMove;
1045 break;
1046 }
1047
1048 qreal pressure;
1049 if (eventType != NSMouseMoved) {
1050 pressure = [theTabletEvent pressure];
1051 } else {
1052 pressure = 0.0;
1053 }
1054
1055 NSPoint tilt = [theTabletEvent tilt];
1056 int xTilt = qRound(tilt.x * 60.0);
1057 int yTilt = qRound(tilt.y * -60.0);
1058 qreal tangentialPressure = 0;
1059 qreal rotation = 0;
1060 int z = 0;
1061 if (deviceData.capabilityMask & 0x0200)
1062 z = [theTabletEvent absoluteZ];
1063
1064 if (deviceData.capabilityMask & 0x0800)
1065 tangentialPressure = [theTabletEvent tangentialPressure];
1066
1067 rotation = [theTabletEvent rotation];
1068 QPointF hiRes = flipPoint(globalPoint);
1069 QTabletEvent qtabletEvent(qType, QPoint(localPoint.x, localPoint.y),
1070 hiRes.toPoint(), hiRes,
1071 deviceData.tabletDeviceType, deviceData.tabletPointerType,
1072 pressure, xTilt, yTilt, tangentialPressure, rotation, z,
1073 qt_cocoaModifiers2QtModifiers([theTabletEvent modifierFlags]),
1074 deviceData.tabletUniqueID);
1075
1076 qt_sendSpontaneousEvent(widgetToGetMouse, &qtabletEvent);
1077 return qtabletEvent.isAccepted();
1078#endif
1079}
1080
1081void qt_mac_updateContentBorderMetricts(void * /*OSWindowRef */window, const ::HIContentBorderMetrics &metrics)
1082{
1083 OSWindowRef theWindow = static_cast<OSWindowRef>(window);
1084#if !defined(QT_MAC_USE_COCOA)
1085# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
1086 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
1087 ::HIWindowSetContentBorderThickness(theWindow, &metrics);
1088 }
1089# else
1090 Q_UNUSED(window);
1091 Q_UNUSED(metrics);
1092# endif
1093#else
1094 if ([theWindow styleMask] & NSTexturedBackgroundWindowMask)
1095 [theWindow setContentBorderThickness:metrics.top forEdge:NSMaxYEdge];
1096 [theWindow setContentBorderThickness:metrics.bottom forEdge:NSMinYEdge];
1097#endif
1098}
1099
1100void qt_mac_showBaseLineSeparator(void * /*OSWindowRef */window, bool show)
1101{
1102#if QT_MAC_USE_COCOA
1103 QMacCocoaAutoReleasePool pool;
1104 OSWindowRef theWindow = static_cast<OSWindowRef>(window);
1105 NSToolbar *macToolbar = [theWindow toolbar];
1106 if (macToolbar)
1107 [macToolbar setShowsBaselineSeparator: show];
1108#endif
1109}
1110
1111QStringList qt_mac_NSArrayToQStringList(void *nsarray)
1112{
1113 QStringList result;
1114 NSArray *array = static_cast<NSArray *>(nsarray);
1115 for (NSUInteger i=0; i<[array count]; ++i)
1116 result << qt_mac_NSStringToQString([array objectAtIndex:i]);
1117 return result;
1118}
1119
1120void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list)
1121{
1122 NSMutableArray *result = [NSMutableArray arrayWithCapacity:list.size()];
1123 for (int i=0; i<list.size(); ++i){
1124 [result addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(list[i]))];
1125 }
1126 return result;
1127}
1128
1129void qt_syncCocoaTitleBarButtons(OSWindowRef window, QWidget *widgetForWindow)
1130{
1131 if (!widgetForWindow)
1132 return;
1133
1134 Qt::WindowFlags flags = widgetForWindow->windowFlags();
1135 bool customize = flags & Qt::CustomizeWindowHint;
1136
1137 NSButton *btn = [window standardWindowButton:NSWindowZoomButton];
1138 // BOOL is not an int, so the bitwise AND doesn't work.
1139 bool go = uint(customize && !(flags & Qt::WindowMaximizeButtonHint)) == 0;
1140 [btn setEnabled:go];
1141
1142 btn = [window standardWindowButton:NSWindowMiniaturizeButton];
1143 go = uint(customize && !(flags & Qt::WindowMinimizeButtonHint)) == 0;
1144 [btn setEnabled:go];
1145
1146 btn = [window standardWindowButton:NSWindowCloseButton];
1147 go = uint(customize && !(flags & Qt::WindowSystemMenuHint
1148 || flags & Qt::WindowCloseButtonHint)) == 0;
1149 [btn setEnabled:go];
1150
1151 [window setShowsToolbarButton:uint(flags & Qt::MacWindowToolBarButtonHint) != 0];
1152}
1153
1154// Carbon: Make sure you call QDEndContext on the context when done with it.
1155CGContextRef qt_mac_graphicsContextFor(QWidget *widget)
1156{
1157 if (!widget)
1158 return 0;
1159
1160#ifndef QT_MAC_USE_COCOA
1161 CGContextRef context;
1162 CGrafPtr port = GetWindowPort(qt_mac_window_for(widget));
1163 QDBeginCGContext(port, &context);
1164#else
1165 CGContextRef context = reinterpret_cast<CGContextRef>([[qt_mac_window_for(widget) graphicsContext] graphicsPort]);
1166#endif
1167 return context;
1168}
1169
1170void qt_mac_dispatchPendingUpdateRequests(QWidget *widget)
1171{
1172 if (!widget)
1173 return;
1174#ifndef QT_MAC_USE_COCOA
1175 HIViewRender(qt_mac_nativeview_for(widget));
1176#else
1177 [qt_mac_nativeview_for(widget) displayIfNeeded];
1178#endif
1179}
1180
1181CGFloat qt_mac_get_scalefactor()
1182{
1183#ifndef QT_MAC_USE_COCOA
1184 return HIGetScaleFactor();
1185#else
1186 return [[NSScreen mainScreen] userSpaceScaleFactor];
1187#endif
1188}
1189
1190QString qt_mac_get_pasteboardString(OSPasteboardRef paste)
1191{
1192 QMacCocoaAutoReleasePool pool;
1193 NSPasteboard *pb = nil;
1194 CFStringRef pbname;
1195 if (PasteboardCopyName (paste, &pbname)) {
1196 pb = [NSPasteboard generalPasteboard];
1197 } else {
1198 pb = [NSPasteboard pasteboardWithName:reinterpret_cast<const NSString *>(pbname)];
1199 CFRelease (pbname);
1200 }
1201 if (pb) {
1202 NSString *text = [pb stringForType:NSStringPboardType];
1203 if (text)
1204 return qt_mac_NSStringToQString(text);
1205 }
1206 return QString();
1207}
1208
1209QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height)
1210{
1211 QPixmap ret(width, height);
1212 ret.fill(QColor(0, 0, 0, 0));
1213
1214 CGRect rect = CGRectMake(0, 0, width, height);
1215
1216 CGContextRef ctx = qt_mac_cg_context(&ret);
1217 CGAffineTransform old_xform = CGContextGetCTM(ctx);
1218 CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform));
1219 CGContextConcatCTM(ctx, CGAffineTransformIdentity);
1220
1221 ::RGBColor b;
1222 b.blue = b.green = b.red = 255*255;
1223 PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon);
1224 CGContextRelease(ctx);
1225 return ret;
1226}
1227
1228void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon)
1229{
1230 int size = 16;
1231 while (size <= 128) {
1232
1233 const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size);
1234 QPixmap mainIcon;
1235 if (standardIcon >= QStyle::SP_CustomBase) {
1236 mainIcon = qt_mac_convert_iconref(icon, size, size);
1237 } else if (QPixmapCache::find(cacheKey, mainIcon) == false) {
1238 mainIcon = qt_mac_convert_iconref(icon, size, size);
1239 QPixmapCache::insert(cacheKey, mainIcon);
1240 }
1241
1242 if (overlayIcon) {
1243 int littleSize = size / 2;
1244 QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize);
1245 QPainter painter(&mainIcon);
1246 painter.drawPixmap(size - littleSize, size - littleSize, overlayPix);
1247 }
1248
1249 retIcon->addPixmap(mainIcon);
1250 size += size; // 16 -> 32 -> 64 -> 128
1251 }
1252}
1253
1254void qt_mac_menu_collapseSeparators(void */*NSMenu **/ theMenu, bool collapse)
1255{
1256 OSMenuRef menu = static_cast<OSMenuRef>(theMenu);
1257 if (collapse) {
1258 bool previousIsSeparator = true; // setting to true kills all the separators placed at the top.
1259 NSMenuItem *previousItem = nil;
1260
1261 NSArray *itemArray = [menu itemArray];
1262 for (unsigned int i = 0; i < [itemArray count]; ++i) {
1263 NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]);
1264 if ([item isSeparatorItem]) {
1265 [item setHidden:previousIsSeparator];
1266 }
1267
1268 if (![item isHidden]) {
1269 previousItem = item;
1270 previousIsSeparator = ([previousItem isSeparatorItem]);
1271 }
1272 }
1273
1274 // We now need to check the final item since we don't want any separators at the end of the list.
1275 if (previousItem && previousIsSeparator)
1276 [previousItem setHidden:YES];
1277 } else {
1278 NSArray *itemArray = [menu itemArray];
1279 for (unsigned int i = 0; i < [itemArray count]; ++i) {
1280 NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]);
1281 if (QAction *action = reinterpret_cast<QAction *>([item tag]))
1282 [item setHidden:!action->isVisible()];
1283 }
1284 }
1285}
1286
1287#ifdef QT_MAC_USE_COCOA
1288void qt_cocoaChangeOverrideCursor(const QCursor &cursor)
1289{
1290 QMacCocoaAutoReleasePool pool;
1291 [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) set];
1292}
1293#endif
1294
1295QMacCocoaAutoReleasePool::QMacCocoaAutoReleasePool()
1296{
1297#ifndef QT_MAC_USE_COCOA
1298 NSApplicationLoad();
1299#endif
1300 pool = (void*)[[NSAutoreleasePool alloc] init];
1301}
1302
1303QMacCocoaAutoReleasePool::~QMacCocoaAutoReleasePool()
1304{
1305 [(NSAutoreleasePool*)pool release];
1306}
1307
1308QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.