xref: /haiku/src/apps/deskbar/BarWindow.cpp (revision f75a7bf508f3156d63a14f8fd77c5e0ca4d08c42)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 #include <stdio.h>
36 #include <Application.h>
37 #include <Directory.h>
38 #include <FindDirectory.h>
39 #include <Path.h>
40 #include <Debug.h>
41 #include <File.h>
42 #include <MenuItem.h>
43 #include <MessageFilter.h>
44 #include <Screen.h>
45 
46 #include "BarWindow.h"
47 #include "BarApp.h"
48 #include "BarMenuBar.h"
49 #include "BarView.h"
50 #include "BeMenu.h"
51 #include "PublicCommands.h"
52 #include "StatusView.h"
53 #include "tracker_private.h"
54 
55 
56 // This is a very ugly hack to be able to call the private BMenuBar::StartMenuBar()
57 // method from the TBarWindow::ShowBeMenu() method.
58 // Don't do this at home -- but why the hell is this method private?
59 #if __MWERKS__
60 	#define BMenuBar_StartMenuBar_Hack StartMenuBar__8BMenuBarFlbbP5BRect
61 #elif __GNUC__ <= 2
62 	#define BMenuBar_StartMenuBar_Hack StartMenuBar__8BMenuBarlbT2P5BRect
63 #elif __GNUC__ > 2
64 	#define BMenuBar_StartMenuBar_Hack _ZN8BMenuBar12StartMenuBarElbbP5BRect
65 #else
66 #	error "You may want to port this ugly hack to your compiler ABI"
67 #endif
68 extern "C" void BMenuBar_StartMenuBar_Hack(BMenuBar *,int32,bool,bool,BRect *);
69 
70 
71 TBeMenu *TBarWindow::sBeMenu = NULL;
72 
73 
74 TBarWindow::TBarWindow()
75 	: BWindow(BRect(-1000.0f, -1000.0f, -1000.0f, -1000.0f), "Deskbar",
76 		B_BORDERED_WINDOW,
77 		B_WILL_ACCEPT_FIRST_CLICK | B_NOT_ZOOMABLE | B_NOT_CLOSABLE
78 			| B_NOT_MOVABLE | B_AVOID_FRONT | B_ASYNCHRONOUS_CONTROLS,
79 		B_ALL_WORKSPACES)
80 {
81 	desk_settings *settings = ((TBarApp *)be_app)->Settings();
82 	if (settings->alwaysOnTop)
83 		SetFeel(B_FLOATING_ALL_WINDOW_FEEL);
84 	fBarView = new TBarView(Bounds(), settings->vertical,settings->left, settings->top,
85 		settings->ampmMode, settings->state, settings->width, settings->showTime);
86 	AddChild(fBarView);
87 
88 	RemoveShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY);
89 	AddShortcut('F', B_COMMAND_KEY, new BMessage(kFindButton));
90 }
91 
92 
93 void
94 TBarWindow::DispatchMessage(BMessage *message, BHandler *handler)
95 {
96 	// Activate the window when you click on it (ie. on the tray area,
97 	// the menu part will do this automatically)
98 	if (message->what == B_MOUSE_DOWN
99 		&& !((TBarApp *)be_app)->Settings()->autoRaise)
100 		Activate(true);
101 
102 	BWindow::DispatchMessage(message, handler);
103 }
104 
105 
106 void
107 TBarWindow::MenusBeginning()
108 {
109 	BPath path;
110 	entry_ref ref;
111 
112 	find_directory (B_USER_DESKBAR_DIRECTORY, &path);
113 	get_ref_for_path(path.Path(), &ref);
114 
115 	BEntry entry(&ref, true);
116 	if (entry.InitCheck() == B_OK && entry.IsDirectory()) {
117 		//	need the entry_ref to the actual item
118 		entry.GetRef(&ref);
119 		//	set the nav directory to the be folder
120 		sBeMenu->SetNavDir(&ref);
121 	} else if (!entry.Exists()) {
122 		//	the Be folder does not exist
123 		//	create one now
124 		BDirectory dir;
125 		if (entry.GetParent(&dir) == B_OK) {
126 			BDirectory bedir;
127 			dir.CreateDirectory("be", &bedir);
128 			if (bedir.GetEntry(&entry) == B_OK
129 				&& entry.GetRef(&ref) == B_OK)
130 				sBeMenu->SetNavDir(&ref);
131 		}
132 	} else {
133 		//	this really should never happen
134 		TRESPASS();
135 		return;
136 	}
137 
138 	sBeMenu->NeedsToRebuild();
139 	sBeMenu->ResetTargets();
140 
141 	fBarView->SetEventMask(0);
142 		// This works around a BeOS bug - the menu is quit with every
143 		// B_MOUSE_DOWN the window receives...
144 
145 	BWindow::MenusBeginning();
146 }
147 
148 
149 void
150 TBarWindow::MenusEnded()
151 {
152 	BWindow::MenusEnded();
153 
154 	if (sBeMenu->LockLooper()) {
155 		// TODO: is this ok?
156 		sBeMenu->RemoveItems(0, sBeMenu->CountItems(), true);
157 		sBeMenu->UnlockLooper();
158 	}
159 
160 	fBarView->UpdateAutoRaise();
161 }
162 
163 
164 void
165 TBarWindow::MessageReceived(BMessage *message)
166 {
167 	switch (message->what) {
168 		case kFindButton:
169 		{
170 			BMessenger tracker(kTrackerSignature);
171 			tracker.SendMessage(message);
172 			break;
173 		}
174 
175 		case 'gloc':
176 			GetLocation(message);
177 			break;
178 
179 		case 'sloc':
180 			SetLocation(message);
181 			break;
182 
183 		case 'gexp':
184 			IsExpanded(message);
185 			break;
186 
187 		case 'sexp':
188 			Expand(message);
189 			break;
190 
191 		case 'info':
192 			ItemInfo(message);
193 			break;
194 
195 		case 'exst':
196 			ItemExists(message);
197 			break;
198 
199 		case 'cwnt':
200 			CountItems(message);
201 			break;
202 
203 		case 'adon':
204 		case 'icon':
205 			AddItem(message);
206 			break;
207 
208 		case 'remv':
209 			RemoveItem(message);
210 			break;
211 
212 		case 'iloc':
213 			GetIconFrame(message);
214 			break;
215 
216 		default:
217 			BWindow::MessageReceived(message);
218 			break;
219 	}
220 }
221 
222 
223 void
224 TBarWindow::SaveSettings()
225 {
226 	fBarView->SaveSettings();
227 }
228 
229 
230 bool
231 TBarWindow::QuitRequested()
232 {
233 	be_app->PostMessage(B_QUIT_REQUESTED);
234 
235 	return BWindow::QuitRequested();
236 }
237 
238 
239 void
240 TBarWindow::WorkspaceActivated(int32 workspace, bool active)
241 {
242 	BWindow::WorkspaceActivated(workspace, active);
243 
244 	if (active && !(fBarView->Expando() && fBarView->Vertical()))
245 		fBarView->UpdatePlacement();
246 	else {
247 		BRect screenFrame = (BScreen(fBarView->Window())).Frame();
248 		fBarView->SizeWindow(screenFrame);
249 		fBarView->PositionWindow(screenFrame);
250 		fBarView->Invalidate();
251 	}
252 }
253 
254 
255 void
256 TBarWindow::ScreenChanged(BRect size, color_space depth)
257 {
258 	BWindow::ScreenChanged(size, depth);
259 
260 	fBarView->UpdatePlacement();
261 }
262 
263 
264 void
265 TBarWindow::SetBeMenu(TBeMenu *menu)
266 {
267 	sBeMenu = menu;
268 }
269 
270 
271 TBeMenu *
272 TBarWindow::BeMenu()
273 {
274 	return sBeMenu;
275 }
276 
277 
278 void
279 TBarWindow::ShowBeMenu()
280 {
281 	BMenuBar *menuBar = fBarView->BarMenuBar();
282 	if (menuBar == NULL)
283 		menuBar = KeyMenuBar();
284 
285 	if (menuBar == NULL)
286 		return;
287 
288 	BMenuBar_StartMenuBar_Hack(menuBar,0,true,true,NULL);
289 }
290 
291 
292 void
293 TBarWindow::ShowTeamMenu()
294 {
295 	int32 index = 0;
296 	if (fBarView->BarMenuBar() == NULL)
297 		index = 2;
298 
299 	if (KeyMenuBar() == NULL)
300 		return;
301 
302 	BMenuBar_StartMenuBar_Hack(KeyMenuBar(),index,true,true,NULL);
303 }
304 
305 
306 /**	determines the actual location of the window */
307 
308 deskbar_location
309 TBarWindow::DeskbarLocation() const
310 {
311 	bool left = fBarView->Left();
312 	bool top = fBarView->Top();
313 
314 	if (fBarView->AcrossTop())
315 		return B_DESKBAR_TOP;
316 
317 	if (fBarView->AcrossBottom())
318 		return B_DESKBAR_BOTTOM;
319 
320 	if (left && top)
321 		return B_DESKBAR_LEFT_TOP;
322 
323 	if (!left && top)
324 		return B_DESKBAR_RIGHT_TOP;
325 
326 	if (left && !top)
327 		return B_DESKBAR_LEFT_BOTTOM;
328 
329 	return B_DESKBAR_RIGHT_BOTTOM;
330 }
331 
332 
333 void
334 TBarWindow::GetLocation(BMessage *message)
335 {
336 	BMessage reply('rply');
337 	reply.AddInt32("location", (int32)DeskbarLocation());
338 	reply.AddBool("expanded", fBarView->Expando());
339 
340 	message->SendReply(&reply);
341 }
342 
343 
344 void
345 TBarWindow::SetDeskbarLocation(deskbar_location location, bool newExpandState)
346 {
347 	// left top and right top are the only two that
348 	// currently pay attention to expand, ignore for all others
349 
350 	bool left = false, top = true, vertical, expand;
351 
352 	switch (location) {
353 		case B_DESKBAR_TOP:
354 			left = true;
355 			top = true;
356 			vertical = false;
357 			expand = true;
358 			break;
359 
360 		case B_DESKBAR_BOTTOM:
361 			left = true;
362 			top = false;
363 			vertical = false;
364 			expand = true;
365 			break;
366 
367 		case B_DESKBAR_LEFT_TOP:
368 			left = true;
369 			top = true;
370 			vertical = true;
371 			expand = newExpandState;
372 			break;
373 
374 		case B_DESKBAR_RIGHT_TOP:
375 			left = false;
376 			top = true;
377 			vertical = true;
378 			expand = newExpandState;
379 			break;
380 
381 		case B_DESKBAR_LEFT_BOTTOM:
382 			left = true;
383 			top = false;
384 			vertical = true;
385 			expand = false;
386 			break;
387 
388 		case B_DESKBAR_RIGHT_BOTTOM:
389 			left = false;
390 			top = false;
391 			vertical = true;
392 			expand = false;
393 			break;
394 
395 		default:
396 			left = true;
397 			top = true;
398 			vertical = false;
399 			expand = true;
400 			break;
401 	}
402 
403 	fBarView->ChangeState(expand, vertical, left, top);
404 }
405 
406 void
407 TBarWindow::SetLocation(BMessage *message)
408 {
409 	deskbar_location location;
410 	bool expand;
411 	if (message->FindInt32("location", (int32 *)&location) == B_OK
412 		&& message->FindBool("expand", &expand) == B_OK)
413 		SetDeskbarLocation(location, expand);
414 }
415 
416 
417 void
418 TBarWindow::IsExpanded(BMessage *message)
419 {
420 	BMessage reply('rply');
421 	reply.AddBool("expanded", fBarView->Expando());
422 	message->SendReply(&reply);
423 }
424 
425 
426 void
427 TBarWindow::Expand(BMessage *message)
428 {
429 	bool expand;
430 	if (message->FindBool("expand", &expand) == B_OK) {
431 		bool vertical = fBarView->Vertical();
432 		bool left = fBarView->Left();
433 		bool top = fBarView->Top();
434 		fBarView->ChangeState(expand, vertical, left, top);
435 	}
436 }
437 
438 
439 void
440 TBarWindow::ItemInfo(BMessage *message)
441 {
442 	BMessage replyMsg;
443 	const char *name;
444 	int32 id;
445 	DeskbarShelf shelf;
446 	if (message->FindInt32("id", &id) == B_OK) {
447 		if (fBarView->ItemInfo(id, &name, &shelf) == B_OK) {
448 			replyMsg.AddString("name", name);
449 #if SHELF_AWARE
450 			replyMsg.AddInt32("shelf", (int32)shelf);
451 #endif
452 		}
453 	} else if (message->FindString("name", &name) == B_OK) {
454 		if (fBarView->ItemInfo(name, &id, &shelf) == B_OK) {
455 			replyMsg.AddInt32("id", id);
456 #if SHELF_AWARE
457 			replyMsg.AddInt32("shelf", (int32)shelf);
458 #endif
459 		}
460 	}
461 
462 	message->SendReply(&replyMsg);
463 }
464 
465 
466 void
467 TBarWindow::ItemExists(BMessage *message)
468 {
469 	BMessage replyMsg;
470 	const char *name;
471 	int32 id;
472 	DeskbarShelf shelf;
473 
474 #if SHELF_AWARE
475 	if (message->FindInt32("shelf", (int32 *)&shelf) != B_OK)
476 #endif
477 		shelf = B_DESKBAR_TRAY;
478 
479 	bool exists = false;
480 	if (message->FindInt32("id", &id) == B_OK)
481 		exists = fBarView->ItemExists(id, shelf);
482 	else if (message->FindString("name", &name) == B_OK)
483 		exists = fBarView->ItemExists(name, shelf);
484 
485 	replyMsg.AddBool("exists", exists);
486 	message->SendReply(&replyMsg);
487 }
488 
489 
490 void
491 TBarWindow::CountItems(BMessage *message)
492 {
493 	DeskbarShelf shelf;
494 
495 #if SHELF_AWARE
496 	if (message->FindInt32("shelf", (int32 *)&shelf) != B_OK)
497 #endif
498 		shelf = B_DESKBAR_TRAY;
499 
500 	BMessage reply('rply');
501 	reply.AddInt32("count", fBarView->CountItems(shelf));
502 	message->SendReply(&reply);
503 }
504 
505 
506 void
507 TBarWindow::AddItem(BMessage *message)
508 {
509 	DeskbarShelf shelf;
510 	entry_ref ref;
511 	int32 id = 999;
512 	BMessage reply;
513 	status_t err = B_ERROR;
514 
515 	BMessage archivedView;
516 	if (message->FindMessage("view", &archivedView) == B_OK) {
517 #if SHELF_AWARE
518 		if (message->FindInt32("shelf", (int32 *)&shelf) != B_OK)
519 #endif
520 			shelf = B_DESKBAR_TRAY;
521 
522 		BMessage* archive = new BMessage(archivedView);
523 		err = fBarView->AddItem(archive, shelf, &id);
524 		if (err < B_OK)
525 			delete archive;
526 	} else if (message->FindRef("addon", &ref) == B_OK) {
527 		//
528 		//	exposing the name of the view here is not so great
529 		TReplicantTray *tray = dynamic_cast<TReplicantTray *>(FindView("Status"));
530 		if (tray) {
531 			// Force this into the deskbar even if the security code is wrong
532 			// This is OK because the user specifically asked for this replicant
533 			BEntry entry(&ref);
534 			err = tray->LoadAddOn(&entry, &id, true);
535 		}
536 	}
537 
538 	if (err == B_OK)
539 		reply.AddInt32("id", id);
540 	else
541 		reply.AddInt32("error", err);
542 
543 	message->SendReply(&reply);
544 }
545 
546 
547 void
548 TBarWindow::RemoveItem(BMessage *message)
549 {
550 	int32 id;
551 	const char *name;
552 
553 	// 	ids ought to be unique across all shelves, assuming, of course,
554 	//	that sometime in the future there may be more than one
555 #if SHELF_AWARE
556 	if (message->FindInt32("shelf", (int32 *)&shelf) == B_OK) {
557 		if (message->FindString("name", &name) == B_OK)
558 			fBarView->RemoveItem(name, shelf);
559 	} else {
560 #endif
561 		if (message->FindInt32("id", &id) == B_OK) {
562 			fBarView->RemoveItem(id);
563 		//	remove the following two lines if and when the
564 		//	shelf option returns
565 		} else if (message->FindString("name", &name) == B_OK)
566 			fBarView->RemoveItem(name, B_DESKBAR_TRAY);
567 
568 #if SHELF_AWARE
569 	}
570 #endif
571 }
572 
573 
574 void
575 TBarWindow::GetIconFrame(BMessage *message)
576 {
577 	BRect frame(0, 0, 0, 0);
578 
579 	const char *name;
580 	int32 id;
581 	if (message->FindInt32("id", &id) == B_OK)
582 		frame = fBarView->IconFrame(id);
583 	else if (message->FindString("name", &name) == B_OK)
584 		frame = fBarView->IconFrame(name);
585 
586 	BMessage reply('rply');
587 	reply.AddRect("frame", frame);
588 	message->SendReply(&reply);
589 }
590