xref: /haiku/src/kits/tracker/DeskWindow.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
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 trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 #include <Debug.h>
36 #include <FindDirectory.h>
37 #include <NodeMonitor.h>
38 #include <Path.h>
39 #include <PopUpMenu.h>
40 #include <Screen.h>
41 #include <Volume.h>
42 #include <VolumeRoster.h>
43 
44 #include <fcntl.h>
45 #include <unistd.h>
46 
47 #include "Attributes.h"
48 #include "AutoLock.h"
49 #include "BackgroundImage.h"
50 #include "Commands.h"
51 #include "DesktopPoseView.h"
52 #include "DeskWindow.h"
53 #include "FSUtils.h"
54 #include "IconMenuItem.h"
55 #include "MountMenu.h"
56 #include "PoseView.h"
57 #include "Tracker.h"
58 #include "TemplatesMenu.h"
59 
60 #if OPEN_TRACKER
61 #include "DeviceMap.h"
62 #else
63 #include <private/storage/DeviceMap.h>
64 #endif
65 
66 const char *kShelfPath = "tracker_shelf";
67 	// replicant support
68 
69 
70 BDeskWindow::BDeskWindow(LockingList<BWindow> *windowList)
71 	:	BContainerWindow(windowList, 0,
72 			kPrivateDesktopWindowLook, kPrivateDesktopWindowFeel,
73 			B_NOT_MOVABLE | B_WILL_ACCEPT_FIRST_CLICK |
74 			B_NOT_CLOSABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS,
75 			B_ALL_WORKSPACES),
76 		fDeskShelf(0),
77 		fTrashContextMenu(0),
78 		fShouldUpdateAddonShortcuts(true)
79 {
80 }
81 
82 
83 BDeskWindow::~BDeskWindow()
84 {
85 	SaveDesktopPoseLocations();
86 		// explicit call to SavePoseLocations so that extended pose info
87 		// gets committed properly
88 	PoseView()->DisableSaveLocation();
89 		// prevent double-saving, this would slow down quitting
90 	PoseView()->StopSettingsWatch();
91 	stop_watching(this);
92 }
93 
94 
95 static void
96 WatchAddOnDir(directory_which dirName, BDeskWindow *window)
97 {
98 	BPath path;
99 	if (find_directory(dirName, &path) == B_OK) {
100 		path.Append("Tracker");
101 		BNode node(path.Path());
102 		node_ref nodeRef;
103 		node.GetNodeRef(&nodeRef);
104 		TTracker::WatchNode(&nodeRef, B_WATCH_DIRECTORY, window);
105 	}
106 }
107 
108 
109 void
110 BDeskWindow::Init(const BMessage *)
111 {
112 	AddTrashContextMenu();
113 	//
114 	//	Set the size of the screen before calling the container window's
115 	//	Init() because it will add volume poses to this window and
116 	// 	they will be clipped otherwise
117 	//
118 	BScreen screen(this);
119 	fOldFrame = screen.Frame();
120 
121 	PoseView()->SetShowHideSelection(false);
122 	ResizeTo(fOldFrame.Width(), fOldFrame.Height());
123 
124 	entry_ref ref;
125 	BPath path;
126 	if (!BootedInSafeMode() && FSFindTrackerSettingsDir(&path) == B_OK) {
127 		path.Append(kShelfPath);
128 		close(open(path.Path(), O_RDONLY | O_CREAT));
129 		if (get_ref_for_path(path.Path(), &ref) == B_OK)
130 			fDeskShelf = new BShelf(&ref, fPoseView);
131 		if (fDeskShelf)
132 			fDeskShelf->SetDisplaysZombies(true);
133 	}
134 
135 	// watch add-on directories so that we can track the addons with
136 	// corresponding shortcuts
137 	WatchAddOnDir(B_BEOS_ADDONS_DIRECTORY, this);
138 	WatchAddOnDir(B_USER_ADDONS_DIRECTORY, this);
139 	WatchAddOnDir(B_COMMON_ADDONS_DIRECTORY, this);
140 
141 	_inherited::Init();
142 }
143 
144 
145 struct AddOneShortcutParams {
146 	BDeskWindow *window;
147 	std::set<uint32> *currentAddonShortcuts;
148 };
149 
150 static bool
151 AddOneShortcut(const Model *model, const char *, uint32 shortcut, bool /*primary*/, void *context)
152 {
153 	if (!shortcut)
154 		// no shortcut, bail
155 		return false;
156 
157 	AddOneShortcutParams *params = (AddOneShortcutParams *)context;
158 	BMessage *runAddon = new BMessage(kLoadAddOn);
159 	runAddon->AddRef("refs", model->EntryRef());
160 
161 	params->window->AddShortcut(shortcut, B_OPTION_KEY | B_COMMAND_KEY,
162 		runAddon);
163 	params->currentAddonShortcuts->insert(shortcut);
164 	PRINT(("adding new shortcut %c\n", (char)shortcut));
165 
166 	return false;
167 }
168 
169 
170 void
171 BDeskWindow::MenusBeginning()
172 {
173 	_inherited::MenusBeginning();
174 
175 	if (fShouldUpdateAddonShortcuts) {
176 		PRINT(("updating addon shortcuts\n"));
177 		fShouldUpdateAddonShortcuts = false;
178 
179 		// remove all current addon shortcuts
180 		for (std::set<uint32>::iterator it= fCurrentAddonShortcuts.begin();
181 			it != fCurrentAddonShortcuts.end(); it++) {
182 			PRINT(("removing shortcut %c\n", *it));
183 			RemoveShortcut(*it, B_OPTION_KEY | B_COMMAND_KEY);
184 		}
185 
186 		fCurrentAddonShortcuts.clear();
187 
188 		AddOneShortcutParams params;
189 		params.window = this;
190 		params.currentAddonShortcuts = &fCurrentAddonShortcuts;
191 		EachAddon(&AddOneShortcut, &params);
192 	}
193 }
194 
195 
196 void
197 BDeskWindow::Quit()
198 {
199 	if (fNavigationItem) {
200 		// this duplicates BContainerWindow::Quit because
201 		// fNavigationItem can be part of fTrashContextMenu
202 		// and would get deleted with it
203 		BMenu *menu = fNavigationItem->Menu();
204 		if (menu)
205 			menu->RemoveItem(fNavigationItem);
206 		delete fNavigationItem;
207 		fNavigationItem = 0;
208 	}
209 
210 	delete fTrashContextMenu;
211 	fTrashContextMenu = NULL;
212 
213 	delete fDeskShelf;
214 	_inherited::Quit();
215 }
216 
217 
218 BPoseView *
219 BDeskWindow::NewPoseView(Model *model, BRect rect, uint32 viewMode)
220 {
221 	return new DesktopPoseView(model, rect, viewMode);
222 }
223 
224 
225 void
226 BDeskWindow::CreatePoseView(Model *model)
227 {
228 	fPoseView = NewPoseView(model, Bounds(), kIconMode);
229 	fPoseView->SetIconMapping(false);
230 	fPoseView->SetEnsurePosesVisible(true);
231 	fPoseView->SetAutoScroll(false);
232 
233 	BScreen screen(this);
234 	rgb_color desktopColor = screen.DesktopColor();
235 	if (desktopColor.alpha != 255) {
236 		desktopColor.alpha = 255;
237 		screen.SetDesktopColor(desktopColor);
238 	}
239 
240 	fPoseView->SetViewColor(desktopColor);
241 	fPoseView->SetLowColor(desktopColor);
242 
243 	AddChild(fPoseView);
244 
245 	PoseView()->StartSettingsWatch();
246 }
247 
248 
249 void
250 BDeskWindow::AddWindowContextMenus(BMenu *menu)
251 {
252 	TemplatesMenu *tempateMenu = new TemplatesMenu(PoseView());
253 
254 	menu->AddItem(tempateMenu);
255 	tempateMenu->SetTargetForItems(PoseView());
256 	tempateMenu->SetFont(be_plain_font);
257 
258 	menu->AddSeparatorItem();
259 	menu->AddItem(new BMenuItem("Icon View", new BMessage(kIconMode)));
260 	menu->AddItem(new BMenuItem("Mini Icon View", new BMessage(kMiniIconMode)));
261 	menu->AddSeparatorItem();
262 	BMenuItem *pasteItem;
263 	menu->AddItem(pasteItem = new BMenuItem("Paste", new BMessage(B_PASTE), 'V'));
264 	menu->AddSeparatorItem();
265 	menu->AddItem(new BMenuItem("Clean Up", new BMessage(kCleanup), 'K'));
266 	menu->AddItem(new BMenuItem("Select"B_UTF8_ELLIPSIS,
267 		new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY));
268 	menu->AddItem(new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A'));
269 
270 	menu->AddSeparatorItem();
271 	menu->AddItem(new MountMenu("Mount"));
272 
273 	menu->AddSeparatorItem();
274 	menu->AddItem(new BMenu(kAddOnsMenuName));
275 
276 	// target items as needed
277 	menu->SetTargetForItems(PoseView());
278 	pasteItem->SetTarget(this);
279 }
280 
281 
282 void
283 BDeskWindow::AddTrashContextMenu()
284 {
285 	// setup special trash context menu
286 	fTrashContextMenu = new BPopUpMenu("TrashContext", false, false);
287 	fTrashContextMenu->SetFont(be_plain_font);
288 	fTrashContextMenu->AddItem(new BMenuItem("Empty Trash",
289 		new BMessage(kEmptyTrash)));
290 	fTrashContextMenu->AddItem(new BMenuItem("Open",
291 		new BMessage(kOpenSelection), 'O'));
292 	fTrashContextMenu->AddItem(new BMenuItem("Get Info", new BMessage(kGetInfo), 'I'));
293 	fTrashContextMenu->SetTargetForItems(PoseView());
294 }
295 
296 
297 void
298 BDeskWindow::ShowContextMenu(BPoint loc, const entry_ref *ref, BView *view)
299 {
300 	BEntry entry;
301 
302 	// cleanup previous entries
303 	DeleteSubmenu(fNavigationItem);
304 
305 	if (ref && entry.SetTo(ref) == B_OK && FSIsTrashDir(&entry)) {
306 		//
307 		//	don't show any menu if this is the trash
308 		if (Dragging() && FSIsTrashDir(&entry))
309 			return;
310 
311 		// selected item was trash, show the trash context menu instead
312 		BPoint global(loc);
313 		PoseView()->ConvertToScreen(&global);
314 		PoseView()->CommitActivePose();
315 		BRect mouse_rect(global.x, global.y, global.x, global.y);
316 		mouse_rect.InsetBy(-5, -5);
317 
318 		EnableNamedMenuItem(fTrashContextMenu, kEmptyTrash,
319 			static_cast<TTracker *>(be_app)->TrashFull());
320 
321 		SetupNavigationMenu(ref, fTrashContextMenu);
322 		fTrashContextMenu->Go(global, true, false, mouse_rect, true);
323 	} else
324 		_inherited::ShowContextMenu(loc, ref, view);
325 }
326 
327 
328 void
329 BDeskWindow::WorkspaceActivated(int32 workspace, bool state)
330 {
331 	if (fBackgroundImage)
332 		fBackgroundImage->WorkspaceActivated(PoseView(), workspace, state);
333 }
334 
335 
336 void
337 BDeskWindow::SaveDesktopPoseLocations()
338 {
339 	PoseView()->SavePoseLocations(&fOldFrame);
340 }
341 
342 
343 void
344 BDeskWindow::ScreenChanged(BRect frame, color_space space)
345 {
346 	bool frameChanged = (frame != fOldFrame);
347 
348 	SaveDesktopPoseLocations();
349 	fOldFrame = frame;
350 	ResizeTo(frame.Width(), frame.Height());
351 
352 	if (fBackgroundImage)
353 		fBackgroundImage->ScreenChanged(frame, space);
354 
355 	PoseView()->CheckPoseVisibility(frameChanged ? &frame : 0);
356 		// if frame changed, pass new frame so that icons can
357 		// get rearranged based on old pose info for the frame
358 }
359 
360 
361 void
362 BDeskWindow::UpdateDesktopBackgroundImages()
363 {
364 	WindowStateNodeOpener opener(this, false);
365 	fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage,
366 		opener.Node(), true, PoseView());
367 }
368 
369 
370 void
371 BDeskWindow::Show()
372 {
373 	if (fBackgroundImage)
374 		fBackgroundImage->Show(PoseView(), current_workspace());
375 
376 	PoseView()->CheckPoseVisibility();
377 
378 	_inherited::Show();
379 }
380 
381 
382 bool
383 BDeskWindow::ShouldAddScrollBars() const
384 {
385 	return false;
386 }
387 
388 
389 bool
390 BDeskWindow::ShouldAddMenus() const
391 {
392 	return false;
393 }
394 
395 
396 bool
397 BDeskWindow::ShouldAddContainerView() const
398 {
399 	return false;
400 }
401 
402 
403 void
404 BDeskWindow::MessageReceived(BMessage *message)
405 {
406 	if (message->WasDropped()) {
407 		const rgb_color *color;
408 		int32 size;
409 		// handle "roColour"-style color drops
410 		if (message->FindData("RGBColor", 'RGBC',
411 			(const void **)&color, &size) == B_OK) {
412 			BScreen(this).SetDesktopColor(*color);
413 			fPoseView->SetViewColor(*color);
414 			fPoseView->SetLowColor(*color);
415 			return;
416 		}
417 	}
418 
419 	switch (message->what) {
420 		case B_NODE_MONITOR:
421 			PRINT(("will update addon shortcuts\n"));
422 			fShouldUpdateAddonShortcuts = true;
423 			break;
424 
425 		default:
426 			_inherited::MessageReceived(message);
427 			break;
428 	}
429 }
430 
431