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