1/*
2 * Copyright 2003-2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Jérôme Duval
7 */
8
9
10#include "PasswordAlert.h"
11
12#include <string.h>
13
14#include <File.h>
15#include <FindDirectory.h>
16#include <IconUtils.h>
17#include <Path.h>
18#include <Resources.h>
19#include <Screen.h>
20#include <View.h>
21
22
23static const int kWindowIconOffset = 27;
24static const int kIconStripeWidth = 30;
25static const int kTextIconOffset = kWindowIconOffset + kIconStripeWidth - 2;
26static const int kTextTopOffset = 6;
27static const int kSemTimeOut = 50000;
28
29
30class TAlertView : public BView {
31public:
32							TAlertView(BRect frame);
33							TAlertView(BMessage* archive);
34							~TAlertView();
35
36	virtual void			Draw(BRect updateRect);
37
38			void			SetBitmap(BBitmap* Icon) { fIconBitmap = Icon; }
39			BBitmap*		Bitmap() { return fIconBitmap; }
40
41private:
42			BBitmap*		fIconBitmap;
43};
44
45
46//	#pragma mark - PasswordAlert
47
48
49PasswordAlert::PasswordAlert(const char* title, const char* text)
50	:
51	BWindow(BRect(0, 0, 450, 45), title, B_MODAL_WINDOW,
52		B_NOT_CLOSABLE | B_NOT_RESIZABLE),
53	fTextControl(NULL),
54	fAlertSem(-1)
55{
56	// Set up the "_master_" view
57	TAlertView* masterView = new TAlertView(Bounds());
58	masterView->SetBitmap(InitIcon());
59	AddChild(masterView);
60
61	// Set up the text view
62	BRect textControlRect(kTextIconOffset, kTextTopOffset,
63		Bounds().right - 5, Bounds().bottom);
64
65	fTextControl = new BTextControl(textControlRect, "_password_", text,
66		NULL, new BMessage('pass'), B_FOLLOW_ALL);
67	fTextControl->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
68	fTextControl->TextView()->HideTyping(true);
69	fTextControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
70	fTextControl->SetDivider(10 + fTextControl->StringWidth(text));
71
72	masterView->AddChild(fTextControl);
73
74	BRect screenFrame = BScreen(B_MAIN_SCREEN_ID).Frame();
75	BPoint point;
76	point.x = screenFrame.Width() / 2 - Bounds().Width() / 2;
77	point.y = screenFrame.Height() / 2 - Bounds().Height() / 2;
78	if (screenFrame.Contains(point))
79		MoveTo(point);
80
81	fTextControl->MakeFocus();
82}
83
84
85PasswordAlert::~PasswordAlert()
86{
87}
88
89
90BBitmap*
91PasswordAlert::InitIcon()
92{
93	// The alert icons are in the app_server resources
94	BBitmap* icon = NULL;
95	BPath path;
96	if (find_directory(B_BEOS_SERVERS_DIRECTORY, &path) == B_OK) {
97		path.Append("app_server");
98		BFile file;
99		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK) {
100			BResources resources;
101			if (resources.SetTo(&file) == B_OK) {
102				// Which icon are we trying to load?
103				const char* iconName = "warn";
104
105				// Load the raw icon data
106				size_t size;
107				const void* rawIcon
108					= resources.LoadResource(B_VECTOR_ICON_TYPE, iconName,
109						&size);
110
111				if (rawIcon != NULL) {
112					// Now build the bitmap
113					icon = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32);
114					if (BIconUtils::GetVectorIcon((const uint8*)rawIcon, size,
115							icon) != B_OK) {
116						delete icon;
117						return NULL;
118					}
119				}
120			}
121		}
122	}
123
124	return icon;
125}
126
127
128void
129PasswordAlert::Go(BString& password)
130{
131	fAlertSem = create_sem(0, "AlertSem");
132	if (fAlertSem < B_OK) {
133		Quit();
134		return;
135	}
136
137	// Get the originating window, if it exists
138	BWindow* window
139		= dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
140
141	Show();
142
143	// Heavily modified from TextEntryAlert code; the original didn't let the
144	// blocked window ever draw.
145	if (window != NULL) {
146		status_t result;
147		for (;;) {
148			do {
149				result = acquire_sem_etc(fAlertSem, 1, B_RELATIVE_TIMEOUT,
150					kSemTimeOut);
151				// We've (probably) had our time slice taken away from us
152			} while (result == B_INTERRUPTED);
153
154			if (result == B_BAD_SEM_ID) {
155				// Semaphore was finally nuked in MessageReceived
156				break;
157			}
158			window->UpdateIfNeeded();
159		}
160	} else {
161		// No window to update, so just hang out until we're done.
162		while (acquire_sem(fAlertSem) == B_INTERRUPTED) {
163			;
164		}
165	}
166
167	// Have to cache the value since we delete on Quit()
168	password = fTextControl->Text();
169	if (Lock())
170		Quit();
171}
172
173
174void
175PasswordAlert::MessageReceived(BMessage* msg)
176{
177	if (msg->what != 'pass')
178		return BWindow::MessageReceived(msg);
179
180	delete_sem(fAlertSem);
181	fAlertSem = -1;
182}
183
184
185//	#pragma mark - TAlertView
186
187
188TAlertView::TAlertView(BRect frame)
189	:
190	BView(frame, "TAlertView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
191	fIconBitmap(NULL)
192{
193	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
194}
195
196
197TAlertView::~TAlertView()
198{
199	delete fIconBitmap;
200}
201
202
203void
204TAlertView::Draw(BRect updateRect)
205{
206	// Here's the fun stuff
207	if (fIconBitmap != NULL) {
208		BRect stripeRect = Bounds();
209		stripeRect.right = kIconStripeWidth;
210		SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
211		FillRect(stripeRect);
212
213		SetDrawingMode(B_OP_ALPHA);
214		DrawBitmapAsync(fIconBitmap, BPoint(18, 6));
215		SetDrawingMode(B_OP_COPY);
216	}
217}
218