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