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 (numViews == 20) return 0;
78 pthread_mutex_lock(&viewManLock);
80 views[numViews++] = v;
83 pthread_mutex_unlock(&viewManLock);
88 int ViewMan::addNoLock(View* v)
90 if (!initted) return 0;
91 if (numViews == 20) return 0;
93 views[numViews++] = v;
101 // ---------------------------------------------------- REMOVE CODE
103 int ViewMan::removeView(View* toDelete, int noLock)
105 if (!initted) return 0;
106 if (numViews == 0) return 0;
108 if (!noLock) pthread_mutex_lock(&viewManLock);
110 Log::getInstance()->log("ViewMan", Log::DEBUG, "entering remove, numViews=%i", numViews);
114 if (toDelete == NULL)
116 toDelete = views[numViews-1];
121 // to be deleted view is more likely to be at the top
122 for (i = numViews-1; i >= 0; i--)
124 Log::getInstance()->log("ViewMan", Log::DEBUG, "todel: %p, i=%i, views[i]=%p", toDelete, i, views[i]);
125 if (views[i] == toDelete) break;
130 // not a View we have!
131 if (!noLock) pthread_mutex_unlock(&viewManLock);
136 Log::getInstance()->log("ViewMan", Log::DEBUG, "Starting deleteView");
138 Log::getInstance()->log("ViewMan", Log::DEBUG, "Done deleteView");
140 // Shift the views on top down one
142 for(int j = i; j < numViews; j++) views[j] = views[j+1];
148 if (!noLock) pthread_mutex_unlock(&viewManLock);
153 /////////////////////////////////////////////////////////////////////////////
155 /////////////////////////////////////////////////////////////////////////////
157 void ViewMan::deleteView(int z)
159 Log::getInstance()->log("ViewMan", Log::DEBUG, "Delete view %i of %i", z, numViews);
161 boxSplit(views[z]->area, z + 1, numViews, 1, rl);
164 repaintRevealed(z, rl.front());
170 void ViewMan::update(int z)
172 // get the region for the whole view, could be less than that
173 // for smaller updates
175 Region r = views[z]->area;
181 boxSplit(r, z+1, numViews, 1, rl);
192 void ViewMan::repaintRevealed(int x, Region r)
195 boxSplit(r, x - 1, -1, -1, rl);
201 views[r2.z]->show(r2);
206 void ViewMan::boxSplit(Region r, int start, int end, int direction, RegionList& rl)
208 // printf("Y= S=%i E=%i D=%i: Boxsplit: %i %i %i %i\n", start, end, direction, r.x, r.y, r.w, r.h);
210 for(int z = start; z != end; z += direction)
212 if (r.overlappedBy(views[z]->area))
214 // printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);
219 if (views[z]->area.y > r.y)
221 // printf("Z=%i S=%i E=%i D=%i: Case 1 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, views[z]->area.x, views[z]->area.y, views[z]->area.w, views[z]->area.h);
222 top = views[z]->area.y;
227 newR.h = views[z]->area.y - r.y;
228 boxSplit(newR, z + direction, end, direction, rl);
234 newR2.y = views[z]->area.y;
236 newR2.h = r.h - newR.h;
237 boxSplit(newR2, z, end, -1, rl);
242 if (views[z]->area.y2() < r.y2())
244 // printf("Z=%i S=%i E=%i D=%i: Case 2 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, views[z]->area.x, views[z]->area.y, views[z]->area.w, views[z]->area.h);
245 btm = views[z]->area.y2();
248 newR.y = views[z]->area.y2() + 1;
250 newR.h = r.y2() - newR.y + 1;
251 boxSplit(newR, z + direction, end, direction, rl);
259 newR2.h = r.h - newR.h;
260 boxSplit(newR2, z, end, -1, rl);
265 if (views[z]->area.x > r.x)
267 // printf("Z=%i S=%i E=%i D=%i: Case 3 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, views[z]->area.x, views[z]->area.y, views[z]->area.w, views[z]->area.h);
271 newR.w = views[z]->area.x - r.x;
272 newR.h = btm - top + 1;
273 boxSplit(newR, z + direction, end, direction, rl);
278 newR2.x = r.x + newR.w;
280 newR2.w = r.w - newR.w;
282 boxSplit(newR2, z, end, -1, rl);
287 if (views[z]->area.x2() < r.x2())
289 // printf("Z=%i S=%i E=%i D=%i: Case 4 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, views[z]->area.x, views[z]->area.y, views[z]->area.w, views[z]->area.h);
291 newR.x = views[z]->area.x2() + 1;
293 newR.w = r.x2() - newR.x + 1;
294 newR.h = btm - top + 1;
295 boxSplit(newR, z + direction, end, direction, rl);
302 newR2.w = r.w - newR.w;
304 boxSplit(newR2, z, end, -1, rl);
311 // we are going down the stack
312 // r is underlapped by views[z]
313 // but we have not split
314 // Therefore this region under test is
315 // completely covering views[z]
317 // don't go any further down, generate a region and quit
319 // printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);
324 // printf("Returning from Z=%i\n", z);
329 // printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);
333 // if direction = 1 then we have come to a region that is
334 // entirely clear of higher views and needs to be redrawn
336 // if direction = -1 then we have come to a region that is on
337 // the very bottom with nothing below it to repaint.
338 // do nothing. stale window data will be left on screen?
347 void ViewMan::drawBlack(Region& r)
349 Surface* surface = Surface::getScreen();
350 surface->fillblt(r.x, r.y, r.w, r.h, surface->rgba(0, 0, 0, 255));
353 /////////////////////////////////////////////////////////////////////////////
355 /////////////////////////////////////////////////////////////////////////////
357 // ---------------------------------------------------- END OF REMOVE CODE
360 void ViewMan::removeAll()
362 pthread_mutex_lock(&viewManLock);
364 // 1.. Don't delete wallpaper. No point.
365 for (; numViews > 1; --numViews)
367 delete views[numViews-1];
370 // Surface::bufferToScreen();
373 pthread_mutex_unlock(&viewManLock);
376 int ViewMan::handleCommand(UCHAR command)
378 pthread_mutex_lock(&viewManLock);
384 if (command != Remote::NA_NONE)
386 // handle command return values
387 // 0 - drop through to next view
388 // 1 - dont drop to next view, but not handled
389 // 2 - handled - stop command here
390 // 4 - handled - delete this view
392 for (i=numViews-1; i>=0; i--)
394 Log::getInstance()->log("ViewMan", Log::DEBUG, "Giving command to i=%i", i);
395 retVal = views[i]->handleCommand(command);
398 // not handled but don't give to any more views
399 pthread_mutex_unlock(&viewManLock);
406 if (views[i]->seconds)
408 struct timespec currentTime;
409 clock_gettime(CLOCK_REALTIME, ¤tTime);
410 views[i]->delSec = currentTime.tv_sec + views[i]->seconds;
411 views[i]->delNSec = currentTime.tv_nsec;
414 pthread_mutex_unlock(&viewManLock);
418 else if (retVal == 4)
420 // removeNoLock(views[i]);
423 Log::getInstance()->log("ViewMan", Log::DEBUG, "Return 4: i=%i, views[i]=%p", i, views[i]);
424 removeView(views[i], 1);
425 pthread_mutex_unlock(&viewManLock);
433 // fake the return code
437 Log::getInstance()->log("ViewMan", Log::DEBUG, "out of handlecommand code, now on to messages");
439 processMessageQueue();
441 pthread_mutex_unlock(&viewManLock);
445 void ViewMan::processMessage(Message* m)
449 for (int i = numViews-1; i >= 0; i--)
451 if (views[i] == m->to)
453 Log::getInstance()->log("ViewMan", Log::DEBUG, "sending message to view");
454 Log::getInstance()->log("ViewMan", Log::DEBUG, "%p %p %lu", m->from, m->to, m->message);
455 views[i]->processMessage(m);
461 Log::getInstance()->log("ViewMan", Log::DEBUG, "it's for meeee!");
465 case Message::CLOSE_ME:
467 removeView((View*)m->from, 1);
470 case Message::SWAP_ME_FOR:
472 View* toReplace = (View*) m->parameter;
474 removeView((View*)m->from, 1);
476 views[numViews] = toReplace;
478 if (toReplace->seconds)
480 struct timespec currentTime;
481 clock_gettime(CLOCK_REALTIME, ¤tTime);
482 toReplace->delSec = currentTime.tv_sec + toReplace->seconds;
483 toReplace->delNSec = currentTime.tv_nsec;
490 case Message::ADD_VIEW:
492 View* toAdd = (View*)m->parameter;
500 int ViewMan::timedDelete(View* v, int seconds, int lockMutex)
504 if (lockMutex) pthread_mutex_lock(&viewManLock);
506 struct timespec currentTime;
507 clock_gettime(CLOCK_REALTIME, ¤tTime);
513 v->seconds = seconds;
514 v->delSec = currentTime.tv_sec + seconds;
515 v->delNSec = currentTime.tv_nsec;
519 // for cancelling the delete
532 if (lockMutex) pthread_mutex_unlock(&viewManLock);
538 // THE THREAD CODE STARTS HERE /////////////////////////////////////////////////////////////
540 void ViewMan::resetThread()
542 // must be called with mutex already locked
544 pthread_cond_signal(&autoDeleteThreadSignal);
547 // undeclared function
548 void startAutoDeleteThread2(void *arg)
550 ViewMan *v = (ViewMan *)arg;
551 v->startAutoDeleteThread3();
553 int ViewMan::startAutoDeleteThread()
555 pthread_mutex_lock(&viewManLock);
557 autoDeleteThreadRun = 1;
558 if (pthread_create(&autoDeleteThread, NULL, (void*(*)(void*))startAutoDeleteThread2, (void *)this) == -1) return 0;
562 void ViewMan::startAutoDeleteThread3()
564 struct timespec nextTime;
565 View* nextToDelete = NULL;
567 // I don't want signals
570 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
580 // Work out the next View to be deleted
583 nextTime.tv_nsec = 0;
586 for(int i = 0; i < numViews; i++)
588 if ((views[i]->delSec > 0) && (views[i]->delNSec > 0))
590 if ((nextTime.tv_sec == 0) && (nextTime.tv_nsec == 0))
592 nextTime.tv_sec = views[i]->delSec;
593 nextTime.tv_nsec = views[i]->delNSec;
594 nextToDelete = views[i];
598 if (views[i]->delSec < nextTime.tv_sec)
600 nextTime.tv_sec = views[i]->delSec;
601 nextTime.tv_nsec = views[i]->delNSec;
602 nextToDelete = views[i];
604 else if (views[i]->delSec == nextTime.tv_sec)
606 if (views[i]->delNSec < nextTime.tv_nsec)
608 nextTime.tv_sec = views[i]->delNSec;
609 nextTime.tv_nsec = views[i]->delNSec;
610 nextToDelete = views[i];
620 if (nextTime.tv_sec == 0)
622 pthread_cond_wait(&autoDeleteThreadSignal, &viewManLock);
626 pthread_cond_timedwait(&autoDeleteThreadSignal, &viewManLock, &nextTime);
629 // ok. we have been signalled or the time has run out
631 // see if we have been signalled. we only get signalled if we
632 // are to reset the timer or if we are to die completely
633 if (!autoDeleteThreadRun)
636 // exiting thread with mutex locked
639 if (resetThreadFlag) continue;
642 Log::getInstance()->log("ViewMan", Log::DEBUG, "About to remove %p", nextToDelete);
643 removeView(nextToDelete, 1); // enter this method with mutex locked