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