winemac: Fix wglSwapBuffers() to operate on the HDC, not the current GL context.
[wine/multimedia.git] / dlls / winemac.drv / cocoa_status_item.m
blobf0a5863cb8ea7488cdc0c5aa8a13d4632a173b45
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];
99             self.item = nil;
100         }
101     }
103     - (void) postMouseButtonEvent:(NSEvent*)nsevent;
104     {
105         macdrv_event* event;
106         NSUInteger typeMask = NSEventMaskFromType([nsevent type]);
108         event = macdrv_create_event(STATUS_ITEM_MOUSE_BUTTON, nil);
109         event->status_item_mouse_button.item = (macdrv_status_item)self;
110         event->status_item_mouse_button.button = [nsevent buttonNumber];
111         event->status_item_mouse_button.down = (typeMask & (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask)) != 0;
112         event->status_item_mouse_button.count = [nsevent clickCount];
113         [queue postEvent:event];
114         macdrv_release_event(event);
115     }
118     /*
119      * ---------- NSView methods ----------
120      */
121     - (void) drawRect:(NSRect)rect
122     {
123         [item drawStatusBarBackgroundInRect:[self bounds] withHighlight:NO];
125         if (image)
126         {
127             NSSize imageSize = [image size];
128             NSRect bounds = [self bounds];
129             NSPoint imageOrigin = NSMakePoint(NSMidX(bounds) - imageSize.width / 2,
130                                               NSMidY(bounds) - imageSize.height / 2);
132             imageOrigin = [self convertPointToBase:imageOrigin];
133             imageOrigin.x = floor(imageOrigin.x);
134             imageOrigin.y = floor(imageOrigin.y);
135             imageOrigin = [self convertPointFromBase:imageOrigin];
137             [image drawAtPoint:imageOrigin
138                       fromRect:NSZeroRect
139                      operation:NSCompositeSourceOver
140                       fraction:1];
141         }
142     }
145     /*
146      * ---------- NSResponder methods ----------
147      */
148     - (void) mouseDown:(NSEvent*)event
149     {
150         [self postMouseButtonEvent:event];
151     }
153     - (void) mouseDragged:(NSEvent*)event
154     {
155         [self mouseMoved:event];
156     }
158     - (void) mouseMoved:(NSEvent*)nsevent
159     {
160         macdrv_event* event;
161         event = macdrv_create_event(STATUS_ITEM_MOUSE_MOVE, nil);
162         event->status_item_mouse_move.item = (macdrv_status_item)self;
163         [queue postEvent:event];
164         macdrv_release_event(event);
165     }
167     - (void) mouseUp:(NSEvent*)event
168     {
169         [self postMouseButtonEvent:event];
170     }
172     - (void) otherMouseDown:(NSEvent*)event
173     {
174         [self postMouseButtonEvent:event];
175     }
177     - (void) otherMouseDragged:(NSEvent*)event
178     {
179         [self mouseMoved:event];
180     }
182     - (void) otherMouseUp:(NSEvent*)event
183     {
184         [self postMouseButtonEvent:event];
185     }
187     - (void) rightMouseDown:(NSEvent*)event
188     {
189         [self postMouseButtonEvent:event];
190     }
192     - (void) rightMouseDragged:(NSEvent*)event
193     {
194         [self mouseMoved:event];
195     }
197     - (void) rightMouseUp:(NSEvent*)event
198     {
199         [self postMouseButtonEvent:event];
200     }
202 @end
205 /***********************************************************************
206  *              macdrv_create_status_item
208  * Creates a new status item in the status bar.
209  */
210 macdrv_status_item macdrv_create_status_item(macdrv_event_queue q)
212     WineEventQueue* queue = (WineEventQueue*)q;
213     __block WineStatusItem* statusItem;
215     OnMainThread(^{
216         statusItem = [[WineStatusItem alloc] initWithEventQueue:queue];
217     });
219     return (macdrv_status_item)statusItem;
222 /***********************************************************************
223  *              macdrv_destroy_status_item
225  * Removes a status item previously returned by
226  * macdrv_create_status_item() from the status bar and destroys it.
227  */
228 void macdrv_destroy_status_item(macdrv_status_item s)
230     WineStatusItem* statusItem = (WineStatusItem*)s;
232     OnMainThreadAsync(^{
233         [statusItem removeFromStatusBar];
234         [statusItem release];
235     });
238 /***********************************************************************
239  *              macdrv_set_status_item_image
241  * Sets the image for a status item.  If cgimage is NULL, clears the
242  * image of the status item (leaving it a blank spot on the menu bar).
243  */
244 void macdrv_set_status_item_image(macdrv_status_item s, CGImageRef cgimage)
246     WineStatusItem* statusItem = (WineStatusItem*)s;
248     CGImageRetain(cgimage);
250     OnMainThreadAsync(^{
251         NSImage* image = nil;
252         if (cgimage)
253         {
254             NSSize size;
255             CGFloat maxSize = [[NSStatusBar systemStatusBar] thickness];
256             BOOL changed = FALSE;
258             image = [[NSImage alloc] initWithCGImage:cgimage size:NSZeroSize];
259             CGImageRelease(cgimage);
260             size = [image size];
261             while (size.width > maxSize || size.height > maxSize)
262             {
263                 size.width /= 2.0;
264                 size.height /= 2.0;
265                 changed = TRUE;
266             }
267             if (changed)
268                 [image setSize:size];
269         }
270         statusItem.image = image;
271         [image release];
272     });
275 /***********************************************************************
276  *              macdrv_set_status_item_tooltip
278  * Sets the tooltip string for a status item.  If cftip is NULL, clears
279  * the tooltip string for the status item.
280  */
281 void macdrv_set_status_item_tooltip(macdrv_status_item s, CFStringRef cftip)
283     WineStatusItem* statusItem = (WineStatusItem*)s;
284     NSString* tip = (NSString*)cftip;
286     if (![tip length]) tip = nil;
287     OnMainThreadAsync(^{
288         [statusItem setToolTip:tip];
289     });