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 & (NSEventMaskLeftMouseDown |
121 NSEventMaskRightMouseDown |
122 NSEventMaskOtherMouseDown)) != 0;
123 event->status_item_mouse_button.count = [nsevent clickCount];
124 event->status_item_mouse_button.x = floor(point.x);
125 event->status_item_mouse_button.y = floor(point.y);
126 [queue postEvent:event];
127 macdrv_release_event(event);
132 * ---------- NSView methods ----------
134 - (void) drawRect:(NSRect)rect
136 [item drawStatusBarBackgroundInRect:[self bounds] withHighlight:NO];
140 NSSize imageSize = [image size];
141 NSRect bounds = [self bounds];
142 NSPoint imageOrigin = NSMakePoint(NSMidX(bounds) - imageSize.width / 2,
143 NSMidY(bounds) - imageSize.height / 2);
145 imageOrigin = [self convertPointToBase:imageOrigin];
146 imageOrigin.x = floor(imageOrigin.x);
147 imageOrigin.y = floor(imageOrigin.y);
148 imageOrigin = [self convertPointFromBase:imageOrigin];
150 [image drawAtPoint:imageOrigin
152 operation:NSCompositingOperationSourceOver
159 * ---------- NSResponder methods ----------
161 - (void) mouseDown:(NSEvent*)event
163 [self postMouseButtonEvent:event];
166 - (void) mouseDragged:(NSEvent*)event
168 [self mouseMoved:event];
171 - (void) mouseMoved:(NSEvent*)nsevent
174 CGPoint point = CGEventGetLocation([nsevent CGEvent]);
176 point = cgpoint_win_from_mac(point);
178 event = macdrv_create_event(STATUS_ITEM_MOUSE_MOVE, nil);
179 event->status_item_mouse_move.item = (macdrv_status_item)self;
180 event->status_item_mouse_move.x = floor(point.x);
181 event->status_item_mouse_move.y = floor(point.y);
182 [queue postEvent:event];
183 macdrv_release_event(event);
186 - (void) mouseUp:(NSEvent*)event
188 [self postMouseButtonEvent:event];
191 - (void) otherMouseDown:(NSEvent*)event
193 [self postMouseButtonEvent:event];
196 - (void) otherMouseDragged:(NSEvent*)event
198 [self mouseMoved:event];
201 - (void) otherMouseUp:(NSEvent*)event
203 [self postMouseButtonEvent:event];
206 - (void) rightMouseDown:(NSEvent*)event
208 [self postMouseButtonEvent:event];
211 - (void) rightMouseDragged:(NSEvent*)event
213 [self mouseMoved:event];
216 - (void) rightMouseUp:(NSEvent*)event
218 [self postMouseButtonEvent:event];
224 /***********************************************************************
225 * macdrv_create_status_item
227 * Creates a new status item in the status bar.
229 macdrv_status_item macdrv_create_status_item(macdrv_event_queue q)
231 WineEventQueue* queue = (WineEventQueue*)q;
232 __block WineStatusItem* statusItem;
235 statusItem = [[WineStatusItem alloc] initWithEventQueue:queue];
238 return (macdrv_status_item)statusItem;
241 /***********************************************************************
242 * macdrv_destroy_status_item
244 * Removes a status item previously returned by
245 * macdrv_create_status_item() from the status bar and destroys it.
247 void macdrv_destroy_status_item(macdrv_status_item s)
249 WineStatusItem* statusItem = (WineStatusItem*)s;
252 [statusItem removeFromStatusBar];
253 [statusItem release];
257 /***********************************************************************
258 * macdrv_set_status_item_image
260 * Sets the image for a status item. If cgimage is NULL, clears the
261 * image of the status item (leaving it a blank spot on the menu bar).
263 void macdrv_set_status_item_image(macdrv_status_item s, CGImageRef cgimage)
265 WineStatusItem* statusItem = (WineStatusItem*)s;
267 CGImageRetain(cgimage);
270 NSImage* image = nil;
274 CGFloat maxSize = [[NSStatusBar systemStatusBar] thickness];
275 BOOL changed = FALSE;
277 image = [[NSImage alloc] initWithCGImage:cgimage size:NSZeroSize];
278 CGImageRelease(cgimage);
280 while (size.width > maxSize || size.height > maxSize)
287 [image setSize:size];
289 statusItem.image = image;
294 /***********************************************************************
295 * macdrv_set_status_item_tooltip
297 * Sets the tooltip string for a status item. If cftip is NULL, clears
298 * the tooltip string for the status item.
300 void macdrv_set_status_item_tooltip(macdrv_status_item s, CFStringRef cftip)
302 WineStatusItem* statusItem = (WineStatusItem*)s;
303 NSString* tip = (NSString*)cftip;
305 if (![tip length]) tip = nil;
307 [statusItem setToolTip:tip];