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