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