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