winemac: Implement SetWindowRgn.

This commit is contained in:
Ken Thomases 2013-01-14 20:23:58 -06:00 committed by Alexandre Julliard
parent 7d6ebfa742
commit 2d4bcc47be
6 changed files with 250 additions and 16 deletions

View File

@ -31,6 +31,9 @@ @interface WineWindow : NSPanel <NSWindowDelegate>
void* surface;
pthread_mutex_t* surface_mutex;
NSBezierPath* shape;
BOOL shapeChangedSinceLastDraw;
}
@end

View File

@ -68,6 +68,10 @@ @interface WineWindow ()
@property (nonatomic) void* surface;
@property (nonatomic) pthread_mutex_t* surface_mutex;
@property (copy, nonatomic) NSBezierPath* shape;
@property (nonatomic) BOOL shapeChangedSinceLastDraw;
@property (readonly, nonatomic) BOOL needsTransparency;
+ (void) flipRect:(NSRect*)rect;
@end
@ -111,11 +115,19 @@ - (void) drawRect:(NSRect)rect
[surfaceClip addClip];
}
[window.shape addClip];
context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextDrawImage(context, imageRect, image);
CGImageRelease(image);
if (window.shapeChangedSinceLastDraw)
{
window.shapeChangedSinceLastDraw = FALSE;
[window invalidateShadow];
}
}
}
@ -130,6 +142,7 @@ @implementation WineWindow
@synthesize disabled, noActivate, floating, latentParentWindow;
@synthesize surface, surface_mutex;
@synthesize shape, shapeChangedSinceLastDraw;
+ (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
windowFrame:(NSRect)window_frame
@ -171,6 +184,7 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w
- (void) dealloc
{
[latentParentWindow release];
[shape release];
[super dealloc];
}
@ -322,6 +336,44 @@ - (void) setDisabled:(BOOL)newValue
}
}
- (BOOL) needsTransparency
{
return (self.shape != nil);
}
- (void) checkTransparency
{
if (![self isOpaque] && !self.needsTransparency)
{
[self setBackgroundColor:[NSColor windowBackgroundColor]];
[self setOpaque:YES];
}
else if ([self isOpaque] && self.needsTransparency)
{
[self setBackgroundColor:[NSColor clearColor]];
[self setOpaque:NO];
}
}
- (void) setShape:(NSBezierPath*)newShape
{
if (shape == newShape) return;
if (shape && newShape && [shape isEqual:newShape]) return;
if (shape)
{
[[self contentView] setNeedsDisplayInRect:[shape bounds]];
[shape release];
}
if (newShape)
[[self contentView] setNeedsDisplayInRect:[newShape bounds]];
shape = [newShape copy];
self.shapeChangedSinceLastDraw = TRUE;
[self checkTransparency];
}
/*
* ---------- NSWindow method overrides ----------
@ -559,3 +611,32 @@ void macdrv_window_needs_display(macdrv_window w, CGRect rect)
[pool release];
}
/***********************************************************************
* macdrv_set_window_shape
*
* Sets the shape of a Cocoa window from an array of rectangles. If
* rects is NULL, resets the window's shape to its frame.
*/
void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineWindow* window = (WineWindow*)w;
OnMainThread(^{
if (!rects || !count)
window.shape = nil;
else
{
NSBezierPath* path;
unsigned int i;
path = [NSBezierPath bezierPath];
for (i = 0; i < count; i++)
[path appendBezierPathWithRect:NSRectFromCGRect(rects[i])];
window.shape = path;
}
});
[pool release];
}

View File

@ -74,6 +74,12 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
* Mac USER driver
*/
/* Mac driver private messages, must be in the range 0x80001000..0x80001fff */
enum macdrv_window_messages
{
WM_MACDRV_SET_WIN_REGION = 0x80001000,
};
/* macdrv private window data */
struct macdrv_win_data
{
@ -83,6 +89,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
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? */
BOOL shaped : 1; /* is window using a custom region shape? */
struct window_surface *surface;
};

View File

@ -153,5 +153,6 @@ extern int macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
extern CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data) DECLSPEC_HIDDEN;
extern int get_surface_region_rects(void *window_surface, const CGRect **rects, int *count) DECLSPEC_HIDDEN;
extern void macdrv_window_needs_display(macdrv_window w, CGRect rect) DECLSPEC_HIDDEN;
extern void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count) DECLSPEC_HIDDEN;
#endif /* __WINE_MACDRV_COCOA_H */

View File

