2 * MACDRV Cocoa window code
4 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #import <Carbon/Carbon.h>
22 #import <CoreVideo/CoreVideo.h>
24 #import "cocoa_window.h"
26 #include "macdrv_cocoa.h"
28 #import "cocoa_event.h"
29 #import "cocoa_opengl.h"
32 #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
34 NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
35 NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8,
36 NSWindowFullScreenButton = 7,
37 NSFullScreenWindowMask = 1 << 14,
40 @interface NSWindow (WineFullScreenExtensions)
41 - (void) toggleFullScreen:(id)sender;
46 /* Additional Mac virtual keycode, to complement those in Carbon's <HIToolbox/Events.h>. */
48 kVK_RightCommand = 0x36, /* Invented for Wine; was unused */
52 static NSUInteger style_mask_for_features(const struct macdrv_window_features* wf)
54 NSUInteger style_mask;
58 style_mask = NSTitledWindowMask;
59 if (wf->close_button) style_mask |= NSClosableWindowMask;
60 if (wf->minimize_button) style_mask |= NSMiniaturizableWindowMask;
61 if (wf->resizable || wf->maximize_button) style_mask |= NSResizableWindowMask;
62 if (wf->utility) style_mask |= NSUtilityWindowMask;
64 else style_mask = NSBorderlessWindowMask;
70 static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
73 for (screen in screens)
75 if (NSIntersectsRect(frame, [screen frame]))
82 static NSScreen* screen_covered_by_rect(NSRect rect, NSArray* screens)
84 for (NSScreen* screen in screens)
86 if (NSContainsRect(rect, [screen frame]))
93 /* We rely on the supposedly device-dependent modifier flags to distinguish the
94 keys on the left side of the keyboard from those on the right. Some event
95 sources don't set those device-depdendent flags. If we see a device-independent
96 flag for a modifier without either corresponding device-dependent flag, assume
98 static inline void fix_device_modifiers_by_generic(NSUInteger* modifiers)
100 if ((*modifiers & (NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK)) == NX_COMMANDMASK)
101 *modifiers |= NX_DEVICELCMDKEYMASK;
102 if ((*modifiers & (NX_SHIFTMASK | NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK)) == NX_SHIFTMASK)
103 *modifiers |= NX_DEVICELSHIFTKEYMASK;
104 if ((*modifiers & (NX_CONTROLMASK | NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK)) == NX_CONTROLMASK)
105 *modifiers |= NX_DEVICELCTLKEYMASK;
106 if ((*modifiers & (NX_ALTERNATEMASK | NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK)) == NX_ALTERNATEMASK)
107 *modifiers |= NX_DEVICELALTKEYMASK;
110 /* As we manipulate individual bits of a modifier mask, we can end up with
111 inconsistent sets of flags. In particular, we might set or clear one of the
112 left/right-specific bits, but not the corresponding non-side-specific bit.
113 Fix that. If either side-specific bit is set, set the non-side-specific bit,
114 otherwise clear it. */
115 static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
117 if (*modifiers & (NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK))
118 *modifiers |= NX_COMMANDMASK;
120 *modifiers &= ~NX_COMMANDMASK;
121 if (*modifiers & (NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK))
122 *modifiers |= NX_SHIFTMASK;
124 *modifiers &= ~NX_SHIFTMASK;
125 if (*modifiers & (NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK))
126 *modifiers |= NX_CONTROLMASK;
128 *modifiers &= ~NX_CONTROLMASK;
129 if (*modifiers & (NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK))
130 *modifiers |= NX_ALTERNATEMASK;
132 *modifiers &= ~NX_ALTERNATEMASK;
135 static inline NSUInteger adjusted_modifiers_for_option_behavior(NSUInteger modifiers)
137 fix_device_modifiers_by_generic(&modifiers);
138 if (left_option_is_alt && (modifiers & NX_DEVICELALTKEYMASK))
140 modifiers |= NX_DEVICELCMDKEYMASK;
141 modifiers &= ~NX_DEVICELALTKEYMASK;
143 if (right_option_is_alt && (modifiers & NX_DEVICERALTKEYMASK))
145 modifiers |= NX_DEVICERCMDKEYMASK;
146 modifiers &= ~NX_DEVICERALTKEYMASK;
148 fix_generic_modifiers_by_device(&modifiers);
154 @interface NSWindow (WineAccessPrivateMethods)
155 - (id) _displayChanged;
159 @interface WineDisplayLink : NSObject
161 CGDirectDisplayID _displayID;
162 CVDisplayLinkRef _link;
163 NSMutableSet* _windows;
165 NSTimeInterval _actualRefreshPeriod;
166 NSTimeInterval _nominalRefreshPeriod;
169 - (id) initWithDisplayID:(CGDirectDisplayID)displayID;
171 - (void) addWindow:(WineWindow*)window;
172 - (void) removeWindow:(WineWindow*)window;
174 - (NSTimeInterval) refreshPeriod;
180 @implementation WineDisplayLink
182 static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext);
184 - (id) initWithDisplayID:(CGDirectDisplayID)displayID
189 CVReturn status = CVDisplayLinkCreateWithCGDisplay(displayID, &_link);
190 if (status == kCVReturnSuccess && !_link)
191 status = kCVReturnError;
192 if (status == kCVReturnSuccess)
193 status = CVDisplayLinkSetOutputCallback(_link, WineDisplayLinkCallback, self);
194 if (status != kCVReturnSuccess)
200 _displayID = displayID;
201 _windows = [[NSMutableSet alloc] init];
210 CVDisplayLinkStop(_link);
211 CVDisplayLinkRelease(_link);
217 - (void) addWindow:(WineWindow*)window
219 @synchronized(self) {
220 BOOL needsStart = !_windows.count;
221 [_windows addObject:window];
223 CVDisplayLinkStart(_link);
227 - (void) removeWindow:(WineWindow*)window
229 @synchronized(self) {
230 BOOL wasRunning = _windows.count > 0;
231 [_windows removeObject:window];
232 if (wasRunning && !_windows.count)
233 CVDisplayLinkStop(_link);
240 @synchronized(self) {
241 windows = [_windows copy];
243 dispatch_async(dispatch_get_main_queue(), ^{
244 BOOL anyDisplayed = FALSE;
245 for (WineWindow* window in windows)
247 if ([window viewsNeedDisplay])
249 [window displayIfNeeded];
254 CVDisplayLinkStop(_link);
259 - (NSTimeInterval) refreshPeriod
261 if (_actualRefreshPeriod || (_actualRefreshPeriod = CVDisplayLinkGetActualOutputVideoRefreshPeriod(_link)))
262 return _actualRefreshPeriod;
264 if (_nominalRefreshPeriod)
265 return _nominalRefreshPeriod;
267 CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(_link);
268 if (time.flags & kCVTimeIsIndefinite)
270 _nominalRefreshPeriod = time.timeValue / (double)time.timeScale;
271 return _nominalRefreshPeriod;
276 CVDisplayLinkStart(_link);
279 static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
281 WineDisplayLink* link = displayLinkContext;
283 return kCVReturnSuccess;
289 @interface WineContentView : NSView <NSTextInputClient>
291 NSMutableArray* glContexts;
292 NSMutableArray* pendingGlContexts;
293 BOOL clearedGlSurface;
295 NSMutableAttributedString* markedText;
296 NSRange markedTextSelection;
299 - (void) addGLContext:(WineOpenGLContext*)context;
300 - (void) removeGLContext:(WineOpenGLContext*)context;
301 - (void) updateGLContexts;
306 @interface WineWindow ()
308 @property (readwrite, nonatomic) BOOL disabled;
309 @property (readwrite, nonatomic) BOOL noActivate;
310 @property (readwrite, nonatomic) BOOL floating;
311 @property (readwrite, getter=isFakingClose, nonatomic) BOOL fakingClose;
312 @property (retain, nonatomic) NSWindow* latentParentWindow;
314 @property (nonatomic) void* hwnd;
315 @property (retain, readwrite, nonatomic) WineEventQueue* queue;
317 @property (nonatomic) void* surface;
318 @property (nonatomic) pthread_mutex_t* surface_mutex;
320 @property (copy, nonatomic) NSBezierPath* shape;
321 @property (copy, nonatomic) NSData* shapeData;
322 @property (nonatomic) BOOL shapeChangedSinceLastDraw;
323 @property (readonly, nonatomic) BOOL needsTransparency;
325 @property (nonatomic) BOOL colorKeyed;
326 @property (nonatomic) CGFloat colorKeyRed, colorKeyGreen, colorKeyBlue;
327 @property (nonatomic) BOOL usePerPixelAlpha;
329 @property (assign, nonatomic) void* imeData;
330 @property (nonatomic) BOOL commandDone;
332 @property (readonly, copy, nonatomic) NSArray* childWineWindows;
334 - (void) updateColorSpace;
335 - (void) updateForGLSubviews;
337 - (BOOL) becameEligibleParentOrChild;
338 - (void) becameIneligibleChild;
343 @implementation WineContentView
347 [markedText release];
348 [glContexts release];
349 [pendingGlContexts release];
358 - (void) drawRect:(NSRect)rect
360 WineWindow* window = (WineWindow*)[self window];
362 for (WineOpenGLContext* context in pendingGlContexts)
364 if (!clearedGlSurface)
366 context.shouldClearToBlack = TRUE;
367 clearedGlSurface = TRUE;
369 context.needsUpdate = TRUE;
371 [glContexts addObjectsFromArray:pendingGlContexts];
372 [pendingGlContexts removeAllObjects];
374 if ([window contentView] != self)
377 if (window.shapeChangedSinceLastDraw && window.shape && !window.colorKeyed && !window.usePerPixelAlpha)
379 [[NSColor clearColor] setFill];
382 [window.shape addClip];
384 [[NSColor windowBackgroundColor] setFill];
388 if (window.surface && window.surface_mutex &&
389 !pthread_mutex_lock(window.surface_mutex))
394 if (get_surface_blit_rects(window.surface, &rects, &count) && count)
396 CGContextRef context;
399 [window.shape addClip];
401 context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
402 CGContextSetBlendMode(context, kCGBlendModeCopy);
403 CGContextSetInterpolationQuality(context, kCGInterpolationNone);
405 for (i = 0; i < count; i++)
410 imageRect = CGRectIntersection(rects[i], NSRectToCGRect(rect));
411 image = create_surface_image(window.surface, &imageRect, FALSE);
415 if (window.colorKeyed)
417 CGImageRef maskedImage;
418 CGFloat components[] = { window.colorKeyRed - 0.5, window.colorKeyRed + 0.5,
419 window.colorKeyGreen - 0.5, window.colorKeyGreen + 0.5,
420 window.colorKeyBlue - 0.5, window.colorKeyBlue + 0.5 };
421 maskedImage = CGImageCreateWithMaskingColors(image, components);
424 CGImageRelease(image);
429 CGContextDrawImage(context, imageRect, image);
431 CGImageRelease(image);
436 pthread_mutex_unlock(window.surface_mutex);
439 // If the window may be transparent, then we have to invalidate the
440 // shadow every time we draw. Also, if this is the first time we've
441 // drawn since changing from transparent to opaque.
442 if (window.colorKeyed || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw)
444 window.shapeChangedSinceLastDraw = FALSE;
445 [window invalidateShadow];
449 - (void) addGLContext:(WineOpenGLContext*)context
452 glContexts = [[NSMutableArray alloc] init];
453 if (!pendingGlContexts)
454 pendingGlContexts = [[NSMutableArray alloc] init];
456 if ([[self window] windowNumber] > 0 && !NSIsEmptyRect([self visibleRect]))
458 [glContexts addObject:context];
459 if (!clearedGlSurface)
461 context.shouldClearToBlack = TRUE;
462 clearedGlSurface = TRUE;
464 context.needsUpdate = TRUE;
468 [pendingGlContexts addObject:context];
469 [self setNeedsDisplay:YES];
472 [(WineWindow*)[self window] updateForGLSubviews];
475 - (void) removeGLContext:(WineOpenGLContext*)context
477 [glContexts removeObjectIdenticalTo:context];
478 [pendingGlContexts removeObjectIdenticalTo:context];
479 [(WineWindow*)[self window] updateForGLSubviews];
482 - (void) updateGLContexts
484 for (WineOpenGLContext* context in glContexts)
485 context.needsUpdate = TRUE;
488 - (BOOL) hasGLContext
490 return [glContexts count] || [pendingGlContexts count];
493 - (BOOL) acceptsFirstMouse:(NSEvent*)theEvent
498 - (BOOL) preservesContentDuringLiveResize
500 // Returning YES from this tells Cocoa to keep our view's content during
501 // a Cocoa-driven resize. In theory, we're also supposed to override
502 // -setFrameSize: to mark exposed sections as needing redisplay, but
503 // user32 will take care of that in a roundabout way. This way, we don't
504 // redraw until the window surface is flushed.
506 // This doesn't do anything when we resize the window ourselves.
510 - (BOOL)acceptsFirstResponder
512 return [[self window] contentView] == self;
515 - (BOOL) mouseDownCanMoveWindow
520 - (void) completeText:(NSString*)text
523 WineWindow* window = (WineWindow*)[self window];
525 event = macdrv_create_event(IM_SET_TEXT, window);
526 event->im_set_text.data = [window imeData];
527 event->im_set_text.text = (CFStringRef)[text copy];
528 event->im_set_text.complete = TRUE;
530 [[window queue] postEvent:event];
532 macdrv_release_event(event);
534 [markedText deleteCharactersInRange:NSMakeRange(0, [markedText length])];
535 markedTextSelection = NSMakeRange(0, 0);
536 [[self inputContext] discardMarkedText];
539 - (NSFocusRingType) focusRingType
541 return NSFocusRingTypeNone;
545 * ---------- NSTextInputClient methods ----------
547 - (NSTextInputContext*) inputContext
550 markedText = [[NSMutableAttributedString alloc] init];
551 return [super inputContext];
554 - (void) insertText:(id)string replacementRange:(NSRange)replacementRange
556 if ([string isKindOfClass:[NSAttributedString class]])
557 string = [string string];
559 if ([string isKindOfClass:[NSString class]])
560 [self completeText:string];
563 - (void) doCommandBySelector:(SEL)aSelector
565 [(WineWindow*)[self window] setCommandDone:TRUE];
568 - (void) setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
570 if ([string isKindOfClass:[NSAttributedString class]])
571 string = [string string];
573 if ([string isKindOfClass:[NSString class]])
576 WineWindow* window = (WineWindow*)[self window];
578 if (replacementRange.location == NSNotFound)
579 replacementRange = NSMakeRange(0, [markedText length]);
581 [markedText replaceCharactersInRange:replacementRange withString:string];
582 markedTextSelection = selectedRange;
583 markedTextSelection.location += replacementRange.location;
585 event = macdrv_create_event(IM_SET_TEXT, window);
586 event->im_set_text.data = [window imeData];
587 event->im_set_text.text = (CFStringRef)[[markedText string] copy];
588 event->im_set_text.complete = FALSE;
589 event->im_set_text.cursor_pos = markedTextSelection.location + markedTextSelection.length;
591 [[window queue] postEvent:event];
593 macdrv_release_event(event);
595 [[self inputContext] invalidateCharacterCoordinates];
601 [self completeText:nil];
604 - (NSRange) selectedRange
606 return markedTextSelection;
609 - (NSRange) markedRange
611 NSRange range = NSMakeRange(0, [markedText length]);
613 range.location = NSNotFound;
617 - (BOOL) hasMarkedText
619 return [markedText length] > 0;
622 - (NSAttributedString*) attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
624 if (aRange.location >= [markedText length])
627 aRange = NSIntersectionRange(aRange, NSMakeRange(0, [markedText length]));
629 *actualRange = aRange;
630 return [markedText attributedSubstringFromRange:aRange];
633 - (NSArray*) validAttributesForMarkedText
635 return [NSArray array];
638 - (NSRect) firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
641 WineWindow* window = (WineWindow*)[self window];
644 aRange = NSIntersectionRange(aRange, NSMakeRange(0, [markedText length]));
646 query = macdrv_create_query();
647 query->type = QUERY_IME_CHAR_RECT;
648 query->window = (macdrv_window)[window retain];
649 query->ime_char_rect.data = [window imeData];
650 query->ime_char_rect.range = CFRangeMake(aRange.location, aRange.length);
652 if ([window.queue query:query timeout:1])
654 aRange = NSMakeRange(query->ime_char_rect.range.location, query->ime_char_rect.range.length);
655 ret = NSRectFromCGRect(query->ime_char_rect.rect);
656 [[WineApplicationController sharedController] flipRect:&ret];
659 ret = NSMakeRect(100, 100, aRange.length ? 1 : 0, 12);
661 macdrv_release_query(query);
664 *actualRange = aRange;
668 - (NSUInteger) characterIndexForPoint:(NSPoint)aPoint
673 - (NSInteger) windowLevel
675 return [[self window] level];
681 @implementation WineWindow
683 static WineWindow* causing_becomeKeyWindow;
685 @synthesize disabled, noActivate, floating, fullscreen, fakingClose, latentParentWindow, hwnd, queue;
686 @synthesize surface, surface_mutex;
687 @synthesize shape, shapeData, shapeChangedSinceLastDraw;
688 @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue;
689 @synthesize usePerPixelAlpha;
690 @synthesize imeData, commandDone;
692 + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
693 windowFrame:(NSRect)window_frame
695 queue:(WineEventQueue*)queue
698 WineContentView* contentView;
699 NSTrackingArea* trackingArea;
700 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
702 [[WineApplicationController sharedController] flipRect:&window_frame];
704 window = [[[self alloc] initWithContentRect:window_frame
705 styleMask:style_mask_for_features(wf)
706 backing:NSBackingStoreBuffered
707 defer:YES] autorelease];
709 if (!window) return nil;
711 /* Standardize windows to eliminate differences between titled and
712 borderless windows and between NSWindow and NSPanel. */
713 [window setHidesOnDeactivate:NO];
714 [window setReleasedWhenClosed:NO];
716 [window setOneShot:YES];
717 [window disableCursorRects];
718 [window setShowsResizeIndicator:NO];
719 [window setHasShadow:wf->shadow];
720 [window setAcceptsMouseMovedEvents:YES];
721 [window setColorSpace:[NSColorSpace genericRGBColorSpace]];
722 [window setDelegate:window];
723 [window setAutodisplay:NO];
725 window.queue = queue;
726 window->savedContentMinSize = NSZeroSize;
727 window->savedContentMaxSize = NSMakeSize(FLT_MAX, FLT_MAX);
728 window->resizable = wf->resizable;
729 window->_lastDisplayTime = [[NSDate distantPast] timeIntervalSinceReferenceDate];
731 [window registerForDraggedTypes:[NSArray arrayWithObjects:(NSString*)kUTTypeData,
732 (NSString*)kUTTypeContent,
735 contentView = [[[WineContentView alloc] initWithFrame:NSZeroRect] autorelease];
738 [contentView setAutoresizesSubviews:NO];
740 /* We use tracking areas in addition to setAcceptsMouseMovedEvents:YES
741 because they give us mouse moves in the background. */
742 trackingArea = [[[NSTrackingArea alloc] initWithRect:[contentView bounds]
743 options:(NSTrackingMouseMoved |
744 NSTrackingActiveAlways |
745 NSTrackingInVisibleRect)
747 userInfo:nil] autorelease];
750 [contentView addTrackingArea:trackingArea];
752 [window setContentView:contentView];
753 [window setInitialFirstResponder:contentView];
755 [nc addObserver:window
756 selector:@selector(updateFullscreen)
757 name:NSApplicationDidChangeScreenParametersNotification
759 [window updateFullscreen];
761 [nc addObserver:window
762 selector:@selector(applicationWillHide)
763 name:NSApplicationWillHideNotification
765 [nc addObserver:window
766 selector:@selector(applicationDidUnhide)
767 name:NSApplicationDidUnhideNotification
770 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:window
771 selector:@selector(checkWineDisplayLink)
772 name:NSWorkspaceActiveSpaceDidChangeNotification
773 object:[NSWorkspace sharedWorkspace]];
780 [[NSNotificationCenter defaultCenter] removeObserver:self];
782 [latentChildWindows release];
783 [latentParentWindow release];
789 - (BOOL) preventResizing
791 BOOL preventForClipping = cursor_clipping_locks_windows && [[WineApplicationController sharedController] clippingCursor];
792 return ([self styleMask] & NSResizableWindowMask) && (disabled || !resizable || preventForClipping);
795 - (BOOL) allowsMovingWithMaximized:(BOOL)inMaximized
797 if (allow_immovable_windows && (disabled || inMaximized))
799 else if (cursor_clipping_locks_windows && [[WineApplicationController sharedController] clippingCursor])
805 - (void) adjustFeaturesForState
807 NSUInteger style = [self styleMask];
809 if (style & NSClosableWindowMask)
810 [[self standardWindowButton:NSWindowCloseButton] setEnabled:!self.disabled];
811 if (style & NSMiniaturizableWindowMask)
812 [[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!self.disabled];
813 if (style & NSResizableWindowMask)
814 [[self standardWindowButton:NSWindowZoomButton] setEnabled:!self.disabled];
815 if ([self respondsToSelector:@selector(toggleFullScreen:)])
817 if ([self collectionBehavior] & NSWindowCollectionBehaviorFullScreenPrimary)
818 [[self standardWindowButton:NSWindowFullScreenButton] setEnabled:!self.disabled];
821 if ([self preventResizing])
823 NSSize size = [self contentRectForFrameRect:[self frame]].size;
824 [self setContentMinSize:size];
825 [self setContentMaxSize:size];
829 [self setContentMaxSize:savedContentMaxSize];
830 [self setContentMinSize:savedContentMinSize];
833 if (allow_immovable_windows || cursor_clipping_locks_windows)
834 [self setMovable:[self allowsMovingWithMaximized:maximized]];
837 - (void) adjustFullScreenBehavior:(NSWindowCollectionBehavior)behavior
839 if ([self respondsToSelector:@selector(toggleFullScreen:)])
841 NSUInteger style = [self styleMask];
843 if (behavior & NSWindowCollectionBehaviorParticipatesInCycle &&
844 style & NSResizableWindowMask && !(style & NSUtilityWindowMask) && !maximized)
846 behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
847 behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
851 behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
852 behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
853 if (style & NSFullScreenWindowMask)
854 [super toggleFullScreen:nil];
858 if (behavior != [self collectionBehavior])
860 [self setCollectionBehavior:behavior];
861 [self adjustFeaturesForState];
865 - (void) setWindowFeatures:(const struct macdrv_window_features*)wf
867 static const NSUInteger usedStyles = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask |
868 NSResizableWindowMask | NSUtilityWindowMask | NSBorderlessWindowMask;
869 NSUInteger currentStyle = [self styleMask];
870 NSUInteger newStyle = style_mask_for_features(wf) | (currentStyle & ~usedStyles);
872 if (newStyle != currentStyle)
874 NSString* title = [[[self title] copy] autorelease];
875 BOOL showingButtons = (currentStyle & (NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)) != 0;
876 BOOL shouldShowButtons = (newStyle & (NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)) != 0;
877 if (shouldShowButtons != showingButtons && !((newStyle ^ currentStyle) & NSClosableWindowMask))
879 // -setStyleMask: is buggy on 10.7+ with respect to NSResizableWindowMask.
880 // If transitioning from NSTitledWindowMask | NSResizableWindowMask to
881 // just NSTitledWindowMask, the window buttons should disappear rather
882 // than just being disabled. But they don't. Similarly in reverse.
883 // The workaround is to also toggle NSClosableWindowMask at the same time.
884 [self setStyleMask:newStyle ^ NSClosableWindowMask];
886 [self setStyleMask:newStyle];
888 // -setStyleMask: resets the firstResponder to the window. Set it
889 // back to the content view.
890 if ([[self contentView] acceptsFirstResponder])
891 [self makeFirstResponder:[self contentView]];
893 [self adjustFullScreenBehavior:[self collectionBehavior]];
895 if ([[self title] length] == 0 && [title length] > 0)
896 [self setTitle:title];
899 resizable = wf->resizable;
900 [self adjustFeaturesForState];
901 [self setHasShadow:wf->shadow];
904 // Indicates if the window would be visible if the app were not hidden.
905 - (BOOL) wouldBeVisible
907 return [NSApp isHidden] ? savedVisibleState : [self isVisible];
912 return [self wouldBeVisible] || [self isMiniaturized];
915 - (NSInteger) minimumLevelForActive:(BOOL)active
919 if (self.floating && (active || topmost_float_inactive == TOPMOST_FLOAT_INACTIVE_ALL ||
920 (topmost_float_inactive == TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN && !fullscreen)))
921 level = NSFloatingWindowLevel;
923 level = NSNormalWindowLevel;
929 captured = (fullscreen || [self screen]) && [[WineApplicationController sharedController] areDisplaysCaptured];
931 if (captured || fullscreen)
934 level = CGShieldingWindowLevel() + 1; /* Need +1 or we don't get mouse moves */
936 level = NSStatusWindowLevel + 1;
946 - (void) postDidUnminimizeEvent
950 /* Coalesce events by discarding any previous ones still in the queue. */
951 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_UNMINIMIZE)
954 event = macdrv_create_event(WINDOW_DID_UNMINIMIZE, self);
955 [queue postEvent:event];
956 macdrv_release_event(event);
959 - (void) sendResizeStartQuery
961 macdrv_query* query = macdrv_create_query();
962 query->type = QUERY_RESIZE_START;
963 query->window = (macdrv_window)[self retain];
965 [self.queue query:query timeout:0.3];
966 macdrv_release_query(query);
969 - (void) setMacDrvState:(const struct macdrv_window_state*)state
971 NSWindowCollectionBehavior behavior;
973 self.disabled = state->disabled;
974 self.noActivate = state->no_activate;
976 if (self.floating != state->floating)
978 self.floating = state->floating;
981 // Became floating. If child of non-floating window, make that
982 // relationship latent.
983 WineWindow* parent = (WineWindow*)[self parentWindow];
984 if (parent && !parent.floating)
985 [self becameIneligibleChild];
989 // Became non-floating. If parent of floating children, make that
990 // relationship latent.
992 for (child in [self childWineWindows])
995 [child becameIneligibleChild];
999 // Check our latent relationships. If floating status was the only
1000 // reason they were latent, then make them active.
1001 if ([self isVisible])
1002 [self becameEligibleParentOrChild];
1004 [[WineApplicationController sharedController] adjustWindowLevels];
1007 if (state->minimized_valid)
1009 macdrv_event_mask discard = event_mask_for_type(WINDOW_DID_UNMINIMIZE);
1011 pendingMinimize = FALSE;
1012 if (state->minimized && ![self isMiniaturized])
1014 if ([self wouldBeVisible])
1016 if ([self styleMask] & NSFullScreenWindowMask)
1018 [self postDidUnminimizeEvent];
1019 discard &= ~event_mask_for_type(WINDOW_DID_UNMINIMIZE);
1023 [super miniaturize:nil];
1024 discard |= event_mask_for_type(WINDOW_BROUGHT_FORWARD) |
1025 event_mask_for_type(WINDOW_GOT_FOCUS) |
1026 event_mask_for_type(WINDOW_LOST_FOCUS);
1030 pendingMinimize = TRUE;
1032 else if (!state->minimized && [self isMiniaturized])
1034 ignore_windowDeminiaturize = TRUE;
1035 [self deminiaturize:nil];
1036 discard |= event_mask_for_type(WINDOW_LOST_FOCUS);
1040 [queue discardEventsMatchingMask:discard forWindow:self];
1043 if (state->maximized != maximized)
1045 maximized = state->maximized;
1046 [self adjustFeaturesForState];
1048 if (!maximized && [self inLiveResize])
1049 [self sendResizeStartQuery];
1052 behavior = NSWindowCollectionBehaviorDefault;
1053 if (state->excluded_by_expose)
1054 behavior |= NSWindowCollectionBehaviorTransient;
1056 behavior |= NSWindowCollectionBehaviorManaged;
1057 if (state->excluded_by_cycle)
1059 behavior |= NSWindowCollectionBehaviorIgnoresCycle;
1060 if ([self isOrderedIn])
1061 [NSApp removeWindowsItem:self];
1065 behavior |= NSWindowCollectionBehaviorParticipatesInCycle;
1066 if ([self isOrderedIn])
1067 [NSApp addWindowsItem:self title:[self title] filename:NO];
1069 [self adjustFullScreenBehavior:behavior];
1072 - (BOOL) addChildWineWindow:(WineWindow*)child assumeVisible:(BOOL)assumeVisible
1074 BOOL reordered = FALSE;
1076 if ([self isVisible] && (assumeVisible || [child isVisible]) && (self.floating || !child.floating))
1078 if ([self level] > [child level])
1079 [child setLevel:[self level]];
1080 [self addChildWindow:child ordered:NSWindowAbove];
1081 [child checkWineDisplayLink];
1082 [latentChildWindows removeObjectIdenticalTo:child];
1083 child.latentParentWindow = nil;
1088 if (!latentChildWindows)
1089 latentChildWindows = [[NSMutableArray alloc] init];
1090 if (![latentChildWindows containsObject:child])
1091 [latentChildWindows addObject:child];
1092 child.latentParentWindow = self;
1098 - (BOOL) addChildWineWindow:(WineWindow*)child
1100 return [self addChildWineWindow:child assumeVisible:FALSE];
1103 - (void) removeChildWineWindow:(WineWindow*)child
1105 [self removeChildWindow:child];
1106 if (child.latentParentWindow == self)
1107 child.latentParentWindow = nil;
1108 [latentChildWindows removeObjectIdenticalTo:child];
1111 - (BOOL) becameEligibleParentOrChild
1113 BOOL reordered = FALSE;
1116 if (latentParentWindow.floating || !self.floating)
1118 // If we aren't visible currently, we assume that we should be and soon
1119 // will be. So, if the latent parent is visible that's enough to assume
1120 // we can establish the parent-child relationship in Cocoa. That will
1121 // actually make us visible, which is fine.
1122 if ([latentParentWindow addChildWineWindow:self assumeVisible:TRUE])
1126 // Here, though, we may not actually be visible yet and adding a child
1127 // won't make us visible. The caller will have to call this method
1128 // again after actually making us visible.
1129 if ([self isVisible] && (count = [latentChildWindows count]))
1131 NSMutableIndexSet* indexesToRemove = [NSMutableIndexSet indexSet];
1134 for (i = 0; i < count; i++)
1136 WineWindow* child = [latentChildWindows objectAtIndex:i];
1137 if ([child isVisible] && (self.floating || !child.floating))
1139 if (child.latentParentWindow == self)
1141 if ([self level] > [child level])
1142 [child setLevel:[self level]];
1143 [self addChildWindow:child ordered:NSWindowAbove];
1144 child.latentParentWindow = nil;
1148 ERR(@"shouldn't happen: %@ thinks %@ is a latent child, but it doesn't agree\n", self, child);
1149 [indexesToRemove addIndex:i];
1153 [latentChildWindows removeObjectsAtIndexes:indexesToRemove];
1159 - (void) becameIneligibleChild
1161 WineWindow* parent = (WineWindow*)[self parentWindow];
1164 if (!parent->latentChildWindows)
1165 parent->latentChildWindows = [[NSMutableArray alloc] init];
1166 [parent->latentChildWindows insertObject:self atIndex:0];
1167 self.latentParentWindow = parent;
1168 [parent removeChildWindow:self];
1172 - (void) becameIneligibleParentOrChild
1174 NSArray* childWindows = [self childWineWindows];
1176 [self becameIneligibleChild];
1178 if ([childWindows count])
1182 for (child in childWindows)
1184 child.latentParentWindow = self;
1185 [self removeChildWindow:child];
1188 if (latentChildWindows)
1189 [latentChildWindows replaceObjectsInRange:NSMakeRange(0, 0) withObjectsFromArray:childWindows];
1191 latentChildWindows = [childWindows mutableCopy];
1195 // Determine if, among Wine windows, this window is directly above or below
1196 // a given other Wine window with no other Wine window intervening.
1197 // Intervening non-Wine windows are ignored.
1198 - (BOOL) isOrdered:(NSWindowOrderingMode)orderingMode relativeTo:(WineWindow*)otherWindow
1200 NSNumber* windowNumber;
1201 NSNumber* otherWindowNumber;
1202 NSArray* windowNumbers;
1203 NSUInteger windowIndex, otherWindowIndex, lowIndex, highIndex, i;
1205 if (![self isVisible] || ![otherWindow isVisible])
1208 windowNumber = [NSNumber numberWithInteger:[self windowNumber]];
1209 otherWindowNumber = [NSNumber numberWithInteger:[otherWindow windowNumber]];
1210 windowNumbers = [[self class] windowNumbersWithOptions:0];
1211 windowIndex = [windowNumbers indexOfObject:windowNumber];
1212 otherWindowIndex = [windowNumbers indexOfObject:otherWindowNumber];
1214 if (windowIndex == NSNotFound || otherWindowIndex == NSNotFound)
1217 if (orderingMode == NSWindowAbove)
1219 lowIndex = windowIndex;
1220 highIndex = otherWindowIndex;
1222 else if (orderingMode == NSWindowBelow)
1224 lowIndex = otherWindowIndex;
1225 highIndex = windowIndex;
1230 if (highIndex <= lowIndex)
1233 for (i = lowIndex + 1; i < highIndex; i++)
1235 NSInteger interveningWindowNumber = [[windowNumbers objectAtIndex:i] integerValue];
1236 NSWindow* interveningWindow = [NSApp windowWithWindowNumber:interveningWindowNumber];
1237 if ([interveningWindow isKindOfClass:[WineWindow class]])
1244 - (void) order:(NSWindowOrderingMode)mode childWindow:(WineWindow*)child relativeTo:(WineWindow*)other
1246 NSMutableArray* windowNumbers;
1247 NSNumber* childWindowNumber;
1248 NSUInteger otherIndex, limit;
1249 NSArray* origChildren;
1250 NSMutableArray* children;
1252 // Get the z-order from the window server and modify it to reflect the
1253 // requested window ordering.
1254 windowNumbers = [[[[self class] windowNumbersWithOptions:NSWindowNumberListAllSpaces] mutableCopy] autorelease];
1255 childWindowNumber = [NSNumber numberWithInteger:[child windowNumber]];
1256 [windowNumbers removeObject:childWindowNumber];
1257 otherIndex = [windowNumbers indexOfObject:[NSNumber numberWithInteger:[other windowNumber]]];
1258 [windowNumbers insertObject:childWindowNumber atIndex:otherIndex + (mode == NSWindowAbove ? 0 : 1)];
1260 // Get our child windows and sort them in the reverse of the desired
1261 // z-order (back-to-front).
1262 origChildren = [self childWineWindows];
1263 children = [[origChildren mutableCopy] autorelease];
1264 [children sortWithOptions:NSSortStable
1265 usingComparator:^NSComparisonResult(id obj1, id obj2){
1266 NSNumber* window1Number = [NSNumber numberWithInteger:[obj1 windowNumber]];
1267 NSNumber* window2Number = [NSNumber numberWithInteger:[obj2 windowNumber]];
1268 NSUInteger index1 = [windowNumbers indexOfObject:window1Number];
1269 NSUInteger index2 = [windowNumbers indexOfObject:window2Number];
1270 if (index1 == NSNotFound)
1272 if (index2 == NSNotFound)
1273 return NSOrderedSame;
1275 return NSOrderedAscending;
1277 else if (index2 == NSNotFound)
1278 return NSOrderedDescending;
1279 else if (index1 < index2)
1280 return NSOrderedDescending;
1281 else if (index2 < index1)
1282 return NSOrderedAscending;
1284 return NSOrderedSame;
1287 // If the current and desired children arrays match up to a point, leave
1288 // those matching children alone.
1289 limit = MIN([origChildren count], [children count]);
1290 for (otherIndex = 0; otherIndex < limit; otherIndex++)
1292 if ([origChildren objectAtIndex:otherIndex] != [children objectAtIndex:otherIndex])
1295 [children removeObjectsInRange:NSMakeRange(0, otherIndex)];
1297 // Remove all of the child windows and re-add them back-to-front so they
1298 // are in the desired order.
1299 for (other in children)
1300 [self removeChildWindow:other];
1301 for (other in children)
1302 [self addChildWindow:other ordered:NSWindowAbove];
1305 /* Returns whether or not the window was ordered in, which depends on if
1306 its frame intersects any screen. */
1307 - (void) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next activate:(BOOL)activate
1309 WineApplicationController* controller = [WineApplicationController sharedController];
1310 if (![self isMiniaturized])
1312 BOOL needAdjustWindowLevels = FALSE;
1315 [controller transformProcessToForeground];
1317 wasVisible = [self isVisible];
1320 [NSApp activateIgnoringOtherApps:YES];
1322 NSDisableScreenUpdates();
1324 if ([self becameEligibleParentOrChild])
1325 needAdjustWindowLevels = TRUE;
1329 WineWindow* other = [prev isVisible] ? prev : next;
1330 NSWindowOrderingMode orderingMode = [prev isVisible] ? NSWindowBelow : NSWindowAbove;
1332 if (![self isOrdered:orderingMode relativeTo:other])
1334 WineWindow* parent = (WineWindow*)[self parentWindow];
1335 WineWindow* otherParent = (WineWindow*)[other parentWindow];
1337 // This window level may not be right for this window based
1338 // on floating-ness, fullscreen-ness, etc. But we set it
1339 // temporarily to allow us to order the windows properly.
1340 // Then the levels get fixed by -adjustWindowLevels.
1341 if ([self level] != [other level])
1342 [self setLevel:[other level]];
1343 [self orderWindow:orderingMode relativeTo:[other windowNumber]];
1344 [self checkWineDisplayLink];
1346 // The above call to -[NSWindow orderWindow:relativeTo:] won't
1347 // reorder windows which are both children of the same parent
1348 // relative to each other, so do that separately.
1349 if (parent && parent == otherParent)
1350 [parent order:orderingMode childWindow:self relativeTo:other];
1352 needAdjustWindowLevels = TRUE;
1357 // Again, temporarily set level to make sure we can order to
1359 next = [controller frontWineWindow];
1360 if (next && [self level] < [next level])
1361 [self setLevel:[next level]];
1362 [self orderFront:nil];
1363 [self checkWineDisplayLink];
1364 needAdjustWindowLevels = TRUE;
1367 if ([self becameEligibleParentOrChild])
1368 needAdjustWindowLevels = TRUE;
1370 if (needAdjustWindowLevels)
1372 if (!wasVisible && fullscreen && [self isOnActiveSpace])
1373 [controller updateFullscreenWindows];
1374 [controller adjustWindowLevels];
1377 if (pendingMinimize)
1379 [super miniaturize:nil];
1380 pendingMinimize = FALSE;
1383 NSEnableScreenUpdates();
1385 /* Cocoa may adjust the frame when the window is ordered onto the screen.
1386 Generate a frame-changed event just in case. The back end will ignore
1387 it if nothing actually changed. */
1388 [self windowDidResize:nil];
1390 if (![self isExcludedFromWindowsMenu])
1391 [NSApp addWindowsItem:self title:[self title] filename:NO];
1397 WineApplicationController* controller = [WineApplicationController sharedController];
1398 BOOL wasVisible = [self isVisible];
1399 BOOL wasOnActiveSpace = [self isOnActiveSpace];
1401 if ([self isMiniaturized])
1402 pendingMinimize = TRUE;
1404 WineWindow* parent = (WineWindow*)self.parentWindow;
1405 if ([parent isKindOfClass:[WineWindow class]])
1406 [parent grabDockIconSnapshotFromWindow:self force:NO];
1408 [self becameIneligibleParentOrChild];
1409 if ([self isMiniaturized])
1413 fakingClose = FALSE;
1416 [self orderOut:nil];
1417 [self checkWineDisplayLink];
1418 savedVisibleState = FALSE;
1419 if (wasVisible && wasOnActiveSpace && fullscreen)
1420 [controller updateFullscreenWindows];
1421 [controller adjustWindowLevels];
1422 [NSApp removeWindowsItem:self];
1424 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_BROUGHT_FORWARD) |
1425 event_mask_for_type(WINDOW_GOT_FOCUS) |
1426 event_mask_for_type(WINDOW_LOST_FOCUS) |
1427 event_mask_for_type(WINDOW_MAXIMIZE_REQUESTED) |
1428 event_mask_for_type(WINDOW_MINIMIZE_REQUESTED) |
1429 event_mask_for_type(WINDOW_RESTORE_REQUESTED)
1433 - (void) updateFullscreen
1435 NSRect contentRect = [self contentRectForFrameRect:[self frame]];
1436 BOOL nowFullscreen = !([self styleMask] & NSFullScreenWindowMask) && screen_covered_by_rect(contentRect, [NSScreen screens]);
1438 if (nowFullscreen != fullscreen)
1440 WineApplicationController* controller = [WineApplicationController sharedController];
1442 fullscreen = nowFullscreen;
1443 if ([self isVisible] && [self isOnActiveSpace])
1444 [controller updateFullscreenWindows];
1446 [controller adjustWindowLevels];
1450 - (void) setFrameFromWine:(NSRect)contentRect
1452 /* Origin is (left, top) in a top-down space. Need to convert it to
1453 (left, bottom) in a bottom-up space. */
1454 [[WineApplicationController sharedController] flipRect:&contentRect];
1456 /* The back end is establishing a new window size and position. It's
1457 not interested in any stale events regarding those that may be sitting
1459 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
1462 if (!NSIsEmptyRect(contentRect))
1464 NSRect frame, oldFrame;
1466 oldFrame = [self frame];
1467 frame = [self frameRectForContentRect:contentRect];
1468 if (!NSEqualRects(frame, oldFrame))
1470 BOOL equalSizes = NSEqualSizes(frame.size, oldFrame.size);
1471 BOOL needEnableScreenUpdates = FALSE;
1473 if ([self preventResizing])
1475 // Allow the following calls to -setFrame:display: to work even
1476 // if they would violate the content size constraints. This
1477 // shouldn't be necessary since the content size constraints are
1478 // documented to not constrain that method, but it seems to be.
1479 [self setContentMinSize:NSZeroSize];
1480 [self setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
1483 if (equalSizes && [[self childWineWindows] count])
1485 // If we change the window frame such that the origin moves
1486 // but the size doesn't change, then Cocoa moves child
1487 // windows with the parent. We don't want that so we fake
1488 // a change of the size and then change it back.
1489 NSRect bogusFrame = frame;
1490 bogusFrame.size.width++;
1492 NSDisableScreenUpdates();
1493 needEnableScreenUpdates = TRUE;
1495 ignore_windowResize = TRUE;
1496 [self setFrame:bogusFrame display:NO];
1497 ignore_windowResize = FALSE;
1500 [self setFrame:frame display:YES];
1501 if ([self preventResizing])
1503 [self setContentMinSize:contentRect.size];
1504 [self setContentMaxSize:contentRect.size];
1507 if (needEnableScreenUpdates)
1508 NSEnableScreenUpdates();
1511 [self updateColorSpace];
1513 if (!enteringFullScreen &&
1514 [[NSProcessInfo processInfo] systemUptime] - enteredFullScreenTime > 1.0)
1515 nonFullscreenFrame = frame;
1517 [self updateFullscreen];
1519 if ([self isOrderedIn])
1521 /* In case Cocoa adjusted the frame we tried to set, generate a frame-changed
1522 event. The back end will ignore it if nothing actually changed. */
1523 [self windowDidResize:nil];
1529 - (void) setMacDrvParentWindow:(WineWindow*)parent
1531 WineWindow* oldParent = (WineWindow*)[self parentWindow];
1532 if ((oldParent && oldParent != parent) || (!oldParent && latentParentWindow != parent))
1534 [oldParent removeChildWineWindow:self];
1535 [latentParentWindow removeChildWineWindow:self];
1536 if ([parent addChildWineWindow:self])
1537 [[WineApplicationController sharedController] adjustWindowLevels];
1541 - (void) setDisabled:(BOOL)newValue
1543 if (disabled != newValue)
1545 disabled = newValue;
1546 [self adjustFeaturesForState];
1550 - (BOOL) needsTransparency
1552 return self.shape || self.colorKeyed || self.usePerPixelAlpha ||
1553 (gl_surface_mode == GL_SURFACE_BEHIND && [[self.contentView valueForKeyPath:@"subviews.@max.hasGLContext"] boolValue]);
1556 - (void) checkTransparency
1558 if (![self isOpaque] && !self.needsTransparency)
1560 self.shapeChangedSinceLastDraw = TRUE;
1561 [[self contentView] setNeedsDisplay:YES];
1562 [self setBackgroundColor:[NSColor windowBackgroundColor]];
1563 [self setOpaque:YES];
1565 else if ([self isOpaque] && self.needsTransparency)
1567 self.shapeChangedSinceLastDraw = TRUE;
1568 [[self contentView] setNeedsDisplay:YES];
1569 [self setBackgroundColor:[NSColor clearColor]];
1570 [self setOpaque:NO];
1574 - (void) setShape:(NSBezierPath*)newShape
1576 if (shape == newShape) return;
1580 [[self contentView] setNeedsDisplayInRect:[shape bounds]];
1584 [[self contentView] setNeedsDisplayInRect:[newShape bounds]];
1586 shape = [newShape copy];
1587 self.shapeChangedSinceLastDraw = TRUE;
1589 [self checkTransparency];
1592 - (void) makeFocused:(BOOL)activate
1596 [[WineApplicationController sharedController] transformProcessToForeground];
1597 [NSApp activateIgnoringOtherApps:YES];
1600 causing_becomeKeyWindow = self;
1601 [self makeKeyWindow];
1602 causing_becomeKeyWindow = nil;
1604 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_GOT_FOCUS) |
1605 event_mask_for_type(WINDOW_LOST_FOCUS)
1609 - (void) postKey:(uint16_t)keyCode
1610 pressed:(BOOL)pressed
1611 modifiers:(NSUInteger)modifiers
1612 event:(NSEvent*)theEvent
1614 macdrv_event* event;
1616 WineApplicationController* controller = [WineApplicationController sharedController];
1618 event = macdrv_create_event(pressed ? KEY_PRESS : KEY_RELEASE, self);
1619 event->key.keycode = keyCode;
1620 event->key.modifiers = modifiers;
1621 event->key.time_ms = [controller ticksForEventTime:[theEvent timestamp]];
1623 if ((cgevent = [theEvent CGEvent]))
1625 CGEventSourceKeyboardType keyboardType = CGEventGetIntegerValueField(cgevent,
1626 kCGKeyboardEventKeyboardType);
1627 if (keyboardType != controller.keyboardType)
1629 controller.keyboardType = keyboardType;
1630 [controller keyboardSelectionDidChange];
1634 [queue postEvent:event];
1636 macdrv_release_event(event);
1638 [controller noteKey:keyCode pressed:pressed];
1641 - (void) postKeyEvent:(NSEvent *)theEvent
1643 [self flagsChanged:theEvent];
1644 [self postKey:[theEvent keyCode]
1645 pressed:[theEvent type] == NSKeyDown
1646 modifiers:adjusted_modifiers_for_option_behavior([theEvent modifierFlags])
1650 - (void) setWineMinSize:(NSSize)minSize maxSize:(NSSize)maxSize
1652 savedContentMinSize = minSize;
1653 savedContentMaxSize = maxSize;
1654 if (![self preventResizing])
1656 [self setContentMinSize:minSize];
1657 [self setContentMaxSize:maxSize];
1661 - (WineWindow*) ancestorWineWindow
1663 WineWindow* ancestor = self;
1666 WineWindow* parent = (WineWindow*)[ancestor parentWindow];
1667 if ([parent isKindOfClass:[WineWindow class]])
1675 - (void) postBroughtForwardEvent
1677 macdrv_event* event = macdrv_create_event(WINDOW_BROUGHT_FORWARD, self);
1678 [queue postEvent:event];
1679 macdrv_release_event(event);
1682 - (void) updateForCursorClipping
1684 [self adjustFeaturesForState];
1687 - (void) endWindowDragging
1691 if (draggingPhase == 3)
1693 macdrv_event* event = macdrv_create_event(WINDOW_DRAG_END, self);
1694 [queue postEvent:event];
1695 macdrv_release_event(event);
1699 [[WineApplicationController sharedController] window:self isBeingDragged:NO];
1703 - (NSMutableDictionary*) displayIDToDisplayLinkMap
1705 static NSMutableDictionary* displayIDToDisplayLinkMap;
1706 if (!displayIDToDisplayLinkMap)
1708 displayIDToDisplayLinkMap = [[NSMutableDictionary alloc] init];
1710 [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidChangeScreenParametersNotification
1713 usingBlock:^(NSNotification *note){
1714 NSMutableSet* badDisplayIDs = [NSMutableSet setWithArray:displayIDToDisplayLinkMap.allKeys];
1715 NSSet* validDisplayIDs = [NSSet setWithArray:[[NSScreen screens] valueForKeyPath:@"deviceDescription.NSScreenNumber"]];
1716 [badDisplayIDs minusSet:validDisplayIDs];
1717 [displayIDToDisplayLinkMap removeObjectsForKeys:[badDisplayIDs allObjects]];
1720 return displayIDToDisplayLinkMap;
1723 - (WineDisplayLink*) wineDisplayLink
1725 if (!_lastDisplayID)
1728 NSMutableDictionary* displayIDToDisplayLinkMap = [self displayIDToDisplayLinkMap];
1729 return [displayIDToDisplayLinkMap objectForKey:[NSNumber numberWithUnsignedInt:_lastDisplayID]];
1732 - (void) checkWineDisplayLink
1734 NSScreen* screen = self.screen;
1735 if (![self isVisible] || ![self isOnActiveSpace] || [self isMiniaturized] || [self isEmptyShaped])
1737 #if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
1738 if ([self respondsToSelector:@selector(occlusionState)] && !(self.occlusionState & NSWindowOcclusionStateVisible))
1742 NSNumber* displayIDNumber = [screen.deviceDescription objectForKey:@"NSScreenNumber"];
1743 CGDirectDisplayID displayID = [displayIDNumber unsignedIntValue];
1744 if (displayID == _lastDisplayID)
1747 NSMutableDictionary* displayIDToDisplayLinkMap = [self displayIDToDisplayLinkMap];
1751 WineDisplayLink* link = [displayIDToDisplayLinkMap objectForKey:[NSNumber numberWithUnsignedInt:_lastDisplayID]];
1752 [link removeWindow:self];
1756 WineDisplayLink* link = [displayIDToDisplayLinkMap objectForKey:displayIDNumber];
1759 link = [[[WineDisplayLink alloc] initWithDisplayID:displayID] autorelease];
1760 [displayIDToDisplayLinkMap setObject:link forKey:displayIDNumber];
1762 [link addWindow:self];
1763 [self displayIfNeeded];
1765 _lastDisplayID = displayID;
1768 - (BOOL) isEmptyShaped
1770 return (self.shapeData.length == sizeof(CGRectZero) && !memcmp(self.shapeData.bytes, &CGRectZero, sizeof(CGRectZero)));
1773 - (BOOL) canProvideSnapshot
1775 return (self.windowNumber > 0 && ![self isEmptyShaped]);
1778 - (void) grabDockIconSnapshotFromWindow:(WineWindow*)window force:(BOOL)force
1780 if (![self isEmptyShaped])
1783 NSTimeInterval now = [[NSProcessInfo processInfo] systemUptime];
1784 if (!force && now < lastDockIconSnapshot + 1)
1789 if (![window canProvideSnapshot])
1795 for (WineWindow* childWindow in self.childWindows)
1797 if (![childWindow isKindOfClass:[WineWindow class]] || ![childWindow canProvideSnapshot])
1800 NSSize size = childWindow.frame.size;
1801 CGFloat area = size.width * size.height;
1802 if (!window || area > bestArea)
1804 window = childWindow;
1813 const void* windowID = (const void*)(CGWindowID)window.windowNumber;
1814 CFArrayRef windowIDs = CFArrayCreate(NULL, &windowID, 1, NULL);
1815 CGImageRef windowImage = CGWindowListCreateImageFromArray(CGRectNull, windowIDs, kCGWindowImageBoundsIgnoreFraming);
1816 CFRelease(windowIDs);
1820 NSImage* appImage = [NSApp applicationIconImage];
1822 appImage = [NSImage imageNamed:NSImageNameApplicationIcon];
1824 NSImage* dockIcon = [[[NSImage alloc] initWithSize:NSMakeSize(256, 256)] autorelease];
1825 [dockIcon lockFocus];
1827 CGContextRef cgcontext = [[NSGraphicsContext currentContext] graphicsPort];
1829 CGRect rect = CGRectMake(8, 8, 240, 240);
1830 size_t width = CGImageGetWidth(windowImage);
1831 size_t height = CGImageGetHeight(windowImage);
1834 rect.size.height *= height / (double)width;
1835 rect.origin.y += (CGRectGetWidth(rect) - CGRectGetHeight(rect)) / 2;
1837 else if (width != height)
1839 rect.size.width *= width / (double)height;
1840 rect.origin.x += (CGRectGetHeight(rect) - CGRectGetWidth(rect)) / 2;
1843 CGContextDrawImage(cgcontext, rect, windowImage);
1844 [appImage drawInRect:NSMakeRect(156, 4, 96, 96)];
1846 [dockIcon unlockFocus];
1848 CGImageRelease(windowImage);
1850 NSImageView* imageView = (NSImageView*)self.dockTile.contentView;
1851 if (![imageView isKindOfClass:[NSImageView class]])
1853 imageView = [[[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, 256, 256)] autorelease];
1854 imageView.imageScaling = NSImageScaleProportionallyUpOrDown;
1855 self.dockTile.contentView = imageView;
1857 imageView.image = dockIcon;
1858 [self.dockTile display];
1859 lastDockIconSnapshot = now;
1862 - (void) checkEmptyShaped
1864 if (self.dockTile.contentView && ![self isEmptyShaped])
1866 self.dockTile.contentView = nil;
1867 lastDockIconSnapshot = 0;
1869 [self checkWineDisplayLink];
1874 * ---------- NSWindow method overrides ----------
1876 - (BOOL) canBecomeKeyWindow
1878 if (causing_becomeKeyWindow == self) return YES;
1879 if (self.disabled || self.noActivate) return NO;
1880 return [self isKeyWindow];
1883 - (BOOL) canBecomeMainWindow
1885 return [self canBecomeKeyWindow];
1888 - (NSRect) constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
1890 // If a window is sized to completely cover a screen, then it's in
1891 // full-screen mode. In that case, we don't allow NSWindow to constrain
1893 NSArray* screens = [NSScreen screens];
1894 NSRect contentRect = [self contentRectForFrameRect:frameRect];
1895 if (!screen_covered_by_rect(contentRect, screens) &&
1896 frame_intersects_screens(frameRect, screens))
1897 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
1901 // This private method of NSWindow is called as Cocoa reacts to the display
1902 // configuration changing. Among other things, it adjusts the window's
1903 // frame based on how the screen(s) changed size. That tells Wine that the
1904 // window has been moved. We don't want that. Rather, we want to make
1905 // sure that the WinAPI notion of the window position is maintained/
1906 // restored, possibly undoing or overriding Cocoa's adjustment.
1908 // So, we queue a REASSERT_WINDOW_POSITION event to the back end before
1909 // Cocoa has a chance to adjust the frame, thus preceding any resulting
1910 // WINDOW_FRAME_CHANGED event that may get queued. The back end will
1911 // reassert its notion of the position. That call won't get processed
1912 // until after this method returns, so it will override whatever this
1913 // method does to the window position. It will also discard any pending
1914 // WINDOW_FRAME_CHANGED events.
1916 // Unfortunately, the only way I've found to know when Cocoa is _about to_
1917 // adjust the window's position due to a display change is to hook into
1918 // this private method. This private method has remained stable from 10.6
1919 // through 10.11. If it does change, the most likely thing is that it
1920 // will be removed and no longer called and this fix will simply stop
1921 // working. The only real danger would be if Apple changed the return type
1922 // to a struct or floating-point type, which would change the calling
1924 - (id) _displayChanged
1926 macdrv_event* event = macdrv_create_event(REASSERT_WINDOW_POSITION, self);
1927 [queue postEvent:event];
1928 macdrv_release_event(event);
1930 return [super _displayChanged];
1933 - (BOOL) isExcludedFromWindowsMenu
1935 return !([self collectionBehavior] & NSWindowCollectionBehaviorParticipatesInCycle);
1938 - (BOOL) validateMenuItem:(NSMenuItem *)menuItem
1940 BOOL ret = [super validateMenuItem:menuItem];
1942 if ([menuItem action] == @selector(makeKeyAndOrderFront:))
1943 ret = [self isKeyWindow] || (!self.disabled && !self.noActivate);
1944 if ([menuItem action] == @selector(toggleFullScreen:) && (self.disabled || maximized))
1950 /* We don't call this. It's the action method of the items in the Window menu. */
1951 - (void) makeKeyAndOrderFront:(id)sender
1953 if ([self isMiniaturized])
1954 [self deminiaturize:nil];
1955 [self orderBelow:nil orAbove:nil activate:NO];
1956 [[self ancestorWineWindow] postBroughtForwardEvent];
1958 if (![self isKeyWindow] && !self.disabled && !self.noActivate)
1959 [[WineApplicationController sharedController] windowGotFocus:self];
1962 - (void) sendEvent:(NSEvent*)event
1964 NSEventType type = event.type;
1966 /* NSWindow consumes certain key-down events as part of Cocoa's keyboard
1967 interface control. For example, Control-Tab switches focus among
1968 views. We want to bypass that feature, so directly route key-down
1969 events to -keyDown:. */
1970 if (type == NSKeyDown)
1971 [[self firstResponder] keyDown:event];
1974 if (!draggingPhase && maximized && ![self isMovable] &&
1975 ![self allowsMovingWithMaximized:YES] && [self allowsMovingWithMaximized:NO] &&
1976 type == NSLeftMouseDown && (self.styleMask & NSTitledWindowMask))
1978 NSRect titleBar = self.frame;
1979 NSRect contentRect = [self contentRectForFrameRect:titleBar];
1980 titleBar.size.height = NSMaxY(titleBar) - NSMaxY(contentRect);
1981 titleBar.origin.y = NSMaxY(contentRect);
1983 dragStartPosition = [self convertBaseToScreen:event.locationInWindow];
1985 if (NSMouseInRect(dragStartPosition, titleBar, NO))
1987 static const NSWindowButton buttons[] = {
1988 NSWindowCloseButton,
1989 NSWindowMiniaturizeButton,
1991 NSWindowFullScreenButton,
1993 BOOL hitButton = NO;
1996 for (i = 0; i < sizeof(buttons) / sizeof(buttons[0]); i++)
2000 if (buttons[i] == NSWindowFullScreenButton && ![self respondsToSelector:@selector(toggleFullScreen:)])
2003 button = [self standardWindowButton:buttons[i]];
2004 if ([button hitTest:[button.superview convertPoint:event.locationInWindow fromView:nil]])
2014 dragWindowStartPosition = NSMakePoint(NSMinX(titleBar), NSMaxY(titleBar));
2015 [[WineApplicationController sharedController] window:self isBeingDragged:YES];
2019 else if (draggingPhase && (type == NSLeftMouseDragged || type == NSLeftMouseUp))
2021 if ([self isMovable])
2023 NSPoint point = [self convertBaseToScreen:event.locationInWindow];
2024 NSPoint newTopLeft = dragWindowStartPosition;
2026 newTopLeft.x += point.x - dragStartPosition.x;
2027 newTopLeft.y += point.y - dragStartPosition.y;
2029 if (draggingPhase == 2)
2031 macdrv_event* event = macdrv_create_event(WINDOW_DRAG_BEGIN, self);
2032 [queue postEvent:event];
2033 macdrv_release_event(event);
2038 [self setFrameTopLeftPoint:newTopLeft];
2040 else if (draggingPhase == 1 && type == NSLeftMouseDragged)
2042 macdrv_event* event;
2043 NSRect frame = [self contentRectForFrameRect:self.frame];
2045 [[WineApplicationController sharedController] flipRect:&frame];
2047 event = macdrv_create_event(WINDOW_RESTORE_REQUESTED, self);
2048 event->window_restore_requested.keep_frame = TRUE;
2049 event->window_restore_requested.frame = NSRectToCGRect(frame);
2050 [queue postEvent:event];
2051 macdrv_release_event(event);
2056 if (type == NSLeftMouseUp)
2057 [self endWindowDragging];
2060 [super sendEvent:event];
2064 - (void) miniaturize:(id)sender
2066 macdrv_event* event = macdrv_create_event(WINDOW_MINIMIZE_REQUESTED, self);
2067 [queue postEvent:event];
2068 macdrv_release_event(event);
2070 WineWindow* parent = (WineWindow*)self.parentWindow;
2071 if ([parent isKindOfClass:[WineWindow class]])
2072 [parent grabDockIconSnapshotFromWindow:self force:YES];
2075 - (void) toggleFullScreen:(id)sender
2077 if (!self.disabled && !maximized)
2078 [super toggleFullScreen:sender];
2081 - (void) setViewsNeedDisplay:(BOOL)value
2083 if (value && ![self viewsNeedDisplay])
2085 WineDisplayLink* link = [self wineDisplayLink];
2088 NSTimeInterval now = [[NSProcessInfo processInfo] systemUptime];
2089 if (_lastDisplayTime + [link refreshPeriod] < now)
2090 [self setAutodisplay:YES];
2094 _lastDisplayTime = now;
2098 [super setViewsNeedDisplay:value];
2103 _lastDisplayTime = [[NSProcessInfo processInfo] systemUptime];
2105 [self setAutodisplay:NO];
2108 - (void) displayIfNeeded
2110 _lastDisplayTime = [[NSProcessInfo processInfo] systemUptime];
2111 [super displayIfNeeded];
2112 [self setAutodisplay:NO];
2115 - (NSArray*) childWineWindows
2117 NSArray* childWindows = self.childWindows;
2118 NSIndexSet* indexes = [childWindows indexesOfObjectsPassingTest:^BOOL(id child, NSUInteger idx, BOOL *stop){
2119 return [child isKindOfClass:[WineWindow class]];
2121 return [childWindows objectsAtIndexes:indexes];
2124 // We normally use the generic/calibrated RGB color space for the window,
2125 // rather than the device color space, to avoid expensive color conversion
2126 // which slows down drawing. However, for windows displaying OpenGL, having
2127 // a different color space than the screen greatly reduces frame rates, often
2128 // limiting it to the display refresh rate.
2130 // To avoid this, we switch back to the screen color space whenever the
2131 // window is covered by a view with an attached OpenGL context.
2132 - (void) updateColorSpace
2134 NSRect contentRect = [[self contentView] frame];
2135 BOOL coveredByGLView = FALSE;
2136 for (WineContentView* view in [[self contentView] subviews])
2138 if ([view hasGLContext])
2140 NSRect frame = [view convertRect:[view bounds] toView:nil];
2141 if (NSContainsRect(frame, contentRect))
2143 coveredByGLView = TRUE;
2149 if (coveredByGLView)
2150 [self setColorSpace:nil];
2152 [self setColorSpace:[NSColorSpace genericRGBColorSpace]];
2155 - (void) updateForGLSubviews
2157 [self updateColorSpace];
2158 if (gl_surface_mode == GL_SURFACE_BEHIND)
2159 [self checkTransparency];
2164 * ---------- NSResponder method overrides ----------
2166 - (void) keyDown:(NSEvent *)theEvent { [self postKeyEvent:theEvent]; }
2168 - (void) flagsChanged:(NSEvent *)theEvent
2170 static const struct {
2174 { NX_ALPHASHIFTMASK, kVK_CapsLock },
2175 { NX_DEVICELSHIFTKEYMASK, kVK_Shift },
2176 { NX_DEVICERSHIFTKEYMASK, kVK_RightShift },
2177 { NX_DEVICELCTLKEYMASK, kVK_Control },
2178 { NX_DEVICERCTLKEYMASK, kVK_RightControl },
2179 { NX_DEVICELALTKEYMASK, kVK_Option },
2180 { NX_DEVICERALTKEYMASK, kVK_RightOption },
2181 { NX_DEVICELCMDKEYMASK, kVK_Command },
2182 { NX_DEVICERCMDKEYMASK, kVK_RightCommand },
2185 NSUInteger modifierFlags = adjusted_modifiers_for_option_behavior([theEvent modifierFlags]);
2187 int i, last_changed;
2189 fix_device_modifiers_by_generic(&modifierFlags);
2190 changed = modifierFlags ^ lastModifierFlags;
2193 for (i = 0; i < sizeof(modifiers)/sizeof(modifiers[0]); i++)
2194 if (changed & modifiers[i].mask)
2197 for (i = 0; i <= last_changed; i++)
2199 if (changed & modifiers[i].mask)
2201 BOOL pressed = (modifierFlags & modifiers[i].mask) != 0;
2203 if (i == last_changed)
2204 lastModifierFlags = modifierFlags;
2207 lastModifierFlags ^= modifiers[i].mask;
2208 fix_generic_modifiers_by_device(&lastModifierFlags);
2211 // Caps lock generates one event for each press-release action.
2212 // We need to simulate a pair of events for each actual event.
2213 if (modifiers[i].mask == NX_ALPHASHIFTMASK)
2215 [self postKey:modifiers[i].keycode
2217 modifiers:lastModifierFlags
2218 event:(NSEvent*)theEvent];
2222 [self postKey:modifiers[i].keycode
2224 modifiers:lastModifierFlags
2225 event:(NSEvent*)theEvent];
2230 - (void) applicationWillHide
2232 savedVisibleState = [self isVisible];
2235 - (void) applicationDidUnhide
2237 if ([self isVisible])
2238 [self becameEligibleParentOrChild];
2243 * ---------- NSWindowDelegate methods ----------
2245 - (NSSize) window:(NSWindow*)window willUseFullScreenContentSize:(NSSize)proposedSize
2247 macdrv_query* query;
2250 query = macdrv_create_query();
2251 query->type = QUERY_MIN_MAX_INFO;
2252 query->window = (macdrv_window)[self retain];
2253 [self.queue query:query timeout:0.5];
2254 macdrv_release_query(query);
2256 size = [self contentMaxSize];
2257 if (proposedSize.width < size.width)
2258 size.width = proposedSize.width;
2259 if (proposedSize.height < size.height)
2260 size.height = proposedSize.height;
2264 - (void)windowDidBecomeKey:(NSNotification *)notification
2266 WineApplicationController* controller = [WineApplicationController sharedController];
2267 NSEvent* event = [controller lastFlagsChanged];
2269 [self flagsChanged:event];
2271 if (causing_becomeKeyWindow == self) return;
2273 [controller windowGotFocus:self];
2276 - (void) windowDidChangeOcclusionState:(NSNotification*)notification
2278 [self checkWineDisplayLink];
2281 - (void) windowDidChangeScreen:(NSNotification*)notification
2283 [self checkWineDisplayLink];
2286 - (void)windowDidDeminiaturize:(NSNotification *)notification
2288 WineApplicationController* controller = [WineApplicationController sharedController];
2290 if (!ignore_windowDeminiaturize)
2291 [self postDidUnminimizeEvent];
2292 ignore_windowDeminiaturize = FALSE;
2294 [self becameEligibleParentOrChild];
2296 if (fullscreen && [self isOnActiveSpace])
2297 [controller updateFullscreenWindows];
2298 [controller adjustWindowLevels];
2300 if (![self parentWindow])
2301 [self postBroughtForwardEvent];
2303 if (!self.disabled && !self.noActivate)
2305 causing_becomeKeyWindow = self;
2306 [self makeKeyWindow];
2307 causing_becomeKeyWindow = nil;
2308 [controller windowGotFocus:self];
2311 [self windowDidResize:notification];
2312 [self checkWineDisplayLink];
2315 - (void) windowDidEndLiveResize:(NSNotification *)notification
2319 macdrv_event* event = macdrv_create_event(WINDOW_RESIZE_ENDED, self);
2320 [queue postEvent:event];
2321 macdrv_release_event(event);
2325 - (void) windowDidEnterFullScreen:(NSNotification*)notification
2327 enteringFullScreen = FALSE;
2328 enteredFullScreenTime = [[NSProcessInfo processInfo] systemUptime];
2331 - (void) windowDidExitFullScreen:(NSNotification*)notification
2333 exitingFullScreen = FALSE;
2334 [self setFrame:nonFullscreenFrame display:YES animate:NO];
2335 [self windowDidResize:nil];
2338 - (void) windowDidFailToEnterFullScreen:(NSWindow*)window
2340 enteringFullScreen = FALSE;
2341 enteredFullScreenTime = 0;
2344 - (void) windowDidFailToExitFullScreen:(NSWindow*)window
2346 exitingFullScreen = FALSE;
2347 [self windowDidResize:nil];
2350 - (void)windowDidMiniaturize:(NSNotification *)notification
2352 if (fullscreen && [self isOnActiveSpace])
2353 [[WineApplicationController sharedController] updateFullscreenWindows];
2354 [self checkWineDisplayLink];
2357 - (void)windowDidMove:(NSNotification *)notification
2359 [self windowDidResize:notification];
2362 - (void)windowDidResignKey:(NSNotification *)notification
2364 macdrv_event* event;
2366 if (causing_becomeKeyWindow) return;
2368 event = macdrv_create_event(WINDOW_LOST_FOCUS, self);
2369 [queue postEvent:event];
2370 macdrv_release_event(event);
2373 - (void)windowDidResize:(NSNotification *)notification
2375 macdrv_event* event;
2376 NSRect frame = [self frame];
2378 if ([self inLiveResize])
2380 if (NSMinX(frame) != NSMinX(frameAtResizeStart))
2381 resizingFromLeft = TRUE;
2382 if (NSMaxY(frame) != NSMaxY(frameAtResizeStart))
2383 resizingFromTop = TRUE;
2386 frame = [self contentRectForFrameRect:frame];
2388 if (ignore_windowResize || exitingFullScreen) return;
2390 if ([self preventResizing])
2392 [self setContentMinSize:frame.size];
2393 [self setContentMaxSize:frame.size];
2396 [[WineApplicationController sharedController] flipRect:&frame];
2398 /* Coalesce events by discarding any previous ones still in the queue. */
2399 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
2402 event = macdrv_create_event(WINDOW_FRAME_CHANGED, self);
2403 event->window_frame_changed.frame = NSRectToCGRect(frame);
2404 event->window_frame_changed.fullscreen = ([self styleMask] & NSFullScreenWindowMask) != 0;
2405 event->window_frame_changed.in_resize = [self inLiveResize];
2406 [queue postEvent:event];
2407 macdrv_release_event(event);
2409 [[[self contentView] inputContext] invalidateCharacterCoordinates];
2410 [self updateFullscreen];
2413 - (BOOL)windowShouldClose:(id)sender
2415 macdrv_event* event = macdrv_create_event(WINDOW_CLOSE_REQUESTED, self);
2416 [queue postEvent:event];
2417 macdrv_release_event(event);
2421 - (BOOL) windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame
2425 macdrv_event* event = macdrv_create_event(WINDOW_RESTORE_REQUESTED, self);
2426 [queue postEvent:event];
2427 macdrv_release_event(event);
2430 else if (!resizable)
2432 macdrv_event* event = macdrv_create_event(WINDOW_MAXIMIZE_REQUESTED, self);
2433 [queue postEvent:event];
2434 macdrv_release_event(event);
2441 - (void) windowWillClose:(NSNotification*)notification
2445 if (fakingClose) return;
2446 if (latentParentWindow)
2448 [latentParentWindow->latentChildWindows removeObjectIdenticalTo:self];
2449 self.latentParentWindow = nil;
2452 for (child in latentChildWindows)
2454 if (child.latentParentWindow == self)
2455 child.latentParentWindow = nil;
2457 [latentChildWindows removeAllObjects];
2460 - (void) windowWillEnterFullScreen:(NSNotification*)notification
2462 enteringFullScreen = TRUE;
2463 nonFullscreenFrame = [self frame];
2466 - (void) windowWillExitFullScreen:(NSNotification*)notification
2468 exitingFullScreen = TRUE;
2471 - (void)windowWillMiniaturize:(NSNotification *)notification
2473 [self becameIneligibleParentOrChild];
2474 [self grabDockIconSnapshotFromWindow:nil force:NO];
2477 - (NSSize) windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize
2479 if ([self inLiveResize])
2482 return self.frame.size;
2485 macdrv_query* query;
2487 rect = [self frame];
2488 if (resizingFromLeft)
2489 rect.origin.x = NSMaxX(rect) - frameSize.width;
2490 if (!resizingFromTop)
2491 rect.origin.y = NSMaxY(rect) - frameSize.height;
2492 rect.size = frameSize;
2493 rect = [self contentRectForFrameRect:rect];
2494 [[WineApplicationController sharedController] flipRect:&rect];
2496 query = macdrv_create_query();
2497 query->type = QUERY_RESIZE_SIZE;
2498 query->window = (macdrv_window)[self retain];
2499 query->resize_size.rect = NSRectToCGRect(rect);
2500 query->resize_size.from_left = resizingFromLeft;
2501 query->resize_size.from_top = resizingFromTop;
2503 if ([self.queue query:query timeout:0.1])
2505 rect = NSRectFromCGRect(query->resize_size.rect);
2506 rect = [self frameRectForContentRect:rect];
2507 frameSize = rect.size;
2510 macdrv_release_query(query);
2516 - (void) windowWillStartLiveResize:(NSNotification *)notification
2518 [self endWindowDragging];
2522 macdrv_event* event;
2523 NSRect frame = [self contentRectForFrameRect:self.frame];
2525 [[WineApplicationController sharedController] flipRect:&frame];
2527 event = macdrv_create_event(WINDOW_RESTORE_REQUESTED, self);
2528 event->window_restore_requested.keep_frame = TRUE;
2529 event->window_restore_requested.frame = NSRectToCGRect(frame);
2530 [queue postEvent:event];
2531 macdrv_release_event(event);
2534 [self sendResizeStartQuery];
2536 frameAtResizeStart = [self frame];
2537 resizingFromLeft = resizingFromTop = FALSE;
2540 - (NSRect) windowWillUseStandardFrame:(NSWindow*)window defaultFrame:(NSRect)proposedFrame
2542 macdrv_query* query;
2543 NSRect currentContentRect, proposedContentRect, newContentRect, screenRect;
2546 query = macdrv_create_query();
2547 query->type = QUERY_MIN_MAX_INFO;
2548 query->window = (macdrv_window)[self retain];
2549 [self.queue query:query timeout:0.5];
2550 macdrv_release_query(query);
2552 currentContentRect = [self contentRectForFrameRect:[self frame]];
2553 proposedContentRect = [self contentRectForFrameRect:proposedFrame];
2555 maxSize = [self contentMaxSize];
2556 newContentRect.size.width = MIN(NSWidth(proposedContentRect), maxSize.width);
2557 newContentRect.size.height = MIN(NSHeight(proposedContentRect), maxSize.height);
2559 // Try to keep the top-left corner where it is.
2560 newContentRect.origin.x = NSMinX(currentContentRect);
2561 newContentRect.origin.y = NSMaxY(currentContentRect) - NSHeight(newContentRect);
2563 // If that pushes the bottom or right off the screen, pull it up and to the left.
2564 screenRect = [self contentRectForFrameRect:[[self screen] visibleFrame]];
2565 if (NSMaxX(newContentRect) > NSMaxX(screenRect))
2566 newContentRect.origin.x = NSMaxX(screenRect) - NSWidth(newContentRect);
2567 if (NSMinY(newContentRect) < NSMinY(screenRect))
2568 newContentRect.origin.y = NSMinY(screenRect);
2570 // If that pushes the top or left off the screen, push it down and the right
2571 // again. Do this last because the top-left corner is more important than the
2573 if (NSMinX(newContentRect) < NSMinX(screenRect))
2574 newContentRect.origin.x = NSMinX(screenRect);
2575 if (NSMaxY(newContentRect) > NSMaxY(screenRect))
2576 newContentRect.origin.y = NSMaxY(screenRect) - NSHeight(newContentRect);
2578 return [self frameRectForContentRect:newContentRect];
2583 * ---------- NSPasteboardOwner methods ----------
2585 - (void) pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
2587 macdrv_query* query = macdrv_create_query();
2588 query->type = QUERY_PASTEBOARD_DATA;
2589 query->window = (macdrv_window)[self retain];
2590 query->pasteboard_data.type = (CFStringRef)[type copy];
2592 [self.queue query:query timeout:3];
2593 macdrv_release_query(query);
2598 * ---------- NSDraggingDestination methods ----------
2600 - (NSDragOperation) draggingEntered:(id <NSDraggingInfo>)sender
2602 return [self draggingUpdated:sender];
2605 - (void) draggingExited:(id <NSDraggingInfo>)sender
2607 // This isn't really a query. We don't need any response. However, it
2608 // has to be processed in a similar manner as the other drag-and-drop
2609 // queries in order to maintain the proper order of operations.
2610 macdrv_query* query = macdrv_create_query();
2611 query->type = QUERY_DRAG_EXITED;
2612 query->window = (macdrv_window)[self retain];
2614 [self.queue query:query timeout:0.1];
2615 macdrv_release_query(query);
2618 - (NSDragOperation) draggingUpdated:(id <NSDraggingInfo>)sender
2620 NSDragOperation ret;
2621 NSPoint pt = [[self contentView] convertPoint:[sender draggingLocation] fromView:nil];
2622 NSPasteboard* pb = [sender draggingPasteboard];
2624 macdrv_query* query = macdrv_create_query();
2625 query->type = QUERY_DRAG_OPERATION;
2626 query->window = (macdrv_window)[self retain];
2627 query->drag_operation.x = pt.x;
2628 query->drag_operation.y = pt.y;
2629 query->drag_operation.offered_ops = [sender draggingSourceOperationMask];
2630 query->drag_operation.accepted_op = NSDragOperationNone;
2631 query->drag_operation.pasteboard = (CFTypeRef)[pb retain];
2633 [self.queue query:query timeout:3];
2634 ret = query->status ? query->drag_operation.accepted_op : NSDragOperationNone;
2635 macdrv_release_query(query);
2640 - (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
2643 NSPoint pt = [[self contentView] convertPoint:[sender draggingLocation] fromView:nil];
2644 NSPasteboard* pb = [sender draggingPasteboard];
2646 macdrv_query* query = macdrv_create_query();
2647 query->type = QUERY_DRAG_DROP;
2648 query->window = (macdrv_window)[self retain];
2649 query->drag_drop.x = pt.x;
2650 query->drag_drop.y = pt.y;
2651 query->drag_drop.op = [sender draggingSourceOperationMask];
2652 query->drag_drop.pasteboard = (CFTypeRef)[pb retain];
2654 [self.queue query:query timeout:3 * 60 processEvents:YES];
2655 ret = query->status;
2656 macdrv_release_query(query);
2661 - (BOOL) wantsPeriodicDraggingUpdates
2669 /***********************************************************************
2670 * macdrv_create_cocoa_window
2672 * Create a Cocoa window with the given content frame and features (e.g.
2673 * title bar, close box, etc.).
2675 macdrv_window macdrv_create_cocoa_window(const struct macdrv_window_features* wf,
2676 CGRect frame, void* hwnd, macdrv_event_queue queue)
2678 __block WineWindow* window;
2681 window = [[WineWindow createWindowWithFeatures:wf
2682 windowFrame:NSRectFromCGRect(frame)
2684 queue:(WineEventQueue*)queue] retain];
2687 return (macdrv_window)window;
2690 /***********************************************************************
2691 * macdrv_destroy_cocoa_window
2693 * Destroy a Cocoa window.
2695 void macdrv_destroy_cocoa_window(macdrv_window w)
2697 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2698 WineWindow* window = (WineWindow*)w;
2701 [window doOrderOut];
2704 [window.queue discardEventsMatchingMask:-1 forWindow:window];
2710 /***********************************************************************
2711 * macdrv_get_window_hwnd
2713 * Get the hwnd that was set for the window at creation.
2715 void* macdrv_get_window_hwnd(macdrv_window w)
2717 WineWindow* window = (WineWindow*)w;
2721 /***********************************************************************
2722 * macdrv_set_cocoa_window_features
2724 * Update a Cocoa window's features.
2726 void macdrv_set_cocoa_window_features(macdrv_window w,
2727 const struct macdrv_window_features* wf)
2729 WineWindow* window = (WineWindow*)w;
2732 [window setWindowFeatures:wf];
2736 /***********************************************************************
2737 * macdrv_set_cocoa_window_state
2739 * Update a Cocoa window's state.
2741 void macdrv_set_cocoa_window_state(macdrv_window w,
2742 const struct macdrv_window_state* state)
2744 WineWindow* window = (WineWindow*)w;
2747 [window setMacDrvState:state];
2751 /***********************************************************************
2752 * macdrv_set_cocoa_window_title
2754 * Set a Cocoa window's title.
2756 void macdrv_set_cocoa_window_title(macdrv_window w, const unsigned short* title,
2759 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2760 WineWindow* window = (WineWindow*)w;
2761 NSString* titleString;
2764 titleString = [NSString stringWithCharacters:title length:length];
2767 OnMainThreadAsync(^{
2768 [window setTitle:titleString];
2769 if ([window isOrderedIn] && ![window isExcludedFromWindowsMenu])
2770 [NSApp changeWindowsItem:window title:titleString filename:NO];
2776 /***********************************************************************
2777 * macdrv_order_cocoa_window
2779 * Reorder a Cocoa window relative to other windows. If prev is
2780 * non-NULL, it is ordered below that window. Else, if next is non-NULL,
2781 * it is ordered above that window. Otherwise, it is ordered to the
2784 void macdrv_order_cocoa_window(macdrv_window w, macdrv_window p,
2785 macdrv_window n, int activate)
2787 WineWindow* window = (WineWindow*)w;
2788 WineWindow* prev = (WineWindow*)p;
2789 WineWindow* next = (WineWindow*)n;
2791 OnMainThreadAsync(^{
2792 [window orderBelow:prev
2796 [window.queue discardEventsMatchingMask:event_mask_for_type(WINDOW_BROUGHT_FORWARD)
2798 [next.queue discardEventsMatchingMask:event_mask_for_type(WINDOW_BROUGHT_FORWARD)
2802 /***********************************************************************
2803 * macdrv_hide_cocoa_window
2805 * Hides a Cocoa window.
2807 void macdrv_hide_cocoa_window(macdrv_window w)
2809 WineWindow* window = (WineWindow*)w;
2812 [window doOrderOut];
2816 /***********************************************************************
2817 * macdrv_set_cocoa_window_frame
2819 * Move a Cocoa window.
2821 void macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame)
2823 WineWindow* window = (WineWindow*)w;
2826 [window setFrameFromWine:NSRectFromCGRect(*new_frame)];
2830 /***********************************************************************
2831 * macdrv_get_cocoa_window_frame
2833 * Gets the frame of a Cocoa window.
2835 void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame)
2837 WineWindow* window = (WineWindow*)w;
2842 frame = [window contentRectForFrameRect:[window frame]];
2843 [[WineApplicationController sharedController] flipRect:&frame];
2844 *out_frame = NSRectToCGRect(frame);
2848 /***********************************************************************
2849 * macdrv_set_cocoa_parent_window
2851 * Sets the parent window for a Cocoa window. If parent is NULL, clears
2852 * the parent window.
2854 void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent)
2856 WineWindow* window = (WineWindow*)w;
2859 [window setMacDrvParentWindow:(WineWindow*)parent];
2863 /***********************************************************************
2864 * macdrv_set_window_surface
2866 void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex)
2868 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2869 WineWindow* window = (WineWindow*)w;
2872 window.surface = surface;
2873 window.surface_mutex = mutex;
2879 /***********************************************************************
2880 * macdrv_window_needs_display
2882 * Mark a window as needing display in a specified rect (in non-client
2883 * area coordinates).
2885 void macdrv_window_needs_display(macdrv_window w, CGRect rect)
2887 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2888 WineWindow* window = (WineWindow*)w;
2890 OnMainThreadAsync(^{
2891 [[window contentView] setNeedsDisplayInRect:NSRectFromCGRect(rect)];
2897 /***********************************************************************
2898 * macdrv_set_window_shape
2900 * Sets the shape of a Cocoa window from an array of rectangles. If
2901 * rects is NULL, resets the window's shape to its frame.
2903 void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count)
2905 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2906 WineWindow* window = (WineWindow*)w;
2909 if (!rects || !count)
2912 window.shapeData = nil;
2913 [window checkEmptyShaped];
2917 size_t length = sizeof(*rects) * count;
2918 if (window.shapeData.length != length || memcmp(window.shapeData.bytes, rects, length))
2923 path = [NSBezierPath bezierPath];
2924 for (i = 0; i < count; i++)
2925 [path appendBezierPathWithRect:NSRectFromCGRect(rects[i])];
2926 window.shape = path;
2927 window.shapeData = [NSData dataWithBytes:rects length:length];
2928 [window checkEmptyShaped];
2936 /***********************************************************************
2937 * macdrv_set_window_alpha
2939 void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha)
2941 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2942 WineWindow* window = (WineWindow*)w;
2944 [window setAlphaValue:alpha];
2949 /***********************************************************************
2950 * macdrv_set_window_color_key
2952 void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat keyGreen,
2955 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2956 WineWindow* window = (WineWindow*)w;
2959 window.colorKeyed = TRUE;
2960 window.colorKeyRed = keyRed;
2961 window.colorKeyGreen = keyGreen;
2962 window.colorKeyBlue = keyBlue;
2963 [window checkTransparency];
2969 /***********************************************************************
2970 * macdrv_clear_window_color_key
2972 void macdrv_clear_window_color_key(macdrv_window w)
2974 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2975 WineWindow* window = (WineWindow*)w;
2978 window.colorKeyed = FALSE;
2979 [window checkTransparency];
2985 /***********************************************************************
2986 * macdrv_window_use_per_pixel_alpha
2988 void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha)
2990 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2991 WineWindow* window = (WineWindow*)w;
2994 window.usePerPixelAlpha = use_per_pixel_alpha;
2995 [window checkTransparency];
3001 /***********************************************************************
3002 * macdrv_give_cocoa_window_focus
3004 * Makes the Cocoa window "key" (gives it keyboard focus). This also
3005 * orders it front and, if its frame was not within the desktop bounds,
3006 * Cocoa will typically move it on-screen.
3008 void macdrv_give_cocoa_window_focus(macdrv_window w, int activate)
3010 WineWindow* window = (WineWindow*)w;
3013 [window makeFocused:activate];
3017 /***********************************************************************
3018 * macdrv_set_window_min_max_sizes
3020 * Sets the window's minimum and maximum content sizes.
3022 void macdrv_set_window_min_max_sizes(macdrv_window w, CGSize min_size, CGSize max_size)
3024 WineWindow* window = (WineWindow*)w;
3027 [window setWineMinSize:NSSizeFromCGSize(min_size) maxSize:NSSizeFromCGSize(max_size)];
3031 /***********************************************************************
3032 * macdrv_create_view
3034 * Creates and returns a view in the specified rect of the window. The
3035 * caller is responsible for calling macdrv_dispose_view() on the view
3036 * when it is done with it.
3038 macdrv_view macdrv_create_view(macdrv_window w, CGRect rect)
3040 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3041 WineWindow* window = (WineWindow*)w;
3042 __block WineContentView* view;
3044 if (CGRectIsNull(rect)) rect = CGRectZero;
3047 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
3049 view = [[WineContentView alloc] initWithFrame:NSRectFromCGRect(rect)];
3050 [view setAutoresizesSubviews:NO];
3051 [nc addObserver:view
3052 selector:@selector(updateGLContexts)
3053 name:NSViewGlobalFrameDidChangeNotification
3055 [nc addObserver:view
3056 selector:@selector(updateGLContexts)
3057 name:NSApplicationDidChangeScreenParametersNotification
3059 [[window contentView] addSubview:view];
3060 [window updateForGLSubviews];
3064 return (macdrv_view)view;
3067 /***********************************************************************
3068 * macdrv_dispose_view
3070 * Destroys a view previously returned by macdrv_create_view.
3072 void macdrv_dispose_view(macdrv_view v)
3074 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3075 WineContentView* view = (WineContentView*)v;
3078 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
3079 WineWindow* window = (WineWindow*)[view window];
3081 [nc removeObserver:view
3082 name:NSViewGlobalFrameDidChangeNotification
3084 [nc removeObserver:view
3085 name:NSApplicationDidChangeScreenParametersNotification
3087 [view removeFromSuperview];
3089 [window updateForGLSubviews];
3095 /***********************************************************************
3096 * macdrv_set_view_window_and_frame
3098 * Move a view to a new window and/or position within its window. If w
3099 * is NULL, leave the view in its current window and just change its
3102 void macdrv_set_view_window_and_frame(macdrv_view v, macdrv_window w, CGRect rect)
3104 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3105 WineContentView* view = (WineContentView*)v;
3106 WineWindow* window = (WineWindow*)w;
3108 if (CGRectIsNull(rect)) rect = CGRectZero;
3111 BOOL changedWindow = (window && window != [view window]);
3112 NSRect newFrame = NSRectFromCGRect(rect);
3113 NSRect oldFrame = [view frame];
3114 BOOL needUpdateWindowForGLSubviews = FALSE;
3118 WineWindow* oldWindow = (WineWindow*)[view window];
3119 [view removeFromSuperview];
3120 [oldWindow updateForGLSubviews];
3121 [[window contentView] addSubview:view];
3122 needUpdateWindowForGLSubviews = TRUE;
3125 if (!NSEqualRects(oldFrame, newFrame))
3128 [[view superview] setNeedsDisplayInRect:oldFrame];
3129 if (NSEqualPoints(oldFrame.origin, newFrame.origin))
3130 [view setFrameSize:newFrame.size];
3131 else if (NSEqualSizes(oldFrame.size, newFrame.size))
3132 [view setFrameOrigin:newFrame.origin];
3134 [view setFrame:newFrame];
3135 [view setNeedsDisplay:YES];
3136 needUpdateWindowForGLSubviews = TRUE;
3139 if (needUpdateWindowForGLSubviews)
3140 [(WineWindow*)[view window] updateForGLSubviews];
3146 /***********************************************************************
3147 * macdrv_add_view_opengl_context
3149 * Add an OpenGL context to the list being tracked for each view.
3151 void macdrv_add_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
3153 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3154 WineContentView* view = (WineContentView*)v;
3155 WineOpenGLContext *context = (WineOpenGLContext*)c;
3158 [view addGLContext:context];
3164 /***********************************************************************
3165 * macdrv_remove_view_opengl_context
3167 * Add an OpenGL context to the list being tracked for each view.
3169 void macdrv_remove_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
3171 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3172 WineContentView* view = (WineContentView*)v;
3173 WineOpenGLContext *context = (WineOpenGLContext*)c;
3175 OnMainThreadAsync(^{
3176 [view removeGLContext:context];
3182 /***********************************************************************
3183 * macdrv_window_background_color
3185 * Returns the standard Mac window background color as a 32-bit value of
3186 * the form 0x00rrggbb.
3188 uint32_t macdrv_window_background_color(void)
3190 static uint32_t result;
3191 static dispatch_once_t once;
3193 // Annoyingly, [NSColor windowBackgroundColor] refuses to convert to other
3194 // color spaces (RGB or grayscale). So, the only way to get RGB values out
3195 // of it is to draw with it.
3196 dispatch_once(&once, ^{
3198 unsigned char rgbx[4];
3199 unsigned char *planes = rgbx;
3200 NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&planes
3207 colorSpaceName:NSCalibratedRGBColorSpace
3211 [NSGraphicsContext saveGraphicsState];
3212 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap]];
3213 [[NSColor windowBackgroundColor] set];
3214 NSRectFill(NSMakeRect(0, 0, 1, 1));
3215 [NSGraphicsContext restoreGraphicsState];
3217 result = rgbx[0] << 16 | rgbx[1] << 8 | rgbx[2];
3224 /***********************************************************************
3225 * macdrv_send_text_input_event
3227 int macdrv_send_text_input_event(int pressed, unsigned int flags, int repeat, int keyc, void* data)
3232 WineWindow* window = (WineWindow*)[NSApp keyWindow];
3233 if (![window isKindOfClass:[WineWindow class]])
3235 window = (WineWindow*)[NSApp mainWindow];
3236 if (![window isKindOfClass:[WineWindow class]])
3237 window = [[WineApplicationController sharedController] frontWineWindow];
3242 NSUInteger localFlags = flags;
3246 window.imeData = data;
3247 fix_device_modifiers_by_generic(&localFlags);
3249 // An NSEvent created with +keyEventWithType:... is internally marked
3250 // as synthetic and doesn't get sent through input methods. But one
3251 // created from a CGEvent doesn't have that problem.
3252 c = CGEventCreateKeyboardEvent(NULL, keyc, pressed);
3253 CGEventSetFlags(c, localFlags);
3254 CGEventSetIntegerValueField(c, kCGKeyboardEventAutorepeat, repeat);
3255 event = [NSEvent eventWithCGEvent:c];
3258 window.commandDone = FALSE;
3259 ret = [[[window contentView] inputContext] handleEvent:event] && !window.commandDone;