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