1 /* 2 * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "ScreenshotWindow.h" 7 8 #include "PNGDump.h" 9 10 #include <Alert.h> 11 #include <Application.h> 12 #include <Bitmap.h> 13 #include <Box.h> 14 #include <BitmapStream.h> 15 #include <Button.h> 16 #include <CardLayout.h> 17 #include <CheckBox.h> 18 #include <Directory.h> 19 #include <Entry.h> 20 #include <File.h> 21 #include <FindDirectory.h> 22 #include <FilePanel.h> 23 #include <GridLayoutBuilder.h> 24 #include <GroupLayoutBuilder.h> 25 #include <LayoutItem.h> 26 #include <Menu.h> 27 #include <MenuField.h> 28 #include <MenuItem.h> 29 #include <Message.h> 30 #include <NodeInfo.h> 31 #include <Path.h> 32 #include <RadioButton.h> 33 #include <Screen.h> 34 #include <String.h> 35 #include <StringView.h> 36 #include <SpaceLayoutItem.h> 37 #include <TextControl.h> 38 #include <TranslatorFormats.h> 39 #include <TranslationUtils.h> 40 #include <TranslatorRoster.h> 41 #include <View.h> 42 #include <WindowInfo.h> 43 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 48 49 enum { 50 kScreenshotType, 51 kIncludeBorder, 52 kShowMouse, 53 kBackToSave, 54 kTakeScreenshot, 55 kImageOutputFormat, 56 kLocationChanged, 57 kChooseLocation, 58 kFinishScreenshot, 59 kShowOptions 60 }; 61 62 63 // #pragma mark - DirectoryRefFilter 64 65 66 class DirectoryRefFilter : public BRefFilter { 67 public: 68 virtual ~DirectoryRefFilter() {} 69 bool Filter(const entry_ref* ref, BNode* node, 70 struct stat_beos* stat, const char* filetype) 71 { 72 return node->IsDirectory(); 73 } 74 }; 75 76 77 // #pragma mark - ScreenshotWindow 78 79 80 ScreenshotWindow::ScreenshotWindow(bigtime_t delay, bool includeBorder, 81 bool includeMouse, bool grabActiveWindow, bool showConfigWindow, 82 bool saveScreenshotSilent) 83 : BWindow(BRect(0, 0, 200.0, 100.0), "Take Screenshot", B_TITLED_WINDOW, 84 B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_QUIT_ON_WINDOW_CLOSE | 85 B_AVOID_FRONT | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), 86 fDelayControl(NULL), 87 fScreenshot(NULL), 88 fOutputPathPanel(NULL), 89 fLastSelectedPath(NULL), 90 fDelay(delay), 91 fIncludeBorder(includeBorder), 92 fIncludeMouse(includeMouse), 93 fGrabActiveWindow(grabActiveWindow), 94 fShowConfigWindow(showConfigWindow) 95 { 96 if (saveScreenshotSilent) { 97 _TakeScreenshot(); 98 _SaveScreenshotSilent(); 99 be_app_messenger.SendMessage(B_QUIT_REQUESTED); 100 } else { 101 _InitWindow(); 102 _CenterAndShow(); 103 } 104 } 105 106 107 ScreenshotWindow::~ScreenshotWindow() 108 { 109 if (fOutputPathPanel) 110 delete fOutputPathPanel->RefFilter(); 111 112 delete fScreenshot; 113 delete fOutputPathPanel; 114 } 115 116 117 void 118 ScreenshotWindow::MessageReceived(BMessage* message) 119 { 120 switch (message->what) { 121 case kScreenshotType: { 122 fGrabActiveWindow = false; 123 if (fActiveWindow->Value() == B_CONTROL_ON) 124 fGrabActiveWindow = true; 125 fWindowBorder->SetEnabled(fGrabActiveWindow); 126 } break; 127 128 case kIncludeBorder: { 129 fIncludeBorder = (fWindowBorder->Value() == B_CONTROL_ON); 130 } break; 131 132 case kShowMouse: { 133 fIncludeMouse = (fShowMouse->Value() == B_CONTROL_ON); 134 } break; 135 136 case kBackToSave: { 137 BCardLayout* layout = dynamic_cast<BCardLayout*> (GetLayout()); 138 if (layout) 139 layout->SetVisibleItem(1L); 140 SetTitle("Save Screenshot"); 141 } break; 142 143 case kTakeScreenshot: { 144 Hide(); 145 _TakeScreenshot(); 146 _UpdatePreviewPanel(); 147 Show(); 148 } break; 149 150 case kImageOutputFormat: { 151 message->FindInt32("be:type", &fImageFileType); 152 message->FindInt32("be:translator", &fTranslator); 153 } break; 154 155 case kLocationChanged: { 156 void* source = NULL; 157 if (message->FindPointer("source", &source) == B_OK) 158 fLastSelectedPath = static_cast<BMenuItem*> (source); 159 160 const char* text = fNameControl->Text(); 161 fNameControl->SetText(_FindValidFileName(text).String()); 162 } break; 163 164 case kChooseLocation: { 165 if (!fOutputPathPanel) { 166 BMessenger target(this); 167 fOutputPathPanel = new BFilePanel(B_OPEN_PANEL, &target, 168 NULL, B_DIRECTORY_NODE, false, NULL, new DirectoryRefFilter()); 169 fOutputPathPanel->Window()->SetTitle("Choose folder"); 170 fOutputPathPanel->SetButtonLabel(B_DEFAULT_BUTTON, "Select"); 171 } 172 fOutputPathPanel->Show(); 173 } break; 174 175 case B_CANCEL: { 176 fLastSelectedPath->SetMarked(true); 177 } break; 178 179 case B_REFS_RECEIVED: { 180 entry_ref ref; 181 if (message->FindRef("refs", &ref) == B_OK) { 182 BString path(BPath(&ref).Path()); 183 int32 index = _PathIndexInMenu(path); 184 if (index < 0) { 185 _AddItemToPathMenu(path.String(), 186 path, fOutputPathMenu->CountItems() - 2, true); 187 } else { 188 fOutputPathMenu->ItemAt(index)->SetMarked(true); 189 } 190 } 191 } break; 192 193 case kFinishScreenshot: 194 _WriteSettings(); 195 if (_SaveScreenshot() != B_OK) 196 break; 197 198 // fall through 199 case B_QUIT_REQUESTED: 200 be_app_messenger.SendMessage(B_QUIT_REQUESTED); 201 break; 202 203 case kShowOptions: { 204 BCardLayout* layout = dynamic_cast<BCardLayout*> (GetLayout()); 205 if (layout) 206 layout->SetVisibleItem(0L); 207 SetTitle("Take Screenshot"); 208 fBackToSave->SetEnabled(true); 209 } break; 210 211 default: { 212 BWindow::MessageReceived(message); 213 } break; 214 }; 215 216 } 217 218 219 void 220 ScreenshotWindow::_InitWindow() 221 { 222 BCardLayout* layout = new BCardLayout(); 223 SetLayout(layout); 224 225 _SetupFirstLayoutItem(layout); 226 _SetupSecondLayoutItem(layout); 227 228 if (!fShowConfigWindow) { 229 _TakeScreenshot(); 230 _UpdatePreviewPanel(); 231 layout->SetVisibleItem(1L); 232 } else { 233 layout->SetVisibleItem(0L); 234 } 235 } 236 237 238 void 239 ScreenshotWindow::_SetupFirstLayoutItem(BCardLayout* layout) 240 { 241 BStringView* stringView = new BStringView("", "Options"); 242 stringView->SetFont(be_bold_font); 243 stringView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 244 245 fActiveWindow = new BRadioButton("Capture active window", 246 new BMessage(kScreenshotType)); 247 fWholeDesktop = new BRadioButton("Capture entire screen", 248 new BMessage(kScreenshotType)); 249 fWholeDesktop->SetValue(B_CONTROL_ON); 250 251 BString delay; 252 delay << fDelay / 1000000; 253 fDelayControl = new BTextControl("", "Take screenshot after a delay of", 254 delay.String(), NULL); 255 _DisallowChar(fDelayControl->TextView()); 256 fDelayControl->TextView()->SetAlignment(B_ALIGN_RIGHT); 257 258 BStringView* stringView2 = new BStringView("", "seconds"); 259 stringView2->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 260 261 fWindowBorder = new BCheckBox("Include window border", 262 new BMessage(kIncludeBorder)); 263 fWindowBorder->SetEnabled(false); 264 265 fShowMouse = new BCheckBox("Include mouse pointer", 266 new BMessage(kShowMouse)); 267 fShowMouse->SetValue(fIncludeMouse); 268 269 BBox* divider = new BBox(B_FANCY_BORDER, NULL); 270 divider->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1)); 271 272 fBackToSave = new BButton("", "Back to save", new BMessage(kBackToSave)); 273 fBackToSave->SetEnabled(false); 274 275 fTakeScreenshot = new BButton("", "Take Screenshot", 276 new BMessage(kTakeScreenshot)); 277 278 layout->AddView(0, BGroupLayoutBuilder(B_VERTICAL) 279 .Add(stringView) 280 .Add(BGridLayoutBuilder() 281 .Add(BSpaceLayoutItem::CreateHorizontalStrut(15.0), 0, 0) 282 .Add(fWholeDesktop, 1, 0) 283 .Add(BSpaceLayoutItem::CreateHorizontalStrut(15.0), 0, 1) 284 .Add(fActiveWindow, 1, 1) 285 .SetInsets(0.0, 5.0, 0.0, 0.0)) 286 .AddGroup(B_HORIZONTAL) 287 .AddStrut(30.0) 288 .Add(fWindowBorder) 289 .End() 290 .AddStrut(10.0) 291 .AddGroup(B_HORIZONTAL) 292 .AddStrut(15.0) 293 .Add(fShowMouse) 294 .End() 295 .AddStrut(5.0) 296 .AddGroup(B_HORIZONTAL, 5.0) 297 .AddStrut(10.0) 298 .Add(fDelayControl->CreateLabelLayoutItem()) 299 .Add(fDelayControl->CreateTextViewLayoutItem()) 300 .Add(stringView2) 301 .End() 302 .AddStrut(10.0) 303 .AddGlue() 304 .Add(divider) 305 .AddStrut(10) 306 .AddGroup(B_HORIZONTAL, 10.0) 307 .Add(fBackToSave) 308 .AddGlue() 309 .Add(new BButton("", "Cancel", new BMessage(B_QUIT_REQUESTED))) 310 .Add(fTakeScreenshot) 311 .End() 312 .SetInsets(10.0, 10.0, 10.0, 10.0) 313 ); 314 315 if (fGrabActiveWindow) { 316 fWindowBorder->SetEnabled(true); 317 fActiveWindow->SetValue(B_CONTROL_ON); 318 fWindowBorder->SetValue(fIncludeBorder); 319 } 320 } 321 322 323 void 324 ScreenshotWindow::_SetupSecondLayoutItem(BCardLayout* layout) 325 { 326 fPreview = new PreviewView(); 327 328 fNameControl = new BTextControl("", "Name:", "screenshot1", NULL); 329 330 BMessage settings(_ReadSettings()); 331 332 _SetupTranslatorMenu(new BMenu("Please select"), settings); 333 BMenuField* menuField = new BMenuField("Save as:", fTranslatorMenu); 334 335 _SetupOutputPathMenu(new BMenu("Please select"), settings); 336 BMenuField* menuField2 = new BMenuField("Save in:", fOutputPathMenu); 337 338 fNameControl->SetText(_FindValidFileName("screenshot1").String()); 339 340 BBox* divider = new BBox(B_FANCY_BORDER, NULL); 341 divider->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1)); 342 343 BGridLayout* gridLayout = BGridLayoutBuilder(0.0, 5.0) 344 .Add(fNameControl->CreateLabelLayoutItem(), 0, 0) 345 .Add(fNameControl->CreateTextViewLayoutItem(), 1, 0) 346 .Add(menuField->CreateLabelLayoutItem(), 0, 1) 347 .Add(menuField->CreateMenuBarLayoutItem(), 1, 1) 348 .Add(menuField2->CreateLabelLayoutItem(), 0, 2) 349 .Add(menuField2->CreateMenuBarLayoutItem(), 1, 2); 350 gridLayout->SetMinColumnWidth(1, menuField->StringWidth("SomethingLongHere")); 351 352 layout->AddView(1, BGroupLayoutBuilder(B_VERTICAL) 353 .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10.0) 354 .Add(fPreview) 355 .AddGroup(B_VERTICAL) 356 .Add(gridLayout->View()) 357 .AddGlue() 358 .End()) 359 .AddStrut(10) 360 .Add(divider) 361 .AddStrut(10) 362 .AddGroup(B_HORIZONTAL, 10.0) 363 .Add(new BButton("", "Options", new BMessage(kShowOptions))) 364 .AddGlue() 365 .Add(new BButton("", "Cancel", new BMessage(B_QUIT_REQUESTED))) 366 .Add(new BButton("", "Save", new BMessage(kFinishScreenshot))) 367 .End() 368 .SetInsets(10.0, 10.0, 10.0, 10.0) 369 ); 370 } 371 372 373 void 374 ScreenshotWindow::_DisallowChar(BTextView* textView) 375 { 376 for (uint32 i = 0; i < '0'; ++i) 377 textView->DisallowChar(i); 378 379 for (uint32 i = '9' + 1; i < 255; ++i) 380 textView->DisallowChar(i); 381 } 382 383 384 void 385 ScreenshotWindow::_SetupTranslatorMenu(BMenu* translatorMenu, 386 const BMessage& settings) 387 { 388 fTranslatorMenu = translatorMenu; 389 390 BMessage message(kImageOutputFormat); 391 fTranslatorMenu = new BMenu("Please select"); 392 BTranslationUtils::AddTranslationItems(fTranslatorMenu, B_TRANSLATOR_BITMAP, 393 &message, NULL, NULL, NULL); 394 395 fTranslatorMenu->SetLabelFromMarked(true); 396 397 if (fTranslatorMenu->ItemAt(0)) 398 fTranslatorMenu->ItemAt(0)->SetMarked(true); 399 400 if (settings.FindInt32("be:type", &fImageFileType) != B_OK) 401 fImageFileType = B_PNG_FORMAT; 402 403 int32 imageFileType; 404 for (int32 i = 0; i < fTranslatorMenu->CountItems(); ++i) { 405 BMenuItem* item = fTranslatorMenu->ItemAt(i); 406 if (item && item->Message()) { 407 item->Message()->FindInt32("be:type", &imageFileType); 408 if (fImageFileType == imageFileType) { 409 item->SetMarked(true); 410 break; 411 } 412 } 413 } 414 } 415 416 417 void 418 ScreenshotWindow::_SetupOutputPathMenu(BMenu* outputPathMenu, 419 const BMessage& settings) 420 { 421 fOutputPathMenu = outputPathMenu; 422 fOutputPathMenu->SetLabelFromMarked(true); 423 424 BString lastSelectedPath; 425 settings.FindString("lastSelectedPath", &lastSelectedPath); 426 427 BPath path; 428 find_directory(B_USER_DIRECTORY, &path); 429 430 BString label("Home folder"); 431 _AddItemToPathMenu(path.Path(), label, 0, (path.Path() == lastSelectedPath)); 432 433 path.Append("Desktop"); 434 label.SetTo("Desktop"); 435 _AddItemToPathMenu(path.Path(), label, 0, (path.Path() == lastSelectedPath)); 436 437 find_directory(B_BEOS_ETC_DIRECTORY, &path); 438 path.Append("artwork"); 439 440 label.SetTo("Artwork folder"); 441 _AddItemToPathMenu(path.Path(), label, 2, (path.Path() == lastSelectedPath)); 442 443 int32 i = 0; 444 BString userPath; 445 while (settings.FindString("path", i++, &userPath) == B_OK) { 446 _AddItemToPathMenu(userPath.String(), userPath, 3, 447 (userPath == lastSelectedPath)); 448 } 449 450 if (!fLastSelectedPath) { 451 if (settings.IsEmpty() || lastSelectedPath.Length() == 0) { 452 fOutputPathMenu->ItemAt(1)->SetMarked(true); 453 fLastSelectedPath = fOutputPathMenu->ItemAt(1); 454 } else { 455 _AddItemToPathMenu(lastSelectedPath.String(), lastSelectedPath, 3, 456 true); 457 } 458 } 459 460 fOutputPathMenu->AddItem(new BSeparatorItem()); 461 fOutputPathMenu->AddItem(new BMenuItem("Choose folder...", 462 new BMessage(kChooseLocation))); 463 } 464 465 466 void 467 ScreenshotWindow::_AddItemToPathMenu(const char* path, BString& label, 468 int32 index, bool markItem) 469 { 470 BMessage* message = new BMessage(kLocationChanged); 471 message->AddString("path", path); 472 473 fOutputPathMenu->TruncateString(&label, B_TRUNCATE_MIDDLE, 474 fOutputPathMenu->StringWidth("SomethingLongHere")); 475 476 fOutputPathMenu->AddItem(new BMenuItem(label.String(), message), index); 477 478 if (markItem) { 479 fOutputPathMenu->ItemAt(index)->SetMarked(true); 480 fLastSelectedPath = fOutputPathMenu->ItemAt(index); 481 } 482 } 483 484 485 void 486 ScreenshotWindow::_CenterAndShow() 487 { 488 BSize size = GetLayout()->PreferredSize(); 489 ResizeTo(size.Width(), size.Height()); 490 491 BRect frame(BScreen(this).Frame()); 492 MoveTo((frame.Width() - size.Width()) / 2.0, 493 (frame.Height() - size.Height()) / 2.0); 494 495 Show(); 496 } 497 498 499 void 500 ScreenshotWindow::_UpdatePreviewPanel() 501 { 502 float height = 150.0f; 503 504 float width = (fScreenshot->Bounds().Width() / 505 fScreenshot->Bounds().Height()) * height; 506 507 // to prevent a preview way too wide 508 if (width > 400.0f) { 509 width = 400.0f; 510 height = (fScreenshot->Bounds().Height() / 511 fScreenshot->Bounds().Width()) * width; 512 } 513 514 fPreview->SetExplicitMinSize(BSize(width, height)); 515 fPreview->SetExplicitMaxSize(BSize(width, height)); 516 517 fPreview->ClearViewBitmap(); 518 fPreview->SetViewBitmap(fScreenshot, fScreenshot->Bounds(), 519 fPreview->Bounds(), B_FOLLOW_ALL, 0); 520 521 BCardLayout* layout = dynamic_cast<BCardLayout*> (GetLayout()); 522 if (layout) 523 layout->SetVisibleItem(1L); 524 525 SetTitle("Save Screenshot"); 526 } 527 528 529 BString 530 ScreenshotWindow::_FindValidFileName(const char* name) const 531 { 532 BString fileName(name); 533 if (!fLastSelectedPath) 534 return fileName; 535 536 const char* path; 537 BMessage* message = fLastSelectedPath->Message(); 538 if (!message || message->FindString("path", &path) != B_OK) 539 return fileName; 540 541 BPath outputPath(path); 542 outputPath.Append(name); 543 if (!BEntry(outputPath.Path()).Exists()) 544 return fileName; 545 546 if (strncmp(name, "screenshot", strlen("screenshot")) == 0) 547 fileName.SetTo("screenshot"); 548 549 BEntry entry; 550 int32 index = 1; 551 char filename[32]; 552 do { 553 sprintf(filename, "%s%ld", fileName.String(), index++); 554 outputPath.SetTo(path); 555 outputPath.Append(filename); 556 entry.SetTo(outputPath.Path()); 557 } while (entry.Exists()); 558 559 return BString(filename); 560 } 561 562 563 int32 564 ScreenshotWindow::_PathIndexInMenu(const BString& path) const 565 { 566 BString userPath; 567 for (int32 i = 0; i < fOutputPathMenu->CountItems(); ++i) { 568 BMenuItem* item = fOutputPathMenu->ItemAt(i); 569 if (item && item->Message() 570 && item->Message()->FindString("path", &userPath) == B_OK) { 571 if (userPath == path) 572 return i; 573 } 574 } 575 return -1; 576 } 577 578 579 BMessage 580 ScreenshotWindow::_ReadSettings() const 581 { 582 BPath settingsPath; 583 find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath); 584 settingsPath.Append("screenshot"); 585 586 BMessage settings; 587 588 BFile file(settingsPath.Path(), B_READ_ONLY); 589 if (file.InitCheck() == B_OK) 590 settings.Unflatten(&file); 591 592 return settings; 593 } 594 595 596 void 597 ScreenshotWindow::_WriteSettings() const 598 { 599 BMessage settings; 600 settings.AddInt32("be:type", fImageFileType); 601 602 BString path; 603 int32 count = fOutputPathMenu->CountItems(); 604 if (count > 5) { 605 for (int32 i = count - 3; i > count - 8 && i > 2; --i) { 606 BMenuItem* item = fOutputPathMenu->ItemAt(i); 607 if (item) { 608 BMessage* msg = item->Message(); 609 if (msg && msg->FindString("path", &path) == B_OK) 610 settings.AddString("path", path.String()); 611 } 612 } 613 } 614 615 if (fLastSelectedPath) { 616 BMessage* msg = fLastSelectedPath->Message(); 617 if (msg && msg->FindString("path", &path) == B_OK) 618 settings.AddString("lastSelectedPath", path.String()); 619 } 620 621 BPath settingsPath; 622 find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath); 623 settingsPath.Append("screenshot"); 624 625 BFile file(settingsPath.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); 626 if (file.InitCheck() == B_OK) { 627 ssize_t size; 628 settings.Flatten(&file, &size); 629 } 630 } 631 632 633 void 634 ScreenshotWindow::_TakeScreenshot() 635 { 636 if (fDelayControl) 637 snooze((atoi(fDelayControl->Text()) * 1000000) + 50000); 638 639 BRect frame; 640 delete fScreenshot; 641 if (_GetActiveWindowFrame(&frame) == B_OK) { 642 fScreenshot = new BBitmap(frame.OffsetToCopy(B_ORIGIN), B_RGBA32); 643 BScreen(this).ReadBitmap(fScreenshot, fIncludeMouse, &frame); 644 } else { 645 BScreen(this).GetBitmap(&fScreenshot, fIncludeMouse); 646 } 647 } 648 649 650 status_t 651 ScreenshotWindow::_GetActiveWindowFrame(BRect* frame) 652 { 653 if (!fGrabActiveWindow || !frame) 654 return B_ERROR; 655 656 int32* tokens; 657 int32 tokenCount; 658 status_t status = BPrivate::get_window_order(current_workspace(), &tokens, 659 &tokenCount); 660 if (status != B_OK || !tokens || tokenCount < 1) 661 return B_ERROR; 662 663 status = B_ERROR; 664 for (int32 i = 0; i < tokenCount; ++i) { 665 client_window_info* windowInfo = get_window_info(tokens[i]); 666 if (!windowInfo->is_mini && !windowInfo->show_hide_level > 0) { 667 frame->left = windowInfo->window_left; 668 frame->top = windowInfo->window_top; 669 frame->right = windowInfo->window_right; 670 frame->bottom = windowInfo->window_bottom; 671 672 status = B_OK; 673 if (fIncludeBorder) { 674 float border = (windowInfo->border_size); 675 frame->InsetBy(-(border), -(border)); 676 frame->top -= windowInfo->tab_height; 677 } 678 free(windowInfo); 679 680 BRect screenFrame(BScreen(this).Frame()); 681 if (frame->left < screenFrame.left) 682 frame->left = screenFrame.left; 683 if (frame->top < screenFrame.top) 684 frame->top = screenFrame.top; 685 if (frame->right > screenFrame.right) 686 frame->right = screenFrame.right; 687 if (frame->bottom > screenFrame.bottom) 688 frame->bottom = screenFrame.bottom; 689 690 break; 691 } 692 free(windowInfo); 693 } 694 free(tokens); 695 return status; 696 } 697 698 699 status_t 700 ScreenshotWindow::_SaveScreenshot() 701 { 702 if (!fScreenshot || !fLastSelectedPath) 703 return B_ERROR; 704 705 const char* _path; 706 BMessage* message = fLastSelectedPath->Message(); 707 if (!message || message->FindString("path", &_path) != B_OK) 708 return B_ERROR; 709 710 BEntry entry; 711 BPath path; 712 713 path = _path; 714 path.Append(fNameControl->Text()); 715 entry.SetTo(path.Path()); 716 717 if (entry.Exists()) { 718 BAlert *myAlert = new BAlert("overwrite", "This file already exists.\n" 719 "Are you sure would you like to overwrite it?", 720 "Cancel", "Overwrite", NULL, 721 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 722 723 myAlert->SetShortcut(0, B_ESCAPE); 724 int32 button_index = myAlert->Go(); 725 if (button_index == 0) { 726 return B_CANCELED; 727 } 728 } 729 730 BFile file(&entry, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); 731 if (file.InitCheck() != B_OK) { 732 return B_ERROR; 733 } 734 BBitmapStream bitmapStream(fScreenshot); 735 BTranslatorRoster* roster = BTranslatorRoster::Default(); 736 roster->Translate(&bitmapStream, NULL, NULL, &file, fImageFileType, 737 B_TRANSLATOR_BITMAP); 738 fScreenshot = NULL; 739 740 BNodeInfo nodeInfo(&file); 741 if (nodeInfo.InitCheck() != B_OK) 742 return B_ERROR; 743 744 int32 numFormats; 745 const translation_format* formats = NULL; 746 if (roster->GetOutputFormats(fTranslator, &formats, &numFormats) != B_OK) 747 return B_OK; 748 749 for (int32 i = 0; i < numFormats; ++i) { 750 if (formats[i].type == uint32(fImageFileType)) { 751 nodeInfo.SetType(formats[i].MIME); 752 break; 753 } 754 } 755 return B_OK; 756 } 757 758 759 void 760 ScreenshotWindow::_SaveScreenshotSilent() const 761 { 762 if (!fScreenshot) 763 return; 764 765 BPath homePath; 766 if (find_directory(B_USER_DIRECTORY, &homePath) != B_OK) { 767 fprintf(stderr, "failed to find user home folder\n"); 768 return; 769 } 770 771 BPath path; 772 BEntry entry; 773 int32 index = 1; 774 do { 775 char filename[32]; 776 sprintf(filename, "screenshot%ld", index++); 777 path = homePath; 778 path.Append(filename); 779 entry.SetTo(path.Path()); 780 } while (entry.Exists()); 781 782 // Dump to PNG 783 SaveToPNG(path.Path(), fScreenshot->Bounds(), fScreenshot->ColorSpace(), 784 fScreenshot->Bits(), fScreenshot->BitsLength(), 785 fScreenshot->BytesPerRow()); 786 } 787