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