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