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