a8594e7f998fdb30d680645c48ec46d4b1a48074
[platform/upstream/enlightenment.git] / src / bin / e_desktop_editor.c
1 #include "e.h"
2
3 /* TODO: Check cache update */
4
5 struct _E_Config_Dialog_Data
6 {
7    Efreet_Desktop *desktop;
8    int             type; /* desktop type */
9
10    char           *name; /* app name (e.g. Firefox) */
11    char           *generic_name; /* generic app name (e.g. Web Browser) */
12    char           *comment; /* a longer description */
13    char           *exec; /* command to execute */
14    char           *try_exec; /* executable to test for an apps existence */
15    char           *url; /* url to open */
16
17    char           *startup_wm_class; /* window class */
18    char           *categories; /* list of category names that app is in */
19    char           *mimes; /* list of mimes this app can handle */
20    char           *icon; /* absolute path to file or icon name */
21
22    int             startup_notify;
23    int             terminal;
24    int             show_in_menus;
25
26    E_Desktop_Edit *editor;
27
28    char           *orig_path; /* informational only */
29    Evas_Object    *orig_path_entry; /* to set when info changes */
30    Evas_Object    *icon_entry; /* to set when icon changes */
31
32    /* speed up check_changed tests */
33    Eina_Bool       changed_categories;
34    Eina_Bool       changed_mimes;
35    Eina_Bool       edited_categories;
36    Eina_Bool       edited_mimes;
37 };
38
39 /* local subsystem functions */
40
41 static int          _e_desktop_edit_view_create(E_Desktop_Edit *editor, E_Comp *c);
42 static void         _e_desktop_edit_free(E_Desktop_Edit *editor);
43 static void        *_e_desktop_edit_create_data(E_Config_Dialog *cfd);
44 static void         _e_desktop_edit_free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *data);
45 static int          _e_desktop_edit_basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *data);
46 static int          _e_desktop_edit_basic_check_changed(E_Config_Dialog *cfd, E_Config_Dialog_Data *data);
47 static Evas_Object *_e_desktop_edit_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *data);
48 static void         _e_desktop_editor_cb_icon_select(void *data1, void *data2);
49 static void         _e_desktop_edit_cb_icon_select_destroy(void *obj);
50 static void         _e_desktop_edit_cb_icon_select_ok(void *data, E_Dialog *dia);
51 static void         _e_desktop_edit_cb_icon_select_cancel(void *data, E_Dialog *dia);
52 static void         _e_desktop_editor_icon_update(E_Config_Dialog_Data *cfdata);
53 static void         _e_desktop_editor_cb_exec_select(void *data1, void *data2);
54 static void         _e_desktop_edit_cb_exec_select_destroy(void *obj);
55 static void         _e_desktop_edit_cb_exec_select_ok(void *data, E_Dialog *dia);
56 static void         _e_desktop_edit_cb_exec_select_cancel(void *data, E_Dialog *dia);
57 static void         _e_desktop_editor_exec_update(E_Config_Dialog_Data *cfdata);
58 static void         _e_desktop_edit_select_cb(void *data, Evas_Object *obj);
59 static void         _e_desktop_editor_icon_entry_changed(void *data, Evas_Object *obj);
60
61 #define IFDUP(src, dst) if (src) dst = strdup(src); else \
62     dst = NULL
63
64
65 static int
66 _e_util_icon_save(Ecore_X_Icon *icon, const char *filename)
67 {
68    Ecore_Evas *ee;
69    Evas *evas;
70    Evas_Object *im;
71    int ret;
72
73    ee = ecore_evas_buffer_new(icon->width, icon->height);
74    if (!ee) return 0;
75    evas = ecore_evas_get(ee);
76    evas_image_cache_set(evas, 0);
77    evas_font_cache_set(evas, 0);
78
79    im = evas_object_image_add(evas);
80    if (!im)
81      {
82         ecore_evas_free(ee);
83         return 0;
84      }
85    evas_object_move(im, 0, 0);
86    evas_object_resize(im, icon->width, icon->height);
87    evas_object_image_size_set(im, icon->width, icon->height);
88    evas_object_image_data_copy_set(im, icon->data);
89    evas_object_image_alpha_set(im, 1);
90    evas_object_show(im);
91    ret = evas_object_image_save(im, filename, NULL, NULL);
92    evas_object_del(im);
93    ecore_evas_free(ee);
94    return ret;
95 }
96 /* externally accessible functions */
97
98 EAPI Efreet_Desktop *
99 e_desktop_client_create(E_Client *ec)
100 {
101    Efreet_Desktop *desktop = NULL;
102    const char *desktop_dir, *icon_dir;
103    const char *bname, *bclass, *btitle;
104    char path[PATH_MAX];
105
106    bname = ec->icccm.name;
107    if ((bname) && (bname[0] == 0)) bname = NULL;
108    bclass = ec->icccm.class;
109    if ((bclass) && (bclass[0] == 0)) bclass = NULL;
110    btitle = e_client_util_name_get(ec);
111
112    desktop_dir = e_user_desktop_dir_get();
113
114    if ((!desktop_dir) || (!e_util_dir_check(desktop_dir))) return NULL;
115
116    icon_dir = e_user_icon_dir_get();
117    if ((!icon_dir) || (!e_util_dir_check(icon_dir))) return NULL;
118
119    if (bname)
120      {
121         snprintf(path, sizeof(path), "%s/%s.desktop", desktop_dir, bname);
122         desktop = efreet_desktop_empty_new(path);
123      }
124    else
125      {
126         int i;
127
128         for (i = 1; i < 65536; i++)
129           {
130              snprintf(path, sizeof(path), "%s/_new_app-%i.desktop",
131                       desktop_dir, i);
132              if (!ecore_file_exists(path))
133                {
134                   desktop = efreet_desktop_empty_new(path);
135                   break;
136                }
137           }
138         if (!desktop)
139           {
140              snprintf(path, sizeof(path), "%s/_rename_me-%i.desktop",
141                       desktop_dir, (int)ecore_time_get());
142              desktop = efreet_desktop_empty_new(NULL);
143           }
144      }
145
146    if (!desktop)
147      {
148         //XXX out of memory?
149         return NULL;
150      }
151    if (bclass) desktop->name = strdup(bclass);
152    else if (bname)
153      desktop->name = strdup(bname);
154    else if (btitle)
155      desktop->name = strdup(btitle);
156
157    if (btitle) desktop->comment = strdup(btitle);
158
159    if (bclass) desktop->startup_wm_class = strdup(bclass);
160    if (ec->icccm.command.argc > 0)
161      // FIXME this should concat the entire argv array together
162      desktop->exec = strdup(ec->icccm.command.argv[0]);
163    else if (bname)
164      desktop->exec = strdup(bname);
165
166 // disable this
167 //   if (ec->netwm.startup_id > 0) desktop->startup_notify = 1;
168    if (ec->netwm.icons)
169      {
170         /* FIXME
171          * - Find the icon with the best size
172          * - Should use mkstemp
173          */
174         char file[PATH_MAX];
175
176         snprintf(file, sizeof(file), "%s-%.6f.png", bname ?: "", ecore_time_get());
177         snprintf(path, sizeof(path), "%s/%s", icon_dir, file);
178         if (_e_util_icon_save(&(ec->netwm.icons[0]), path))
179           desktop->icon = strdup(file);
180         else
181           fprintf(stderr, "Could not save file from ARGB: %s\n", path);
182      }
183    return desktop;
184 }
185
186 EAPI E_Desktop_Edit *
187 e_desktop_border_edit(E_Comp *c, E_Client *ec)
188 {
189    E_Desktop_Edit *editor;
190    int new_desktop = 0;
191
192    editor = E_OBJECT_ALLOC(E_Desktop_Edit, E_DESKTOP_EDIT_TYPE, _e_desktop_edit_free);
193    if (!editor) return NULL;
194    if (ec->desktop)
195      editor->desktop = ec->desktop;
196
197    /* the border does not yet have a desktop entry. add one and pre-populate
198       it with values from the border */
199    if (!editor->desktop)
200      {
201         editor->desktop = e_desktop_client_create(ec);
202         if ((editor->desktop) && (editor->desktop->icon))
203           editor->tmp_image_path = strdup(editor->desktop->icon);
204         new_desktop = 1;
205      }
206
207 #if 0
208    if ((!bname) && (!bclass))
209      {
210         e_util_dialog_show(_("Incomplete Window Properties"),
211                            _("The window you are creating an icon for<br>"
212                              "does not contain window name and class<br>"
213                              "properties. Without these, you will have to<br>"
214                              "use the window title instead. This will only<br>"
215                              "work if the window title is the same at<br>"
216                              "the time the window starts up, and does not<br>"
217                              "change."));
218      }
219 #endif
220    if (!_e_desktop_edit_view_create(editor, c))
221      {
222         e_object_del(E_OBJECT(editor));
223         editor = NULL;
224      }
225    else
226      e_config_dialog_changed_set(editor->cfd, new_desktop);
227
228    return editor;
229 }
230
231 EAPI E_Desktop_Edit *
232 e_desktop_edit(E_Comp *c, Efreet_Desktop *desktop)
233 {
234    E_Desktop_Edit *editor;
235
236    editor = E_OBJECT_ALLOC(E_Desktop_Edit, E_DESKTOP_EDIT_TYPE, _e_desktop_edit_free);
237    if (!editor) return NULL;
238    if (desktop) editor->desktop = desktop;
239    if (!_e_desktop_edit_view_create(editor, c))
240      {
241         e_object_del(E_OBJECT(editor));
242         editor = NULL;
243      }
244    return editor;
245 }
246
247 static int
248 _e_desktop_edit_view_create(E_Desktop_Edit *editor, E_Comp *c EINA_UNUSED)
249 {
250    E_Config_Dialog_View *v;
251
252    v = E_NEW(E_Config_Dialog_View, 1);
253    if (!v) return 0;
254
255    /* view methods */
256    v->create_cfdata = _e_desktop_edit_create_data;
257    v->free_cfdata = _e_desktop_edit_free_data;
258    v->basic.apply_cfdata = _e_desktop_edit_basic_apply_data;
259    v->basic.create_widgets = _e_desktop_edit_basic_create_widgets;
260    v->basic.check_changed = _e_desktop_edit_basic_check_changed;
261
262    editor->cfd =
263      e_config_dialog_new(NULL, _("Desktop Entry Editor"), "E",
264                          "applications/new_application",
265                          "preferences-applications", 0, v, editor);
266
267    if (!editor->cfd)
268      {
269         E_FREE(v);
270         return 0;
271      }
272
273    return 1;
274 }
275
276 /* local subsystem functions */
277 static void
278 _e_desktop_edit_free(E_Desktop_Edit *editor)
279 {
280    if (!editor) return;
281    E_OBJECT_CHECK(editor);
282    E_OBJECT_TYPE_CHECK(editor, E_DESKTOP_EDIT_TYPE);
283
284    E_FREE(editor->tmp_image_path);
285    E_FREE(editor);
286 }
287
288 /**
289  * Populates the config dialog's data from the .desktop file passed in
290  */
291 static void *
292 _e_desktop_edit_create_data(E_Config_Dialog *cfd)
293 {
294    E_Config_Dialog_Data *cfdata;
295    Efreet_Desktop *desktop = NULL;
296    char path[PATH_MAX];
297
298    cfdata = E_NEW(E_Config_Dialog_Data, 1);
299    if (!cfdata) return NULL;
300    e_win_no_reopen_set(cfd->dia->win, 1);
301    cfdata->editor = cfd->data;
302
303    /*
304     * If we can't write to the file on it's current location,
305     * we always save to the user's applications dir.
306     * If the file is already there, then edit it directly. Otherwise, create
307     * a new empty desktop entry there.
308     *
309     * cfdata->editor->desktop is the the desktop passed in
310     * cfdata->desktop is the desktop to save
311     * desktop is the desktop to load
312     */
313    path[0] = '\0';
314    if (cfdata->editor->desktop)
315      {
316         char dir[PATH_MAX];
317         const char *file;
318
319         if (ecore_file_can_write(cfdata->editor->desktop->orig_path))
320           cfdata->desktop = efreet_desktop_uncached_new(cfdata->editor->desktop->orig_path);
321         else
322           {
323              snprintf(dir, sizeof(dir), "%s/applications", efreet_data_home_get());
324              if (!strncmp(dir, cfdata->editor->desktop->orig_path, strlen(dir)))
325                cfdata->desktop = efreet_desktop_uncached_new(cfdata->editor->desktop->orig_path);
326              else
327                {
328                   /* file not in user's dir, so create new desktop that points there */
329                   if (!ecore_file_exists(dir)) ecore_file_mkdir(dir);
330                   file = ecore_file_file_get(cfdata->editor->desktop->orig_path);
331                   snprintf(path, sizeof(path), "%s/%s", dir, file);
332                   /*
333                    * if a file already exists in the user dir with this name, we
334                    * fetch the pointer to it, so the caches stay consistent (this
335                    * probably will never return non null, since the ui shouldn't
336                    * provide a means to edit a file in a system dir when one
337                    * exists in the user's
338                    */
339                   cfdata->desktop = efreet_desktop_uncached_new(path);
340                }
341           }
342         desktop = cfdata->editor->desktop;
343      }
344
345    if (!cfdata->desktop)
346      cfdata->desktop = efreet_desktop_empty_new(path);
347
348    if (!desktop) desktop = cfdata->desktop;
349
350    IFDUP(desktop->name, cfdata->name);
351    IFDUP(desktop->generic_name, cfdata->generic_name);
352    IFDUP(desktop->comment, cfdata->comment);
353    IFDUP(desktop->exec, cfdata->exec);
354    IFDUP(desktop->try_exec, cfdata->try_exec);
355    IFDUP(desktop->url, cfdata->url);
356    IFDUP(desktop->startup_wm_class, cfdata->startup_wm_class);
357    IFDUP(desktop->orig_path, cfdata->orig_path);
358
359    if (desktop->categories)
360      cfdata->categories = efreet_desktop_string_list_join(desktop->categories);
361    if (desktop->mime_types)
362      cfdata->mimes = efreet_desktop_string_list_join(desktop->mime_types);
363
364    IFDUP(desktop->icon, cfdata->icon);
365
366    cfdata->startup_notify = desktop->startup_notify;
367    cfdata->terminal = desktop->terminal;
368    cfdata->show_in_menus = !desktop->no_display;
369
370    if (cfdata->exec && *cfdata->exec)
371      cfdata->type = 0;
372    else if (cfdata->url && *cfdata->url)
373      cfdata->type = 1;
374
375    return cfdata;
376 }
377
378 /**
379  * Frees the config dialog data
380  */
381 static void
382 _e_desktop_edit_free_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
383 {
384    if (cfdata->editor->tmp_image_path)
385      {
386         if ((!cfdata->desktop) || (!cfdata->editor->saved) ||
387             (!cfdata->desktop->icon) ||
388             (strcmp(cfdata->editor->tmp_image_path, cfdata->desktop->icon)))
389           {
390              ecore_file_unlink(cfdata->editor->tmp_image_path);
391           }
392      }
393    if (cfdata->desktop) efreet_desktop_free(cfdata->desktop);
394
395    E_FREE(cfdata->name);
396    E_FREE(cfdata->generic_name);
397    E_FREE(cfdata->comment);
398    E_FREE(cfdata->exec);
399    E_FREE(cfdata->try_exec);
400    E_FREE(cfdata->url);
401    E_FREE(cfdata->startup_wm_class);
402    E_FREE(cfdata->categories);
403    E_FREE(cfdata->icon);
404    E_FREE(cfdata->mimes);
405    E_FREE(cfdata->orig_path);
406
407    if (cfdata->editor->icon_fsel_dia)
408      e_object_del(E_OBJECT(cfdata->editor->icon_fsel_dia));
409
410    e_object_del(E_OBJECT(cfdata->editor));
411    free(cfdata);
412 }
413
414 static void
415 _e_desktop_edit_user_local_desktop_filename_generate(E_Config_Dialog_Data *cfdata, char *path)
416 {
417    char buf[PATH_MAX];
418    const char *name;
419    unsigned int i;
420    int prefix;
421
422    if ((cfdata->name) && (cfdata->name[0]))
423      name = cfdata->name;
424    else if ((cfdata->desktop) && (cfdata->desktop->name) &&
425             (cfdata->desktop->name[0]))
426      name = cfdata->name;
427    else
428      name = NULL;
429
430    if (name)
431      {
432         const char *s = name;
433         for (i = 0; i < sizeof(buf) - 1 && s[i]; i++)
434           {
435              if (isalnum(s[i]))
436                buf[i] = s[i];
437              else
438                buf[i] = '_';
439           }
440         buf[i] = '\0';
441      }
442    else
443      eina_strlcpy(buf, "unnamed_desktop", sizeof(buf));
444
445    i = snprintf(path, PATH_MAX, "%s/applications/%s.desktop",
446                 efreet_data_home_get(), buf);
447    if (i >= PATH_MAX)
448      {
449         path[0] = '\0';
450         return;
451      }
452    prefix = i - (sizeof(".desktop") - 1);
453
454    for (i = 0; ecore_file_exists(path); i++)
455      snprintf(path + prefix, PATH_MAX - prefix, "-%u.desktop", i);
456 }
457
458 static void
459 _e_desktop_edit_update_orig_path(E_Config_Dialog_Data *cfdata)
460 {
461    const char *orig_path;
462    char path[PATH_MAX];
463
464    if ((cfdata->desktop->orig_path) && (cfdata->desktop->orig_path[0]))
465      orig_path = cfdata->desktop->orig_path;
466    else
467      {
468         _e_desktop_edit_user_local_desktop_filename_generate(cfdata, path);
469         orig_path = cfdata->orig_path = strdup(path);
470      }
471
472    if (cfdata->orig_path_entry)
473      e_widget_entry_text_set(cfdata->orig_path_entry, orig_path);
474 }
475
476 /**
477  * Apply the basic config dialog
478  */
479 static int
480 _e_desktop_edit_basic_apply_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
481 {
482    E_FREE(cfdata->desktop->name);
483    IFDUP(cfdata->name, cfdata->desktop->name);
484    E_FREE(cfdata->desktop->comment);
485    IFDUP(cfdata->comment, cfdata->desktop->comment);
486
487    switch (cfdata->type)
488      {
489       case 1:
490         E_FREE(cfdata->desktop->url);
491         IFDUP(cfdata->url, cfdata->desktop->url);
492         break;
493
494       default:
495         E_FREE(cfdata->desktop->exec);
496         IFDUP(cfdata->exec, cfdata->desktop->exec);
497         E_FREE(cfdata->desktop->try_exec);
498         IFDUP(cfdata->try_exec, cfdata->desktop->try_exec);
499         break;
500      }
501
502    E_FREE(cfdata->desktop->generic_name);
503    IFDUP(cfdata->generic_name, cfdata->desktop->generic_name);
504    E_FREE(cfdata->desktop->startup_wm_class);
505    IFDUP(cfdata->startup_wm_class, cfdata->desktop->startup_wm_class);
506
507
508    E_FREE_LIST(cfdata->desktop->categories, eina_stringshare_del);
509    if (cfdata->categories)
510      cfdata->desktop->categories = efreet_desktop_string_list_parse(cfdata->categories);
511
512    E_FREE_LIST(cfdata->desktop->mime_types, eina_stringshare_del);
513    if (cfdata->mimes)
514      cfdata->desktop->mime_types = efreet_desktop_string_list_parse(cfdata->mimes);
515
516    E_FREE(cfdata->desktop->icon);
517    IFDUP(cfdata->icon, cfdata->desktop->icon);
518
519    cfdata->desktop->startup_notify = cfdata->startup_notify;
520    cfdata->desktop->terminal = cfdata->terminal;
521    cfdata->desktop->no_display = !cfdata->show_in_menus;
522
523    if (cfdata->desktop->orig_path && cfdata->desktop->orig_path[0])
524      cfdata->editor->saved = efreet_desktop_save(cfdata->desktop);
525    else
526      {
527         _e_desktop_edit_update_orig_path(cfdata);
528         cfdata->editor->saved = efreet_desktop_save_as
529             (cfdata->desktop, cfdata->orig_path);
530      }
531    return 1;
532 }
533
534 static int
535 _e_desktop_edit_basic_check_changed(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
536 {
537    int ret;
538
539    if ((cfdata->startup_notify != cfdata->desktop->startup_notify) ||
540        (cfdata->terminal != cfdata->desktop->terminal) ||
541        (cfdata->show_in_menus != !cfdata->desktop->no_display))
542      return 1;
543
544 #define CHECK(k)                                               \
545   do                                                           \
546     {                                                          \
547        const char *__k;                                        \
548        if (cfdata->desktop->k)                                 \
549          __k = cfdata->desktop->k;                             \
550        else if ((cfdata->editor) && (cfdata->editor->desktop)) \
551          __k = cfdata->editor->desktop->k;                     \
552        else                                                    \
553          __k = NULL;                                           \
554        if ((cfdata->k && !__k) || (!cfdata->k && __k) ||       \
555            (cfdata->k && __k && strcmp(cfdata->k, __k) != 0))  \
556          return 1;                                             \
557     }                                                          \
558   while (0)
559
560    CHECK(name);
561    CHECK(exec);
562    CHECK(try_exec);
563    CHECK(url);
564    CHECK(comment);
565    CHECK(generic_name);
566    CHECK(startup_wm_class);
567    CHECK(icon);
568 #undef CHECK
569
570    ret = 0;
571
572    if (cfdata->edited_categories)
573      {
574         const char *str;
575         Eina_List *lst = NULL, *old_lst;
576
577         cfdata->edited_categories = EINA_FALSE;
578         cfdata->changed_categories = EINA_FALSE;
579
580         if (cfdata->desktop->categories)
581           old_lst = cfdata->desktop->categories;
582         else if ((cfdata->editor) && (cfdata->editor->desktop))
583           old_lst = cfdata->editor->desktop->categories;
584         else
585           old_lst = NULL;
586
587         if (cfdata->categories)
588           lst = efreet_desktop_string_list_parse(cfdata->categories);
589         if (eina_list_count(lst) != eina_list_count(old_lst))
590           cfdata->changed_categories = EINA_TRUE;
591
592         EINA_LIST_FREE(lst, str)
593           {
594              if (!cfdata->changed_categories)
595                {
596                   Eina_List *n;
597                   const char *old;
598                   Eina_Bool found = EINA_FALSE;
599                   EINA_LIST_FOREACH(old_lst, n, old)
600                     {
601                        if (strcmp(str, old) == 0)
602                          {
603                             found = EINA_TRUE;
604                             break;
605                          }
606                     }
607                   if (!found)
608                     cfdata->changed_categories = EINA_TRUE;
609                }
610              eina_stringshare_del(str);
611           }
612      }
613    ret |= cfdata->changed_categories;
614
615    if (!ret)
616      {
617         if (cfdata->edited_mimes)
618           {
619              const char *str;
620              Eina_List *lst = NULL, *old_lst;
621
622              cfdata->edited_mimes = EINA_FALSE;
623              cfdata->changed_mimes = EINA_FALSE;
624
625              if (cfdata->desktop->mime_types)
626                old_lst = cfdata->desktop->mime_types;
627              else if ((cfdata->editor) && (cfdata->editor->desktop))
628                old_lst = cfdata->editor->desktop->mime_types;
629              else
630                old_lst = NULL;
631
632              if (cfdata->mimes)
633                lst = efreet_desktop_string_list_parse(cfdata->mimes);
634              if (eina_list_count(lst) != eina_list_count(old_lst))
635                cfdata->changed_mimes = EINA_TRUE;
636
637              EINA_LIST_FREE(lst, str)
638                {
639                   if (!cfdata->changed_mimes)
640                     {
641                        Eina_List *n;
642                        const char *old;
643                        Eina_Bool found = EINA_FALSE;
644                        EINA_LIST_FOREACH(old_lst, n, old)
645                          {
646                             if (strcmp(str, old) == 0)
647                               {
648                                  found = EINA_TRUE;
649                                  break;
650                               }
651                          }
652                        if (!found)
653                          cfdata->changed_mimes = EINA_TRUE;
654                     }
655                   eina_stringshare_del(str);
656                }
657           }
658         ret |= cfdata->changed_mimes;
659      }
660
661    return ret;
662 }
663
664 static void
665 _e_desktop_editor_name_changed(void *data, Evas_Object *obj __UNUSED__)
666 {
667    E_Config_Dialog_Data *cfdata = data;
668    _e_desktop_edit_update_orig_path(cfdata);
669 }
670
671 static void
672 _e_desktop_editor_categories_changed(void *data, Evas_Object *obj __UNUSED__)
673 {
674    E_Config_Dialog_Data *cfdata = data;
675    cfdata->edited_categories = EINA_TRUE;
676 }
677
678 static void
679 _e_desktop_editor_icon_entry_changed(void *data, Evas_Object *obj __UNUSED__)
680 {
681    E_Config_Dialog_Data *cfdata = data;
682    _e_desktop_editor_icon_update(cfdata);
683 }
684
685 static void
686 _e_desktop_editor_mimes_changed(void *data, Evas_Object *obj __UNUSED__)
687 {
688    E_Config_Dialog_Data *cfdata = data;
689    cfdata->edited_mimes = EINA_TRUE;
690 }
691
692 static Evas_Object *
693 _e_desktop_edit_basic_create_widgets(E_Config_Dialog *cfd __UNUSED__, Evas *evas, E_Config_Dialog_Data *cfdata)
694 {
695    E_Desktop_Edit *editor = cfdata->editor;
696    E_Radio_Group *rg;
697    Evas_Object *otb, *ol, *o, *ot;
698    Evas_Coord mw, mh;
699
700    editor->evas = evas;
701
702    otb = e_widget_toolbook_add(evas, 48 * e_scale, 48 * e_scale);
703
704    ot = e_widget_table_add(evas, 0);
705
706    o = e_widget_label_add(evas, _("Name"));
707    e_widget_table_object_append(ot, o, 0, 0, 1, 1, 1, 1, 0, 0);
708
709    o = e_widget_entry_add(evas, &(cfdata->name), NULL, NULL, NULL);
710    e_widget_size_min_get(o, &mw, &mh);
711    if (mw < 220) mw = 220;
712    e_widget_size_min_set(o, mw, mh);
713    if ((!cfdata->desktop->orig_path) || (!cfdata->desktop->orig_path[0]))
714      e_widget_on_change_hook_set(o, _e_desktop_editor_name_changed, cfdata);
715    e_widget_table_object_append(ot, o, 1, 0, 1, 1, 1, 1, 1, 0);
716
717    o = e_widget_label_add(evas, _("Comment"));
718    e_widget_table_object_append(ot, o, 0, 1, 1, 1, 1, 1, 0, 0);
719
720    o = e_widget_entry_add(evas, &(cfdata->comment), NULL, NULL, NULL);
721    e_widget_table_object_append(ot, o, 1, 1, 1, 1, 1, 1, 1, 0);
722
723    rg = e_widget_radio_group_new(&(cfdata->type));
724
725    // desktop type: application
726
727    o = e_widget_radio_add(evas, _("Application"), 0, rg);
728    e_widget_table_object_append(ot, o, 0, 2, 1, 1, 1, 1, 0, 0);
729
730    editor->entry_widget_exec = e_widget_entry_add
731        (evas, &(cfdata->exec), NULL, NULL, NULL);
732    e_widget_table_object_append(ot, editor->entry_widget_exec, 1, 2, 1, 1, 1, 1, 1, 0);
733
734    o = e_widget_button_add
735        (evas, "...", NULL, _e_desktop_editor_cb_exec_select, cfdata, editor);
736    e_widget_table_object_append(ot, o, 2, 2, 1, 1, 0, 0, 0, 0);
737
738    // desktop type: url
739    o = e_widget_radio_add(evas, _("URL"), 1, rg);
740    e_widget_table_object_append(ot, o, 0, 3, 1, 1, 1, 1, 0, 0);
741
742    editor->entry_widget_url = e_widget_entry_add
743        (evas, &(cfdata->url), NULL, NULL, NULL);
744    e_widget_table_object_append(ot, editor->entry_widget_url, 1, 3, 1, 1, 1, 1, 1, 0);
745    // FIXME: add url selection dialog (file:/etc/..)
746
747    e_widget_toolbook_page_append
748      (otb, NULL, _("Basic"), ot, 1, 0, 1, 0, 0.5, 0.0);
749
750    /* e_widget_size_min_get(ol, &mw, &mh); */
751
752    ot = e_widget_table_add(evas, 0);
753
754    editor->img_widget = e_widget_button_add
755        (evas, "", NULL, _e_desktop_editor_cb_icon_select, cfdata, editor);
756    _e_desktop_editor_icon_update(cfdata);
757    e_widget_size_min_set(editor->img_widget, 192, 192);
758
759    e_widget_table_object_append(ot, editor->img_widget, 0, 0, 2, 1, 1, 1, 0, 0);
760
761    o = e_widget_label_add(evas, _("Icon"));
762    e_widget_table_object_append(ot, o, 0, 1, 1, 1, 1, 1, 0, 0);
763
764    o = e_widget_entry_add(evas, &(cfdata->icon), NULL, NULL, NULL);
765    cfdata->icon_entry = o;
766    e_widget_on_change_hook_set(o, _e_desktop_editor_icon_entry_changed, cfdata);
767    e_widget_table_object_append(ot, o, 1, 1, 1, 1, 1, 1, 1, 0);
768
769    e_widget_toolbook_page_append
770      (otb, NULL, _("Icon"), ot, 0, 0, 0, 0, 0.5, 0.5);
771
772    ot = e_widget_table_add(evas, 0);
773
774    o = e_widget_label_add(evas, _("Generic Name"));
775    e_widget_table_object_append(ot, o, 0, 0, 1, 1, 1, 1, 0, 0);
776
777    o = e_widget_entry_add(evas, &(cfdata->generic_name), NULL, NULL, NULL);
778    e_widget_table_object_append(ot, o, 1, 0, 1, 1, 1, 1, 1, 0);
779
780    o = e_widget_label_add(evas, _("Window Class"));
781    e_widget_table_object_append(ot, o, 0, 1, 1, 1, 1, 1, 0, 0);
782
783    o = e_widget_entry_add(evas, &(cfdata->startup_wm_class), NULL, NULL, NULL);
784    e_widget_table_object_append(ot, o, 1, 1, 1, 1, 1, 1, 1, 0);
785
786    o = e_widget_label_add(evas, _("Categories"));
787    e_widget_table_object_append(ot, o, 0, 2, 1, 1, 1, 1, 0, 0);
788
789    o = e_widget_entry_add(evas, &(cfdata->categories), NULL, NULL, NULL);
790    e_widget_on_change_hook_set(o, _e_desktop_editor_categories_changed, cfdata);
791    e_widget_table_object_append(ot, o, 1, 2, 1, 1, 1, 1, 1, 0);
792
793    o = e_widget_label_add(evas, _("Mime Types"));
794    e_widget_table_object_append(ot, o, 0, 3, 1, 1, 1, 1, 0, 0);
795
796    o = e_widget_entry_add(evas, &(cfdata->mimes), NULL, NULL, NULL);
797    e_widget_on_change_hook_set(o, _e_desktop_editor_mimes_changed, cfdata);
798    e_widget_table_object_append(ot, o, 1, 3, 1, 1, 1, 1, 1, 0);
799
800    o = e_widget_label_add(evas, _("Desktop file"));
801    e_widget_table_object_append(ot, o, 0, 4, 1, 1, 1, 1, 0, 0);
802
803    o = e_widget_entry_add(evas, NULL, NULL, NULL, NULL);
804    e_widget_table_object_append(ot, o, 1, 4, 1, 1, 1, 1, 1, 0);
805    e_widget_entry_readonly_set(o, 1);
806    cfdata->orig_path_entry = o;
807    _e_desktop_edit_update_orig_path(cfdata);
808
809    e_widget_toolbook_page_append
810      (otb, NULL, _("General"), ot, 1, 0, 1, 0, 0.5, 0.0);
811
812    ol = e_widget_list_add(evas, 0, 0);
813    o = e_widget_check_add(evas, _("Startup Notify"), &(cfdata->startup_notify));
814    e_widget_list_object_append(ol, o, 1, 0, 0.0);
815    o = e_widget_check_add(evas, _("Run in Terminal"), &(cfdata->terminal));
816    e_widget_list_object_append(ol, o, 1, 0, 0.0);
817    o = e_widget_check_add(evas, _("Show in Menus"), &(cfdata->show_in_menus));
818    e_widget_list_object_append(ol, o, 1, 0, 0.0);
819    e_widget_toolbook_page_append
820      (otb, NULL, _("Options"), ol, 1, 0, 1, 0, 0.5, 0.0);
821
822    e_widget_toolbook_page_show(otb, 0);
823
824    e_util_win_auto_resize_fill(cfd->dia->win);
825    elm_win_center(cfd->dia->win, 1, 1);
826
827    return otb;
828 }
829
830 static void
831 _e_desktop_editor_cb_icon_select(void *data1, void *data2)
832 {
833    E_Config_Dialog_Data *cfdata;
834    E_Dialog *dia;
835    Evas_Object *o;
836    Evas_Coord mw, mh;
837    E_Desktop_Edit *editor;
838    char *path = NULL;
839    const char *icon_path = NULL;
840    char buf[PATH_MAX + 32];
841
842    editor = data2;
843    cfdata = data1;
844
845    if (editor->icon_fsel_dia) return;
846
847    dia = e_dialog_new(NULL, "E", "_eap_icon_select_dialog");
848    if (!dia) return;
849    e_object_del_attach_func_set(E_OBJECT(dia),
850                                 _e_desktop_edit_cb_icon_select_destroy);
851    snprintf(buf, sizeof(buf), _("Select an Icon for '%s'"), ecore_file_file_get(cfdata->orig_path));
852    e_dialog_title_set(dia, buf);
853    dia->data = cfdata;
854
855    /* absolute path to icon */
856    /* XXX change this to a generic icon selector (that can do either
857     * files from a dir, or icons in the current theme */
858    if (cfdata->icon)
859      {
860         if (ecore_file_exists(cfdata->icon))
861           icon_path = cfdata->icon;
862         else
863           icon_path = efreet_icon_path_find(e_config->icon_theme, cfdata->icon, 64);
864
865         if (icon_path)
866           path = ecore_file_dir_get(icon_path);
867      }
868
869    if (path)
870      {
871         o = e_widget_fsel_add(evas_object_evas_get(dia->win), "/", path, NULL, NULL,
872                               _e_desktop_edit_select_cb, cfdata,
873                               NULL, cfdata, 1);
874         free(path);
875      }
876    else
877      {
878         o = e_widget_fsel_add(evas_object_evas_get(dia->win), "~/", "/", NULL, NULL,
879                               _e_desktop_edit_select_cb, cfdata,
880                               NULL, cfdata, 1);
881      }
882
883    evas_object_show(o);
884    editor->icon_fsel = o;
885    e_widget_size_min_get(o, &mw, &mh);
886    e_dialog_content_set(dia, o, mw, mh);
887
888    /* buttons at the bottom */
889    e_dialog_button_add(dia, _("OK"), NULL,
890                        _e_desktop_edit_cb_icon_select_ok, cfdata);
891    e_dialog_button_add(dia, _("Cancel"), NULL,
892                        _e_desktop_edit_cb_icon_select_cancel, cfdata);
893    elm_win_center(dia->win, 1, 1);
894    e_dialog_show(dia);
895    editor->icon_fsel_dia = dia;
896 }
897
898 static void
899 _e_desktop_editor_cb_exec_select(void *data1, void *data2)
900 {
901    E_Config_Dialog_Data *cfdata;
902    E_Dialog *dia;
903    Evas_Object *o;
904    Evas_Coord mw, mh;
905    E_Desktop_Edit *editor;
906    char *path = NULL;
907
908    editor = data2;
909    cfdata = data1;
910
911    if (editor->exec_fsel_dia) return;
912
913    dia = e_dialog_new(NULL, "E", "_eap_exec_select_dialog");
914    if (!dia) return;
915    e_object_del_attach_func_set(E_OBJECT(dia),
916                                 _e_desktop_edit_cb_exec_select_destroy);
917    e_dialog_title_set(dia, _("Select an Executable"));
918    dia->data = cfdata;
919
920    /* absolute path to exe */
921    if (cfdata->exec)
922      {
923         path = ecore_file_dir_get(cfdata->exec);
924         if (path && !ecore_file_exists(path))
925           {
926              free(path);
927              path = NULL;
928           }
929      }
930
931    if (path)
932      {
933         o = e_widget_fsel_add(evas_object_evas_get(dia->win), "/", path, NULL, NULL,
934                               _e_desktop_edit_select_cb, cfdata,
935                               NULL, cfdata, 1);
936         free(path);
937         path = NULL;
938      }
939    else
940      {
941         o = e_widget_fsel_add(evas_object_evas_get(dia->win), "~/", "/", NULL, NULL,
942                               _e_desktop_edit_select_cb, cfdata,
943                               NULL, cfdata, 1);
944      }
945
946    evas_object_show(o);
947    editor->exec_fsel = o;
948    e_widget_size_min_get(o, &mw, &mh);
949    e_dialog_content_set(dia, o, mw, mh);
950
951    /* buttons at the bottom */
952    e_dialog_button_add(dia, _("OK"), NULL,
953                        _e_desktop_edit_cb_exec_select_ok, cfdata);
954    e_dialog_button_add(dia, _("Cancel"), NULL,
955                        _e_desktop_edit_cb_exec_select_cancel, cfdata);
956    elm_win_center(dia->win, 1, 1);
957    e_dialog_show(dia);
958    editor->exec_fsel_dia = dia;
959 }
960
961 static void
962 _e_desktop_edit_select_cb(void *data __UNUSED__, Evas_Object *obj __UNUSED__)
963 {
964 }
965
966 static void
967 _e_desktop_edit_cb_icon_select_destroy(void *obj)
968 {
969    E_Dialog *dia = obj;
970    E_Config_Dialog_Data *cfdata = dia->data;
971
972 /* extra unref isn't needed - there is no extra ref() anywhere i saw */
973 /*   e_object_unref(E_OBJECT(dia));*/
974    _e_desktop_edit_cb_icon_select_cancel(cfdata, NULL);
975 }
976
977 static void
978 _e_desktop_edit_cb_icon_select_ok(void *data, E_Dialog *dia)
979 {
980    E_Config_Dialog_Data *cfdata;
981    const char *file;
982    char *dir;
983    const char *icon_dir;
984
985    cfdata = data;
986    file = e_widget_fsel_selection_path_get(cfdata->editor->icon_fsel);
987    dir = ecore_file_dir_get(file);
988
989    E_FREE(cfdata->icon);
990
991    /* TODO: Check for theme icon */
992    icon_dir = e_user_icon_dir_get();
993    if ((icon_dir) && (e_util_dir_check(icon_dir)) && (!e_util_strcmp(dir, icon_dir)))
994      {
995         cfdata->icon = strdup(ecore_file_file_get(file));
996      }
997    else
998      {
999         Eina_List *xdg_dirs, *l;
1000         char buf[PATH_MAX];
1001
1002         xdg_dirs = efreet_data_dirs_get();
1003
1004         EINA_LIST_FOREACH(xdg_dirs, l, icon_dir)
1005           {
1006              snprintf(buf, sizeof(buf), "%s/icons", icon_dir);
1007              if (!ecore_file_is_dir(buf)) continue;
1008              if (!e_util_strcmp(dir, buf))
1009                {
1010                   cfdata->icon = strdup(ecore_file_file_get(file));
1011                   break;
1012                }
1013           }
1014      }
1015    if (!cfdata->icon)
1016      {
1017         IFDUP(file, cfdata->icon);
1018      }
1019    else
1020      {
1021         /* strip ext */
1022         char *p;
1023         p = strrchr(cfdata->icon, '.');
1024         if (p)
1025           {
1026              /* TODO: Check if known extension */
1027              *p = '\0';
1028           }
1029      }
1030    E_FREE(dir);
1031    e_widget_entry_text_set(cfdata->icon_entry, cfdata->icon);
1032
1033    _e_desktop_edit_cb_icon_select_cancel(data, dia);
1034 }
1035
1036 static void
1037 _e_desktop_edit_cb_icon_select_cancel(void *data, E_Dialog *dia)
1038 {
1039    E_Config_Dialog_Data *cfdata;
1040
1041    cfdata = data;
1042    if (dia) e_util_defer_object_del(E_OBJECT(dia));
1043    cfdata->editor->icon_fsel_dia = NULL;
1044    _e_desktop_editor_icon_update(cfdata);
1045 }
1046
1047 static void
1048 _e_desktop_editor_icon_update(E_Config_Dialog_Data *cfdata)
1049 {
1050    Evas_Object *o;
1051
1052    if (!cfdata->editor->img_widget) return;
1053    o = e_util_icon_theme_icon_add(cfdata->icon, 128, cfdata->editor->evas);
1054
1055    /* NB this takes care of freeing any previous icon object */
1056    e_widget_button_icon_set(cfdata->editor->img_widget, o);
1057    e_widget_change(cfdata->editor->img_widget);
1058 }
1059
1060 static void
1061 _e_desktop_edit_cb_exec_select_destroy(void *obj)
1062 {
1063    E_Dialog *dia = obj;
1064    E_Config_Dialog_Data *cfdata = dia->data;
1065
1066 /* guess it should work like _e_desktop_edit_cb_icon_select_destroy */
1067 /*    e_object_unref(E_OBJECT(dia)); */
1068    _e_desktop_edit_cb_exec_select_cancel(cfdata, NULL);
1069 }
1070
1071 static void
1072 _e_desktop_edit_cb_exec_select_ok(void *data, E_Dialog *dia)
1073 {
1074    E_Config_Dialog_Data *cfdata;
1075    const char *file;
1076
1077    cfdata = data;
1078    file = e_widget_fsel_selection_path_get(cfdata->editor->exec_fsel);
1079
1080    E_FREE(cfdata->exec);
1081    cfdata->exec = eina_str_escape(file);
1082    E_FREE(cfdata->try_exec);
1083    IFDUP(cfdata->exec, cfdata->try_exec);
1084
1085    _e_desktop_edit_cb_exec_select_cancel(data, dia);
1086 }
1087
1088 static void
1089 _e_desktop_edit_cb_exec_select_cancel(void *data, E_Dialog *dia)
1090 {
1091    E_Config_Dialog_Data *cfdata;
1092
1093    cfdata = data;
1094    if (dia) e_util_defer_object_del(E_OBJECT(dia));
1095    cfdata->editor->exec_fsel_dia = NULL;
1096    _e_desktop_editor_exec_update(cfdata);
1097 }
1098
1099 static void
1100 _e_desktop_editor_exec_update(E_Config_Dialog_Data *cfdata)
1101 {
1102    if (!cfdata->editor->entry_widget_exec) return;
1103    e_widget_entry_text_set(cfdata->editor->entry_widget_exec, cfdata->exec);
1104 }
1105