Merge remote branch 'remotes/origin/fantempplugin'
[enigma2.git] / lib / gdi / grc.cpp
1 #include <unistd.h>
2 #include <lib/gdi/grc.h>
3 #include <lib/gdi/font.h>
4 #include <lib/base/init.h>
5 #include <lib/base/init_num.h>
6
7 #ifndef SYNC_PAINT
8 void *gRC::thread_wrapper(void *ptr)
9 {
10         return ((gRC*)ptr)->thread();
11 }
12 #endif
13
14 gRC *gRC::instance=0;
15
16 gRC::gRC(): rp(0), wp(0)
17 #ifdef SYNC_PAINT
18 ,m_notify_pump(eApp, 0)
19 #else
20 ,m_notify_pump(eApp, 1)
21 #endif
22 {
23         ASSERT(!instance);
24         instance=this;
25         CONNECT(m_notify_pump.recv_msg, gRC::recv_notify);
26 #ifndef SYNC_PAINT
27         pthread_mutex_init(&mutex, 0);
28         pthread_cond_init(&cond, 0);
29         int res = pthread_create(&the_thread, 0, thread_wrapper, this);
30         if (res)
31                 eFatal("RC thread couldn't be created");
32         else
33                 eDebug("RC thread created successfully");
34 #endif
35         m_spinner_enabled = 0;
36 }
37
38 DEFINE_REF(gRC);
39
40 gRC::~gRC()
41 {
42         instance=0;
43
44         gOpcode o;
45         o.opcode=gOpcode::shutdown;
46         submit(o);
47 #ifndef SYNC_PAINT
48         eDebug("waiting for gRC thread shutdown");
49         pthread_join(the_thread, 0);
50         eDebug("gRC thread has finished");
51 #endif
52 }
53
54 void gRC::submit(const gOpcode &o)
55 {
56         while(1)
57         {
58 #ifndef SYNC_PAINT
59                 pthread_mutex_lock(&mutex);
60 #endif
61                 int tmp=wp+1;
62                 if ( tmp == MAXSIZE )
63                         tmp=0;
64                 if ( tmp == rp )
65                 {
66 #ifndef SYNC_PAINT
67                         pthread_cond_signal(&cond);  // wakeup gdi thread
68                         pthread_mutex_unlock(&mutex);
69 #else
70                         thread();
71 #endif
72                         //printf("render buffer full...\n");
73                         //fflush(stdout);
74                         usleep(1000);  // wait 1 msec
75                         continue;
76                 }
77                 int free=rp-wp;
78                 if ( free <= 0 )
79                         free+=MAXSIZE;
80                 queue[wp++]=o;
81                 if ( wp == MAXSIZE )
82                         wp = 0;
83                 if (o.opcode==gOpcode::flush||o.opcode==gOpcode::shutdown||o.opcode==gOpcode::notify)
84 #ifndef SYNC_PAINT
85                         pthread_cond_signal(&cond);  // wakeup gdi thread
86                 pthread_mutex_unlock(&mutex);
87 #else
88                         thread(); // paint
89 #endif
90                 break;
91         }
92 }
93
94 void *gRC::thread()
95 {
96         int need_notify = 0;
97 #ifndef SYNC_PAINT
98         while (1)
99         {
100 #else
101         while (rp != wp)
102         {
103 #endif
104 #ifndef SYNC_PAINT
105                 pthread_mutex_lock(&mutex);
106 #endif
107                 if ( rp != wp )
108                 {
109                                 /* make sure the spinner is not displayed when we something is painted */
110                         disableSpinner();
111
112                         gOpcode o(queue[rp++]);
113                         if ( rp == MAXSIZE )
114                                 rp=0;
115 #ifndef SYNC_PAINT
116                         pthread_mutex_unlock(&mutex);
117 #endif
118                         if (o.opcode==gOpcode::shutdown)
119                                 break;
120                         else if (o.opcode==gOpcode::notify)
121                                 need_notify = 1;
122                         else if (o.opcode==gOpcode::setCompositing)
123                         {
124                                 m_compositing = o.parm.setCompositing;
125                                 m_compositing->Release();
126                         } else if(o.dc)
127                         {
128                                 o.dc->exec(&o);
129                                 // o.dc is a gDC* filled with grabref... so we must release it here
130                                 o.dc->Release();
131                         }
132                 }
133                 else
134                 {
135                         if (need_notify)
136                         {
137                                 need_notify = 0;
138                                 m_notify_pump.send(1);
139                         }
140 #ifndef SYNC_PAINT
141                         while(rp == wp)
142                         {
143                         
144                                         /* when the main thread is non-idle for a too long time without any display output,
145                                            we want to display a spinner. */
146                                 struct timespec timeout;
147                                 clock_gettime(CLOCK_REALTIME, &timeout);
148
149                                 if (m_spinner_enabled)
150                                 {
151                                         timeout.tv_nsec += 100*1000*1000;
152                                         /* yes, this is required. */
153                                         if (timeout.tv_nsec > 1000*1000*1000)
154                                         {
155                                                 timeout.tv_nsec -= 1000*1000*1000;
156                                                 timeout.tv_sec++;
157                                         }
158                                 }
159                                 else
160                                         timeout.tv_sec += 2;
161
162                                 int idle = 1;
163
164                                 if (pthread_cond_timedwait(&cond, &mutex, &timeout) == ETIMEDOUT)
165                                 {
166                                         if (eApp && !eApp->isIdle())
167                                                 idle = 0;
168                                 }
169
170                                 if (!idle)
171                                 {
172                                         if (!m_spinner_enabled)
173                                                 eDebug("main thread is non-idle! display spinner!");
174                                         enableSpinner();
175                                 } else
176                                         disableSpinner();
177                         }
178                         pthread_mutex_unlock(&mutex);
179 #endif
180                 }
181         }
182 #ifndef SYNC_PAINT
183         pthread_exit(0);
184 #endif
185         return 0;
186 }
187
188 void gRC::recv_notify(const int &i)
189 {
190         notify();
191 }
192
193 gRC *gRC::getInstance()
194 {
195         return instance;
196 }
197
198 void gRC::enableSpinner()
199 {
200         if (!m_spinner_dc)
201         {
202                 eDebug("no spinner DC!");
203                 return;
204         }
205
206         gOpcode o;
207         o.opcode = m_spinner_enabled ? gOpcode::incrementSpinner : gOpcode::enableSpinner;
208         m_spinner_dc->exec(&o);
209         m_spinner_enabled = 1;
210         o.opcode = gOpcode::flush;
211         m_spinner_dc->exec(&o);
212 }
213
214 void gRC::disableSpinner()
215 {
216         if (!m_spinner_enabled)
217                 return;
218
219         if (!m_spinner_dc)
220         {
221                 eDebug("no spinner DC!");
222                 return;
223         }
224
225         m_spinner_enabled = 0;
226         
227         gOpcode o;
228         o.opcode = gOpcode::disableSpinner;
229         m_spinner_dc->exec(&o);
230         o.opcode = gOpcode::flush;
231         m_spinner_dc->exec(&o);
232 }
233
234 static int gPainter_instances;
235
236 gPainter::gPainter(gDC *dc, eRect rect): m_dc(dc), m_rc(gRC::getInstance())
237 {
238 //      ASSERT(!gPainter_instances);
239         gPainter_instances++;
240 //      begin(rect);
241 }
242
243 gPainter::~gPainter()
244 {
245         end();
246         gPainter_instances--;
247 }
248
249 void gPainter::setBackgroundColor(const gColor &color)
250 {
251         if ( m_dc->islocked() )
252                 return;
253         gOpcode o;
254         o.opcode = gOpcode::setBackgroundColor;
255         o.dc = m_dc.grabRef();
256         o.parm.setColor = new gOpcode::para::psetColor;
257         o.parm.setColor->color = color;
258
259         m_rc->submit(o);
260 }
261
262 void gPainter::setForegroundColor(const gColor &color)
263 {
264         if ( m_dc->islocked() )
265                 return;
266         gOpcode o;
267         o.opcode = gOpcode::setForegroundColor;
268         o.dc = m_dc.grabRef();
269         o.parm.setColor = new gOpcode::para::psetColor;
270         o.parm.setColor->color = color;
271
272         m_rc->submit(o);
273 }
274
275 void gPainter::setBackgroundColor(const gRGB &color)
276 {
277         if ( m_dc->islocked() )
278                 return;
279         gOpcode o;
280         o.opcode = gOpcode::setBackgroundColorRGB;
281         o.dc = m_dc.grabRef();
282         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
283         o.parm.setColorRGB->color = color;
284
285         m_rc->submit(o);
286 }
287
288 void gPainter::setForegroundColor(const gRGB &color)
289 {
290         if ( m_dc->islocked() )
291                 return;
292         gOpcode o;
293         o.opcode = gOpcode::setForegroundColorRGB;
294         o.dc = m_dc.grabRef();
295         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
296         o.parm.setColorRGB->color = color;
297
298         m_rc->submit(o);
299 }
300
301 void gPainter::setFont(gFont *font)
302 {
303         if ( m_dc->islocked() )
304                 return;
305         gOpcode o;
306         o.opcode = gOpcode::setFont;
307         o.dc = m_dc.grabRef();
308         font->AddRef();
309         o.parm.setFont = new gOpcode::para::psetFont;
310         o.parm.setFont->font = font;
311
312         m_rc->submit(o);
313 }
314
315 void gPainter::renderText(const eRect &pos, const std::string &string, int flags)
316 {
317         if ( m_dc->islocked() )
318                 return;
319         gOpcode o;
320         o.opcode=gOpcode::renderText;
321         o.dc = m_dc.grabRef();
322         o.parm.renderText = new gOpcode::para::prenderText;
323         o.parm.renderText->area = pos;
324         o.parm.renderText->text = string.empty()?0:strdup(string.c_str());
325         o.parm.renderText->flags = flags;
326         m_rc->submit(o);
327 }
328
329 void gPainter::renderPara(eTextPara *para, ePoint offset)
330 {
331         if ( m_dc->islocked() )
332                 return;
333         ASSERT(para);
334         gOpcode o;
335         o.opcode=gOpcode::renderPara;
336         o.dc = m_dc.grabRef();
337         o.parm.renderPara = new gOpcode::para::prenderPara;
338         o.parm.renderPara->offset = offset;
339
340         para->AddRef();
341         o.parm.renderPara->textpara = para;
342         m_rc->submit(o);
343 }
344
345 void gPainter::fill(const eRect &area)
346 {
347         if ( m_dc->islocked() )
348                 return;
349         gOpcode o;
350         o.opcode=gOpcode::fill;
351
352         o.dc = m_dc.grabRef();
353         o.parm.fill = new gOpcode::para::pfillRect;
354         o.parm.fill->area = area;
355         m_rc->submit(o);
356 }
357
358 void gPainter::fill(const gRegion &region)
359 {
360         if ( m_dc->islocked() )
361                 return;
362         gOpcode o;
363         o.opcode=gOpcode::fillRegion;
364
365         o.dc = m_dc.grabRef();
366         o.parm.fillRegion = new gOpcode::para::pfillRegion;
367         o.parm.fillRegion->region = region;
368         m_rc->submit(o);
369 }
370
371 void gPainter::clear()
372 {
373         if ( m_dc->islocked() )
374                 return;
375         gOpcode o;
376         o.opcode=gOpcode::clear;
377         o.dc = m_dc.grabRef();
378         o.parm.fill = new gOpcode::para::pfillRect;
379         o.parm.fill->area = eRect();
380         m_rc->submit(o);
381 }
382
383 void gPainter::blit(gPixmap *pixmap, ePoint pos, const eRect &clip, int flags)
384 {
385         blitScale(pixmap, eRect(pos, eSize()), clip, flags, 0);
386 }
387
388 void gPainter::blitScale(gPixmap *pixmap, const eRect &position, const eRect &clip, int flags, int aflags)
389 {
390         flags |= aflags;
391
392         if ( m_dc->islocked() )
393                 return;
394         gOpcode o;
395
396         ASSERT(pixmap);
397
398         o.opcode=gOpcode::blit;
399         o.dc = m_dc.grabRef();
400         pixmap->AddRef();
401         o.parm.blit  = new gOpcode::para::pblit;
402         o.parm.blit->pixmap = pixmap;
403         o.parm.blit->clip = clip;
404         o.parm.blit->flags = flags;
405         o.parm.blit->position = position;
406         m_rc->submit(o);
407 }
408
409 void gPainter::setPalette(gRGB *colors, int start, int len)
410 {
411         if ( m_dc->islocked() )
412                 return;
413         ASSERT(colors);
414         gOpcode o;
415         o.opcode=gOpcode::setPalette;
416         o.dc = m_dc.grabRef();
417         gPalette *p=new gPalette;
418
419         o.parm.setPalette = new gOpcode::para::psetPalette;
420         p->data=new gRGB[len];
421
422         memcpy(p->data, colors, len*sizeof(gRGB));
423         p->start=start;
424         p->colors=len;
425         o.parm.setPalette->palette = p;
426         m_rc->submit(o);
427 }
428
429 void gPainter::setPalette(gPixmap *source)
430 {
431         ASSERT(source);
432         setPalette(source->surface->clut.data, source->surface->clut.start, source->surface->clut.colors);
433 }
434
435 void gPainter::mergePalette(gPixmap *target)
436 {
437         if ( m_dc->islocked() )
438                 return;
439         ASSERT(target);
440         gOpcode o;
441         o.opcode = gOpcode::mergePalette;
442         o.dc = m_dc.grabRef();
443         target->AddRef();
444         o.parm.mergePalette = new gOpcode::para::pmergePalette;
445         o.parm.mergePalette->target = target;
446         m_rc->submit(o);
447 }
448
449 void gPainter::line(ePoint start, ePoint end)
450 {
451         if ( m_dc->islocked() )
452                 return;
453         gOpcode o;
454         o.opcode=gOpcode::line;
455         o.dc = m_dc.grabRef();
456         o.parm.line = new gOpcode::para::pline;
457         o.parm.line->start = start;
458         o.parm.line->end = end;
459         m_rc->submit(o);
460 }
461
462 void gPainter::setOffset(ePoint val)
463 {
464         if ( m_dc->islocked() )
465                 return;
466         gOpcode o;
467         o.opcode=gOpcode::setOffset;
468         o.dc = m_dc.grabRef();
469         o.parm.setOffset = new gOpcode::para::psetOffset;
470         o.parm.setOffset->rel = 0;
471         o.parm.setOffset->value = val;
472         m_rc->submit(o);
473 }
474
475 void gPainter::moveOffset(ePoint rel)
476 {
477         if ( m_dc->islocked() )
478                 return;
479         gOpcode o;
480         o.opcode=gOpcode::setOffset;
481         o.dc = m_dc.grabRef();
482         o.parm.setOffset = new gOpcode::para::psetOffset;
483         o.parm.setOffset->rel = 1;
484         o.parm.setOffset->value = rel;
485         m_rc->submit(o);
486 }
487
488 void gPainter::resetOffset()
489 {
490         if ( m_dc->islocked() )
491                 return;
492         gOpcode o;
493         o.opcode=gOpcode::setOffset;
494         o.dc = m_dc.grabRef();
495         o.parm.setOffset = new gOpcode::para::psetOffset;
496         o.parm.setOffset->rel = 0;
497         o.parm.setOffset->value = ePoint(0, 0);
498         m_rc->submit(o);
499 }
500
501 void gPainter::resetClip(const gRegion &region)
502 {
503         if ( m_dc->islocked() )
504                 return;
505         gOpcode o;
506         o.opcode = gOpcode::setClip;
507         o.dc = m_dc.grabRef();
508         o.parm.clip = new gOpcode::para::psetClip;
509         o.parm.clip->region = region;
510         m_rc->submit(o);
511 }
512
513 void gPainter::clip(const gRegion &region)
514 {
515         if ( m_dc->islocked() )
516                 return;
517         gOpcode o;
518         o.opcode = gOpcode::addClip;
519         o.dc = m_dc.grabRef();
520         o.parm.clip = new gOpcode::para::psetClip;
521         o.parm.clip->region = region;
522         m_rc->submit(o);
523 }
524
525 void gPainter::clippop()
526 {
527         if ( m_dc->islocked() )
528                 return;
529         gOpcode o;
530         o.opcode = gOpcode::popClip;
531         o.dc = m_dc.grabRef();
532         m_rc->submit(o);
533 }
534
535 void gPainter::waitVSync()
536 {
537         if ( m_dc->islocked() )
538                 return;
539         gOpcode o;
540         o.opcode = gOpcode::waitVSync;
541         o.dc = m_dc.grabRef();
542         m_rc->submit(o);
543 }
544
545 void gPainter::flip()
546 {
547         if ( m_dc->islocked() )
548                 return;
549         gOpcode o;
550         o.opcode = gOpcode::flip;
551         o.dc = m_dc.grabRef();
552         m_rc->submit(o);
553 }
554
555 void gPainter::notify()
556 {
557         if ( m_dc->islocked() )
558                 return;
559         gOpcode o;
560         o.opcode = gOpcode::notify;
561         o.dc = m_dc.grabRef();
562         m_rc->submit(o);
563 }
564
565 void gPainter::setCompositing(gCompositingData *comp)
566 {
567         gOpcode o;
568         o.opcode = gOpcode::setCompositing;
569         o.dc = 0;
570         o.parm.setCompositing = comp;
571         comp->AddRef(); /* will be freed in ::thread */
572         m_rc->submit(o);
573 }
574
575 void gPainter::flush()
576 {
577         if ( m_dc->islocked() )
578                 return;
579         gOpcode o;
580         o.opcode = gOpcode::flush;
581         o.dc = m_dc.grabRef();
582         m_rc->submit(o);
583 }
584
585 void gPainter::end()
586 {
587         if ( m_dc->islocked() )
588                 return;
589 }
590
591 gDC::gDC()
592 {
593         m_spinner_pic = 0;
594 }
595
596 gDC::gDC(gPixmap *pixmap): m_pixmap(pixmap)
597 {
598         m_spinner_pic = 0;
599 }
600
601 gDC::~gDC()
602 {
603         delete[] m_spinner_pic;
604 }
605
606 void gDC::exec(gOpcode *o)
607 {
608         switch (o->opcode)
609         {
610         case gOpcode::setBackgroundColor:
611                 m_background_color = o->parm.setColor->color;
612                 m_background_color_rgb = getRGB(m_background_color);
613                 delete o->parm.setColor;
614                 break;
615         case gOpcode::setForegroundColor:
616                 m_foreground_color = o->parm.setColor->color;
617                 m_background_color_rgb = getRGB(m_foreground_color);
618                 delete o->parm.setColor;
619                 break;
620         case gOpcode::setBackgroundColorRGB:
621                 if (m_pixmap->needClut())
622                         m_background_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
623                 m_background_color_rgb = o->parm.setColorRGB->color;
624                 delete o->parm.setColorRGB;
625                 break;
626         case gOpcode::setForegroundColorRGB:
627                 if (m_pixmap->needClut())
628                         m_foreground_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
629                 m_foreground_color_rgb = o->parm.setColorRGB->color;
630                 delete o->parm.setColorRGB;
631                 break;
632         case gOpcode::setFont:
633                 m_current_font = o->parm.setFont->font;
634                 o->parm.setFont->font->Release();
635                 delete o->parm.setFont;
636                 break;
637         case gOpcode::renderText:
638         {
639                 ePtr<eTextPara> para = new eTextPara(o->parm.renderText->area);
640                 int flags = o->parm.renderText->flags;
641                 ASSERT(m_current_font);
642                 para->setFont(m_current_font);
643                 para->renderString(o->parm.renderText->text, (flags & gPainter::RT_WRAP) ? RS_WRAP : 0);
644                 if (o->parm.renderText->text)
645                         free(o->parm.renderText->text);
646                 if (flags & gPainter::RT_HALIGN_RIGHT)
647                         para->realign(eTextPara::dirRight);
648                 else if (flags & gPainter::RT_HALIGN_CENTER)
649                         para->realign(eTextPara::dirCenter);
650                 else if (flags & gPainter::RT_HALIGN_BLOCK)
651                         para->realign(eTextPara::dirBlock);
652                 
653                 ePoint offset = m_current_offset;
654                 
655                 if (o->parm.renderText->flags & gPainter::RT_VALIGN_CENTER)
656                 {
657                         eRect bbox = para->getBoundBox();
658                         int vcentered_top = o->parm.renderText->area.top() + ((o->parm.renderText->area.height() - bbox.height()) / 2);
659                         int correction = vcentered_top - bbox.top();
660                         offset += ePoint(0, correction);
661                 }
662                 
663                 para->blit(*this, offset, m_background_color_rgb, m_foreground_color_rgb);
664                 delete o->parm.renderText;
665                 break;
666         }
667         case gOpcode::renderPara:
668         {
669                 o->parm.renderPara->textpara->blit(*this, o->parm.renderPara->offset + m_current_offset, m_background_color_rgb, m_foreground_color_rgb);
670                 o->parm.renderPara->textpara->Release();
671                 delete o->parm.renderPara;
672                 break;
673         }
674         case gOpcode::fill:
675         {
676                 eRect area = o->parm.fill->area;
677                 area.moveBy(m_current_offset);
678                 gRegion clip = m_current_clip & area;
679                 if (m_pixmap->needClut())
680                         m_pixmap->fill(clip, m_foreground_color);
681                 else
682                         m_pixmap->fill(clip, m_foreground_color_rgb);
683                 delete o->parm.fill;
684                 break;
685         }
686         case gOpcode::fillRegion:
687         {
688                 o->parm.fillRegion->region.moveBy(m_current_offset);
689                 gRegion clip = m_current_clip & o->parm.fillRegion->region;
690                 if (m_pixmap->needClut())
691                         m_pixmap->fill(clip, m_foreground_color);
692                 else
693                         m_pixmap->fill(clip, m_foreground_color_rgb);
694                 delete o->parm.fillRegion;
695                 break;
696         }
697         case gOpcode::clear:
698                 if (m_pixmap->needClut())
699                         m_pixmap->fill(m_current_clip, m_background_color);
700                 else
701                         m_pixmap->fill(m_current_clip, m_background_color_rgb);
702                 delete o->parm.fill;
703                 break;
704         case gOpcode::blit:
705         {
706                 gRegion clip;
707                                 // this code should be checked again but i'm too tired now
708                 
709                 o->parm.blit->position.moveBy(m_current_offset);
710                 
711                 if (o->parm.blit->clip.valid())
712                 {
713                         o->parm.blit->clip.moveBy(m_current_offset);
714                         clip.intersect(gRegion(o->parm.blit->clip), m_current_clip);
715                 } else
716                         clip = m_current_clip;
717                 
718                 m_pixmap->blit(*o->parm.blit->pixmap, o->parm.blit->position, clip, o->parm.blit->flags);
719                 o->parm.blit->pixmap->Release();
720                 delete o->parm.blit;
721                 break;
722         }
723         case gOpcode::setPalette:
724                 if (o->parm.setPalette->palette->start > m_pixmap->surface->clut.colors)
725                         o->parm.setPalette->palette->start = m_pixmap->surface->clut.colors;
726                 if (o->parm.setPalette->palette->colors > (m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start))
727                         o->parm.setPalette->palette->colors = m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start;
728                 if (o->parm.setPalette->palette->colors)
729                         memcpy(m_pixmap->surface->clut.data+o->parm.setPalette->palette->start, o->parm.setPalette->palette->data, o->parm.setPalette->palette->colors*sizeof(gRGB));
730                 
731                 delete[] o->parm.setPalette->palette->data;
732                 delete o->parm.setPalette->palette;
733                 delete o->parm.setPalette;
734                 break;
735         case gOpcode::mergePalette:
736                 m_pixmap->mergePalette(*o->parm.mergePalette->target);
737                 o->parm.mergePalette->target->Release();
738                 delete o->parm.mergePalette;
739                 break; 
740         case gOpcode::line:
741         {
742                 ePoint start = o->parm.line->start + m_current_offset, end = o->parm.line->end + m_current_offset;
743                 m_pixmap->line(m_current_clip, start, end, m_foreground_color);
744                 delete o->parm.line;
745                 break;
746         }
747         case gOpcode::addClip:
748                 m_clip_stack.push(m_current_clip);
749                 o->parm.clip->region.moveBy(m_current_offset);
750                 m_current_clip &= o->parm.clip->region;
751                 delete o->parm.clip;
752                 break;
753         case gOpcode::setClip:
754                 o->parm.clip->region.moveBy(m_current_offset);
755                 m_current_clip = o->parm.clip->region & eRect(ePoint(0, 0), m_pixmap->size());
756                 delete o->parm.clip;
757                 break;
758         case gOpcode::popClip:
759                 if (!m_clip_stack.empty())
760                 {
761                         m_current_clip = m_clip_stack.top();
762                         m_clip_stack.pop();
763                 }
764                 break;
765         case gOpcode::setOffset:
766                 if (o->parm.setOffset->rel)
767                         m_current_offset += o->parm.setOffset->value;
768                 else
769                         m_current_offset  = o->parm.setOffset->value;
770                 delete o->parm.setOffset;
771                 break;
772         case gOpcode::waitVSync:
773                 break;
774         case gOpcode::flip:
775                 break;
776         case gOpcode::flush:
777                 break;
778         case gOpcode::enableSpinner:
779                 enableSpinner();
780                 break;
781         case gOpcode::disableSpinner:
782                 disableSpinner();
783                 break;
784         case gOpcode::incrementSpinner:
785                 incrementSpinner();
786                 break;
787         default:
788                 eFatal("illegal opcode %d. expect memory leak!", o->opcode);
789         }
790 }
791
792 gRGB gDC::getRGB(gColor col)
793 {
794         if ((!m_pixmap) || (!m_pixmap->surface->clut.data))
795                 return gRGB(col, col, col);
796         if (col<0)
797         {
798                 eFatal("bla transp");
799                 return gRGB(0, 0, 0, 0xFF);
800         }
801         return m_pixmap->surface->clut.data[col];
802 }
803
804 void gDC::enableSpinner()
805 {
806         ASSERT(m_spinner_saved);
807         
808                 /* save the background to restore it later. We need to negative position because we want to blit from the middle of the screen. */
809         m_spinner_saved->blit(*m_pixmap, eRect(-m_spinner_pos.topLeft(), eSize()), gRegion(eRect(ePoint(0, 0), m_spinner_saved->size())), 0);
810         
811         incrementSpinner();
812 }
813
814 void gDC::disableSpinner()
815 {
816         ASSERT(m_spinner_saved);
817
818                 /* restore background */
819         m_pixmap->blit(*m_spinner_saved, eRect(m_spinner_pos.topLeft(), eSize()), gRegion(m_spinner_pos), 0);
820 }
821
822 void gDC::incrementSpinner()
823 {
824         ASSERT(m_spinner_saved);
825         
826         static int blub;
827         blub++;
828
829 #if 0
830         int i;
831         
832         for (i = 0; i < 5; ++i)
833         {
834                 int x = i * 20 + m_spinner_pos.left();
835                 int y = m_spinner_pos.top();
836                 
837                 int col = ((blub - i) * 30) % 256;
838
839                 m_pixmap->fill(eRect(x, y, 10, 10), gRGB(col, col, col));
840         }
841 #endif
842
843         m_spinner_temp->blit(*m_spinner_saved, eRect(0, 0, 0, 0), eRect(ePoint(0, 0), m_spinner_pos.size()));
844
845         if (m_spinner_pic[m_spinner_i])
846                 m_spinner_temp->blit(*m_spinner_pic[m_spinner_i], eRect(0, 0, 0, 0), eRect(ePoint(0, 0), m_spinner_pos.size()), gPixmap::blitAlphaTest);
847
848         m_pixmap->blit(*m_spinner_temp, eRect(m_spinner_pos.topLeft(), eSize()), gRegion(m_spinner_pos), 0);
849         m_spinner_i++;
850         m_spinner_i %= m_spinner_num;
851 }
852
853 void gDC::setSpinner(eRect pos, ePtr<gPixmap> *pic, int len)
854 {
855         ASSERT(m_pixmap);
856         ASSERT(m_pixmap->surface);
857         m_spinner_saved = new gPixmap(pos.size(), m_pixmap->surface->bpp);
858         m_spinner_temp = new gPixmap(pos.size(), m_pixmap->surface->bpp);
859         m_spinner_pos = pos;
860         
861         m_spinner_i = 0;
862         m_spinner_num = len;
863         
864         int i;
865         if (m_spinner_pic)
866                 delete[] m_spinner_pic;
867         
868         m_spinner_pic = new ePtr<gPixmap>[len];
869         
870         for (i = 0; i < len; ++i)
871                 m_spinner_pic[i] = pic[i];
872 }
873
874 DEFINE_REF(gDC);
875
876 eAutoInitPtr<gRC> init_grc(eAutoInitNumbers::graphic, "gRC");