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