Commit 8da2cb16 authored by Ken Thomases's avatar Ken Thomases Committed by Alexandre Julliard

winemac: Implement basic window functionality.

parent 35319684
......@@ -11,6 +11,7 @@ C_SRCS = \
OBJC_SRCS = \
cocoa_app.m \
cocoa_display.m \
cocoa_main.m
cocoa_main.m \
cocoa_window.m
@MAKE_DLL_RULES@
......@@ -28,3 +28,6 @@
- (void) transformProcessToForeground;
@end
void OnMainThread(dispatch_block_t block);
void OnMainThreadAsync(dispatch_block_t block);
......@@ -56,3 +56,23 @@
}
@end
/***********************************************************************
* OnMainThread
*
* Run a block on the main thread synchronously.
*/
void OnMainThread(dispatch_block_t block)
{
dispatch_sync(dispatch_get_main_queue(), block);
}
/***********************************************************************
* OnMainThreadAsync
*
* Run a block on the main thread asynchronously.
*/
void OnMainThreadAsync(dispatch_block_t block)
{
dispatch_async(dispatch_get_main_queue(), block);
}
/*
* MACDRV Cocoa window declarations
*
* 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 <AppKit/AppKit.h>
@interface WineWindow : NSPanel <NSWindowDelegate>
@end
/*
* 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;
}
......@@ -70,4 +70,20 @@ static inline const char *wine_dbgstr_cgrect(CGRect cgrect)
extern CGRect macdrv_get_desktop_rect(void) DECLSPEC_HIDDEN;
/**************************************************************************
* Mac USER driver
*/
/* macdrv private window data */
struct macdrv_win_data
{
HWND hwnd; /* hwnd that this private data belongs to */
macdrv_window cocoa_window;
RECT window_rect; /* USER window rectangle relative to parent */
RECT whole_rect; /* Mac window rectangle for the whole window relative to parent */
RECT client_rect; /* client area relative to parent */
BOOL on_screen : 1; /* is window ordered in? */
};
#endif /* __WINE_MACDRV_H */
......@@ -97,6 +97,8 @@
#endif
typedef struct macdrv_opaque_window* macdrv_window;
struct macdrv_display {
CGDirectDisplayID displayID;
CGRect frame;
......@@ -112,4 +114,27 @@ extern int macdrv_start_cocoa_app(void) DECLSPEC_HIDDEN;
extern int macdrv_get_displays(struct macdrv_display** displays, int* count) DECLSPEC_HIDDEN;
extern void macdrv_free_displays(struct macdrv_display* displays) DECLSPEC_HIDDEN;
/* window */
struct macdrv_window_features {
unsigned int title_bar:1;
unsigned int close_button:1;
unsigned int minimize_button:1;
unsigned int resizable:1;
unsigned int utility:1;
unsigned int shadow:1;
};
extern macdrv_window macdrv_create_cocoa_window(const struct macdrv_window_features* wf,
CGRect frame) DECLSPEC_HIDDEN;
extern void macdrv_destroy_cocoa_window(macdrv_window w) DECLSPEC_HIDDEN;
extern void macdrv_set_cocoa_window_features(macdrv_window w,
const struct macdrv_window_features* wf) DECLSPEC_HIDDEN;
extern void macdrv_set_cocoa_window_title(macdrv_window w, const UniChar* title,
size_t length) DECLSPEC_HIDDEN;
extern int macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
macdrv_window next) DECLSPEC_HIDDEN;
extern void macdrv_hide_cocoa_window(macdrv_window w) DECLSPEC_HIDDEN;
extern int macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame) DECLSPEC_HIDDEN;
#endif /* __WINE_MACDRV_COCOA_H */
......@@ -5,5 +5,12 @@
# USER driver
@ cdecl CreateDesktopWindow(long) macdrv_CreateDesktopWindow
@ cdecl CreateWindow(long) macdrv_CreateWindow
@ cdecl DestroyWindow(long) macdrv_DestroyWindow
@ cdecl EnumDisplayMonitors(long ptr ptr long) macdrv_EnumDisplayMonitors
@ cdecl GetMonitorInfo(long ptr) macdrv_GetMonitorInfo
@ cdecl SetParent(long long long) macdrv_SetParent
@ cdecl SetWindowStyle(ptr long ptr) macdrv_SetWindowStyle
@ cdecl SetWindowText(long wstr) macdrv_SetWindowText
@ cdecl WindowPosChanged(long long long ptr ptr ptr ptr ptr) macdrv_WindowPosChanged
@ cdecl WindowPosChanging(long long long ptr ptr ptr ptr) macdrv_WindowPosChanging
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment