2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 ViewMan* ViewMan::instance = NULL;
32 autoDeleteThreadRun = 0;
41 ViewMan* ViewMan::getInstance()
48 if (initted) return 0;
49 pthread_mutex_init(&viewManLock, NULL);
50 pthread_cond_init(&autoDeleteThreadSignal, NULL);
51 if (!startAutoDeleteThread()) return 0;
56 int ViewMan::shutdown()
58 if (!initted) return 0;
60 // FIXME don't think this can work properly, removeAll leaves the wallpaper there!
63 // get the lock here to ensure that the thread is waiting on the cond
64 pthread_mutex_lock(&viewManLock);
65 autoDeleteThreadRun = 0;
66 pthread_cond_signal(&autoDeleteThreadSignal);
67 pthread_mutex_unlock(&viewManLock);
68 pthread_join(autoDeleteThread, NULL);
73 int ViewMan::add(View* v)
75 if (!initted) return 0;
76 if (topView == 10) return 0;
78 pthread_mutex_lock(&viewManLock);
84 pthread_mutex_unlock(&viewManLock);
89 int ViewMan::addNoLock(View* v)
91 if (!initted) return 0;
92 if (topView == 10) return 0;
103 // ---------------------------------------------------- REMOVE CODE
105 int ViewMan::removeView(View* toDelete, int noLock, int noShow)
107 if (!initted) return 0;
108 if (topView == 0) return 0;
110 if (!noLock) pthread_mutex_lock(&viewManLock);
112 Log::getInstance()->log("ViewMan", Log::DEBUG, "entering remove, %u topview", topView);
116 int slotTakenFrom = 0;
118 if (toDelete == NULL)
120 toDelete = views[topView];
126 // to be deleted view is more likely to be at the top
129 for (i = topView; i > 0; i--)
131 if (views[i] == toDelete)
133 if (i == topView) wasTopView = 1;
140 // not a View we have!
141 if (!noLock) pthread_mutex_unlock(&viewManLock);
146 // Save the position we are deleting the view from
149 // Shift the views on top down one
150 for(; i < topView; i++)
152 views[i] = views[i + 1];
156 // Done. Now on to drawing.
158 View* newTopBox = views[topView]; // just to make second optimisation easier
160 // First optimisation. If there are no views left, don't do anything!
163 Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using optimisation 1");
166 // second optimisation. if view being deleted is entirely within the view underneath it,
167 // and was the top most box,
168 // only need to redraw the one underneath
170 && (toDelete->getScreenX() >= newTopBox->getScreenX())
171 && (toDelete->getScreenY() >= newTopBox->getScreenY())
172 && ((toDelete->getScreenX() + toDelete->getWidth()) <= (newTopBox->getScreenX() + newTopBox->getWidth()))
173 && ((toDelete->getScreenY() + toDelete->getHeight()) <= (newTopBox->getScreenY() + newTopBox->getHeight()))
177 Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using optimisation 2");
180 // third optimisation. if the box being deleted is totally within one above it, don't do anything
181 else if ((slotTakenFrom <= topView) && isTotallyCovered(toDelete, slotTakenFrom))
183 Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using optimisation 3");
186 // no optimisations left, redo everything.
189 for (int j = 1; j <= topView; j++)
193 if (!noShow) Surface::bufferToScreen();
195 Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using no optimisation");
202 if (!noLock) pthread_mutex_unlock(&viewManLock);
207 int ViewMan::isTotallyCovered(View* toDelete, int slotTakenFrom)
209 int todelx1 = toDelete->getScreenX();
210 int todelx2 = toDelete->getScreenX() + toDelete->getWidth();
211 int todely1 = toDelete->getScreenY();
212 int todely2 = toDelete->getScreenY() + toDelete->getHeight();
224 for (int i = slotTakenFrom; i <= topView; i++)
226 currentx1 = views[i]->getScreenX();
227 currentx2 = currentx1 + views[i]->getWidth();
228 currenty1 = views[i]->getScreenY();
229 currenty2 = currenty1 + views[i]->getHeight();
231 // printf("Iteration in tc before. i=%i x1=%i x2=%i y1=%i y2=%i cx1=%i cx2=%i cy1=%i cy2=%i\n", i, x1, x2, y1, y2, currentx1, currentx2, currenty1, currenty2);
233 if (currentx1 < x1) x1 = currentx1;
234 if (currentx2 > x2) x2 = currentx2;
235 if (currenty1 < y1) y1 = currenty1;
236 if (currenty2 > y2) y2 = currenty2;
238 // printf("Iteration in tc after . i=%i x1=%i x2=%i y1=%i y2=%i\n", i, x1, x2, y1, y2);
241 // k, now x1 x2 y1 y2 contain the dimensions of the biggest box over the deleted slot
257 // ---------------------------------------------------- END OF REMOVE CODE
260 void ViewMan::removeAll()
262 pthread_mutex_lock(&viewManLock);
264 // FIXME for don't delete wallpaper cos surface destroy doesn't work
266 for (; topView > 1; topView--)
268 delete views[topView];
271 Surface::bufferToScreen();
274 pthread_mutex_unlock(&viewManLock);
277 int ViewMan::handleCommand(UCHAR command)
279 pthread_mutex_lock(&viewManLock);
285 if (command != Remote::NA_NONE)
288 // handle command return values
289 // 0 - drop through to next view
290 // 1 - dont drop to next view, but not handled
291 // 2 - handled - stop command here
292 // 4 - handled - delete this view
294 for (i=topView; i>0; i--)
296 retVal = views[i]->handleCommand(command);
299 // not handled but don't give to any more views
300 pthread_mutex_unlock(&viewManLock);
307 if (views[i]->seconds)
309 struct timespec currentTime;
310 clock_gettime(CLOCK_REALTIME, ¤tTime);
311 views[i]->delSec = currentTime.tv_sec + views[i]->seconds;
312 views[i]->delNSec = currentTime.tv_nsec;
315 pthread_mutex_unlock(&viewManLock);
319 else if (retVal == 4)
321 // removeNoLock(views[i]);
324 removeView(views[i], 1);
325 pthread_mutex_unlock(&viewManLock);
333 // fake the return code
337 Log::getInstance()->log("ViewMan", Log::DEBUG, "out of handlecommand code, now on to messages");
339 processMessageQueue();
341 pthread_mutex_unlock(&viewManLock);
345 void ViewMan::processMessage(Message* m)
349 for (int i = topView; i > 0; i--)
351 if (views[i] == m->to)
353 Log::getInstance()->log("ViewMan", Log::DEBUG, "sending message to view");
354 Log::getInstance()->log("ViewMan", Log::DEBUG, "%p %p %lu", m->from, m->to, m->message);
355 views[i]->processMessage(m);
361 Log::getInstance()->log("ViewMan", Log::DEBUG, "it's for meeee!");
365 case Message::CLOSE_ME:
367 removeView((View*)m->from, 1, 1);
370 case Message::UPDATE_SCREEN:
372 Surface::bufferToScreen();
375 case Message::SWAP_ME_FOR:
377 View* toReplace = (View*) m->parameter;
379 removeView((View*)m->from, 1, 1);
382 views[topView] = toReplace;
383 if (toReplace->seconds)
385 struct timespec currentTime;
386 clock_gettime(CLOCK_REALTIME, ¤tTime);
387 toReplace->delSec = currentTime.tv_sec + toReplace->seconds;
388 toReplace->delNSec = currentTime.tv_nsec;
392 Surface::bufferToScreen();
396 case Message::ADD_VIEW:
398 View* toAdd = (View*)m->parameter;
406 int ViewMan::timedDelete(View* v, int seconds, int lockMutex)
410 if (lockMutex) pthread_mutex_lock(&viewManLock);
412 struct timespec currentTime;
413 clock_gettime(CLOCK_REALTIME, ¤tTime);
419 v->seconds = seconds;
420 v->delSec = currentTime.tv_sec + seconds;
421 v->delNSec = currentTime.tv_nsec;
425 // for cancelling the delete
438 if (lockMutex) pthread_mutex_unlock(&viewManLock);
444 // THE THREAD CODE STARTS HERE /////////////////////////////////////////////////////////////
446 void ViewMan::resetThread()
448 // must be called with mutex already locked
450 pthread_cond_signal(&autoDeleteThreadSignal);
453 // undeclared function
454 void startAutoDeleteThread2(void *arg)
456 ViewMan *v = (ViewMan *)arg;
457 v->startAutoDeleteThread3();
459 int ViewMan::startAutoDeleteThread()
461 pthread_mutex_lock(&viewManLock);
463 autoDeleteThreadRun = 1;
464 if (pthread_create(&autoDeleteThread, NULL, (void*(*)(void*))startAutoDeleteThread2, (void *)this) == -1) return 0;
468 void ViewMan::startAutoDeleteThread3()
470 struct timespec nextTime;
471 View* nextToDelete = NULL;
473 // I don't want signals
476 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
486 // Work out the next View to be deleted
489 nextTime.tv_nsec = 0;
492 for(int i = 1; i <= topView; i++)
494 if ((views[i]->delSec > 0) && (views[i]->delNSec > 0))
496 if ((nextTime.tv_sec == 0) && (nextTime.tv_nsec == 0))
498 nextTime.tv_sec = views[i]->delSec;
499 nextTime.tv_nsec = views[i]->delNSec;
500 nextToDelete = views[i];
504 if (views[i]->delSec < nextTime.tv_sec)
506 nextTime.tv_sec = views[i]->delSec;
507 nextTime.tv_nsec = views[i]->delNSec;
508 nextToDelete = views[i];
510 else if (views[i]->delSec == nextTime.tv_sec)
512 if (views[i]->delNSec < nextTime.tv_nsec)
514 nextTime.tv_sec = views[i]->delNSec;
515 nextTime.tv_nsec = views[i]->delNSec;
516 nextToDelete = views[i];
526 if (nextTime.tv_sec == 0)
528 pthread_cond_wait(&autoDeleteThreadSignal, &viewManLock);
532 pthread_cond_timedwait(&autoDeleteThreadSignal, &viewManLock, &nextTime);
535 // ok. we have been signalled or the time has run out
537 // see if we have been signalled. we only get signalled if we
538 // are to reset the timer or if we are to die completely
539 if (!autoDeleteThreadRun)
542 // exiting thread with mutex locked
545 if (resetThreadFlag) continue;
548 Log::getInstance()->log("ViewMan", Log::DEBUG, "About to remove %p", nextToDelete);
549 removeView(nextToDelete, 1); // enter this method with mutex locked