xref: /haiku/src/kits/tracker/DeskWindow.cpp (revision 0e50eab75e25d0d82090e22dbff766dfaa6f5e86)
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 #if B_BEOS_VERSION > B_BEOS_VERSION_5
238 		// This call seems to have the power to cause R5 to freeze!
239 		// Please report if commenting this out helped or helped not
240 		// on your system
241 		screen.SetDesktopColor(desktopColor);
242 #endif
243 	}
244 
245 	fPoseView->SetViewColor(desktopColor);
246 	fPoseView->SetLowColor(desktopColor);
247 
248 	AddChild(fPoseView);
249 
250 	PoseView()->StartSettingsWatch();
251 }
252 
253 
254 void
255 BDeskWindow::AddWindowContextMenus(BMenu *menu)
256 {
257 	TemplatesMenu *tempateMenu = new TemplatesMenu(PoseView());
258 
259 	menu->AddItem(tempateMenu);
260 	tempateMenu->SetTargetForItems(PoseView());
261 	tempateMenu->SetFont(be_plain_font);
262 
263 	menu->AddSeparatorItem();
264 	menu->AddItem(new BMenuItem("Icon View", new BMessage(kIconMode)));
265 	menu->AddItem(new BMenuItem("Mini Icon View", new BMessage(kMiniIconMode)));
266 	menu->AddSeparatorItem();
267 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
268 	BMenuItem *pasteItem;
269 	menu->AddItem(pasteItem = new BMenuItem("Paste", new BMessage(B_PASTE), 'V'));
270 	menu->AddSeparatorItem();
271 #endif
272 	menu->AddItem(new BMenuItem("Clean Up", new BMessage(kCleanup), 'K'));
273 	menu->AddItem(new BMenuItem("Select"B_UTF8_ELLIPSIS,
274 		new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY));
275 	menu->AddItem(new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A'));
276 
277 	menu->AddSeparatorItem();
278 	menu->AddItem(new MountMenu("Mount"));
279 
280 	menu->AddSeparatorItem();
281 	menu->AddItem(new BMenu(kAddOnsMenuName));
282 
283 	// target items as needed
284 	menu->SetTargetForItems(PoseView());
285 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
286 	pasteItem->SetTarget(this);
287 #endif
288 }
289 
290 
291 void
292 BDeskWindow::AddTrashContextMenu()
293 {
294 	// setup special trash context menu
295 	fTrashContextMenu = new BPopUpMenu("TrashContext", false, false);
296 	fTrashContextMenu->SetFont(be_plain_font);
297 	fTrashContextMenu->AddItem(new BMenuItem("Empty Trash",
298 		new BMessage(kEmptyTrash)));
299 	fTrashContextMenu->AddItem(new BMenuItem("Open",
300 		new BMessage(kOpenSelection), 'O'));
301 	fTrashContextMenu->AddItem(new BMenuItem("Get Info",
302 		new BMessage(kGetInfo), 'I'));
303 	fTrashContextMenu->SetTargetForItems(PoseView());
304 }
305 
306 
307 void
308 BDeskWindow::ShowContextMenu(BPoint loc, const entry_ref *ref, BView *view)
309 {
310 	BEntry entry;
311 
312 	// cleanup previous entries
313 	DeleteSubmenu(fNavigationItem);
314 
315 	if (ref && entry.SetTo(ref) == B_OK && FSIsTrashDir(&entry)) {
316 		//
317 		//	don't show any menu if this is the trash
318 		if (Dragging() && FSIsTrashDir(&entry))
319 			return;
320 
321 		// selected item was trash, show the trash context menu instead
322 		BPoint global(loc);
323 		PoseView()->ConvertToScreen(&global);
324 		PoseView()->CommitActivePose();
325 		BRect mouse_rect(global.x, global.y, global.x, global.y);
326 		mouse_rect.InsetBy(-5, -5);
327 
328 		EnableNamedMenuItem(fTrashContextMenu, kEmptyTrash,
329 			static_cast<TTracker *>(be_app)->TrashFull());
330 
331 		SetupNavigationMenu(ref, fTrashContextMenu);
332 		fTrashContextMenu->Go(global, true, false, mouse_rect, true);
333 	} else
334 		_inherited::ShowContextMenu(loc, ref, view);
335 }
336 
337 
338 void
339 BDeskWindow::WorkspaceActivated(int32 workspace, bool state)
340 {
341 	if (fBackgroundImage)
342 		fBackgroundImage->WorkspaceActivated(PoseView(), workspace, state);
343 }
344 
345 
346 void
347 BDeskWindow::SaveDesktopPoseLocations()
348 {
349 	PoseView()->SavePoseLocations(&fOldFrame);
350 }
351 
352 
353 void
354 BDeskWindow::ScreenChanged(BRect frame, color_space space)
355 {
356 	bool frameChanged = (frame != fOldFrame);
357 
358 	SaveDesktopPoseLocations();
359 	fOldFrame = frame;
360 	ResizeTo(frame.Width(), frame.Height());
361 
362 	if (fBackgroundImage)
363 		fBackgroundImage->ScreenChanged(frame, space);
364 
365 	PoseView()->CheckPoseVisibility(frameChanged ? &frame : 0);
366 		// if frame changed, pass new frame so that icons can
367 		// get rearranged based on old pose info for the frame
368 }
369 
370 
371 void
372 BDeskWindow::UpdateDesktopBackgroundImages()
373 {
374 	WindowStateNodeOpener opener(this, false);
375 	fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage,
376 		opener.Node(), true, PoseView());
377 }
378 
379 
380 void
381 BDeskWindow::Show()
382 {
383 	if (fBackgroundImage)
384 		fBackgroundImage->Show(PoseView(), current_workspace());
385 
386 	PoseView()->CheckPoseVisibility();
387 
388 	_inherited::Show();
389 }
390 
391 
392 bool
393 BDeskWindow::ShouldAddScrollBars() const
394 {
395 	return false;
396 }
397 
398 
399 bool
400 BDeskWindow::ShouldAddMenus() const
401 {
402 	return false;
403 }
404 
405 
406 bool
407 BDeskWindow::ShouldAddContainerView() const
408 {
409 	return false;
410 }
411 
412 
413 void
414 BDeskWindow::MessageReceived(BMessage *message)
415 {
416 	if (message->WasDropped()) {
417 		const rgb_color *color;
418 		int32 size;
419 		// handle "roColour"-style color drops
420 		if (message->FindData("RGBColor", 'RGBC',
421 			(const void **)&color, &size) == B_OK) {
422 			BScreen(this).SetDesktopColor(*color);
423 			fPoseView->SetViewColor(*color);
424 			fPoseView->SetLowColor(*color);
425 			return;
426 		}
427 	}
428 
429 	switch (message->what) {
430 		case B_NODE_MONITOR:
431 			PRINT(("will update addon shortcuts\n"));
432 			fShouldUpdateAddonShortcuts = true;
433 			break;
434 
435 		default:
436 			_inherited::MessageReceived(message);
437 			break;
438 	}
439 }
440 
441