Sweden-Number/dlls/winemac.drv/cocoa_window.m

332 lines
8.9 KiB
Mathematica
Raw Normal View History

/*
* MACDRV Cocoa window code
*
* Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#import "cocoa_window.h"
#include "macdrv_cocoa.h"
#import "cocoa_app.h"
static NSUInteger style_mask_for_features(const struct macdrv_window_features* wf)
{
NSUInteger style_mask;
if (wf->title_bar)
{
style_mask = NSTitledWindowMask;
if (wf->close_button) style_mask |= NSClosableWindowMask;
if (wf->minimize_button) style_mask |= NSMiniaturizableWindowMask;
if (wf->resizable) style_mask |= NSResizableWindowMask;
if (wf->utility) style_mask |= NSUtilityWindowMask;
}
else style_mask = NSBorderlessWindowMask;
return style_mask;
}
static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
{
NSScreen* screen;
for (screen in screens)
{
if (NSIntersectsRect(frame, [screen frame]))
return TRUE;
}
return FALSE;
}
@interface WineContentView : NSView
@end
@interface WineWindow ()
+ (void) flipRect:(NSRect*)rect;
@end
@implementation WineContentView
- (BOOL) isFlipped
{
return YES;
}
@end
@implementation WineWindow
+ (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
windowFrame:(NSRect)window_frame
{
WineWindow* window;
WineContentView* contentView;
[self flipRect:&window_frame];
window = [[[self alloc] initWithContentRect:window_frame
styleMask:style_mask_for_features(wf)
backing:NSBackingStoreBuffered
defer:YES] autorelease];
/* Standardize windows to eliminate differences between titled and
borderless windows and between NSWindow and NSPanel. */
[window setHidesOnDeactivate:NO];
[window setReleasedWhenClosed:NO];
[window disableCursorRects];
[window setShowsResizeIndicator:NO];
[window setHasShadow:wf->shadow];
[window setDelegate:window];
contentView = [[[WineContentView alloc] initWithFrame:NSZeroRect] autorelease];
if (!contentView)
return nil;
[contentView setAutoresizesSubviews:NO];
[window setContentView:contentView];
return window;
}
+ (void) flipRect:(NSRect*)rect
{
rect->origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - NSMaxY(*rect);
}
- (void) setWindowFeatures:(const struct macdrv_window_features*)wf
{
[self setStyleMask:style_mask_for_features(wf)];
[self setHasShadow:wf->shadow];
}
/* Returns whether or not the window was ordered in, which depends on if
its frame intersects any screen. */
- (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next
{
BOOL on_screen = frame_intersects_screens([self frame], [NSScreen screens]);
if (on_screen)
{
[NSApp transformProcessToForeground];
if (prev)
[self orderWindow:NSWindowBelow relativeTo:[prev windowNumber]];
else
[self orderWindow:NSWindowAbove relativeTo:[next windowNumber]];
}
return on_screen;
}
- (BOOL) setFrameIfOnScreen:(NSRect)contentRect
{
NSArray* screens = [NSScreen screens];
BOOL on_screen = [self isVisible];
NSRect frame, oldFrame;
if (![screens count]) return on_screen;
/* Origin is (left, top) in a top-down space. Need to convert it to
(left, bottom) in a bottom-up space. */
[[self class] flipRect:&contentRect];
if (on_screen)
{
on_screen = frame_intersects_screens(contentRect, screens);
if (!on_screen)
[self orderOut:nil];
}
oldFrame = [self frame];
frame = [self frameRectForContentRect:contentRect];
if (!NSEqualRects(frame, oldFrame))
{
if (NSEqualSizes(frame.size, oldFrame.size))
[self setFrameOrigin:frame.origin];
else
[self setFrame:frame display:YES];
}
return on_screen;
}
/*
* ---------- NSWindow method overrides ----------
*/
- (BOOL) canBecomeKeyWindow
{
return YES;
}
- (BOOL) canBecomeMainWindow
{
return [self canBecomeKeyWindow];
}
/*
* ---------- NSWindowDelegate methods ----------
*/
- (BOOL)windowShouldClose:(id)sender
{
return NO;
}
@end
/***********************************************************************
* macdrv_create_cocoa_window
*
* Create a Cocoa window with the given content frame and features (e.g.
* title bar, close box, etc.).
*/
macdrv_window macdrv_create_cocoa_window(const struct macdrv_window_features* wf,
CGRect frame)
{
__block WineWindow* window;
OnMainThread(^{
window = [[WineWindow createWindowWithFeatures:wf
windowFrame:NSRectFromCGRect(frame)] retain];
});
return (macdrv_window)window;
}
/***********************************************************************
* macdrv_destroy_cocoa_window
*
* Destroy a Cocoa window.
*/
void macdrv_destroy_cocoa_window(macdrv_window w)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineWindow* window = (WineWindow*)w;
[window close];
[window release];
[pool release];
}
/***********************************************************************
* macdrv_set_cocoa_window_features
*
* Update a Cocoa window's features.
*/
void macdrv_set_cocoa_window_features(macdrv_window w,
const struct macdrv_window_features* wf)
{
WineWindow* window = (WineWindow*)w;
OnMainThread(^{
[window setWindowFeatures:wf];
});
}
/***********************************************************************
* macdrv_set_cocoa_window_title
*
* Set a Cocoa window's title.
*/
void macdrv_set_cocoa_window_title(macdrv_window w, const unsigned short* title,
size_t length)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineWindow* window = (WineWindow*)w;
NSString* titleString;
if (title)
titleString = [NSString stringWithCharacters:title length:length];
else
titleString = @"";
OnMainThreadAsync(^{
[window setTitle:titleString];
});
[pool release];
}
/***********************************************************************
* macdrv_order_cocoa_window
*
* Reorder a Cocoa window relative to other windows. If prev is
* non-NULL, it is ordered below that window. Else, if next is non-NULL,
* it is ordered above that window. Otherwise, it is ordered to the
* front.
*
* Returns true if the window has actually been ordered onto the screen
* (i.e. if its frame intersects with a screen). Otherwise, false.
*/
int macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
macdrv_window next)
{
WineWindow* window = (WineWindow*)w;
__block BOOL on_screen;
OnMainThread(^{
on_screen = [window orderBelow:(WineWindow*)prev
orAbove:(WineWindow*)next];
});
return on_screen;
}
/***********************************************************************
* macdrv_hide_cocoa_window
*
* Hides a Cocoa window.
*/
void macdrv_hide_cocoa_window(macdrv_window w)
{
WineWindow* window = (WineWindow*)w;
OnMainThread(^{
[window orderOut:nil];
});
}
/***********************************************************************
* macdrv_set_cocoa_window_frame
*
* Move a Cocoa window. If the window has been moved out of the bounds
* of the desktop, it is ordered out. (This routine won't ever order a
* window in, though.)
*
* Returns true if the window is on screen; false otherwise.
*/
int macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame)
{
WineWindow* window = (WineWindow*)w;
__block BOOL on_screen;
OnMainThread(^{
on_screen = [window setFrameIfOnScreen:NSRectFromCGRect(*new_frame)];
});
return on_screen;
}