]> git.vomp.tv Git - vompclient.git/blob - boxstack.cc
Reverting changes in mutex
[vompclient.git] / boxstack.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
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.
10
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.
15
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "boxstack.h"
22
23 #include "command.h"
24 #include "remote.h"
25 #include "log.h"
26
27 BoxStack* BoxStack::instance = NULL;
28
29 BoxStack::BoxStack()
30 {
31   if (instance) return;
32   instance = this;
33   initted = 0;
34   numBoxes = 0;
35 }
36
37 BoxStack::~BoxStack()
38 {
39   instance = NULL;
40 }
41
42 BoxStack* BoxStack::getInstance()
43 {
44   return instance;
45 }
46
47 int BoxStack::init()
48 {
49   if (initted) return 0;
50   initted = 1;
51   
52   return 1;
53 }
54
55 int BoxStack::shutdown()
56 {
57   if (!initted) return 0;
58
59   // FIXME don't think this can work properly, removeAll leaves the wallpaper there!
60   removeAll();
61
62   initted = 0;
63   return 1;
64 }
65
66 int BoxStack::addVideoDisplay(Boxx* box,VideoDisplay vd)
67 {
68           boxLock.Lock();
69           videoStack.push(pair<Boxx*,VideoDisplay>(box,vd));
70           boxLock.Unlock();
71           Video::getInstance()->setVideoDisplay(vd);
72           return 1;
73 }
74
75 int BoxStack::add(Boxx* v)
76 {
77   if (!initted) return 0;
78   Log::getInstance()->log("BoxStack", Log::DEBUG, "add called"); 
79   boxLock.Lock();
80   Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for add");  
81   
82   if (numBoxes == 16)
83   { //Error
84     Log::getInstance()->log("BoxStack", Log::ERR, "More than 16 boxes! Unlocked for add"); 
85     boxLock.Unlock();
86     return 0;
87   }
88   boxes[numBoxes++] = v;
89   boxLock.Unlock();
90   VideoDisplay vd;
91   if (v->getVideoDisplay(vd)) {
92           Log::getInstance()->log("BoxStack", Log::DEBUG, "Add video display");
93           addVideoDisplay(v,vd);
94   }
95
96
97
98   Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for add");
99   
100   return 1;
101 }
102
103 // ---------------------------------------------------- REMOVE CODE
104
105 int BoxStack::remove(Boxx* toDelete)
106 {
107   if (!initted) return 0;
108   VideoDisplay *display = NULL;
109
110   boxLock.Lock();
111   Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for remove");  
112   
113   if (numBoxes == 0)
114   {
115     boxLock.Unlock();
116     Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove numBoxes == 0");  
117     return 0;
118   }
119
120 //  Log::getInstance()->log("BoxStack", Log::DEBUG, "entering remove, numBoxes=%i", numBoxes);
121
122   int i;
123
124   if (toDelete == NULL)
125   {
126     toDelete = boxes[numBoxes-1];
127     i = numBoxes - 1;
128   }
129   else
130   {
131     // to be deleted box is more likely to be at the top
132     for (i = numBoxes-1; i >= 0; i--)
133     {
134 //      Log::getInstance()->log("BoxStack", Log::DEBUG, "todel: %p, i=%i, boxes[i]=%p", toDelete, i, boxes[i]);
135       if (boxes[i] == toDelete) break;
136     }
137
138     if (i == -1)
139     {
140       // not a Box we have!
141       // FIXME
142       boxLock.Unlock();
143       Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove - no boxx deleted");  
144       return 0;
145     }
146   }
147
148   boxLock.Unlock();
149
150 toDelete->preDelete();
151
152   boxLock.Lock();
153
154 //  Log::getInstance()->log("BoxStack", Log::DEBUG, "Starting deleteBox");
155   deleteBox(i);
156 //  Log::getInstance()->log("BoxStack", Log::DEBUG, "Done deleteBox");
157
158   // Shift the boxes on top down one
159   --numBoxes;
160   for(int j = i; j < numBoxes; j++) boxes[j] = boxes[j+1];
161
162   // If there is only the wallpaper left signal command
163   if (numBoxes == 1)
164   {
165     Message* m = new Message();
166     m->to = Command::getInstance();
167     m->message = Message::LAST_VIEW_CLOSE;
168     Command::getInstance()->postMessageNoLock(m);
169   }
170
171   if (!videoStack.empty() && videoStack.top().first==toDelete) {
172         videoStack.pop();
173     if (!videoStack.empty()) display=&videoStack.top().second;
174   }
175   boxLock.Unlock();
176   Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for remove");  
177  
178   // Delete the box
179   //AVO: do this delete outside the lock to allow for recursive calls within the destructor
180   //     as this box is not in the stack any more, there is no chance for a second delete
181   Log::getInstance()->log("BoxStack", Log::DEBUG, "remove: going to delete boxx %p, num %d", toDelete, numBoxes);  
182   delete toDelete;
183   if  (display) {
184           Log::getInstance()->log("BoxStack", Log::DEBUG, "setVideoDisplay %d %d %d %d %d %d", display->mode, display->fallbackMode,
185                           display->x, display->y, display->width, display->height);
186           Video::getInstance()->setVideoDisplay(*display);
187   }
188
189   return 1;
190 }
191
192 /////////////////////////////////////////////////////////////////////////////
193 // NEW STUFF
194 /////////////////////////////////////////////////////////////////////////////
195
196 void BoxStack::deleteBox(int z)
197 {
198 //  Log::getInstance()->log("BoxStack", Log::DEBUG, "Delete box %i of %i", z, numBoxes);
199   RegionList rl;
200   boxSplit(boxes[z]->area, z + 1, numBoxes, 1, rl);
201   while(!rl.empty())
202   {
203     repaintRevealed(z, rl.front());
204     rl.pop_front();
205   }
206 }
207
208 void BoxStack::redrawAllBoxes()
209 {
210   boxLock.Lock();
211
212   for (int z = 0; z < numBoxes; z++)
213   {
214           boxes[z]->draw();
215   }
216
217
218   boxLock.Unlock();
219   update(NULL,NULL); // should blt all
220 }
221
222 void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)
223 {
224   Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");
225   if (!initted) return; // it is allowed to call this before init
226   boxLock.Lock();
227   Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for update");
228
229   // Get the z index of the box
230   int z = 0;
231   if (toUpdate)
232   {
233     for (z = 0; z < numBoxes; z++)
234     {
235       if (boxes[z] == toUpdate) break;
236     }
237
238     if (z == numBoxes)
239     {
240       // not a Box we have!
241       boxLock.Unlock();
242       Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for update! box not inside boxstack");
243       return;
244     }
245   }
246   else
247   {
248     toUpdate = boxes[0];
249   }
250
251   if (!toUpdate) {
252       boxLock.Unlock();
253           Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update, no box present");
254           return ;
255   }
256
257   // get the region for the whole box, could be less than that
258   // for smaller updates
259
260   Region r = toUpdate->area;
261
262   if (regionToUpdate)
263   {
264     // Can be null if the whole box should be updated
265     // If this is given the numbers are relative to the size of the box, not the screen
266
267     r.x += regionToUpdate->x;
268     r.y += regionToUpdate->y;
269     r.w = regionToUpdate->w;
270     r.h = regionToUpdate->h;
271   }
272
273   RegionList rl;
274
275   Region r2;
276   boxSplit(r, z+1, numBoxes, 1, rl);
277   while(!rl.empty())
278   {
279     r2 = rl.front();
280     r2.z = z;
281     boxes[z]->blt(r2);
282     rl.pop_front();
283   }
284
285   boxLock.Unlock();
286   Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update");
287 }
288
289 void BoxStack::repaintRevealed(int x, Region r)
290 {
291   RegionList rl;
292   boxSplit(r, x - 1, -1, -1, rl);
293
294   Region r2;
295   while(!rl.empty())
296   {
297     r2 = rl.front();
298     boxes[r2.z]->blt(r2);
299     rl.pop_front();
300   }
301 }
302
303 void BoxStack::boxSplit(Region r, int start, int end, int direction, RegionList& rl)
304 {
305 //  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);
306
307   for(int z = start; z != end; z += direction)
308   {
309     if (r.overlappedBy(boxes[z]->area))
310     {
311 //      printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);
312
313       int top = r.y;
314       int btm = r.y2();
315
316       if (boxes[z]->area.y > r.y)
317       {
318 //        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);
319         top = boxes[z]->area.y;
320         Region newR;
321         newR.x = r.x;
322         newR.y = r.y;
323         newR.w = r.w;
324         newR.h = boxes[z]->area.y - r.y;
325         boxSplit(newR, z + direction, end, direction, rl);
326
327         if (direction == -1)
328         {
329           Region newR2;
330           newR2.x = r.x;
331           newR2.y = boxes[z]->area.y;
332           newR2.w = r.w;
333           newR2.h = r.h - newR.h;
334           boxSplit(newR2, z, end, -1, rl);
335           return;
336         }
337       }
338
339       if (boxes[z]->area.y2() < r.y2())
340       {
341 //        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);
342         btm = boxes[z]->area.y2();
343         Region newR;
344         newR.x = r.x;
345         newR.y = boxes[z]->area.y2() + 1;
346         newR.w = r.w;
347         newR.h = r.y2() - newR.y + 1;
348         boxSplit(newR, z + direction, end, direction, rl);
349
350         if (direction == -1)
351         {
352           Region newR2;
353           newR2.x = r.x;
354           newR2.y = r.y;
355           newR2.w = r.w;
356           newR2.h = r.h - newR.h;
357           boxSplit(newR2, z, end, -1, rl);
358           return;
359         }
360       }
361
362       if (boxes[z]->area.x > r.x)
363       {
364 //        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);
365         Region newR;
366         newR.x = r.x;
367         newR.y = top;
368         newR.w = boxes[z]->area.x - r.x;
369         newR.h = btm - top + 1;
370         boxSplit(newR, z + direction, end, direction, rl);
371
372         if (direction == -1)
373         {
374           Region newR2;
375           newR2.x = r.x + newR.w;
376           newR2.y = r.y;
377           newR2.w = r.w - newR.w;
378           newR2.h = r.h;
379           boxSplit(newR2, z, end, -1, rl);
380           return;
381         }
382       }
383
384       if (boxes[z]->area.x2() < r.x2())
385       {
386 //        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);
387         Region newR;
388         newR.x = boxes[z]->area.x2() + 1;
389         newR.y = top;
390         newR.w = r.x2() - newR.x + 1;
391         newR.h = btm - top + 1;
392         boxSplit(newR, z + direction, end, direction, rl);
393
394         if (direction == -1)
395         {
396           Region newR2;
397           newR2.x = r.x;
398           newR2.y = r.y;
399           newR2.w = r.w - newR.w;
400           newR2.h = r.h;
401           boxSplit(newR2, z, end, -1, rl);
402           return;
403         }
404       }
405
406       if (direction == -1)
407       {
408         // we are going down the stack
409         // r is underlapped by boxes[z]
410         // but we have not split
411         // Therefore this region under test is
412         // completely covering boxes[z]
413
414         // don't go any further down, generate a region and quit
415
416 //        printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);
417         r.z = z;
418         rl.push_front(r);
419       }
420
421 //      printf("Returning from Z=%i\n", z);
422       return;
423     }
424     else
425     {
426 //      printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);
427     }
428   }
429
430   // if direction = 1 then we have come to a region that is
431   // entirely clear of higher boxes and needs to be redrawn
432
433   // if direction = -1 then we have come to a region that is on
434   // the very bottom with nothing below it to repaint.
435   // do nothing. stale window data will be left on screen?
436
437   if (direction == 1)
438   {
439     rl.push_front(r);
440   }
441 }
442
443 /////////////////////////////////////////////////////////////////////////////
444 // END NEW STUFF
445 /////////////////////////////////////////////////////////////////////////////
446
447 // ---------------------------------------------------- END OF REMOVE CODE
448
449
450 void BoxStack::removeAll()
451 {
452   // 1.. Don't delete wallpaper. No point.
453
454   // Need locking on this one??
455   
456   // This is pretty silly now that preDelete needs mutex unlocked
457   
458   Boxx* toDel = NULL;
459   VideoDisplay *display = NULL;
460   
461   while(numBoxes > 1)
462   {
463     boxLock.Lock(); 
464
465     if (numBoxes == 1)
466     {
467       boxLock.Unlock();
468       break;
469     }    
470   
471     toDel = boxes[numBoxes - 1];
472
473     boxLock.Unlock();
474
475     toDel->preDelete();
476     
477     boxLock.Lock();
478
479     // If boxes[numBoxes - 1] isn't toDel then there's a problem
480     if (boxes[numBoxes - 1] == toDel)
481     {
482       --numBoxes;
483     }
484     else
485     {
486       Log::getInstance()->log("BoxStack", Log::ERR, "Can this actually happen? Why?");
487       toDel = NULL;
488     }
489
490     if (!videoStack.empty() && videoStack.top().first==toDel) {
491         videoStack.pop();
492         if (!videoStack.empty()) display=&videoStack.top().second;
493     }
494     boxLock.Unlock();
495
496     //AVO: do the delete outside the lock to allow for recursive deletes
497     Log::getInstance()->log("BoxStack", Log::DEBUG, "going to delete boxx %p, num=%d", toDel, numBoxes);
498     if (display) Video::getInstance()->setVideoDisplay(*display);
499
500
501     if (toDel) delete toDel;
502   }
503
504
505 }
506
507 int BoxStack::handleCommand(int command)
508 {
509   int retVal;
510   int retVal2 = 0;
511   int i;
512
513   if (command != Remote::NA_NONE)
514   {
515     // handle command return values
516     // 0 - drop through to next box
517     // 1 - dont drop to next box, but not handled
518     // 2 - handled - stop command here
519     // 4 - handled - delete this box
520
521     for (i=numBoxes-1; i>=0; i--)
522     {
523 //      Log::getInstance()->log("BoxStack", Log::DEBUG, "Giving command to i=%i", i);
524       retVal = boxes[i]->handleCommand(command);
525       if (retVal == 1)
526       {
527         // not handled but don't give to any more boxes
528         return 0;
529       }
530
531       if (retVal == 2)
532       {
533         // command handled
534         retVal2 = 1;
535         break;
536       }
537       else if (retVal == 4)
538       {
539 //        Log::getInstance()->log("BoxStack", Log::DEBUG, "Return 4: i=%i, boxes[i]=%p", i, boxes[i]);
540         remove(boxes[i]);
541         retVal2 = 1;
542         break;
543       }
544     }
545   }
546   else
547   {
548     // fake the return code
549     retVal2 = 2;
550   }
551
552   return retVal2;
553 }
554
555 void BoxStack::processMessage(Message* m)
556 {
557   if (m->to != this)
558   {
559     for (int i = numBoxes-1; i >= 0; i--)
560     {
561       if (boxes[i] == m->to)
562       {
563         Log::getInstance()->log("BoxStack", Log::DEBUG, "sending message from box %p to box %p %lu", m->from, m->to, m->message);
564         boxes[i]->processMessage(m);
565         return;
566       }
567     }
568     return;
569   }
570
571   /* Handle mouse events*/
572   // They come in with m->to = NULL? and just need to be delivered to top box?
573   if ((numBoxes > 1) && ((m->message == Message::MOUSE_MOVE) || (m->message == Message::MOUSE_LBDOWN)
574                   || (m->message == Message::MOUSE_ANDROID_SCROLL)))
575   {
576     boxes[numBoxes-1]->processMessage(m);
577     return;
578   }
579
580   Log::getInstance()->log("BoxStack", Log::DEBUG, "it's for meeee!");
581
582   switch(m->message)
583   {
584     case Message::CLOSE_ME:
585     {
586       remove((Boxx*)m->from);
587       break;
588     }
589     case Message::ADD_VIEW: // currently not used by anything but it might come in useful again
590     {
591       Boxx* toAdd = (Boxx*)m->parameter;
592       add(toAdd);
593       toAdd->draw();
594       update(toAdd);
595       break;
596     }
597   }
598 }