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