tcp: Add APICall trace entry and move TRACEs into locked parts.
[haiku.git] / src / add-ons / screen_savers / slideshowsaver / SlideShowSaver.cpp
blobcb029a9404552bb25b7c8d1460d244177045b69e
1 /*****************************************************************************/
2 // SlideShowSaver
3 // Written by Michael Wilber
4 // Slide show code derived from ShowImage code, written by Michael Pfeiffer
5 //
6 // SlideShowSaver.cpp
7 //
8 //
9 // Copyright (C) Haiku
11 // Permission is hereby granted, free of charge, to any person obtaining a
12 // copy of this software and associated documentation files (the "Software"),
13 // to deal in the Software without restriction, including without limitation
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 // and/or sell copies of the Software, and to permit persons to whom the
16 // Software is furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included
19 // in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 // DEALINGS IN THE SOFTWARE.
28 /*****************************************************************************/
31 #include "SlideShowSaver.h"
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
37 #include <BitmapStream.h>
38 #include <Catalog.h>
39 #include <Directory.h>
40 #include <File.h>
41 #include <List.h>
42 #include <Path.h>
43 #include <StringView.h>
44 #include <TranslatorRoster.h>
46 #include "SlideShowConfigView.h"
49 // Called by system to get the screen saver
50 extern "C" _EXPORT BScreenSaver *
51 instantiate_screen_saver(BMessage *message, image_id id)
53 return new SlideShowSaver(message, id);
56 // returns B_ERROR if problems reading ref
57 // B_OK if ref is not a directory
58 // B_OK + 1 if ref is a directory
59 status_t
60 ent_is_dir(const entry_ref *ref)
62 BEntry ent(ref);
63 if (ent.InitCheck() != B_OK)
64 return B_ERROR;
66 struct stat st;
67 if (ent.GetStat(&st) != B_OK)
68 return B_ERROR;
70 return S_ISDIR(st.st_mode) ? (B_OK + 1) : B_OK;
73 int CompareEntries(const void* a, const void* b)
75 entry_ref *r1, *r2;
76 r1 = *(entry_ref**)a;
77 r2 = *(entry_ref**)b;
78 return strcasecmp(r1->name, r2->name);
81 // Default settings for the Translator
82 LiveSetting gDefaultSettings[] = {
83 LiveSetting(CHANGE_CAPTION, SAVER_SETTING_CAPTION, true),
84 // Show image caption by default
85 LiveSetting(CHANGE_BORDER, SAVER_SETTING_BORDER, true),
86 // Show image border by default
87 LiveSetting(CHANGE_DIRECTORY, SAVER_SETTING_DIRECTORY, "/boot/home"),
88 // Set default image directory to home
89 LiveSetting(CHANGE_DELAY, SAVER_SETTING_DELAY, (int32) 3000)
90 // Default delay: 3 seconds
93 SlideShowSaver::SlideShowSaver(BMessage *archive, image_id image)
95 BScreenSaver(archive, image), fLock("SlideShow Lock")
97 B_TRANSLATE_MARK_SYSTEM_NAME_VOID("SlideShowSaver");
99 fNewDirectory = true;
100 fBitmap = NULL;
101 fShowBorder = true;
102 fShowCaption = true;
104 fSettings = new LiveSettings("SlideShowSaver_Settings",
105 gDefaultSettings, sizeof(gDefaultSettings) / sizeof(LiveSetting));
106 fSettings->LoadSettings();
107 // load settings from the settings file
109 fSettings->AddObserver(this);
112 SlideShowSaver::~SlideShowSaver()
114 delete fBitmap;
115 fBitmap = NULL;
117 fSettings->RemoveObserver(this);
118 fSettings->Release();
121 // Called by fSettings to notify that someone has changed
122 // a setting. For example, if the user changes a setting
123 // on the config panel, this will be called to notify this
124 // object.
125 void
126 SlideShowSaver::SettingChanged(uint32 setting)
128 switch (setting) {
129 case CHANGE_CAPTION:
130 UpdateShowCaption();
131 break;
132 case CHANGE_BORDER:
133 UpdateShowBorder();
134 break;
135 case CHANGE_DIRECTORY:
136 UpdateDirectory();
137 break;
138 case CHANGE_DELAY:
139 UpdateTickSize();
140 break;
142 default:
143 break;
147 status_t
148 SlideShowSaver::UpdateTickSize()
150 // Tick size is in microseconds, but is stored in settings as
151 // milliseconds
152 bigtime_t ticks = static_cast<bigtime_t>
153 (fSettings->SetGetInt32(SAVER_SETTING_DELAY)) * 1000;
154 SetTickSize(ticks);
156 return B_OK;
159 status_t
160 SlideShowSaver::UpdateShowCaption()
162 fShowCaption = fSettings->SetGetBool(SAVER_SETTING_CAPTION);
163 return B_OK;
166 status_t
167 SlideShowSaver::UpdateShowBorder()
169 fShowBorder = fSettings->SetGetBool(SAVER_SETTING_BORDER);
170 return B_OK;
173 status_t
174 SlideShowSaver::UpdateDirectory()
176 status_t result = B_OK;
178 fLock.Lock();
180 BString strDirectory;
181 fSettings->GetString(SAVER_SETTING_DIRECTORY, strDirectory);
182 BDirectory dir(strDirectory.String());
183 if (dir.InitCheck() != B_OK || dir.GetNextRef(&fCurrentRef) != B_OK)
184 result = B_ERROR;
185 // Use ShowNextImage to find which translatable image is
186 // alphabetically first in the given directory, and load it
187 if (result == B_OK && ShowNextImage(true, true) == false)
188 result = B_ERROR;
190 fNewDirectory = true;
192 fLock.Unlock();
194 return result;
197 void
198 SlideShowSaver::StartConfig(BView *view)
200 view->AddChild(new SlideShowConfigView(
201 BRect(10, 10, 250, 300), "SlideShowSaver Config",
202 B_FOLLOW_ALL, B_WILL_DRAW, fSettings->Acquire()));
205 status_t
206 SlideShowSaver::StartSaver(BView *view, bool preview)
208 UpdateShowCaption();
209 UpdateShowBorder();
211 if (UpdateDirectory() != B_OK)
212 return B_ERROR;
214 // Read ticksize setting and set it as the delay
215 UpdateTickSize();
217 return B_OK;
220 void
221 SlideShowSaver::Draw(BView *view, int32 frame)
223 fLock.Lock();
225 view->SetLowColor(0, 0, 0);
226 view->SetHighColor(192, 192, 192);
227 view->SetViewColor(192, 192, 192);
229 bool bResult = false;
230 if (fNewDirectory == true) {
231 // Already have a bitmap on the first frame
232 bResult = true;
233 } else {
234 bResult = ShowNextImage(true, false);
235 // try rewinding to beginning
236 if (bResult == false)
237 bResult = ShowNextImage(true, true);
239 fNewDirectory = false;
241 if (bResult == true && fBitmap != NULL) {
242 BRect destRect(0, 0, fBitmap->Bounds().Width(), fBitmap->Bounds().Height()),
243 vwBounds = view->Bounds();
245 if (destRect.Width() < vwBounds.Width()) {
246 destRect.OffsetBy((vwBounds.Width() - destRect.Width()) / 2, 0);
248 if (destRect.Height() < vwBounds.Height()) {
249 destRect.OffsetBy(0, (vwBounds.Height() - destRect.Height()) / 2);
252 BRect border = destRect, bounds = view->Bounds();
253 // top
254 view->FillRect(BRect(0, 0, bounds.right, border.top-1), B_SOLID_LOW);
255 // left
256 view->FillRect(BRect(0, border.top, border.left-1, border.bottom), B_SOLID_LOW);
257 // right
258 view->FillRect(BRect(border.right+1, border.top, bounds.right, border.bottom), B_SOLID_LOW);
259 // bottom
260 view->FillRect(BRect(0, border.bottom+1, bounds.right, bounds.bottom), B_SOLID_LOW);
262 if (fShowBorder == true) {
263 BRect strokeRect = destRect;
264 strokeRect.InsetBy(-1, -1);
265 view->StrokeRect(strokeRect);
268 view->DrawBitmap(fBitmap, fBitmap->Bounds(), destRect);
270 if (fShowCaption == true)
271 DrawCaption(view);
274 fLock.Unlock();
277 status_t
278 SlideShowSaver::SetImage(const entry_ref *pref)
280 entry_ref ref;
281 if (!pref)
282 ref = fCurrentRef;
283 else
284 ref = *pref;
286 BTranslatorRoster *proster = BTranslatorRoster::Default();
287 if (!proster)
288 return B_ERROR;
290 if (ent_is_dir(pref) != B_OK)
291 // if ref is erroneous or a directory, return error
292 return B_ERROR;
294 BFile file(&ref, B_READ_ONLY);
295 translator_info info;
296 memset(&info, 0, sizeof(translator_info));
297 BMessage ioExtension;
298 //if (ref != fCurrentRef)
299 // if new image, reset to first document
300 // fDocumentIndex = 1;
301 if (ioExtension.AddInt32("/documentIndex", 1 /*fDocumentIndex*/) != B_OK)
302 return B_ERROR;
303 if (proster->Identify(&file, &ioExtension, &info, 0, NULL,
304 B_TRANSLATOR_BITMAP) != B_OK)
305 return B_ERROR;
307 // Translate image data and create a new ShowImage window
308 BBitmapStream outstream;
309 if (proster->Translate(&file, &info, &ioExtension, &outstream,
310 B_TRANSLATOR_BITMAP) != B_OK)
311 return B_ERROR;
312 BBitmap *newBitmap = NULL;
313 if (outstream.DetachBitmap(&newBitmap) != B_OK)
314 return B_ERROR;
316 // Now that I've successfully loaded the new bitmap,
317 // I can be sure it is safe to delete the old one,
318 // and clear everything
319 delete fBitmap;
320 fBitmap = newBitmap;
321 newBitmap = NULL;
322 fCurrentRef = ref;
324 // Get path to use in caption
325 fCaption = "<< Unable to read the path >>";
326 BEntry entry(&fCurrentRef);
327 if (entry.InitCheck() == B_OK) {
328 BPath path(&entry);
329 if (path.InitCheck() == B_OK) {
330 fCaption = path.Path();
334 return B_OK;
337 // Function originally from Haiku ShowImage
338 bool
339 SlideShowSaver::ShowNextImage(bool next, bool rewind)
341 bool found;
342 entry_ref curRef, imgRef;
344 curRef = fCurrentRef;
345 found = FindNextImage(&curRef, &imgRef, next, rewind);
346 if (found) {
347 // Keep trying to load images until:
348 // 1. The image loads successfully
349 // 2. The last file in the directory is found (for find next or find first)
350 // 3. The first file in the directory is found (for find prev)
351 // 4. The call to FindNextImage fails for any other reason
352 while (SetImage(&imgRef) != B_OK) {
353 curRef = imgRef;
354 found = FindNextImage(&curRef, &imgRef, next, false);
355 if (!found)
356 return false;
358 return true;
360 return false;
363 // Function taken from Haiku ShowImage,
364 // function originally written by Michael Pfeiffer
365 bool
366 SlideShowSaver::IsImage(const entry_ref *pref)
368 if (!pref)
369 return false;
371 if (ent_is_dir(pref) != B_OK)
372 // if ref is erroneous or a directory, return false
373 return false;
375 BFile file(pref, B_READ_ONLY);
376 if (file.InitCheck() != B_OK)
377 return false;
379 BTranslatorRoster *proster = BTranslatorRoster::Default();
380 if (!proster)
381 return false;
383 BMessage ioExtension;
384 if (ioExtension.AddInt32("/documentIndex", 1) != B_OK)
385 return false;
387 translator_info info;
388 memset(&info, 0, sizeof(translator_info));
389 if (proster->Identify(&file, &ioExtension, &info, 0, NULL,
390 B_TRANSLATOR_BITMAP) != B_OK)
391 return false;
393 return true;
396 // Function taken from Haiku ShowImage,
397 // function originally written by Michael Pfeiffer
398 bool
399 SlideShowSaver::FindNextImage(entry_ref *in_current, entry_ref *out_image, bool next, bool rewind)
401 // ASSERT(next || !rewind);
402 BEntry curImage(in_current);
403 entry_ref entry, *ref;
404 BDirectory parent;
405 BList entries;
406 bool found = false;
407 int32 cur;
409 if (curImage.GetParent(&parent) != B_OK)
410 return false;
412 while (parent.GetNextRef(&entry) == B_OK) {
413 if (entry != *in_current) {
414 entries.AddItem(new entry_ref(entry));
415 } else {
416 // insert current ref, so we can find it easily after sorting
417 entries.AddItem(in_current);
421 entries.SortItems(CompareEntries);
423 cur = entries.IndexOf(in_current);
424 // ASSERT(cur >= 0);
426 // remove it so FreeEntries() does not delete it
427 entries.RemoveItem(in_current);
429 if (next) {
430 // find the next image in the list
431 if (rewind) cur = 0; // start with first
432 for (; (ref = (entry_ref*)entries.ItemAt(cur)) != NULL; cur ++) {
433 if (IsImage(ref)) {
434 found = true;
435 *out_image = (const entry_ref)*ref;
436 break;
439 } else {
440 // find the previous image in the list
441 cur --;
442 for (; cur >= 0; cur --) {
443 ref = (entry_ref*)entries.ItemAt(cur);
444 if (IsImage(ref)) {
445 found = true;
446 *out_image = (const entry_ref)*ref;
447 break;
452 FreeEntries(&entries);
453 return found;
456 // Function taken from Haiku ShowImage,
457 // function originally written by Michael Pfeiffer
458 void
459 SlideShowSaver::FreeEntries(BList *entries)
461 const int32 n = entries->CountItems();
462 for (int32 i = 0; i < n; i ++) {
463 entry_ref *ref = (entry_ref *)entries->ItemAt(i);
464 delete ref;
466 entries->MakeEmpty();
469 void
470 SlideShowSaver::LayoutCaption(BView *view, BFont &font, BPoint &pos, BRect &rect)
472 font_height fontHeight;
473 float width, height;
474 BRect bounds(view->Bounds());
475 font = be_plain_font;
476 width = font.StringWidth(fCaption.String()) + 1; // 1 for text shadow
477 font.GetHeight(&fontHeight);
478 height = fontHeight.ascent + fontHeight.descent;
479 // center text horizontally
480 pos.x = (bounds.left + bounds.right - width)/2;
481 // flush bottom
482 pos.y = bounds.bottom - fontHeight.descent - 5;
484 // background rectangle
485 rect.Set(0, 0, (width-1)+2, (height-1)+2+1); // 2 for border and 1 for text shadow
486 rect.OffsetTo(pos);
487 rect.OffsetBy(-1, -1-fontHeight.ascent); // -1 for border
490 void
491 SlideShowSaver::DrawCaption(BView *view)
493 BFont font;
494 BPoint pos;
495 BRect rect;
496 LayoutCaption(view, font, pos, rect);
498 view->PushState();
499 // draw background
500 view->SetDrawingMode(B_OP_ALPHA);
501 view->SetHighColor(0, 0, 255, 128);
502 view->FillRect(rect);
503 // draw text
504 view->SetDrawingMode(B_OP_OVER);
505 view->SetFont(&font);
506 view->SetLowColor(B_TRANSPARENT_COLOR);
507 // text shadow
508 pos += BPoint(1, 1);
509 view->SetHighColor(0, 0, 0);
510 view->SetPenSize(1);
511 view->DrawString(fCaption.String(), pos);
512 // text
513 pos -= BPoint(1, 1);
514 view->SetHighColor(255, 255, 0);
515 view->DrawString(fCaption.String(), pos);
516 view->PopState();