1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Josh Aas <josh@mozilla.com>
24 * Sylvain Pasche <sylvain.pasche@gmail.com>
25 * Stuart Morgan <stuart.morgan@alumni.case.edu>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "gfxImageSurface.h"
42 #include "nsCocoaUtils.h"
43 #include "nsMenuBarX.h"
44 #include "nsCocoaWindow.h"
46 #include "nsIInterfaceRequestorUtils.h"
47 #include "nsIAppShellService.h"
48 #include "nsIXULWindow.h"
49 #include "nsIBaseWindow.h"
50 #include "nsIServiceManager.h"
51 #include "nsMenuUtilsX.h"
52 #include "nsToolkit.h"
54 float nsCocoaUtils::MenuBarScreenHeight()
56 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
58 NSArray* allScreens = [NSScreen screens];
59 if ([allScreens count])
60 return [[allScreens objectAtIndex:0] frame].size.height;
62 return 0.0; // If there are no screens, there's not much we can say.
64 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0.0);
67 float nsCocoaUtils::FlippedScreenY(float y)
69 return MenuBarScreenHeight() - y;
72 NSRect nsCocoaUtils::GeckoRectToCocoaRect(const nsIntRect &geckoRect)
74 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
76 // We only need to change the Y coordinate by starting with the primary screen
77 // height, subtracting the gecko Y coordinate, and subtracting the height.
78 return NSMakeRect(geckoRect.x,
79 MenuBarScreenHeight() - (geckoRect.y + geckoRect.height),
83 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakeRect(0.0, 0.0, 0.0, 0.0));
86 nsIntRect nsCocoaUtils::CocoaRectToGeckoRect(const NSRect &cocoaRect)
88 // We only need to change the Y coordinate by starting with the primary screen
89 // height and subtracting both the cocoa y origin and the height of the
92 rect.x = NSToIntRound(cocoaRect.origin.x);
93 rect.y = NSToIntRound(FlippedScreenY(cocoaRect.origin.y + cocoaRect.size.height));
94 rect.width = NSToIntRound(cocoaRect.origin.x + cocoaRect.size.width) - rect.x;
95 rect.height = NSToIntRound(FlippedScreenY(cocoaRect.origin.y)) - rect.y;
99 NSPoint nsCocoaUtils::ScreenLocationForEvent(NSEvent* anEvent)
101 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
103 // Don't trust mouse locations of mouse move events, see bug 443178.
104 if (!anEvent || [anEvent type] == NSMouseMoved)
105 return [NSEvent mouseLocation];
107 return [[anEvent window] convertBaseToScreen:[anEvent locationInWindow]];
109 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakePoint(0.0, 0.0));
112 BOOL nsCocoaUtils::IsEventOverWindow(NSEvent* anEvent, NSWindow* aWindow)
114 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
116 return NSPointInRect(ScreenLocationForEvent(anEvent), [aWindow frame]);
118 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
121 NSPoint nsCocoaUtils::EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow)
123 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
125 return [aWindow convertScreenToBase:ScreenLocationForEvent(anEvent)];
127 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakePoint(0.0, 0.0));
130 void nsCocoaUtils::HideOSChromeOnScreen(PRBool aShouldHide, NSScreen* aScreen)
132 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
134 // Keep track of how many hiding requests have been made, so that they can
136 static int sMenuBarHiddenCount = 0, sDockHiddenCount = 0;
138 // Always hide the Dock, since it's not necessarily on the primary screen.
139 sDockHiddenCount += aShouldHide ? 1 : -1;
140 NS_ASSERTION(sMenuBarHiddenCount >= 0, "Unbalanced HideMenuAndDockForWindow calls");
142 // Only hide the menu bar if the window is on the same screen.
143 // The menu bar is always on the first screen in the screen list.
144 if (aScreen == [[NSScreen screens] objectAtIndex:0]) {
145 sMenuBarHiddenCount += aShouldHide ? 1 : -1;
146 NS_ASSERTION(sDockHiddenCount >= 0, "Unbalanced HideMenuAndDockForWindow calls");
149 // TODO This should be upgraded to use [NSApplication setPresentationOptions:]
150 // when support for 10.5 is dropped.
151 if (sMenuBarHiddenCount > 0) {
152 ::SetSystemUIMode(kUIModeAllHidden, 0);
153 } else if (sDockHiddenCount > 0) {
154 ::SetSystemUIMode(kUIModeContentHidden, 0);
156 ::SetSystemUIMode(kUIModeNormal, 0);
159 NS_OBJC_END_TRY_ABORT_BLOCK;
163 #define NS_APPSHELLSERVICE_CONTRACTID "@mozilla.org/appshell/appShellService;1"
164 nsIWidget* nsCocoaUtils::GetHiddenWindowWidget()
166 nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
168 NS_WARNING("Couldn't get AppShellService in order to get hidden window ref");
172 nsCOMPtr<nsIXULWindow> hiddenWindow;
173 appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
175 // Don't warn, this happens during shutdown, bug 358607.
179 nsCOMPtr<nsIBaseWindow> baseHiddenWindow;
180 baseHiddenWindow = do_GetInterface(hiddenWindow);
181 if (!baseHiddenWindow) {
182 NS_WARNING("Couldn't get nsIBaseWindow from hidden window (nsIXULWindow)");
186 nsCOMPtr<nsIWidget> hiddenWindowWidget;
187 if (NS_FAILED(baseHiddenWindow->GetMainWidget(getter_AddRefs(hiddenWindowWidget)))) {
188 NS_WARNING("Couldn't get nsIWidget from hidden window (nsIBaseWindow)");
192 return hiddenWindowWidget;
195 void nsCocoaUtils::PrepareForNativeAppModalDialog()
197 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
199 // Don't do anything if this is embedding. We'll assume that if there is no hidden
200 // window we shouldn't do anything, and that should cover the embedding case.
201 nsMenuBarX* hiddenWindowMenuBar = nsMenuUtilsX::GetHiddenWindowMenuBar();
202 if (!hiddenWindowMenuBar)
205 // First put up the hidden window menu bar so that app menu event handling is correct.
206 hiddenWindowMenuBar->Paint();
208 NSMenu* mainMenu = [NSApp mainMenu];
209 NS_ASSERTION([mainMenu numberOfItems] > 0, "Main menu does not have any items, something is terribly wrong!");
211 // Create new menu bar for use with modal dialog
212 NSMenu* newMenuBar = [[NSMenu alloc] initWithTitle:@""];
214 // Swap in our app menu. Note that the event target is whatever window is up when
215 // the app modal dialog goes up.
216 NSMenuItem* firstMenuItem = [[mainMenu itemAtIndex:0] retain];
217 [mainMenu removeItemAtIndex:0];
218 [newMenuBar insertItem:firstMenuItem atIndex:0];
219 [firstMenuItem release];
221 // Add standard edit menu
222 [newMenuBar addItem:nsMenuUtilsX::GetStandardEditMenuItem()];
224 // Show the new menu bar
225 [NSApp setMainMenu:newMenuBar];
226 [newMenuBar release];
228 NS_OBJC_END_TRY_ABORT_BLOCK;
231 void nsCocoaUtils::CleanUpAfterNativeAppModalDialog()
233 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
235 // Don't do anything if this is embedding. We'll assume that if there is no hidden
236 // window we shouldn't do anything, and that should cover the embedding case.
237 nsMenuBarX* hiddenWindowMenuBar = nsMenuUtilsX::GetHiddenWindowMenuBar();
238 if (!hiddenWindowMenuBar)
241 NSWindow* mainWindow = [NSApp mainWindow];
243 hiddenWindowMenuBar->Paint();
245 [WindowDelegate paintMenubarForWindow:mainWindow];
247 NS_OBJC_END_TRY_ABORT_BLOCK;
250 nsresult nsCocoaUtils::CreateCGImageFromSurface(gfxImageSurface *aFrame, CGImageRef *aResult)
253 PRInt32 width = aFrame->Width();
254 PRInt32 stride = aFrame->Stride();
255 PRInt32 height = aFrame->Height();
256 if ((stride % 4 != 0) || (height < 1) || (width < 1)) {
257 return NS_ERROR_FAILURE;
260 // Create a CGImageRef with the bits from the image, taking into account
261 // the alpha ordering and endianness of the machine so we don't have to
262 // touch the bits ourselves.
263 CGDataProviderRef dataProvider = ::CGDataProviderCreateWithData(NULL,
267 CGColorSpaceRef colorSpace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
268 *aResult = ::CGImageCreate(width,
274 kCGBitmapByteOrder32Host | kCGImageAlphaFirst,
278 kCGRenderingIntentDefault);
279 ::CGColorSpaceRelease(colorSpace);
280 ::CGDataProviderRelease(dataProvider);
281 return *aResult ? NS_OK : NS_ERROR_FAILURE;
284 nsresult nsCocoaUtils::CreateNSImageFromCGImage(CGImageRef aInputImage, NSImage **aResult)
286 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
288 PRInt32 width = ::CGImageGetWidth(aInputImage);
289 PRInt32 height = ::CGImageGetHeight(aInputImage);
290 NSRect imageRect = ::NSMakeRect(0.0, 0.0, width, height);
292 // Create a new image to receive the Quartz image data.
293 *aResult = [[NSImage alloc] initWithSize:imageRect.size];
295 [*aResult lockFocus];
297 // Get the Quartz context and draw.
298 CGContextRef imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
299 ::CGContextDrawImage(imageContext, *(CGRect*)&imageRect, aInputImage);
301 [*aResult unlockFocus];
304 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
307 nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer *aImage, PRUint32 aWhichFrame, NSImage **aResult)
309 nsRefPtr<gfxImageSurface> frame;
310 nsresult rv = aImage->CopyFrame(aWhichFrame,
311 imgIContainer::FLAG_SYNC_DECODE,
312 getter_AddRefs(frame));
313 if (NS_FAILED(rv) || !frame) {
314 return NS_ERROR_FAILURE;
316 CGImageRef imageRef = NULL;
317 rv = nsCocoaUtils::CreateCGImageFromSurface(frame, &imageRef);
318 if (NS_FAILED(rv) || !imageRef) {
319 return NS_ERROR_FAILURE;
322 rv = nsCocoaUtils::CreateNSImageFromCGImage(imageRef, aResult);
323 if (NS_FAILED(rv) || !aResult) {
324 return NS_ERROR_FAILURE;
326 ::CGImageRelease(imageRef);