winemac: Implement WINDOW_FRAME_CHANGED event to tell Wine when window is moved or resized.

This commit is contained in:
Ken Thomases 2013-01-27 16:19:29 -06:00 committed by Alexandre Julliard
parent b28aff0dd7
commit 6e59740e18
6 changed files with 177 additions and 2 deletions

View File

@ -207,6 +207,10 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w
[window setContentView:contentView];
/* In case Cocoa adjusted the frame we tried to set, generate a frame-changed
event. The back end will ignore it if nothing actually changed. */
[window windowDidResize:nil];
return window;
}
@ -297,6 +301,11 @@ - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next
self.latentParentWindow = nil;
}
/* Cocoa may adjust the frame when the window is ordered onto the screen.
Generate a frame-changed event just in case. The back end will ignore
it if nothing actually changed. */
[self windowDidResize:nil];
if (![self isExcludedFromWindowsMenu])
[NSApp addWindowsItem:self title:[self title] filename:NO];
}
@ -341,6 +350,10 @@ - (BOOL) setFrameIfOnScreen:(NSRect)contentRect
[self setFrame:frame display:YES];
}
/* In case Cocoa adjusted the frame we tried to set, generate a frame-changed
event. The back end will ignore it if nothing actually changed. */
[self windowDidResize:nil];
return on_screen;
}
@ -435,6 +448,28 @@ - (BOOL) validateMenuItem:(NSMenuItem *)menuItem
/*
* ---------- NSWindowDelegate methods ----------
*/
- (void)windowDidMove:(NSNotification *)notification
{
[self windowDidResize:notification];
}
- (void)windowDidResize:(NSNotification *)notification
{
macdrv_event event;
NSRect frame = [self contentRectForFrameRect:[self frame]];
[[self class] flipRect:&frame];
/* Coalesce events by discarding any previous ones still in the queue. */
[queue discardEventsMatchingMask:event_mask_for_type(WINDOW_FRAME_CHANGED)
forWindow:self];
event.type = WINDOW_FRAME_CHANGED;
event.window = (macdrv_window)[self retain];
event.window_frame_changed.frame = NSRectToCGRect(frame);
[queue postEvent:&event];
}
- (BOOL)windowShouldClose:(id)sender
{
macdrv_event event;
@ -611,6 +646,24 @@ int macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame)
return on_screen;
}
/***********************************************************************
* macdrv_get_cocoa_window_frame
*
* Gets the frame of a Cocoa window.
*/
void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame)
{
WineWindow* window = (WineWindow*)w;
OnMainThread(^{
NSRect frame;
frame = [window contentRectForFrameRect:[window frame]];
[[window class] flipRect:&frame];
*out_frame = NSRectToCGRect(frame);
});
}
/***********************************************************************
* macdrv_set_cocoa_parent_window
*

View File

@ -33,6 +33,7 @@ static const char *dbgstr_event(int type)
{
static const char * const event_names[] = {
"WINDOW_CLOSE_REQUESTED",
"WINDOW_FRAME_CHANGED",
};
if (0 <= type && type < NUM_EVENT_TYPES) return event_names[type];
@ -50,7 +51,10 @@ static macdrv_event_mask get_event_mask(DWORD mask)
if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return -1;
if (mask & QS_POSTMESSAGE)
{
event_mask |= event_mask_for_type(WINDOW_CLOSE_REQUESTED);
event_mask |= event_mask_for_type(WINDOW_FRAME_CHANGED);
}
return event_mask;
}
@ -76,6 +80,9 @@ void macdrv_handle_event(macdrv_event *event)
case WINDOW_CLOSE_REQUESTED:
macdrv_window_close_requested(hwnd);
break;
case WINDOW_FRAME_CHANGED:
macdrv_window_frame_changed(hwnd, event->window_frame_changed.frame);
break;
default:
TRACE(" ignoring\n");
break;

View File

@ -118,5 +118,6 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
extern void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha) DECLSPEC_HIDDEN;
extern void macdrv_window_close_requested(HWND hwnd) DECLSPEC_HIDDEN;
extern void macdrv_window_frame_changed(HWND hwnd, CGRect frame) DECLSPEC_HIDDEN;
#endif /* __WINE_MACDRV_H */

View File

