xref: /haiku/src/apps/expander/PasswordAlert.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 
23 static const int kWindowIconOffset = 27;
24 static const int kIconStripeWidth = 30;
25 static const int kTextIconOffset = kWindowIconOffset + kIconStripeWidth - 2;
26 static const int kTextTopOffset = 6;
27 static const int kSemTimeOut = 50000;
28 
29 
30 class TAlertView : public BView {
31 public:
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 
41 private:
42 			BBitmap*		fIconBitmap;
43 };
44 
45 
46 //	#pragma mark - PasswordAlert
47 
48 
49 PasswordAlert::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 
85 PasswordAlert::~PasswordAlert()
86 {
87 }
88 
89 
90 BBitmap*
91 PasswordAlert::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 
128 void
129 PasswordAlert::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 
174 void
175 PasswordAlert::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 
188 TAlertView::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 
197 TAlertView::~TAlertView()
198 {
199 	delete fIconBitmap;
200 }
201 
202 
203 void
204 TAlertView::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