2 * MACDRV Cocoa status item class
4 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #import <Cocoa/Cocoa.h>
22 #include "macdrv_cocoa.h"
24 #import "cocoa_event.h"
27 @interface WineStatusItem : NSView
30 WineEventQueue* queue;
31 NSTrackingArea* trackingArea;
35 @property (retain, nonatomic) NSStatusItem* item;
36 @property (assign, nonatomic) WineEventQueue* queue;
37 @property (retain, nonatomic) NSImage* image;
42 @implementation WineStatusItem
44 @synthesize item, queue, image;
46 - (id) initWithEventQueue:(WineEventQueue*)inQueue
48 NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
49 CGFloat thickness = [statusBar thickness];
51 self = [super initWithFrame:NSMakeRect(0, 0, thickness, thickness)];
54 item = [[statusBar statusItemWithLength:NSSquareStatusItemLength] retain];
55 // This is a retain cycle which is broken in -removeFromStatusBar.
60 trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
61 options:NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect
64 [self addTrackingArea:trackingArea];
73 NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
74 [statusBar removeStatusItem:item];
78 [trackingArea release];
82 - (void) setImage:(NSImage*)inImage
87 image = [inImage retain];
88 [self setNeedsDisplay:YES];
92 - (void) removeFromStatusBar
96 NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
97 [statusBar removeStatusItem:item];
100 [queue discardEventsPassingTest:^BOOL (macdrv_event* event){
101 return ((event->type == STATUS_ITEM_MOUSE_BUTTON && event->status_item_mouse_button.item == (macdrv_status_item)self) ||
102 (event->type == STATUS_ITEM_MOUSE_MOVE && event->status_item_mouse_move.item == (macdrv_status_item)self));
109 - (void) postMouseButtonEvent:(NSEvent*)nsevent;
112 NSUInteger typeMask = NSEventMaskFromType([nsevent type]);
113 CGPoint point = CGEventGetLocation([nsevent CGEvent]);
115 point = cgpoint_win_from_mac(point);
117 event = macdrv_create_event(STATUS_ITEM_MOUSE_BUTTON, nil);
118 event->status_item_mouse_button.item = (macdrv_status_item)self;
119 event->status_item_mouse_button.button = [nsevent buttonNumber];
120 event->status_item_mouse_button.down = (typeMask & (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask)) != 0;
121 event->status_item_mouse_button.count = [nsevent clickCount];
122 event->status_item_mouse_button.x = floor(point.x);
123 event->status_item_mouse_button.y = floor(point.y);
124 [queue postEvent:event];
125 macdrv_release_event(event);
130 * ---------- NSView methods ----------
132 - (void) drawRect:(NSRect)rect
134 [item drawStatusBarBackgroundInRect:[self bounds] withHighlight:NO];
138 NSSize imageSize = [image size];
139 NSRect bounds = [self bounds];
140 NSPoint imageOrigin = NSMakePoint(NSMidX(bounds) - imageSize.width / 2,
141 NSMidY(bounds) - imageSize.height / 2);
143 imageOrigin = [self convertPointToBase:imageOrigin];
144 imageOrigin.x = floor(imageOrigin.x);
145 imageOrigin.y = floor(imageOrigin.y);
146 imageOrigin = [self convertPointFromBase:imageOrigin];
148 [image drawAtPoint:imageOrigin
150 operation:NSCompositeSourceOver
157 * ---------- NSResponder methods ----------
159 - (void) mouseDown:(NSEvent*)event
161 [self postMouseButtonEvent:event];
164 - (void) mouseDragged:(NSEvent*)event
166 [self mouseMoved:event];
169 - (void) mouseMoved:(NSEvent*)nsevent
172 CGPoint point = CGEventGetLocation([nsevent CGEvent]);
174 point = cgpoint_win_from_mac(point);
176 event = macdrv_create_event(STATUS_ITEM_MOUSE_MOVE, nil);
177 event->status_item_mouse_move.item = (macdrv_status_item)self;
178 event->status_item_mouse_move.x = floor(point.x);
179 event->status_item_mouse_move.y = floor(point.y);
180 [queue postEvent:event];
181 macdrv_release_event(event);
184 - (void) mouseUp:(NSEvent*)event
186 [self postMouseButtonEvent:event];
189 - (void) otherMouseDown:(NSEvent*)event
191 [self postMouseButtonEvent:event];
194 - (void) otherMouseDragged:(NSEvent*)event
196 [self mouseMoved:event];
199 - (void) otherMouseUp:(NSEvent*)event
201 [self postMouseButtonEvent:event];
204 - (void) rightMouseDown:(NSEvent*)event
206 [self postMouseButtonEvent:event];
209 - (void) rightMouseDragged:(NSEvent*)event
211 [self mouseMoved:event];
214 - (void) rightMouseUp:(NSEvent*)event
216 [self postMouseButtonEvent:event];
222 /***********************************************************************
223 * macdrv_create_status_item
225 * Creates a new status item in the status bar.
227 macdrv_status_item macdrv_create_status_item(macdrv_event_queue q)
229 WineEventQueue* queue = (WineEventQueue*)q;
230 __block WineStatusItem* statusItem;
233 statusItem = [[WineStatusItem alloc] initWithEventQueue:queue];
236 return (macdrv_status_item)statusItem;
239 /***********************************************************************
240 * macdrv_destroy_status_item
242 * Removes a status item previously returned by
243 * macdrv_create_status_item() from the status bar and destroys it.
245 void macdrv_destroy_status_item(macdrv_status_item s)
247 WineStatusItem* statusItem = (WineStatusItem*)s;
250 [statusItem removeFromStatusBar];
251 [statusItem release];
255 /***********************************************************************
256 * macdrv_set_status_item_image
258 * Sets the image for a status item. If cgimage is NULL, clears the
259 * image of the status item (leaving it a blank spot on the menu bar).
261 void macdrv_set_status_item_image(macdrv_status_item s, CGImageRef cgimage)
263 WineStatusItem* statusItem = (WineStatusItem*)s;
265 CGImageRetain(cgimage);
268 NSImage* image = nil;
272 CGFloat maxSize = [[NSStatusBar systemStatusBar] thickness];
273 BOOL changed = FALSE;
275 image = [[NSImage alloc] initWithCGImage:cgimage size:NSZeroSize];
276 CGImageRelease(cgimage);
278 while (size.width > maxSize || size.height > maxSize)
285 [image setSize:size];
287 statusItem.image = image;
292 /***********************************************************************
293 * macdrv_set_status_item_tooltip
295 * Sets the tooltip string for a status item. If cftip is NULL, clears
296 * the tooltip string for the status item.
298 void macdrv_set_status_item_tooltip(macdrv_status_item s, CFStringRef cftip)
300 WineStatusItem* statusItem = (WineStatusItem*)s;
301 NSString* tip = (NSString*)cftip;
303 if (![tip length]) tip = nil;
305 [statusItem setToolTip:tip];