Screenshot application enhancements:

- Remove the options panel, and the "-o, --options" switch, put all options
    inside the main panel as discussed in ticket #3831.
- Add a "Copy to clipboard" button, as discussed in ticket #3831.
- Add a "-c, --clipboard" switch to quickly copy a screenshot to the clipboard
    without launching the GUI.
- All settings apply directly to the current schreenshot as well as new 
    Screenshots, as discussed in ticket #4100.
- Separate executables for the CLI (Screenshot) and GUI (ScreenshotApp).
    When "Screenshot" is launched it runs in the background, and launches the
    GUI (if not run with the -s or -c switch) before quiting itself. When a new
    screenshot is requested through the ScreenshotApp GUI interface,
    ScreenshotApp launches Screenshot before quiting itself, after which
    Screenshot re-launches ScreenshotApp. This fixes ticket #4100.
    Note that because of this change the deskbar entry will show "ScreenshotApp"
    and not "Screenshot" as might be expected. I am not sure if this is a
    problem.
- Fixed the code that determines the active window because it was just finding
    the top most window. This change fixes tickets #3112, #4878, and #4423.
- Hide the cursor by calling BApplication::HideCursor(). 
    This fixes ticket #2988 (but *not* #2997).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37017 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Wim van der Meer
2010-06-05 11:23:22 +00:00
parent 5003f66a4c
commit 2ec6b3cf5d
13 changed files with 1169 additions and 920 deletions
+2 -1
View File
@@ -66,7 +66,8 @@ SYSTEM_APPS = AboutSystem ActivityMonitor CharacterMap CodyCam DeskCalc Devices
DiskProbe DiskUsage DriveSetup CDPlayer Expander Icon-O-Matic Installer DiskProbe DiskUsage DriveSetup CDPlayer Expander Icon-O-Matic Installer
LaunchBox Magnify Mail MediaConverter MediaPlayer MidiPlayer NetworkStatus LaunchBox Magnify Mail MediaConverter MediaPlayer MidiPlayer NetworkStatus
PackageInstaller People PoorMan PowerStatus ProcessController Screenshot 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 SYSTEM_PREFERENCES = Appearance Backgrounds CPUFrequency DataTranslations
<preference>Deskbar E-mail FileTypes Fonts Keyboard Keymap Locale Media <preference>Deskbar E-mail FileTypes Fonts Keyboard Keymap Locale Media
+17 -10
View File
@@ -1,19 +1,26 @@
SubDir HAIKU_TOP src apps screenshot ; SubDir HAIKU_TOP src apps screenshot ;
UseLibraryHeaders zlib ;
UsePrivateHeaders interface ; UsePrivateHeaders interface ;
Application Screenshot : Application ScreenshotApp :
main.cpp ScreenshotApp.cpp
PreviewView.cpp
Screenshot.cpp
ScreenshotWindow.cpp ScreenshotWindow.cpp
: be tracker translation libz.so liblocale.so $(TARGET_LIBSUPC++) PreviewView.cpp
: Screenshot.rdef Utility.cpp
: be locale tracker translation $(TARGET_LIBSUPC++)
: ScreenshotApp.rdef
; ;
DoCatalogs Screenshot : DoCatalogs ScreenshotApp :
x-vnd.Haiku-Screenshot x-vnd.Haiku-ScreenshotApp
: :
ScreenshotWindow.cpp ScreenshotWindow.cpp
Utility.cpp
;
Application Screenshot :
Screenshot.cpp
Utility.cpp
: be locale translation $(TARGET_LIBSUPC++)
: Screenshot.rdef
; ;
+316 -107
View File
@@ -1,35 +1,39 @@
/* /*
* Copyright 2010 Wim van der Meer <[email protected]>
* Copyright Karsten Heimrich, [email protected]. All rights reserved. * Copyright Karsten Heimrich, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Karsten Heimrich * Karsten Heimrich
* Fredrik Modéen * Fredrik Modéen
* Christophe Huriaux
* Wim van der Meer
*/ */
#include "Screenshot.h" #include "Screenshot.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <Catalog.h>
#include <AppDefs.h>
#include <Bitmap.h>
#include <Locale.h> #include <Locale.h>
#include <Roster.h>
#include <Screen.h>
#include <TranslatorFormats.h> #include <TranslatorFormats.h>
#include <WindowInfo.h>
#include "ScreenshotWindow.h" #include "Utility.h"
Screenshot::Screenshot() Screenshot::Screenshot()
: :
BApplication("application/x-vnd.Haiku-Screenshot"), BApplication("application/x-vnd.Haiku-Screenshot"),
fArgvReceived(false), fUtility(new Utility()),
fRefsReceived(false), fLaunchGui(true)
fImageFileType(B_PNG_FORMAT)
{ {
be_locale->GetAppCatalog(&fCatalog); be_locale->GetAppCatalog(&fCatalog);
} }
@@ -37,45 +41,7 @@ Screenshot::Screenshot()
Screenshot::~Screenshot() Screenshot::~Screenshot()
{ {
} delete fUtility;
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;
} }
@@ -83,13 +49,13 @@ void
Screenshot::ArgvReceived(int32 argc, char** argv) Screenshot::ArgvReceived(int32 argc, char** argv)
{ {
bigtime_t delay = 0; bigtime_t delay = 0;
const char* outputFilename = NULL; const char* outputFilename = NULL;
bool includeBorder = false; bool includeBorder = false;
bool includeMouse = false; bool includeCursor = false;
bool grabActiveWindow = false; bool grabActiveWindow = false;
bool showConfigureWindow = false;
bool saveScreenshotSilent = false; bool saveScreenshotSilent = false;
bool copyToClipboard = false;
uint32 imageFileType = B_PNG_FORMAT;
for (int32 i = 0; i < argc; i++) { for (int32 i = 0; i < argc; i++) {
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
@@ -99,21 +65,18 @@ Screenshot::ArgvReceived(int32 argc, char** argv)
includeBorder = true; includeBorder = true;
else if (strcmp(argv[i], "-m") == 0 else if (strcmp(argv[i], "-m") == 0
|| strcmp(argv[i], "--mouse-pointer") == 0) || strcmp(argv[i], "--mouse-pointer") == 0)
includeMouse = true; includeCursor = true;
else if (strcmp(argv[i], "-w") == 0 else if (strcmp(argv[i], "-w") == 0
|| strcmp(argv[i], "--window") == 0) || strcmp(argv[i], "--window") == 0)
grabActiveWindow = true; grabActiveWindow = true;
else if (strcmp(argv[i], "-s") == 0 else if (strcmp(argv[i], "-s") == 0
|| strcmp(argv[i], "--silent") == 0) || strcmp(argv[i], "--silent") == 0)
saveScreenshotSilent = true; saveScreenshotSilent = true;
else if (strcmp(argv[i], "-o") == 0
|| strcmp(argv[i], "--options") == 0)
showConfigureWindow = true;
else if (strcmp(argv[i], "-f") == 0 else if (strcmp(argv[i], "-f") == 0
|| strncmp(argv[i], "--format", 6) == 0 || strncmp(argv[i], "--format", 6) == 0
|| strncmp(argv[i], "--format=", 7) == 0) { || strncmp(argv[i], "--format=", 7) == 0)
_SetImageTypeSilence(argv[i + 1]); imageFileType = _GetImageType(argv[i + 1]);
} else if (strcmp(argv[i], "-d") == 0 else if (strcmp(argv[i], "-d") == 0
|| strncmp(argv[i], "--delay", 7) == 0 || strncmp(argv[i], "--delay", 7) == 0
|| strncmp(argv[i], "--delay=", 8) == 0) { || strncmp(argv[i], "--delay=", 8) == 0) {
int32 seconds = -1; int32 seconds = -1;
@@ -123,60 +86,306 @@ Screenshot::ArgvReceived(int32 argc, char** argv)
delay = seconds * 1000000; delay = seconds * 1000000;
i++; i++;
} else { } else {
printf("Screenshot: option requires an argument -- %s\n" printf("Screenshot: option requires an argument -- %s\n",
, argv[i]); argv[i]);
exit(0); 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]; 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; if (saveScreenshotSilent)
fUtility->Save(&screenshot, outputFilename, imageFileType);
new ScreenshotWindow(delay, includeBorder, includeMouse, grabActiveWindow,
showConfigureWindow, saveScreenshotSilent, fImageFileType,
outputFilename);
}
delete screenshot;
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;
} }
} }
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();
}
+18 -16
View File
@@ -1,10 +1,6 @@
/* /*
* Copyright Karsten Heimrich, [email protected]. All rights reserved. * Copyright 2010 Wim van der Meer <[email protected]>
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*
* Authors:
* Karsten Heimrich
* Fredrik Modéen
*/ */
#ifndef SCREENSHOT_H #ifndef SCREENSHOT_H
#define SCREENSHOT_H #define SCREENSHOT_H
@@ -14,23 +10,29 @@
#include <Catalog.h> #include <Catalog.h>
class BBitmap;
class Utility;
class Screenshot : public BApplication { class Screenshot : public BApplication {
public: public:
Screenshot(); Screenshot();
virtual ~Screenshot(); ~Screenshot();
virtual void ReadyToRun(); void ReadyToRun();
virtual void RefsReceived(BMessage* message); void ArgvReceived(int32 argc, char** argv);
virtual void ArgvReceived(int32 argc, char** argv);
private: private:
void _ShowHelp() const; void _ShowHelp();
void _SetImageTypeSilence(const char* name); void _New(bigtime_t delay);
status_t _GetActiveWindowFrame();
int32 _GetImageType(const char* name) const;
bool fArgvReceived; Utility* fUtility;
bool fRefsReceived; BCatalog fCatalog;
int32 fImageFileType;
BCatalog fCatalog; bool fLaunchGui;
}; };
#endif /* SCREENSHOT_H */
#endif // SCREENSHOT_H
+3 -9
View File
@@ -1,20 +1,15 @@
resource app_signature "application/x-vnd.Haiku-Screenshot"; 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 { resource app_version {
major = 1, major = 1,
middle = 0, middle = 0,
minor = 0, minor = 0,
variety = B_APPV_BETA,
/* 0 = development 1 = alpha 2 = beta
3 = gamma 4 = golden master 5 = final */
variety = 2,
internal = 0, internal = 0,
short_info = "Screenshot", short_info = "Screenshot",
long_info = "Screenshot ©2008-2009 Haiku" long_info = "Screenshot ©2008-2010 Haiku"
}; };
resource vector_icon { resource vector_icon {
@@ -48,4 +43,3 @@ resource vector_icon {
$"0B73BD11333F6C1B4A6724C968940A0D010D02B8307E3A7163BA7600B82C644A" $"0B73BD11333F6C1B4A6724C968940A0D010D02B8307E3A7163BA7600B82C644A"
$"AAA84832F80A0D010E023EE2433C8C01BC90D03EDCDB4A6EE0C86667" $"AAA84832F80A0D010E023EE2433C8C01BC90D03EDCDB4A6EE0C86667"
}; };
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright 2010 Wim van der Meer <[email protected]>
* All rights reserved. Distributed under the terms of the MIT license.
*
* Authors:
* Wim van der Meer
*/
#include "ScreenshotApp.h"
#include <stdlib.h>
#include <Bitmap.h>
#include <Locale.h>
#include <Roster.h>
#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();
}
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright 2010 Wim van der Meer <[email protected]>
* Distributed under the terms of the MIT License.
*
* Authors:
* Wim van der Meer
*/
#ifndef SCREENSHOT_APP_H
#define SCREENSHOT_APP_H
#include <Application.h>
#include <Catalog.h>
class Utility;
class ScreenshotApp : public BApplication {
public:
ScreenshotApp();
~ScreenshotApp();
void MessageReceived(BMessage* message);
void ReadyToRun();
private:
BCatalog fCatalog;
Utility* fUtility;
};
#endif // SCREENSHOT_APP_H
+45
View File
@@ -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"
};
File diff suppressed because it is too large Load Diff
+26 -53
View File
@@ -1,88 +1,65 @@
/* /*
* Copyright Karsten Heimrich, [email protected]. All rights reserved. * Copyright 2010 Wim van der Meer <[email protected]>
* Distributed under the terms of the MIT License. * Copyright Karsten Heimrich, [email protected]e.
* All rights reserved. Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Karsten Heimrich * Karsten Heimrich
* Fredrik Modéen * Fredrik Modéen
* Wim van der Meer, [email protected] * Wim van der Meer
*/ */
#ifndef SCREENSHOT_WINDOW_H #ifndef SCREENSHOT_WINDOW_H
#define SCREENSHOT_WINDOW_H #define SCREENSHOT_WINDOW_H
#include <String.h> #include <String.h>
#include <Window.h>
#include <TranslationDefs.h> #include <TranslationDefs.h>
#include <TranslatorFormats.h> #include <TranslatorFormats.h>
#include <Window.h>
class BBitmap; class BBitmap;
class BButton;
class BCardLayout;
class BCheckBox; class BCheckBox;
class BFilePanel; class BFilePanel;
class BMenu; class BMenu;
class BRadioButton; class BPath;
class BTextControl; class BTextControl;
class BTextView; class BTextView;
class BPath;
class PreviewView; class PreviewView;
class Utility;
class ScreenshotWindow : public BWindow { class ScreenshotWindow : public BWindow {
public: public:
ScreenshotWindow(); ScreenshotWindow(const Utility& utility);
ScreenshotWindow(bigtime_t delay, ~ScreenshotWindow();
bool includeBorder,
bool includeMouse,
bool grabActiveWindow,
bool showConfigWindow,
bool saveScreenshotSilent,
int32 imageFileType = B_PNG_FORMAT,
const char* outputFilename = NULL);
virtual ~ScreenshotWindow();
virtual void MessageReceived(BMessage* message); void MessageReceived(BMessage* message);
void Quit();
private: private:
void _InitWindow(const BMessage& settings); void _NewScreenshot();
BPath _GetDirectory(); void _UpdatePreviewPanel();
void _SetupFirstLayoutItem(BCardLayout* layout);
void _SetupSecondLayoutItem(BCardLayout* layout,
const BMessage& settings);
void _DisallowChar(BTextView* textView); void _DisallowChar(BTextView* textView);
void _SetupTranslatorMenu(BMenu* translatorMenu); void _SetupOutputPathMenu(const BMessage& settings);
void _SetupOutputPathMenu(BMenu* outputPathMenu,
const BMessage& settings);
void _AddItemToPathMenu(const char* path, void _AddItemToPathMenu(const char* path,
BString& label, int32 index, bool markItem); BString& label, int32 index, bool markItem);
void _UpdatePreviewPanel();
void _UpdateFilenameSelection(); void _UpdateFilenameSelection();
BString _FindValidFileName(const char* name); void _SetupTranslatorMenu();
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);
status_t _SaveScreenshot(); 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; PreviewView* fPreview;
BRadioButton* fActiveWindow; BCheckBox* fActiveWindow;
BRadioButton* fWholeDesktop;
BTextControl* fDelayControl; BTextControl* fDelayControl;
BCheckBox* fWindowBorder; BCheckBox* fWindowBorder;
BCheckBox* fShowMouse; BCheckBox* fShowCursor;
BButton* fBackToSave;
BButton* fTakeScreenshot;
BButton* fSaveScreenshot;
BTextControl* fNameControl; BTextControl* fNameControl;
BMenu* fTranslatorMenu; BMenu* fTranslatorMenu;
BMenu* fOutputPathMenu; BMenu* fOutputPathMenu;
@@ -91,17 +68,13 @@ private:
BMenuItem* fLastSelectedPath; BMenuItem* fLastSelectedPath;
bigtime_t fDelay; bigtime_t fDelay;
float fTabHeight;
bool fIncludeBorder; bool fIncludeBorder;
bool fIncludeMouse; bool fIncludeCursor;
bool fGrabActiveWindow; bool fGrabActiveWindow;
bool fShowConfigWindow;
bool fSaveScreenshotSilent;
BString fOutputFilename; BString fOutputFilename;
BString fExtension; BString fExtension;
int32 fImageFileType; int32 fImageFileType;
}; };
#endif /* SCREENSHOT_WINDOW_H */
#endif // SCREENSHOT_WINDOW_H
+267
View File
@@ -0,0 +1,267 @@
/*
* Copyright 2010 Wim van der Meer <[email protected]>
* Copyright Karsten Heimrich, [email protected]. 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 <Bitmap.h>
#include <BitmapStream.h>
#include <Catalog.h>
#include <Clipboard.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Looper.h>
#include <MimeType.h>
#include <NodeInfo.h>
#include <Path.h>
#include <Region.h>
#include <Screen.h>
#include <String.h>
#include <Translator.h>
#include <View.h>
#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);
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright 2010 Wim van der Meer <[email protected]>
* Distributed under the terms of the MIT License.
*/
#ifndef UTILITY_H
#define UTILITY_H
#include <Point.h>
#include <Rect.h>
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
-14
View File
@@ -1,14 +0,0 @@
/*
* Copyright Karsten Heimrich, [email protected]. 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();
}