Merge remote branch 'remotes/origin/bug_620_dvdburn_absolutepaths'
[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                                         {
168                                                 int idle_count = eApp->idleCount();
169                                                 if (idle_count == m_prev_idle_count)
170                                                         idle = 0;
171                                                 else
172                                                         m_prev_idle_count = idle_count;
173                                         }
174                                 }
175
176                                 if (!idle)
177                                 {
178                                         if (!m_spinner_enabled)
179                                                 eDebug("main thread is non-idle! display spinner!");
180                                         enableSpinner();
181                                 } else
182                                         disableSpinner();
183                         }
184                         pthread_mutex_unlock(&mutex);
185 #endif
186                 }
187         }
188 #ifndef SYNC_PAINT
189         pthread_exit(0);
190 #endif
191         return 0;
192 }
193
194 void gRC::recv_notify(const int &i)
195 {
196         notify();
197 }
198
199 gRC *gRC::getInstance()
200 {
201         return instance;
202 }
203
204 void gRC::enableSpinner()
205 {
206         if (!m_spinner_dc)
207         {
208                 eDebug("no spinner DC!");
209                 return;
210         }
211
212         gOpcode o;
213         o.opcode = m_spinner_enabled ? gOpcode::incrementSpinner : gOpcode::enableSpinner;
214         m_spinner_dc->exec(&o);
215         m_spinner_enabled = 1;
216         o.opcode = gOpcode::flush;
217         m_spinner_dc->exec(&o);
218 }
219
220 void gRC::disableSpinner()
221 {
222         if (!m_spinner_enabled)
223                 return;
224
225         if (!m_spinner_dc)
226         {
227                 eDebug("no spinner DC!");
228                 return;
229         }
230
231         m_spinner_enabled = 0;
232         
233         gOpcode o;
234         o.opcode = gOpcode::disableSpinner;
235         m_spinner_dc->exec(&o);
236         o.opcode = gOpcode::flush;
237         m_spinner_dc->exec(&o);
238 }
239
240 static int gPainter_instances;
241
242 gPainter::gPainter(gDC *dc, eRect rect): m_dc(dc), m_rc(gRC::getInstance())
243 {
244 //      ASSERT(!gPainter_instances);
245         gPainter_instances++;
246 //      begin(rect);
247 }
248
249 gPainter::~gPainter()
250 {
251         end();
252         gPainter_instances--;
253 }
254
255 void gPainter::setBackgroundColor(const gColor &color)
256 {
257         if ( m_dc->islocked() )
258                 return;
259         gOpcode o;
260         o.opcode = gOpcode::setBackgroundColor;
261         o.dc = m_dc.grabRef();
262         o.parm.setColor = new gOpcode::para::psetColor;
263         o.parm.setColor->color = color;
264
265         m_rc->submit(o);
266 }
267
268 void gPainter::setForegroundColor(const gColor &color)
269 {
270         if ( m_dc->islocked() )
271                 return;
272         gOpcode o;
273         o.opcode = gOpcode::setForegroundColor;
274         o.dc = m_dc.grabRef();
275         o.parm.setColor = new gOpcode::para::psetColor;
276         o.parm.setColor->color = color;
277
278         m_rc->submit(o);
279 }
280
281 void gPainter::setBackgroundColor(const gRGB &color)
282 {
283         if ( m_dc->islocked() )
284                 return;
285         gOpcode o;
286         o.opcode = gOpcode::setBackgroundColorRGB;
287         o.dc = m_dc.grabRef();
288         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
289         o.parm.setColorRGB->color = color;
290
291         m_rc->submit(o);
292 }
293
294 void gPainter::setForegroundColor(const gRGB &color)
295 {
296         if ( m_dc->islocked() )
297                 return;
298         gOpcode o;
299         o.opcode = gOpcode::setForegroundColorRGB;
300         o.dc = m_dc.grabRef();
301         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
302         o.parm.setColorRGB->color = color;
303
304         m_rc->submit(o);
305 }
306
307 void gPainter::setFont(gFont *font)
308 {
309         if ( m_dc->islocked() )
310                 return;
311         gOpcode o;
312         o.opcode = gOpcode::setFont;
313         o.dc = m_dc.grabRef();
314         font->AddRef();
315         o.parm.setFont = new gOpcode::para::psetFont;
316         o.parm.setFont->font = font;
317
318         m_rc->submit(o);
319 }
320
321 void gPainter::renderText(const eRect &pos, const std::string &string, int flags)
322 {
323         if ( m_dc->islocked() )
324                 return;
325         gOpcode o;
326         o.opcode=gOpcode::renderText;
327         o.dc = m_dc.grabRef();
328         o.parm.renderText = new gOpcode::para::prenderText;
329         o.parm.renderText->area = pos;
330         o.parm.renderText->text = string.empty()?0:strdup(string.c_str());
331         o.parm.renderText->flags = flags;
332         m_rc->submit(o);
333 }
334
335 void gPainter::renderPara(eTextPara *para, ePoint offset)
336 {
337         if ( m_dc->islocked() )
338                 return;
339         ASSERT(para);
340         gOpcode o;
341         o.opcode=gOpcode::renderPara;
342         o.dc = m_dc.grabRef();
343         o.parm.renderPara = new gOpcode::para::prenderPara;
344         o.parm.renderPara->offset = offset;
345
346         para->AddRef();
347         o.parm.renderPara->textpara = para;
348         m_rc->submit(o);
349 }
350
351 void gPainter::fill(const eRect &area)
352 {
353         if ( m_dc->islocked() )
354                 return;
355         gOpcode o;
356         o.opcode=gOpcode::fill;
357
358         o.dc = m_dc.grabRef();
359         o.parm.fill = new gOpcode::para::pfillRect;
360         o.parm.fill->area = area;
361         m_rc->submit(o);
362 }
363
364 void gPainter::fill(const gRegion &region)
365 {
366         if ( m_dc->islocked() )
367                 return;
368         gOpcode o;
369         o.opcode=gOpcode::fillRegion;
370
371         o.dc = m_dc.grabRef();
372         o.parm.fillRegion = new gOpcode::para::pfillRegion;
373         o.parm.fillRegion->region = region;
374         m_rc->submit(o);
375 }
376
377 void gPainter::clear()
378 {
379         if ( m_dc->islocked() )
380                 return;
381         gOpcode o;
382         o.opcode=gOpcode::clear;
383         o.dc = m_dc.grabRef();
384         o.parm.fill = new gOpcode::para::pfillRect;
385         o.parm.fill->area = eRect();
386         m_rc->submit(o);
387 }
388
389 void gPainter::blit(gPixmap *pixmap, ePoint pos, const eRect &clip, int flags)
390 {
391         blitScale(pixmap, eRect(pos, eSize()), clip, flags, 0);
392 }
393
394 void gPainter::blitScale(gPixmap *pixmap, const eRect &position, const eRect &clip, int flags, int aflags)
395 {
396         flags |= aflags;
397
398         if ( m_dc->islocked() )
399                 return;
400         gOpcode o;
401
402         ASSERT(pixmap);
403
404         o.opcode=gOpcode::blit;
405         o.dc = m_dc.grabRef();
406         pixmap->AddRef();
407         o.parm.blit  = new gOpcode::para::pblit;
408         o.parm.blit->pixmap = pixmap;
409         o.parm.blit->clip = clip;
410         o.parm.blit->flags = flags;
411         o.parm.blit->position = position;
412         m_rc->submit(o);
413 }
414
415 void gPainter::setPalette(gRGB *colors, int start, int len)
416 {
417         if ( m_dc->islocked() )
418                 return;
419         ASSERT(colors);
420         gOpcode o;
421         o.opcode=gOpcode::setPalette;
422         o.dc = m_dc.grabRef();
423         gPalette *p=new gPalette;
424
425         o.parm.setPalette = new gOpcode::para::psetPalette;
426         p->data=new gRGB[len];
427
428         memcpy(p->data, colors, len*sizeof(gRGB));
429         p->start=start;
430         p->colors=len;
431         o.parm.setPalette->palette = p;
432         m_rc->submit(o);
433 }
434
435 void gPainter::setPalette(gPixmap *source)
436 {
437         ASSERT(source);
438         setPalette(source->surface->clut.data, source->surface->clut.start, source->surface->clut.colors);
439 }
440
441 void gPainter::mergePalette(gPixmap *target)
442 {
443         if ( m_dc->islocked() )
444                 return;
445         ASSERT(target);
446         gOpcode o;
447         o.opcode = gOpcode::mergePalette;
448         o.dc = m_dc.grabRef();
449         target->AddRef();
450         o.parm.mergePalette = new gOpcode::para::pmergePalette;
451         o.parm.mergePalette->target = target;
452         m_rc->submit(o);
453 }
454
455 void gPainter::line(ePoint start, ePoint end)
456 {
457         if ( m_dc->islocked() )
458                 return;
459         gOpcode o;
460         o.opcode=gOpcode::line;
461         o.dc = m_dc.grabRef();
462         o.parm.line = new gOpcode::para::pline;
463         o.parm.line->start = start;
464         o.parm.line->end = end;
465         m_rc->submit(o);
466 }
467
468 void gPainter::setOffset(ePoint val)
469 {
470         if ( m_dc->islocked() )
471                 return;
472         gOpcode o;
473         o.opcode=gOpcode::setOffset;
474         o.dc = m_dc.grabRef();
475         o.parm.setOffset = new gOpcode::para::psetOffset;
476         o.parm.setOffset->rel = 0;
477         o.parm.setOffset->value = val;
478         m_rc->submit(o);
479 }
480
481 void gPainter::moveOffset(ePoint rel)
482 {
483         if ( m_dc->islocked() )
484                 return;
485         gOpcode o;
486         o.opcode=gOpcode::setOffset;
487         o.dc = m_dc.grabRef();
488         o.parm.setOffset = new gOpcode::para::psetOffset;
489         o.parm.setOffset->rel = 1;
490         o.parm.setOffset->value = rel;
491         m_rc->submit(o);
492 }
493
494 void gPainter::resetOffset()
495 {
496         if ( m_dc->islocked() )
497                 return;
498         gOpcode o;
499         o.opcode=gOpcode::setOffset;
500         o.dc = m_dc.grabRef();
501         o.parm.setOffset = new gOpcode::para::psetOffset;
502         o.parm.setOffset->rel = 0;
503         o.parm.setOffset->value = ePoint(0, 0);
504         m_rc->submit(o);
505 }
506
507 void gPainter::resetClip(const gRegion &region)
508 {
509         if ( m_dc->islocked() )
510                 return;
511         gOpcode o;
512         o.opcode = gOpcode::setClip;
513         o.dc = m_dc.grabRef();
514         o.parm.clip = new gOpcode::para::psetClip;
515         o.parm.clip->region = region;
516         m_rc->submit(o);
517 }
518
519 void gPainter::clip(const gRegion &region)
520 {
521         if ( m_dc->islocked() )
522                 return;
523         gOpcode o;
524         o.opcode = gOpcode::addClip;
525         o.dc = m_dc.grabRef();
526         o.parm.clip = new gOpcode::para::psetClip;
527         o.parm.clip->region = region;
528         m_rc->submit(o);
529 }
530
531 void gPainter::clippop()
532 {
533         if ( m_dc->islocked() )
534                 return;
535         gOpcode o;
536         o.opcode = gOpcode::popClip;
537         o.dc = m_dc.grabRef();
538         m_rc->submit(o);
539 }
540
541 void gPainter::waitVSync()
542 {
543         if ( m_dc->islocked() )
544                 return;
545         gOpcode o;
546         o.opcode = gOpcode::waitVSync;
547         o.dc = m_dc.grabRef();
548         m_rc->submit(o);
549 }
550
551 void gPainter::flip()
552 {
553         if ( m_dc->islocked() )
554                 return;
555         gOpcode o;
556         o.opcode = gOpcode::flip;
557         o.dc = m_dc.grabRef();
558         m_rc->submit(o);
559 }
560
561 void gPainter::notify()
562 {
563         if ( m_dc->islocked() )
564                 return;
565         gOpcode o;
566         o.opcode = gOpcode::notify;
567         o.dc = m_dc.grabRef();
568         m_rc->submit(o);
569 }
570
571 void gPainter::setCompositing(gCompositingData *comp)
572 {
573         gOpcode o;
574         o.opcode = gOpcode::setCompositing;
575         o.dc = 0;
576         o.parm.setCompositing = comp;
577         comp->AddRef(); /* will be freed in ::thread */
578         m_rc->submit(o);
579 }
580
581 void gPainter::flush()
582 {
583         if ( m_dc->islocked() )
584                 return;
585         gOpcode o;
586         o.opcode = gOpcode::flush;
587         o.dc = m_dc.grabRef();
588         m_rc->submit(o);
589 }
590
591 void gPainter::end()
592 {
593         if ( m_dc->islocked() )
594                 return;
595 }
596
597 gDC::gDC()
598 {
599         m_spinner_pic = 0;
600 }
601
602 gDC::gDC(gPixmap *pixmap): m_pixmap(pixmap)
603 {
604         m_spinner_pic = 0;
605 }
606
607 gDC::~gDC()
608 {
609         delete[] m_spinner_pic;
610 }
611
612 void gDC::exec(const gOpcode *o)
613 {
614         switch (o->opcode)
615         {
616         case gOpcode::setBackgroundColor:
617                 m_background_color = o->parm.setColor->color;
618                 m_background_color_rgb = getRGB(m_background_color);
619                 delete o->parm.setColor;
620                 break;
621         case gOpcode::setForegroundColor:
622                 m_foreground_color = o->parm.setColor->color;
623                 m_background_color_rgb = getRGB(m_foreground_color);
624                 delete o->parm.setColor;
625                 break;
626         case gOpcode::setBackgroundColorRGB:
627                 if (m_pixmap->needClut())
628                         m_background_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
629                 m_background_color_rgb = o->parm.setColorRGB->color;
630                 delete o->parm.setColorRGB;
631                 break;
632         case gOpcode::setForegroundColorRGB:
633                 if (m_pixmap->needClut())
634                         m_foreground_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
635                 m_foreground_color_rgb = o->parm.setColorRGB->color;
636                 delete o->parm.setColorRGB;
637                 break;
638         case gOpcode::setFont:
639                 m_current_font = o->parm.setFont->font;
640                 o->parm.setFont->font->Release();
641                 delete o->parm.setFont;
642                 break;
643         case gOpcode::renderText:
644         {
645                 ePtr<eTextPara> para = new eTextPara(o->parm.renderText->area);
646                 int flags = o->parm.renderText->flags;
647                 ASSERT(m_current_font);
648                 para->setFont(m_current_font);
649                 para->renderString(o->parm.renderText->text, (flags & gPainter::RT_WRAP) ? RS_WRAP : 0);
650                 if (o->parm.renderText->text)
651                         free(o->parm.renderText->text);
652                 if (flags & gPainter::RT_HALIGN_RIGHT)
653                         para->realign(eTextPara::dirRight);
654                 else if (flags & gPainter::RT_HALIGN_CENTER)
655                         para->realign(eTextPara::dirCenter);
656                 else if (flags & gPainter::RT_HALIGN_BLOCK)
657                         para->realign(eTextPara::dirBlock);
658                 
659                 ePoint offset = m_current_offset;
660                 
661                 if (o->parm.renderText->flags & gPainter::RT_VALIGN_CENTER)
662                 {
663                         eRect bbox = para->getBoundBox();
664                         int vcentered_top = o->parm.renderText->area.top() + ((o->parm.renderText->area.height() - bbox.height()) / 2);
665                         int correction = vcentered_top - bbox.top();
666                         offset += ePoint(0, correction);
667                 }
668                 
669                 para->blit(*this, offset, m_background_color_rgb, m_foreground_color_rgb);
670                 delete o->parm.renderText;
671                 break;
672         }
673         case gOpcode::renderPara:
674         {
675                 o->parm.renderPara->textpara->blit(*this, o->parm.renderPara->offset + m_current_offset, m_background_color_rgb, m_foreground_color_rgb);
676                 o->parm.renderPara->textpara->Release();
677                 delete o->parm.renderPara;
678                 break;
679         }
680         case gOpcode::fill:
681         {
682                 eRect area = o->parm.fill->area;
683                 area.moveBy(m_current_offset);
684                 gRegion clip = m_current_clip & area;
685                 if (m_pixmap->needClut())
686                         m_pixmap->fill(clip, m_foreground_color);
687                 else
688                         m_pixmap->fill(clip, m_foreground_color_rgb);
689                 delete o->parm.fill;
690                 break;
691         }
692         case gOpcode::fillRegion:
693         {
694                 o->parm.fillRegion->region.moveBy(m_current_offset);
695                 gRegion clip = m_current_clip & o->parm.fillRegion->region;
696                 if (m_pixmap->needClut())
697                         m_pixmap->fill(clip, m_foreground_color);
698                 else
699                         m_pixmap->fill(clip, m_foreground_color_rgb);
700                 delete o->parm.fillRegion;
701                 break;
702         }
703         case gOpcode::clear:
704                 if (m_pixmap->needClut())
705                         m_pixmap->fill(m_current_clip, m_background_color);
706                 else
707                         m_pixmap->fill(m_current_clip, m_background_color_rgb);
708                 delete o->parm.fill;
709                 break;
710         case gOpcode::blit:
711         {
712                 gRegion clip;
713                                 // this code should be checked again but i'm too tired now
714                 
715                 o->parm.blit->position.moveBy(m_current_offset);
716                 
717                 if (o->parm.blit->clip.valid())
718                 {
719                         o->parm.blit->clip.moveBy(m_current_offset);
720                         clip.intersect(gRegion(o->parm.blit->clip), m_current_clip);
721                 } else
722                         clip = m_current_clip;
723                 
724                 m_pixmap->blit(*o->parm.blit->pixmap, o->parm.blit->position, clip, o->parm.blit->flags);
725                 o->parm.blit->pixmap->Release();
726                 delete o->parm.blit;
727                 break;
728         }
729         case gOpcode::setPalette:
730                 if (o->parm.setPalette->palette->start > m_pixmap->surface->clut.colors)
731                         o->parm.setPalette->palette->start = m_pixmap->surface->clut.colors;
732                 if (o->parm.setPalette->palette->colors > (m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start))
733                         o->parm.setPalette->palette->colors = m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start;
734                 if (o->parm.setPalette->palette->colors)
735                         memcpy(m_pixmap->surface->clut.data+o->parm.setPalette->palette->start, o->parm.setPalette->palette->data, o->parm.setPalette->palette->colors*sizeof(gRGB));
736                 
737                 delete[] o->parm.setPalette->palette->data;
738                 delete o->parm.setPalette->palette;
739                 delete o->parm.setPalette;
740                 break;
741         case gOpcode::mergePalette:
742                 m_pixmap->mergePalette(*o->parm.mergePalette->target);
743                 o->parm.mergePalette->target->Release();
744                 delete o->parm.mergePalette;
745                 break; 
746         case gOpcode::line:
747         {
748                 ePoint start = o->parm.line->start + m_current_offset, end = o->parm.line->end + m_current_offset;
749                 m_pixmap->line(m_current_clip, start, end, m_foreground_color);
750                 delete o->parm.line;
751                 break;
752         }
753         case gOpcode::addClip:
754                 m_clip_stack.push(m_current_clip);
755                 o->parm.clip->region.moveBy(m_current_offset);
756                 m_current_clip &= o->parm.clip->region;
757                 delete o->parm.clip;
758                 break;
759         case gOpcode::setClip:
760                 o->parm.clip->region.moveBy(m_current_offset);
761                 m_current_clip = o->parm.clip->region & eRect(ePoint(0, 0), m_pixmap->size());
762                 delete o->parm.clip;
763                 break;
764         case gOpcode::popClip:
765                 if (!m_clip_stack.empty())
766                 {
767                         m_current_clip = m_clip_stack.top();
768                         m_clip_stack.pop();
769                 }
770                 break;
771         case gOpcode::setOffset:
772                 if (o->parm.setOffset->rel)
773                         m_current_offset += o->parm.setOffset->value;
774                 else
775                         m_current_offset  = o->parm.setOffset->value;
776                 delete o->parm.setOffset;
777                 break;
778         case gOpcode::waitVSync:
779                 break;
780         case gOpcode::flip:
781                 break;
782         case gOpcode::flush:
783                 break;
784         case gOpcode::enableSpinner:
785                 enableSpinner();
786                 break;
787         case gOpcode::disableSpinner:
788                 disableSpinner();
789                 break;
790         case gOpcode::incrementSpinner:
791                 incrementSpinner();
792                 break;
793         default:
794                 eFatal("illegal opcode %d. expect memory leak!", o->opcode);
795         }
796 }
797
798 gRGB gDC::getRGB(gColor col)
799 {
800         if ((!m_pixmap) || (!m_pixmap->surface->clut.data))
801                 return gRGB(col, col, col);
802         if (col<0)
803         {
804                 eFatal("bla transp");
805                 return gRGB(0, 0, 0, 0xFF);
806         }
807         return m_pixmap->surface->clut.data[col];
808 }
809
810 void gDC::enableSpinner()
811 {
812         ASSERT(m_spinner_saved);
813         
814                 /* save the background to restore it later. We need to negative position because we want to blit from the middle of the screen. */
815         m_spinner_saved->blit(*m_pixmap, eRect(-m_spinner_pos.topLeft(), eSize()), gRegion(eRect(ePoint(0, 0), m_spinner_saved->size())), 0);
816         
817         incrementSpinner();
818 }
819
820 void gDC::disableSpinner()
821 {
822         ASSERT(m_spinner_saved);
823
824                 /* restore background */
825         m_pixmap->blit(*m_spinner_saved, eRect(m_spinner_pos.topLeft(), eSize()), gRegion(m_spinner_pos), 0);
826 }
827
828 void gDC::incrementSpinner()
829 {
830         ASSERT(m_spinner_saved);
831         
832         static int blub;
833         blub++;
834
835 #if 0
836         int i;
837         
838         for (i = 0; i < 5; ++i)
839         {
840                 int x = i * 20 + m_spinner_pos.left();
841                 int y = m_spinner_pos.top();
842                 
843                 int col = ((blub - i) * 30) % 256;
844
845                 m_pixmap->fill(eRect(x, y, 10, 10), gRGB(col, col, col));
846         }
847 #endif
848
849         m_spinner_temp->blit(*m_spinner_saved, eRect(0, 0, 0, 0), eRect(ePoint(0, 0), m_spinner_pos.size()));
850
851         if (m_spinner_pic[m_spinner_i])
852                 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);
853
854         m_pixmap->blit(*m_spinner_temp, eRect(m_spinner_pos.topLeft(), eSize()), gRegion(m_spinner_pos), 0);
855         m_spinner_i++;
856         m_spinner_i %= m_spinner_num;
857 }
858
859 void gDC::setSpinner(eRect pos, ePtr<gPixmap> *pic, int len)
860 {
861         ASSERT(m_pixmap);
862         ASSERT(m_pixmap->surface);
863         m_spinner_saved = new gPixmap(pos.size(), m_pixmap->surface->bpp);
864         m_spinner_temp = new gPixmap(pos.size(), m_pixmap->surface->bpp);
865         m_spinner_pos = pos;
866         
867         m_spinner_i = 0;
868         m_spinner_num = len;
869         
870         int i;
871         if (m_spinner_pic)
872                 delete[] m_spinner_pic;
873         
874         m_spinner_pic = new ePtr<gPixmap>[len];
875         
876         for (i = 0; i < len; ++i)
877                 m_spinner_pic[i] = pic[i];
878 }
879
880 DEFINE_REF(gDC);
881
882 eAutoInitPtr<gRC> init_grc(eAutoInitNumbers::graphic, "gRC");