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

Last change on this file since 763 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

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