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