winemac: Implement basic window functionality.
This commit is contained in:
parent
35319684d3
commit
8da2cb1698
|
@ -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 @@ @interface WineApplication : NSApplication <NSApplicationDelegate>
|
|||
- (void) transformProcessToForeground;
|
||||
|
||||
@end
|
||||
|
||||
void OnMainThread(dispatch_block_t block);
|
||||
void OnMainThreadAsync(dispatch_block_t block);
|
||||
|
|
|
@ -56,3 +56,23 @@ - (void) transformProcessToForeground
|
|||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* 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 RECT rect_from_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_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 */
|
||||
|
|
|
@ -25,11 +25,439 @@
|
|||
|
||||
#include "macdrv.h"
|
||||
#include "winuser.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/server.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
|
||||
|
||||
|
||||
static CRITICAL_SECTION win_data_section;
|
||||
static CRITICAL_SECTION_DEBUG critsect_debug =
|
||||
{
|
||||
0, 0, &win_data_section,
|
||||
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
|
||||
};
|
||||
static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
static CFMutableDictionaryRef win_datas;
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_cocoa_window_features
|
||||
*/
|
||||
static void get_cocoa_window_features(struct macdrv_win_data *data,
|
||||
DWORD style, DWORD ex_style,
|
||||
struct macdrv_window_features* wf)
|
||||
{
|
||||
memset(wf, 0, sizeof(*wf));
|
||||
|
||||
if (IsRectEmpty(&data->window_rect)) return;
|
||||
|
||||
if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
|
||||
{
|
||||
wf->shadow = 1;
|
||||
wf->title_bar = 1;
|
||||
if (style & WS_SYSMENU) wf->close_button = 1;
|
||||
if (style & WS_MINIMIZEBOX) wf->minimize_button = 1;
|
||||
if (style & WS_MAXIMIZEBOX) wf->resizable = 1;
|
||||
if (ex_style & WS_EX_TOOLWINDOW) wf->utility = 1;
|
||||
}
|
||||
if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = 1;
|
||||
else if (style & WS_THICKFRAME)
|
||||
{
|
||||
wf->shadow = 1;
|
||||
wf->resizable = 1;
|
||||
}
|
||||
else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_mac_rect_offset
|
||||
*
|
||||
* Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
|
||||
*/
|
||||
static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
|
||||
{
|
||||
DWORD ex_style, style_mask = 0, ex_style_mask = 0;
|
||||
struct macdrv_window_features wf;
|
||||
|
||||
rect->top = rect->bottom = rect->left = rect->right = 0;
|
||||
|
||||
ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
|
||||
|
||||
get_cocoa_window_features(data, style, ex_style, &wf);
|
||||
|
||||
if (wf.title_bar) style_mask |= WS_CAPTION;
|
||||
if (wf.shadow)
|
||||
{
|
||||
style_mask |= WS_DLGFRAME | WS_THICKFRAME;
|
||||
ex_style_mask |= WS_EX_DLGMODALFRAME;
|
||||
}
|
||||
|
||||
AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
|
||||
|
||||
TRACE("%p/%p style %08x ex_style %08x -> %s\n", data->hwnd, data->cocoa_window,
|
||||
style, ex_style, wine_dbgstr_rect(rect));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* show_window
|
||||
*/
|
||||
static void show_window(struct macdrv_win_data *data)
|
||||
{
|
||||
TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
|
||||
|
||||
data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* hide_window
|
||||
*/
|
||||
static void hide_window(struct macdrv_win_data *data)
|
||||
{
|
||||
TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
|
||||
|
||||
macdrv_hide_cocoa_window(data->cocoa_window);
|
||||
data->on_screen = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_window_to_mac_rect
|
||||
*
|
||||
* Convert a rect from client to Mac window coordinates
|
||||
*/
|
||||
static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
|
||||
{
|
||||
RECT rc;
|
||||
|
||||
if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
|
||||
if (IsRectEmpty(rect)) return;
|
||||
|
||||
get_mac_rect_offset(data, style, &rc);
|
||||
|
||||
rect->left -= rc.left;
|
||||
rect->right -= rc.right;
|
||||
rect->top -= rc.top;
|
||||
rect->bottom -= rc.bottom;
|
||||
if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
|
||||
if (rect->left >= rect->right) rect->right = rect->left + 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_mac_to_window_rect
|
||||
*
|
||||
* Opposite of macdrv_window_to_mac_rect
|
||||
*/
|
||||
static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
|
||||
{
|
||||
RECT rc;
|
||||
DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
|
||||
|
||||
if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
|
||||
if (IsRectEmpty(rect)) return;
|
||||
|
||||
get_mac_rect_offset(data, style, &rc);
|
||||
|
||||
rect->left += rc.left;
|
||||
rect->right += rc.right;
|
||||
rect->top += rc.top;
|
||||
rect->bottom += rc.bottom;
|
||||
if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
|
||||
if (rect->left >= rect->right) rect->right = rect->left + 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* constrain_window_frame
|
||||
*
|
||||
* Alter a window frame rectangle to fit within a) Cocoa's documented
|
||||
* limits, and b) sane sizes, like twice the desktop rect.
|
||||
*/
|
||||
static void constrain_window_frame(CGRect* frame)
|
||||
{
|
||||
CGRect desktop_rect = macdrv_get_desktop_rect();
|
||||
int max_width, max_height;
|
||||
|
||||
max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
|
||||
max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
|
||||
|
||||
if (frame->origin.x < -16000) frame->origin.x = -16000;
|
||||
if (frame->origin.y < -16000) frame->origin.y = -16000;
|
||||
if (frame->origin.x > 16000) frame->origin.x = 16000;
|
||||
if (frame->origin.y > 16000) frame->origin.y = 16000;
|
||||
if (frame->size.width > max_width) frame->size.width = max_width;
|
||||
if (frame->size.height > max_height) frame->size.height = max_height;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* alloc_win_data
|
||||
*/
|
||||
static struct macdrv_win_data *alloc_win_data(HWND hwnd)
|
||||
{
|
||||
struct macdrv_win_data *data;
|
||||
|
||||
if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
|
||||
{
|
||||
data->hwnd = hwnd;
|
||||
EnterCriticalSection(&win_data_section);
|
||||
if (!win_datas)
|
||||
win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
|
||||
CFDictionarySetValue(win_datas, hwnd, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_win_data
|
||||
*
|
||||
* Lock and return the data structure associated with a window.
|
||||
*/
|
||||
static struct macdrv_win_data *get_win_data(HWND hwnd)
|
||||
{
|
||||
struct macdrv_win_data *data;
|
||||
|
||||
if (!hwnd) return NULL;
|
||||
EnterCriticalSection(&win_data_section);
|
||||
if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
|
||||
return data;
|
||||
LeaveCriticalSection(&win_data_section);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* release_win_data
|
||||
*
|
||||
* Release the data returned by get_win_data.
|
||||
*/
|
||||
static void release_win_data(struct macdrv_win_data *data)
|
||||
{
|
||||
if (data) LeaveCriticalSection(&win_data_section);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_get_cocoa_window
|
||||
*
|
||||
* Return the Mac window associated with the full area of a window
|
||||
*/
|
||||
static macdrv_window macdrv_get_cocoa_window(HWND hwnd)
|
||||
{
|
||||
struct macdrv_win_data *data = get_win_data(hwnd);
|
||||
macdrv_window ret = data ? data->cocoa_window : NULL;
|
||||
release_win_data(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* set_cocoa_window_properties
|
||||
*
|
||||
* Set the window properties for a Cocoa window based on its Windows
|
||||
* properties.
|
||||
*/
|
||||
static void set_cocoa_window_properties(struct macdrv_win_data *data)
|
||||
{
|
||||
DWORD style, ex_style;
|
||||
struct macdrv_window_features wf;
|
||||
|
||||
style = GetWindowLongW(data->hwnd, GWL_STYLE);
|
||||
ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
|
||||
|
||||
get_cocoa_window_features(data, style, ex_style, &wf);
|
||||
macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* create_cocoa_window
|
||||
*
|
||||
* Create the whole Mac window for a given window
|
||||
*/
|
||||
static void create_cocoa_window(struct macdrv_win_data *data)
|
||||
{
|
||||
WCHAR text[1024];
|
||||
struct macdrv_window_features wf;
|
||||
CGRect frame;
|
||||
DWORD style, ex_style;
|
||||
|
||||
style = GetWindowLongW(data->hwnd, GWL_STYLE);
|
||||
ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
|
||||
|
||||
data->whole_rect = data->window_rect;
|
||||
macdrv_window_to_mac_rect(data, style, &data->whole_rect);
|
||||
|
||||
memset(&wf, 0, sizeof(wf));
|
||||
get_cocoa_window_features(data, style, ex_style, &wf);
|
||||
|
||||
frame = cgrect_from_rect(data->whole_rect);
|
||||
constrain_window_frame(&frame);
|
||||
|
||||
TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
|
||||
wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
|
||||
|
||||
data->cocoa_window = macdrv_create_cocoa_window(&wf, frame);
|
||||
if (!data->cocoa_window) return;
|
||||
|
||||
set_cocoa_window_properties(data);
|
||||
|
||||
/* set the window text */
|
||||
if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
|
||||
macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* destroy_cocoa_window
|
||||
*
|
||||
* Destroy the whole Mac window for a given window.
|
||||
*/
|
||||
static void destroy_cocoa_window(struct macdrv_win_data *data)
|
||||
{
|
||||
if (!data->cocoa_window) return;
|
||||
|
||||
TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
|
||||
|
||||
macdrv_destroy_cocoa_window(data->cocoa_window);
|
||||
data->cocoa_window = 0;
|
||||
data->on_screen = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_create_win_data
|
||||
*
|
||||
* Create a Mac data window structure for an existing window.
|
||||
*/
|
||||
static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
|
||||
const RECT *client_rect)
|
||||
{
|
||||
struct macdrv_win_data *data;
|
||||
HWND parent;
|
||||
|
||||
if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
|
||||
|
||||
if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
|
||||
return NULL;
|
||||
|
||||
/* don't create win data for HWND_MESSAGE windows */
|
||||
if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
|
||||
|
||||
if (!(data = alloc_win_data(hwnd))) return NULL;
|
||||
|
||||
data->whole_rect = data->window_rect = *window_rect;
|
||||
data->client_rect = *client_rect;
|
||||
|
||||
if (parent == GetDesktopWindow())
|
||||
{
|
||||
create_cocoa_window(data);
|
||||
TRACE("win %p/%p window %s whole %s client %s\n",
|
||||
hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
|
||||
wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* sync_window_position
|
||||
*
|
||||
* Synchronize the Mac window position with the Windows one
|
||||
*/
|
||||
static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags)
|
||||
{
|
||||
CGRect frame = cgrect_from_rect(data->whole_rect);
|
||||
constrain_window_frame(&frame);
|
||||
|
||||
data->on_screen = macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
|
||||
|
||||
TRACE("win %p/%p pos %s\n", data->hwnd, data->cocoa_window,
|
||||
wine_dbgstr_rect(&data->whole_rect));
|
||||
|
||||
if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
|
||||
{
|
||||
HWND next = NULL;
|
||||
macdrv_window prev_window = NULL;
|
||||
macdrv_window next_window = NULL;
|
||||
|
||||
/* find window that this one must be after */
|
||||
HWND prev = GetWindow(data->hwnd, GW_HWNDPREV);
|
||||
while (prev && !((GetWindowLongW(prev, GWL_STYLE) & WS_VISIBLE) &&
|
||||
(prev_window = macdrv_get_cocoa_window(prev))))
|
||||
prev = GetWindow(prev, GW_HWNDPREV);
|
||||
if (!prev_window)
|
||||
{
|
||||
/* find window that this one must be before */
|
||||
next = GetWindow(data->hwnd, GW_HWNDNEXT);
|
||||
while (next && !((GetWindowLongW(next, GWL_STYLE) & WS_VISIBLE) &&
|
||||
(next_window = macdrv_get_cocoa_window(next))))
|
||||
next = GetWindow(next, GW_HWNDNEXT);
|
||||
}
|
||||
|
||||
data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window);
|
||||
|
||||
TRACE("win %p/%p below %p/%p above %p/%p\n",
|
||||
data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* move_window_bits
|
||||
*
|
||||
* Move the window bits when a window is moved.
|
||||
*/
|
||||
static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
|
||||
const RECT *old_client_rect, const RECT *new_client_rect,
|
||||
const RECT *new_window_rect)
|
||||
{
|
||||
RECT src_rect = *old_rect;
|
||||
RECT dst_rect = *new_rect;
|
||||
HDC hdc_src, hdc_dst;
|
||||
HRGN rgn;
|
||||
HWND parent = 0;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
|
||||
parent = GetAncestor(hwnd, GA_PARENT);
|
||||
hdc_src = GetDCEx(parent, 0, DCX_CACHE);
|
||||
hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
|
||||
/* make src rect relative to the old position of the window */
|
||||
OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
|
||||
if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
|
||||
hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
|
||||
}
|
||||
|
||||
rgn = CreateRectRgnIndirect(&dst_rect);
|
||||
SelectClipRgn(hdc_dst, rgn);
|
||||
DeleteObject(rgn);
|
||||
ExcludeUpdateRgn(hdc_dst, hwnd);
|
||||
|
||||
TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
|
||||
wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
|
||||
BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
|
||||
dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
|
||||
hdc_src, src_rect.left, src_rect.top, SRCCOPY);
|
||||
|
||||
ReleaseDC(hwnd, hdc_dst);
|
||||
if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* CreateDesktopWindow (MACDRV.@)
|
||||
*/
|
||||
|
@ -71,3 +499,210 @@ BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* CreateWindow (MACDRV.@)
|
||||
*/
|
||||
BOOL CDECL macdrv_CreateWindow(HWND hwnd)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DestroyWindow (MACDRV.@)
|
||||
*/
|
||||
void CDECL macdrv_DestroyWindow(HWND hwnd)
|
||||
{
|
||||
struct macdrv_win_data *data;
|
||||
|
||||
TRACE("%p\n", hwnd);
|
||||
|
||||
if (!(data = get_win_data(hwnd))) return;
|
||||
|
||||
destroy_cocoa_window(data);
|
||||
|
||||
CFDictionaryRemoveValue(win_datas, hwnd);
|
||||
release_win_data(data);
|
||||
HeapFree(GetProcessHeap(), 0, data);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* SetParent (MACDRV.@)
|
||||
*/
|
||||
void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
|
||||
{
|
||||
struct macdrv_win_data *data;
|
||||
|
||||
TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
|
||||
|
||||
if (parent == old_parent) return;
|
||||
if (!(data = get_win_data(hwnd))) return;
|
||||
|
||||
if (parent != GetDesktopWindow()) /* a child window */
|
||||
{
|
||||
if (old_parent == GetDesktopWindow())
|
||||
{
|
||||
/* destroy the old Mac window */
|
||||
destroy_cocoa_window(data);
|
||||
}
|
||||
}
|
||||
else /* new top level window */
|
||||
create_cocoa_window(data);
|
||||
release_win_data(data);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* SetWindowStyle (MACDRV.@)
|
||||
*
|
||||
* Update the state of the Cocoa window to reflect a style change
|
||||
*/
|
||||
void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
|
||||
{
|
||||
struct macdrv_win_data *data;
|
||||
|
||||
TRACE("%p, %d, %p\n", hwnd, offset, style);
|
||||
|
||||
if (hwnd == GetDesktopWindow()) return;
|
||||
if (!(data = get_win_data(hwnd))) return;
|
||||
|
||||
if (data->cocoa_window)
|
||||
set_cocoa_window_properties(data);
|
||||
|
||||
release_win_data(data);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* SetWindowText (MACDRV.@)
|
||||
*/
|
||||
void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
|
||||
{
|
||||
macdrv_window win;
|
||||
|
||||
TRACE("%p, %s\n", hwnd, debugstr_w(text));
|
||||
|
||||
if ((win = macdrv_get_cocoa_window(hwnd)))
|
||||
macdrv_set_cocoa_window_title(win, text, strlenW(text));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* WindowPosChanging (MACDRV.@)
|
||||
*/
|
||||
void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
|
||||
const RECT *window_rect, const RECT *client_rect,
|
||||
RECT *visible_rect, struct window_surface **surface)
|
||||
{
|
||||
struct macdrv_win_data *data = get_win_data(hwnd);
|
||||
DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
|
||||
|
||||
TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
|
||||
swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
|
||||
wine_dbgstr_rect(visible_rect), surface);
|
||||
|
||||
if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
|
||||
|
||||
*visible_rect = *window_rect;
|
||||
macdrv_window_to_mac_rect(data, style, visible_rect);
|
||||
TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
|
||||
wine_dbgstr_rect(visible_rect));
|
||||
|
||||
/* release the window surface if necessary */
|
||||
if (!data->cocoa_window) goto done;
|
||||
if (swp_flags & SWP_HIDEWINDOW) goto done;
|
||||
|
||||
if (*surface) window_surface_release(*surface);
|
||||
*surface = NULL;
|
||||
|
||||
done:
|
||||
release_win_data(data);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* WindowPosChanged (MACDRV.@)
|
||||
*/
|
||||
void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
|
||||
const RECT *window_rect, const RECT *client_rect,
|
||||
const RECT *visible_rect, const RECT *valid_rects,
|
||||
struct window_surface *surface)
|
||||
{
|
||||
struct macdrv_win_data *data;
|
||||
DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
|
||||
RECT old_window_rect, old_whole_rect, old_client_rect;
|
||||
|
||||
if (!(data = get_win_data(hwnd))) return;
|
||||
|
||||
old_window_rect = data->window_rect;
|
||||
old_whole_rect = data->whole_rect;
|
||||
old_client_rect = data->client_rect;
|
||||
data->window_rect = *window_rect;
|
||||
data->whole_rect = *visible_rect;
|
||||
data->client_rect = *client_rect;
|
||||
|
||||
TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
|
||||
hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
|
||||
wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
|
||||
new_style, swp_flags, surface);
|
||||
|
||||
if (!IsRectEmpty(&valid_rects[0]))
|
||||
{
|
||||
macdrv_window window = data->cocoa_window;
|
||||
int x_offset = old_whole_rect.left - data->whole_rect.left;
|
||||
int y_offset = old_whole_rect.top - data->whole_rect.top;
|
||||
|
||||
/* if all that happened is that the whole window moved, copy everything */
|
||||
if (!(swp_flags & SWP_FRAMECHANGED) &&
|
||||
old_whole_rect.right - data->whole_rect.right == x_offset &&
|
||||
old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
|
||||
old_client_rect.left - data->client_rect.left == x_offset &&
|
||||
old_client_rect.right - data->client_rect.right == x_offset &&
|
||||
old_client_rect.top - data->client_rect.top == y_offset &&
|
||||
old_client_rect.bottom - data->client_rect.bottom == y_offset &&
|
||||
!memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
|
||||
{
|
||||
/* A Cocoa window's bits are moved automatically */
|
||||
if (!window && (x_offset != 0 || y_offset != 0))
|
||||
{
|
||||
release_win_data(data);
|
||||
move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
|
||||
&old_client_rect, client_rect, window_rect);
|
||||
if (!(data = get_win_data(hwnd))) return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
release_win_data(data);
|
||||
move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
|
||||
&old_client_rect, client_rect, window_rect);
|
||||
if (!(data = get_win_data(hwnd))) return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data->cocoa_window) goto done;
|
||||
|
||||
if (data->on_screen)
|
||||
{
|
||||
if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
|
||||
hide_window(data);
|
||||
}
|
||||
|
||||
if (new_style & WS_VISIBLE)
|
||||
{
|
||||
if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
|
||||
set_cocoa_window_properties(data);
|
||||
|
||||
if (!data->on_screen)
|
||||
show_window(data);
|
||||
}
|
||||
|
||||
sync_window_position(data, swp_flags);
|
||||
set_cocoa_window_properties(data);
|
||||
|
||||
done:
|
||||
release_win_data(data);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue