RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / kits / tracker / DeskWindow.cpp
blob9e357303cd91591a4802d5eb165cd93da8db0aac
1 /*
2 Open Tracker License
4 Terms and Conditions
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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:
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.
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.
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.
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.
36 #include "DeskWindow.h"
38 #include <Catalog.h>
39 #include <Debug.h>
40 #include <FindDirectory.h>
41 #include <Locale.h>
42 #include <Messenger.h>
43 #include <NodeMonitor.h>
44 #include <Path.h>
45 #include <PathFinder.h>
46 #include <PathMonitor.h>
47 #include <PopUpMenu.h>
48 #include <Resources.h>
49 #include <Screen.h>
50 #include <String.h>
51 #include <StringList.h>
52 #include <Volume.h>
53 #include <WindowPrivate.h>
55 #include <fcntl.h>
56 #include <unistd.h>
58 #include "Attributes.h"
59 #include "AutoLock.h"
60 #include "BackgroundImage.h"
61 #include "Commands.h"
62 #include "FSUtils.h"
63 #include "IconMenuItem.h"
64 #include "KeyInfos.h"
65 #include "MountMenu.h"
66 #include "PoseView.h"
67 #include "Tracker.h"
68 #include "TemplatesMenu.h"
71 const char* kShelfPath = "tracker_shelf";
72 // replicant support
74 const char* kShortcutsSettings = "shortcuts_settings";
75 const char* kDefaultShortcut = "BEOS:default_shortcut";
76 const uint32 kDefaultModifiers = B_OPTION_KEY | B_COMMAND_KEY;
79 static struct AddonShortcut*
80 MatchOne(struct AddonShortcut* item, void* castToName)
82 if (strcmp(item->model->Name(), (const char*)castToName) == 0) {
83 // found match, bail out
84 return item;
87 return 0;
91 static void
92 AddOneShortcut(Model* model, char key, uint32 modifiers, BDeskWindow* window)
94 if (key == '\0')
95 return;
97 BMessage* runAddon = new BMessage(kLoadAddOn);
98 runAddon->AddRef("refs", model->EntryRef());
99 window->AddShortcut(key, modifiers, runAddon);
104 static struct AddonShortcut*
105 RevertToDefault(struct AddonShortcut* item, void* castToWindow)
107 if (item->key != item->defaultKey || item->modifiers != kDefaultModifiers) {
108 BDeskWindow* window = static_cast<BDeskWindow*>(castToWindow);
109 if (window != NULL) {
110 window->RemoveShortcut(item->key, item->modifiers);
111 item->key = item->defaultKey;
112 item->modifiers = kDefaultModifiers;
113 AddOneShortcut(item->model, item->key, item->modifiers, window);
117 return 0;
121 static struct AddonShortcut*
122 FindElement(struct AddonShortcut* item, void* castToOther)
124 Model* other = static_cast<Model*>(castToOther);
125 if (*item->model->EntryRef() == *other->EntryRef())
126 return item;
128 return 0;
132 static void
133 LoadAddOnDir(BDirectory directory, BDeskWindow* window,
134 LockingList<AddonShortcut>* list)
136 BEntry entry;
137 while (directory.GetNextEntry(&entry) == B_OK) {
138 Model* model = new Model(&entry);
139 if (model->InitCheck() == B_OK && model->IsSymLink()) {
140 // resolve symlinks
141 Model* resolved = new Model(model->EntryRef(), true, true);
142 if (resolved->InitCheck() == B_OK)
143 model->SetLinkTo(resolved);
144 else
145 delete resolved;
147 if (model->InitCheck() != B_OK
148 || !model->ResolveIfLink()->IsExecutable()) {
149 delete model;
150 continue;
153 char* name = strdup(model->Name());
154 if (!list->EachElement(MatchOne, name)) {
155 struct AddonShortcut* item = new struct AddonShortcut;
156 item->model = model;
158 BResources resources(model->ResolveIfLink()->EntryRef());
159 size_t size;
160 char* shortcut = (char*)resources.LoadResource(B_STRING_TYPE,
161 kDefaultShortcut, &size);
162 if (shortcut == NULL || strlen(shortcut) > 1)
163 item->key = '\0';
164 else
165 item->key = shortcut[0];
166 AddOneShortcut(model, item->key, kDefaultModifiers, window);
167 item->defaultKey = item->key;
168 item->modifiers = kDefaultModifiers;
169 list->AddItem(item);
171 free(name);
174 node_ref nodeRef;
175 directory.GetNodeRef(&nodeRef);
177 TTracker::WatchNode(&nodeRef, B_WATCH_DIRECTORY, window);
181 // #pragma mark - BDeskWindow
184 #undef B_TRANSLATION_CONTEXT
185 #define B_TRANSLATION_CONTEXT "DeskWindow"
188 BDeskWindow::BDeskWindow(LockingList<BWindow>* windowList)
190 BContainerWindow(windowList, 0, kDesktopWindowLook,
191 kDesktopWindowFeel, B_NOT_MOVABLE | B_WILL_ACCEPT_FIRST_CLICK
192 | B_NOT_ZOOMABLE | B_NOT_CLOSABLE | B_NOT_MINIMIZABLE
193 | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS, B_ALL_WORKSPACES,
194 false, true),
195 fDeskShelf(NULL),
196 fNodeRef(NULL),
197 fShortcutsSettings(NULL)
199 // Add icon view switching shortcuts. These are displayed in the context
200 // menu, although they obviously don't work from those menu items.
201 BMessage* message = new BMessage(kIconMode);
202 AddShortcut('1', B_COMMAND_KEY, message, PoseView());
204 message = new BMessage(kMiniIconMode);
205 AddShortcut('2', B_COMMAND_KEY, message, PoseView());
207 message = new BMessage(kIconMode);
208 message->AddInt32("scale", 1);
209 AddShortcut('+', B_COMMAND_KEY, message, PoseView());
211 message = new BMessage(kIconMode);
212 message->AddInt32("scale", 0);
213 AddShortcut('-', B_COMMAND_KEY, message, PoseView());
217 BDeskWindow::~BDeskWindow()
219 SaveDesktopPoseLocations();
220 // explicit call to SavePoseLocations so that extended pose info
221 // gets committed properly
222 PoseView()->DisableSaveLocation();
223 // prevent double-saving, this would slow down quitting
224 PoseView()->StopSettingsWatch();
225 stop_watching(this);
229 void
230 BDeskWindow::Init(const BMessage*)
232 // Set the size of the screen before calling the container window's
233 // Init() because it will add volume poses to this window and
234 // they will be clipped otherwise
236 BScreen screen(this);
237 fOldFrame = screen.Frame();
239 PoseView()->SetShowHideSelection(false);
240 ResizeTo(fOldFrame.Width(), fOldFrame.Height());
242 InitKeyIndices();
243 InitAddonsList(false);
244 ApplyShortcutPreferences(false);
246 _inherited::Init();
248 entry_ref ref;
249 BPath path;
250 if (!BootedInSafeMode() && FSFindTrackerSettingsDir(&path) == B_OK) {
251 path.Append(kShelfPath);
252 close(open(path.Path(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR
253 | S_IRGRP | S_IROTH));
254 if (get_ref_for_path(path.Path(), &ref) == B_OK)
255 fDeskShelf = new BShelf(&ref, fPoseView);
257 if (fDeskShelf != NULL)
258 fDeskShelf->SetDisplaysZombies(true);
263 void
264 BDeskWindow::InitAddonsList(bool update)
266 AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
267 if (lock.IsLocked()) {
268 if (update) {
269 for (int i = fAddonsList->CountItems() - 1; i >= 0; i--) {
270 AddonShortcut* item = fAddonsList->ItemAt(i);
271 RemoveShortcut(item->key, B_OPTION_KEY | B_COMMAND_KEY);
273 fAddonsList->MakeEmpty(true);
276 BStringList addOnPaths;
277 BPathFinder::FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY, "Tracker",
278 addOnPaths);
279 int32 count = addOnPaths.CountStrings();
280 for (int32 i = 0; i < count; i++) {
281 LoadAddOnDir(BDirectory(addOnPaths.StringAt(i)), this,
282 fAddonsList);
288 void
289 BDeskWindow::ApplyShortcutPreferences(bool update)
291 AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
292 if (lock.IsLocked()) {
293 if (!update) {
294 BPath path;
295 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
296 BPathMonitor::StartWatching(path.Path(),
297 B_WATCH_STAT | B_WATCH_FILES_ONLY, this);
298 path.Append(kShortcutsSettings);
299 fShortcutsSettings = new char[strlen(path.Path()) + 1];
300 strcpy(fShortcutsSettings, path.Path());
304 fAddonsList->EachElement(RevertToDefault, this);
306 BFile shortcutSettings(fShortcutsSettings, B_READ_ONLY);
307 BMessage fileMsg;
308 if (shortcutSettings.InitCheck() != B_OK
309 || fileMsg.Unflatten(&shortcutSettings) != B_OK) {
310 fNodeRef = NULL;
311 return;
313 shortcutSettings.GetNodeRef(fNodeRef);
315 int32 i = 0;
316 BMessage message;
317 while (fileMsg.FindMessage("spec", i++, &message) == B_OK) {
318 int32 key;
319 if (message.FindInt32("key", &key) == B_OK) {
320 // only handle shortcuts referring add-ons
321 BString command;
322 if (message.FindString("command", &command) != B_OK)
323 continue;
325 bool isInAddons = false;
327 BStringList addOnPaths;
328 BPathFinder::FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY,
329 "Tracker/", addOnPaths);
330 for (int32 i = 0; i < addOnPaths.CountStrings(); i++) {
331 if (command.StartsWith(addOnPaths.StringAt(i))) {
332 isInAddons = true;
333 break;
337 if (!isInAddons)
338 continue;
340 BEntry entry(command);
341 if (entry.InitCheck() != B_OK)
342 continue;
344 const char* shortcut = GetKeyName(key);
345 if (strlen(shortcut) != 1)
346 continue;
348 uint32 modifiers = B_COMMAND_KEY;
349 // it's required by interface kit to at least
350 // have B_COMMAND_KEY
351 int32 value;
352 if (message.FindInt32("mcidx", 0, &value) == B_OK)
353 modifiers |= (value != 0 ? B_SHIFT_KEY : 0);
355 if (message.FindInt32("mcidx", 1, &value) == B_OK)
356 modifiers |= (value != 0 ? B_CONTROL_KEY : 0);
358 if (message.FindInt32("mcidx", 3, &value) == B_OK)
359 modifiers |= (value != 0 ? B_OPTION_KEY : 0);
361 Model model(&entry);
362 AddonShortcut* item = fAddonsList->EachElement(FindElement,
363 &model);
364 if (item != NULL) {
365 if (item->key != '\0')
366 RemoveShortcut(item->key, item->modifiers);
368 item->key = shortcut[0];
369 item->modifiers = modifiers;
370 AddOneShortcut(&model, item->key, item->modifiers, this);
378 void
379 BDeskWindow::Quit()
381 if (fNavigationItem != NULL) {
382 // this duplicates BContainerWindow::Quit because
383 // fNavigationItem can be part of fTrashContextMenu
384 // and would get deleted with it
385 BMenu* menu = fNavigationItem->Menu();
386 if (menu != NULL)
387 menu->RemoveItem(fNavigationItem);
389 delete fNavigationItem;
390 fNavigationItem = 0;
393 fAddonsList->MakeEmpty(true);
394 delete fAddonsList;
396 delete fDeskShelf;
397 _inherited::Quit();
401 BPoseView*
402 BDeskWindow::NewPoseView(Model* model, uint32 viewMode)
404 return new DesktopPoseView(model, viewMode);
408 void
409 BDeskWindow::CreatePoseView(Model* model)
411 fPoseView = NewPoseView(model, kIconMode);
412 fPoseView->SetIconMapping(false);
413 fPoseView->SetEnsurePosesVisible(true);
414 fPoseView->SetAutoScroll(false);
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
428 fPoseView->SetViewColor(desktopColor);
429 fPoseView->SetLowColor(desktopColor);
431 fPoseView->SetResizingMode(B_FOLLOW_ALL);
432 fPoseView->ResizeTo(Bounds().Size());
433 AddChild(fPoseView);
435 PoseView()->StartSettingsWatch();
439 void
440 BDeskWindow::AddWindowContextMenus(BMenu* menu)
442 TemplatesMenu* tempateMenu = new TemplatesMenu(PoseView(),
443 B_TRANSLATE("New"));
445 menu->AddItem(tempateMenu);
446 tempateMenu->SetTargetForItems(PoseView());
447 tempateMenu->SetFont(be_plain_font);
449 menu->AddSeparatorItem();
451 BMenu* iconSizeMenu = new BMenu(B_TRANSLATE("Icon view"));
453 BMessage* message = new BMessage(kIconMode);
454 message->AddInt32("size", 32);
455 BMenuItem* item = new BMenuItem(B_TRANSLATE("32 x 32"), message);
456 item->SetMarked(PoseView()->IconSizeInt() == 32);
457 item->SetTarget(PoseView());
458 iconSizeMenu->AddItem(item);
460 message = new BMessage(kIconMode);
461 message->AddInt32("size", 40);
462 item = new BMenuItem(B_TRANSLATE("40 x 40"), message);
463 item->SetMarked(PoseView()->IconSizeInt() == 40);
464 item->SetTarget(PoseView());
465 iconSizeMenu->AddItem(item);
467 message = new BMessage(kIconMode);
468 message->AddInt32("size", 48);
469 item = new BMenuItem(B_TRANSLATE("48 x 48"), message);
470 item->SetMarked(PoseView()->IconSizeInt() == 48);
471 item->SetTarget(PoseView());
472 iconSizeMenu->AddItem(item);
474 message = new BMessage(kIconMode);
475 message->AddInt32("size", 64);
476 item = new BMenuItem(B_TRANSLATE("64 x 64"), message);
477 item->SetMarked(PoseView()->IconSizeInt() == 64);
478 item->SetTarget(PoseView());
479 iconSizeMenu->AddItem(item);
481 message = new BMessage(kIconMode);
482 message->AddInt32("size", 96);
483 item = new BMenuItem(B_TRANSLATE("96 x 96"), message);
484 item->SetMarked(PoseView()->IconSizeInt() == 96);
485 item->SetTarget(PoseView());
486 iconSizeMenu->AddItem(item);
488 message = new BMessage(kIconMode);
489 message->AddInt32("size", 128);
490 item = new BMenuItem(B_TRANSLATE("128 x 128"), message);
491 item->SetMarked(PoseView()->IconSizeInt() == 128);
492 item->SetTarget(PoseView());
493 iconSizeMenu->AddItem(item);
495 iconSizeMenu->AddSeparatorItem();
497 message = new BMessage(kIconMode);
498 message->AddInt32("scale", 0);
499 item = new BMenuItem(B_TRANSLATE("Decrease size"), message, '-');
500 item->SetTarget(PoseView());
501 iconSizeMenu->AddItem(item);
503 message = new BMessage(kIconMode);
504 message->AddInt32("scale", 1);
505 item = new BMenuItem(B_TRANSLATE("Increase size"), message, '+');
506 item->SetTarget(PoseView());
507 iconSizeMenu->AddItem(item);
509 // A sub menu where the super item can be invoked.
510 menu->AddItem(iconSizeMenu);
511 iconSizeMenu->Superitem()->SetShortcut('1', B_COMMAND_KEY);
512 iconSizeMenu->Superitem()->SetMessage(new BMessage(kIconMode));
513 iconSizeMenu->Superitem()->SetTarget(PoseView());
514 iconSizeMenu->Superitem()->SetMarked(PoseView()->ViewMode() == kIconMode);
516 item = new BMenuItem(B_TRANSLATE("Mini icon view"),
517 new BMessage(kMiniIconMode), '2');
518 item->SetMarked(PoseView()->ViewMode() == kMiniIconMode);
519 menu->AddItem(item);
521 menu->AddSeparatorItem();
523 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
524 BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"),
525 new BMessage(B_PASTE), 'V'));
526 menu->AddItem(pasteItem);
527 menu->AddSeparatorItem();
528 #endif
529 menu->AddItem(new BMenuItem(B_TRANSLATE("Clean up"),
530 new BMessage(kCleanup), 'K'));
531 menu->AddItem(new BMenuItem(B_TRANSLATE("Select" B_UTF8_ELLIPSIS),
532 new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY));
533 menu->AddItem(new BMenuItem(B_TRANSLATE("Select all"),
534 new BMessage(B_SELECT_ALL), 'A'));
536 menu->AddSeparatorItem();
537 menu->AddItem(new MountMenu(B_TRANSLATE("Mount")));
539 menu->AddSeparatorItem();
540 menu->AddItem(new BMenu(B_TRANSLATE("Add-ons")));
542 // target items as needed
543 menu->SetTargetForItems(PoseView());
544 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
545 pasteItem->SetTarget(this);
546 #endif
550 void
551 BDeskWindow::WorkspaceActivated(int32 workspace, bool state)
553 if (fBackgroundImage)
554 fBackgroundImage->WorkspaceActivated(PoseView(), workspace, state);
558 void
559 BDeskWindow::SaveDesktopPoseLocations()
561 PoseView()->SavePoseLocations(&fOldFrame);
565 void
566 BDeskWindow::ScreenChanged(BRect frame, color_space space)
568 bool frameChanged = (frame != fOldFrame);
570 SaveDesktopPoseLocations();
571 fOldFrame = frame;
572 ResizeTo(frame.Width(), frame.Height());
574 if (fBackgroundImage)
575 fBackgroundImage->ScreenChanged(frame, space);
577 PoseView()->CheckPoseVisibility(frameChanged ? &frame : 0);
578 // if frame changed, pass new frame so that icons can
579 // get rearranged based on old pose info for the frame
583 void
584 BDeskWindow::UpdateDesktopBackgroundImages()
586 WindowStateNodeOpener opener(this, false);
587 fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage,
588 opener.Node(), true, PoseView());
592 void
593 BDeskWindow::Show()
595 if (fBackgroundImage)
596 fBackgroundImage->Show(PoseView(), current_workspace());
598 PoseView()->CheckPoseVisibility();
600 _inherited::Show();
604 bool
605 BDeskWindow::ShouldAddScrollBars() const
607 return false;
611 bool
612 BDeskWindow::ShouldAddMenus() const
614 return false;
618 bool
619 BDeskWindow::ShouldAddContainerView() const
621 return false;
625 void
626 BDeskWindow::MessageReceived(BMessage* message)
628 if (message->WasDropped()) {
629 const rgb_color* color;
630 ssize_t size;
631 // handle "roColour"-style color drops
632 if (message->FindData("RGBColor", 'RGBC',
633 (const void**)&color, &size) == B_OK) {
634 BScreen(this).SetDesktopColor(*color);
635 fPoseView->SetViewColor(*color);
636 fPoseView->SetLowColor(*color);
638 // Notify the backgrounds app that the background changed
639 status_t initStatus;
640 BMessenger messenger("application/x-vnd.Haiku-Backgrounds", -1,
641 &initStatus);
642 if (initStatus == B_OK)
643 messenger.SendMessage(message);
645 return;
649 switch (message->what) {
650 case B_PATH_MONITOR:
652 const char* path = "";
653 if (!(message->FindString("path", &path) == B_OK
654 && strcmp(path, fShortcutsSettings) == 0)) {
656 dev_t device;
657 ino_t node;
658 if (fNodeRef == NULL
659 || message->FindInt32("device", &device) != B_OK
660 || message->FindInt64("node", &node) != B_OK
661 || device != fNodeRef->device
662 || node != fNodeRef->node)
663 break;
665 ApplyShortcutPreferences(true);
666 break;
668 case B_NODE_MONITOR:
669 PRINT(("will update addon shortcuts\n"));
670 InitAddonsList(true);
671 ApplyShortcutPreferences(true);
672 break;
674 default:
675 _inherited::MessageReceived(message);
676 break;