]> git.sesse.net Git - vlc/blob - modules/gui/macosx/MainWindowTitle.m
macosx: prevent ugly rendering artifacts when resizing the black main window on a...
[vlc] / modules / gui / macosx / MainWindowTitle.m
1 /*****************************************************************************
2  * MainWindowTitle.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2011-2012 Felix Paul Kühne
5  * $Id$
6  *
7  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #import <vlc_common.h>
25 #import "intf.h"
26 #import "MainWindowTitle.h"
27 #import "CoreInteraction.h"
28 #import "CompatibilityFixes.h"
29
30 /*****************************************************************************
31  * VLCMainWindowTitleView
32  *
33  * this is our title bar, which can do anything a title should do
34  * it relies on the VLCWindowButtonCell to display the correct traffic light
35  * states, since we can't capture the mouse-moved events here correctly
36  *****************************************************************************/
37
38 @implementation VLCMainWindowTitleView
39 - (void)dealloc
40 {
41     [[NSNotificationCenter defaultCenter] removeObserver: self];
42
43     [o_red_img release];
44     [o_red_over_img release];
45     [o_red_on_img release];
46     [o_yellow_img release];
47     [o_yellow_over_img release];
48     [o_yellow_on_img release];
49     [o_green_img release];
50     [o_green_over_img release];
51     [o_green_on_img release];
52
53     [super dealloc];
54 }
55
56 - (void)awakeFromNib
57 {
58     [self setAutoresizesSubviews: YES];
59     [self setImagesLeft:[NSImage imageNamed:@"topbar-dark-left"] middle: [NSImage imageNamed:@"topbar-dark-center-fill"] right:[NSImage imageNamed:@"topbar-dark-right"]];
60
61     [self loadButtonIcons];
62     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(controlTintChanged:) name: NSControlTintDidChangeNotification object: nil];
63
64     [o_red_btn setImage: o_red_img];
65     [o_red_btn setAlternateImage: o_red_on_img];
66     [[o_red_btn cell] setShowsBorderOnlyWhileMouseInside: YES];
67     [[o_red_btn cell] setTag: 0];
68     [o_yellow_btn setImage: o_yellow_img];
69     [o_yellow_btn setAlternateImage: o_yellow_on_img];
70     [[o_yellow_btn cell] setShowsBorderOnlyWhileMouseInside: YES];
71     [[o_yellow_btn cell] setTag: 1];
72     [o_green_btn setImage: o_green_img];
73     [o_green_btn setAlternateImage: o_green_on_img];
74     [[o_green_btn cell] setShowsBorderOnlyWhileMouseInside: YES];
75     [[o_green_btn cell] setTag: 2];
76     [o_fullscreen_btn setImage: [NSImage imageNamed:@"window-fullscreen"]];
77     [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"window-fullscreen-on"]];
78     [[o_fullscreen_btn cell] setShowsBorderOnlyWhileMouseInside: YES];
79     [[o_fullscreen_btn cell] setTag: 3];
80 }
81
82 - (void)controlTintChanged:(NSNotification *)notification
83 {
84     [o_red_img release];
85     [o_red_over_img release];
86     [o_red_on_img release];
87     [o_yellow_img release];
88     [o_yellow_over_img release];
89     [o_yellow_on_img release];
90     [o_green_img release];
91     [o_green_over_img release];
92     [o_green_on_img release];
93
94     [self loadButtonIcons];
95
96     [o_red_btn setNeedsDisplay];
97     [o_yellow_btn setNeedsDisplay];
98     [o_green_btn setNeedsDisplay];
99 }
100
101 - (void)loadButtonIcons
102 {
103     if (OSX_LION)
104     {
105         if( [NSColor currentControlTint] == NSBlueControlTint )
106         {
107             o_red_img = [[NSImage imageNamed:@"lion-window-close"] retain];
108             o_red_over_img = [[NSImage imageNamed:@"lion-window-close-over"] retain];
109             o_red_on_img = [[NSImage imageNamed:@"lion-window-close-on"] retain];
110             o_yellow_img = [[NSImage imageNamed:@"lion-window-minimize"] retain];
111             o_yellow_over_img = [[NSImage imageNamed:@"lion-window-minimize-over"] retain];
112             o_yellow_on_img = [[NSImage imageNamed:@"lion-window-minimize-on"] retain];
113             o_green_img = [[NSImage imageNamed:@"lion-window-zoom"] retain];
114             o_green_over_img = [[NSImage imageNamed:@"lion-window-zoom-over"] retain];
115             o_green_on_img = [[NSImage imageNamed:@"lion-window-zoom-on"] retain];
116         } else {
117             o_red_img = [[NSImage imageNamed:@"lion-window-close-graphite"] retain];
118             o_red_over_img = [[NSImage imageNamed:@"lion-window-close-over-graphite"] retain];
119             o_red_on_img = [[NSImage imageNamed:@"lion-window-close-on-graphite"] retain];
120             o_yellow_img = [[NSImage imageNamed:@"lion-window-minimize-graphite"] retain];
121             o_yellow_over_img = [[NSImage imageNamed:@"lion-window-minimize-over-graphite"] retain];
122             o_yellow_on_img = [[NSImage imageNamed:@"lion-window-minimize-on-graphite"] retain];
123             o_green_img = [[NSImage imageNamed:@"lion-window-zoom-graphite"] retain];
124             o_green_over_img = [[NSImage imageNamed:@"lion-window-zoom-over-graphite"] retain];
125             o_green_on_img = [[NSImage imageNamed:@"lion-window-zoom-on-graphite"] retain];            
126         }
127     } else {
128         if( [NSColor currentControlTint] == NSBlueControlTint )
129         {
130             o_red_img = [[NSImage imageNamed:@"snowleo-window-close"] retain];
131             o_red_over_img = [[NSImage imageNamed:@"snowleo-window-close-over"] retain];
132             o_red_on_img = [[NSImage imageNamed:@"snowleo-window-close-on"] retain];
133             o_yellow_img = [[NSImage imageNamed:@"snowleo-window-minimize"] retain];
134             o_yellow_over_img = [[NSImage imageNamed:@"snowleo-window-minimize-over"] retain];
135             o_yellow_on_img = [[NSImage imageNamed:@"snowleo-window-minimize-on"] retain];
136             o_green_img = [[NSImage imageNamed:@"snowleo-window-zoom"] retain];
137             o_green_over_img = [[NSImage imageNamed:@"snowleo-window-zoom-over"] retain];
138             o_green_on_img = [[NSImage imageNamed:@"snowleo-window-zoom-on"] retain];
139         } else {
140             o_red_img = [[NSImage imageNamed:@"snowleo-window-close-graphite"] retain];
141             o_red_over_img = [[NSImage imageNamed:@"snowleo-window-close-over-graphite"] retain];
142             o_red_on_img = [[NSImage imageNamed:@"snowleo-window-close-on-graphite"] retain];
143             o_yellow_img = [[NSImage imageNamed:@"snowleo-window-minimize-graphite"] retain];
144             o_yellow_over_img = [[NSImage imageNamed:@"snowleo-window-minimize-over-graphite"] retain];
145             o_yellow_on_img = [[NSImage imageNamed:@"snowleo-window-minimize-on-graphite"] retain];
146             o_green_img = [[NSImage imageNamed:@"snowleo-window-zoom-graphite"] retain];
147             o_green_over_img = [[NSImage imageNamed:@"snowleo-window-zoom-over-graphite"] retain];
148             o_green_on_img = [[NSImage imageNamed:@"snowleo-window-zoom-on-graphite"] retain];            
149         }
150     }
151 }
152
153 - (BOOL)mouseDownCanMoveWindow
154 {
155     return YES;
156 }
157
158 - (IBAction)buttonAction:(id)sender
159 {
160     if (sender == o_red_btn)
161         [[self window] orderOut: sender];
162     else if (sender == o_yellow_btn)
163         [[self window] miniaturize: sender];
164     else if (sender == o_green_btn)
165         [[self window] performZoom: sender];
166     else if (sender == o_fullscreen_btn)
167         [[VLCCoreInteraction sharedInstance] toggleFullscreen];
168     else
169         msg_Err( VLCIntf, "unknown button action sender" );
170
171     [self setWindowButtonOver: NO];
172     [self setWindowFullscreenButtonOver: NO];
173 }
174
175 - (void)setWindowTitle:(NSString *)title
176 {
177     [o_title_lbl setStringValue: title];
178 }
179
180 - (void)setFullscreenButtonHidden:(BOOL)b_value
181 {
182     [o_fullscreen_btn setHidden: b_value];
183 }
184
185 - (void)setWindowButtonOver:(BOOL)b_value
186 {
187     if( b_value )
188     {
189         [o_red_btn setImage: o_red_over_img];
190         [o_yellow_btn setImage: o_yellow_over_img];
191         [o_green_btn setImage: o_green_over_img];
192     }
193     else
194     {
195         [o_red_btn setImage: o_red_img];
196         [o_yellow_btn setImage: o_yellow_img];
197         [o_green_btn setImage: o_green_img];
198     }
199 }
200
201 - (void)setWindowFullscreenButtonOver:(BOOL)b_value
202 {
203     if (b_value)
204         [o_fullscreen_btn setImage: [NSImage imageNamed:@"window-fullscreen-over"]];
205     else
206         [o_fullscreen_btn setImage: [NSImage imageNamed:@"window-fullscreen"]];
207 }
208 @end
209
210 /*****************************************************************************
211  * VLCWindowButtonCell
212  *
213  * since the title bar cannot fetch these mouse events (the more top-level
214  * NSButton is unable fetch them as well), we are using a subclass of the
215  * button cell to do so. It's set in the nib for the respective objects.
216  *****************************************************************************/
217
218 @implementation VLCWindowButtonCell
219
220 - (void)mouseEntered:(NSEvent *)theEvent
221 {
222     if ([self tag] == 3)
223         [(VLCMainWindowTitleView *)[[self controlView] superview] setWindowFullscreenButtonOver: YES];
224     else
225         [(VLCMainWindowTitleView *)[[self controlView] superview] setWindowButtonOver: YES];
226 }
227
228 - (void)mouseExited:(NSEvent *)theEvent
229 {
230     if ([self tag] == 3)
231         [(VLCMainWindowTitleView *)[[self controlView] superview] setWindowFullscreenButtonOver: NO];
232     else
233         [(VLCMainWindowTitleView *)[[self controlView] superview] setWindowButtonOver: NO];
234 }
235
236 @end
237
238
239 /*****************************************************************************
240  * VLCResizeControl
241  *
242  * For Leopard and Snow Leopard, we need to emulate the resize control on the
243  * bottom right of the window, since it is gone by using the borderless window
244  * mask. A proper fix would be Lion-only.
245  *****************************************************************************/
246
247 @implementation VLCResizeControl
248
249 - (void)mouseDragged:(NSEvent *)theEvent
250 {
251     NSRect windowFrame = [[self window] frame];
252     CGFloat deltaX, deltaY, oldOriginY;
253     deltaX = [theEvent deltaX];
254     deltaY = [theEvent deltaY];
255     oldOriginY = windowFrame.origin.y;
256
257     windowFrame.origin.y = (oldOriginY + windowFrame.size.height) - (windowFrame.size.height + deltaY);
258     windowFrame.size.width += deltaX;
259     windowFrame.size.height += deltaY;
260
261     NSSize winMinSize = [self window].minSize;
262     if (windowFrame.size.width < winMinSize.width)
263         windowFrame.size.width = winMinSize.width;
264
265     if (windowFrame.size.height < winMinSize.height)
266     {
267         windowFrame.size.height = winMinSize.height;
268         windowFrame.origin.y = oldOriginY;
269     }
270
271     [[self window] setFrame: windowFrame display: YES animate: NO];
272 }
273
274 @end
275
276 /*****************************************************************************
277  * VLCColorView
278  *
279  * since we are using a clear window color when using the black window 
280  * style, some filling is needed behind the video and some other elements
281  *****************************************************************************/
282
283 @implementation VLCColorView
284
285 - (void)drawRect:(NSRect)rect {
286     [[NSColor blackColor] setFill];
287     NSRectFill(rect);
288 }
289
290 @end