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>
23 #import "cocoa_window.h"
25 #include "macdrv_cocoa.h"
27 #import "cocoa_event.h"
28 #import "cocoa_opengl.h"
31 /* Additional Mac virtual keycode, to complement those in Carbon's <HIToolbox/Events.h>. */
33 kVK_RightCommand = 0x36, /* Invented for Wine; was unused */
37 static NSUInteger style_mask_for_features(const struct macdrv_window_features* wf)
39 NSUInteger style_mask;
43 style_mask = NSTitledWindowMask;
44 if (wf->close_button) style_mask |= NSClosableWindowMask;
45 if (wf->minimize_button) style_mask |= NSMiniaturizableWindowMask;
46 if (wf->resizable) style_mask |= NSResizableWindowMask;
47 if (wf->utility) style_mask |= NSUtilityWindowMask;
49 else style_mask = NSBorderlessWindowMask;
55 static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
58 for (screen in screens)
60 if (NSIntersectsRect(frame, [screen frame]))
67 static NSScreen* screen_covered_by_rect(NSRect rect, NSArray* screens)
69 for (NSScreen* screen in screens)
71 if (NSContainsRect(rect, [screen frame]))
78 /* We rely on the supposedly device-dependent modifier flags to distinguish the
79 keys on the left side of the keyboard from those on the right. Some event
80 sources don't set those device-depdendent flags. If we see a device-independent
81 flag for a modifier without either corresponding device-dependent flag, assume
83 static inline void fix_device_modifiers_by_generic(NSUInteger* modifiers)
85 if ((*modifiers & (NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK)) == NX_COMMANDMASK)
86 *modifiers |= NX_DEVICELCMDKEYMASK;
87 if ((*modifiers & (NX_SHIFTMASK | NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK)) == NX_SHIFTMASK)
88 *modifiers |= NX_DEVICELSHIFTKEYMASK;
89 if ((*modifiers & (NX_CONTROLMASK | NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK)) == NX_CONTROLMASK)
90 *modifiers |= NX_DEVICELCTLKEYMASK;
91 if ((*modifiers & (NX_ALTERNATEMASK | NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK)) == NX_ALTERNATEMASK)
92 *modifiers |= NX_DEVICELALTKEYMASK;
95 /* As we manipulate individual bits of a modifier mask, we can end up with
96 inconsistent sets of flags. In particular, we might set or clear one of the
97 left/right-specific bits, but not the corresponding non-side-specific bit.
98 Fix that. If either side-specific bit is set, set the non-side-specific bit,
99 otherwise clear it. */
100 static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
102 if (*modifiers & (NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK))
103 *modifiers |= NX_COMMANDMASK;
105 *modifiers &= ~NX_COMMANDMASK;
106 if (*modifiers & (NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK))
107 *modifiers |= NX_SHIFTMASK;
109 *modifiers &= ~NX_SHIFTMASK;
110 if (*modifiers & (NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK))
111 *modifiers |= NX_CONTROLMASK;
113 *modifiers &= ~NX_CONTROLMASK;
114 if (*modifiers & (NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK))
115 *modifiers |= NX_ALTERNATEMASK;
117 *modifiers &= ~NX_ALTERNATEMASK;
121 @interface WineContentView : NSView
123 NSMutableArray* glContexts;
124 NSMutableArray* pendingGlContexts;
127 - (void) addGLContext:(WineOpenGLContext*)context;
128 - (void) removeGLContext:(WineOpenGLContext*)context;
129 - (void) updateGLContexts;
134 @interface WineWindow ()
136 @property (nonatomic) BOOL disabled;
137 @property (nonatomic) BOOL noActivate;
138 @property (readwrite, nonatomic) BOOL floating;
139 @property (retain, nonatomic) NSWindow* latentParentWindow;
141 @property (nonatomic) void* hwnd;
142 @property (retain, readwrite, nonatomic) WineEventQueue* queue;
144 @property (nonatomic) void* surface;
145 @property (nonatomic) pthread_mutex_t* surface_mutex;
147 @property (copy, nonatomic) NSBezierPath* shape;
148 @property (nonatomic) BOOL shapeChangedSinceLastDraw;
149 @property (readonly, nonatomic) BOOL needsTransparency;
151 @property (nonatomic) BOOL colorKeyed;
152 @property (nonatomic) CGFloat colorKeyRed, colorKeyGreen, colorKeyBlue;
153 @property (nonatomic) BOOL usePerPixelAlpha;
155 @property (readwrite, nonatomic) NSInteger levelWhenActive;
160 @implementation WineContentView
164 [glContexts release];
165 [pendingGlContexts release];
174 - (void) drawRect:(NSRect)rect
176 WineWindow* window = (WineWindow*)[self window];
178 for (WineOpenGLContext* context in pendingGlContexts)
179 context.needsUpdate = TRUE;
180 [glContexts addObjectsFromArray:pendingGlContexts];
181 [pendingGlContexts removeAllObjects];
183 if ([window contentView] != self)
186 if (window.surface && window.surface_mutex &&
187 !pthread_mutex_lock(window.surface_mutex))
192 if (get_surface_blit_rects(window.surface, &rects, &count) && count)
194 CGContextRef context;
197 [window.shape addClip];
199 context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
200 CGContextSetBlendMode(context, kCGBlendModeCopy);
202 for (i = 0; i < count; i++)
207 imageRect = CGRectIntersection(rects[i], NSRectToCGRect(rect));
208 image = create_surface_image(window.surface, &imageRect, FALSE);
212 if (window.colorKeyed)
214 CGImageRef maskedImage;
215 CGFloat components[] = { window.colorKeyRed - 0.5, window.colorKeyRed + 0.5,
216 window.colorKeyGreen - 0.5, window.colorKeyGreen + 0.5,
217 window.colorKeyBlue - 0.5, window.colorKeyBlue + 0.5 };
218 maskedImage = CGImageCreateWithMaskingColors(image, components);
221 CGImageRelease(image);
226 CGContextDrawImage(context, imageRect, image);
228 CGImageRelease(image);
233 pthread_mutex_unlock(window.surface_mutex);
236 // If the window may be transparent, then we have to invalidate the
237 // shadow every time we draw. Also, if this is the first time we've
238 // drawn since changing from transparent to opaque.
239 if (![window isOpaque] || window.shapeChangedSinceLastDraw)
241 window.shapeChangedSinceLastDraw = FALSE;
242 [window invalidateShadow];
246 /* By default, NSView will swallow right-clicks in an attempt to support contextual
247 menus. We need to bypass that and allow the event to make it to the window. */
248 - (void) rightMouseDown:(NSEvent*)theEvent
250 [[self window] rightMouseDown:theEvent];
253 - (void) addGLContext:(WineOpenGLContext*)context
256 glContexts = [[NSMutableArray alloc] init];
257 if (!pendingGlContexts)
258 pendingGlContexts = [[NSMutableArray alloc] init];
259 [pendingGlContexts addObject:context];
260 [self setNeedsDisplay:YES];
263 - (void) removeGLContext:(WineOpenGLContext*)context
265 [glContexts removeObjectIdenticalTo:context];
266 [pendingGlContexts removeObjectIdenticalTo:context];
269 - (void) updateGLContexts
271 for (WineOpenGLContext* context in glContexts)
272 context.needsUpdate = TRUE;
275 - (BOOL) acceptsFirstMouse:(NSEvent*)theEvent
283 @implementation WineWindow
285 @synthesize disabled, noActivate, floating, latentParentWindow, hwnd, queue;
286 @synthesize surface, surface_mutex;
287 @synthesize shape, shapeChangedSinceLastDraw;
288 @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue;
289 @synthesize usePerPixelAlpha;
290 @synthesize levelWhenActive;
292 + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
293 windowFrame:(NSRect)window_frame
295 queue:(WineEventQueue*)queue
298 WineContentView* contentView;
299 NSTrackingArea* trackingArea;
301 [NSApp flipRect:&window_frame];
303 window = [[[self alloc] initWithContentRect:window_frame
304 styleMask:style_mask_for_features(wf)
305 backing:NSBackingStoreBuffered
306 defer:YES] autorelease];
308 if (!window) return nil;
309 window->normalStyleMask = [window styleMask];
311 /* Standardize windows to eliminate differences between titled and
312 borderless windows and between NSWindow and NSPanel. */
313 [window setHidesOnDeactivate:NO];
314 [window setReleasedWhenClosed:NO];
316 [window disableCursorRects];
317 [window setShowsResizeIndicator:NO];
318 [window setHasShadow:wf->shadow];
319 [window setAcceptsMouseMovedEvents:YES];
320 [window setColorSpace:[NSColorSpace genericRGBColorSpace]];
321 [window setDelegate:window];
323 window.queue = queue;
325 [window registerForDraggedTypes:[NSArray arrayWithObjects:(NSString*)kUTTypeData,
326 (NSString*)kUTTypeContent,
329 contentView = [[[WineContentView alloc] initWithFrame:NSZeroRect] autorelease];
332 [contentView setAutoresizesSubviews:NO];
334 /* We use tracking areas in addition to setAcceptsMouseMovedEvents:YES
335 because they give us mouse moves in the background. */
336 trackingArea = [[[NSTrackingArea alloc] initWithRect:[contentView bounds]
337 options:(NSTrackingMouseMoved |
338 NSTrackingActiveAlways |
339 NSTrackingInVisibleRect)
341 userInfo:nil] autorelease];
344 [contentView addTrackingArea:trackingArea];
346 [window setContentView:contentView];
354 [latentParentWindow release];
359 - (void) adjustFeaturesForState
361 NSUInteger style = normalStyleMask;
364 style &= ~NSResizableWindowMask;
365 if (style != [self styleMask])
366 [self setStyleMask:style];
368 if (style & NSClosableWindowMask)
369 [[self standardWindowButton:NSWindowCloseButton] setEnabled:!self.disabled];
370 if (style & NSMiniaturizableWindowMask)
371 [[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!self.disabled];
374 - (void) setWindowFeatures:(const struct macdrv_window_features*)wf
376 normalStyleMask = style_mask_for_features(wf);
377 [self adjustFeaturesForState];
378 [self setHasShadow:wf->shadow];
381 - (void) adjustWindowLevel
384 BOOL fullscreen, captured;
387 WineWindow* other = nil;
389 screen = screen_covered_by_rect([self frame], [NSScreen screens]);
390 fullscreen = (screen != nil);
391 captured = (screen || [self screen]) && [NSApp areDisplaysCaptured];
393 if (captured || fullscreen)
396 level = CGShieldingWindowLevel() + 1; /* Need +1 or we don't get mouse moves */
398 level = NSMainMenuWindowLevel + 1;
403 else if (self.floating)
404 level = NSFloatingWindowLevel;
406 level = NSNormalWindowLevel;
408 index = [[NSApp orderedWineWindows] indexOfObjectIdenticalTo:self];
409 if (index != NSNotFound && index + 1 < [[NSApp orderedWineWindows] count])
411 other = [[NSApp orderedWineWindows] objectAtIndex:index + 1];
412 if (level < [other level])
413 level = [other level];
416 if (level != [self level])
418 [self setLevelWhenActive:level];
420 /* Setting the window level above has moved this window to the front
421 of all other windows at the same level. We need to move it
422 back into its proper place among other windows of that level.
423 Also, any windows which are supposed to be in front of it had
424 better have the same or higher window level. If not, bump them
426 if (index != NSNotFound)
428 for (; index > 0; index--)
430 other = [[NSApp orderedWineWindows] objectAtIndex:index - 1];
431 if ([other level] < level)
432 [other setLevelWhenActive:level];
435 [self orderWindow:NSWindowBelow relativeTo:[other windowNumber]];
443 - (void) setMacDrvState:(const struct macdrv_window_state*)state
445 NSWindowCollectionBehavior behavior;
447 self.disabled = state->disabled;
448 self.noActivate = state->no_activate;
450 self.floating = state->floating;
451 [self adjustWindowLevel];
453 behavior = NSWindowCollectionBehaviorDefault;
454 if (state->excluded_by_expose)
455 behavior |= NSWindowCollectionBehaviorTransient;
457 behavior |= NSWindowCollectionBehaviorManaged;
458 if (state->excluded_by_cycle)
460 behavior |= NSWindowCollectionBehaviorIgnoresCycle;
461 if ([self isVisible])
462 [NSApp removeWindowsItem:self];
466 behavior |= NSWindowCollectionBehaviorParticipatesInCycle;
467 if ([self isVisible])
468 [NSApp addWindowsItem:self title:[self title] filename:NO];
470 [self setCollectionBehavior:behavior];
472 if (state->minimized && ![self isMiniaturized])
474 ignore_windowMiniaturize = TRUE;
475 [self miniaturize:nil];
477 else if (!state->minimized && [self isMiniaturized])
479 ignore_windowDeminiaturize = TRUE;
480 [self deminiaturize:nil];
483 /* Whatever events regarding minimization might have been in the queue are now stale. */
484 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_MINIMIZE) |
485 event_mask_for_type(WINDOW_DID_UNMINIMIZE)
489 /* Returns whether or not the window was ordered in, which depends on if
490 its frame intersects any screen. */
491 - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next
493 BOOL on_screen = frame_intersects_screens([self frame], [NSScreen screens]);
496 [NSApp transformProcessToForeground];
500 /* Make sure that windows that should be above this one really are.
501 This is necessary since a full-screen window gets a boost to its
502 window level to be in front of the menu bar and Dock and that moves
503 it out of the z-order that Win32 would otherwise establish. */
504 if ([prev level] < [self level])
506 NSUInteger index = [[NSApp orderedWineWindows] indexOfObjectIdenticalTo:prev];
507 if (index != NSNotFound)
509 [prev setLevelWhenActive:[self level]];
510 for (; index > 0; index--)
512 WineWindow* other = [[NSApp orderedWineWindows] objectAtIndex:index - 1];
513 if ([other level] < [self level])
514 [other setLevelWhenActive:[self level]];
518 [self orderWindow:NSWindowBelow relativeTo:[prev windowNumber]];
519 [NSApp wineWindow:self ordered:NSWindowBelow relativeTo:prev];
523 /* Similarly, make sure this window is really above what it should be. */
524 if (next && [next level] > [self level])
525 [self setLevelWhenActive:[next level]];
526 [self orderWindow:NSWindowAbove relativeTo:[next windowNumber]];
527 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:next];
529 if (latentParentWindow)
531 if ([latentParentWindow level] > [self level])
532 [self setLevelWhenActive:[latentParentWindow level]];
533 [latentParentWindow addChildWindow:self ordered:NSWindowAbove];
534 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:latentParentWindow];
535 self.latentParentWindow = nil;
538 /* Cocoa may adjust the frame when the window is ordered onto the screen.
539 Generate a frame-changed event just in case. The back end will ignore
540 it if nothing actually changed. */
541 [self windowDidResize:nil];
543 if (![self isExcludedFromWindowsMenu])
544 [NSApp addWindowsItem:self title:[self title] filename:NO];
552 self.latentParentWindow = [self parentWindow];
553 [latentParentWindow removeChildWindow:self];
555 [NSApp wineWindow:self ordered:NSWindowOut relativeTo:nil];
556 [NSApp removeWindowsItem:self];
559 - (BOOL) setFrameIfOnScreen:(NSRect)contentRect
561 NSArray* screens = [NSScreen screens];
562 BOOL on_screen = [self isVisible];
563 NSRect frame, oldFrame;
565 if (![screens count]) return on_screen;
567 /* Origin is (left, top) in a top-down space. Need to convert it to
568 (left, bottom) in a bottom-up space. */
569 [NSApp flipRect:&contentRect];
573 on_screen = frame_intersects_screens(contentRect, screens);
578 if (!NSIsEmptyRect(contentRect))
580 oldFrame = [self frame];
581 frame = [self frameRectForContentRect:contentRect];
582 if (!NSEqualRects(frame, oldFrame))
584 if (NSEqualSizes(frame.size, oldFrame.size))
585 [self setFrameOrigin:frame.origin];
587 [self setFrame:frame display:YES];
593 [self adjustWindowLevel];
595 /* In case Cocoa adjusted the frame we tried to set, generate a frame-changed
596 event. The back end will ignore it if nothing actually changed. */
597 [self windowDidResize:nil];
601 /* The back end is establishing a new window size and position. It's
602 not interested in any stale events regarding those that may be sitting
604 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
611 - (void) setMacDrvParentWindow:(WineWindow*)parent
613 if ([self parentWindow] != parent)
615 [[self parentWindow] removeChildWindow:self];
616 self.latentParentWindow = nil;
617 if ([self isVisible] && parent)
619 if ([parent level] > [self level])
620 [self setLevelWhenActive:[parent level]];
621 [parent addChildWindow:self ordered:NSWindowAbove];
622 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:parent];
625 self.latentParentWindow = parent;
629 - (void) setDisabled:(BOOL)newValue
631 if (disabled != newValue)
634 [self adjustFeaturesForState];
638 - (BOOL) needsTransparency
640 return self.shape || self.colorKeyed || self.usePerPixelAlpha;
643 - (void) checkTransparency
645 if (![self isOpaque] && !self.needsTransparency)
647 [self setBackgroundColor:[NSColor windowBackgroundColor]];
648 [self setOpaque:YES];
650 else if ([self isOpaque] && self.needsTransparency)
652 [self setBackgroundColor:[NSColor clearColor]];
657 - (void) setShape:(NSBezierPath*)newShape
659 if (shape == newShape) return;
660 if (shape && newShape && [shape isEqual:newShape]) return;
664 [[self contentView] setNeedsDisplayInRect:[shape bounds]];
668 [[self contentView] setNeedsDisplayInRect:[newShape bounds]];
670 shape = [newShape copy];
671 self.shapeChangedSinceLastDraw = TRUE;
673 [self checkTransparency];
676 - (void) postMouseButtonEvent:(NSEvent *)theEvent pressed:(int)pressed
678 CGPoint pt = CGEventGetLocation([theEvent CGEvent]);
681 event.type = MOUSE_BUTTON;
682 event.window = (macdrv_window)[self retain];
683 event.mouse_button.button = [theEvent buttonNumber];
684 event.mouse_button.pressed = pressed;
685 event.mouse_button.x = pt.x;
686 event.mouse_button.y = pt.y;
687 event.mouse_button.time_ms = [NSApp ticksForEventTime:[theEvent timestamp]];
689 [queue postEvent:&event];
696 [NSApp transformProcessToForeground];
698 /* If a borderless window is offscreen, orderFront: won't move
699 it onscreen like it would for a titled window. Do that ourselves. */
700 screens = [NSScreen screens];
701 if (!([self styleMask] & NSTitledWindowMask) && ![self isVisible] &&
702 !frame_intersects_screens([self frame], screens))
704 NSScreen* primaryScreen = [screens objectAtIndex:0];
705 NSRect frame = [primaryScreen frame];
706 [self setFrameTopLeftPoint:NSMakePoint(NSMinX(frame), NSMaxY(frame))];
707 frame = [self constrainFrameRect:[self frame] toScreen:primaryScreen];
708 [self setFrame:frame display:YES];
711 if ([[NSApp orderedWineWindows] count])
715 front = [[NSApp orderedWineWindows] objectAtIndex:0];
718 for (front in [NSApp orderedWineWindows])
719 if (!front.floating) break;
721 if (front && [front levelWhenActive] > [self levelWhenActive])
722 [self setLevelWhenActive:[front levelWhenActive]];
724 [self orderFront:nil];
725 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:nil];
726 causing_becomeKeyWindow = TRUE;
727 [self makeKeyWindow];
728 causing_becomeKeyWindow = FALSE;
729 if (latentParentWindow)
731 if ([latentParentWindow level] > [self level])
732 [self setLevelWhenActive:[latentParentWindow level]];
733 [latentParentWindow addChildWindow:self ordered:NSWindowAbove];
734 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:latentParentWindow];
735 self.latentParentWindow = nil;
737 if (![self isExcludedFromWindowsMenu])
738 [NSApp addWindowsItem:self title:[self title] filename:NO];
740 /* Cocoa may adjust the frame when the window is ordered onto the screen.
741 Generate a frame-changed event just in case. The back end will ignore
742 it if nothing actually changed. */
743 [self windowDidResize:nil];
746 - (void) postKey:(uint16_t)keyCode
747 pressed:(BOOL)pressed
748 modifiers:(NSUInteger)modifiers
749 event:(NSEvent*)theEvent
753 WineApplication* app = (WineApplication*)NSApp;
755 event.type = pressed ? KEY_PRESS : KEY_RELEASE;
756 event.window = (macdrv_window)[self retain];
757 event.key.keycode = keyCode;
758 event.key.modifiers = modifiers;
759 event.key.time_ms = [app ticksForEventTime:[theEvent timestamp]];
761 if ((cgevent = [theEvent CGEvent]))
763 CGEventSourceKeyboardType keyboardType = CGEventGetIntegerValueField(cgevent,
764 kCGKeyboardEventKeyboardType);
765 if (keyboardType != app.keyboardType)
767 app.keyboardType = keyboardType;
768 [app keyboardSelectionDidChange];
772 [queue postEvent:&event];
775 - (void) postKeyEvent:(NSEvent *)theEvent
777 [self flagsChanged:theEvent];
778 [self postKey:[theEvent keyCode]
779 pressed:[theEvent type] == NSKeyDown
780 modifiers:[theEvent modifierFlags]
784 - (void) postMouseMovedEvent:(NSEvent *)theEvent absolute:(BOOL)absolute
790 CGPoint point = CGEventGetLocation([theEvent CGEvent]);
792 event.type = MOUSE_MOVED_ABSOLUTE;
793 event.mouse_moved.x = point.x;
794 event.mouse_moved.y = point.y;
801 /* Add event delta to accumulated delta error */
802 /* deltaY is already flipped */
803 mouseMoveDeltaX += [theEvent deltaX];
804 mouseMoveDeltaY += [theEvent deltaY];
806 event.type = MOUSE_MOVED;
807 event.mouse_moved.x = mouseMoveDeltaX;
808 event.mouse_moved.y = mouseMoveDeltaY;
810 /* Keep the remainder after integer truncation. */
811 mouseMoveDeltaX -= event.mouse_moved.x;
812 mouseMoveDeltaY -= event.mouse_moved.y;
815 if (event.type == MOUSE_MOVED_ABSOLUTE || event.mouse_moved.x || event.mouse_moved.y)
817 event.window = (macdrv_window)[self retain];
818 event.mouse_moved.time_ms = [NSApp ticksForEventTime:[theEvent timestamp]];
820 [queue postEvent:&event];
824 - (void) setLevelWhenActive:(NSInteger)level
826 levelWhenActive = level;
827 if (([NSApp isActive] || level <= NSFloatingWindowLevel) &&
828 level != [self level])
829 [self setLevel:level];
834 * ---------- NSWindow method overrides ----------
836 - (BOOL) canBecomeKeyWindow
838 if (causing_becomeKeyWindow) return YES;
839 if (self.disabled || self.noActivate) return NO;
840 return [self isKeyWindow];
843 - (BOOL) canBecomeMainWindow
845 return [self canBecomeKeyWindow];
848 - (NSRect) constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
850 // If a window is sized to completely cover a screen, then it's in
851 // full-screen mode. In that case, we don't allow NSWindow to constrain
853 NSRect contentRect = [self contentRectForFrameRect:frameRect];
854 if (!screen_covered_by_rect(contentRect, [NSScreen screens]))
855 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
859 - (BOOL) isExcludedFromWindowsMenu
861 return !([self collectionBehavior] & NSWindowCollectionBehaviorParticipatesInCycle);
864 - (BOOL) validateMenuItem:(NSMenuItem *)menuItem
866 if ([menuItem action] == @selector(makeKeyAndOrderFront:))
867 return [self isKeyWindow] || (!self.disabled && !self.noActivate);
868 return [super validateMenuItem:menuItem];
871 /* We don't call this. It's the action method of the items in the Window menu. */
872 - (void) makeKeyAndOrderFront:(id)sender
874 if (![self isKeyWindow] && !self.disabled && !self.noActivate)
875 [NSApp windowGotFocus:self];
878 - (void) sendEvent:(NSEvent*)event
880 /* NSWindow consumes certain key-down events as part of Cocoa's keyboard
881 interface control. For example, Control-Tab switches focus among
882 views. We want to bypass that feature, so directly route key-down
883 events to -keyDown:. */
884 if ([event type] == NSKeyDown)
885 [[self firstResponder] keyDown:event];
888 if ([event type] == NSLeftMouseDown)
890 NSWindowButton windowButton;
891 BOOL broughtWindowForward = TRUE;
893 /* Since our windows generally claim they can't be made key, clicks
894 in their title bars are swallowed by the theme frame stuff. So,
895 we hook directly into the event stream and assume that any click
896 in the window will activate it, if Wine and the Win32 program
898 if (![self isKeyWindow] && !self.disabled && !self.noActivate)
899 [NSApp windowGotFocus:self];
901 /* Any left-click on our window anyplace other than the close or
902 minimize buttons will bring it forward. */
903 for (windowButton = NSWindowCloseButton;
904 windowButton <= NSWindowMiniaturizeButton;
907 NSButton* button = [[event window] standardWindowButton:windowButton];
910 NSPoint point = [button convertPoint:[event locationInWindow] fromView:nil];
911 if ([button mouse:point inRect:[button bounds]])
913 broughtWindowForward = FALSE;
919 if (broughtWindowForward)
920 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:nil];
923 [super sendEvent:event];
929 * ---------- NSResponder method overrides ----------
931 - (void) mouseDown:(NSEvent *)theEvent { [self postMouseButtonEvent:theEvent pressed:1]; }
932 - (void) rightMouseDown:(NSEvent *)theEvent { [self mouseDown:theEvent]; }
933 - (void) otherMouseDown:(NSEvent *)theEvent { [self mouseDown:theEvent]; }
935 - (void) mouseUp:(NSEvent *)theEvent { [self postMouseButtonEvent:theEvent pressed:0]; }
936 - (void) rightMouseUp:(NSEvent *)theEvent { [self mouseUp:theEvent]; }
937 - (void) otherMouseUp:(NSEvent *)theEvent { [self mouseUp:theEvent]; }
939 - (void) keyDown:(NSEvent *)theEvent { [self postKeyEvent:theEvent]; }
940 - (void) keyUp:(NSEvent *)theEvent { [self postKeyEvent:theEvent]; }
942 - (void) flagsChanged:(NSEvent *)theEvent
944 static const struct {
948 { NX_ALPHASHIFTMASK, kVK_CapsLock },
949 { NX_DEVICELSHIFTKEYMASK, kVK_Shift },
950 { NX_DEVICERSHIFTKEYMASK, kVK_RightShift },
951 { NX_DEVICELCTLKEYMASK, kVK_Control },
952 { NX_DEVICERCTLKEYMASK, kVK_RightControl },
953 { NX_DEVICELALTKEYMASK, kVK_Option },
954 { NX_DEVICERALTKEYMASK, kVK_RightOption },
955 { NX_DEVICELCMDKEYMASK, kVK_Command },
956 { NX_DEVICERCMDKEYMASK, kVK_RightCommand },
959 NSUInteger modifierFlags = [theEvent modifierFlags];
963 fix_device_modifiers_by_generic(&modifierFlags);
964 changed = modifierFlags ^ lastModifierFlags;
967 for (i = 0; i < sizeof(modifiers)/sizeof(modifiers[0]); i++)
968 if (changed & modifiers[i].mask)
971 for (i = 0; i <= last_changed; i++)
973 if (changed & modifiers[i].mask)
975 BOOL pressed = (modifierFlags & modifiers[i].mask) != 0;
977 if (i == last_changed)
978 lastModifierFlags = modifierFlags;
981 lastModifierFlags ^= modifiers[i].mask;
982 fix_generic_modifiers_by_device(&lastModifierFlags);
985 // Caps lock generates one event for each press-release action.
986 // We need to simulate a pair of events for each actual event.
987 if (modifiers[i].mask == NX_ALPHASHIFTMASK)
989 [self postKey:modifiers[i].keycode
991 modifiers:lastModifierFlags
992 event:(NSEvent*)theEvent];
996 [self postKey:modifiers[i].keycode
998 modifiers:lastModifierFlags
999 event:(NSEvent*)theEvent];
1004 - (void) scrollWheel:(NSEvent *)theEvent
1010 BOOL continuous = FALSE;
1012 cgevent = [theEvent CGEvent];
1013 pt = CGEventGetLocation(cgevent);
1015 event.type = MOUSE_SCROLL;
1016 event.window = (macdrv_window)[self retain];
1017 event.mouse_scroll.x = pt.x;
1018 event.mouse_scroll.y = pt.y;
1019 event.mouse_scroll.time_ms = [NSApp ticksForEventTime:[theEvent timestamp]];
1021 if (CGEventGetIntegerValueField(cgevent, kCGScrollWheelEventIsContinuous))
1025 /* Continuous scroll wheel events come from high-precision scrolling
1026 hardware like Apple's Magic Mouse, Mighty Mouse, and trackpads.
1027 For these, we can get more precise data from the CGEvent API. */
1028 /* Axis 1 is vertical, axis 2 is horizontal. */
1029 x = CGEventGetDoubleValueField(cgevent, kCGScrollWheelEventPointDeltaAxis2);
1030 y = CGEventGetDoubleValueField(cgevent, kCGScrollWheelEventPointDeltaAxis1);
1034 double pixelsPerLine = 10;
1035 CGEventSourceRef source;
1037 /* The non-continuous values are in units of "lines", not pixels. */
1038 if ((source = CGEventCreateSourceFromEvent(cgevent)))
1040 pixelsPerLine = CGEventSourceGetPixelsPerLine(source);
1044 x = pixelsPerLine * [theEvent deltaX];
1045 y = pixelsPerLine * [theEvent deltaY];
1048 /* Mac: negative is right or down, positive is left or up.
1049 Win32: negative is left or down, positive is right or up.
1050 So, negate the X scroll value to translate. */
1053 /* The x,y values so far are in pixels. Win32 expects to receive some
1054 fraction of WHEEL_DELTA == 120. By my estimation, that's roughly
1055 6 times the pixel value. */
1056 event.mouse_scroll.x_scroll = 6 * x;
1057 event.mouse_scroll.y_scroll = 6 * y;
1061 /* For non-continuous "clicky" wheels, if there was any motion, make
1062 sure there was at least WHEEL_DELTA motion. This is so, at slow
1063 speeds where the system's acceleration curve is actually reducing the
1064 scroll distance, the user is sure to get some action out of each click.
1065 For example, this is important for rotating though weapons in a
1066 first-person shooter. */
1067 if (0 < event.mouse_scroll.x_scroll && event.mouse_scroll.x_scroll < 120)
1068 event.mouse_scroll.x_scroll = 120;
1069 else if (-120 < event.mouse_scroll.x_scroll && event.mouse_scroll.x_scroll < 0)
1070 event.mouse_scroll.x_scroll = -120;
1072 if (0 < event.mouse_scroll.y_scroll && event.mouse_scroll.y_scroll < 120)
1073 event.mouse_scroll.y_scroll = 120;
1074 else if (-120 < event.mouse_scroll.y_scroll && event.mouse_scroll.y_scroll < 0)
1075 event.mouse_scroll.y_scroll = -120;
1078 if (event.mouse_scroll.x_scroll || event.mouse_scroll.y_scroll)
1079 [queue postEvent:&event];
1084 * ---------- NSWindowDelegate methods ----------
1086 - (void)windowDidBecomeKey:(NSNotification *)notification
1088 NSEvent* event = [NSApp lastFlagsChanged];
1090 [self flagsChanged:event];
1092 if (causing_becomeKeyWindow) return;
1094 [NSApp windowGotFocus:self];
1097 - (void)windowDidDeminiaturize:(NSNotification *)notification
1099 if (!ignore_windowDeminiaturize)
1103 /* Coalesce events by discarding any previous ones still in the queue. */
1104 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_MINIMIZE) |
1105 event_mask_for_type(WINDOW_DID_UNMINIMIZE)
1108 event.type = WINDOW_DID_UNMINIMIZE;
1109 event.window = (macdrv_window)[self retain];
1110 [queue postEvent:&event];
1113 ignore_windowDeminiaturize = FALSE;
1115 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:nil];
1118 - (void)windowDidMove:(NSNotification *)notification
1120 [self windowDidResize:notification];
1123 - (void)windowDidResignKey:(NSNotification *)notification
1127 if (causing_becomeKeyWindow) return;
1129 event.type = WINDOW_LOST_FOCUS;
1130 event.window = (macdrv_window)[self retain];
1131 [queue postEvent:&event];
1134 - (void)windowDidResize:(NSNotification *)notification
1137 NSRect frame = [self contentRectForFrameRect:[self frame]];
1139 [NSApp flipRect:&frame];
1141 /* Coalesce events by discarding any previous ones still in the queue. */
1142 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
1145 event.type = WINDOW_FRAME_CHANGED;
1146 event.window = (macdrv_window)[self retain];
1147 event.window_frame_changed.frame = NSRectToCGRect(frame);
1148 [queue postEvent:&event];
1151 - (BOOL)windowShouldClose:(id)sender
1154 event.type = WINDOW_CLOSE_REQUESTED;
1155 event.window = (macdrv_window)[self retain];
1156 [queue postEvent:&event];
1160 - (void)windowWillMiniaturize:(NSNotification *)notification
1162 if (!ignore_windowMiniaturize)
1166 /* Coalesce events by discarding any previous ones still in the queue. */
1167 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_MINIMIZE) |
1168 event_mask_for_type(WINDOW_DID_UNMINIMIZE)
1171 event.type = WINDOW_DID_MINIMIZE;
1172 event.window = (macdrv_window)[self retain];
1173 [queue postEvent:&event];
1176 ignore_windowMiniaturize = FALSE;
1181 * ---------- NSPasteboardOwner methods ----------
1183 - (void) pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
1185 macdrv_query* query = macdrv_create_query();
1186 query->type = QUERY_PASTEBOARD_DATA;
1187 query->window = (macdrv_window)[self retain];
1188 query->pasteboard_data.type = (CFStringRef)[type copy];
1190 [self.queue query:query timeout:3];
1191 macdrv_release_query(query);
1196 * ---------- NSDraggingDestination methods ----------
1198 - (NSDragOperation) draggingEntered:(id <NSDraggingInfo>)sender
1200 return [self draggingUpdated:sender];
1203 - (void) draggingExited:(id <NSDraggingInfo>)sender
1205 // This isn't really a query. We don't need any response. However, it
1206 // has to be processed in a similar manner as the other drag-and-drop
1207 // queries in order to maintain the proper order of operations.
1208 macdrv_query* query = macdrv_create_query();
1209 query->type = QUERY_DRAG_EXITED;
1210 query->window = (macdrv_window)[self retain];
1212 [self.queue query:query timeout:0.1];
1213 macdrv_release_query(query);
1216 - (NSDragOperation) draggingUpdated:(id <NSDraggingInfo>)sender
1218 NSDragOperation ret;
1219 NSPoint pt = [[self contentView] convertPoint:[sender draggingLocation] fromView:nil];
1220 NSPasteboard* pb = [sender draggingPasteboard];
1222 macdrv_query* query = macdrv_create_query();
1223 query->type = QUERY_DRAG_OPERATION;
1224 query->window = (macdrv_window)[self retain];
1225 query->drag_operation.x = pt.x;
1226 query->drag_operation.y = pt.y;
1227 query->drag_operation.offered_ops = [sender draggingSourceOperationMask];
1228 query->drag_operation.accepted_op = NSDragOperationNone;
1229 query->drag_operation.pasteboard = (CFTypeRef)[pb retain];
1231 [self.queue query:query timeout:3];
1232 ret = query->status ? query->drag_operation.accepted_op : NSDragOperationNone;
1233 macdrv_release_query(query);
1238 - (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
1241 NSPoint pt = [[self contentView] convertPoint:[sender draggingLocation] fromView:nil];
1242 NSPasteboard* pb = [sender draggingPasteboard];
1244 macdrv_query* query = macdrv_create_query();
1245 query->type = QUERY_DRAG_DROP;
1246 query->window = (macdrv_window)[self retain];
1247 query->drag_drop.x = pt.x;
1248 query->drag_drop.y = pt.y;
1249 query->drag_drop.op = [sender draggingSourceOperationMask];
1250 query->drag_drop.pasteboard = (CFTypeRef)[pb retain];
1252 [self.queue query:query timeout:3 * 60 processEvents:YES];
1253 ret = query->status;
1254 macdrv_release_query(query);
1259 - (BOOL) wantsPeriodicDraggingUpdates
1267 /***********************************************************************
1268 * macdrv_create_cocoa_window
1270 * Create a Cocoa window with the given content frame and features (e.g.
1271 * title bar, close box, etc.).
1273 macdrv_window macdrv_create_cocoa_window(const struct macdrv_window_features* wf,
1274 CGRect frame, void* hwnd, macdrv_event_queue queue)
1276 __block WineWindow* window;
1279 window = [[WineWindow createWindowWithFeatures:wf
1280 windowFrame:NSRectFromCGRect(frame)
1282 queue:(WineEventQueue*)queue] retain];
1285 return (macdrv_window)window;
1288 /***********************************************************************
1289 * macdrv_destroy_cocoa_window
1291 * Destroy a Cocoa window.
1293 void macdrv_destroy_cocoa_window(macdrv_window w)
1295 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1296 WineWindow* window = (WineWindow*)w;
1298 [window.queue discardEventsMatchingMask:-1 forWindow:window];
1305 /***********************************************************************
1306 * macdrv_get_window_hwnd
1308 * Get the hwnd that was set for the window at creation.
1310 void* macdrv_get_window_hwnd(macdrv_window w)
1312 WineWindow* window = (WineWindow*)w;
1316 /***********************************************************************
1317 * macdrv_set_cocoa_window_features
1319 * Update a Cocoa window's features.
1321 void macdrv_set_cocoa_window_features(macdrv_window w,
1322 const struct macdrv_window_features* wf)
1324 WineWindow* window = (WineWindow*)w;
1327 [window setWindowFeatures:wf];
1331 /***********************************************************************
1332 * macdrv_set_cocoa_window_state
1334 * Update a Cocoa window's state.
1336 void macdrv_set_cocoa_window_state(macdrv_window w,
1337 const struct macdrv_window_state* state)
1339 WineWindow* window = (WineWindow*)w;
1342 [window setMacDrvState:state];
1346 /***********************************************************************
1347 * macdrv_set_cocoa_window_title
1349 * Set a Cocoa window's title.
1351 void macdrv_set_cocoa_window_title(macdrv_window w, const unsigned short* title,
1354 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1355 WineWindow* window = (WineWindow*)w;
1356 NSString* titleString;
1359 titleString = [NSString stringWithCharacters:title length:length];
1362 OnMainThreadAsync(^{
1363 [window setTitle:titleString];
1364 if ([window isVisible] && ![window isExcludedFromWindowsMenu])
1365 [NSApp changeWindowsItem:window title:titleString filename:NO];
1371 /***********************************************************************
1372 * macdrv_order_cocoa_window
1374 * Reorder a Cocoa window relative to other windows. If prev is
1375 * non-NULL, it is ordered below that window. Else, if next is non-NULL,
1376 * it is ordered above that window. Otherwise, it is ordered to the
1379 * Returns true if the window has actually been ordered onto the screen
1380 * (i.e. if its frame intersects with a screen). Otherwise, false.
1382 int macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
1385 WineWindow* window = (WineWindow*)w;
1386 __block BOOL on_screen;
1389 on_screen = [window orderBelow:(WineWindow*)prev
1390 orAbove:(WineWindow*)next];
1396 /***********************************************************************
1397 * macdrv_hide_cocoa_window
1399 * Hides a Cocoa window.
1401 void macdrv_hide_cocoa_window(macdrv_window w)
1403 WineWindow* window = (WineWindow*)w;
1406 [window doOrderOut];
1410 /***********************************************************************
1411 * macdrv_set_cocoa_window_frame
1413 * Move a Cocoa window. If the window has been moved out of the bounds
1414 * of the desktop, it is ordered out. (This routine won't ever order a
1415 * window in, though.)
1417 * Returns true if the window is on screen; false otherwise.
1419 int macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame)
1421 WineWindow* window = (WineWindow*)w;
1422 __block BOOL on_screen;
1425 on_screen = [window setFrameIfOnScreen:NSRectFromCGRect(*new_frame)];
1431 /***********************************************************************
1432 * macdrv_get_cocoa_window_frame
1434 * Gets the frame of a Cocoa window.
1436 void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame)
1438 WineWindow* window = (WineWindow*)w;
1443 frame = [window contentRectForFrameRect:[window frame]];
1444 [NSApp flipRect:&frame];
1445 *out_frame = NSRectToCGRect(frame);
1449 /***********************************************************************
1450 * macdrv_set_cocoa_parent_window
1452 * Sets the parent window for a Cocoa window. If parent is NULL, clears
1453 * the parent window.
1455 void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent)
1457 WineWindow* window = (WineWindow*)w;
1460 [window setMacDrvParentWindow:(WineWindow*)parent];
1464 /***********************************************************************
1465 * macdrv_set_window_surface
1467 void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex)
1469 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1470 WineWindow* window = (WineWindow*)w;
1473 window.surface = surface;
1474 window.surface_mutex = mutex;
1480 /***********************************************************************
1481 * macdrv_window_needs_display
1483 * Mark a window as needing display in a specified rect (in non-client
1484 * area coordinates).
1486 void macdrv_window_needs_display(macdrv_window w, CGRect rect)
1488 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1489 WineWindow* window = (WineWindow*)w;
1491 OnMainThreadAsync(^{
1492 [[window contentView] setNeedsDisplayInRect:NSRectFromCGRect(rect)];
1498 /***********************************************************************
1499 * macdrv_set_window_shape
1501 * Sets the shape of a Cocoa window from an array of rectangles. If
1502 * rects is NULL, resets the window's shape to its frame.
1504 void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count)
1506 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1507 WineWindow* window = (WineWindow*)w;
1510 if (!rects || !count)
1517 path = [NSBezierPath bezierPath];
1518 for (i = 0; i < count; i++)
1519 [path appendBezierPathWithRect:NSRectFromCGRect(rects[i])];
1520 window.shape = path;
1527 /***********************************************************************
1528 * macdrv_set_window_alpha
1530 void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha)
1532 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1533 WineWindow* window = (WineWindow*)w;
1535 [window setAlphaValue:alpha];
1540 /***********************************************************************
1541 * macdrv_set_window_color_key
1543 void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat keyGreen,
1546 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1547 WineWindow* window = (WineWindow*)w;
1550 window.colorKeyed = TRUE;
1551 window.colorKeyRed = keyRed;
1552 window.colorKeyGreen = keyGreen;
1553 window.colorKeyBlue = keyBlue;
1554 [window checkTransparency];
1560 /***********************************************************************
1561 * macdrv_clear_window_color_key
1563 void macdrv_clear_window_color_key(macdrv_window w)
1565 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1566 WineWindow* window = (WineWindow*)w;
1569 window.colorKeyed = FALSE;
1570 [window checkTransparency];
1576 /***********************************************************************
1577 * macdrv_window_use_per_pixel_alpha
1579 void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha)
1581 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1582 WineWindow* window = (WineWindow*)w;
1585 window.usePerPixelAlpha = use_per_pixel_alpha;
1586 [window checkTransparency];
1592 /***********************************************************************
1593 * macdrv_give_cocoa_window_focus
1595 * Makes the Cocoa window "key" (gives it keyboard focus). This also
1596 * orders it front and, if its frame was not within the desktop bounds,
1597 * Cocoa will typically move it on-screen.
1599 void macdrv_give_cocoa_window_focus(macdrv_window w)
1601 WineWindow* window = (WineWindow*)w;
1604 [window makeFocused];
1608 /***********************************************************************
1609 * macdrv_create_view
1611 * Creates and returns a view in the specified rect of the window. The
1612 * caller is responsible for calling macdrv_dispose_view() on the view
1613 * when it is done with it.
1615 macdrv_view macdrv_create_view(macdrv_window w, CGRect rect)
1617 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1618 WineWindow* window = (WineWindow*)w;
1619 __block WineContentView* view;
1621 if (CGRectIsNull(rect)) rect = CGRectZero;
1624 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
1626 view = [[WineContentView alloc] initWithFrame:NSRectFromCGRect(rect)];
1627 [view setAutoresizesSubviews:NO];
1628 [nc addObserver:view
1629 selector:@selector(updateGLContexts)
1630 name:NSViewGlobalFrameDidChangeNotification
1632 [nc addObserver:view
1633 selector:@selector(updateGLContexts)
1634 name:NSApplicationDidChangeScreenParametersNotification
1636 [[window contentView] addSubview:view];
1640 return (macdrv_view)view;
1643 /***********************************************************************
1644 * macdrv_dispose_view
1646 * Destroys a view previously returned by macdrv_create_view.
1648 void macdrv_dispose_view(macdrv_view v)
1650 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1651 WineContentView* view = (WineContentView*)v;
1654 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
1656 [nc removeObserver:view
1657 name:NSViewGlobalFrameDidChangeNotification
1659 [nc removeObserver:view
1660 name:NSApplicationDidChangeScreenParametersNotification
1662 [view removeFromSuperview];
1669 /***********************************************************************
1670 * macdrv_set_view_window_and_frame
1672 * Move a view to a new window and/or position within its window. If w
1673 * is NULL, leave the view in its current window and just change its
1676 void macdrv_set_view_window_and_frame(macdrv_view v, macdrv_window w, CGRect rect)
1678 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1679 WineContentView* view = (WineContentView*)v;
1680 WineWindow* window = (WineWindow*)w;
1682 if (CGRectIsNull(rect)) rect = CGRectZero;
1685 BOOL changedWindow = (window && window != [view window]);
1686 NSRect newFrame = NSRectFromCGRect(rect);
1687 NSRect oldFrame = [view frame];
1691 [view removeFromSuperview];
1692 [[window contentView] addSubview:view];
1695 if (!NSEqualRects(oldFrame, newFrame))
1698 [[view superview] setNeedsDisplayInRect:oldFrame];
1699 if (NSEqualPoints(oldFrame.origin, newFrame.origin))
1700 [view setFrameSize:newFrame.size];
1701 else if (NSEqualSizes(oldFrame.size, newFrame.size))
1702 [view setFrameOrigin:newFrame.origin];
1704 [view setFrame:newFrame];
1705 [view setNeedsDisplay:YES];
1712 /***********************************************************************
1713 * macdrv_add_view_opengl_context
1715 * Add an OpenGL context to the list being tracked for each view.
1717 void macdrv_add_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
1719 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1720 WineContentView* view = (WineContentView*)v;
1721 WineOpenGLContext *context = (WineOpenGLContext*)c;
1723 OnMainThreadAsync(^{
1724 [view addGLContext:context];
1730 /***********************************************************************
1731 * macdrv_remove_view_opengl_context
1733 * Add an OpenGL context to the list being tracked for each view.
1735 void macdrv_remove_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
1737 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1738 WineContentView* view = (WineContentView*)v;
1739 WineOpenGLContext *context = (WineOpenGLContext*)c;
1741 OnMainThreadAsync(^{
1742 [view removeGLContext:context];