winemac: Implement a WINDOW_GOT_FOCUS event for when Cocoa tries to focus a window.
This commit is contained in:
parent
beccf0f8c0
commit
7863a230ec
|
@ -27,6 +27,7 @@
|
|||
|
||||
|
||||
@class WineEventQueue;
|
||||
@class WineWindow;
|
||||
|
||||
|
||||
@interface WineApplication : NSApplication <NSApplicationDelegate>
|
||||
|
@ -37,6 +38,8 @@ @interface WineApplication : NSApplication <NSApplicationDelegate>
|
|||
NSTimeInterval eventTimeAdjustment;
|
||||
|
||||
NSMutableArray* keyWindows;
|
||||
NSMutableSet* triedWindows;
|
||||
unsigned long windowFocusSerial;
|
||||
}
|
||||
|
||||
- (void) transformProcessToForeground;
|
||||
|
@ -47,6 +50,8 @@ - (void) unregisterEventQueue:(WineEventQueue*)queue;
|
|||
- (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 @@ - (double) ticksForEventTime:(NSTimeInterval)eventTime
|
|||
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 @@ @interface WineWindow : NSPanel <NSWindowDelegate>
|
|||
BOOL causing_becomeKeyWindow;
|
||||
}
|
||||
|
||||
@property (retain, readonly, nonatomic) WineEventQueue* queue;
|
||||
|
||||
@end
|
||||
|
|
|
@ -67,7 +67,7 @@ @interface WineWindow ()
|
|||
@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 @@ - (BOOL) validateMenuItem:(NSMenuItem *)menuItem
|
|||
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 @@ - (void) otherMouseUp:(NSEvent *)theEvent { [self mouseUp:theEvent]; }
|
|||
/*
|
||||
* ---------- 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 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
|
|||
|
||||
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 @@
|
|||
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 @@
|
|||
MOUSE_BUTTON,
|
||||
WINDOW_CLOSE_REQUESTED,
|
||||
WINDOW_FRAME_CHANGED,
|
||||
WINDOW_GOT_FOCUS,
|
||||
NUM_EVENT_TYPES
|
||||
};
|
||||
|
||||
|
@ -144,6 +147,10 @@
|
|||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue