2 Copyright 2004-2005 Chris Tallon
\r
4 This file is part of VOMP.
\r
6 VOMP is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 VOMP is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with VOMP; if not, write to the Free Software
\r
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
21 #include "boxstack.h"
\r
23 #include "command.h"
\r
27 BoxStack* BoxStack::instance = NULL;
\r
29 BoxStack::BoxStack()
\r
31 if (instance) return;
\r
37 BoxStack::~BoxStack()
\r
42 BoxStack* BoxStack::getInstance()
\r
47 int BoxStack::init()
\r
49 if (initted) return 0;
\r
53 pthread_mutex_init(&boxLock, NULL);
\r
55 boxLock = CreateMutex(NULL,FALSE,NULL);
\r
61 int BoxStack::shutdown()
\r
63 if (!initted) return 0;
\r
65 // FIXME don't think this can work properly, removeAll leaves the wallpaper there!
\r
72 int BoxStack::add(Boxx* v)
\r
74 if (!initted) return 0;
\r
75 Log::getInstance()->log("BoxStack", Log::DEBUG, "add called");
\r
77 pthread_mutex_lock(&boxLock);
\r
79 WaitForSingleObject(boxLock, INFINITE);
\r
81 Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for add");
\r
85 Log::getInstance()->log("BoxStack", Log::ERR, "More than 16 boxes! Unlocked for add");
\r
87 pthread_mutex_unlock(&boxLock);
\r
89 ReleaseMutex(boxLock);
\r
93 boxes[numBoxes++] = v;
\r
96 pthread_mutex_unlock(&boxLock);
\r
98 ReleaseMutex(boxLock);
\r
101 Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for add");
\r
106 // ---------------------------------------------------- REMOVE CODE
\r
108 int BoxStack::remove(Boxx* toDelete)
\r
110 if (!initted) return 0;
\r
113 pthread_mutex_lock(&boxLock);
\r
115 WaitForSingleObject(boxLock, INFINITE);
\r
117 Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for remove");
\r
122 pthread_mutex_unlock(&boxLock);
\r
124 ReleaseMutex(boxLock);
\r
126 Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove numBoxes == 0");
\r
130 // Log::getInstance()->log("BoxStack", Log::DEBUG, "entering remove, numBoxes=%i", numBoxes);
\r
134 if (toDelete == NULL)
\r
136 toDelete = boxes[numBoxes-1];
\r
141 // to be deleted box is more likely to be at the top
\r
142 for (i = numBoxes-1; i >= 0; i--)
\r
144 // Log::getInstance()->log("BoxStack", Log::DEBUG, "todel: %p, i=%i, boxes[i]=%p", toDelete, i, boxes[i]);
\r
145 if (boxes[i] == toDelete) break;
\r
150 // not a Box we have!
\r
153 pthread_mutex_unlock(&boxLock);
\r
155 ReleaseMutex(boxLock);
\r
157 Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove - no boxx deleted");
\r
163 pthread_mutex_unlock(&boxLock);
\r
165 ReleaseMutex(boxLock);
\r
168 toDelete->preDelete();
\r
171 pthread_mutex_lock(&boxLock);
\r
173 WaitForSingleObject(boxLock, INFINITE);
\r
176 // Log::getInstance()->log("BoxStack", Log::DEBUG, "Starting deleteBox");
\r
178 // Log::getInstance()->log("BoxStack", Log::DEBUG, "Done deleteBox");
\r
180 // Shift the boxes on top down one
\r
182 for(int j = i; j < numBoxes; j++) boxes[j] = boxes[j+1];
\r
184 // If there is only the wallpaper left signal command
\r
187 Message* m = new Message();
\r
188 m->to = Command::getInstance();
\r
189 m->message = Message::LAST_VIEW_CLOSE;
\r
190 Command::getInstance()->postMessageNoLock(m);
\r
194 pthread_mutex_unlock(&boxLock);
\r
196 ReleaseMutex(boxLock);
\r
198 Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for remove");
\r
201 //AVO: do this delete outside the lock to allow for recursive calls within the destructor
\r
202 // as this box is not in the stack any more, there is no chance for a second delete
\r
203 Log::getInstance()->log("BoxStack", Log::DEBUG, "remove: going to delete boxx %p, num %d", toDelete, numBoxes);
\r
209 /////////////////////////////////////////////////////////////////////////////
\r
211 /////////////////////////////////////////////////////////////////////////////
\r
213 void BoxStack::deleteBox(int z)
\r
215 // Log::getInstance()->log("BoxStack", Log::DEBUG, "Delete box %i of %i", z, numBoxes);
\r
217 boxSplit(boxes[z]->area, z + 1, numBoxes, 1, rl);
\r
220 repaintRevealed(z, rl.front());
\r
225 void BoxStack::redrawAllBoxes()
\r
228 pthread_mutex_lock(&boxLock);
\r
230 WaitForSingleObject(boxLock, INFINITE);
\r
233 for (int z = 0; z < numBoxes; z++)
\r
240 pthread_mutex_unlock(&boxLock);
\r
242 ReleaseMutex(boxLock);
\r
244 update(NULL,NULL); // should blt all
\r
247 void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)
\r
249 Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");
\r
250 if (!initted) return; // it is allowed to call this before init
\r
252 pthread_mutex_lock(&boxLock);
\r
254 WaitForSingleObject(boxLock, INFINITE);
\r
256 Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for update");
\r
258 // Get the z index of the box
\r
262 for (z = 0; z < numBoxes; z++)
\r
264 if (boxes[z] == toUpdate) break;
\r
269 // not a Box we have!
\r
271 pthread_mutex_unlock(&boxLock);
\r
273 ReleaseMutex(boxLock);
\r
275 Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for update! box not inside boxstack");
\r
281 toUpdate = boxes[0];
\r
286 pthread_mutex_unlock(&boxLock);
\r
288 ReleaseMutex(boxLock);
\r
290 Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update, no box present");
\r
294 // get the region for the whole box, could be less than that
\r
295 // for smaller updates
\r
297 Region r = toUpdate->area;
\r
299 if (regionToUpdate)
\r
301 // Can be null if the whole box should be updated
\r
302 // If this is given the numbers are relative to the size of the box, not the screen
\r
304 r.x += regionToUpdate->x;
\r
305 r.y += regionToUpdate->y;
\r
306 r.w = regionToUpdate->w;
\r
307 r.h = regionToUpdate->h;
\r
313 boxSplit(r, z+1, numBoxes, 1, rl);
\r
323 pthread_mutex_unlock(&boxLock);
\r
325 ReleaseMutex(boxLock);
\r
327 Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update");
\r
330 void BoxStack::repaintRevealed(int x, Region r)
\r
333 boxSplit(r, x - 1, -1, -1, rl);
\r
339 boxes[r2.z]->blt(r2);
\r
344 void BoxStack::boxSplit(Region r, int start, int end, int direction, RegionList& rl)
\r
346 // 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);
\r
348 for(int z = start; z != end; z += direction)
\r
350 if (r.overlappedBy(boxes[z]->area))
\r
352 // printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);
\r
357 if (boxes[z]->area.y > r.y)
\r
359 // 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, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
\r
360 top = boxes[z]->area.y;
\r
365 newR.h = boxes[z]->area.y - r.y;
\r
366 boxSplit(newR, z + direction, end, direction, rl);
\r
368 if (direction == -1)
\r
372 newR2.y = boxes[z]->area.y;
\r
374 newR2.h = r.h - newR.h;
\r
375 boxSplit(newR2, z, end, -1, rl);
\r
380 if (boxes[z]->area.y2() < r.y2())
\r
382 // 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, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
\r
383 btm = boxes[z]->area.y2();
\r
386 newR.y = boxes[z]->area.y2() + 1;
\r
388 newR.h = r.y2() - newR.y + 1;
\r
389 boxSplit(newR, z + direction, end, direction, rl);
\r
391 if (direction == -1)
\r
397 newR2.h = r.h - newR.h;
\r
398 boxSplit(newR2, z, end, -1, rl);
\r
403 if (boxes[z]->area.x > r.x)
\r
405 // 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, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
\r
409 newR.w = boxes[z]->area.x - r.x;
\r
410 newR.h = btm - top + 1;
\r
411 boxSplit(newR, z + direction, end, direction, rl);
\r
413 if (direction == -1)
\r
416 newR2.x = r.x + newR.w;
\r
418 newR2.w = r.w - newR.w;
\r
420 boxSplit(newR2, z, end, -1, rl);
\r
425 if (boxes[z]->area.x2() < r.x2())
\r
427 // 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, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
\r
429 newR.x = boxes[z]->area.x2() + 1;
\r
431 newR.w = r.x2() - newR.x + 1;
\r
432 newR.h = btm - top + 1;
\r
433 boxSplit(newR, z + direction, end, direction, rl);
\r
435 if (direction == -1)
\r
440 newR2.w = r.w - newR.w;
\r
442 boxSplit(newR2, z, end, -1, rl);
\r
447 if (direction == -1)
\r
449 // we are going down the stack
\r
450 // r is underlapped by boxes[z]
\r
451 // but we have not split
\r
452 // Therefore this region under test is
\r
453 // completely covering boxes[z]
\r
455 // don't go any further down, generate a region and quit
\r
457 // printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);
\r
462 // printf("Returning from Z=%i\n", z);
\r
467 // printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);
\r
471 // if direction = 1 then we have come to a region that is
\r
472 // entirely clear of higher boxes and needs to be redrawn
\r
474 // if direction = -1 then we have come to a region that is on
\r
475 // the very bottom with nothing below it to repaint.
\r
476 // do nothing. stale window data will be left on screen?
\r
478 if (direction == 1)
\r
484 /////////////////////////////////////////////////////////////////////////////
\r
486 /////////////////////////////////////////////////////////////////////////////
\r
488 // ---------------------------------------------------- END OF REMOVE CODE
\r
491 void BoxStack::removeAll()
\r
493 // 1.. Don't delete wallpaper. No point.
\r
495 // Need locking on this one??
\r
497 // This is pretty silly now that preDelete needs mutex unlocked
\r
499 Boxx* toDel = NULL;
\r
501 while(numBoxes > 1)
\r
504 pthread_mutex_lock(&boxLock);
\r
506 WaitForSingleObject(boxLock, INFINITE);
\r
512 pthread_mutex_unlock(&boxLock);
\r
514 ReleaseMutex(boxLock);
\r
519 toDel = boxes[numBoxes - 1];
\r
522 pthread_mutex_unlock(&boxLock);
\r
524 ReleaseMutex(boxLock);
\r
527 toDel->preDelete();
\r
530 pthread_mutex_lock(&boxLock);
\r
532 WaitForSingleObject(boxLock, INFINITE);
\r
535 // If boxes[numBoxes - 1] isn't toDel then there's a problem
\r
536 if (boxes[numBoxes - 1] == toDel)
\r
542 Log::getInstance()->log("BoxStack", Log::ERR, "Can this actually happen? Why?");
\r
547 pthread_mutex_unlock(&boxLock);
\r
549 ReleaseMutex(boxLock);
\r
552 //AVO: do the delete outside the lock to allow for recursive deletes
\r
553 Log::getInstance()->log("BoxStack", Log::DEBUG, "going to delete boxx %p, num=%d", toDel, numBoxes);
\r
554 if (toDel) delete toDel;
\r
558 int BoxStack::handleCommand(int command)
\r
564 if (command != Remote::NA_NONE)
\r
566 // handle command return values
\r
567 // 0 - drop through to next box
\r
568 // 1 - dont drop to next box, but not handled
\r
569 // 2 - handled - stop command here
\r
570 // 4 - handled - delete this box
\r
572 for (i=numBoxes-1; i>=0; i--)
\r
574 // Log::getInstance()->log("BoxStack", Log::DEBUG, "Giving command to i=%i", i);
\r
575 retVal = boxes[i]->handleCommand(command);
\r
578 // not handled but don't give to any more boxes
\r
588 else if (retVal == 4)
\r
590 // Log::getInstance()->log("BoxStack", Log::DEBUG, "Return 4: i=%i, boxes[i]=%p", i, boxes[i]);
\r
599 // fake the return code
\r
606 void BoxStack::processMessage(Message* m)
\r
610 for (int i = numBoxes-1; i >= 0; i--)
\r
612 if (boxes[i] == m->to)
\r
614 Log::getInstance()->log("BoxStack", Log::DEBUG, "sending message from box %p to box %p %lu", m->from, m->to, m->message);
\r
615 boxes[i]->processMessage(m);
\r
622 /* Handle mouse events*/
\r
623 // They come in with m->to = NULL? and just need to be delivered to top box?
\r
624 if ((numBoxes > 1) && ((m->message == Message::MOUSE_MOVE) || (m->message == Message::MOUSE_LBDOWN)
\r
625 || (m->message == Message::MOUSE_ANDROID_SCROLL)))
\r
627 boxes[numBoxes-1]->processMessage(m);
\r
631 Log::getInstance()->log("BoxStack", Log::DEBUG, "it's for meeee!");
\r
635 case Message::CLOSE_ME:
\r
637 remove((Boxx*)m->from);
\r
640 case Message::ADD_VIEW: // currently not used by anything but it might come in useful again
\r
642 Boxx* toAdd = (Boxx*)m->parameter;
\r