diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 24f585acc9..2f0c9c0ef2 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -66,7 +66,8 @@ SYSTEM_APPS = AboutSystem ActivityMonitor CharacterMap CodyCam DeskCalc Devices DiskProbe DiskUsage DriveSetup CDPlayer Expander Icon-O-Matic Installer LaunchBox Magnify Mail MediaConverter MediaPlayer MidiPlayer NetworkStatus PackageInstaller People PoorMan PowerStatus ProcessController Screenshot - ShowImage SoundRecorder StyledEdit Terminal TextSearch TV Workspaces + ScreenshotApp ShowImage SoundRecorder StyledEdit Terminal TextSearch TV + Workspaces ; SYSTEM_PREFERENCES = Appearance Backgrounds CPUFrequency DataTranslations Deskbar E-mail FileTypes Fonts Keyboard Keymap Locale Media diff --git a/src/apps/screenshot/Jamfile b/src/apps/screenshot/Jamfile index 49cf7d9a82..e1f2fff750 100644 --- a/src/apps/screenshot/Jamfile +++ b/src/apps/screenshot/Jamfile @@ -1,19 +1,26 @@ SubDir HAIKU_TOP src apps screenshot ; -UseLibraryHeaders zlib ; UsePrivateHeaders interface ; -Application Screenshot : - main.cpp - PreviewView.cpp - Screenshot.cpp +Application ScreenshotApp : + ScreenshotApp.cpp ScreenshotWindow.cpp - : be tracker translation libz.so liblocale.so $(TARGET_LIBSUPC++) - : Screenshot.rdef + PreviewView.cpp + Utility.cpp + : be locale tracker translation $(TARGET_LIBSUPC++) + : ScreenshotApp.rdef ; -DoCatalogs Screenshot : - x-vnd.Haiku-Screenshot +DoCatalogs ScreenshotApp : + x-vnd.Haiku-ScreenshotApp : - ScreenshotWindow.cpp + ScreenshotWindow.cpp + Utility.cpp +; + +Application Screenshot : + Screenshot.cpp + Utility.cpp + : be locale translation $(TARGET_LIBSUPC++) + : Screenshot.rdef ; diff --git a/src/apps/screenshot/Screenshot.cpp b/src/apps/screenshot/Screenshot.cpp index 8d0a0df988..e3ba57eae3 100644 --- a/src/apps/screenshot/Screenshot.cpp +++ b/src/apps/screenshot/Screenshot.cpp @@ -1,35 +1,39 @@ /* + * Copyright 2010 Wim van der Meer * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Karsten Heimrich * Fredrik Modéen + * Christophe Huriaux + * Wim van der Meer */ #include "Screenshot.h" - #include #include #include -#include + +#include +#include #include - - +#include +#include #include +#include -#include "ScreenshotWindow.h" +#include "Utility.h" Screenshot::Screenshot() : BApplication("application/x-vnd.Haiku-Screenshot"), - fArgvReceived(false), - fRefsReceived(false), - fImageFileType(B_PNG_FORMAT) + fUtility(new Utility()), + fLaunchGui(true) { be_locale->GetAppCatalog(&fCatalog); } @@ -37,45 +41,7 @@ Screenshot::Screenshot() Screenshot::~Screenshot() { -} - - -void -Screenshot::ReadyToRun() -{ - if (!fArgvReceived && !fRefsReceived) - new ScreenshotWindow(); - - fArgvReceived = false; - fRefsReceived = false; -} - - -void -Screenshot::RefsReceived(BMessage* message) -{ - int32 delay = 0; - message->FindInt32("delay", &delay); - - bool includeBorder = false; - message->FindBool("border", &includeBorder); - - bool includeMouse = false; - message->FindBool("border", &includeMouse); - - bool grabActiveWindow = false; - message->FindBool("window", &grabActiveWindow); - - bool saveScreenshotSilent = false; - message->FindBool("silent", &saveScreenshotSilent); - - bool showConfigureWindow = false; - message->FindBool("configure", &showConfigureWindow); - - new ScreenshotWindow(delay * 1000000, includeBorder, includeMouse, - grabActiveWindow, showConfigureWindow, saveScreenshotSilent); - - fRefsReceived = true; + delete fUtility; } @@ -83,13 +49,13 @@ void Screenshot::ArgvReceived(int32 argc, char** argv) { bigtime_t delay = 0; - const char* outputFilename = NULL; bool includeBorder = false; - bool includeMouse = false; + bool includeCursor = false; bool grabActiveWindow = false; - bool showConfigureWindow = false; bool saveScreenshotSilent = false; + bool copyToClipboard = false; + uint32 imageFileType = B_PNG_FORMAT; for (int32 i = 0; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) @@ -99,21 +65,18 @@ Screenshot::ArgvReceived(int32 argc, char** argv) includeBorder = true; else if (strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--mouse-pointer") == 0) - includeMouse = true; + includeCursor = true; else if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--window") == 0) grabActiveWindow = true; else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--silent") == 0) saveScreenshotSilent = true; - else if (strcmp(argv[i], "-o") == 0 - || strcmp(argv[i], "--options") == 0) - showConfigureWindow = true; else if (strcmp(argv[i], "-f") == 0 || strncmp(argv[i], "--format", 6) == 0 - || strncmp(argv[i], "--format=", 7) == 0) { - _SetImageTypeSilence(argv[i + 1]); - } else if (strcmp(argv[i], "-d") == 0 + || strncmp(argv[i], "--format=", 7) == 0) + imageFileType = _GetImageType(argv[i + 1]); + else if (strcmp(argv[i], "-d") == 0 || strncmp(argv[i], "--delay", 7) == 0 || strncmp(argv[i], "--delay=", 8) == 0) { int32 seconds = -1; @@ -123,60 +86,306 @@ Screenshot::ArgvReceived(int32 argc, char** argv) delay = seconds * 1000000; i++; } else { - printf("Screenshot: option requires an argument -- %s\n" - , argv[i]); - exit(0); + printf("Screenshot: option requires an argument -- %s\n", + argv[i]); + fLaunchGui = false; + return; } - } else if (i == argc - 1) + } else if (strcmp(argv[i], "-c") == 0 + || strcmp(argv[i], "--clipboard") == 0) + copyToClipboard = true; + else if (i == argc - 1) outputFilename = argv[i]; } + + if (argc > 1) + _New(delay); + + if (copyToClipboard || saveScreenshotSilent) { + fLaunchGui = false; + + BBitmap* screenshot = fUtility->MakeScreenshot(includeCursor, + grabActiveWindow, includeBorder); + + if (screenshot == NULL) + return; + + if (copyToClipboard) + fUtility->CopyToClipboard(*screenshot); - fArgvReceived = true; - - new ScreenshotWindow(delay, includeBorder, includeMouse, grabActiveWindow, - showConfigureWindow, saveScreenshotSilent, fImageFileType, - outputFilename); -} + if (saveScreenshotSilent) + fUtility->Save(&screenshot, outputFilename, imageFileType); - -void -Screenshot::_ShowHelp() const -{ - printf("Screenshot [OPTIONS] [FILE] Creates a bitmap of the current screen\n\n"); - printf("FILE is the optional output path / filename used in silent mode. If FILE is not given, a default filename will be generated in the prefered directory.\n\n"); - printf("OPTIONS\n"); - printf(" -o, --options Show options window first\n"); - printf(" -m, --mouse-pointer Include the mouse pointer\n"); - printf(" -b, --border Include the window border\n"); - printf(" -w, --window Capture the active window instead of the entire screen\n"); - printf(" -d, --delay=seconds Take screenshot after specified delay [in seconds]\n"); - printf(" -s, --silent Saves the screenshot without showing the app window\n"); - printf(" overrides --options\n"); - printf(" -f, --format=image Write the image format you like to save as\n"); - printf(" [bmp], [gif], [jpg], [png], [ppm], [targa], [tiff]\n"); - printf("\n"); - printf("Note: OPTION -b, --border takes only effect when used with -w, --window\n"); - exit(0); -} - - -void -Screenshot::_SetImageTypeSilence(const char* name) -{ - if (strcmp(name, "bmp") == 0) - fImageFileType = B_BMP_FORMAT; - else if (strcmp(name, "gif") == 0) - fImageFileType = B_GIF_FORMAT; - else if (strcmp(name, "jpg") == 0 || strcmp(name, "jpeg") == 0) - fImageFileType = B_JPEG_FORMAT; - else if (strcmp(name, "ppm") == 0) - fImageFileType = B_PPM_FORMAT; - else if (strcmp(name, "targa") == 0 || strcmp(name, "tga") == 0) - fImageFileType = B_TGA_FORMAT; - else if (strcmp(name, "tif") == 0 || strcmp(name, "tiff") == 0) - fImageFileType = B_TIFF_FORMAT; - else { - // Default to PNG. - fImageFileType = B_PNG_FORMAT; + delete screenshot; } } + + +void +Screenshot::ReadyToRun() +{ + if (fLaunchGui) { + // Launch the GUI application + if (fUtility->wholeScreen == NULL) { + // No command line parameters were given + be_roster->Launch("application/x-vnd.Haiku-ScreenshotApp"); + } else { + // Send the utility data and the command line settings to the GUI + BMessage message; + message.what = SS_UTILITY_DATA; + + BMessage* bitmap = new BMessage(); + fUtility->wholeScreen->Archive(bitmap); + message.AddMessage("wholeScreen", bitmap); + + bitmap = new BMessage(); + fUtility->cursorBitmap->Archive(bitmap); + message.AddMessage("cursorBitmap", bitmap); + + bitmap = new BMessage(); + fUtility->cursorAreaBitmap->Archive(bitmap); + message.AddMessage("cursorAreaBitmap", bitmap); + + message.AddPoint("cursorPosition", fUtility->cursorPosition); + message.AddRect("activeWindowFrame", fUtility->activeWindowFrame); + message.AddRect("tabFrame", fUtility->tabFrame); + message.AddFloat("borderSize", fUtility->borderSize); + + be_roster->Launch("application/x-vnd.Haiku-ScreenshotApp", + &message); + } + } + + be_app->PostMessage(B_QUIT_REQUESTED); +} + + +void +Screenshot::_ShowHelp() +{ + printf("Screenshot [OPTIONS] [FILE] Creates a bitmap of the current " + "screen\n\n"); + printf("FILE is the optional output path / filename used in silent mode. " + "An exisiting\nfile with the same name will be overwritten without " + "warning. If FILE is not\ngiven the screenshot will be saved to a " + "file with the default filename in the\nuser's home directory.\n\n"); + printf("OPTIONS\n"); + printf(" -m, --mouse-pointer Include the mouse pointer\n"); + printf(" -b, --border Include the window border\n"); + printf(" -w, --window Capture the active window instead of the " + "entire screen\n"); + printf(" -d, --delay=seconds Take screenshot after the specified delay " + "[in seconds]\n"); + printf(" -s, --silent Saves the screenshot without showing the " + "application\n window\n"); + printf(" -f, --format=image Give the image format you like to save " + "as\n"); + printf(" [bmp], [gif], [jpg], [png], [ppm], " + "[tga], [tif]\n"); + printf(" -c, --clipboard Copies the screenshot to the system " + "clipboard without\n showing the application " + "window\n"); + printf("\n"); + printf("Note: OPTION -b, --border takes only effect when used with -w, " + "--window\n"); + + fLaunchGui = false; +} + + +void +Screenshot::_New(bigtime_t delay) +{ + delete fUtility->wholeScreen; + delete fUtility->cursorBitmap; + delete fUtility->cursorAreaBitmap; + + if (delay > 0) + snooze(delay); + + _GetActiveWindowFrame(); + + // There is a bug in the drawEngine code that prevents the drawCursor + // flag from hiding the cursor when GetBitmap is called, so we need to hide + // the cursor by ourselves. Refer to trac tickets #2988 and #2997 + bool cursorIsHidden = IsCursorHidden(); + if (!cursorIsHidden) + HideCursor(); + if (BScreen().GetBitmap(&fUtility->wholeScreen, false) != B_OK) + return; + if (!cursorIsHidden) + ShowCursor(); + + // Get the current cursor position, bitmap, and hotspot + BPoint cursorHotSpot; + get_mouse(&fUtility->cursorPosition, NULL); + get_mouse_bitmap(&fUtility->cursorBitmap, &cursorHotSpot); + fUtility->cursorPosition -= cursorHotSpot; + + // Put the mouse area in a bitmap + BRect bounds = fUtility->cursorBitmap->Bounds(); + int cursorWidth = bounds.IntegerWidth() + 1; + int cursorHeight = bounds.IntegerHeight() + 1; + fUtility->cursorAreaBitmap = new BBitmap(bounds, B_RGBA32); + + fUtility->cursorAreaBitmap->ImportBits(fUtility->wholeScreen->Bits(), + fUtility->wholeScreen->BitsLength(), + fUtility->wholeScreen->BytesPerRow(), + fUtility->wholeScreen->ColorSpace(), + fUtility->cursorPosition, BPoint(0, 0), + cursorWidth, cursorHeight); + + // Fill in the background of the mouse bitmap + uint8* bits = (uint8*)fUtility->cursorBitmap->Bits(); + uint8* areaBits = (uint8*)fUtility->cursorAreaBitmap->Bits(); + for (int32 i = 0; i < cursorHeight; i++) { + for (int32 j = 0; j < cursorWidth; j++) { + uint8 alpha = 255 - bits[3]; + bits[0] = ((areaBits[0] * alpha) >> 8) + bits[0]; + bits[1] = ((areaBits[1] * alpha) >> 8) + bits[1]; + bits[2] = ((areaBits[2] * alpha) >> 8) + bits[2]; + bits[3] = 255; + areaBits += 4; + bits += 4; + } + } +} + + +status_t +Screenshot::_GetActiveWindowFrame() +{ + fUtility->activeWindowFrame.Set(0, 0, -1, -1); + + // Create a messenger to communicate with the active application + app_info appInfo; + status_t status = be_roster->GetActiveAppInfo(&appInfo); + if (status != B_OK) + return status; + BMessenger messenger(appInfo.signature, appInfo.team); + if (!messenger.IsValid()) + return B_ERROR; + + // Loop through the windows of the active application to find out which + // window is active + int32 tokenCount; + int32* tokens = get_token_list(appInfo.team, &tokenCount); + bool foundActiveWindow = false; + BMessage message; + BMessage reply; + int32 index = 0; + int32 token = -1; + client_window_info* windowInfo = NULL; + bool modalWindow = false; + while (true) { + message.MakeEmpty(); + reply.MakeEmpty(); + + message.what = B_GET_PROPERTY; + message.AddSpecifier("Active"); + message.AddSpecifier("Window", index); + messenger.SendMessage(&message, &reply, B_INFINITE_TIMEOUT, 50000); + + if (reply.what == B_MESSAGE_NOT_UNDERSTOOD) + break; + + if (!reply.what) { + // Reply timout, this probably means that we have a modal window + // so we'll just get the window frame of the top most window + modalWindow = true; + free(tokens); + status_t status = BPrivate::get_window_order(current_workspace(), + &tokens, &tokenCount); + if (status != B_OK || !tokens || tokenCount < 1) + return B_ERROR; + foundActiveWindow = true; + } else if (reply.FindBool("result", &foundActiveWindow) != B_OK) + foundActiveWindow = false; + + if (foundActiveWindow) { + // Get the client_window_info of the active window + foundActiveWindow = false; + for (int i = 0; i < tokenCount; i++) { + token = tokens[i]; + windowInfo = get_window_info(token); + if (!windowInfo->is_mini && !windowInfo->show_hide_level > 0) { + foundActiveWindow = true; + break; + } + free(windowInfo); + } + if (foundActiveWindow) + break; + } + index++; + } + free(tokens); + + if (!foundActiveWindow) + return B_ERROR; + + // Get the TabFrame using the scripting interface + if (!modalWindow) { + message.MakeEmpty(); + message.what = B_GET_PROPERTY; + message.AddSpecifier("TabFrame"); + message.AddSpecifier("Window", index); + reply.MakeEmpty(); + messenger.SendMessage(&message, &reply); + + if (reply.FindRect("result", &fUtility->tabFrame) != B_OK) + return B_ERROR; + } else + fUtility->tabFrame.Set(0, 0, 0, 0); + + // Get the active window frame from the client_window_info + fUtility->activeWindowFrame.left = windowInfo->window_left; + fUtility->activeWindowFrame.top = windowInfo->window_top; + fUtility->activeWindowFrame.right = windowInfo->window_right; + fUtility->activeWindowFrame.bottom = windowInfo->window_bottom; + fUtility->borderSize = windowInfo->border_size; + + free(windowInfo); + + // Make sure that fActiveWindowFrame doesn't extend beyond the screen frame + BRect screenFrame(BScreen().Frame()); + if (fUtility->activeWindowFrame.left < screenFrame.left) + fUtility->activeWindowFrame.left = screenFrame.left; + if (fUtility->activeWindowFrame.top < screenFrame.top) + fUtility->activeWindowFrame.top = screenFrame.top; + if (fUtility->activeWindowFrame.right > screenFrame.right) + fUtility->activeWindowFrame.right = screenFrame.right; + if (fUtility->activeWindowFrame.bottom > screenFrame.bottom) + fUtility->activeWindowFrame.bottom = screenFrame.bottom; + + return B_OK; +} + + +int32 +Screenshot::_GetImageType(const char* name) const +{ + if (strcmp(name, "bmp") == 0) + return B_BMP_FORMAT; + else if (strcmp(name, "gif") == 0) + return B_GIF_FORMAT; + else if (strcmp(name, "jpg") == 0 || strcmp(name, "jpeg") == 0) + return B_JPEG_FORMAT; + else if (strcmp(name, "ppm") == 0) + return B_PPM_FORMAT; + else if (strcmp(name, "tga") == 0 || strcmp(name, "targa") == 0) + return B_TGA_FORMAT; + else if (strcmp(name, "tif") == 0 || strcmp(name, "tiff") == 0) + return B_TIFF_FORMAT; + else { + return B_PNG_FORMAT; + } +} + + +int +main() +{ + Screenshot screenshot; + return screenshot.Run(); +} diff --git a/src/apps/screenshot/Screenshot.h b/src/apps/screenshot/Screenshot.h index 0a829109e6..3350ad7748 100644 --- a/src/apps/screenshot/Screenshot.h +++ b/src/apps/screenshot/Screenshot.h @@ -1,10 +1,6 @@ /* - * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved. + * Copyright 2010 Wim van der Meer * Distributed under the terms of the MIT License. - * - * Authors: - * Karsten Heimrich - * Fredrik Modéen */ #ifndef SCREENSHOT_H #define SCREENSHOT_H @@ -14,23 +10,29 @@ #include +class BBitmap; +class Utility; + + class Screenshot : public BApplication { public: Screenshot(); - virtual ~Screenshot(); + ~Screenshot(); - virtual void ReadyToRun(); - virtual void RefsReceived(BMessage* message); - virtual void ArgvReceived(int32 argc, char** argv); + void ReadyToRun(); + void ArgvReceived(int32 argc, char** argv); private: - void _ShowHelp() const; - void _SetImageTypeSilence(const char* name); + void _ShowHelp(); + void _New(bigtime_t delay); + status_t _GetActiveWindowFrame(); + int32 _GetImageType(const char* name) const; - bool fArgvReceived; - bool fRefsReceived; - int32 fImageFileType; - BCatalog fCatalog; + Utility* fUtility; + BCatalog fCatalog; + + bool fLaunchGui; }; -#endif /* SCREENSHOT_H */ + +#endif // SCREENSHOT_H diff --git a/src/apps/screenshot/Screenshot.rdef b/src/apps/screenshot/Screenshot.rdef index dad86c94c8..43448c7269 100644 --- a/src/apps/screenshot/Screenshot.rdef +++ b/src/apps/screenshot/Screenshot.rdef @@ -1,20 +1,15 @@ - resource app_signature "application/x-vnd.Haiku-Screenshot"; -resource app_flags B_MULTIPLE_LAUNCH; +resource app_flags B_MULTIPLE_LAUNCH | B_BACKGROUND_APP; resource app_version { major = 1, middle = 0, minor = 0, - - /* 0 = development 1 = alpha 2 = beta - 3 = gamma 4 = golden master 5 = final */ - variety = 2, + variety = B_APPV_BETA, internal = 0, - short_info = "Screenshot", - long_info = "Screenshot ©2008-2009 Haiku" + long_info = "Screenshot ©2008-2010 Haiku" }; resource vector_icon { @@ -48,4 +43,3 @@ resource vector_icon { $"0B73BD11333F6C1B4A6724C968940A0D010D02B8307E3A7163BA7600B82C644A" $"AAA84832F80A0D010E023EE2433C8C01BC90D03EDCDB4A6EE0C86667" }; - diff --git a/src/apps/screenshot/ScreenshotApp.cpp b/src/apps/screenshot/ScreenshotApp.cpp new file mode 100644 index 0000000000..7aefb6a4ac --- /dev/null +++ b/src/apps/screenshot/ScreenshotApp.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2010 Wim van der Meer + * All rights reserved. Distributed under the terms of the MIT license. + * + * Authors: + * Wim van der Meer + */ + + +#include "ScreenshotApp.h" + +#include + +#include +#include +#include + +#include "ScreenshotWindow.h" +#include "Utility.h" + + +ScreenshotApp::ScreenshotApp() + : + BApplication("application/x-vnd.Haiku-ScreenshotApp"), + fUtility(new Utility) +{ + be_locale->GetAppCatalog(&fCatalog); +} + + +ScreenshotApp::~ScreenshotApp() +{ + delete fUtility; +} + + +void +ScreenshotApp::MessageReceived(BMessage* message) +{ + status_t status = B_OK; + switch (message->what) { + case SS_UTILITY_DATA: + { + BMessage bitmap; + status = message->FindMessage("wholeScreen", &bitmap); + if (status != B_OK) + break; + + fUtility->wholeScreen = new BBitmap(&bitmap); + + status = message->FindMessage("cursorBitmap", &bitmap); + if (status != B_OK) + break; + + fUtility->cursorBitmap = new BBitmap(&bitmap); + + status = message->FindMessage("cursorAreaBitmap", &bitmap); + if (status != B_OK) + break; + + fUtility->cursorAreaBitmap = new BBitmap(&bitmap); + + status = message->FindPoint("cursorPosition", + &fUtility->cursorPosition); + if (status != B_OK) + break; + + status = message->FindRect("activeWindowFrame", + &fUtility->activeWindowFrame); + if (status != B_OK) + break; + + status = message->FindRect("tabFrame", &fUtility->tabFrame); + if (status != B_OK) + break; + + status = message->FindFloat("borderSize", &fUtility->borderSize); + if (status != B_OK) + break; + + break; + } + + default: + BApplication::MessageReceived(message); + break; + } + + if (status != B_OK) + be_app->PostMessage(B_QUIT_REQUESTED); +} + + +void +ScreenshotApp::ReadyToRun() +{ + new ScreenshotWindow(*fUtility); +} + + +int +main() +{ + ScreenshotApp app; + return app.Run(); +} diff --git a/src/apps/screenshot/ScreenshotApp.h b/src/apps/screenshot/ScreenshotApp.h new file mode 100644 index 0000000000..f310f6ee63 --- /dev/null +++ b/src/apps/screenshot/ScreenshotApp.h @@ -0,0 +1,33 @@ +/* + * Copyright 2010 Wim van der Meer + * Distributed under the terms of the MIT License. + * + * Authors: + * Wim van der Meer + */ +#ifndef SCREENSHOT_APP_H +#define SCREENSHOT_APP_H + + +#include +#include + + +class Utility; + + +class ScreenshotApp : public BApplication { +public: + ScreenshotApp(); + ~ScreenshotApp(); + + void MessageReceived(BMessage* message); + void ReadyToRun(); + +private: + BCatalog fCatalog; + Utility* fUtility; +}; + + +#endif // SCREENSHOT_APP_H diff --git a/src/apps/screenshot/ScreenshotApp.rdef b/src/apps/screenshot/ScreenshotApp.rdef new file mode 100644 index 0000000000..88683897b9 --- /dev/null +++ b/src/apps/screenshot/ScreenshotApp.rdef @@ -0,0 +1,45 @@ +resource app_signature "application/x-vnd.Haiku-ScreenshotApp"; + +resource app_flags B_MULTIPLE_LAUNCH; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + variety = B_APPV_BETA, + internal = 0, + short_info = "ScreenshotApp", + long_info = "ScreenshotApp ©2008-2010 Haiku" +}; + +resource vector_icon { + $"6E6369660E050102000603399E0F3D9C0ABF82B23B84A84B88504910C900A5B1" + $"FFBCEAF1FFFFB3B8FF020106023E49240000000000003CAAAA4940004A80007C" + $"896EFFFFC0D5FF0401920332669805D803FFCB0005FF020016023CC7ED389BBF" + $"BA16553E39B04A41E44546E300FFFFD3020016023C529D3753A2B8966F3D9D07" + $"4AF244490EAF005EFFC502001602BCDCFABCCC663C90D9BCA00D47B5864B0A2A" + $"0090FFF4020006023CC0000000000000003D000047C00048A0001F010101FFC1" + $"ACAC020106023A26EC38CA29B828213953DA48968D4B2BC600434A68FF0F1238" + $"05FF0F0606AE0BB40BC14A33C5ACB75CC370BDEFC804C13ECA02CA27BF80C117" + $"BB1EC51BBD3EBF06BA053AB8BA0606AE0BB40BC14A33C5ACB75CC370BDEFC804" + $"C13ECA02CA27BF80C117BB1EC51BBD3EBF06BA053AB8BA0605AE02B57D43B9B9" + $"C5EDB7BB49BBB756BD75CB34CA8DC3AE40340605AE02B57D43B9B9C5EDB7BB49" + $"BBB756BD75CB34CA8DC3AE40340A093B5E3D60BFCDCB3B4560C516C7EE604B5B" + $"485D4A44560606AA0B27444054523FC074BC08C072BC07C073BC07BEE7BB113A" + $"3208022E4733420A062C3E2C50485E4E584E44323C0A042C3E48484E44323C0A" + $"044848485E4E584E440A042C3E2C50485E48480A04363E54505E43393A0204C0" + $"80C3B945C4F0BF41C281BC4DC353BD60C254BB39C452BC9BC754BB5DC61DBDDA" + $"C88CC0CEC7BABFBBC8B9C1E2C6BB0204B7E1C43BB8D9C34DB6EAC52BB893C86B" + $"B73BC70BB9EAC9CEBCBFC936BBC7CA26BDB5C848BC0FC507BD66C668BAB7C3A6" + $"0604EE3355BC43C7D1BBDDC837BCA9C76B3851BC83C828BCE9C7C2BC1DC88E17" + $"0A030104000A0001021001178400040A020103000A0001001001178400040A01" + $"0101000A0001051001178200040A040105000A050105023E2E8B000000000000" + $"3E2E8B472E8B48945D0A06010630212001178300040A070106123FFC76B8A84F" + $"38A84F3FFC7642069D437F0F01178200040A07010630282401178200040A0701" + $"06302B2601178200040A070106302E2801178200040A03010B000A0001073028" + $"A92301178400040A0801082028A9230A0901092028A9230A0A010A2028A9230A" + $"070106123CE1EA3F79B7BE878F3DF5DD4ADA30C89CFA01178200040A0B010D12" + $"BEE243BC8C013C90D0BEDCDB4A31144BF5A201178400040A0C010D023F72923D" + $"0B73BD11333F6C1B4A6724C968940A0D010D02B8307E3A7163BA7600B82C644A" + $"AAA84832F80A0D010E023EE2433C8C01BC90D03EDCDB4A6EE0C86667" +}; diff --git a/src/apps/screenshot/ScreenshotWindow.cpp b/src/apps/screenshot/ScreenshotWindow.cpp index 5270cc4d18..26b3514f70 100644 --- a/src/apps/screenshot/ScreenshotWindow.cpp +++ b/src/apps/screenshot/ScreenshotWindow.cpp @@ -1,81 +1,58 @@ /* - * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved. - * Distributed under the terms of the MIT License. + * Copyright 2010 Wim van der Meer + * Copyright Karsten Heimrich, host.haiku@gmx.de. + * All rights reserved. Distributed under the terms of the MIT License. * * Authors: * Karsten Heimrich * Fredrik Modéen * Christophe Huriaux - * Wim van der Meer, WPJvanderMeer@gmail.com + * Wim van der Meer */ #include "ScreenshotWindow.h" - -#include #include - #include #include #include #include -#include #include -#include #include #include -#include -#include #include -#include #include +#include #include #include -#include -#include #include #include #include -#include -#include #include -#include -#include #include -#include #include #include -#include #include -#include #include -#include -#include -#include - #include "PreviewView.h" +#include "Utility.h" enum { - kScreenshotType, + kActiveWindow, kIncludeBorder, - kShowMouse, - kBackToSave, - kTakeScreenshot, - kImageOutputFormat, + kIncludeCursor, + kNewScreenshot, + kImageFormat, kLocationChanged, kChooseLocation, - kFinishScreenshot, - kShowOptions + kSaveScreenshot }; -// #pragma mark - DirectoryRefFilter - - class DirectoryRefFilter : public BRefFilter { public: virtual ~DirectoryRefFilter() @@ -90,142 +67,191 @@ public: }; -// #pragma mark - ScreenshotWindow - - #undef B_TRANSLATE_CONTEXT #define B_TRANSLATE_CONTEXT "ScreenshotWindow" -ScreenshotWindow::ScreenshotWindow() +ScreenshotWindow::ScreenshotWindow(const Utility& utility) : - BWindow(BRect(0, 0, 200.0, 100.0), B_TRANSLATE("Retake screenshot"), - B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE - | B_QUIT_ON_WINDOW_CLOSE | B_AVOID_FRONT - | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), + BWindow(BRect(0, 0, 200.0, 100.0), B_TRANSLATE("Screenshot"), + B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_AVOID_FRONT + | B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS + | B_CLOSE_ON_ESCAPE), + fUtility(utility), fDelayControl(NULL), fScreenshot(NULL), fOutputPathPanel(NULL), fLastSelectedPath(NULL), fDelay(0), - fTabHeight(0), fIncludeBorder(false), - fIncludeMouse(false), + fIncludeCursor(false), fGrabActiveWindow(false), - fShowConfigWindow(false), - fSaveScreenshotSilent(false), fOutputFilename(NULL), fExtension(""), fImageFileType(B_PNG_FORMAT) { - BMessage settings = _ReadSettings(); + // Check if fUtility contains valid data + if (fUtility.wholeScreen == NULL) { + // New screenshot using zero delay + _NewScreenshot(); + return; + } + + // _ReadSettings() needs a valid fOutputPathMenu + fOutputPathMenu = new BMenu(B_TRANSLATE("Please select")); + _ReadSettings(); - if (settings.FindInt32("type", &fImageFileType) != B_OK) - fImageFileType = B_PNG_FORMAT; - settings.FindBool("includeBorder", &fIncludeBorder); - settings.FindBool("includeMouse", &fIncludeMouse); - settings.FindBool("grabActiveWindow", &fGrabActiveWindow); - settings.FindInt64("delay", &fDelay); - settings.FindString("outputFilename", &fOutputFilename); + fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, fGrabActiveWindow, + fIncludeBorder); + + fActiveWindow = new BCheckBox(B_TRANSLATE("Capture active window"), + new BMessage(kActiveWindow)); + if (fGrabActiveWindow) + fActiveWindow->SetValue(B_CONTROL_ON); + + fWindowBorder = new BCheckBox(B_TRANSLATE("Include window border"), + new BMessage(kIncludeBorder)); + if (fIncludeBorder) + fWindowBorder->SetValue(B_CONTROL_ON); + if (!fGrabActiveWindow) + fWindowBorder->SetEnabled(false); + + fShowCursor = new BCheckBox(B_TRANSLATE("Include mouse pointer"), + new BMessage(kIncludeCursor)); + if (fIncludeCursor) + fShowCursor->SetValue(B_CONTROL_ON); + + BString delay; + delay << fDelay / 1000000; + fDelayControl = new BTextControl("", B_TRANSLATE("Delay:"), delay.String(), + NULL); + _DisallowChar(fDelayControl->TextView()); + fDelayControl->TextView()->SetAlignment(B_ALIGN_RIGHT); + BStringView* seconds = new BStringView("", B_TRANSLATE("seconds")); + seconds->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); + + BString name(fUtility.sDefaultFileNameBase); + name << 1; + name = _FindValidFileName(name.String()); + fNameControl = new BTextControl("", B_TRANSLATE("Name:"), name, NULL); + + BMenuField* menuField2 = new BMenuField(B_TRANSLATE("Save in:"), + fOutputPathMenu); + + fTranslatorMenu = new BMenu(B_TRANSLATE("Please select")); + _SetupTranslatorMenu(); + BMenuField* menuField = new BMenuField(B_TRANSLATE("Save as:"), + fTranslatorMenu); + + BBox* divider = new BBox(B_FANCY_BORDER, NULL); + divider->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1)); + + BButton* saveScreenshot = new BButton("", B_TRANSLATE("Save"), + new BMessage(kSaveScreenshot)); + + fPreview = new PreviewView(); + + BGridLayout* gridLayout = BGridLayoutBuilder(0.0, 5.0) + .Add(fNameControl->CreateLabelLayoutItem(), 0, 0) + .Add(fNameControl->CreateTextViewLayoutItem(), 1, 0) + .Add(menuField->CreateLabelLayoutItem(), 0, 1) + .Add(menuField->CreateMenuBarLayoutItem(), 1, 1) + .Add(menuField2->CreateLabelLayoutItem(), 0, 2) + .Add(menuField2->CreateMenuBarLayoutItem(), 1, 2); + gridLayout->SetMinColumnWidth(1, + menuField->StringWidth("SomethingLongHere")); + + SetLayout(new BGroupLayout(B_HORIZONTAL)); + + AddChild(BGroupLayoutBuilder(B_VERTICAL) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10.0) + .Add(fPreview) + .AddGroup(B_VERTICAL) + .Add(fActiveWindow) + .Add(fWindowBorder) + .Add(fShowCursor) + .AddGroup(B_HORIZONTAL, 5.0) + .Add(fDelayControl->CreateLabelLayoutItem()) + .Add(fDelayControl->CreateTextViewLayoutItem()) + .Add(seconds) + .End() + .AddStrut(10.0) + .Add(gridLayout->View()) + .AddGlue() + .End()) + .AddStrut(10) + .Add(divider) + .AddStrut(10) + .AddGroup(B_HORIZONTAL, 10.0) + .Add(new BButton("", B_TRANSLATE("Copy to clipboard"), + new BMessage(B_COPY))) + .Add(new BButton("", B_TRANSLATE("New screenshot"), + new BMessage(kNewScreenshot))) + .AddGlue() + .Add(saveScreenshot) + .End() + .SetInsets(10.0, 10.0, 10.0, 10.0) + ); + + saveScreenshot->MakeDefault(true); + + _UpdatePreviewPanel(); + _UpdateFilenameSelection(); - _TakeScreenshot(0); - _InitWindow(settings); CenterOnScreen(); Show(); } -ScreenshotWindow::ScreenshotWindow(bigtime_t delay, bool includeBorder, - bool includeMouse, bool grabActiveWindow, bool showConfigWindow, - bool saveScreenshotSilent, int32 imageFileType, const char* outputFilename) - : - BWindow(BRect(0, 0, 200.0, 100.0), B_TRANSLATE("Retake screenshot"), - B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE - | B_QUIT_ON_WINDOW_CLOSE | B_AVOID_FRONT - | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), - fDelayControl(NULL), - fScreenshot(NULL), - fOutputPathPanel(NULL), - fLastSelectedPath(NULL), - fDelay(0), - fTabHeight(0), - fIncludeBorder(includeBorder), - fIncludeMouse(includeMouse), - fGrabActiveWindow(grabActiveWindow), - fShowConfigWindow(showConfigWindow), - fSaveScreenshotSilent(saveScreenshotSilent), - fOutputFilename(outputFilename), - fExtension(""), - fImageFileType(imageFileType) -{ - if (fSaveScreenshotSilent) { - _TakeScreenshot(delay); - _SaveScreenshot(); - be_app_messenger.SendMessage(B_QUIT_REQUESTED); - } else { - if (!fShowConfigWindow) - _TakeScreenshot(delay); - - BMessage settings = _ReadSettings(); - _InitWindow(settings); - CenterOnScreen(); - Show(); - } -} - - ScreenshotWindow::~ScreenshotWindow() { if (fOutputPathPanel) delete fOutputPathPanel->RefFilter(); - delete fScreenshot; delete fOutputPathPanel; + delete fScreenshot; } void ScreenshotWindow::MessageReceived(BMessage* message) { -// message->PrintToStream(); switch (message->what) { - case kScreenshotType: + case kActiveWindow: fGrabActiveWindow = false; if (fActiveWindow->Value() == B_CONTROL_ON) fGrabActiveWindow = true; + fWindowBorder->SetEnabled(fGrabActiveWindow); + + delete fScreenshot; + fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, + fGrabActiveWindow, fIncludeBorder); + _UpdatePreviewPanel(); break; case kIncludeBorder: fIncludeBorder = (fWindowBorder->Value() == B_CONTROL_ON); - break; - - case kShowMouse: - fIncludeMouse = (fShowMouse->Value() == B_CONTROL_ON); - break; - - case kBackToSave: - { - BCardLayout* layout = dynamic_cast (GetLayout()); - if (layout) - layout->SetVisibleItem(1L); - - fSaveScreenshot->MakeDefault(true); - - SetTitle(B_TRANSLATE("Save screenshot")); - break; - } - - case kTakeScreenshot: - fDelay = (atoi(fDelayControl->Text()) * 1000000) + 50000; - Hide(); - _TakeScreenshot(fDelay); + delete fScreenshot; + fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, + fGrabActiveWindow, fIncludeBorder); _UpdatePreviewPanel(); - Show(); - _UpdateFilenameSelection(); break; - case kImageOutputFormat: + case kIncludeCursor: + fIncludeCursor = (fShowCursor->Value() == B_CONTROL_ON); + delete fScreenshot; + fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, + fGrabActiveWindow, fIncludeBorder); + _UpdatePreviewPanel(); + break; + + case kNewScreenshot: + fDelay = (atoi(fDelayControl->Text()) * 1000000) + 50000; + _NewScreenshot(); + break; + + case kImageFormat: message->FindInt32("be:type", &fImageFileType); fNameControl->SetText(_FindValidFileName( fNameControl->Text()).String()); @@ -240,6 +266,7 @@ ScreenshotWindow::MessageReceived(BMessage* message) fNameControl->SetText(_FindValidFileName( fNameControl->Text()).String()); + _UpdateFilenameSelection(); break; } @@ -265,44 +292,14 @@ ScreenshotWindow::MessageReceived(BMessage* message) fLastSelectedPath->SetMarked(true); break; - case B_REFS_RECEIVED: - { - entry_ref ref; - if (message->FindRef("refs", &ref) == B_OK) { - BString path(BPath(&ref).Path()); - int32 index = _PathIndexInMenu(path); - if (index < 0) - _AddItemToPathMenu(path.String(), path, - fOutputPathMenu->CountItems() - 2, true); - else - fOutputPathMenu->ItemAt(index)->SetMarked(true); - } - break; - } - - case kFinishScreenshot: - _WriteSettings(); - if (_SaveScreenshot() != B_OK) - break; - - // fall through - case B_QUIT_REQUESTED: - _WriteSettings(); - be_app_messenger.SendMessage(B_QUIT_REQUESTED); + case kSaveScreenshot: + if (_SaveScreenshot() == B_OK) + be_app->PostMessage(B_QUIT_REQUESTED); break; - case kShowOptions: - { - BCardLayout* layout = dynamic_cast (GetLayout()); - - if (layout) - layout->SetVisibleItem(0L); - SetDefaultButton(NULL); - - SetTitle(B_TRANSLATE("Take Screenshot")); - fBackToSave->SetEnabled(true); + case B_COPY: + fUtility.CopyToClipboard(fScreenshot); break; - } default: BWindow::MessageReceived(message); @@ -311,191 +308,55 @@ ScreenshotWindow::MessageReceived(BMessage* message) } -BPath -ScreenshotWindow::_GetDirectory() +void +ScreenshotWindow::Quit() { - BPath path; - if (!fSaveScreenshotSilent) { - BMessage* message = fLastSelectedPath->Message(); - const char* stringPath; - if (!message || message->FindString("path", &stringPath) != B_OK) { - fprintf(stderr, "failed to find path in message\n"); - } else - path.SetTo(stringPath); - } else { - if (find_directory(B_USER_DIRECTORY, &path) != B_OK) - fprintf(stderr, "failed to find user home folder\n"); - } - return path; + if (fUtility.wholeScreen != NULL) + _WriteSettings(); + BWindow::Quit(); } void -ScreenshotWindow::_InitWindow(const BMessage& settings) +ScreenshotWindow::_NewScreenshot() { - BCardLayout* layout = new BCardLayout(); - SetLayout(layout); - - _SetupFirstLayoutItem(layout); - _SetupSecondLayoutItem(layout, settings); - - if (!fShowConfigWindow) { - _UpdatePreviewPanel(); - layout->SetVisibleItem(1L); - fSaveScreenshot->MakeDefault(true); - } else { - layout->SetVisibleItem(0L); - SetDefaultButton(NULL); - } -} - - -void -ScreenshotWindow::_SetupFirstLayoutItem(BCardLayout* layout) -{ - BStringView* stringView = new BStringView("", B_TRANSLATE("Options")); - stringView->SetFont(be_bold_font); - stringView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); - - fActiveWindow = new BRadioButton(B_TRANSLATE("Capture active window"), - new BMessage(kScreenshotType)); - fWholeDesktop = new BRadioButton(B_TRANSLATE("Capture entire screen"), - new BMessage(kScreenshotType)); - fWholeDesktop->SetValue(B_CONTROL_ON); + int32 argc = 3; + char* argv[3]; + argv[0] = "Screenshot"; + argv[1] = "--delay"; BString delay; delay << fDelay / 1000000; - fDelayControl = new BTextControl("", - B_TRANSLATE("Take screenshot after a delay of"), delay.String(), NULL); - _DisallowChar(fDelayControl->TextView()); - fDelayControl->TextView()->SetAlignment(B_ALIGN_RIGHT); + int32 charCount = delay.Length(); + argv[2] = (char*)malloc(charCount + 1); + delay.CopyInto(argv[2], 0, charCount); + argv[2][charCount] = '\0'; - BStringView* stringView2 = new BStringView("", B_TRANSLATE("seconds")); - stringView2->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); - - fWindowBorder = new BCheckBox(B_TRANSLATE("Include window border"), - new BMessage(kIncludeBorder)); - fWindowBorder->SetEnabled(false); - - fShowMouse = new BCheckBox(B_TRANSLATE("Include mouse pointer"), - new BMessage(kShowMouse)); - fShowMouse->SetValue(fIncludeMouse); - - BBox* divider = new BBox(B_FANCY_BORDER, NULL); - divider->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1)); - - fBackToSave = new BButton("", B_TRANSLATE("Back to saving"), - new BMessage(kBackToSave)); - fBackToSave->SetEnabled(false); - - fTakeScreenshot = new BButton("", B_TRANSLATE("Take screenshot"), - new BMessage(kTakeScreenshot)); - - layout->AddView(0, BGroupLayoutBuilder(B_VERTICAL) - .Add(stringView) - .Add(BGridLayoutBuilder() - .Add(BSpaceLayoutItem::CreateHorizontalStrut(15.0), 0, 0) - .Add(fWholeDesktop, 1, 0) - .Add(BSpaceLayoutItem::CreateHorizontalStrut(15.0), 0, 1) - .Add(fActiveWindow, 1, 1) - .SetInsets(0.0, 5.0, 0.0, 0.0)) - .AddGroup(B_HORIZONTAL) - .AddStrut(30.0) - .Add(fWindowBorder) - .End() - .AddStrut(10.0) - .AddGroup(B_HORIZONTAL) - .AddStrut(15.0) - .Add(fShowMouse) - .End() - .AddStrut(5.0) - .AddGroup(B_HORIZONTAL, 5.0) - .AddStrut(10.0) - .Add(fDelayControl->CreateLabelLayoutItem()) - .Add(fDelayControl->CreateTextViewLayoutItem()) - .Add(stringView2) - .End() - .AddStrut(10.0) - .AddGlue() - .Add(divider) - .AddStrut(10) - .AddGroup(B_HORIZONTAL, 10.0) - .Add(fBackToSave) - .AddGlue() - .Add(new BButton("", B_TRANSLATE("Cancel"), - new BMessage(B_QUIT_REQUESTED))) - .Add(fTakeScreenshot) - .End() - .SetInsets(10.0, 10.0, 10.0, 10.0) - ); - - if (fGrabActiveWindow) { - fWindowBorder->SetEnabled(true); - fActiveWindow->SetValue(B_CONTROL_ON); - fWindowBorder->SetValue(fIncludeBorder); - } + be_roster->Launch("application/x-vnd.Haiku-Screenshot", argc, argv); + be_app->PostMessage(B_QUIT_REQUESTED); } void -ScreenshotWindow::_SetupSecondLayoutItem(BCardLayout* layout, - const BMessage& settings) +ScreenshotWindow::_UpdatePreviewPanel() { - fPreview = new PreviewView(); + float height = 150.0f; - fNameControl = new BTextControl("", B_TRANSLATE("Name:"), - B_TRANSLATE_COMMENT("screenshot1", "!! Filename of first " - "screenshot !!"), NULL); + float width = (fScreenshot->Bounds().Width() + / fScreenshot->Bounds().Height()) * height; - _SetupOutputPathMenu(new BMenu(B_TRANSLATE("Please select")), settings); + // to prevent a preview way too wide + if (width > 400.0f) { + width = 400.0f; + height = (fScreenshot->Bounds().Height() + / fScreenshot->Bounds().Width()) * width; + } - BMenuField* menuField2 = new BMenuField(B_TRANSLATE("Save in:"), - fOutputPathMenu); + fPreview->SetExplicitMinSize(BSize(width, height)); - fNameControl->SetText(_FindValidFileName( - B_TRANSLATE_COMMENT("screenshot1", "!! Filename of first " - "screenshot !!")).String()); - - _SetupTranslatorMenu(new BMenu(B_TRANSLATE("Please select"))); - BMenuField* menuField = new BMenuField(B_TRANSLATE("Save as:"), - fTranslatorMenu); - - BBox* divider = new BBox(B_FANCY_BORDER, NULL); - divider->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1)); - - fSaveScreenshot = new BButton("", - B_TRANSLATE("Save"), new BMessage(kFinishScreenshot)); - - BGridLayout* gridLayout = BGridLayoutBuilder(0.0, 5.0) - .Add(fNameControl->CreateLabelLayoutItem(), 0, 0) - .Add(fNameControl->CreateTextViewLayoutItem(), 1, 0) - .Add(menuField->CreateLabelLayoutItem(), 0, 1) - .Add(menuField->CreateMenuBarLayoutItem(), 1, 1) - .Add(menuField2->CreateLabelLayoutItem(), 0, 2) - .Add(menuField2->CreateMenuBarLayoutItem(), 1, 2); - gridLayout->SetMinColumnWidth(1, - menuField->StringWidth("SomethingLongHere")); - - layout->AddView(1, BGroupLayoutBuilder(B_VERTICAL) - .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10.0) - .Add(fPreview) - .AddGroup(B_VERTICAL) - .Add(gridLayout->View()) - .AddGlue() - .End()) - .AddStrut(10) - .Add(divider) - .AddStrut(10) - .AddGroup(B_HORIZONTAL, 10.0) - .Add(new BButton("", B_TRANSLATE("Options"), - new BMessage(kShowOptions))) - .AddGlue() - .Add(new BButton("", B_TRANSLATE("Cancel"), - new BMessage(B_QUIT_REQUESTED))) - .Add(fSaveScreenshot) - .End() - .SetInsets(10.0, 10.0, 10.0, 10.0) - ); + fPreview->ClearViewBitmap(); + fPreview->SetViewBitmap(fScreenshot, fScreenshot->Bounds(), + fPreview->Bounds(), B_FOLLOW_ALL, 0); } @@ -511,40 +372,8 @@ ScreenshotWindow::_DisallowChar(BTextView* textView) void -ScreenshotWindow::_SetupTranslatorMenu(BMenu* translatorMenu) +ScreenshotWindow::_SetupOutputPathMenu(const BMessage& settings) { - fTranslatorMenu = translatorMenu; - - BMessage message(kImageOutputFormat); - fTranslatorMenu = new BMenu("Please select"); - BTranslationUtils::AddTranslationItems(fTranslatorMenu, B_TRANSLATOR_BITMAP, - &message, NULL, NULL, NULL); - - fTranslatorMenu->SetLabelFromMarked(true); - - if (fTranslatorMenu->ItemAt(0)) - fTranslatorMenu->ItemAt(0)->SetMarked(true); - - int32 imageFileType; - for (int32 i = 0; i < fTranslatorMenu->CountItems(); ++i) { - BMenuItem* item = fTranslatorMenu->ItemAt(i); - if (item && item->Message()) { - item->Message()->FindInt32("be:type", &imageFileType); - if (fImageFileType == imageFileType) { - item->SetMarked(true); - MessageReceived(item->Message()); - break; - } - } - } -} - - -void -ScreenshotWindow::_SetupOutputPathMenu(BMenu* outputPathMenu, - const BMessage& settings) -{ - fOutputPathMenu = outputPathMenu; fOutputPathMenu->SetLabelFromMarked(true); BString lastSelectedPath; @@ -571,7 +400,7 @@ ScreenshotWindow::_SetupOutputPathMenu(BMenu* outputPathMenu, int32 i = 0; BString userPath; - while (settings.FindString("path", i++, &userPath) == B_OK) { + while (settings.FindString("path", ++i, &userPath) == B_OK) { _AddItemToPathMenu(userPath.String(), userPath, 3, (userPath == lastSelectedPath)); } @@ -611,45 +440,76 @@ ScreenshotWindow::_AddItemToPathMenu(const char* path, BString& label, void -ScreenshotWindow::_UpdatePreviewPanel() +ScreenshotWindow::_UpdateFilenameSelection() { - float height = 150.0f; + fNameControl->MakeFocus(true); + fNameControl->TextView()->Select(0, fNameControl->TextView()->TextLength() + - fExtension.Length()); - float width = (fScreenshot->Bounds().Width() - / fScreenshot->Bounds().Height()) * height; - - // to prevent a preview way too wide - if (width > 400.0f) { - width = 400.0f; - height = (fScreenshot->Bounds().Height() - / fScreenshot->Bounds().Width()) * width; - } - - fPreview->SetExplicitMinSize(BSize(width, height)); - fPreview->SetExplicitMaxSize(BSize(width, height)); - - fPreview->ClearViewBitmap(); - fPreview->SetViewBitmap(fScreenshot, fScreenshot->Bounds(), - fPreview->Bounds(), B_FOLLOW_ALL, 0); - - BCardLayout* layout = dynamic_cast (GetLayout()); - if (layout) - layout->SetVisibleItem(1L); - - _UpdateFilenameSelection(); - - SetTitle(B_TRANSLATE("Save screenshot")); + fNameControl->TextView()->ScrollToSelection(); } void -ScreenshotWindow::_UpdateFilenameSelection() +ScreenshotWindow::_SetupTranslatorMenu() { - fNameControl->MakeFocus(true); - fNameControl->TextView()->Select(0, - fNameControl->TextView()->TextLength() - - fExtension.Length()); - fNameControl->TextView()->ScrollToSelection(); + BMessage message(kImageFormat); + fTranslatorMenu = new BMenu("Please select"); + BTranslationUtils::AddTranslationItems(fTranslatorMenu, B_TRANSLATOR_BITMAP, + &message, NULL, NULL, NULL); + + fTranslatorMenu->SetLabelFromMarked(true); + + if (fTranslatorMenu->ItemAt(0)) + fTranslatorMenu->ItemAt(0)->SetMarked(true); + + int32 imageFileType; + for (int32 i = 0; i < fTranslatorMenu->CountItems(); ++i) { + BMenuItem* item = fTranslatorMenu->ItemAt(i); + if (item && item->Message()) { + item->Message()->FindInt32("be:type", &imageFileType); + if (fImageFileType == imageFileType) { + item->SetMarked(true); + MessageReceived(item->Message()); + break; + } + } + } +} + + +status_t +ScreenshotWindow::_SaveScreenshot() +{ + if (!fScreenshot || !fLastSelectedPath) + return B_ERROR; + + BPath path(_GetDirectory()); + + if (path == NULL) + return B_ERROR; + + path.Append(fNameControl->Text()); + + BEntry entry; + entry.SetTo(path.Path()); + + if (entry.Exists()) { + BAlert* overwriteAlert = new BAlert( + B_TRANSLATE("overwrite"), + B_TRANSLATE("This file already exists.\n Are you sure would " + "you like to overwrite it?"), + B_TRANSLATE("Cancel"), + B_TRANSLATE("Overwrite"), + NULL, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); + + overwriteAlert->SetShortcut(0, B_ESCAPE); + + if (overwriteAlert->Go() == 0) + return B_CANCELED; + } + + return fUtility.Save(&fScreenshot, path.Path(), fImageFileType); } @@ -661,40 +521,14 @@ ScreenshotWindow::_FindValidFileName(const char* name) if (fExtension.Compare("")) baseName.RemoveLast(fExtension); - if (!fSaveScreenshotSilent && !fLastSelectedPath) + if (!fLastSelectedPath) return baseName; BPath orgPath(_GetDirectory()); if (orgPath == NULL) return baseName; - BTranslatorRoster* roster = BTranslatorRoster::Default(); - - translator_id id = 0; - if (_FindTranslator(fImageFileType, &id) == B_OK) { - - const translation_format* formats = NULL; - - int32 numFormats; - if (roster->GetOutputFormats(id, &formats, &numFormats) == B_OK) { - for (int32 i = 0; i < numFormats; ++i) { - if (formats[i].type == uint32(fImageFileType)) { - BMimeType mimeType(formats[i].MIME); - BMessage msgExtensions; - if (mimeType.GetFileExtensions(&msgExtensions) == B_OK) { - const char* extension; - if (msgExtensions.FindString("extensions", 0, - &extension) == B_OK) { - fExtension.SetTo(extension); - fExtension.Prepend("."); - } else - fExtension.SetTo(""); - } - break; - } - } - } - } + fExtension = BString(fUtility.GetFileNameExtension(fImageFileType)); BPath outputPath = orgPath; BString fileName; @@ -704,68 +538,76 @@ ScreenshotWindow::_FindValidFileName(const char* name) if (!BEntry(outputPath.Path()).Exists()) return fileName; - if (baseName.FindFirst(B_TRANSLATE_COMMENT("screenshot", - "!! Basename of screenshot files. !!")) == 0) - baseName.SetTo(B_TRANSLATE_COMMENT("screenshot", - "!! Basename of screenshot files. !!")); + if (baseName.FindFirst(fUtility.sDefaultFileNameBase) == 0) + baseName.SetTo(fUtility.sDefaultFileNameBase); BEntry entry; int32 index = 1; - char filename[B_FILE_NAME_LENGTH]; + do { - sprintf(filename, "%s%ld%s", baseName.String(), index++, - fExtension.String()); + fileName = ""; + fileName << baseName << index++ << fExtension; outputPath.SetTo(orgPath.Path()); - outputPath.Append(filename); + outputPath.Append(fileName); entry.SetTo(outputPath.Path()); } while (entry.Exists()); - return BString(filename); + return fileName; } -int32 -ScreenshotWindow::_PathIndexInMenu(const BString& path) const +BPath +ScreenshotWindow::_GetDirectory() { - BString userPath; - for (int32 i = 0; i < fOutputPathMenu->CountItems(); ++i) { - BMenuItem* item = fOutputPathMenu->ItemAt(i); - if (item && item->Message() - && item->Message()->FindString("path", &userPath) == B_OK) { - if (userPath == path) - return i; - } - } - return -1; + BPath path; + + BMessage* message = fLastSelectedPath->Message(); + const char* stringPath; + if (message && message->FindString("path", &stringPath) == B_OK) + path.SetTo(stringPath); + + return path; } -BMessage -ScreenshotWindow::_ReadSettings() const +void +ScreenshotWindow::_ReadSettings() { BMessage settings; BPath settingsPath; if (find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath) != B_OK) - return settings; + return; + settingsPath.Append("Screenshot_settings"); BFile file(settingsPath.Path(), B_READ_ONLY); if (file.InitCheck() == B_OK) settings.Unflatten(&file); - return settings; + if (settings.FindInt32("type", &fImageFileType) != B_OK) + fImageFileType = B_PNG_FORMAT; + settings.FindBool("includeBorder", &fIncludeBorder); + settings.FindBool("includeCursor", &fIncludeCursor); + settings.FindBool("grabActiveWindow", &fGrabActiveWindow); + settings.FindInt64("delay", &fDelay); + settings.FindString("outputFilename", &fOutputFilename); + + _SetupOutputPathMenu(settings); } void -ScreenshotWindow::_WriteSettings() const +ScreenshotWindow::_WriteSettings() { + if (fDelayControl) + fDelay = (atoi(fDelayControl->Text()) * 1000000) + 50000; + BMessage settings; settings.AddInt32("type", fImageFileType); settings.AddBool("includeBorder", fIncludeBorder); - settings.AddBool("includeMouse", fIncludeMouse); + settings.AddBool("includeCursor", fIncludeCursor); settings.AddBool("grabActiveWindow", fGrabActiveWindow); settings.AddInt64("delay", fDelay); settings.AddString("outputFilename", fOutputFilename); @@ -801,268 +643,3 @@ ScreenshotWindow::_WriteSettings() const settings.Flatten(&file, &size); } } - - -void -ScreenshotWindow::_TakeScreenshot(bigtime_t delay) -{ - if (delay > 0) - snooze(delay); - - BRect frame; - delete fScreenshot; - if (_GetActiveWindowFrame(&frame) == B_OK) { - fScreenshot = new BBitmap(frame.OffsetToCopy(B_ORIGIN), B_RGBA32, true); - BScreen(this).ReadBitmap(fScreenshot, fIncludeMouse, &frame); - if (fIncludeBorder) - _MakeTabSpaceTransparent(&frame); - } else - BScreen(this).GetBitmap(&fScreenshot, fIncludeMouse); -} - - -status_t -ScreenshotWindow::_GetActiveWindowFrame(BRect* frame) -{ - if (!fGrabActiveWindow || !frame) - return B_ERROR; - - int32* tokens; - int32 tokenCount; - status_t status = BPrivate::get_window_order(current_workspace(), &tokens, - &tokenCount); - if (status != B_OK || !tokens || tokenCount < 1) - return B_ERROR; - - status = B_ERROR; - for (int32 i = 0; i < tokenCount; ++i) { - client_window_info* windowInfo = get_window_info(tokens[i]); - if (!windowInfo->is_mini && !windowInfo->show_hide_level > 0) { - frame->left = windowInfo->window_left; - frame->top = windowInfo->window_top; - frame->right = windowInfo->window_right; - frame->bottom = windowInfo->window_bottom; - - status = B_OK; - if (fIncludeBorder) { - float border = (windowInfo->border_size); - frame->InsetBy(-(border), -(border)); - frame->top -= windowInfo->tab_height; - fTabHeight = windowInfo->tab_height; - } - free(windowInfo); - - BRect screenFrame(BScreen(this).Frame()); - if (frame->left < screenFrame.left) - frame->left = screenFrame.left; - if (frame->top < screenFrame.top) - frame->top = screenFrame.top; - if (frame->right > screenFrame.right) - frame->right = screenFrame.right; - if (frame->bottom > screenFrame.bottom) - frame->bottom = screenFrame.bottom; - - break; - } - free(windowInfo); - } - free(tokens); - return status; -} - - -status_t -ScreenshotWindow::_SaveScreenshot() -{ - if (!fScreenshot || (!fSaveScreenshotSilent && !fLastSelectedPath)) - return B_ERROR; - - BPath path(_GetDirectory()); - - if (path == NULL) - return B_ERROR; - - if (fSaveScreenshotSilent) { - if (!fOutputFilename.Compare("")) { - path.Append(_FindValidFileName(B_TRANSLATE_COMMENT("screenshot1", - "!! Filename of first screenshot !!")).String()); - } else - path.SetTo(fOutputFilename); - } else - path.Append(fNameControl->Text()); - - BEntry entry; - entry.SetTo(path.Path()); - - if (!fSaveScreenshotSilent) { - if (entry.Exists()) { - BAlert* overwriteAlert = new BAlert( - B_TRANSLATE("overwrite"), - B_TRANSLATE("This file already exists.\n Are you sure would " - "you like to overwrite it?"), - B_TRANSLATE("Cancel"), - B_TRANSLATE("Overwrite"), - NULL, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); - - overwriteAlert->SetShortcut(0, B_ESCAPE); - - if (overwriteAlert->Go() == 0) - return B_CANCELED; - } - } - - BFile file(&entry, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); - if (file.InitCheck() != B_OK) - return B_ERROR; - - BBitmapStream bitmapStream(fScreenshot); - BTranslatorRoster* roster = BTranslatorRoster::Default(); - roster->Translate(&bitmapStream, NULL, NULL, &file, fImageFileType, - B_TRANSLATOR_BITMAP); - fScreenshot = NULL; - - BNodeInfo nodeInfo(&file); - if (nodeInfo.InitCheck() != B_OK) - return B_ERROR; - - translator_id id = 0; - if (_FindTranslator(fImageFileType, &id) != B_OK) - return B_ERROR; - - int32 numFormats; - const translation_format* formats = NULL; - - if (roster->GetOutputFormats(id, &formats, &numFormats) != B_OK) - return B_ERROR; - - for (int32 i = 0; i < numFormats; ++i) { - if (formats[i].type == uint32(fImageFileType)) { - nodeInfo.SetType(formats[i].MIME); - break; - } - } - - return B_OK; -} - - -void -ScreenshotWindow::_MakeTabSpaceTransparent(BRect* frame) -{ - if (!frame) - return; - - if (fScreenshot->ColorSpace() != B_RGBA32) - return; - - BRect fullFrame = *frame; - - BMessage message; - BMessage reply; - - app_info appInfo; - if (be_roster->GetActiveAppInfo(&appInfo) != B_OK) - return; - - BMessenger messenger(appInfo.signature, appInfo.team); - if (!messenger.IsValid()) - return; - - bool foundActiveWindow = false; - int32 index = 0; - - while (true) { - message.MakeEmpty(); - message.what = B_GET_PROPERTY; - message.AddSpecifier("Active"); - message.AddSpecifier("Window", index); - - reply.MakeEmpty(); - messenger.SendMessage(&message, &reply); - - if (reply.what == B_MESSAGE_NOT_UNDERSTOOD) - break; - - bool result; - if (reply.FindBool("result", &result) == B_OK) { - foundActiveWindow = result; - - if (foundActiveWindow) - break; - } - index++; - } - - if (!foundActiveWindow) - return; - - message.MakeEmpty(); - message.what = B_GET_PROPERTY; - message.AddSpecifier("TabFrame"); - message.AddSpecifier("Window", index); - reply.MakeEmpty(); - messenger.SendMessage(&message, &reply); - - BRect tabFrame; - if (reply.FindRect("result", &tabFrame) != B_OK) - return; - - if (!fullFrame.Contains(tabFrame)) - return; - - BRegion tabSpace(fullFrame); - fullFrame.OffsetBy(0, fTabHeight); - tabSpace.Exclude(fullFrame); - tabSpace.Exclude(tabFrame); - fullFrame.OffsetBy(0, -fTabHeight); - tabSpace.OffsetBy(-fullFrame.left, -fullFrame.top); - BScreen screen; - BRect screenFrame = screen.Frame(); - tabSpace.OffsetBy(-screenFrame.left, -screenFrame.top); - - BView view(fScreenshot->Bounds(), "bitmap", B_FOLLOW_ALL_SIDES, 0); - fScreenshot->AddChild(&view); - if (view.Looper() && view.Looper()->Lock()) { - view.SetDrawingMode(B_OP_COPY); - view.SetHighColor(B_TRANSPARENT_32_BIT); - - for (int i = 0; i < tabSpace.CountRects(); i++) - view.FillRect(tabSpace.RectAt(i)); - - view.Sync(); - view.Looper()->Unlock(); - } - fScreenshot->RemoveChild(&view); -} - - -status_t -ScreenshotWindow::_FindTranslator(uint32 imageType, translator_id* id) -{ - translator_id* translators = NULL; - int32 numTranslators = 0; - BTranslatorRoster* roster = BTranslatorRoster::Default(); - status_t status = roster->GetAllTranslators(&translators, &numTranslators); - if (status != B_OK) - return status; - - status = B_ERROR; - for (int32 x = 0; x < numTranslators && status != B_OK; x++) { - int32 numFormats; - const translation_format* formats = NULL; - - if (roster->GetOutputFormats(x, &formats, &numFormats) == B_OK) { - for (int32 i = 0; i < numFormats; ++i) { - if (formats[i].type == imageType) { - *id = x; - status = B_OK; - break; - } - } - } - } - - delete [] translators; - - return status; -} diff --git a/src/apps/screenshot/ScreenshotWindow.h b/src/apps/screenshot/ScreenshotWindow.h index a4c0bae505..333588a9d0 100644 --- a/src/apps/screenshot/ScreenshotWindow.h +++ b/src/apps/screenshot/ScreenshotWindow.h @@ -1,88 +1,65 @@ /* - * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved. - * Distributed under the terms of the MIT License. + * Copyright 2010 Wim van der Meer + * Copyright Karsten Heimrich, host.haiku@gmx.de. + * All rights reserved. Distributed under the terms of the MIT License. * * Authors: * Karsten Heimrich * Fredrik Modéen - * Wim van der Meer, WPJvanderMeer@gmail.com + * Wim van der Meer */ #ifndef SCREENSHOT_WINDOW_H #define SCREENSHOT_WINDOW_H #include -#include #include #include +#include class BBitmap; -class BButton; -class BCardLayout; class BCheckBox; class BFilePanel; class BMenu; -class BRadioButton; +class BPath; class BTextControl; class BTextView; -class BPath; + class PreviewView; +class Utility; class ScreenshotWindow : public BWindow { public: - ScreenshotWindow(); - ScreenshotWindow(bigtime_t delay, - bool includeBorder, - bool includeMouse, - bool grabActiveWindow, - bool showConfigWindow, - bool saveScreenshotSilent, - int32 imageFileType = B_PNG_FORMAT, - const char* outputFilename = NULL); - virtual ~ScreenshotWindow(); + ScreenshotWindow(const Utility& utility); + ~ScreenshotWindow(); - virtual void MessageReceived(BMessage* message); + void MessageReceived(BMessage* message); + void Quit(); private: - void _InitWindow(const BMessage& settings); - BPath _GetDirectory(); - void _SetupFirstLayoutItem(BCardLayout* layout); - void _SetupSecondLayoutItem(BCardLayout* layout, - const BMessage& settings); + void _NewScreenshot(); + void _UpdatePreviewPanel(); void _DisallowChar(BTextView* textView); - void _SetupTranslatorMenu(BMenu* translatorMenu); - void _SetupOutputPathMenu(BMenu* outputPathMenu, - const BMessage& settings); + void _SetupOutputPathMenu(const BMessage& settings); void _AddItemToPathMenu(const char* path, BString& label, int32 index, bool markItem); - - void _UpdatePreviewPanel(); void _UpdateFilenameSelection(); - BString _FindValidFileName(const char* name); - int32 _PathIndexInMenu(const BString& path) const; - - BMessage _ReadSettings() const; - void _WriteSettings() const; - - void _TakeScreenshot(bigtime_t delay); - status_t _GetActiveWindowFrame(BRect* frame); - void _MakeTabSpaceTransparent(BRect* frame); - + void _SetupTranslatorMenu(); status_t _SaveScreenshot(); + BString _FindValidFileName(const char* name); + BPath _GetDirectory(); + void _ReadSettings(); + void _WriteSettings(); - status_t _FindTranslator(uint32 imageType, translator_id* id); + const Utility& fUtility; PreviewView* fPreview; - BRadioButton* fActiveWindow; - BRadioButton* fWholeDesktop; + BCheckBox* fActiveWindow; BTextControl* fDelayControl; BCheckBox* fWindowBorder; - BCheckBox* fShowMouse; - BButton* fBackToSave; - BButton* fTakeScreenshot; - BButton* fSaveScreenshot; + BCheckBox* fShowCursor; BTextControl* fNameControl; BMenu* fTranslatorMenu; BMenu* fOutputPathMenu; @@ -91,17 +68,13 @@ private: BMenuItem* fLastSelectedPath; bigtime_t fDelay; - float fTabHeight; - bool fIncludeBorder; - bool fIncludeMouse; + bool fIncludeCursor; bool fGrabActiveWindow; - bool fShowConfigWindow; - bool fSaveScreenshotSilent; BString fOutputFilename; BString fExtension; - int32 fImageFileType; }; -#endif /* SCREENSHOT_WINDOW_H */ + +#endif // SCREENSHOT_WINDOW_H diff --git a/src/apps/screenshot/Utility.cpp b/src/apps/screenshot/Utility.cpp new file mode 100644 index 0000000000..6160980dd9 --- /dev/null +++ b/src/apps/screenshot/Utility.cpp @@ -0,0 +1,267 @@ +/* + * Copyright 2010 Wim van der Meer + * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Karsten Heimrich + * Fredrik Modéen + * Christophe Huriaux + * Wim van der Meer + */ + + +#include "Utility.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef B_TRANSLATE_CONTEXT +#define B_TRANSLATE_CONTEXT "Screenshot" + + +const char* Utility::sDefaultFileNameBase = + B_TRANSLATE_MARK_COMMENT("screenshot", + "Base filename of screenshot files"); + + +Utility::Utility() + : + wholeScreen(NULL), + cursorBitmap(NULL), + cursorAreaBitmap(NULL) +{ +} + + +Utility::~Utility() +{ + delete wholeScreen; + delete cursorBitmap; + delete cursorAreaBitmap; +} + + +void +Utility::CopyToClipboard(const BBitmap& screenshot) const +{ + if (be_clipboard->Lock()) { + be_clipboard->Clear(); + BMessage* clipboard = be_clipboard->Data(); + if (clipboard) { + BMessage* bitmap = new BMessage(); + screenshot.Archive(bitmap); + clipboard->AddMessage("image/bitmap", bitmap); + be_clipboard->Commit(); + } + be_clipboard->Unlock(); + } +} + + +/*! + Save the screenshot to the file with the specified filename and type. + Note that any existing file with the same filename will be overwritten + without warning. +*/ +status_t +Utility::Save(BBitmap** screenshot, const char* fileName, uint32 imageType) + const +{ + BString fileNameString(fileName); + + // Generate a default filename when none is given + if (fileNameString.Compare("") == 0) { + BPath homePath; + if (find_directory(B_USER_DIRECTORY, &homePath) != B_OK) + return B_ERROR; + + BEntry entry; + int32 index = 1; + BString extension = GetFileNameExtension(imageType); + do { + fileNameString.SetTo(homePath.Path()); + fileNameString << "/" << sDefaultFileNameBase << index++ + << extension; + entry.SetTo(fileNameString.String()); + } while (entry.Exists()); + } + + // Create the file + BFile file(fileNameString, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); + if (file.InitCheck() != B_OK) + return B_ERROR; + + // Write the screenshot bitmap to the file + BBitmapStream stream(*screenshot); + BTranslatorRoster* roster = BTranslatorRoster::Default(); + roster->Translate(&stream, NULL, NULL, &file, imageType, + B_TRANSLATOR_BITMAP); + *screenshot = NULL; + + // Set the file MIME attribute + BNodeInfo nodeInfo(&file); + if (nodeInfo.InitCheck() != B_OK) + return B_ERROR; + + nodeInfo.SetType(_GetMimeString(imageType)); + + return B_OK; +} + + +BBitmap* +Utility::MakeScreenshot(bool includeMouse, bool activeWindow, + bool includeBorder) const +{ + if (wholeScreen == NULL) + return NULL; + + BRect bounds = cursorBitmap->Bounds(); + int cursorWidth = bounds.IntegerWidth() + 1; + int cursorHeight = bounds.IntegerHeight() + 1; + + if (includeMouse && cursorBitmap != NULL) { + // Import the cursor bitmap into wholeScreen + wholeScreen->ImportBits(cursorBitmap->Bits(), + cursorBitmap->BitsLength(), cursorBitmap->BytesPerRow(), + cursorBitmap->ColorSpace(), BPoint(0, 0), cursorPosition, + cursorWidth, cursorHeight); + + } else if (cursorAreaBitmap != NULL) { + // Import the cursor area bitmap into wholeScreen + wholeScreen->ImportBits(cursorAreaBitmap->Bits(), + cursorAreaBitmap->BitsLength(), cursorAreaBitmap->BytesPerRow(), + cursorAreaBitmap->ColorSpace(), BPoint(0, 0), cursorPosition, + cursorWidth, cursorHeight); + } + + BBitmap* screenshot = NULL; + + if (activeWindow && activeWindowFrame.IsValid()) { + + BRect frame(activeWindowFrame); + if (includeBorder) { + frame.InsetBy(-borderSize, -borderSize); + frame.top -= tabFrame.bottom - tabFrame.top; + } + + screenshot = new BBitmap(frame.OffsetToCopy(B_ORIGIN), B_RGBA32, true); + + if (screenshot->ImportBits(wholeScreen->Bits(), + wholeScreen->BitsLength(), wholeScreen->BytesPerRow(), + wholeScreen->ColorSpace(), frame.LeftTop(), + BPoint(0, 0), frame.IntegerWidth() + 1, + frame.IntegerHeight() + 1) != B_OK) { + delete screenshot; + return NULL; + } + + if (includeBorder) + _MakeTabSpaceTransparent(screenshot, frame); + } else + screenshot = new BBitmap(wholeScreen); + + return screenshot; +} + + +const char* +Utility::GetFileNameExtension(uint32 imageType) const +{ + BMimeType mimeType(_GetMimeString(imageType)); + BString extension(""); + + BMessage message; + if (mimeType.GetFileExtensions(&message) == B_OK) { + const char* ext; + if (message.FindString("extensions", 0, &ext) == B_OK) { + extension.SetTo(ext); + extension.Prepend("."); + } else + extension.SetTo(""); + } + + return extension.String(); +} + + +const char* +Utility::_GetMimeString(uint32 imageType) const +{ + char dummy[] = ""; + translator_id* translators = NULL; + int32 numTranslators = 0; + BTranslatorRoster* roster = BTranslatorRoster::Default(); + status_t status = roster->GetAllTranslators(&translators, &numTranslators); + if (status != B_OK) + return dummy; + + for (int32 x = 0; x < numTranslators; x++) { + const translation_format* formats = NULL; + int32 numFormats; + + if (roster->GetOutputFormats(x, &formats, &numFormats) == B_OK) { + for (int32 i = 0; i < numFormats; ++i) { + if (formats[i].type == imageType) { + delete [] translators; + return formats[i].MIME; + } + } + } + } + delete [] translators; + return dummy; +} + + +void +Utility::_MakeTabSpaceTransparent(BBitmap* screenshot, BRect frame) const +{ + if (!frame.IsValid() || screenshot->ColorSpace() != B_RGBA32) + return; + + if (!frame.Contains(tabFrame)) + return; + + float tabHeight = tabFrame.bottom - tabFrame.top; + + BRegion tabSpace(frame); + frame.OffsetBy(0, tabHeight); + tabSpace.Exclude(frame); + tabSpace.Exclude(tabFrame); + frame.OffsetBy(0, -tabHeight); + tabSpace.OffsetBy(-frame.left, -frame.top); + BScreen screen; + BRect screenFrame = screen.Frame(); + tabSpace.OffsetBy(-screenFrame.left, -screenFrame.top); + + BView view(screenshot->Bounds(), "bitmap", B_FOLLOW_ALL_SIDES, 0); + screenshot->AddChild(&view); + if (view.Looper() && view.Looper()->Lock()) { + view.SetDrawingMode(B_OP_COPY); + view.SetHighColor(B_TRANSPARENT_32_BIT); + + for (int i = 0; i < tabSpace.CountRects(); i++) + view.FillRect(tabSpace.RectAt(i)); + + view.Sync(); + view.Looper()->Unlock(); + } + screenshot->RemoveChild(&view); +} diff --git a/src/apps/screenshot/Utility.h b/src/apps/screenshot/Utility.h new file mode 100644 index 0000000000..eb40b6a8cd --- /dev/null +++ b/src/apps/screenshot/Utility.h @@ -0,0 +1,49 @@ +/* + * Copyright 2010 Wim van der Meer + * Distributed under the terms of the MIT License. + */ +#ifndef UTILITY_H +#define UTILITY_H + + +#include +#include + + +class BBitmap; + + +// Command constant for sending utility data to the GUI app +const int32 SS_UTILITY_DATA = 'SSUD'; + + +class Utility { +public: + Utility(); + ~Utility(); + + void CopyToClipboard(const BBitmap& screenshot) const; + status_t Save(BBitmap** screenshot, const char* fileName, + uint32 imageType) const; + BBitmap* MakeScreenshot(bool includeCursor, bool activeWindow, + bool includeBorder) const; + const char* GetFileNameExtension(uint32 imageType) const; + + BBitmap* wholeScreen; + BBitmap* cursorBitmap; + BBitmap* cursorAreaBitmap; + BPoint cursorPosition; + BRect activeWindowFrame; + BRect tabFrame; + float borderSize; + + static const char* sDefaultFileNameBase; + +private: + void _MakeTabSpaceTransparent(BBitmap* screenshot, + BRect frame) const; + const char* _GetMimeString(uint32 imageType) const; +}; + + +#endif // UTILITY_H diff --git a/src/apps/screenshot/main.cpp b/src/apps/screenshot/main.cpp deleted file mode 100644 index 6c5867e72d..0000000000 --- a/src/apps/screenshot/main.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved. - * Distributed under the terms of the MIT License. - */ - -#include "Screenshot.h" - - -int -main(int argc, char* argv[]) -{ - Screenshot screenshot; - return screenshot.Run(); -}