winemac: Add support for mouse-move and right- and middle-click events on systray icons in the Mac status bar.
This commit is contained in:
parent
ee771fddaa
commit
7ed00f6d97
|
@ -24,34 +24,44 @@
|
|||
#import "cocoa_event.h"
|
||||
|
||||
|
||||
@interface WineStatusItem : NSObject
|
||||
@interface WineStatusItem : NSView
|
||||
{
|
||||
NSStatusItem* item;
|
||||
WineEventQueue* queue;
|
||||
NSTrackingArea* trackingArea;
|
||||
NSImage* image;
|
||||
}
|
||||
|
||||
@property (retain, nonatomic) NSStatusItem* item;
|
||||
@property (assign, nonatomic) WineEventQueue* queue;
|
||||
@property (retain, nonatomic) NSImage* image;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation WineStatusItem
|
||||
|
||||
@synthesize item, queue;
|
||||
@synthesize item, queue, image;
|
||||
|
||||
- (id) initWithEventQueue:(WineEventQueue*)inQueue
|
||||
{
|
||||
self = [super init];
|
||||
NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
|
||||
CGFloat thickness = [statusBar thickness];
|
||||
|
||||
self = [super initWithFrame:NSMakeRect(0, 0, thickness, thickness)];
|
||||
if (self)
|
||||
{
|
||||
NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
|
||||
item = [[statusBar statusItemWithLength:NSSquareStatusItemLength] retain];
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(clicked:)];
|
||||
[item setDoubleAction:@selector(doubleClicked:)];
|
||||
// This is a retain cycle which is broken in -removeFromStatusBar.
|
||||
[item setView:self];
|
||||
|
||||
queue = inQueue;
|
||||
|
||||
trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
|
||||
options:NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:trackingArea];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -64,37 +74,129 @@ - (void) dealloc
|
|||
[statusBar removeStatusItem:item];
|
||||
[item release];
|
||||
}
|
||||
[image release];
|
||||
[trackingArea release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) setImage:(NSImage*)inImage
|
||||
{
|
||||
if (image != inImage)
|
||||
{
|
||||
[image release];
|
||||
image = [inImage retain];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) removeFromStatusBar
|
||||
{
|
||||
if (item)
|
||||
{
|
||||
NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
|
||||
[statusBar removeStatusItem:item];
|
||||
[item setView:nil];
|
||||
self.item = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) postClickedEventWithCount:(int)count
|
||||
- (void) postMouseButtonEvent:(NSEvent*)nsevent;
|
||||
{
|
||||
macdrv_event* event;
|
||||
event = macdrv_create_event(STATUS_ITEM_CLICKED, nil);
|
||||
event->status_item_clicked.item = (macdrv_status_item)self;
|
||||
event->status_item_clicked.count = count;
|
||||
NSUInteger typeMask = NSEventMaskFromType([nsevent type]);
|
||||
|
||||
event = macdrv_create_event(STATUS_ITEM_MOUSE_BUTTON, nil);
|
||||
event->status_item_mouse_button.item = (macdrv_status_item)self;
|
||||
event->status_item_mouse_button.button = [nsevent buttonNumber];
|
||||
event->status_item_mouse_button.down = (typeMask & (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask)) != 0;
|
||||
event->status_item_mouse_button.count = [nsevent clickCount];
|
||||
[queue postEvent:event];
|
||||
macdrv_release_event(event);
|
||||
}
|
||||
|
||||
- (void) clicked:(id)sender
|
||||
|
||||
/*
|
||||
* ---------- NSView methods ----------
|
||||
*/
|
||||
- (void) drawRect:(NSRect)rect
|
||||
{
|
||||
[self postClickedEventWithCount:1];
|
||||
[item drawStatusBarBackgroundInRect:[self bounds] withHighlight:NO];
|
||||
|
||||
if (image)
|
||||
{
|
||||
NSSize imageSize = [image size];
|
||||
NSRect bounds = [self bounds];
|
||||
NSPoint imageOrigin = NSMakePoint(NSMidX(bounds) - imageSize.width / 2,
|
||||
NSMidY(bounds) - imageSize.height / 2);
|
||||
|
||||
imageOrigin = [self convertPointToBase:imageOrigin];
|
||||
imageOrigin.x = floor(imageOrigin.x);
|
||||
imageOrigin.y = floor(imageOrigin.y);
|
||||
imageOrigin = [self convertPointFromBase:imageOrigin];
|
||||
|
||||
[image drawAtPoint:imageOrigin
|
||||
fromRect:NSZeroRect
|
||||
operation:NSCompositeSourceOver
|
||||
fraction:1];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) doubleClicked:(id)sender
|
||||
|
||||
/*
|
||||
* ---------- NSResponder methods ----------
|
||||
*/
|
||||
- (void) mouseDown:(NSEvent*)event
|
||||
{
|
||||
[self postClickedEventWithCount:2];
|
||||
[self postMouseButtonEvent:event];
|
||||
}
|
||||
|
||||
- (void) mouseDragged:(NSEvent*)event
|
||||
{
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void) mouseMoved:(NSEvent*)nsevent
|
||||
{
|
||||
macdrv_event* event;
|
||||
event = macdrv_create_event(STATUS_ITEM_MOUSE_MOVE, nil);
|
||||
event->status_item_mouse_move.item = (macdrv_status_item)self;
|
||||
[queue postEvent:event];
|
||||
macdrv_release_event(event);
|
||||
}
|
||||
|
||||
- (void) mouseUp:(NSEvent*)event
|
||||
{
|
||||
[self postMouseButtonEvent:event];
|
||||
}
|
||||
|
||||
- (void) otherMouseDown:(NSEvent*)event
|
||||
{
|
||||
[self postMouseButtonEvent:event];
|
||||
}
|
||||
|
||||
- (void) otherMouseDragged:(NSEvent*)event
|
||||
{
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void) otherMouseUp:(NSEvent*)event
|
||||
{
|
||||
[self postMouseButtonEvent:event];
|
||||
}
|
||||
|
||||
- (void) rightMouseDown:(NSEvent*)event
|
||||
{
|
||||
[self postMouseButtonEvent:event];
|
||||
}
|
||||
|
||||
- (void) rightMouseDragged:(NSEvent*)event
|
||||
{
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void) rightMouseUp:(NSEvent*)event
|
||||
{
|
||||
[self postMouseButtonEvent:event];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -165,7 +267,7 @@ void macdrv_set_status_item_image(macdrv_status_item s, CGImageRef cgimage)
|
|||
if (changed)
|
||||
[image setSize:size];
|
||||
}
|
||||
[statusItem.item setImage:image];
|
||||
statusItem.image = image;
|
||||
[image release];
|
||||
});
|
||||
}
|
||||
|
@ -183,6 +285,6 @@ void macdrv_set_status_item_tooltip(macdrv_status_item s, CFStringRef cftip)
|
|||
|
||||
if (![tip length]) tip = nil;
|
||||
OnMainThreadAsync(^{
|
||||
[statusItem.item setToolTip:tip];
|
||||
[statusItem setToolTip:tip];
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,7 +45,8 @@ static const char *dbgstr_event(int type)
|
|||
"MOUSE_SCROLL",
|
||||
"QUERY_EVENT",
|
||||
"RELEASE_CAPTURE",
|
||||
"STATUS_ITEM_CLICKED",
|
||||
"STATUS_ITEM_MOUSE_BUTTON",
|
||||
"STATUS_ITEM_MOUSE_MOVE",
|
||||
"WINDOW_CLOSE_REQUESTED",
|
||||
"WINDOW_DID_MINIMIZE",
|
||||
"WINDOW_DID_UNMINIMIZE",
|
||||
|
@ -93,7 +94,8 @@ static macdrv_event_mask get_event_mask(DWORD mask)
|
|||
event_mask |= event_mask_for_type(APP_QUIT_REQUESTED);
|
||||
event_mask |= event_mask_for_type(DISPLAYS_CHANGED);
|
||||
event_mask |= event_mask_for_type(IM_SET_TEXT);
|
||||
event_mask |= event_mask_for_type(STATUS_ITEM_CLICKED);
|
||||
event_mask |= event_mask_for_type(STATUS_ITEM_MOUSE_BUTTON);
|
||||
event_mask |= event_mask_for_type(STATUS_ITEM_MOUSE_MOVE);
|
||||
event_mask |= event_mask_for_type(WINDOW_CLOSE_REQUESTED);
|
||||
event_mask |= event_mask_for_type(WINDOW_DID_MINIMIZE);
|
||||
event_mask |= event_mask_for_type(WINDOW_DID_UNMINIMIZE);
|
||||
|
@ -207,8 +209,11 @@ void macdrv_handle_event(const macdrv_event *event)
|
|||
case RELEASE_CAPTURE:
|
||||
macdrv_release_capture(hwnd, event);
|
||||
break;
|
||||
case STATUS_ITEM_CLICKED:
|
||||
macdrv_status_item_clicked(event);
|
||||
case STATUS_ITEM_MOUSE_BUTTON:
|
||||
macdrv_status_item_mouse_button(event);
|
||||
break;
|
||||
case STATUS_ITEM_MOUSE_MOVE:
|
||||
macdrv_status_item_mouse_move(event);
|
||||
break;
|
||||
case WINDOW_CLOSE_REQUESTED:
|
||||
macdrv_window_close_requested(hwnd);
|
||||
|
|
|
@ -195,7 +195,8 @@ extern CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP
|
|||
extern CGImageRef create_cgimage_from_icon(HANDLE icon, int width, int height) DECLSPEC_HIDDEN;
|
||||
extern CFArrayRef create_app_icon_images(void) DECLSPEC_HIDDEN;
|
||||
|
||||
extern void macdrv_status_item_clicked(const macdrv_event *event) DECLSPEC_HIDDEN;
|
||||
extern void macdrv_status_item_mouse_button(const macdrv_event *event) DECLSPEC_HIDDEN;
|
||||
extern void macdrv_status_item_mouse_move(const macdrv_event *event) DECLSPEC_HIDDEN;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
|
|
|
@ -176,7 +176,8 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display,
|
|||
MOUSE_SCROLL,
|
||||
QUERY_EVENT,
|
||||
RELEASE_CAPTURE,
|
||||
STATUS_ITEM_CLICKED,
|
||||
STATUS_ITEM_MOUSE_BUTTON,
|
||||
STATUS_ITEM_MOUSE_MOVE,
|
||||
WINDOW_CLOSE_REQUESTED,
|
||||
WINDOW_DID_MINIMIZE,
|
||||
WINDOW_DID_UNMINIMIZE,
|
||||
|
@ -248,8 +249,13 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display,
|
|||
} query_event;
|
||||
struct {
|
||||
macdrv_status_item item;
|
||||
int button;
|
||||
int down;
|
||||
int count;
|
||||
} status_item_clicked;
|
||||
} status_item_mouse_button;
|
||||
struct {
|
||||
macdrv_status_item item;
|
||||
} status_item_mouse_move;
|
||||
struct {
|
||||
CGRect frame;
|
||||
} window_frame_changed;
|
||||
|
|
|
@ -308,22 +308,38 @@ int CDECL wine_notify_icon(DWORD msg, NOTIFYICONDATAW *data)
|
|||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_status_item_clicked
|
||||
* macdrv_status_item_mouse_button
|
||||
*
|
||||
* Handle STATUS_ITEM_CLICKED events.
|
||||
* Handle STATUS_ITEM_MOUSE_BUTTON events.
|
||||
*/
|
||||
void macdrv_status_item_clicked(const macdrv_event *event)
|
||||
void macdrv_status_item_mouse_button(const macdrv_event *event)
|
||||
{
|
||||
struct tray_icon *icon;
|
||||
|
||||
TRACE("item %p count %d\n", event->status_item_clicked.item,
|
||||
event->status_item_clicked.count);
|
||||
TRACE("item %p button %d down %d count %d\n", event->status_item_mouse_button.item,
|
||||
event->status_item_mouse_button.button, event->status_item_mouse_button.down,
|
||||
event->status_item_mouse_button.count);
|
||||
|
||||
LIST_FOR_EACH_ENTRY(icon, &icon_list, struct tray_icon, entry)
|
||||
{
|
||||
if (icon->status_item == event->status_item_clicked.item)
|
||||
if (icon->status_item == event->status_item_mouse_button.item)
|
||||
{
|
||||
UINT down;
|
||||
UINT msg;
|
||||
|
||||
switch (event->status_item_mouse_button.button)
|
||||
{
|
||||
case 0: msg = WM_LBUTTONDOWN; break;
|
||||
case 1: msg = WM_RBUTTONDOWN; break;
|
||||
case 2: msg = WM_MBUTTONDOWN; break;
|
||||
default:
|
||||
TRACE("ignoring button beyond the third\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!event->status_item_mouse_button.down)
|
||||
msg += WM_LBUTTONUP - WM_LBUTTONDOWN;
|
||||
else if (event->status_item_mouse_button.count % 2 == 0)
|
||||
msg += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
|
||||
|
||||
if (!SendMessageW(icon->owner, WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS, 0, 0) &&
|
||||
GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
|
||||
|
@ -333,18 +349,8 @@ void macdrv_status_item_clicked(const macdrv_event *event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (event->status_item_clicked.count == 1)
|
||||
{
|
||||
down = WM_LBUTTONDOWN;
|
||||
TRACE("posting WM_LBUTTONDOWN to hwnd %p id 0x%x\n", icon->owner, icon->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
down = WM_LBUTTONDBLCLK;
|
||||
TRACE("posting WM_LBUTTONDBLCLK to hwnd %p id 0x%x\n", icon->owner, icon->id);
|
||||
}
|
||||
|
||||
if (!PostMessageW(icon->owner, icon->callback_message, icon->id, down) &&
|
||||
TRACE("posting msg 0x%04x to hwnd %p id 0x%x\n", msg, icon->owner, icon->id);
|
||||
if (!PostMessageW(icon->owner, icon->callback_message, icon->id, msg) &&
|
||||
GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
|
||||
{
|
||||
WARN("window %p was destroyed, removing icon 0x%x\n", icon->owner, icon->id);
|
||||
|
@ -352,12 +358,33 @@ void macdrv_status_item_clicked(const macdrv_event *event)
|
|||
return;
|
||||
}
|
||||
|
||||
TRACE("posting WM_LBUTTONUP to hwnd %p id 0x%x\n", icon->owner, icon->id);
|
||||
if (!PostMessageW(icon->owner, icon->callback_message, icon->id, WM_LBUTTONUP) &&
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_status_item_mouse_move
|
||||
*
|
||||
* Handle STATUS_ITEM_MOUSE_MOVE events.
|
||||
*/
|
||||
void macdrv_status_item_mouse_move(const macdrv_event *event)
|
||||
{
|
||||
struct tray_icon *icon;
|
||||
|
||||
TRACE("item %p\n", event->status_item_mouse_move.item);
|
||||
|
||||
LIST_FOR_EACH_ENTRY(icon, &icon_list, struct tray_icon, entry)
|
||||
{
|
||||
if (icon->status_item == event->status_item_mouse_move.item)
|
||||
{
|
||||
if (!PostMessageW(icon->owner, icon->callback_message, icon->id, WM_MOUSEMOVE) &&
|
||||
GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
|
||||
{
|
||||
WARN("window %p was destroyed, removing icon 0x%x\n", icon->owner, icon->id);
|
||||
delete_icon(icon);
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue