1 /*
2  * Copyright (C) 2020 The HIME team, Taiwan
3  * Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
4  * Copyright (C) 2012 tytsim <https://github.com/tytsim>
5  * Copyright (C) 2012 Favonia <favonia@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation version 2.1
10  * of the License.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include <signal.h>
23 
24 #include "hime.h"
25 
26 #include "gtab.h"
27 #include "lang.h"
28 
29 GtkWidget *main_window;
30 extern gboolean button_order;
31 char utf8_edit[] = HIME_SCRIPT_DIR "/utf8-edit";
32 
cb_alt_shift()33 static void cb_alt_shift () {
34     char tt[512];
35     snprintf (tt, sizeof (tt), "( cd ~/.config/hime && %s phrase.table ) &", utf8_edit);
36     system (tt);
37 }
38 
cb_symbol_table()39 static void cb_symbol_table () {
40     char tt[512];
41     snprintf (tt, sizeof (tt), "( cd ~/.config/hime && %s symbol-table ) &", utf8_edit);
42     system (tt);
43 }
44 
cb_gb_output_toggle()45 static void cb_gb_output_toggle () {
46     send_hime_message (GDK_DISPLAY (), GB_OUTPUT_TOGGLE);
47     exit (0);
48 }
49 
cb_win_kbm_toggle()50 static void cb_win_kbm_toggle () {
51     send_hime_message (GDK_DISPLAY (), KBM_TOGGLE);
52     exit (0);
53 }
54 
cb_gb_translate_toggle()55 static void cb_gb_translate_toggle () {
56     system (HIME_BIN_DIR "/hime-sim2trad &");
57     exit (0);
58 }
59 
cb_juying_learn()60 static void cb_juying_learn () {
61     system (HIME_BIN_DIR "/hime-juyin-learn &");
62     exit (0);
63 }
64 
create_result_win(const int res,const char * cmd)65 static void create_result_win (const int res, const char *cmd) {
66     GtkWidget *dialog = NULL;
67     if (res) {
68         dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
69                                          "%s code:%d '%s'\n%s", _ ("Failed"), res, strerror (res), cmd);
70     } else {
71         dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
72                                          _ ("Success"));
73     }
74     if (dialog == NULL)
75         exit (-1);
76 
77     gtk_dialog_run (GTK_DIALOG (dialog));
78     gtk_widget_destroy (dialog);
79 }
80 
cb_ts_export()81 static void cb_ts_export () {
82     GtkWidget *file_selector =
83         gtk_file_chooser_dialog_new (
84             _ ("Please input filename for exporting data"),
85             GTK_WINDOW (main_window),
86             GTK_FILE_CHOOSER_ACTION_SAVE,
87             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
88             GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
89             NULL);
90 
91     gtk_dialog_set_alternative_button_order (
92         GTK_DIALOG (file_selector),
93         GTK_RESPONSE_ACCEPT,
94         GTK_RESPONSE_CANCEL,
95         -1);
96 
97     char hime_dir[512];
98     get_hime_dir (hime_dir);
99     char cmd[512];
100     char fname[256];
101     char *filename = inmd[default_input_method].filename;
102     char tt[256];
103     if (inmd[default_input_method].method_type == method_type_TSIN) {
104         get_hime_user_fname (tsin32_f, fname);
105         gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (file_selector), tsin32_f);
106     } else if (filename) {
107         strcat (strcpy (tt, filename), ".append.gtab.tsin-db");
108         if (!get_hime_user_fname (tt, fname)) {
109             strcat (strcpy (tt, filename), ".tsin-db");
110             if (!get_hime_user_fname (tt, fname))
111                 p_err ("cannot find %s", fname);
112         }
113         gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (file_selector), tt);
114     }
115 
116     gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (file_selector), TRUE);
117     if (gtk_dialog_run (GTK_DIALOG (file_selector)) == GTK_RESPONSE_ACCEPT) {
118         gchar *selected_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_selector));
119         snprintf (cmd, sizeof (cmd), HIME_BIN_DIR "/hime-tsd2a32 %s -o %s", fname, selected_filename);
120         dbg ("exec %s\n", cmd);
121         int res = system (cmd);
122         res = 0;  // some problem in system(), the exit code is not reliable
123         create_result_win (res, cmd);
124     }
125     gtk_widget_destroy (file_selector);
126 }
127 
ts_import(const gchar * selected_filename)128 static void ts_import (const gchar *selected_filename) {
129     char cmd[256];
130     char *home = getenv ("HOME");
131     if (!home)
132         home = "";
133     if (inmd[default_input_method].method_type == method_type_TSIN) {
134         snprintf (cmd, sizeof (cmd),
135                   "cd %s/.config/hime && " HIME_BIN_DIR "/hime-tsd2a32 %s > tmpfile && cat %s >> tmpfile && " HIME_BIN_DIR "/hime-tsa2d32 tmpfile %s",
136                   home, tsin32_f, selected_filename, tsin32_f);
137         int res = system (cmd);
138         res = 0;
139         create_result_win (res, cmd);
140     } else {
141         char tt[512];
142         snprintf (tt, sizeof (tt), HIME_SCRIPT_DIR "/tsin-gtab-import %s '%s'", inmd[default_input_method].filename,
143                   selected_filename);
144         system (tt);
145     }
146 }
147 
cb_ts_import()148 static void cb_ts_import () {
149     /* Create the selector */
150 
151     GtkWidget *file_selector =
152         gtk_file_chooser_dialog_new (
153             _ ("Please input filename for importing data"),
154             GTK_WINDOW (main_window),
155             GTK_FILE_CHOOSER_ACTION_OPEN,
156             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
157             GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
158             NULL);
159 
160     gtk_dialog_set_alternative_button_order (
161         GTK_DIALOG (file_selector),
162         GTK_RESPONSE_ACCEPT,
163         GTK_RESPONSE_CANCEL,
164         -1);
165 
166     if (gtk_dialog_run (GTK_DIALOG (file_selector)) == GTK_RESPONSE_ACCEPT) {
167         gchar *selected_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_selector));
168 
169         ts_import (selected_filename);
170     }
171     gtk_widget_destroy (file_selector);
172 }
173 
cb_ts_edit()174 static void cb_ts_edit () {
175     system (HIME_BIN_DIR "/hime-ts-edit");
176 }
177 
cb_tslearn()178 static void cb_tslearn () {
179     system ("hime-tslearn &");
180     exit (0);
181 }
182 
cb_ts_import_sys()183 static void cb_ts_import_sys () {
184     char tt[512];
185     snprintf (tt, sizeof (tt), "cd ~/.config/hime && " HIME_BIN_DIR "/hime-tsd2a32 %s > tmpfile && " HIME_BIN_DIR "/hime-tsd2a32 %s/%s >> tmpfile && " HIME_BIN_DIR "/hime-tsa2d32 tmpfile",
186               tsin32_f, HIME_TABLE_DIR, tsin32_f);
187     dbg ("exec %s\n", tt);
188     system (tt);
189 }
190 
191 /* XXX */
192 #include "gst.h"
193 #include "hime-module-cb.h"
194 #include "hime-module.h"
195 #include "im-client/hime-im-client-attr.h"
196 #include "pho.h"
197 #include "tsin.h"
198 HIME_module_callback_functions *init_HIME_module_callback_functions (char *sofile);
199 
200 /* The type of the entries in the table.
201  * XXX XXX XXX XXX XXX XXX XXX XXX XXX */
202 typedef struct {
203     const char *name;
204     GtkWidget *(*create) ();
205     void (*save) ();
206     void (*destroy) ();
207 } TAB_ENTRY;
208 
209 /* XXX hime-setup-gtab.c */
210 GtkWidget *create_gtab_widget ();
211 void save_gtab_conf ();
212 void destroy_gtab_widget ();
213 
214 /* XXX hime-setup-appearance.c */
215 GtkWidget *create_appearance_widget ();
216 void save_appearance_conf ();
217 void destroy_appearance_widget ();
218 
219 /* XXX hime-setup-pho.c */
220 GtkWidget *create_kbm_widget ();
221 void save_kbm_conf ();
222 void destroy_kbm_widget ();
223 
224 /* XXX hime-setup-list.c */
225 GtkWidget *create_gtablist_widget ();
226 void save_gtablist_conf ();
227 void destroy_gtablist_widget ();
228 
229 GtkWidget *misc_widget = NULL;
230 
pack_start_new_button_with_callback(GtkBox * box,const gchar * label,GCallback cb,gpointer * user_data)231 static void pack_start_new_button_with_callback (
232     GtkBox *box,
233     const gchar *label,
234     GCallback cb,
235     gpointer *user_data) {
236     GtkWidget *button = gtk_button_new_with_label (label);
237     if (button == NULL)
238         exit (-1);
239     gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 5);
240     g_signal_connect (G_OBJECT (button), "clicked", cb, user_data);
241 }
242 
create_misc_widget(void)243 static GtkWidget *create_misc_widget (void) {
244     GtkWidget *top_widget = gtk_vbox_new (FALSE, 5);
245     gtk_orientable_set_orientation (GTK_ORIENTABLE (top_widget), GTK_ORIENTATION_VERTICAL);
246 
247     pack_start_new_button_with_callback (GTK_BOX (top_widget),
248                                          _ ("Edit Alt-Shift phrases"), G_CALLBACK (cb_alt_shift), NULL);
249 
250     pack_start_new_button_with_callback (GTK_BOX (top_widget),
251                                          _ ("Edit symbols"), G_CALLBACK (cb_symbol_table), NULL);
252 
253     if (!hime_status_tray) {
254         pack_start_new_button_with_callback (GTK_BOX (top_widget),
255                                              _ ("Toggle Simplified Chinese output"), G_CALLBACK (cb_gb_output_toggle), NULL);
256 
257         pack_start_new_button_with_callback (GTK_BOX (top_widget),
258                                              _ ("Toggle virtual keyboard"), G_CALLBACK (cb_win_kbm_toggle), NULL);
259     }
260 
261     pack_start_new_button_with_callback (GTK_BOX (top_widget),
262                                          _ ("Convert clipboard's Simplified Chinese to Traditional Chinese"), G_CALLBACK (cb_gb_translate_toggle), NULL);
263 
264     pack_start_new_button_with_callback (GTK_BOX (top_widget),
265                                          _ ("Lookup phonations of words in clipboard"), G_CALLBACK (cb_juying_learn), NULL);
266 
267     GtkWidget *frame_ts = gtk_frame_new (_ ("Options for Tsin's database"));
268     gtk_box_pack_start (GTK_BOX (top_widget), frame_ts, FALSE, FALSE, 5);
269     GtkWidget *vbox_ts = gtk_vbox_new (FALSE, 5);
270     gtk_orientable_set_orientation (GTK_ORIENTABLE (vbox_ts), GTK_ORIENTATION_VERTICAL);
271     gtk_container_add (GTK_CONTAINER (frame_ts), vbox_ts);
272 
273     pack_start_new_button_with_callback (GTK_BOX (vbox_ts),
274                                          _ ("Export phrase database"), G_CALLBACK (cb_ts_export), NULL);
275 
276     pack_start_new_button_with_callback (GTK_BOX (vbox_ts),
277                                          _ ("Import phrase database"), G_CALLBACK (cb_ts_import), NULL);
278 
279     pack_start_new_button_with_callback (GTK_BOX (vbox_ts),
280                                          _ ("Edit phrase database"), G_CALLBACK (cb_ts_edit), NULL);
281 
282     pack_start_new_button_with_callback (GTK_BOX (vbox_ts),
283                                          _ ("Learn phrases in articles"), G_CALLBACK (cb_tslearn), NULL);
284 
285     pack_start_new_button_with_callback (GTK_BOX (vbox_ts),
286                                          _ ("Import global database"), G_CALLBACK (cb_ts_import_sys), NULL);
287 
288     int i;
289     for (i = 0; i < inmdN; i++) {
290         INMD *pinmd = &inmd[i];
291         if (pinmd->method_type != method_type_MODULE || pinmd->disabled)
292             continue;
293 
294         HIME_module_callback_functions *f = init_HIME_module_callback_functions (pinmd->filename);
295         if (!f)
296             continue;
297 
298         if (!f->module_setup_window_create) {
299             free (f);
300             continue;
301         }
302 
303         char tt[128];
304         strcpy (tt, pinmd->cname);
305         strcat (tt, _ ("Configuration"));
306         pack_start_new_button_with_callback (GTK_BOX (top_widget),
307                                              tt, G_CALLBACK (f->module_setup_window_create), GINT_TO_POINTER (hime_setup_window_type_utility));
308     }
309 
310     return top_widget;
311 }
312 
dummy()313 static void dummy () {}
314 
315 /* The table defining all tabs */
316 #define TAB_TABLE_SIZE 5
317 static TAB_ENTRY tab_table[TAB_TABLE_SIZE] =
318     {{N_ ("開啟/關閉/預設輸入法"), create_gtablist_widget, save_gtablist_conf, destroy_gtablist_widget}, {N_ ("Appearance Settings"), create_appearance_widget, save_appearance_conf, destroy_appearance_widget}, {N_ ("Settings for Bopomofo, Tsin, and Pinyin"), create_kbm_widget, save_kbm_conf, destroy_kbm_widget}, {N_ ("Settings for gtab input methods"), create_gtab_widget, save_gtab_conf, destroy_gtab_widget}, {N_ ("雜項"), create_misc_widget, dummy, dummy}};
319 
save_all_tabs(void)320 static void save_all_tabs (void) {
321     int i = 0; /* non-C99 */
322     for (i = 0; i < TAB_TABLE_SIZE; i++)
323         tab_table[i].save ();
324 }
325 
destroy_all_tabs(void)326 static void destroy_all_tabs (void) {
327     int i = 0; /* non-C99 */
328     for (i = 0; i < TAB_TABLE_SIZE; i++)
329         tab_table[i].destroy ();
330 }
331 
dialog_response_handler(GtkDialog * dialog,gint response,gpointer user_data)332 static void dialog_response_handler (GtkDialog *dialog,
333                                      gint response,
334                                      gpointer user_data) {
335     switch (response) {
336     case GTK_RESPONSE_OK:
337         save_all_tabs ();
338         break;
339     default:
340         break;
341     }
342 
343     /* Clean up */
344     destroy_all_tabs ();
345     gtk_main_quit ();
346 }
347 
run_dialog(void)348 static void run_dialog (void) {
349     /* Create the notebook. */
350     GtkWidget *notebook = gtk_notebook_new ();
351     if (notebook == NULL) {
352         fprintf (stderr, "notebook == NULL?!\n");
353         exit (-1);
354     }
355 
356     /* Put tabs into the notebook. */
357     int i = 0; /* non-C99 */
358     for (i = 0; i < TAB_TABLE_SIZE; i++) {
359         GtkWidget *child = tab_table[i].create ();
360         if (child == NULL) {
361             fprintf (stderr, "[%d] child == NULL?!\n", i);
362             exit (-1);
363         }
364 
365         GtkWidget *label = gtk_label_new (_ (tab_table[i].name));
366         if (label == NULL) {
367             fprintf (stderr, "[%d] label == NULL?! (%s translated to %s)\n", i, tab_table[i].name, _ (tab_table[i].name));
368             exit (-1);
369         }
370 
371         if (gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child, label) == -1) {
372             fprintf (stderr, "[%d] append_page\n", i);
373             exit (-1);
374         }
375     }
376 
377     /* Create the dialog */
378     GtkWidget *dialog = gtk_dialog_new_with_buttons (
379         _ ("hime setup"),
380         NULL,
381         GTK_DIALOG_DESTROY_WITH_PARENT,
382         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
383         GTK_STOCK_OK, GTK_RESPONSE_OK,
384         NULL);
385     if (dialog == NULL) {
386         fprintf (stderr, "dialog == NULL?!\n");
387         exit (-1);
388     }
389 
390     /* Alternative button order when button-orde = 1 */
391     gtk_dialog_set_alternative_button_order (
392         GTK_DIALOG (dialog),
393         GTK_RESPONSE_OK,
394         GTK_RESPONSE_CANCEL,
395         -1);
396 
397     /* Put the notebook into the dialog. */
398     GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
399     gtk_container_add (GTK_CONTAINER (content_area), notebook);
400 
401     /* Run the dialog and save the setting when 'OK' is clicked. */
402     g_signal_connect_swapped (
403         dialog,
404         "response",
405         G_CALLBACK (dialog_response_handler),
406         NULL);
407 
408     gtk_widget_show_all (dialog);
409 }
410 
411 void exec_setup_scripts ();
412 
main(int argc,char ** argv)413 int main (int argc, char **argv) {
414     set_is_chs ();
415 
416     exec_setup_scripts ();
417 
418     init_TableDir ();
419 
420     load_settings ();
421 
422     load_gtab_list (FALSE);
423 
424     gtk_init (&argc, &argv);
425 
426 #if HIME_I18N_MESSAGE
427     bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
428     textdomain (GETTEXT_PACKAGE);
429 #endif
430 
431     g_object_get (gtk_settings_get_default (), "gtk-alternative-button-order", &button_order, NULL);
432 
433 #if 0
434   // once you invoke hime-setup, the left-right buton tips is disabled
435   save_hime_conf_int(LEFT_RIGHT_BUTTON_TIPS, 0);
436 #endif
437 
438     run_dialog ();
439     gtk_main ();
440     return 0;
441 }
442