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.
36 #include "DeskWindow.h"
40 #include <FindDirectory.h>
42 #include <Messenger.h>
43 #include <NodeMonitor.h>
45 #include <PathFinder.h>
46 #include <PathMonitor.h>
47 #include <PopUpMenu.h>
48 #include <Resources.h>
51 #include <StringList.h>
53 #include <WindowPrivate.h>
58 #include "Attributes.h"
60 #include "BackgroundImage.h"
63 #include "IconMenuItem.h"
65 #include "MountMenu.h"
68 #include "TemplatesMenu.h"
71 const char* kShelfPath
= "tracker_shelf";
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
92 AddOneShortcut(Model
* model
, char key
, uint32 modifiers
, BDeskWindow
* window
)
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
);
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())
133 LoadAddOnDir(BDirectory directory
, BDeskWindow
* window
,
134 LockingList
<AddonShortcut
>* list
)
137 while (directory
.GetNextEntry(&entry
) == B_OK
) {
138 Model
* model
= new Model(&entry
);
139 if (model
->InitCheck() == B_OK
&& model
->IsSymLink()) {
141 Model
* resolved
= new Model(model
->EntryRef(), true, true);
142 if (resolved
->InitCheck() == B_OK
)
143 model
->SetLinkTo(resolved
);
147 if (model
->InitCheck() != B_OK
148 || !model
->ResolveIfLink()->IsExecutable()) {
153 char* name
= strdup(model
->Name());
154 if (!list
->EachElement(MatchOne
, name
)) {
155 struct AddonShortcut
* item
= new struct AddonShortcut
;
158 BResources
resources(model
->ResolveIfLink()->EntryRef());
160 char* shortcut
= (char*)resources
.LoadResource(B_STRING_TYPE
,
161 kDefaultShortcut
, &size
);
162 if (shortcut
== NULL
|| strlen(shortcut
) > 1)
165 item
->key
= shortcut
[0];
166 AddOneShortcut(model
, item
->key
, kDefaultModifiers
, window
);
167 item
->defaultKey
= item
->key
;
168 item
->modifiers
= kDefaultModifiers
;
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
,
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();
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());
243 InitAddonsList(false);
244 ApplyShortcutPreferences(false);
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);
264 BDeskWindow::InitAddonsList(bool update
)
266 AutoLock
<LockingList
<AddonShortcut
> > lock(fAddonsList
);
267 if (lock
.IsLocked()) {
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",
279 int32 count
= addOnPaths
.CountStrings();
280 for (int32 i
= 0; i
< count
; i
++) {
281 LoadAddOnDir(BDirectory(addOnPaths
.StringAt(i
)), this,
289 BDeskWindow::ApplyShortcutPreferences(bool update
)
291 AutoLock
<LockingList
<AddonShortcut
> > lock(fAddonsList
);
292 if (lock
.IsLocked()) {
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
);
308 if (shortcutSettings
.InitCheck() != B_OK
309 || fileMsg
.Unflatten(&shortcutSettings
) != B_OK
) {
313 shortcutSettings
.GetNodeRef(fNodeRef
);
317 while (fileMsg
.FindMessage("spec", i
++, &message
) == B_OK
) {
319 if (message
.FindInt32("key", &key
) == B_OK
) {
320 // only handle shortcuts referring add-ons
322 if (message
.FindString("command", &command
) != B_OK
)
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
))) {
340 BEntry
entry(command
);
341 if (entry
.InitCheck() != B_OK
)
344 const char* shortcut
= GetKeyName(key
);
345 if (strlen(shortcut
) != 1)
348 uint32 modifiers
= B_COMMAND_KEY
;
349 // it's required by interface kit to at least
350 // have B_COMMAND_KEY
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);
362 AddonShortcut
* item
= fAddonsList
->EachElement(FindElement
,
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);
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();
387 menu
->RemoveItem(fNavigationItem
);
389 delete fNavigationItem
;
393 fAddonsList
->MakeEmpty(true);
402 BDeskWindow::NewPoseView(Model
* model
, uint32 viewMode
)
404 return new DesktopPoseView(model
, viewMode
);
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
424 screen
.SetDesktopColor(desktopColor
);
428 fPoseView
->SetViewColor(desktopColor
);
429 fPoseView
->SetLowColor(desktopColor
);
431 fPoseView
->SetResizingMode(B_FOLLOW_ALL
);
432 fPoseView
->ResizeTo(Bounds().Size());
435 PoseView()->StartSettingsWatch();
440 BDeskWindow::AddWindowContextMenus(BMenu
* menu
)
442 TemplatesMenu
* tempateMenu
= new TemplatesMenu(PoseView(),
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
);
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();
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);
551 BDeskWindow::WorkspaceActivated(int32 workspace
, bool state
)
553 if (fBackgroundImage
)
554 fBackgroundImage
->WorkspaceActivated(PoseView(), workspace
, state
);
559 BDeskWindow::SaveDesktopPoseLocations()
561 PoseView()->SavePoseLocations(&fOldFrame
);
566 BDeskWindow::ScreenChanged(BRect frame
, color_space space
)
568 bool frameChanged
= (frame
!= fOldFrame
);
570 SaveDesktopPoseLocations();
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
584 BDeskWindow::UpdateDesktopBackgroundImages()
586 WindowStateNodeOpener
opener(this, false);
587 fBackgroundImage
= BackgroundImage::Refresh(fBackgroundImage
,
588 opener
.Node(), true, PoseView());
595 if (fBackgroundImage
)
596 fBackgroundImage
->Show(PoseView(), current_workspace());
598 PoseView()->CheckPoseVisibility();
605 BDeskWindow::ShouldAddScrollBars() const
612 BDeskWindow::ShouldAddMenus() const
619 BDeskWindow::ShouldAddContainerView() const
626 BDeskWindow::MessageReceived(BMessage
* message
)
628 if (message
->WasDropped()) {
629 const rgb_color
* color
;
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
640 BMessenger
messenger("application/x-vnd.Haiku-Backgrounds", -1,
642 if (initStatus
== B_OK
)
643 messenger
.SendMessage(message
);
649 switch (message
->what
) {
652 const char* path
= "";
653 if (!(message
->FindString("path", &path
) == B_OK
654 && strcmp(path
, fShortcutsSettings
) == 0)) {
659 || message
->FindInt32("device", &device
) != B_OK
660 || message
->FindInt64("node", &node
) != B_OK
661 || device
!= fNodeRef
->device
662 || node
!= fNodeRef
->node
)
665 ApplyShortcutPreferences(true);
669 PRINT(("will update addon shortcuts\n"));
670 InitAddonsList(true);
671 ApplyShortcutPreferences(true);
675 _inherited::MessageReceived(message
);