1 /* 2 * Copyright 2003-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Phipps 7 * Jérôme Duval, jerome.duval@free.fr 8 * Axel Dörfler, axeld@pinc-software.de 9 */ 10 11 12 #include "ScreenSaverRunner.h" 13 #include "ScreenSaverSettings.h" 14 15 #include <FindDirectory.h> 16 #include <Screen.h> 17 #include <ScreenSaver.h> 18 #include <View.h> 19 20 #include <stdio.h> 21 22 ScreenSaverRunner::ScreenSaverRunner(BWindow* window, BView* view, 23 bool preview, ScreenSaverSettings& settings) 24 : 25 fSaver(NULL), 26 fWindow(window), 27 fView(view), 28 fSettings(settings), 29 fPreview(preview), 30 fAddonImage(-1), 31 fThread(-1), 32 fQuitting(false) 33 { 34 fDirectWindow = dynamic_cast<BDirectWindow *>(fWindow); 35 _LoadAddOn(); 36 } 37 38 39 ScreenSaverRunner::~ScreenSaverRunner() 40 { 41 if (!fQuitting) 42 Quit(); 43 44 _CleanUp(); 45 } 46 47 48 BScreenSaver* 49 ScreenSaverRunner::ScreenSaver() const 50 { 51 return fSaver; 52 } 53 54 55 bool 56 ScreenSaverRunner::HasStarted() const 57 { 58 return fHasStarted; 59 } 60 61 62 status_t 63 ScreenSaverRunner::Run() 64 { 65 fThread = spawn_thread(&_ThreadFunc, "ScreenSaverRenderer", B_LOW_PRIORITY, this); 66 Resume(); 67 68 return fThread >= B_OK ? B_OK : fThread; 69 } 70 71 72 void 73 ScreenSaverRunner::Quit() 74 { 75 fQuitting = true; 76 Resume(); 77 78 if (fThread >= 0) { 79 status_t returnValue; 80 wait_for_thread(fThread, &returnValue); 81 } 82 } 83 84 85 void 86 ScreenSaverRunner::Suspend() 87 { 88 suspend_thread(fThread); 89 } 90 91 92 void 93 ScreenSaverRunner::Resume() 94 { 95 resume_thread(fThread); 96 } 97 98 99 void 100 ScreenSaverRunner::_LoadAddOn() 101 { 102 // This is a new set of preferences. Free up what we did have 103 // TODO: this is currently not meant to be used after creation 104 if (fThread >= B_OK) { 105 Suspend(); 106 if (fSaver != NULL) 107 fSaver->StopSaver(); 108 } 109 _CleanUp(); 110 111 if (!strcmp("", fSettings.ModuleName())) { 112 Resume(); 113 return; 114 } 115 116 BScreenSaver* (*instantiate)(BMessage*, image_id); 117 118 // try all directories until the first one succeeds 119 120 directory_which which[] = {B_BEOS_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, 121 B_USER_ADDONS_DIRECTORY}; 122 BPath path; 123 124 for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) { 125 if (find_directory(which[i], &path, false) != B_OK) 126 continue; 127 128 path.Append("Screen Savers"); 129 path.Append(fSettings.ModuleName()); 130 131 fAddonImage = load_add_on(path.Path()); 132 if (fAddonImage >= B_OK) 133 break; 134 } 135 136 if (fAddonImage < B_OK) { 137 printf("Unable to open add-on: %s: %s\n", path.Path(), strerror(fAddonImage)); 138 } else { 139 // Look for the one C function that should exist. 140 if (get_image_symbol(fAddonImage, "instantiate_screen_saver", 141 B_SYMBOL_TYPE_TEXT, (void **)&instantiate) != B_OK) { 142 printf("Unable to find the instantiator\n"); 143 } else { 144 BMessage state; 145 fSettings.GetModuleState(fSettings.ModuleName(), &state); 146 fSaver = instantiate(&state, fAddonImage); 147 } 148 149 if (fSaver->InitCheck() != B_OK) { 150 printf("ScreenSaver initialization failed: %s!\n", strerror(fSaver->InitCheck())); 151 _CleanUp(); 152 } 153 } 154 155 Resume(); 156 } 157 158 159 void 160 ScreenSaverRunner::_CleanUp() 161 { 162 delete fSaver; 163 fSaver = NULL; 164 165 if (fAddonImage >= 0) { 166 unload_add_on(fAddonImage); 167 fAddonImage = -1; 168 } 169 } 170 171 172 void 173 ScreenSaverRunner::_Run() 174 { 175 const uint32 kTickBase = 50000; 176 if (fWindow->Lock()) { 177 fView->SetViewColor(0, 0, 0); 178 fView->SetLowColor(0, 0, 0); 179 if (fSaver) 180 fHasStarted = fSaver->StartSaver(fView, fPreview) == B_OK; 181 fWindow->Unlock(); 182 } 183 184 int32 snoozeCount = 0; 185 int32 frame = 0; 186 bigtime_t lastTickTime = 0; 187 bigtime_t tick = fSaver ? fSaver->TickSize() : kTickBase; 188 189 while (!fQuitting) { 190 // break the idle time up into ticks so that we can evaluate 191 // the quit condition with greater responsiveness 192 // otherwise a screen saver that sets, say, a 30 second tick 193 // will result in the screen saver not responding to deactivation 194 // for that length of time 195 snooze(kTickBase); 196 if (system_time() - lastTickTime < tick) 197 continue; 198 else { 199 // re-evaluate the tick time after each successful wakeup - 200 // screensavers can adjust it on the fly and we must be 201 // prepared to accomodate that 202 tick = fSaver ? fSaver->TickSize() : kTickBase; 203 lastTickTime = system_time(); 204 } 205 206 if (snoozeCount) { 207 // if we are sleeping, do nothing 208 snoozeCount--; 209 } else if (fSaver != NULL && fHasStarted) { 210 if (fSaver->LoopOnCount() && frame >= fSaver->LoopOnCount()) { 211 // Time to nap 212 frame = 0; 213 snoozeCount = fSaver->LoopOffCount(); 214 } else if (fWindow->LockWithTimeout(5000LL) == B_OK) { 215 if (!fQuitting) { 216 // NOTE: R5 really calls DirectDraw() 217 // and then Draw() for the same frame 218 if (fDirectWindow) 219 fSaver->DirectDraw(frame); 220 fSaver->Draw(fView, frame); 221 fView->Sync(); 222 frame++; 223 } 224 fWindow->Unlock(); 225 } 226 } else 227 snoozeCount = 1000; 228 } 229 230 if (fSaver) 231 fSaver->StopSaver(); 232 } 233 234 235 status_t 236 ScreenSaverRunner::_ThreadFunc(void *data) 237 { 238 ScreenSaverRunner* runner = (ScreenSaverRunner*)data; 239 runner->_Run(); 240 return B_OK; 241 } 242 243