fix typo
[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 }
36
37 DEFINE_REF(gRC);
38
39 gRC::~gRC()
40 {
41         instance=0;
42
43         gOpcode o;
44         o.opcode=gOpcode::shutdown;
45         submit(o);
46 #ifndef SYNC_PAINT
47         eDebug("waiting for gRC thread shutdown");
48         pthread_join(the_thread, 0);
49         eDebug("gRC thread has finished");
50 #endif
51 }
52
53 void gRC::submit(const gOpcode &o)
54 {
55         while(1)
56         {
57 #ifndef SYNC_PAINT
58                 pthread_mutex_lock(&mutex);
59 #endif
60                 int tmp=wp+1;
61                 if ( tmp == MAXSIZE )
62                         tmp=0;
63                 if ( tmp == rp )
64                 {
65 #ifndef SYNC_PAINT
66                         pthread_mutex_unlock(&mutex);
67 #else
68                         thread();
69 #endif
70                         //printf("render buffer full...\n");
71                         //fflush(stdout);
72                         usleep(1000);  // wait 1 msec
73                         continue;
74                 }
75                 int free=rp-wp;
76                 if ( free <= 0 )
77                         free+=MAXSIZE;
78                 queue[wp++]=o;
79                 if ( wp == MAXSIZE )
80                         wp = 0;
81                 if (o.opcode==gOpcode::flush||o.opcode==gOpcode::shutdown||o.opcode==gOpcode::notify)
82 #ifndef SYNC_PAINT
83                         pthread_cond_signal(&cond);  // wakeup gdi thread
84                 pthread_mutex_unlock(&mutex);
85 #else
86                         thread(); // paint
87 #endif
88                 break;
89         }
90 }
91
92 void *gRC::thread()
93 {
94         int need_notify = 0;
95 #ifndef SYNC_PAINT
96         while (1)
97         {
98 #else
99         while (rp != wp)
100         {
101 #endif
102 #ifndef SYNC_PAINT
103                 pthread_mutex_lock(&mutex);
104 #endif
105                 if ( rp != wp )
106                 {
107                         gOpcode o(queue[rp++]);
108                         if ( rp == MAXSIZE )
109                                 rp=0;
110 #ifndef SYNC_PAINT
111                         pthread_mutex_unlock(&mutex);
112 #endif
113                         if (o.opcode==gOpcode::shutdown)
114                                 break;
115                         else if (o.opcode==gOpcode::notify)
116                                 need_notify = 1;
117                         else
118                         {
119                                 o.dc->exec(&o);
120                                 // o.dc is a gDC* filled with grabref... so we must release it here
121                                 o.dc->Release();
122                         }
123                 }
124                 else
125                 {
126                         if (need_notify)
127                         {
128                                 need_notify = 0;
129                                 m_notify_pump.send(1);
130                         }
131 #ifndef SYNC_PAINT
132                         while(rp == wp)
133                                 pthread_cond_wait(&cond, &mutex);
134                         pthread_mutex_unlock(&mutex);
135 #endif
136                 }
137         }
138 #ifndef SYNC_PAINT
139         pthread_exit(0);
140 #endif
141         return 0;
142 }
143
144 void gRC::recv_notify(const int &i)
145 {
146         notify();
147 }
148
149 gRC *gRC::getInstance()
150 {
151         return instance;
152 }
153
154 static int gPainter_instances;
155
156 gPainter::gPainter(gDC *dc, eRect rect): m_dc(dc), m_rc(gRC::getInstance())
157 {
158 //      ASSERT(!gPainter_instances);
159         gPainter_instances++;
160 //      begin(rect);
161 }
162
163 gPainter::~gPainter()
164 {
165         end();
166         gPainter_instances--;
167 }
168
169 void gPainter::setBackgroundColor(const gColor &color)
170 {
171         if ( m_dc->islocked() )
172                 return;
173         gOpcode o;
174         o.opcode = gOpcode::setBackgroundColor;
175         o.dc = m_dc.grabRef();
176         o.parm.setColor = new gOpcode::para::psetColor;
177         o.parm.setColor->color = color;
178
179         m_rc->submit(o);
180 }
181
182 void gPainter::setForegroundColor(const gColor &color)
183 {
184         if ( m_dc->islocked() )
185                 return;
186         gOpcode o;
187         o.opcode = gOpcode::setForegroundColor;
188         o.dc = m_dc.grabRef();
189         o.parm.setColor = new gOpcode::para::psetColor;
190         o.parm.setColor->color = color;
191
192         m_rc->submit(o);
193 }
194
195 void gPainter::setBackgroundColor(const gRGB &color)
196 {
197         if ( m_dc->islocked() )
198                 return;
199         gOpcode o;
200         o.opcode = gOpcode::setBackgroundColorRGB;
201         o.dc = m_dc.grabRef();
202         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
203         o.parm.setColorRGB->color = color;
204
205         m_rc->submit(o);
206 }
207
208 void gPainter::setForegroundColor(const gRGB &color)
209 {
210         if ( m_dc->islocked() )
211                 return;
212         gOpcode o;
213         o.opcode = gOpcode::setForegroundColorRGB;
214         o.dc = m_dc.grabRef();
215         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
216         o.parm.setColorRGB->color = color;
217
218         m_rc->submit(o);
219 }
220
221 void gPainter::setFont(gFont *font)
222 {
223         if ( m_dc->islocked() )
224                 return;
225         gOpcode o;
226         o.opcode = gOpcode::setFont;
227         o.dc = m_dc.grabRef();
228         font->AddRef();
229         o.parm.setFont = new gOpcode::para::psetFont;
230         o.parm.setFont->font = font;
231
232         m_rc->submit(o);
233 }
234
235 void gPainter::renderText(const eRect &pos, const std::string &string, int flags)
236 {
237         if ( m_dc->islocked() )
238                 return;
239         gOpcode o;
240         o.opcode=gOpcode::renderText;
241         o.dc = m_dc.grabRef();
242         o.parm.renderText = new gOpcode::para::prenderText;
243         o.parm.renderText->area = pos;
244         o.parm.renderText->text = string.empty()?0:strdup(string.c_str());
245         o.parm.renderText->flags = flags;
246         m_rc->submit(o);
247 }
248
249 void gPainter::renderPara(eTextPara *para, ePoint offset)
250 {
251         if ( m_dc->islocked() )
252                 return;
253         gOpcode o;
254         o.opcode=gOpcode::renderPara;
255         o.dc = m_dc.grabRef();
256         o.parm.renderPara = new gOpcode::para::prenderPara;
257         o.parm.renderPara->offset = offset;
258
259         para->AddRef();
260         o.parm.renderPara->textpara = para;
261         m_rc->submit(o);
262 }
263
264 void gPainter::fill(const eRect &area)
265 {
266         if ( m_dc->islocked() )
267                 return;
268         gOpcode o;
269         o.opcode=gOpcode::fill;
270
271         o.dc = m_dc.grabRef();
272         o.parm.fill = new gOpcode::para::pfillRect;
273         o.parm.fill->area = area;
274         m_rc->submit(o);
275 }
276
277 void gPainter::fill(const gRegion &region)
278 {
279         if ( m_dc->islocked() )
280                 return;
281         gOpcode o;
282         o.opcode=gOpcode::fillRegion;
283
284         o.dc = m_dc.grabRef();
285         o.parm.fillRegion = new gOpcode::para::pfillRegion;
286         o.parm.fillRegion->region = region;
287         m_rc->submit(o);
288 }
289
290 void gPainter::clear()
291 {
292         if ( m_dc->islocked() )
293                 return;
294         gOpcode o;
295         o.opcode=gOpcode::clear;
296         o.dc = m_dc.grabRef();
297         o.parm.fill = new gOpcode::para::pfillRect;
298         o.parm.fill->area = eRect();
299         m_rc->submit(o);
300 }
301
302 void gPainter::blit(gPixmap *pixmap, ePoint pos, const eRect &clip, int flags)
303 {
304         if ( m_dc->islocked() )
305                 return;
306         gOpcode o;
307
308         ASSERT(pixmap);
309
310         o.opcode=gOpcode::blit;
311         o.dc = m_dc.grabRef();
312         pixmap->AddRef();
313         o.parm.blit  = new gOpcode::para::pblit;
314         o.parm.blit->pixmap = pixmap;
315         o.parm.blit->position = pos;
316         o.parm.blit->clip = clip;
317         o.parm.blit->flags=flags;
318         m_rc->submit(o);
319 }
320
321
322 void gPainter::setPalette(gRGB *colors, int start, int len)
323 {
324         if ( m_dc->islocked() )
325                 return;
326         gOpcode o;
327         o.opcode=gOpcode::setPalette;
328         o.dc = m_dc.grabRef();
329         gPalette *p=new gPalette;
330
331         o.parm.setPalette = new gOpcode::para::psetPalette;
332         p->data=new gRGB[len];
333
334         memcpy(p->data, colors, len*sizeof(gRGB));
335         p->start=start;
336         p->colors=len;
337         o.parm.setPalette->palette = p;
338         m_rc->submit(o);
339 }
340
341 void gPainter::setPalette(gPixmap *source)
342 {
343         ASSERT(source);
344         setPalette(source->surface->clut.data, source->surface->clut.start, source->surface->clut.colors);
345 }
346
347 void gPainter::mergePalette(gPixmap *target)
348 {
349         if ( m_dc->islocked() )
350                 return;
351         gOpcode o;
352         o.opcode = gOpcode::mergePalette;
353         o.dc = m_dc.grabRef();
354         target->AddRef();
355         o.parm.mergePalette = new gOpcode::para::pmergePalette;
356         o.parm.mergePalette->target = target;
357         m_rc->submit(o);
358 }
359
360 void gPainter::line(ePoint start, ePoint end)
361 {
362         if ( m_dc->islocked() )
363                 return;
364         gOpcode o;
365         o.opcode=gOpcode::line;
366         o.dc = m_dc.grabRef();
367         o.parm.line = new gOpcode::para::pline;
368         o.parm.line->start = start;
369         o.parm.line->end = end;
370         m_rc->submit(o);
371 }
372
373 void gPainter::setOffset(ePoint val)
374 {
375         if ( m_dc->islocked() )
376                 return;
377         gOpcode o;
378         o.opcode=gOpcode::setOffset;
379         o.dc = m_dc.grabRef();
380         o.parm.setOffset = new gOpcode::para::psetOffset;
381         o.parm.setOffset->rel = 0;
382         o.parm.setOffset->value = val;
383         m_rc->submit(o);
384 }
385
386 void gPainter::moveOffset(ePoint rel)
387 {
388         if ( m_dc->islocked() )
389                 return;
390         gOpcode o;
391         o.opcode=gOpcode::setOffset;
392         o.dc = m_dc.grabRef();
393         o.parm.setOffset = new gOpcode::para::psetOffset;
394         o.parm.setOffset->rel = 1;
395         o.parm.setOffset->value = rel;
396         m_rc->submit(o);
397 }
398
399 void gPainter::resetOffset()
400 {
401         if ( m_dc->islocked() )
402                 return;
403         gOpcode o;
404         o.opcode=gOpcode::setOffset;
405         o.dc = m_dc.grabRef();
406         o.parm.setOffset = new gOpcode::para::psetOffset;
407         o.parm.setOffset->rel = 0;
408         o.parm.setOffset->value = ePoint(0, 0);
409         m_rc->submit(o);
410 }
411
412 void gPainter::resetClip(const gRegion &region)
413 {
414         if ( m_dc->islocked() )
415                 return;
416         gOpcode o;
417         o.opcode = gOpcode::setClip;
418         o.dc = m_dc.grabRef();
419         o.parm.clip = new gOpcode::para::psetClip;
420         o.parm.clip->region = region;
421         m_rc->submit(o);
422 }
423
424 void gPainter::clip(const gRegion &region)
425 {
426         if ( m_dc->islocked() )
427                 return;
428         gOpcode o;
429         o.opcode = gOpcode::addClip;
430         o.dc = m_dc.grabRef();
431         o.parm.clip = new gOpcode::para::psetClip;
432         o.parm.clip->region = region;
433         m_rc->submit(o);
434 }
435
436 void gPainter::clippop()
437 {
438         if ( m_dc->islocked() )
439                 return;
440         gOpcode o;
441         o.opcode = gOpcode::popClip;
442         o.dc = m_dc.grabRef();
443         m_rc->submit(o);
444 }
445
446 void gPainter::flush()
447 {
448         if ( m_dc->islocked() )
449                 return;
450         gOpcode o;
451         o.opcode = gOpcode::flush;
452         o.dc = m_dc.grabRef();
453         m_rc->submit(o);
454 }
455
456 void gPainter::waitVSync()
457 {
458         if ( m_dc->islocked() )
459                 return;
460         gOpcode o;
461         o.opcode = gOpcode::waitVSync;
462         o.dc = m_dc.grabRef();
463         m_rc->submit(o);
464 }
465
466 void gPainter::flip()
467 {
468         if ( m_dc->islocked() )
469                 return;
470         gOpcode o;
471         o.opcode = gOpcode::flip;
472         o.dc = m_dc.grabRef();
473         m_rc->submit(o);
474 }
475
476 void gPainter::notify()
477 {
478         if ( m_dc->islocked() )
479                 return;
480         gOpcode o;
481         o.opcode = gOpcode::notify;
482         o.dc = m_dc.grabRef();
483         m_rc->submit(o);
484 }
485
486 void gPainter::end()
487 {
488         if ( m_dc->islocked() )
489                 return;
490         gOpcode o;
491         o.opcode = gOpcode::flush;
492         o.dc = m_dc.grabRef();
493         m_rc->submit(o);
494 }
495
496 gDC::gDC()
497 {
498 }
499
500 gDC::gDC(gPixmap *pixmap): m_pixmap(pixmap)
501 {
502 }
503
504 gDC::~gDC()
505 {
506 }
507
508 void gDC::exec(gOpcode *o)
509 {
510         switch (o->opcode)
511         {
512         case gOpcode::setBackgroundColor:
513                 m_background_color = o->parm.setColor->color;
514                 m_background_color_rgb = getRGB(m_background_color);
515                 delete o->parm.setColor;
516                 break;
517         case gOpcode::setForegroundColor:
518                 m_foreground_color = o->parm.setColor->color;
519                 m_background_color_rgb = getRGB(m_foreground_color);
520                 delete o->parm.setColor;
521                 break;
522         case gOpcode::setBackgroundColorRGB:
523                 if (m_pixmap->needClut())
524                         m_background_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
525                 m_background_color_rgb = o->parm.setColorRGB->color;
526                 delete o->parm.setColorRGB;
527                 break;
528         case gOpcode::setForegroundColorRGB:
529                 if (m_pixmap->needClut())
530                         m_foreground_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
531                 m_foreground_color_rgb = o->parm.setColorRGB->color;
532                 delete o->parm.setColorRGB;
533                 break;
534         case gOpcode::setFont:
535                 m_current_font = o->parm.setFont->font;
536                 o->parm.setFont->font->Release();
537                 delete o->parm.setFont;
538                 break;
539         case gOpcode::renderText:
540         {
541                 ePtr<eTextPara> para = new eTextPara(o->parm.renderText->area);
542                 int flags = o->parm.renderText->flags;
543                 assert(m_current_font);
544                 para->setFont(m_current_font);
545                 para->renderString(o->parm.renderText->text, (flags & gPainter::RT_WRAP) ? RS_WRAP : 0);
546                 if (o->parm.renderText->text)
547                         free(o->parm.renderText->text);
548                 if (flags & gPainter::RT_HALIGN_RIGHT)
549                         para->realign(eTextPara::dirRight);
550                 else if (flags & gPainter::RT_HALIGN_CENTER)
551                         para->realign(eTextPara::dirCenter);
552                 else if (flags & gPainter::RT_HALIGN_BLOCK)
553                         para->realign(eTextPara::dirBlock);
554                 
555                 ePoint offset = m_current_offset;
556                 
557                 if (o->parm.renderText->flags & gPainter::RT_VALIGN_CENTER)
558                 {
559                         eRect bbox = para->getBoundBox();
560                         int vcentered_top = o->parm.renderText->area.top() + ((o->parm.renderText->area.height() - bbox.height()) / 2);
561                         int correction = vcentered_top - bbox.top();
562                         offset += ePoint(0, correction);
563                 }
564                 
565                 para->blit(*this, offset, m_background_color_rgb, m_foreground_color_rgb);
566                 delete o->parm.renderText;
567                 break;
568         }
569         case gOpcode::renderPara:
570         {
571                 o->parm.renderPara->textpara->blit(*this, o->parm.renderPara->offset + m_current_offset, m_background_color_rgb, m_foreground_color_rgb);
572                 o->parm.renderPara->textpara->Release();
573                 delete o->parm.renderPara;
574                 break;
575         }
576         case gOpcode::fill:
577         {
578                 eRect area = o->parm.fill->area;
579                 area.moveBy(m_current_offset);
580                 gRegion clip = m_current_clip & area;
581                 if (m_pixmap->needClut())
582                         m_pixmap->fill(clip, m_foreground_color);
583                 else
584                         m_pixmap->fill(clip, m_foreground_color_rgb);
585                 delete o->parm.fill;
586                 break;
587         }
588         case gOpcode::fillRegion:
589         {
590                 o->parm.fillRegion->region.moveBy(m_current_offset);
591                 gRegion clip = m_current_clip & o->parm.fillRegion->region;
592                 if (m_pixmap->needClut())
593                         m_pixmap->fill(clip, m_foreground_color);
594                 else
595                         m_pixmap->fill(clip, m_foreground_color_rgb);
596                 delete o->parm.fillRegion;
597                 break;
598         }
599         case gOpcode::clear:
600                 if (m_pixmap->needClut())
601                         m_pixmap->fill(m_current_clip, m_background_color);
602                 else
603                         m_pixmap->fill(m_current_clip, m_background_color_rgb);
604                 delete o->parm.fill;
605                 break;
606         case gOpcode::blit:
607         {
608                 gRegion clip;
609                                 // this code should be checked again but i'm too tired now
610                 
611                 o->parm.blit->position += m_current_offset;
612                 
613                 if (o->parm.blit->clip.valid())
614                 {
615                         o->parm.blit->clip.moveBy(m_current_offset);
616                         clip.intersect(gRegion(o->parm.blit->clip), m_current_clip);
617                 } else
618                         clip = m_current_clip;
619                 
620                 m_pixmap->blit(*o->parm.blit->pixmap, o->parm.blit->position, clip, o->parm.blit->flags);
621                 o->parm.blit->pixmap->Release();
622                 delete o->parm.blit;
623                 break;
624         }
625         case gOpcode::setPalette:
626                 if (o->parm.setPalette->palette->start > m_pixmap->surface->clut.colors)
627                         o->parm.setPalette->palette->start = m_pixmap->surface->clut.colors;
628                 if (o->parm.setPalette->palette->colors > (m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start))
629                         o->parm.setPalette->palette->colors = m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start;
630                 if (o->parm.setPalette->palette->colors)
631                         memcpy(m_pixmap->surface->clut.data+o->parm.setPalette->palette->start, o->parm.setPalette->palette->data, o->parm.setPalette->palette->colors*sizeof(gRGB));
632                 
633                 delete[] o->parm.setPalette->palette->data;
634                 delete o->parm.setPalette->palette;
635                 delete o->parm.setPalette;
636                 break;
637         case gOpcode::mergePalette:
638                 m_pixmap->mergePalette(*o->parm.mergePalette->target);
639                 o->parm.mergePalette->target->Release();
640                 delete o->parm.mergePalette;
641                 break; 
642         case gOpcode::line:
643         {
644                 ePoint start = o->parm.line->start + m_current_offset, end = o->parm.line->end + m_current_offset;
645                 m_pixmap->line(m_current_clip, start, end, m_foreground_color);
646                 delete o->parm.line;
647                 break;
648         }
649         case gOpcode::addClip:
650                 m_clip_stack.push(m_current_clip);
651                 o->parm.clip->region.moveBy(m_current_offset);
652                 m_current_clip &= o->parm.clip->region;
653                 delete o->parm.clip;
654                 break;
655         case gOpcode::setClip:
656                 o->parm.clip->region.moveBy(m_current_offset);
657                 m_current_clip = o->parm.clip->region & eRect(ePoint(0, 0), m_pixmap->size());
658                 delete o->parm.clip;
659                 break;
660         case gOpcode::popClip:
661                 if (!m_clip_stack.empty())
662                 {
663                         m_current_clip = m_clip_stack.top();
664                         m_clip_stack.pop();
665                 }
666                 break;
667         case gOpcode::setOffset:
668                 if (o->parm.setOffset->rel)
669                         m_current_offset += o->parm.setOffset->value;
670                 else
671                         m_current_offset  = o->parm.setOffset->value;
672                 delete o->parm.setOffset;
673                 break;
674         case gOpcode::waitVSync:
675                 break;
676         case gOpcode::flip:
677                 break;
678         case gOpcode::flush:
679                 break;
680         default:
681                 eFatal("illegal opcode %d. expect memory leak!", o->opcode);
682         }
683 }
684
685 gRGB gDC::getRGB(gColor col)
686 {
687         if ((!m_pixmap) || (!m_pixmap->surface->clut.data))
688                 return gRGB(col, col, col);
689         if (col<0)
690         {
691                 eFatal("bla transp");
692                 return gRGB(0, 0, 0, 0xFF);
693         }
694         return m_pixmap->surface->clut.data[col];
695 }
696
697 DEFINE_REF(gDC);
698
699 eAutoInitPtr<gRC> init_grc(eAutoInitNumbers::graphic, "gRC");