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