vfs: check userland buffers before reading them.
[haiku.git] / src / kits / screensaver / ScreenSaverRunner.cpp
blob2eefca76bbaca6b7051604287193eb1d11b9e4d9
1 /*
2 * Copyright 2003-2013 Haiku, Inc. All rights reserved
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Jérôme Duval, jerome.duval@free.fr
8 * Michael Phipps
9 * John Scipione, jscipione@gmail.com
13 #include "ScreenSaverRunner.h"
15 #include <stdio.h>
17 #include <DirectWindow.h>
18 #include <FindDirectory.h>
19 #include <Message.h>
20 #include <Window.h>
23 ScreenSaverRunner::ScreenSaverRunner(BWindow* window, BView* view,
24 ScreenSaverSettings& settings)
26 fWindow(window),
27 fView(view),
28 fIsDirectDraw(dynamic_cast<BDirectWindow*>(window) != NULL),
29 fSettings(settings),
30 fSaver(NULL),
31 fAddonImage(-1),
32 fThread(-1),
33 fQuitting(false)
35 _LoadAddOn();
39 ScreenSaverRunner::~ScreenSaverRunner()
41 if (!fQuitting)
42 Quit();
44 _CleanUp();
48 status_t
49 ScreenSaverRunner::Run()
51 fThread = spawn_thread(&_ThreadFunc, "ScreenSaverRenderer", B_LOW_PRIORITY,
52 this);
53 Resume();
55 return fThread >= B_OK ? B_OK : fThread;
59 void
60 ScreenSaverRunner::Quit()
62 fQuitting = true;
63 Resume();
65 if (fThread >= 0) {
66 status_t returnValue;
67 wait_for_thread(fThread, &returnValue);
72 status_t
73 ScreenSaverRunner::Suspend()
75 return suspend_thread(fThread);
79 status_t
80 ScreenSaverRunner::Resume()
82 return resume_thread(fThread);
86 void
87 ScreenSaverRunner::_LoadAddOn()
89 // This is a new set of preferences. Free up what we did have
90 // TODO: this is currently not meant to be used after creation
91 if (fThread >= B_OK) {
92 Suspend();
93 if (fSaver != NULL)
94 fSaver->StopSaver();
96 _CleanUp();
98 const char* moduleName = fSettings.ModuleName();
99 if (moduleName == NULL || *moduleName == '\0') {
100 Resume();
101 return;
104 BScreenSaver* (*instantiate)(BMessage*, image_id);
106 // try each directory until one succeeds
108 directory_which which[] = {
109 B_USER_NONPACKAGED_ADDONS_DIRECTORY,
110 B_USER_ADDONS_DIRECTORY,
111 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
112 B_SYSTEM_ADDONS_DIRECTORY,
114 BPath path;
116 for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) {
117 if (find_directory(which[i], &path, false) != B_OK)
118 continue;
119 else if (path.Append("Screen Savers") != B_OK)
120 continue;
121 else if (path.Append(fSettings.ModuleName()) != B_OK)
122 continue;
124 fAddonImage = load_add_on(path.Path());
125 if (fAddonImage > 0)
126 break;
129 if (fAddonImage > 0) {
130 // look for the one C function that should exist,
131 // instantiate_screen_saver()
132 if (get_image_symbol(fAddonImage, "instantiate_screen_saver",
133 B_SYMBOL_TYPE_TEXT, (void **)&instantiate) != B_OK) {
134 fprintf(stderr, "Unable to find the instantiation function.\n");
135 } else {
136 BMessage state;
137 fSettings.GetModuleState(moduleName, &state);
138 fSaver = instantiate(&state, fAddonImage);
141 if (fSaver == NULL) {
142 fprintf(stderr, "Screen saver initialization failed.\n");
143 _CleanUp();
144 } else if (fSaver->InitCheck() != B_OK) {
145 fprintf(stderr, "Screen saver initialization failed: %s.\n",
146 strerror(fSaver->InitCheck()));
147 _CleanUp();
149 } else
150 fprintf(stderr, "Unable to open add-on %s.\n", path.Path());
152 Resume();
156 void
157 ScreenSaverRunner::_CleanUp()
159 delete fSaver;
160 fSaver = NULL;
162 if (fAddonImage >= 0) {
163 status_t result = unload_add_on(fAddonImage);
164 if (result != B_OK) {
165 fprintf(stderr, "Unable to unload screen saver add-on: %s.\n",
166 strerror(result));
168 fAddonImage = -1;
173 status_t
174 ScreenSaverRunner::_Run()
176 static const uint32 kInitialTickRate = 50000;
178 // TODO: This code is getting awfully complicated and should
179 // probably be refactored.
180 uint32 tickBase = kInitialTickRate;
181 int32 snoozeCount = 0;
182 int32 frame = 0;
183 bigtime_t lastTickTime = 0;
184 bigtime_t tick = fSaver != NULL ? fSaver->TickSize() : tickBase;
186 while (!fQuitting) {
187 // break the idle time up into ticks so that we can evaluate
188 // the quit condition with greater responsiveness
189 // otherwise a screen saver that sets, say, a 30 second tick
190 // will result in the screen saver not responding to deactivation
191 // for that length of time
192 snooze(tickBase);
193 if (system_time() - lastTickTime < tick)
194 continue;
195 else {
196 // re-evaluate the tick time after each successful wakeup
197 // screensavers can adjust it on the fly, and we must be
198 // prepared to accomodate that
199 tick = fSaver != NULL ? fSaver->TickSize() : tickBase;
201 if (tick < tickBase) {
202 if (tick < 0)
203 tick = 0;
204 tickBase = tick;
205 } else if (tickBase < kInitialTickRate
206 && tick >= kInitialTickRate) {
207 tickBase = kInitialTickRate;
210 lastTickTime = system_time();
213 if (snoozeCount) {
214 // if we are sleeping, do nothing
215 snoozeCount--;
216 } else if (fSaver != NULL) {
217 if (fSaver->LoopOnCount() && frame >= fSaver->LoopOnCount()) {
218 // Time to nap
219 frame = 0;
220 snoozeCount = fSaver->LoopOffCount();
221 } else if (fWindow->LockWithTimeout(5000LL) == B_OK) {
222 if (!fQuitting) {
223 // NOTE: BeOS R5 really calls DirectDraw()
224 // and then Draw() for the same frame
225 if (fIsDirectDraw)
226 fSaver->DirectDraw(frame);
227 fSaver->Draw(fView, frame);
228 fView->Sync();
229 frame++;
231 fWindow->Unlock();
233 } else
234 snoozeCount = 1000;
237 if (fSaver != NULL)
238 fSaver->StopSaver();
240 return B_OK;
244 status_t
245 ScreenSaverRunner::_ThreadFunc(void* data)
247 ScreenSaverRunner* runner = (ScreenSaverRunner*)data;
248 return runner->_Run();