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