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_region_rects(window.surface, &rects, &count) || count)
197 imageRect = NSRectToCGRect(rect);
198 image = create_surface_image(window.surface, &imageRect, FALSE);
202 CGContextRef context;
206 NSBezierPath* surfaceClip = [NSBezierPath bezierPath];
208 for (i = 0; i < count; i++)
209 [surfaceClip appendBezierPathWithRect:NSRectFromCGRect(rects[i])];
210 [surfaceClip addClip];
213 [window.shape addClip];
215 if (window.colorKeyed)
217 CGImageRef maskedImage;
218 CGFloat components[] = { window.colorKeyRed - 0.5, window.colorKeyRed + 0.5,
219 window.colorKeyGreen - 0.5, window.colorKeyGreen + 0.5,
220 window.colorKeyBlue - 0.5, window.colorKeyBlue + 0.5 };
221 maskedImage = CGImageCreateWithMaskingColors(image, components);
224 CGImageRelease(image);
229 context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
230 CGContextSetBlendMode(context, kCGBlendModeCopy);
231 CGContextDrawImage(context, imageRect, image);
233 CGImageRelease(image);
235 if (window.shapeChangedSinceLastDraw || window.colorKeyed ||
236 window.usePerPixelAlpha)
238 window.shapeChangedSinceLastDraw = FALSE;
239 [window invalidateShadow];
244 pthread_mutex_unlock(window.surface_mutex);
248 /* By default, NSView will swallow right-clicks in an attempt to support contextual
249 menus. We need to bypass that and allow the event to make it to the window. */
250 - (void) rightMouseDown:(NSEvent*)theEvent
252 [[self window] rightMouseDown:theEvent];
255 - (void) addGLContext:(WineOpenGLContext*)context
258 glContexts = [[NSMutableArray alloc] init];
259 if (!pendingGlContexts)
260 pendingGlContexts = [[NSMutableArray alloc] init];
261 [pendingGlContexts addObject:context];
262 [self setNeedsDisplay:YES];
265 - (void) removeGLContext:(WineOpenGLContext*)context
267 [glContexts removeObjectIdenticalTo:context];
268 [pendingGlContexts removeObjectIdenticalTo:context];
271 - (void) updateGLContexts
273 for (WineOpenGLContext* context in glContexts)
274 context.needsUpdate = TRUE;
277 - (BOOL) acceptsFirstMouse:(NSEvent*)theEvent
285 @implementation WineWindow
287 @synthesize disabled, noActivate, floating, latentParentWindow, hwnd, queue;
288 @synthesize surface, surface_mutex;
289 @synthesize shape, shapeChangedSinceLastDraw;
290 @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue;
291 @synthesize usePerPixelAlpha;
292 @synthesize levelWhenActive;
294 + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
295 windowFrame:(NSRect)window_frame
297 queue:(WineEventQueue*)queue
300 WineContentView* contentView;
301 NSTrackingArea* trackingArea;
303 [NSApp flipRect:&window_frame];
305 window = [[[self alloc] initWithContentRect:window_frame
306 styleMask:style_mask_for_features(wf)
307 backing:NSBackingStoreBuffered
308 defer:YES] autorelease];
310 if (!window) return nil;
311 window->normalStyleMask = [window styleMask];
313 /* Standardize windows to eliminate differences between titled and
314 borderless windows and between NSWindow and NSPanel. */
315 [window setHidesOnDeactivate:NO];
316 [window setReleasedWhenClosed:NO];
318 [window disableCursorRects];
319 [window setShowsResizeIndicator:NO];
320 [window setHasShadow:wf->shadow];
321 [window setAcceptsMouseMovedEvents:YES];
322 [window setColorSpace:[NSColorSpace genericRGBColorSpace]];
323 [window setDelegate:window];
325 window.queue = queue;
327 [window registerForDraggedTypes:[NSArray arrayWithObjects:(NSString*)kUTTypeData,
328 (NSString*)kUTTypeContent,
331 contentView = [[[WineContentView alloc] initWithFrame:NSZeroRect] autorelease];
334 [contentView setAutoresizesSubviews:NO];
336 /* We use tracking areas in addition to setAcceptsMouseMovedEvents:YES
337 because they give us mouse moves in the background. */
338 trackingArea = [[[NSTrackingArea alloc] initWithRect:[contentView bounds]
339 options:(NSTrackingMouseMoved |
340 NSTrackingActiveAlways |
341 NSTrackingInVisibleRect)
343 userInfo:nil] autorelease];
346 [contentView addTrackingArea:trackingArea];
348 [window setContentView:contentView];
356 [latentParentWindow release];
361 - (void) adjustFeaturesForState
363 NSUInteger style = normalStyleMask;
366 style &= ~NSResizableWindowMask;
367 if (style != [self styleMask])
368 [self setStyleMask:style];
370 if (style & NSClosableWindowMask)
371 [[self standardWindowButton:NSWindowCloseButton] setEnabled:!self.disabled];
372 if (style & NSMiniaturizableWindowMask)
373 [[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!self.disabled];
376 - (void) setWindowFeatures:(const struct macdrv_window_features*)wf
378 normalStyleMask = style_mask_for_features(wf);
379 [self adjustFeaturesForState];
380 [self setHasShadow:wf->shadow];
383 - (void) adjustWindowLevel
386 BOOL fullscreen, captured;
389 WineWindow* other = nil;
391 screen = screen_covered_by_rect([self frame], [NSScreen screens]);
392 fullscreen = (screen != nil);
393 captured = (screen || [self screen]) && [NSApp areDisplaysCaptured];
395 if (captured || fullscreen)
398 level = CGShieldingWindowLevel() + 1; /* Need +1 or we don't get mouse moves */
400 level = NSMainMenuWindowLevel + 1;
405 else if (self.floating)
406 level = NSFloatingWindowLevel;
408 level = NSNormalWindowLevel;
410 index = [[NSApp orderedWineWindows] indexOfObjectIdenticalTo:self];
411 if (index != NSNotFound && index + 1 < [[NSApp orderedWineWindows] count])
413 other = [[NSApp orderedWineWindows] objectAtIndex:index + 1];
414 if (level < [other level])
415 level = [other level];
418 if (level != [self level])
420 [self setLevelWhenActive:level];
422 /* Setting the window level above has moved this window to the front
423 of all other windows at the same level. We need to move it
424 back into its proper place among other windows of that level.
425 Also, any windows which are supposed to be in front of it had
426 better have the same or higher window level. If not, bump them
428 if (index != NSNotFound)
430 for (; index > 0; index--)
432 other = [[NSApp orderedWineWindows] objectAtIndex:index - 1];
433 if ([other level] < level)
434 [other setLevelWhenActive:level];
437 [self orderWindow:NSWindowBelow relativeTo:[other windowNumber]];
445 - (void) setMacDrvState:(const struct macdrv_window_state*)state
447 NSWindowCollectionBehavior behavior;
449 self.disabled = state->disabled;
450 self.noActivate = state->no_activate;
452 self.floating = state->floating;
453 [self adjustWindowLevel];
455 behavior = NSWindowCollectionBehaviorDefault;
456 if (state->excluded_by_expose)
457 behavior |= NSWindowCollectionBehaviorTransient;
459 behavior |= NSWindowCollectionBehaviorManaged;
460 if (state->excluded_by_cycle)
462 behavior |= NSWindowCollectionBehaviorIgnoresCycle;
463 if ([self isVisible])
464 [NSApp removeWindowsItem:self];
468 behavior |= NSWindowCollectionBehaviorParticipatesInCycle;
469 if ([self isVisible])
470 [NSApp addWindowsItem:self title:[self title] filename:NO];
472 [self setCollectionBehavior:behavior];
474 if (state->minimized && ![self isMiniaturized])
476 ignore_windowMiniaturize = TRUE;
477 [self miniaturize:nil];
479 else if (!state->minimized && [self isMiniaturized])
481 ignore_windowDeminiaturize = TRUE;
482 [self deminiaturize:nil];
485 /* Whatever events regarding minimization might have been in the queue are now stale. */
486 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_MINIMIZE) |
487 event_mask_for_type(WINDOW_DID_UNMINIMIZE)
491 /* Returns whether or not the window was ordered in, which depends on if
492 its frame intersects any screen. */
493 - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next
495 BOOL on_screen = frame_intersects_screens([self frame], [NSScreen screens]);
498 [NSApp transformProcessToForeground];
502 /* Make sure that windows that should be above this one really are.
503 This is necessary since a full-screen window gets a boost to its
504 window level to be in front of the menu bar and Dock and that moves
505 it out of the z-order that Win32 would otherwise establish. */
506 if ([prev level] < [self level])
508 NSUInteger index = [[NSApp orderedWineWindows] indexOfObjectIdenticalTo:prev];
509 if (index != NSNotFound)
511 [prev setLevelWhenActive:[self level]];
512 for (; index > 0; index--)
514 WineWindow* other = [[NSApp orderedWineWindows] objectAtIndex:index - 1];
515 if ([other level] < [self level])
516 [other setLevelWhenActive:[self level]];
520 [self orderWindow:NSWindowBelow relativeTo:[prev windowNumber]];
521 [NSApp wineWindow:self ordered:NSWindowBelow relativeTo:prev];
525 /* Similarly, make sure this window is really above what it should be. */
526 if (next && [next level] > [self level])
527 [self setLevelWhenActive:[next level]];
528 [self orderWindow:NSWindowAbove relativeTo:[next windowNumber]];
529 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:next];
531 if (latentParentWindow)
533 if ([latentParentWindow level] > [self level])
534 [self setLevelWhenActive:[latentParentWindow level]];
535 [latentParentWindow addChildWindow:self ordered:NSWindowAbove];
536 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:latentParentWindow];
537 self.latentParentWindow = nil;
540 /* Cocoa may adjust the frame when the window is ordered onto the screen.
541 Generate a frame-changed event just in case. The back end will ignore
542 it if nothing actually changed. */
543 [self windowDidResize:nil];
545 if (![self isExcludedFromWindowsMenu])
546 [NSApp addWindowsItem:self title:[self title] filename:NO];
554 self.latentParentWindow = [self parentWindow];
555 [latentParentWindow removeChildWindow:self];
557 [NSApp wineWindow:self ordered:NSWindowOut relativeTo:nil];
558 [NSApp removeWindowsItem:self];
561 - (BOOL) setFrameIfOnScreen:(NSRect)contentRect
563 NSArray* screens = [NSScreen screens];
564 BOOL on_screen = [self isVisible];
565 NSRect frame, oldFrame;
567 if (![screens count]) return on_screen;
569 /* Origin is (left, top) in a top-down space. Need to convert it to
570 (left, bottom) in a bottom-up space. */
571 [NSApp flipRect:&contentRect];
575 on_screen = frame_intersects_screens(contentRect, screens);
580 if (!NSIsEmptyRect(contentRect))
582 oldFrame = [self frame];
583 frame = [self frameRectForContentRect:contentRect];
584 if (!NSEqualRects(frame, oldFrame))
586 if (NSEqualSizes(frame.size, oldFrame.size))
587 [self setFrameOrigin:frame.origin];
589 [self setFrame:frame display:YES];
595 [self adjustWindowLevel];
597 /* In case Cocoa adjusted the frame we tried to set, generate a frame-changed
598 event. The back end will ignore it if nothing actually changed. */
599 [self windowDidResize:nil];
603 /* The back end is establishing a new window size and position. It's
604 not interested in any stale events regarding those that may be sitting
606 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
613 - (void) setMacDrvParentWindow:(WineWindow*)parent
615 if ([self parentWindow] != parent)
617 [[self parentWindow] removeChildWindow:self];
618 self.latentParentWindow = nil;
619 if ([self isVisible] && parent)
621 if ([parent level] > [self level])
622 [self setLevelWhenActive:[parent level]];
623 [parent addChildWindow:self ordered:NSWindowAbove];
624 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:parent];
627 self.latentParentWindow = parent;
631 - (void) setDisabled:(BOOL)newValue
633 if (disabled != newValue)
636 [self adjustFeaturesForState];
640 - (BOOL) needsTransparency
642 return self.shape || self.colorKeyed || self.usePerPixelAlpha;
645 - (void) checkTransparency
647 if (![self isOpaque] && !self.needsTransparency)
649 [self setBackgroundColor:[NSColor windowBackgroundColor]];
650 [self setOpaque:YES];
652 else if ([self isOpaque] && self.needsTransparency)
654 [self setBackgroundColor:[NSColor clearColor]];
659 - (void) setShape:(NSBezierPath*)newShape
661 if (shape == newShape) return;
662 if (shape && newShape && [shape isEqual:newShape]) return;
666 [[self contentView] setNeedsDisplayInRect:[shape bounds]];
670 [[self contentView] setNeedsDisplayInRect:[newShape bounds]];
672 shape = [newShape copy];
673 self.shapeChangedSinceLastDraw = TRUE;
675 [self checkTransparency];
678 - (void) postMouseButtonEvent:(NSEvent *)theEvent pressed:(int)pressed
680 CGPoint pt = CGEventGetLocation([theEvent CGEvent]);
683 event.type = MOUSE_BUTTON;
684 event.window = (macdrv_window)[self retain];
685 event.mouse_button.button = [theEvent buttonNumber];
686 event.mouse_button.pressed = pressed;
687 event.mouse_button.x = pt.x;
688 event.mouse_button.y = pt.y;
689 event.mouse_button.time_ms = [NSApp ticksForEventTime:[theEvent timestamp]];
691 [queue postEvent:&event];
698 [NSApp transformProcessToForeground];
700 /* If a borderless window is offscreen, orderFront: won't move
701 it onscreen like it would for a titled window. Do that ourselves. */
702 screens = [NSScreen screens];
703 if (!([self styleMask] & NSTitledWindowMask) && ![self isVisible] &&
704 !frame_intersects_screens([self frame], screens))
706 NSScreen* primaryScreen = [screens objectAtIndex:0];
707 NSRect frame = [primaryScreen frame];
708 [self setFrameTopLeftPoint:NSMakePoint(NSMinX(frame), NSMaxY(frame))];
709 frame = [self constrainFrameRect:[self frame] toScreen:primaryScreen];
710 [self setFrame:frame display:YES];
713 if ([[NSApp orderedWineWindows] count])
717 front = [[NSApp orderedWineWindows] objectAtIndex:0];
720 for (front in [NSApp orderedWineWindows])
721 if (!front.floating) break;
723 if (front && [front levelWhenActive] > [self levelWhenActive])
724 [self setLevelWhenActive:[front levelWhenActive]];
726 [self orderFront:nil];
727 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:nil];
728 causing_becomeKeyWindow = TRUE;
729 [self makeKeyWindow];
730 causing_becomeKeyWindow = FALSE;
731 if (latentParentWindow)
733 if ([latentParentWindow level] > [self level])
734 [self setLevelWhenActive:[latentParentWindow level]];
735 [latentParentWindow addChildWindow:self ordered:NSWindowAbove];
736 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:latentParentWindow];
737 self.latentParentWindow = nil;
739 if (![self isExcludedFromWindowsMenu])
740 [NSApp addWindowsItem:self title:[self title] filename:NO];
742 /* Cocoa may adjust the frame when the window is ordered onto the screen.
743 Generate a frame-changed event just in case. The back end will ignore
744 it if nothing actually changed. */
745 [self windowDidResize:nil];
748 - (void) postKey:(uint16_t)keyCode
749 pressed:(BOOL)pressed
750 modifiers:(NSUInteger)modifiers
751 event:(NSEvent*)theEvent
755 WineApplication* app = (WineApplication*)NSApp;
757 event.type = pressed ? KEY_PRESS : KEY_RELEASE;
758 event.window = (macdrv_window)[self retain];
759 event.key.keycode = keyCode;
760 event.key.modifiers = modifiers;
761 event.key.time_ms = [app ticksForEventTime:[theEvent timestamp]];
763 if ((cgevent = [theEvent CGEvent]))
765 CGEventSourceKeyboardType keyboardType = CGEventGetIntegerValueField(cgevent,
766 kCGKeyboardEventKeyboardType);
767 if (keyboardType != app.keyboardType)
769 app.keyboardType = keyboardType;
770 [app keyboardSelectionDidChange];
774 [queue postEvent:&event];
777 - (void) postKeyEvent:(NSEvent *)theEvent
779 [self flagsChanged:theEvent];
780 [self postKey:[theEvent keyCode]
781 pressed:[theEvent type] == NSKeyDown
782 modifiers:[theEvent modifierFlags]
786 - (void) postMouseMovedEvent:(NSEvent *)theEvent absolute:(BOOL)absolute
792 CGPoint point = CGEventGetLocation([theEvent CGEvent]);
794 event.type = MOUSE_MOVED_ABSOLUTE;
795 event.mouse_moved.x = point.x;
796 event.mouse_moved.y = point.y;
803 /* Add event delta to accumulated delta error */
804 /* deltaY is already flipped */
805 mouseMoveDeltaX += [theEvent deltaX];
806 mouseMoveDeltaY += [theEvent deltaY];
808 event.type = MOUSE_MOVED;
809 event.mouse_moved.x = mouseMoveDeltaX;
810 event.mouse_moved.y = mouseMoveDeltaY;
812 /* Keep the remainder after integer truncation. */
813 mouseMoveDeltaX -= event.mouse_moved.x;
814 mouseMoveDeltaY -= event.mouse_moved.y;
817 if (event.type == MOUSE_MOVED_ABSOLUTE || event.mouse_moved.x || event.mouse_moved.y)
819 event.window = (macdrv_window)[self retain];
820 event.mouse_moved.time_ms = [NSApp ticksForEventTime:[theEvent timestamp]];
822 [queue postEvent:&event];
826 - (void) setLevelWhenActive:(NSInteger)level
828 levelWhenActive = level;
829 if (([NSApp isActive] || level <= NSFloatingWindowLevel) &&
830 level != [self level])
831 [self setLevel:level];
836 * ---------- NSWindow method overrides ----------
838 - (BOOL) canBecomeKeyWindow
840 if (causing_becomeKeyWindow) return YES;
841 if (self.disabled || self.noActivate) return NO;
842 return [self isKeyWindow];
845 - (BOOL) canBecomeMainWindow
847 return [self canBecomeKeyWindow];
850 - (NSRect) constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
852 // If a window is sized to completely cover a screen, then it's in
853 // full-screen mode. In that case, we don't allow NSWindow to constrain
855 NSRect contentRect = [self contentRectForFrameRect:frameRect];
856 if (!screen_covered_by_rect(contentRect, [NSScreen screens]))
857 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
861 - (BOOL) isExcludedFromWindowsMenu
863 return !([self collectionBehavior] & NSWindowCollectionBehaviorParticipatesInCycle);
866 - (BOOL) validateMenuItem:(NSMenuItem *)menuItem
868 if ([menuItem action] == @selector(makeKeyAndOrderFront:))
869 return [self isKeyWindow] || (!self.disabled && !self.noActivate);
870 return [super validateMenuItem:menuItem];
873 /* We don't call this. It's the action method of the items in the Window menu. */
874 - (void) makeKeyAndOrderFront:(id)sender
876 if (![self isKeyWindow] && !self.disabled && !self.noActivate)
877 [NSApp windowGotFocus:self];
880 - (void) sendEvent:(NSEvent*)event
882 /* NSWindow consumes certain key-down events as part of Cocoa's keyboard
883 interface control. For example, Control-Tab switches focus among
884 views. We want to bypass that feature, so directly route key-down
885 events to -keyDown:. */
886 if ([event type] == NSKeyDown)
887 [[self firstResponder] keyDown:event];
890 if ([event type] == NSLeftMouseDown)
892 NSWindowButton windowButton;
893 BOOL broughtWindowForward = TRUE;
895 /* Since our windows generally claim they can't be made key, clicks
896 in their title bars are swallowed by the theme frame stuff. So,
897 we hook directly into the event stream and assume that any click
898 in the window will activate it, if Wine and the Win32 program
900 if (![self isKeyWindow] && !self.disabled && !self.noActivate)
901 [NSApp windowGotFocus:self];
903 /* Any left-click on our window anyplace other than the close or
904 minimize buttons will bring it forward. */
905 for (windowButton = NSWindowCloseButton;
906 windowButton <= NSWindowMiniaturizeButton;
909 NSButton* button = [[event window] standardWindowButton:windowButton];
912 NSPoint point = [button convertPoint:[event locationInWindow] fromView:nil];
913 if ([button mouse:point inRect:[button bounds]])
915 broughtWindowForward = FALSE;
921 if (broughtWindowForward)
922 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:nil];
925 [super sendEvent:event];
931 * ---------- NSResponder method overrides ----------
933 - (void) mouseDown:(NSEvent *)theEvent { [self postMouseButtonEvent:theEvent pressed:1]; }
934 - (void) rightMouseDown:(NSEvent *)theEvent { [self mouseDown:theEvent]; }
935 - (void) otherMouseDown:(NSEvent *)theEvent { [self mouseDown:theEvent]; }
937 - (void) mouseUp:(NSEvent *)theEvent { [self postMouseButtonEvent:theEvent pressed:0]; }
938 - (void) rightMouseUp:(NSEvent *)theEvent { [self mouseUp:theEvent]; }
939 - (void) otherMouseUp:(NSEvent *)theEvent { [self mouseUp:theEvent]; }
941 - (void) keyDown:(NSEvent *)theEvent { [self postKeyEvent:theEvent]; }
942 - (void) keyUp:(NSEvent *)theEvent { [self postKeyEvent:theEvent]; }
944 - (void) flagsChanged:(NSEvent *)theEvent
946 static const struct {
950 { NX_ALPHASHIFTMASK, kVK_CapsLock },
951 { NX_DEVICELSHIFTKEYMASK, kVK_Shift },
952 { NX_DEVICERSHIFTKEYMASK, kVK_RightShift },
953 { NX_DEVICELCTLKEYMASK, kVK_Control },
954 { NX_DEVICERCTLKEYMASK, kVK_RightControl },
955 { NX_DEVICELALTKEYMASK, kVK_Option },
956 { NX_DEVICERALTKEYMASK, kVK_RightOption },
957 { NX_DEVICELCMDKEYMASK, kVK_Command },
958 { NX_DEVICERCMDKEYMASK, kVK_RightCommand },
961 NSUInteger modifierFlags = [theEvent modifierFlags];
965 fix_device_modifiers_by_generic(&modifierFlags);
966 changed = modifierFlags ^ lastModifierFlags;
969 for (i = 0; i < sizeof(modifiers)/sizeof(modifiers[0]); i++)
970 if (changed & modifiers[i].mask)
973 for (i = 0; i <= last_changed; i++)
975 if (changed & modifiers[i].mask)
977 BOOL pressed = (modifierFlags & modifiers[i].mask) != 0;
979 if (i == last_changed)
980 lastModifierFlags = modifierFlags;
983 lastModifierFlags ^= modifiers[i].mask;
984 fix_generic_modifiers_by_device(&lastModifierFlags);
987 // Caps lock generates one event for each press-release action.
988 // We need to simulate a pair of events for each actual event.
989 if (modifiers[i].mask == NX_ALPHASHIFTMASK)
991 [self postKey:modifiers[i].keycode
993 modifiers:lastModifierFlags
994 event:(NSEvent*)theEvent];
998 [self postKey:modifiers[i].keycode
1000 modifiers:lastModifierFlags
1001 event:(NSEvent*)theEvent];
1006 - (void) scrollWheel:(NSEvent *)theEvent
1012 BOOL continuous = FALSE;
1014 cgevent = [theEvent CGEvent];
1015 pt = CGEventGetLocation(cgevent);
1017 event.type = MOUSE_SCROLL;
1018 event.window = (macdrv_window)[self retain];
1019 event.mouse_scroll.x = pt.x;
1020 event.mouse_scroll.y = pt.y;
1021 event.mouse_scroll.time_ms = [NSApp ticksForEventTime:[theEvent timestamp]];
1023 if (CGEventGetIntegerValueField(cgevent, kCGScrollWheelEventIsContinuous))
1027 /* Continuous scroll wheel events come from high-precision scrolling
1028 hardware like Apple's Magic Mouse, Mighty Mouse, and trackpads.
1029 For these, we can get more precise data from the CGEvent API. */
1030 /* Axis 1 is vertical, axis 2 is horizontal. */
1031 x = CGEventGetDoubleValueField(cgevent, kCGScrollWheelEventPointDeltaAxis2);
1032 y = CGEventGetDoubleValueField(cgevent, kCGScrollWheelEventPointDeltaAxis1);
1036 double pixelsPerLine = 10;
1037 CGEventSourceRef source;
1039 /* The non-continuous values are in units of "lines", not pixels. */
1040 if ((source = CGEventCreateSourceFromEvent(cgevent)))
1042 pixelsPerLine = CGEventSourceGetPixelsPerLine(source);
1046 x = pixelsPerLine * [theEvent deltaX];
1047 y = pixelsPerLine * [theEvent deltaY];
1050 /* Mac: negative is right or down, positive is left or up.
1051 Win32: negative is left or down, positive is right or up.
1052 So, negate the X scroll value to translate. */
1055 /* The x,y values so far are in pixels. Win32 expects to receive some
1056 fraction of WHEEL_DELTA == 120. By my estimation, that's roughly
1057 6 times the pixel value. */
1058 event.mouse_scroll.x_scroll = 6 * x;
1059 event.mouse_scroll.y_scroll = 6 * y;
1063 /* For non-continuous "clicky" wheels, if there was any motion, make
1064 sure there was at least WHEEL_DELTA motion. This is so, at slow
1065 speeds where the system's acceleration curve is actually reducing the
1066 scroll distance, the user is sure to get some action out of each click.
1067 For example, this is important for rotating though weapons in a
1068 first-person shooter. */
1069 if (0 < event.mouse_scroll.x_scroll && event.mouse_scroll.x_scroll < 120)
1070 event.mouse_scroll.x_scroll = 120;
1071 else if (-120 < event.mouse_scroll.x_scroll && event.mouse_scroll.x_scroll < 0)
1072 event.mouse_scroll.x_scroll = -120;
1074 if (0 < event.mouse_scroll.y_scroll && event.mouse_scroll.y_scroll < 120)
1075 event.mouse_scroll.y_scroll = 120;
1076 else if (-120 < event.mouse_scroll.y_scroll && event.mouse_scroll.y_scroll < 0)
1077 event.mouse_scroll.y_scroll = -120;
1080 if (event.mouse_scroll.x_scroll || event.mouse_scroll.y_scroll)
1081 [queue postEvent:&event];
1086 * ---------- NSWindowDelegate methods ----------
1088 - (void)windowDidBecomeKey:(NSNotification *)notification
1090 NSEvent* event = [NSApp lastFlagsChanged];
1092 [self flagsChanged:event];
1094 if (causing_becomeKeyWindow) return;
1096 [NSApp windowGotFocus:self];
1099 - (void)windowDidDeminiaturize:(NSNotification *)notification
1101 if (!ignore_windowDeminiaturize)
1105 /* Coalesce events by discarding any previous ones still in the queue. */
1106 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_MINIMIZE) |
1107 event_mask_for_type(WINDOW_DID_UNMINIMIZE)
1110 event.type = WINDOW_DID_UNMINIMIZE;
1111 event.window = (macdrv_window)[self retain];
1112 [queue postEvent:&event];
1115 ignore_windowDeminiaturize = FALSE;
1117 [NSApp wineWindow:self ordered:NSWindowAbove relativeTo:nil];
1120 - (void)windowDidMove:(NSNotification *)notification
1122 [self windowDidResize:notification];
1125 - (void)windowDidResignKey:(NSNotification *)notification
1129 if (causing_becomeKeyWindow) return;
1131 event.type = WINDOW_LOST_FOCUS;
1132 event.window = (macdrv_window)[self retain];
1133 [queue postEvent:&event];
1136 - (void)windowDidResize:(NSNotification *)notification
1139 NSRect frame = [self contentRectForFrameRect:[self frame]];
1141 [NSApp flipRect:&frame];
1143 /* Coalesce events by discarding any previous ones still in the queue. */
1144 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
1147 event.type = WINDOW_FRAME_CHANGED;
1148 event.window = (macdrv_window)[self retain];
1149 event.window_frame_changed.frame = NSRectToCGRect(frame);
1150 [queue postEvent:&event];
1153 - (BOOL)windowShouldClose:(id)sender
1156 event.type = WINDOW_CLOSE_REQUESTED;
1157 event.window = (macdrv_window)[self retain];
1158 [queue postEvent:&event];
1162 - (void)windowWillMiniaturize:(NSNotification *)notification
1164 if (!ignore_windowMiniaturize)
1168 /* Coalesce events by discarding any previous ones still in the queue. */
1169 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_MINIMIZE) |
1170 event_mask_for_type(WINDOW_DID_UNMINIMIZE)
1173 event.type = WINDOW_DID_MINIMIZE;
1174 event.window = (macdrv_window)[self retain];
1175 [queue postEvent:&event];
1178 ignore_windowMiniaturize = FALSE;
1183 * ---------- NSPasteboardOwner methods ----------
1185 - (void) pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
1187 macdrv_query* query = macdrv_create_query();
1188 query->type = QUERY_PASTEBOARD_DATA;
1189 query->window = (macdrv_window)[self retain];
1190 query->pasteboard_data.type = (CFStringRef)[type copy];
1192 [self.queue query:query timeout:3];
1193 macdrv_release_query(query);
1198 * ---------- NSDraggingDestination methods ----------
1200 - (NSDragOperation) draggingEntered:(id <NSDraggingInfo>)sender
1202 return [self draggingUpdated:sender];
1205 - (void) draggingExited:(id <NSDraggingInfo>)sender
1207 // This isn't really a query. We don't need any response. However, it
1208 // has to be processed in a similar manner as the other drag-and-drop
1209 // queries in order to maintain the proper order of operations.
1210 macdrv_query* query = macdrv_create_query();
1211 query->type = QUERY_DRAG_EXITED;
1212 query->window = (macdrv_window)[self retain];
1214 [self.queue query:query timeout:0.1];
1215 macdrv_release_query(query);
1218 - (NSDragOperation) draggingUpdated:(id <NSDraggingInfo>)sender
1220 NSDragOperation ret;
1221 NSPoint pt = [[self contentView] convertPoint:[sender draggingLocation] fromView:nil];
1222 NSPasteboard* pb = [sender draggingPasteboard];
1224 macdrv_query* query = macdrv_create_query();
1225 query->type = QUERY_DRAG_OPERATION;
1226 query->window = (macdrv_window)[self retain];
1227 query->drag_operation.x = pt.x;
1228 query->drag_operation.y = pt.y;
1229 query->drag_operation.offered_ops = [sender draggingSourceOperationMask];
1230 query->drag_operation.accepted_op = NSDragOperationNone;
1231 query->drag_operation.pasteboard = (CFTypeRef)[pb retain];
1233 [self.queue query:query timeout:3];
1234 ret = query->status ? query->drag_operation.accepted_op : NSDragOperationNone;
1235 macdrv_release_query(query);
1240 - (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
1243 NSPoint pt = [[self contentView] convertPoint:[sender draggingLocation] fromView:nil];
1244 NSPasteboard* pb = [sender draggingPasteboard];
1246 macdrv_query* query = macdrv_create_query();
1247 query->type = QUERY_DRAG_DROP;
1248 query->window = (macdrv_window)[self retain];
1249 query->drag_drop.x = pt.x;
1250 query->drag_drop.y = pt.y;
1251 query->drag_drop.op = [sender draggingSourceOperationMask];
1252 query->drag_drop.pasteboard = (CFTypeRef)[pb retain];
1254 [self.queue query:query timeout:3 * 60 processEvents:YES];
1255 ret = query->status;
1256 macdrv_release_query(query);
1261 - (BOOL) wantsPeriodicDraggingUpdates
1269 /***********************************************************************
1270 * macdrv_create_cocoa_window
1272 * Create a Cocoa window with the given content frame and features (e.g.
1273 * title bar, close box, etc.).
1275 macdrv_window macdrv_create_cocoa_window(const struct macdrv_window_features* wf,
1276 CGRect frame, void* hwnd, macdrv_event_queue queue)
1278 __block WineWindow* window;
1281 window = [[WineWindow createWindowWithFeatures:wf
1282 windowFrame:NSRectFromCGRect(frame)
1284 queue:(WineEventQueue*)queue] retain];
1287 return (macdrv_window)window;
1290 /***********************************************************************
1291 * macdrv_destroy_cocoa_window
1293 * Destroy a Cocoa window.
1295 void macdrv_destroy_cocoa_window(macdrv_window w)
1297 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1298 WineWindow* window = (WineWindow*)w;
1300 [window.queue discardEventsMatchingMask:-1 forWindow:window];
1307 /***********************************************************************
1308 * macdrv_get_window_hwnd
1310 * Get the hwnd that was set for the window at creation.
1312 void* macdrv_get_window_hwnd(macdrv_window w)
1314 WineWindow* window = (WineWindow*)w;
1318 /***********************************************************************
1319 * macdrv_set_cocoa_window_features
1321 * Update a Cocoa window's features.
1323 void macdrv_set_cocoa_window_features(macdrv_window w,
1324 const struct macdrv_window_features* wf)
1326 WineWindow* window = (WineWindow*)w;
1329 [window setWindowFeatures:wf];
1333 /***********************************************************************
1334 * macdrv_set_cocoa_window_state
1336 * Update a Cocoa window's state.
1338 void macdrv_set_cocoa_window_state(macdrv_window w,
1339 const struct macdrv_window_state* state)
1341 WineWindow* window = (WineWindow*)w;
1344 [window setMacDrvState:state];
1348 /***********************************************************************
1349 * macdrv_set_cocoa_window_title
1351 * Set a Cocoa window's title.
1353 void macdrv_set_cocoa_window_title(macdrv_window w, const unsigned short* title,
1356 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1357 WineWindow* window = (WineWindow*)w;
1358 NSString* titleString;
1361 titleString = [NSString stringWithCharacters:title length:length];
1364 OnMainThreadAsync(^{
1365 [window setTitle:titleString];
1366 if ([window isVisible] && ![window isExcludedFromWindowsMenu])
1367 [NSApp changeWindowsItem:window title:titleString filename:NO];
1373 /***********************************************************************
1374 * macdrv_order_cocoa_window
1376 * Reorder a Cocoa window relative to other windows. If prev is
1377 * non-NULL, it is ordered below that window. Else, if next is non-NULL,
1378 * it is ordered above that window. Otherwise, it is ordered to the
1381 * Returns true if the window has actually been ordered onto the screen
1382 * (i.e. if its frame intersects with a screen). Otherwise, false.
1384 int macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
1387 WineWindow* window = (WineWindow*)w;
1388 __block BOOL on_screen;
1391 on_screen = [window orderBelow:(WineWindow*)prev
1392 orAbove:(WineWindow*)next];
1398 /***********************************************************************
1399 * macdrv_hide_cocoa_window
1401 * Hides a Cocoa window.
1403 void macdrv_hide_cocoa_window(macdrv_window w)
1405 WineWindow* window = (WineWindow*)w;
1408 [window doOrderOut];
1412 /***********************************************************************
1413 * macdrv_set_cocoa_window_frame
1415 * Move a Cocoa window. If the window has been moved out of the bounds
1416 * of the desktop, it is ordered out. (This routine won't ever order a
1417 * window in, though.)
1419 * Returns true if the window is on screen; false otherwise.
1421 int macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame)
1423 WineWindow* window = (WineWindow*)w;
1424 __block BOOL on_screen;
1427 on_screen = [window setFrameIfOnScreen:NSRectFromCGRect(*new_frame)];
1433 /***********************************************************************
1434 * macdrv_get_cocoa_window_frame
1436 * Gets the frame of a Cocoa window.
1438 void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame)
1440 WineWindow* window = (WineWindow*)w;
1445 frame = [window contentRectForFrameRect:[window frame]];
1446 [NSApp flipRect:&frame];
1447 *out_frame = NSRectToCGRect(frame);
1451 /***********************************************************************
1452 * macdrv_set_cocoa_parent_window
1454 * Sets the parent window for a Cocoa window. If parent is NULL, clears
1455 * the parent window.
1457 void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent)
1459 WineWindow* window = (WineWindow*)w;
1462 [window setMacDrvParentWindow:(WineWindow*)parent];
1466 /***********************************************************************
1467 * macdrv_set_window_surface
1469 void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex)
1471 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1472 WineWindow* window = (WineWindow*)w;
1475 window.surface = surface;
1476 window.surface_mutex = mutex;
1482 /***********************************************************************
1483 * macdrv_window_needs_display
1485 * Mark a window as needing display in a specified rect (in non-client
1486 * area coordinates).
1488 void macdrv_window_needs_display(macdrv_window w, CGRect rect)
1490 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1491 WineWindow* window = (WineWindow*)w;
1493 OnMainThreadAsync(^{
1494 [[window contentView] setNeedsDisplayInRect:NSRectFromCGRect(rect)];
1500 /***********************************************************************
1501 * macdrv_set_window_shape
1503 * Sets the shape of a Cocoa window from an array of rectangles. If
1504 * rects is NULL, resets the window's shape to its frame.
1506 void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count)
1508 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1509 WineWindow* window = (WineWindow*)w;
1512 if (!rects || !count)
1519 path = [NSBezierPath bezierPath];
1520 for (i = 0; i < count; i++)
1521 [path appendBezierPathWithRect:NSRectFromCGRect(rects[i])];
1522 window.shape = path;
1529 /***********************************************************************
1530 * macdrv_set_window_alpha
1532 void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha)
1534 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1535 WineWindow* window = (WineWindow*)w;
1537 [window setAlphaValue:alpha];
1542 /***********************************************************************
1543 * macdrv_set_window_color_key
1545 void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat keyGreen,
1548 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1549 WineWindow* window = (WineWindow*)w;
1552 window.colorKeyed = TRUE;
1553 window.colorKeyRed = keyRed;
1554 window.colorKeyGreen = keyGreen;
1555 window.colorKeyBlue = keyBlue;
1556 [window checkTransparency];
1562 /***********************************************************************
1563 * macdrv_clear_window_color_key
1565 void macdrv_clear_window_color_key(macdrv_window w)
1567 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1568 WineWindow* window = (WineWindow*)w;
1571 window.colorKeyed = FALSE;
1572 [window checkTransparency];
1578 /***********************************************************************
1579 * macdrv_window_use_per_pixel_alpha
1581 void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha)
1583 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1584 WineWindow* window = (WineWindow*)w;
1587 window.usePerPixelAlpha = use_per_pixel_alpha;
1588 [window checkTransparency];
1594 /***********************************************************************
1595 * macdrv_give_cocoa_window_focus
1597 * Makes the Cocoa window "key" (gives it keyboard focus). This also
1598 * orders it front and, if its frame was not within the desktop bounds,
1599 * Cocoa will typically move it on-screen.
1601 void macdrv_give_cocoa_window_focus(macdrv_window w)
1603 WineWindow* window = (WineWindow*)w;
1606 [window makeFocused];
1610 /***********************************************************************
1611 * macdrv_create_view
1613 * Creates and returns a view in the specified rect of the window. The
1614 * caller is responsible for calling macdrv_dispose_view() on the view
1615 * when it is done with it.
1617 macdrv_view macdrv_create_view(macdrv_window w, CGRect rect)
1619 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1620 WineWindow* window = (WineWindow*)w;
1621 __block WineContentView* view;
1623 if (CGRectIsNull(rect)) rect = CGRectZero;
1626 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
1628 view = [[WineContentView alloc] initWithFrame:NSRectFromCGRect(rect)];
1629 [view setAutoresizesSubviews:NO];
1630 [nc addObserver:view
1631 selector:@selector(updateGLContexts)
1632 name:NSViewGlobalFrameDidChangeNotification
1634 [nc addObserver:view
1635 selector:@selector(updateGLContexts)
1636 name:NSApplicationDidChangeScreenParametersNotification
1638 [[window contentView] addSubview:view];
1642 return (macdrv_view)view;
1645 /***********************************************************************
1646 * macdrv_dispose_view
1648 * Destroys a view previously returned by macdrv_create_view.
1650 void macdrv_dispose_view(macdrv_view v)
1652 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1653 WineContentView* view = (WineContentView*)v;
1656 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
1658 [nc removeObserver:view
1659 name:NSViewGlobalFrameDidChangeNotification
1661 [nc removeObserver:view
1662 name:NSApplicationDidChangeScreenParametersNotification
1664 [view removeFromSuperview];
1671 /***********************************************************************
1672 * macdrv_set_view_window_and_frame
1674 * Move a view to a new window and/or position within its window. If w
1675 * is NULL, leave the view in its current window and just change its
1678 void macdrv_set_view_window_and_frame(macdrv_view v, macdrv_window w, CGRect rect)
1680 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1681 WineContentView* view = (WineContentView*)v;
1682 WineWindow* window = (WineWindow*)w;
1684 if (CGRectIsNull(rect)) rect = CGRectZero;
1687 BOOL changedWindow = (window && window != [view window]);
1688 NSRect newFrame = NSRectFromCGRect(rect);
1689 NSRect oldFrame = [view frame];
1693 [view removeFromSuperview];
1694 [[window contentView] addSubview:view];
1697 if (!NSEqualRects(oldFrame, newFrame))
1700 [[view superview] setNeedsDisplayInRect:oldFrame];
1701 if (NSEqualPoints(oldFrame.origin, newFrame.origin))
1702 [view setFrameSize:newFrame.size];
1703 else if (NSEqualSizes(oldFrame.size, newFrame.size))
1704 [view setFrameOrigin:newFrame.origin];
1706 [view setFrame:newFrame];
1707 [view setNeedsDisplay:YES];
1714 /***********************************************************************
1715 * macdrv_add_view_opengl_context
1717 * Add an OpenGL context to the list being tracked for each view.
1719 void macdrv_add_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
1721 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1722 WineContentView* view = (WineContentView*)v;
1723 WineOpenGLContext *context = (WineOpenGLContext*)c;
1725 OnMainThreadAsync(^{
1726 [view addGLContext:context];
1732 /***********************************************************************
1733 * macdrv_remove_view_opengl_context
1735 * Add an OpenGL context to the list being tracked for each view.
1737 void macdrv_remove_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
1739 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1740 WineContentView* view = (WineContentView*)v;
1741 WineOpenGLContext *context = (WineOpenGLContext*)c;
1743 OnMainThreadAsync(^{
1744 [view removeGLContext:context];