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