Commit 7863a230 authored by Ken Thomases's avatar Ken Thomases Committed by Alexandre Julliard

winemac: Implement a WINDOW_GOT_FOCUS event for when Cocoa tries to focus a window.

parent beccf0f8
......@@ -27,6 +27,7 @@
@class WineEventQueue;
@class WineWindow;
@interface WineApplication : NSApplication <NSApplicationDelegate>
......@@ -37,6 +38,8 @@
NSTimeInterval eventTimeAdjustment;
NSMutableArray* keyWindows;
NSMutableSet* triedWindows;
unsigned long windowFocusSerial;
}
- (void) transformProcessToForeground;
......@@ -47,6 +50,8 @@
- (void) computeEventTimeAdjustmentFromTicks:(unsigned long long)tickcount uptime:(uint64_t)uptime_ns;
- (double) ticksForEventTime:(NSTimeInterval)eventTime;
- (void) windowGotFocus:(WineWindow*)window;
@end
void OnMainThread(dispatch_block_t block);
......
......@@ -19,6 +19,8 @@
*/
#import "cocoa_app.h"
#import "cocoa_event.h"
#import "cocoa_window.h"
int macdrv_err_on;
......@@ -121,10 +123,65 @@ int macdrv_err_on;
return (eventTime + eventTimeAdjustment) * 1000;
}
/* Invalidate old focus offers across all queues. */
- (void) invalidateGotFocusEvents
{
WineEventQueue* queue;
windowFocusSerial++;
[eventQueuesLock lock];
for (queue in eventQueues)
{
[queue discardEventsMatchingMask:event_mask_for_type(WINDOW_GOT_FOCUS)
forWindow:nil];
}
[eventQueuesLock unlock];
}
- (void) windowGotFocus:(WineWindow*)window
{
macdrv_event event;
[NSApp invalidateGotFocusEvents];
event.type = WINDOW_GOT_FOCUS;
event.window = (macdrv_window)[window retain];
event.window_got_focus.serial = windowFocusSerial;
if (triedWindows)
event.window_got_focus.tried_windows = [triedWindows retain];
else
event.window_got_focus.tried_windows = [[NSMutableSet alloc] init];
[window.queue postEvent:&event];
}
- (void) windowRejectedFocusEvent:(const macdrv_event*)event
{
if (event->window_got_focus.serial == windowFocusSerial)
{
triedWindows = (NSMutableSet*)event->window_got_focus.tried_windows;
[triedWindows addObject:(WineWindow*)event->window];
for (NSWindow* window in [keyWindows arrayByAddingObjectsFromArray:[self orderedWindows]])
{
if (![triedWindows containsObject:window] && [window canBecomeKeyWindow])
{
[window makeKeyWindow];
break;
}
}
triedWindows = nil;
}
}
/*
* ---------- NSApplicationDelegate methods ----------
*/
- (void)applicationDidResignActive:(NSNotification *)notification
{
[self invalidateGotFocusEvents];
}
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
......@@ -189,3 +246,16 @@ void LogErrorv(const char* func, NSString* format, va_list args)
fprintf(stderr, "err:%s:%s", func, [message UTF8String]);
[message release];
}
/***********************************************************************
* macdrv_window_rejected_focus
*
* Pass focus to the next window that hasn't already rejected this same
* WINDOW_GOT_FOCUS event.
*/
void macdrv_window_rejected_focus(const macdrv_event *event)
{
OnMainThread(^{
[NSApp windowRejectedFocusEvent:event];
});
}
......@@ -275,6 +275,13 @@ void macdrv_cleanup_event(macdrv_event *event)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
switch (event->type)
{
case WINDOW_GOT_FOCUS:
[(NSMutableSet*)event->window_got_focus.tried_windows release];
break;
}
[(WineWindow*)event->window release];
[pool release];
......
......@@ -49,4 +49,6 @@
BOOL causing_becomeKeyWindow;
}
@property (retain, readonly, nonatomic) WineEventQueue* queue;
@end
......@@ -67,7 +67,7 @@ static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
@property (retain, nonatomic) NSWindow* latentParentWindow;
@property (nonatomic) void* hwnd;
@property (retain, nonatomic) WineEventQueue* queue;
@property (retain, readwrite, nonatomic) WineEventQueue* queue;
@property (nonatomic) void* surface;
@property (nonatomic) pthread_mutex_t* surface_mutex;
......@@ -505,6 +505,29 @@ static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
return [super validateMenuItem:menuItem];
}
/* We don't call this. It's the action method of the items in the Window menu. */
- (void) makeKeyAndOrderFront:(id)sender
{
if (![self isKeyWindow] && !self.disabled && !self.noActivate)
[NSApp windowGotFocus:self];
}
- (void) sendEvent:(NSEvent*)event
{
if ([event type] == NSLeftMouseDown)
{
/* Since our windows generally claim they can't be made key, clicks
in their title bars are swallowed by the theme frame stuff. So,
we hook directly into the event stream and assume that any click
in the window will activate it, if Wine and the Win32 program
accept. */
if (![self isKeyWindow] && !self.disabled && !self.noActivate)
[NSApp windowGotFocus:self];
}
[super sendEvent:event];
}
/*
* ---------- NSResponder method overrides ----------
......@@ -521,6 +544,13 @@ static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
/*
* ---------- NSWindowDelegate methods ----------
*/
- (void)windowDidBecomeKey:(NSNotification *)notification
{
if (causing_becomeKeyWindow) return;
[NSApp windowGotFocus:self];
}
- (void)windowDidMove:(NSNotification *)notification
{
[self windowDidResize:notification];
......
......@@ -35,6 +35,7 @@ static const char *dbgstr_event(int type)
"MOUSE_BUTTON",
"WINDOW_CLOSE_REQUESTED",
"WINDOW_FRAME_CHANGED",
"WINDOW_GOT_FOCUS",
};
if (0 <= type && type < NUM_EVENT_TYPES) return event_names[type];
......@@ -58,6 +59,7 @@ static macdrv_event_mask get_event_mask(DWORD mask)
{
event_mask |= event_mask_for_type(WINDOW_CLOSE_REQUESTED);
event_mask |= event_mask_for_type(WINDOW_FRAME_CHANGED);
event_mask |= event_mask_for_type(WINDOW_GOT_FOCUS);
}
return event_mask;
......@@ -90,6 +92,9 @@ void macdrv_handle_event(macdrv_event *event)
case WINDOW_FRAME_CHANGED:
macdrv_window_frame_changed(hwnd, event->window_frame_changed.frame);
break;
case WINDOW_GOT_FOCUS:
macdrv_window_got_focus(hwnd, event);
break;
default:
TRACE(" ignoring\n");
break;
......
......@@ -119,6 +119,7 @@ extern void set_surface_use_alpha(struct window_surface *window_surface, BOOL us
extern void macdrv_window_close_requested(HWND hwnd) DECLSPEC_HIDDEN;
extern void macdrv_window_frame_changed(HWND hwnd, CGRect frame) DECLSPEC_HIDDEN;
extern void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN;
extern void macdrv_mouse_button(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN;
......
......@@ -101,6 +101,7 @@
typedef struct macdrv_opaque_window* macdrv_window;
typedef struct macdrv_opaque_event_queue* macdrv_event_queue;
struct macdrv_event;
struct macdrv_display {
CGDirectDisplayID displayID;
......@@ -113,6 +114,7 @@ struct macdrv_display {
extern int macdrv_err_on;
extern int macdrv_start_cocoa_app(unsigned long long tickcount) DECLSPEC_HIDDEN;
extern void macdrv_window_rejected_focus(const struct macdrv_event *event) DECLSPEC_HIDDEN;
/* display */
......@@ -125,6 +127,7 @@ enum {
MOUSE_BUTTON,
WINDOW_CLOSE_REQUESTED,
WINDOW_FRAME_CHANGED,
WINDOW_GOT_FOCUS,
NUM_EVENT_TYPES
};
......@@ -144,6 +147,10 @@ typedef struct macdrv_event {
struct {
CGRect frame;
} window_frame_changed;
struct {
unsigned long serial;
void *tried_windows;
} window_got_focus;
};
} macdrv_event;
......
......@@ -1419,3 +1419,37 @@ done:
if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
}
/***********************************************************************
* macdrv_window_got_focus
*
* Handler for WINDOW_GOT_FOCUS events.
*/
void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
{
if (!hwnd) return;
TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE), GetFocus(),
GetActiveWindow(), GetForegroundWindow());
if (can_activate_window(hwnd))
{
/* simulate a mouse click on the caption to find out
* whether the window wants to be activated */
LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
(WPARAM)GetAncestor(hwnd, GA_ROOT),
MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
{
TRACE("setting foreground window to %p\n", hwnd);
SetForegroundWindow(hwnd);
return;
}
}
TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
macdrv_window_rejected_focus(event);
}
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