* Copyright 2009 Vincent Duvert, vincent.duvert@free.fr
* Copyright 2014 Haiku, Inc. All rights reserved.
*
* Distributed under the terms of the MIT License.
*
* Authors:
* Vincent Duvert, vincent.duvert@free.fr
* John Scipione, jscipione@gmail.com
*/
#include "IconsSaver.h"
#include <stdlib.h>
#include <Bitmap.h>
#include <Catalog.h>
#include <DefaultSettingsView.h>
#include <MimeType.h>
#include "IconDisplay.h"
#include "VectorIcon.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Screensaver Icons"
#define RAND_BETWEEN(a, b) ((rand() % ((b) - (a) + 1) + (a)))
static const int32 kMaxConcurrentIcons = 15;
static const int32 kMinIconWidthPercentage = 5;
static const int32 kMaxIconWidthPercentage = 20;
static const int32 kMinIconCount = 20;
static const int32 kMaxIconCount = 384;
const rgb_color kBackgroundColor = ui_color(B_DESKTOP_COLOR);
BScreenSaver* instantiate_screen_saver(BMessage* msg, image_id image)
{
return new IconsSaver(msg, image);
}
IconsSaver::IconsSaver(BMessage* archive, image_id image)
:
BScreenSaver(archive, image),
fIcons(NULL),
fBackBitmap(NULL),
fBackView(NULL),
fMinSize(0),
fMaxSize(0)
{
}
IconsSaver::~IconsSaver()
{
vector_icon* icon;
while ((icon = fVectorIcons.RemoveItemAt((int32)0)) != NULL) {
delete[] icon->data;
free(icon);
}
}
status_t
IconsSaver::StartSaver(BView* view, bool )
{
if (fVectorIcons.CountItems() < kMinIconCount)
_GetVectorIcons();
srand(system_time() % INT_MAX);
BRect screenRect(0, 0, view->Frame().Width(), view->Frame().Height());
fBackBitmap = new BBitmap(screenRect, B_RGBA32, true);
if (!fBackBitmap->IsValid())
return B_NO_MEMORY;
fBackView = new BView(screenRect, "back view", 0, 0);
if (fBackView == NULL)
return B_NO_MEMORY;
fBackView->SetViewColor(kBackgroundColor);
fBackView->SetHighColor(kBackgroundColor);
fBackBitmap->AddChild(fBackView);
if (fBackBitmap->Lock()) {
fBackView->FillRect(fBackView->Frame());
fBackView->SetDrawingMode(B_OP_ALPHA);
fBackView->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
fBackView->Sync();
fBackBitmap->Unlock();
}
fIcons = new IconDisplay[kMaxConcurrentIcons];
fMaxSize = (screenRect.IntegerWidth() * kMaxIconWidthPercentage) / 100;
fMinSize = (screenRect.IntegerWidth() * kMinIconWidthPercentage) / 100;
if (fMaxSize > 255)
fMaxSize = 255;
if (fMaxSize > screenRect.IntegerHeight())
fMaxSize = screenRect.IntegerHeight();
if (fMinSize > fMaxSize)
fMinSize = fMaxSize;
return B_OK;
}
void
IconsSaver::StopSaver()
{
delete[] fIcons;
fIcons = NULL;
delete fBackBitmap;
fBackBitmap = NULL;
}
void
IconsSaver::Draw(BView* view, int32 frame)
{
static int32 previousFrame = 0;
if (fBackBitmap->Lock()) {
for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++)
fIcons[i].ClearOn(fBackView);
int32 delta = frame - previousFrame;
for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++)
fIcons[i].DrawOn(fBackView, delta);
fBackView->Sync();
fBackBitmap->Unlock();
}
view->DrawBitmap(fBackBitmap);
previousFrame = frame;
if (fVectorIcons.CountItems() < kMinIconCount)
return;
for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++) {
if (!fIcons[i].IsRunning()) {
uint16 size = RAND_BETWEEN(fMinSize, fMaxSize);
uint16 maxX = view->Frame().IntegerWidth() - size;
uint16 maxY = view->Frame().IntegerHeight() - size;
BRect iconFrame(0, 0, size, size);
iconFrame.OffsetTo(RAND_BETWEEN(0, maxX), RAND_BETWEEN(0, maxY));
for (uint8 j = 0 ; j < kMaxConcurrentIcons ; j++) {
if (fIcons[j].IsRunning() &&
iconFrame.Intersects(fIcons[j].GetFrame()))
return;
}
int32 index = RAND_BETWEEN(0, fVectorIcons.CountItems() - 1);
fIcons[i].Run(fVectorIcons.ItemAt(index), iconFrame);
return;
}
}
}
void
IconsSaver::StartConfig(BView* view)
{
BPrivate::BuildDefaultSettingsView(view, "Icons",
B_TRANSLATE("by Vincent Duvert"));
}
void
IconsSaver::_GetVectorIcons()
{
BMessage types;
if (BMimeType::GetInstalledTypes(&types) != B_OK)
return;
const char* type;
for (int32 i = 0; types.FindString("types", i, &type) == B_OK; i++) {
BMimeType mimeType(type);
if (mimeType.InitCheck() != B_OK)
continue;
uint8* data;
size_t size;
if (mimeType.GetIcon(&data, &size) != B_OK) {
continue;
}
vector_icon* icon = (vector_icon*)malloc(sizeof(vector_icon));
if (icon == NULL) {
delete[] data;
continue;
}
icon->data = data;
icon->size = size;
fVectorIcons.AddItem(icon);
if (fVectorIcons.CountItems() >= kMaxIconCount) {
return;
}
}
}