xref: /haiku/src/apps/screenshot/ScreenshotWindow.cpp (revision 155fa31ec619414bb0e0fb1ffe9ad913e4ecd398)
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