merged hv7 mod
[goodguy/history.git] / cinelerra-5.1 / guicast / bcresources.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009-2015 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program 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  * This program 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bcipc.h"
24 #include "bclistbox.inc"
25 #include "bcfontentry.h"
26 #include "bcresources.h"
27 #include "bcsignals.h"
28 #include "bcsynchronous.h"
29 #include "bcwindowbase.h"
30 #include "bccolors.h"
31 #include "bccmodels.h"
32 #include "cstrdup.h"
33 #include "fonts.h"
34 #include "language.h"
35 #include "vframe.h"
36
37 #include <string.h>
38 #include <iconv.h>
39 #include <sys/ipc.h>
40 #include <sys/shm.h>
41 #include <X11/extensions/XShm.h>
42 #include <fontconfig/fontconfig.h>
43 #include <fontconfig/fcfreetype.h>
44 #include <unistd.h>
45
46
47
48
49
50 int BC_Resources::error = 0;
51
52 VFrame* BC_Resources::bg_image = 0;
53 VFrame* BC_Resources::menu_bg = 0;
54
55 int BC_Resources::locale_utf8 = 0;
56 int BC_Resources::little_endian = 0;
57 char BC_Resources::language[LEN_LANG] = {0};
58 char BC_Resources::region[LEN_LANG] = {0};
59 char BC_Resources::encoding[LEN_ENCOD] = {0};
60 const char *BC_Resources::wide_encoding = 0;
61 ArrayList<BC_FontEntry*> *BC_Resources::fontlist = 0;
62 const char *BC_Resources::fc_properties[] = { FC_SLANT, FC_WEIGHT, FC_WIDTH };
63 #define LEN_FCPROP (sizeof(BC_Resources::fc_properties) / sizeof(const char*))
64
65 static const char *def_small_font = "-*-helvetica-medium-r-normal-*-%d-*";  // 10
66 static const char *def_small_font2 = "-*-helvetica-medium-r-normal-*-%d-*"; // 11
67 static const char *def_medium_font = "-*-helvetica-bold-r-normal-*-%d-*";   // 14
68 static const char *def_medium_font2 = "-*-helvetica-bold-r-normal-*-%d-*";  // 14
69 static const char *def_large_font = "-*-helvetica-bold-r-normal-*-%d-*";    // 18
70 static const char *def_large_font2 = "-*-helvetica-bold-r-normal-*-%d-*";   // 20
71 static const char *def_big_font =
72   "-*-bitstream charter-bold-r-normal-*-*-0-%d-%d-p-0-iso8859-1"; // 160
73 static const char *def_big_font2 =
74   "-*-nimbus sans l-bold-r-normal-*-*-0-%d-%d-p-0-iso8859-1";     // 160
75 static const char *def_clock_font = "-*-helvetica-bold-r-normal-*-%d-*";      // 16
76 static const char *def_clock_font2 = "-*-helvetica-bold-r-normal-*-%d-*";     // 18
77 static const char *def_small_fontset =  "-*-helvetica-medium-r-normal-*-%d-*";// 10
78 static const char *def_medium_fontset = "-*-helvetica-bold-r-normal-*-%d-*";  // 14
79 static const char *def_large_fontset =  "-*-helvetica-bold-r-normal-*-%d-*";  // 18
80 static const char *def_big_fontset =    "-*-helvetica-bold-r-normal-*-%d-*";  // 24
81 static const char *def_clock_fontset = "-*-helvetica-bold-r-normal-*-%d-*";   // 16
82
83 static const char *def_small_font_xft = "Sans:pixelsize=%.4f";           // 10.6667
84 static const char *def_small_b_font_xft = "Sans:bold:pixelsize=%.4f";    // 10.6667
85 static const char *def_medium_font_xft = "Sans:pixelsize=%.4f";          // 13.3333
86 static const char *def_medium_b_font_xft = "Sans:bold:pixelsize=%.4f";   // 13.3333
87 static const char *def_large_font_xft = "Sans:pixelsize=%.4f";           // 21.3333
88 static const char *def_large_b_font_xft = "Sans:bold:pixelsize=%.4f";    // 21.3333
89 static const char *def_big_font_xft = "Sans:pixelsize=37.3333";          // 37.3333
90 static const char *def_big_b_font_xft = "Sans:bold:pixelsize=37.33333";  // 37.3333
91 static const char *def_clock_font_xft = "Sans:pixelsize=16";             // 16
92
93 #define default_font_xft2 "-microsoft-verdana-*-*-*-*-*-*-*-*-*-*-*-*"
94
95 const char* BC_Resources::small_font = 0;
96 const char* BC_Resources::small_font2 = 0;
97 const char* BC_Resources::medium_font = 0;
98 const char* BC_Resources::medium_font2 = 0;
99 const char* BC_Resources::large_font = 0;
100 const char* BC_Resources::large_font2 = 0;
101 const char* BC_Resources::big_font = 0;
102 const char* BC_Resources::big_font2 = 0;
103 const char* BC_Resources::clock_font = 0;
104 const char* BC_Resources::clock_font2 = 0;
105 const char* BC_Resources::small_fontset = 0;
106 const char* BC_Resources::medium_fontset = 0;
107 const char* BC_Resources::large_fontset = 0;
108 const char* BC_Resources::big_fontset = 0;
109 const char* BC_Resources::clock_fontset = 0;
110 const char* BC_Resources::small_font_xft = 0;
111 const char* BC_Resources::small_font_xft2 = 0;
112 const char* BC_Resources::small_b_font_xft = 0;
113 const char* BC_Resources::medium_font_xft = 0;
114 const char* BC_Resources::medium_font_xft2 = 0;
115 const char* BC_Resources::medium_b_font_xft = 0;
116 const char* BC_Resources::large_font_xft = 0;
117 const char* BC_Resources::large_font_xft2 = 0;
118 const char* BC_Resources::large_b_font_xft = 0;
119 const char* BC_Resources::big_font_xft = 0;
120 const char* BC_Resources::big_font_xft2 = 0;
121 const char* BC_Resources::big_b_font_xft = 0;
122 const char* BC_Resources::clock_font_xft = 0;
123 const char* BC_Resources::clock_font_xft2 = 0;
124
125 #define def_font(v, s...) do { sprintf(string,def_##v,s); v = cstrdup(string); } while(0)
126 #define set_font(v, s) do { sprintf(string, "%s", s); v = cstrdup(string); } while(0)
127 #define iround(v) ((int)(v+0.5))
128 void BC_Resources::init_font_defs(double scale)
129 {
130         char string[BCTEXTLEN];
131         def_font(small_font,       iround(scale*11));
132         def_font(small_font2,      iround(scale*11));
133         def_font(medium_font,      iround(scale*14));
134         def_font(medium_font2,     iround(scale*14));
135         def_font(large_font,       iround(scale*18));
136         def_font(large_font2,      iround(scale*20));
137         def_font(big_font,         iround(scale*160), iround(scale*160));
138         def_font(big_font2,        iround(scale*16), iround(scale*16));
139         def_font(clock_font,       iround(scale*16), iround(scale*16));
140         def_font(clock_font2,      iround(scale*16), iround(scale*16));
141         def_font(small_fontset,    iround(scale*10));
142         def_font(medium_fontset,   iround(scale*14));
143         def_font(large_fontset,    iround(scale*18));
144         def_font(big_fontset,      iround(scale*24));
145         def_font(clock_fontset,    iround(scale*16));
146         def_font(small_font_xft,   (scale*10.6667));
147         def_font(small_b_font_xft, (scale*10.6667));
148         def_font(medium_font_xft,  (scale*13.3333));
149         def_font(medium_b_font_xft,(scale*13.3333));
150         def_font(large_font_xft,   (scale*21.3333));
151         def_font(large_b_font_xft, (scale*21.3333));
152         def_font(big_font_xft,     (scale*37.3333));
153         def_font(big_b_font_xft,   (scale*37.3333));
154         def_font(clock_font_xft,   (scale*16));
155
156         set_font(small_font_xft2,  default_font_xft2);
157         set_font(medium_font_xft2, default_font_xft2);
158         set_font(large_font_xft2,  default_font_xft2);
159         set_font(big_font_xft2,    default_font_xft2);
160         set_font(clock_font_xft2,  default_font_xft2);
161 }
162 void BC_Resources::finit_font_defs()
163 {
164         delete [] small_font;
165         delete [] small_font2;
166         delete [] medium_font;
167         delete [] medium_font2;
168         delete [] large_font;
169         delete [] large_font2;
170         delete [] big_font;
171         delete [] big_font2;
172         delete [] clock_font;
173         delete [] clock_font2;
174         delete [] small_fontset;
175         delete [] medium_fontset;
176         delete [] large_fontset;
177         delete [] big_fontset;
178         delete [] clock_fontset;
179         delete [] small_font_xft;
180         delete [] small_b_font_xft;
181         delete [] medium_font_xft;
182         delete [] medium_b_font_xft;
183         delete [] large_font_xft;
184         delete [] large_b_font_xft;
185         delete [] big_font_xft;
186         delete [] big_b_font_xft;
187         delete [] clock_font_xft;
188
189         delete [] small_font_xft2;
190         delete [] medium_font_xft2;
191         delete [] large_font_xft2;
192         delete [] big_font_xft2;
193         delete [] clock_font_xft2;
194 }
195
196
197 suffix_to_type_t BC_Resources::suffix_to_type[] =
198 {
199     { "aac", ICON_SOUND },
200     { "ac3", ICON_SOUND },
201     { "dts", ICON_SOUND },
202     { "flac", ICON_SOUND },
203     { "mp2", ICON_SOUND },
204     { "mp3", ICON_SOUND },
205     { "wav", ICON_SOUND },
206     { "wma", ICON_SOUND },
207     { "wmv", ICON_SOUND },
208     { "avi", ICON_FILM },
209     { "bmp", ICON_FILM },
210     { "cr2", ICON_FILM },
211     { "dnxhd", ICON_FILM },
212     { "dvd", ICON_FILM },
213     { "dv", ICON_FILM },
214     { "f4v", ICON_FILM },
215     { "flv", ICON_FILM },
216     { "gif", ICON_FILM },
217     { "gxf", ICON_FILM },
218     { "h264", ICON_FILM },
219     { "h265", ICON_FILM },
220     { "hevc", ICON_FILM },
221     { "ifo", ICON_FILM },
222     { "jpeg", ICON_FILM },
223     { "jpg", ICON_FILM },
224     { "m2t", ICON_FILM },
225     { "m2ts", ICON_FILM },
226     { "m2v", ICON_FILM },
227     { "m4v", ICON_FILM },
228     { "mkv", ICON_FILM },
229     { "mov", ICON_FILM },
230     { "mp4", ICON_FILM },
231     { "mpeg", ICON_FILM },
232     { "mpg", ICON_FILM },
233     { "mts", ICON_FILM },
234     { "mxf", ICON_FILM },
235     { "ogg", ICON_FILM },
236     { "ogv", ICON_FILM },
237     { "pcm", ICON_FILM },
238     { "pgm", ICON_FILM },
239     { "png", ICON_FILM },
240     { "ppm", ICON_FILM },
241     { "qt", ICON_FILM },
242     { "rm", ICON_FILM },
243     { "swf", ICON_FILM },
244     { "tiff", ICON_FILM },
245     { "tif", ICON_FILM },
246     { "ts",  ICON_FILM },
247     { "vob", ICON_FILM },
248     { "vts", ICON_FILM },
249     { "webm", ICON_FILM },
250     { "webp", ICON_FILM },
251     { "xml", ICON_FILM },
252     { "y4m", ICON_FILM },
253     { 0, 0 },
254 };
255
256 BC_Signals* BC_Resources::signal_handler = 0;
257 Mutex BC_Resources::fontconfig_lock("BC_Resources::fonconfig_lock");
258
259 int BC_Resources::x_error_handler(Display *display, XErrorEvent *event)
260 {
261 #if defined(OUTPUT_X_ERROR)
262         char string[1024];
263         XGetErrorText(event->display, event->error_code, string, 1024);
264         fprintf(stderr, "BC_Resources::x_error_handler: error_code=%d opcode=%d,%d %s\n",
265                 event->error_code,
266                 event->request_code,
267                 event->minor_code,
268                 string);
269 #endif
270
271         BC_Resources::error = 1;
272 // This bug only happens in 32 bit mode.
273 //      if(sizeof(long) == 4)
274 //              BC_WindowBase::get_resources()->use_xft = 0;
275         return 0;
276 }
277
278 int BC_Resources::machine_cpus = 1;
279
280 int BC_Resources::get_machine_cpus()
281 {
282         int cpus = 1;
283         FILE *proc = fopen("/proc/cpuinfo", "r");
284         if( proc ) {
285                 char string[BCTEXTLEN], *cp;
286                 while(!feof(proc) && fgets(string, sizeof(string), proc) ) {
287                         if( !strncasecmp(string, "processor", 9) &&
288                             (cp = strchr(string, ':')) != 0 ) {
289                                 int n = atol(cp+1) + 1;
290                                 if( n > cpus ) cpus = n;
291                         }
292                         else if( !strncasecmp(string, "cpus detected", 13) &&
293                             (cp = strchr(string, ':')) != 0 )
294                                 cpus = atol(cp+1);
295                 }
296                 fclose(proc);
297         }
298         return cpus;
299 }
300
301 void BC_Resources::new_vframes(int n, VFrame *vframes[], ...)
302 {
303         va_list ap;
304         va_start(ap, vframes);
305         for( int i=0; i<n; ++i )
306                 vframes[i] = va_arg(ap, VFrame *);
307         va_end(ap);
308 }
309
310 VFrame *BC_Resources::default_type_to_icon[6] = { 0, };
311 VFrame *BC_Resources::default_bar = 0;
312 VFrame *BC_Resources::default_cancel_images[3] = { 0, };
313 VFrame *BC_Resources::default_ok_images[3] = { 0, };
314 VFrame *BC_Resources::default_usethis_images[3] = { 0, };
315 #if 0
316 VFrame *BC_Resources::default_checkbox_images[5] = { 0, };
317 VFrame *BC_Resources::default_radial_images[5] = { 0, };
318 VFrame *BC_Resources::default_label_images[5] = { 0, };
319 #endif
320 VFrame *BC_Resources::default_menuitem_data[3] = { 0, };
321 VFrame *BC_Resources::default_menubar_data[3] = { 0, };
322 VFrame *BC_Resources::default_menu_popup_bg = 0;
323 VFrame *BC_Resources::default_menu_bar_bg = 0;
324 VFrame *BC_Resources::default_check_image = 0;
325 VFrame *BC_Resources::default_filebox_text_images[3] = { 0, };
326 VFrame *BC_Resources::default_filebox_icons_images[3] = { 0, };
327 VFrame *BC_Resources::default_filebox_updir_images[3] = { 0, };
328 VFrame *BC_Resources::default_filebox_newfolder_images[3] = { 0, };
329 VFrame *BC_Resources::default_filebox_rename_images[3] = { 0, };
330 VFrame *BC_Resources::default_filebox_delete_images[3] = { 0, };
331 VFrame *BC_Resources::default_filebox_reload_images[3] = { 0, };
332 VFrame *BC_Resources::default_listbox_button[4] = { 0, };
333 VFrame *BC_Resources::default_listbox_bg = 0;
334 VFrame *BC_Resources::default_listbox_expand[5] = { 0, };
335 VFrame *BC_Resources::default_listbox_column[3] = { 0, };
336 VFrame *BC_Resources::default_listbox_up = 0;
337 VFrame *BC_Resources::default_listbox_dn = 0;
338 VFrame *BC_Resources::default_pot_images[3] = { 0, };
339 VFrame *BC_Resources::default_progress_images[2] = { 0, };
340 VFrame *BC_Resources::default_medium_7segment[20] = { 0, };
341
342 BC_Resources::BC_Resources()
343 {
344         synchronous = 0;
345         vframe_shm = 0;
346         double default_scale = 1.0; // display_size/1000.;
347         char *env = getenv("BC_FONT_SCALE");
348         font_scale = env ? atof(env) : default_scale;
349         if( font_scale <= 0 ) font_scale = 1;
350         init_font_defs(font_scale);
351         env = getenv("BC_ICON_SCALE");
352         icon_scale = env ? atof(env) : default_scale;
353         if( icon_scale <= 0 ) icon_scale = 1;
354
355         id_lock = new Mutex("BC_Resources::id_lock");
356         create_window_lock = new Mutex("BC_Resources::create_window_lock", 1);
357         id = 0;
358         machine_cpus = get_machine_cpus();
359
360         for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
361                 filebox_history[i].path[0] = 0;
362
363 #ifdef HAVE_XFT
364         XftInitFtLibrary();
365 #endif
366
367         little_endian = (*(const u_int32_t*)"\01\0\0\0") & 1;
368         wide_encoding = little_endian ?  "UTF32LE" : "UTF32BE";
369         use_xvideo = 1;
370
371 #include "images/file_folder_png.h"
372 #include "images/file_unknown_png.h"
373 #include "images/file_film_png.h"
374 #include "images/file_sound_png.h"
375 #include "images/file_label_png.h"
376 #include "images/file_column_png.h"
377 new_vframes(6,default_type_to_icon,
378         new VFramePng(file_folder_png),
379         new VFramePng(file_unknown_png),
380         new VFramePng(file_film_png),
381         new VFramePng(file_sound_png),
382         new VFramePng(file_label_png),
383         new VFramePng(file_column_png));
384
385 #include "images/bar_png.h"
386         default_bar = new VFramePng(bar_png);
387
388 #include "images/cancel_up_png.h"
389 #include "images/cancel_hi_png.h"
390 #include "images/cancel_dn_png.h"
391 new_vframes(3,default_cancel_images,
392         new VFramePng(cancel_up_png),
393         new VFramePng(cancel_hi_png),
394         new VFramePng(cancel_dn_png));
395
396 #include "images/ok_up_png.h"
397 #include "images/ok_hi_png.h"
398 #include "images/ok_dn_png.h"
399 new_vframes(3,default_ok_images,
400         new VFramePng(ok_up_png),
401         new VFramePng(ok_hi_png),
402         new VFramePng(ok_dn_png));
403
404 #include "images/usethis_up_png.h"
405 #include "images/usethis_uphi_png.h"
406 #include "images/usethis_dn_png.h"
407 new_vframes(3,default_usethis_images,
408         new VFramePng(usethis_up_png),
409         new VFramePng(usethis_uphi_png),
410         new VFramePng(usethis_dn_png));
411
412 #if 0
413 #include "images/checkbox_checked_png.h"
414 #include "images/checkbox_dn_png.h"
415 #include "images/checkbox_checkedhi_png.h"
416 #include "images/checkbox_up_png.h"
417 #include "images/checkbox_hi_png.h"
418 new_vframes(5,default_checkbox_images,
419         new VFramePng(checkbox_up_png),
420         new VFramePng(checkbox_hi_png),
421         new VFramePng(checkbox_checked_png),
422         new VFramePng(checkbox_dn_png),
423         new VFramePng(checkbox_checkedhi_png));
424
425 #include "images/radial_checked_png.h"
426 #include "images/radial_dn_png.h"
427 #include "images/radial_checkedhi_png.h"
428 #include "images/radial_up_png.h"
429 #include "images/radial_hi_png.h"
430 new_vframes(5,default_radial_images,
431         new VFramePng(radial_up_png),
432         new VFramePng(radial_hi_png),
433         new VFramePng(radial_checked_png),
434         new VFramePng(radial_dn_png),
435         new VFramePng(radial_checkedhi_png));
436
437 new_vframes(5,default_label_images,
438         new VFramePng(radial_up_png),
439         new VFramePng(radial_hi_png),
440         new VFramePng(radial_checked_png),
441         new VFramePng(radial_dn_png),
442         new VFramePng(radial_checkedhi_png));
443 #endif
444
445 #include "images/menuitem_up_png.h"
446 #include "images/menuitem_hi_png.h"
447 #include "images/menuitem_dn_png.h"
448 new_vframes(3,default_menuitem_data,
449         new VFramePng(menuitem_up_png),
450         new VFramePng(menuitem_hi_png),
451         new VFramePng(menuitem_dn_png));
452
453 #include "images/menubar_up_png.h"
454 #include "images/menubar_hi_png.h"
455 #include "images/menubar_dn_png.h"
456 new_vframes(3,default_menubar_data,
457         new VFramePng(menubar_up_png),
458         new VFramePng(menubar_hi_png),
459         new VFramePng(menubar_dn_png));
460
461 #include "images/menu_popup_bg_png.h"
462         default_menu_popup_bg = new VFramePng(menu_popup_bg_png);
463
464 #include "images/menubar_bg_png.h"
465         default_menu_bar_bg = new VFramePng(menubar_bg_png);
466
467 #include "images/check_png.h"
468         default_check_image = new VFramePng(check_png);
469
470 #include "images/file_text_up_png.h"
471 #include "images/file_text_hi_png.h"
472 #include "images/file_text_dn_png.h"
473 #include "images/file_icons_up_png.h"
474 #include "images/file_icons_hi_png.h"
475 #include "images/file_icons_dn_png.h"
476 #include "images/file_newfolder_up_png.h"
477 #include "images/file_newfolder_hi_png.h"
478 #include "images/file_newfolder_dn_png.h"
479 #include "images/file_rename_up_png.h"
480 #include "images/file_rename_hi_png.h"
481 #include "images/file_rename_dn_png.h"
482 #include "images/file_updir_up_png.h"
483 #include "images/file_updir_hi_png.h"
484 #include "images/file_updir_dn_png.h"
485 #include "images/file_delete_up_png.h"
486 #include "images/file_delete_hi_png.h"
487 #include "images/file_delete_dn_png.h"
488 #include "images/file_reload_up_png.h"
489 #include "images/file_reload_hi_png.h"
490 #include "images/file_reload_dn_png.h"
491 new_vframes(3,default_filebox_text_images,
492         new VFramePng(file_text_up_png),
493         new VFramePng(file_text_hi_png),
494         new VFramePng(file_text_dn_png));
495
496 new_vframes(3,default_filebox_icons_images,
497         new VFramePng(file_icons_up_png),
498         new VFramePng(file_icons_hi_png),
499         new VFramePng(file_icons_dn_png));
500
501 new_vframes(3,default_filebox_updir_images,
502         new VFramePng(file_updir_up_png),
503         new VFramePng(file_updir_hi_png),
504         new VFramePng(file_updir_dn_png));
505
506 new_vframes(3,default_filebox_newfolder_images,
507         new VFramePng(file_newfolder_up_png),
508         new VFramePng(file_newfolder_hi_png),
509         new VFramePng(file_newfolder_dn_png));
510
511 new_vframes(3,default_filebox_rename_images,
512         new VFramePng(file_rename_up_png),
513         new VFramePng(file_rename_hi_png),
514         new VFramePng(file_rename_dn_png));
515
516 new_vframes(3,default_filebox_delete_images,
517         new VFramePng(file_delete_up_png),
518         new VFramePng(file_delete_hi_png),
519         new VFramePng(file_delete_dn_png));
520
521 new_vframes(3,default_filebox_reload_images,
522         new VFramePng(file_reload_up_png),
523         new VFramePng(file_reload_hi_png),
524         new VFramePng(file_reload_dn_png));
525
526 #include "images/listbox_button_dn_png.h"
527 #include "images/listbox_button_hi_png.h"
528 #include "images/listbox_button_up_png.h"
529 #include "images/listbox_button_disabled_png.h"
530 new_vframes(4,default_listbox_button,
531         new VFramePng(listbox_button_up_png),
532         new VFramePng(listbox_button_hi_png),
533         new VFramePng(listbox_button_dn_png),
534         new VFramePng(listbox_button_disabled_png));
535
536 default_listbox_bg = 0;
537
538 #include "images/listbox_expandchecked_png.h"
539 #include "images/listbox_expandcheckedhi_png.h"
540 #include "images/listbox_expanddn_png.h"
541 #include "images/listbox_expandup_png.h"
542 #include "images/listbox_expanduphi_png.h"
543 new_vframes(5,default_listbox_expand,
544         new VFramePng(listbox_expandup_png),
545         new VFramePng(listbox_expanduphi_png),
546         new VFramePng(listbox_expandchecked_png),
547         new VFramePng(listbox_expanddn_png),
548         new VFramePng(listbox_expandcheckedhi_png));
549
550 #include "images/listbox_columnup_png.h"
551 #include "images/listbox_columnhi_png.h"
552 #include "images/listbox_columndn_png.h"
553 new_vframes(3,default_listbox_column,
554         new VFramePng(listbox_columnup_png),
555         new VFramePng(listbox_columnhi_png),
556         new VFramePng(listbox_columndn_png));
557
558 #include "images/listbox_up_png.h"
559         default_listbox_up = new VFramePng(listbox_up_png);
560
561 #include "images/listbox_dn_png.h"
562         default_listbox_dn = new VFramePng(listbox_dn_png);
563
564 #include "images/pot_hi_png.h"
565 #include "images/pot_up_png.h"
566 #include "images/pot_dn_png.h"
567 new_vframes(3,default_pot_images,
568         new VFramePng(pot_up_png),
569         new VFramePng(pot_hi_png),
570         new VFramePng(pot_dn_png));
571
572 #include "images/progress_up_png.h"
573 #include "images/progress_hi_png.h"
574 new_vframes(2,default_progress_images,
575         new VFramePng(progress_up_png),
576         new VFramePng(progress_hi_png));
577
578 #include "images/7seg_small/0_png.h"
579 #include "images/7seg_small/1_png.h"
580 #include "images/7seg_small/2_png.h"
581 #include "images/7seg_small/3_png.h"
582 #include "images/7seg_small/4_png.h"
583 #include "images/7seg_small/5_png.h"
584 #include "images/7seg_small/6_png.h"
585 #include "images/7seg_small/7_png.h"
586 #include "images/7seg_small/8_png.h"
587 #include "images/7seg_small/9_png.h"
588 #include "images/7seg_small/colon_png.h"
589 #include "images/7seg_small/period_png.h"
590 #include "images/7seg_small/a_png.h"
591 #include "images/7seg_small/b_png.h"
592 #include "images/7seg_small/c_png.h"
593 #include "images/7seg_small/d_png.h"
594 #include "images/7seg_small/e_png.h"
595 #include "images/7seg_small/f_png.h"
596 #include "images/7seg_small/space_png.h"
597 #include "images/7seg_small/dash_png.h"
598 new_vframes(20,default_medium_7segment,
599         new VFramePng(_0_png),
600         new VFramePng(_1_png),
601         new VFramePng(_2_png),
602         new VFramePng(_3_png),
603         new VFramePng(_4_png),
604         new VFramePng(_5_png),
605         new VFramePng(_6_png),
606         new VFramePng(_7_png),
607         new VFramePng(_8_png),
608         new VFramePng(_9_png),
609         new VFramePng(colon_png),
610         new VFramePng(period_png),
611         new VFramePng(a_png),
612         new VFramePng(b_png),
613         new VFramePng(c_png),
614         new VFramePng(d_png),
615         new VFramePng(e_png),
616         new VFramePng(f_png),
617         new VFramePng(space_png),
618         new VFramePng(dash_png));
619
620         type_to_icon = default_type_to_icon;
621         bar_data = default_bar;
622         check = default_check_image;
623         listbox_button = default_listbox_button;
624         listbox_bg = default_listbox_bg;
625         listbox_expand = default_listbox_expand;
626         listbox_column = default_listbox_column;
627         listbox_up = default_listbox_up;
628         listbox_dn = default_listbox_dn;
629         listbox_title_overlap = 0;
630         listbox_title_margin = 0;
631         listbox_title_color = BLACK;
632         listbox_title_hotspot = 5;
633
634         listbox_border1 = DKGREY;
635         listbox_border2_hi = RED;
636         listbox_border2 = BLACK;
637         listbox_border3_hi = RED;
638         listbox_border3 = MEGREY;
639         listbox_border4 = WHITE;
640         listbox_selected = BLUE;
641         listbox_highlighted = LTGREY;
642         listbox_inactive = WHITE;
643         listbox_text = BLACK;
644
645         pan_data = 0;
646         pan_text_color = YELLOW;
647
648         generic_button_margin = 15;
649         draw_clock_background=1;
650
651         use_shm = -1;
652         shm_reply = 1;
653
654 // Initialize
655         bg_color = ORANGE;
656         bg_shadow1 = DKGREY;
657         bg_shadow2 = BLACK;
658         bg_light1 = WHITE;
659         bg_light2 = bg_color;
660
661
662         border_light1 = bg_color;
663         border_light2 = MEGREY;
664         border_shadow1 = BLACK;
665         border_shadow2 = bg_color;
666
667         default_text_color = BLACK;
668         disabled_text_color = DMGREY;
669
670         button_light = MEGREY;           // bright corner
671 //      button_highlighted = LTGREY;  // face when highlighted
672         button_highlighted = 0xffe000;  // face when highlighted
673         button_down = MDGREY;         // face when down
674 //      button_up = MEGREY;           // face when up
675         button_up = 0xffc000;           // face when up
676         button_shadow = BLACK;       // dark corner
677         button_uphighlighted = RED;   // upper side when highlighted
678
679         tumble_data = 0;
680         tumble_duration = 150;
681
682         ok_images = default_ok_images;
683         cancel_images = default_cancel_images;
684         usethis_button_images = default_usethis_images;
685         filebox_descend_images = default_ok_images;
686
687         menu_light = LTCYAN;
688         menu_highlighted = LTBLUE;
689         menu_down = MDCYAN;
690         menu_up = MECYAN;
691         menu_shadow = DKCYAN;
692
693         menu_title_bg = default_menubar_data;
694         menu_popup_bg = default_menu_popup_bg;
695         menu_bar_bg = default_menu_bar_bg;
696
697         popupmenu_images = 0;
698
699
700         popupmenu_margin = 10;
701         popupmenu_btnup = 1;
702         popupmenu_triangle_margin = 10;
703
704         min_menu_w = 0;
705         menu_title_text = BLACK;
706         popup_title_text = BLACK;
707         menu_item_text = BLACK;
708         menu_highlighted_fontcolor = BLACK;
709         progress_text = BLACK;
710         grab_input_focus = 1;
711
712         text_default = BLACK;
713         highlight_inverse = WHITE ^ BLUE;
714         text_background = WHITE;
715         text_background_hi = LTYELLOW;
716         text_background_noborder_hi = LTGREY;
717         text_background_noborder = -1;
718         text_border1 = DKGREY;
719         text_border2 = BLACK;
720         text_border2_hi = RED;
721         text_border3 = MEGREY;
722         text_border3_hi = LTPINK;
723         text_border4 = WHITE;
724         text_highlight = BLUE;
725         text_selected_highlight = SLBLUE;
726         text_inactive_highlight = MEGREY;
727
728         toggle_highlight_bg = 0;
729         toggle_text_margin = 0;
730
731 // Delays must all be different for repeaters
732         double_click = 300;
733         blink_rate = 250;
734         scroll_repeat = 150;
735         tooltip_delay = 1000;
736         tooltip_bg_color = YELLOW;
737         tooltips_enabled = 1;
738         textbox_focus_policy = 0;
739
740         filebox_margin = 110;
741         dirbox_margin = 90;
742         filebox_mode = LISTBOX_TEXT;
743         sprintf(filebox_filter, "*");
744         filebox_w = 640;
745         filebox_h = 480;
746         filebox_columntype[0] = FILEBOX_NAME;
747         filebox_columntype[1] = FILEBOX_SIZE;
748         filebox_columntype[2] = FILEBOX_DATE;
749         filebox_columntype[3] = FILEBOX_EXTENSION;
750         filebox_columnwidth[0] = 200;
751         filebox_columnwidth[1] = 100;
752         filebox_columnwidth[2] = 100;
753         filebox_columnwidth[3] = 100;
754         dirbox_columntype[0] = FILEBOX_NAME;
755         dirbox_columntype[1] = FILEBOX_DATE;
756         dirbox_columnwidth[0] = 200;
757         dirbox_columnwidth[1] = 100;
758
759         filebox_text_images = default_filebox_text_images;
760         filebox_icons_images = default_filebox_icons_images;
761         filebox_updir_images = default_filebox_updir_images;
762         filebox_newfolder_images = default_filebox_newfolder_images;
763         filebox_rename_images = default_filebox_rename_images;
764         filebox_delete_images = default_filebox_delete_images;
765         filebox_reload_images = default_filebox_reload_images;
766         directory_color = BLUE;
767         file_color = BLACK;
768
769         filebox_sortcolumn = 0;
770         filebox_sortorder = BC_ListBox::SORT_ASCENDING;
771         dirbox_sortcolumn = 0;
772         dirbox_sortorder = BC_ListBox::SORT_ASCENDING;
773
774
775         pot_images = default_pot_images;
776         pot_offset = 2;
777         pot_x1 = pot_images[0]->get_w() / 2 - pot_offset;
778         pot_y1 = pot_images[0]->get_h() / 2 - pot_offset;
779         pot_r = pot_x1;
780         pot_needle_color = BLACK;
781
782         progress_images = default_progress_images;
783
784         xmeter_images = 0;
785         ymeter_images = 0;
786         meter_font = SMALLFONT_3D;
787         meter_font_color = RED;
788         meter_title_w = 20;
789         meter_3d = 1;
790         medium_7segment = default_medium_7segment;
791
792         audiovideo_color = RED;
793
794         use_fontset = 0;
795
796 // Xft has priority over font set
797 #ifdef HAVE_XFT
798 // But Xft dies in 32 bit mode after some amount of drawing.
799         use_xft = 1;
800 #else
801         use_xft = 0;
802 #endif
803
804
805         drag_radius = 10;
806         recursive_resizing = 1;
807
808
809 }
810
811 void BC_Resources::del_vframes(VFrame *vframes[], int n)
812 {
813         while( --n >= 0 ) delete vframes[n];
814 }
815
816 BC_Resources::~BC_Resources()
817 {
818         delete id_lock;
819         delete create_window_lock;
820         del_vframes(default_type_to_icon, 6);
821         delete default_bar;
822         del_vframes(default_cancel_images, 3);
823         del_vframes(default_ok_images, 3);
824         del_vframes(default_usethis_images, 3);
825 #if 0
826         del_vframes(default_checkbox_images, 5);
827         del_vframes(default_radial_images, 5);
828         del_vframes(default_label_images, 5);
829 #endif
830         del_vframes(default_menuitem_data, 3);
831         del_vframes(default_menubar_data, 3);
832         delete default_menu_popup_bg;
833         delete default_menu_bar_bg;
834         delete default_check_image;
835         del_vframes(default_filebox_text_images, 3);
836         del_vframes(default_filebox_icons_images, 3);
837         del_vframes(default_filebox_updir_images, 3);
838         del_vframes(default_filebox_newfolder_images, 3);
839         del_vframes(default_filebox_rename_images, 3);
840         del_vframes(default_filebox_delete_images, 3);
841         del_vframes(default_filebox_reload_images, 3);
842         del_vframes(default_listbox_button, 4);
843         delete default_listbox_bg;
844         del_vframes(default_listbox_expand, 5);
845         del_vframes(default_listbox_column, 3);
846         delete default_listbox_up;
847         delete default_listbox_dn;
848         del_vframes(default_pot_images, 3);
849         del_vframes(default_progress_images, 2);
850         del_vframes(default_medium_7segment, 20);
851         if( fontlist ) {
852                 fontlist->remove_all_objects();
853                 delete fontlist;
854         }
855         finit_font_defs();
856 }
857
858 int BC_Resources::initialize_display(BC_WindowBase *window)
859 {
860 // Set up IPC cleanup handlers
861 //      bc_init_ipc();
862
863 // Test for shm.  Must come before yuv test
864         init_shm(window);
865         return 0;
866 }
867
868
869 void BC_Resources::init_shm(BC_WindowBase *window)
870 {
871         use_shm = 0;
872         int (*old_handler)(Display *, XErrorEvent *) =
873                 XSetErrorHandler(BC_Resources::x_error_handler);
874
875         if(XShmQueryExtension(window->display))
876         {
877                 XShmSegmentInfo test_shm;
878                 memset(&test_shm,0,sizeof(test_shm));
879                 XImage *test_image = XShmCreateImage(window->display, window->vis,
880                         window->default_depth, ZPixmap, (char*)NULL, &test_shm, 5, 5);
881                 BC_Resources::error = 0;
882                 test_shm.shmid = shmget(IPC_PRIVATE, 5 * test_image->bytes_per_line, (IPC_CREAT | 0600));
883                 if(test_shm.shmid != -1) {
884                         char *data = (char *)shmat(test_shm.shmid, NULL, 0);
885                         if(data != (void *)-1) {
886                                 shmctl(test_shm.shmid, IPC_RMID, 0);
887                                 test_shm.shmaddr = data;
888                                 test_shm.readOnly = 0;
889
890                                 if(XShmAttach(window->display, &test_shm)) {
891                                         XSync(window->display, False);
892                                         use_shm = 1;
893                                 }
894                                 shmdt(data);
895                         }
896                 }
897
898                 XDestroyImage(test_image);
899                 if(BC_Resources::error) use_shm = 0;
900         }
901         XSetErrorHandler(old_handler);
902 }
903
904
905
906
907 BC_Synchronous* BC_Resources::get_synchronous()
908 {
909         return synchronous;
910 }
911
912 void BC_Resources::set_synchronous(BC_Synchronous *synchronous)
913 {
914         this->synchronous = synchronous;
915 }
916
917
918
919
920 int BC_Resources::get_bg_color() { return bg_color; }
921
922 int BC_Resources::get_bg_shadow1() { return bg_shadow1; }
923
924 int BC_Resources::get_bg_shadow2() { return bg_shadow2; }
925
926 int BC_Resources::get_bg_light1() { return bg_light1; }
927
928 int BC_Resources::get_bg_light2() { return bg_light2; }
929
930
931 int BC_Resources::get_id()
932 {
933         id_lock->lock("BC_Resources::get_id");
934         int result = id++;
935         id_lock->unlock();
936         return result;
937 }
938
939 int BC_Resources::get_filebox_id()
940 {
941         id_lock->lock("BC_Resources::get_filebox_id");
942         int result = filebox_id++;
943         id_lock->unlock();
944         return result;
945 }
946
947
948 void BC_Resources::set_signals(BC_Signals *signal_handler)
949 {
950         BC_Resources::signal_handler = signal_handler;
951 }
952
953 int BC_Resources::init_fontconfig(const char *search_path)
954 {
955         if( fontlist ) return 0;
956         fontlist = new ArrayList<BC_FontEntry*>;
957
958 #define get_str(str,sep,ptr,cond) do { char *out = str; \
959   while( *ptr && !strchr(sep,*ptr) && (cond) ) *out++ = *ptr++; \
960   *out = 0; \
961 } while(0)
962
963 #define skip_str(sep, ptr) do { \
964   while( *ptr && strchr(sep,*ptr) ) ++ptr; \
965 } while(0)
966
967         char find_command[BCTEXTLEN];
968         char *fp = find_command, *ep = fp+sizeof(find_command)-1;
969         fp += snprintf(fp, ep-fp, "find '%s'", search_path);
970         const char *bc_font_path = getenv("BC_FONT_PATH");
971         if( bc_font_path ) {
972                 const char *path = bc_font_path;
973                 for( int len=0; *path; path+=len ) {
974                         const char *cp = strchr(path,':');
975                         len = !cp ? strlen(path) : cp-path;
976                         char font_path[BCTEXTLEN];
977                         memcpy(font_path, path, len);  font_path[len] = 0;
978                         if( cp ) ++len;
979                         fp += snprintf(fp, ep-fp, " '%s'", font_path);
980                 }
981         }
982         fp += snprintf(fp, ep-fp, " -name 'fonts.scale' -print -exec cat {} \\;");
983         FILE *in = popen(find_command, "r");
984
985         FT_Library freetype_library = 0;
986 //      FT_Face freetype_face = 0;
987 //      FT_Init_FreeType(&freetype_library);
988
989         char line[BCTEXTLEN], current_dir[BCTEXTLEN];
990         current_dir[0] = 0;
991
992         while( !feof(in) && fgets(line, BCTEXTLEN, in) ) {
993                 if(!strlen(line)) break;
994
995                 char *in_ptr = line;
996
997 // Get current directory
998                 if(line[0] == '/') {
999                         get_str(current_dir, "\n", in_ptr,1);
1000                         for( int i=strlen(current_dir); --i>=0 && current_dir[i]!='/'; )
1001                                 current_dir[i] = 0;
1002                         continue;
1003                 }
1004
1005 //printf("TitleMain::build_fonts %s\n", line);
1006                 BC_FontEntry *entry = new BC_FontEntry;
1007                 char string[BCTEXTLEN];
1008 // Path
1009                 get_str(string, "\n", in_ptr, in_ptr[0]!=' ' || in_ptr[1]!='-');
1010                 entry->path = cstrcat(2, current_dir, string);
1011 // Foundary
1012                 skip_str(" -", in_ptr);
1013                 get_str(string, "-\n", in_ptr, 1);
1014                 if( !string[0] ) { delete entry;  continue; }
1015                 entry->foundry = cstrdup(string);
1016                 if(*in_ptr == '-') in_ptr++;
1017 // Family
1018                 get_str(string, "-\n", in_ptr, 1);
1019                 if( !string[0] ) { delete entry;  continue; }
1020                 entry->family = cstrdup(string);
1021                 if(*in_ptr == '-') in_ptr++;
1022 // Weight
1023                 get_str(string, "-\n", in_ptr, 1);
1024                 entry->weight = cstrdup(string);
1025                 if(*in_ptr == '-') in_ptr++;
1026 // Slant
1027                 get_str(string, "-\n", in_ptr, 1);
1028                 entry->slant = cstrdup(string);
1029                 if(*in_ptr == '-') in_ptr++;
1030 // SWidth
1031                 get_str(string, "-\n", in_ptr, 1);
1032                 entry->swidth = cstrdup(string);
1033                 if(*in_ptr == '-') in_ptr++;
1034 // Adstyle
1035                 get_str(string, "-\n", in_ptr, 1);
1036                 entry->adstyle = cstrdup(string);
1037                 if(*in_ptr == '-') in_ptr++;
1038 // pixelsize
1039                 get_str(string, "-\n", in_ptr, 1);
1040                 entry->pixelsize = atol(string);
1041                 if(*in_ptr == '-') in_ptr++;
1042 // pointsize
1043                 get_str(string, "-\n", in_ptr, 1);
1044                 entry->pointsize = atol(string);
1045                 if(*in_ptr == '-') in_ptr++;
1046 // xres
1047                 get_str(string, "-\n", in_ptr, 1);
1048                 entry->xres = atol(string);
1049                 if(*in_ptr == '-') in_ptr++;
1050 // yres
1051                 get_str(string, "-\n", in_ptr, 1);
1052                 entry->yres = atol(string);
1053                 if(*in_ptr == '-') in_ptr++;
1054 // spacing
1055                 get_str(string, "-\n", in_ptr, 1);
1056                 entry->spacing = cstrdup(string);
1057                 if(*in_ptr == '-') in_ptr++;
1058 // avg_width
1059                 get_str(string, "-\n", in_ptr, 1);
1060                 entry->avg_width = atol(string);
1061                 if(*in_ptr == '-') in_ptr++;
1062 // registry
1063                 get_str(string, "-\n", in_ptr, 1);
1064                 entry->registry = cstrdup(string);
1065                 if(*in_ptr == '-') in_ptr++;
1066 // encoding
1067                 get_str(string, "-\n", in_ptr, 1);
1068                 entry->encoding = cstrdup(string);
1069                 if(*in_ptr == '-') in_ptr++;
1070
1071 // Add to list
1072 //printf("TitleMain::build_fonts 1 %s\n", entry->path);
1073 // This takes a real long time to do.  Instead just take all fonts
1074 //              if(!load_freetype_face(freetype_library,
1075 //                      freetype_face, entry->path) )
1076 // Fix parameters
1077                 sprintf(line, "%s (%s)", entry->family, entry->foundry);
1078                 entry->displayname = cstrdup(line);
1079
1080                 if(!strcasecmp(entry->weight, "demibold")) {
1081                         entry->fixed_style |= BC_FONT_BOLD;
1082                         entry->style |= FL_WEIGHT_DEMIBOLD;
1083                 }
1084                 else if(!strcasecmp(entry->weight, "bold")) {
1085                         entry->fixed_style |= BC_FONT_BOLD;
1086                         entry->style |= FL_WEIGHT_BOLD;
1087                 }
1088                 else {
1089                         entry->style |= FL_WEIGHT_NORMAL;
1090                 }
1091
1092                 if(!strcasecmp(entry->slant, "r")) {
1093                         entry->style |= FL_SLANT_ROMAN;
1094                 }
1095                 else if(!strcasecmp(entry->slant, "i")) {
1096                         entry->style |= FL_SLANT_ITALIC;
1097                         entry->fixed_style |= BC_FONT_ITALIC;
1098                 }
1099                 else if(!strcasecmp(entry->slant, "o")) {
1100                         entry->style |= FL_SLANT_OBLIQUE;
1101                         entry->fixed_style |= BC_FONT_ITALIC;
1102                 }
1103
1104                 if(!strcasecmp(entry->swidth, "normal"))
1105                         entry->style |= FL_WIDTH_NORMAL;
1106                 else if(!strcasecmp(entry->swidth, "ultracondensed"))
1107                         entry->style |= FL_WIDTH_ULTRACONDENSED;
1108                 else if(!strcasecmp(entry->swidth, "extracondensed"))
1109                         entry->style |= FL_WIDTH_EXTRACONDENSED;
1110                 else if(!strcasecmp(entry->swidth, "condensed"))
1111                         entry->style |= FL_WIDTH_CONDENSED;
1112                 else if(!strcasecmp(entry->swidth, "semicondensed"))
1113                         entry->style |= FL_WIDTH_SEMICONDENSED;
1114                 else if(!strcasecmp(entry->swidth, "semiexpanded"))
1115                         entry->style |= FL_WIDTH_SEMIEXPANDED;
1116                 else if(!strcasecmp(entry->swidth, "expanded"))
1117                         entry->style |= FL_WIDTH_EXPANDED;
1118                 else if(!strcasecmp(entry->swidth, "extraexpanded"))
1119                         entry->style |= FL_WIDTH_EXTRAEXPANDED;
1120                 else if(!strcasecmp(entry->swidth, "ultraexpanded"))
1121                         entry->style |= FL_WIDTH_ULTRAEXPANDED;
1122                 else
1123                         entry->style |= FL_WIDTH_NORMAL;
1124
1125                 fontlist->append(entry);
1126 //              printf("TitleMain::build_fonts %s: success\n",  entry->path);
1127 //printf("TitleMain::build_fonts 2\n");
1128         }
1129         pclose(in);
1130
1131
1132 // Load all the fonts from fontconfig
1133         FcPattern *pat;
1134         FcFontSet *fs;
1135         FcObjectSet *os;
1136         FcChar8 *family, *file, *foundry, *style, *format;
1137         int slant, spacing, width, weight;
1138         int force_style = 0;
1139 // if you want limit search to TrueType put 1
1140         int limit_to_trutype = 1;
1141         FcConfig *config;
1142         int i;
1143         char tmpstring[BCTEXTLEN];
1144         if(!FcInit())
1145                 return 1;
1146         config = FcConfigGetCurrent();
1147         FcConfigSetRescanInterval(config, 0);
1148
1149         pat = FcPatternCreate();
1150         os = FcObjectSetBuild ( FC_FAMILY, FC_FILE, FC_FOUNDRY, FC_WEIGHT,
1151                 FC_WIDTH, FC_SLANT, FC_FONTFORMAT, FC_SPACING, FC_STYLE, (char *) 0);
1152         FcPatternAddBool(pat, FC_SCALABLE, true);
1153
1154         if(language[0]) {
1155                 char langstr[LEN_LANG * 3];
1156                 strcpy(langstr, language);
1157
1158                 if(region[0]) {
1159                         strcat(langstr, "-");
1160                         strcat(langstr, region);
1161                 }
1162
1163                 FcLangSet *ls =  FcLangSetCreate();
1164                 if(FcLangSetAdd(ls, (const FcChar8*)langstr))
1165                 if(FcPatternAddLangSet(pat, FC_LANG, ls))
1166                 FcLangSetDestroy(ls);
1167         }
1168
1169         fs = FcFontList(config, pat, os);
1170         FcPatternDestroy(pat);
1171         FcObjectSetDestroy(os);
1172
1173         for (i = 0; fs && i < fs->nfont; i++) {
1174                 FcPattern *font = fs->fonts[i];
1175                 force_style = 0;
1176                 FcPatternGetString(font, FC_FONTFORMAT, 0, &format);
1177                 //on this point you can limit font search
1178                 if(limit_to_trutype && strcmp((char *)format, "TrueType"))
1179                         continue;
1180
1181                 sprintf(tmpstring, "%s", format);
1182                 BC_FontEntry *entry = new BC_FontEntry;
1183                 if(FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {
1184                         entry->path = cstrdup((char*)file);
1185                 }
1186
1187                 if(FcPatternGetString(font, FC_FOUNDRY, 0, &foundry) == FcResultMatch) {
1188                         entry->foundry = cstrdup((char*)foundry);
1189                 }
1190
1191                 if(FcPatternGetInteger(font, FC_WEIGHT, 0, &weight) == FcResultMatch) {
1192                         switch(weight) {
1193                         case FC_WEIGHT_THIN:
1194                         case FC_WEIGHT_EXTRALIGHT:
1195                         case FC_WEIGHT_LIGHT:
1196                         case FC_WEIGHT_BOOK:
1197                                 force_style = 1;
1198                                 entry->weight = cstrdup("medium");
1199                                 break;
1200
1201                         case FC_WEIGHT_NORMAL:
1202                         case FC_WEIGHT_MEDIUM:
1203                         default:
1204                                 entry->weight = cstrdup("medium");
1205                                 break;
1206
1207                         case FC_WEIGHT_BLACK:
1208                         case FC_WEIGHT_SEMIBOLD:
1209                         case FC_WEIGHT_BOLD:
1210                                 entry->weight = cstrdup("bold");
1211                                 entry->fixed_style |= BC_FONT_BOLD;
1212                                 break;
1213
1214                         case FC_WEIGHT_EXTRABOLD:
1215                         case FC_WEIGHT_EXTRABLACK:
1216                                 force_style = 1;
1217                                 entry->weight = cstrdup("bold");
1218                                 entry->fixed_style |= BC_FONT_BOLD;
1219                                 break;
1220                         }
1221                 }
1222
1223                 if(FcPatternGetString(font, FC_FAMILY, 0, &family) == FcResultMatch)
1224                         entry->family = cstrdup((char*)family);
1225
1226                 if(FcPatternGetInteger(font, FC_SLANT, 0, &slant) == FcResultMatch) {
1227                         switch(slant) {
1228                         case FC_SLANT_ROMAN:
1229                         default:
1230                                 entry->slant = cstrdup("r");
1231                                 entry->style |= FL_SLANT_ROMAN;
1232                                 break;
1233                         case FC_SLANT_ITALIC:
1234                                 entry->slant = cstrdup("i");
1235                                 entry->style |= FL_SLANT_ITALIC;
1236                                 entry->fixed_style |= BC_FONT_ITALIC;
1237                                 break;
1238                         case FC_SLANT_OBLIQUE:
1239                                 entry->slant = cstrdup("o");
1240                                 entry->style |= FL_SLANT_OBLIQUE;
1241                                 entry->fixed_style |= BC_FONT_ITALIC;
1242                                 break;
1243                         }
1244                 }
1245
1246                 if(FcPatternGetInteger(font, FC_WIDTH, 0, &width) == FcResultMatch) {
1247                         switch(width) {
1248                         case FC_WIDTH_ULTRACONDENSED:
1249                                 entry->swidth = cstrdup("ultracondensed");
1250                                 break;
1251
1252                         case FC_WIDTH_EXTRACONDENSED:
1253                                 entry->swidth = cstrdup("extracondensed");
1254                                 break;
1255
1256                         case FC_WIDTH_CONDENSED:
1257                                 entry->swidth = cstrdup("condensed");
1258                                 break;
1259                         case FC_WIDTH_SEMICONDENSED:
1260                                 entry->swidth = cstrdup("semicondensed");
1261                                 break;
1262
1263                         case FC_WIDTH_NORMAL:
1264                         default:
1265                                 entry->swidth = cstrdup("normal");
1266                                 break;
1267
1268                         case FC_WIDTH_SEMIEXPANDED:
1269                                 entry->swidth = cstrdup("semiexpanded");
1270                                 break;
1271
1272                         case FC_WIDTH_EXPANDED:
1273                                 entry->swidth = cstrdup("expanded");
1274                                 break;
1275
1276                         case FC_WIDTH_EXTRAEXPANDED:
1277                                 entry->swidth = cstrdup("extraexpanded");
1278                                 break;
1279
1280                         case FC_WIDTH_ULTRAEXPANDED:
1281                                 entry->swidth = cstrdup("ultraexpanded");
1282                                 break;
1283                         }
1284                 }
1285
1286                 if(FcPatternGetInteger(font, FC_SPACING, 0, &spacing) == FcResultMatch) {
1287                         switch(spacing) {
1288                         case 0:
1289                         default:
1290                                 entry->spacing = cstrdup("p");
1291                                 break;
1292
1293                         case 90:
1294                                 entry->spacing = cstrdup("d");
1295                                 break;
1296
1297                         case 100:
1298                                 entry->spacing = cstrdup("m");
1299                                 break;
1300
1301                         case 110:
1302                                 entry->spacing = cstrdup("c");
1303                                 break;
1304                         }
1305                 }
1306
1307                 // Add fake stuff for compatibility
1308                 entry->adstyle = cstrdup(" ");
1309                 entry->pixelsize = 0;
1310                 entry->pointsize = 0;
1311                 entry->xres = 0;
1312                 entry->yres = 0;
1313                 entry->avg_width = 0;
1314                 entry->registry = cstrdup("utf");
1315                 entry->encoding = cstrdup("8");
1316
1317                 if(!FcPatternGetString(font, FC_STYLE, 0, &style) == FcResultMatch)
1318                         force_style = 0;
1319
1320                 // If font has a style unmanaged by titler plugin, force style to be displayed on name
1321                 // in this way we can shown all available fonts styles.
1322                 if(force_style) {
1323                         sprintf(tmpstring, "%s (%s)", entry->family, style);
1324                         entry->displayname = cstrdup(tmpstring);
1325                 }
1326                 else {
1327                         if(strcmp(entry->foundry, "unknown")) {
1328                                 sprintf(tmpstring, "%s (%s)", entry->family, entry->foundry);
1329                                 entry->displayname = cstrdup(tmpstring);
1330                         }
1331                         else {
1332                                 sprintf(tmpstring, "%s", entry->family);
1333                                 entry->displayname = cstrdup(tmpstring);
1334                         }
1335
1336                 }
1337                 fontlist->append(entry);
1338         }
1339
1340         FcFontSetDestroy(fs);
1341         if(freetype_library)
1342                 FT_Done_FreeType(freetype_library);
1343 // for(int i = 0; i < fonts->total; i++)
1344 //      fonts->values[i]->dump();
1345
1346         FcConfigAppFontAddDir(0, (const FcChar8*)search_path);
1347         FcConfigSetRescanInterval(0, 0);
1348
1349         os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_FOUNDRY, FC_WEIGHT,
1350                 FC_WIDTH, FC_SLANT, FC_SPACING, FC_STYLE, (char *)0);
1351         pat = FcPatternCreate();
1352         FcPatternAddBool(pat, FC_SCALABLE, true);
1353
1354         if(language[0])
1355         {
1356                 char langstr[LEN_LANG * 3];
1357                 strcpy(langstr, language);
1358
1359                 if(region[0])
1360                 {
1361                         strcat(langstr, "-");
1362                         strcat(langstr, region);
1363                 }
1364
1365                 FcLangSet *ls =  FcLangSetCreate();
1366                 if(FcLangSetAdd(ls, (const FcChar8*)langstr))
1367                         if(FcPatternAddLangSet(pat, FC_LANG, ls))
1368                 FcLangSetDestroy(ls);
1369         }
1370
1371         fs = FcFontList(0, pat, os);
1372         FcPatternDestroy(pat);
1373         FcObjectSetDestroy(os);
1374
1375         for(int i = 0; i < fs->nfont; i++)
1376         {
1377                 FcPattern *font = fs->fonts[i];
1378                 BC_FontEntry *entry = new BC_FontEntry;
1379
1380                 FcChar8 *strvalue;
1381                 if(FcPatternGetString(font, FC_FILE, 0, &strvalue) == FcResultMatch)
1382                 {
1383                         entry->path = new char[strlen((char*)strvalue) + 1];
1384                         strcpy(entry->path, (char*)strvalue);
1385                 }
1386
1387                 if(FcPatternGetString(font, FC_FOUNDRY, 0, &strvalue) == FcResultMatch)
1388                 {
1389                         entry->foundry = new char[strlen((char*)strvalue) + 1];
1390                         strcpy(entry->foundry, (char *)strvalue);
1391                 }
1392
1393                 if(FcPatternGetString(font, FC_FAMILY, 0, &strvalue) == FcResultMatch)
1394                 {
1395                         entry->family = new char[strlen((char*)strvalue) + 2];
1396                         strcpy(entry->family, (char*)strvalue);
1397                 }
1398
1399                 int intvalue;
1400                 if(FcPatternGetInteger(font, FC_SLANT, 0, &intvalue) == FcResultMatch)
1401                 {
1402                         switch(intvalue)
1403                         {
1404                         case FC_SLANT_ROMAN:
1405                         default:
1406                                 entry->style |= FL_SLANT_ROMAN;
1407                                 break;
1408
1409                         case FC_SLANT_ITALIC:
1410                                 entry->style |= FL_SLANT_ITALIC;
1411                                 break;
1412
1413                         case FC_SLANT_OBLIQUE:
1414                                 entry->style |= FL_SLANT_OBLIQUE;
1415                                 break;
1416                         }
1417                 }
1418
1419                 if(FcPatternGetInteger(font, FC_WEIGHT, 0, &intvalue) == FcResultMatch)
1420                 {
1421                         switch(intvalue)
1422                         {
1423                         case FC_WEIGHT_THIN:
1424                                 entry->style |= FL_WEIGHT_THIN;
1425                                 break;
1426
1427                         case FC_WEIGHT_EXTRALIGHT:
1428                                 entry->style |= FL_WEIGHT_EXTRALIGHT;
1429                                 break;
1430
1431                         case FC_WEIGHT_LIGHT:
1432                                 entry->style |= FL_WEIGHT_LIGHT;
1433                                 break;
1434
1435                         case FC_WEIGHT_BOOK:
1436                                 entry->style |= FL_WEIGHT_BOOK;
1437                                 break;
1438
1439                         case FC_WEIGHT_NORMAL:
1440                         default:
1441                                 entry->style |= FL_WEIGHT_NORMAL;
1442                                 break;
1443
1444                         case FC_WEIGHT_MEDIUM:
1445                                 entry->style |= FL_WEIGHT_MEDIUM;
1446                                 break;
1447
1448                         case FC_WEIGHT_DEMIBOLD:
1449                                 entry->style |= FL_WEIGHT_DEMIBOLD;
1450                                 break;
1451
1452                         case FC_WEIGHT_BOLD:
1453                                 entry->style |= FL_WEIGHT_BOLD;
1454                                 break;
1455
1456                         case FC_WEIGHT_EXTRABOLD:
1457                                 entry->style |= FL_WEIGHT_EXTRABOLD;
1458                                 break;
1459
1460                         case FC_WEIGHT_BLACK:
1461                                 entry->style |= FL_WEIGHT_BLACK;
1462                                 break;
1463
1464                         case FC_WEIGHT_EXTRABLACK:
1465                                 entry->style |= FL_WEIGHT_EXTRABLACK;
1466                                 break;
1467                         }
1468                 }
1469
1470                 if(FcPatternGetInteger(font, FC_WIDTH, 0, &intvalue) == FcResultMatch)
1471                 {
1472                         switch(intvalue)
1473                         {
1474                         case FC_WIDTH_ULTRACONDENSED:
1475                                 entry->style |= FL_WIDTH_ULTRACONDENSED;
1476                                 break;
1477
1478                         case FC_WIDTH_EXTRACONDENSED:
1479                                 entry->style |= FL_WIDTH_EXTRACONDENSED;
1480                                 break;
1481
1482                         case FC_WIDTH_CONDENSED:
1483                                 entry->style |= FL_WIDTH_CONDENSED;
1484                                 break;
1485
1486                         case FC_WIDTH_SEMICONDENSED:
1487                                 entry->style = FL_WIDTH_SEMICONDENSED;
1488                                 break;
1489
1490                         case FC_WIDTH_NORMAL:
1491                         default:
1492                                 entry->style |= FL_WIDTH_NORMAL;
1493                                 break;
1494
1495                         case FC_WIDTH_SEMIEXPANDED:
1496                                 entry->style |= FL_WIDTH_SEMIEXPANDED;
1497                                 break;
1498
1499                         case FC_WIDTH_EXPANDED:
1500                                 entry->style |= FL_WIDTH_EXPANDED;
1501                                 break;
1502
1503                         case FC_WIDTH_EXTRAEXPANDED:
1504                                 entry->style |= FL_WIDTH_EXTRAEXPANDED;
1505                                 break;
1506
1507                         case FC_WIDTH_ULTRAEXPANDED:
1508                                 entry->style |= FL_WIDTH_ULTRAEXPANDED;
1509                                 break;
1510                         }
1511                 }
1512                 if(FcPatternGetInteger(font, FC_SPACING, 0, &intvalue) == FcResultMatch)
1513                 {
1514                         switch(intvalue)
1515                         {
1516                         case FC_PROPORTIONAL:
1517                         default:
1518                                 entry->style |= FL_PROPORTIONAL;
1519                                 break;
1520
1521                         case FC_DUAL:
1522                                 entry->style |= FL_DUAL;
1523                                 break;
1524
1525                         case FC_MONO:
1526                                 entry->style |= FL_MONO;
1527                                 break;
1528
1529                         case FC_CHARCELL:
1530                                 entry->style |= FL_CHARCELL;
1531                                 break;
1532                         }
1533                 }
1534                 if(entry->foundry && strcmp(entry->foundry, "unknown"))
1535                 {
1536                         char tempstr[BCTEXTLEN];
1537                         sprintf(tempstr, "%s (%s)", entry->family, entry->foundry);
1538                         entry->displayname = new char[strlen(tempstr) + 1];
1539                         strcpy(entry->displayname, tempstr);
1540                 }
1541                 else
1542                 {
1543                         entry->displayname = new char[strlen(entry->family) + 1];
1544                         strcpy(entry->displayname, entry->family);
1545                 }
1546                 fontlist->append(entry);
1547         }
1548         FcFontSetDestroy(fs);
1549         return 0;
1550 }
1551
1552 #define STYLE_MATCH(fst, stl, msk) ((fst) & (msk) & (stl)) && \
1553        !((fst) & ~(style) & (msk))
1554
1555 BC_FontEntry *BC_Resources::find_fontentry(const char *displayname, int style,
1556         int mask, int preferred)
1557 {
1558         BC_FontEntry *entry, *style_match, *preferred_match;
1559
1560         if(!fontlist)
1561                 return 0;
1562
1563         style_match = 0;
1564         preferred_match = 0;
1565
1566         if(displayname)
1567         {
1568                 for(int i = 0; i < fontlist->total; i++)
1569                 {
1570                         entry = fontlist->values[i];
1571
1572                         if(strcmp(entry->displayname, displayname) == 0 &&
1573                                         STYLE_MATCH(entry->style, style, mask))
1574                         {
1575                                 if(!style_match)
1576                                         style_match = entry;
1577                                 if(!preferred_match && entry->fixed_style == preferred)
1578                                         preferred_match = entry;
1579                         }
1580                 }
1581                 if(preferred_match)
1582                         return preferred_match;
1583
1584                 if(style_match)
1585                         return style_match;
1586         }
1587
1588 // No exact match - assume normal width font
1589         style |= FL_WIDTH_NORMAL;
1590         mask |= FL_WIDTH_MASK;
1591         style_match = 0;
1592         preferred_match = 0;
1593
1594         for(int i = 0; i < fontlist->total; i++)
1595         {
1596                 entry = fontlist->values[i];
1597
1598                 if(STYLE_MATCH(entry->style, style, mask))
1599                 {
1600                         if(!style_match)
1601                                 style_match = entry;
1602
1603                         if(!preferred_match && (entry->style & preferred))
1604                                 preferred_match = entry;
1605
1606                         if(!strncasecmp(displayname, entry->family,
1607                                         strlen(entry->family)))
1608                         return entry;
1609                 }
1610         }
1611
1612         if(preferred_match)
1613                 return preferred_match;
1614
1615         return style_match;
1616 }
1617
1618 size_t BC_Resources::encode(const char *from_enc, const char *to_enc,
1619         char *input, int input_length, char *output, int output_length)
1620 {
1621         size_t inbytes, outbytes = 0;
1622         iconv_t cd;
1623         char *outbase = output;
1624
1625         if(!from_enc || *from_enc == 0)
1626                 from_enc = "UTF-8";
1627
1628         if(!to_enc || *to_enc == 0)
1629                 to_enc = "UTF-8";
1630
1631         if(input_length < 0)
1632                 inbytes = strlen(input);
1633         else
1634                 inbytes = input_length;
1635
1636         if(strcmp(from_enc, to_enc) && inbytes)
1637         {
1638                 if((cd = iconv_open(to_enc, from_enc)) == (iconv_t)-1)
1639                 {
1640                         printf(_("Conversion from %s to %s is not available\n"),
1641                                 from_enc, to_enc);
1642                         return 0;
1643                 }
1644
1645                 outbytes = output_length - 1;
1646
1647                 iconv(cd, &input, &inbytes, &output, &outbytes);
1648
1649                 iconv_close(cd);
1650                 inbytes = output - outbase;
1651         }
1652         else if(inbytes)
1653         {
1654                 memcpy(output,  input, inbytes);
1655                 outbytes -= inbytes;
1656         }
1657         for(int i = 0; i < 4; i++)
1658         {
1659                 output[i] = 0;
1660                 if(outbytes-- == 0)
1661                         break;
1662         }
1663         return inbytes;
1664 }
1665
1666 void BC_Resources::encode_to_utf8(char *buffer, int buflen)
1667 {
1668         if(BC_Resources::locale_utf8) return;
1669         char lbuf[buflen];
1670         encode(encoding, 0, buffer, buflen, lbuf, buflen);
1671         strcpy(buffer, lbuf);
1672 }
1673
1674 int BC_Resources::find_font_by_char(FT_ULong char_code, char *path_new, const FT_Face oldface)
1675 {
1676         FcPattern *font, *ofont;
1677         FcChar8 *file;
1678         int result = 0;
1679
1680         *path_new = 0;
1681
1682         // Do not search control codes
1683         if(char_code < ' ')
1684                 return 0;
1685
1686         if( (ofont = FcFreeTypeQueryFace(oldface, (const FcChar8*)"", 4097, 0)) != 0 ) {
1687                 if( (font = find_similar_font(char_code, ofont)) != 0 ) {
1688                         if(FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {
1689                                 strcpy(path_new, (char*)file);
1690                                 result = 1;
1691                         }
1692                         FcPatternDestroy(font);
1693                 }
1694                 FcPatternDestroy(ofont);
1695         }
1696         return result;
1697 }
1698
1699 FcPattern* BC_Resources::find_similar_font(FT_ULong char_code, FcPattern *oldfont)
1700 {
1701         FcPattern *pat, *font;
1702         FcFontSet *fs;
1703         FcObjectSet *os;
1704         FcCharSet *fcs;
1705         int ival;
1706
1707         // Do not search control codes
1708         if(char_code < ' ')
1709                 return 0;
1710
1711         fontconfig_lock.lock("BC_Resources::find_similar_font");
1712         pat = FcPatternCreate();
1713         os = FcObjectSetBuild(FC_FILE, FC_CHARSET, FC_SCALABLE, FC_FAMILY,
1714                 FC_SLANT, FC_WEIGHT, FC_WIDTH, (char *)0);
1715
1716         FcPatternAddBool(pat, FC_SCALABLE, true);
1717         fcs = FcCharSetCreate();
1718         if(FcCharSetAddChar(fcs, char_code))
1719                 FcPatternAddCharSet(pat, FC_CHARSET, fcs);
1720         FcCharSetDestroy(fcs);
1721         for( int i=0; i<(int)LEN_FCPROP; ++i ) {
1722                 if(FcPatternGetInteger(oldfont, fc_properties[i], 0, &ival) == FcResultMatch)
1723                         FcPatternAddInteger(pat, fc_properties[i], ival);
1724         }
1725         fs = FcFontList(0, pat, os);
1726         for( int i=LEN_FCPROP; --i>=0 && !fs->nfont; ) {
1727                 FcFontSetDestroy(fs);
1728                 FcPatternDel(pat, fc_properties[i]);
1729                 fs = FcFontList(0, pat, os);
1730         }
1731         FcPatternDestroy(pat);
1732         FcObjectSetDestroy(os);
1733
1734         pat = 0;
1735
1736         for (int i = 0; i < fs->nfont; i++)
1737         {
1738                 font = fs->fonts[i];
1739                 if(FcPatternGetCharSet(font, FC_CHARSET, 0, &fcs) == FcResultMatch)
1740                 {
1741                         if(FcCharSetHasChar(fcs, char_code))
1742                         {
1743                                 pat =  FcPatternDuplicate(font);
1744                                 break;
1745                         }
1746                 }
1747         }
1748         FcFontSetDestroy(fs);
1749         fontconfig_lock.unlock();
1750
1751         return pat;
1752 }
1753
1754 void BC_Resources::dump_fonts(FILE *fp)
1755 {
1756         for( int i=0; i<fontlist->total; ++i ) {
1757                 BC_FontEntry *ep = fontlist->values[i];
1758                 fprintf(fp,"%s = %s\n",ep->displayname,ep->path);
1759                 fprintf(fp,"  %s:%s:%s:%s:%s:%s:%d:%d:%d:%d:%d:%s:%d:%s:%s:%d\n",
1760                         ep->foundry, ep->family, ep->weight, ep->slant, ep->swidth, ep->adstyle,
1761                         ep->pixelsize, ep->pointsize, ep->xres, ep->yres, ep->style, ep->spacing,
1762                         ep->avg_width, ep->registry, ep->encoding, ep->fixed_style);
1763         }
1764 }
1765