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