xref: /haiku/src/apps/deskbar/BarWindow.cpp (revision 6d7890478b78265f4670978a58384fb438de0007)
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 'gloc':
172 			GetLocation(message);
173 			break;
174 
175 		case 'sloc':
176 			SetLocation(message);
177 			break;
178 
179 		case 'gexp':
180 			IsExpanded(message);
181 			break;
182 
183 		case 'sexp':
184 			Expand(message);
185 			break;
186 
187 		case 'info':
188 			ItemInfo(message);
189 			break;
190 
191 		case 'exst':
192 			ItemExists(message);
193 			break;
194 
195 		case 'cwnt':
196 			CountItems(message);
197 			break;
198 
199 		case 'adon':
200 		case 'icon':
201 			AddItem(message);
202 			break;
203 
204 		case 'remv':
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 		// update width setting
247 		static_cast<TBarApp*>(be_app)->Settings()->width = newWidth;
248 	}
249 
250 	if (Lock()) {
251 		fBarView->ResizeTo(width, fBarView->Bounds().Height());
252 		if (fBarView->Vertical() && fBarView->ExpandoState())
253 			fBarView->ExpandoMenuBar()->SetMaxContentWidth(width);
254 
255 		Unlock();
256 	}
257 }
258 
259 
260 void
261 TBarWindow::SaveSettings()
262 {
263 	fBarView->SaveSettings();
264 }
265 
266 
267 bool
268 TBarWindow::QuitRequested()
269 {
270 	be_app->PostMessage(B_QUIT_REQUESTED);
271 
272 	return BWindow::QuitRequested();
273 }
274 
275 
276 void
277 TBarWindow::WorkspaceActivated(int32 workspace, bool active)
278 {
279 	BWindow::WorkspaceActivated(workspace, active);
280 
281 	if (active && !(fBarView->ExpandoState() && fBarView->Vertical()))
282 		fBarView->UpdatePlacement();
283 	else {
284 		BRect screenFrame = (BScreen(fBarView->Window())).Frame();
285 		fBarView->SizeWindow(screenFrame);
286 		fBarView->PositionWindow(screenFrame);
287 		fBarView->Invalidate();
288 	}
289 }
290 
291 
292 void
293 TBarWindow::ScreenChanged(BRect size, color_space depth)
294 {
295 	BWindow::ScreenChanged(size, depth);
296 
297 	fBarView->UpdatePlacement();
298 }
299 
300 
301 void
302 TBarWindow::SetDeskbarMenu(TDeskbarMenu* menu)
303 {
304 	sDeskbarMenu = menu;
305 }
306 
307 
308 TDeskbarMenu*
309 TBarWindow::DeskbarMenu()
310 {
311 	return sDeskbarMenu;
312 }
313 
314 
315 void
316 TBarWindow::ShowDeskbarMenu()
317 {
318 	BMenuBar* menuBar = fBarView->BarMenuBar();
319 	if (menuBar == NULL)
320 		menuBar = KeyMenuBar();
321 
322 	if (menuBar == NULL)
323 		return;
324 
325 	BMenuBar_StartMenuBar_Hack(menuBar, 0, true, true, NULL);
326 }
327 
328 
329 void
330 TBarWindow::ShowTeamMenu()
331 {
332 	int32 index = 0;
333 	if (fBarView->BarMenuBar() == NULL)
334 		index = 2;
335 
336 	if (KeyMenuBar() == NULL)
337 		return;
338 
339 	BMenuBar_StartMenuBar_Hack(KeyMenuBar(), index, true, true, NULL);
340 }
341 
342 
343 // determines the actual location of the window
344 
345 deskbar_location
346 TBarWindow::DeskbarLocation() const
347 {
348 	bool left = fBarView->Left();
349 	bool top = fBarView->Top();
350 
351 	if (fBarView->AcrossTop())
352 		return B_DESKBAR_TOP;
353 
354 	if (fBarView->AcrossBottom())
355 		return B_DESKBAR_BOTTOM;
356 
357 	if (left && top)
358 		return B_DESKBAR_LEFT_TOP;
359 
360 	if (!left && top)
361 		return B_DESKBAR_RIGHT_TOP;
362 
363 	if (left && !top)
364 		return B_DESKBAR_LEFT_BOTTOM;
365 
366 	return B_DESKBAR_RIGHT_BOTTOM;
367 }
368 
369 
370 void
371 TBarWindow::GetLocation(BMessage* message)
372 {
373 	BMessage reply('rply');
374 	reply.AddInt32("location", (int32)DeskbarLocation());
375 	reply.AddBool("expanded", fBarView->ExpandoState());
376 
377 	message->SendReply(&reply);
378 }
379 
380 
381 void
382 TBarWindow::SetDeskbarLocation(deskbar_location location, bool newExpandState)
383 {
384 	// left top and right top are the only two that
385 	// currently pay attention to expand, ignore for all others
386 
387 	bool left = false, top = true, vertical, expand;
388 
389 	switch (location) {
390 		case B_DESKBAR_TOP:
391 			left = true;
392 			top = true;
393 			vertical = false;
394 			expand = true;
395 			break;
396 
397 		case B_DESKBAR_BOTTOM:
398 			left = true;
399 			top = false;
400 			vertical = false;
401 			expand = true;
402 			break;
403 
404 		case B_DESKBAR_LEFT_TOP:
405 			left = true;
406 			top = true;
407 			vertical = true;
408 			expand = newExpandState;
409 			break;
410 
411 		case B_DESKBAR_RIGHT_TOP:
412 			left = false;
413 			top = true;
414 			vertical = true;
415 			expand = newExpandState;
416 			break;
417 
418 		case B_DESKBAR_LEFT_BOTTOM:
419 			left = true;
420 			top = false;
421 			vertical = true;
422 			expand = false;
423 			break;
424 
425 		case B_DESKBAR_RIGHT_BOTTOM:
426 			left = false;
427 			top = false;
428 			vertical = true;
429 			expand = false;
430 			break;
431 
432 		default:
433 			left = true;
434 			top = true;
435 			vertical = false;
436 			expand = true;
437 			break;
438 	}
439 
440 	fBarView->ChangeState(expand, vertical, left, top);
441 }
442 
443 
444 void
445 TBarWindow::SetLocation(BMessage* message)
446 {
447 	deskbar_location location;
448 	bool expand;
449 	if (message->FindInt32("location", (int32*)&location) == B_OK
450 		&& message->FindBool("expand", &expand) == B_OK)
451 		SetDeskbarLocation(location, expand);
452 }
453 
454 
455 void
456 TBarWindow::IsExpanded(BMessage* message)
457 {
458 	BMessage reply('rply');
459 	reply.AddBool("expanded", fBarView->ExpandoState());
460 	message->SendReply(&reply);
461 }
462 
463 
464 void
465 TBarWindow::Expand(BMessage* message)
466 {
467 	bool expand;
468 	if (message->FindBool("expand", &expand) == B_OK) {
469 		bool vertical = fBarView->Vertical();
470 		bool left = fBarView->Left();
471 		bool top = fBarView->Top();
472 		fBarView->ChangeState(expand, vertical, left, top);
473 	}
474 }
475 
476 
477 void
478 TBarWindow::ItemInfo(BMessage* message)
479 {
480 	BMessage replyMsg;
481 	const char* name;
482 	int32 id;
483 	DeskbarShelf shelf;
484 	if (message->FindInt32("id", &id) == B_OK) {
485 		if (fBarView->ItemInfo(id, &name, &shelf) == B_OK) {
486 			replyMsg.AddString("name", name);
487 #if SHELF_AWARE
488 			replyMsg.AddInt32("shelf", (int32)shelf);
489 #endif
490 		}
491 	} else if (message->FindString("name", &name) == B_OK) {
492 		if (fBarView->ItemInfo(name, &id, &shelf) == B_OK) {
493 			replyMsg.AddInt32("id", id);
494 #if SHELF_AWARE
495 			replyMsg.AddInt32("shelf", (int32)shelf);
496 #endif
497 		}
498 	}
499 
500 	message->SendReply(&replyMsg);
501 }
502 
503 
504 void
505 TBarWindow::ItemExists(BMessage* message)
506 {
507 	BMessage replyMsg;
508 	const char* name;
509 	int32 id;
510 	DeskbarShelf shelf;
511 
512 #if SHELF_AWARE
513 	if (message->FindInt32("shelf", (int32*)&shelf) != B_OK)
514 #endif
515 		shelf = B_DESKBAR_TRAY;
516 
517 	bool exists = false;
518 	if (message->FindInt32("id", &id) == B_OK)
519 		exists = fBarView->ItemExists(id, shelf);
520 	else if (message->FindString("name", &name) == B_OK)
521 		exists = fBarView->ItemExists(name, shelf);
522 
523 	replyMsg.AddBool("exists", exists);
524 	message->SendReply(&replyMsg);
525 }
526 
527 
528 void
529 TBarWindow::CountItems(BMessage* message)
530 {
531 	DeskbarShelf shelf;
532 
533 #if SHELF_AWARE
534 	if (message->FindInt32("shelf", (int32*)&shelf) != B_OK)
535 #endif
536 		shelf = B_DESKBAR_TRAY;
537 
538 	BMessage reply('rply');
539 	reply.AddInt32("count", fBarView->CountItems(shelf));
540 	message->SendReply(&reply);
541 }
542 
543 
544 void
545 TBarWindow::AddItem(BMessage* message)
546 {
547 	DeskbarShelf shelf = B_DESKBAR_TRAY;
548 	entry_ref ref;
549 	int32 id = 999;
550 	BMessage reply;
551 	status_t err = B_ERROR;
552 
553 	BMessage* archivedView = new BMessage();
554 	ObjectDeleter<BMessage> deleter(archivedView);
555 	if (message->FindMessage("view", archivedView) == B_OK) {
556 #if SHELF_AWARE
557 		message->FindInt32("shelf", &shelf);
558 #endif
559 		err = fBarView->AddItem(archivedView, shelf, &id);
560 		if (err == B_OK) {
561 			// Detach the deleter since AddReplicant is taking ownership
562 			// on success. This should be changed on server side.
563 			deleter.Detach();
564 		}
565 	} else if (message->FindRef("addon", &ref) == B_OK) {
566 		BEntry entry(&ref);
567 		err = entry.InitCheck();
568 		if (err == B_OK)
569 			err = fBarView->AddItem(&entry, shelf, &id);
570 	}
571 
572 	if (err == B_OK)
573 		reply.AddInt32("id", id);
574 	else
575 		reply.AddInt32("error", err);
576 
577 	message->SendReply(&reply);
578 }
579 
580 
581 void
582 TBarWindow::RemoveItem(BMessage* message)
583 {
584 	int32 id;
585 	const char* name;
586 
587 	// ids ought to be unique across all shelves, assuming, of course,
588 	// that sometime in the future there may be more than one
589 #if SHELF_AWARE
590 	if (message->FindInt32("shelf", (int32*)&shelf) == B_OK) {
591 		if (message->FindString("name", &name) == B_OK)
592 			fBarView->RemoveItem(name, shelf);
593 	} else {
594 #endif
595 		if (message->FindInt32("id", &id) == B_OK) {
596 			fBarView->RemoveItem(id);
597 		// remove the following two lines if and when the
598 		// shelf option returns
599 		} else if (message->FindString("name", &name) == B_OK)
600 			fBarView->RemoveItem(name, B_DESKBAR_TRAY);
601 
602 #if SHELF_AWARE
603 	}
604 #endif
605 }
606 
607 
608 void
609 TBarWindow::GetIconFrame(BMessage* message)
610 {
611 	BRect frame(0, 0, 0, 0);
612 
613 	const char* name;
614 	int32 id;
615 	if (message->FindInt32("id", &id) == B_OK)
616 		frame = fBarView->IconFrame(id);
617 	else if (message->FindString("name", &name) == B_OK)
618 		frame = fBarView->IconFrame(name);
619 
620 	BMessage reply('rply');
621 	reply.AddRect("frame", frame);
622 	message->SendReply(&reply);
623 }
624 
625 
626 bool
627 TBarWindow::IsShowingMenu() const
628 {
629 	return fShowingMenu;
630 }
631 
632 
633 bool
634 TBarWindow::_IsFocusMessage(BMessage* message)
635 {
636 	BMessage::Private messagePrivate(message);
637 	if (!messagePrivate.UsePreferredTarget())
638 		return false;
639 
640 	bool feedFocus;
641 	if (message->HasInt32("_token")
642 		&& (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus))
643 		return false;
644 
645 	return true;
646 }
647