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 "cocoa_window.h"
23 #include "macdrv_cocoa.h"
27 static NSUInteger style_mask_for_features(const struct macdrv_window_features* wf)
29 NSUInteger style_mask;
33 style_mask = NSTitledWindowMask;
34 if (wf->close_button) style_mask |= NSClosableWindowMask;
35 if (wf->minimize_button) style_mask |= NSMiniaturizableWindowMask;
36 if (wf->resizable) style_mask |= NSResizableWindowMask;
37 if (wf->utility) style_mask |= NSUtilityWindowMask;
39 else style_mask = NSBorderlessWindowMask;
45 static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
48 for (screen in screens)
50 if (NSIntersectsRect(frame, [screen frame]))
57 @interface WineContentView : NSView
61 @interface WineWindow ()
63 @property (nonatomic) BOOL disabled;
64 @property (nonatomic) BOOL noActivate;
66 + (void) flipRect:(NSRect*)rect;
71 @implementation WineContentView
81 @implementation WineWindow
83 @synthesize disabled, noActivate;
85 + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
86 windowFrame:(NSRect)window_frame
89 WineContentView* contentView;
91 [self flipRect:&window_frame];
93 window = [[[self alloc] initWithContentRect:window_frame
94 styleMask:style_mask_for_features(wf)
95 backing:NSBackingStoreBuffered
96 defer:YES] autorelease];
98 if (!window) return nil;
99 window->normalStyleMask = [window styleMask];
101 /* Standardize windows to eliminate differences between titled and
102 borderless windows and between NSWindow and NSPanel. */
103 [window setHidesOnDeactivate:NO];
104 [window setReleasedWhenClosed:NO];
106 [window disableCursorRects];
107 [window setShowsResizeIndicator:NO];
108 [window setHasShadow:wf->shadow];
109 [window setDelegate:window];
111 contentView = [[[WineContentView alloc] initWithFrame:NSZeroRect] autorelease];
114 [contentView setAutoresizesSubviews:NO];
116 [window setContentView:contentView];
121 + (void) flipRect:(NSRect*)rect
123 rect->origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - NSMaxY(*rect);
126 - (void) adjustFeaturesForState
128 NSUInteger style = normalStyleMask;
131 style &= ~NSResizableWindowMask;
132 if (style != [self styleMask])
133 [self setStyleMask:style];
135 if (style & NSClosableWindowMask)
136 [[self standardWindowButton:NSWindowCloseButton] setEnabled:!self.disabled];
137 if (style & NSMiniaturizableWindowMask)
138 [[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!self.disabled];
141 - (void) setWindowFeatures:(const struct macdrv_window_features*)wf
143 normalStyleMask = style_mask_for_features(wf);
144 [self adjustFeaturesForState];
145 [self setHasShadow:wf->shadow];
148 - (void) setMacDrvState:(const struct macdrv_window_state*)state
150 self.disabled = state->disabled;
151 self.noActivate = state->no_activate;
154 /* Returns whether or not the window was ordered in, which depends on if
155 its frame intersects any screen. */
156 - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next
158 BOOL on_screen = frame_intersects_screens([self frame], [NSScreen screens]);
161 [NSApp transformProcessToForeground];
164 [self orderWindow:NSWindowBelow relativeTo:[prev windowNumber]];
166 [self orderWindow:NSWindowAbove relativeTo:[next windowNumber]];
172 - (BOOL) setFrameIfOnScreen:(NSRect)contentRect
174 NSArray* screens = [NSScreen screens];
175 BOOL on_screen = [self isVisible];
176 NSRect frame, oldFrame;
178 if (![screens count]) return on_screen;
180 /* Origin is (left, top) in a top-down space. Need to convert it to
181 (left, bottom) in a bottom-up space. */
182 [[self class] flipRect:&contentRect];
186 on_screen = frame_intersects_screens(contentRect, screens);
191 oldFrame = [self frame];
192 frame = [self frameRectForContentRect:contentRect];
193 if (!NSEqualRects(frame, oldFrame))
195 if (NSEqualSizes(frame.size, oldFrame.size))
196 [self setFrameOrigin:frame.origin];
198 [self setFrame:frame display:YES];
204 - (void) setDisabled:(BOOL)newValue
206 if (disabled != newValue)
209 [self adjustFeaturesForState];
215 * ---------- NSWindow method overrides ----------
217 - (BOOL) canBecomeKeyWindow
219 if (self.disabled || self.noActivate) return NO;
223 - (BOOL) canBecomeMainWindow
225 return [self canBecomeKeyWindow];
230 * ---------- NSWindowDelegate methods ----------
232 - (BOOL)windowShouldClose:(id)sender
240 /***********************************************************************
241 * macdrv_create_cocoa_window
243 * Create a Cocoa window with the given content frame and features (e.g.
244 * title bar, close box, etc.).
246 macdrv_window macdrv_create_cocoa_window(const struct macdrv_window_features* wf,
249 __block WineWindow* window;
252 window = [[WineWindow createWindowWithFeatures:wf
253 windowFrame:NSRectFromCGRect(frame)] retain];
256 return (macdrv_window)window;
259 /***********************************************************************
260 * macdrv_destroy_cocoa_window
262 * Destroy a Cocoa window.
264 void macdrv_destroy_cocoa_window(macdrv_window w)
266 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
267 WineWindow* window = (WineWindow*)w;
275 /***********************************************************************
276 * macdrv_set_cocoa_window_features
278 * Update a Cocoa window's features.
280 void macdrv_set_cocoa_window_features(macdrv_window w,
281 const struct macdrv_window_features* wf)
283 WineWindow* window = (WineWindow*)w;
286 [window setWindowFeatures:wf];
290 /***********************************************************************
291 * macdrv_set_cocoa_window_state
293 * Update a Cocoa window's state.
295 void macdrv_set_cocoa_window_state(macdrv_window w,
296 const struct macdrv_window_state* state)
298 WineWindow* window = (WineWindow*)w;
301 [window setMacDrvState:state];
305 /***********************************************************************
306 * macdrv_set_cocoa_window_title
308 * Set a Cocoa window's title.
310 void macdrv_set_cocoa_window_title(macdrv_window w, const unsigned short* title,
313 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
314 WineWindow* window = (WineWindow*)w;
315 NSString* titleString;
318 titleString = [NSString stringWithCharacters:title length:length];
322 [window setTitle:titleString];
328 /***********************************************************************
329 * macdrv_order_cocoa_window
331 * Reorder a Cocoa window relative to other windows. If prev is
332 * non-NULL, it is ordered below that window. Else, if next is non-NULL,
333 * it is ordered above that window. Otherwise, it is ordered to the
336 * Returns true if the window has actually been ordered onto the screen
337 * (i.e. if its frame intersects with a screen). Otherwise, false.
339 int macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
342 WineWindow* window = (WineWindow*)w;
343 __block BOOL on_screen;
346 on_screen = [window orderBelow:(WineWindow*)prev
347 orAbove:(WineWindow*)next];
353 /***********************************************************************
354 * macdrv_hide_cocoa_window
356 * Hides a Cocoa window.
358 void macdrv_hide_cocoa_window(macdrv_window w)
360 WineWindow* window = (WineWindow*)w;
363 [window orderOut:nil];
367 /***********************************************************************
368 * macdrv_set_cocoa_window_frame
370 * Move a Cocoa window. If the window has been moved out of the bounds
371 * of the desktop, it is ordered out. (This routine won't ever order a
372 * window in, though.)
374 * Returns true if the window is on screen; false otherwise.
376 int macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame)
378 WineWindow* window = (WineWindow*)w;
379 __block BOOL on_screen;
382 on_screen = [window setFrameIfOnScreen:NSRectFromCGRect(*new_frame)];