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]);
114 event = macdrv_create_event(STATUS_ITEM_MOUSE_BUTTON, nil);
115 event->status_item_mouse_button.item = (macdrv_status_item)self;
116 event->status_item_mouse_button.button = [nsevent buttonNumber];
117 event->status_item_mouse_button.down = (typeMask & (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask)) != 0;
118 event->status_item_mouse_button.count = [nsevent clickCount];
119 [queue postEvent:event];
120 macdrv_release_event(event);
125 * ---------- NSView methods ----------
127 - (void) drawRect:(NSRect)rect
129 [item drawStatusBarBackgroundInRect:[self bounds] withHighlight:NO];
133 NSSize imageSize = [image size];
134 NSRect bounds = [self bounds];
135 NSPoint imageOrigin = NSMakePoint(NSMidX(bounds) - imageSize.width / 2,
136 NSMidY(bounds) - imageSize.height / 2);
138 imageOrigin = [self convertPointToBase:imageOrigin];
139 imageOrigin.x = floor(imageOrigin.x);
140 imageOrigin.y = floor(imageOrigin.y);
141 imageOrigin = [self convertPointFromBase:imageOrigin];
143 [image drawAtPoint:imageOrigin
145 operation:NSCompositeSourceOver
152 * ---------- NSResponder methods ----------
154 - (void) mouseDown:(NSEvent*)event
156 [self postMouseButtonEvent:event];
159 - (void) mouseDragged:(NSEvent*)event
161 [self mouseMoved:event];
164 - (void) mouseMoved:(NSEvent*)nsevent
167 event = macdrv_create_event(STATUS_ITEM_MOUSE_MOVE, nil);
168 event->status_item_mouse_move.item = (macdrv_status_item)self;
169 [queue postEvent:event];
170 macdrv_release_event(event);
173 - (void) mouseUp:(NSEvent*)event
175 [self postMouseButtonEvent:event];
178 - (void) otherMouseDown:(NSEvent*)event
180 [self postMouseButtonEvent:event];
183 - (void) otherMouseDragged:(NSEvent*)event
185 [self mouseMoved:event];
188 - (void) otherMouseUp:(NSEvent*)event
190 [self postMouseButtonEvent:event];
193 - (void) rightMouseDown:(NSEvent*)event
195 [self postMouseButtonEvent:event];
198 - (void) rightMouseDragged:(NSEvent*)event
200 [self mouseMoved:event];
203 - (void) rightMouseUp:(NSEvent*)event
205 [self postMouseButtonEvent:event];
211 /***********************************************************************
212 * macdrv_create_status_item
214 * Creates a new status item in the status bar.
216 macdrv_status_item macdrv_create_status_item(macdrv_event_queue q)
218 WineEventQueue* queue = (WineEventQueue*)q;
219 __block WineStatusItem* statusItem;
222 statusItem = [[WineStatusItem alloc] initWithEventQueue:queue];
225 return (macdrv_status_item)statusItem;
228 /***********************************************************************
229 * macdrv_destroy_status_item
231 * Removes a status item previously returned by
232 * macdrv_create_status_item() from the status bar and destroys it.
234 void macdrv_destroy_status_item(macdrv_status_item s)
236 WineStatusItem* statusItem = (WineStatusItem*)s;
239 [statusItem removeFromStatusBar];
240 [statusItem release];
244 /***********************************************************************
245 * macdrv_set_status_item_image
247 * Sets the image for a status item. If cgimage is NULL, clears the
248 * image of the status item (leaving it a blank spot on the menu bar).
250 void macdrv_set_status_item_image(macdrv_status_item s, CGImageRef cgimage)
252 WineStatusItem* statusItem = (WineStatusItem*)s;
254 CGImageRetain(cgimage);
257 NSImage* image = nil;
261 CGFloat maxSize = [[NSStatusBar systemStatusBar] thickness];
262 BOOL changed = FALSE;
264 image = [[NSImage alloc] initWithCGImage:cgimage size:NSZeroSize];
265 CGImageRelease(cgimage);
267 while (size.width > maxSize || size.height > maxSize)
274 [image setSize:size];
276 statusItem.image = image;
281 /***********************************************************************
282 * macdrv_set_status_item_tooltip
284 * Sets the tooltip string for a status item. If cftip is NULL, clears
285 * the tooltip string for the status item.
287 void macdrv_set_status_item_tooltip(macdrv_status_item s, CFStringRef cftip)
289 WineStatusItem* statusItem = (WineStatusItem*)s;
290 NSString* tip = (NSString*)cftip;
292 if (![tip length]) tip = nil;
294 [statusItem setToolTip:tip];