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