@ -57,17 +57,20 @@ static void get_cocoa_window_features(struct macdrv_win_data *data,
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 (!data->shaped)
{
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;
if (!data->shaped) wf->resizable = 1;
}
else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = 1;
}
@ -118,25 +121,28 @@ static void get_cocoa_window_state(struct macdrv_win_data *data,
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)
if (!data->shaped)
{
style_mask |= WS_DLGFRAME | WS_THICKFRAME;
ex_style_mask |= WS_EX_DLGMODALFRAME;
struct macdrv_window_features wf;
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));
TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
style, ex_style, data->shaped, wine_dbgstr_rect(rect));
}
@ -324,6 +330,70 @@ static void set_cocoa_window_properties(struct macdrv_win_data *data)
}
/***********************************************************************
* sync_window_region
*
* Update the window region.
*/
static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
{
HRGN hrgn = win_region;
RGNDATA *region_data;
const CGRect* rects;
int count;
if (!data->cocoa_window) return;
data->shaped = FALSE;
if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
{
if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
{
DeleteObject(hrgn);
hrgn = 0;
}
}
if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
MirrorRgn(data->hwnd, hrgn);
if (hrgn)
{
OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
data->window_rect.top - data->whole_rect.top);
}
region_data = get_region_data(hrgn, 0);
if (region_data)
{
rects = (CGRect*)region_data->Buffer;
count = region_data->rdh.nCount;
/* Special case optimization. If the region entirely encloses the Cocoa
window, it's the same as there being no region. It's potentially
hard/slow to test this for arbitrary regions, so we just check for
very simple regions. */
if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
{
TRACE("optimizing for simple region that contains Cocoa content rect\n");
rects = NULL;
count = 0;
}
}
else
{
rects = NULL;
count = 0;
}
TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
macdrv_set_window_shape(data->cocoa_window, rects, count);
HeapFree(GetProcessHeap(), 0, region_data);
data->shaped = (region_data != NULL);
if (hrgn && hrgn != win_region) DeleteObject(hrgn);
}
/**********************************************************************
* create_cocoa_window
*
@ -335,6 +405,15 @@ static void create_cocoa_window(struct macdrv_win_data *data)
struct macdrv_window_features wf;
CGRect frame;
DWORD style, ex_style;
HRGN win_rgn;
if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
GetWindowRgn(data->hwnd, win_rgn) == ERROR)
{
DeleteObject(win_rgn);
win_rgn = 0;
}
data->shaped = (win_rgn != 0);
style = GetWindowLongW(data->hwnd, GWL_STYLE);
ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
@ -352,13 +431,19 @@ static void create_cocoa_window(struct macdrv_win_data *data)
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;
if (!data->cocoa_window) goto done;
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));
/* set the window region */
if (win_rgn) sync_window_region(data, win_rgn);
done:
if (win_rgn) DeleteObject(win_rgn);
}
@ -495,6 +580,7 @@ static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags)
constrain_window_frame(&frame);
data->on_screen = macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
if (data->shaped) sync_window_region(data, (HRGN)1);
TRACE("win %p/%p pos %s\n", data->hwnd, data->cocoa_window,
wine_dbgstr_rect(&data->whole_rect));
@ -671,6 +757,35 @@ void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
}
/***********************************************************************
* SetWindowRgn (MACDRV.@)
*
* Assign specified region to window (for non-rectangular windows)
*/
int CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
{
struct macdrv_win_data *data;
TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
if ((data = get_win_data(hwnd)))
{
sync_window_region(data, hrgn);
release_win_data(data);
}
else
{
DWORD procid;
GetWindowThreadProcessId(hwnd, &procid);
if (procid != GetCurrentProcessId())
SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
}
return TRUE;
}
/***********************************************************************
* SetWindowStyle (MACDRV.@)
*
@ -706,6 +821,31 @@ void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
}
/**********************************************************************
* WindowMessage (MACDRV.@)
*/
LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
struct macdrv_win_data *data;
TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
switch(msg)
{
case WM_MACDRV_SET_WIN_REGION:
if ((data = get_win_data(hwnd)))
{
sync_window_region(data, (HRGN)1);
release_win_data(data);
}
return 0;
}
FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
return 0;
}
static inline RECT get_surface_rect(const RECT *visible_rect)
{
RECT rect;

View File

@ -10,7 +10,9 @@
@ cdecl EnumDisplayMonitors(long ptr ptr long) macdrv_EnumDisplayMonitors
@ cdecl GetMonitorInfo(long ptr) macdrv_GetMonitorInfo
@ cdecl SetParent(long long long) macdrv_SetParent
@ cdecl SetWindowRgn(long long long) macdrv_SetWindowRgn
@ cdecl SetWindowStyle(ptr long ptr) macdrv_SetWindowStyle
@ cdecl SetWindowText(long wstr) macdrv_SetWindowText
@ cdecl WindowMessage(long long long long) macdrv_WindowMessage
@ cdecl WindowPosChanged(long long long ptr ptr ptr ptr ptr) macdrv_WindowPosChanged
@ cdecl WindowPosChanging(long long long ptr ptr ptr ptr) macdrv_WindowPosChanging