1 /* 2 * Copyright 2009 Vincent Duvert, vincent.duvert@free.fr 3 * Copyright 2014 Haiku, Inc. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 * 7 * Authors: 8 * Vincent Duvert, vincent.duvert@free.fr 9 * John Scipione, jscipione@gmail.com 10 */ 11 12 13 #include "IconsSaver.h" 14 15 #include <stdlib.h> 16 17 #include <Bitmap.h> 18 #include <Catalog.h> 19 #include <DefaultSettingsView.h> 20 #include <MimeType.h> 21 22 #include "IconDisplay.h" 23 #include "VectorIcon.h" 24 25 26 #undef B_TRANSLATION_CONTEXT 27 #define B_TRANSLATION_CONTEXT "Screensaver Icons" 28 29 30 #define RAND_BETWEEN(a, b) ((rand() % ((b) - (a) + 1) + (a))) 31 32 33 static const int32 kMaxConcurrentIcons = 15; 34 static const int32 kMinIconWidthPercentage = 5; 35 // percentage of the screen width 36 static const int32 kMaxIconWidthPercentage = 20; 37 // same here 38 static const int32 kMinIconCount = 20; 39 static const int32 kMaxIconCount = 384; 40 41 42 const rgb_color kBackgroundColor = ui_color(B_DESKTOP_COLOR); 43 44 45 BScreenSaver* instantiate_screen_saver(BMessage* msg, image_id image) 46 { 47 return new IconsSaver(msg, image); 48 } 49 50 51 // #pragma mark - IconsSaver 52 53 54 IconsSaver::IconsSaver(BMessage* archive, image_id image) 55 : 56 BScreenSaver(archive, image), 57 fIcons(NULL), 58 fBackBitmap(NULL), 59 fBackView(NULL), 60 fMinSize(0), 61 fMaxSize(0) 62 { 63 } 64 65 66 IconsSaver::~IconsSaver() 67 { 68 vector_icon* icon; 69 while ((icon = fVectorIcons.RemoveItemAt((int32)0)) != NULL) { 70 delete[] icon->data; 71 free(icon); 72 } 73 } 74 75 76 status_t 77 IconsSaver::StartSaver(BView* view, bool /*preview*/) 78 { 79 if (fVectorIcons.CountItems() < kMinIconCount) 80 _GetVectorIcons(); 81 82 srand(system_time() % INT_MAX); 83 84 BRect screenRect(0, 0, view->Frame().Width(), view->Frame().Height()); 85 fBackBitmap = new BBitmap(screenRect, B_RGBA32, true); 86 if (!fBackBitmap->IsValid()) 87 return B_NO_MEMORY; 88 89 fBackView = new BView(screenRect, "back view", 0, 0); 90 if (fBackView == NULL) 91 return B_NO_MEMORY; 92 93 fBackView->SetViewColor(kBackgroundColor); 94 fBackView->SetHighColor(kBackgroundColor); 95 96 fBackBitmap->AddChild(fBackView); 97 if (fBackBitmap->Lock()) { 98 fBackView->FillRect(fBackView->Frame()); 99 fBackView->SetDrawingMode(B_OP_ALPHA); 100 fBackView->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 101 fBackView->Sync(); 102 fBackBitmap->Unlock(); 103 } 104 105 fIcons = new IconDisplay[kMaxConcurrentIcons]; 106 107 fMaxSize = (screenRect.IntegerWidth() * kMaxIconWidthPercentage) / 100; 108 fMinSize = (screenRect.IntegerWidth() * kMinIconWidthPercentage) / 100; 109 if (fMaxSize > 255) 110 fMaxSize = 255; 111 112 if (fMaxSize > screenRect.IntegerHeight()) 113 fMaxSize = screenRect.IntegerHeight(); 114 115 if (fMinSize > fMaxSize) 116 fMinSize = fMaxSize; 117 118 return B_OK; 119 } 120 121 122 void 123 IconsSaver::StopSaver() 124 { 125 delete[] fIcons; 126 fIcons = NULL; 127 delete fBackBitmap; 128 fBackBitmap = NULL; 129 } 130 131 132 void 133 IconsSaver::Draw(BView* view, int32 frame) 134 { 135 static int32 previousFrame = 0; 136 137 // update drawing 138 if (fBackBitmap->Lock()) { 139 for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++) 140 fIcons[i].ClearOn(fBackView); 141 142 int32 delta = frame - previousFrame; 143 for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++) 144 fIcons[i].DrawOn(fBackView, delta); 145 146 fBackView->Sync(); 147 fBackBitmap->Unlock(); 148 } 149 150 // sync the view with the back buffer 151 view->DrawBitmap(fBackBitmap); 152 previousFrame = frame; 153 154 if (fVectorIcons.CountItems() < kMinIconCount) 155 return; 156 157 // restart one icon 158 for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++) { 159 if (!fIcons[i].IsRunning()) { 160 uint16 size = RAND_BETWEEN(fMinSize, fMaxSize); 161 uint16 maxX = view->Frame().IntegerWidth() - size; 162 uint16 maxY = view->Frame().IntegerHeight() - size; 163 164 BRect iconFrame(0, 0, size, size); 165 iconFrame.OffsetTo(RAND_BETWEEN(0, maxX), RAND_BETWEEN(0, maxY)); 166 167 // Check that the icon doesn't overlap with others 168 for (uint8 j = 0 ; j < kMaxConcurrentIcons ; j++) { 169 if (fIcons[j].IsRunning() && 170 iconFrame.Intersects(fIcons[j].GetFrame())) 171 return; 172 } 173 174 int32 index = RAND_BETWEEN(0, fVectorIcons.CountItems() - 1); 175 fIcons[i].Run(fVectorIcons.ItemAt(index), iconFrame); 176 return; 177 } 178 } 179 } 180 181 182 void 183 IconsSaver::StartConfig(BView* view) 184 { 185 BPrivate::BuildDefaultSettingsView(view, "Icons", 186 B_TRANSLATE("by Vincent Duvert")); 187 } 188 189 190 // #pragma mark - IconsSaver private methods 191 192 193 void 194 IconsSaver::_GetVectorIcons() 195 { 196 // Load vector icons from the MIME type database 197 BMessage types; 198 if (BMimeType::GetInstalledTypes(&types) != B_OK) 199 return; 200 201 const char* type; 202 for (int32 i = 0; types.FindString("types", i, &type) == B_OK; i++) { 203 BMimeType mimeType(type); 204 if (mimeType.InitCheck() != B_OK) 205 continue; 206 207 uint8* data; 208 size_t size; 209 210 if (mimeType.GetIcon(&data, &size) != B_OK) { 211 // didn't find an icon 212 continue; 213 } 214 215 vector_icon* icon = (vector_icon*)malloc(sizeof(vector_icon)); 216 if (icon == NULL) { 217 // ran out of memory, delete the icon data 218 delete[] data; 219 continue; 220 } 221 222 icon->data = data; 223 icon->size = size; 224 225 // found a vector icon, add it to the list 226 fVectorIcons.AddItem(icon); 227 if (fVectorIcons.CountItems() >= kMaxIconCount) { 228 // this is enough to choose from, stop eating memory... 229 return; 230 } 231 } 232 } 233