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