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