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