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