xref: /haiku/src/add-ons/tracker/zipomatic/ZipOMatic.cpp (revision 03187b607b2b5eec7ee059f1ead09bdba14991fb)
1 // license: public domain
2 // authors: jonas.sundstrom@kirilla.com
3 
4 
5 #include "ZipOMatic.h"
6 
7 #include <Alert.h>
8 #include <Roster.h>
9 #include <Screen.h>
10 #include <TrackerAddOnAppLaunch.h>
11 
12 #include "ZipOMaticMisc.h"
13 #include "ZipOMaticWindow.h"
14 
15 
16 int
17 main()
18 {
19 	ZipOMatic app;
20 	app.Run();
21 
22 	return 0;
23 }
24 
25 
26 ZipOMatic::ZipOMatic()
27 	:
28 	BApplication(ZIPOMATIC_APP_SIG),
29 	fSettings(),
30 	fGotRefs(false),
31 	fInvoker(new BInvoker(new BMessage(ZIPPO_QUIT_OR_CONTINUE), NULL, this)),
32 	fWindowFrame(200, 200, 430, 310)
33 {
34 	status_t status = _ReadSettings();
35 
36 	if (status != B_OK)
37 		ErrorMessage("_ReadSettings()", status);
38 }
39 
40 
41 ZipOMatic::~ZipOMatic()
42 {
43 	status_t status = _WriteSettings();
44 
45 	if (status != B_OK)
46 		ErrorMessage("_WriteSettings()", status);
47 }
48 
49 
50 void
51 ZipOMatic::RefsReceived(BMessage* message)
52 {
53 	message->RemoveName("dir_ref");
54 
55 	entry_ref ref;
56 	if (message->FindRef("refs", &ref) != B_OK) {
57 		if (!IsLaunching())
58 			PostMessage(B_SILENT_RELAUNCH);
59 		return;
60 	}
61 
62 	if (IsLaunching())
63 		fGotRefs = true;
64 
65 	BMessage* msg = new BMessage(*message);
66 
67 	_UseExistingOrCreateNewWindow(msg);
68 }
69 
70 
71 void
72 ZipOMatic::ReadyToRun()
73 {
74 	if (!fGotRefs)
75 		_UseExistingOrCreateNewWindow();
76 }
77 
78 
79 void
80 ZipOMatic::MessageReceived(BMessage* message)
81 {
82 	switch (message->what) {
83 		case ZIPPO_WINDOW_QUIT:
84 		{
85 			BRect frame;
86 			if (message->FindRect("frame", &frame) == B_OK)
87 				fWindowFrame = frame;
88 			snooze(200000);
89 			if (CountWindows() == 0)
90 				Quit();
91 			break;
92 		}
93 		case B_SILENT_RELAUNCH:
94 			_SilentRelaunch();
95 			break;
96 
97 		case ZIPPO_QUIT_OR_CONTINUE:
98 		{
99 			int32 button;
100 			if (message->FindInt32("which", &button) == B_OK)
101 				if (button == 0) {
102 					_StopZipping();
103 				} else  {
104 					if (CountWindows() == 0)
105 						Quit();
106 				}
107 			break;
108 		}
109 
110 		default:
111 			BApplication::MessageReceived(message);
112 			break;
113 	}
114 }
115 
116 
117 bool
118 ZipOMatic::QuitRequested  (void)
119 {
120 	if (CountWindows() <= 0)
121 		return true;
122 
123 	BWindow* window;
124 	ZippoWindow* zippo;
125 	ZippoWindow* lastFoundZippo = NULL;
126 	int32 zippoCount = 0;
127 
128 	for (int32 i = 0;; i++) {
129 		window = WindowAt(i);
130 		if (window == NULL)
131 			break;
132 
133 		zippo = dynamic_cast<ZippoWindow*>(window);
134 		if (zippo == NULL)
135 			continue;
136 
137 		lastFoundZippo = zippo;
138 
139 		if (zippo->Lock()) {
140 			if (zippo->IsZipping())
141 				zippoCount++;
142 			else
143 				zippo->PostMessage(B_QUIT_REQUESTED);
144 
145 			zippo->Unlock();
146 		}
147 	}
148 
149 	if (zippoCount == 1) {
150 		// This is likely the most frequent case - a single zipper.
151 		// We post a message to the window so it can put up its own
152 		// BAlert instead of the app-wide BAlert. This avoids making
153 		// a difference between having pressed Commmand-W or Command-Q.
154 		// Closing or quitting, it doesn't matter for a single window.
155 
156 		if (lastFoundZippo->Lock()) {
157 			lastFoundZippo->Activate();
158 			lastFoundZippo->PostMessage(B_QUIT_REQUESTED);
159 			lastFoundZippo->Unlock();
160 		}
161 		return false;
162 	}
163 
164 	if (zippoCount > 0) {
165 		// The multi-zipper case differs from the single-zipper case
166 		// in that zippers are not paused while the BAlert is up.
167 
168 		BString question;
169 		question << "You have " << zippoCount;
170 		question << " Zip-O-Matic running.\n\nDo you want to stop them?";
171 
172 		BAlert* alert = new BAlert("Stop or Continue", question.String(),
173 			"Stop them", "Let them continue", NULL, B_WIDTH_AS_USUAL,
174 			B_WARNING_ALERT);
175 		alert->Go(fInvoker);
176 		alert->Activate();
177 			// BAlert, being modal, does not show on the current workspace
178 			// if the application has no window there. Activate() triggers
179 			// a switch to a workspace where it does have a window.
180 
181 			// TODO: See if AS_ACTIVATE_WINDOW should be handled differently
182 			// in src/servers/app/Desktop.cpp Desktop::ActivateWindow()
183 			// or if maybe BAlert should (and does not?) activate itself.
184 
185 		return false;
186 	}
187 
188 	if (CountWindows() <= 0)
189 		return true;
190 
191 	return false;
192 }
193 
194 
195 void
196 ZipOMatic::_SilentRelaunch()
197 {
198 	_UseExistingOrCreateNewWindow();
199 }
200 
201 
202 void
203 ZipOMatic::_UseExistingOrCreateNewWindow(BMessage* message)
204 {
205 	int32 windowCount = 0;
206 	ZippoWindow* window;
207 	bool foundNonBusyWindow = false;
208 
209 	while (1) {
210 		window = dynamic_cast<ZippoWindow*>(WindowAt(windowCount++));
211 		if (window == NULL)
212 			break;
213 
214 		if (window->Lock()) {
215 			if (!window->IsZipping()) {
216 				foundNonBusyWindow = true;
217 				if (message != NULL)
218 					window->PostMessage(message);
219 				window->SetWorkspaces(B_CURRENT_WORKSPACE);
220 				window->Activate();
221 				window->Unlock();
222 				break;
223 			}
224 			window->Unlock();
225 		}
226 	}
227 
228 	if (!foundNonBusyWindow)
229 	{
230 		BScreen screen;
231 		fWindowFrame.OffsetBy(screen.Frame().LeftTop());
232 
233 		_CascadeOnFrameCollision(&fWindowFrame);
234 		if(!screen.Frame().Contains(fWindowFrame)) {
235 			fWindowFrame.OffsetTo(screen.Frame().LeftTop());
236 			fWindowFrame.OffsetBy(20,45);
237 				// TODO: replace with CenterOnScreen()
238 		}
239 
240 		ZippoWindow * window = new ZippoWindow(fWindowFrame, message);
241 		window->Show();
242 	}
243 }
244 
245 
246 void
247 ZipOMatic::_StopZipping()
248 {
249 	BWindow* window;
250 	ZippoWindow* zippo;
251 	BList list;
252 
253 	for (int32 i = 0;; i++) {
254 		window = WindowAt(i);
255 		if (window == NULL)
256 			break;
257 
258 		zippo = dynamic_cast<ZippoWindow*>(window);
259 		if (zippo == NULL)
260 			continue;
261 
262 		list.AddItem(zippo);
263 	}
264 
265 	for (int32 i = 0;; i++) {
266 		zippo = static_cast<ZippoWindow*>(list.ItemAt(i));
267 		if (zippo == NULL)
268 			break;
269 
270 		if (zippo->Lock()) {
271 			if (zippo->IsZipping())
272 				zippo->StopZipping();
273 
274 			zippo->PostMessage(B_QUIT_REQUESTED);
275 			zippo->Unlock();
276 		}
277 	}
278 }
279 
280 
281 status_t
282 ZipOMatic::_ReadSettings()
283 {
284 	status_t status = B_OK;
285 
286 	status = fSettings.SetTo("zipomatic.msg");
287 	if (status != B_OK)
288 		return status;
289 
290 	status = fSettings.InitCheck();
291 	if (status != B_OK)
292 		return status;
293 
294 	status = fSettings.InitCheck();
295 	if (status != B_OK)
296 		return status;
297 
298 	status = fSettings.ReadSettings();
299 	if (status != B_OK)
300 		return status;
301 
302 	BRect frame;
303 	status = fSettings.FindRect("frame", &frame);
304 	if (status != B_OK)
305 		return status;
306 
307 	fWindowFrame = frame;
308 
309 	return B_OK;
310 }
311 
312 
313 status_t
314 ZipOMatic::_WriteSettings()
315 {
316 	status_t status = B_OK;
317 
318 	status = fSettings.InitCheck();
319 	if (status != B_OK)
320 		return status;
321 
322 	status = fSettings.MakeEmpty();
323 	if (status != B_OK)
324 		return status;
325 
326 	status = fSettings.AddRect("frame", fWindowFrame);
327 	if (status != B_OK)
328 		return status;
329 
330 	status = fSettings.WriteSettings();
331 	if (status != B_OK)
332 		return status;
333 
334 	return B_OK;
335 }
336 
337 
338 void
339 ZipOMatic::_CascadeOnFrameCollision(BRect* frame)
340 {
341 	BWindow* window;
342 	ZippoWindow* zippo;
343 	BList list;
344 
345 	for (int32 i = 0;; i++) {
346 		window = WindowAt(i);
347 		if (window == NULL)
348 			break;
349 
350 		zippo = dynamic_cast<ZippoWindow*>(window);
351 		if (zippo == NULL)
352 			continue;
353 
354 		list.AddItem(zippo);
355 	}
356 
357 	for (int32 i = 0;; i++) {
358 		zippo = static_cast<ZippoWindow*>(list.ItemAt(i));
359 		if (zippo == NULL)
360 			break;
361 
362 		if (zippo->Lock()) {
363 			if (frame->LeftTop() == zippo->Frame().LeftTop())
364 				frame->OffsetBy(20, 20);
365 			zippo->Unlock();
366 		}
367 	}
368 }
369 
370