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:0.3 flags:WineQueryNoPreemptWait])
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 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
781 [[NSNotificationCenter defaultCenter] removeObserver:self];
783 [latentChildWindows release];
784 [latentParentWindow release];
790 - (BOOL) preventResizing
792 BOOL preventForClipping = cursor_clipping_locks_windows && [[WineApplicationController sharedController] clippingCursor];
793 return ([self styleMask] & NSResizableWindowMask) && (disabled || !resizable || preventForClipping);
796 - (BOOL) allowsMovingWithMaximized:(BOOL)inMaximized
798 if (allow_immovable_windows && (disabled || inMaximized))
800 else if (cursor_clipping_locks_windows && [[WineApplicationController sharedController] clippingCursor])
806 - (void) adjustFeaturesForState
808 NSUInteger style = [self styleMask];
810 if (style & NSClosableWindowMask)
811 [[self standardWindowButton:NSWindowCloseButton] setEnabled:!self.disabled];
812 if (style & NSMiniaturizableWindowMask)
813 [[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!self.disabled];
814 if (style & NSResizableWindowMask)
815 [[self standardWindowButton:NSWindowZoomButton] setEnabled:!self.disabled];
816 if ([self respondsToSelector:@selector(toggleFullScreen:)])
818 if ([self collectionBehavior] & NSWindowCollectionBehaviorFullScreenPrimary)
819 [[self standardWindowButton:NSWindowFullScreenButton] setEnabled:!self.disabled];
822 if ([self preventResizing])
824 NSSize size = [self contentRectForFrameRect:[self frame]].size;
825 [self setContentMinSize:size];
826 [self setContentMaxSize:size];
830 [self setContentMaxSize:savedContentMaxSize];
831 [self setContentMinSize:savedContentMinSize];
834 if (allow_immovable_windows || cursor_clipping_locks_windows)
835 [self setMovable:[self allowsMovingWithMaximized:maximized]];
838 - (void) adjustFullScreenBehavior:(NSWindowCollectionBehavior)behavior
840 if ([self respondsToSelector:@selector(toggleFullScreen:)])
842 NSUInteger style = [self styleMask];
844 if (behavior & NSWindowCollectionBehaviorParticipatesInCycle &&
845 style & NSResizableWindowMask && !(style & NSUtilityWindowMask) && !maximized)
847 behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
848 behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
852 behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
853 behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
854 if (style & NSFullScreenWindowMask)
855 [super toggleFullScreen:nil];
859 if (behavior != [self collectionBehavior])
861 [self setCollectionBehavior:behavior];
862 [self adjustFeaturesForState];
866 - (void) setWindowFeatures:(const struct macdrv_window_features*)wf
868 static const NSUInteger usedStyles = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask |
869 NSResizableWindowMask | NSUtilityWindowMask | NSBorderlessWindowMask;
870 NSUInteger currentStyle = [self styleMask];
871 NSUInteger newStyle = style_mask_for_features(wf) | (currentStyle & ~usedStyles);
873 if (newStyle != currentStyle)
875 NSString* title = [[[self title] copy] autorelease];
876 BOOL showingButtons = (currentStyle & (NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)) != 0;
877 BOOL shouldShowButtons = (newStyle & (NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)) != 0;
878 if (shouldShowButtons != showingButtons && !((newStyle ^ currentStyle) & NSClosableWindowMask))
880 // -setStyleMask: is buggy on 10.7+ with respect to NSResizableWindowMask.
881 // If transitioning from NSTitledWindowMask | NSResizableWindowMask to
882 // just NSTitledWindowMask, the window buttons should disappear rather
883 // than just being disabled. But they don't. Similarly in reverse.
884 // The workaround is to also toggle NSClosableWindowMask at the same time.
885 [self setStyleMask:newStyle ^ NSClosableWindowMask];
887 [self setStyleMask:newStyle];
889 // -setStyleMask: resets the firstResponder to the window. Set it
890 // back to the content view.
891 if ([[self contentView] acceptsFirstResponder])
892 [self makeFirstResponder:[self contentView]];
894 [self adjustFullScreenBehavior:[self collectionBehavior]];
896 if ([[self title] length] == 0 && [title length] > 0)
897 [self setTitle:title];
900 resizable = wf->resizable;
901 [self adjustFeaturesForState];
902 [self setHasShadow:wf->shadow];
905 // Indicates if the window would be visible if the app were not hidden.
906 - (BOOL) wouldBeVisible
908 return [NSApp isHidden] ? savedVisibleState : [self isVisible];
913 return [self wouldBeVisible] || [self isMiniaturized];
916 - (NSInteger) minimumLevelForActive:(BOOL)active
920 if (self.floating && (active || topmost_float_inactive == TOPMOST_FLOAT_INACTIVE_ALL ||
921 (topmost_float_inactive == TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN && !fullscreen)))
922 level = NSFloatingWindowLevel;
924 level = NSNormalWindowLevel;
930 captured = (fullscreen || [self screen]) && [[WineApplicationController sharedController] areDisplaysCaptured];
932 if (captured || fullscreen)
935 level = CGShieldingWindowLevel() + 1; /* Need +1 or we don't get mouse moves */
937 level = NSStatusWindowLevel + 1;
947 - (void) postDidUnminimizeEvent
951 /* Coalesce events by discarding any previous ones still in the queue. */
952 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_UNMINIMIZE)
955 event = macdrv_create_event(WINDOW_DID_UNMINIMIZE, self);
956 [queue postEvent:event];
957 macdrv_release_event(event);
960 - (void) sendResizeStartQuery
962 macdrv_query* query = macdrv_create_query();
963 query->type = QUERY_RESIZE_START;
964 query->window = (macdrv_window)[self retain];
966 [self.queue query:query timeout:0.3];
967 macdrv_release_query(query);
970 - (void) setMacDrvState:(const struct macdrv_window_state*)state
972 NSWindowCollectionBehavior behavior;
974 self.disabled = state->disabled;
975 self.noActivate = state->no_activate;
977 if (self.floating != state->floating)
979 self.floating = state->floating;
982 // Became floating. If child of non-floating window, make that
983 // relationship latent.
984 WineWindow* parent = (WineWindow*)[self parentWindow];
985 if (parent && !parent.floating)
986 [self becameIneligibleChild];
990 // Became non-floating. If parent of floating children, make that
991 // relationship latent.
993 for (child in [self childWineWindows])
996 [child becameIneligibleChild];
1000 // Check our latent relationships. If floating status was the only
1001 // reason they were latent, then make them active.
1002 if ([self isVisible])
1003 [self becameEligibleParentOrChild];
1005 [[WineApplicationController sharedController] adjustWindowLevels];
1008 if (state->minimized_valid)
1010 macdrv_event_mask discard = event_mask_for_type(WINDOW_DID_UNMINIMIZE);
1012 pendingMinimize = FALSE;
1013 if (state->minimized && ![self isMiniaturized])
1015 if ([self wouldBeVisible])
1017 if ([self styleMask] & NSFullScreenWindowMask)
1019 [self postDidUnminimizeEvent];
1020 discard &= ~event_mask_for_type(WINDOW_DID_UNMINIMIZE);
1024 [super miniaturize:nil];
1025 discard |= event_mask_for_type(WINDOW_BROUGHT_FORWARD) |
1026 event_mask_for_type(WINDOW_GOT_FOCUS) |
1027 event_mask_for_type(WINDOW_LOST_FOCUS);
1031 pendingMinimize = TRUE;
1033 else if (!state->minimized && [self isMiniaturized])
1035 ignore_windowDeminiaturize = TRUE;
1036 [self deminiaturize:nil];
1037 discard |= event_mask_for_type(WINDOW_LOST_FOCUS);
1041 [queue discardEventsMatchingMask:discard forWindow:self];
1044 if (state->maximized != maximized)
1046 maximized = state->maximized;
1047 [self adjustFeaturesForState];
1049 if (!maximized && [self inLiveResize])
1050 [self sendResizeStartQuery];
1053 behavior = NSWindowCollectionBehaviorDefault;
1054 if (state->excluded_by_expose)
1055 behavior |= NSWindowCollectionBehaviorTransient;
1057 behavior |= NSWindowCollectionBehaviorManaged;
1058 if (state->excluded_by_cycle)
1060 behavior |= NSWindowCollectionBehaviorIgnoresCycle;
1061 if ([self isOrderedIn])
1062 [NSApp removeWindowsItem:self];
1066 behavior |= NSWindowCollectionBehaviorParticipatesInCycle;
1067 if ([self isOrderedIn])
1068 [NSApp addWindowsItem:self title:[self title] filename:NO];
1070 [self adjustFullScreenBehavior:behavior];
1073 - (BOOL) addChildWineWindow:(WineWindow*)child assumeVisible:(BOOL)assumeVisible
1075 BOOL reordered = FALSE;
1077 if ([self isVisible] && (assumeVisible || [child isVisible]) && (self.floating || !child.floating))
1079 if ([self level] > [child level])
1080 [child setLevel:[self level]];
1081 [self addChildWindow:child ordered:NSWindowAbove];
1082 [child checkWineDisplayLink];
1083 [latentChildWindows removeObjectIdenticalTo:child];
1084 child.latentParentWindow = nil;
1089 if (!latentChildWindows)
1090 latentChildWindows = [[NSMutableArray alloc] init];
1091 if (![latentChildWindows containsObject:child])
1092 [latentChildWindows addObject:child];
1093 child.latentParentWindow = self;
1099 - (BOOL) addChildWineWindow:(WineWindow*)child
1101 return [self addChildWineWindow:child assumeVisible:FALSE];
1104 - (void) removeChildWineWindow:(WineWindow*)child
1106 [self removeChildWindow:child];
1107 if (child.latentParentWindow == self)
1108 child.latentParentWindow = nil;
1109 [latentChildWindows removeObjectIdenticalTo:child];
1112 - (BOOL) becameEligibleParentOrChild
1114 BOOL reordered = FALSE;
1117 if (latentParentWindow.floating || !self.floating)
1119 // If we aren't visible currently, we assume that we should be and soon
1120 // will be. So, if the latent parent is visible that's enough to assume
1121 // we can establish the parent-child relationship in Cocoa. That will
1122 // actually make us visible, which is fine.
1123 if ([latentParentWindow addChildWineWindow:self assumeVisible:TRUE])
1127 // Here, though, we may not actually be visible yet and adding a child
1128 // won't make us visible. The caller will have to call this method
1129 // again after actually making us visible.
1130 if ([self isVisible] && (count = [latentChildWindows count]))
1132 NSMutableIndexSet* indexesToRemove = [NSMutableIndexSet indexSet];
1135 for (i = 0; i < count; i++)
1137 WineWindow* child = [latentChildWindows objectAtIndex:i];
1138 if ([child isVisible] && (self.floating || !child.floating))
1140 if (child.latentParentWindow == self)
1142 if ([self level] > [child level])
1143 [child setLevel:[self level]];
1144 [self addChildWindow:child ordered:NSWindowAbove];
1145 child.latentParentWindow = nil;
1149 ERR(@"shouldn't happen: %@ thinks %@ is a latent child, but it doesn't agree\n", self, child);
1150 [indexesToRemove addIndex:i];
1154 [latentChildWindows removeObjectsAtIndexes:indexesToRemove];
1160 - (void) becameIneligibleChild
1162 WineWindow* parent = (WineWindow*)[self parentWindow];
1165 if (!parent->latentChildWindows)
1166 parent->latentChildWindows = [[NSMutableArray alloc] init];
1167 [parent->latentChildWindows insertObject:self atIndex:0];
1168 self.latentParentWindow = parent;
1169 [parent removeChildWindow:self];
1173 - (void) becameIneligibleParentOrChild
1175 NSArray* childWindows = [self childWineWindows];
1177 [self becameIneligibleChild];
1179 if ([childWindows count])
1183 for (child in childWindows)
1185 child.latentParentWindow = self;
1186 [self removeChildWindow:child];
1189 if (latentChildWindows)
1190 [latentChildWindows replaceObjectsInRange:NSMakeRange(0, 0) withObjectsFromArray:childWindows];
1192 latentChildWindows = [childWindows mutableCopy];
1196 // Determine if, among Wine windows, this window is directly above or below
1197 // a given other Wine window with no other Wine window intervening.
1198 // Intervening non-Wine windows are ignored.
1199 - (BOOL) isOrdered:(NSWindowOrderingMode)orderingMode relativeTo:(WineWindow*)otherWindow
1201 NSNumber* windowNumber;
1202 NSNumber* otherWindowNumber;
1203 NSArray* windowNumbers;
1204 NSUInteger windowIndex, otherWindowIndex, lowIndex, highIndex, i;
1206 if (![self isVisible] || ![otherWindow isVisible])
1209 windowNumber = [NSNumber numberWithInteger:[self windowNumber]];
1210 otherWindowNumber = [NSNumber numberWithInteger:[otherWindow windowNumber]];
1211 windowNumbers = [[self class] windowNumbersWithOptions:0];
1212 windowIndex = [windowNumbers indexOfObject:windowNumber];
1213 otherWindowIndex = [windowNumbers indexOfObject:otherWindowNumber];
1215 if (windowIndex == NSNotFound || otherWindowIndex == NSNotFound)
1218 if (orderingMode == NSWindowAbove)
1220 lowIndex = windowIndex;
1221 highIndex = otherWindowIndex;
1223 else if (orderingMode == NSWindowBelow)
1225 lowIndex = otherWindowIndex;
1226 highIndex = windowIndex;
1231 if (highIndex <= lowIndex)
1234 for (i = lowIndex + 1; i < highIndex; i++)
1236 NSInteger interveningWindowNumber = [[windowNumbers objectAtIndex:i] integerValue];
1237 NSWindow* interveningWindow = [NSApp windowWithWindowNumber:interveningWindowNumber];
1238 if ([interveningWindow isKindOfClass:[WineWindow class]])
1245 - (void) order:(NSWindowOrderingMode)mode childWindow:(WineWindow*)child relativeTo:(WineWindow*)other
1247 NSMutableArray* windowNumbers;
1248 NSNumber* childWindowNumber;
1249 NSUInteger otherIndex, limit;
1250 NSArray* origChildren;
1251 NSMutableArray* children;
1253 // Get the z-order from the window server and modify it to reflect the
1254 // requested window ordering.
1255 windowNumbers = [[[[self class] windowNumbersWithOptions:NSWindowNumberListAllSpaces] mutableCopy] autorelease];
1256 childWindowNumber = [NSNumber numberWithInteger:[child windowNumber]];
1257 [windowNumbers removeObject:childWindowNumber];
1258 otherIndex = [windowNumbers indexOfObject:[NSNumber numberWithInteger:[other windowNumber]]];
1259 [windowNumbers insertObject:childWindowNumber atIndex:otherIndex + (mode == NSWindowAbove ? 0 : 1)];
1261 // Get our child windows and sort them in the reverse of the desired
1262 // z-order (back-to-front).
1263 origChildren = [self childWineWindows];
1264 children = [[origChildren mutableCopy] autorelease];
1265 [children sortWithOptions:NSSortStable
1266 usingComparator:^NSComparisonResult(id obj1, id obj2){
1267 NSNumber* window1Number = [NSNumber numberWithInteger:[obj1 windowNumber]];
1268 NSNumber* window2Number = [NSNumber numberWithInteger:[obj2 windowNumber]];
1269 NSUInteger index1 = [windowNumbers indexOfObject:window1Number];
1270 NSUInteger index2 = [windowNumbers indexOfObject:window2Number];
1271 if (index1 == NSNotFound)
1273 if (index2 == NSNotFound)
1274 return NSOrderedSame;
1276 return NSOrderedAscending;
1278 else if (index2 == NSNotFound)
1279 return NSOrderedDescending;
1280 else if (index1 < index2)
1281 return NSOrderedDescending;
1282 else if (index2 < index1)
1283 return NSOrderedAscending;
1285 return NSOrderedSame;
1288 // If the current and desired children arrays match up to a point, leave
1289 // those matching children alone.
1290 limit = MIN([origChildren count], [children count]);
1291 for (otherIndex = 0; otherIndex < limit; otherIndex++)
1293 if ([origChildren objectAtIndex:otherIndex] != [children objectAtIndex:otherIndex])
1296 [children removeObjectsInRange:NSMakeRange(0, otherIndex)];
1298 // Remove all of the child windows and re-add them back-to-front so they
1299 // are in the desired order.
1300 for (other in children)
1301 [self removeChildWindow:other];
1302 for (other in children)
1303 [self addChildWindow:other ordered:NSWindowAbove];
1306 /* Returns whether or not the window was ordered in, which depends on if
1307 its frame intersects any screen. */
1308 - (void) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next activate:(BOOL)activate
1310 WineApplicationController* controller = [WineApplicationController sharedController];
1311 if (![self isMiniaturized])
1313 BOOL needAdjustWindowLevels = FALSE;
1316 [controller transformProcessToForeground];
1318 wasVisible = [self isVisible];
1321 [NSApp activateIgnoringOtherApps:YES];
1323 NSDisableScreenUpdates();
1325 if ([self becameEligibleParentOrChild])
1326 needAdjustWindowLevels = TRUE;
1330 WineWindow* other = [prev isVisible] ? prev : next;
1331 NSWindowOrderingMode orderingMode = [prev isVisible] ? NSWindowBelow : NSWindowAbove;
1333 if (![self isOrdered:orderingMode relativeTo:other])
1335 WineWindow* parent = (WineWindow*)[self parentWindow];
1336 WineWindow* otherParent = (WineWindow*)[other parentWindow];
1338 // This window level may not be right for this window based
1339 // on floating-ness, fullscreen-ness, etc. But we set it
1340 // temporarily to allow us to order the windows properly.
1341 // Then the levels get fixed by -adjustWindowLevels.
1342 if ([self level] != [other level])
1343 [self setLevel:[other level]];
1344 [self orderWindow:orderingMode relativeTo:[other windowNumber]];
1345 [self checkWineDisplayLink];
1347 // The above call to -[NSWindow orderWindow:relativeTo:] won't
1348 // reorder windows which are both children of the same parent
1349 // relative to each other, so do that separately.
1350 if (parent && parent == otherParent)
1351 [parent order:orderingMode childWindow:self relativeTo:other];
1353 needAdjustWindowLevels = TRUE;
1358 // Again, temporarily set level to make sure we can order to
1360 next = [controller frontWineWindow];
1361 if (next && [self level] < [next level])
1362 [self setLevel:[next level]];
1363 [self orderFront:nil];
1364 [self checkWineDisplayLink];
1365 needAdjustWindowLevels = TRUE;
1368 if ([self becameEligibleParentOrChild])
1369 needAdjustWindowLevels = TRUE;
1371 if (needAdjustWindowLevels)
1373 if (!wasVisible && fullscreen && [self isOnActiveSpace])
1374 [controller updateFullscreenWindows];
1375 [controller adjustWindowLevels];
1378 if (pendingMinimize)
1380 [super miniaturize:nil];
1381 pendingMinimize = FALSE;
1384 NSEnableScreenUpdates();
1386 /* Cocoa may adjust the frame when the window is ordered onto the screen.
1387 Generate a frame-changed event just in case. The back end will ignore
1388 it if nothing actually changed. */
1389 [self windowDidResize:nil];
1391 if (![self isExcludedFromWindowsMenu])
1392 [NSApp addWindowsItem:self title:[self title] filename:NO];
1398 WineApplicationController* controller = [WineApplicationController sharedController];
1399 BOOL wasVisible = [self isVisible];
1400 BOOL wasOnActiveSpace = [self isOnActiveSpace];
1402 if ([self isMiniaturized])
1403 pendingMinimize = TRUE;
1405 WineWindow* parent = (WineWindow*)self.parentWindow;
1406 if ([parent isKindOfClass:[WineWindow class]])
1407 [parent grabDockIconSnapshotFromWindow:self force:NO];
1409 [self becameIneligibleParentOrChild];
1410 if ([self isMiniaturized])
1414 fakingClose = FALSE;
1417 [self orderOut:nil];
1418 [self checkWineDisplayLink];
1419 savedVisibleState = FALSE;
1420 if (wasVisible && wasOnActiveSpace && fullscreen)
1421 [controller updateFullscreenWindows];
1422 [controller adjustWindowLevels];
1423 [NSApp removeWindowsItem:self];
1425 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_BROUGHT_FORWARD) |
1426 event_mask_for_type(WINDOW_GOT_FOCUS) |
1427 event_mask_for_type(WINDOW_LOST_FOCUS) |
1428 event_mask_for_type(WINDOW_MAXIMIZE_REQUESTED) |
1429 event_mask_for_type(WINDOW_MINIMIZE_REQUESTED) |
1430 event_mask_for_type(WINDOW_RESTORE_REQUESTED)
1434 - (void) updateFullscreen
1436 NSRect contentRect = [self contentRectForFrameRect:[self frame]];
1437 BOOL nowFullscreen = !([self styleMask] & NSFullScreenWindowMask) && screen_covered_by_rect(contentRect, [NSScreen screens]);
1439 if (nowFullscreen != fullscreen)
1441 WineApplicationController* controller = [WineApplicationController sharedController];
1443 fullscreen = nowFullscreen;
1444 if ([self isVisible] && [self isOnActiveSpace])
1445 [controller updateFullscreenWindows];
1447 [controller adjustWindowLevels];
1451 - (void) setFrameFromWine:(NSRect)contentRect
1453 /* Origin is (left, top) in a top-down space. Need to convert it to
1454 (left, bottom) in a bottom-up space. */
1455 [[WineApplicationController sharedController] flipRect:&contentRect];
1457 /* The back end is establishing a new window size and position. It's
1458 not interested in any stale events regarding those that may be sitting
1460 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
1463 if (!NSIsEmptyRect(contentRect))
1465 NSRect frame, oldFrame;
1467 oldFrame = [self frame];
1468 frame = [self frameRectForContentRect:contentRect];
1469 if (!NSEqualRects(frame, oldFrame))
1471 BOOL equalSizes = NSEqualSizes(frame.size, oldFrame.size);
1472 BOOL needEnableScreenUpdates = FALSE;
1474 if ([self preventResizing])
1476 // Allow the following calls to -setFrame:display: to work even
1477 // if they would violate the content size constraints. This
1478 // shouldn't be necessary since the content size constraints are
1479 // documented to not constrain that method, but it seems to be.
1480 [self setContentMinSize:NSZeroSize];
1481 [self setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
1484 if (equalSizes && [[self childWineWindows] count])
1486 // If we change the window frame such that the origin moves
1487 // but the size doesn't change, then Cocoa moves child
1488 // windows with the parent. We don't want that so we fake
1489 // a change of the size and then change it back.
1490 NSRect bogusFrame = frame;
1491 bogusFrame.size.width++;
1493 NSDisableScreenUpdates();
1494 needEnableScreenUpdates = TRUE;
1496 ignore_windowResize = TRUE;
1497 [self setFrame:bogusFrame display:NO];
1498 ignore_windowResize = FALSE;
1501 [self setFrame:frame display:YES];
1502 if ([self preventResizing])
1504 [self setContentMinSize:contentRect.size];
1505 [self setContentMaxSize:contentRect.size];
1508 if (needEnableScreenUpdates)
1509 NSEnableScreenUpdates();
1512 [self updateColorSpace];
1514 if (!enteringFullScreen &&
1515 [[NSProcessInfo processInfo] systemUptime] - enteredFullScreenTime > 1.0)
1516 nonFullscreenFrame = frame;
1518 [self updateFullscreen];
1520 if ([self isOrderedIn])
1522 /* In case Cocoa adjusted the frame we tried to set, generate a frame-changed
1523 event. The back end will ignore it if nothing actually changed. */
1524 [self windowDidResize:nil];
1530 - (void) setMacDrvParentWindow:(WineWindow*)parent
1532 WineWindow* oldParent = (WineWindow*)[self parentWindow];
1533 if ((oldParent && oldParent != parent) || (!oldParent && latentParentWindow != parent))
1535 [oldParent removeChildWineWindow:self];
1536 [latentParentWindow removeChildWineWindow:self];
1537 if ([parent addChildWineWindow:self])
1538 [[WineApplicationController sharedController] adjustWindowLevels];
1542 - (void) setDisabled:(BOOL)newValue
1544 if (disabled != newValue)
1546 disabled = newValue;
1547 [self adjustFeaturesForState];
1551 - (BOOL) needsTransparency
1553 return self.shape || self.colorKeyed || self.usePerPixelAlpha ||
1554 (gl_surface_mode == GL_SURFACE_BEHIND && [[self.contentView valueForKeyPath:@"subviews.@max.hasGLContext"] boolValue]);
1557 - (void) checkTransparency
1559 if (![self isOpaque] && !self.needsTransparency)
1561 self.shapeChangedSinceLastDraw = TRUE;
1562 [[self contentView] setNeedsDisplay:YES];
1563 [self setBackgroundColor:[NSColor windowBackgroundColor]];
1564 [self setOpaque:YES];
1566 else if ([self isOpaque] && self.needsTransparency)
1568 self.shapeChangedSinceLastDraw = TRUE;
1569 [[self contentView] setNeedsDisplay:YES];
1570 [self setBackgroundColor:[NSColor clearColor]];
1571 [self setOpaque:NO];
1575 - (void) setShape:(NSBezierPath*)newShape
1577 if (shape == newShape) return;
1581 [[self contentView] setNeedsDisplayInRect:[shape bounds]];
1585 [[self contentView] setNeedsDisplayInRect:[newShape bounds]];
1587 shape = [newShape copy];
1588 self.shapeChangedSinceLastDraw = TRUE;
1590 [self checkTransparency];
1593 - (void) makeFocused:(BOOL)activate
1597 [[WineApplicationController sharedController] transformProcessToForeground];
1598 [NSApp activateIgnoringOtherApps:YES];
1601 causing_becomeKeyWindow = self;
1602 [self makeKeyWindow];
1603 causing_becomeKeyWindow = nil;
1605 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_GOT_FOCUS) |
1606 event_mask_for_type(WINDOW_LOST_FOCUS)
1610 - (void) postKey:(uint16_t)keyCode
1611 pressed:(BOOL)pressed
1612 modifiers:(NSUInteger)modifiers
1613 event:(NSEvent*)theEvent
1615 macdrv_event* event;
1617 WineApplicationController* controller = [WineApplicationController sharedController];
1619 event = macdrv_create_event(pressed ? KEY_PRESS : KEY_RELEASE, self);
1620 event->key.keycode = keyCode;
1621 event->key.modifiers = modifiers;
1622 event->key.time_ms = [controller ticksForEventTime:[theEvent timestamp]];
1624 if ((cgevent = [theEvent CGEvent]))
1626 CGEventSourceKeyboardType keyboardType = CGEventGetIntegerValueField(cgevent,
1627 kCGKeyboardEventKeyboardType);
1628 if (keyboardType != controller.keyboardType)
1630 controller.keyboardType = keyboardType;
1631 [controller keyboardSelectionDidChange];
1635 [queue postEvent:event];
1637 macdrv_release_event(event);
1639 [controller noteKey:keyCode pressed:pressed];
1642 - (void) postKeyEvent:(NSEvent *)theEvent
1644 [self flagsChanged:theEvent];
1645 [self postKey:[theEvent keyCode]
1646 pressed:[theEvent type] == NSKeyDown
1647 modifiers:adjusted_modifiers_for_option_behavior([theEvent modifierFlags])
1651 - (void) setWineMinSize:(NSSize)minSize maxSize:(NSSize)maxSize
1653 savedContentMinSize = minSize;
1654 savedContentMaxSize = maxSize;
1655 if (![self preventResizing])
1657 [self setContentMinSize:minSize];
1658 [self setContentMaxSize:maxSize];
1662 - (WineWindow*) ancestorWineWindow
1664 WineWindow* ancestor = self;
1667 WineWindow* parent = (WineWindow*)[ancestor parentWindow];
1668 if ([parent isKindOfClass:[WineWindow class]])
1676 - (void) postBroughtForwardEvent
1678 macdrv_event* event = macdrv_create_event(WINDOW_BROUGHT_FORWARD, self);
1679 [queue postEvent:event];
1680 macdrv_release_event(event);
1683 - (void) updateForCursorClipping
1685 [self adjustFeaturesForState];
1688 - (void) endWindowDragging
1692 if (draggingPhase == 3)
1694 macdrv_event* event = macdrv_create_event(WINDOW_DRAG_END, self);
1695 [queue postEvent:event];
1696 macdrv_release_event(event);
1700 [[WineApplicationController sharedController] window:self isBeingDragged:NO];
1704 - (NSMutableDictionary*) displayIDToDisplayLinkMap
1706 static NSMutableDictionary* displayIDToDisplayLinkMap;
1707 if (!displayIDToDisplayLinkMap)
1709 displayIDToDisplayLinkMap = [[NSMutableDictionary alloc] init];
1711 [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidChangeScreenParametersNotification
1714 usingBlock:^(NSNotification *note){
1715 NSMutableSet* badDisplayIDs = [NSMutableSet setWithArray:displayIDToDisplayLinkMap.allKeys];
1716 NSSet* validDisplayIDs = [NSSet setWithArray:[[NSScreen screens] valueForKeyPath:@"deviceDescription.NSScreenNumber"]];
1717 [badDisplayIDs minusSet:validDisplayIDs];
1718 [displayIDToDisplayLinkMap removeObjectsForKeys:[badDisplayIDs allObjects]];
1721 return displayIDToDisplayLinkMap;
1724 - (WineDisplayLink*) wineDisplayLink
1726 if (!_lastDisplayID)
1729 NSMutableDictionary* displayIDToDisplayLinkMap = [self displayIDToDisplayLinkMap];
1730 return [displayIDToDisplayLinkMap objectForKey:[NSNumber numberWithUnsignedInt:_lastDisplayID]];
1733 - (void) checkWineDisplayLink
1735 NSScreen* screen = self.screen;
1736 if (![self isVisible] || ![self isOnActiveSpace] || [self isMiniaturized] || [self isEmptyShaped])
1738 #if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
1739 if ([self respondsToSelector:@selector(occlusionState)] && !(self.occlusionState & NSWindowOcclusionStateVisible))
1743 NSNumber* displayIDNumber = [screen.deviceDescription objectForKey:@"NSScreenNumber"];
1744 CGDirectDisplayID displayID = [displayIDNumber unsignedIntValue];
1745 if (displayID == _lastDisplayID)
1748 NSMutableDictionary* displayIDToDisplayLinkMap = [self displayIDToDisplayLinkMap];
1752 WineDisplayLink* link = [displayIDToDisplayLinkMap objectForKey:[NSNumber numberWithUnsignedInt:_lastDisplayID]];
1753 [link removeWindow:self];
1757 WineDisplayLink* link = [displayIDToDisplayLinkMap objectForKey:displayIDNumber];
1760 link = [[[WineDisplayLink alloc] initWithDisplayID:displayID] autorelease];
1761 [displayIDToDisplayLinkMap setObject:link forKey:displayIDNumber];
1763 [link addWindow:self];
1764 [self displayIfNeeded];
1766 _lastDisplayID = displayID;
1769 - (BOOL) isEmptyShaped
1771 return (self.shapeData.length == sizeof(CGRectZero) && !memcmp(self.shapeData.bytes, &CGRectZero, sizeof(CGRectZero)));
1774 - (BOOL) canProvideSnapshot
1776 return (self.windowNumber > 0 && ![self isEmptyShaped]);
1779 - (void) grabDockIconSnapshotFromWindow:(WineWindow*)window force:(BOOL)force
1781 if (![self isEmptyShaped])
1784 NSTimeInterval now = [[NSProcessInfo processInfo] systemUptime];
1785 if (!force && now < lastDockIconSnapshot + 1)
1790 if (![window canProvideSnapshot])
1796 for (WineWindow* childWindow in self.childWindows)
1798 if (![childWindow isKindOfClass:[WineWindow class]] || ![childWindow canProvideSnapshot])
1801 NSSize size = childWindow.frame.size;
1802 CGFloat area = size.width * size.height;
1803 if (!window || area > bestArea)
1805 window = childWindow;
1814 const void* windowID = (const void*)(CGWindowID)window.windowNumber;
1815 CFArrayRef windowIDs = CFArrayCreate(NULL, &windowID, 1, NULL);
1816 CGImageRef windowImage = CGWindowListCreateImageFromArray(CGRectNull, windowIDs, kCGWindowImageBoundsIgnoreFraming);
1817 CFRelease(windowIDs);
1821 NSImage* appImage = [NSApp applicationIconImage];
1823 appImage = [NSImage imageNamed:NSImageNameApplicationIcon];
1825 NSImage* dockIcon = [[[NSImage alloc] initWithSize:NSMakeSize(256, 256)] autorelease];
1826 [dockIcon lockFocus];
1828 CGContextRef cgcontext = [[NSGraphicsContext currentContext] graphicsPort];
1830 CGRect rect = CGRectMake(8, 8, 240, 240);
1831 size_t width = CGImageGetWidth(windowImage);
1832 size_t height = CGImageGetHeight(windowImage);
1835 rect.size.height *= height / (double)width;
1836 rect.origin.y += (CGRectGetWidth(rect) - CGRectGetHeight(rect)) / 2;
1838 else if (width != height)
1840 rect.size.width *= width / (double)height;
1841 rect.origin.x += (CGRectGetHeight(rect) - CGRectGetWidth(rect)) / 2;
1844 CGContextDrawImage(cgcontext, rect, windowImage);
1845 [appImage drawInRect:NSMakeRect(156, 4, 96, 96)
1847 operation:NSCompositeSourceOver
1852 [dockIcon unlockFocus];
1854 CGImageRelease(windowImage);
1856 NSImageView* imageView = (NSImageView*)self.dockTile.contentView;
1857 if (![imageView isKindOfClass:[NSImageView class]])
1859 imageView = [[[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, 256, 256)] autorelease];
1860 imageView.imageScaling = NSImageScaleProportionallyUpOrDown;
1861 self.dockTile.contentView = imageView;
1863 imageView.image = dockIcon;
1864 [self.dockTile display];
1865 lastDockIconSnapshot = now;
1868 - (void) checkEmptyShaped
1870 if (self.dockTile.contentView && ![self isEmptyShaped])
1872 self.dockTile.contentView = nil;
1873 lastDockIconSnapshot = 0;
1875 [self checkWineDisplayLink];
1880 * ---------- NSWindow method overrides ----------
1882 - (BOOL) canBecomeKeyWindow
1884 if (causing_becomeKeyWindow == self) return YES;
1885 if (self.disabled || self.noActivate) return NO;
1886 return [self isKeyWindow];
1889 - (BOOL) canBecomeMainWindow
1891 return [self canBecomeKeyWindow];
1894 - (NSRect) constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
1896 // If a window is sized to completely cover a screen, then it's in
1897 // full-screen mode. In that case, we don't allow NSWindow to constrain
1899 NSArray* screens = [NSScreen screens];
1900 NSRect contentRect = [self contentRectForFrameRect:frameRect];
1901 if (!screen_covered_by_rect(contentRect, screens) &&
1902 frame_intersects_screens(frameRect, screens))
1903 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
1907 // This private method of NSWindow is called as Cocoa reacts to the display
1908 // configuration changing. Among other things, it adjusts the window's
1909 // frame based on how the screen(s) changed size. That tells Wine that the
1910 // window has been moved. We don't want that. Rather, we want to make
1911 // sure that the WinAPI notion of the window position is maintained/
1912 // restored, possibly undoing or overriding Cocoa's adjustment.
1914 // So, we queue a REASSERT_WINDOW_POSITION event to the back end before
1915 // Cocoa has a chance to adjust the frame, thus preceding any resulting
1916 // WINDOW_FRAME_CHANGED event that may get queued. The back end will
1917 // reassert its notion of the position. That call won't get processed
1918 // until after this method returns, so it will override whatever this
1919 // method does to the window position. It will also discard any pending
1920 // WINDOW_FRAME_CHANGED events.
1922 // Unfortunately, the only way I've found to know when Cocoa is _about to_
1923 // adjust the window's position due to a display change is to hook into
1924 // this private method. This private method has remained stable from 10.6
1925 // through 10.11. If it does change, the most likely thing is that it
1926 // will be removed and no longer called and this fix will simply stop
1927 // working. The only real danger would be if Apple changed the return type
1928 // to a struct or floating-point type, which would change the calling
1930 - (id) _displayChanged
1932 macdrv_event* event = macdrv_create_event(REASSERT_WINDOW_POSITION, self);
1933 [queue postEvent:event];
1934 macdrv_release_event(event);
1936 return [super _displayChanged];
1939 - (BOOL) isExcludedFromWindowsMenu
1941 return !([self collectionBehavior] & NSWindowCollectionBehaviorParticipatesInCycle);
1944 - (BOOL) validateMenuItem:(NSMenuItem *)menuItem
1946 BOOL ret = [super validateMenuItem:menuItem];
1948 if ([menuItem action] == @selector(makeKeyAndOrderFront:))
1949 ret = [self isKeyWindow] || (!self.disabled && !self.noActivate);
1950 if ([menuItem action] == @selector(toggleFullScreen:) && (self.disabled || maximized))
1956 /* We don't call this. It's the action method of the items in the Window menu. */
1957 - (void) makeKeyAndOrderFront:(id)sender
1959 if ([self isMiniaturized])
1960 [self deminiaturize:nil];
1961 [self orderBelow:nil orAbove:nil activate:NO];
1962 [[self ancestorWineWindow] postBroughtForwardEvent];
1964 if (![self isKeyWindow] && !self.disabled && !self.noActivate)
1965 [[WineApplicationController sharedController] windowGotFocus:self];
1968 - (void) sendEvent:(NSEvent*)event
1970 NSEventType type = event.type;
1972 /* NSWindow consumes certain key-down events as part of Cocoa's keyboard
1973 interface control. For example, Control-Tab switches focus among
1974 views. We want to bypass that feature, so directly route key-down
1975 events to -keyDown:. */
1976 if (type == NSKeyDown)
1977 [[self firstResponder] keyDown:event];
1980 if (!draggingPhase && maximized && ![self isMovable] &&
1981 ![self allowsMovingWithMaximized:YES] && [self allowsMovingWithMaximized:NO] &&
1982 type == NSLeftMouseDown && (self.styleMask & NSTitledWindowMask))
1984 NSRect titleBar = self.frame;
1985 NSRect contentRect = [self contentRectForFrameRect:titleBar];
1986 titleBar.size.height = NSMaxY(titleBar) - NSMaxY(contentRect);
1987 titleBar.origin.y = NSMaxY(contentRect);
1989 dragStartPosition = [self convertBaseToScreen:event.locationInWindow];
1991 if (NSMouseInRect(dragStartPosition, titleBar, NO))
1993 static const NSWindowButton buttons[] = {
1994 NSWindowCloseButton,
1995 NSWindowMiniaturizeButton,
1997 NSWindowFullScreenButton,
1999 BOOL hitButton = NO;
2002 for (i = 0; i < sizeof(buttons) / sizeof(buttons[0]); i++)
2006 if (buttons[i] == NSWindowFullScreenButton && ![self respondsToSelector:@selector(toggleFullScreen:)])
2009 button = [self standardWindowButton:buttons[i]];
2010 if ([button hitTest:[button.superview convertPoint:event.locationInWindow fromView:nil]])
2020 dragWindowStartPosition = NSMakePoint(NSMinX(titleBar), NSMaxY(titleBar));
2021 [[WineApplicationController sharedController] window:self isBeingDragged:YES];
2025 else if (draggingPhase && (type == NSLeftMouseDragged || type == NSLeftMouseUp))
2027 if ([self isMovable])
2029 NSPoint point = [self convertBaseToScreen:event.locationInWindow];
2030 NSPoint newTopLeft = dragWindowStartPosition;
2032 newTopLeft.x += point.x - dragStartPosition.x;
2033 newTopLeft.y += point.y - dragStartPosition.y;
2035 if (draggingPhase == 2)
2037 macdrv_event* event = macdrv_create_event(WINDOW_DRAG_BEGIN, self);
2038 [queue postEvent:event];
2039 macdrv_release_event(event);
2044 [self setFrameTopLeftPoint:newTopLeft];
2046 else if (draggingPhase == 1 && type == NSLeftMouseDragged)
2048 macdrv_event* event;
2049 NSRect frame = [self contentRectForFrameRect:self.frame];
2051 [[WineApplicationController sharedController] flipRect:&frame];
2053 event = macdrv_create_event(WINDOW_RESTORE_REQUESTED, self);
2054 event->window_restore_requested.keep_frame = TRUE;
2055 event->window_restore_requested.frame = NSRectToCGRect(frame);
2056 [queue postEvent:event];
2057 macdrv_release_event(event);
2062 if (type == NSLeftMouseUp)
2063 [self endWindowDragging];
2066 [super sendEvent:event];
2070 - (void) miniaturize:(id)sender
2072 macdrv_event* event = macdrv_create_event(WINDOW_MINIMIZE_REQUESTED, self);
2073 [queue postEvent:event];
2074 macdrv_release_event(event);
2076 WineWindow* parent = (WineWindow*)self.parentWindow;
2077 if ([parent isKindOfClass:[WineWindow class]])
2078 [parent grabDockIconSnapshotFromWindow:self force:YES];
2081 - (void) toggleFullScreen:(id)sender
2083 if (!self.disabled && !maximized)
2084 [super toggleFullScreen:sender];
2087 - (void) setViewsNeedDisplay:(BOOL)value
2089 if (value && ![self viewsNeedDisplay])
2091 WineDisplayLink* link = [self wineDisplayLink];
2094 NSTimeInterval now = [[NSProcessInfo processInfo] systemUptime];
2095 if (_lastDisplayTime + [link refreshPeriod] < now)
2096 [self setAutodisplay:YES];
2100 _lastDisplayTime = now;
2104 [super setViewsNeedDisplay:value];
2109 _lastDisplayTime = [[NSProcessInfo processInfo] systemUptime];
2111 [self setAutodisplay:NO];
2114 - (void) displayIfNeeded
2116 _lastDisplayTime = [[NSProcessInfo processInfo] systemUptime];
2117 [super displayIfNeeded];
2118 [self setAutodisplay:NO];
2121 - (NSArray*) childWineWindows
2123 NSArray* childWindows = self.childWindows;
2124 NSIndexSet* indexes = [childWindows indexesOfObjectsPassingTest:^BOOL(id child, NSUInteger idx, BOOL *stop){
2125 return [child isKindOfClass:[WineWindow class]];
2127 return [childWindows objectsAtIndexes:indexes];
2130 // We normally use the generic/calibrated RGB color space for the window,
2131 // rather than the device color space, to avoid expensive color conversion
2132 // which slows down drawing. However, for windows displaying OpenGL, having
2133 // a different color space than the screen greatly reduces frame rates, often
2134 // limiting it to the display refresh rate.
2136 // To avoid this, we switch back to the screen color space whenever the
2137 // window is covered by a view with an attached OpenGL context.
2138 - (void) updateColorSpace
2140 NSRect contentRect = [[self contentView] frame];
2141 BOOL coveredByGLView = FALSE;
2142 for (WineContentView* view in [[self contentView] subviews])
2144 if ([view hasGLContext])
2146 NSRect frame = [view convertRect:[view bounds] toView:nil];
2147 if (NSContainsRect(frame, contentRect))
2149 coveredByGLView = TRUE;
2155 if (coveredByGLView)
2156 [self setColorSpace:nil];
2158 [self setColorSpace:[NSColorSpace genericRGBColorSpace]];
2161 - (void) updateForGLSubviews
2163 [self updateColorSpace];
2164 if (gl_surface_mode == GL_SURFACE_BEHIND)
2165 [self checkTransparency];
2170 * ---------- NSResponder method overrides ----------
2172 - (void) keyDown:(NSEvent *)theEvent { [self postKeyEvent:theEvent]; }
2174 - (void) flagsChanged:(NSEvent *)theEvent
2176 static const struct {
2180 { NX_ALPHASHIFTMASK, kVK_CapsLock },
2181 { NX_DEVICELSHIFTKEYMASK, kVK_Shift },
2182 { NX_DEVICERSHIFTKEYMASK, kVK_RightShift },
2183 { NX_DEVICELCTLKEYMASK, kVK_Control },
2184 { NX_DEVICERCTLKEYMASK, kVK_RightControl },
2185 { NX_DEVICELALTKEYMASK, kVK_Option },
2186 { NX_DEVICERALTKEYMASK, kVK_RightOption },
2187 { NX_DEVICELCMDKEYMASK, kVK_Command },
2188 { NX_DEVICERCMDKEYMASK, kVK_RightCommand },
2191 NSUInteger modifierFlags = adjusted_modifiers_for_option_behavior([theEvent modifierFlags]);
2193 int i, last_changed;
2195 fix_device_modifiers_by_generic(&modifierFlags);
2196 changed = modifierFlags ^ lastModifierFlags;
2199 for (i = 0; i < sizeof(modifiers)/sizeof(modifiers[0]); i++)
2200 if (changed & modifiers[i].mask)
2203 for (i = 0; i <= last_changed; i++)
2205 if (changed & modifiers[i].mask)
2207 BOOL pressed = (modifierFlags & modifiers[i].mask) != 0;
2209 if (i == last_changed)
2210 lastModifierFlags = modifierFlags;
2213 lastModifierFlags ^= modifiers[i].mask;
2214 fix_generic_modifiers_by_device(&lastModifierFlags);
2217 // Caps lock generates one event for each press-release action.
2218 // We need to simulate a pair of events for each actual event.
2219 if (modifiers[i].mask == NX_ALPHASHIFTMASK)
2221 [self postKey:modifiers[i].keycode
2223 modifiers:lastModifierFlags
2224 event:(NSEvent*)theEvent];
2228 [self postKey:modifiers[i].keycode
2230 modifiers:lastModifierFlags
2231 event:(NSEvent*)theEvent];
2236 - (void) applicationWillHide
2238 savedVisibleState = [self isVisible];
2241 - (void) applicationDidUnhide
2243 if ([self isVisible])
2244 [self becameEligibleParentOrChild];
2249 * ---------- NSWindowDelegate methods ----------
2251 - (NSSize) window:(NSWindow*)window willUseFullScreenContentSize:(NSSize)proposedSize
2253 macdrv_query* query;
2256 query = macdrv_create_query();
2257 query->type = QUERY_MIN_MAX_INFO;
2258 query->window = (macdrv_window)[self retain];
2259 [self.queue query:query timeout:0.5];
2260 macdrv_release_query(query);
2262 size = [self contentMaxSize];
2263 if (proposedSize.width < size.width)
2264 size.width = proposedSize.width;
2265 if (proposedSize.height < size.height)
2266 size.height = proposedSize.height;
2270 - (void)windowDidBecomeKey:(NSNotification *)notification
2272 WineApplicationController* controller = [WineApplicationController sharedController];
2273 NSEvent* event = [controller lastFlagsChanged];
2275 [self flagsChanged:event];
2277 if (causing_becomeKeyWindow == self) return;
2279 [controller windowGotFocus:self];
2282 - (void) windowDidChangeOcclusionState:(NSNotification*)notification
2284 [self checkWineDisplayLink];
2287 - (void) windowDidChangeScreen:(NSNotification*)notification
2289 [self checkWineDisplayLink];
2292 - (void)windowDidDeminiaturize:(NSNotification *)notification
2294 WineApplicationController* controller = [WineApplicationController sharedController];
2296 if (!ignore_windowDeminiaturize)
2297 [self postDidUnminimizeEvent];
2298 ignore_windowDeminiaturize = FALSE;
2300 [self becameEligibleParentOrChild];
2302 if (fullscreen && [self isOnActiveSpace])
2303 [controller updateFullscreenWindows];
2304 [controller adjustWindowLevels];
2306 if (![self parentWindow])
2307 [self postBroughtForwardEvent];
2309 if (!self.disabled && !self.noActivate)
2311 causing_becomeKeyWindow = self;
2312 [self makeKeyWindow];
2313 causing_becomeKeyWindow = nil;
2314 [controller windowGotFocus:self];
2317 [self windowDidResize:notification];
2318 [self checkWineDisplayLink];
2321 - (void) windowDidEndLiveResize:(NSNotification *)notification
2325 macdrv_event* event = macdrv_create_event(WINDOW_RESIZE_ENDED, self);
2326 [queue postEvent:event];
2327 macdrv_release_event(event);
2331 - (void) windowDidEnterFullScreen:(NSNotification*)notification
2333 enteringFullScreen = FALSE;
2334 enteredFullScreenTime = [[NSProcessInfo processInfo] systemUptime];
2337 - (void) windowDidExitFullScreen:(NSNotification*)notification
2339 exitingFullScreen = FALSE;
2340 [self setFrame:nonFullscreenFrame display:YES animate:NO];
2341 [self windowDidResize:nil];
2344 - (void) windowDidFailToEnterFullScreen:(NSWindow*)window
2346 enteringFullScreen = FALSE;
2347 enteredFullScreenTime = 0;
2350 - (void) windowDidFailToExitFullScreen:(NSWindow*)window
2352 exitingFullScreen = FALSE;
2353 [self windowDidResize:nil];
2356 - (void)windowDidMiniaturize:(NSNotification *)notification
2358 if (fullscreen && [self isOnActiveSpace])
2359 [[WineApplicationController sharedController] updateFullscreenWindows];
2360 [self checkWineDisplayLink];
2363 - (void)windowDidMove:(NSNotification *)notification
2365 [self windowDidResize:notification];
2368 - (void)windowDidResignKey:(NSNotification *)notification
2370 macdrv_event* event;
2372 if (causing_becomeKeyWindow) return;
2374 event = macdrv_create_event(WINDOW_LOST_FOCUS, self);
2375 [queue postEvent:event];
2376 macdrv_release_event(event);
2379 - (void)windowDidResize:(NSNotification *)notification
2381 macdrv_event* event;
2382 NSRect frame = [self frame];
2384 if ([self inLiveResize])
2386 if (NSMinX(frame) != NSMinX(frameAtResizeStart))
2387 resizingFromLeft = TRUE;
2388 if (NSMaxY(frame) != NSMaxY(frameAtResizeStart))
2389 resizingFromTop = TRUE;
2392 frame = [self contentRectForFrameRect:frame];
2394 if (ignore_windowResize || exitingFullScreen) return;
2396 if ([self preventResizing])
2398 [self setContentMinSize:frame.size];
2399 [self setContentMaxSize:frame.size];
2402 [[WineApplicationController sharedController] flipRect:&frame];
2404 /* Coalesce events by discarding any previous ones still in the queue. */
2405 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
2408 event = macdrv_create_event(WINDOW_FRAME_CHANGED, self);
2409 event->window_frame_changed.frame = NSRectToCGRect(frame);
2410 event->window_frame_changed.fullscreen = ([self styleMask] & NSFullScreenWindowMask) != 0;
2411 event->window_frame_changed.in_resize = [self inLiveResize];
2412 [queue postEvent:event];
2413 macdrv_release_event(event);
2415 [[[self contentView] inputContext] invalidateCharacterCoordinates];
2416 [self updateFullscreen];
2419 - (BOOL)windowShouldClose:(id)sender
2421 macdrv_event* event = macdrv_create_event(WINDOW_CLOSE_REQUESTED, self);
2422 [queue postEvent:event];
2423 macdrv_release_event(event);
2427 - (BOOL) windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame
2431 macdrv_event* event = macdrv_create_event(WINDOW_RESTORE_REQUESTED, self);
2432 [queue postEvent:event];
2433 macdrv_release_event(event);
2436 else if (!resizable)
2438 macdrv_event* event = macdrv_create_event(WINDOW_MAXIMIZE_REQUESTED, self);
2439 [queue postEvent:event];
2440 macdrv_release_event(event);
2447 - (void) windowWillClose:(NSNotification*)notification
2451 if (fakingClose) return;
2452 if (latentParentWindow)
2454 [latentParentWindow->latentChildWindows removeObjectIdenticalTo:self];
2455 self.latentParentWindow = nil;
2458 for (child in latentChildWindows)
2460 if (child.latentParentWindow == self)
2461 child.latentParentWindow = nil;
2463 [latentChildWindows removeAllObjects];
2466 - (void) windowWillEnterFullScreen:(NSNotification*)notification
2468 enteringFullScreen = TRUE;
2469 nonFullscreenFrame = [self frame];
2472 - (void) windowWillExitFullScreen:(NSNotification*)notification
2474 exitingFullScreen = TRUE;
2477 - (void)windowWillMiniaturize:(NSNotification *)notification
2479 [self becameIneligibleParentOrChild];
2480 [self grabDockIconSnapshotFromWindow:nil force:NO];
2483 - (NSSize) windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize
2485 if ([self inLiveResize])
2488 return self.frame.size;
2491 macdrv_query* query;
2493 rect = [self frame];
2494 if (resizingFromLeft)
2495 rect.origin.x = NSMaxX(rect) - frameSize.width;
2496 if (!resizingFromTop)
2497 rect.origin.y = NSMaxY(rect) - frameSize.height;
2498 rect.size = frameSize;
2499 rect = [self contentRectForFrameRect:rect];
2500 [[WineApplicationController sharedController] flipRect:&rect];
2502 query = macdrv_create_query();
2503 query->type = QUERY_RESIZE_SIZE;
2504 query->window = (macdrv_window)[self retain];
2505 query->resize_size.rect = NSRectToCGRect(rect);
2506 query->resize_size.from_left = resizingFromLeft;
2507 query->resize_size.from_top = resizingFromTop;
2509 if ([self.queue query:query timeout:0.1])
2511 rect = NSRectFromCGRect(query->resize_size.rect);
2512 rect = [self frameRectForContentRect:rect];
2513 frameSize = rect.size;
2516 macdrv_release_query(query);
2522 - (void) windowWillStartLiveResize:(NSNotification *)notification
2524 [self endWindowDragging];
2528 macdrv_event* event;
2529 NSRect frame = [self contentRectForFrameRect:self.frame];
2531 [[WineApplicationController sharedController] flipRect:&frame];
2533 event = macdrv_create_event(WINDOW_RESTORE_REQUESTED, self);
2534 event->window_restore_requested.keep_frame = TRUE;
2535 event->window_restore_requested.frame = NSRectToCGRect(frame);
2536 [queue postEvent:event];
2537 macdrv_release_event(event);
2540 [self sendResizeStartQuery];
2542 frameAtResizeStart = [self frame];
2543 resizingFromLeft = resizingFromTop = FALSE;
2546 - (NSRect) windowWillUseStandardFrame:(NSWindow*)window defaultFrame:(NSRect)proposedFrame
2548 macdrv_query* query;
2549 NSRect currentContentRect, proposedContentRect, newContentRect, screenRect;
2552 query = macdrv_create_query();
2553 query->type = QUERY_MIN_MAX_INFO;
2554 query->window = (macdrv_window)[self retain];
2555 [self.queue query:query timeout:0.5];
2556 macdrv_release_query(query);
2558 currentContentRect = [self contentRectForFrameRect:[self frame]];
2559 proposedContentRect = [self contentRectForFrameRect:proposedFrame];
2561 maxSize = [self contentMaxSize];
2562 newContentRect.size.width = MIN(NSWidth(proposedContentRect), maxSize.width);
2563 newContentRect.size.height = MIN(NSHeight(proposedContentRect), maxSize.height);
2565 // Try to keep the top-left corner where it is.
2566 newContentRect.origin.x = NSMinX(currentContentRect);
2567 newContentRect.origin.y = NSMaxY(currentContentRect) - NSHeight(newContentRect);
2569 // If that pushes the bottom or right off the screen, pull it up and to the left.
2570 screenRect = [self contentRectForFrameRect:[[self screen] visibleFrame]];
2571 if (NSMaxX(newContentRect) > NSMaxX(screenRect))
2572 newContentRect.origin.x = NSMaxX(screenRect) - NSWidth(newContentRect);
2573 if (NSMinY(newContentRect) < NSMinY(screenRect))
2574 newContentRect.origin.y = NSMinY(screenRect);
2576 // If that pushes the top or left off the screen, push it down and the right
2577 // again. Do this last because the top-left corner is more important than the
2579 if (NSMinX(newContentRect) < NSMinX(screenRect))
2580 newContentRect.origin.x = NSMinX(screenRect);
2581 if (NSMaxY(newContentRect) > NSMaxY(screenRect))
2582 newContentRect.origin.y = NSMaxY(screenRect) - NSHeight(newContentRect);
2584 return [self frameRectForContentRect:newContentRect];
2589 * ---------- NSPasteboardOwner methods ----------
2591 - (void) pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
2593 macdrv_query* query = macdrv_create_query();
2594 query->type = QUERY_PASTEBOARD_DATA;
2595 query->window = (macdrv_window)[self retain];
2596 query->pasteboard_data.type = (CFStringRef)[type copy];
2598 [self.queue query:query timeout:3];
2599 macdrv_release_query(query);
2604 * ---------- NSDraggingDestination methods ----------
2606 - (NSDragOperation) draggingEntered:(id <NSDraggingInfo>)sender
2608 return [self draggingUpdated:sender];
2611 - (void) draggingExited:(id <NSDraggingInfo>)sender
2613 // This isn't really a query. We don't need any response. However, it
2614 // has to be processed in a similar manner as the other drag-and-drop
2615 // queries in order to maintain the proper order of operations.
2616 macdrv_query* query = macdrv_create_query();
2617 query->type = QUERY_DRAG_EXITED;
2618 query->window = (macdrv_window)[self retain];
2620 [self.queue query:query timeout:0.1];
2621 macdrv_release_query(query);
2624 - (NSDragOperation) draggingUpdated:(id <NSDraggingInfo>)sender
2626 NSDragOperation ret;
2627 NSPoint pt = [[self contentView] convertPoint:[sender draggingLocation] fromView:nil];
2628 NSPasteboard* pb = [sender draggingPasteboard];
2630 macdrv_query* query = macdrv_create_query();
2631 query->type = QUERY_DRAG_OPERATION;
2632 query->window = (macdrv_window)[self retain];
2633 query->drag_operation.x = pt.x;
2634 query->drag_operation.y = pt.y;
2635 query->drag_operation.offered_ops = [sender draggingSourceOperationMask];
2636 query->drag_operation.accepted_op = NSDragOperationNone;
2637 query->drag_operation.pasteboard = (CFTypeRef)[pb retain];
2639 [self.queue query:query timeout:3];
2640 ret = query->status ? query->drag_operation.accepted_op : NSDragOperationNone;
2641 macdrv_release_query(query);
2646 - (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
2649 NSPoint pt = [[self contentView] convertPoint:[sender draggingLocation] fromView:nil];
2650 NSPasteboard* pb = [sender draggingPasteboard];
2652 macdrv_query* query = macdrv_create_query();
2653 query->type = QUERY_DRAG_DROP;
2654 query->window = (macdrv_window)[self retain];
2655 query->drag_drop.x = pt.x;
2656 query->drag_drop.y = pt.y;
2657 query->drag_drop.op = [sender draggingSourceOperationMask];
2658 query->drag_drop.pasteboard = (CFTypeRef)[pb retain];
2660 [self.queue query:query timeout:3 * 60 flags:WineQueryProcessEvents];
2661 ret = query->status;
2662 macdrv_release_query(query);
2667 - (BOOL) wantsPeriodicDraggingUpdates
2675 /***********************************************************************
2676 * macdrv_create_cocoa_window
2678 * Create a Cocoa window with the given content frame and features (e.g.
2679 * title bar, close box, etc.).
2681 macdrv_window macdrv_create_cocoa_window(const struct macdrv_window_features* wf,
2682 CGRect frame, void* hwnd, macdrv_event_queue queue)
2684 __block WineWindow* window;
2687 window = [[WineWindow createWindowWithFeatures:wf
2688 windowFrame:NSRectFromCGRect(frame)
2690 queue:(WineEventQueue*)queue] retain];
2693 return (macdrv_window)window;
2696 /***********************************************************************
2697 * macdrv_destroy_cocoa_window
2699 * Destroy a Cocoa window.
2701 void macdrv_destroy_cocoa_window(macdrv_window w)
2703 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2704 WineWindow* window = (WineWindow*)w;
2707 [window doOrderOut];
2710 [window.queue discardEventsMatchingMask:-1 forWindow:window];
2716 /***********************************************************************
2717 * macdrv_get_window_hwnd
2719 * Get the hwnd that was set for the window at creation.
2721 void* macdrv_get_window_hwnd(macdrv_window w)
2723 WineWindow* window = (WineWindow*)w;
2727 /***********************************************************************
2728 * macdrv_set_cocoa_window_features
2730 * Update a Cocoa window's features.
2732 void macdrv_set_cocoa_window_features(macdrv_window w,
2733 const struct macdrv_window_features* wf)
2735 WineWindow* window = (WineWindow*)w;
2738 [window setWindowFeatures:wf];
2742 /***********************************************************************
2743 * macdrv_set_cocoa_window_state
2745 * Update a Cocoa window's state.
2747 void macdrv_set_cocoa_window_state(macdrv_window w,
2748 const struct macdrv_window_state* state)
2750 WineWindow* window = (WineWindow*)w;
2753 [window setMacDrvState:state];
2757 /***********************************************************************
2758 * macdrv_set_cocoa_window_title
2760 * Set a Cocoa window's title.
2762 void macdrv_set_cocoa_window_title(macdrv_window w, const unsigned short* title,
2765 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2766 WineWindow* window = (WineWindow*)w;
2767 NSString* titleString;
2770 titleString = [NSString stringWithCharacters:title length:length];
2773 OnMainThreadAsync(^{
2774 [window setTitle:titleString];
2775 if ([window isOrderedIn] && ![window isExcludedFromWindowsMenu])
2776 [NSApp changeWindowsItem:window title:titleString filename:NO];
2782 /***********************************************************************
2783 * macdrv_order_cocoa_window
2785 * Reorder a Cocoa window relative to other windows. If prev is
2786 * non-NULL, it is ordered below that window. Else, if next is non-NULL,
2787 * it is ordered above that window. Otherwise, it is ordered to the
2790 void macdrv_order_cocoa_window(macdrv_window w, macdrv_window p,
2791 macdrv_window n, int activate)
2793 WineWindow* window = (WineWindow*)w;
2794 WineWindow* prev = (WineWindow*)p;
2795 WineWindow* next = (WineWindow*)n;
2797 OnMainThreadAsync(^{
2798 [window orderBelow:prev
2802 [window.queue discardEventsMatchingMask:event_mask_for_type(WINDOW_BROUGHT_FORWARD)
2804 [next.queue discardEventsMatchingMask:event_mask_for_type(WINDOW_BROUGHT_FORWARD)
2808 /***********************************************************************
2809 * macdrv_hide_cocoa_window
2811 * Hides a Cocoa window.
2813 void macdrv_hide_cocoa_window(macdrv_window w)
2815 WineWindow* window = (WineWindow*)w;
2818 [window doOrderOut];
2822 /***********************************************************************
2823 * macdrv_set_cocoa_window_frame
2825 * Move a Cocoa window.
2827 void macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame)
2829 WineWindow* window = (WineWindow*)w;
2832 [window setFrameFromWine:NSRectFromCGRect(*new_frame)];
2836 /***********************************************************************
2837 * macdrv_get_cocoa_window_frame
2839 * Gets the frame of a Cocoa window.
2841 void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame)
2843 WineWindow* window = (WineWindow*)w;
2848 frame = [window contentRectForFrameRect:[window frame]];
2849 [[WineApplicationController sharedController] flipRect:&frame];
2850 *out_frame = NSRectToCGRect(frame);
2854 /***********************************************************************
2855 * macdrv_set_cocoa_parent_window
2857 * Sets the parent window for a Cocoa window. If parent is NULL, clears
2858 * the parent window.
2860 void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent)
2862 WineWindow* window = (WineWindow*)w;
2865 [window setMacDrvParentWindow:(WineWindow*)parent];
2869 /***********************************************************************
2870 * macdrv_set_window_surface
2872 void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex)
2874 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2875 WineWindow* window = (WineWindow*)w;
2878 window.surface = surface;
2879 window.surface_mutex = mutex;
2885 /***********************************************************************
2886 * macdrv_window_needs_display
2888 * Mark a window as needing display in a specified rect (in non-client
2889 * area coordinates).
2891 void macdrv_window_needs_display(macdrv_window w, CGRect rect)
2893 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2894 WineWindow* window = (WineWindow*)w;
2896 OnMainThreadAsync(^{
2897 [[window contentView] setNeedsDisplayInRect:NSRectFromCGRect(rect)];
2903 /***********************************************************************
2904 * macdrv_set_window_shape
2906 * Sets the shape of a Cocoa window from an array of rectangles. If
2907 * rects is NULL, resets the window's shape to its frame.
2909 void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count)
2911 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2912 WineWindow* window = (WineWindow*)w;
2915 if (!rects || !count)
2918 window.shapeData = nil;
2919 [window checkEmptyShaped];
2923 size_t length = sizeof(*rects) * count;
2924 if (window.shapeData.length != length || memcmp(window.shapeData.bytes, rects, length))
2929 path = [NSBezierPath bezierPath];
2930 for (i = 0; i < count; i++)
2931 [path appendBezierPathWithRect:NSRectFromCGRect(rects[i])];
2932 window.shape = path;
2933 window.shapeData = [NSData dataWithBytes:rects length:length];
2934 [window checkEmptyShaped];
2942 /***********************************************************************
2943 * macdrv_set_window_alpha
2945 void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha)
2947 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2948 WineWindow* window = (WineWindow*)w;
2950 [window setAlphaValue:alpha];
2955 /***********************************************************************
2956 * macdrv_set_window_color_key
2958 void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat keyGreen,
2961 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2962 WineWindow* window = (WineWindow*)w;
2965 window.colorKeyed = TRUE;
2966 window.colorKeyRed = keyRed;
2967 window.colorKeyGreen = keyGreen;
2968 window.colorKeyBlue = keyBlue;
2969 [window checkTransparency];
2975 /***********************************************************************
2976 * macdrv_clear_window_color_key
2978 void macdrv_clear_window_color_key(macdrv_window w)
2980 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2981 WineWindow* window = (WineWindow*)w;
2984 window.colorKeyed = FALSE;
2985 [window checkTransparency];
2991 /***********************************************************************
2992 * macdrv_window_use_per_pixel_alpha
2994 void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha)
2996 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
2997 WineWindow* window = (WineWindow*)w;
3000 window.usePerPixelAlpha = use_per_pixel_alpha;
3001 [window checkTransparency];
3007 /***********************************************************************
3008 * macdrv_give_cocoa_window_focus
3010 * Makes the Cocoa window "key" (gives it keyboard focus). This also
3011 * orders it front and, if its frame was not within the desktop bounds,
3012 * Cocoa will typically move it on-screen.
3014 void macdrv_give_cocoa_window_focus(macdrv_window w, int activate)
3016 WineWindow* window = (WineWindow*)w;
3019 [window makeFocused:activate];
3023 /***********************************************************************
3024 * macdrv_set_window_min_max_sizes
3026 * Sets the window's minimum and maximum content sizes.
3028 void macdrv_set_window_min_max_sizes(macdrv_window w, CGSize min_size, CGSize max_size)
3030 WineWindow* window = (WineWindow*)w;
3033 [window setWineMinSize:NSSizeFromCGSize(min_size) maxSize:NSSizeFromCGSize(max_size)];
3037 /***********************************************************************
3038 * macdrv_create_view
3040 * Creates and returns a view in the specified rect of the window. The
3041 * caller is responsible for calling macdrv_dispose_view() on the view
3042 * when it is done with it.
3044 macdrv_view macdrv_create_view(macdrv_window w, CGRect rect)
3046 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3047 WineWindow* window = (WineWindow*)w;
3048 __block WineContentView* view;
3050 if (CGRectIsNull(rect)) rect = CGRectZero;
3053 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
3055 view = [[WineContentView alloc] initWithFrame:NSRectFromCGRect(rect)];
3056 [view setAutoresizesSubviews:NO];
3057 [nc addObserver:view
3058 selector:@selector(updateGLContexts)
3059 name:NSViewGlobalFrameDidChangeNotification
3061 [nc addObserver:view
3062 selector:@selector(updateGLContexts)
3063 name:NSApplicationDidChangeScreenParametersNotification
3065 [[window contentView] addSubview:view];
3066 [window updateForGLSubviews];
3070 return (macdrv_view)view;
3073 /***********************************************************************
3074 * macdrv_dispose_view
3076 * Destroys a view previously returned by macdrv_create_view.
3078 void macdrv_dispose_view(macdrv_view v)
3080 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3081 WineContentView* view = (WineContentView*)v;
3084 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
3085 WineWindow* window = (WineWindow*)[view window];
3087 [nc removeObserver:view
3088 name:NSViewGlobalFrameDidChangeNotification
3090 [nc removeObserver:view
3091 name:NSApplicationDidChangeScreenParametersNotification
3093 [view removeFromSuperview];
3095 [window updateForGLSubviews];
3101 /***********************************************************************
3102 * macdrv_set_view_window_and_frame
3104 * Move a view to a new window and/or position within its window. If w
3105 * is NULL, leave the view in its current window and just change its
3108 void macdrv_set_view_window_and_frame(macdrv_view v, macdrv_window w, CGRect rect)
3110 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3111 WineContentView* view = (WineContentView*)v;
3112 WineWindow* window = (WineWindow*)w;
3114 if (CGRectIsNull(rect)) rect = CGRectZero;
3117 BOOL changedWindow = (window && window != [view window]);
3118 NSRect newFrame = NSRectFromCGRect(rect);
3119 NSRect oldFrame = [view frame];
3120 BOOL needUpdateWindowForGLSubviews = FALSE;
3124 WineWindow* oldWindow = (WineWindow*)[view window];
3125 [view removeFromSuperview];
3126 [oldWindow updateForGLSubviews];
3127 [[window contentView] addSubview:view];
3128 needUpdateWindowForGLSubviews = TRUE;
3131 if (!NSEqualRects(oldFrame, newFrame))
3134 [[view superview] setNeedsDisplayInRect:oldFrame];
3135 if (NSEqualPoints(oldFrame.origin, newFrame.origin))
3136 [view setFrameSize:newFrame.size];
3137 else if (NSEqualSizes(oldFrame.size, newFrame.size))
3138 [view setFrameOrigin:newFrame.origin];
3140 [view setFrame:newFrame];
3141 [view setNeedsDisplay:YES];
3142 needUpdateWindowForGLSubviews = TRUE;
3145 if (needUpdateWindowForGLSubviews)
3146 [(WineWindow*)[view window] updateForGLSubviews];
3152 /***********************************************************************
3153 * macdrv_add_view_opengl_context
3155 * Add an OpenGL context to the list being tracked for each view.
3157 void macdrv_add_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
3159 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3160 WineContentView* view = (WineContentView*)v;
3161 WineOpenGLContext *context = (WineOpenGLContext*)c;
3164 [view addGLContext:context];
3170 /***********************************************************************
3171 * macdrv_remove_view_opengl_context
3173 * Add an OpenGL context to the list being tracked for each view.
3175 void macdrv_remove_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
3177 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
3178 WineContentView* view = (WineContentView*)v;
3179 WineOpenGLContext *context = (WineOpenGLContext*)c;
3181 OnMainThreadAsync(^{
3182 [view removeGLContext:context];
3188 /***********************************************************************
3189 * macdrv_window_background_color
3191 * Returns the standard Mac window background color as a 32-bit value of
3192 * the form 0x00rrggbb.
3194 uint32_t macdrv_window_background_color(void)
3196 static uint32_t result;
3197 static dispatch_once_t once;
3199 // Annoyingly, [NSColor windowBackgroundColor] refuses to convert to other
3200 // color spaces (RGB or grayscale). So, the only way to get RGB values out
3201 // of it is to draw with it.
3202 dispatch_once(&once, ^{
3204 unsigned char rgbx[4];
3205 unsigned char *planes = rgbx;
3206 NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&planes
3213 colorSpaceName:NSCalibratedRGBColorSpace
3217 [NSGraphicsContext saveGraphicsState];
3218 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap]];
3219 [[NSColor windowBackgroundColor] set];
3220 NSRectFill(NSMakeRect(0, 0, 1, 1));
3221 [NSGraphicsContext restoreGraphicsState];
3223 result = rgbx[0] << 16 | rgbx[1] << 8 | rgbx[2];
3230 /***********************************************************************
3231 * macdrv_send_text_input_event
3233 void macdrv_send_text_input_event(int pressed, unsigned int flags, int repeat, int keyc, void* data, int* done)
3235 OnMainThreadAsync(^{
3237 macdrv_event* event;
3238 WineWindow* window = (WineWindow*)[NSApp keyWindow];
3239 if (![window isKindOfClass:[WineWindow class]])
3241 window = (WineWindow*)[NSApp mainWindow];
3242 if (![window isKindOfClass:[WineWindow class]])
3243 window = [[WineApplicationController sharedController] frontWineWindow];
3248 NSUInteger localFlags = flags;
3252 window.imeData = data;
3253 fix_device_modifiers_by_generic(&localFlags);
3255 // An NSEvent created with +keyEventWithType:... is internally marked
3256 // as synthetic and doesn't get sent through input methods. But one
3257 // created from a CGEvent doesn't have that problem.
3258 c = CGEventCreateKeyboardEvent(NULL, keyc, pressed);
3259 CGEventSetFlags(c, localFlags);
3260 CGEventSetIntegerValueField(c, kCGKeyboardEventAutorepeat, repeat);
3261 event = [NSEvent eventWithCGEvent:c];
3264 window.commandDone = FALSE;
3265 ret = [[[window contentView] inputContext] handleEvent:event] && !window.commandDone;
3270 event = macdrv_create_event(SENT_TEXT_INPUT, window);
3271 event->sent_text_input.handled = ret;
3272 event->sent_text_input.done = done;
3273 [[window queue] postEvent:event];
3274 macdrv_release_event(event);