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