winemac: Implement window surface rendering.
This commit is contained in:
parent
ddf922d7a1
commit
7d6ebfa742
|
@ -6,6 +6,7 @@ C_SRCS = \
|
||||||
display.c \
|
display.c \
|
||||||
gdi.c \
|
gdi.c \
|
||||||
macdrv_main.c \
|
macdrv_main.c \
|
||||||
|
surface.c \
|
||||||
window.c
|
window.c
|
||||||
|
|
||||||
OBJC_SRCS = \
|
OBJC_SRCS = \
|
||||||
|
|
|
@ -28,6 +28,9 @@ @interface WineWindow : NSPanel <NSWindowDelegate>
|
||||||
BOOL noActivate;
|
BOOL noActivate;
|
||||||
BOOL floating;
|
BOOL floating;
|
||||||
WineWindow* latentParentWindow;
|
WineWindow* latentParentWindow;
|
||||||
|
|
||||||
|
void* surface;
|
||||||
|
pthread_mutex_t* surface_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -65,6 +65,9 @@ @interface WineWindow ()
|
||||||
@property (nonatomic) BOOL floating;
|
@property (nonatomic) BOOL floating;
|
||||||
@property (retain, nonatomic) NSWindow* latentParentWindow;
|
@property (retain, nonatomic) NSWindow* latentParentWindow;
|
||||||
|
|
||||||
|
@property (nonatomic) void* surface;
|
||||||
|
@property (nonatomic) pthread_mutex_t* surface_mutex;
|
||||||
|
|
||||||
+ (void) flipRect:(NSRect*)rect;
|
+ (void) flipRect:(NSRect*)rect;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -77,12 +80,56 @@ - (BOOL) isFlipped
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) drawRect:(NSRect)rect
|
||||||
|
{
|
||||||
|
WineWindow* window = (WineWindow*)[self window];
|
||||||
|
|
||||||
|
if (window.surface && window.surface_mutex &&
|
||||||
|
!pthread_mutex_lock(window.surface_mutex))
|
||||||
|
{
|
||||||
|
const CGRect* rects;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if (!get_surface_region_rects(window.surface, &rects, &count) || count)
|
||||||
|
{
|
||||||
|
CGRect imageRect;
|
||||||
|
CGImageRef image;
|
||||||
|
|
||||||
|
imageRect = NSRectToCGRect(rect);
|
||||||
|
image = create_surface_image(window.surface, &imageRect, FALSE);
|
||||||
|
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
CGContextRef context;
|
||||||
|
|
||||||
|
if (rects && count)
|
||||||
|
{
|
||||||
|
NSBezierPath* surfaceClip = [NSBezierPath bezierPath];
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
[surfaceClip appendBezierPathWithRect:NSRectFromCGRect(rects[i])];
|
||||||
|
[surfaceClip addClip];
|
||||||
|
}
|
||||||
|
|
||||||
|
context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
|
||||||
|
CGContextSetBlendMode(context, kCGBlendModeCopy);
|
||||||
|
CGContextDrawImage(context, imageRect, image);
|
||||||
|
|
||||||
|
CGImageRelease(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(window.surface_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation WineWindow
|
@implementation WineWindow
|
||||||
|
|
||||||
@synthesize disabled, noActivate, floating, latentParentWindow;
|
@synthesize disabled, noActivate, floating, latentParentWindow;
|
||||||
|
@synthesize surface, surface_mutex;
|
||||||
|
|
||||||
+ (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
|
+ (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
|
||||||
windowFrame:(NSRect)window_frame
|
windowFrame:(NSRect)window_frame
|
||||||
|
@ -108,6 +155,7 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w
|
||||||
[window disableCursorRects];
|
[window disableCursorRects];
|
||||||
[window setShowsResizeIndicator:NO];
|
[window setShowsResizeIndicator:NO];
|
||||||
[window setHasShadow:wf->shadow];
|
[window setHasShadow:wf->shadow];
|
||||||
|
[window setColorSpace:[NSColorSpace genericRGBColorSpace]];
|
||||||
[window setDelegate:window];
|
[window setDelegate:window];
|
||||||
|
|
||||||
contentView = [[[WineContentView alloc] initWithFrame:NSZeroRect] autorelease];
|
contentView = [[[WineContentView alloc] initWithFrame:NSZeroRect] autorelease];
|
||||||
|
@ -477,3 +525,37 @@ void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent)
|
||||||
[window setMacDrvParentWindow:(WineWindow*)parent];
|
[window setMacDrvParentWindow:(WineWindow*)parent];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_set_window_surface
|
||||||
|
*/
|
||||||
|
void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
WineWindow* window = (WineWindow*)w;
|
||||||
|
|
||||||
|
OnMainThread(^{
|
||||||
|
window.surface = surface;
|
||||||
|
window.surface_mutex = mutex;
|
||||||
|
});
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_window_needs_display
|
||||||
|
*
|
||||||
|
* Mark a window as needing display in a specified rect (in non-client
|
||||||
|
* area coordinates).
|
||||||
|
*/
|
||||||
|
void macdrv_window_needs_display(macdrv_window w, CGRect rect)
|
||||||
|
{
|
||||||
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
WineWindow* window = (WineWindow*)w;
|
||||||
|
|
||||||
|
OnMainThreadAsync(^{
|
||||||
|
[[window contentView] setNeedsDisplayInRect:NSRectFromCGRect(rect)];
|
||||||
|
});
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
}
|
||||||
|
|
|
@ -83,7 +83,11 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
|
||||||
RECT whole_rect; /* Mac window rectangle for the whole window relative to parent */
|
RECT whole_rect; /* Mac window rectangle for the whole window relative to parent */
|
||||||
RECT client_rect; /* client area relative to parent */
|
RECT client_rect; /* client area relative to parent */
|
||||||
BOOL on_screen : 1; /* is window ordered in? */
|
BOOL on_screen : 1; /* is window ordered in? */
|
||||||
|
struct window_surface *surface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp) DECLSPEC_HIDDEN;
|
||||||
|
extern struct window_surface *create_surface(macdrv_window window, const RECT *rect) DECLSPEC_HIDDEN;
|
||||||
|
extern void set_window_surface(macdrv_window window, struct window_surface *window_surface) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
#endif /* __WINE_MACDRV_H */
|
#endif /* __WINE_MACDRV_H */
|
||||||
|
|
|
@ -85,6 +85,8 @@
|
||||||
#undef UnionRect
|
#undef UnionRect
|
||||||
#undef DPRINTF
|
#undef DPRINTF
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
|
||||||
#ifndef DECLSPEC_HIDDEN
|
#ifndef DECLSPEC_HIDDEN
|
||||||
# if defined(__MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
|
# if defined(__MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
|
||||||
|
@ -147,5 +149,9 @@ extern int macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
|
||||||
extern void macdrv_hide_cocoa_window(macdrv_window w) 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;
|
extern int macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame) DECLSPEC_HIDDEN;
|
||||||
extern void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) DECLSPEC_HIDDEN;
|
extern void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) DECLSPEC_HIDDEN;
|
||||||
|
extern void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex) DECLSPEC_HIDDEN;
|
||||||
|
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;
|
||||||
|
|
||||||
#endif /* __WINE_MACDRV_COCOA_H */
|
#endif /* __WINE_MACDRV_COCOA_H */
|
||||||
|
|
|
@ -0,0 +1,340 @@
|
||||||
|
/*
|
||||||
|
* Mac driver window surface implementation
|
||||||
|
*
|
||||||
|
* Copyright 1993, 1994, 2011 Alexandre Julliard
|
||||||
|
* Copyright 2006 Damjan Jovanovic
|
||||||
|
* Copyright 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "macdrv.h"
|
||||||
|
#include "winuser.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
|
||||||
|
|
||||||
|
|
||||||
|
/* only for use on sanitized BITMAPINFO structures */
|
||||||
|
static inline int get_dib_info_size(const BITMAPINFO *info, UINT coloruse)
|
||||||
|
{
|
||||||
|
if (info->bmiHeader.biCompression == BI_BITFIELDS)
|
||||||
|
return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
|
||||||
|
if (coloruse == DIB_PAL_COLORS)
|
||||||
|
return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
|
||||||
|
return FIELD_OFFSET(BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_dib_stride(int width, int bpp)
|
||||||
|
{
|
||||||
|
return ((width * bpp + 31) >> 3) & ~3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_dib_image_size(const BITMAPINFO *info)
|
||||||
|
{
|
||||||
|
return get_dib_stride(info->bmiHeader.biWidth, info->bmiHeader.biBitCount)
|
||||||
|
* abs(info->bmiHeader.biHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void reset_bounds(RECT *bounds)
|
||||||
|
{
|
||||||
|
bounds->left = bounds->top = INT_MAX;
|
||||||
|
bounds->right = bounds->bottom = INT_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct macdrv_window_surface
|
||||||
|
{
|
||||||
|
struct window_surface header;
|
||||||
|
macdrv_window window;
|
||||||
|
RECT bounds;
|
||||||
|
RGNDATA *region_data;
|
||||||
|
BYTE *bits;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
BITMAPINFO info; /* variable size, must be last */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct macdrv_window_surface *get_mac_surface(struct window_surface *surface)
|
||||||
|
{
|
||||||
|
return (struct macdrv_window_surface *)surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_surface_lock
|
||||||
|
*/
|
||||||
|
static void macdrv_surface_lock(struct window_surface *window_surface)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&surface->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_surface_unlock
|
||||||
|
*/
|
||||||
|
static void macdrv_surface_unlock(struct window_surface *window_surface)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&surface->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_surface_get_bitmap_info
|
||||||
|
*/
|
||||||
|
static void *macdrv_surface_get_bitmap_info(struct window_surface *window_surface,
|
||||||
|
BITMAPINFO *info)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
|
||||||
|
memcpy(info, &surface->info, get_dib_info_size(&surface->info, DIB_RGB_COLORS));
|
||||||
|
return surface->bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_surface_get_bounds
|
||||||
|
*/
|
||||||
|
static RECT *macdrv_surface_get_bounds(struct window_surface *window_surface)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
|
||||||
|
return &surface->bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_surface_set_region
|
||||||
|
*/
|
||||||
|
static void macdrv_surface_set_region(struct window_surface *window_surface, HRGN region)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
|
||||||
|
TRACE("updating surface %p with %p\n", surface, region);
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, surface->region_data);
|
||||||
|
surface->region_data = NULL;
|
||||||
|
|
||||||
|
if (region)
|
||||||
|
{
|
||||||
|
int rc = OffsetRgn(region, surface->header.rect.left, surface->header.rect.top);
|
||||||
|
if (rc != ERROR)
|
||||||
|
surface->region_data = get_region_data(region, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_surface_flush
|
||||||
|
*/
|
||||||
|
static void macdrv_surface_flush(struct window_surface *window_surface)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
CGRect rect;
|
||||||
|
|
||||||
|
window_surface->funcs->lock(window_surface);
|
||||||
|
|
||||||
|
TRACE("flushing %p %s bounds %s bits %p\n", surface, wine_dbgstr_rect(&surface->header.rect),
|
||||||
|
wine_dbgstr_rect(&surface->bounds), surface->bits);
|
||||||
|
|
||||||
|
rect = cgrect_from_rect(surface->bounds);
|
||||||
|
rect = CGRectOffset(rect, surface->header.rect.left, surface->header.rect.top);
|
||||||
|
reset_bounds(&surface->bounds);
|
||||||
|
|
||||||
|
window_surface->funcs->unlock(window_surface);
|
||||||
|
|
||||||
|
if (!CGRectIsEmpty(rect))
|
||||||
|
macdrv_window_needs_display(surface->window, rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_surface_destroy
|
||||||
|
*/
|
||||||
|
static void macdrv_surface_destroy(struct window_surface *window_surface)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
|
||||||
|
TRACE("freeing %p bits %p\n", surface, surface->bits);
|
||||||
|
HeapFree(GetProcessHeap(), 0, surface->bits);
|
||||||
|
pthread_mutex_destroy(&surface->mutex);
|
||||||
|
HeapFree(GetProcessHeap(), 0, surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct window_surface_funcs macdrv_surface_funcs =
|
||||||
|
{
|
||||||
|
macdrv_surface_lock,
|
||||||
|
macdrv_surface_unlock,
|
||||||
|
macdrv_surface_get_bitmap_info,
|
||||||
|
macdrv_surface_get_bounds,
|
||||||
|
macdrv_surface_set_region,
|
||||||
|
macdrv_surface_flush,
|
||||||
|
macdrv_surface_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* create_surface
|
||||||
|
*/
|
||||||
|
struct window_surface *create_surface(macdrv_window window, const RECT *rect)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface;
|
||||||
|
int width = rect->right - rect->left, height = rect->bottom - rect->top;
|
||||||
|
DWORD *colors;
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||||
|
FIELD_OFFSET(struct macdrv_window_surface, info.bmiColors[3]));
|
||||||
|
if (!surface) return NULL;
|
||||||
|
|
||||||
|
err = pthread_mutexattr_init(&attr);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
if (!err)
|
||||||
|
err = pthread_mutex_init(&surface->mutex, &attr);
|
||||||
|
pthread_mutexattr_destroy(&attr);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, surface);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader);
|
||||||
|
surface->info.bmiHeader.biWidth = width;
|
||||||
|
surface->info.bmiHeader.biHeight = height; /* bottom-up */
|
||||||
|
surface->info.bmiHeader.biPlanes = 1;
|
||||||
|
surface->info.bmiHeader.biBitCount = 32;
|
||||||
|
surface->info.bmiHeader.biSizeImage = get_dib_image_size(&surface->info);
|
||||||
|
surface->info.bmiHeader.biCompression = BI_RGB;
|
||||||
|
surface->info.bmiHeader.biClrUsed = 0;
|
||||||
|
|
||||||
|
colors = (DWORD *)((char *)&surface->info + surface->info.bmiHeader.biSize);
|
||||||
|
colors[0] = 0x00ff0000;
|
||||||
|
colors[1] = 0x0000ff00;
|
||||||
|
colors[2] = 0x000000ff;
|
||||||
|
|
||||||
|
surface->header.funcs = &macdrv_surface_funcs;
|
||||||
|
surface->header.rect = *rect;
|
||||||
|
surface->header.ref = 1;
|
||||||
|
surface->window = window;
|
||||||
|
reset_bounds(&surface->bounds);
|
||||||
|
surface->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, surface->info.bmiHeader.biSizeImage);
|
||||||
|
if (!surface->bits) goto failed;
|
||||||
|
|
||||||
|
TRACE("created %p for %p %s bits %p-%p\n", surface, window, wine_dbgstr_rect(rect),
|
||||||
|
surface->bits, surface->bits + surface->info.bmiHeader.biSizeImage);
|
||||||
|
|
||||||
|
return &surface->header;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
macdrv_surface_destroy(&surface->header);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* set_window_surface
|
||||||
|
*/
|
||||||
|
void set_window_surface(macdrv_window window, struct window_surface *window_surface)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
macdrv_set_window_surface(window, window_surface, surface ? &surface->mutex : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* get_surface_region_rects
|
||||||
|
*
|
||||||
|
* Caller must hold the surface lock. Indirectly returns the surface
|
||||||
|
* region rects. Returns zero if the surface has no region set (it is
|
||||||
|
* unclipped); returns non-zero if the surface does have a region set.
|
||||||
|
*
|
||||||
|
* IMPORTANT: This function is called from non-Wine threads, so it
|
||||||
|
* must not use Win32 or Wine functions, including debug
|
||||||
|
* logging.
|
||||||
|
*/
|
||||||
|
int get_surface_region_rects(void *window_surface, const CGRect **rects, int *count)
|
||||||
|
{
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
|
||||||
|
if (surface->region_data)
|
||||||
|
{
|
||||||
|
*rects = (const CGRect*)surface->region_data->Buffer;
|
||||||
|
*count = surface->region_data->rdh.nCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*rects = NULL;
|
||||||
|
*count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (surface->region_data != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* create_surface_image
|
||||||
|
*
|
||||||
|
* Caller must hold the surface lock. On input, *rect is the requested
|
||||||
|
* image rect, relative to the window whole_rect, a.k.a. visible_rect.
|
||||||
|
* On output, it's been intersected with that part backed by the surface
|
||||||
|
* and is the actual size of the returned image. copy_data indicates if
|
||||||
|
* the caller will keep the returned image beyond the point where the
|
||||||
|
* surface bits can be guaranteed to remain valid and unchanged. If so,
|
||||||
|
* the bits are copied instead of merely referenced by the image.
|
||||||
|
*
|
||||||
|
* IMPORTANT: This function is called from non-Wine threads, so it
|
||||||
|
* must not use Win32 or Wine functions, including debug
|
||||||
|
* logging.
|
||||||
|
*/
|
||||||
|
CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data)
|
||||||
|
{
|
||||||
|
CGImageRef cgimage = NULL;
|
||||||
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
width = surface->header.rect.right - surface->header.rect.left;
|
||||||
|
height = surface->header.rect.bottom - surface->header.rect.top;
|
||||||
|
*rect = CGRectIntersection(cgrect_from_rect(surface->header.rect), *rect);
|
||||||
|
if (!CGRectIsEmpty(*rect))
|
||||||
|
{
|
||||||
|
CGRect visrect;
|
||||||
|
CGColorSpaceRef colorspace;
|
||||||
|
CGDataProviderRef provider;
|
||||||
|
int bytes_per_row, offset, size;
|
||||||
|
|
||||||
|
visrect = CGRectOffset(*rect, -surface->header.rect.left, -surface->header.rect.top);
|
||||||
|
|
||||||
|
colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
|
||||||
|
bytes_per_row = get_dib_stride(width, 32);
|
||||||
|
offset = CGRectGetMinX(visrect) * 4 + (height - CGRectGetMaxY(visrect)) * bytes_per_row;
|
||||||
|
size = min(CGRectGetHeight(visrect) * bytes_per_row,
|
||||||
|
surface->info.bmiHeader.biSizeImage - offset);
|
||||||
|
|
||||||
|
if (copy_data)
|
||||||
|
{
|
||||||
|
CFDataRef data = CFDataCreate(NULL, (UInt8*)surface->bits + offset, size);
|
||||||
|
provider = CGDataProviderCreateWithCFData(data);
|
||||||
|
CFRelease(data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
provider = CGDataProviderCreateWithData(NULL, surface->bits + offset, size, NULL);
|
||||||
|
|
||||||
|
cgimage = CGImageCreate(CGRectGetWidth(visrect), CGRectGetHeight(visrect),
|
||||||
|
8, 32, bytes_per_row, colorspace,
|
||||||
|
kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
|
||||||
|
provider, NULL, FALSE, kCGRenderingIntentDefault);
|
||||||
|
CGDataProviderRelease(provider);
|
||||||
|
CGColorSpaceRelease(colorspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cgimage;
|
||||||
|
}
|
|
@ -376,6 +376,8 @@ static void destroy_cocoa_window(struct macdrv_win_data *data)
|
||||||
macdrv_destroy_cocoa_window(data->cocoa_window);
|
macdrv_destroy_cocoa_window(data->cocoa_window);
|
||||||
data->cocoa_window = 0;
|
data->cocoa_window = 0;
|
||||||
data->on_screen = FALSE;
|
data->on_screen = FALSE;
|
||||||
|
if (data->surface) window_surface_release(data->surface);
|
||||||
|
data->surface = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -415,6 +417,73 @@ static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *win
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* get_region_data
|
||||||
|
*
|
||||||
|
* Calls GetRegionData on the given region and converts the rectangle
|
||||||
|
* array to CGRect format. The returned buffer must be freed by
|
||||||
|
* caller using HeapFree(GetProcessHeap(),...).
|
||||||
|
* If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
|
||||||
|
*/
|
||||||
|
RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
|
||||||
|
{
|
||||||
|
RGNDATA *data;
|
||||||
|
DWORD size;
|
||||||
|
int i;
|
||||||
|
RECT *rect;
|
||||||
|
CGRect *cgrect;
|
||||||
|
|
||||||
|
if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
|
||||||
|
if (sizeof(CGRect) > sizeof(RECT))
|
||||||
|
{
|
||||||
|
/* add extra size for CGRect array */
|
||||||
|
int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
|
||||||
|
size += count * (sizeof(CGRect) - sizeof(RECT));
|
||||||
|
}
|
||||||
|
if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
|
||||||
|
if (!GetRegionData(hrgn, size, data))
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect = (RECT *)data->Buffer;
|
||||||
|
cgrect = (CGRect *)data->Buffer;
|
||||||
|
if (hdc_lptodp) /* map to device coordinates */
|
||||||
|
{
|
||||||
|
LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
|
||||||
|
for (i = 0; i < data->rdh.nCount; i++)
|
||||||
|
{
|
||||||
|
if (rect[i].right < rect[i].left)
|
||||||
|
{
|
||||||
|
INT tmp = rect[i].right;
|
||||||
|
rect[i].right = rect[i].left;
|
||||||
|
rect[i].left = tmp;
|
||||||
|
}
|
||||||
|
if (rect[i].bottom < rect[i].top)
|
||||||
|
{
|
||||||
|
INT tmp = rect[i].bottom;
|
||||||
|
rect[i].bottom = rect[i].top;
|
||||||
|
rect[i].top = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizeof(CGRect) > sizeof(RECT))
|
||||||
|
{
|
||||||
|
/* need to start from the end */
|
||||||
|
for (i = data->rdh.nCount-1; i >= 0; i--)
|
||||||
|
cgrect[i] = cgrect_from_rect(rect[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < data->rdh.nCount; i++)
|
||||||
|
cgrect[i] = cgrect_from_rect(rect[i]);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* sync_window_position
|
* sync_window_position
|
||||||
*
|
*
|
||||||
|
@ -637,6 +706,21 @@ void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline RECT get_surface_rect(const RECT *visible_rect)
|
||||||
|
{
|
||||||
|
RECT rect;
|
||||||
|
RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
|
||||||
|
|
||||||
|
IntersectRect(&rect, visible_rect, &desktop_rect);
|
||||||
|
OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
|
||||||
|
rect.left &= ~127;
|
||||||
|
rect.top &= ~127;
|
||||||
|
rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
|
||||||
|
rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* WindowPosChanging (MACDRV.@)
|
* WindowPosChanging (MACDRV.@)
|
||||||
*/
|
*/
|
||||||
|
@ -646,6 +730,7 @@ void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags
|
||||||
{
|
{
|
||||||
struct macdrv_win_data *data = get_win_data(hwnd);
|
struct macdrv_win_data *data = get_win_data(hwnd);
|
||||||
DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
|
DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
|
||||||
|
RECT surface_rect;
|
||||||
|
|
||||||
TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
|
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),
|
swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
|
||||||
|
@ -658,13 +743,28 @@ void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags
|
||||||
TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
|
TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
|
||||||
wine_dbgstr_rect(visible_rect));
|
wine_dbgstr_rect(visible_rect));
|
||||||
|
|
||||||
/* release the window surface if necessary */
|
/* create the window surface if necessary */
|
||||||
if (!data->cocoa_window) goto done;
|
if (!data->cocoa_window) goto done;
|
||||||
if (swp_flags & SWP_HIDEWINDOW) goto done;
|
if (swp_flags & SWP_HIDEWINDOW) goto done;
|
||||||
|
|
||||||
if (*surface) window_surface_release(*surface);
|
if (*surface) window_surface_release(*surface);
|
||||||
*surface = NULL;
|
*surface = NULL;
|
||||||
|
|
||||||
|
surface_rect = get_surface_rect(visible_rect);
|
||||||
|
if (data->surface)
|
||||||
|
{
|
||||||
|
if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
|
||||||
|
{
|
||||||
|
/* existing surface is good enough */
|
||||||
|
window_surface_add_ref(data->surface);
|
||||||
|
*surface = data->surface;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
|
||||||
|
|
||||||
|
*surface = create_surface(data->cocoa_window, &surface_rect);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
release_win_data(data);
|
release_win_data(data);
|
||||||
}
|
}
|
||||||
|
@ -690,6 +790,11 @@ void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
|
||||||
data->window_rect = *window_rect;
|
data->window_rect = *window_rect;
|
||||||
data->whole_rect = *visible_rect;
|
data->whole_rect = *visible_rect;
|
||||||
data->client_rect = *client_rect;
|
data->client_rect = *client_rect;
|
||||||
|
if (surface)
|
||||||
|
window_surface_add_ref(surface);
|
||||||
|
set_window_surface(data->cocoa_window, surface);
|
||||||
|
if (data->surface) window_surface_release(data->surface);
|
||||||
|
data->surface = surface;
|
||||||
|
|
||||||
TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
|
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),
|
hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
|
||||||
|
|
Loading…
Reference in New Issue