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