@ -123,6 +123,7 @@
/* event */
enum {
WINDOW_CLOSE_REQUESTED,
WINDOW_FRAME_CHANGED,
NUM_EVENT_TYPES
};
@ -131,6 +132,11 @@
typedef struct macdrv_event {
int type;
macdrv_window window;
union {
struct {
CGRect frame;
} window_frame_changed;
};
} macdrv_event;
static inline macdrv_event_mask event_mask_for_type(int type)
@ -179,6 +185,7 @@ 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;
extern void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame) 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;

View File

@ -949,6 +949,51 @@ void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
}
/***********************************************************************
* ShowWindow (MACDRV.@)
*/
UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
{
struct macdrv_thread_data *thread_data = macdrv_thread_data();
struct macdrv_win_data *data = get_win_data(hwnd);
CGRect frame;
if (!data || !data->cocoa_window) goto done;
if (IsRectEmpty(rect)) goto done;
if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
{
if (rect->left != -32000 || rect->top != -32000)
{
OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
}
goto done;
}
if (!data->on_screen) goto done;
/* only fetch the new rectangle if the ShowWindow was a result of an external event */
if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
goto done;
if (thread_data->current_event->type != WINDOW_FRAME_CHANGED)
goto done;
TRACE("win %p/%p cmd %d at %s flags %08x\n",
hwnd, data->cocoa_window, cmd, wine_dbgstr_rect(rect), swp);
macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
*rect = rect_from_cgrect(frame);
macdrv_mac_to_window_rect(data, rect);
TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
done:
release_win_data(data);
return swp;
}
/***********************************************************************
* UpdateLayeredWindow (MACDRV.@)
*/
@ -1148,12 +1193,15 @@ void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
const RECT *visible_rect, const RECT *valid_rects,
struct window_surface *surface)
{
struct macdrv_thread_data *thread_data;
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;
thread_data = macdrv_thread_data();
old_window_rect = data->window_rect;
old_whole_rect = data->whole_rect;
old_client_rect = data->client_rect;
@ -1224,8 +1272,14 @@ void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
show_window(data);
}
sync_window_position(data, swp_flags);
set_cocoa_window_properties(data);
/* check if we are currently processing an event relevant to this window */
if (!thread_data || !thread_data->current_event ||
thread_data->current_event->window != data->cocoa_window ||
thread_data->current_event->type != WINDOW_FRAME_CHANGED)
{
sync_window_position(data, swp_flags);
set_cocoa_window_properties(data);
}
done:
release_win_data(data);
@ -1279,3 +1333,55 @@ void macdrv_window_close_requested(HWND hwnd)
PostMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
}
}
/***********************************************************************
* macdrv_window_frame_changed
*
* Handler for WINDOW_FRAME_CHANGED events.
*/
void macdrv_window_frame_changed(HWND hwnd, CGRect frame)
{
struct macdrv_win_data *data;
RECT rect;
HWND parent;
UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
int width, height;
if (!hwnd) return;
if (!(data = get_win_data(hwnd))) return;
if (!data->on_screen) goto done;
/* Get geometry */
parent = GetAncestor(hwnd, GA_PARENT);
TRACE("win %p/%p new Cocoa frame %s\n", hwnd, data->cocoa_window, wine_dbgstr_cgrect(frame));
rect = rect_from_cgrect(frame);
macdrv_mac_to_window_rect(data, &rect);
MapWindowPoints(0, parent, (POINT *)&rect, 2);
width = rect.right - rect.left;
height = rect.bottom - rect.top;
if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
flags |= SWP_NOMOVE;
else
TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
data->window_rect.top, rect.left, rect.top);
if ((data->window_rect.right - data->window_rect.left == width &&
data->window_rect.bottom - data->window_rect.top == height) ||
(IsRectEmpty(&data->window_rect) && width <= 0 && height <= 0))
flags |= SWP_NOSIZE;
else
TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
data->window_rect.bottom - data->window_rect.top, width, height);
done:
release_win_data(data);
if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
}

View File

@ -15,6 +15,7 @@
@ cdecl SetWindowRgn(long long long) macdrv_SetWindowRgn
@ cdecl SetWindowStyle(ptr long ptr) macdrv_SetWindowStyle
@ cdecl SetWindowText(long wstr) macdrv_SetWindowText
@ cdecl ShowWindow(long long ptr long) macdrv_ShowWindow
@ cdecl UpdateLayeredWindow(long ptr ptr) macdrv_UpdateLayeredWindow
@ cdecl WindowMessage(long long long long) macdrv_WindowMessage
@ cdecl WindowPosChanged(long long long ptr ptr ptr ptr ptr) macdrv_WindowPosChanged