registrar: Shutdown Icon Animation
In the case that an application is blocked by a model panel during shutdown, the icon will now show a "waiting" animation like in BeOS R5. Fixes #7980 Change-Id: Iec79fcaf431407ff51430a1a8e4c8ec41571059d Reviewed-on: https://review.haiku-os.org/c/haiku/+/4001 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
parent
8f265e03c9
commit
65f4a22735
@ -3,6 +3,7 @@
|
||||
* Copyright 2006-2009, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2006-2008, Stephan Aßmus.
|
||||
* Copyright 2006, Ryan Leavengood.
|
||||
* Copyright 2021, Jacob Secunda.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
@ -76,6 +77,10 @@ static const int kStripeWidth = 30;
|
||||
static const int kIconVSpacing = 6;
|
||||
static const int kIconSize = 32;
|
||||
|
||||
// The speed of the animation played when an application is blocked on a modal
|
||||
// panel.
|
||||
static const bigtime_t kIconAnimateInterval = 50000; // 0.05 s
|
||||
|
||||
// message what fields (must not clobber the registrar's message namespace)
|
||||
enum {
|
||||
MSG_PHASE_TIMED_OUT = 'phto',
|
||||
@ -414,18 +419,16 @@ public:
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t AddApp(team_id team, BBitmap* miniIcon, BBitmap* largeIcon)
|
||||
status_t AddApp(team_id team, BBitmap* appIcon)
|
||||
{
|
||||
AppInfo* info = new(nothrow) AppInfo;
|
||||
if (!info) {
|
||||
delete miniIcon;
|
||||
delete largeIcon;
|
||||
delete appIcon;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
info->team = team;
|
||||
info->miniIcon = miniIcon;
|
||||
info->largeIcon = largeIcon;
|
||||
info->appIcon = appIcon;
|
||||
|
||||
if (!fAppInfos.AddItem(info)) {
|
||||
delete info;
|
||||
@ -480,6 +483,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SetWaitAnimationEnabled(bool enable)
|
||||
{
|
||||
fRootView->IconWaitAnimationEnabled(enable);
|
||||
}
|
||||
|
||||
void SetWaitForShutdown()
|
||||
{
|
||||
fKillAppButton->Hide();
|
||||
@ -507,13 +515,11 @@ public:
|
||||
private:
|
||||
struct AppInfo {
|
||||
team_id team;
|
||||
BBitmap *miniIcon;
|
||||
BBitmap *largeIcon;
|
||||
BBitmap* appIcon;
|
||||
|
||||
~AppInfo()
|
||||
{
|
||||
delete miniIcon;
|
||||
delete largeIcon;
|
||||
delete appIcon;
|
||||
}
|
||||
};
|
||||
|
||||
@ -539,12 +545,29 @@ private:
|
||||
class TAlertView : public BView {
|
||||
public:
|
||||
TAlertView(BRect frame, const char* name, uint32 resizeMask,
|
||||
uint32 flags)
|
||||
: BView(frame, name, resizeMask, flags | B_WILL_DRAW),
|
||||
fAppInfo(NULL)
|
||||
uint32 flags)
|
||||
:
|
||||
BView(frame, name, resizeMask, flags | B_WILL_DRAW),
|
||||
fCurrentIconBitmap(NULL),
|
||||
fNormalIconBitmap(NULL),
|
||||
fTintedIconBitmap(NULL),
|
||||
fAnimationActive(false),
|
||||
fAnimationWorker(-1),
|
||||
fCurrentAnimationRow(-1),
|
||||
fAnimationLightenPhase(true)
|
||||
{
|
||||
}
|
||||
|
||||
~TAlertView()
|
||||
{
|
||||
atomic_set(&fAnimationActive, false);
|
||||
wait_for_thread(fAnimationWorker, NULL);
|
||||
|
||||
delete fCurrentIconBitmap;
|
||||
delete fNormalIconBitmap;
|
||||
delete fTintedIconBitmap;
|
||||
}
|
||||
|
||||
virtual void Draw(BRect updateRect)
|
||||
{
|
||||
BRect stripeRect = Bounds();
|
||||
@ -552,26 +575,193 @@ private:
|
||||
SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
|
||||
FillRect(stripeRect);
|
||||
|
||||
if (fAppInfo && fAppInfo->largeIcon) {
|
||||
if (fAppInfo->largeIcon->ColorSpace() == B_RGBA32) {
|
||||
if (fCurrentIconBitmap != NULL && fCurrentIconBitmap->IsValid()) {
|
||||
if (fCurrentIconBitmap->ColorSpace() == B_RGBA32) {
|
||||
SetDrawingMode(B_OP_ALPHA);
|
||||
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
||||
} else
|
||||
SetDrawingMode(B_OP_OVER);
|
||||
|
||||
DrawBitmapAsync(fAppInfo->largeIcon,
|
||||
DrawBitmap(fCurrentIconBitmap,
|
||||
BPoint(kStripeWidth - kIconSize / 2, kIconVSpacing));
|
||||
}
|
||||
}
|
||||
|
||||
void SetAppInfo(AppInfo* info)
|
||||
{
|
||||
fAppInfo = info;
|
||||
IconWaitAnimationEnabled(false);
|
||||
|
||||
BAutolock lock(Window());
|
||||
if (!lock.IsLocked())
|
||||
return;
|
||||
|
||||
delete fCurrentIconBitmap;
|
||||
fCurrentIconBitmap = NULL;
|
||||
|
||||
delete fNormalIconBitmap;
|
||||
fNormalIconBitmap = NULL;
|
||||
|
||||
delete fTintedIconBitmap;
|
||||
fTintedIconBitmap = NULL;
|
||||
|
||||
if (info != NULL && info->appIcon != NULL
|
||||
&& info->appIcon->IsValid()) {
|
||||
fCurrentIconBitmap = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32);
|
||||
|
||||
if (fCurrentIconBitmap == NULL
|
||||
|| fCurrentIconBitmap->ImportBits(info->appIcon) != B_OK) {
|
||||
delete fCurrentIconBitmap;
|
||||
fCurrentIconBitmap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void IconWaitAnimationEnabled(bool enable)
|
||||
{
|
||||
if (atomic_get(&fAnimationActive) == enable)
|
||||
return;
|
||||
|
||||
BAutolock lock(Window());
|
||||
if (!lock.IsLocked())
|
||||
return;
|
||||
|
||||
if (enable) {
|
||||
if (fCurrentIconBitmap == NULL
|
||||
|| !fCurrentIconBitmap->IsValid())
|
||||
return;
|
||||
|
||||
if (fNormalIconBitmap == NULL
|
||||
|| !fNormalIconBitmap->IsValid()) {
|
||||
delete fNormalIconBitmap;
|
||||
fNormalIconBitmap = NULL;
|
||||
|
||||
fNormalIconBitmap = new BBitmap(BRect(0, 0, 31, 31),
|
||||
B_BITMAP_NO_SERVER_LINK, B_RGBA32);
|
||||
|
||||
if (fNormalIconBitmap == NULL
|
||||
|| fNormalIconBitmap->ImportBits(fCurrentIconBitmap)
|
||||
!= B_OK) {
|
||||
delete fNormalIconBitmap;
|
||||
fNormalIconBitmap = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fTintedIconBitmap == NULL
|
||||
|| !fTintedIconBitmap->IsValid()) {
|
||||
delete fTintedIconBitmap;
|
||||
fTintedIconBitmap = NULL;
|
||||
|
||||
fTintedIconBitmap = new BBitmap(BRect(0, 0, 31, 31),
|
||||
B_BITMAP_NO_SERVER_LINK, B_RGBA32);
|
||||
|
||||
if (fTintedIconBitmap == NULL
|
||||
|| fTintedIconBitmap->ImportBits(fNormalIconBitmap)
|
||||
!= B_OK) {
|
||||
delete fTintedIconBitmap;
|
||||
fTintedIconBitmap = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int32 width =
|
||||
fTintedIconBitmap->Bounds().IntegerWidth() + 1;
|
||||
int32 height =
|
||||
fTintedIconBitmap->Bounds().IntegerHeight() + 1;
|
||||
int32 rowLength = fTintedIconBitmap->BytesPerRow();
|
||||
|
||||
uint8* iconBits = (uint8*)fTintedIconBitmap->Bits();
|
||||
|
||||
for (int32 y = 0; y < height; y++) {
|
||||
for (int32 x = 0; x < width; x++) {
|
||||
int32 offset = (y * rowLength) + (x * 4);
|
||||
|
||||
rgb_color pixelColor = make_color(iconBits[offset],
|
||||
iconBits[offset + 1], iconBits[offset + 2],
|
||||
iconBits[offset + 3]);
|
||||
|
||||
pixelColor = tint_color(pixelColor,
|
||||
B_DARKEN_2_TINT);
|
||||
|
||||
iconBits[offset] = pixelColor.red;
|
||||
iconBits[offset + 1] = pixelColor.green;
|
||||
iconBits[offset + 2] = pixelColor.blue;
|
||||
iconBits[offset + 3] = pixelColor.alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fAnimationWorker = spawn_thread(&_AnimateWaitIconWorker,
|
||||
"thumb twiddling", B_DISPLAY_PRIORITY, this);
|
||||
|
||||
if (fAnimationWorker < B_NO_ERROR)
|
||||
return;
|
||||
|
||||
atomic_set(&fAnimationActive, true);
|
||||
if (resume_thread(fAnimationWorker) != B_OK)
|
||||
atomic_set(&fAnimationActive, false);
|
||||
} else {
|
||||
atomic_set(&fAnimationActive, false);
|
||||
wait_for_thread(fAnimationWorker, NULL);
|
||||
|
||||
fCurrentAnimationRow = -1;
|
||||
fAnimationLightenPhase = true;
|
||||
|
||||
if (fCurrentIconBitmap != NULL && fNormalIconBitmap != NULL)
|
||||
fCurrentIconBitmap->ImportBits(fNormalIconBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const AppInfo *fAppInfo;
|
||||
status_t _AnimateWaitIcon()
|
||||
{
|
||||
while (atomic_get(&fAnimationActive)) {
|
||||
if (LockLooperWithTimeout(kIconAnimateInterval) != B_OK)
|
||||
continue;
|
||||
|
||||
if (fCurrentAnimationRow < 0) {
|
||||
fCurrentAnimationRow =
|
||||
fCurrentIconBitmap->Bounds().IntegerHeight();
|
||||
fAnimationLightenPhase = !fAnimationLightenPhase;
|
||||
}
|
||||
|
||||
BBitmap* sourceBitmap = fAnimationLightenPhase ?
|
||||
fNormalIconBitmap : fTintedIconBitmap;
|
||||
|
||||
fCurrentIconBitmap->ImportBits(sourceBitmap,
|
||||
BPoint(0, fCurrentAnimationRow),
|
||||
BPoint(0, fCurrentAnimationRow),
|
||||
sourceBitmap->Bounds().IntegerWidth(), 1);
|
||||
|
||||
fCurrentAnimationRow--;
|
||||
|
||||
Invalidate();
|
||||
|
||||
UnlockLooper();
|
||||
|
||||
snooze(kIconAnimateInterval);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t _AnimateWaitIconWorker(void* cookie)
|
||||
{
|
||||
TAlertView* ourView = (TAlertView*)cookie;
|
||||
return ourView->_AnimateWaitIcon();
|
||||
}
|
||||
|
||||
private:
|
||||
BBitmap* fCurrentIconBitmap;
|
||||
BBitmap* fNormalIconBitmap;
|
||||
BBitmap* fTintedIconBitmap;
|
||||
int32 fAnimationActive;
|
||||
thread_id fAnimationWorker;
|
||||
int32 fCurrentAnimationRow;
|
||||
bool fAnimationLightenPhase;
|
||||
};
|
||||
|
||||
private:
|
||||
@ -1006,35 +1196,21 @@ ShutdownProcess::_AddShutdownWindowApps(AppInfoList& infos)
|
||||
strerror(error));
|
||||
}
|
||||
|
||||
// get the application icons
|
||||
color_space format = B_RGBA32;
|
||||
|
||||
// mini icon
|
||||
BBitmap* miniIcon = new(nothrow) BBitmap(BRect(0, 0, 15, 15), format);
|
||||
if (miniIcon != NULL) {
|
||||
error = miniIcon->InitCheck();
|
||||
// get the application icon
|
||||
BBitmap* appIcon = new(nothrow) BBitmap(BRect(0, 0, 31, 31),
|
||||
B_BITMAP_NO_SERVER_LINK, B_RGBA32);
|
||||
if (appIcon != NULL) {
|
||||
error = appIcon->InitCheck();
|
||||
if (error == B_OK)
|
||||
error = appFileInfo.GetTrackerIcon(miniIcon, B_MINI_ICON);
|
||||
error = appFileInfo.GetTrackerIcon(appIcon, B_LARGE_ICON);
|
||||
if (error != B_OK) {
|
||||
delete miniIcon;
|
||||
miniIcon = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// mini icon
|
||||
BBitmap* largeIcon = new(nothrow) BBitmap(BRect(0, 0, 31, 31), format);
|
||||
if (largeIcon != NULL) {
|
||||
error = largeIcon->InitCheck();
|
||||
if (error == B_OK)
|
||||
error = appFileInfo.GetTrackerIcon(largeIcon, B_LARGE_ICON);
|
||||
if (error != B_OK) {
|
||||
delete largeIcon;
|
||||
largeIcon = NULL;
|
||||
delete appIcon;
|
||||
appIcon = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// add the app
|
||||
error = fWindow->AddApp(info->team, miniIcon, largeIcon);
|
||||
error = fWindow->AddApp(info->team, appIcon);
|
||||
if (error != B_OK) {
|
||||
WARNING("ShutdownProcess::_AddShutdownWindowApps(): Failed to "
|
||||
"add app to the shutdown window: %s\n", strerror(error));
|
||||
@ -1098,6 +1274,17 @@ ShutdownProcess::_SetShutdownWindowKillButtonEnabled(bool enabled)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ShutdownProcess::_SetShutdownWindowWaitAnimationEnabled(bool enabled)
|
||||
{
|
||||
if (fHasGUI) {
|
||||
BAutolock _(fWindow);
|
||||
|
||||
fWindow->SetWaitAnimationEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ShutdownProcess::_SetShutdownWindowWaitForShutdown()
|
||||
{
|
||||
@ -1719,6 +1906,7 @@ ShutdownProcess::_QuitBlockingApp(AppInfoList& list, team_id team,
|
||||
_SetShutdownWindowText(buffer.String());
|
||||
_SetShutdownWindowCurrentApp(team);
|
||||
_SetShutdownWindowKillButtonEnabled(true);
|
||||
_SetShutdownWindowWaitAnimationEnabled(true);
|
||||
}
|
||||
|
||||
if (modal || debugged) {
|
||||
@ -1760,6 +1948,7 @@ ShutdownProcess::_QuitBlockingApp(AppInfoList& list, team_id team,
|
||||
}
|
||||
|
||||
_SetShutdownWindowKillButtonEnabled(false);
|
||||
_SetShutdownWindowWaitAnimationEnabled(false);
|
||||
|
||||
if (appGone)
|
||||
return;
|
||||
@ -1816,6 +2005,7 @@ ShutdownProcess::_DisplayAbortingApp(team_id team)
|
||||
buffer.ReplaceFirst("%appName%", appName);
|
||||
|
||||
// set up the window
|
||||
_SetShutdownWindowWaitAnimationEnabled(false);
|
||||
_SetShutdownWindowCurrentApp(team);
|
||||
_SetShutdownWindowText(buffer.String());
|
||||
_SetShutdownWindowWaitForAbortedOK();
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
|
||||
* Copyright 2021, Jacob Secunda.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Manages the shutdown process.
|
||||
@ -64,6 +66,8 @@ private:
|
||||
bool enabled);
|
||||
void _SetShutdownWindowKillButtonEnabled(
|
||||
bool enabled);
|
||||
void _SetShutdownWindowWaitAnimationEnabled(
|
||||
bool enabled);
|
||||
void _SetShutdownWindowWaitForShutdown();
|
||||
void _SetShutdownWindowWaitForAbortedOK();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user