xref: /haiku/src/kits/tracker/DeskWindow.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
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_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 		EachAddon(&AddOneShortcut, &params);
208 	}
209 }
210 
211 
212 void
213 BDeskWindow::Quit()
214 {
215 	if (fNavigationItem) {
216 		// this duplicates BContainerWindow::Quit because
217 		// fNavigationItem can be part of fTrashContextMenu
218 		// and would get deleted with it
219 		BMenu *menu = fNavigationItem->Menu();
220 		if (menu)
221 			menu->RemoveItem(fNavigationItem);
222 		delete fNavigationItem;
223 		fNavigationItem = 0;
224 	}
225 
226 	delete fTrashContextMenu;
227 	fTrashContextMenu = NULL;
228 
229 	delete fDeskShelf;
230 	_inherited::Quit();
231 }
232 
233 
234 BPoseView *
235 BDeskWindow::NewPoseView(Model *model, BRect rect, uint32 viewMode)
236 {
237 	return new DesktopPoseView(model, rect, viewMode);
238 }
239 
240 
241 void
242 BDeskWindow::CreatePoseView(Model *model)
243 {
244 	fPoseView = NewPoseView(model, Bounds(), kIconMode);
245 	fPoseView->SetIconMapping(false);
246 	fPoseView->SetEnsurePosesVisible(true);
247 	fPoseView->SetAutoScroll(false);
248 
249 	BScreen screen(this);
250 	rgb_color desktopColor = screen.DesktopColor();
251 	if (desktopColor.alpha != 255) {
252 		desktopColor.alpha = 255;
253 #if B_BEOS_VERSION > B_BEOS_VERSION_5
254 		// This call seems to have the power to cause R5 to freeze!
255 		// Please report if commenting this out helped or helped not
256 		// on your system
257 		screen.SetDesktopColor(desktopColor);
258 #endif
259 	}
260 
261 	fPoseView->SetViewColor(desktopColor);
262 	fPoseView->SetLowColor(desktopColor);
263 
264 	AddChild(fPoseView);
265 
266 	PoseView()->StartSettingsWatch();
267 }
268 
269 
270 void
271 BDeskWindow::AddWindowContextMenus(BMenu *menu)
272 {
273 	TemplatesMenu* tempateMenu = new TemplatesMenu(PoseView(),
274 		B_TRANSLATE("New"));
275 
276 	menu->AddItem(tempateMenu);
277 	tempateMenu->SetTargetForItems(PoseView());
278 	tempateMenu->SetFont(be_plain_font);
279 
280 	menu->AddSeparatorItem();
281 
282 	BMenu* iconSizeMenu = new BMenu(B_TRANSLATE("Icon view"));
283 
284 	BMessage* message = new BMessage(kIconMode);
285 	message->AddInt32("size", 32);
286 	BMenuItem* item = new BMenuItem(B_TRANSLATE("32 x 32"), message);
287 	item->SetMarked(PoseView()->IconSizeInt() == 32);
288 	item->SetTarget(PoseView());
289 	iconSizeMenu->AddItem(item);
290 
291 	message = new BMessage(kIconMode);
292 	message->AddInt32("size", 40);
293 	item = new BMenuItem(B_TRANSLATE("40 x 40"), message);
294 	item->SetMarked(PoseView()->IconSizeInt() == 40);
295 	item->SetTarget(PoseView());
296 	iconSizeMenu->AddItem(item);
297 
298 	message = new BMessage(kIconMode);
299 	message->AddInt32("size", 48);
300 	item = new BMenuItem(B_TRANSLATE("48 x 48"), message);
301 	item->SetMarked(PoseView()->IconSizeInt() == 48);
302 	item->SetTarget(PoseView());
303 	iconSizeMenu->AddItem(item);
304 
305 	message = new BMessage(kIconMode);
306 	message->AddInt32("size", 64);
307 	item = new BMenuItem(B_TRANSLATE("64 x 64"), message);
308 	item->SetMarked(PoseView()->IconSizeInt() == 64);
309 	item->SetTarget(PoseView());
310 	iconSizeMenu->AddItem(item);
311 
312 	iconSizeMenu->AddSeparatorItem();
313 
314 	message = new BMessage(kIconMode);
315 	message->AddInt32("scale", 0);
316 	item = new BMenuItem(B_TRANSLATE("Decrease size"), message, '-');
317 	item->SetTarget(PoseView());
318 	iconSizeMenu->AddItem(item);
319 
320 	message = new BMessage(kIconMode);
321 	message->AddInt32("scale", 1);
322 	item = new BMenuItem(B_TRANSLATE("Increase size"), message, '+');
323 	item->SetTarget(PoseView());
324 	iconSizeMenu->AddItem(item);
325 
326 	// A sub menu where the super item can be invoked.
327 	menu->AddItem(iconSizeMenu);
328 	iconSizeMenu->Superitem()->SetShortcut('1', B_COMMAND_KEY);
329 	iconSizeMenu->Superitem()->SetMessage(new BMessage(kIconMode));
330 	iconSizeMenu->Superitem()->SetTarget(PoseView());
331 	iconSizeMenu->Superitem()->SetMarked(PoseView()->ViewMode() == kIconMode);
332 
333 	item = new BMenuItem(B_TRANSLATE("Mini icon view"),
334 		new BMessage(kMiniIconMode), '2');
335 	item->SetMarked(PoseView()->ViewMode() == kMiniIconMode);
336 	menu->AddItem(item);
337 
338 	menu->AddSeparatorItem();
339 
340 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
341 	BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"),
342 		new BMessage(B_PASTE), 'V'));
343 	menu->AddItem(pasteItem);
344 	menu->AddSeparatorItem();
345 #endif
346 	menu->AddItem(new BMenuItem(B_TRANSLATE("Clean up"), new BMessage(kCleanup),
347 		'K'));
348 	menu->AddItem(new BMenuItem(B_TRANSLATE("Select"B_UTF8_ELLIPSIS),
349 		new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY));
350 	menu->AddItem(new BMenuItem(B_TRANSLATE("Select all"),
351 		new BMessage(B_SELECT_ALL), 'A'));
352 
353 	menu->AddSeparatorItem();
354 	menu->AddItem(new MountMenu(B_TRANSLATE("Mount")));
355 
356 	menu->AddSeparatorItem();
357 	menu->AddItem(new BMenu(B_TRANSLATE("Add-ons")));
358 
359 	// target items as needed
360 	menu->SetTargetForItems(PoseView());
361 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
362 	pasteItem->SetTarget(this);
363 #endif
364 }
365 
366 
367 void
368 BDeskWindow::WorkspaceActivated(int32 workspace, bool state)
369 {
370 	if (fBackgroundImage)
371 		fBackgroundImage->WorkspaceActivated(PoseView(), workspace, state);
372 }
373 
374 
375 void
376 BDeskWindow::SaveDesktopPoseLocations()
377 {
378 	PoseView()->SavePoseLocations(&fOldFrame);
379 }
380 
381 
382 void
383 BDeskWindow::ScreenChanged(BRect frame, color_space space)
384 {
385 	bool frameChanged = (frame != fOldFrame);
386 
387 	SaveDesktopPoseLocations();
388 	fOldFrame = frame;
389 	ResizeTo(frame.Width(), frame.Height());
390 
391 	if (fBackgroundImage)
392 		fBackgroundImage->ScreenChanged(frame, space);
393 
394 	PoseView()->CheckPoseVisibility(frameChanged ? &frame : 0);
395 		// if frame changed, pass new frame so that icons can
396 		// get rearranged based on old pose info for the frame
397 }
398 
399 
400 void
401 BDeskWindow::UpdateDesktopBackgroundImages()
402 {
403 	WindowStateNodeOpener opener(this, false);
404 	fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage,
405 		opener.Node(), true, PoseView());
406 }
407 
408 
409 void
410 BDeskWindow::Show()
411 {
412 	if (fBackgroundImage)
413 		fBackgroundImage->Show(PoseView(), current_workspace());
414 
415 	PoseView()->CheckPoseVisibility();
416 
417 	_inherited::Show();
418 }
419 
420 
421 bool
422 BDeskWindow::ShouldAddScrollBars() const
423 {
424 	return false;
425 }
426 
427 
428 bool
429 BDeskWindow::ShouldAddMenus() const
430 {
431 	return false;
432 }
433 
434 
435 bool
436 BDeskWindow::ShouldAddContainerView() const
437 {
438 	return false;
439 }
440 
441 
442 void
443 BDeskWindow::MessageReceived(BMessage *message)
444 {
445 	if (message->WasDropped()) {
446 		const rgb_color *color;
447 		int32 size;
448 		// handle "roColour"-style color drops
449 		if (message->FindData("RGBColor", 'RGBC',
450 			(const void **)&color, &size) == B_OK) {
451 			BScreen(this).SetDesktopColor(*color);
452 			fPoseView->SetViewColor(*color);
453 			fPoseView->SetLowColor(*color);
454 			return;
455 		}
456 	}
457 
458 	switch (message->what) {
459 		case B_NODE_MONITOR:
460 			PRINT(("will update addon shortcuts\n"));
461 			fShouldUpdateAddonShortcuts = true;
462 			break;
463 
464 		default:
465 			_inherited::MessageReceived(message);
466 			break;
467 	}
468 }
469 
470