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