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