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, 88 bool /*primary*/, void* context) 89 { 90 if (!shortcut) 91 // no shortcut, bail 92 return false; 93 94 AddOneShortcutParams* params = (AddOneShortcutParams*)context; 95 BMessage* runAddon = new BMessage(kLoadAddOn); 96 runAddon->AddRef("refs", model->EntryRef()); 97 98 params->window->AddShortcut(shortcut, B_OPTION_KEY | B_COMMAND_KEY, 99 runAddon); 100 params->currentAddonShortcuts->insert(shortcut); 101 PRINT(("adding new shortcut %c\n", (char)shortcut)); 102 103 return false; 104 } 105 106 107 // #pragma mark - 108 109 #undef B_TRANSLATION_CONTEXT 110 #define B_TRANSLATION_CONTEXT "DeskWindow" 111 112 BDeskWindow::BDeskWindow(LockingList<BWindow>* windowList) 113 : 114 BContainerWindow(windowList, 0, kPrivateDesktopWindowLook, 115 kPrivateDesktopWindowFeel, B_NOT_MOVABLE | B_WILL_ACCEPT_FIRST_CLICK 116 | B_NOT_ZOOMABLE | B_NOT_CLOSABLE | B_NOT_MINIMIZABLE 117 | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS, B_ALL_WORKSPACES), 118 fDeskShelf(0), 119 fTrashContextMenu(0), 120 fShouldUpdateAddonShortcuts(true) 121 { 122 // Add icon view switching shortcuts. These are displayed in the context 123 // menu, although they obviously don't work from those menu items. 124 BMessage* message = new BMessage(kIconMode); 125 AddShortcut('1', B_COMMAND_KEY, message, PoseView()); 126 127 message = new BMessage(kMiniIconMode); 128 AddShortcut('2', B_COMMAND_KEY, message, PoseView()); 129 130 message = new BMessage(kIconMode); 131 message->AddInt32("scale", 1); 132 AddShortcut('+', B_COMMAND_KEY, message, PoseView()); 133 134 message = new BMessage(kIconMode); 135 message->AddInt32("scale", 0); 136 AddShortcut('-', B_COMMAND_KEY, message, PoseView()); 137 } 138 139 140 BDeskWindow::~BDeskWindow() 141 { 142 SaveDesktopPoseLocations(); 143 // explicit call to SavePoseLocations so that extended pose info 144 // gets committed properly 145 PoseView()->DisableSaveLocation(); 146 // prevent double-saving, this would slow down quitting 147 PoseView()->StopSettingsWatch(); 148 stop_watching(this); 149 } 150 151 152 void 153 BDeskWindow::Init(const BMessage*) 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_ADDONS_DIRECTORY, this); 179 WatchAddOnDir(B_COMMON_ADDONS_DIRECTORY, this); 180 WatchAddOnDir(B_SYSTEM_ADDONS_DIRECTORY, this); 181 182 _inherited::Init(); 183 } 184 185 186 void 187 BDeskWindow::MenusBeginning() 188 { 189 _inherited::MenusBeginning(); 190 191 if (fShouldUpdateAddonShortcuts) { 192 PRINT(("updating addon shortcuts\n")); 193 fShouldUpdateAddonShortcuts = false; 194 195 // remove all current addon shortcuts 196 for (std::set<uint32>::iterator it= fCurrentAddonShortcuts.begin(); 197 it != fCurrentAddonShortcuts.end(); it++) { 198 PRINT(("removing shortcut %c\n", (int)*it)); 199 RemoveShortcut(*it, B_OPTION_KEY | B_COMMAND_KEY); 200 } 201 202 fCurrentAddonShortcuts.clear(); 203 204 AddOneShortcutParams params; 205 params.window = this; 206 params.currentAddonShortcuts = &fCurrentAddonShortcuts; 207 208 BObjectList<BString> mimeTypes(10, true); 209 BuildMimeTypeList(mimeTypes); 210 211 EachAddon(&AddOneShortcut, ¶ms, mimeTypes); 212 } 213 } 214 215 216 void 217 BDeskWindow::Quit() 218 { 219 if (fNavigationItem) { 220 // this duplicates BContainerWindow::Quit because 221 // fNavigationItem can be part of fTrashContextMenu 222 // and would get deleted with it 223 BMenu* menu = fNavigationItem->Menu(); 224 if (menu) 225 menu->RemoveItem(fNavigationItem); 226 delete fNavigationItem; 227 fNavigationItem = 0; 228 } 229 230 delete fTrashContextMenu; 231 fTrashContextMenu = NULL; 232 233 delete fDeskShelf; 234 _inherited::Quit(); 235 } 236 237 238 BPoseView* 239 BDeskWindow::NewPoseView(Model* model, BRect rect, uint32 viewMode) 240 { 241 return new DesktopPoseView(model, rect, viewMode); 242 } 243 244 245 void 246 BDeskWindow::CreatePoseView(Model* model) 247 { 248 fPoseView = NewPoseView(model, Bounds(), kIconMode); 249 fPoseView->SetIconMapping(false); 250 fPoseView->SetEnsurePosesVisible(true); 251 fPoseView->SetAutoScroll(false); 252 253 BScreen screen(this); 254 rgb_color desktopColor = screen.DesktopColor(); 255 if (desktopColor.alpha != 255) { 256 desktopColor.alpha = 255; 257 #if B_BEOS_VERSION > B_BEOS_VERSION_5 258 // This call seems to have the power to cause R5 to freeze! 259 // Please report if commenting this out helped or helped not 260 // on your system 261 screen.SetDesktopColor(desktopColor); 262 #endif 263 } 264 265 fPoseView->SetViewColor(desktopColor); 266 fPoseView->SetLowColor(desktopColor); 267 268 AddChild(fPoseView); 269 270 PoseView()->StartSettingsWatch(); 271 } 272 273 274 void 275 BDeskWindow::AddWindowContextMenus(BMenu* menu) 276 { 277 TemplatesMenu* tempateMenu = new TemplatesMenu(PoseView(), 278 B_TRANSLATE("New")); 279 280 menu->AddItem(tempateMenu); 281 tempateMenu->SetTargetForItems(PoseView()); 282 tempateMenu->SetFont(be_plain_font); 283 284 menu->AddSeparatorItem(); 285 286 BMenu* iconSizeMenu = new BMenu(B_TRANSLATE("Icon view")); 287 288 BMessage* message = new BMessage(kIconMode); 289 message->AddInt32("size", 32); 290 BMenuItem* item = new BMenuItem(B_TRANSLATE("32 x 32"), message); 291 item->SetMarked(PoseView()->IconSizeInt() == 32); 292 item->SetTarget(PoseView()); 293 iconSizeMenu->AddItem(item); 294 295 message = new BMessage(kIconMode); 296 message->AddInt32("size", 40); 297 item = new BMenuItem(B_TRANSLATE("40 x 40"), message); 298 item->SetMarked(PoseView()->IconSizeInt() == 40); 299 item->SetTarget(PoseView()); 300 iconSizeMenu->AddItem(item); 301 302 message = new BMessage(kIconMode); 303 message->AddInt32("size", 48); 304 item = new BMenuItem(B_TRANSLATE("48 x 48"), message); 305 item->SetMarked(PoseView()->IconSizeInt() == 48); 306 item->SetTarget(PoseView()); 307 iconSizeMenu->AddItem(item); 308 309 message = new BMessage(kIconMode); 310 message->AddInt32("size", 64); 311 item = new BMenuItem(B_TRANSLATE("64 x 64"), message); 312 item->SetMarked(PoseView()->IconSizeInt() == 64); 313 item->SetTarget(PoseView()); 314 iconSizeMenu->AddItem(item); 315 316 message = new BMessage(kIconMode); 317 message->AddInt32("size", 96); 318 item = new BMenuItem(B_TRANSLATE("96 x 96"), message); 319 item->SetMarked(PoseView()->IconSizeInt() == 96); 320 item->SetTarget(PoseView()); 321 iconSizeMenu->AddItem(item); 322 323 message = new BMessage(kIconMode); 324 message->AddInt32("size", 128); 325 item = new BMenuItem(B_TRANSLATE("128 x 128"), message); 326 item->SetMarked(PoseView()->IconSizeInt() == 128); 327 item->SetTarget(PoseView()); 328 iconSizeMenu->AddItem(item); 329 330 iconSizeMenu->AddSeparatorItem(); 331 332 message = new BMessage(kIconMode); 333 message->AddInt32("scale", 0); 334 item = new BMenuItem(B_TRANSLATE("Decrease size"), message, '-'); 335 item->SetTarget(PoseView()); 336 iconSizeMenu->AddItem(item); 337 338 message = new BMessage(kIconMode); 339 message->AddInt32("scale", 1); 340 item = new BMenuItem(B_TRANSLATE("Increase size"), message, '+'); 341 item->SetTarget(PoseView()); 342 iconSizeMenu->AddItem(item); 343 344 // A sub menu where the super item can be invoked. 345 menu->AddItem(iconSizeMenu); 346 iconSizeMenu->Superitem()->SetShortcut('1', B_COMMAND_KEY); 347 iconSizeMenu->Superitem()->SetMessage(new BMessage(kIconMode)); 348 iconSizeMenu->Superitem()->SetTarget(PoseView()); 349 iconSizeMenu->Superitem()->SetMarked(PoseView()->ViewMode() == kIconMode); 350 351 item = new BMenuItem(B_TRANSLATE("Mini icon view"), 352 new BMessage(kMiniIconMode), '2'); 353 item->SetMarked(PoseView()->ViewMode() == kMiniIconMode); 354 menu->AddItem(item); 355 356 menu->AddSeparatorItem(); 357 358 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU 359 BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"), 360 new BMessage(B_PASTE), 'V')); 361 menu->AddItem(pasteItem); 362 menu->AddSeparatorItem(); 363 #endif 364 menu->AddItem(new BMenuItem(B_TRANSLATE("Clean up"), 365 new BMessage(kCleanup), 'K')); 366 menu->AddItem(new BMenuItem(B_TRANSLATE("Select"B_UTF8_ELLIPSIS), 367 new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY)); 368 menu->AddItem(new BMenuItem(B_TRANSLATE("Select all"), 369 new BMessage(B_SELECT_ALL), 'A')); 370 371 menu->AddSeparatorItem(); 372 menu->AddItem(new MountMenu(B_TRANSLATE("Mount"))); 373 374 menu->AddSeparatorItem(); 375 menu->AddItem(new BMenu(B_TRANSLATE("Add-ons"))); 376 377 // target items as needed 378 menu->SetTargetForItems(PoseView()); 379 #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU 380 pasteItem->SetTarget(this); 381 #endif 382 } 383 384 385 void 386 BDeskWindow::WorkspaceActivated(int32 workspace, bool state) 387 { 388 if (fBackgroundImage) 389 fBackgroundImage->WorkspaceActivated(PoseView(), workspace, state); 390 } 391 392 393 void 394 BDeskWindow::SaveDesktopPoseLocations() 395 { 396 PoseView()->SavePoseLocations(&fOldFrame); 397 } 398 399 400 void 401 BDeskWindow::ScreenChanged(BRect frame, color_space space) 402 { 403 bool frameChanged = (frame != fOldFrame); 404 405 SaveDesktopPoseLocations(); 406 fOldFrame = frame; 407 ResizeTo(frame.Width(), frame.Height()); 408 409 if (fBackgroundImage) 410 fBackgroundImage->ScreenChanged(frame, space); 411 412 PoseView()->CheckPoseVisibility(frameChanged ? &frame : 0); 413 // if frame changed, pass new frame so that icons can 414 // get rearranged based on old pose info for the frame 415 } 416 417 418 void 419 BDeskWindow::UpdateDesktopBackgroundImages() 420 { 421 WindowStateNodeOpener opener(this, false); 422 fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage, 423 opener.Node(), true, PoseView()); 424 } 425 426 427 void 428 BDeskWindow::Show() 429 { 430 if (fBackgroundImage) 431 fBackgroundImage->Show(PoseView(), current_workspace()); 432 433 PoseView()->CheckPoseVisibility(); 434 435 _inherited::Show(); 436 } 437 438 439 bool 440 BDeskWindow::ShouldAddScrollBars() const 441 { 442 return false; 443 } 444 445 446 bool 447 BDeskWindow::ShouldAddMenus() const 448 { 449 return false; 450 } 451 452 453 bool 454 BDeskWindow::ShouldAddContainerView() const 455 { 456 return false; 457 } 458 459 460 void 461 BDeskWindow::MessageReceived(BMessage* message) 462 { 463 if (message->WasDropped()) { 464 const rgb_color* color; 465 int32 size; 466 // handle "roColour"-style color drops 467 if (message->FindData("RGBColor", 'RGBC', 468 (const void**)&color, &size) == B_OK) { 469 BScreen(this).SetDesktopColor(*color); 470 fPoseView->SetViewColor(*color); 471 fPoseView->SetLowColor(*color); 472 return; 473 } 474 } 475 476 switch (message->what) { 477 case B_NODE_MONITOR: 478 PRINT(("will update addon shortcuts\n")); 479 fShouldUpdateAddonShortcuts = true; 480 break; 481 482 default: 483 _inherited::MessageReceived(message); 484 break; 485 } 486 } 487