xref: /haiku/src/kits/tracker/DeskWindow.cpp (revision b289aaf66bbf6e173aa90fa194fc256965f1b34d)
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 
61 const char *kShelfPath = "tracker_shelf";
62 	// replicant support
63 
64 
65 static void
66 WatchAddOnDir(directory_which dirName, BDeskWindow *window)
67 {
68 	BPath path;
69 	if (find_directory(dirName, &path) == B_OK) {
70 		path.Append("Tracker");
71 		BNode node(path.Path());
72 		node_ref nodeRef;
73 		node.GetNodeRef(&nodeRef);
74 		TTracker::WatchNode(&nodeRef, B_WATCH_DIRECTORY, window);
75 	}
76 }
77 
78 
79 struct AddOneShortcutParams {
80 	BDeskWindow *window;
81 	std::set<uint32> *currentAddonShortcuts;
82 };
83 
84 static bool
85 AddOneShortcut(const Model *model, const char *, uint32 shortcut, bool /*primary*/, void *context)
86 {
87 	if (!shortcut)
88 		// no shortcut, bail
89 		return false;
90 
91 	AddOneShortcutParams *params = (AddOneShortcutParams *)context;
92 	BMessage *runAddon = new BMessage(kLoadAddOn);
93 	runAddon->AddRef("refs", model->EntryRef());
94 
95 	params->window->AddShortcut(shortcut, B_OPTION_KEY | B_COMMAND_KEY,
96 		runAddon);
97 	params->currentAddonShortcuts->insert(shortcut);
98 	PRINT(("adding new shortcut %c\n", (char)shortcut));
99 
100 	return false;
101 }
102 
103 
104 // #pragma mark -
105 
106 
107 BDeskWindow::BDeskWindow(LockingList<BWindow> *windowList)
108 	:
109 	BContainerWindow(windowList, 0, kPrivateDesktopWindowLook,
110 		kPrivateDesktopWindowFeel, B_NOT_MOVABLE | B_WILL_ACCEPT_FIRST_CLICK
111 			| B_NOT_ZOOMABLE | B_NOT_CLOSABLE | B_NOT_MINIMIZABLE
112 			| B_ASYNCHRONOUS_CONTROLS, B_ALL_WORKSPACES),
113 	fDeskShelf(0),
114 	fTrashContextMenu(0),
115 	fShouldUpdateAddonShortcuts(true)
116 {
117 	// Add icon view switching shortcuts. These are displayed in the context
118 	// menu, although they obviously don't work from those menu items.
119 	BMessage* message = new BMessage(kIconMode);
120 	AddShortcut('1', B_COMMAND_KEY, message, PoseView());
121 
122 	message = new BMessage(kMiniIconMode);
123 	AddShortcut('2', B_COMMAND_KEY, message, PoseView());
124 
125 	message = new BMessage(kIconMode);
126 	message->AddInt32("scale", 1);
127 	AddShortcut('+', B_COMMAND_KEY, message, PoseView());
128 
129 	message = new BMessage(kIconMode);
130 	message->AddInt32("scale", 0);
131 	AddShortcut('-', B_COMMAND_KEY, message, PoseView());
132 }
133 
134 
135 BDeskWindow::~BDeskWindow()
136 {
137 	SaveDesktopPoseLocations();
138 		// explicit call to SavePoseLocations so that extended pose info
139 		// gets committed properly
140 	PoseView()->DisableSaveLocation();
141 		// prevent double-saving, this would slow down quitting
142 	PoseView()->StopSettingsWatch();
143 	stop_watching(this);
144 }
145 
146 
147 void
148 BDeskWindow::Init(const BMessage *)
149 {
150 	//
151 	//	Set the size of the screen before calling the container window's
152 	//	Init() because it will add volume poses to this window and
153 	// 	they will be clipped otherwise
154 	//
155 	BScreen screen(this);
156 	fOldFrame = screen.Frame();
157 
158 	PoseView()->SetShowHideSelection(false);
159 	ResizeTo(fOldFrame.Width(), fOldFrame.Height());
160 
161 	entry_ref ref;
162 	BPath path;
163 	if (!BootedInSafeMode() && FSFindTrackerSettingsDir(&path) == B_OK) {
164 		path.Append(kShelfPath);
165 		close(open(path.Path(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
166 		if (get_ref_for_path(path.Path(), &ref) == B_OK)
167 			fDeskShelf = new BShelf(&ref, fPoseView);
168 		if (fDeskShelf)
169 			fDeskShelf->SetDisplaysZombies(true);
170 	}
171 
172 	// watch add-on directories so that we can track the addons with
173 	// corresponding shortcuts
174 	WatchAddOnDir(B_BEOS_ADDONS_DIRECTORY, this);
175 	WatchAddOnDir(B_USER_ADDONS_DIRECTORY, this);
176 	WatchAddOnDir(B_COMMON_ADDONS_DIRECTORY, this);
177 
178 	_inherited::Init();
179 }
180 
181 
182 void
183 BDeskWindow::MenusBeginning()
184 {
185 	_inherited::MenusBeginning();
186 
187 	if (fShouldUpdateAddonShortcuts) {
188 		PRINT(("updating addon shortcuts\n"));
189 		fShouldUpdateAddonShortcuts = false;
190 
191 		// remove all current addon shortcuts
192 		for (std::set<uint32>::iterator it= fCurrentAddonShortcuts.begin();
193 			it != fCurrentAddonShortcuts.end(); it++) {
194 			PRINT(("removing shortcut %c\n", *it));
195 			RemoveShortcut(*it, B_OPTION_KEY | B_COMMAND_KEY);
196 		}
197 
198 		fCurrentAddonShortcuts.clear();
199 
200 		AddOneShortcutParams params;
201 		params.window = this;
202 		params.currentAddonShortcuts = &fCurrentAddonShortcuts;
203 		EachAddon(&AddOneShortcut, &params);
204 	}
205 }
206 
207 
208 void
209 BDeskWindow::Quit()
210 {
211 	if (fNavigationItem) {
212 		// this duplicates BContainerWindow::Quit because
213 		// fNavigationItem can be part of fTrashContextMenu
214 		// and would get deleted with it
215 		BMenu *menu = fNavigationItem->Menu();
216 		if (menu)
217 			menu->RemoveItem(fNavigationItem);
218 		delete fNavigationItem;
219 		fNavigationItem = 0;
220 	}
221 
222 	delete fTrashContextMenu;
223 	fTrashContextMenu = NULL;
224 
225 	delete fDeskShelf;
226 	_inherited::Quit();
227 }
228 
229 
230 BPoseView *
231 BDeskWindow::NewPoseView(Model *model, BRect rect, uint32 viewMode)
232 {
233 	return new DesktopPoseView(model, rect, viewMode);
234 }
235 
236 
237 void
238 BDeskWindow::CreatePoseView(Model *model)
239 {
240 	fPoseView = NewPoseView(model, Bounds(), kIconMode);
241 	fPoseView->SetIconMapping(false);
242 	fPoseView->SetEnsurePosesVisible(true);
243 	fPoseView->SetAutoScroll(false);
244 
245 	BScreen screen(this);
246 	rgb_color desktopColor = screen.DesktopColor();
247 	if (desktopColor.alpha != 255) {
248 		desktopColor.alpha = 255;
249 #if B_BEOS_VERSION > B_BEOS_VERSION_5
250 		// This call seems to have the power to cause R5 to freeze!
251 		// Please report if commenting this out helped or helped not
252 		// on your system
253 		screen.SetDesktopColor(desktopColor);
254 #endif
255 	}
256 
257 	fPoseView->SetViewColor(desktopColor);
258 	fPoseView->SetLowColor(desktopColor);
259 
260 	AddChild(fPoseView);
261 
262 	PoseView()->StartSettingsWatch();
263 }
264 
265 
266 void
267 BDeskWindow::AddWindowContextMenus(BMenu *menu)
268 {
269 	TemplatesMenu *tempateMenu = new TemplatesMenu(PoseView());
270 
271 	menu->AddItem(tempateMenu);
272 	tempateMenu->SetTargetForItems(PoseView());
273 	tempateMenu->SetFont(be_plain_font);
274 
275 	menu->AddSeparatorItem();
276 
277 	BMenu* iconSizeMenu = new BMenu("Icon view");
278 
279 	BMessage* message = new BMessage(kIconMode);
280 	message->AddInt32("size", 32);
281 	BMenuItem* item = new BMenuItem("32 x 32", message);
282 	item->SetMarked(PoseView()->IconSizeInt() == 32);
283 	item->SetTarget(PoseView());
284 	iconSizeMenu->AddItem(item);
285 
286 	message = new BMessage(kIconMode);
287 	message->AddInt32("size", 40);
288 	item = new BMenuItem("40 x 40", message);
289 	item->SetMarked(PoseView()->IconSizeInt() == 40);
290 	item->SetTarget(PoseView());
291 	iconSizeMenu->AddItem(item);
292 
293 	message = new BMessage(kIconMode);
294 	message->AddInt32("size", 48);
295 	item = new BMenuItem("48 x 48", message);
296 	item->SetMarked(PoseView()->IconSizeInt() == 48);
297 	item->SetTarget(PoseView());
298 	iconSizeMenu->AddItem(item);
299 
300 	message = new BMessage(kIconMode);
301 	message->AddInt32("size", 64);
302 	item = new BMenuItem("64 x 64", message);
303 	item->SetMarked(PoseView()->IconSizeInt() == 64);
304 	item->SetTarget(PoseView());
305 	iconSizeMenu->AddItem(item);
306 
307 	iconSizeMenu->AddSeparatorItem();
308 
309 	message = new BMessage(kIconMode);
310 	message->AddInt32("scale", 0);
311 	item = new BMenuItem("Decrease size", message, '-');
312 	item->SetTarget(PoseView());
313 	iconSizeMenu->AddItem(item);
314 
315 	message = new BMessage(kIconMode);
316 	message->AddInt32("scale", 1);
317 	item = new BMenuItem("Increase size", message, '+');
318 	item->SetTarget(PoseView());
319 	iconSizeMenu->AddItem(item);
320 
321 	// A sub menu where the super item can be invoked.
322 	menu->AddItem(iconSizeMenu);
323 	iconSizeMenu->Superitem()->SetShortcut('1', B_COMMAND_KEY);
324 	iconSizeMenu->Superitem()->SetMessage(new BMessage(kIconMode));
325 	iconSizeMenu->Superitem()->SetTarget(PoseView());
326 	iconSizeMenu->Superitem()->SetMarked(PoseView()->ViewMode() == kIconMode);
327 
328 	item = new BMenuItem("Mini icon view", new BMessage(kMiniIconMode), '2');
329 	item->SetMarked(PoseView()->ViewMode() == kMiniIconMode);
330 	menu->AddItem(item);
331 
332 	menu->AddSeparatorItem();
333 
334 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
335 	BMenuItem *pasteItem;
336 	menu->AddItem(pasteItem = new BMenuItem("Paste", new BMessage(B_PASTE), 'V'));
337 	menu->AddSeparatorItem();
338 #endif
339 	menu->AddItem(new BMenuItem("Clean up", new BMessage(kCleanup), 'K'));
340 	menu->AddItem(new BMenuItem("Select"B_UTF8_ELLIPSIS,
341 		new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY));
342 	menu->AddItem(new BMenuItem("Select all", new BMessage(B_SELECT_ALL), 'A'));
343 
344 	menu->AddSeparatorItem();
345 	menu->AddItem(new MountMenu("Mount"));
346 
347 	menu->AddSeparatorItem();
348 	menu->AddItem(new BMenu(kAddOnsMenuName));
349 
350 	// target items as needed
351 	menu->SetTargetForItems(PoseView());
352 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
353 	pasteItem->SetTarget(this);
354 #endif
355 }
356 
357 
358 void
359 BDeskWindow::WorkspaceActivated(int32 workspace, bool state)
360 {
361 	if (fBackgroundImage)
362 		fBackgroundImage->WorkspaceActivated(PoseView(), workspace, state);
363 }
364 
365 
366 void
367 BDeskWindow::SaveDesktopPoseLocations()
368 {
369 	PoseView()->SavePoseLocations(&fOldFrame);
370 }
371 
372 
373 void
374 BDeskWindow::ScreenChanged(BRect frame, color_space space)
375 {
376 	bool frameChanged = (frame != fOldFrame);
377 
378 	SaveDesktopPoseLocations();
379 	fOldFrame = frame;
380 	ResizeTo(frame.Width(), frame.Height());
381 
382 	if (fBackgroundImage)
383 		fBackgroundImage->ScreenChanged(frame, space);
384 
385 	PoseView()->CheckPoseVisibility(frameChanged ? &frame : 0);
386 		// if frame changed, pass new frame so that icons can
387 		// get rearranged based on old pose info for the frame
388 }
389 
390 
391 void
392 BDeskWindow::UpdateDesktopBackgroundImages()
393 {
394 	WindowStateNodeOpener opener(this, false);
395 	fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage,
396 		opener.Node(), true, PoseView());
397 }
398 
399 
400 void
401 BDeskWindow::Show()
402 {
403 	if (fBackgroundImage)
404 		fBackgroundImage->Show(PoseView(), current_workspace());
405 
406 	PoseView()->CheckPoseVisibility();
407 
408 	_inherited::Show();
409 }
410 
411 
412 bool
413 BDeskWindow::ShouldAddScrollBars() const
414 {
415 	return false;
416 }
417 
418 
419 bool
420 BDeskWindow::ShouldAddMenus() const
421 {
422 	return false;
423 }
424 
425 
426 bool
427 BDeskWindow::ShouldAddContainerView() const
428 {
429 	return false;
430 }
431 
432 
433 void
434 BDeskWindow::MessageReceived(BMessage *message)
435 {
436 	if (message->WasDropped()) {
437 		const rgb_color *color;
438 		int32 size;
439 		// handle "roColour"-style color drops
440 		if (message->FindData("RGBColor", 'RGBC',
441 			(const void **)&color, &size) == B_OK) {
442 			BScreen(this).SetDesktopColor(*color);
443 			fPoseView->SetViewColor(*color);
444 			fPoseView->SetLowColor(*color);
445 			return;
446 		}
447 	}
448 
449 	switch (message->what) {
450 		case B_NODE_MONITOR:
451 			PRINT(("will update addon shortcuts\n"));
452 			fShouldUpdateAddonShortcuts = true;
453 			break;
454 
455 		default:
456 			_inherited::MessageReceived(message);
457 			break;
458 	}
459 }
460 
461