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;
65 @property (nonatomic) BOOL floating;
66 @property (retain, nonatomic) NSWindow* latentParentWindow;
68 + (void) flipRect:(NSRect*)rect;
73 @implementation WineContentView
83 @implementation WineWindow
85 @synthesize disabled, noActivate, floating, latentParentWindow;
87 + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
88 windowFrame:(NSRect)window_frame
91 WineContentView* contentView;
93 [self flipRect:&window_frame];
95 window = [[[self alloc] initWithContentRect:window_frame
96 styleMask:style_mask_for_features(wf)
97 backing:NSBackingStoreBuffered
98 defer:YES] autorelease];
100 if (!window) return nil;
101 window->normalStyleMask = [window styleMask];
103 /* Standardize windows to eliminate differences between titled and
104 borderless windows and between NSWindow and NSPanel. */
105 [window setHidesOnDeactivate:NO];
106 [window setReleasedWhenClosed:NO];
108 [window disableCursorRects];
109 [window setShowsResizeIndicator:NO];
110 [window setHasShadow:wf->shadow];
111 [window setDelegate:window];
113 contentView = [[[WineContentView alloc] initWithFrame:NSZeroRect] autorelease];
116 [contentView setAutoresizesSubviews:NO];
118 [window setContentView:contentView];
125 [latentParentWindow release];
129 + (void) flipRect:(NSRect*)rect
131 rect->origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - NSMaxY(*rect);
134 - (void) adjustFeaturesForState
136 NSUInteger style = normalStyleMask;
139 style &= ~NSResizableWindowMask;
140 if (style != [self styleMask])
141 [self setStyleMask:style];
143 if (style & NSClosableWindowMask)
144 [[self standardWindowButton:NSWindowCloseButton] setEnabled:!self.disabled];
145 if (style & NSMiniaturizableWindowMask)
146 [[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!self.disabled];
149 - (void) setWindowFeatures:(const struct macdrv_window_features*)wf
151 normalStyleMask = style_mask_for_features(wf);
152 [self adjustFeaturesForState];
153 [self setHasShadow:wf->shadow];
156 - (void) setMacDrvState:(const struct macdrv_window_state*)state
160 self.disabled = state->disabled;
161 self.noActivate = state->no_activate;
163 self.floating = state->floating;
164 level = state->floating ? NSFloatingWindowLevel : NSNormalWindowLevel;
165 if (level != [self level])
166 [self setLevel:level];
169 /* Returns whether or not the window was ordered in, which depends on if
170 its frame intersects any screen. */
171 - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next
173 BOOL on_screen = frame_intersects_screens([self frame], [NSScreen screens]);
176 [NSApp transformProcessToForeground];
179 [self orderWindow:NSWindowBelow relativeTo:[prev windowNumber]];
181 [self orderWindow:NSWindowAbove relativeTo:[next windowNumber]];
182 if (latentParentWindow)
184 [latentParentWindow addChildWindow:self ordered:NSWindowAbove];
185 self.latentParentWindow = nil;
194 self.latentParentWindow = [self parentWindow];
195 [latentParentWindow removeChildWindow:self];
199 - (BOOL) setFrameIfOnScreen:(NSRect)contentRect
201 NSArray* screens = [NSScreen screens];
202 BOOL on_screen = [self isVisible];
203 NSRect frame, oldFrame;
205 if (![screens count]) return on_screen;
207 /* Origin is (left, top) in a top-down space. Need to convert it to
208 (left, bottom) in a bottom-up space. */
209 [[self class] flipRect:&contentRect];
213 on_screen = frame_intersects_screens(contentRect, screens);
218 oldFrame = [self frame];
219 frame = [self frameRectForContentRect:contentRect];
220 if (!NSEqualRects(frame, oldFrame))
222 if (NSEqualSizes(frame.size, oldFrame.size))
223 [self setFrameOrigin:frame.origin];
225 [self setFrame:frame display:YES];
231 - (void) setMacDrvParentWindow:(WineWindow*)parent
233 if ([self parentWindow] != parent)
235 [[self parentWindow] removeChildWindow:self];
236 self.latentParentWindow = nil;
237 if ([self isVisible] && parent)
238 [parent addChildWindow:self ordered:NSWindowAbove];
240 self.latentParentWindow = parent;
244 - (void) setDisabled:(BOOL)newValue
246 if (disabled != newValue)
249 [self adjustFeaturesForState];
255 * ---------- NSWindow method overrides ----------
257 - (BOOL) canBecomeKeyWindow
259 if (self.disabled || self.noActivate) return NO;
263 - (BOOL) canBecomeMainWindow
265 return [self canBecomeKeyWindow];
270 * ---------- NSWindowDelegate methods ----------
272 - (BOOL)windowShouldClose:(id)sender
280 /***********************************************************************
281 * macdrv_create_cocoa_window
283 * Create a Cocoa window with the given content frame and features (e.g.
284 * title bar, close box, etc.).
286 macdrv_window macdrv_create_cocoa_window(const struct macdrv_window_features* wf,
289 __block WineWindow* window;
292 window = [[WineWindow createWindowWithFeatures:wf
293 windowFrame:NSRectFromCGRect(frame)] retain];
296 return (macdrv_window)window;
299 /***********************************************************************
300 * macdrv_destroy_cocoa_window
302 * Destroy a Cocoa window.
304 void macdrv_destroy_cocoa_window(macdrv_window w)
306 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
307 WineWindow* window = (WineWindow*)w;
315 /***********************************************************************
316 * macdrv_set_cocoa_window_features
318 * Update a Cocoa window's features.
320 void macdrv_set_cocoa_window_features(macdrv_window w,
321 const struct macdrv_window_features* wf)
323 WineWindow* window = (WineWindow*)w;
326 [window setWindowFeatures:wf];
330 /***********************************************************************
331 * macdrv_set_cocoa_window_state
333 * Update a Cocoa window's state.
335 void macdrv_set_cocoa_window_state(macdrv_window w,
336 const struct macdrv_window_state* state)
338 WineWindow* window = (WineWindow*)w;
341 [window setMacDrvState:state];
345 /***********************************************************************
346 * macdrv_set_cocoa_window_title
348 * Set a Cocoa window's title.
350 void macdrv_set_cocoa_window_title(macdrv_window w, const unsigned short* title,
353 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
354 WineWindow* window = (WineWindow*)w;
355 NSString* titleString;
358 titleString = [NSString stringWithCharacters:title length:length];
362 [window setTitle:titleString];
368 /***********************************************************************
369 * macdrv_order_cocoa_window
371 * Reorder a Cocoa window relative to other windows. If prev is
372 * non-NULL, it is ordered below that window. Else, if next is non-NULL,
373 * it is ordered above that window. Otherwise, it is ordered to the
376 * Returns true if the window has actually been ordered onto the screen
377 * (i.e. if its frame intersects with a screen). Otherwise, false.
379 int macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
382 WineWindow* window = (WineWindow*)w;
383 __block BOOL on_screen;
386 on_screen = [window orderBelow:(WineWindow*)prev
387 orAbove:(WineWindow*)next];
393 /***********************************************************************
394 * macdrv_hide_cocoa_window
396 * Hides a Cocoa window.
398 void macdrv_hide_cocoa_window(macdrv_window w)
400 WineWindow* window = (WineWindow*)w;
407 /***********************************************************************
408 * macdrv_set_cocoa_window_frame
410 * Move a Cocoa window. If the window has been moved out of the bounds
411 * of the desktop, it is ordered out. (This routine won't ever order a
412 * window in, though.)
414 * Returns true if the window is on screen; false otherwise.
416 int macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame)
418 WineWindow* window = (WineWindow*)w;
419 __block BOOL on_screen;
422 on_screen = [window setFrameIfOnScreen:NSRectFromCGRect(*new_frame)];
428 /***********************************************************************
429 * macdrv_set_cocoa_parent_window
431 * Sets the parent window for a Cocoa window. If parent is NULL, clears
434 void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent)
436 WineWindow* window = (WineWindow*)w;
439 [window setMacDrvParentWindow:(WineWindow*)parent];