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