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