1 /*
2  * Copyright (C) 2000-2019 the xine project
3  *
4  * This file is part of xine, a unix video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <X11/Xlib.h>
28 #include <errno.h>
29 
30 #include "_xitk.h"
31 
32 #include "utils.h"
33 
34 int xitk_x_error = 0;
35 
36 /*
37  * Get a pixel color from rgb values.
38  */
xitk_get_pixel_color_from_rgb(ImlibData * im,int r,int g,int b)39 unsigned int xitk_get_pixel_color_from_rgb(ImlibData *im, int r, int g, int b) {
40   XColor       xcolor;
41   unsigned int pixcol;
42 
43   ABORT_IF_NULL(im);
44 
45   xcolor.flags = DoRed | DoBlue | DoGreen;
46 
47   xcolor.red   = r<<8;
48   xcolor.green = g<<8;
49   xcolor.blue  = b<<8;
50 
51   XLOCK (im->x.x_lock_display, im->x.disp);
52   XAllocColor(im->x.disp, Imlib_get_colormap(im), &xcolor);
53   XUNLOCK (im->x.x_unlock_display, im->x.disp);
54 
55   pixcol = xcolor.pixel;
56 
57   return pixcol;
58 }
59 
60 /*
61  * Some default pixel colors.
62  */
xitk_get_pixel_color_black(ImlibData * im)63 unsigned int xitk_get_pixel_color_black(ImlibData *im) {
64   int user_color = xitk_get_black_color();
65   if(user_color >= 0)
66     return (unsigned int) user_color;
67   return xitk_get_pixel_color_from_rgb(im, 0, 0, 0);
68 }
xitk_get_pixel_color_white(ImlibData * im)69 unsigned int xitk_get_pixel_color_white(ImlibData *im) {
70   int user_color = xitk_get_white_color();
71   if(user_color >= 0)
72     return (unsigned int) user_color;
73   return xitk_get_pixel_color_from_rgb(im, 255, 255, 255);
74 }
xitk_get_pixel_color_lightgray(ImlibData * im)75 unsigned int xitk_get_pixel_color_lightgray(ImlibData *im) {
76   int user_color = xitk_get_focus_color();
77   if(user_color >= 0)
78     return (unsigned int) user_color;
79   return xitk_get_pixel_color_from_rgb(im, 224, 224, 224);
80 }
xitk_get_pixel_color_gray(ImlibData * im)81 unsigned int xitk_get_pixel_color_gray(ImlibData *im) {
82   int user_color = xitk_get_background_color();
83   if(user_color >= 0)
84     return (unsigned int) user_color;
85   return xitk_get_pixel_color_from_rgb(im, 190, 190, 190);
86 }
xitk_get_pixel_color_darkgray(ImlibData * im)87 unsigned int xitk_get_pixel_color_darkgray(ImlibData *im) {
88   int user_color = xitk_get_select_color();
89   if(user_color >= 0)
90     return (unsigned int) user_color;
91   return xitk_get_pixel_color_from_rgb(im, 128, 128, 128);
92 }
xitk_get_pixel_color_warning_foreground(ImlibData * im)93 unsigned int xitk_get_pixel_color_warning_foreground(ImlibData *im) {
94   int user_color = xitk_get_warning_foreground();
95   if(user_color >= 0)
96     return (unsigned int) user_color;
97   return xitk_get_pixel_color_black(im);
98 }
xitk_get_pixel_color_warning_background(ImlibData * im)99 unsigned int xitk_get_pixel_color_warning_background(ImlibData *im) {
100   int user_color = xitk_get_warning_background();
101   if(user_color >= 0)
102     return (unsigned int) user_color;
103   return xitk_get_pixel_color_from_rgb(im, 255, 255, 0);
104 }
105 
_xitk_pix_font_find_char(xitk_pix_font_t * pf,xitk_point_t * found,int this_char)106 static int _xitk_pix_font_find_char (xitk_pix_font_t *pf, xitk_point_t *found, int this_char) {
107   int range, n = 0;
108 
109   for (range = 0; pf->unicode_ranges[range].first > 0; range++) {
110     if ((this_char >= pf->unicode_ranges[range].first) && (this_char <= pf->unicode_ranges[range].last))
111       break;
112     n += pf->unicode_ranges[range].last - pf->unicode_ranges[range].first + 1;
113   }
114 
115   if (pf->unicode_ranges[range].first <= 0) {
116     *found = pf->unknown;
117     return 0;
118   }
119 
120   n += this_char - pf->unicode_ranges[range].first;
121   found->x = (n % pf->chars_per_row) * pf->char_width;
122   found->y = (n / pf->chars_per_row) * pf->char_height;
123   return 1;
124 }
125 
xitk_image_set_pix_font(xitk_image_t * image,const char * format)126 void xitk_image_set_pix_font (xitk_image_t *image, const char *format) {
127   xitk_pix_font_t *pf;
128   int range, total;
129 
130   if (!image || !format)
131     return;
132   if (image->pix_font)
133     return;
134   image->pix_font = pf = malloc (sizeof (*pf));
135   if (!pf)
136     return;
137 
138   pf->width = image->width;
139   pf->height = image->height;
140 
141   range = 0;
142   total = 0;
143   do {
144     const uint8_t *p = (const uint8_t *)format;
145     int v;
146     uint8_t z;
147     if (!p)
148       break;
149     while (1) {
150       while (*p && (*p != '('))
151         p++;
152       if (!(*p))
153         break;
154       p++;
155       if ((*p ^ '0') < 10)
156         break;
157     }
158     if (!(*p))
159       break;
160 
161     v = 0;
162     while ((z = (*p ^ '0')) < 10)
163       v = v * 10u + z, p++;
164     if (v <= 0)
165       break;
166     pf->chars_per_row = v;
167     if (*p != '!')
168       break;
169     p++;
170 
171     while (1) {
172       pf->unicode_ranges[range].last = 0;
173       v = 0;
174       while ((z = (*p ^ '0')) < 10)
175         v = v * 10u + z, p++;
176       pf->unicode_ranges[range].first = v;
177       if (*p != '-')
178         break;
179       p++;
180       v = 0;
181       while ((z = (*p ^ '0')) < 10)
182         v = v * 10u + z, p++;
183       pf->unicode_ranges[range].last = v;
184       if (pf->unicode_ranges[range].last < pf->unicode_ranges[range].first)
185         pf->unicode_ranges[range].last = pf->unicode_ranges[range].first;
186       total += pf->unicode_ranges[range].last - pf->unicode_ranges[range].first + 1;
187       range++;
188       if (range >= XITK_MAX_UNICODE_RANGES)
189         break;
190       if (*p != '!')
191         break;
192       p++;
193     }
194   } while (0);
195 
196   if (range == 0) {
197     pf->chars_per_row = 32;
198     pf->unicode_ranges[0].first = 32;
199     pf->unicode_ranges[0].last = 127;
200     total = 127 - 32 + 1;
201     range = 1;
202   }
203 
204   pf->char_width = pf->width / pf->chars_per_row;
205   pf->chars_total = total;
206   total = (total + pf->chars_per_row - 1) / pf->chars_per_row;
207   pf->char_height = pf->height / total;
208   pf->unicode_ranges[range].first = 0;
209   pf->unicode_ranges[range].last = 0;
210 
211   pf->unknown.x = 0;
212   pf->unknown.y = 0;
213   _xitk_pix_font_find_char (pf, &pf->unknown, 127);
214   _xitk_pix_font_find_char (pf, &pf->space, ' ');
215   _xitk_pix_font_find_char (pf, &pf->asterisk, '*');
216 }
217 
_xitk_image_destroy_pix_font(xitk_pix_font_t ** pix_font)218 static void _xitk_image_destroy_pix_font (xitk_pix_font_t **pix_font) {
219   free (*pix_font);
220   *pix_font = NULL;
221 }
222 
223 /*
224  *
225  */
xitk_image_free_image(ImlibData * im,xitk_image_t ** src)226 void xitk_image_free_image(ImlibData *im, xitk_image_t **src) {
227 
228   ABORT_IF_NULL(im);
229   ABORT_IF_NULL(*src);
230 
231   if((*src)->mask)
232     xitk_image_destroy_xitk_pixmap((*src)->mask);
233 
234   if((*src)->image)
235     xitk_image_destroy_xitk_pixmap((*src)->image);
236 
237   _xitk_image_destroy_pix_font (&(*src)->pix_font);
238 
239   XITK_FREE((*src));
240   *src = NULL;
241 }
242 
243 /*
244  *
245  */
xitk_image_create_pixmap(ImlibData * im,int width,int height)246 Pixmap xitk_image_create_pixmap(ImlibData *im, int width, int height) {
247   Pixmap p;
248 
249   ABORT_IF_NULL(im);
250   ABORT_IF_NOT_COND(width > 0);
251   ABORT_IF_NOT_COND(height > 0);
252 
253   XLOCK (im->x.x_lock_display, im->x.disp);
254   p = XCreatePixmap(im->x.disp, im->x.base_window, width, height, im->x.depth);
255   XUNLOCK (im->x.x_unlock_display, im->x.disp);
256 
257   return p;
258 }
259 
260 /*
261  *
262  */
xitk_image_xitk_pixmap_destroyer(xitk_pixmap_t * xpix)263 static void xitk_image_xitk_pixmap_destroyer(xitk_pixmap_t *xpix) {
264   ABORT_IF_NULL(xpix);
265 
266   XLOCK (xpix->imlibdata->x.x_lock_display, xpix->imlibdata->x.disp);
267 
268   if(xpix->pixmap != None)
269     XFreePixmap(xpix->imlibdata->x.disp, xpix->pixmap);
270 
271   XFreeGC(xpix->imlibdata->x.disp, xpix->gc);
272   XSync(xpix->imlibdata->x.disp, False);
273 
274 #ifdef HAVE_SHM
275   if(xpix->shm) {
276     XShmSegmentInfo *shminfo = xpix->shminfo;
277 
278     XShmDetach(xpix->imlibdata->x.disp, shminfo);
279 
280     if(xpix->xim)
281       XDestroyImage(xpix->xim);
282 
283     if(shmdt(shminfo->shmaddr) < 0)
284       XITK_WARNING("shmdt() failed: '%s'\n", strerror(errno));
285 
286     if(shmctl(shminfo->shmid, IPC_RMID, 0) < 0)
287       XITK_WARNING("shmctl() failed: '%s'\n", strerror(errno));
288 
289 
290     free(shminfo);
291   }
292 #endif
293 
294   XUNLOCK (xpix->imlibdata->x.x_unlock_display, xpix->imlibdata->x.disp);
295 
296   XITK_FREE(xpix);
297 }
298 
299 /*
300  *
301  */
xitk_image_create_xitk_pixmap_with_depth(ImlibData * im,int width,int height,int depth)302 xitk_pixmap_t *xitk_image_create_xitk_pixmap_with_depth(ImlibData *im, int width, int height, int depth) {
303   xitk_pixmap_t    *xpix;
304 #ifdef HAVE_SHM
305   XShmSegmentInfo  *shminfo;
306 #endif
307 
308   ABORT_IF_NULL(im);
309   ABORT_IF_NOT_COND(width > 0);
310   ABORT_IF_NOT_COND(height > 0);
311 
312   xpix            = (xitk_pixmap_t *) xitk_xmalloc(sizeof(xitk_pixmap_t));
313   xpix->imlibdata = im;
314   xpix->destroy   = xitk_image_xitk_pixmap_destroyer;
315   xpix->width     = width;
316   xpix->height    = height;
317   xpix->xim       = NULL;
318   xpix->shm       = 0;
319 
320   XLOCK (im->x.x_lock_display, im->x.disp);
321 
322 #ifdef HAVE_SHM
323   if(xitk_is_use_xshm() == 2) {
324     XImage   *xim;
325 
326     shminfo = (XShmSegmentInfo *) xitk_xmalloc(sizeof(XShmSegmentInfo));
327 
328     xitk_x_error = 0;
329     xitk_install_x_error_handler();
330 
331     xim = XShmCreateImage(im->x.disp, im->x.visual, depth, ZPixmap, NULL, shminfo, width, height);
332     if(!xim) {
333       XITK_WARNING("XShmCreateImage() failed.\n");
334       free(shminfo);
335       xitk_uninstall_x_error_handler();
336       goto __noxshm_pixmap;
337     }
338 
339     shminfo->shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, IPC_CREAT | 0777);
340     if(shminfo->shmid < 0) {
341       XITK_WARNING("shmget() failed.\n");
342       XDestroyImage(xim);
343       free(shminfo);
344       xitk_uninstall_x_error_handler();
345       goto __noxshm_pixmap;
346     }
347 
348     shminfo->shmaddr  = xim->data = shmat(shminfo->shmid, 0, 0);
349     if(xim->data == (char *) -1) {
350       XITK_WARNING("shmmat() failed.\n");
351       XDestroyImage(xim);
352       shmctl(shminfo->shmid, IPC_RMID, 0);
353       free(shminfo);
354       xitk_uninstall_x_error_handler();
355       goto __noxshm_pixmap;
356     }
357 
358     shminfo->readOnly = False;
359     XShmAttach(im->x.disp, shminfo);
360     XSync(im->x.disp, False);
361 
362     if(xitk_x_error) {
363       XITK_WARNING("XShmAttach() failed.\n");
364       XDestroyImage(xim);
365       shmdt(shminfo->shmaddr);
366       shmctl(shminfo->shmid, IPC_RMID, 0);
367       free(shminfo);
368       xitk_uninstall_x_error_handler();
369       goto __noxshm_pixmap;
370     }
371 
372     xpix->xim    = xim;
373     xpix->pixmap = XShmCreatePixmap(im->x.disp, im->x.base_window,
374 				    shminfo->shmaddr, shminfo, width, height, depth);
375 
376     if(!xpix->pixmap) {
377       XITK_WARNING("XShmCreatePixmap() failed.\n");
378       XShmDetach(xpix->imlibdata->x.disp, xpix->shminfo);
379       XDestroyImage(xim);
380       shmdt(shminfo->shmaddr);
381       shmctl(shminfo->shmid, IPC_RMID, 0);
382       free(shminfo);
383       xitk_uninstall_x_error_handler();
384       goto __noxshm_pixmap;
385     }
386     else {
387       xpix->shm                    = 1;
388       xpix->shminfo                = shminfo;
389       xpix->gcv.graphics_exposures = False;
390       xpix->gc                     = XCreateGC(im->x.disp, xpix->pixmap, GCGraphicsExposures, &xpix->gcv);
391       xitk_uninstall_x_error_handler();
392     }
393   }
394   else
395 #endif
396     {
397 #ifdef HAVE_SHM /* Just to make GCC happy */
398     __noxshm_pixmap:
399 #endif
400       xpix->shm     = 0;
401 #ifdef HAVE_SHM
402       xpix->shminfo = NULL;
403 #endif
404       xpix->pixmap  = XCreatePixmap(im->x.disp, im->x.base_window, width, height, depth);
405 
406       xpix->gcv.graphics_exposures = False;
407       xpix->gc = XCreateGC(im->x.disp, xpix->pixmap, GCGraphicsExposures, &xpix->gcv);
408     }
409   XUNLOCK (im->x.x_unlock_display, im->x.disp);
410 
411   return xpix;
412 }
413 
xitk_image_create_xitk_pixmap(ImlibData * im,int width,int height)414 xitk_pixmap_t *xitk_image_create_xitk_pixmap(ImlibData *im, int width, int height) {
415   return xitk_image_create_xitk_pixmap_with_depth(im, width, height, im->x.depth);
416 }
xitk_image_create_xitk_mask_pixmap(ImlibData * im,int width,int height)417 xitk_pixmap_t *xitk_image_create_xitk_mask_pixmap(ImlibData *im, int width, int height) {
418   return xitk_image_create_xitk_pixmap_with_depth(im, width, height, 1);
419 }
420 
xitk_image_destroy_xitk_pixmap(xitk_pixmap_t * p)421 void xitk_image_destroy_xitk_pixmap(xitk_pixmap_t *p) {
422   ABORT_IF_NULL(p);
423   p->destroy(p);
424 }
425 
426 #if 0
427 /*
428  *
429  */
430 Pixmap xitk_image_create_mask_pixmap(ImlibData *im, int width, int height) {
431   Pixmap p;
432 
433   ABORT_IF_NULL(im);
434   ABORT_IF_NOT_COND(width > 0);
435   ABORT_IF_NOT_COND(height > 0);
436 
437   XLOCK (im->x.x_lock_display, im->x.disp);
438   p = XCreatePixmap(im->x.disp, im->x.base_window, width, height, 1);
439   XUNLOCK (im->x.x_unlock_display, im->x.disp);
440 
441   return p;
442 }
443 #endif
444 
445 /*
446  *
447  */
xitk_image_change_image(ImlibData * im,xitk_image_t * src,xitk_image_t * dest,int width,int height)448 void xitk_image_change_image(ImlibData *im,
449 			     xitk_image_t *src, xitk_image_t *dest, int width, int height) {
450   ABORT_IF_NULL(im);
451   ABORT_IF_NULL(src);
452   ABORT_IF_NULL(dest);
453   ABORT_IF_NOT_COND(width > 0);
454   ABORT_IF_NOT_COND(height > 0);
455 
456   if(dest->mask)
457     xitk_image_destroy_xitk_pixmap(dest->mask);
458 
459   if(src->mask) {
460     xitk_image_destroy_xitk_pixmap(src->mask);
461 
462     dest->mask = xitk_image_create_xitk_pixmap(im, width, height);
463 
464     XLOCK (im->x.x_lock_display, im->x.disp);
465     XCopyArea(im->x.disp, src->mask->pixmap, dest->mask->pixmap, dest->mask->gc,
466 	      0, 0, width, height, 0, 0);
467     XUNLOCK (im->x.x_unlock_display, im->x.disp);
468 
469   }
470   else
471     dest->mask = NULL;
472 
473   if(dest->image)
474     xitk_image_destroy_xitk_pixmap(dest->image);
475 
476   dest->image = xitk_image_create_xitk_pixmap(im, width, height);
477 
478   XLOCK (im->x.x_lock_display, im->x.disp);
479   XCopyArea(im->x.disp, src->image->pixmap, dest->image->pixmap, dest->image->gc,
480 	    0, 0, width, height, 0, 0);
481   XUNLOCK (im->x.x_unlock_display, im->x.disp);
482 
483   dest->width = width;
484   dest->height = height;
485 }
486 
487 /*
488  *
489  */
xitk_image_create_image(ImlibData * im,int width,int height)490 xitk_image_t *xitk_image_create_image(ImlibData *im, int width, int height) {
491   xitk_image_t *i;
492 
493   ABORT_IF_NULL(im);
494   ABORT_IF_NOT_COND(width > 0);
495   ABORT_IF_NOT_COND(height > 0);
496 
497   i         = (xitk_image_t *) xitk_xmalloc(sizeof(xitk_image_t));
498   i->mask   = NULL;
499   i->image  = xitk_image_create_xitk_pixmap(im, width, height);
500   i->width  = width;
501   i->height = height;
502 
503   return i;
504 }
505 
506 /*
507  *
508  */
xitk_image_create_image_with_colors_from_string(ImlibData * im,const char * fontname,int width,int align,const char * str,unsigned int foreground,unsigned int background)509 xitk_image_t *xitk_image_create_image_with_colors_from_string(ImlibData *im,
510                                                               const char *fontname,
511                                                               int width, int align, const char *str,
512                                                               unsigned int foreground,
513                                                               unsigned int background) {
514   xitk_image_t   *image;
515   xitk_font_t    *fs;
516   GC              gc;
517   int             length, height, lbearing, rbearing, ascent, descent, linel, linew, wlinew, lastws;
518   int             maxw = 0;
519   const char     *p;
520   char           *bp;
521   char           *lines[256];
522   int             numlines = 0;
523   char            buf[BUFSIZ]; /* Could be allocated dynamically for bigger texts */
524 
525   int             add_line_spc = 2;
526 
527   ABORT_IF_NULL(im);
528   ABORT_IF_NULL(fontname);
529   ABORT_IF_NULL(str);
530   ABORT_IF_NOT_COND(width > 0);
531 
532   XLOCK (im->x.x_lock_display, im->x.disp);
533   gc = XCreateGC(im->x.disp, im->x.base_window, None, None);
534   XUNLOCK (im->x.x_unlock_display, im->x.disp);
535 
536   /* Creating an image from an empty string would cause an abort with failed */
537   /* condition "width > 0". So we substitute some spaces (one single space   */
538   /* may not be enough!). Should only happen in case of error.               */
539   if(!*str)
540     str = "   ";
541 
542   fs = xitk_font_load_font(im->x.disp, fontname);
543   xitk_font_set_font(fs, gc);
544   xitk_font_string_extent(fs, str, NULL, NULL, NULL, &ascent, &descent);
545   height = ascent + descent;
546 
547   p      = str;
548   bp     = buf;
549   wlinew = linew = lastws = linel = 0;
550 
551   /*
552    * Create string image using exactly the ink width
553    * without left and right spacing measures
554    */
555 
556   while((*p!='\0') && (bp + linel) < (buf + BUFSIZ - TABULATION_SIZE - 2)) {
557 
558     switch(*p) {
559 
560     case '\t':
561       {
562 	int a;
563 
564 	if((linel == 0) || (bp[linel - 1] != ' ')) {
565 	  lastws = linel;
566 	  wlinew = linew; /* width if wrapped */
567 	}
568 
569 	a = TABULATION_SIZE - (linel % TABULATION_SIZE);
570 
571         while(a--)
572           bp[linel++] = ' ';
573       }
574       break;
575 
576       case '\a':
577       case '\b':
578       case '\f':
579       case '\r':
580       case '\v':
581         break; /* Ignore those */
582 
583     case '\n':
584       lines[numlines++] = bp;
585       bp                = bp + linel + 1;
586 
587       wlinew = lastws = linel = 0;
588 
589       if(linew > maxw)
590 	maxw = linew;
591       break;
592 
593     case ' ':
594       if((linel == 0) || (bp[linel-1] != ' ')) {
595 	lastws = linel;
596 	wlinew = linew; /* width if wrapped */
597       }
598 
599       /* fall through */
600     default:
601       bp[linel++] = *p;
602 
603       if(!lastws)
604 	wlinew = linew;
605       break;
606     }
607 
608     bp[linel] = '\0'; /* terminate the string for reading with xitk_font_string_extent or strlen */
609 
610     xitk_font_string_extent(fs, bp, &lbearing, &rbearing, NULL, NULL, NULL);
611     if((linew = rbearing - lbearing) > width) {
612 
613       if(lastws == 0) { /* if we haven't found a whitespace */
614         bp[linel]         = bp[linel-1]; /* Move that last character down */
615         bp[linel-1]       = 0;
616         lines[numlines++] = bp;
617         bp                += linel;
618         linel             = 1;
619         bp[linel]         = 0;
620       }
621       else {
622         char *nextword = (bp + lastws);
623         int   wordlen;
624 
625         while(*nextword == ' ')
626           nextword++;
627 
628         wordlen           = (bp + linel) - nextword;
629         bp[lastws]        = '\0';
630         lines[numlines++] = bp;
631         bp                = bp + lastws + 1;
632 
633         if(bp != nextword)
634           memmove(bp, nextword, wordlen + 1);
635 
636         linel = wordlen;
637         lastws = 0;
638       }
639 
640       if(wlinew > maxw)
641         maxw = wlinew;
642 
643       xitk_font_string_extent(fs, bp, &lbearing, &rbearing, NULL, NULL, NULL);
644       linew = rbearing - lbearing;
645     }
646 
647     p++;
648   }
649 
650   if(linel) { /* In case last chars aren't stored */
651     lines[numlines++] = bp;
652 
653     if(linew > maxw)
654       maxw = linew;
655   }
656 
657   /* If default resp. left aligned, we may shrink the image */
658   if((align == ALIGN_DEFAULT) || (align == ALIGN_LEFT))
659     width = MIN(maxw, width);
660 
661   image = xitk_image_create_image(im, width, (height + add_line_spc) * numlines - add_line_spc);
662   draw_flat_with_color(im, image->image, image->width, image->height, background);
663 
664   { /* Draw string in image */
665     int i, y, x = 0;
666 
667     XLOCK (im->x.x_lock_display, im->x.disp);
668     XSetForeground(im->x.disp, gc, foreground);
669     XUNLOCK (im->x.x_unlock_display, im->x.disp);
670 
671     for(y = ascent, i = 0; i < numlines; i++, y += (height + add_line_spc)) {
672       xitk_font_string_extent(fs, lines[i], &lbearing, &rbearing, NULL, NULL, NULL);
673       length = rbearing - lbearing;
674 
675       if((align == ALIGN_DEFAULT) || (align == ALIGN_LEFT))
676         x = 0;
677       else if(align == ALIGN_CENTER)
678         x = (width - length) >> 1;
679       else if(align == ALIGN_RIGHT)
680         x = (width - length);
681 
682       xitk_font_draw_string(fs, image->image->pixmap, gc,
683 			    (x - lbearing), y, lines[i], strlen(lines[i]));
684 			    /*   ^^^^^^^^ Adjust to start of ink */
685     }
686   }
687 
688   xitk_font_unload_font(fs);
689 
690   XLOCK (im->x.x_lock_display, im->x.disp);
691   XFreeGC(im->x.disp, gc);
692   XUNLOCK (im->x.x_unlock_display, im->x.disp);
693 
694   return image;
695 }
xitk_image_create_image_from_string(ImlibData * im,const char * fontname,int width,int align,const char * str)696 xitk_image_t *xitk_image_create_image_from_string(ImlibData *im,
697                                                   const char *fontname,
698                                                   int width, int align, const char *str) {
699 
700   return xitk_image_create_image_with_colors_from_string(im,fontname, width, align, str,
701 							 xitk_get_pixel_color_black(im),
702 							 xitk_get_pixel_color_gray(im));
703 }
704 /*
705  *
706  */
xitk_image_add_mask(ImlibData * im,xitk_image_t * dest)707 void xitk_image_add_mask(ImlibData *im, xitk_image_t *dest) {
708   ABORT_IF_NULL(im);
709   ABORT_IF_NULL(dest);
710 
711   if(dest->mask)
712     xitk_image_destroy_xitk_pixmap(dest->mask);
713 
714   dest->mask = xitk_image_create_xitk_mask_pixmap(im, dest->width, dest->height);
715 
716   XLOCK (im->x.x_lock_display, im->x.disp);
717   XSetForeground(im->x.disp, dest->mask->gc, 1);
718   XFillRectangle(im->x.disp, dest->mask->pixmap, dest->mask->gc, 0, 0, dest->width, dest->height);
719   XUNLOCK (im->x.x_unlock_display, im->x.disp);
720 }
721 
menu_draw_arrow_branch(ImlibData * im,xitk_image_t * p)722 void menu_draw_arrow_branch(ImlibData *im, xitk_image_t *p) {
723   int            w;
724   int            h;
725   XPoint         points[4];
726   int            i;
727   int            x1, x2, x3;
728   int            y1, y2, y3;
729 
730   ABORT_IF_NULL(im);
731   ABORT_IF_NULL(p);
732 
733   w = p->width / 3;
734   h = p->height;
735 
736   x1 = (w - 5);
737   y1 = (h / 2);
738 
739   x2 = (w - 10);
740   y2 = ((h / 2) + 5);
741 
742   x3 = (w - 10);
743   y3 = ((h / 2) - 5);
744 
745   XLOCK (im->x.x_lock_display, im->x.disp);
746   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
747   XUNLOCK (im->x.x_unlock_display, im->x.disp);
748 
749   for(i = 0; i < 3; i++) {
750 
751     if(i == 2) {
752       x1++; x2++; x3++;
753       y1++; y2++; y3++;
754     }
755 
756     points[0].x = x1;
757     points[0].y = y1;
758     points[1].x = x2;
759     points[1].y = y2;
760     points[2].x = x3;
761     points[2].y = y3;
762     points[3].x = x1;
763     points[3].y = y1;
764 
765     XLOCK (im->x.x_lock_display, im->x.disp);
766     XFillPolygon(im->x.disp, p->image->pixmap, p->image->gc,
767 		 &points[0], 4, Convex, CoordModeOrigin);
768     XUNLOCK (im->x.x_unlock_display, im->x.disp);
769 
770     x1 += w;
771     x2 += w;
772     x3 += w;
773   }
774 
775 }
776 
777 /*
778  *
779  */
_draw_arrow(ImlibData * im,xitk_image_t * p,int direction)780 static void _draw_arrow(ImlibData *im, xitk_image_t *p, int direction) {
781   int            w;
782   int            h;
783   XSegment      *segments;
784   int            nsegments;
785   int            i, s;
786   int            x1, x2, dx;
787   int            y1, y2, dy;
788 
789   ABORT_IF_NULL(im);
790   ABORT_IF_NULL(p);
791 
792   w = p->width / 3;
793   h = p->height;
794 
795   /*
796    * XFillPolygon doesn't yield equally shaped arbitrary sized small triangles
797    * because of its filling algorithm (see also fill-rule in XCreateGC(3X11)
798    * as for which pixels are drawn on the boundary).
799    * So we handcraft them using XDrawSegments applying Bresenham's algorithm.
800    */
801 
802   /* Coords of the enclosing rectangle for the triangle:   */
803   /* Pay attention to integer precision loss and calculate */
804   /* carefully to obtain symmetrical and centered shapes.  */
805   x1 = ((w - 1) / 2) - (w / 4);
806   x2 = ((w - 1) / 2) + (w / 4);
807   y1 = ((h - 1) / 2) - (h / 4);
808   y2 = ((h - 1) / 2) + (h / 4);
809 
810   dx = (x2 - x1 + 1);
811   dy = (y2 - y1 + 1);
812 
813   if(direction == DIRECTION_UP || direction == DIRECTION_DOWN) {
814     int y, iy, dd;
815 
816     nsegments = dy;
817     segments = (XSegment *) calloc(nsegments, sizeof(XSegment));
818 
819     if(direction == DIRECTION_DOWN) {
820       y = y1; iy = 1;
821     }
822     else {
823       y = y2; iy = -1;
824     }
825     dx = (dx + 1) / 2;
826     dd = 0;
827     for(s = 0; s < nsegments; s++) {
828       segments[s].y1 = y; segments[s].x1 = x1;
829       segments[s].y2 = y; segments[s].x2 = x2;
830       y += iy;
831       if(dy >= dx) {
832 	if((dd += dx) >= dy) {
833 	  x1++; x2--;
834 	  dd -= dy;
835 	}
836       }
837       else {
838 	do {
839 	  x1++; x2--;
840 	} while((dd += dy) < dx);
841 	dd -= dx;
842       }
843     }
844   }
845   else if(direction == DIRECTION_LEFT || direction == DIRECTION_RIGHT) {
846     int x, ix, dd;
847 
848     nsegments = dx;
849     segments = (XSegment *) calloc(nsegments, sizeof(XSegment));
850 
851     if(direction == DIRECTION_RIGHT) {
852       x = x1; ix = 1;
853     }
854     else {
855       x = x2; ix = -1;
856     }
857     dy = (dy + 1) / 2;
858     dd = 0;
859     for(s = 0; s < nsegments; s++) {
860       segments[s].x1 = x; segments[s].y1 = y1;
861       segments[s].x2 = x; segments[s].y2 = y2;
862       x += ix;
863       if(dx >= dy) {
864 	if((dd += dy) >= dx) {
865 	  y1++; y2--;
866 	  dd -= dx;
867 	}
868       }
869       else {
870 	do {
871 	  y1++; y2--;
872 	} while((dd += dx) < dy);
873 	dd -= dy;
874       }
875     }
876   }
877   else {
878     XITK_WARNING("direction '%d' is unhandled.\n", direction);
879     return;
880   }
881 
882   XLOCK (im->x.x_lock_display, im->x.disp);
883   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
884   XUNLOCK (im->x.x_unlock_display, im->x.disp);
885 
886   for(i = 0; i < 3; i++) {
887 
888     if(i == 2) {
889       for(s = 0; s < nsegments; s++) {
890 	segments[s].x1++; segments[s].y1++;
891 	segments[s].x2++; segments[s].y2++;
892       }
893     }
894 
895     XLOCK (im->x.x_lock_display, im->x.disp);
896     XDrawSegments(im->x.disp, p->image->pixmap, p->image->gc,
897 		  &segments[0], nsegments);
898     XUNLOCK (im->x.x_unlock_display, im->x.disp);
899 
900     for(s = 0; s < nsegments; s++) {
901       segments[s].x1 += w;
902       segments[s].x2 += w;
903     }
904   }
905 
906   free(segments);
907 }
908 
909 /*
910  *
911  */
draw_arrow_up(ImlibData * im,xitk_image_t * p)912 void draw_arrow_up(ImlibData *im, xitk_image_t *p) {
913   _draw_arrow(im, p, DIRECTION_UP);
914 }
draw_arrow_down(ImlibData * im,xitk_image_t * p)915 void draw_arrow_down(ImlibData *im, xitk_image_t *p) {
916   _draw_arrow(im, p, DIRECTION_DOWN);
917 }
draw_arrow_left(ImlibData * im,xitk_image_t * p)918 void draw_arrow_left(ImlibData *im, xitk_image_t *p) {
919   _draw_arrow(im, p, DIRECTION_LEFT);
920 }
draw_arrow_right(ImlibData * im,xitk_image_t * p)921 void draw_arrow_right(ImlibData *im, xitk_image_t *p) {
922   _draw_arrow(im, p, DIRECTION_RIGHT);
923 }
924 
925 /*
926  *
927  */
_draw_rectangular_box(ImlibData * im,xitk_pixmap_t * p,int x,int y,int excstart,int excstop,int width,int height,int relief)928 static void _draw_rectangular_box(ImlibData *im, xitk_pixmap_t *p,
929 				  int x, int y, int excstart, int excstop,
930 				  int width, int height, int relief) {
931   ABORT_IF_NULL(im);
932   ABORT_IF_NULL(p);
933 
934   XLOCK (im->x.x_lock_display, im->x.disp);
935   if(relief == DRAW_OUTTER)
936     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_white(im));
937   else if(relief == DRAW_INNER)
938     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_black(im));
939 
940   XDrawLine(im->x.disp, p->pixmap, p->gc, x, y, (x + excstart), y);
941   XDrawLine(im->x.disp, p->pixmap, p->gc, (x + excstop), y, (x + width - 1), y);
942   XDrawLine(im->x.disp, p->pixmap, p->gc, x, y, x, (y + height));
943   XUNLOCK (im->x.x_unlock_display, im->x.disp);
944 
945   XLOCK (im->x.x_lock_display, im->x.disp);
946   if(relief == DRAW_OUTTER)
947     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_black(im));
948   else if(relief == DRAW_INNER)
949     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_white(im));
950 
951   XDrawLine(im->x.disp, p->pixmap, p->gc, (x + width), y, (x + width), (y + height));
952   XDrawLine(im->x.disp, p->pixmap, p->gc, (x + 1), (y + height), (x + width), (y + height));
953   XUNLOCK (im->x.x_unlock_display, im->x.disp);
954 }
955 
956 /*
957  *
958  */
_draw_rectangular_box_light(ImlibData * im,xitk_pixmap_t * p,int x,int y,int excstart,int excstop,int width,int height,int relief)959 static void _draw_rectangular_box_light(ImlibData *im, xitk_pixmap_t *p,
960 					int x, int y, int excstart, int excstop,
961 					int width, int height, int relief) {
962   ABORT_IF_NULL(im);
963   ABORT_IF_NULL(p);
964 
965   XLOCK (im->x.x_lock_display, im->x.disp);
966   if(relief == DRAW_OUTTER)
967     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_white(im));
968   else if(relief == DRAW_INNER)
969     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_darkgray(im));
970 
971   XDrawLine(im->x.disp, p->pixmap, p->gc, x, y, (x + excstart), y);
972   XDrawLine(im->x.disp, p->pixmap, p->gc, (x + excstop), y, (x + width - 1), y);
973   XDrawLine(im->x.disp, p->pixmap, p->gc, x, y, x, (y + height));
974   XUNLOCK (im->x.x_unlock_display, im->x.disp);
975 
976   XLOCK (im->x.x_lock_display, im->x.disp);
977   if(relief == DRAW_OUTTER)
978     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_darkgray(im));
979   else if(relief == DRAW_INNER)
980     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_white(im));
981 
982   XDrawLine(im->x.disp, p->pixmap, p->gc, (x + width), y, (x + width), (y + height));
983   XDrawLine(im->x.disp, p->pixmap, p->gc, (x + 1), (y + height), (x + width), (y + height));
984   XUNLOCK (im->x.x_unlock_display, im->x.disp);
985 }
986 
987 /*
988  *
989  */
_draw_rectangular_box_with_colors(ImlibData * im,xitk_pixmap_t * p,int x,int y,int width,int height,unsigned int lcolor,unsigned int dcolor,int relief)990 static void _draw_rectangular_box_with_colors(ImlibData *im, xitk_pixmap_t *p,
991 					      int x, int y, int width, int height,
992 					      unsigned int lcolor, unsigned int dcolor,
993 					      int relief) {
994   ABORT_IF_NULL(im);
995   ABORT_IF_NULL(p);
996 
997   XLOCK (im->x.x_lock_display, im->x.disp);
998   if(relief == DRAW_OUTTER)
999     XSetForeground(im->x.disp, p->gc, lcolor);
1000   else if(relief == DRAW_INNER)
1001     XSetForeground(im->x.disp, p->gc, dcolor);
1002 
1003   XDrawLine(im->x.disp, p->pixmap, p->gc, x, y, (x + width - 1), y);
1004   XDrawLine(im->x.disp, p->pixmap, p->gc, x, y, x, (y + height));
1005   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1006 
1007   XLOCK (im->x.x_lock_display, im->x.disp);
1008   if(relief == DRAW_OUTTER)
1009     XSetForeground(im->x.disp, p->gc, dcolor);
1010   else if(relief == DRAW_INNER)
1011     XSetForeground(im->x.disp, p->gc, lcolor);
1012 
1013   XDrawLine(im->x.disp, p->pixmap, p->gc, (x + width), y, (x + width), (y + height));
1014   XDrawLine(im->x.disp, p->pixmap, p->gc, (x + 1), (y + height), (x + width), (y + height));
1015   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1016 }
1017 
1018 /*
1019  *
1020  */
draw_rectangular_inner_box(ImlibData * im,xitk_pixmap_t * p,int x,int y,int width,int height)1021 void draw_rectangular_inner_box(ImlibData *im, xitk_pixmap_t *p,
1022 				int x, int y, int width, int height) {
1023   _draw_rectangular_box(im, p, x, y, 0, 0, width, height, DRAW_INNER);
1024 }
draw_rectangular_outter_box(ImlibData * im,xitk_pixmap_t * p,int x,int y,int width,int height)1025 void draw_rectangular_outter_box(ImlibData *im, xitk_pixmap_t *p,
1026 				 int x, int y, int width, int height) {
1027   _draw_rectangular_box(im, p, x, y, 0, 0, width, height, DRAW_OUTTER);
1028 }
draw_rectangular_inner_box_light(ImlibData * im,xitk_pixmap_t * p,int x,int y,int width,int height)1029 void draw_rectangular_inner_box_light(ImlibData *im, xitk_pixmap_t *p,
1030 				      int x, int y, int width, int height) {
1031   _draw_rectangular_box_light(im, p, x, y, 0, 0, width, height, DRAW_INNER);
1032 }
draw_rectangular_outter_box_light(ImlibData * im,xitk_pixmap_t * p,int x,int y,int width,int height)1033 void draw_rectangular_outter_box_light(ImlibData *im, xitk_pixmap_t *p,
1034 				       int x, int y, int width, int height) {
1035   _draw_rectangular_box_light(im, p, x, y, 0, 0, width, height, DRAW_OUTTER);
1036 }
1037 
_draw_check_round(ImlibData * im,xitk_image_t * p,int x,int y,int d,int checked)1038 static void _draw_check_round(ImlibData *im, xitk_image_t *p, int x, int y, int d, int checked) {
1039   XLOCK (im->x.x_lock_display, im->x.disp);
1040   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1041   XFillArc(im->x.disp, p->image->pixmap, p->image->gc, x, y, d, d, (30 * 64), (180 * 64));
1042   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1043 
1044   XLOCK (im->x.x_lock_display, im->x.disp);
1045   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_darkgray(im));
1046   XFillArc(im->x.disp, p->image->pixmap, p->image->gc, x, y, d, d, (210 * 64), (180 * 64));
1047   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1048 
1049   XLOCK (im->x.x_lock_display, im->x.disp);
1050   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_white(im));
1051   XFillArc(im->x.disp, p->image->pixmap, p->image->gc, x + 2, y + 2, d - 4, d - 4, (0 * 64), (360 * 64));
1052   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1053 
1054   if(checked) {
1055     XLOCK (im->x.x_lock_display, im->x.disp);
1056     XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1057     XFillArc(im->x.disp, p->image->pixmap, p->image->gc, x + 4, y + 4, d - 8, d - 8, (0 * 64), (360 * 64));
1058     XUNLOCK (im->x.x_unlock_display, im->x.disp);
1059   }
1060 }
_draw_check_check(ImlibData * im,xitk_image_t * p,int x,int y,int d,int checked)1061 static void _draw_check_check(ImlibData *im, xitk_image_t *p, int x, int y, int d, int checked) {
1062   /* background */
1063   XLOCK (im->x.x_lock_display, im->x.disp);
1064   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_lightgray(im));
1065   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, x, y, d, d);
1066   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1067   /* */
1068   XLOCK (im->x.x_lock_display, im->x.disp);
1069   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1070   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, x, y, x + d, y);
1071   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, x, y, x, y + d);
1072   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1073 
1074   XLOCK (im->x.x_lock_display, im->x.disp);
1075   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_darkgray(im));
1076   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, x, y + d, x + d, y + d);
1077   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, x + d, y, x + d, y + d);
1078   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1079 
1080   if(checked) {
1081     XLOCK (im->x.x_lock_display, im->x.disp);
1082     XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1083     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, x + (d / 5), (y + ((d / 3) * 2)) - 2, x + (d / 2), y + d - 2);
1084     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, x + (d / 5)+1, (y + ((d / 3) * 2)) - 2, x + (d / 2) + 1, y + d - 2);
1085     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, x + (d / 2), y + d - 2, x + d - 2, y+1);
1086     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, x + (d / 2) + 1, y + d - 2, x + d - 1, y+1);
1087     XUNLOCK (im->x.x_unlock_display, im->x.disp);
1088   }
1089 
1090 }
1091 
draw_check_three_state_round_style(ImlibData * im,xitk_image_t * p,int x,int y,int d,int w,int checked)1092 static void draw_check_three_state_round_style(ImlibData *im, xitk_image_t *p, int x, int y, int d, int w, int checked) {
1093   int i;
1094 
1095   ABORT_IF_NULL(im);
1096   ABORT_IF_NULL(p);
1097 
1098   for(i = 0; i < 3; i++) {
1099     if(i == 2) {
1100       x++;
1101       y++;
1102     }
1103 
1104     _draw_check_round(im, p, x, y, d, checked);
1105     x += w;
1106   }
1107 }
1108 
draw_check_three_state_check_style(ImlibData * im,xitk_image_t * p,int x,int y,int d,int w,int checked)1109 static void draw_check_three_state_check_style(ImlibData *im, xitk_image_t *p, int x, int y, int d, int w, int checked) {
1110   int i;
1111 
1112   ABORT_IF_NULL(im);
1113   ABORT_IF_NULL(p);
1114 
1115   for(i = 0; i < 3; i++) {
1116     if(i == 2) {
1117       x++;
1118       y++;
1119     }
1120 
1121     _draw_check_check(im, p, x, y, d, checked);
1122     x += w;
1123   }
1124 }
1125 
menu_draw_check(ImlibData * im,xitk_image_t * p,int checked)1126 void menu_draw_check(ImlibData *im, xitk_image_t *p, int checked) {
1127   int  style = xitk_get_checkstyle_feature();
1128 
1129   ABORT_IF_NULL(im);
1130   ABORT_IF_NULL(p);
1131 
1132   switch(style) {
1133 
1134   case CHECK_STYLE_CHECK:
1135     draw_check_three_state_check_style(im, p, 4, 4, p->height - 8, p->width / 3, checked);
1136     break;
1137 
1138   case CHECK_STYLE_ROUND:
1139     draw_check_three_state_round_style(im, p, 4, 4, p->height - 8, p->width / 3, checked);
1140     break;
1141 
1142   case CHECK_STYLE_OLD:
1143   default:
1144     {
1145       int      relief = (checked) ? DRAW_INNER : DRAW_OUTTER;
1146       int      nrelief = (checked) ? DRAW_OUTTER : DRAW_INNER;
1147       int      w, h;
1148 
1149       w = p->width / 3;
1150       h = p->height - 12;
1151       _draw_rectangular_box(im, p->image, 4,               6,     0, 0, 12, h, relief);
1152       _draw_rectangular_box(im, p->image, w + 4,           6,     0, 0, 12, h, relief);
1153       _draw_rectangular_box(im, p->image, (w * 2) + 4 + 1, 6 + 1, 0, 0, 12, h, nrelief);
1154     }
1155     break;
1156   }
1157 }
1158 
1159 /*
1160  *
1161  */
_draw_three_state(ImlibData * im,xitk_image_t * p,int style)1162 static void _draw_three_state(ImlibData *im, xitk_image_t *p, int style) {
1163   int           w;
1164   int           h;
1165 
1166   ABORT_IF_NULL(im);
1167   ABORT_IF_NULL(p);
1168 
1169   w = p->width / 3;
1170   h = p->height;
1171 
1172   XLOCK (im->x.x_lock_display, im->x.disp);
1173   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_gray(im));
1174   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, w , h);
1175   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_lightgray(im));
1176   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, w, 0, (w * 2) , h);
1177   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1178 
1179   XLOCK (im->x.x_lock_display, im->x.disp);
1180   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_white(im));
1181   if(style == STYLE_BEVEL) {
1182     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, w, 0);
1183     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, 0, (h - 1));
1184   }
1185   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w, 0, (w * 2), 0);
1186   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w, 0, w, (h - 1));
1187   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1188 
1189   XLOCK (im->x.x_lock_display, im->x.disp);
1190   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_darkgray(im));
1191   if(style == STYLE_BEVEL) {
1192     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w - 2), 2, (w - 2), (h - 3));
1193     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 2, (h - 2), w-2, (h - 2));
1194   }
1195   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 2*w - 2,     2, 2*w - 2, h - 3);
1196   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc,     w+2, h - 2, 2*w - 2, h - 2);
1197   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc,   w * 2,     0,   w * 3,     0);
1198   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc,   w * 2,     0,   w * 2, h - 1);
1199   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1200 
1201   XLOCK (im->x.x_lock_display, im->x.disp);
1202   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, w * 2 , 0, (w - 1), (h - 1));
1203 
1204   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1205   if(style == STYLE_BEVEL) {
1206     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w - 1), 0, (w - 1), (h - 1));
1207     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0, (h - 1), w-1, (h - 1));
1208   }
1209   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2)+1, 1, (w * 3)-1, 1);
1210   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2)+1, 1, (w * 2)+1, (h - 2));
1211   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2) - 1, 0, (w * 2) - 1, h);
1212   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w, (h - 1), (w * 2)-1, (h - 1));
1213   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1214 
1215   XLOCK (im->x.x_lock_display, im->x.disp);
1216   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_white(im));
1217   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 3) - 1, 1, (w * 3) - 1, (h - 1));
1218   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2) + 1, (h - 1), (w * 3), (h - 1));
1219   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1220 }
1221 
1222 /*
1223  *
1224  */
_draw_two_state(ImlibData * im,xitk_image_t * p,int style)1225 static void _draw_two_state(ImlibData *im, xitk_image_t *p, int style) {
1226   int           w;
1227   int           h;
1228 
1229   ABORT_IF_NULL(im);
1230   ABORT_IF_NULL(p);
1231 
1232   w = p->width / 2;
1233   h = p->height;
1234 
1235   XLOCK (im->x.x_lock_display, im->x.disp);
1236   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_gray(im));
1237   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, w - 1, h - 1);
1238   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_lightgray(im));
1239   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, w, 0, (w * 2) - 1 , h - 1);
1240   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1241 
1242   XLOCK (im->x.x_lock_display, im->x.disp);
1243   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1244   if(style == STYLE_BEVEL) {
1245     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, w, 0);
1246     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, 0, (h - 1));
1247   }
1248   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w, 0, (w * 2), 0);
1249   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w, 0, w, (h - 1));
1250   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1251 
1252   XLOCK (im->x.x_lock_display, im->x.disp);
1253   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_white(im));
1254   if(style == STYLE_BEVEL) {
1255     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w - 1), 0 , (w - 1), (h - 1));
1256     XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0 ,(h - 1), w , (h - 1));
1257   }
1258   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2) - 1, 0, (w * 2) - 1, h);
1259   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w, (h - 1),(w * 2), (h - 1));
1260   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1261 }
1262 
1263 /*
1264  *
1265  */
_draw_relief(ImlibData * im,xitk_pixmap_t * p,int w,int h,int relief,int light)1266 static void _draw_relief(ImlibData *im, xitk_pixmap_t *p, int w, int h, int relief, int light) {
1267   ABORT_IF_NULL(im);
1268   ABORT_IF_NULL(p);
1269 
1270   XLOCK (im->x.x_lock_display, im->x.disp);
1271   XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_gray(im));
1272   XFillRectangle(im->x.disp, p->pixmap, p->gc, 0, 0, w , h);
1273   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1274 
1275   if(relief != DRAW_FLATTER) {
1276 
1277     _draw_rectangular_box_with_colors(im, p, 0, 0, w-1, h-1,
1278 				      xitk_get_pixel_color_white(im),
1279 				      ((light)
1280 				       ? xitk_get_pixel_color_darkgray(im)
1281 				       : xitk_get_pixel_color_black(im)),
1282 				      relief);
1283   }
1284 
1285 }
1286 
draw_checkbox_check(ImlibData * im,xitk_image_t * p)1287 void draw_checkbox_check(ImlibData *im, xitk_image_t *p) {
1288   int  style = xitk_get_checkstyle_feature();
1289 
1290   XLOCK (im->x.x_lock_display, im->x.disp);
1291   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_gray(im));
1292   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, p->width, p->height);
1293   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1294 
1295   switch(style) {
1296 
1297   case CHECK_STYLE_CHECK:
1298     {
1299       int w;
1300 
1301       w = p->width / 3;
1302       _draw_check_check(im, p, 0, 0, p->height, 0);
1303       _draw_check_check(im, p, w, 0, p->height, 0);
1304       _draw_check_check(im, p, w * 2, 0, p->height, 1);
1305     }
1306     break;
1307 
1308   case CHECK_STYLE_ROUND:
1309     {
1310       int w;
1311 
1312       w = p->width / 3;
1313       _draw_check_round(im, p, 0, 0, p->height, 0);
1314       _draw_check_round(im, p, w, 0, p->height, 0);
1315       _draw_check_round(im, p, w * 2, 0, p->height, 1);
1316     }
1317     break;
1318 
1319   case CHECK_STYLE_OLD:
1320   default:
1321     _draw_three_state(im, p, STYLE_BEVEL);
1322     break;
1323   }
1324 }
1325 
1326 /*
1327  *
1328  */
draw_flat_three_state(ImlibData * im,xitk_image_t * p)1329 void draw_flat_three_state(ImlibData *im, xitk_image_t *p) {
1330   _draw_three_state(im, p, STYLE_FLAT);
1331 }
1332 
1333 /*
1334  *
1335  */
draw_bevel_three_state(ImlibData * im,xitk_image_t * p)1336 void draw_bevel_three_state(ImlibData *im, xitk_image_t *p) {
1337   _draw_three_state(im, p, STYLE_BEVEL);
1338 }
1339 
1340 /*
1341  *
1342  */
draw_bevel_two_state(ImlibData * im,xitk_image_t * p)1343 void draw_bevel_two_state(ImlibData *im, xitk_image_t *p) {
1344   _draw_two_state(im, p, STYLE_BEVEL);
1345 }
1346 
1347 /*
1348  *
1349  */
_draw_paddle_three_state(ImlibData * im,xitk_image_t * p,int direction)1350 static void _draw_paddle_three_state(ImlibData *im, xitk_image_t *p, int direction) {
1351   int           w;
1352   int           h;
1353 
1354   ABORT_IF_NULL(im);
1355   ABORT_IF_NULL(p);
1356 
1357   w = p->width / 3;
1358   h = p->height;
1359 
1360   XLOCK (im->x.x_lock_display, im->x.disp);
1361   /* Draw mask */
1362   XSetForeground(im->x.disp, p->mask->gc, 0);
1363   /* Top */
1364   XDrawLine(im->x.disp, p->mask->pixmap, p->mask->gc, 0, 0, (w - 1), 0);
1365   XDrawLine(im->x.disp, p->mask->pixmap, p->mask->gc, 0, 1, (w - 1), 1);
1366   /* Bottom */
1367   XDrawLine(im->x.disp, p->mask->pixmap, p->mask->gc, 0, (h - 1), (w - 1), (h - 1));
1368   XDrawLine(im->x.disp, p->mask->pixmap, p->mask->gc, 0, (h - 1) - 1, (w - 1), (h - 1) - 1);
1369   /* Left */
1370   XDrawLine(im->x.disp, p->mask->pixmap, p->mask->gc, 0, 0, 0, (h - 1));
1371   XDrawLine(im->x.disp, p->mask->pixmap, p->mask->gc, 1, 0, 1, (h - 1));
1372   /* Right */
1373   XDrawLine(im->x.disp, p->mask->pixmap, p->mask->gc, (w - 1), 0, (w - 1), (h - 1));
1374   XDrawLine(im->x.disp, p->mask->pixmap, p->mask->gc, (w - 1) - 1, 0, (w - 1) - 1, (h - 1));
1375   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1376 
1377   XLOCK (im->x.x_lock_display, im->x.disp);
1378   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_gray(im));
1379   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, 2, 2, w - 4, (h - 1) - 2);
1380 
1381   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_lightgray(im));
1382   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, w + 2, 2, (w * 2) - 4, (h - 1) - 2);
1383 
1384   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_darkgray(im));
1385   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, (w * 2) + 2, 2, ((w * 3) - 1) - 4, (h - 1) - 2);
1386   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1387 
1388   _draw_rectangular_box_with_colors(im, p->image, 2, 2, (w-1)-4, (h-1)-4,
1389 				    xitk_get_pixel_color_white(im),
1390 				    xitk_get_pixel_color_black(im),
1391 				    DRAW_OUTTER);
1392   _draw_rectangular_box_with_colors(im, p->image, w+2, 2, (w-1)-4, (h-1)-4,
1393 				    xitk_get_pixel_color_white(im),
1394 				    xitk_get_pixel_color_black(im),
1395 				    DRAW_OUTTER);
1396   _draw_rectangular_box_with_colors(im, p->image, (w*2)+2, 2, (w-1)-4, (h-1)-4,
1397 				    xitk_get_pixel_color_white(im),
1398 				    xitk_get_pixel_color_black(im),
1399 				    DRAW_INNER);
1400 
1401   { /* Enlightening paddle */
1402     int xx, yy, ww, hh;
1403     int i, offset = 0;
1404 
1405     if(direction == DIRECTION_UP) {
1406       xx = 4; yy = ((h-1)>>1); ww = (w-1) - 8; hh = 1;
1407     }
1408     else if(direction == DIRECTION_LEFT) {
1409       xx = ((w-1)>>1); yy = 4; ww = 1; hh = (h-1) - 8;
1410     }
1411     else {
1412       XITK_WARNING("direction '%d' is unhandled.\n",direction);
1413       return;
1414     }
1415 
1416     for(i = 0; i < 3; i++, offset += w) {
1417       if(i == 2) { xx++; yy++; }
1418       draw_rectangular_outter_box(im, p->image, xx + offset, yy, ww, hh);
1419     }
1420   }
1421 
1422 }
1423 
1424 /*
1425  *
1426  */
draw_paddle_three_state_vertical(ImlibData * im,xitk_image_t * p)1427 void draw_paddle_three_state_vertical(ImlibData *im, xitk_image_t *p) {
1428   _draw_paddle_three_state(im, p, DIRECTION_UP);
1429 }
draw_paddle_three_state_horizontal(ImlibData * im,xitk_image_t * p)1430 void draw_paddle_three_state_horizontal(ImlibData *im, xitk_image_t *p) {
1431   _draw_paddle_three_state(im, p, DIRECTION_LEFT);
1432 }
1433 
1434 /*
1435  *
1436  */
draw_inner(ImlibData * im,xitk_pixmap_t * p,int w,int h)1437 void draw_inner(ImlibData *im, xitk_pixmap_t *p, int w, int h) {
1438   _draw_relief(im, p, w, h, DRAW_INNER, 0);
1439 }
draw_inner_light(ImlibData * im,xitk_pixmap_t * p,int w,int h)1440 void draw_inner_light(ImlibData *im, xitk_pixmap_t *p, int w, int h) {
1441   _draw_relief(im, p, w, h, DRAW_INNER, 1);
1442 }
1443 
1444 /*
1445  *
1446  */
draw_outter(ImlibData * im,xitk_pixmap_t * p,int w,int h)1447 void draw_outter(ImlibData *im, xitk_pixmap_t *p, int w, int h) {
1448   _draw_relief(im, p, w, h, DRAW_OUTTER, 0);
1449 }
draw_outter_light(ImlibData * im,xitk_pixmap_t * p,int w,int h)1450 void draw_outter_light(ImlibData *im, xitk_pixmap_t *p, int w, int h) {
1451   _draw_relief(im, p, w, h, DRAW_OUTTER, 1);
1452 }
1453 
1454 /*
1455  *
1456  */
draw_flat(ImlibData * im,xitk_pixmap_t * p,int w,int h)1457 void draw_flat(ImlibData *im, xitk_pixmap_t *p, int w, int h) {
1458   _draw_relief(im, p, w, h, DRAW_FLATTER, 1);
1459 }
1460 
1461 /*
1462  *
1463  */
draw_flat_with_color(ImlibData * im,xitk_pixmap_t * p,int w,int h,unsigned int color)1464 void draw_flat_with_color(ImlibData *im, xitk_pixmap_t *p, int w, int h, unsigned int color) {
1465   ABORT_IF_NULL(im);
1466   ABORT_IF_NULL(p);
1467 
1468   XLOCK (im->x.x_lock_display, im->x.disp);
1469   XSetForeground(im->x.disp, p->gc, color);
1470   XFillRectangle(im->x.disp, p->pixmap, p->gc, 0, 0, w , h);
1471   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1472 }
1473 
1474 /*
1475  * Draw a frame outline with embedded title.
1476  */
_draw_frame(ImlibData * im,xitk_pixmap_t * p,const char * title,const char * fontname,int style,int x,int y,int w,int h)1477 static void _draw_frame(ImlibData *im, xitk_pixmap_t *p,
1478                         const char *title, const char *fontname,
1479                         int style, int x, int y, int w, int h) {
1480   xitk_font_t   *fs = NULL;
1481   int            sty[2];
1482   int            yoff = 0, xstart = 0, xstop = 0;
1483   int            ascent = 0, descent = 0, lbearing = 0, rbearing = 0;
1484   int            titlelen = 0;
1485   const char    *titlebuf = NULL;
1486   char           buf[BUFSIZ];
1487 
1488   ABORT_IF_NULL(im);
1489   ABORT_IF_NULL(p);
1490 
1491   if(title) {
1492     int maxinkwidth = (w - 12);
1493 
1494     titlelen = strlen(title);
1495     titlebuf = title;
1496 
1497     fs = xitk_font_load_font(im->x.disp, (fontname ? fontname : DEFAULT_FONT_12));
1498     xitk_font_set_font(fs, p->gc);
1499     xitk_font_text_extent(fs, title, titlelen, &lbearing, &rbearing, NULL, &ascent, &descent);
1500 
1501     /* Limit title to frame width */
1502     if((rbearing - lbearing) > maxinkwidth) {
1503       char  dots[]  = "...";
1504       int   dotslen = strlen(dots);
1505       int   dotsrbearing;
1506       int   titlewidth;
1507 
1508       /* Cut title, append dots */
1509       xitk_font_text_extent(fs, dots, dotslen, NULL, &dotsrbearing, NULL, NULL, NULL);
1510       do {
1511 	titlelen--;
1512 	xitk_font_text_extent(fs, title, titlelen, NULL, NULL, &titlewidth, NULL, NULL);
1513 	rbearing = titlewidth + dotsrbearing;
1514       } while((rbearing - lbearing) > maxinkwidth);
1515       { /* Cut possible incomplete multibyte character at the end */
1516 	int titlewidth1;
1517 	while((titlelen > 0) &&
1518 	      (xitk_font_text_extent(fs, title, (titlelen - 1), NULL, NULL, &titlewidth1, NULL, NULL),
1519 	       titlewidth1 == titlewidth))
1520 	  titlelen--;
1521       }
1522       if(titlelen > (sizeof(buf) - dotslen - 1)) /* Should never happen, */
1523 	titlelen = (sizeof(buf) - dotslen - 1);  /* just to be sure ...  */
1524       strlcpy(buf, title, titlelen);
1525       strcat(buf, dots);
1526       titlelen += dotslen;
1527       titlebuf = buf;
1528     }
1529   }
1530 
1531   sty[0] = (style == DRAW_INNER) ? DRAW_INNER : DRAW_OUTTER;
1532   sty[1] = (style == DRAW_INNER) ? DRAW_OUTTER : DRAW_INNER;
1533 
1534   /* Dont draw frame box under frame title */
1535   if(title) {
1536     yoff = (ascent >> 1) + 1; /* Roughly v-center outline to ascent part of glyphs */
1537     xstart = 4 - 1;
1538     xstop = (rbearing - lbearing) + 8;
1539   }
1540 
1541   _draw_rectangular_box_light(im, p, x, (y + yoff),
1542 			      xstart, xstop,
1543 			      w, (h - yoff), sty[0]);
1544 
1545   if(title)
1546     xstart--, xstop--;
1547 
1548   _draw_rectangular_box_light(im, p, (x + 1), ((y + yoff) + 1),
1549 			      xstart, xstop,
1550 			      (w - 2), ((h - yoff) - 2), sty[1]);
1551 
1552   if(title) {
1553     XLOCK (im->x.x_lock_display, im->x.disp);
1554     XSetForeground(im->x.disp, p->gc, xitk_get_pixel_color_black(im));
1555     xitk_font_draw_string(fs, p->pixmap, p->gc, (x - lbearing + 6), (y + ascent), titlebuf, titlelen);
1556     XUNLOCK (im->x.x_unlock_display, im->x.disp);
1557 
1558     xitk_font_unload_font(fs);
1559   }
1560 
1561 }
1562 
1563 /*
1564  *
1565  */
draw_inner_frame(ImlibData * im,xitk_pixmap_t * p,const char * title,const char * fontname,int x,int y,int w,int h)1566 void draw_inner_frame(ImlibData *im, xitk_pixmap_t *p,
1567                       const char *title, const char *fontname,
1568                       int x, int y, int w, int h) {
1569   _draw_frame(im, p, title, fontname, DRAW_INNER, x, y, w, h);
1570 }
draw_outter_frame(ImlibData * im,xitk_pixmap_t * p,const char * title,const char * fontname,int x,int y,int w,int h)1571 void draw_outter_frame(ImlibData *im, xitk_pixmap_t *p,
1572                        const char *title, const char *fontname,
1573                        int x, int y, int w, int h) {
1574   _draw_frame(im, p, title, fontname, DRAW_OUTTER, x, y, w, h);
1575 }
1576 
1577 /*
1578  *
1579  */
draw_tab(ImlibData * im,xitk_image_t * p)1580 void draw_tab(ImlibData *im, xitk_image_t *p) {
1581   int           w, h;
1582 
1583   ABORT_IF_NULL(im);
1584   ABORT_IF_NULL(p);
1585 
1586   w = p->width / 3;
1587   h = p->height;
1588 
1589   XLOCK (im->x.x_lock_display, im->x.disp);
1590   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_gray(im));
1591   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, (w * 3), h);
1592   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_lightgray(im));
1593   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, 0, 3, (w - 1), h);
1594   XFillRectangle(im->x.disp, p->image->pixmap, p->image->gc, w, 0, (w - 1), h);
1595   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1596 
1597   XLOCK (im->x.x_lock_display, im->x.disp);
1598   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_white(im));
1599   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0, 3, w, 3);
1600   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0, 3, 0, h);
1601   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w, 0, (w * 2) - 1, 0);
1602   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w, 0, w, h);
1603   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1604 
1605   XLOCK (im->x.x_lock_display, im->x.disp);
1606   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2) + 3, 0, (w * 3) - 1, 0);
1607   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2), 3, (w * 2), (h - 1));
1608   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2), 3, (w * 2) + 3, 0);
1609   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1610 
1611   XLOCK (im->x.x_lock_display, im->x.disp);
1612   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1613   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w - 1), 3, (w - 1), h);
1614   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2) - 1, 0, (w * 2) - 1, h);
1615   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 3) - 1, 0, (w * 3) - 1, h);
1616   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1617 
1618   XLOCK (im->x.x_lock_display, im->x.disp);
1619   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_white(im));
1620   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 0, (h - 1), (w * 2) - 1, (h - 1));
1621   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1622 }
1623 
1624 /*
1625  *
1626  */
draw_paddle_rotate(ImlibData * im,xitk_image_t * p)1627 void draw_paddle_rotate(ImlibData *im, xitk_image_t *p) {
1628   int           w;
1629   int           h;
1630   unsigned int  ccolor, fcolor, ncolor;
1631 
1632   ABORT_IF_NULL(im);
1633   ABORT_IF_NULL(p);
1634 
1635   w = p->width/3;
1636   h = p->height;
1637   ncolor = xitk_get_pixel_color_darkgray(im);
1638   fcolor = xitk_get_pixel_color_warning_background(im);
1639   ccolor = xitk_get_pixel_color_lightgray(im);
1640 
1641   {
1642     int x, i;
1643     unsigned int bg_colors[3] = { ncolor, fcolor, ccolor };
1644 
1645     XLOCK (im->x.x_lock_display, im->x.disp);
1646     XSetForeground(im->x.disp, p->mask->gc, 0);
1647     XFillRectangle(im->x.disp, p->mask->pixmap, p->mask->gc, 0, 0, w * 3 , h);
1648     XSetForeground(im->x.disp, p->mask->gc, 1);
1649     XUNLOCK (im->x.x_unlock_display, im->x.disp);
1650 
1651     for(x = 0, i = 0; i < 3; i++) {
1652       XLOCK (im->x.x_lock_display, im->x.disp);
1653       XSetForeground(im->x.disp, p->mask->gc, 1);
1654       XFillArc(im->x.disp, p->mask->pixmap, p->mask->gc, x, 0, w-1, h-1, (0 * 64), (360 * 64));
1655       XDrawArc(im->x.disp, p->mask->pixmap, p->mask->gc, x, 0, w-1, h-1, (0 * 64), (360 * 64));
1656       XUNLOCK (im->x.x_unlock_display, im->x.disp);
1657 
1658       XLOCK (im->x.x_lock_display, im->x.disp);
1659       XSetForeground(im->x.disp, p->image->gc, bg_colors[i]);
1660       XFillArc(im->x.disp, p->image->pixmap, p->image->gc, x, 0, w-1, h-1, (0 * 64), (360 * 64));
1661       XDrawArc(im->x.disp, p->image->pixmap, p->image->gc, x, 0, w-1, h-1, (0 * 64), (360 * 64));
1662       XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1663       XDrawArc(im->x.disp, p->image->pixmap, p->image->gc, x, 0, w-1, h-1, (0 * 64), (360 * 64));
1664       XUNLOCK (im->x.x_unlock_display, im->x.disp);
1665 
1666       x += w;
1667     }
1668   }
1669 }
1670 
1671 /*
1672  *
1673  */
draw_rotate_button(ImlibData * im,xitk_image_t * p)1674 void draw_rotate_button(ImlibData *im, xitk_image_t *p) {
1675   int           w;
1676   int           h;
1677 
1678   ABORT_IF_NULL(im);
1679   ABORT_IF_NULL(p);
1680 
1681   w = p->width;
1682   h = p->height;
1683 
1684   XLOCK (im->x.x_lock_display, im->x.disp);
1685 
1686   /* Draw mask */
1687   XSetForeground(im->x.disp, p->mask->gc, 0);
1688   XFillRectangle(im->x.disp, p->mask->pixmap, p->mask->gc, 0, 0, w , h);
1689 
1690   XSetForeground(im->x.disp, p->mask->gc, 1);
1691   XFillArc(im->x.disp, p->mask->pixmap, p->mask->gc, 0, 0, w-1, h-1, (0 * 64), (360 * 64));
1692   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1693 
1694   /* */
1695   XLOCK (im->x.x_lock_display, im->x.disp);
1696   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_gray(im));
1697   XFillArc(im->x.disp, p->image->pixmap, p->image->gc, 0, 0, w-1, h-1, (0 * 64), (360 * 64));
1698 
1699   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_white(im));
1700   //  XDrawArc(im->x.disp, p->image, p->image->gc, 0, 0, w-1, h-1, (30 * 64), (180 * 64));
1701   XDrawArc(im->x.disp, p->image->pixmap, p->image->gc, 1, 1, w-2, h-2, (30 * 64), (180 * 64));
1702   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1703 
1704   XLOCK (im->x.x_lock_display, im->x.disp);
1705   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_darkgray(im));
1706   //  XDrawArc(im->x.disp, p->image, p->image->gc, 0, 0, w-1, h-1, (210 * 64), (180 * 64));
1707   XDrawArc(im->x.disp, p->image->pixmap, p->image->gc, 1, 1, w-3, h-3, (210 * 64), (180 * 64));
1708   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1709 }
1710 
1711 /*
1712  *
1713  */
draw_button_plus(ImlibData * im,xitk_image_t * p)1714 void draw_button_plus(ImlibData *im, xitk_image_t *p) {
1715   int           w, h;
1716 
1717   ABORT_IF_NULL(im);
1718   ABORT_IF_NULL(p);
1719 
1720   draw_button_minus(im, p);
1721 
1722   w = p->width / 3;
1723   h = p->height;
1724 
1725   XLOCK (im->x.x_lock_display, im->x.disp);
1726   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1727 
1728   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w >> 1) - 1, 2, (w >> 1) - 1, h - 4);
1729   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w + (w >> 1) - 1, 2, w + (w >> 1) - 1, h - 4);
1730   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2) + (w >> 1), 3, (w * 2) + (w >> 1), h - 3);
1731 
1732   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1733 }
1734 
1735 /*
1736  *
1737  */
draw_button_minus(ImlibData * im,xitk_image_t * p)1738 void draw_button_minus(ImlibData *im, xitk_image_t *p) {
1739   int           w, h;
1740 
1741   ABORT_IF_NULL(im);
1742   ABORT_IF_NULL(p);
1743 
1744   w = p->width / 3;
1745   h = p->height;
1746 
1747   XLOCK (im->x.x_lock_display, im->x.disp);
1748   XSetForeground(im->x.disp, p->image->gc, xitk_get_pixel_color_black(im));
1749 
1750   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, 2, (h >> 1) - 1, w - 4, (h >> 1) - 1);
1751   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, w + 2, (h >> 1) - 1, (w * 2) - 4, (h >> 1) - 1);
1752   XDrawLine(im->x.disp, p->image->pixmap, p->image->gc, (w * 2) + 3, h >> 1, (w * 3) - 3, h >> 1);
1753 
1754   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1755 }
1756 
1757 /*
1758  *
1759  */
xitk_image_load_image(ImlibData * im,const char * image)1760 xitk_image_t *xitk_image_load_image(ImlibData *im, const char *image) {
1761   ImlibImage    *img = NULL;
1762   xitk_image_t  *i;
1763 
1764   ABORT_IF_NULL(im);
1765 
1766   if(image == NULL) {
1767     XITK_WARNING("image name is NULL\n");
1768     return NULL;
1769   }
1770 
1771   XLOCK (im->x.x_lock_display, im->x.disp);
1772   if(!(img = Imlib_load_image(im, (char *)image))) {
1773     XITK_WARNING("%s(): couldn't find image %s\n", __FUNCTION__, image);
1774     XUNLOCK (im->x.x_unlock_display, im->x.disp);
1775     return NULL;
1776   }
1777 
1778   Imlib_render (im, img, img->rgb_width, img->rgb_height);
1779   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1780 
1781   i = (xitk_image_t *) xitk_xmalloc(sizeof(xitk_image_t));
1782   i->image         = xitk_image_create_xitk_pixmap(im, img->rgb_width, img->rgb_height);
1783   i->pix_font      = NULL;
1784   XLOCK (im->x.x_lock_display, im->x.disp);
1785   i->image->pixmap = Imlib_copy_image(im, img);
1786   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1787 
1788   if(img->shape_mask) {
1789     i->mask          = xitk_image_create_xitk_mask_pixmap(im, img->rgb_width, img->rgb_height);
1790     XLOCK (im->x.x_lock_display, im->x.disp);
1791     i->mask->pixmap  = Imlib_copy_mask(im, img);
1792     XUNLOCK (im->x.x_unlock_display, im->x.disp);
1793   }
1794   else {
1795     i->mask = NULL;
1796   }
1797 
1798   i->width         = img->rgb_width;
1799   i->height        = img->rgb_height;
1800 
1801   XLOCK (im->x.x_lock_display, im->x.disp);
1802   Imlib_destroy_image(im, img);
1803   XUNLOCK (im->x.x_unlock_display, im->x.disp);
1804 
1805   return i;
1806 }
1807 
1808 /*
1809  * ********************************************************************************
1810  *                              Widget specific part
1811  * ********************************************************************************
1812  */
1813 
1814 /*
1815  *
1816  */
notify_destroy(xitk_widget_t * w)1817 static void notify_destroy(xitk_widget_t *w) {
1818   image_private_data_t *private_data;
1819 
1820   if(w && ((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_IMAGE)) {
1821     private_data = (image_private_data_t *) w->private_data;
1822 
1823     if(!private_data->skin_element_name)
1824       xitk_image_free_image(private_data->imlibdata, &(private_data->skin));
1825 
1826     XITK_FREE(private_data->skin_element_name);
1827     XITK_FREE(private_data);
1828   }
1829 }
1830 
1831 /*
1832  *
1833  */
notify_inside(xitk_widget_t * w,int x,int y)1834 static int notify_inside(xitk_widget_t *w, int x, int y) {
1835   return 0;
1836 }
1837 
1838 /*
1839  *
1840  */
get_skin(xitk_widget_t * w,int sk)1841 static xitk_image_t *get_skin(xitk_widget_t *w, int sk) {
1842   image_private_data_t *private_data;
1843 
1844   if(w && ((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_IMAGE)) {
1845     private_data = (image_private_data_t *) w->private_data;
1846     if(sk == BACKGROUND_SKIN && private_data->skin) {
1847       return private_data->skin;
1848     }
1849   }
1850 
1851   return NULL;
1852 }
1853 
1854 /*
1855  *
1856  */
paint_image(xitk_widget_t * w)1857 static void paint_image (xitk_widget_t *w) {
1858   image_private_data_t *private_data;
1859   xitk_image_t         *skin;
1860   GC                    lgc;
1861 
1862   if(w && (((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_IMAGE) && w->visible == 1)) {
1863     private_data = (image_private_data_t *) w->private_data;
1864 
1865     skin = private_data->skin;
1866 
1867     XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
1868     lgc = XCreateGC(private_data->imlibdata->x.disp, w->wl->win, None, None);
1869     XCopyGC(private_data->imlibdata->x.disp, w->wl->gc, (1 << GCLastBit) - 1, lgc);
1870     XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
1871 
1872     if (skin->mask) {
1873       XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
1874       XSetClipOrigin(private_data->imlibdata->x.disp, lgc, w->x, w->y);
1875       XSetClipMask(private_data->imlibdata->x.disp, lgc, skin->mask->pixmap);
1876       XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
1877     }
1878 
1879     XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
1880     XCopyArea (private_data->imlibdata->x.disp, skin->image->pixmap, w->wl->win, lgc, 0, 0,
1881 	       skin->width, skin->height, w->x, w->y);
1882 
1883     XFreeGC(private_data->imlibdata->x.disp, lgc);
1884     XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
1885   }
1886 
1887 }
1888 
1889 /*
1890  *
1891  */
notify_change_skin(xitk_widget_t * w,xitk_skin_config_t * skonfig)1892 static void notify_change_skin(xitk_widget_t *w, xitk_skin_config_t *skonfig) {
1893   image_private_data_t *private_data;
1894 
1895   if(w && (((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_IMAGE) && w->visible == 1)) {
1896     private_data = (image_private_data_t *) w->private_data;
1897 
1898     if(private_data->skin_element_name) {
1899 
1900       xitk_skin_lock(skonfig);
1901 
1902       private_data->skin = xitk_skin_get_image(skonfig,
1903 					       xitk_skin_get_skin_filename(skonfig, private_data->skin_element_name));
1904 
1905       w->x               = xitk_skin_get_coord_x(skonfig, private_data->skin_element_name);
1906       w->y               = xitk_skin_get_coord_y(skonfig, private_data->skin_element_name);
1907       w->width           = private_data->skin->width;
1908       w->height          = private_data->skin->height;
1909 
1910       xitk_skin_unlock(skonfig);
1911 
1912       xitk_set_widget_pos(w, w->x, w->y);
1913     }
1914   }
1915 }
1916 
notify_event(xitk_widget_t * w,widget_event_t * event,widget_event_result_t * result)1917 static int notify_event(xitk_widget_t *w, widget_event_t *event, widget_event_result_t *result) {
1918   int retval = 0;
1919 
1920   switch(event->type) {
1921   case WIDGET_EVENT_PAINT:
1922     paint_image(w);
1923     break;
1924   case WIDGET_EVENT_INSIDE:
1925     result->value = notify_inside(w, event->x, event->y);
1926     retval = 1;
1927     break;
1928   case WIDGET_EVENT_CHANGE_SKIN:
1929     notify_change_skin(w, event->skonfig);
1930     break;
1931   case WIDGET_EVENT_DESTROY:
1932     notify_destroy(w);
1933     break;
1934   case WIDGET_EVENT_GET_SKIN:
1935     if(result) {
1936       result->image = get_skin(w, event->skin_layer);
1937       retval = 1;
1938     }
1939     break;
1940   }
1941 
1942   return retval;
1943 }
1944 
1945 /*
1946  *
1947  */
_xitk_image_create(xitk_widget_list_t * wl,xitk_skin_config_t * skonfig,xitk_image_widget_t * im,int x,int y,const char * skin_element_name,xitk_image_t * skin)1948 static xitk_widget_t *_xitk_image_create (xitk_widget_list_t *wl,
1949 					  xitk_skin_config_t *skonfig,
1950 					  xitk_image_widget_t *im,
1951 					  int x, int y,
1952 					  const char *skin_element_name,
1953 					  xitk_image_t *skin) {
1954   xitk_widget_t              *mywidget;
1955   image_private_data_t       *private_data;
1956 
1957   mywidget = (xitk_widget_t *) xitk_xmalloc (sizeof(xitk_widget_t));
1958 
1959   private_data = (image_private_data_t *) xitk_xmalloc (sizeof (image_private_data_t));
1960 
1961   private_data->imlibdata         = im->imlibdata;
1962   private_data->skin_element_name = (skin_element_name == NULL) ? NULL : strdup(im->skin_element_name);
1963 
1964   private_data->bWidget           = mywidget;
1965   private_data->skin              = skin;
1966 
1967   mywidget->private_data          = private_data;
1968 
1969   mywidget->wl                    = wl;
1970 
1971   mywidget->enable                = 0;
1972   mywidget->running               = 1;
1973   mywidget->visible               = 0;
1974   mywidget->have_focus            = FOCUS_LOST;
1975   mywidget->imlibdata             = private_data->imlibdata;
1976   mywidget->x                     = x;
1977   mywidget->y                     = y;
1978   mywidget->width                 = private_data->skin->width;
1979   mywidget->height                = private_data->skin->height;
1980   mywidget->type                  = WIDGET_TYPE_IMAGE;
1981   mywidget->event                 = notify_event;
1982   mywidget->tips_timeout          = 0;
1983   mywidget->tips_string           = NULL;
1984 
1985   return mywidget;
1986 }
1987 
xitk_image_create(xitk_widget_list_t * wl,xitk_skin_config_t * skonfig,xitk_image_widget_t * im)1988 xitk_widget_t *xitk_image_create (xitk_widget_list_t *wl,
1989 				  xitk_skin_config_t *skonfig, xitk_image_widget_t *im) {
1990 
1991   XITK_CHECK_CONSTITENCY(im);
1992 
1993   return _xitk_image_create(wl, skonfig, im,
1994 			    (xitk_skin_get_coord_x(skonfig, im->skin_element_name)),
1995 			    (xitk_skin_get_coord_y(skonfig, im->skin_element_name)),
1996 			    im->skin_element_name,
1997 			    (xitk_skin_get_image(skonfig,
1998 						 xitk_skin_get_skin_filename(skonfig, im->skin_element_name))));
1999 }
2000 
2001 /*
2002  *
2003  */
xitk_noskin_image_create(xitk_widget_list_t * wl,xitk_image_widget_t * im,xitk_image_t * image,int x,int y)2004 xitk_widget_t *xitk_noskin_image_create (xitk_widget_list_t *wl,
2005 					 xitk_image_widget_t *im,
2006 					 xitk_image_t *image, int x, int y) {
2007   XITK_CHECK_CONSTITENCY(im);
2008 
2009   return _xitk_image_create(wl, NULL, im, x, y, NULL, image);
2010 }
2011