TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / winemac.drv / cocoa_status_item.m
blobc38dc51a93db6faacea9606724d8c87deb9dc6c4
1 /*
2  * MACDRV Cocoa status item class
3  *
4  * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
5  *
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.
10  *
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.
15  *
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
19  */
21 #import <Cocoa/Cocoa.h>
22 #include "macdrv_cocoa.h"
23 #import "cocoa_app.h"
24 #import "cocoa_event.h"
27 @interface WineStatusItem : NSView
29     NSStatusItem* item;
30     WineEventQueue* queue;
31     NSTrackingArea* trackingArea;
32     NSImage* image;
35 @property (retain, nonatomic) NSStatusItem* item;
36 @property (assign, nonatomic) WineEventQueue* queue;
37 @property (retain, nonatomic) NSImage* image;
39 @end
42 @implementation WineStatusItem
44 @synthesize item, queue, image;
46     - (id) initWithEventQueue:(WineEventQueue*)inQueue
47     {
48         NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
49         CGFloat thickness = [statusBar thickness];
51         self = [super initWithFrame:NSMakeRect(0, 0, thickness, thickness)];
52         if (self)
53         {
54             item = [[statusBar statusItemWithLength:NSSquareStatusItemLength] retain];
55             // This is a retain cycle which is broken in -removeFromStatusBar.
56             [item setView:self];
58             queue = inQueue;
60             trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
61                                                         options:NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect
62                                                           owner:self
63                                                        userInfo:nil];
64             [self addTrackingArea:trackingArea];
65         }
66         return self;
67     }
69     - (void) dealloc
70     {
71         if (item)
72         {
73             NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
74             [statusBar removeStatusItem:item];
75             [item release];
76         }
77         [image release];
78         [trackingArea release];
79         [super dealloc];
80     }
82     - (void) setImage:(NSImage*)inImage
83     {
84         if (image != inImage)
85         {
86             [image release];
87             image = [inImage retain];
88             [self setNeedsDisplay:YES];
89         }
90     }
92     - (void) removeFromStatusBar
93     {
94         if (item)
95         {
96             NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
97             [statusBar removeStatusItem:item];
98             [item setView:nil];
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));
103             }];
105             self.item = nil;
106         }
107     }
109     - (void) postMouseButtonEvent:(NSEvent*)nsevent;
110     {
111         macdrv_event* event;
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);
121     }
124     /*
125      * ---------- NSView methods ----------
126      */
127     - (void) drawRect:(NSRect)rect
128     {
129         [item drawStatusBarBackgroundInRect:[self bounds] withHighlight:NO];
131         if (image)
132         {
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
144                       fromRect:NSZeroRect
145                      operation:NSCompositeSourceOver
146                       fraction:1];
147         }
148     }
151     /*
152      * ---------- NSResponder methods ----------
153      */
154     - (void) mouseDown:(NSEvent*)event
155     {
156         [self postMouseButtonEvent:event];
157     }
159     - (void) mouseDragged:(NSEvent*)event
160     {
161         [self mouseMoved:event];
162     }
164     - (void) mouseMoved:(NSEvent*)nsevent
165     {
166         macdrv_event* event;
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);
171     }
173     - (void) mouseUp:(NSEvent*)event
174     {
175         [self postMouseButtonEvent:event];
176     }
178     - (void) otherMouseDown:(NSEvent*)event
179     {
180         [self postMouseButtonEvent:event];
181     }
183     - (void) otherMouseDragged:(NSEvent*)event
184     {
185         [self mouseMoved:event];
186     }
188     - (void) otherMouseUp:(NSEvent*)event
189     {
190         [self postMouseButtonEvent:event];
191     }
193     - (void) rightMouseDown:(NSEvent*)event
194     {
195         [self postMouseButtonEvent:event];
196     }
198     - (void) rightMouseDragged:(NSEvent*)event
199     {
200         [self mouseMoved:event];
201     }
203     - (void) rightMouseUp:(NSEvent*)event
204     {
205         [self postMouseButtonEvent:event];
206     }
208 @end
211 /***********************************************************************
212  *              macdrv_create_status_item
214  * Creates a new status item in the status bar.
215  */
216 macdrv_status_item macdrv_create_status_item(macdrv_event_queue q)
218     WineEventQueue* queue = (WineEventQueue*)q;
219     __block WineStatusItem* statusItem;
221     OnMainThread(^{
222         statusItem = [[WineStatusItem alloc] initWithEventQueue:queue];
223     });
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.
233  */
234 void macdrv_destroy_status_item(macdrv_status_item s)
236     WineStatusItem* statusItem = (WineStatusItem*)s;
238     OnMainThreadAsync(^{
239         [statusItem removeFromStatusBar];
240         [statusItem release];
241     });
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).
249  */
250 void macdrv_set_status_item_image(macdrv_status_item s, CGImageRef cgimage)
252     WineStatusItem* statusItem = (WineStatusItem*)s;
254     CGImageRetain(cgimage);
256     OnMainThreadAsync(^{
257         NSImage* image = nil;
258         if (cgimage)
259         {
260             NSSize size;
261             CGFloat maxSize = [[NSStatusBar systemStatusBar] thickness];
262             BOOL changed = FALSE;
264             image = [[NSImage alloc] initWithCGImage:cgimage size:NSZeroSize];
265             CGImageRelease(cgimage);
266             size = [image size];
267             while (size.width > maxSize || size.height > maxSize)
268             {
269                 size.width /= 2.0;
270                 size.height /= 2.0;
271                 changed = TRUE;
272             }
273             if (changed)
274                 [image setSize:size];
275         }
276         statusItem.image = image;
277         [image release];
278     });
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.
286  */
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;
293     OnMainThreadAsync(^{
294         [statusItem setToolTip:tip];
295     });