1 /*
2  * This file is part of YAD.
3  *
4  * YAD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * YAD is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with YAD. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Copyright (C) 2008-2020, Victor Ananjevsky <ananasik@gmail.com>
18  */
19 
20 #include <ctype.h>
21 #include <stdlib.h>
22 
23 #include "yad.h"
24 
25 #include "calendar.xpm"
26 
27 static GSList *fields = NULL;
28 static guint n_fields;
29 
30 /* expand %N in command to fields values */
31 static GString *
expand_action(gchar * cmd)32 expand_action (gchar * cmd)
33 {
34   GString *xcmd;
35   guint i = 0;
36 
37   xcmd = g_string_new ("");
38   while (cmd[i])
39     {
40       if (cmd[i] == '%')
41         {
42           i++;
43           if (g_ascii_isdigit (cmd[i]))
44             {
45               YadField *fld;
46               gchar *buf, *arg;
47               guint num, j = i;
48 
49               /* get field num */
50               while (g_ascii_isdigit (cmd[j]))
51                 j++;
52               buf = g_strndup (cmd + i, j - i);
53               num = g_ascii_strtoll (buf, NULL, 10);
54               g_free (buf);
55               if (num > 0 && num <= n_fields)
56                 num--;
57               else
58                 continue;
59 
60               /* get field value */
61               arg = NULL;
62               fld = g_slist_nth_data (options.form_data.fields, num);
63               switch (fld->type)
64                 {
65                 case YAD_FIELD_SIMPLE:
66                 case YAD_FIELD_HIDDEN:
67                 case YAD_FIELD_READ_ONLY:
68                 case YAD_FIELD_COMPLETE:
69                 case YAD_FIELD_FILE_SAVE:
70                 case YAD_FIELD_DIR_CREATE:
71                 case YAD_FIELD_MFILE:
72                 case YAD_FIELD_MDIR:
73                 case YAD_FIELD_DATE:
74                   buf = escape_char ((gchar *) gtk_entry_get_text (GTK_ENTRY (g_slist_nth_data (fields, num))), '"');
75                   arg = g_shell_quote (buf ? buf : "");
76                   g_free (buf);
77                   break;
78                 case YAD_FIELD_NUM:
79                   {
80                     guint prec = gtk_spin_button_get_digits (GTK_SPIN_BUTTON (g_slist_nth_data (fields, num)));
81                     arg = g_strdup_printf ("%.*f", prec, gtk_spin_button_get_value (GTK_SPIN_BUTTON (g_slist_nth_data (fields, num))));
82                     break;
83                   }
84                 case YAD_FIELD_CHECK:
85                   arg = g_strdup (print_bool_val (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (g_slist_nth_data (fields, num)))));
86                   break;
87                 case YAD_FIELD_COMBO:
88                 case YAD_FIELD_COMBO_ENTRY:
89                   buf = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (g_slist_nth_data (fields, num)));
90                   arg = g_shell_quote (buf ? buf : "");
91                   g_free (buf);
92                   break;
93                 case YAD_FIELD_SCALE:
94                   arg = g_strdup_printf ("%d", (gint) gtk_range_get_value (GTK_RANGE (g_slist_nth_data (fields, num))));
95                   break;
96                 case YAD_FIELD_FILE:
97                 case YAD_FIELD_DIR:
98                   arg = g_shell_quote (gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (g_slist_nth_data (fields, num))));
99                   break;
100                 case YAD_FIELD_FONT:
101                   arg = g_shell_quote (gtk_font_chooser_get_font (GTK_FONT_CHOOSER (g_slist_nth_data (fields, num))));
102                   break;
103                 case YAD_FIELD_LINK:
104                   arg = g_shell_quote (gtk_link_button_get_uri (GTK_LINK_BUTTON (g_slist_nth_data (fields, num))));
105                   break;
106                 case YAD_FIELD_APP:
107                   {
108                     GList *wl = gtk_container_get_children (GTK_CONTAINER (g_slist_nth_data (fields, num)));
109                     GAppInfo *info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (wl->data));
110                     arg =  g_shell_quote (g_app_info_get_executable (info));
111                     g_object_unref (info);
112                     break;
113                   }
114                 case YAD_FIELD_COLOR:
115                   {
116                     GdkRGBA c;
117                     GtkColorChooser *cb = GTK_COLOR_CHOOSER (g_slist_nth_data (fields, num));
118                     gtk_color_chooser_get_rgba (cb, &c);
119                     buf = get_color (&c);
120                     arg = g_shell_quote (buf ? buf : "");
121                     g_free (buf);
122                     break;
123                   }
124                 case YAD_FIELD_TEXT:
125                   {
126                     GtkTextBuffer *tb;
127                     GtkTextIter b, e;
128                     gchar *txt;
129 
130                     tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (g_slist_nth_data (fields, num)));
131                     gtk_text_buffer_get_bounds (tb, &b, &e);
132                     txt = gtk_text_buffer_get_text (tb, &b, &e, FALSE);
133 
134                     /* escape special chars */
135                     buf = escape_str (txt);
136                     g_free (txt);
137 
138                     /* escape quotes */
139                     txt = escape_char (buf, '"');
140                     g_free (buf);
141 
142                     arg = g_shell_quote (txt ? txt : "");
143                     g_free (txt);
144                   }
145                 default: ;
146                 }
147               if (arg)
148                 {
149                   g_string_append (xcmd, arg);
150                   g_free (arg);
151                 }
152               i = j;
153             }
154           else
155             {
156               g_string_append_c (xcmd, cmd[i]);
157               i++;
158             }
159         }
160       else
161         {
162           g_string_append_c (xcmd, cmd[i]);
163           i++;
164         }
165     }
166   g_string_append_c (xcmd, '\0');
167 
168   return xcmd;
169 }
170 
171 static void
set_field_value(guint num,gchar * value)172 set_field_value (guint num, gchar * value)
173 {
174   GtkWidget *w;
175   gchar **s;
176   YadField *fld = g_slist_nth_data (options.form_data.fields, num);
177 
178   w = GTK_WIDGET (g_slist_nth_data (fields, num));
179   if (g_ascii_strcasecmp (value, "@disabled@") == 0)
180     {
181       gtk_widget_set_sensitive (w, FALSE);
182       return;
183     }
184   else
185     gtk_widget_set_sensitive (w, TRUE);
186 
187   switch (fld->type)
188     {
189     case YAD_FIELD_READ_ONLY:
190       gtk_widget_set_sensitive (w, FALSE);
191     case YAD_FIELD_SIMPLE:
192     case YAD_FIELD_HIDDEN:
193     case YAD_FIELD_MFILE:
194     case YAD_FIELD_MDIR:
195     case YAD_FIELD_FILE_SAVE:
196     case YAD_FIELD_DIR_CREATE:
197     case YAD_FIELD_DATE:
198       gtk_entry_set_text (GTK_ENTRY (w), value);
199       break;
200 
201     case YAD_FIELD_NUM:
202       s = g_strsplit (value, options.common_data.item_separator, -1);
203       if (s[0])
204         {
205           gdouble val = g_ascii_strtod (s[0], NULL);
206           w = g_slist_nth_data (fields, num);
207           if (s[1])
208             {
209               gchar **s1 = g_strsplit (s[1], "..", 2);
210               if (s1[0] && s1[1])
211                 {
212                   gdouble min, max;
213                   min = g_ascii_strtod (s1[0], NULL);
214                   max = g_ascii_strtod (s1[1], NULL);
215                   if (min < max)
216                     gtk_spin_button_set_range (GTK_SPIN_BUTTON (w), min, max);
217                 }
218               g_strfreev (s1);
219               if (s[2])
220                 {
221                   gdouble step = g_ascii_strtod (s[2], NULL);
222                   gtk_spin_button_set_increments (GTK_SPIN_BUTTON (w), step, step * 10);
223                   if (s[3])
224                     {
225                       guint prec = (guint) g_ascii_strtoull (s[3], NULL, 0);
226                       if (prec > 20)
227                         prec = 20;
228                       gtk_spin_button_set_digits (GTK_SPIN_BUTTON (w), prec);
229                     }
230                 }
231             }
232           /* set initial value must be after setting range and step */
233           gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), val);
234         }
235       g_strfreev (s);
236       break;
237 
238     case YAD_FIELD_CHECK:
239       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), get_bool_val (value));
240       break;
241 
242     case YAD_FIELD_COMPLETE:
243       {
244         GtkEntryCompletion *c;
245         GtkTreeModel *m;
246         GtkTreeIter it;
247         gint i = 0, def = -1;
248 
249         c = gtk_entry_get_completion (GTK_ENTRY (w));
250         m = gtk_entry_completion_get_model (GTK_ENTRY_COMPLETION (c));
251         gtk_list_store_clear (GTK_LIST_STORE (m));
252 
253         s = g_strsplit (value, options.common_data.item_separator, -1);
254         while (s[i])
255           {
256             gtk_list_store_append (GTK_LIST_STORE (m), &it);
257             if (s[i][0] == '^')
258               {
259                 gtk_list_store_set (GTK_LIST_STORE (m), &it, 0, g_strcompress (s[i] + 1), -1);
260                 def = i;
261               }
262             else
263               gtk_list_store_set (GTK_LIST_STORE (m), &it, 0, g_strcompress (s[i]), -1);
264 
265             i++;
266           }
267         if (def >= 0)
268           gtk_entry_set_text (GTK_ENTRY (w), s[def] + 1);
269         else
270           gtk_entry_set_text (GTK_ENTRY (w), "");
271         g_strfreev (s);
272         break;
273       }
274 
275     case YAD_FIELD_COMBO:
276     case YAD_FIELD_COMBO_ENTRY:
277       {
278         GtkTreeModel *m;
279         gint i = 0, def = 0;
280 
281         /* cleanup previous values */
282         m = gtk_combo_box_get_model (GTK_COMBO_BOX (w));
283         gtk_list_store_clear (GTK_LIST_STORE (m));
284 
285         s = g_strsplit (value, options.common_data.item_separator, -1);
286         while (s[i])
287           {
288             gchar *buf;
289 
290             if (s[i][0] == '^')
291               {
292                 buf = g_strcompress (s[i] + 1);
293                 def = i;
294               }
295             else
296               buf = g_strcompress (s[i]);
297             gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), buf);
298             g_free (buf);
299             i++;
300           }
301         gtk_combo_box_set_active (GTK_COMBO_BOX (w), def);
302         g_strfreev (s);
303         break;
304       }
305 
306     case YAD_FIELD_DIR:
307       gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), value);
308     case YAD_FIELD_FILE:
309       gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w), value);
310       break;
311 
312     case YAD_FIELD_FONT:
313       gtk_font_chooser_set_font (GTK_FONT_CHOOSER (w), value);
314       break;
315 
316     case YAD_FIELD_SCALE:
317       gtk_range_set_value (GTK_RANGE (w), atoi (value));
318       break;
319 
320     case YAD_FIELD_APP:
321       {
322         GtkWidget *b;
323         GList *wl;
324 
325         for (wl = gtk_container_get_children (GTK_CONTAINER (w)); wl; wl = wl->next)
326           {
327             GtkWidget *cw = GTK_WIDGET (wl->data);
328             gtk_container_remove (GTK_CONTAINER (w), cw);
329             gtk_widget_destroy (cw);
330           }
331 
332         if (value && value[0])
333           b = gtk_app_chooser_button_new (value);
334         else
335           b = gtk_app_chooser_button_new ("text/plain");
336         gtk_widget_set_name (b, "yad-form-app");
337         gtk_box_pack_start (GTK_BOX (w), b, TRUE, TRUE, 0);
338         gtk_widget_show_all (w);
339         break;
340       }
341 
342     case YAD_FIELD_COLOR:
343       {
344         GdkRGBA c;
345         gdk_rgba_parse (&c, value);
346         gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (w), &c);
347         break;
348       }
349 
350     case YAD_FIELD_BUTTON:
351     case YAD_FIELD_FULL_BUTTON:
352       g_object_set_data_full (G_OBJECT (w), "cmd", g_strdup (value), g_free);
353       break;
354 
355     case YAD_FIELD_LINK:
356       gtk_link_button_set_uri (GTK_LINK_BUTTON (w), value);
357       break;
358 
359     case YAD_FIELD_TEXT:
360       {
361         GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (w));
362         gchar *txt = g_strcompress (value);
363         gtk_text_buffer_set_text (tb, txt, -1);
364         g_free (txt);
365         break;
366       }
367 
368     default:;
369     }
370 }
371 
372 static void
button_clicked_cb(GtkButton * b,gpointer data)373 button_clicked_cb (GtkButton * b, gpointer data)
374 {
375   gchar *action = (gchar *) g_object_get_data (G_OBJECT (b), "cmd");
376 
377   if (action && action[0])
378     {
379       if (action[0] == '@')
380         {
381           gchar *data;
382           gint exit = 1;
383           GString *cmd = expand_action (action + 1);
384           exit = run_command_sync (cmd->str, &data);
385           if (exit == 0)
386             {
387               guint i = 0;
388               gchar **lines = g_strsplit (data, "\n", 0);
389               while (lines[i] && lines[i][0])
390                 {
391                   gint fn;
392                   gchar *ptr = lines[i];
393 
394                   while (isblank (*ptr)) ptr++;
395 
396                   if (isdigit (*ptr))
397                     {
398                       gchar **ln = g_strsplit (ptr, ":", 2);
399                       fn = g_ascii_strtoll (ln[0], NULL, 10);
400                       if (fn && ln[1])
401                         set_field_value (fn - 1, ln[1]);
402                       g_strfreev (ln);
403                     }
404                   i++;
405                 }
406             }
407           g_free (data);
408           g_string_free (cmd, TRUE);
409         }
410       else
411         {
412           GString *cmd = expand_action (action);
413           run_command_async (cmd->str);
414           g_string_free (cmd, TRUE);
415         }
416     }
417 
418   /* set focus to specified field */
419   if (options.form_data.focus_field > 0 && options.form_data.focus_field <= n_fields)
420     gtk_widget_grab_focus (GTK_WIDGET (g_slist_nth_data (fields, options.form_data.focus_field - 1)));
421 }
422 
423 static void
form_activate_cb(GtkEntry * entry,gpointer data)424 form_activate_cb (GtkEntry * entry, gpointer data)
425 {
426   if (options.plug == -1)
427     yad_exit (options.data.def_resp);
428 }
429 
430 static void
select_files_cb(GtkEntry * entry,GtkEntryIconPosition pos,GdkEventButton * event,gpointer data)431 select_files_cb (GtkEntry * entry, GtkEntryIconPosition pos, GdkEventButton * event, gpointer data)
432 {
433   GtkWidget *dlg;
434   GList *filt;
435   static gchar *path = NULL;
436 
437   if (event->button == 1)
438     {
439       YadFieldType type = GPOINTER_TO_INT (data);
440 
441       if (!path)
442         {
443           const gchar *val = gtk_entry_get_text (entry);
444 
445           if (g_file_test (val, G_FILE_TEST_IS_DIR))
446             path = g_strdup (val);
447           else
448             path = val ? g_path_get_dirname (val) : g_get_current_dir ();
449         }
450 
451       if (type == YAD_FIELD_MFILE)
452         {
453           dlg = gtk_file_chooser_dialog_new (_("Select files"),
454                                              GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (entry))),
455                                              GTK_FILE_CHOOSER_ACTION_OPEN,
456                                              _("Cancel"), GTK_RESPONSE_CANCEL,
457                                              _("OK"), GTK_RESPONSE_ACCEPT, NULL);
458         }
459       else
460         {
461           dlg = gtk_file_chooser_dialog_new (_("Select folders"),
462                                              GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (entry))),
463                                              GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
464                                              _("Cancel"), GTK_RESPONSE_CANCEL,
465                                              _("OK"), GTK_RESPONSE_ACCEPT, NULL);
466         }
467       gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
468       gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlg), path);
469 
470       g_signal_connect (dlg, "map", G_CALLBACK (gtk_file_chooser_set_show_hidden), GINT_TO_POINTER (options.common_data.show_hidden));
471 
472       /* add preview */
473       if (options.common_data.preview)
474         {
475           GtkWidget *p = gtk_image_new ();
476           gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dlg), p);
477           g_signal_connect (dlg, "update-preview", G_CALLBACK (update_preview), p);
478         }
479 
480       /* add filters */
481       for (filt = options.common_data.filters; filt; filt = filt->next)
482         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), GTK_FILE_FILTER (filt->data));
483 
484       if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT)
485         {
486           GSList *files, *ptr;
487           GString *str;
488 
489           str = g_string_new ("");
490           files = ptr = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dlg));
491 
492           while (ptr)
493             {
494               if (ptr->data)
495                 {
496                   gchar *fn = g_filename_from_uri ((gchar *) ptr->data, NULL, NULL);
497                   g_string_append (str, fn);
498                   g_string_append (str, options.common_data.item_separator);
499                   g_free (fn);
500                 }
501               ptr = ptr->next;
502             }
503 
504           str->str[str->len - 1] = '\0';        // remove last item separator
505           gtk_entry_set_text (entry, str->str);
506 
507           g_slist_free (files);
508           g_string_free (str, TRUE);
509         }
510 
511       g_free (path);
512       path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dlg));
513       gtk_widget_destroy (dlg);
514     }
515 }
516 
517 static void
create_files_cb(GtkEntry * entry,GtkEntryIconPosition pos,GdkEventButton * event,gpointer data)518 create_files_cb (GtkEntry * entry, GtkEntryIconPosition pos, GdkEventButton * event, gpointer data)
519 {
520   GtkWidget *dlg;
521   GList *filt;
522   static gchar *path = NULL;
523 
524   if (event->button == 1)
525     {
526       YadFieldType type = GPOINTER_TO_INT (data);
527 
528       if (!path)
529         {
530           const gchar *val = gtk_entry_get_text (entry);
531 
532           if (g_file_test (val, G_FILE_TEST_IS_DIR))
533             path = g_strdup (val);
534           else
535             path = val ? g_path_get_dirname (val) : g_get_current_dir ();
536         }
537 
538       if (type == YAD_FIELD_FILE_SAVE)
539         {
540           dlg = gtk_file_chooser_dialog_new (_("Select or create file"),
541                                              GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (entry))),
542                                              GTK_FILE_CHOOSER_ACTION_SAVE,
543                                              _("Cancel"), GTK_RESPONSE_CANCEL,
544                                              _("OK"), GTK_RESPONSE_ACCEPT, NULL);
545         }
546       else
547         {
548           dlg = gtk_file_chooser_dialog_new (_("Select or create folder"),
549                                              GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (entry))),
550                                              GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER,
551                                              _("Cancel"), GTK_RESPONSE_CANCEL,
552                                              _("OK"), GTK_RESPONSE_ACCEPT, NULL);
553         }
554       gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlg), path);
555 
556       g_signal_connect (dlg, "map", G_CALLBACK (gtk_file_chooser_set_show_hidden), GINT_TO_POINTER (options.common_data.show_hidden));
557 
558       /* add preview */
559       if (options.common_data.preview)
560         {
561           GtkWidget *p = gtk_image_new ();
562           gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dlg), p);
563           g_signal_connect (dlg, "update-preview", G_CALLBACK (update_preview), p);
564         }
565 
566       /* add filters */
567       for (filt = options.common_data.filters; filt; filt = filt->next)
568         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), GTK_FILE_FILTER (filt->data));
569 
570       if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT)
571         {
572           gchar *file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
573 
574           gtk_entry_set_text (entry, file);
575           g_free (file);
576         }
577 
578       g_free (path);
579       path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dlg));
580       gtk_widget_destroy (dlg);
581     }
582 }
583 
584 static void
date_selected_cb(GtkCalendar * c,gpointer data)585 date_selected_cb (GtkCalendar * c, gpointer data)
586 {
587   gtk_dialog_response (GTK_DIALOG (data), GTK_RESPONSE_ACCEPT);
588 }
589 
590 static void
select_date_cb(GtkEntry * entry,GtkEntryIconPosition pos,GdkEventButton * event,gpointer data)591 select_date_cb (GtkEntry * entry, GtkEntryIconPosition pos, GdkEventButton * event, gpointer data)
592 {
593   GtkWidget *dlg, *cal;
594 
595   if (event->button == 1)
596     {
597       GDate *d;
598 
599       dlg = gtk_dialog_new_with_buttons (_("Select date"),
600                                          GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (entry))),
601                                          GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
602                                          _("Cancel"), GTK_RESPONSE_CANCEL,
603                                          _("OK"), GTK_RESPONSE_ACCEPT, NULL);
604       cal = gtk_calendar_new ();
605       gtk_widget_show (cal);
606       g_signal_connect (G_OBJECT (cal), "day-selected-double-click", G_CALLBACK (date_selected_cb), dlg);
607       gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), cal, TRUE, TRUE, 5);
608 
609       d = g_date_new ();
610       g_date_set_parse (d, gtk_entry_get_text (entry));
611       if (g_date_valid (d))
612         {
613           gtk_calendar_select_day (GTK_CALENDAR (cal), g_date_get_day (d));
614           gtk_calendar_select_month (GTK_CALENDAR (cal), g_date_get_month (d) - 1, g_date_get_year (d));
615         }
616       g_date_free (d);
617 
618       if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT)
619         {
620           guint day, month, year;
621           gchar *format = options.common_data.date_format;
622           gchar time_string[128];
623 
624           gtk_calendar_get_date (GTK_CALENDAR (cal), &day, &month, &year);
625           d = g_date_new_dmy (year, month + 1, day);
626           g_date_strftime (time_string, 127, format, d);
627           gtk_entry_set_text (entry, time_string);
628           g_date_free (d);
629         }
630       gtk_widget_destroy (dlg);
631     }
632 
633   gtk_widget_grab_focus (GTK_WIDGET (entry));
634 }
635 
636 static gboolean
link_clicked_cb(GtkLinkButton * btn,gpointer data)637 link_clicked_cb (GtkLinkButton *btn, gpointer data)
638 {
639   const gchar *uri = gtk_link_button_get_uri (btn);
640   open_uri (uri);
641   return TRUE;
642 }
643 
644 static gboolean
handle_stdin(GIOChannel * ch,GIOCondition cond,gpointer data)645 handle_stdin (GIOChannel * ch, GIOCondition cond, gpointer data)
646 {
647   static guint cnt = 0;
648 
649   if ((cond == G_IO_IN) || (cond == G_IO_IN + G_IO_HUP))
650     {
651       GError *err = NULL;
652       GString *string = g_string_new (NULL);
653 
654       while (ch->is_readable != TRUE);
655 
656       do
657         {
658           gint status;
659 
660           if (cnt == n_fields)
661             {
662               if (options.form_data.cycle_read)
663                 cnt = 0;
664               else
665                 {
666                   g_io_channel_shutdown (ch, TRUE, NULL);
667                   return FALSE;
668                 }
669             }
670 
671           do
672             {
673               status = g_io_channel_read_line_string (ch, string, NULL, &err);
674 
675               while (gtk_events_pending ())
676                 gtk_main_iteration ();
677             }
678           while (status == G_IO_STATUS_AGAIN);
679 
680           if (status != G_IO_STATUS_NORMAL)
681             {
682               if (err)
683                 {
684                   g_printerr ("yad_form_handle_stdin(): %s\n", err->message);
685                   g_error_free (err);
686                   err = NULL;
687                 }
688               /* stop handling */
689               g_io_channel_shutdown (ch, TRUE, NULL);
690               return FALSE;
691             }
692 
693           strip_new_line (string->str);
694           if (string->str[0])
695             {
696               if (string->str[0] == '\014')
697                 {
698                   gint i;
699                   /* clear the form and reset fields counter */
700                   for (i = 0; i < n_fields; i++)
701                     set_field_value (i, "");
702                   cnt = -1; /* must be -1 due to next increment */
703                 }
704               else
705                 set_field_value (cnt, string->str);
706             }
707           cnt++;
708         }
709       while (g_io_channel_get_buffer_condition (ch) == G_IO_IN);
710       g_string_free (string, TRUE);
711     }
712 
713   if ((cond != G_IO_IN) && (cond != G_IO_IN + G_IO_HUP))
714     {
715       g_io_channel_shutdown (ch, TRUE, NULL);
716       return FALSE;
717     }
718 
719   return TRUE;
720 }
721 
722 GtkWidget *
form_create_widget(GtkWidget * dlg)723 form_create_widget (GtkWidget * dlg)
724 {
725   GtkWidget *tbl, *w = NULL;
726   GList *filt;
727 
728   if (options.form_data.fields)
729     {
730       GtkWidget *l, *e;
731       GdkPixbuf *pb;
732       guint i, col, row, rows;
733 
734       n_fields = g_slist_length (options.form_data.fields);
735 
736       row = col = 0;
737       rows = n_fields / options.form_data.columns;
738       if (n_fields % options.form_data.columns > 0)
739         rows++;
740 
741       tbl = gtk_grid_new ();
742       gtk_grid_set_row_spacing (GTK_GRID (tbl), 5);
743       gtk_grid_set_column_spacing (GTK_GRID (tbl), 5);
744 
745       if (options.form_data.scroll)
746         {
747           GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
748           gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE);
749           gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.hscroll_policy, options.vscroll_policy);
750           gtk_container_add (GTK_CONTAINER (sw), tbl);
751           w = sw;
752         }
753       else
754         w = tbl;
755 
756       /* create form */
757       for (i = 0; i < n_fields; i++)
758         {
759           YadField *fld = g_slist_nth_data (options.form_data.fields, i);
760 
761           /* add field label */
762           l = NULL;
763           if (fld->type != YAD_FIELD_CHECK && fld->type != YAD_FIELD_BUTTON &&
764               fld->type != YAD_FIELD_FULL_BUTTON && fld->type != YAD_FIELD_LINK &&
765               fld->type != YAD_FIELD_LABEL && fld->type != YAD_FIELD_TEXT)
766             {
767               gchar *buf;
768 
769               if (fld->name)
770                 buf = g_strcompress (fld->name);
771               else
772                 buf = g_strdup ("");
773 
774               l = gtk_label_new (NULL);
775               if (!options.data.no_markup)
776                 {
777                   gtk_label_set_markup_with_mnemonic (GTK_LABEL (l), buf);
778                   if (fld->tip)
779                     gtk_widget_set_tooltip_markup (l, fld->tip);
780                 }
781               else
782                 {
783                   gtk_label_set_text_with_mnemonic (GTK_LABEL (l), buf);
784                   if (fld->tip)
785                     gtk_widget_set_tooltip_text (l, fld->tip);
786                 }
787               gtk_widget_set_name (l, "yad-form-flabel");
788               gtk_label_set_xalign (GTK_LABEL (l), options.common_data.align);
789               gtk_grid_attach (GTK_GRID (tbl), l, col * 2, row, 1, 1);
790               g_free (buf);
791             }
792 
793           /* add field entry */
794           switch (fld->type)
795             {
796             case YAD_FIELD_SIMPLE:
797             case YAD_FIELD_HIDDEN:
798             case YAD_FIELD_READ_ONLY:
799             case YAD_FIELD_COMPLETE:
800               e = gtk_entry_new ();
801               gtk_widget_set_name (e, "yad-form-entry");
802               if (fld->tip)
803                 {
804                   if (!options.data.no_markup)
805                     gtk_widget_set_tooltip_markup (e, fld->tip);
806                   else
807                     gtk_widget_set_tooltip_text (e, fld->tip);
808                 }
809               g_signal_connect (G_OBJECT (e), "activate", G_CALLBACK (form_activate_cb), dlg);
810               if (fld->type == YAD_FIELD_HIDDEN)
811                 gtk_entry_set_visibility (GTK_ENTRY (e), FALSE);
812               else if (fld->type == YAD_FIELD_READ_ONLY)
813                 gtk_widget_set_sensitive (e, FALSE);
814               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
815               gtk_widget_set_hexpand (e, TRUE);
816 
817               if (fld->type == YAD_FIELD_COMPLETE)
818                 {
819                   GtkEntryCompletion *c = gtk_entry_completion_new ();
820                   GtkListStore *m = gtk_list_store_new (1, G_TYPE_STRING);
821 
822                   gtk_entry_set_completion (GTK_ENTRY (e), c);
823                   gtk_entry_completion_set_model (c, GTK_TREE_MODEL (m));
824                   gtk_entry_completion_set_text_column (c, 0);
825 
826                   if (options.common_data.complete != YAD_COMPLETE_SIMPLE)
827                     gtk_entry_completion_set_match_func (c, check_complete, NULL, NULL);
828 
829                   g_object_unref (m);
830                   g_object_unref (c);
831                 }
832 
833               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
834               fields = g_slist_append (fields, e);
835               break;
836 
837             case YAD_FIELD_NUM:
838               e = gtk_spin_button_new_with_range (0.0, 65525.0, 1.0);
839               gtk_widget_set_name (e, "yad-form-spin");
840               if (fld->tip)
841                 {
842                   if (!options.data.no_markup)
843                     gtk_widget_set_tooltip_markup (e, fld->tip);
844                   else
845                     gtk_widget_set_tooltip_text (e, fld->tip);
846                 }
847               gtk_entry_set_alignment (GTK_ENTRY (e), 1.0);
848               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
849               gtk_widget_set_hexpand (e, TRUE);
850               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
851               fields = g_slist_append (fields, e);
852               break;
853 
854             case YAD_FIELD_CHECK:
855               {
856                 gchar *buf;
857                 if (fld->name)
858                   buf = g_strcompress (fld->name);
859                 else
860                   buf = g_strdup ("");
861                 e = gtk_check_button_new_with_label (buf);
862                 gtk_widget_set_name (e, "yad-form-check");
863                 if (fld->tip)
864                   {
865                     if (!options.data.no_markup)
866                       gtk_widget_set_tooltip_markup (e, fld->tip);
867                     else
868                       gtk_widget_set_tooltip_text (e, fld->tip);
869                   }
870                 gtk_grid_attach (GTK_GRID (tbl), e, col * 2, row, 2, 1);
871                 gtk_widget_set_hexpand (e, TRUE);
872                 fields = g_slist_append (fields, e);
873                 g_free (buf);
874               }
875               break;
876 
877             case YAD_FIELD_COMBO:
878               e = gtk_combo_box_text_new ();
879               gtk_widget_set_name (e, "yad-form-combo");
880               if (fld->tip)
881                 {
882                   if (!options.data.no_markup)
883                     gtk_widget_set_tooltip_markup (e, fld->tip);
884                   else
885                     gtk_widget_set_tooltip_text (e, fld->tip);
886                 }
887               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
888               gtk_widget_set_hexpand (e, TRUE);
889               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
890               fields = g_slist_append (fields, e);
891               break;
892 
893             case YAD_FIELD_COMBO_ENTRY:
894               e = gtk_combo_box_text_new_with_entry ();
895               gtk_widget_set_name (e, "yad-form-edit-combo");
896               if (fld->tip)
897                 {
898                   if (!options.data.no_markup)
899                     gtk_widget_set_tooltip_markup (e, fld->tip);
900                   else
901                     gtk_widget_set_tooltip_text (e, fld->tip);
902                 }
903               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
904               gtk_widget_set_hexpand (e, TRUE);
905               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
906               fields = g_slist_append (fields, e);
907               break;
908 
909             case YAD_FIELD_FILE:
910               e = gtk_file_chooser_button_new (_("Select file"), GTK_FILE_CHOOSER_ACTION_OPEN);
911               gtk_widget_set_name (e, "yad-form-file");
912               if (fld->tip)
913                 {
914                   if (!options.data.no_markup)
915                     gtk_widget_set_tooltip_markup (e, fld->tip);
916                   else
917                     gtk_widget_set_tooltip_text (e, fld->tip);
918                 }
919               gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (e), g_get_current_dir ());
920               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
921               gtk_widget_set_hexpand (e, TRUE);
922               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
923               fields = g_slist_append (fields, e);
924 
925               /* add preview */
926               if (options.common_data.preview)
927                 {
928                   GtkWidget *p = gtk_image_new ();
929                   gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (e), p);
930                   g_signal_connect (e, "update-preview", G_CALLBACK (update_preview), p);
931                 }
932 
933               /* add filters */
934               for (filt = options.common_data.filters; filt; filt = filt->next)
935                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (e), GTK_FILE_FILTER (filt->data));
936 
937               break;
938 
939             case YAD_FIELD_DIR:
940               e = gtk_file_chooser_button_new (_("Select folder"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
941               gtk_widget_set_name (e, "yad-form-file");
942               if (fld->tip)
943                 {
944                   if (!options.data.no_markup)
945                     gtk_widget_set_tooltip_markup (e, fld->tip);
946                   else
947                     gtk_widget_set_tooltip_text (e, fld->tip);
948                 }
949               gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (e), g_get_current_dir ());
950               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
951               gtk_widget_set_hexpand (e, TRUE);
952               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
953               fields = g_slist_append (fields, e);
954               break;
955 
956             case YAD_FIELD_FONT:
957               e = gtk_font_button_new ();
958               gtk_widget_set_name (e, "yad-form-font");
959               if (fld->tip)
960                 {
961                   if (!options.data.no_markup)
962                     gtk_widget_set_tooltip_markup (e, fld->tip);
963                   else
964                     gtk_widget_set_tooltip_text (e, fld->tip);
965                 }
966               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
967               gtk_widget_set_hexpand (e, TRUE);
968               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
969               fields = g_slist_append (fields, e);
970               break;
971 
972             case YAD_FIELD_APP:
973               e = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
974               if (fld->tip)
975                 {
976                   if (!options.data.no_markup)
977                     gtk_widget_set_tooltip_markup (e, fld->tip);
978                   else
979                     gtk_widget_set_tooltip_text (e, fld->tip);
980                 }
981               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
982               gtk_widget_set_hexpand (e, TRUE);
983               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
984               fields = g_slist_append (fields, e);
985               break;
986 
987             case YAD_FIELD_COLOR:
988               e = gtk_color_button_new ();
989               gtk_widget_set_name (e, "yad-form-color");
990               if (fld->tip)
991                 {
992                   if (!options.data.no_markup)
993                     gtk_widget_set_tooltip_markup (e, fld->tip);
994                   else
995                     gtk_widget_set_tooltip_text (e, fld->tip);
996                 }
997               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
998               gtk_widget_set_hexpand (e, TRUE);
999               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
1000               fields = g_slist_append (fields, e);
1001               break;
1002 
1003             case YAD_FIELD_MFILE:
1004             case YAD_FIELD_MDIR:
1005               e = gtk_entry_new ();
1006               gtk_widget_set_name (e, "yad-form-entry");
1007               if (fld->tip)
1008                 {
1009                   if (!options.data.no_markup)
1010                     gtk_widget_set_tooltip_markup (e, fld->tip);
1011                   else
1012                     gtk_widget_set_tooltip_text (e, fld->tip);
1013                 }
1014               gtk_entry_set_icon_from_icon_name (GTK_ENTRY (e), GTK_ENTRY_ICON_SECONDARY, "document-open");
1015               g_signal_connect (G_OBJECT (e), "icon-press", G_CALLBACK (select_files_cb), GINT_TO_POINTER (fld->type));
1016               g_signal_connect (G_OBJECT (e), "activate", G_CALLBACK (form_activate_cb), dlg);
1017               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
1018               gtk_widget_set_hexpand (e, TRUE);
1019               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
1020               fields = g_slist_append (fields, e);
1021               break;
1022 
1023             case YAD_FIELD_FILE_SAVE:
1024             case YAD_FIELD_DIR_CREATE:
1025               e = gtk_entry_new ();
1026               gtk_widget_set_name (e, "yad-form-entry");
1027               if (fld->tip)
1028                 {
1029                   if (!options.data.no_markup)
1030                     gtk_widget_set_tooltip_markup (e, fld->tip);
1031                   else
1032                     gtk_widget_set_tooltip_text (e, fld->tip);
1033                 }
1034               gtk_entry_set_icon_from_icon_name (GTK_ENTRY (e), GTK_ENTRY_ICON_SECONDARY, "document-open");
1035               g_signal_connect (G_OBJECT (e), "icon-press", G_CALLBACK (create_files_cb), GINT_TO_POINTER (fld->type));
1036               g_signal_connect (G_OBJECT (e), "activate", G_CALLBACK (form_activate_cb), dlg);
1037               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
1038               gtk_widget_set_hexpand (e, TRUE);
1039               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
1040               fields = g_slist_append (fields, e);
1041               break;
1042 
1043             case YAD_FIELD_DATE:
1044               e = gtk_entry_new ();
1045               gtk_widget_set_name (e, "yad-form-entry");
1046               if (fld->tip)
1047                 {
1048                   if (!options.data.no_markup)
1049                     gtk_widget_set_tooltip_markup (e, fld->tip);
1050                   else
1051                     gtk_widget_set_tooltip_text (e, fld->tip);
1052                 }
1053               pb = gdk_pixbuf_new_from_xpm_data (calendar_xpm);
1054               gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (e), GTK_ENTRY_ICON_SECONDARY, pb);
1055               g_object_unref (pb);
1056               g_signal_connect (G_OBJECT (e), "icon-press", G_CALLBACK (select_date_cb), e);
1057               g_signal_connect (G_OBJECT (e), "activate", G_CALLBACK (form_activate_cb), dlg);
1058               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
1059               gtk_widget_set_hexpand (e, TRUE);
1060               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
1061               fields = g_slist_append (fields, e);
1062               break;
1063 
1064             case YAD_FIELD_SCALE:
1065               e = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0.0, 100.0, 1.0);
1066               gtk_widget_set_name (e, "yad-form-scale");
1067               if (fld->tip)
1068                 {
1069                   if (!options.data.no_markup)
1070                     gtk_widget_set_tooltip_markup (e, fld->tip);
1071                   else
1072                     gtk_widget_set_tooltip_text (e, fld->tip);
1073                 }
1074               gtk_scale_set_value_pos (GTK_SCALE (e), GTK_POS_LEFT);
1075               gtk_grid_attach (GTK_GRID (tbl), e, 1 + col * 2, row, 1, 1);
1076               gtk_widget_set_hexpand (e, TRUE);
1077               gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
1078               fields = g_slist_append (fields, e);
1079               break;
1080 
1081             case YAD_FIELD_BUTTON:
1082             case YAD_FIELD_FULL_BUTTON:
1083               e = gtk_button_new ();
1084               gtk_widget_set_name (e, "yad-form-button");
1085               if (fld->tip)
1086                 {
1087                   if (!options.data.no_markup)
1088                     gtk_widget_set_tooltip_markup (e, fld->tip);
1089                   else
1090                     gtk_widget_set_tooltip_text (e, fld->tip);
1091                 }
1092               g_signal_connect (G_OBJECT (e), "clicked", G_CALLBACK (button_clicked_cb), NULL);
1093               gtk_container_add (GTK_CONTAINER (e), get_label (fld->name, 2, e));
1094               if (fld->type == YAD_FIELD_BUTTON)
1095                 gtk_button_set_relief (GTK_BUTTON (e), GTK_RELIEF_NONE);
1096               gtk_grid_attach (GTK_GRID (tbl), e, col * 2, row, 2, 1);
1097               gtk_widget_set_hexpand (e, TRUE);
1098               fields = g_slist_append (fields, e);
1099               break;
1100 
1101             case YAD_FIELD_LINK:
1102               {
1103                 gchar *buf;
1104                 if (fld->name)
1105                   buf = g_strdup (fld->name[0] ? fld->name : _("Link"));
1106                 else
1107                   buf = g_strdup (_("Link"));
1108 
1109                 e = gtk_link_button_new_with_label ("", buf);
1110                 gtk_widget_set_name (e, "yad-form-link");
1111                 if (fld->tip)
1112                   {
1113                     if (!options.data.no_markup)
1114                       gtk_widget_set_tooltip_markup (e, fld->tip);
1115                     else
1116                       gtk_widget_set_tooltip_text (e, fld->tip);
1117                   }
1118                 g_signal_connect (G_OBJECT (e), "activate-link", G_CALLBACK (link_clicked_cb), NULL);
1119                 gtk_grid_attach (GTK_GRID (tbl), e, col * 2, row, 2, 1);
1120                 gtk_widget_set_hexpand (e, TRUE);
1121                 fields = g_slist_append (fields, e);
1122                 g_free (buf);
1123                 break;
1124               }
1125 
1126             case YAD_FIELD_LABEL:
1127               if (fld->name && fld->name[0])
1128                 {
1129                   gchar *buf = g_strcompress (fld->name);
1130                   e = gtk_label_new (NULL);
1131                   gtk_widget_set_name (e, "yad-form-label");
1132                   if (fld->tip)
1133                     {
1134                       if (!options.data.no_markup)
1135                         gtk_widget_set_tooltip_markup (e, fld->tip);
1136                       else
1137                         gtk_widget_set_tooltip_text (e, fld->tip);
1138                     }
1139                   if (options.data.no_markup)
1140                     gtk_label_set_text (GTK_LABEL (e), buf);
1141                   else
1142                     gtk_label_set_markup (GTK_LABEL (e), buf);
1143                   gtk_label_set_line_wrap (GTK_LABEL (e), TRUE);
1144                   gtk_label_set_selectable (GTK_LABEL (e), options.data.selectable_labels);
1145                   gtk_label_set_xalign (GTK_LABEL (e), options.common_data.align);
1146                   g_free (buf);
1147                 }
1148               else
1149                 {
1150                   e = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
1151                   gtk_widget_set_name (e, "yad-form-separator");
1152                 }
1153               gtk_grid_attach (GTK_GRID (tbl), e, col * 2, row, 2, 1);
1154               gtk_widget_set_hexpand (e, TRUE);
1155               fields = g_slist_append (fields, e);
1156               break;
1157 
1158             case YAD_FIELD_TEXT:
1159               {
1160                 GtkWidget *l, *sw, *b;
1161                 gchar *ltxt;
1162 
1163                 if (fld->name)
1164                   ltxt = g_strcompress (fld->name);
1165                 else
1166                   ltxt = g_strdup ("");
1167 
1168                 b = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
1169                 l = gtk_label_new ("");
1170                 gtk_label_set_xalign (GTK_LABEL (l), 0.0);
1171                 if (options.data.no_markup)
1172                   gtk_label_set_text (GTK_LABEL (l), ltxt);
1173                 else
1174                   gtk_label_set_markup (GTK_LABEL (l), ltxt);
1175                 g_free (ltxt);
1176                 gtk_box_pack_start (GTK_BOX (b), l, FALSE, FALSE, 0);
1177 
1178                 sw = gtk_scrolled_window_new (NULL, NULL);
1179                 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
1180                 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.hscroll_policy, options.vscroll_policy);
1181                 gtk_box_pack_start (GTK_BOX (b), sw, TRUE, TRUE, 0);
1182 
1183                 e = gtk_text_view_new ();
1184                 gtk_widget_set_name (e, "yad-form-text");
1185                 if (fld->tip)
1186                   {
1187                     if (!options.data.no_markup)
1188                       gtk_widget_set_tooltip_markup (e, fld->tip);
1189                     else
1190                       gtk_widget_set_tooltip_text (e, fld->tip);
1191                   }
1192                 gtk_text_view_set_editable (GTK_TEXT_VIEW (e), TRUE);
1193                 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (e), GTK_WRAP_WORD_CHAR);
1194                 gtk_container_add (GTK_CONTAINER (sw), e);
1195 
1196 #ifdef HAVE_SPELL
1197                 if (options.common_data.enable_spell)
1198                   {
1199                     GspellTextView *spell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (e));
1200                     gspell_text_view_basic_setup (spell_view);
1201                   }
1202 #endif
1203 
1204                 gtk_grid_attach (GTK_GRID (tbl), b, col * 2, row, 2, 1);
1205                 gtk_widget_set_hexpand (b, TRUE);
1206                 gtk_widget_set_vexpand (b, TRUE);
1207                 gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
1208                 fields = g_slist_append (fields, e);
1209 
1210                 break;
1211               }
1212             }
1213 
1214           /* increase row and column */
1215           row++;
1216           if (row >= rows)
1217             {
1218               row = 0;
1219               col++;
1220             }
1221         }
1222 
1223       /* fill entries with data */
1224       if (options.extra_data)
1225         {
1226           i = 0;
1227           while (options.extra_data[i] && i < n_fields)
1228             {
1229               set_field_value (i, options.extra_data[i]);
1230               i++;
1231             }
1232         }
1233       else
1234         {
1235           GIOChannel *channel = g_io_channel_unix_new (0);
1236           g_io_channel_set_encoding (channel, NULL, NULL);
1237           g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
1238           g_io_add_watch (channel, G_IO_IN | G_IO_HUP, handle_stdin, NULL);
1239         }
1240     }
1241 
1242   if (options.form_data.focus_field > 0 && options.form_data.focus_field <= n_fields)
1243     gtk_widget_grab_focus (GTK_WIDGET (g_slist_nth_data (fields, options.form_data.focus_field - 1)));
1244 
1245   return w;
1246 }
1247 
1248 static void
form_print_field(guint fn)1249 form_print_field (guint fn)
1250 {
1251   gchar *buf;
1252   YadField *fld = g_slist_nth_data (options.form_data.fields, fn);
1253 
1254   switch (fld->type)
1255     {
1256     case YAD_FIELD_SIMPLE:
1257     case YAD_FIELD_HIDDEN:
1258     case YAD_FIELD_READ_ONLY:
1259     case YAD_FIELD_COMPLETE:
1260     case YAD_FIELD_MFILE:
1261     case YAD_FIELD_MDIR:
1262     case YAD_FIELD_FILE_SAVE:
1263     case YAD_FIELD_DIR_CREATE:
1264     case YAD_FIELD_DATE:
1265       if (options.common_data.quoted_output)
1266         {
1267           buf = g_shell_quote (gtk_entry_get_text (GTK_ENTRY (g_slist_nth_data (fields, fn))));
1268           g_printf ("%s%s", buf, options.common_data.separator);
1269           g_free (buf);
1270         }
1271       else
1272         g_printf ("%s%s", gtk_entry_get_text (GTK_ENTRY (g_slist_nth_data (fields, fn))),
1273                   options.common_data.separator);
1274       break;
1275     case YAD_FIELD_NUM:
1276       {
1277         guint prec = gtk_spin_button_get_digits (GTK_SPIN_BUTTON (g_slist_nth_data (fields, fn)));
1278         if (options.common_data.quoted_output)
1279           g_printf ("'%.*f'%s", prec, gtk_spin_button_get_value (GTK_SPIN_BUTTON (g_slist_nth_data (fields, fn))),
1280                     options.common_data.separator);
1281         else
1282           g_printf ("%.*f%s", prec, gtk_spin_button_get_value (GTK_SPIN_BUTTON (g_slist_nth_data (fields, fn))),
1283                     options.common_data.separator);
1284         break;
1285       }
1286     case YAD_FIELD_CHECK:
1287       if (options.common_data.quoted_output)
1288         g_printf ("'%s'%s", print_bool_val (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (g_slist_nth_data (fields, fn)))),
1289                   options.common_data.separator);
1290       else
1291         g_printf ("%s%s", print_bool_val (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (g_slist_nth_data (fields, fn)))),
1292                   options.common_data.separator);
1293       break;
1294     case YAD_FIELD_COMBO:
1295     case YAD_FIELD_COMBO_ENTRY:
1296       if (options.common_data.num_output && fld->type == YAD_FIELD_COMBO)
1297         g_printf ("%d%s", gtk_combo_box_get_active (GTK_COMBO_BOX (g_slist_nth_data (fields, fn))) + 1,
1298                   options.common_data.separator);
1299       else if (options.common_data.quoted_output)
1300         {
1301           buf = g_shell_quote (gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (g_slist_nth_data (fields, fn))));
1302           g_printf ("%s%s", buf, options.common_data.separator);
1303           g_free (buf);
1304         }
1305       else
1306         g_printf ("%s%s", gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (g_slist_nth_data (fields, fn))),
1307                   options.common_data.separator);
1308       break;
1309     case YAD_FIELD_FILE:
1310     case YAD_FIELD_DIR:
1311       if (options.common_data.quoted_output)
1312         {
1313           gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (g_slist_nth_data (fields, fn)));
1314           buf = g_shell_quote (fname ? fname : "");
1315           g_free (fname);
1316           g_printf ("%s%s", buf ? buf : "", options.common_data.separator);
1317           g_free (buf);
1318         }
1319       else
1320         {
1321           buf = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (g_slist_nth_data (fields, fn)));
1322           g_printf ("%s%s", buf ? buf : "", options.common_data.separator);
1323           g_free (buf);
1324         }
1325       break;
1326     case YAD_FIELD_FONT:
1327       {
1328         gchar *fname = gtk_font_chooser_get_font (GTK_FONT_CHOOSER (g_slist_nth_data (fields, fn)));
1329         if (options.common_data.quoted_output)
1330           g_printf ("'%s'%s", fname ? fname : "", options.common_data.separator);
1331         else
1332           g_printf ("%s%s", fname ? fname : "", options.common_data.separator);
1333         g_free (fname);
1334         break;
1335       }
1336     case YAD_FIELD_APP:
1337       {
1338         gchar *exec;
1339         GAppInfo *info = NULL;
1340         GList *wl = gtk_container_get_children (GTK_CONTAINER (g_slist_nth_data (fields, fn)));
1341 
1342         if (wl)
1343           {
1344             info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (wl->data));
1345             if (info)
1346               exec = (gchar *) g_app_info_get_executable (info);
1347             else
1348               exec = "";
1349           }
1350         else
1351           exec = "";
1352 
1353         if (options.common_data.quoted_output)
1354           {
1355             buf = g_shell_quote (exec);
1356             g_printf ("%s%s", buf, options.common_data.separator);
1357             g_free (buf);
1358           }
1359         else
1360           g_printf ("%s%s", exec, options.common_data.separator);
1361         if (info)
1362           g_object_unref (info);
1363         break;
1364       }
1365     case YAD_FIELD_COLOR:
1366       {
1367         gchar *cs;
1368         GdkRGBA c;
1369         GtkColorChooser *cb = GTK_COLOR_CHOOSER (g_slist_nth_data (fields, fn));
1370         gtk_color_chooser_get_rgba (cb, &c);
1371         cs = get_color (&c);
1372 
1373         if (options.common_data.quoted_output)
1374           {
1375             buf = g_shell_quote (cs ? cs : "");
1376             g_printf ("%s%s", buf, options.common_data.separator);
1377             g_free (buf);
1378           }
1379         else
1380           g_printf ("%s%s", cs, options.common_data.separator);
1381         g_free (cs);
1382         break;
1383       }
1384     case YAD_FIELD_SCALE:
1385       if (options.common_data.quoted_output)
1386         g_printf ("'%d'%s", (gint) gtk_range_get_value (GTK_RANGE (g_slist_nth_data (fields, fn))),
1387                   options.common_data.separator);
1388       else
1389         g_printf ("%d%s", (gint) gtk_range_get_value (GTK_RANGE (g_slist_nth_data (fields, fn))),
1390                   options.common_data.separator);
1391       break;
1392     case YAD_FIELD_LINK:
1393       if (options.common_data.quoted_output)
1394         {
1395           buf = g_shell_quote (gtk_link_button_get_uri (GTK_LINK_BUTTON (g_slist_nth_data (fields, fn))));
1396           g_printf ("%s%s", buf, options.common_data.separator);
1397           g_free (buf);
1398         }
1399       else
1400         g_printf ("%s%s", gtk_link_button_get_uri (GTK_LINK_BUTTON (g_slist_nth_data (fields, fn))),
1401                   options.common_data.separator);
1402       break;
1403     case YAD_FIELD_BUTTON:
1404     case YAD_FIELD_FULL_BUTTON:
1405     case YAD_FIELD_LABEL:
1406       if (options.common_data.quoted_output)
1407         g_printf ("''%s", options.common_data.separator);
1408       else
1409         g_printf ("%s", options.common_data.separator);
1410       break;
1411     case YAD_FIELD_TEXT:
1412       {
1413         gchar *txt;
1414         GtkTextBuffer *tb;
1415         GtkTextIter b, e;
1416 
1417         tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (g_slist_nth_data (fields, fn)));
1418         gtk_text_buffer_get_bounds (tb, &b, &e);
1419         txt = escape_str (gtk_text_buffer_get_text (tb, &b, &e, FALSE));
1420         if (options.common_data.quoted_output)
1421           {
1422             buf = g_shell_quote (txt);
1423             g_printf ("%s%s", buf, options.common_data.separator);
1424             g_free (buf);
1425           }
1426         else
1427           g_printf ("%s%s", txt, options.common_data.separator);
1428         g_free (txt);
1429       }
1430     }
1431 }
1432 
1433 void
form_print_result(void)1434 form_print_result (void)
1435 {
1436   guint i;
1437 
1438   if (options.form_data.output_by_row)
1439     {
1440       guint j, rows;
1441 
1442       rows = n_fields / options.form_data.columns;
1443       rows += (n_fields % options.form_data.columns ? 1 : 0);
1444       for (i = 0; i < rows; i++)
1445         {
1446           for (j = 0; j < options.form_data.columns; j++)
1447             {
1448               guint fld = i + rows * j;
1449               if (fld < n_fields)
1450                 form_print_field (fld);
1451             }
1452         }
1453     }
1454   else
1455     {
1456       for (i = 0; i < n_fields; i++)
1457         form_print_field (i);
1458     }
1459   g_printf ("\n");
1460 }
1461