xref: /haiku/src/kits/tracker/DeskWindow.cpp (revision 991dadd6324f7b7a68e94743a39ebae789823228)
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 <PathFinder.h>
42 #include <PathMonitor.h>
43 #include <PopUpMenu.h>
44 #include <Resources.h>
45 #include <Roster.h>
46 #include <Screen.h>
47 #include <String.h>
48 #include <StringList.h>
49 #include <Volume.h>
50 #include <VolumeRoster.h>
51 
52 #include <fcntl.h>
53 #include <unistd.h>
54 
55 #include "Attributes.h"
56 #include "AutoLock.h"
57 #include "BackgroundImage.h"
58 #include "Commands.h"
59 #include "DesktopPoseView.h"
60 #include "DeskWindow.h"
61 #include "FSUtils.h"
62 #include "IconMenuItem.h"
63 #include "KeyInfos.h"
64 #include "MountMenu.h"
65 #include "PoseView.h"
66 #include "Tracker.h"
67 #include "TemplatesMenu.h"
68 
69 
70 const char* kShelfPath = "tracker_shelf";
71 	// replicant support
72 
73 const char* kShortcutsSettings = "shortcuts_settings";
74 const char* kDefaultShortcut = "BEOS:default_shortcut";
75 const uint32 kDefaultModifiers = B_OPTION_KEY | B_COMMAND_KEY;
76 
77 
78 static struct AddonShortcut*
79 MatchOne(struct AddonShortcut* item, void* castToName)
80 {
81 	if (strcmp(item->model->Name(), (const char*)castToName) == 0) {
82 		// found match, bail out
83 		return item;
84 	}
85 
86 	return 0;
87 }
88 
89 
90 static void
91 AddOneShortcut(Model* model, char key, uint32 modifiers, BDeskWindow* window)
92 {
93 	if (key == '\0')
94 		return;
95 
96 	BMessage* runAddon = new BMessage(kLoadAddOn);
97 	runAddon->AddRef("refs", model->EntryRef());
98 	window->AddShortcut(key, modifiers, runAddon);
99 }
100 
101 
102 
103 static struct AddonShortcut*
104 RevertToDefault(struct AddonShortcut* item, void* castToWindow)
105 {
106 	if (item->key != item->defaultKey || item->modifiers != kDefaultModifiers) {
107 		BDeskWindow* window = static_cast<BDeskWindow*>(castToWindow);
108 		if (window != NULL) {
109 			window->RemoveShortcut(item->key, item->modifiers);
110 			item->key = item->defaultKey;
111 			item->modifiers = kDefaultModifiers;
112 			AddOneShortcut(item->model, item->key, item->modifiers, window);
113 		}
114 	}
115 
116 	return 0;
117 }
118 
119 
120 static struct AddonShortcut*
121 FindElement(struct AddonShortcut* item, void* castToOther)
122 {
123 	Model* other = static_cast<Model*>(castToOther);
124 	if (*item->model->EntryRef() == *other->EntryRef())
125 		return item;
126 
127 	return 0;
128 }
129 
130 
131 static void
132 LoadAddOnDir(BDirectory directory, BDeskWindow* window,
133 	LockingList<AddonShortcut>* list)
134 {
135 	BEntry entry;
136 	while (directory.GetNextEntry(&entry) == B_OK) {
137 		Model* model = new Model(&entry);
138 		if (model->InitCheck() == B_OK && model->IsSymLink()) {
139 			// resolve symlinks
140 			Model* resolved = new Model(model->EntryRef(), true, true);
141 			if (resolved->InitCheck() == B_OK)
142 				model->SetLinkTo(resolved);
143 			else
144 				delete resolved;
145 		}
146 		if (model->InitCheck() != B_OK
147 			|| !model->ResolveIfLink()->IsExecutable()) {
148 			delete model;
149 			continue;
150 		}
151 
152 		char* name = strdup(model->Name());
153 		if (!list->EachElement(MatchOne, name)) {
154 			struct AddonShortcut* item = new struct AddonShortcut;
155 			item->model = model;
156 
157 			BResources resources(model->ResolveIfLink()->EntryRef());
158 			size_t size;
159 			char* shortcut = (char*)resources.LoadResource(B_STRING_TYPE,
160 				kDefaultShortcut, &size);
161 			if (shortcut == NULL || strlen(shortcut) > 1)
162 				item->key = '\0';
163 			else
164 				item->key = shortcut[0];
165 			AddOneShortcut(model, item->key, kDefaultModifiers, window);
166 			item->defaultKey = item->key;
167 			item->modifiers = kDefaultModifiers;
168 			list->AddItem(item);
169 		}
170 		free(name);
171 	}
172 
173 	node_ref nodeRef;
174 	directory.GetNodeRef(&nodeRef);
175 
176 	TTracker::WatchNode(&nodeRef, B_WATCH_DIRECTORY, window);
177 }
178 
179 
180 // #pragma mark - BDeskWindow
181 
182 
183 #undef B_TRANSLATION_CONTEXT
184 #define B_TRANSLATION_CONTEXT "DeskWindow"
185 
186 
187 BDeskWindow::BDeskWindow(LockingList<BWindow>* windowList)
188 	:
189 	BContainerWindow(windowList, 0, kPrivateDesktopWindowLook,
190 		kPrivateDesktopWindowFeel, B_NOT_MOVABLE | B_WILL_ACCEPT_FIRST_CLICK
191 			| B_NOT_ZOOMABLE | B_NOT_CLOSABLE | B_NOT_MINIMIZABLE
192 			| B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS, B_ALL_WORKSPACES),
193 	fDeskShelf(NULL),
194 	fTrashContextMenu(NULL),
195 	fNodeRef(NULL),
196 	fShortcutsSettings(NULL)
197 {
198 	// Add icon view switching shortcuts. These are displayed in the context
199 	// menu, although they obviously don't work from those menu items.
200 	BMessage* message = new BMessage(kIconMode);
201 	AddShortcut('1', B_COMMAND_KEY, message, PoseView());
202 
203 	message = new BMessage(kMiniIconMode);
204 	AddShortcut('2', B_COMMAND_KEY, message, PoseView());
205 
206 	message = new BMessage(kIconMode);
207 	message->AddInt32("scale", 1);
208 	AddShortcut('+', B_COMMAND_KEY, message, PoseView());
209 
210 	message = new BMessage(kIconMode);
211 	message->AddInt32("scale", 0);
212 	AddShortcut('-', B_COMMAND_KEY, message, PoseView());
213 }
214 
215 
216 BDeskWindow::~BDeskWindow()
217 {
218 	SaveDesktopPoseLocations();
219 		// explicit call to SavePoseLocations so that extended pose info
220 		// gets committed properly
221 	PoseView()->DisableSaveLocation();
222 		// prevent double-saving, this would slow down quitting
223 	PoseView()->StopSettingsWatch();
224 	stop_watching(this);
225 }
226 
227 
228 void
229 BDeskWindow::Init(const BMessage*)
230 {
231 	// Set the size of the screen before calling the container window's
232 	// Init() because it will add volume poses to this window and
233 	// they will be clipped otherwise
234 
235 	BScreen screen(this);
236 	fOldFrame = screen.Frame();
237 
238 	PoseView()->SetShowHideSelection(false);
239 	ResizeTo(fOldFrame.Width(), fOldFrame.Height());
240 
241 	entry_ref ref;
242 	BPath path;
243 	if (!BootedInSafeMode() && FSFindTrackerSettingsDir(&path) == B_OK) {
244 		path.Append(kShelfPath);
245 		close(open(path.Path(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR
246 			| S_IRGRP | S_IROTH));
247 		if (get_ref_for_path(path.Path(), &ref) == B_OK)
248 			fDeskShelf = new BShelf(&ref, fPoseView);
249 
250 		if (fDeskShelf != NULL)
251 			fDeskShelf->SetDisplaysZombies(true);
252 	}
253 	InitKeyIndices();
254 	InitAddonsList(false);
255 	ApplyShortcutPreferences(false);
256 
257 	_inherited::Init();
258 }
259 
260 
261 void
262 BDeskWindow::InitAddonsList(bool update)
263 {
264 	AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
265 	if (lock.IsLocked()) {
266 		if (update) {
267 			for (int i = fAddonsList->CountItems() - 1; i >= 0; i--) {
268 				AddonShortcut* item = fAddonsList->ItemAt(i);
269 				RemoveShortcut(item->key, B_OPTION_KEY | B_COMMAND_KEY);
270 			}
271 			fAddonsList->MakeEmpty(true);
272 		}
273 
274 		BStringList addOnPaths;
275 		BPathFinder::FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY, "Tracker/",
276 			addOnPaths);
277 		for (int32 i = 0; i < addOnPaths.CountStrings(); i++) {
278 			LoadAddOnDir(BDirectory(addOnPaths.StringAt(i)), this,
279 				fAddonsList);
280 		}
281 	}
282 }
283 
284 
285 void
286 BDeskWindow::ApplyShortcutPreferences(bool update)
287 {
288 	AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
289 	if (lock.IsLocked()) {
290 		if (!update) {
291 			BPath path;
292 			if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
293 				BPathMonitor::StartWatching(path.Path(),
294 					B_WATCH_STAT | B_WATCH_FILES_ONLY, this);
295 				path.Append(kShortcutsSettings);
296 				fShortcutsSettings = new char[strlen(path.Path()) + 1];
297 				strcpy(fShortcutsSettings, path.Path());
298 			}
299 		}
300 
301 		fAddonsList->EachElement(RevertToDefault, this);
302 
303 		BFile shortcutSettings(fShortcutsSettings, B_READ_ONLY);
304 		BMessage fileMsg;
305 		if (shortcutSettings.InitCheck() != B_OK
306 			|| fileMsg.Unflatten(&shortcutSettings) != B_OK) {
307 			fNodeRef = NULL;
308 			return;
309 		}
310 		shortcutSettings.GetNodeRef(fNodeRef);
311 
312 		int32 i = 0;
313 		BMessage message;
314 		while (fileMsg.FindMessage("spec", i++, &message) == B_OK) {
315 			int32 key;
316 			if (message.FindInt32("key", &key) == B_OK) {
317 				// only handle shortcuts referring add-ons
318 				BString command;
319 				if (message.FindString("command", &command) != B_OK)
320 					continue;
321 
322 				bool isInAddons = false;
323 
324 				BStringList addOnPaths;
325 				BPathFinder::FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY,
326 					"Tracker/", addOnPaths);
327 				for (int32 i = 0; i < addOnPaths.CountStrings(); i++) {
328 					if (command.FindFirst(addOnPaths.StringAt(i)) == 0) {
329 						isInAddons = true;
330 						break;
331 					}
332 				}
333 
334 				if (!isInAddons)
335 					continue;
336 
337 				BEntry entry(command);
338 				if (entry.InitCheck() != B_OK)
339 					continue;
340 
341 				const char* shortcut = GetKeyName(key);
342 				if (strlen(shortcut) != 1)
343 					continue;
344 
345 				uint32 modifiers = B_COMMAND_KEY;
346 					// it's required by interface kit to at least
347 					// have B_COMMAND_KEY
348 				int32 value;
349 				if (message.FindInt32("mcidx", 0, &value) == B_OK)
350 					modifiers |= (value != 0 ? B_SHIFT_KEY : 0);
351 
352 				if (message.FindInt32("mcidx", 1, &value) == B_OK)
353 					modifiers |= (value != 0 ? B_CONTROL_KEY : 0);
354 
355 				if (message.FindInt32("mcidx", 3, &value) == B_OK)
356 					modifiers |= (value != 0 ? B_OPTION_KEY : 0);
357 
358 				Model model(&entry);
359 				AddonShortcut* item = fAddonsList->EachElement(FindElement,
360 					&model);
361 				if (item != NULL) {
362 					if (item->key != '\0')
363 						RemoveShortcut(item->key, item->modifiers);
364 
365 					item->key = shortcut[0];
366 					item->modifiers = modifiers;
367 					AddOneShortcut(&model, item->key, item->modifiers, this);
368 				}
369 			}
370 		}
371 	}
372 }
373 
374 
375 void
376 BDeskWindow::Quit()
377 {
378 	if (fNavigationItem != NULL) {
379 		// this duplicates BContainerWindow::Quit because
380 		// fNavigationItem can be part of fTrashContextMenu
381 		// and would get deleted with it
382 		BMenu* menu = fNavigationItem->Menu();
383 		if (menu != NULL)
384 			menu->RemoveItem(fNavigationItem);
385 
386 		delete fNavigationItem;
387 		fNavigationItem = 0;
388 	}
389 
390 	fAddonsList->MakeEmpty(true);
391 	delete fAddonsList;
392 
393 	delete fTrashContextMenu;
394 	fTrashContextMenu = NULL;
395 
396 	delete fDeskShelf;
397 	_inherited::Quit();
398 }
399 
400 
401 BPoseView*
402 BDeskWindow::NewPoseView(Model* model, BRect rect, uint32 viewMode)
403 {
404 	return new DesktopPoseView(model, rect, viewMode);
405 }
406 
407 
408 void
409 BDeskWindow::CreatePoseView(Model* model)
410 {
411 	fPoseView = NewPoseView(model, Bounds(), kIconMode);
412 	fPoseView->SetIconMapping(false);
413 	fPoseView->SetEnsurePosesVisible(true);
414 	fPoseView->SetAutoScroll(false);
415 
416 	BScreen screen(this);
417 	rgb_color desktopColor = screen.DesktopColor();
418 	if (desktopColor.alpha != 255) {
419 		desktopColor.alpha = 255;
420 #if B_BEOS_VERSION > B_BEOS_VERSION_5
421 		// This call seems to have the power to cause R5 to freeze!
422 		// Please report if commenting this out helped or helped not
423 		// on your system
424 		screen.SetDesktopColor(desktopColor);
425 #endif
426 	}
427 
428 	fPoseView->SetViewColor(desktopColor);
429 	fPoseView->SetLowColor(desktopColor);
430 
431 	AddChild(fPoseView);
432 
433 	PoseView()->StartSettingsWatch();
434 }
435 
436 
437 void
438 BDeskWindow::AddWindowContextMenus(BMenu* menu)
439 {
440 	BRoster roster;
441 	if (!roster.IsRunning(kDeskbarSignature)) {
442 		menu->AddItem(new BMenuItem(B_TRANSLATE("Restart Deskbar"),
443 			new BMessage(kRestartDeskbar)));
444 		menu->AddSeparatorItem();
445 	}
446 
447 	TemplatesMenu* tempateMenu = new TemplatesMenu(PoseView(),
448 		B_TRANSLATE("New"));
449 
450 	menu->AddItem(tempateMenu);
451 	tempateMenu->SetTargetForItems(PoseView());
452 	tempateMenu->SetFont(be_plain_font);
453 
454 	menu->AddSeparatorItem();
455 
456 	BMenu* iconSizeMenu = new BMenu(B_TRANSLATE("Icon view"));
457 
458 	BMessage* message = new BMessage(kIconMode);
459 	message->AddInt32("size", 32);
460 	BMenuItem* item = new BMenuItem(B_TRANSLATE("32 x 32"), message);
461 	item->SetMarked(PoseView()->IconSizeInt() == 32);
462 	item->SetTarget(PoseView());
463 	iconSizeMenu->AddItem(item);
464 
465 	message = new BMessage(kIconMode);
466 	message->AddInt32("size", 40);
467 	item = new BMenuItem(B_TRANSLATE("40 x 40"), message);
468 	item->SetMarked(PoseView()->IconSizeInt() == 40);
469 	item->SetTarget(PoseView());
470 	iconSizeMenu->AddItem(item);
471 
472 	message = new BMessage(kIconMode);
473 	message->AddInt32("size", 48);
474 	item = new BMenuItem(B_TRANSLATE("48 x 48"), message);
475 	item->SetMarked(PoseView()->IconSizeInt() == 48);
476 	item->SetTarget(PoseView());
477 	iconSizeMenu->AddItem(item);
478 
479 	message = new BMessage(kIconMode);
480 	message->AddInt32("size", 64);
481 	item = new BMenuItem(B_TRANSLATE("64 x 64"), message);
482 	item->SetMarked(PoseView()->IconSizeInt() == 64);
483 	item->SetTarget(PoseView());
484 	iconSizeMenu->AddItem(item);
485 
486 	message = new BMessage(kIconMode);
487 	message->AddInt32("size", 96);
488 	item = new BMenuItem(B_TRANSLATE("96 x 96"), message);
489 	item->SetMarked(PoseView()->IconSizeInt() == 96);
490 	item->SetTarget(PoseView());
491 	iconSizeMenu->AddItem(item);
492 
493 	message = new BMessage(kIconMode);
494 	message->AddInt32("size", 128);
495 	item = new BMenuItem(B_TRANSLATE("128 x 128"), message);
496 	item->SetMarked(PoseView()->IconSizeInt() == 128);
497 	item->SetTarget(PoseView());
498 	iconSizeMenu->AddItem(item);
499 
500 	iconSizeMenu->AddSeparatorItem();
501 
502 	message = new BMessage(kIconMode);
503 	message->AddInt32("scale", 0);
504 	item = new BMenuItem(B_TRANSLATE("Decrease size"), message, '-');
505 	item->SetTarget(PoseView());
506 	iconSizeMenu->AddItem(item);
507 
508 	message = new BMessage(kIconMode);
509 	message->AddInt32("scale", 1);
510 	item = new BMenuItem(B_TRANSLATE("Increase size"), message, '+');
511 	item->SetTarget(PoseView());
512 	iconSizeMenu->AddItem(item);
513 
514 	// A sub menu where the super item can be invoked.
515 	menu->AddItem(iconSizeMenu);
516 	iconSizeMenu->Superitem()->SetShortcut('1', B_COMMAND_KEY);
517 	iconSizeMenu->Superitem()->SetMessage(new BMessage(kIconMode));
518 	iconSizeMenu->Superitem()->SetTarget(PoseView());
519 	iconSizeMenu->Superitem()->SetMarked(PoseView()->ViewMode() == kIconMode);
520 
521 	item = new BMenuItem(B_TRANSLATE("Mini icon view"),
522 		new BMessage(kMiniIconMode), '2');
523 	item->SetMarked(PoseView()->ViewMode() == kMiniIconMode);
524 	menu->AddItem(item);
525 
526 	menu->AddSeparatorItem();
527 
528 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
529 	BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"),
530 		new BMessage(B_PASTE), 'V'));
531 	menu->AddItem(pasteItem);
532 	menu->AddSeparatorItem();
533 #endif
534 	menu->AddItem(new BMenuItem(B_TRANSLATE("Clean up"),
535 		new BMessage(kCleanup), 'K'));
536 	menu->AddItem(new BMenuItem(B_TRANSLATE("Select" B_UTF8_ELLIPSIS),
537 		new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY));
538 	menu->AddItem(new BMenuItem(B_TRANSLATE("Select all"),
539 		new BMessage(B_SELECT_ALL), 'A'));
540 
541 	menu->AddSeparatorItem();
542 	menu->AddItem(new MountMenu(B_TRANSLATE("Mount")));
543 
544 	menu->AddSeparatorItem();
545 	menu->AddItem(new BMenu(B_TRANSLATE("Add-ons")));
546 
547 	// target items as needed
548 	menu->SetTargetForItems(PoseView());
549 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
550 	pasteItem->SetTarget(this);
551 #endif
552 }
553 
554 
555 void
556 BDeskWindow::WorkspaceActivated(int32 workspace, bool state)
557 {
558 	if (fBackgroundImage)
559 		fBackgroundImage->WorkspaceActivated(PoseView(), workspace, state);
560 }
561 
562 
563 void
564 BDeskWindow::SaveDesktopPoseLocations()
565 {
566 	PoseView()->SavePoseLocations(&fOldFrame);
567 }
568 
569 
570 void
571 BDeskWindow::ScreenChanged(BRect frame, color_space space)
572 {
573 	bool frameChanged = (frame != fOldFrame);
574 
575 	SaveDesktopPoseLocations();
576 	fOldFrame = frame;
577 	ResizeTo(frame.Width(), frame.Height());
578 
579 	if (fBackgroundImage)
580 		fBackgroundImage->ScreenChanged(frame, space);
581 
582 	PoseView()->CheckPoseVisibility(frameChanged ? &frame : 0);
583 		// if frame changed, pass new frame so that icons can
584 		// get rearranged based on old pose info for the frame
585 }
586 
587 
588 void
589 BDeskWindow::UpdateDesktopBackgroundImages()
590 {
591 	WindowStateNodeOpener opener(this, false);
592 	fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage,
593 		opener.Node(), true, PoseView());
594 }
595 
596 
597 void
598 BDeskWindow::Show()
599 {
600 	if (fBackgroundImage)
601 		fBackgroundImage->Show(PoseView(), current_workspace());
602 
603 	PoseView()->CheckPoseVisibility();
604 
605 	_inherited::Show();
606 }
607 
608 
609 bool
610 BDeskWindow::ShouldAddScrollBars() const
611 {
612 	return false;
613 }
614 
615 
616 bool
617 BDeskWindow::ShouldAddMenus() const
618 {
619 	return false;
620 }
621 
622 
623 bool
624 BDeskWindow::ShouldAddContainerView() const
625 {
626 	return false;
627 }
628 
629 
630 void
631 BDeskWindow::MessageReceived(BMessage* message)
632 {
633 	if (message->WasDropped()) {
634 		const rgb_color* color;
635 		ssize_t size;
636 		// handle "roColour"-style color drops
637 		if (message->FindData("RGBColor", 'RGBC',
638 			(const void**)&color, &size) == B_OK) {
639 			BScreen(this).SetDesktopColor(*color);
640 			fPoseView->SetViewColor(*color);
641 			fPoseView->SetLowColor(*color);
642 			return;
643 		}
644 	}
645 
646 	switch (message->what) {
647 		case B_PATH_MONITOR:
648 		{
649 			const char* path = "";
650 			if (!(message->FindString("path", &path) == B_OK
651 					&& strcmp(path, fShortcutsSettings) == 0)) {
652 
653 				dev_t device;
654 				ino_t node;
655 				if (fNodeRef == NULL
656 					|| message->FindInt32("device", &device) != B_OK
657 					|| message->FindInt64("node", &node) != B_OK
658 					|| device != fNodeRef->device
659 					|| node != fNodeRef->node)
660 					break;
661 			}
662 			ApplyShortcutPreferences(true);
663 			break;
664 		}
665 		case B_NODE_MONITOR:
666 			PRINT(("will update addon shortcuts\n"));
667 			InitAddonsList(true);
668 			ApplyShortcutPreferences(true);
669 			break;
670 
671 		default:
672 			_inherited::MessageReceived(message);
673 			break;
674 	}
675 }
676