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
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdio.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/keysym.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
33 #include <unistd.h>
34 #include <pthread.h>
35 #include <errno.h>
36
37 #include "common.h"
38
39 #define WINDOW_WIDTH 500
40 #define WINDOW_HEIGHT 390
41 #define MAX_DISP_ENTRIES 10
42
43 #define MAXFILES 65535
44
45 #ifndef S_ISLNK
46 #define S_ISLNK(mode) 0
47 #endif
48 #ifndef S_ISFIFO
49 #define S_ISFIFO(mode) 0
50 #endif
51 #ifndef S_ISSOCK
52 #define S_ISSOCK(mode) 0
53 #endif
54 #ifndef S_ISCHR
55 #define S_ISCHR(mode) 0
56 #endif
57 #ifndef S_ISBLK
58 #define S_ISBLK(mode) 0
59 #endif
60 #ifndef S_ISREG
61 #define S_ISREG(mode) 0
62 #endif
63 #if !S_IXUGO
64 #define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
65 #endif
66
67
68 typedef struct {
69 const char *name;
70 const char *ending;
71 } filebrowser_filter_t;
72
73 static const filebrowser_filter_t __fb_filters[] = {
74 { N_("All files"), "*" },
75 { N_("All known subtitles"), ".sub .srt .asc .smi .ssa .ass .txt " },
76 { N_("All known playlists"), ".pls .m3u .sfv .tox .asx .smil .smi .xml .fxd " },
77 /* media files */
78 { "*.4xm", ".4xm " },
79 { "*.ac3", ".ac3 " },
80 { "*.aif, *.aiff", ".aif .aiff " },
81 {"*.asf, *.wmv, *.wma, *.wvx, *.wax", ".asf .wmv .wma .wvx .wax " },
82 { "*.aud", ".aud " },
83 { "*.avi", ".avi " },
84 { "*.cin", ".cin " },
85 { "*.cpk, *.cak, *.film", ".cpk .cak .film " },
86 { "*.dv, *.dif", ".dv .dif " },
87 { "*.fli, *.flc", ".fli .flc " },
88 { "*.mp3, *.mp2, *.mpa, *.mpega", ".mp3 .mp2 .mpa .mpega " },
89 { "*.mjpg", ".mjpg " },
90 { "*.mov, *.qt, *.mp4", ".mov .qt .mp4 " },
91 { "*.m2p", ".m2p " },
92 { "*.mpg, *.mpeg", ".mpg .mpeg " },
93 { "*.mpv", ".mpv " },
94 { "*.mve, *.mv8", ".mve .mv8 " },
95 { "*.nsf", ".nsf " },
96 { "*.nsv", ".nsv " },
97 { "*.ogg, *.ogm, *.spx", ".ogg .ogm .spx " },
98 { "*.pes", ".pes " },
99 { "*.png, *.mng", ".png .mng " },
100 { "*.pva", ".pva " },
101 { "*.ra", ".ra " },
102 { "*.rm, *.ram, *.rmvb ", ".rm .ram .rmvb " },
103 { "*.roq", ".roq " },
104 { "*.str, *.iki, *.ik2, *.dps, *.dat, *.xa1, *.xa2, *.xas, *.xap, *.xa",
105 ".str .iki .ik2 .dps .dat .xa1 .xa2 .xas .xap .xa " },
106 { "*.snd, *.au", ".snd .au " },
107 { "*.ts, *.m2t, *.trp", ".ts .m2t .trp " },
108 { "*.vqa", ".vqa " },
109 { "*.vob", ".vob " },
110 { "*.voc", ".voc " },
111 { "*.vox", ".vox " },
112 { "*.wav", ".wav " },
113 { "*.wve", ".wve " },
114 { "*.y4m", ".y4m " },
115 { NULL, NULL }
116 };
117
118 typedef struct {
119 char *name;
120 } fileinfo_t;
121
122 #define DEFAULT_SORT 0
123 #define REVERSE_SORT 1
124
125 #define NORMAL_CURS 0
126 #define WAIT_CURS 1
127
128 struct filebrowser_s {
129 gGui_t *gui;
130
131 xitk_window_t *xwin;
132
133 xitk_widget_list_t *widget_list;
134
135 xitk_widget_t *origin;
136
137 xitk_widget_t *directories_browser;
138 xitk_widget_t *directories_sort;
139 int directories_sort_direction;
140 xitk_widget_t *files_browser;
141 xitk_widget_t *files_sort;
142 int files_sort_direction;
143
144 xitk_image_t *sort_skin_up;
145 xitk_image_t *sort_skin_down;
146
147 xitk_widget_t *rename;
148 xitk_widget_t *delete;
149 xitk_widget_t *create;
150
151 xitk_widget_t *filters;
152 int filter_selected;
153 const char **file_filters;
154
155 xitk_widget_t *show_hidden;
156 int show_hidden_files;
157
158 char current_dir[XINE_PATH_MAX + 1];
159 char filename[XINE_NAME_MAX + 1];
160
161 fileinfo_t *dir_files;
162 char **directories;
163 int directories_num;
164 int directories_sel;
165
166 fileinfo_t *norm_files;
167 char **files;
168 int files_num;
169
170 int running;
171 int visible;
172
173 xitk_widget_t *close;
174
175 hidden_file_toggle_t hidden_cb;
176
177 filebrowser_callback_button_t cbb[3];
178 xitk_widget_t *cb_buttons[2];
179
180 xitk_register_key_t widget_key;
181 };
182
183
184 typedef struct {
185 xitk_window_t *xwin;
186 xitk_widget_list_t *widget_list;
187 xitk_widget_t *input;
188
189 xitk_string_callback_t callback;
190 filebrowser_t *fb;
191
192 xitk_widget_t *button_apply;
193 xitk_widget_t *button_cancel;
194
195 xitk_register_key_t widget_key;
196 } filename_editor_t;
197
198 /*
199 * Enable/disable widgets in file browser window
200 */
_fb_enability(filebrowser_t * fb,int enable)201 static void _fb_enability(filebrowser_t *fb, int enable) {
202 void (*enability)(xitk_widget_t *) = (enable == 1) ? xitk_enable_widget : xitk_disable_widget;
203
204 enability(fb->origin);
205 enability(fb->directories_browser);
206 enability(fb->directories_sort);
207 enability(fb->files_browser);
208 enability(fb->files_sort);
209 enability(fb->rename);
210 enability(fb->delete);
211 enability(fb->create);
212 enability(fb->filters);
213 if(fb->cb_buttons[0]) {
214 enability(fb->cb_buttons[0]);
215 if(fb->cb_buttons[1])
216 enability(fb->cb_buttons[1]);
217 }
218 enability(fb->show_hidden);
219 enability(fb->close);
220 }
fb_deactivate(filebrowser_t * fb)221 static void fb_deactivate(filebrowser_t *fb) {
222 _fb_enability(fb, 0);
223 }
fb_reactivate(filebrowser_t * fb)224 static void fb_reactivate(filebrowser_t *fb) {
225 _fb_enability(fb, 1);
226 }
227
_fb_set_cursor(filebrowser_t * fb,int state)228 static void _fb_set_cursor(filebrowser_t *fb, int state) {
229 if(fb) {
230 if(state == WAIT_CURS)
231 xitk_cursors_define_window_cursor (fb->gui->display, (xitk_window_get_window(fb->xwin)), xitk_cursor_watch);
232 else
233 xitk_cursors_restore_window_cursor (fb->gui->display, (xitk_window_get_window(fb->xwin)));
234 }
235 }
236 /*
237 * **************************************************
238 */
239 static void fb_exit(xitk_widget_t *, void *);
240
241 /*
242 * ************************* filename editor **************************
243 */
fne_destroy(filename_editor_t * fne)244 static void fne_destroy(filename_editor_t *fne) {
245 if(fne) {
246
247 xitk_unregister_event_handler(&fne->widget_key);
248
249 xitk_destroy_widgets(fne->widget_list);
250 xitk_window_destroy_window(gGui->imlib_data, fne->xwin);
251
252 fne->xwin = NULL;
253 /* xitk_dlist_init (&fne->widget_list->list); */
254
255 gGui->x_lock_display (gGui->display);
256 XFreeGC(gGui->display, (XITK_WIDGET_LIST_GC(fne->widget_list)));
257 gGui->x_unlock_display (gGui->display);
258
259 XITK_WIDGET_LIST_FREE(fne->widget_list);
260
261 free(fne);
262 }
263 }
fne_apply_cb(xitk_widget_t * w,void * data)264 static void fne_apply_cb(xitk_widget_t *w, void *data) {
265 filename_editor_t *fne = (filename_editor_t *) data;
266
267 if(fne->callback)
268 fne->callback(NULL, (void *)fne->fb, (xitk_inputtext_get_text(fne->input)));
269
270 fb_reactivate(fne->fb);
271 fne_destroy(fne);
272 }
fne_cancel_cb(xitk_widget_t * w,void * data)273 static void fne_cancel_cb(xitk_widget_t *w, void *data) {
274 filename_editor_t *fne = (filename_editor_t *) data;
275
276 fb_reactivate(fne->fb);
277 fne_destroy(fne);
278 }
fne_handle_event(XEvent * event,void * data)279 static void fne_handle_event(XEvent *event, void *data) {
280 switch(event->type) {
281
282 case KeyPress:
283 if(xitk_get_key_pressed(event) == XK_Escape)
284 fne_cancel_cb(NULL, data);
285 else
286 gui_handle_event(event, gGui);
287 break;
288 }
289 }
fb_create_input_window(char * title,char * text,xitk_string_callback_t cb,filebrowser_t * fb)290 static void fb_create_input_window(char *title, char *text,
291 xitk_string_callback_t cb, filebrowser_t *fb) {
292 filename_editor_t *fne;
293 GC gc;
294 int x, y, w;
295 int width = WINDOW_WIDTH;
296 int height = 102;
297 xitk_labelbutton_widget_t lb;
298 xitk_inputtext_widget_t inp;
299
300 fb->gui->x_lock_display (fb->gui->display);
301 x = (((DisplayWidth (fb->gui->display, fb->gui->screen))) >> 1) - (width >> 1);
302 y = (((DisplayHeight (fb->gui->display, fb->gui->screen))) >> 1) - (height >> 1);
303 fb->gui->x_unlock_display (fb->gui->display);
304
305 fne = (filename_editor_t *) calloc(1, sizeof(filename_editor_t));
306
307 fne->callback = cb;
308 fne->fb = fb;
309
310 fne->xwin = xitk_window_create_dialog_window (fb->gui->imlib_data, title, x, y, width, height);
311
312 xitk_set_wm_window_type((xitk_window_get_window(fne->xwin)), WINDOW_TYPE_NORMAL);
313 change_class_name((xitk_window_get_window(fne->xwin)));
314 change_icon((xitk_window_get_window(fne->xwin)));
315
316 fb->gui->x_lock_display (fb->gui->display);
317 gc = XCreateGC (fb->gui->display, (xitk_window_get_window(fne->xwin)), None, None);
318 fb->gui->x_unlock_display (fb->gui->display);
319
320 fne->widget_list = xitk_widget_list_new();
321
322 xitk_widget_list_set(fne->widget_list,
323 WIDGET_LIST_WINDOW, (void *) (xitk_window_get_window(fne->xwin)));
324 xitk_widget_list_set(fne->widget_list, WIDGET_LIST_GC, gc);
325
326 XITK_WIDGET_INIT(&lb, fb->gui->imlib_data);
327 XITK_WIDGET_INIT(&inp, fb->gui->imlib_data);
328
329 x = 15;
330 y = 30;
331 w = width - 30;
332
333 inp.skin_element_name = NULL;
334 inp.text = text;
335 inp.max_length = XITK_PATH_MAX + XITK_NAME_MAX + 1;
336 inp.callback = NULL;
337 inp.userdata = (void *)fne;
338 fne->input = xitk_noskin_inputtext_create (fne->widget_list, &inp,
339 x, y, w, 20, "Black", "Black", fontname);
340 xitk_add_widget (fne->widget_list, fne->input);
341
342 xitk_enable_and_show_widget(fne->input);
343
344 y = height - (23 + 15);
345 x = 15;
346 w = 100;
347
348 lb.button_type = CLICK_BUTTON;
349 lb.label = _("Apply");
350 lb.align = ALIGN_CENTER;
351 lb.callback = fne_apply_cb;
352 lb.state_callback = NULL;
353 lb.userdata = (void *)fne;
354 lb.skin_element_name = NULL;
355 fne->button_apply = xitk_noskin_labelbutton_create (fne->widget_list,
356 &lb, x, y, w, 23, "Black", "Black", "White", btnfontname);
357 xitk_add_widget (fne->widget_list, fne->button_apply);
358 xitk_enable_and_show_widget(fne->button_apply);
359
360 x = width - (w + 15);
361
362 lb.button_type = CLICK_BUTTON;
363 lb.label = _("Cancel");
364 lb.align = ALIGN_CENTER;
365 lb.callback = fne_cancel_cb;
366 lb.state_callback = NULL;
367 lb.userdata = (void *)fne;
368 lb.skin_element_name = NULL;
369 fne->button_cancel = xitk_noskin_labelbutton_create (fne->widget_list,
370 &lb, x, y, w, 23, "Black", "Black", "White", btnfontname);
371 xitk_add_widget (fne->widget_list, fne->button_cancel);
372 xitk_enable_and_show_widget(fne->button_cancel);
373
374 {
375 char buffer[256];
376 snprintf(buffer, sizeof(buffer), "filenameed%u", (unsigned int) time(NULL));
377
378 fne->widget_key = xitk_register_event_handler(buffer,
379 (xitk_window_get_window(fne->xwin)),
380 fne_handle_event,
381 NULL,
382 NULL,
383 fne->widget_list,
384 (void *)fne);
385 }
386
387 fb->gui->x_lock_display (fb->gui->display);
388 XRaiseWindow (fb->gui->display, xitk_window_get_window(fne->xwin));
389 XMapWindow (fb->gui->display, xitk_window_get_window(fne->xwin));
390 if (!fb->gui->use_root_window && fb->gui->video_display == fb->gui->display)
391 XSetTransientForHint (fb->gui->display, xitk_window_get_window (fne->xwin), fb->gui->video_window);
392 fb->gui->x_unlock_display (fb->gui->display);
393 layer_above_video(xitk_window_get_window(fne->xwin));
394
395 try_to_set_input_focus(xitk_window_get_window(fne->xwin));
396 }
397 /*
398 * ************************** END OF filename editor **************************
399 */
400
401 /*
402 * **************************** File related funcs **************************
403 */
404
405 /*
406 * Return 1 if file match with current filter, otherwise 0.
407 */
is_file_match_to_filter(filebrowser_t * fb,char * file)408 static int is_file_match_to_filter(filebrowser_t *fb, char *file) {
409
410 if(!fb->filter_selected)
411 return 1;
412 else {
413 char *ending;
414
415 if((ending = strrchr(file, '.'))) {
416 char ext[strlen(ending) + 2];
417 char *p;
418
419 sprintf(ext, "%s ", ending);
420
421 p = ext;
422 while(*p) {
423 *p = tolower(*p);
424 p++;
425 }
426
427 if(strstr(__fb_filters[fb->filter_selected].ending, ext))
428 return 1;
429
430 }
431 }
432 return 0;
433 }
434
fb_update_origin(filebrowser_t * fb)435 static void fb_update_origin(filebrowser_t *fb) {
436 char buf[XITK_PATH_MAX + XITK_NAME_MAX + 2];
437
438 if(strcmp(fb->current_dir, "/"))
439 snprintf(buf, sizeof(buf), "%s/%s", fb->current_dir, fb->filename);
440 else
441 snprintf(buf, sizeof(buf), "/%s", fb->filename);
442
443 xitk_inputtext_change_text(fb->origin, buf);
444 }
445
fb_extract_path_and_file(filebrowser_t * fb,const char * filepathname)446 static void fb_extract_path_and_file(filebrowser_t *fb, const char *filepathname) {
447 if(filepathname && *filepathname) {
448 char *dirname = NULL;
449 char *filename = NULL;
450 char _filepathname[XITK_PATH_MAX + XITK_NAME_MAX + 2];
451 char *p;
452
453 if((*filepathname == '~') && (*(filepathname + 1) == '/' || *(filepathname + 1) == '\0')) {
454 const char *homedir = xine_get_homedir();
455
456 snprintf(_filepathname, sizeof(_filepathname), "%s%s", homedir, (filepathname + 1));
457 }
458 else {
459 if((*filepathname == '\\') && (*(filepathname + 1) == '~'))
460 filepathname++;
461 if(*filepathname == '/')
462 strlcpy(_filepathname, filepathname, sizeof(_filepathname));
463 else
464 snprintf(_filepathname, sizeof(_filepathname), "%s/%s", fb->current_dir, filepathname);
465 }
466
467 p = _filepathname + strlen(_filepathname) - 1;
468 while((p > _filepathname) && (*p == '/')) /* Remove trailing '/' from path name */
469 *p-- = '\0';
470
471 if(is_a_dir(_filepathname)) { /* Whole name is a dir name */
472 dirname = _filepathname;
473 }
474 else {
475 filename = strrchr(_filepathname, '/');
476
477 if(!filename) { /* Whole name treated as file name */
478 filename = _filepathname;
479 }
480 else { /* Split into dir and file part */
481 *filename++ = '\0';
482
483 if(*_filepathname == '\0')
484 dirname = "/"; /* Dir part was "/", restore it */
485 else
486 dirname = _filepathname;
487
488 p = dirname + strlen(dirname) - 1;
489 while((p > dirname) && (*p == '/')) /* Remove trailing '/' from dir name */
490 *p-- = '\0';
491
492 if(!is_a_dir(dirname)) /* Invalid path, don't change anything */
493 return;
494 }
495 }
496
497 if(dirname)
498 strlcpy(fb->current_dir, dirname, sizeof(fb->current_dir));
499
500 if(filename)
501 strlcpy(fb->filename, filename, sizeof(fb->filename));
502 else
503 *fb->filename = '\0';
504 }
505 }
506
507 /*
508 * Sorting function, it comes from GNU fileutils package.
509 */
510 #define S_N 0x0
511 #define S_I 0x4
512 #define S_F 0x8
513 #define S_Z 0xC
514 #define CMP 2
515 #define LEN 3
516 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
my_strverscmp(const char * s1,const char * s2)517 static int my_strverscmp(const char *s1, const char *s2) {
518 const unsigned char *p1 = (const unsigned char *) s1;
519 const unsigned char *p2 = (const unsigned char *) s2;
520 unsigned char c1, c2;
521 int state;
522 int diff;
523 static const unsigned int next_state[] = {
524 S_N, S_I, S_Z, S_N,
525 S_N, S_I, S_I, S_I,
526 S_N, S_F, S_F, S_F,
527 S_N, S_F, S_Z, S_Z
528 };
529 static const int result_type[] = {
530 CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
531 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
532 CMP, -1, -1, CMP, 1, LEN, LEN, CMP,
533 1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
534 CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
535 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
536 CMP, 1, 1, CMP, -1, CMP, CMP, CMP,
537 -1, CMP, CMP, CMP
538 };
539
540 if(p1 == p2)
541 return 0;
542
543 c1 = *p1++;
544 c2 = *p2++;
545
546 state = S_N | ((c1 == '0') + (ISDIGIT(c1) != 0));
547
548 while((diff = c1 - c2) == 0 && c1 != '\0') {
549 state = next_state[state];
550 c1 = *p1++;
551 c2 = *p2++;
552 state |= (c1 == '0') + (ISDIGIT(c1) != 0);
553 }
554
555 state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT(c2) != 0))];
556
557 switch(state) {
558 case CMP:
559 return diff;
560
561 case LEN:
562 while(ISDIGIT(*p1++))
563 if(!ISDIGIT(*p2++))
564 return 1;
565
566 return ISDIGIT(*p2) ? -1 : diff;
567
568 default:
569 return state;
570 }
571 }
572
573 /*
574 * Wrapper to my_strverscmp() for qsort() calls, which sort mrl_t type array.
575 */
_sortfiles_default(const fileinfo_t * s1,const fileinfo_t * s2)576 static int _sortfiles_default(const fileinfo_t *s1, const fileinfo_t *s2) {
577 return(my_strverscmp(s1->name, s2->name));
578 }
_sortfiles_reverse(const fileinfo_t * s1,const fileinfo_t * s2)579 static int _sortfiles_reverse(const fileinfo_t *s1, const fileinfo_t *s2) {
580 return(my_strverscmp(s2->name, s1->name));
581 }
582
sort_files(filebrowser_t * fb)583 static void sort_files(filebrowser_t *fb) {
584 int (*func) () = NULL;
585
586 if(fb->files) {
587 int i = 0;
588
589 while(fb->files[i]) {
590 SAFE_FREE(fb->files[i]);
591 i++;
592 }
593 }
594
595 if(fb->files_num) {
596 int i;
597
598 if(fb->files_sort_direction == REVERSE_SORT)
599 func = _sortfiles_reverse;
600 else /*if(fb->files_sort_direction == DEFAULT_SORT)*/
601 func = _sortfiles_default;
602
603 qsort(fb->norm_files, fb->files_num, sizeof(fileinfo_t), func);
604
605 fb->files = (char **) realloc(fb->files, sizeof(char *) * (fb->files_num + 2));
606
607 for(i = 0; i < fb->files_num; i++)
608 fb->files[i] = strdup(fb->norm_files[i].name);
609
610 fb->files[i] = NULL;
611 }
612
613 xitk_browser_update_list(fb->files_browser, (const char *const *)fb->files, NULL, fb->files_num, 0);
614 }
615
sort_directories(filebrowser_t * fb)616 static void sort_directories(filebrowser_t *fb) {
617 int (*func) () = NULL;
618
619 if(fb->directories) {
620 int i = 0;
621
622 while(fb->directories[i]) {
623 SAFE_FREE(fb->directories[i]);
624 i++;
625 }
626 }
627
628 if(fb->directories_num) {
629 int i;
630
631 if(fb->directories_sort_direction == REVERSE_SORT)
632 func = _sortfiles_reverse;
633 else /*if(fb->directories_sort_direction == DEFAULT_SORT)*/
634 func = _sortfiles_default;
635
636 qsort(fb->dir_files, fb->directories_num, sizeof(fileinfo_t), func);
637
638 fb->directories = (char **) realloc(fb->directories, sizeof(char *) * (fb->directories_num + 2));
639 for(i = 0; i < fb->directories_num; i++) {
640 fb->directories[i] = (char *) malloc(strlen(fb->dir_files[i].name) + 2);
641 sprintf(fb->directories[i], "%s%c", fb->dir_files[i].name, '/');
642 }
643
644 fb->directories[i] = NULL;
645 }
646
647 xitk_browser_update_list(fb->directories_browser,
648 (const char *const *)fb->directories, NULL, fb->directories_num, 0);
649 }
650
fb_getdir(filebrowser_t * fb)651 static void fb_getdir(filebrowser_t *fb) {
652 char fullfilename[XINE_PATH_MAX + XINE_NAME_MAX + 2];
653 struct dirent *pdirent;
654 int num_dir_files = 0;
655 int num_norm_files = 0;
656 DIR *pdir;
657 int num_files = -1;
658
659 _fb_set_cursor(fb, WAIT_CURS);
660
661 if(fb->norm_files) {
662 while(fb->files_num) {
663 free(fb->norm_files[fb->files_num - 1].name);
664 fb->files_num--;
665 }
666 }
667
668 if(fb->dir_files) {
669 while(fb->directories_num) {
670 free(fb->dir_files[fb->directories_num - 1].name);
671 fb->directories_num--;
672 }
673 }
674
675 /* Following code relies on the fact that fb->current_dir has no trailing '/' */
676 if((pdir = opendir(fb->current_dir)) == NULL) {
677 char *p = strrchr(fb->current_dir, '/');
678
679 xine_error(_("Unable to open directory '%s': %s."),
680 (p && *(p + 1)) ? p + 1 : fb->current_dir, strerror(errno));
681
682 /* One step back if dir has a subdir component */
683 if(p && *(p + 1)) {
684 if(p == fb->current_dir) /* we are in the root dir */
685 *(p + 1) = '\0';
686 else
687 *p = '\0';
688
689 fb_update_origin(fb);
690 fb_getdir(fb);
691 }
692 return;
693 }
694
695 while((pdirent = readdir(pdir)) != NULL) {
696
697 snprintf(fullfilename, sizeof(fullfilename), "%s/%s", fb->current_dir, pdirent->d_name);
698
699 if(is_a_dir(fullfilename)) {
700
701 /* if user don't want to see hidden files, ignore them */
702 if(fb->show_hidden_files == 0 &&
703 ((strlen(pdirent->d_name) > 1)
704 && (pdirent->d_name[0] == '.' && pdirent->d_name[1] != '.'))) {
705 ;
706 }
707 else {
708 fb->dir_files[num_dir_files].name = strdup(pdirent->d_name);
709 num_dir_files++;
710 }
711
712 } /* Hmmmm, an hidden file ? */
713 else if((strlen(pdirent->d_name) > 1)
714 && (pdirent->d_name[0] == '.' && pdirent->d_name[1] != '.')) {
715
716 /* if user don't want to see hidden files, ignore them */
717 if(fb->show_hidden_files) {
718 if(is_file_match_to_filter(fb, pdirent->d_name)) {
719 fb->norm_files[num_norm_files].name = strdup(pdirent->d_name);
720 num_norm_files++;
721 }
722 }
723
724 } /* So a *normal* one. */
725 else {
726 if(is_file_match_to_filter(fb, pdirent->d_name)) {
727 fb->norm_files[num_norm_files].name = strdup(pdirent->d_name);
728 num_norm_files++;
729 }
730 }
731
732 num_files++;
733 }
734
735 closedir(pdir);
736
737 /*
738 * Sort arrays
739 */
740 fb->directories_num = num_dir_files;
741 fb->files_num = num_norm_files;
742 sort_directories(fb);
743 sort_files(fb);
744 _fb_set_cursor(fb, NORMAL_CURS);
745 }
746
747 /*
748 * ****************************** END OF file related funcs ***************************
749 */
750
751 /*
752 * ***************************** widget callbacks *******************************
753 */
fb_select(xitk_widget_t * w,void * data,int selected)754 static void fb_select(xitk_widget_t *w, void *data, int selected) {
755 filebrowser_t *fb = (filebrowser_t *) data;
756
757 if(w == fb->files_browser) {
758 strlcpy(fb->filename, fb->norm_files[selected].name, sizeof(fb->filename));
759 fb_update_origin(fb);
760 }
761 }
762
fb_callback_button_cb(xitk_widget_t * w,void * data)763 static void fb_callback_button_cb(xitk_widget_t *w, void *data) {
764 filebrowser_t *fb = (filebrowser_t *) data;
765
766 if(w == fb->cb_buttons[0]) {
767 if(fb->cbb[0].need_a_file && (!strlen(fb->filename)))
768 return;
769 fb->cbb[0].callback(fb);
770 }
771 else if(w == fb->cb_buttons[1]) {
772 if(fb->cbb[1].need_a_file && (!strlen(fb->filename)))
773 return;
774 fb->cbb[1].callback(fb);
775 }
776
777 fb_exit(NULL, (void *)fb);
778 }
779
780
fb_dbl_select(xitk_widget_t * w,void * data,int selected)781 static void fb_dbl_select(xitk_widget_t *w, void *data, int selected) {
782 filebrowser_t *fb = (filebrowser_t *) data;
783
784 if(w == fb->directories_browser) {
785 char buf[XITK_PATH_MAX + XITK_NAME_MAX + 2];
786
787 /* Want to re-read current dir */
788 if(!strcasecmp(fb->dir_files[selected].name, ".")) {
789 /* NOOP */
790 }
791 else if(!strcasecmp(fb->dir_files[selected].name, "..")) {
792 char *p;
793
794 strlcpy(buf, fb->current_dir, sizeof(buf));
795 if(strlen(buf) > 1) { /* not '/' directory */
796
797 p = &buf[strlen(buf)-1];
798 while(*p && *p != '/') {
799 *p = '\0';
800 p--;
801 }
802
803 /* Remove last '/' if current_dir isn't root */
804 if((strlen(buf) > 1) && *p == '/')
805 *p = '\0';
806
807 strlcpy(fb->current_dir, buf, sizeof(fb->current_dir));
808 }
809 }
810 else {
811
812 /* not '/' directory */
813 if(strcasecmp(fb->current_dir, "/")) {
814 snprintf(buf, sizeof(buf), "%s/%s", fb->current_dir, fb->dir_files[selected].name);
815 }
816 else {
817 snprintf(buf, sizeof(buf), "/%s", fb->dir_files[selected].name);
818 }
819
820 if(is_a_dir(buf))
821 strlcpy(fb->current_dir, buf, sizeof(fb->current_dir));
822
823 }
824
825 fb_update_origin(fb);
826 fb_getdir(fb);
827 }
828 else if(w == fb->files_browser) {
829 strlcpy(fb->filename, fb->norm_files[selected].name, sizeof(fb->filename));
830 fb_callback_button_cb(fb->cb_buttons[0], (void *)data);
831 }
832
833 }
834
fb_change_origin(xitk_widget_t * w,void * data,const char * currenttext)835 static void fb_change_origin(xitk_widget_t *w, void *data, const char *currenttext) {
836 filebrowser_t *fb = (filebrowser_t *)data;
837
838 fb_extract_path_and_file(fb, currenttext);
839 fb_update_origin(fb);
840 fb_getdir(fb);
841 }
842
fb_sort(xitk_widget_t * w,void * data)843 static void fb_sort(xitk_widget_t *w, void *data) {
844 filebrowser_t *fb = (filebrowser_t *) data;
845
846 if(w == fb->directories_sort) {
847 xitk_image_t *dsimage = xitk_get_widget_foreground_skin(fb->directories_sort);
848
849 fb->directories_sort_direction = (fb->directories_sort_direction == DEFAULT_SORT) ?
850 REVERSE_SORT : DEFAULT_SORT;
851
852 xitk_hide_widget(fb->directories_sort);
853
854 if(fb->directories_sort_direction == DEFAULT_SORT)
855 xitk_image_change_image (fb->gui->imlib_data, fb->sort_skin_down,
856 dsimage, dsimage->width, dsimage->height);
857 else
858 xitk_image_change_image (fb->gui->imlib_data, fb->sort_skin_up,
859 dsimage, dsimage->width, dsimage->height);
860
861 xitk_show_widget(fb->directories_sort);
862
863 sort_directories(fb);
864 }
865 else if(w == fb->files_sort) {
866 xitk_image_t *fsimage = xitk_get_widget_foreground_skin(fb->files_sort);
867
868 fb->files_sort_direction = (fb->files_sort_direction == DEFAULT_SORT) ?
869 REVERSE_SORT : DEFAULT_SORT;
870
871 xitk_hide_widget(fb->files_sort);
872
873 if(fb->files_sort_direction == DEFAULT_SORT)
874 xitk_image_change_image (fb->gui->imlib_data, fb->sort_skin_down,
875 fsimage, fsimage->width, fsimage->height);
876 else
877 xitk_image_change_image (fb->gui->imlib_data, fb->sort_skin_up,
878 fsimage, fsimage->width, fsimage->height);
879
880 xitk_show_widget(fb->files_sort);
881
882 sort_files(fb);
883 }
884 }
885
fb_exit(xitk_widget_t * w,void * data)886 static void fb_exit(xitk_widget_t *w, void *data) {
887 filebrowser_t *fb = (filebrowser_t *) data;
888
889 if(fb) {
890 int i;
891
892 fb->running = 0;
893 fb->visible = 0;
894
895 xitk_unregister_event_handler(&fb->widget_key);
896
897 xitk_destroy_widgets(fb->widget_list);
898 xitk_window_destroy_window (fb->gui->imlib_data, fb->xwin);
899
900 fb->xwin = NULL;
901 /* xitk_dlist_init (&fb->widget_list->list); */
902
903 fb->gui->x_lock_display (fb->gui->display);
904 XFreeGC (fb->gui->display, (XITK_WIDGET_LIST_GC(fb->widget_list)));
905 fb->gui->x_unlock_display (fb->gui->display);
906
907 XITK_WIDGET_LIST_FREE(fb->widget_list);
908
909 if(fb->norm_files) {
910 while(fb->files_num) {
911 free(fb->norm_files[fb->files_num - 1].name);
912 fb->files_num--;
913 }
914 }
915 SAFE_FREE(fb->norm_files);
916
917 if(fb->dir_files) {
918 while(fb->directories_num) {
919 free(fb->dir_files[fb->directories_num - 1].name);
920 fb->directories_num--;
921 }
922 }
923 SAFE_FREE(fb->dir_files);
924
925 if(fb->files) {
926 i = 0;
927
928 while(fb->files[i]) {
929 free(fb->files[i]);
930 i++;
931 }
932 free(fb->files);
933 }
934
935 if(fb->directories) {
936 i = 0;
937
938 while(fb->directories[i]) {
939 free(fb->directories[i]);
940 i++;
941 }
942 free(fb->directories);
943 }
944
945 free(fb->file_filters);
946
947 SAFE_FREE(fb->cbb[0].label);
948 SAFE_FREE(fb->cbb[1].label);
949
950 xitk_image_free_image (fb->gui->imlib_data, &fb->sort_skin_up);
951 xitk_image_free_image (fb->gui->imlib_data, &fb->sort_skin_down);
952
953 free(fb);
954 fb = NULL;
955 }
956 }
_fb_exit(xitk_widget_t * w,void * data)957 static void _fb_exit(xitk_widget_t *w, void *data) {
958 filebrowser_t *fb = (filebrowser_t *) data;
959 if(fb->cbb[2].callback)
960 fb->cbb[2].callback(fb);
961 fb_exit(NULL, (void *)fb);
962 }
963
fb_delete_file_cb(xitk_widget_t * w,void * data,int button)964 static void fb_delete_file_cb(xitk_widget_t *w, void *data, int button) {
965 filebrowser_t *fb = (filebrowser_t *) data;
966
967 switch(button) {
968 case XITK_WINDOW_ANSWER_YES:
969 {
970 char buf[XITK_PATH_MAX + XITK_NAME_MAX + 2];
971 int sel = xitk_browser_get_current_selected(fb->files_browser);
972
973 snprintf(buf, sizeof(buf), "%s%s%s",
974 fb->current_dir, ((fb->current_dir[0] && strcmp(fb->current_dir, "/")) ? "/" : ""),
975 fb->norm_files[sel].name);
976
977 if((unlink(buf)) == -1)
978 xine_error(_("Unable to delete file '%s': %s."), buf, strerror(errno));
979 else
980 fb_getdir(fb);
981
982 }
983 break;
984 }
985 fb_reactivate(fb);
986 }
987
fb_delete_file(xitk_widget_t * w,void * data)988 static void fb_delete_file(xitk_widget_t *w, void *data) {
989 filebrowser_t *fb = (filebrowser_t *) data;
990 int sel;
991
992 if((sel = xitk_browser_get_current_selected(fb->files_browser)) >= 0) {
993 char buf[256 + XITK_PATH_MAX + XITK_NAME_MAX + 2];
994
995 snprintf(buf, sizeof(buf), _("Do you really want to delete the file '%s%s%s' ?"),
996 fb->current_dir, ((fb->current_dir[0] && strcmp(fb->current_dir, "/")) ? "/" : ""),
997 fb->norm_files[sel].name);
998
999 fb_deactivate(fb);
1000 xitk_window_dialog_yesno (fb->gui->imlib_data, _("Confirm deletion ?"),
1001 fb_delete_file_cb,
1002 fb_delete_file_cb,
1003 (void *)fb, ALIGN_DEFAULT, "%s", buf);
1004 }
1005 }
1006
fb_rename_file_cb(xitk_widget_t * w,void * data,const char * newname)1007 static void fb_rename_file_cb(xitk_widget_t *w, void *data, const char *newname) {
1008 filebrowser_t *fb = (filebrowser_t *) data;
1009 char buf[XITK_PATH_MAX + XITK_NAME_MAX + 2];
1010 int sel = xitk_browser_get_current_selected(fb->files_browser);
1011
1012 snprintf(buf, sizeof(buf), "%s%s%s",
1013 fb->current_dir, ((fb->current_dir[0] && strcmp(fb->current_dir, "/")) ? "/" : ""),
1014 fb->norm_files[sel].name);
1015
1016 if((rename(buf, newname)) == -1)
1017 xine_error(_("Unable to rename file '%s' to '%s': %s."), buf, newname, strerror(errno));
1018 else
1019 fb_getdir(fb);
1020
1021 }
fb_rename_file(xitk_widget_t * w,void * data)1022 static void fb_rename_file(xitk_widget_t *w, void *data) {
1023 filebrowser_t *fb = (filebrowser_t *) data;
1024 int sel;
1025
1026 if((sel = xitk_browser_get_current_selected(fb->files_browser)) >= 0) {
1027 char buf[XITK_PATH_MAX + XITK_NAME_MAX + 2];
1028
1029 snprintf(buf, sizeof(buf), "%s%s%s",
1030 fb->current_dir, ((fb->current_dir[0] && strcmp(fb->current_dir, "/")) ? "/" : ""),
1031 fb->norm_files[sel].name);
1032
1033 fb_deactivate(fb);
1034 fb_create_input_window(_("Rename file"), buf, fb_rename_file_cb, fb);
1035 }
1036 }
1037
fb_create_directory_cb(xitk_widget_t * w,void * data,const char * newdir)1038 static void fb_create_directory_cb(xitk_widget_t *w, void *data, const char *newdir) {
1039 filebrowser_t *fb = (filebrowser_t *) data;
1040
1041 if(!mkdir_safe(newdir))
1042 xine_error(_("Unable to create the directory '%s': %s."), newdir, strerror(errno));
1043 else
1044 fb_getdir(fb);
1045 }
fb_create_directory(xitk_widget_t * w,void * data)1046 static void fb_create_directory(xitk_widget_t *w, void *data) {
1047 filebrowser_t *fb = (filebrowser_t *) data;
1048 char buf[XITK_PATH_MAX + XITK_NAME_MAX + 2];
1049
1050 snprintf(buf, sizeof(buf), "%s%s",
1051 fb->current_dir, ((fb->current_dir[0] && strcmp(fb->current_dir, "/")) ? "/" : ""));
1052
1053 fb_deactivate(fb);
1054 fb_create_input_window(_("Create a new directory"), buf, fb_create_directory_cb, fb);
1055 }
1056
fb_select_file_filter(xitk_widget_t * w,void * data,int selected)1057 static void fb_select_file_filter(xitk_widget_t *w, void *data, int selected) {
1058 filebrowser_t *fb = (filebrowser_t *) data;
1059
1060 fb->filter_selected = selected;
1061 fb_getdir(fb);
1062 }
1063
fb_hidden_files(xitk_widget_t * w,void * data,int state)1064 static void fb_hidden_files(xitk_widget_t *w, void *data, int state) {
1065 filebrowser_t *fb = (filebrowser_t *) data;
1066
1067 fb->show_hidden_files = state;
1068 fb->hidden_cb(1, state);
1069 fb_getdir(fb);
1070 }
fb_lbl_hidden_files(xitk_widget_t * w,void * data)1071 static void fb_lbl_hidden_files(xitk_widget_t *w, void *data) {
1072 filebrowser_t *fb = (filebrowser_t *) data;
1073
1074 xitk_checkbox_set_state(fb->show_hidden, (!xitk_checkbox_get_state(fb->show_hidden)));
1075 xitk_checkbox_callback_exec(fb->show_hidden);
1076 }
1077
fb_handle_events(XEvent * event,void * data)1078 static void fb_handle_events(XEvent *event, void *data) {
1079 filebrowser_t *fb = (filebrowser_t *) data;
1080
1081 switch(event->type) {
1082
1083 case KeyPress:
1084 if(xitk_get_key_pressed(event) == XK_Escape) {
1085 if(xitk_is_widget_enabled(fb->close)) /* Exit only if close button would exit */
1086 _fb_exit(NULL, data);
1087 }
1088 else {
1089 int sel = xitk_browser_get_current_selected(fb->files_browser);
1090
1091 if(sel >= 0)
1092 fb_select(fb->files_browser, (void *) fb, sel);
1093 else
1094 gui_handle_event(event, data);
1095 }
1096 break;
1097 }
1098 }
1099
filebrowser_raise_window(filebrowser_t * fb)1100 void filebrowser_raise_window(filebrowser_t *fb) {
1101 if(fb != NULL)
1102 raise_window(xitk_window_get_window(fb->xwin), fb->visible, fb->running);
1103 }
1104
filebrowser_end(filebrowser_t * fb)1105 void filebrowser_end(filebrowser_t *fb) {
1106 if(fb)
1107 fb_exit(NULL, (void *)fb);
1108 }
1109
filebrowser_get_current_dir(filebrowser_t * fb)1110 char *filebrowser_get_current_dir(filebrowser_t *fb) {
1111 char *current_dir = NULL;
1112
1113 if(fb)
1114 current_dir = strdup(fb->current_dir);
1115
1116 return current_dir;
1117 }
1118
filebrowser_get_current_filename(filebrowser_t * fb)1119 char *filebrowser_get_current_filename(filebrowser_t *fb) {
1120 char *filename = NULL;
1121
1122 if(fb && strlen(fb->filename))
1123 filename = strdup(fb->filename);
1124
1125 return filename;
1126 }
1127
filebrowser_get_full_filename(filebrowser_t * fb)1128 char *filebrowser_get_full_filename(filebrowser_t *fb) {
1129 char *fullfilename = NULL;
1130
1131 if(fb)
1132 fullfilename = strdup(xitk_inputtext_get_text(fb->origin));
1133
1134 return fullfilename;
1135 }
1136
filebrowser_get_all_files(filebrowser_t * fb)1137 char **filebrowser_get_all_files(filebrowser_t *fb) {
1138 char **files = NULL;
1139
1140 if(fb && fb->files_num) {
1141 int i;
1142 files = (char **) calloc((fb->files_num + 2), sizeof(char *));
1143
1144 for(i = 0; i < fb->files_num; i++)
1145 files[i] = strdup(fb->norm_files[i].name);
1146 files[i] = NULL;
1147 }
1148
1149 return files;
1150 }
1151
create_filebrowser(char * window_title,char * filepathname,hidden_file_toggle_t hidden_cb,filebrowser_callback_button_t * cbb1,filebrowser_callback_button_t * cbb2,filebrowser_callback_button_t * cbb_close)1152 filebrowser_t *create_filebrowser(char *window_title, char *filepathname, hidden_file_toggle_t hidden_cb,
1153 filebrowser_callback_button_t *cbb1,
1154 filebrowser_callback_button_t *cbb2,
1155 filebrowser_callback_button_t *cbb_close) {
1156 filebrowser_t *fb;
1157 GC gc;
1158 xitk_labelbutton_widget_t lb;
1159 xitk_label_widget_t lbl;
1160 xitk_checkbox_widget_t cb;
1161 xitk_pixmap_t *bg;
1162 xitk_browser_widget_t br;
1163 xitk_inputtext_widget_t inp;
1164 xitk_button_widget_t b;
1165 xitk_combo_widget_t cmb;
1166 xitk_widget_t *widget;
1167 int i, x, y, w, width, height;
1168
1169 fb = (filebrowser_t *) calloc(1, sizeof(filebrowser_t));
1170 if (!fb)
1171 return NULL;
1172
1173 fb->gui = gGui;
1174
1175 if(cbb1 && (strlen(cbb1->label) && cbb1->callback)) {
1176 fb->cbb[0].label = strdup(cbb1->label);
1177 fb->cbb[0].callback = cbb1->callback;
1178 fb->cbb[0].need_a_file = cbb1->need_a_file;
1179 if(cbb2 && (strlen(cbb2->label) && cbb2->callback)) {
1180 fb->cbb[1].label = strdup(cbb2->label);
1181 fb->cbb[1].callback = cbb2->callback;
1182 fb->cbb[1].need_a_file = cbb2->need_a_file;
1183 }
1184 else {
1185 fb->cbb[1].label = NULL;
1186 fb->cbb[1].callback = NULL;
1187 }
1188 }
1189 else {
1190 fb->cbb[0].label = NULL;
1191 fb->cbb[0].callback = NULL;
1192 fb->cbb[1].label = NULL;
1193 fb->cbb[1].callback = NULL;
1194 }
1195
1196 if(cbb_close)
1197 fb->cbb[2].callback = cbb_close->callback;
1198
1199 fb->gui->x_lock_display (fb->gui->display);
1200 x = (((DisplayWidth (fb->gui->display, fb->gui->screen))) >> 1) - (WINDOW_WIDTH >> 1);
1201 y = (((DisplayHeight (fb->gui->display, fb->gui->screen))) >> 1) - (WINDOW_HEIGHT >> 1);
1202 fb->gui->x_unlock_display (fb->gui->display);
1203
1204 /* Create window */
1205 fb->xwin = xitk_window_create_dialog_window (fb->gui->imlib_data,
1206 (window_title) ? window_title : _("File Browser"),
1207 x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
1208
1209 xitk_set_wm_window_type((xitk_window_get_window(fb->xwin)), WINDOW_TYPE_NORMAL);
1210 change_class_name((xitk_window_get_window(fb->xwin)));
1211 change_icon((xitk_window_get_window(fb->xwin)));
1212
1213 fb->directories = NULL;
1214 fb->directories_num = 0;
1215 fb->files = NULL;
1216 fb->files_num = 0;
1217 fb->directories_sort_direction = DEFAULT_SORT;
1218 fb->files_sort_direction = DEFAULT_SORT;
1219 fb->hidden_cb = hidden_cb;
1220 fb->show_hidden_files = hidden_cb(0, 0);
1221
1222 strlcpy(fb->current_dir, xine_get_homedir(), sizeof(fb->current_dir));
1223 memset(&fb->filename, 0, sizeof(fb->filename));
1224 fb_extract_path_and_file(fb, filepathname);
1225
1226 fb->norm_files = (fileinfo_t *) calloc(MAXFILES, sizeof(fileinfo_t));
1227 fb->dir_files = (fileinfo_t *) calloc(MAXFILES, sizeof(fileinfo_t));
1228
1229 fb->files = (char **) calloc(2, sizeof(char *));
1230 fb->directories = (char **) calloc(2, sizeof(char *));
1231
1232 fb->file_filters = (const char **) malloc(sizeof(filebrowser_filter_t) * ((sizeof(__fb_filters) / sizeof(__fb_filters[0])) + 1));
1233
1234 for(i = 0; __fb_filters[i].ending; i++)
1235 fb->file_filters[i] = _(__fb_filters[i].name);
1236
1237 fb->file_filters[i] = NULL;
1238 fb->filter_selected = 0;
1239
1240 fb->gui->x_lock_display (fb->gui->display);
1241 gc = XCreateGC (fb->gui->display,
1242 (xitk_window_get_window(fb->xwin)), None, None);
1243 fb->gui->x_unlock_display (fb->gui->display);
1244
1245 fb->widget_list = xitk_widget_list_new();
1246
1247 xitk_widget_list_set(fb->widget_list,
1248 WIDGET_LIST_WINDOW, (void *) (xitk_window_get_window(fb->xwin)));
1249 xitk_widget_list_set(fb->widget_list, WIDGET_LIST_GC, gc);
1250
1251 XITK_WIDGET_INIT(&lb, fb->gui->imlib_data);
1252 XITK_WIDGET_INIT(&lbl, fb->gui->imlib_data);
1253 XITK_WIDGET_INIT(&cb, fb->gui->imlib_data);
1254 XITK_WIDGET_INIT(&br, fb->gui->imlib_data);
1255 XITK_WIDGET_INIT(&inp, fb->gui->imlib_data);
1256 XITK_WIDGET_INIT(&cmb, fb->gui->imlib_data);
1257 XITK_WIDGET_INIT(&b, fb->gui->imlib_data);
1258
1259 xitk_window_get_window_size(fb->xwin, &width, &height);
1260 bg = xitk_image_create_xitk_pixmap (fb->gui->imlib_data, width, height);
1261 fb->gui->x_lock_display (fb->gui->display);
1262 XCopyArea (fb->gui->display, (xitk_window_get_background(fb->xwin)), bg->pixmap,
1263 bg->gc, 0, 0, width, height, 0, 0);
1264 fb->gui->x_unlock_display (fb->gui->display);
1265
1266
1267 x = 15;
1268 y = 30;
1269 w = WINDOW_WIDTH - 30;
1270
1271 inp.skin_element_name = NULL;
1272 inp.text = NULL;
1273 inp.max_length = XITK_PATH_MAX + XITK_NAME_MAX + 1;
1274 inp.callback = fb_change_origin;
1275 inp.userdata = (void *)fb;
1276 fb->origin = xitk_noskin_inputtext_create (fb->widget_list, &inp,
1277 x, y, w, 20, "Black", "Black", fontname);
1278 xitk_add_widget (fb->widget_list, fb->origin);
1279 xitk_enable_and_show_widget(fb->origin);
1280
1281 fb_update_origin(fb);
1282
1283 y += 45;
1284 w = (WINDOW_WIDTH - 30 - 10) / 2;
1285
1286 br.arrow_up.skin_element_name = NULL;
1287 br.slider.skin_element_name = NULL;
1288 br.arrow_dn.skin_element_name = NULL;
1289 br.browser.skin_element_name = NULL;
1290 br.browser.max_displayed_entries = MAX_DISP_ENTRIES;
1291 br.browser.num_entries = fb->directories_num;
1292 br.browser.entries = (const char *const *)fb->directories;
1293 br.callback = fb_select;
1294 br.dbl_click_callback = fb_dbl_select;
1295 br.parent_wlist = fb->widget_list;
1296 br.userdata = (void *)fb;
1297 fb->directories_browser = xitk_noskin_browser_create (fb->widget_list, &br,
1298 (XITK_WIDGET_LIST_GC(fb->widget_list)), x + 2, y + 2, w - 4 - 12, 20, 12, fontname);
1299 xitk_add_widget (fb->widget_list, fb->directories_browser);
1300 xitk_enable_and_show_widget(fb->directories_browser);
1301
1302 draw_rectangular_inner_box (fb->gui->imlib_data, bg, x, y,
1303 w - 1, xitk_get_widget_height(fb->directories_browser) + 4 - 1);
1304
1305 y -= 15;
1306
1307 b.skin_element_name = NULL;
1308 b.callback = fb_sort;
1309 b.userdata = (void *)fb;
1310 fb->directories_sort = xitk_noskin_button_create (fb->widget_list, &b, x, y, w, 15);
1311 xitk_add_widget (fb->widget_list, fb->directories_sort);
1312 xitk_enable_and_show_widget(fb->directories_sort);
1313
1314 x = WINDOW_WIDTH - (w + 15);
1315 y += 15;
1316
1317 br.arrow_up.skin_element_name = NULL;
1318 br.slider.skin_element_name = NULL;
1319 br.arrow_dn.skin_element_name = NULL;
1320 br.browser.skin_element_name = NULL;
1321 br.browser.max_displayed_entries = MAX_DISP_ENTRIES;
1322 br.browser.num_entries = fb->files_num;
1323 br.browser.entries = (const char *const *)fb->files;
1324 br.callback = fb_select;
1325 br.dbl_click_callback = fb_dbl_select;
1326 br.parent_wlist = fb->widget_list;
1327 br.userdata = (void *)fb;
1328 fb->files_browser = xitk_noskin_browser_create (fb->widget_list, &br,
1329 (XITK_WIDGET_LIST_GC(fb->widget_list)), x + 2, y + 2, w - 4 - 12, 20, 12, fontname);
1330 xitk_add_widget (fb->widget_list, fb->files_browser);
1331 xitk_enable_and_show_widget(fb->files_browser);
1332
1333 draw_rectangular_inner_box (fb->gui->imlib_data, bg, x, y,
1334 w - 1, xitk_get_widget_height(fb->files_browser) + 4 - 1);
1335
1336 y -= 15;
1337
1338 b.skin_element_name = NULL;
1339 b.callback = fb_sort;
1340 b.userdata = (void *)fb;
1341 fb->files_sort = xitk_noskin_button_create (fb->widget_list, &b, x, y, w, 15);
1342 xitk_add_widget (fb->widget_list, fb->files_sort);
1343 xitk_enable_and_show_widget(fb->files_sort);
1344
1345
1346 {
1347 xitk_image_t *dsimage = xitk_get_widget_foreground_skin(fb->directories_sort);
1348 xitk_image_t *fsimage = xitk_get_widget_foreground_skin(fb->files_sort);
1349 xitk_image_t *image;
1350 XPoint points[4];
1351 int i, j, w, offset;
1352 short x1, x2, x3;
1353 short y1, y2, y3;
1354
1355 fb->sort_skin_up = xitk_image_create_image (fb->gui->imlib_data,
1356 dsimage->width, dsimage->height);
1357 fb->sort_skin_down = xitk_image_create_image (fb->gui->imlib_data,
1358 dsimage->width, dsimage->height);
1359
1360 draw_bevel_three_state (fb->gui->imlib_data, fb->sort_skin_up);
1361 draw_bevel_three_state (fb->gui->imlib_data, fb->sort_skin_down);
1362
1363 w = dsimage->width / 3;
1364
1365 for(j = 0; j < 2; j++) {
1366 if(j == 0)
1367 image = fb->sort_skin_up;
1368 else
1369 image = fb->sort_skin_down;
1370
1371 offset = 0;
1372 for(i = 0; i < 2; i++) {
1373 draw_rectangular_outter_box (fb->gui->imlib_data, image->image,
1374 5, 4 + offset, w - 45, 1);
1375 draw_rectangular_outter_box (fb->gui->imlib_data, image->image,
1376 w - 20, 4 + offset, 10, 1);
1377 draw_rectangular_outter_box (fb->gui->imlib_data, image->image,
1378 w + 5, 4 + offset, w - 45, 1);
1379 draw_rectangular_outter_box (fb->gui->imlib_data, image->image,
1380 (w * 2) - 20, 4 + offset, 10, 1);
1381 draw_rectangular_outter_box (fb->gui->imlib_data, image->image,
1382 (w * 2) + 5 + 1, 4 + 1 + offset, w - 45, 1);
1383 draw_rectangular_outter_box (fb->gui->imlib_data, image->image,
1384 ((w * 3) - 20) + 1, 4 + 1 + offset, 10 + 1, 1);
1385 offset += 4;
1386 }
1387
1388 offset = 0;
1389 for(i = 0; i < 3; i++) {
1390 int k;
1391
1392 if(j == 0) {
1393 x1 = (w - 30) + offset;
1394 y1 = (2);
1395
1396 x2 = (w - 30) - 7 + offset;
1397 y2 = (2 + 8);
1398
1399 x3 = (w - 30) + 7 + offset;
1400 y3 = (2 + 8);
1401 }
1402 else {
1403 x1 = (w - 30) + offset;
1404 y1 = (2 + 8);
1405
1406 x2 = (w - 30) - 6 + offset;
1407 y2 = (3);
1408
1409 x3 = (w - 30) + 6 + offset;
1410 y3 = (3);
1411 }
1412
1413 if(i == 2) {
1414 x1++; x2++; x3++;
1415 y1++; y2++; y3++;
1416 }
1417
1418 points[0].x = x1;
1419 points[0].y = y1;
1420 points[1].x = x2;
1421 points[1].y = y2;
1422 points[2].x = x3;
1423 points[2].y = y3;
1424 points[3].x = x1;
1425 points[3].y = y1;
1426
1427 offset += w;
1428
1429 fb->gui->x_lock_display (fb->gui->display);
1430 XSetForeground (fb->gui->display, image->image->gc,
1431 xitk_get_pixel_color_lightgray (fb->gui->imlib_data));
1432 XFillPolygon (fb->gui->display, image->image->pixmap, image->image->gc,
1433 &points[0], 4, Convex, CoordModeOrigin);
1434 fb->gui->x_unlock_display (fb->gui->display);
1435
1436 fb->gui->x_lock_display (fb->gui->display);
1437 for(k = 0; k < 3; k++) {
1438 if(k == 0)
1439 XSetForeground (fb->gui->display, image->image->gc,
1440 xitk_get_pixel_color_black (fb->gui->imlib_data));
1441 else if(k == 1)
1442 XSetForeground (fb->gui->display, image->image->gc,
1443 xitk_get_pixel_color_darkgray (fb->gui->imlib_data));
1444 else
1445 XSetForeground (fb->gui->display, image->image->gc,
1446 xitk_get_pixel_color_white (fb->gui->imlib_data));
1447
1448 XDrawLine (fb->gui->display, image->image->pixmap, image->image->gc,
1449 points[k].x, points[k].y, points[k+1].x, points[k+1].y);
1450 }
1451 fb->gui->x_unlock_display (fb->gui->display);
1452
1453 }
1454 }
1455
1456 xitk_image_change_image (fb->gui->imlib_data, fb->sort_skin_down,
1457 dsimage, dsimage->width, dsimage->height);
1458 xitk_image_change_image (fb->gui->imlib_data, fb->sort_skin_down,
1459 fsimage, fsimage->width, fsimage->height);
1460 }
1461
1462 y += xitk_get_widget_height(fb->files_browser) + 15 + 4 + 5;
1463
1464 cmb.skin_element_name = NULL;
1465 cmb.layer_above = (is_layer_above());
1466 cmb.parent_wlist = fb->widget_list;
1467 cmb.entries = fb->file_filters;
1468 cmb.parent_wkey = &fb->widget_key;
1469 cmb.callback = fb_select_file_filter;
1470 cmb.userdata = (void *)fb;
1471 fb->filters = xitk_noskin_combo_create (fb->widget_list, &cmb, x, y, w, NULL, NULL);
1472 xitk_add_widget (fb->widget_list, fb->filters);
1473 xitk_combo_set_select(fb->filters, fb->filter_selected);
1474 xitk_enable_and_show_widget(fb->filters);
1475
1476 x = 15;
1477
1478 cb.skin_element_name = NULL;
1479 cb.callback = fb_hidden_files;
1480 cb.userdata = (void *) fb;
1481 fb->show_hidden = xitk_noskin_checkbox_create (fb->widget_list, &cb, x, y+5, 10, 10);
1482 xitk_add_widget (fb->widget_list, fb->show_hidden);
1483 xitk_checkbox_set_state(fb->show_hidden, fb->show_hidden_files);
1484 xitk_enable_and_show_widget(fb->show_hidden);
1485
1486 lbl.window = xitk_window_get_window(fb->xwin);
1487 lbl.gc = (XITK_WIDGET_LIST_GC(fb->widget_list));
1488 lbl.skin_element_name = NULL;
1489 lbl.label = _("Show hidden file");
1490 lbl.callback = fb_lbl_hidden_files;
1491 lbl.userdata = (void *) fb;
1492 widget = xitk_noskin_label_create (fb->widget_list, &lbl, x + 15, y, w - 15, 20, fontname);
1493 xitk_add_widget (fb->widget_list, widget);
1494 xitk_enable_and_show_widget(widget);
1495
1496 y = WINDOW_HEIGHT - (23 + 15) - (23 + 8);
1497 w = (WINDOW_WIDTH - (4 * 15)) / 3;
1498
1499 lb.button_type = CLICK_BUTTON;
1500 lb.label = _("Rename");
1501 lb.align = ALIGN_CENTER;
1502 lb.callback = fb_rename_file;
1503 lb.state_callback = NULL;
1504 lb.userdata = (void *)fb;
1505 lb.skin_element_name = NULL;
1506 fb->rename = xitk_noskin_labelbutton_create (fb->widget_list,
1507 &lb, x, y, w, 23, "Black", "Black", "White", btnfontname);
1508 xitk_add_widget (fb->widget_list, fb->rename);
1509 xitk_enable_and_show_widget(fb->rename);
1510
1511 x = (WINDOW_WIDTH - w) / 2;
1512
1513 lb.button_type = CLICK_BUTTON;
1514 lb.label = _("Delete");
1515 lb.align = ALIGN_CENTER;
1516 lb.callback = fb_delete_file;
1517 lb.state_callback = NULL;
1518 lb.userdata = (void *)fb;
1519 lb.skin_element_name = NULL;
1520 fb->delete = xitk_noskin_labelbutton_create (fb->widget_list,
1521 &lb, x, y, w, 23, "Black", "Black", "White", btnfontname);
1522 xitk_add_widget (fb->widget_list, fb->delete);
1523 xitk_enable_and_show_widget(fb->delete);
1524
1525 x = WINDOW_WIDTH - (w + 15);
1526
1527 lb.button_type = CLICK_BUTTON;
1528 lb.label = _("Create a directory");
1529 lb.align = ALIGN_CENTER;
1530 lb.callback = fb_create_directory;
1531 lb.state_callback = NULL;
1532 lb.userdata = (void *)fb;
1533 lb.skin_element_name = NULL;
1534 fb->create = xitk_noskin_labelbutton_create (fb->widget_list,
1535 &lb, x, y, w, 23, "Black", "Black", "White", btnfontname);
1536 xitk_add_widget (fb->widget_list, fb->create);
1537 xitk_enable_and_show_widget(fb->create);
1538
1539 fb->cb_buttons[0] = fb->cb_buttons[1] = NULL;
1540
1541 y = WINDOW_HEIGHT - (23 + 15);
1542
1543 if(fb->cbb[0].label) {
1544 x = 15;
1545
1546 lb.button_type = CLICK_BUTTON;
1547 lb.label = fb->cbb[0].label;
1548 lb.align = ALIGN_CENTER;
1549 lb.callback = fb_callback_button_cb;
1550 lb.state_callback = NULL;
1551 lb.userdata = (void *)fb;
1552 lb.skin_element_name = NULL;
1553 fb->cb_buttons[0] = xitk_noskin_labelbutton_create (fb->widget_list,
1554 &lb, x, y, w, 23, "Black", "Black", "White", btnfontname);
1555 xitk_add_widget (fb->widget_list, fb->cb_buttons[0]);
1556
1557 xitk_enable_and_show_widget(fb->cb_buttons[0]);
1558
1559 if(fb->cbb[1].label) {
1560 x = (WINDOW_WIDTH - w) / 2;
1561
1562 lb.button_type = CLICK_BUTTON;
1563 lb.label = fb->cbb[1].label;
1564 lb.align = ALIGN_CENTER;
1565 lb.callback = fb_callback_button_cb;
1566 lb.state_callback = NULL;
1567 lb.userdata = (void *)fb;
1568 lb.skin_element_name = NULL;
1569 fb->cb_buttons[1] = xitk_noskin_labelbutton_create (fb->widget_list,
1570 &lb, x, y, w, 23, "Black", "Black", "White", btnfontname);
1571 xitk_add_widget (fb->widget_list, fb->cb_buttons[1]);
1572 xitk_enable_and_show_widget(fb->cb_buttons[1]);
1573 }
1574 }
1575
1576 x = WINDOW_WIDTH - (w + 15);
1577
1578 lb.button_type = CLICK_BUTTON;
1579 lb.label = _("Close");
1580 lb.align = ALIGN_CENTER;
1581 lb.callback = _fb_exit;
1582 lb.state_callback = NULL;
1583 lb.userdata = (void *)fb;
1584 lb.skin_element_name = NULL;
1585 fb->close = xitk_noskin_labelbutton_create (fb->widget_list,
1586 &lb, x, y, w, 23, "Black", "Black", "White", btnfontname);
1587 xitk_add_widget (fb->widget_list, fb->close);
1588 xitk_enable_and_show_widget(fb->close);
1589
1590 xitk_window_change_background (fb->gui->imlib_data, fb->xwin, bg->pixmap, width, height);
1591 xitk_image_destroy_xitk_pixmap(bg);
1592
1593
1594 if(fb->cb_buttons[0])
1595 xitk_set_focus_to_widget(fb->cb_buttons[0]);
1596
1597 {
1598 char buffer[256];
1599 snprintf(buffer, sizeof(buffer), "filebrowser%u", (unsigned int) time(NULL));
1600 fb->widget_key = xitk_register_event_handler(buffer,
1601 (xitk_window_get_window(fb->xwin)),
1602 fb_handle_events,
1603 NULL,
1604 NULL,
1605 fb->widget_list,
1606 (void *)fb);
1607 }
1608
1609 fb->visible = 1;
1610 fb->running = 1;
1611 filebrowser_raise_window(fb);
1612
1613 fb_getdir(fb);
1614
1615 layer_above_video(xitk_window_get_window(fb->xwin));
1616 try_to_set_input_focus(xitk_window_get_window(fb->xwin));
1617
1618 return fb;
1619 }
1620