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;
62 // get the lock here to ensure that the thread is waiting on the cond
63 pthread_mutex_lock(&viewManLock);
64 autoDeleteThreadRun = 0;
65 pthread_cond_signal(&autoDeleteThreadSignal);
66 pthread_mutex_unlock(&viewManLock);
67 pthread_join(autoDeleteThread, NULL);
72 int ViewMan::add(View* v)
74 if (!initted) return 0;
75 if (topView == 10) return 0;
77 pthread_mutex_lock(&viewManLock);
83 pthread_mutex_unlock(&viewManLock);
88 int ViewMan::addNoLock(View* v)
90 if (!initted) return 0;
91 if (topView == 10) return 0;
102 // ---------------------------------------------------- REMOVE CODE
104 int ViewMan::removeView(View* toDelete, int noLock, int noShow)
106 if (!initted) return 0;
107 if (topView == 0) return 0;
109 if (!noLock) pthread_mutex_lock(&viewManLock);
111 Log::getInstance()->log("ViewMan", Log::DEBUG, "entering remove, %u topview", topView);
115 int slotTakenFrom = 0;
117 if (toDelete == NULL)
119 toDelete = views[topView];
125 // to be deleted view is more likely to be at the top
128 for (i = topView; i > 0; i--)
130 if (views[i] == toDelete)
132 if (i == topView) wasTopView = 1;
139 // not a View we have!
140 if (!noLock) pthread_mutex_unlock(&viewManLock);
145 // Save the position we are deleting the view from
148 // Shift the views on top down one
149 for(; i < topView; i++)
151 views[i] = views[i + 1];
155 // Done. Now on to drawing.
157 View* newTopBox = views[topView]; // just to make second optimisation easier
159 // First optimisation. If there are no views left, don't do anything!
162 Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using optimisation 1");
165 // second optimisation. if view being deleted is entirely within the view underneath it,
166 // and was the top most box,
167 // only need to redraw the one underneath
169 && (toDelete->getScreenX() >= newTopBox->getScreenX())
170 && (toDelete->getScreenY() >= newTopBox->getScreenY())
171 && ((toDelete->getScreenX() + toDelete->getWidth()) <= (newTopBox->getScreenX() + newTopBox->getWidth()))
172 && ((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.
190 Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using no optimisation");
197 if (!noLock) pthread_mutex_unlock(&viewManLock);
202 int ViewMan::isTotallyCovered(View* toDelete, int slotTakenFrom)
204 int todelx1 = toDelete->getScreenX();
205 int todelx2 = toDelete->getScreenX() + toDelete->getWidth();
206 int todely1 = toDelete->getScreenY();
207 int todely2 = toDelete->getScreenY() + toDelete->getHeight();
219 for (int i = slotTakenFrom; i <= topView; i++)
221 currentx1 = views[i]->getScreenX();
222 currentx2 = currentx1 + views[i]->getWidth();
223 currenty1 = views[i]->getScreenY();
224 currenty2 = currenty1 + views[i]->getHeight();
226 // 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);
228 if (currentx1 < x1) x1 = currentx1;
229 if (currentx2 > x2) x2 = currentx2;
230 if (currenty1 < y1) y1 = currenty1;
231 if (currenty2 > y2) y2 = currenty2;
233 // printf("Iteration in tc after . i=%i x1=%i x2=%i y1=%i y2=%i\n", i, x1, x2, y1, y2);
236 // k, now x1 x2 y1 y2 contain the dimensions of the biggest box over the deleted slot
252 void ViewMan::redrawAll(int noShow)
254 for (int i = 1; i <= topView; i++)
259 if (!noShow) Box::showAll();
262 // ---------------------------------------------------- END OF REMOVE CODE
265 void ViewMan::removeAll()
267 pthread_mutex_lock(&viewManLock);
269 // FIXME for don't delete wallpaper cos surface destroy doesn't work
271 for (; topView > 1; topView--)
273 delete views[topView];
277 pthread_mutex_unlock(&viewManLock);
280 int ViewMan::handleCommand(UCHAR command)
282 pthread_mutex_lock(&viewManLock);
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);
331 Log::getInstance()->log("ViewMan", Log::DEBUG, "out of handlecommand code, now on to messages");
333 processMessageQueue();
335 pthread_mutex_unlock(&viewManLock);
339 void ViewMan::processMessage(Message* m)
343 for (int i = topView; i > 0; i--)
345 if (views[i] == m->to)
347 Log::getInstance()->log("ViewMan", Log::DEBUG, "sending message to view");
348 Log::getInstance()->log("ViewMan", Log::DEBUG, "%p %p %lu", m->from, m->to, m->message);
349 views[i]->processMessage(m);
355 Log::getInstance()->log("ViewMan", Log::DEBUG, "it's for meeee!");
359 case Message::CLOSE_ME:
361 removeView((View*)m->from, 1, 1);
364 case Message::UPDATE_SCREEN:
369 case Message::SWAP_ME_FOR:
371 View* toReplace = (View*) m->parameter;
373 removeView((View*)m->from, 1, 1);
376 views[topView] = toReplace;
377 if (toReplace->seconds)
379 struct timespec currentTime;
380 clock_gettime(CLOCK_REALTIME, ¤tTime);
381 toReplace->delSec = currentTime.tv_sec + toReplace->seconds;
382 toReplace->delNSec = currentTime.tv_nsec;
389 case Message::ADD_VIEW:
391 View* toAdd = (View*)m->parameter;
399 int ViewMan::timedDelete(View* v, int seconds, int lock)
403 if (lock) pthread_mutex_lock(&viewManLock);
405 struct timespec currentTime;
406 clock_gettime(CLOCK_REALTIME, ¤tTime);
412 v->seconds = seconds;
413 v->delSec = currentTime.tv_sec + seconds;
414 v->delNSec = currentTime.tv_nsec;
418 // for cancelling the delete
431 if (lock) pthread_mutex_unlock(&viewManLock);
437 // THE THREAD CODE STARTS HERE /////////////////////////////////////////////////////////////
439 void ViewMan::resetThread()
441 // must be called with mutex already locked
443 pthread_cond_signal(&autoDeleteThreadSignal);
446 // undeclared function
447 void startAutoDeleteThread2(void *arg)
449 ViewMan *v = (ViewMan *)arg;
450 v->startAutoDeleteThread3();
452 int ViewMan::startAutoDeleteThread()
454 pthread_mutex_lock(&viewManLock);
456 autoDeleteThreadRun = 1;
457 if (pthread_create(&autoDeleteThread, NULL, (void*(*)(void*))startAutoDeleteThread2, (void *)this) == -1) return 0;
461 void ViewMan::startAutoDeleteThread3()
463 struct timespec nextTime;
464 View* nextToDelete = NULL;
466 // I don't want signals
469 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
479 // Work out the next View to be deleted
482 nextTime.tv_nsec = 0;
485 for(int i = 1; i <= topView; i++)
487 if ((views[i]->delSec > 0) && (views[i]->delNSec > 0))
489 if ((nextTime.tv_sec == 0) && (nextTime.tv_nsec == 0))
491 nextTime.tv_sec = views[i]->delSec;
492 nextTime.tv_nsec = views[i]->delNSec;
493 nextToDelete = views[i];
497 if (views[i]->delSec < nextTime.tv_sec)
499 nextTime.tv_sec = views[i]->delSec;
500 nextTime.tv_nsec = views[i]->delNSec;
501 nextToDelete = views[i];
503 else if (views[i]->delSec == nextTime.tv_sec)
505 if (views[i]->delNSec < nextTime.tv_nsec)
507 nextTime.tv_sec = views[i]->delNSec;
508 nextTime.tv_nsec = views[i]->delNSec;
509 nextToDelete = views[i];
519 if (nextTime.tv_sec == 0)
521 pthread_cond_wait(&autoDeleteThreadSignal, &viewManLock);
525 pthread_cond_timedwait(&autoDeleteThreadSignal, &viewManLock, &nextTime);
528 // ok. we have been signalled or the time has run out
530 // see if we have been signalled. we only get signalled if we
531 // are to reset the timer or if we are to die completely
532 if (!autoDeleteThreadRun)
535 // exiting thread with mutex locked
538 if (resetThreadFlag) continue;
541 Log::getInstance()->log("ViewMan", Log::DEBUG, "About to remove %p", nextToDelete);
542 removeView(nextToDelete, 1); // enter this method with mutex locked