1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30trademarks of Be Incorporated in the United States and other countries. Other
31brand product names are registered trademarks or trademarks of their respective
32holders.
33All 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
83extern "C" void
84	BMenuBar_StartMenuBar_Hack(BMenuBar*, int32, bool, bool, BRect*);
85
86
87TDeskbarMenu* TBarWindow::sDeskbarMenu = NULL;
88
89
90TBarWindow::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	fBarView = new TBarView(Bounds(), settings->vertical, settings->left,
104		settings->top, settings->state, settings->width);
105	AddChild(fBarView);
106
107	RemoveShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY);
108	AddShortcut('F', B_COMMAND_KEY, new BMessage(kFindButton));
109}
110
111
112void
113TBarWindow::MenusBeginning()
114{
115	BPath path;
116	entry_ref ref;
117
118	find_directory (B_USER_DESKBAR_DIRECTORY, &path);
119	get_ref_for_path(path.Path(), &ref);
120
121	BEntry entry(&ref, true);
122	if (entry.InitCheck() == B_OK && entry.IsDirectory()) {
123		//	need the entry_ref to the actual item
124		entry.GetRef(&ref);
125		//	set the nav directory to the deskbar folder
126		sDeskbarMenu->SetNavDir(&ref);
127	} else if (!entry.Exists()) {
128		//	the deskbar folder does not exist
129		//	create one now
130		BDirectory dir;
131		if (entry.GetParent(&dir) == B_OK) {
132			BDirectory deskbarDir;
133			dir.CreateDirectory("deskbar", &deskbarDir);
134			if (deskbarDir.GetEntry(&entry) == B_OK
135				&& entry.GetRef(&ref) == B_OK)
136				sDeskbarMenu->SetNavDir(&ref);
137		}
138	} else {
139		//	this really should never happen
140		TRESPASS();
141		return;
142	}
143
144	sDeskbarMenu->NeedsToRebuild();
145	sDeskbarMenu->ResetTargets();
146
147	fShowingMenu = true;
148	BWindow::MenusBeginning();
149}
150
151
152void
153TBarWindow::MenusEnded()
154{
155	fShowingMenu = false;
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
165
166void
167TBarWindow::MessageReceived(BMessage* message)
168{
169	switch (message->what) {
170		case kFindButton:
171		{
172			BMessenger tracker(kTrackerSignature);
173			tracker.SendMessage(message);
174			break;
175		}
176
177		case 'gloc':
178			GetLocation(message);
179			break;
180
181		case 'sloc':
182			SetLocation(message);
183			break;
184
185		case 'gexp':
186			IsExpanded(message);
187			break;
188
189		case 'sexp':
190			Expand(message);
191			break;
192
193		case 'info':
194			ItemInfo(message);
195			break;
196
197		case 'exst':
198			ItemExists(message);
199			break;
200
201		case 'cwnt':
202			CountItems(message);
203			break;
204
205		case 'adon':
206		case 'icon':
207			AddItem(message);
208			break;
209
210		case 'remv':
211			RemoveItem(message);
212			break;
213
214		case 'iloc':
215			GetIconFrame(message);
216			break;
217
218		default:
219			BWindow::MessageReceived(message);
220			break;
221	}
222}
223
224
225void
226TBarWindow::Minimize(bool minimize)
227{
228	// Don't allow the Deskbar to be minimized
229	if (!minimize)
230		BWindow::Minimize(false);
231}
232
233
234void
235TBarWindow::SaveSettings()
236{
237	fBarView->SaveSettings();
238}
239
240
241bool
242TBarWindow::QuitRequested()
243{
244	be_app->PostMessage(B_QUIT_REQUESTED);
245
246	return BWindow::QuitRequested();
247}
248
249
250void
251TBarWindow::WorkspaceActivated(int32 workspace, bool active)
252{
253	BWindow::WorkspaceActivated(workspace, active);
254
255	if (active && !(fBarView->ExpandoState() && fBarView->Vertical()))
256		fBarView->UpdatePlacement();
257	else {
258		BRect screenFrame = (BScreen(fBarView->Window())).Frame();
259		fBarView->SizeWindow(screenFrame);
260		fBarView->PositionWindow(screenFrame);
261		fBarView->Invalidate();
262	}
263}
264
265
266void
267TBarWindow::ScreenChanged(BRect size, color_space depth)
268{
269	BWindow::ScreenChanged(size, depth);
270
271	fBarView->UpdatePlacement();
272}
273
274
275void
276TBarWindow::SetDeskbarMenu(TDeskbarMenu* menu)
277{
278	sDeskbarMenu = menu;
279}
280
281
282TDeskbarMenu*
283TBarWindow::DeskbarMenu()
284{
285	return sDeskbarMenu;
286}
287
288
289void
290TBarWindow::ShowDeskbarMenu()
291{
292	BMenuBar* menuBar = fBarView->BarMenuBar();
293	if (menuBar == NULL)
294		menuBar = KeyMenuBar();
295
296	if (menuBar == NULL)
297		return;
298
299	BMenuBar_StartMenuBar_Hack(menuBar, 0, true, true, NULL);
300}
301
302
303void
304TBarWindow::ShowTeamMenu()
305{
306	int32 index = 0;
307	if (fBarView->BarMenuBar() == NULL)
308		index = 2;
309
310	if (KeyMenuBar() == NULL)
311		return;
312
313	BMenuBar_StartMenuBar_Hack(KeyMenuBar(), index, true, true, NULL);
314}
315
316
317// determines the actual location of the window
318
319deskbar_location
320TBarWindow::DeskbarLocation() const
321{
322	bool left = fBarView->Left();
323	bool top = fBarView->Top();
324
325	if (fBarView->AcrossTop())
326		return B_DESKBAR_TOP;
327
328	if (fBarView->AcrossBottom())
329		return B_DESKBAR_BOTTOM;
330
331	if (left && top)
332		return B_DESKBAR_LEFT_TOP;
333
334	if (!left && top)
335		return B_DESKBAR_RIGHT_TOP;
336
337	if (left && !top)
338		return B_DESKBAR_LEFT_BOTTOM;
339
340	return B_DESKBAR_RIGHT_BOTTOM;
341}
342
343
344void
345TBarWindow::GetLocation(BMessage* message)
346{
347	BMessage reply('rply');
348	reply.AddInt32("location", (int32)DeskbarLocation());
349	reply.AddBool("expanded", fBarView->ExpandoState());
350
351	message->SendReply(&reply);
352}
353
354
355void
356TBarWindow::SetDeskbarLocation(deskbar_location location, bool newExpandState)
357{
358	// left top and right top are the only two that
359	// currently pay attention to expand, ignore for all others
360
361	bool left = false, top = true, vertical, expand;
362
363	switch (location) {
364		case B_DESKBAR_TOP:
365			left = true;
366			top = true;
367			vertical = false;
368			expand = true;
369			break;
370
371		case B_DESKBAR_BOTTOM:
372			left = true;
373			top = false;
374			vertical = false;
375			expand = true;
376			break;
377
378		case B_DESKBAR_LEFT_TOP:
379			left = true;
380			top = true;
381			vertical = true;
382			expand = newExpandState;
383			break;
384
385		case B_DESKBAR_RIGHT_TOP:
386			left = false;
387			top = true;
388			vertical = true;
389			expand = newExpandState;
390			break;
391
392		case B_DESKBAR_LEFT_BOTTOM:
393			left = true;
394			top = false;
395			vertical = true;
396			expand = false;
397			break;
398
399		case B_DESKBAR_RIGHT_BOTTOM:
400			left = false;
401			top = false;
402			vertical = true;
403			expand = false;
404			break;
405
406		default:
407			left = true;
408			top = true;
409			vertical = false;
410			expand = true;
411			break;
412	}
413
414	fBarView->ChangeState(expand, vertical, left, top);
415}
416
417
418void
419TBarWindow::SetLocation(BMessage* message)
420{
421	deskbar_location location;
422	bool expand;
423	if (message->FindInt32("location", (int32*)&location) == B_OK
424		&& message->FindBool("expand", &expand) == B_OK)
425		SetDeskbarLocation(location, expand);
426}
427
428
429void
430TBarWindow::IsExpanded(BMessage* message)
431{
432	BMessage reply('rply');
433	reply.AddBool("expanded", fBarView->ExpandoState());
434	message->SendReply(&reply);
435}
436
437
438void
439TBarWindow::Expand(BMessage* message)
440{
441	bool expand;
442	if (message->FindBool("expand", &expand) == B_OK) {
443		bool vertical = fBarView->Vertical();
444		bool left = fBarView->Left();
445		bool top = fBarView->Top();
446		fBarView->ChangeState(expand, vertical, left, top);
447	}
448}
449
450
451void
452TBarWindow::ItemInfo(BMessage* message)
453{
454	BMessage replyMsg;
455	const char* name;
456	int32 id;
457	DeskbarShelf shelf;
458	if (message->FindInt32("id", &id) == B_OK) {
459		if (fBarView->ItemInfo(id, &name, &shelf) == B_OK) {
460			replyMsg.AddString("name", name);
461#if SHELF_AWARE
462			replyMsg.AddInt32("shelf", (int32)shelf);
463#endif
464		}
465	} else if (message->FindString("name", &name) == B_OK) {
466		if (fBarView->ItemInfo(name, &id, &shelf) == B_OK) {
467			replyMsg.AddInt32("id", id);
468#if SHELF_AWARE
469			replyMsg.AddInt32("shelf", (int32)shelf);
470#endif
471		}
472	}
473
474	message->SendReply(&replyMsg);
475}
476
477
478void
479TBarWindow::ItemExists(BMessage* message)
480{
481	BMessage replyMsg;
482	const char* name;
483	int32 id;
484	DeskbarShelf shelf;
485
486#if SHELF_AWARE
487	if (message->FindInt32("shelf", (int32*)&shelf) != B_OK)
488#endif
489		shelf = B_DESKBAR_TRAY;
490
491	bool exists = false;
492	if (message->FindInt32("id", &id) == B_OK)
493		exists = fBarView->ItemExists(id, shelf);
494	else if (message->FindString("name", &name) == B_OK)
495		exists = fBarView->ItemExists(name, shelf);
496
497	replyMsg.AddBool("exists", exists);
498	message->SendReply(&replyMsg);
499}
500
501
502void
503TBarWindow::CountItems(BMessage* message)
504{
505	DeskbarShelf shelf;
506
507#if SHELF_AWARE
508	if (message->FindInt32("shelf", (int32*)&shelf) != B_OK)
509#endif
510		shelf = B_DESKBAR_TRAY;
511
512	BMessage reply('rply');
513	reply.AddInt32("count", fBarView->CountItems(shelf));
514	message->SendReply(&reply);
515}
516
517
518void
519TBarWindow::AddItem(BMessage* message)
520{
521	DeskbarShelf shelf = B_DESKBAR_TRAY;
522	entry_ref ref;
523	int32 id = 999;
524	BMessage reply;
525	status_t err = B_ERROR;
526
527	BMessage archivedView;
528	if (message->FindMessage("view", &archivedView) == B_OK) {
529#if SHELF_AWARE
530		message->FindInt32("shelf", &shelf);
531#endif
532		BMessage* archive = new BMessage(archivedView);
533		err = fBarView->AddItem(archive, shelf, &id);
534		if (err < B_OK)
535			delete archive;
536	} else if (message->FindRef("addon", &ref) == B_OK) {
537		BEntry entry(&ref);
538		err = entry.InitCheck();
539		if (err == B_OK)
540			err = fBarView->AddItem(&entry, shelf, &id);
541	}
542
543	if (err == B_OK)
544		reply.AddInt32("id", id);
545	else
546		reply.AddInt32("error", err);
547
548	message->SendReply(&reply);
549}
550
551
552void
553TBarWindow::RemoveItem(BMessage* message)
554{
555	int32 id;
556	const char* name;
557
558	// ids ought to be unique across all shelves, assuming, of course,
559	// that sometime in the future there may be more than one
560#if SHELF_AWARE
561	if (message->FindInt32("shelf", (int32*)&shelf) == B_OK) {
562		if (message->FindString("name", &name) == B_OK)
563			fBarView->RemoveItem(name, shelf);
564	} else {
565#endif
566		if (message->FindInt32("id", &id) == B_OK) {
567			fBarView->RemoveItem(id);
568		// remove the following two lines if and when the
569		// shelf option returns
570		} else if (message->FindString("name", &name) == B_OK)
571			fBarView->RemoveItem(name, B_DESKBAR_TRAY);
572
573#if SHELF_AWARE
574	}
575#endif
576}
577
578
579void
580TBarWindow::GetIconFrame(BMessage* message)
581{
582	BRect frame(0, 0, 0, 0);
583
584	const char* name;
585	int32 id;
586	if (message->FindInt32("id", &id) == B_OK)
587		frame = fBarView->IconFrame(id);
588	else if (message->FindString("name", &name) == B_OK)
589		frame = fBarView->IconFrame(name);
590
591	BMessage reply('rply');
592	reply.AddRect("frame", frame);
593	message->SendReply(&reply);
594}
595
596
597bool
598TBarWindow::IsShowingMenu() const
599{
600	return fShowingMenu;
601}
602
603
604bool
605TBarWindow::_IsFocusMessage(BMessage* message)
606{
607	BMessage::Private messagePrivate(message);
608	if (!messagePrivate.UsePreferredTarget())
609		return false;
610
611	bool feedFocus;
612	if (message->HasInt32("_token")
613		&& (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus))
614		return false;
615
616	return true;
617}
618