VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm

Last change on this file was 103711, checked in by vboxsync, 2 months ago

FE/Qt: Get rid of even more iprt includes, s.a. r162071 and r162072.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.8 KB
Line 
1/* $Id: VBoxUtils-darwin-cocoa.mm 103711 2024-03-06 17:44:24Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Declarations of utility classes and functions for handling Darwin Cocoa specific tasks.
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include "VBoxUtils-darwin.h"
29#include "VBoxCocoaHelper.h"
30
31#include <QMenu>
32
33#import <AppKit/NSEvent.h>
34#import <AppKit/NSColor.h>
35#import <AppKit/NSFont.h>
36#import <AppKit/NSScreen.h>
37#import <AppKit/NSScroller.h>
38#import <AppKit/NSWindow.h>
39#import <AppKit/NSImageView.h>
40
41#import <objc/objc-class.h>
42
43/* For the keyboard stuff */
44#include <Carbon/Carbon.h>
45#include "DarwinKeyboard.h"
46
47/** Easy way of dynamical call for 10.7 AppKit functionality we do not yet support. */
48#define NSWindowCollectionBehaviorFullScreenPrimary (1 << 7)
49#define NSFullScreenWindowMask (1 << 14)
50
51NativeNSWindowRef darwinToNativeWindowImpl(NativeNSViewRef pView)
52{
53 NativeNSWindowRef window = NULL;
54 if (pView)
55 window = [pView window];
56
57 return window;
58}
59
60NativeNSViewRef darwinToNativeViewImpl(NativeNSWindowRef pWindow)
61{
62 NativeNSViewRef view = NULL;
63 if (pWindow)
64 view = [pWindow contentView];
65
66 return view;
67}
68
69NativeNSButtonRef darwinNativeButtonOfWindowImpl(NativeNSWindowRef pWindow, StandardWindowButtonType enmButtonType)
70{
71 /* Return corresponding button: */
72 switch (enmButtonType)
73 {
74 case StandardWindowButtonType_Close: return [pWindow standardWindowButton:NSWindowCloseButton];
75 case StandardWindowButtonType_Miniaturize: return [pWindow standardWindowButton:NSWindowMiniaturizeButton];
76 case StandardWindowButtonType_Zoom: return [pWindow standardWindowButton:NSWindowZoomButton];
77 case StandardWindowButtonType_Toolbar: return [pWindow standardWindowButton:NSWindowToolbarButton];
78 case StandardWindowButtonType_DocumentIcon: return [pWindow standardWindowButton:NSWindowDocumentIconButton];
79 case StandardWindowButtonType_DocumentVersions: /*return [pWindow standardWindowButton:NSWindowDocumentVersionsButton];*/ break;
80 case StandardWindowButtonType_FullScreen: /*return [pWindow standardWindowButton:NSWindowFullScreenButton];*/ break;
81 }
82 /* Return Nul by default: */
83 return Nil;
84}
85
86NativeNSImageRef darwinToNSImageRef(const CGImageRef pImage)
87{
88 /* Create a bitmap rep from the image. */
89 NSBitmapImageRep *bitmapRep = [[[NSBitmapImageRep alloc] initWithCGImage:pImage] autorelease];
90 /* Create an NSImage and add the bitmap rep to it */
91 NSImage *image = [[NSImage alloc] init];
92 [image addRepresentation:bitmapRep];
93 return image;
94}
95
96NativeNSImageRef darwinToNSImageRef(const QImage *pImage)
97{
98 /* Create CGImage on the basis of passed QImage: */
99 CGImageRef pCGImage = ::darwinToCGImageRef(pImage);
100 NativeNSImageRef pNSImage = ::darwinToNSImageRef(pCGImage);
101 CGImageRelease(pCGImage);
102 /* Apply device pixel ratio: */
103 double dScaleFactor = pImage->devicePixelRatio();
104 NSSize imageSize = { (CGFloat)pImage->width() / dScaleFactor,
105 (CGFloat)pImage->height() / dScaleFactor };
106 [pNSImage setSize:imageSize];
107 /* Return result: */
108 return pNSImage;
109}
110
111NativeNSImageRef darwinToNSImageRef(const QPixmap *pPixmap)
112{
113 CGImageRef pCGImage = ::darwinToCGImageRef(pPixmap);
114 NativeNSImageRef pNSImage = ::darwinToNSImageRef(pCGImage);
115 CGImageRelease(pCGImage);
116 return pNSImage;
117}
118
119NativeNSImageRef darwinToNSImageRef(const char *pczSource)
120{
121 CGImageRef pCGImage = ::darwinToCGImageRef(pczSource);
122 NativeNSImageRef pNSImage = ::darwinToNSImageRef(pCGImage);
123 CGImageRelease(pCGImage);
124 return pNSImage;
125}
126
127NativeNSStringRef darwinToNativeString(const char* pcszString)
128{
129 return [NSString stringWithUTF8String: pcszString];
130}
131
132QString darwinFromNativeString(NativeNSStringRef pString)
133{
134 return [pString cStringUsingEncoding :NSASCIIStringEncoding];
135}
136
137void darwinSetShowsToolbarButtonImpl(NativeNSWindowRef pWindow, bool fEnabled)
138{
139 [pWindow setShowsToolbarButton:fEnabled];
140}
141
142void darwinLabelWindow(NativeNSWindowRef pWindow, NativeNSImageRef pImage, double dDpr)
143{
144 /* Get the parent view of the close button. */
145 NSView *wv = [[pWindow standardWindowButton:NSWindowCloseButton] superview];
146 if (wv)
147 {
148 /* We have to calculate the size of the title bar for the center case. */
149 NSSize s = [pImage size];
150 NSSize s1 = [wv frame].size;
151 /* Correctly position the label. */
152 NSImageView *iv = [[NSImageView alloc] initWithFrame:NSMakeRect(s1.width - s.width / dDpr,
153 s1.height - s.height / dDpr - 1,
154 s.width / dDpr, s.height / dDpr)];
155 /* Configure the NSImageView for auto moving. */
156 [iv setImage:pImage];
157 [iv setAutoresizesSubviews:true];
158 [iv setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
159 /* Add it to the parent of the close button. */
160 [wv addSubview:iv positioned:NSWindowBelow relativeTo:nil];
161 }
162}
163
164void darwinSetShowsResizeIndicatorImpl(NativeNSWindowRef pWindow, bool fEnabled)
165{
166 [pWindow setShowsResizeIndicator:fEnabled];
167}
168
169void darwinSetHidesAllTitleButtonsImpl(NativeNSWindowRef pWindow)
170{
171 /* Remove all title buttons by changing the style mask. This method is
172 available from 10.6 on only. */
173 if ([pWindow respondsToSelector: @selector(setStyleMask:)])
174 [pWindow performSelector: @selector(setStyleMask:) withObject: (id)NSTitledWindowMask];
175 else
176 {
177 /* On pre 10.6 disable all the buttons currently displayed. Don't use
178 setHidden cause this remove the buttons, but didn't release the
179 place used for the buttons. */
180 NSButton *pButton = [pWindow standardWindowButton:NSWindowCloseButton];
181 if (pButton != Nil)
182 [pButton setEnabled: NO];
183 pButton = [pWindow standardWindowButton:NSWindowMiniaturizeButton];
184 if (pButton != Nil)
185 [pButton setEnabled: NO];
186 pButton = [pWindow standardWindowButton:NSWindowZoomButton];
187 if (pButton != Nil)
188 [pButton setEnabled: NO];
189 pButton = [pWindow standardWindowButton:NSWindowDocumentIconButton];
190 if (pButton != Nil)
191 [pButton setEnabled: NO];
192 }
193}
194
195void darwinSetShowsWindowTransparentImpl(NativeNSWindowRef pWindow, bool fEnabled)
196{
197 if (fEnabled)
198 {
199 [pWindow setOpaque:NO];
200 [pWindow setBackgroundColor:[NSColor clearColor]];
201 [pWindow setHasShadow:NO];
202 }
203 else
204 {
205 [pWindow setOpaque:YES];
206 [pWindow setBackgroundColor:[NSColor windowBackgroundColor]];
207 [pWindow setHasShadow:YES];
208 }
209}
210
211void darwinSetWindowHasShadow(NativeNSWindowRef pWindow, bool fEnabled)
212{
213 if (fEnabled)
214 [pWindow setHasShadow :YES];
215 else
216 [pWindow setHasShadow :NO];
217}
218
219void darwinMinaturizeWindow(NativeNSWindowRef pWindow)
220{
221 RT_NOREF(pWindow);
222// [[NSApplication sharedApplication] miniaturizeAll];
223// printf("bla\n");
224// [pWindow miniaturize:pWindow];
225// [[NSApplication sharedApplication] deactivate];
226// [pWindow performMiniaturize:nil];
227}
228
229void darwinEnableFullscreenSupport(NativeNSWindowRef pWindow)
230{
231 [pWindow setCollectionBehavior :NSWindowCollectionBehaviorFullScreenPrimary];
232}
233
234void darwinEnableTransienceSupport(NativeNSWindowRef pWindow)
235{
236 [pWindow setCollectionBehavior :NSWindowCollectionBehaviorTransient];
237}
238
239void darwinToggleFullscreenMode(NativeNSWindowRef pWindow)
240{
241 /* Toggle native fullscreen mode for passed pWindow. This method is available since 10.7 only. */
242 if ([pWindow respondsToSelector: @selector(toggleFullScreen:)])
243 [pWindow performSelector: @selector(toggleFullScreen:) withObject: (id)nil];
244}
245
246void darwinToggleWindowZoom(NativeNSWindowRef pWindow)
247{
248 /* Toggle native window zoom for passed pWindow. This method is available since 10.0. */
249 if ([pWindow respondsToSelector: @selector(zoom:)])
250 [pWindow performSelector: @selector(zoom:)];
251}
252
253bool darwinIsInFullscreenMode(NativeNSWindowRef pWindow)
254{
255 /* Check whether passed pWindow is in native fullscreen mode. */
256 return [pWindow styleMask] & NSFullScreenWindowMask;
257}
258
259bool darwinIsOnActiveSpace(NativeNSWindowRef pWindow)
260{
261 /* Check whether passed pWindow is on active space. */
262 return [pWindow isOnActiveSpace];
263}
264
265bool darwinScreensHaveSeparateSpaces()
266{
267 /* Check whether screens have separate spaces.
268 * This method is available since 10.9 only. */
269 if ([NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)])
270 return [NSScreen performSelector: @selector(screensHaveSeparateSpaces)];
271 else
272 return false;
273}
274
275bool darwinIsScrollerStyleOverlay()
276{
277 /* Check whether scrollers by default have legacy style.
278 * This method is available since 10.7 only. */
279 if ([NSScroller respondsToSelector: @selector(preferredScrollerStyle)])
280 {
281 const int enmType = (int)(intptr_t)[NSScroller performSelector: @selector(preferredScrollerStyle)];
282 return enmType == NSScrollerStyleOverlay;
283 }
284 else
285 return false;
286}
287
288/**
289 * Calls the + (void)setMouseCoalescingEnabled:(BOOL)flag class method.
290 *
291 * @param fEnabled Whether to enable or disable coalescing.
292 */
293void darwinSetMouseCoalescingEnabled(bool fEnabled)
294{
295 [NSEvent setMouseCoalescingEnabled:fEnabled];
296}
297
298void darwinWindowAnimateResizeImpl(NativeNSWindowRef pWindow, int x, int y, int width, int height)
299{
300 RT_NOREF(x, y, width);
301
302 /* It seems that Qt doesn't return the height of the window with the
303 * toolbar height included. So add this size manually. Could easily be that
304 * the Trolls fix this in the final release. */
305 NSToolbar *toolbar = [pWindow toolbar];
306 NSRect windowFrame = [pWindow frame];
307 int toolbarHeight = 0;
308 if(toolbar && [toolbar isVisible])
309 toolbarHeight = NSHeight(windowFrame) - NSHeight([[pWindow contentView] frame]);
310 int h = height + toolbarHeight;
311 int h1 = h - NSHeight(windowFrame);
312 windowFrame.size.height = h;
313 windowFrame.origin.y -= h1;
314
315 [pWindow setFrame:windowFrame display:YES animate: YES];
316}
317
318void darwinWindowAnimateResizeNewImpl(NativeNSWindowRef pWindow, int height, bool fAnimate)
319{
320 /* It seems that Qt doesn't return the height of the window with the
321 * toolbar height included. So add this size manually. Could easily be that
322 * the Trolls fix this in the final release. */
323 NSToolbar *toolbar = [pWindow toolbar];
324 NSRect windowFrame = [pWindow frame];
325 int toolbarHeight = 0;
326 if(toolbar && [toolbar isVisible])
327 toolbarHeight = NSHeight(windowFrame) - NSHeight([[pWindow contentView] frame]);
328 int h = height + toolbarHeight;
329 int h1 = h - NSHeight(windowFrame);
330 windowFrame.size.height = h;
331 windowFrame.origin.y -= h1;
332
333 [pWindow setFrame:windowFrame display:YES animate: fAnimate ? YES : NO];
334}
335
336void darwinTest(NativeNSViewRef pViewOld, NativeNSViewRef pViewNew, int h)
337{
338 NSMutableDictionary *pDicts[3] = { nil, nil, nil };
339 int c = 0;
340
341 /* Scaling necessary? */
342 if (h != -1)
343 {
344 NSWindow *pWindow = [(pViewOld ? pViewOld : pViewNew) window];
345 NSToolbar *toolbar = [pWindow toolbar];
346 NSRect windowFrame = [pWindow frame];
347 /* Dictionary containing all animation parameters. */
348 pDicts[c] = [NSMutableDictionary dictionaryWithCapacity:2];
349 /* Specify the animation target. */
350 [pDicts[c] setObject:pWindow forKey:NSViewAnimationTargetKey];
351 /* Scaling effect. */
352 [pDicts[c] setObject:[NSValue valueWithRect:windowFrame] forKey:NSViewAnimationStartFrameKey];
353 int toolbarHeight = 0;
354 if(toolbar && [toolbar isVisible])
355 toolbarHeight = NSHeight(windowFrame) - NSHeight([[pWindow contentView] frame]);
356 int h1 = h + toolbarHeight;
357 int h2 = h1 - NSHeight(windowFrame);
358 windowFrame.size.height = h1;
359 windowFrame.origin.y -= h2;
360 [pDicts[c] setObject:[NSValue valueWithRect:windowFrame] forKey:NSViewAnimationEndFrameKey];
361 ++c;
362 }
363 /* Fade out effect. */
364 if (pViewOld)
365 {
366 /* Dictionary containing all animation parameters. */
367 pDicts[c] = [NSMutableDictionary dictionaryWithCapacity:2];
368 /* Specify the animation target. */
369 [pDicts[c] setObject:pViewOld forKey:NSViewAnimationTargetKey];
370 /* Fade out effect. */
371 [pDicts[c] setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
372 ++c;
373 }
374 /* Fade in effect. */
375 if (pViewNew)
376 {
377 /* Dictionary containing all animation parameters. */
378 pDicts[c] = [NSMutableDictionary dictionaryWithCapacity:2];
379 /* Specify the animation target. */
380 [pDicts[c] setObject:pViewNew forKey:NSViewAnimationTargetKey];
381 /* Fade in effect. */
382 [pDicts[c] setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
383 ++c;
384 }
385 /* Create our animation object. */
386 NSViewAnimation *pAni = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:pDicts count:c]];
387 [pAni setDuration:.15];
388 [pAni setAnimationCurve:NSAnimationEaseIn];
389 [pAni setAnimationBlockingMode:NSAnimationBlocking];
390// [pAni setAnimationBlockingMode:NSAnimationNonblockingThreaded];
391
392 /* Run the animation. */
393 [pAni startAnimation];
394 /* Cleanup */
395 [pAni release];
396}
397
398void darwinWindowInvalidateShadowImpl(NativeNSWindowRef pWindow)
399{
400 [pWindow invalidateShadow];
401}
402
403int darwinWindowToolBarHeight(NativeNSWindowRef pWindow)
404{
405 NSToolbar *toolbar = [pWindow toolbar];
406 NSRect windowFrame = [pWindow frame];
407 int toolbarHeight = 0;
408 int theight = (NSHeight([NSWindow contentRectForFrameRect:[pWindow frame] styleMask:[pWindow styleMask]]) - NSHeight([[pWindow contentView] frame]));
409 /* toolbar height: */
410 if(toolbar && [toolbar isVisible])
411 /* title bar height: */
412 toolbarHeight = NSHeight(windowFrame) - NSHeight([[pWindow contentView] frame]) - theight;
413
414 return toolbarHeight;
415}
416
417int darwinWindowTitleHeight(NativeNSWindowRef pWindow)
418{
419 NSView *pSuperview = [[pWindow standardWindowButton:NSWindowCloseButton] superview];
420 NSSize sz = [pSuperview frame].size;
421 return sz.height;
422}
423
424bool darwinIsToolbarVisible(NativeNSWindowRef pWindow)
425{
426 NSToolbar *pToolbar = [pWindow toolbar];
427
428 return [pToolbar isVisible] == YES;
429}
430
431bool darwinIsWindowMaximized(NativeNSWindowRef pWindow)
432{
433 /* Mac OS X API NSWindow isZoomed returns true even for almost maximized windows,
434 * So implementing this by ourseleves by comparing visible screen-frame & window-frame: */
435 NSRect windowFrame = [pWindow frame];
436 NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
437
438 return (windowFrame.origin.x == screenFrame.origin.x) &&
439 (windowFrame.origin.y == screenFrame.origin.y) &&
440 (windowFrame.size.width == screenFrame.size.width) &&
441 (windowFrame.size.height == screenFrame.size.height);
442}
443
444bool darwinOpenFile(NativeNSStringRef pstrFile)
445{
446 return [[NSWorkspace sharedWorkspace] openFile:pstrFile];
447}
448
449float darwinSmallFontSize()
450{
451 float size = [NSFont systemFontSizeForControlSize: NSSmallControlSize];
452
453 return size;
454}
455
456bool darwinMouseGrabEvents(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)
457{
458 NSEvent *pEvent = (NSEvent*)pvCocoaEvent;
459 NSEventType EvtType = [pEvent type];
460 NSWindow *pWin = ::darwinToNativeWindow((QWidget*)pvUser);
461 if ( pWin == [pEvent window]
462 && ( EvtType == NSLeftMouseDown
463 || EvtType == NSLeftMouseUp
464 || EvtType == NSRightMouseDown
465 || EvtType == NSRightMouseUp
466 || EvtType == NSOtherMouseDown
467 || EvtType == NSOtherMouseUp
468 || EvtType == NSLeftMouseDragged
469 || EvtType == NSRightMouseDragged
470 || EvtType == NSOtherMouseDragged
471 || EvtType == NSMouseMoved
472 || EvtType == NSScrollWheel))
473 {
474 /* When the mouse position is not associated to the mouse cursor, the x
475 and y values are reported as delta values. */
476 float x = [pEvent deltaX];
477 float y = [pEvent deltaY];
478 if (EvtType == NSScrollWheel)
479 {
480 /* In the scroll wheel case we have to do some magic, cause a
481 normal scroll wheel on a mouse behaves different to a trackpad.
482 The following is used within Qt. We use the same to get a
483 similar behavior. */
484 if ([pEvent respondsToSelector:@selector(deviceDeltaX:)])
485 x = (float)(intptr_t)[pEvent performSelector:@selector(deviceDeltaX)] * 2;
486 else
487 x = qBound(-120, (int)(x * 10000), 120);
488 if ([pEvent respondsToSelector:@selector(deviceDeltaY:)])
489 y = (float)(intptr_t)[pEvent performSelector:@selector(deviceDeltaY)] * 2;
490 else
491 y = qBound(-120, (int)(y * 10000), 120);
492 }
493 /* Get the buttons which where pressed when this event occurs. We have
494 to use Carbon here, cause the Cocoa method [NSEvent pressedMouseButtons]
495 is >= 10.6. */
496 uint32 buttonMask = 0;
497 GetEventParameter((EventRef)pvCarbonEvent, kEventParamMouseChord, typeUInt32, 0,
498 sizeof(buttonMask), 0, &buttonMask);
499 /* Produce a Qt event out of our info. */
500 ::darwinSendMouseGrabEvents((QWidget*)pvUser, EvtType, [pEvent buttonNumber], buttonMask, x, y);
501 return true;
502 }
503 return false;
504}
505
506/* Cocoa event handler which checks if the user right clicked at the unified
507 toolbar or the title area. */
508bool darwinUnifiedToolbarEvents(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)
509{
510 RT_NOREF(pvCarbonEvent);
511
512 NSEvent *pEvent = (NSEvent*)pvCocoaEvent;
513 NSEventType EvtType = [pEvent type];
514 NSWindow *pWin = ::darwinToNativeWindow((QWidget*)pvUser);
515 /* First check for the right event type and that we are processing events
516 from the window which was registered by the user. */
517 if ( EvtType == NSRightMouseDown
518 && pWin == [pEvent window])
519 {
520 /* Get the mouse position of the event (screen coordinates) */
521 NSPoint point = [NSEvent mouseLocation];
522 /* Get the frame rectangle of the window (screen coordinates) */
523 NSRect winFrame = [pWin frame];
524 /* Calculate the height of the title and the toolbar */
525 int i = NSHeight(winFrame) - NSHeight([[pWin contentView] frame]);
526 /* Based on that height create a rectangle of the unified toolbar + title */
527 winFrame.origin.y += winFrame.size.height - i;
528 winFrame.size.height = i;
529 /* Check if the mouse press event was on the unified toolbar or title */
530 if (NSMouseInRect(point, winFrame, NO))
531 /* Create a Qt context menu event, with flipped screen coordinates */
532 ::darwinCreateContextMenuEvent(pvUser, point.x, NSHeight([[pWin screen] frame]) - point.y);
533 }
534 return false;
535}
536
537/**
538 * Check for some default application key combinations a Mac user expect, like
539 * CMD+Q or CMD+H.
540 *
541 * @returns true if such a key combo was hit, false otherwise.
542 * @param pEvent The Cocoa event.
543 */
544bool darwinIsApplicationCommand(ConstNativeNSEventRef pEvent)
545{
546 NSEventType eEvtType = [pEvent type];
547 bool fGlobalHotkey = false;
548//
549// if ( (eEvtType == NSKeyDown || eEvtType == NSKeyUp)
550// && [[NSApp mainMenu] performKeyEquivalent:pEvent])
551// return true;
552// return false;
553// && [[[NSApp mainMenu] delegate] menuHasKeyEquivalent:[NSApp mainMenu] forEvent:pEvent target:b action:a])
554
555 switch (eEvtType)
556 {
557 case NSKeyDown:
558 case NSKeyUp:
559 {
560 NSUInteger fEvtMask = [pEvent modifierFlags];
561 unsigned short KeyCode = [pEvent keyCode];
562 if ( ((fEvtMask & (NX_NONCOALSESCEDMASK | NX_COMMANDMASK | NX_DEVICELCMDKEYMASK)) == (NX_NONCOALSESCEDMASK | NX_COMMANDMASK | NX_DEVICELCMDKEYMASK)) /* L+CMD */
563 || ((fEvtMask & (NX_NONCOALSESCEDMASK | NX_COMMANDMASK | NX_DEVICERCMDKEYMASK)) == (NX_NONCOALSESCEDMASK | NX_COMMANDMASK | NX_DEVICERCMDKEYMASK))) /* R+CMD */
564 {
565 if ( KeyCode == 0x0c /* CMD+Q (Quit) */
566 || KeyCode == 0x04) /* CMD+H (Hide) */
567 fGlobalHotkey = true;
568 }
569 else if ( ((fEvtMask & (NX_NONCOALSESCEDMASK | NX_ALTERNATEMASK | NX_DEVICELALTKEYMASK | NX_COMMANDMASK | NX_DEVICELCMDKEYMASK)) == (NX_NONCOALSESCEDMASK | NX_ALTERNATEMASK | NX_DEVICELALTKEYMASK | NX_COMMANDMASK | NX_DEVICELCMDKEYMASK)) /* L+ALT+CMD */
570 || ((fEvtMask & (NX_NONCOALSESCEDMASK | NX_ALTERNATEMASK | NX_DEVICERCMDKEYMASK | NX_COMMANDMASK | NX_DEVICERCMDKEYMASK)) == (NX_NONCOALSESCEDMASK | NX_ALTERNATEMASK | NX_DEVICERCMDKEYMASK | NX_COMMANDMASK | NX_DEVICERCMDKEYMASK))) /* R+ALT+CMD */
571 {
572 if (KeyCode == 0x04) /* ALT+CMD+H (Hide-Others) */
573 fGlobalHotkey = true;
574 }
575 break;
576 }
577 default: break;
578 }
579 return fGlobalHotkey;
580}
581
582void darwinRetranslateAppMenu()
583{
584 /* This is purely Qt internal. If the Trolls change something here, it will
585 not work anymore, but at least it will not be a burning man. */
586 if ([NSApp respondsToSelector:@selector(qt_qcocoamenuLoader)])
587 {
588 id loader = [NSApp performSelector:@selector(qt_qcocoamenuLoader)];
589 if ([loader respondsToSelector:@selector(qtTranslateApplicationMenu)])
590 [loader performSelector:@selector(qtTranslateApplicationMenu)];
591 }
592}
593
594/* Our resize proxy singleton. This class has two major tasks. First it is used
595 to proxy the windowWillResize selector of the Qt delegate. As this is class
596 global and therewith done for all Qt window instances, we have to track the
597 windows we are interested in. This is the second task. */
598@interface UIResizeProxy: NSObject
599{
600 NSMutableArray *m_pArray;
601 bool m_fInit;
602}
603+(UIResizeProxy*)sharedResizeProxy;
604-(void)addWindow:(NSWindow*)pWindow;
605-(void)removeWindow:(NSWindow*)pWindow;
606-(BOOL)containsWindow:(NSWindow*)pWindow;
607@end
608
609static UIResizeProxy *gSharedResizeProxy = nil;
610
611@implementation UIResizeProxy
612+(UIResizeProxy*)sharedResizeProxy
613{
614 if (gSharedResizeProxy == nil)
615 gSharedResizeProxy = [[super allocWithZone:NULL] init];
616 return gSharedResizeProxy;
617}
618-(id)init
619{
620 self = [super init];
621
622 m_fInit = false;
623
624 return self;
625}
626- (void)addWindow:(NSWindow*)pWindow
627{
628 if (!m_fInit)
629 {
630 /* Create an array which contains the registered windows. */
631 m_pArray = [[NSMutableArray alloc] init];
632 /* Swizzle the windowWillResize method. This means replacing the
633 original method with our own one and reroute the original one to
634 another name. */
635 Class oriClass = [[pWindow delegate] class];
636 Class myClass = [UIResizeProxy class];
637 SEL oriSel = @selector(windowWillResize:toSize:);
638 SEL qtSel = @selector(qtWindowWillResize:toSize:);
639 Method m1 = class_getInstanceMethod(oriClass, oriSel);
640 Method m2 = class_getInstanceMethod(myClass, oriSel);
641 Method m3 = class_getInstanceMethod(myClass, qtSel);
642 /* Overwrite the original implementation with our own one. old contains
643 the old implementation. */
644 IMP old = method_setImplementation(m1, method_getImplementation(m2));
645 /* Add a new method to our class with the old implementation. */
646 class_addMethod(oriClass, qtSel, old, method_getTypeEncoding(m3));
647 m_fInit = true;
648 }
649 [m_pArray addObject:pWindow];
650}
651- (void)removeWindow:(NSWindow*)pWindow
652{
653 [m_pArray removeObject:pWindow];
654}
655- (BOOL)containsWindow:(NSWindow*)pWindow
656{
657 return [m_pArray containsObject:pWindow];
658}
659- (NSSize)qtWindowWillResize:(NSWindow *)pWindow toSize:(NSSize)newFrameSize
660{
661 RT_NOREF(pWindow);
662 /* This is a fake implementation. It will be replaced by the original Qt
663 method. */
664 return newFrameSize;
665}
666- (NSSize)windowWillResize:(NSWindow *)pWindow toSize:(NSSize)newFrameSize
667{
668 /* Call the original implementation for newFrameSize. */
669 NSSize qtSize = [self qtWindowWillResize:pWindow toSize:newFrameSize];
670 /* Check if we are responsible for this window. */
671 if (![[UIResizeProxy sharedResizeProxy] containsWindow:pWindow])
672 return qtSize;
673 /* The static modifier method in NSEvent is >= 10.6. It allows us to check
674 the shift modifier state during the resize. If it is not available the
675 user have to press shift before he start to resize. */
676 if ([NSEvent respondsToSelector:@selector(modifierFlags)])
677 {
678 if (((int)(intptr_t)[NSEvent performSelector:@selector(modifierFlags)] & NSShiftKeyMask) == NSShiftKeyMask)
679 return qtSize;
680 }
681 else
682 {
683 /* Shift key pressed when this resize event was initiated? */
684 if (([pWindow resizeFlags] & NSShiftKeyMask) == NSShiftKeyMask)
685 return qtSize;
686 }
687 /* The default case is to calculate the aspect radio of the old size and
688 used it for the new size. */
689 NSSize s = [pWindow frame].size;
690 double a = (double)s.width / s.height;
691 NSSize newSize = NSMakeSize(newFrameSize.width, newFrameSize.width / a);
692 /* We have to make sure the new rectangle meets the minimum requirements. */
693 NSSize testSize = [self qtWindowWillResize:pWindow toSize:newSize];
694 if ( testSize.width > newSize.width
695 || testSize.height > newSize.height)
696 {
697 double w1 = testSize.width / newSize.width;
698 double h1 = testSize.height / newSize.height;
699 if ( w1 > 1
700 && w1 > h1)
701 {
702 newSize.width = testSize.width;
703 newSize.height = testSize.width * a;
704 }else if (h1 > 1)
705 {
706 newSize.width = testSize.height * a;
707 newSize.height = testSize.height;
708 }
709 }
710 return newSize;
711}
712@end
713
714void darwinInstallResizeDelegate(NativeNSWindowRef pWindow)
715{
716 [[UIResizeProxy sharedResizeProxy] addWindow:pWindow];
717}
718
719void darwinUninstallResizeDelegate(NativeNSWindowRef pWindow)
720{
721 [[UIResizeProxy sharedResizeProxy] removeWindow:pWindow];
722}
723
724void *darwinCocoaToCarbonEvent(void *pvCocoaEvent)
725{
726 NSEvent *pEvent = (NSEvent*)pvCocoaEvent;
727 return (void*)[pEvent eventRef];
728}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use