1 // license: public domain 2 // authors: jonas.sundstrom@kirilla.com 3 4 5 #include "ZipOMatic.h" 6 7 #include <Alert.h> 8 #include <Roster.h> 9 #include <Screen.h> 10 #include <TrackerAddOnAppLaunch.h> 11 12 #include "ZipOMaticMisc.h" 13 #include "ZipOMaticWindow.h" 14 15 16 int 17 main() 18 { 19 ZipOMatic app; 20 app.Run(); 21 22 return 0; 23 } 24 25 26 ZipOMatic::ZipOMatic() 27 : 28 BApplication(ZIPOMATIC_APP_SIG), 29 fSettings(), 30 fGotRefs(false), 31 fInvoker(new BInvoker(new BMessage(ZIPPO_QUIT_OR_CONTINUE), NULL, this)), 32 fWindowFrame(200, 200, 430, 310) 33 { 34 status_t status = _ReadSettings(); 35 36 if (status != B_OK) 37 ErrorMessage("_ReadSettings()", status); 38 } 39 40 41 ZipOMatic::~ZipOMatic() 42 { 43 status_t status = _WriteSettings(); 44 45 if (status != B_OK) 46 ErrorMessage("_WriteSettings()", status); 47 } 48 49 50 void 51 ZipOMatic::RefsReceived(BMessage* message) 52 { 53 message->RemoveName("dir_ref"); 54 55 entry_ref ref; 56 if (message->FindRef("refs", &ref) != B_OK) { 57 if (!IsLaunching()) 58 PostMessage(B_SILENT_RELAUNCH); 59 return; 60 } 61 62 if (IsLaunching()) 63 fGotRefs = true; 64 65 BMessage* msg = new BMessage(*message); 66 67 _UseExistingOrCreateNewWindow(msg); 68 } 69 70 71 void 72 ZipOMatic::ReadyToRun() 73 { 74 if (!fGotRefs) 75 _UseExistingOrCreateNewWindow(); 76 } 77 78 79 void 80 ZipOMatic::MessageReceived(BMessage* message) 81 { 82 switch (message->what) { 83 case ZIPPO_WINDOW_QUIT: 84 { 85 BRect frame; 86 if (message->FindRect("frame", &frame) == B_OK) 87 fWindowFrame = frame; 88 snooze(200000); 89 if (CountWindows() == 0) 90 Quit(); 91 break; 92 } 93 case B_SILENT_RELAUNCH: 94 _SilentRelaunch(); 95 break; 96 97 case ZIPPO_QUIT_OR_CONTINUE: 98 { 99 int32 button; 100 if (message->FindInt32("which", &button) == B_OK) 101 if (button == 0) { 102 _StopZipping(); 103 } else { 104 if (CountWindows() == 0) 105 Quit(); 106 } 107 break; 108 } 109 110 default: 111 BApplication::MessageReceived(message); 112 break; 113 } 114 } 115 116 117 bool 118 ZipOMatic::QuitRequested (void) 119 { 120 if (CountWindows() <= 0) 121 return true; 122 123 BWindow* window; 124 ZippoWindow* zippo; 125 ZippoWindow* lastFoundZippo = NULL; 126 int32 zippoCount = 0; 127 128 for (int32 i = 0;; i++) { 129 window = WindowAt(i); 130 if (window == NULL) 131 break; 132 133 zippo = dynamic_cast<ZippoWindow*>(window); 134 if (zippo == NULL) 135 continue; 136 137 lastFoundZippo = zippo; 138 139 if (zippo->Lock()) { 140 if (zippo->IsZipping()) 141 zippoCount++; 142 else 143 zippo->PostMessage(B_QUIT_REQUESTED); 144 145 zippo->Unlock(); 146 } 147 } 148 149 if (zippoCount == 1) { 150 // This is likely the most frequent case - a single zipper. 151 // We post a message to the window so it can put up its own 152 // BAlert instead of the app-wide BAlert. This avoids making 153 // a difference between having pressed Commmand-W or Command-Q. 154 // Closing or quitting, it doesn't matter for a single window. 155 156 if (lastFoundZippo->Lock()) { 157 lastFoundZippo->Activate(); 158 lastFoundZippo->PostMessage(B_QUIT_REQUESTED); 159 lastFoundZippo->Unlock(); 160 } 161 return false; 162 } 163 164 if (zippoCount > 0) { 165 // The multi-zipper case differs from the single-zipper case 166 // in that zippers are not paused while the BAlert is up. 167 168 BString question; 169 question << "You have " << zippoCount; 170 question << " Zip-O-Matic running.\n\nDo you want to stop them?"; 171 172 BAlert* alert = new BAlert("Stop or Continue", question.String(), 173 "Stop them", "Let them continue", NULL, B_WIDTH_AS_USUAL, 174 B_WARNING_ALERT); 175 alert->Go(fInvoker); 176 alert->Activate(); 177 // BAlert, being modal, does not show on the current workspace 178 // if the application has no window there. Activate() triggers 179 // a switch to a workspace where it does have a window. 180 181 // TODO: See if AS_ACTIVATE_WINDOW should be handled differently 182 // in src/servers/app/Desktop.cpp Desktop::ActivateWindow() 183 // or if maybe BAlert should (and does not?) activate itself. 184 185 return false; 186 } 187 188 if (CountWindows() <= 0) 189 return true; 190 191 return false; 192 } 193 194 195 void 196 ZipOMatic::_SilentRelaunch() 197 { 198 _UseExistingOrCreateNewWindow(); 199 } 200 201 202 void 203 ZipOMatic::_UseExistingOrCreateNewWindow(BMessage* message) 204 { 205 int32 windowCount = 0; 206 ZippoWindow* window; 207 bool foundNonBusyWindow = false; 208 209 while (1) { 210 window = dynamic_cast<ZippoWindow*>(WindowAt(windowCount++)); 211 if (window == NULL) 212 break; 213 214 if (window->Lock()) { 215 if (!window->IsZipping()) { 216 foundNonBusyWindow = true; 217 if (message != NULL) 218 window->PostMessage(message); 219 window->SetWorkspaces(B_CURRENT_WORKSPACE); 220 window->Activate(); 221 window->Unlock(); 222 break; 223 } 224 window->Unlock(); 225 } 226 } 227 228 if (!foundNonBusyWindow) 229 { 230 BScreen screen; 231 fWindowFrame.OffsetBy(screen.Frame().LeftTop()); 232 233 _CascadeOnFrameCollision(&fWindowFrame); 234 if(!screen.Frame().Contains(fWindowFrame)) { 235 fWindowFrame.OffsetTo(screen.Frame().LeftTop()); 236 fWindowFrame.OffsetBy(20,45); 237 // TODO: replace with CenterOnScreen() 238 } 239 240 ZippoWindow * window = new ZippoWindow(fWindowFrame, message); 241 window->Show(); 242 } 243 } 244 245 246 void 247 ZipOMatic::_StopZipping() 248 { 249 BWindow* window; 250 ZippoWindow* zippo; 251 BList list; 252 253 for (int32 i = 0;; i++) { 254 window = WindowAt(i); 255 if (window == NULL) 256 break; 257 258 zippo = dynamic_cast<ZippoWindow*>(window); 259 if (zippo == NULL) 260 continue; 261 262 list.AddItem(zippo); 263 } 264 265 for (int32 i = 0;; i++) { 266 zippo = static_cast<ZippoWindow*>(list.ItemAt(i)); 267 if (zippo == NULL) 268 break; 269 270 if (zippo->Lock()) { 271 if (zippo->IsZipping()) 272 zippo->StopZipping(); 273 274 zippo->PostMessage(B_QUIT_REQUESTED); 275 zippo->Unlock(); 276 } 277 } 278 } 279 280 281 status_t 282 ZipOMatic::_ReadSettings() 283 { 284 status_t status = B_OK; 285 286 status = fSettings.SetTo("zipomatic.msg"); 287 if (status != B_OK) 288 return status; 289 290 status = fSettings.InitCheck(); 291 if (status != B_OK) 292 return status; 293 294 status = fSettings.InitCheck(); 295 if (status != B_OK) 296 return status; 297 298 status = fSettings.ReadSettings(); 299 if (status != B_OK) 300 return status; 301 302 BRect frame; 303 status = fSettings.FindRect("frame", &frame); 304 if (status != B_OK) 305 return status; 306 307 fWindowFrame = frame; 308 309 return B_OK; 310 } 311 312 313 status_t 314 ZipOMatic::_WriteSettings() 315 { 316 status_t status = B_OK; 317 318 status = fSettings.InitCheck(); 319 if (status != B_OK) 320 return status; 321 322 status = fSettings.MakeEmpty(); 323 if (status != B_OK) 324 return status; 325 326 status = fSettings.AddRect("frame", fWindowFrame); 327 if (status != B_OK) 328 return status; 329 330 status = fSettings.WriteSettings(); 331 if (status != B_OK) 332 return status; 333 334 return B_OK; 335 } 336 337 338 void 339 ZipOMatic::_CascadeOnFrameCollision(BRect* frame) 340 { 341 BWindow* window; 342 ZippoWindow* zippo; 343 BList list; 344 345 for (int32 i = 0;; i++) { 346 window = WindowAt(i); 347 if (window == NULL) 348 break; 349 350 zippo = dynamic_cast<ZippoWindow*>(window); 351 if (zippo == NULL) 352 continue; 353 354 list.AddItem(zippo); 355 } 356 357 for (int32 i = 0;; i++) { 358 zippo = static_cast<ZippoWindow*>(list.ItemAt(i)); 359 if (zippo == NULL) 360 break; 361 362 if (zippo->Lock()) { 363 if (frame->LeftTop() == zippo->Frame().LeftTop()) 364 frame->OffsetBy(20, 20); 365 zippo->Unlock(); 366 } 367 } 368 } 369 370