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