1 /*
2 * 0BSD
3 *
4 * BSD Zero Clause License
5 *
6 * Copyright (c) 2019 Hermann Meyer
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted.
10
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21
22 /*
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE 1
25 #endif
26 */
27
28 #include <dirent.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <pwd.h>
35
36 #include <libgen.h>
37
38 #include "xfile-dialog.h"
39 #include "xmessage-dialog.h"
40
41 static void combo_response(void *w_, void* user_data);
42 static void set_selected_file(FileDialog *file_dialog);
43
draw_window(void * w_,void * user_data)44 static void draw_window(void *w_, void* user_data) {
45 Widget_t *w = (Widget_t*)w_;
46 XWindowAttributes attrs;
47 XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
48 int width = attrs.width;
49 int height = attrs.height;
50 if (attrs.map_state != IsViewable) return;
51
52 cairo_rectangle(w->crb,0,0,width,height);
53 set_pattern(w,&w->app->color_scheme->selected,&w->app->color_scheme->normal,BACKGROUND_);
54 cairo_fill (w->crb);
55
56 //widget_set_scale(w);
57 use_fg_color_scheme(w, NORMAL_);
58 cairo_set_font_size (w->crb, 12.0);
59 cairo_move_to (w->crb, 20, 35);
60 cairo_show_text(w->crb, _("Base Directory"));
61 cairo_move_to (w->crb, 20, 85);
62 cairo_show_text(w->crb, _("Places"));
63 cairo_move_to (w->crb, 130, 85);
64 cairo_show_text(w->crb, _("Entries"));
65 cairo_move_to (w->crb, 20, 330-w->scale.scale_y);
66 cairo_show_text(w->crb, _("Load: "));
67 cairo_move_to (w->crb, 45, 360-w->scale.scale_y);
68 cairo_show_text(w->crb, _("Show hidden files"));
69 cairo_move_to (w->crb, 45, 390-w->scale.scale_y);
70 cairo_show_text(w->crb, _("List view"));
71 cairo_move_to (w->crb, 60, 330-w->scale.scale_y);
72 cairo_show_text(w->crb, w->label);
73 //widget_reset_scale(w);
74 if (w->image) {
75 cairo_set_source_surface (w->crb, w->image, 180, 332-w->scale.scale_y);
76 cairo_paint (w->crb);
77 }
78 }
79
draw_fd_hslider(void * w_,void * user_data)80 static void draw_fd_hslider(void *w_, void* user_data) {
81 Widget_t *w = (Widget_t*)w_;
82
83 int width = w->width-2;
84 int height = w->height-2;
85 float center = (float)height/2;
86
87 float sliderstate = adj_get_state(w->adj_x);
88
89 use_text_color_scheme(w, get_color_state(w));
90 cairo_move_to (w->crb, 0.0, center);
91 cairo_line_to(w->crb,width,center);
92 cairo_set_line_width(w->crb,center/10);
93 cairo_stroke(w->crb);
94
95 use_bg_color_scheme(w, get_color_state(w));
96 cairo_rectangle(w->crb, (width-height)*sliderstate,0,height, height);
97 cairo_fill(w->crb);
98 cairo_new_path (w->crb);
99
100 use_text_color_scheme(w, get_color_state(w));
101 cairo_set_line_width(w->crb,3);
102 cairo_move_to (w->crb,((width-height)*sliderstate)+center, 0.0);
103 cairo_line_to(w->crb,((width-height)*sliderstate)+center,height);
104 cairo_stroke(w->crb);
105 cairo_new_path (w->crb);
106 }
107
button_quit_callback(void * w_,void * user_data)108 static void button_quit_callback(void *w_, void* user_data) {
109 Widget_t *w = (Widget_t*)w_;
110 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
111
112 if (w->flags & HAS_POINTER && !adj_get_value(w->adj)){
113 file_dialog->parent->func.dialog_callback(file_dialog->parent,NULL);
114 file_dialog->send_clear_func = false;
115 destroy_widget(file_dialog->w,file_dialog->w->app);
116 }
117 }
118
set_files(FileDialog * file_dialog)119 static inline int set_files(FileDialog *file_dialog) {
120 if (file_dialog->list_view) {
121 listview_set_list(file_dialog->ft,file_dialog->fp->file_names , (int)file_dialog->fp->file_counter);
122 } else {
123 multi_listview_set_list(file_dialog->ft,file_dialog->fp->file_names , (int)file_dialog->fp->file_counter);
124 }
125 int ret = -1;
126 int i = 0;
127 for (; i<(int)file_dialog->fp->file_counter; i++) {
128 if(file_dialog->fp->selected_file && strcmp(file_dialog->fp->file_names[i],
129 basename(file_dialog->fp->selected_file))==0 ) ret = i;
130 }
131 return ret;
132 }
133
set_dirs(FileDialog * file_dialog)134 static void set_dirs(FileDialog *file_dialog) {
135 int i = 0;
136 for (; i<(int)file_dialog->fp->dir_counter; i++) {
137 combobox_add_entry(file_dialog->ct,file_dialog->fp->dir_names[i]);
138 }
139 }
140
file_released_b_callback(void * w_,void * button_,void * user_data)141 static void file_released_b_callback(void *w_, void *button_, void* user_data) {
142 Widget_t *w = (Widget_t*)w_;
143 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
144 XButtonEvent *xbutton = (XButtonEvent*)button_;
145 if(xbutton->button == Button1) {
146 set_selected_file(file_dialog);
147 if(file_dialog->fp->selected_file) {
148 file_dialog->w->label = file_dialog->fp->selected_file;
149 expose_widget(file_dialog->w);
150 }
151 }
152 }
153
reload_from_dir(FileDialog * file_dialog)154 static void reload_from_dir(FileDialog *file_dialog) {
155 assert(file_dialog->fp->path != NULL);
156 if (file_dialog->list_view) {
157 listview_remove_list(file_dialog->ft);
158 } else {
159 multi_listview_remove_list(file_dialog->ft);
160 }
161 combobox_delete_entrys(file_dialog->ct);
162 int ds = fp_get_files(file_dialog->fp,file_dialog->fp->path, 1, 1);
163 int set_f = set_files(file_dialog);
164 set_dirs(file_dialog);
165 combobox_set_active_entry(file_dialog->ct, ds);
166 if (set_f != -1) {
167 if (file_dialog->list_view) {
168 listview_set_active_entry(file_dialog->ft, set_f);
169 } else {
170 multi_listview_set_active_entry(file_dialog->ft, set_f);
171 }
172 } else {
173 if (file_dialog->list_view) {
174 listview_unset_active_entry(file_dialog->ft);
175 } else {
176 multi_listview_unset_active_entry(file_dialog->ft);
177 }
178 }
179 listview_unset_active_entry(file_dialog->xdg_dirs);
180 expose_widget(file_dialog->ft);
181 expose_widget(file_dialog->ct);
182 expose_widget(file_dialog->xdg_dirs);
183 }
184
show_preview(FileDialog * file_dialog,const char * file_name)185 static void show_preview(FileDialog *file_dialog, const char* file_name) {
186 Widget_t* w = file_dialog->w;
187 cairo_surface_t *getpng = cairo_image_surface_create_from_png (file_name);
188 int width = cairo_image_surface_get_width(getpng);
189 int height = cairo_image_surface_get_height(getpng);
190 int width_t = 80;
191 int height_t = 80;
192 double x = (double)width_t/(double)width;
193 double y = (double)height_t/(double)height;
194 if (width > 20*height)
195 x = y = (double)width_t/(double)height;
196 cairo_surface_destroy(w->image);
197 w->image = NULL;
198
199 w->image = cairo_surface_create_similar (w->surface,
200 CAIRO_CONTENT_COLOR_ALPHA, width_t, height_t);
201 cairo_t *cri = cairo_create (w->image);
202 cairo_scale(cri, x,y);
203 cairo_set_source_surface (cri, getpng,0,0);
204 cairo_paint (cri);
205 cairo_surface_destroy(getpng);
206 cairo_destroy(cri);
207 expose_widget(w);
208 }
209
set_selected_file(FileDialog * file_dialog)210 static void set_selected_file(FileDialog *file_dialog) {
211 if(adj_get_value(file_dialog->ft->adj)<0 ||
212 adj_get_value(file_dialog->ft->adj) > file_dialog->fp->file_counter) return;
213
214 struct stat sb;
215 if (stat(file_dialog->fp->file_names[(int)adj_get_value(file_dialog->ft->adj)], &sb) == 0 && S_ISDIR(sb.st_mode)) {
216 asprintf(&file_dialog->fp->path, "%s",file_dialog->fp->file_names[(int)adj_get_value(file_dialog->ft->adj)]);
217 reload_from_dir(file_dialog);
218 return;
219 }
220
221 Widget_t* menu = file_dialog->ct->childlist->childs[1];
222 Widget_t* view_port = menu->childlist->childs[0];
223 ComboBox_t *comboboxlist = (ComboBox_t*)view_port->parent_struct;
224 if ((int)adj_get_value(file_dialog->ct->adj) < 0) return;
225 free(file_dialog->fp->selected_file);
226 file_dialog->fp->selected_file = NULL;
227 if (strlen(comboboxlist->list_names[(int)adj_get_value(file_dialog->ct->adj)]) > 1) {
228 asprintf(&file_dialog->fp->selected_file, "%s/%s",
229 comboboxlist->list_names[(int)adj_get_value(file_dialog->ct->adj)],
230 file_dialog->fp->file_names[(int)adj_get_value(file_dialog->ft->adj)]);
231 } else {
232 asprintf(&file_dialog->fp->selected_file, "/%s",
233 file_dialog->fp->file_names[(int)adj_get_value(file_dialog->ft->adj)]);
234 }
235 assert(file_dialog->fp->selected_file != NULL);
236 if (strstr(file_dialog->fp->selected_file, ".png")) {
237 show_preview(file_dialog, file_dialog->fp->selected_file);
238 } else if (file_dialog->w->image) {
239 cairo_surface_destroy(file_dialog->w->image);
240 file_dialog->w->image = NULL;
241 expose_widget(file_dialog->w);
242 }
243 }
244
reload_file_entrys(FileDialog * file_dialog)245 static void reload_file_entrys(FileDialog *file_dialog) {
246 if (file_dialog->list_view) {
247 listview_remove_list(file_dialog->ft);
248 } else {
249 multi_listview_remove_list(file_dialog->ft);
250 }
251 fp_get_files(file_dialog->fp,file_dialog->fp->path, 0, 1);
252 if (!file_dialog->fp->file_counter)
253 fp_get_files(file_dialog->fp,file_dialog->fp->path, 1, 1);
254 int set_f = set_files(file_dialog);
255 if (set_f != -1) {
256 if (file_dialog->list_view) {
257 listview_set_active_entry(file_dialog->ft, set_f);
258 } else {
259 multi_listview_set_active_entry(file_dialog->ft, set_f);
260 }
261 } else {
262 if (file_dialog->list_view) {
263 listview_unset_active_entry(file_dialog->ft);
264 } else {
265 multi_listview_unset_active_entry(file_dialog->ft);
266 }
267 }
268 expose_widget(file_dialog->ft);
269 }
270
combo_response(void * w_,void * user_data)271 static void combo_response(void *w_, void* user_data) {
272 Widget_t *w = (Widget_t*)w_;
273 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
274 Widget_t* menu = w->childlist->childs[1];
275 Widget_t* view_port = menu->childlist->childs[0];
276 ComboBox_t *comboboxlist = (ComboBox_t*)view_port->parent_struct;
277 if ((int)adj_get_value(file_dialog->ct->adj) < 0) return;
278 free(file_dialog->fp->path);
279 file_dialog->fp->path = NULL;
280 asprintf(&file_dialog->fp->path, "%s",comboboxlist->list_names[(int)adj_get_value(w->adj)]);
281 assert(file_dialog->fp->path != NULL);
282 reload_from_dir(file_dialog);
283 }
284
button_ok_callback(void * w_,void * user_data)285 static void button_ok_callback(void *w_, void* user_data) {
286 Widget_t *w = (Widget_t*)w_;
287 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
288 if (w->flags & HAS_POINTER && !*(int*)user_data){
289 if(file_dialog->fp->selected_file) {
290 file_dialog->parent->func.dialog_callback(file_dialog->parent,&file_dialog->fp->selected_file);
291 file_dialog->send_clear_func = false;
292 } else {
293 Widget_t *dia = open_message_dialog(w, INFO_BOX, _("INFO"), _("Please select a file"),NULL);
294 XSetTransientForHint(file_dialog->w->app->dpy, dia->widget, file_dialog->w->widget);
295 return;
296 }
297 destroy_widget(file_dialog->w,file_dialog->w->app);
298 }
299 }
300
file_double_click_callback(void * w_,void * button,void * user_data)301 static void file_double_click_callback(void *w_, void *button, void* user_data) {
302 Widget_t *w = (Widget_t*)w_;
303 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
304 if(!file_dialog->fp->selected_file) {
305 set_selected_file(file_dialog);
306 }
307 if(file_dialog->fp->selected_file) {
308 file_dialog->parent->func.dialog_callback(file_dialog->parent,&file_dialog->fp->selected_file);
309 file_dialog->send_clear_func = false;
310 } else {
311 Widget_t *dia = open_message_dialog(w, INFO_BOX, _("INFO"), _("Please select a file"),NULL);
312 XSetTransientForHint(file_dialog->w->app->dpy, dia->widget, file_dialog->w->widget);
313 return;
314 }
315 destroy_widget(file_dialog->w,file_dialog->w->app);
316 }
317
reload_all(FileDialog * file_dialog)318 static void reload_all(FileDialog *file_dialog) {
319 Widget_t* menu = file_dialog->ct->childlist->childs[1];
320 Widget_t* view_port = menu->childlist->childs[0];
321 ComboBox_t *comboboxlist = (ComboBox_t*)view_port->parent_struct;
322 if ((int)adj_get_value(file_dialog->ct->adj) < 0) return;
323 free(file_dialog->fp->path);
324 file_dialog->fp->path = NULL;
325 asprintf(&file_dialog->fp->path, "%s",comboboxlist->list_names[(int)adj_get_value(file_dialog->ct->adj)]);
326 assert(file_dialog->fp->path != NULL);
327 if (file_dialog->list_view) {
328 listview_remove_list(file_dialog->ft);
329 } else {
330 multi_listview_remove_list(file_dialog->ft);
331 }
332 combobox_delete_entrys(file_dialog->ct);
333 int ds = fp_get_files(file_dialog->fp,file_dialog->fp->path, 1, 1);
334 int set_f = set_files(file_dialog);
335 set_dirs(file_dialog);
336 combobox_set_active_entry(file_dialog->ct, ds);
337 if (set_f != -1) {
338 if (file_dialog->list_view) {
339 listview_set_active_entry(file_dialog->ft, set_f);
340 } else {
341 multi_listview_set_active_entry(file_dialog->ft, set_f);
342 }
343 } else {
344 if (file_dialog->list_view) {
345 listview_unset_active_entry(file_dialog->ft);
346 } else {
347 multi_listview_unset_active_entry(file_dialog->ft);
348 }
349 }
350 expose_widget(file_dialog->ft);
351 }
352
set_scale_factor_callback(void * w_,void * user_data)353 static void set_scale_factor_callback(void *w_, void* user_data) {
354 Widget_t *w = (Widget_t*)w_;
355 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
356 float v = adj_get_value(w->adj);
357 if (!file_dialog->list_view) {
358 multi_listview_set_item_size(file_dialog->ft, v);
359 }
360 }
361
open_dir_callback(void * w_,void * user_data)362 static void open_dir_callback(void *w_, void* user_data) {
363 Widget_t *w = (Widget_t*)w_;
364 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
365 if (w->flags & HAS_POINTER && !*(int*)user_data){
366 reload_from_dir(file_dialog);
367 }
368 }
369
button_hidden_callback(void * w_,void * user_data)370 static void button_hidden_callback(void *w_, void* user_data) {
371 Widget_t *w = (Widget_t*)w_;
372 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
373 if (w->flags & HAS_POINTER) {
374 file_dialog->fp->show_hidden = adj_get_value(w->adj) ? true : false;
375 reload_all(file_dialog);
376 }
377 }
378
button_view_callback(void * w_,void * user_data)379 static void button_view_callback(void *w_, void* user_data) {
380 Widget_t *w = (Widget_t*)w_;
381 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
382 if (w->flags & HAS_POINTER) {
383 file_dialog->list_view = adj_get_value(w->adj) ? true : false;
384 }
385 if (file_dialog->list_view) {
386 destroy_widget(file_dialog->ft, w->app);
387 file_dialog->ft = add_listview(file_dialog->w, "", 130, 90, 510, 225);
388 file_dialog->ft->parent_struct = file_dialog;
389 file_dialog->ft->scale.gravity = NORTHWEST;
390 file_dialog->ft->flags |= NO_PROPAGATE;
391 listview_set_check_dir(file_dialog->ft, 1);
392 file_dialog->ft->func.button_release_callback = file_released_b_callback;
393 file_dialog->ft->func.double_click_callback = file_double_click_callback;
394 int set_f = set_files(file_dialog);
395 if (set_f != -1) {
396 listview_set_active_entry(file_dialog->ft, set_f);
397 } else {
398 listview_unset_active_entry(file_dialog->ft);
399 }
400 widget_show_all(file_dialog->ft);
401 } else {
402 destroy_widget(file_dialog->ft, w->app);
403 file_dialog->ft = add_multi_listview(file_dialog->w, "", 130, 90, 510, 225);
404 file_dialog->ft->parent_struct = file_dialog;
405 file_dialog->ft->scale.gravity = NORTHWEST;
406 file_dialog->ft->flags |= NO_PROPAGATE;
407 multi_listview_set_check_dir(file_dialog->ft, 1);
408 file_dialog->ft->func.button_release_callback = file_released_b_callback;
409 file_dialog->ft->func.double_click_callback = file_double_click_callback;
410 int set_f = set_files(file_dialog);
411 if (set_f != -1) {
412 multi_listview_set_active_entry(file_dialog->ft, set_f);
413 } else {
414 multi_listview_unset_active_entry(file_dialog->ft);
415 }
416 multi_listview_set_item_size(file_dialog->ft,adj_get_value(file_dialog->scale_size->adj));
417 widget_show_all(file_dialog->ft);
418 }
419 resize_childs(file_dialog->w);
420 }
421
set_filter_callback(void * w_,void * user_data)422 static void set_filter_callback(void *w_, void* user_data) {
423 Widget_t *w = (Widget_t*)w_;
424 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
425 if (file_dialog->fp->use_filter != (int)adj_get_value(w->adj)) {
426 file_dialog->fp->use_filter = (int)adj_get_value(w->adj);
427 Widget_t* menu = w->childlist->childs[1];
428 Widget_t* view_port = menu->childlist->childs[0];
429 ComboBox_t *comboboxlist = (ComboBox_t*)view_port->parent_struct;
430 if ((int)adj_get_value(file_dialog->ct->adj) < 0) return;
431 free(file_dialog->fp->filter);
432 file_dialog->fp->filter = NULL;
433 asprintf(&file_dialog->fp->filter, "%s",comboboxlist->list_names[(int)adj_get_value(w->adj)]);
434 assert(file_dialog->fp->filter != NULL);
435
436 reload_file_entrys(file_dialog);
437 }
438 }
439
fd_mem_free(void * w_,void * user_data)440 static void fd_mem_free(void *w_, void* user_data) {
441 Widget_t *w = (Widget_t*)w_;
442 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
443 if(file_dialog->icon) {
444 XFreePixmap(w->app->dpy, (*file_dialog->icon));
445 file_dialog->icon = NULL;
446 }
447 if(file_dialog->send_clear_func)
448 file_dialog->parent->func.dialog_callback(file_dialog->parent,NULL);
449 fp_free(file_dialog->fp);
450 free(file_dialog->fp);
451 free(file_dialog);
452 }
453
starts_with(const char * restrict string,const char * restrict prefix)454 static int starts_with(const char *restrict string, const char *restrict prefix) {
455 while(*prefix)
456 {
457 if(*prefix++ != *string++)
458 return 0;
459 }
460
461 return 1;
462 }
463
strremove(char * string,const char * restrict find)464 static int strremove(char *string, const char *restrict find){
465 if(strstr(string, find) == NULL) return 0;
466 char *temporaryString = malloc(strlen(strstr(string, find) + strlen(find)) + 1);
467 strcpy(temporaryString, strstr(string, find) + strlen(find));
468 char* rep = strstr(string, find);
469 *rep = '\0';
470 //strcat(string, replaceWith);
471 strcat(string, temporaryString);
472 free(temporaryString);
473 return 1;
474 }
475
parse_xdg_dirs(FileDialog * file_dialog)476 static void parse_xdg_dirs(FileDialog *file_dialog) {
477
478 char xdg_dir[204];
479 file_dialog->home_dir = getenv("HOME");
480 if (file_dialog->home_dir == NULL) {
481 file_dialog->home_dir = getpwuid(getuid())->pw_dir;
482 }
483 if (file_dialog->home_dir == NULL) return;
484 sprintf(xdg_dir,"%s/.config/user-dirs.dirs", file_dialog->home_dir);
485 FILE * fp = NULL;
486 char * line = NULL;
487 size_t len = 0;
488 ssize_t read;
489
490 file_dialog->xdg_user_dirs = (char **)realloc(file_dialog->xdg_user_dirs,
491 (file_dialog->xdg_dir_counter + 1) * sizeof(char *));
492 assert(file_dialog->xdg_user_dirs != NULL);
493 asprintf(&file_dialog->xdg_user_dirs[file_dialog->xdg_dir_counter++], "%s", _("Home"));
494 assert(file_dialog->xdg_user_dirs[file_dialog->xdg_dir_counter-1] != NULL);
495
496
497 fp = fopen(xdg_dir, "r");
498 if (fp != NULL) {
499 while ((read = getline(&line, &len, fp)) != -1) {
500 if(starts_with(line,"XDG_")) {
501 char* xdg = strstr(line, "$HOME/");
502 if (!strremove(xdg, "$HOME/")) continue;
503 char* rep = strstr(xdg, "\"");
504 *rep = '\0';
505 file_dialog->xdg_user_dirs = (char **)realloc(file_dialog->xdg_user_dirs,
506 (file_dialog->xdg_dir_counter + 1) * sizeof(char *));
507 assert(file_dialog->xdg_user_dirs != NULL);
508 asprintf(&file_dialog->xdg_user_dirs[file_dialog->xdg_dir_counter++], "%s", xdg);
509 assert(file_dialog->xdg_user_dirs[file_dialog->xdg_dir_counter-1] != NULL);
510 }
511 }
512 fclose(fp);
513 }
514
515 file_dialog->xdg_user_dirs = (char **)realloc(file_dialog->xdg_user_dirs,
516 (file_dialog->xdg_dir_counter + 1) * sizeof(char *));
517 assert(file_dialog->xdg_user_dirs != NULL);
518 asprintf(&file_dialog->xdg_user_dirs[file_dialog->xdg_dir_counter++], "%s", _("Computer"));
519 assert(file_dialog->xdg_user_dirs[file_dialog->xdg_dir_counter-1] != NULL);
520
521 if (line)
522 free(line);
523 }
524
xdg_dir_select_callback(void * w_,void * button,void * user_data)525 static void xdg_dir_select_callback(void *w_, void *button, void* user_data) {
526 Widget_t *w = (Widget_t*)w_;
527 FileDialog *file_dialog = (FileDialog *)w->parent_struct;
528 int v = (int)adj_get_value(w->adj);
529 if (v == 0) {
530 free(file_dialog->fp->path);
531 file_dialog->fp->path = NULL;
532 asprintf(&file_dialog->fp->path, "%s",file_dialog->home_dir);
533 assert(file_dialog->fp->path != NULL);
534 } else if (v == file_dialog->xdg_dir_counter) {
535 free(file_dialog->fp->path);
536 file_dialog->fp->path = NULL;
537 asprintf(&file_dialog->fp->path, "%s",PATH_SEPARATOR);
538 assert(file_dialog->fp->path != NULL);
539 } else {
540 free(file_dialog->fp->path);
541 file_dialog->fp->path = NULL;
542 asprintf(&file_dialog->fp->path, "%s/%s",file_dialog->home_dir,file_dialog->xdg_user_dirs[v]);
543 assert(file_dialog->fp->path != NULL);
544 }
545 reload_from_dir(file_dialog);
546 }
547
add_xdg_dirs(FileDialog * file_dialog)548 static void add_xdg_dirs(FileDialog *file_dialog) {
549 file_dialog->xdg_dirs = add_listview(file_dialog->w, "", 20, 90, 100, 225);
550 file_dialog->xdg_dirs->parent_struct = file_dialog;
551 file_dialog->xdg_dirs->scale.gravity = EASTNORTH;
552 file_dialog->xdg_dirs->flags |= NO_PROPAGATE;
553 listview_set_list(file_dialog->xdg_dirs, file_dialog->xdg_user_dirs, (int)file_dialog->xdg_dir_counter);
554 file_dialog->xdg_dirs->func.button_release_callback = xdg_dir_select_callback;
555 listview_unset_active_entry(file_dialog->xdg_dirs);
556 }
557
open_file_dialog(Widget_t * w,const char * path,const char * filter)558 Widget_t *open_file_dialog(Widget_t *w, const char *path, const char *filter) {
559 FileDialog *file_dialog = (FileDialog*)malloc(sizeof(FileDialog));
560
561 file_dialog->xdg_user_dirs = NULL;
562 file_dialog->xdg_dir_counter = 0;
563 parse_xdg_dirs(file_dialog);
564 file_dialog->fp = (FilePicker*)malloc(sizeof(FilePicker));
565
566 struct stat sb;
567 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
568 fp_init(file_dialog->fp, path);
569 } else if (stat(file_dialog->home_dir, &sb) == 0 && S_ISDIR(sb.st_mode)) {
570 fp_init(file_dialog->fp, file_dialog->home_dir);
571 } else {
572 fp_init(file_dialog->fp, "/");
573 }
574
575 file_dialog->parent = w;
576 file_dialog->send_clear_func = true;
577 file_dialog->icon = NULL;
578 file_dialog->list_view = false;
579
580 file_dialog->w = create_window(w->app, DefaultRootWindow(w->app->dpy), 0, 0, 660, 415);
581
582 XSizeHints* win_size_hints;
583 win_size_hints = XAllocSizeHints();
584 win_size_hints->flags = PMinSize|PBaseSize|PMaxSize|PWinGravity;
585 win_size_hints->min_width = 660;
586 win_size_hints->min_height = 415;
587 win_size_hints->base_width = 660;
588 win_size_hints->base_height = 415;
589 win_size_hints->max_width = 960;
590 win_size_hints->max_height = 865;
591 win_size_hints->win_gravity = CenterGravity;
592 XSetWMNormalHints(file_dialog->w->app->dpy, file_dialog->w->widget, win_size_hints);
593 XFree(win_size_hints);
594
595 file_dialog->w->flags |= HAS_MEM;
596 file_dialog->w->parent_struct = file_dialog;
597 file_dialog->w->flags |= NO_PROPAGATE;
598 widget_set_title(file_dialog->w, _("File Selector"));
599 file_dialog->w->func.expose_callback = draw_window;
600 file_dialog->w->func.mem_free_callback = fd_mem_free;
601 widget_set_icon_from_png(file_dialog->w,file_dialog->icon,LDVAR(directory_png));
602
603 file_dialog->ct = add_combobox(file_dialog->w, "", 20, 40, 550, 30);
604 file_dialog->ct->parent_struct = file_dialog;
605 file_dialog->ct->scale.gravity = NORTHEAST;
606 file_dialog->ct->flags |= NO_PROPAGATE;
607 file_dialog->ct->func.value_changed_callback = combo_response;
608
609 file_dialog->sel_dir = add_button(file_dialog->w, _("Open"), 580, 40, 60, 30);
610 file_dialog->sel_dir->parent_struct = file_dialog;
611 file_dialog->sel_dir->scale.gravity = WESTNORTH;
612 file_dialog->sel_dir->flags |= NO_PROPAGATE;
613 add_tooltip(file_dialog->sel_dir,_("Open sub-directory's"));
614 file_dialog->sel_dir->func.value_changed_callback = open_dir_callback;
615
616 file_dialog->scale_size = add_hslider(file_dialog->w, "", 580, 10, 60, 15);
617 set_adjustment(file_dialog->scale_size->adj, 0.2, 0.2, 0.1, 0.4, 0.01, CL_CONTINUOS);
618 file_dialog->scale_size->parent_struct = file_dialog;
619 file_dialog->scale_size->scale.gravity = WESTNORTH;
620 file_dialog->scale_size->flags |= NO_PROPAGATE;
621 file_dialog->scale_size->func.expose_callback = draw_fd_hslider;
622 add_tooltip(file_dialog->scale_size,_("Set Icon scale factor"));
623 file_dialog->scale_size->func.value_changed_callback = set_scale_factor_callback;
624
625 file_dialog->ft = add_multi_listview(file_dialog->w, "", 130, 90, 510, 225);
626 file_dialog->ft->parent_struct = file_dialog;
627 file_dialog->ft->scale.gravity = NORTHWEST;
628 file_dialog->ft->flags |= NO_PROPAGATE;
629 multi_listview_set_check_dir(file_dialog->ft, 1);
630 file_dialog->ft->func.button_release_callback = file_released_b_callback;
631 file_dialog->ft->func.double_click_callback = file_double_click_callback;
632
633 int ds = fp_get_files(file_dialog->fp,file_dialog->fp->path, 1, 1);
634 int set_f = set_files(file_dialog);
635 set_dirs(file_dialog);
636 combobox_set_active_entry(file_dialog->ct, ds);
637 if (set_f != -1) {
638 multi_listview_set_active_entry(file_dialog->ft, set_f);
639 } else {
640 multi_listview_unset_active_entry(file_dialog->ft);
641 }
642
643 add_xdg_dirs(file_dialog);
644
645 file_dialog->w_quit = add_button(file_dialog->w, _("Cancel"), 580, 340, 60, 60);
646 file_dialog->w_quit->parent_struct = file_dialog;
647 file_dialog->w_quit->scale.gravity = SOUTHWEST;
648 file_dialog->w_quit->flags |= NO_PROPAGATE;
649 add_tooltip(file_dialog->w_quit,_("Exit file selector"));
650 file_dialog->w_quit->func.value_changed_callback = button_quit_callback;
651
652 file_dialog->w_okay = add_button(file_dialog->w, _("Load"), 510, 340, 60, 60);
653 file_dialog->w_okay->parent_struct = file_dialog;
654 file_dialog->w_okay->scale.gravity = SOUTHWEST;
655 file_dialog->w_okay->flags |= NO_PROPAGATE;
656 add_tooltip(file_dialog->w_okay,_("Load selected file"));
657 file_dialog->w_okay->func.value_changed_callback = button_ok_callback;
658
659 file_dialog->set_filter = add_combobox(file_dialog->w, "", 360, 345, 120, 30);
660 file_dialog->set_filter->parent_struct = file_dialog;
661 file_dialog->set_filter->scale.gravity = SOUTHWEST;
662 file_dialog->set_filter->flags |= NO_PROPAGATE;
663 combobox_add_entry(file_dialog->set_filter,_("all"));
664 combobox_add_entry(file_dialog->set_filter,_("application"));
665 combobox_add_entry(file_dialog->set_filter,_("audio"));
666 combobox_add_entry(file_dialog->set_filter,_("font"));
667 combobox_add_entry(file_dialog->set_filter,_("image"));
668 combobox_add_entry(file_dialog->set_filter,_("text"));
669 combobox_add_entry(file_dialog->set_filter,_("video"));
670 combobox_add_entry(file_dialog->set_filter,_("x-content"));
671 if(filter !=NULL && strlen(filter))
672 combobox_add_entry(file_dialog->set_filter,filter);
673 combobox_set_active_entry(file_dialog->set_filter, 0);
674 file_dialog->set_filter->func.value_changed_callback = set_filter_callback;
675 if(filter !=NULL && strlen(filter))
676 combobox_set_active_entry(file_dialog->set_filter, 8);
677 add_tooltip(file_dialog->set_filter->childlist->childs[0], _("File filter type"));
678
679 file_dialog->w_hidden = add_check_button(file_dialog->w, "", 20, 345, 20, 20);
680 file_dialog->w_hidden->parent_struct = file_dialog;
681 file_dialog->w_hidden->scale.gravity = EASTWEST;
682 file_dialog->w_hidden->flags |= NO_PROPAGATE;
683 add_tooltip(file_dialog->w_hidden,_("Show hidden files and folders"));
684 file_dialog->w_hidden->func.value_changed_callback = button_hidden_callback;
685
686 file_dialog->view = add_check_button(file_dialog->w, "", 20, 375, 20, 20);
687 file_dialog->view->parent_struct = file_dialog;
688 file_dialog->view->scale.gravity = EASTWEST;
689 file_dialog->view->flags |= NO_PROPAGATE;
690 add_tooltip(file_dialog->view,_("Show entries in list view"));
691 file_dialog->view->func.value_changed_callback = button_view_callback;
692
693 widget_show_all(file_dialog->w);
694 return file_dialog->w;
695 }
696
697 /*---------------------------------------------------------------------
698 -----------------------------------------------------------------------
699 add_file_button
700 -----------------------------------------------------------------------
701 ----------------------------------------------------------------------*/
702
fdialog_response(void * w_,void * user_data)703 static void fdialog_response(void *w_, void* user_data) {
704 Widget_t *w = (Widget_t*)w_;
705 FileButton *filebutton = (FileButton *)w->parent_struct;
706 if(user_data !=NULL) {
707 char *tmp = strdup(*(const char**)user_data);
708 free(filebutton->last_path);
709 filebutton->last_path = NULL;
710 filebutton->last_path = strdup(dirname(tmp));
711 filebutton->path = filebutton->last_path;
712 free(tmp);
713 }
714 w->func.user_callback(w,user_data);
715 filebutton->is_active = false;
716 adj_set_value(w->adj,0.0);
717 }
718
fbutton_callback(void * w_,void * user_data)719 static void fbutton_callback(void *w_, void* user_data) {
720 Widget_t *w = (Widget_t*)w_;
721 FileButton *filebutton = (FileButton *)w->parent_struct;
722 if (w->flags & HAS_POINTER && adj_get_value(w->adj)){
723 filebutton->w = open_file_dialog(w,filebutton->path,filebutton->filter);
724 Atom wmStateAbove = XInternAtom(w->app->dpy, "_NET_WM_STATE_ABOVE", 1 );
725 Atom wmNetWmState = XInternAtom(w->app->dpy, "_NET_WM_STATE", 1 );
726 XChangeProperty(w->app->dpy, filebutton->w->widget, wmNetWmState, XA_ATOM, 32,
727 PropModeReplace, (unsigned char *) &wmStateAbove, 1);
728 filebutton->is_active = true;
729 } else if (w->flags & HAS_POINTER && !adj_get_value(w->adj)){
730 if(filebutton->is_active)
731 destroy_widget(filebutton->w,w->app);
732 }
733 }
734
fbutton_mem_free(void * w_,void * user_data)735 static void fbutton_mem_free(void *w_, void* user_data) {
736 Widget_t *w = (Widget_t*)w_;
737 FileButton *filebutton = (FileButton *)w->parent_struct;
738 free(filebutton->last_path);
739 filebutton->last_path = NULL;
740 free(filebutton);
741 filebutton = NULL;
742 }
743
add_file_button(Widget_t * parent,int x,int y,int width,int height,const char * path,const char * filter)744 Widget_t *add_file_button(Widget_t *parent, int x, int y, int width, int height,
745 const char *path, const char *filter) {
746 FileButton *filebutton = (FileButton*)malloc(sizeof(FileButton));
747 filebutton->path = path;
748 filebutton->filter = filter;
749 filebutton->last_path = NULL;
750 filebutton->w = NULL;
751 filebutton->is_active = false;
752 Widget_t *fbutton = add_image_toggle_button(parent, "", x, y, width, height);
753 fbutton->parent_struct = filebutton;
754 fbutton->flags |= HAS_MEM;
755 widget_get_png(fbutton, LDVAR(directory_open_png));
756 fbutton->scale.gravity = CENTER;
757 fbutton->func.mem_free_callback = fbutton_mem_free;
758 fbutton->func.value_changed_callback = fbutton_callback;
759 fbutton->func.dialog_callback = fdialog_response;
760 return fbutton;
761 }
762