Codebase list fcitx-configtool / 0db7115
Imported Upstream version 0.4.1 Aron Xu 12 years ago
50 changed file(s) with 4963 addition(s) and 292 deletion(s). Raw diff Collapse all Expand all
66
77 find_package(PkgConfig REQUIRED)
88
9 if (ENABLE_GTK3)
10 set(GLIB_REQUIRED_VERSION "2.28")
11 else (ENABLE_GTK3)
12 set(GLIB_REQUIRED_VERSION "2.26")
13 endif (ENABLE_GTK3)
14
15 PKG_CHECK_MODULES (GLIB2 "glib-2.0 >= ${GLIB_REQUIRED_VERSION}" REQUIRED)
916 PKG_CHECK_MODULES (GIO2 "gio-2.0 >= 2.26" REQUIRED)
1017 PKG_CHECK_MODULES(ISO_CODES "iso-codes" REQUIRED)
1118 _pkgconfig_invoke("iso-codes" ISO_CODES PREFIX "" "--variable=prefix")
3138 set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}")
3239 set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined,--as-needed ${CMAKE_MODULE_LINKER_FLAGS}")
3340
41 string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" FCITX4_MAJOR_VERSION "${FCITX4_VERSION}")
42 string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" FCITX4_MINOR_VERSION "${FCITX4_VERSION}")
43 string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" FCITX4_PATCH_VERSION "${FCITX4_VERSION}")
44
3445 set(datadir ${CMAKE_INSTALL_PREFIX}/share)
3546 set(localedir ${CMAKE_INSTALL_PREFIX}/share/locale)
3647 set(exec_prefix "${CMAKE_INSTALL_PREFIX}")
33 #define EXEC_PREFIX "@exec_prefix@"
44 #define PACKAGE "@FCITX4_PACKAGE_NAME@"
55 #define LIBLOCALEDIR "@liblocaledir@"
6 #define ISO_CODES_PREFIX "@ISO_CODES_PREFIX@"
6 #define ISO_CODES_PREFIX "@ISO_CODES_PREFIX@"
7 #define FCITX4_MAJOR_VERSION @FCITX4_MAJOR_VERSION@
8 #define FCITX4_MINOR_VERSION @FCITX4_MINOR_VERSION@
9 #define FCITX4_PATCH_VERSION @FCITX4_PATCH_VERSION@
10
11 #define FCITX_CHECK_VERSION(major,minor,micro) \
12 (FCITX4_MAJOR_VERSION > (major) || \
13 (FCITX4_MAJOR_VERSION == (major) && FCITX4_MINOR_VERSION > (minor)) || \
14 (FCITX4_MAJOR_VERSION == (major) && FCITX4_MINOR_VERSION == (minor) && \
15 FCITX4_PATCH_VERSION >= (micro)))
22
33 include_directories (
44 ${GTK2_INCLUDE_DIRS}
5 ${GLIB2_INCLUDE_DIRS}
56 ${GIO2_INCLUDE_DIRS}
67 ${FCITX4_FCITX_INCLUDE_DIRS}
78 ${FCITX4_FCITX_UTILS_INCLUDE_DIRS}
1011
1112 link_directories (
1213 ${GTK2_LIBRARY_DIRS}
14 ${GLIB2_LIBRARY_DIRS}
1315 ${GIO2_LIBRARY_DIRS}
1416 ${FCITX4_FCITX_LIBRARY_DIRS}
1517 ${FCITX4_FCITX_UTILS_LIBRARY_DIRS}
4244 ${FCITX4_FCITX_UTILS_LIBRARIES}
4345 ${FCITX4_FCITX_CONFIG_LIBRARIES}
4446 ${FCITX4_FCITX_LIBRARIES}
47 ${GLIB2_LIBRARIES}
4548 ${GIO2_LIBRARIES}
4649 )
4750
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
131131 bind_textdomain_codeset(cfdesc->domain, "UTF-8");
132132
133133 FILE *fp;
134 fp = FcitxXDGGetFileWithPrefix(self->prefix, self->name, "rt", NULL);
134 fp = FcitxXDGGetFileWithPrefix(self->prefix, self->name, "r", NULL);
135135 self->gconfig.configFile = FcitxConfigParseConfigFileFp(fp, cfdesc);
136136
137137 FcitxConfigGroupDesc *cgdesc = NULL;
143143 if (codesc == NULL)
144144 continue;
145145
146 GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
146147 GtkWidget *table = gtk_table_new(2, HASH_COUNT(codesc), FALSE);
147148 GtkWidget *plabel = gtk_label_new(D_(cfdesc->domain, cgdesc->groupName));
148149 GtkWidget *scrollwnd = gtk_scrolled_window_new(NULL, NULL);
149 GtkWidget *viewport = gtk_viewport_new(NULL, NULL);
150
151 gtk_container_set_border_width(GTK_CONTAINER(table), 4);
152 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
153 gtk_container_add(GTK_CONTAINER(scrollwnd), viewport);
154 gtk_container_add(GTK_CONTAINER(viewport), table);
150
151 gtk_container_set_border_width(GTK_CONTAINER(table), 0);
152 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
153 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwnd), table);
154 gtk_box_pack_start(GTK_BOX(hbox), scrollwnd, TRUE, TRUE, 0);
155155 gtk_notebook_append_page(GTK_NOTEBOOK(configNotebook),
156 scrollwnd,
156 hbox,
157157 plabel);
158158
159159 int i = 0;
504504 FcitxConfigResetConfigToDefaultValue(&config_widget->gconfig);
505505 FcitxConfigBindSync(&config_widget->gconfig);
506506 } else if (action == CONFIG_WIDGET_SAVE) {
507 FILE* fp = FcitxXDGGetFileUserWithPrefix(config_widget->prefix, config_widget->name, "wt", NULL);
507 FILE* fp = FcitxXDGGetFileUserWithPrefix(config_widget->prefix, config_widget->name, "w", NULL);
508508
509509 if (fp) {
510510 FcitxConfigSaveConfigFileFp(fp, &config_widget->gconfig, config_widget->cfdesc);
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
8383 GPtrArray *array = NULL;
8484 GVariant* value;
8585 GVariantIter *iter;
86 const gchar *name, *unique_name, *langcode;
86 gchar *name, *unique_name, *langcode;
8787 gboolean enable;
8888 value = g_dbus_proxy_get_cached_property(G_DBUS_PROXY(im), "IMList");
8989
119119 item->unique_name = strdup(unique_name);
120120 item->langcode = strdup(langcode);
121121 g_ptr_array_add(array, item);
122 g_free(name);
123 g_free(unique_name);
124 g_free(langcode);
122125 }
123126 g_variant_iter_free(iter);
124127
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
2828 G_DEFINE_TYPE(FcitxImWidget, fcitx_im_widget, GTK_TYPE_HBOX)
2929
3030 enum {
31 LIST_IM_STRING,
32 LIST_IM,
33 N_COLUMNS
31 AVAIL_TREE_IM_STRING,
32 AVAIL_TREE_IM,
33 AVAIL_TREE_LANG,
34 AVAIL_N_COLUMNS
3435 };
36
37 enum {
38 IM_LIST_IM_STRING,
39 IM_LIST_IM,
40 IM_N_COLUMNS
41 };
42
43 typedef struct {
44 FcitxImWidget* widget;
45 GHashTable* langTable;
46 } foreach_ct;
3547
3648 static void fcitx_im_widget_finalize(GObject* object);
3749 static void _fcitx_im_widget_connect(FcitxImWidget* self);
4961 GtkTreeIter *iter,
5062 gpointer data);
5163 static const gchar* _get_current_lang();
64 static void icon_press_cb (GtkEntry *entry,
65 gint position,
66 GdkEventButton *event,
67 gpointer data);
5268
5369 static void
5470 fcitx_im_widget_class_init(FcitxImWidgetClass *klass)
6076 static void
6177 fcitx_im_widget_init(FcitxImWidget* self)
6278 {
63 self->availimstore = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
79 self->availimstore = gtk_tree_store_new(AVAIL_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING);
6480 self->filtermodel = gtk_tree_model_filter_new(GTK_TREE_MODEL(self->availimstore), NULL);
6581
6682 gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(self->filtermodel),
6884 self ,
6985 NULL);
7086 self->sortmodel = gtk_tree_model_sort_new_with_model(self->filtermodel);
71 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->sortmodel), LIST_IM_STRING, GTK_SORT_ASCENDING);
87 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->sortmodel), AVAIL_TREE_IM_STRING, GTK_SORT_ASCENDING);
7288 self->availimview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(self->sortmodel));
7389
7490 GtkWidget* label = gtk_label_new(_("Available Input Method"));
7591 self->filterentry = gtk_entry_new();
92 gtk_entry_set_icon_from_stock (GTK_ENTRY (self->filterentry),
93 GTK_ENTRY_ICON_SECONDARY,
94 GTK_STOCK_CLEAR);
7695
7796 GtkCellRenderer* renderer;
7897 GtkTreeViewColumn* column;
7998 renderer = gtk_cell_renderer_text_new();
8099 column = gtk_tree_view_column_new_with_attributes(
81100 _("Input Method"), renderer,
82 "text", LIST_IM_STRING,
101 "text", AVAIL_TREE_IM_STRING,
83102 NULL);
84103 gtk_tree_view_append_column(GTK_TREE_VIEW(self->availimview), column);
85104
124143
125144 label = gtk_label_new(_("Current Input Method"));
126145
127 self->imstore = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
146 self->imstore = gtk_list_store_new(IM_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
128147 self->imview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(self->imstore));
129148
130149 renderer = gtk_cell_renderer_text_new();
131150 column = gtk_tree_view_column_new_with_attributes(
132151 _("Input Method"), renderer,
133 "text", LIST_IM_STRING,
152 "text", IM_LIST_IM_STRING,
134153 NULL);
135154 gtk_tree_view_append_column(GTK_TREE_VIEW(self->imview), column);
136155
171190 g_signal_connect(G_OBJECT(self->movedownbutton), "clicked", G_CALLBACK(_fcitx_im_widget_movedown_button_clicked), self);
172191 g_signal_connect(G_OBJECT(self->filterentry), "changed", G_CALLBACK(_fcitx_im_widget_filtertext_changed), self);
173192 g_signal_connect(G_OBJECT(self->onlycurlangcheckbox), "toggled", G_CALLBACK(_fcitx_im_widget_onlycurlangcheckbox_toggled), self);
193 g_signal_connect(G_OBJECT(self->filterentry), "icon-press", G_CALLBACK (icon_press_cb), NULL);
174194
175195
176196 _fcitx_im_widget_connect(self);
188208
189209 void fcitx_im_widget_finalize(GObject* object)
190210 {
191
211 FcitxImWidget* self = FCITX_IM_WIDGET(object);
212 if (self->array) {
213 g_ptr_array_set_free_func(self->array, fcitx_inputmethod_item_free);
214 g_ptr_array_free(self->array, FALSE);
215 self->array = NULL;
216 }
217 g_free(self->focus);
192218 }
193219
194220 void _fcitx_im_widget_imlist_changed_cb(FcitxInputMethod* im, gpointer user_data)
217243
218244 void _fcitx_im_widget_load(FcitxImWidget* self)
219245 {
220 gtk_list_store_clear(self->availimstore);
246 gtk_tree_store_clear(self->availimstore);
221247 gtk_list_store_clear(self->imstore);
222248
223249 if (self->array) {
228254
229255 self->array = fcitx_inputmethod_get_imlist(self->improxy);
230256
231 if (self->array)
232 g_ptr_array_foreach(self->array, _fcitx_inputmethod_insert_foreach_cb, self);
257 if (self->array) {
258 foreach_ct ct;
259 ct.widget = self;
260 ct.langTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
261 g_ptr_array_foreach(self->array, _fcitx_inputmethod_insert_foreach_cb, &ct);
262 g_hash_table_unref(ct.langTable);
263
264 _fcitx_im_widget_im_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(self->imview)), self);
265 g_free(self->focus);
266 self->focus = NULL;
267
268 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self->onlycurlangcheckbox)))
269 gtk_tree_view_expand_all (GTK_TREE_VIEW(self->availimview));
270 }
233271 }
234272
235273 void _fcitx_inputmethod_insert_foreach_cb(gpointer data,
236274 gpointer user_data)
237275 {
276 foreach_ct* ct = user_data;
238277 FcitxIMItem* item = data;
239 FcitxImWidget* self = user_data;
240 GtkTreeIter iter;
241
242 if (item->enable) {
243 gtk_list_store_append(self->imstore, &iter);
244 gtk_list_store_set(self->imstore, &iter, LIST_IM_STRING, item->name, -1);
245 gtk_list_store_set(self->imstore, &iter, LIST_IM, item, -1);
246 } else {
278 FcitxImWidget* self = ct->widget;
279 GtkTreeIter iter;
280
281 GtkTreeIter* langIter = g_hash_table_lookup(ct->langTable, item->langcode);
282
283 if (langIter == NULL) {
284 langIter = g_new(GtkTreeIter, 1);
285 gtk_tree_store_append(self->availimstore, langIter, NULL);
286
247287 char* lang = NULL;
248288 if (strlen(item->langcode) != 0)
249289 lang = gdm_get_language_from_name(item->langcode, NULL);
250 if (!lang)
251 lang = g_strdup_printf("%s", _("Unknown"));
252
253 gchar* string = g_strdup_printf(_("%s - %s"), lang, item->name);
290 if (!lang) {
291 if (strcmp(item->langcode, "*") == 0)
292 lang = g_strdup_printf("%s", _("Unknown"));
293 else
294 lang = g_strdup_printf("%s", _("Unknown"));
295 }
296 gtk_tree_store_set(self->availimstore, langIter, AVAIL_TREE_IM_STRING, lang, -1);
297 gtk_tree_store_set(self->availimstore, langIter, AVAIL_TREE_LANG, item->langcode, -1);
298 gtk_tree_store_set(self->availimstore, langIter, AVAIL_TREE_IM, NULL, -1);
299 g_free(lang);
254300
255 gtk_list_store_append(self->availimstore, &iter);
256 gtk_list_store_set(self->availimstore, &iter, LIST_IM_STRING, string, -1);
257 gtk_list_store_set(self->availimstore, &iter, LIST_IM, item, -1);
301 g_hash_table_insert(ct->langTable, g_strdup(item->langcode), langIter);
302 }
303
304 if (item->enable) {
305 gtk_list_store_append(self->imstore, &iter);
306 gtk_list_store_set(self->imstore, &iter, IM_LIST_IM_STRING, item->name, -1);
307 gtk_list_store_set(self->imstore, &iter, IM_LIST_IM, item, -1);
308 if (g_strcmp0(self->focus, item->unique_name) == 0) {
309 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->imview));
310 gtk_tree_selection_select_iter(selection, &iter);
311 }
312 } else {
258313
259 g_free(lang);
260 g_free(string);
314 gtk_tree_store_append(self->availimstore, &iter, langIter);
315 gtk_tree_store_set(self->availimstore, &iter, AVAIL_TREE_IM_STRING, item->name, -1);
316 gtk_tree_store_set(self->availimstore, &iter, AVAIL_TREE_LANG, NULL, -1);
317 gtk_tree_store_set(self->availimstore, &iter, AVAIL_TREE_IM, item, -1);
261318 }
262319
263320 }
295352 GtkTreeModel *model = gtk_tree_view_get_model(treeView);
296353 GtkTreeIter iter;
297354
355 FcitxIMItem* item = NULL;
298356 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
357 gtk_tree_model_get(model,
358 &iter,
359 AVAIL_TREE_IM, &item,
360 -1);
361 }
362 if (item) {
299363 gtk_widget_set_sensitive(self->addimbutton, TRUE);
300364 } else {
301365 gtk_widget_set_sensitive(self->addimbutton, FALSE);
315379 FcitxIMItem* item = NULL;
316380 gtk_tree_model_get(model,
317381 &iter,
318 LIST_IM, &item,
382 AVAIL_TREE_IM, &item,
319383 -1);
384 if (item == NULL)
385 return;
320386 item->enable = true;
321387
322388 g_ptr_array_remove(self->array, item);
323389 g_ptr_array_add(self->array, item);
390
391 g_free(self->focus);
392 self->focus = g_strdup(item->unique_name);
324393
325394 fcitx_inputmethod_set_imlist(self->improxy, self->array);
326395 }
338407 FcitxIMItem* item = NULL;
339408 gtk_tree_model_get(model,
340409 &iter,
341 LIST_IM, &item,
410 IM_LIST_IM, &item,
342411 -1);
343412 item->enable = false;
344413
359428 FcitxIMItem* item = NULL;
360429 gtk_tree_model_get(model,
361430 &iter,
362 LIST_IM, &item,
431 IM_LIST_IM, &item,
363432 -1);
364433
365434 int i;
377446 gpointer temp = g_ptr_array_index(self->array, i);
378447 g_ptr_array_index(self->array, i) = g_ptr_array_index(self->array, switch_index);
379448 g_ptr_array_index(self->array, switch_index) = temp;
449 g_free(self->focus);
450 self->focus = g_strdup(item->unique_name);
380451
381452 fcitx_inputmethod_set_imlist(self->improxy, self->array);
382453 }
395466 FcitxIMItem* item = NULL;
396467 gtk_tree_model_get(model,
397468 &iter,
398 LIST_IM, &item,
469 IM_LIST_IM, &item,
399470 -1);
400471
401472 int i;
413484 gpointer temp = g_ptr_array_index(self->array, i);
414485 g_ptr_array_index(self->array, i) = g_ptr_array_index(self->array, switch_index);
415486 g_ptr_array_index(self->array, switch_index) = temp;
487 g_free(self->focus);
488 self->focus = g_strdup(item->unique_name);
416489
417490 fcitx_inputmethod_set_imlist(self->improxy, self->array);
418491 }
441514 FcitxIMItem* item = NULL;
442515 gtk_tree_model_get(GTK_TREE_MODEL(self->availimstore),
443516 iter,
444 LIST_IM, &item,
517 AVAIL_TREE_IM, &item,
445518 -1);
446519
520 gboolean flag = TRUE;
447521 if (item) {
448 gboolean flag = TRUE;
449 flag &= (strlen(filter_text) == 0
522 flag = flag && (strlen(filter_text) == 0
450523 || strstr(item->name, filter_text)
451524 || strstr(item->unique_name, filter_text)
452525 || strstr(item->langcode, filter_text));
453 flag &= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self->onlycurlangcheckbox)) ?
526 flag = flag && (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self->onlycurlangcheckbox)) ?
454527 strncmp(item->langcode, _get_current_lang() , 2) == 0 : TRUE) ;
455528 return flag;
456 } else
457 return FALSE;
529 } else {
530 gchar* lang = NULL;
531 gtk_tree_model_get(GTK_TREE_MODEL(self->availimstore),
532 iter,
533 AVAIL_TREE_LANG, &lang,
534 -1);
535 flag = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self->onlycurlangcheckbox)) ?
536 lang != NULL && strncmp(lang, _get_current_lang() , 2) == 0 : TRUE) ;
537 g_free(lang);
538 return flag;
539 }
458540 }
459541
460542 static const gchar* _get_current_lang()
467549 if (!lang)
468550 lang = "C";
469551 return lang;
552 }
553
554 static void
555 icon_press_cb (GtkEntry *entry,
556 gint position,
557 GdkEventButton *event,
558 gpointer data)
559 {
560 gtk_entry_set_text (entry, "");
470561 }
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
4646
4747 typedef struct {
4848 GtkHBox parent;
49 GtkListStore* availimstore;
49 GtkTreeStore* availimstore;
5050 GtkListStore* imstore;
5151 GtkWidget* availimview;
5252 GtkWidget* imview;
6161 GtkTreeModel* filtermodel;
6262 GtkWidget* onlycurlangcheckbox;
6363 GtkTreeModel* sortmodel;
64 gchar* focus;
6465 } FcitxImWidget;
6566
6667 typedef struct {
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
3636 N_COLUMNS
3737 };
3838
39 enum {
40 PAGE_LIST_NAME,
41 PAGE_LIST_PAGE,
42 PAGE_LIST_ICON,
43 PAGE_N_COLUMNS
44 };
45
3946 G_DEFINE_TYPE(FcitxMainWindow, fcitx_main_window, GTK_TYPE_WINDOW)
4047
4148 static void fcitx_main_window_finalize(GObject* object);
4855
4956 static void _fcitx_main_window_add_im_page(FcitxMainWindow* self);
5057
51 static int _fcitx_main_window_close_cb(GtkWidget *theWindow, gpointer data);
52
53 static void _fcitx_main_window_selection_changed_cb(GtkTreeSelection *selection, gpointer data);
54
55 static ConfigPage* _fcitx_main_window_add_page(FcitxMainWindow* self, const char* name, GtkWidget* widget);
58 static void _fcitx_main_window_selection_changed_cb(GtkIconView *iconview, gpointer data);
59
60 static ConfigPage* _fcitx_main_window_add_page(FcitxMainWindow* self, const char* name, GtkWidget* widget, const char* stock);
5661
5762 static void _fcitx_main_window_addon_selection_changed(GtkTreeSelection *selection, gpointer data);
5863
8994 static void
9095 fcitx_main_window_init(FcitxMainWindow* self)
9196 {
92 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
93
94 GtkCellRenderer *renderer;
95 GtkTreeViewColumn *column;
97 GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
98 GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
9699
97100 self->pagestore = _fcitx_main_window_create_model();
98 self->pageview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(self->pagestore));
99
100 renderer = gtk_cell_renderer_text_new();
101 column = gtk_tree_view_column_new_with_attributes(
102 _("Config"), renderer,
103 "text", 0,
104 NULL);
105 gtk_tree_view_append_column(GTK_TREE_VIEW(self->pageview), column);
106
107 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(self->pageview), FALSE);
101 self->pageview = gtk_icon_view_new_with_model(GTK_TREE_MODEL(self->pagestore));
102
103 gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(self->pageview), PAGE_LIST_ICON);
104 gtk_icon_view_set_text_column(GTK_ICON_VIEW(self->pageview), PAGE_LIST_NAME);
105 gtk_icon_view_set_item_orientation(GTK_ICON_VIEW(self->pageview), GTK_ORIENTATION_VERTICAL);
108106
109107 _fcitx_main_window_add_im_page(self);
110108 _fcitx_main_window_add_config_file_page(self);
111109 _fcitx_main_window_add_addon_page(self);
112110
113 gtk_widget_set_size_request(self->pageview, 170, -1);
114111 gtk_widget_set_size_request(GTK_WIDGET(self), -1, 500);
115112
116 self->hpaned = gtk_hpaned_new();
117 GtkWidget *treescroll = gtk_scrolled_window_new(NULL, NULL);
118 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(treescroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
119
120 gtk_container_add(GTK_CONTAINER(treescroll), self->pageview);
121 gtk_paned_add1(GTK_PANED(self->hpaned), treescroll);
122
123 gtk_box_pack_start(GTK_BOX(vbox), self->hpaned, TRUE, TRUE, 0);
113 self->vbox = gtk_vbox_new(FALSE, 0);
114 self->pagelabel = gtk_label_new("");
115 gtk_label_set_use_markup(GTK_LABEL(self->pagelabel), true);
116 gtk_misc_set_alignment(GTK_MISC(self->pagelabel), 0, 0.5);
117
118 gtk_box_pack_start(GTK_BOX(self->vbox), self->pagelabel, FALSE, FALSE, 14);
119 GtkWidget* scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
120 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
121 gtk_container_add(GTK_CONTAINER(scrolledwindow), self->pageview);
122 gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow, FALSE, TRUE, 4);
123 gtk_box_pack_start(GTK_BOX(hbox), self->vbox, TRUE, TRUE, 8);
124 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 8);
124125
125126 gtk_container_add(GTK_CONTAINER(self), vbox);
126127
127 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->pageview));
128 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
129
130 g_signal_connect(G_OBJECT(self), "destroy", G_CALLBACK(_fcitx_main_window_close_cb), NULL);
131 g_signal_connect(G_OBJECT(selection), "changed",
128 gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(self->pageview), GTK_SELECTION_SINGLE);
129 gtk_icon_view_set_item_padding(GTK_ICON_VIEW(self->pageview), 0);
130 gtk_icon_view_set_margin(GTK_ICON_VIEW(self->pageview), 0);
131 gtk_icon_view_set_column_spacing(GTK_ICON_VIEW(self->pageview), 0);
132 gtk_icon_view_set_row_spacing(GTK_ICON_VIEW(self->pageview), 0);
133 gtk_icon_view_set_item_width(GTK_ICON_VIEW(self->pageview), 96);
134
135 g_signal_connect_swapped(G_OBJECT(self), "destroy", G_CALLBACK(gtk_main_quit), NULL);
136 g_signal_connect(G_OBJECT(self->pageview), "selection-changed",
132137 G_CALLBACK(_fcitx_main_window_selection_changed_cb), self);
133138
134 gtk_tree_selection_select_iter(selection, &self->impage->iter);
139 GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(self->pagestore), &self->impage->iter);
140 gtk_icon_view_select_path(GTK_ICON_VIEW(self->pageview), path);
141 gtk_tree_path_free(path);
135142
136143 gtk_window_set_icon_name(GTK_WINDOW(self), "fcitx-configtool");
137144 gtk_window_set_title(GTK_WINDOW(self), _("Fcitx Config"));
153160 utarray_free(self->addons);
154161 }
155162
156 int _fcitx_main_window_close_cb(GtkWidget *theWindow, gpointer data)
157 {
158 gtk_main_quit();
159 return 0;
160 }
161
162 ConfigPage* _fcitx_main_window_add_page(FcitxMainWindow* self, const char* name, GtkWidget* widget)
163 ConfigPage* _fcitx_main_window_add_page(FcitxMainWindow* self, const char* name, GtkWidget* widget, const char* stock)
163164 {
164165 ConfigPage *page = (ConfigPage*) malloc(sizeof(ConfigPage));
165166 memset(page, 0, sizeof(ConfigPage));
171172 gtk_widget_show_all(widget);
172173
173174 gtk_list_store_append(self->pagestore, &page->iter);
174 gtk_list_store_set(self->pagestore, &page->iter, 0, name, 1, page, -1);
175 gtk_list_store_set(self->pagestore, &page->iter,
176 0, name,
177 1, page,
178 2, gtk_widget_render_icon(self->pageview, stock, GTK_ICON_SIZE_DND, NULL),
179 -1);
175180
176181 return page;
177182 }
178183
179 void _fcitx_main_window_selection_changed_cb(GtkTreeSelection *selection, gpointer data)
180 {
181 GtkTreeView *treeView = gtk_tree_selection_get_tree_view(selection);
182 GtkTreeModel *model = gtk_tree_view_get_model(treeView);
184 void _fcitx_main_window_selection_changed_cb(GtkIconView* iconview, gpointer data)
185 {
186 GtkTreeModel *model = gtk_icon_view_get_model(iconview);
183187 GtkTreeIter iter;
184188 ConfigPage* page;
185189 FcitxMainWindow* self = data;
186
187 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
190
191 GList* list = gtk_icon_view_get_selected_items(iconview);
192
193 if (list) {
194 gchar* title;
195 gtk_tree_model_get_iter(GTK_TREE_MODEL(self->pagestore), &iter, (GtkTreePath*)(list->data));
188196 gtk_tree_model_get(model, &iter,
189 1, &page,
197 PAGE_LIST_NAME, &title,
198 PAGE_LIST_PAGE, &page,
190199 -1);
200
201 gchar* text = g_strdup_printf("<b>%s</b>", title);
202 gtk_label_set_markup(GTK_LABEL(self->pagelabel), text);
203 g_free(text);
204 g_free(title);
191205
192206 if (self->lastpage)
193 gtk_container_remove(GTK_CONTAINER(self->hpaned), self->lastpage->page);
194 gtk_paned_add2(GTK_PANED(self->hpaned), page->page);
207 gtk_container_remove(GTK_CONTAINER(self->vbox), self->lastpage->page);
208 gtk_box_pack_end(GTK_BOX(self->vbox), page->page, TRUE, TRUE, 0);
195209 gtk_widget_show_all(GTK_WIDGET(self));
196210
197211 self->lastpage = page;
198212 } else {
199 gtk_tree_selection_select_iter(selection, &self->configpage->iter);
213 GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(self->pagestore), &self->impage->iter);
214 gtk_icon_view_select_path(GTK_ICON_VIEW(self->pageview), path);
215 gtk_tree_path_free(path);
200216 }
217
218 g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
219 g_list_free (list);
201220 }
202221
203222
228247
229248 static GtkListStore *_fcitx_main_window_create_model()
230249 {
231 GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
250 GtkListStore* store = gtk_list_store_new(PAGE_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_PIXBUF);
232251 return store;
233252 }
234253
252271 g_signal_connect(G_OBJECT(applybutton), "clicked", G_CALLBACK(_fcitx_main_window_apply_button_clicked), config_widget);
253272
254273
255 self->configpage = _fcitx_main_window_add_page(self, _("Global Config"), vbox);
274 self->configpage = _fcitx_main_window_add_page(self, _("Global Config"), vbox, GTK_STOCK_PREFERENCES);
256275 }
257276
258277 void _fcitx_main_window_add_im_page(FcitxMainWindow* self)
259278 {
260279 GtkWidget* imwidget = fcitx_im_widget_new();
261 self->impage = _fcitx_main_window_add_page(self, _("Input Method Configuration"), imwidget);
280 self->impage = _fcitx_main_window_add_page(self, _("Input Method"), imwidget, GTK_STOCK_EDIT);
262281 }
263282
264283 void _fcitx_main_window_add_addon_page(FcitxMainWindow* self)
329348 g_signal_connect(G_OBJECT(selection), "changed",
330349 G_CALLBACK(_fcitx_main_window_addon_selection_changed), self);
331350
332 self->addonpage = _fcitx_main_window_add_page(self, _("Addon Configuration"), vbox);
351 self->addonpage = _fcitx_main_window_add_page(self, _("Addon"), vbox, GTK_STOCK_ADD);
333352 }
334353
335354 static void
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
5353 GtkWindow parent;
5454 GtkWidget* pageview;
5555 GtkListStore *pagestore;
56 GtkWidget* hpaned;
56 GtkWidget* vbox;
57 GtkWidget* pagelabel;
5758 ConfigPage* impage;
5859 ConfigPage* configpage;
5960 ConfigPage* lastpage;
+0
-3
gtk/marshall.list less more
0 VOID:UINT,UINT,INT
1 VOID:STRING,STRING,STRING
2 VOID:STRING,INT
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
193193 {
194194 size_t size, i;
195195 GList* result = NULL;
196 #if FCITX_CHECK_VERSION(4,2,1)
197 char** xdgpath = FcitxXDGGetPathWithPrefix(&size, "");
198 #else
196199 char** xdgpath = FcitxXDGGetPath(&size, "XDG_CONFIG_HOME", ".config" , PACKAGE , DATADIR, PACKAGE);
200 #endif
197201
198202 for (i = 0; i < size; i ++) {
199203 char* dirpath = realpath(xdgpath[i], NULL);
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 /***************************************************************************
1 * Copyright (C) 2010~2011 by CSSlayer *
1 * Copyright (C) 2010~2012 by CSSlayer *
22 * *
33 * This program is free software; you can redistribute it and/or modify *
44 * it under the terms of the GNU General Public License as published by *
00 PKG_CHECK_MODULES (GTK3 "gtk+-3.0" REQUIRED)
1 PKG_CHECK_MODULES(UNIQUE3 "unique-3.0")
21
32 include_directories (
43 ${GTK3_INCLUDE_DIRS}
4 ${GLIB2_INCLUDE_DIRS}
55 ${GIO2_INCLUDE_DIRS}
66 ${FCITX4_FCITX_INCLUDE_DIRS}
77 ${FCITX4_FCITX_UTILS_INCLUDE_DIRS}
88 ${FCITX4_FCITX_CONFIG_INCLUDE_DIRS}
9 ../gtk/
109 )
1110
1211 link_directories (
1312 ${GTK3_LIBRARY_DIRS}
13 ${GLIB2_LIBRARY_DIRS}
1414 ${GIO2_LIBRARY_DIRS}
1515 ${FCITX4_FCITX_LIBRARY_DIRS}
1616 ${FCITX4_FCITX_UTILS_LIBRARY_DIRS}
1717 ${FCITX4_FCITX_CONFIG_LIBRARY_DIRS}
1818 )
19 if (UNIQUE3_FOUND)
20 include_directories (${UNIQUE3_INCLUDE_DIRS})
21 link_directories (${UNIQUE3_LIBRARY_DIRS})
22 endif (UNIQUE3_FOUND)
2319
2420 set( fcitx_config_gtk3_sources
25 ../gtk/sub_config_parser.c
26 ../gtk/sub_config_widget.c
27 ../gtk/config_widget.c
28 ../gtk/configdesc.c
29 ../gtk/keygrab.c
30 ../gtk/main.c
31 ../gtk/main_window.c
32 ../gtk/im_widget.c
33 ../gtk/im.c
34 ../gtk/gdm-languages.c
21 sub_config_parser.c
22 sub_config_widget.c
23 config_widget.c
24 configdesc.c
25 keygrab.c
26 main.c
27 main_window.c
28 im_widget.c
29 im.c
30 gdm-languages.c
3531 )
3632
3733 add_executable( fcitx-config-gtk3 ${fcitx_config_gtk3_sources} )
4339 ${FCITX4_FCITX_UTILS_LIBRARIES}
4440 ${FCITX4_FCITX_CONFIG_LIBRARIES}
4541 ${FCITX4_FCITX_LIBRARIES}
42 ${GLIB2_LIBRARIES}
4643 ${GIO2_LIBRARIES}
4744 )
4845
49 if (UNIQUE3_FOUND)
50 target_link_libraries (fcitx-config-gtk3 ${UNIQUE3_LIBRARIES})
51 endif (UNIQUE3_FOUND)
52
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #ifndef COMMON_H
20 #define COMMON_H
21
22 #include <libintl.h>
23
24 #define _(x) gettext(x)
25
26 #endif
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include "config.h"
20
21 #include <gtk/gtk.h>
22 #include <libintl.h>
23 #include <stdlib.h>
24 #include <libgen.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 #include <fcitx-config/fcitx-config.h>
29 #include <fcitx-utils/uthash.h>
30 #include <fcitx-config/hotkey.h>
31 #include <fcitx-config/xdg.h>
32
33 #include "config_widget.h"
34 #include "keygrab.h"
35 #include "sub_config_widget.h"
36
37 #define _(s) gettext(s)
38 #define D_(d, x) dgettext (d, x)
39 #define RoundColor(c) ((c)>=0?((c)<=255?c:255):0)
40
41 G_DEFINE_TYPE(FcitxConfigWidget, fcitx_config_widget, GTK_TYPE_BOX)
42
43 typedef struct {
44 int i;
45 FcitxConfigWidget* widget;
46 GtkWidget* grid;
47 } HashForeachContext;
48
49 enum {
50 PROP_0,
51
52 PROP_CONFIG_DESC,
53 PROP_PREFIX,
54 PROP_NAME,
55 PROP_SUBCONFIG
56 };
57
58 static void
59 fcitx_config_widget_set_property(GObject *gobject,
60 guint prop_id,
61 const GValue *value,
62 GParamSpec *pspec);
63
64
65 static void sync_filter(FcitxGenericConfig* gconfig, FcitxConfigGroup *group, FcitxConfigOption *option, void *value, FcitxConfigSync sync, void *arg);
66
67 static void set_none_font_clicked(GtkWidget *button, gpointer arg);
68
69 static void hash_foreach_cb(gpointer key,
70 gpointer value,
71 gpointer user_data);
72
73 static void
74 fcitx_config_widget_setup_ui(FcitxConfigWidget *self);
75
76 static void
77 fcitx_config_widget_finalize(GObject *object);
78
79 static void
80 fcitx_config_widget_class_init(FcitxConfigWidgetClass *klass)
81 {
82 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
83 gobject_class->set_property = fcitx_config_widget_set_property;
84 gobject_class->finalize = fcitx_config_widget_finalize;
85 g_object_class_install_property(gobject_class,
86 PROP_CONFIG_DESC,
87 g_param_spec_pointer("cfdesc",
88 "Configuration Description",
89 "Configuration Description for this widget",
90 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
91
92 g_object_class_install_property(gobject_class,
93 PROP_PREFIX,
94 g_param_spec_string("prefix",
95 "Prefix of path",
96 "Prefix of configuration path",
97 NULL,
98 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
99
100 g_object_class_install_property(gobject_class,
101 PROP_NAME,
102 g_param_spec_string("name",
103 "File name",
104 "File name of configuration file",
105 NULL,
106 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
107
108 g_object_class_install_property(gobject_class,
109 PROP_SUBCONFIG,
110 g_param_spec_string("subconfig",
111 "subconfig",
112 "subconfig",
113 NULL,
114 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
115 }
116
117 static void
118 fcitx_config_widget_init(FcitxConfigWidget *self)
119 {
120 }
121
122 static void
123 fcitx_config_widget_setup_ui(FcitxConfigWidget *self)
124 {
125 FcitxConfigFileDesc* cfdesc = self->cfdesc;
126 GtkWidget *cvbox = GTK_WIDGET(self);
127 GtkWidget *configNotebook = gtk_notebook_new();
128 gtk_box_pack_start(GTK_BOX(cvbox), configNotebook, TRUE, TRUE, 0);
129 if (cfdesc) {
130 bindtextdomain(cfdesc->domain, LOCALEDIR);
131 bind_textdomain_codeset(cfdesc->domain, "UTF-8");
132
133 FILE *fp;
134 fp = FcitxXDGGetFileWithPrefix(self->prefix, self->name, "r", NULL);
135 self->gconfig.configFile = FcitxConfigParseConfigFileFp(fp, cfdesc);
136
137 FcitxConfigGroupDesc *cgdesc = NULL;
138 FcitxConfigOptionDesc *codesc = NULL;
139 for (cgdesc = cfdesc->groupsDesc;
140 cgdesc != NULL;
141 cgdesc = (FcitxConfigGroupDesc*)cgdesc->hh.next) {
142 codesc = cgdesc->optionsDesc;
143 if (codesc == NULL)
144 continue;
145
146 GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
147 GtkWidget *grid = gtk_grid_new();
148 gtk_widget_set_margin_left(grid, 12);
149 gtk_widget_set_margin_top(grid, 6);
150 gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
151 gtk_grid_set_column_spacing(GTK_GRID(grid), 6);
152 GtkWidget *plabel = gtk_label_new(D_(cfdesc->domain, cgdesc->groupName));
153 GtkWidget *scrollwnd = gtk_scrolled_window_new(NULL, NULL);
154
155 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
156 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwnd), grid);
157 gtk_box_pack_start(GTK_BOX(hbox), scrollwnd, TRUE, TRUE, 0);
158 gtk_notebook_append_page(GTK_NOTEBOOK(configNotebook),
159 hbox,
160 plabel);
161
162 int i = 0;
163 for (; codesc != NULL;
164 codesc = (FcitxConfigOptionDesc*)codesc->hh.next, i++) {
165 const char *s;
166 if (codesc->desc && strlen(codesc->desc) != 0)
167 s = D_(cfdesc->domain, codesc->desc);
168 else
169 s = D_(cfdesc->domain, codesc->optionName);
170
171 GtkWidget *inputWidget = NULL;
172 void *argument = NULL;
173
174 switch (codesc->type) {
175 case T_Integer:
176 inputWidget = gtk_spin_button_new_with_range(-1.0, 10000.0, 1.0);
177 argument = inputWidget;
178 break;
179 case T_Color:
180 inputWidget = gtk_color_button_new();
181 argument = inputWidget;
182 break;
183 case T_Boolean:
184 inputWidget = gtk_check_button_new();
185 argument = inputWidget;
186 break;
187 case T_Font: {
188 inputWidget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
189 argument = gtk_font_button_new();
190 GtkWidget *button = gtk_button_new_with_label(_("Clear font setting"));
191 gtk_box_pack_start(GTK_BOX(inputWidget), argument, TRUE, TRUE, 0);
192 gtk_box_pack_start(GTK_BOX(inputWidget), button, FALSE, FALSE, 0);
193 gtk_font_button_set_use_size(GTK_FONT_BUTTON(argument), FALSE);
194 gtk_font_button_set_show_size(GTK_FONT_BUTTON(argument), FALSE);
195 g_signal_connect(G_OBJECT(button), "clicked", (GCallback) set_none_font_clicked, argument);
196 }
197 break;
198 case T_Enum: {
199 int i;
200 FcitxConfigEnum *e = &codesc->configEnum;
201 #if GTK_CHECK_VERSION(2, 24, 0)
202 inputWidget = gtk_combo_box_text_new();
203 for (i = 0; i < e->enumCount; i ++) {
204 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(inputWidget), D_(cfdesc->domain, e->enumDesc[i]));
205 }
206 #else
207 inputWidget = gtk_combo_box_new_text();
208 for (i = 0; i < e->enumCount; i ++)
209 {
210 gtk_combo_box_append_text(GTK_COMBO_BOX(inputWidget), D_(cfdesc->domain, e->enumDesc[i]));
211 }
212 #endif
213 argument = inputWidget;
214 }
215 break;
216 case T_Hotkey: {
217 GtkWidget *button[2];
218 button[0] = keygrab_button_new();
219 button[1] = keygrab_button_new();
220 inputWidget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
221 gtk_box_pack_start(GTK_BOX(inputWidget), button[0], FALSE, TRUE, 0);
222 gtk_box_pack_start(GTK_BOX(inputWidget), button[1], FALSE, TRUE, 0);
223 argument = g_array_new(FALSE, FALSE, sizeof(void*));
224 g_array_append_val(argument, button[0]);
225 g_array_append_val(argument, button[1]);
226 }
227 break;
228 case T_File:
229 case T_Char:
230 case T_String:
231 inputWidget = gtk_entry_new();
232 argument = inputWidget;
233 break;
234 default:
235 break;
236 }
237
238 if (inputWidget) {
239 GtkWidget* label = gtk_label_new(s);
240 g_object_set(label, "xalign", 0.0f, NULL);
241 gtk_grid_attach(GTK_GRID(grid), label, 0, i, 1, 1);
242 gtk_grid_attach(GTK_GRID(grid), inputWidget, 1, i, 1, 1);
243 FcitxConfigBindValue(self->gconfig.configFile, cgdesc->groupName, codesc->optionName, NULL, sync_filter, argument);
244 }
245 }
246 }
247
248 FcitxConfigBindSync(&self->gconfig);
249 }
250
251 if (self->parser) {
252 GHashTable* subconfigs = self->parser->subconfigs;
253 if (g_hash_table_size(subconfigs) != 0) {
254 GtkWidget *grid = gtk_grid_new();
255 GtkWidget *plabel = gtk_label_new(_("Other"));
256 GtkWidget *scrollwnd = gtk_scrolled_window_new(NULL, NULL);
257 GtkWidget *viewport = gtk_viewport_new(NULL, NULL);
258
259 gtk_container_set_border_width(GTK_CONTAINER(grid), 4);
260 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
261 gtk_container_add(GTK_CONTAINER(scrollwnd), viewport);
262 gtk_container_add(GTK_CONTAINER(viewport), grid);
263 gtk_notebook_append_page(GTK_NOTEBOOK(configNotebook),
264 scrollwnd,
265 plabel);
266
267 HashForeachContext context;
268 context.i = 0;
269 context.grid = grid;
270 context.widget = self;
271 g_hash_table_foreach(subconfigs, hash_foreach_cb, &context);
272 }
273 }
274
275 gtk_widget_set_size_request(configNotebook, 500, -1);
276 gtk_notebook_set_scrollable(GTK_NOTEBOOK(configNotebook), TRUE);
277 }
278 FcitxConfigWidget*
279 fcitx_config_widget_new(FcitxConfigFileDesc* cfdesc, const gchar* prefix, const gchar* name, const char* subconfig)
280 {
281 FcitxConfigWidget* widget =
282 g_object_new(FCITX_TYPE_CONFIG_WIDGET,
283 "cfdesc", cfdesc,
284 "prefix", prefix,
285 "name", name,
286 "subconfig", subconfig,
287 NULL
288 );
289 fcitx_config_widget_setup_ui(widget);
290 return widget;
291 }
292
293 static void
294 fcitx_config_widget_set_property(GObject *gobject,
295 guint prop_id,
296 const GValue *value,
297 GParamSpec *pspec)
298 {
299 FcitxConfigWidget* config_widget = FCITX_CONFIG_WIDGET(gobject);
300 switch (prop_id) {
301 case PROP_CONFIG_DESC:
302 config_widget->cfdesc = g_value_get_pointer(value);
303 break;
304 case PROP_PREFIX:
305 if (config_widget->prefix)
306 g_free(config_widget->prefix);
307 config_widget->prefix = g_strdup(g_value_get_string(value));
308 break;
309 case PROP_NAME:
310 if (config_widget->name)
311 g_free(config_widget->name);
312 config_widget->name = g_strdup(g_value_get_string(value));
313 break;
314 case PROP_SUBCONFIG:
315 if (config_widget->parser)
316 sub_config_parser_free(config_widget->parser);
317 config_widget->parser = sub_config_parser_new(g_value_get_string(value));
318 break;
319 default:
320 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
321 break;
322 }
323 }
324
325 static void set_none_font_clicked(GtkWidget *button, gpointer arg)
326 {
327 gtk_font_button_set_font_name(GTK_FONT_BUTTON(arg), "");
328 }
329
330 void sync_filter(FcitxGenericConfig* gconfig, FcitxConfigGroup *group, FcitxConfigOption *option, void *value, FcitxConfigSync sync, void *arg)
331 {
332 FcitxConfigOptionDesc *codesc = option->optionDesc;
333 if (!codesc)
334 return;
335 if (sync == Raw2Value) {
336 switch (codesc->type) {
337 case T_I18NString:
338 break;
339 case T_Integer: {
340 int value = atoi(option->rawValue);
341 gtk_spin_button_set_value(GTK_SPIN_BUTTON(arg), value);
342 }
343 break;
344 case T_Color: {
345 int r = 0, g = 0, b = 0;
346 char scolor[9];
347 sscanf(option->rawValue, "%d %d %d", &r, &g, &b);
348 r = RoundColor(r);
349 g = RoundColor(g);
350 b = RoundColor(b);
351 snprintf(scolor, 8 , "#%02X%02X%02X", r, g, b);
352 GdkRGBA color;
353 gdk_rgba_parse(&color, scolor);
354 #if GTK_CHECK_VERSION(3,3,0)
355 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(arg), &color);
356 #else
357 gtk_color_button_set_rgba(GTK_COLOR_BUTTON(arg), &color);
358 #endif
359 }
360 break;
361 case T_Boolean: {
362 gboolean bl;
363 if (strcmp(option->rawValue, "True") == 0)
364 bl = TRUE;
365 else
366 bl = FALSE;
367
368 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(arg), bl);
369 }
370 break;
371 case T_Font: {
372 gtk_font_button_set_font_name(GTK_FONT_BUTTON(arg), option->rawValue);
373 }
374 break;
375 case T_Enum: {
376 FcitxConfigEnum* cenum = &codesc->configEnum;
377 int index = 0, i;
378 for (i = 0; i < cenum->enumCount; i++) {
379 if (strcmp(cenum->enumDesc[i], option->rawValue) == 0) {
380 index = i;
381 }
382 }
383 gtk_combo_box_set_active(GTK_COMBO_BOX(arg), index);
384 }
385 break;
386 case T_Hotkey: {
387 FcitxHotkey hotkey[2];
388 int j;
389 FcitxHotkeySetKey(option->rawValue, hotkey);
390 GArray *array = (GArray*) arg;
391
392 for (j = 0; j < 2; j ++) {
393 GtkWidget *button = g_array_index(array, GtkWidget*, j);
394 keygrab_button_set_key(KEYGRAB_BUTTON(button), hotkey[j].sym, hotkey[j].state);
395 if (hotkey[j].desc)
396 free(hotkey[j].desc);
397 }
398 }
399 break;
400 case T_File:
401 case T_Char:
402 case T_String: {
403 gtk_entry_set_text(GTK_ENTRY(arg), option->rawValue);
404 }
405 break;
406 }
407 } else {
408 if (codesc->type != T_I18NString && option->rawValue) {
409 free(option->rawValue);
410 option->rawValue = NULL;
411 }
412 switch (codesc->type) {
413 case T_I18NString:
414 break;
415 case T_Integer: {
416 int value;
417 value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(arg));
418 option->rawValue = g_strdup_printf("%d", value);
419 }
420 break;
421 case T_Color: {
422 int r = 0, g = 0, b = 0;
423 GdkRGBA color;
424 #if GTK_CHECK_VERSION(3,3,0)
425 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(arg), &color);
426 #else
427 gtk_color_button_get_rgba(GTK_COLOR_BUTTON(arg), &color);
428 #endif
429 r = color.red / 256;
430 g = color.green / 256;
431 b = color.blue / 256;
432 r = RoundColor(r);
433 g = RoundColor(g);
434 b = RoundColor(b);
435 option->rawValue = g_strdup_printf("%d %d %d", r, g, b);
436 }
437 break;
438 case T_Boolean: {
439 gboolean bl;
440 bl = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(arg));
441 if (bl)
442 option->rawValue = strdup("True");
443 else
444 option->rawValue = strdup("False");
445 }
446 break;
447 case T_Font: {
448 const char *font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(arg));
449 PangoFontDescription *fontdesc = pango_font_description_from_string(font);
450 if (fontdesc) {
451 const char *family = pango_font_description_get_family(fontdesc);
452 if (family)
453 option->rawValue = strdup(family);
454 else
455 option->rawValue = strdup("");
456 pango_font_description_free(fontdesc);
457 } else
458 option->rawValue = strdup("");
459 }
460 break;
461 case T_Enum: {
462 FcitxConfigEnum* cenum = &codesc->configEnum;
463 int index = 0;
464 index = gtk_combo_box_get_active(GTK_COMBO_BOX(arg));
465 option->rawValue = strdup(cenum->enumDesc[index]);
466 }
467 break;
468 case T_Hotkey: {
469 GArray *array = (GArray*) arg;
470 GtkWidget *button;
471 guint key;
472 GdkModifierType mods;
473 char *strkey[2] = { NULL, NULL };
474 int j = 0, k = 0;
475
476 for (j = 0; j < 2 ; j ++) {
477 button = g_array_index(array, GtkWidget*, j);
478 keygrab_button_get_key(KEYGRAB_BUTTON(button), &key, &mods);
479 strkey[k] = FcitxHotkeyGetKeyString(key, mods);
480 if (strkey[k])
481 k ++;
482 }
483 if (strkey[1])
484 option->rawValue = g_strdup_printf("%s %s", strkey[0], strkey[1]);
485 else if (strkey[0]) {
486 option->rawValue = strdup(strkey[0]);
487 } else
488 option->rawValue = strdup("");
489
490 for (j = 0 ; j < k ; j ++)
491 free(strkey[j]);
492
493 }
494 break;
495 case T_File:
496 case T_Char:
497 case T_String: {
498 option->rawValue = strdup(gtk_entry_get_text(GTK_ENTRY(arg)));
499 }
500 break;
501 }
502
503 }
504 }
505
506 void fcitx_config_widget_response(
507 FcitxConfigWidget* config_widget,
508 ConfigWidgetAction action
509 )
510 {
511 if (!config_widget->cfdesc)
512 return;
513
514 if (action == CONFIG_WIDGET_DEFAULT) {
515 FcitxConfigResetConfigToDefaultValue(&config_widget->gconfig);
516 FcitxConfigBindSync(&config_widget->gconfig);
517 } else if (action == CONFIG_WIDGET_SAVE) {
518 FILE* fp = FcitxXDGGetFileUserWithPrefix(config_widget->prefix, config_widget->name, "w", NULL);
519
520 if (fp) {
521 FcitxConfigSaveConfigFileFp(fp, &config_widget->gconfig, config_widget->cfdesc);
522 fclose(fp);
523
524 GError* error;
525 gchar* argv[3];
526 argv[0] = EXEC_PREFIX "/bin/fcitx-remote";
527 argv[1] = "-r";
528 argv[2] = 0;
529 g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
530 }
531 }
532 }
533
534 void fcitx_config_widget_finalize(GObject *object)
535 {
536 FcitxConfigWidget* config_widget = FCITX_CONFIG_WIDGET(object);
537 g_free(config_widget->name);
538 g_free(config_widget->prefix);
539 sub_config_parser_free(config_widget->parser);
540 G_OBJECT_CLASS(fcitx_config_widget_parent_class)->finalize(object);
541 }
542
543 void hash_foreach_cb(gpointer key,
544 gpointer value,
545 gpointer user_data)
546 {
547 HashForeachContext* context = user_data;
548 FcitxConfigWidget* widget = context->widget;
549
550 FcitxSubConfigPattern* pattern = value;
551 FcitxSubConfig* subconfig = sub_config_new(key, pattern);
552
553 if (subconfig == NULL)
554 return;
555
556 int i = context->i;
557
558 GtkWidget* label = gtk_label_new(dgettext(widget->parser->domain, subconfig->name));
559 g_object_set(label, "xalign", 0.0f, NULL);
560
561 GtkWidget *inputWidget = GTK_WIDGET(fcitx_sub_config_widget_new(subconfig));
562
563 gtk_grid_attach(GTK_GRID(context->grid), label, 0, i, 1, 1);
564 gtk_grid_attach(GTK_GRID(context->grid), inputWidget, 1, i, 1, 1);
565 context->i ++;
566 }
567
568 gboolean fcitx_config_widget_response_cb(GtkDialog *dialog,
569 gint response,
570 gpointer user_data)
571 {
572 if (response == GTK_RESPONSE_OK) {
573 FcitxConfigWidget* config_widget = (FcitxConfigWidget*) user_data;
574 fcitx_config_widget_response(config_widget, CONFIG_WIDGET_SAVE);
575 }
576 gtk_widget_destroy(GTK_WIDGET(dialog));
577 return FALSE;
578 }
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 /* fcitx-config-widget.h */
20
21 #ifndef _FCITX_CONFIG_WIDGET
22 #define _FCITX_CONFIG_WIDGET
23
24 #include <gtk/gtk.h>
25 #include <glib.h>
26 #include <fcitx-config/fcitx-config.h>
27 #include "sub_config_parser.h"
28
29 G_BEGIN_DECLS
30
31 #define FCITX_TYPE_CONFIG_WIDGET fcitx_config_widget_get_type()
32
33 #define FCITX_CONFIG_WIDGET(obj) \
34 (G_TYPE_CHECK_INSTANCE_CAST ((obj), FCITX_TYPE_CONFIG_WIDGET, FcitxConfigWidget))
35
36 #define FCITX_CONFIG_WIDGET_CLASS(klass) \
37 (G_TYPE_CHECK_CLASS_CAST ((klass), FCITX_TYPE_CONFIG_WIDGET, FcitxConfigWidgetClass))
38
39 #define FCITX_IS_CONFIG_WIDGET(obj) \
40 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FCITX_TYPE_CONFIG_WIDGET))
41
42 #define FCITX_IS_CONFIG_WIDGET_CLASS(klass) \
43 (G_TYPE_CHECK_CLASS_TYPE ((klass), FCITX_TYPE_CONFIG_WIDGET))
44
45 #define FCITX_CONFIG_WIDGET_GET_CLASS(obj) \
46 (G_TYPE_INSTANCE_GET_CLASS ((obj), FCITX_TYPE_CONFIG_WIDGET, FcitxConfigWidgetClass))
47
48 typedef struct {
49 GtkBox parent;
50 FcitxConfigFileDesc* cfdesc;
51 gchar* prefix;
52 gchar* name;
53 FcitxSubConfigParser* parser;
54 FcitxGenericConfig gconfig;
55 } FcitxConfigWidget;
56
57 typedef struct {
58 GtkBoxClass parent_class;
59 } FcitxConfigWidgetClass;
60
61 typedef enum {
62 CONFIG_WIDGET_SAVE,
63 CONFIG_WIDGET_CANCEL,
64 CONFIG_WIDGET_DEFAULT
65 } ConfigWidgetAction;
66
67 GType fcitx_config_widget_get_type(void);
68
69 FcitxConfigWidget* fcitx_config_widget_new(FcitxConfigFileDesc* cfdesc, const gchar* prefix, const gchar* name, const char* subconfig);
70
71 void fcitx_config_widget_response(FcitxConfigWidget* config_widget, ConfigWidgetAction action);
72
73 gboolean fcitx_config_widget_response_cb(GtkDialog *dialog,
74 gint response,
75 gpointer user_data);
76
77 G_END_DECLS
78
79 #endif /* _FCITX_CONFIG_WIDGET */
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include <fcitx-utils/uthash.h>
20 #include <fcitx-config/fcitx-config.h>
21 #include <fcitx-config/xdg.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24
25 #include "configdesc.h"
26
27 typedef struct ConfigDescSet {
28 char *filename;
29 FcitxConfigFileDesc *cfdesc;
30 UT_hash_handle hh;
31 } ConfigDescSet;
32
33 static ConfigDescSet* cdset = NULL;
34
35 FcitxConfigFileDesc *get_config_desc(char *filename)
36 {
37 ConfigDescSet *desc = NULL;
38 HASH_FIND_STR(cdset, filename, desc);
39 if (!desc) {
40 FILE * tmpfp = FcitxXDGGetFileWithPrefix("configdesc", filename, "r", NULL);
41 if (tmpfp) {
42 desc = malloc(sizeof(ConfigDescSet));
43 memset(desc, 0 , sizeof(ConfigDescSet));
44 desc->filename = strdup(filename);
45 desc->cfdesc = FcitxConfigParseConfigFileDescFp(tmpfp);
46 fclose(tmpfp);
47
48 HASH_ADD_KEYPTR(hh, cdset, desc->filename, strlen(desc->filename), desc);
49 } else
50 return NULL;
51 }
52
53 return desc->cfdesc;
54 }
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #ifndef CONFIG_DESC_H
20 #define CONFIG_DESC_H
21
22 #include <fcitx-config/fcitx-config.h>
23
24 FcitxConfigFileDesc *get_config_desc(char *filename);
25
26 #endif
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
1 *
2 * Copyright 2008 Red Hat, Inc,
3 * 2007 William Jon McCann <mccann@jhu.edu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 * Written by : William Jon McCann <mccann@jhu.edu>
20 * Ray Strode <rstrode@redhat.com>
21 */
22
23 #include "config.h"
24 #include "common.h"
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <dirent.h>
32 #include <locale.h>
33 #include <langinfo.h>
34 #include <sys/stat.h>
35
36 #include <glib.h>
37
38 #include "gdm-languages.h"
39
40 #include <langinfo.h>
41 #ifndef __LC_LAST
42 #define __LC_LAST 13
43 #endif
44 #include "locarchive.h"
45
46 #define ALIASES_FILE DATADIR "/gdm/locale.alias"
47 #define ARCHIVE_FILE LIBLOCALEDIR "/locale-archive"
48 #define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
49 #define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
50
51 typedef struct _GdmLocale {
52 char *id;
53 char *name;
54 char *language_code;
55 char *territory_code;
56 char *codeset;
57 char *modifier;
58 } GdmLocale;
59
60 static GHashTable *gdm_languages_map;
61 static GHashTable *gdm_territories_map;
62 static GHashTable *gdm_available_locales_map;
63
64 static char * construct_language_name(const char *language,
65 const char *territory,
66 const char *codeset,
67 const char *modifier);
68
69 static gboolean language_name_is_valid(const char *language_name);
70
71 static void
72 gdm_locale_free(GdmLocale *locale)
73 {
74 if (locale == NULL) {
75 return;
76 }
77
78 g_free(locale->id);
79 g_free(locale->name);
80 g_free(locale->codeset);
81 g_free(locale->modifier);
82 g_free(locale);
83 }
84
85 static char *
86 normalize_codeset(const char *codeset)
87 {
88 char *normalized_codeset;
89 const char *p;
90 char *q;
91
92 normalized_codeset = g_strdup(codeset);
93
94 if (codeset != NULL) {
95 for (p = codeset, q = normalized_codeset;
96 *p != '\0'; p++) {
97
98 if (*p == '-' || *p == '_') {
99 continue;
100 }
101
102 *q = g_ascii_tolower(*p);
103 q++;
104 }
105 *q = '\0';
106 }
107
108 return normalized_codeset;
109 }
110
111 /*
112 * According to http://en.wikipedia.org/wiki/Locale
113 * locale names are of the form:
114 * [language[_territory][.codeset][@modifier]]
115 */
116 void
117 gdm_parse_language_name(const char *name,
118 char **language_codep,
119 char **territory_codep,
120 char **codesetp,
121 char **modifierp)
122 {
123 GRegex *re;
124 GMatchInfo *match_info;
125 gboolean res;
126 GError *error;
127 gchar *normalized_codeset = NULL;
128 gchar *normalized_name = NULL;
129
130 match_info = NULL;
131
132 error = NULL;
133 re = g_regex_new("^(?P<language>[^_.@[:space:]]+)"
134 "(_(?P<territory>[[:upper:]]+))?"
135 "(\\.(?P<codeset>[-_0-9a-zA-Z]+))?"
136 "(@(?P<modifier>[[:ascii:]]+))?$",
137 0, 0, &error);
138 if (re == NULL) {
139 g_warning("%s", error->message);
140 goto out;
141 }
142
143 if (!g_regex_match(re, name, 0, &match_info) ||
144 g_match_info_is_partial_match(match_info)) {
145 g_warning("locale %s isn't valid\n", name);
146 goto out;
147 }
148
149 res = g_match_info_matches(match_info);
150 if (! res) {
151 g_warning("Unable to parse locale: %s", name);
152 goto out;
153 }
154
155 if (language_codep != NULL) {
156 *language_codep = g_match_info_fetch_named(match_info, "language");
157 }
158
159 if (territory_codep != NULL) {
160 *territory_codep = g_match_info_fetch_named(match_info, "territory");
161
162 if (*territory_codep != NULL &&
163 *territory_codep[0] == '\0') {
164 g_free(*territory_codep);
165 *territory_codep = NULL;
166 }
167 }
168
169 if (codesetp != NULL) {
170 *codesetp = g_match_info_fetch_named(match_info, "codeset");
171
172 if (*codesetp != NULL &&
173 *codesetp[0] == '\0') {
174 g_free(*codesetp);
175 *codesetp = NULL;
176 }
177 }
178
179 if (modifierp != NULL) {
180 *modifierp = g_match_info_fetch_named(match_info, "modifier");
181
182 if (*modifierp != NULL &&
183 *modifierp[0] == '\0') {
184 g_free(*modifierp);
185 *modifierp = NULL;
186 }
187 }
188
189 if (codesetp != NULL && *codesetp != NULL) {
190 normalized_codeset = normalize_codeset(*codesetp);
191 normalized_name = construct_language_name(language_codep ? *language_codep : NULL,
192 territory_codep ? *territory_codep : NULL,
193 normalized_codeset,
194 modifierp ? *modifierp : NULL);
195
196 if (language_name_is_valid(normalized_name)) {
197 g_free(*codesetp);
198 *codesetp = normalized_codeset;
199 } else {
200 g_free(normalized_codeset);
201 }
202 g_free(normalized_name);
203 }
204
205 out:
206 g_match_info_free(match_info);
207 g_regex_unref(re);
208 }
209
210 static char *
211 construct_language_name(const char *language,
212 const char *territory,
213 const char *codeset,
214 const char *modifier)
215 {
216 char *name;
217
218 g_assert(language[0] != 0);
219 g_assert(territory == NULL || territory[0] != 0);
220 g_assert(codeset == NULL || codeset[0] != 0);
221 g_assert(modifier == NULL || modifier[0] != 0);
222
223 name = g_strdup_printf("%s%s%s%s%s%s%s",
224 language,
225 territory != NULL ? "_" : "",
226 territory != NULL ? territory : "",
227 codeset != NULL ? "." : "",
228 codeset != NULL ? codeset : "",
229 modifier != NULL ? "@" : "",
230 modifier != NULL ? modifier : "");
231
232 return name;
233 }
234
235 char *
236 gdm_normalize_language_name(const char *name)
237 {
238 char *normalized_name;
239 char *language_code;
240 char *territory_code;
241 char *codeset;
242 char *modifier;
243
244 if (name[0] == '\0') {
245 return NULL;
246 }
247
248 gdm_parse_language_name(name,
249 &language_code,
250 &territory_code,
251 &codeset, &modifier);
252
253 normalized_name = construct_language_name(language_code,
254 territory_code,
255 codeset, modifier);
256 g_free(language_code);
257 g_free(territory_code);
258 g_free(codeset);
259 g_free(modifier);
260
261 return normalized_name;
262 }
263
264 static gboolean
265 language_name_is_valid(const char *language_name)
266 {
267 char *old_locale;
268 gboolean is_valid;
269 #ifdef WITH_INCOMPLETE_LOCALES
270 int lc_type_id = LC_CTYPE;
271 #else
272 int lc_type_id = LC_MESSAGES;
273 #endif
274
275 old_locale = g_strdup(setlocale(lc_type_id, NULL));
276 is_valid = setlocale(lc_type_id, language_name) != NULL;
277 setlocale(lc_type_id, old_locale);
278 g_free(old_locale);
279
280 return is_valid;
281 }
282
283 static void
284 language_name_get_codeset_details(const char *language_name,
285 char **pcodeset,
286 gboolean *is_utf8)
287 {
288 char *old_locale;
289 char *codeset;
290
291 old_locale = g_strdup(setlocale(LC_CTYPE, NULL));
292
293 if (setlocale(LC_CTYPE, language_name) == NULL) {
294 g_free(old_locale);
295 return;
296 }
297
298 codeset = nl_langinfo(CODESET);
299
300 if (pcodeset != NULL) {
301 *pcodeset = g_strdup(codeset);
302 }
303
304 if (is_utf8 != NULL) {
305 codeset = normalize_codeset(codeset);
306
307 *is_utf8 = strcmp(codeset, "utf8") == 0;
308 g_free(codeset);
309 }
310
311 setlocale(LC_CTYPE, old_locale);
312 g_free(old_locale);
313 }
314
315 static gboolean
316 language_name_has_translations(const char *language_name)
317 {
318 GDir *dir;
319 char *path;
320 const char *name;
321 gboolean has_translations;
322
323 path = g_build_filename(LOCALEDIR, language_name, "LC_MESSAGES", NULL);
324
325 has_translations = FALSE;
326 dir = g_dir_open(path, 0, NULL);
327 g_free(path);
328
329 if (dir == NULL) {
330 goto out;
331 }
332
333 do {
334 name = g_dir_read_name(dir);
335
336 if (name == NULL) {
337 break;
338 }
339
340 if (g_str_has_suffix(name, ".mo")) {
341 has_translations = TRUE;
342 break;
343 }
344 } while (name != NULL);
345 g_dir_close(dir);
346
347 out:
348 return has_translations;
349 }
350
351 static gboolean
352 add_locale(const char *language_name,
353 gboolean utf8_only)
354 {
355 GdmLocale *locale;
356 GdmLocale *old_locale;
357 char *name;
358 gboolean is_utf8;
359
360 g_return_val_if_fail(language_name != NULL, FALSE);
361
362 language_name_get_codeset_details(language_name, NULL, &is_utf8);
363
364 if (is_utf8) {
365 name = g_strdup(language_name);
366 } else if (utf8_only) {
367 name = g_strdup_printf("%s.utf8", language_name);
368
369 language_name_get_codeset_details(name, NULL, &is_utf8);
370 if (is_utf8) {
371 g_free(name);
372 return FALSE;
373 }
374 } else {
375 name = g_strdup(language_name);
376 }
377
378 if (!language_name_is_valid(name)) {
379 g_warning("Your locale '%s' was failed by setlocale()", name);
380 g_free(name);
381 return FALSE;
382 }
383
384 locale = g_new0(GdmLocale, 1);
385 gdm_parse_language_name(name,
386 &locale->language_code,
387 &locale->territory_code,
388 &locale->codeset,
389 &locale->modifier);
390 g_free(name);
391 name = NULL;
392
393 #ifdef WITH_INCOMPLETE_LOCALES
394 if (utf8_only) {
395 if (locale->territory_code == NULL || locale->modifier) {
396 gdm_locale_free(locale);
397 return FALSE;
398 }
399 }
400 #endif
401
402 locale->id = construct_language_name(locale->language_code, locale->territory_code,
403 NULL, locale->modifier);
404 locale->name = construct_language_name(locale->language_code, locale->territory_code,
405 locale->codeset, locale->modifier);
406
407 #ifndef WITH_INCOMPLETE_LOCALES
408 if (!language_name_has_translations(locale->name) &&
409 !language_name_has_translations(locale->id) &&
410 !language_name_has_translations(locale->language_code) &&
411 utf8_only) {
412 g_warning("Your locale '%s' doesn't have message catalog files",
413 language_name);
414 gdm_locale_free(locale);
415 return FALSE;
416 }
417 #endif
418
419 if (!utf8_only) {
420 g_free(locale->id);
421 locale->id = g_strdup(locale->name);
422 }
423
424 old_locale = g_hash_table_lookup(gdm_available_locales_map, locale->id);
425 if (old_locale != NULL) {
426 if (strlen(old_locale->name) > strlen(locale->name)) {
427 gdm_locale_free(locale);
428 return FALSE;
429 }
430 }
431
432 g_hash_table_insert(gdm_available_locales_map, g_strdup(locale->id), locale);
433
434 return TRUE;
435 }
436
437 struct nameent {
438 char *name;
439 uint32_t locrec_offset;
440 };
441
442 static gboolean
443 collect_locales_from_archive(void)
444 {
445 GMappedFile *mapped;
446 GError *error;
447 char *addr;
448 struct locarhead *head;
449 struct namehashent *namehashtab;
450 struct nameent *names;
451 uint32_t used;
452 uint32_t cnt;
453 gsize len;
454 gboolean locales_collected;
455
456 error = NULL;
457 mapped = g_mapped_file_new(ARCHIVE_FILE, FALSE, &error);
458 if (mapped == NULL) {
459 g_warning("Mapping failed for %s: %s", ARCHIVE_FILE, error->message);
460 g_error_free(error);
461 return FALSE;
462 }
463
464 locales_collected = FALSE;
465
466 addr = g_mapped_file_get_contents(mapped);
467 len = g_mapped_file_get_length(mapped);
468
469 head = (struct locarhead *) addr;
470 if (head->namehash_offset + head->namehash_size > len
471 || head->string_offset + head->string_size > len
472 || head->locrectab_offset + head->locrectab_size > len
473 || head->sumhash_offset + head->sumhash_size > len) {
474 goto out;
475 }
476
477 namehashtab = (struct namehashent *)(addr + head->namehash_offset);
478
479 names = (struct nameent *) g_new0(struct nameent, head->namehash_used);
480 for (cnt = used = 0; cnt < head->namehash_size; ++cnt) {
481 if (namehashtab[cnt].locrec_offset != 0) {
482 names[used].name = addr + namehashtab[cnt].name_offset;
483 names[used++].locrec_offset = namehashtab[cnt].locrec_offset;
484 }
485 }
486
487 for (cnt = 0; cnt < used; ++cnt) {
488 add_locale(names[cnt].name, TRUE);
489 }
490
491 g_free(names);
492
493 locales_collected = TRUE;
494 out:
495
496 g_mapped_file_unref(mapped);
497 return locales_collected;
498 }
499
500 static int
501 select_dirs(const struct dirent *dirent)
502 {
503 int result = 0;
504
505 if (strcmp(dirent->d_name, ".") != 0 && strcmp(dirent->d_name, "..") != 0) {
506 mode_t mode = 0;
507
508 #ifdef _DIRENT_HAVE_D_TYPE
509 if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK) {
510 mode = DTTOIF(dirent->d_type);
511 } else
512 #endif
513 {
514 struct stat st;
515 char *path;
516
517 path = g_build_filename(LIBLOCALEDIR, dirent->d_name, NULL);
518 if (stat(path, &st) == 0) {
519 mode = st.st_mode;
520 }
521 g_free(path);
522 }
523
524 result = S_ISDIR(mode);
525 }
526
527 return result;
528 }
529
530 static void
531 collect_locales_from_directory(void)
532 {
533 struct dirent **dirents;
534 int ndirents;
535 int cnt;
536
537 ndirents = scandir(LIBLOCALEDIR, &dirents, select_dirs, alphasort);
538
539 for (cnt = 0; cnt < ndirents; ++cnt) {
540 add_locale(dirents[cnt]->d_name, TRUE);
541 }
542
543 if (ndirents > 0) {
544 free(dirents);
545 }
546 }
547
548 static void
549 collect_locales_from_locale_file(const char *locale_file)
550 {
551 FILE *langlist;
552 char curline[256];
553 char *getsret;
554
555 if (locale_file == NULL)
556 return;
557
558 langlist = fopen(locale_file, "r");
559
560 if (langlist == NULL)
561 return;
562
563 for (;;) {
564 char *name;
565 char *lang;
566 char **lang_list;
567 int i;
568
569 getsret = fgets(curline, sizeof(curline), langlist);
570 if (getsret == NULL)
571 break;
572
573 if (curline[0] <= ' ' ||
574 curline[0] == '#')
575 continue;
576
577 name = strtok(curline, " \t\r\n");
578 if (name == NULL)
579 continue;
580
581 lang = strtok(NULL, " \t\r\n");
582 if (lang == NULL)
583 continue;
584
585 lang_list = g_strsplit(lang, ",", -1);
586 if (lang_list == NULL)
587 continue;
588
589 lang = NULL;
590 for (i = 0; lang_list[i] != NULL; i++) {
591 if (add_locale(lang_list[i], FALSE)) {
592 break;
593 }
594 }
595 g_strfreev(lang_list);
596 }
597
598 fclose(langlist);
599 }
600
601 static void
602 collect_locales(void)
603 {
604
605 if (gdm_available_locales_map == NULL) {
606 gdm_available_locales_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) gdm_locale_free);
607 }
608
609 if (!collect_locales_from_archive()) {
610 #ifndef WITH_INCOMPLETE_LOCALES
611 g_warning("Could not read list of available locales from libc, "
612 "guessing possible locales from available translations, "
613 "but list may be incomplete!");
614 #endif
615
616 collect_locales_from_directory();
617 }
618 collect_locales_from_locale_file(ALIASES_FILE);
619 }
620
621 static gboolean
622 is_fallback_language(const char *code)
623 {
624 const char *fallback_language_names[] = { "C", "POSIX", NULL };
625 int i;
626
627 for (i = 0; fallback_language_names[i] != NULL; i++) {
628 if (strcmp(code, fallback_language_names[i]) == 0) {
629 return TRUE;
630 }
631 }
632
633 return FALSE;
634 }
635
636 static const char *
637 get_language(const char *code)
638 {
639 const char *name;
640 int len;
641
642 g_assert(code != NULL);
643
644 if (is_fallback_language(code)) {
645 return "Unspecified";
646 }
647
648 len = strlen(code);
649 if (len != 2 && len != 3) {
650 return NULL;
651 }
652
653 name = (const char *) g_hash_table_lookup(gdm_languages_map, code);
654
655 return name;
656 }
657
658 static char *
659 get_first_item_in_semicolon_list(const char *list)
660 {
661 char **items;
662 char *item;
663
664 /* Some entries in iso codes have multiple values, separated
665 * by semicolons. Not really sure which one to pick, so
666 * we just arbitrarily pick the first one.
667 */
668 items = g_strsplit(list, "; ", 2);
669
670 item = g_strdup(items[0]);
671 g_strfreev(items);
672
673 return item;
674 }
675
676 static char *
677 get_translated_language(const char *code,
678 const char *locale)
679 {
680 const char *language;
681 char *name;
682
683 language = get_language(code);
684
685 name = NULL;
686 if (language != NULL) {
687 const char *translated_name;
688 char *old_locale;
689
690 if (locale != NULL) {
691 old_locale = g_strdup(setlocale(LC_MESSAGES, NULL));
692 setlocale(LC_MESSAGES, locale);
693 }
694
695 if (is_fallback_language(code)) {
696 name = g_strdup(_("Unspecified"));
697 } else {
698 translated_name = dgettext("iso_639", language);
699 name = get_first_item_in_semicolon_list(translated_name);
700 }
701
702 if (locale != NULL) {
703 setlocale(LC_MESSAGES, old_locale);
704 g_free(old_locale);
705 }
706 }
707
708 return name;
709 }
710
711 static const char *
712 get_territory(const char *code)
713 {
714 const char *name;
715 int len;
716
717 g_assert(code != NULL);
718
719 len = strlen(code);
720 if (len != 2 && len != 3) {
721 return NULL;
722 }
723
724 name = (const char *) g_hash_table_lookup(gdm_territories_map, code);
725
726 return name;
727 }
728
729 static char *
730 get_translated_territory(const char *code,
731 const char *locale)
732 {
733 const char *territory;
734 char *name;
735
736 territory = get_territory(code);
737
738 name = NULL;
739 if (territory != NULL) {
740 const char *translated_territory;
741 char *old_locale;
742
743 if (locale != NULL) {
744 old_locale = g_strdup(setlocale(LC_MESSAGES, NULL));
745 setlocale(LC_MESSAGES, locale);
746 }
747
748 translated_territory = dgettext("iso_3166", territory);
749 name = get_first_item_in_semicolon_list(translated_territory);
750
751 if (locale != NULL) {
752 setlocale(LC_MESSAGES, old_locale);
753 g_free(old_locale);
754 }
755 }
756
757 return name;
758 }
759
760 static void
761 languages_parse_start_tag(GMarkupParseContext *ctx,
762 const char *element_name,
763 const char **attr_names,
764 const char **attr_values,
765 gpointer user_data,
766 GError **error)
767 {
768 const char *ccode_longB;
769 const char *ccode_longT;
770 const char *ccode;
771 const char *lang_name;
772
773 if (! g_str_equal(element_name, "iso_639_entry") || attr_names == NULL || attr_values == NULL) {
774 return;
775 }
776
777 ccode = NULL;
778 ccode_longB = NULL;
779 ccode_longT = NULL;
780 lang_name = NULL;
781
782 while (*attr_names && *attr_values) {
783 if (g_str_equal(*attr_names, "iso_639_1_code")) {
784 /* skip if empty */
785 if (**attr_values) {
786 if (strlen(*attr_values) != 2) {
787 return;
788 }
789 ccode = *attr_values;
790 }
791 } else if (g_str_equal(*attr_names, "iso_639_2B_code")) {
792 /* skip if empty */
793 if (**attr_values) {
794 if (strlen(*attr_values) != 3) {
795 return;
796 }
797 ccode_longB = *attr_values;
798 }
799 } else if (g_str_equal(*attr_names, "iso_639_2T_code")) {
800 /* skip if empty */
801 if (**attr_values) {
802 if (strlen(*attr_values) != 3) {
803 return;
804 }
805 ccode_longT = *attr_values;
806 }
807 } else if (g_str_equal(*attr_names, "name")) {
808 lang_name = *attr_values;
809 }
810
811 ++attr_names;
812 ++attr_values;
813 }
814
815 if (lang_name == NULL) {
816 return;
817 }
818
819 if (ccode != NULL) {
820 g_hash_table_insert(gdm_languages_map,
821 g_strdup(ccode),
822 g_strdup(lang_name));
823 }
824 if (ccode_longB != NULL) {
825 g_hash_table_insert(gdm_languages_map,
826 g_strdup(ccode_longB),
827 g_strdup(lang_name));
828 }
829 if (ccode_longT != NULL) {
830 g_hash_table_insert(gdm_languages_map,
831 g_strdup(ccode_longT),
832 g_strdup(lang_name));
833 }
834 }
835
836 static void
837 territories_parse_start_tag(GMarkupParseContext *ctx,
838 const char *element_name,
839 const char **attr_names,
840 const char **attr_values,
841 gpointer user_data,
842 GError **error)
843 {
844 const char *acode_2;
845 const char *acode_3;
846 const char *ncode;
847 const char *territory_common_name;
848 const char *territory_name;
849
850 if (! g_str_equal(element_name, "iso_3166_entry") || attr_names == NULL || attr_values == NULL) {
851 return;
852 }
853
854 acode_2 = NULL;
855 acode_3 = NULL;
856 ncode = NULL;
857 territory_common_name = NULL;
858 territory_name = NULL;
859
860 while (*attr_names && *attr_values) {
861 if (g_str_equal(*attr_names, "alpha_2_code")) {
862 /* skip if empty */
863 if (**attr_values) {
864 if (strlen(*attr_values) != 2) {
865 return;
866 }
867 acode_2 = *attr_values;
868 }
869 } else if (g_str_equal(*attr_names, "alpha_3_code")) {
870 /* skip if empty */
871 if (**attr_values) {
872 if (strlen(*attr_values) != 3) {
873 return;
874 }
875 acode_3 = *attr_values;
876 }
877 } else if (g_str_equal(*attr_names, "numeric_code")) {
878 /* skip if empty */
879 if (**attr_values) {
880 if (strlen(*attr_values) != 3) {
881 return;
882 }
883 ncode = *attr_values;
884 }
885 } else if (g_str_equal(*attr_names, "common_name")) {
886 /* skip if empty */
887 if (**attr_values) {
888 territory_common_name = *attr_values;
889 }
890 } else if (g_str_equal(*attr_names, "name")) {
891 territory_name = *attr_values;
892 }
893
894 ++attr_names;
895 ++attr_values;
896 }
897
898 if (territory_common_name != NULL) {
899 territory_name = territory_common_name;
900 }
901
902 if (territory_name == NULL) {
903 return;
904 }
905
906 if (acode_2 != NULL) {
907 g_hash_table_insert(gdm_territories_map,
908 g_strdup(acode_2),
909 g_strdup(territory_name));
910 }
911 if (acode_3 != NULL) {
912 g_hash_table_insert(gdm_territories_map,
913 g_strdup(acode_3),
914 g_strdup(territory_name));
915 }
916 if (ncode != NULL) {
917 g_hash_table_insert(gdm_territories_map,
918 g_strdup(ncode),
919 g_strdup(territory_name));
920 }
921 }
922
923 static void
924 languages_init(void)
925 {
926 GError *error;
927 gboolean res;
928 char *buf;
929 gsize buf_len;
930
931 bindtextdomain("iso_639", ISO_CODES_LOCALESDIR);
932 bind_textdomain_codeset("iso_639", "UTF-8");
933
934 gdm_languages_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
935
936 error = NULL;
937 res = g_file_get_contents(ISO_CODES_DATADIR "/iso_639.xml",
938 &buf,
939 &buf_len,
940 &error);
941 if (res) {
942 GMarkupParseContext *ctx;
943 GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
944
945 ctx = g_markup_parse_context_new(&parser, 0, NULL, NULL);
946
947 error = NULL;
948 res = g_markup_parse_context_parse(ctx, buf, buf_len, &error);
949
950 if (! res) {
951 g_warning("Failed to parse '%s': %s\n",
952 ISO_CODES_DATADIR "/iso_639.xml",
953 error->message);
954 g_error_free(error);
955 }
956
957 g_markup_parse_context_free(ctx);
958 g_free(buf);
959 } else {
960 g_warning("Failed to load '%s': %s\n",
961 ISO_CODES_DATADIR "/iso_639.xml",
962 error->message);
963 g_error_free(error);
964 }
965 }
966
967 static void
968 territories_init(void)
969 {
970 GError *error;
971 gboolean res;
972 char *buf;
973 gsize buf_len;
974
975 bindtextdomain("iso_3166", ISO_CODES_LOCALESDIR);
976 bind_textdomain_codeset("iso_3166", "UTF-8");
977
978 gdm_territories_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
979
980 error = NULL;
981 res = g_file_get_contents(ISO_CODES_DATADIR "/iso_3166.xml",
982 &buf,
983 &buf_len,
984 &error);
985 if (res) {
986 GMarkupParseContext *ctx;
987 GMarkupParser parser = { territories_parse_start_tag, NULL, NULL, NULL, NULL };
988
989 ctx = g_markup_parse_context_new(&parser, 0, NULL, NULL);
990
991 error = NULL;
992 res = g_markup_parse_context_parse(ctx, buf, buf_len, &error);
993
994 if (! res) {
995 g_warning("Failed to parse '%s': %s\n",
996 ISO_CODES_DATADIR "/iso_3166.xml",
997 error->message);
998 g_error_free(error);
999 }
1000
1001 g_markup_parse_context_free(ctx);
1002 g_free(buf);
1003 } else {
1004 g_warning("Failed to load '%s': %s\n",
1005 ISO_CODES_DATADIR "/iso_3166.xml",
1006 error->message);
1007 g_error_free(error);
1008 }
1009 }
1010
1011 char *
1012 gdm_get_language_from_name(const char *name,
1013 const char *locale)
1014 {
1015 GString *full_language;
1016 char *language_code;
1017 char *territory_code;
1018 char *codeset_code;
1019 char *langinfo_codeset;
1020 char *translated_language;
1021 char *translated_territory;
1022 gboolean is_utf8 = TRUE;
1023
1024 translated_territory = NULL;
1025 translated_language = NULL;
1026 langinfo_codeset = NULL;
1027
1028 full_language = g_string_new(NULL);
1029
1030 if (gdm_languages_map == NULL) {
1031 languages_init();
1032 }
1033
1034 if (gdm_territories_map == NULL) {
1035 territories_init();
1036 }
1037
1038 language_code = NULL;
1039 territory_code = NULL;
1040 codeset_code = NULL;
1041
1042 gdm_parse_language_name(name,
1043 &language_code,
1044 &territory_code,
1045 &codeset_code,
1046 NULL);
1047
1048 if (language_code == NULL) {
1049 goto out;
1050 }
1051
1052 translated_language = get_translated_language(language_code, locale);
1053 if (translated_language == NULL) {
1054 goto out;
1055 }
1056
1057 full_language = g_string_append(full_language, translated_language);
1058
1059 if (territory_code != NULL) {
1060 translated_territory = get_translated_territory(territory_code, locale);
1061 }
1062 if (translated_territory != NULL) {
1063 g_string_append_printf(full_language,
1064 " (%s)",
1065 translated_territory);
1066 }
1067
1068 language_name_get_codeset_details(name, &langinfo_codeset, &is_utf8);
1069
1070 if (codeset_code == NULL && langinfo_codeset != NULL) {
1071 codeset_code = g_strdup(langinfo_codeset);
1072 }
1073
1074 out:
1075 g_free(language_code);
1076 g_free(territory_code);
1077 g_free(codeset_code);
1078 g_free(langinfo_codeset);
1079 g_free(translated_language);
1080 g_free(translated_territory);
1081
1082 if (full_language->len == 0) {
1083 g_string_free(full_language, TRUE);
1084 return NULL;
1085 }
1086
1087 return g_string_free(full_language, FALSE);
1088 }
1089
1090 char **
1091 gdm_get_all_language_names(void)
1092 {
1093 GHashTableIter iter;
1094 gpointer key, value;
1095 GPtrArray *array;
1096
1097 if (gdm_available_locales_map == NULL) {
1098 collect_locales();
1099 }
1100
1101 array = g_ptr_array_new();
1102 g_hash_table_iter_init(&iter, gdm_available_locales_map);
1103 while (g_hash_table_iter_next(&iter, &key, &value)) {
1104 GdmLocale *locale;
1105
1106 locale = (GdmLocale *) value;
1107
1108 g_ptr_array_add(array, g_strdup(locale->name));
1109 }
1110 g_ptr_array_add(array, NULL);
1111
1112 return (char **) g_ptr_array_free(array, FALSE);
1113 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
1 *
2 * Copyright 2008 Red Hat, Inc.
3 * Copyright 2007 William Jon McCann <mccann@jhu.edu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 * Written by: Ray Strode
20 * William Jon McCann
21 */
22
23 #ifndef __GDM_LANGUAGES_H
24 #define __GDM_LANGUAGES_H
25
26 G_BEGIN_DECLS
27
28 char * gdm_get_language_from_name(const char *name,
29 const char *locale);
30 char ** gdm_get_all_language_names(void);
31 void gdm_parse_language_name(const char *name,
32 char **language_codep,
33 char **territory_codep,
34 char **codesetp,
35 char **modifierp);
36 char * gdm_normalize_language_name(const char *name);
37
38 G_END_DECLS
39
40 #endif /* __GDM_LANGUAGE_CHOOSER_WIDGET_H */
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include <fcitx/module/dbus/dbusstuff.h>
20 #include <fcitx/module/ipc/ipc.h>
21
22
23 #include "im.h"
24
25 static const gchar introspection_xml[] =
26 "<node>"
27 " <interface name=\"org.fcitx.Fcitx.InputMethod\">"
28 " <property access=\"readwrite\" type=\"a(sssb)\" name=\"IMList\">"
29 " <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"true\"/>"
30 " </property>"
31 " </interface>"
32 "</node>";
33
34
35 enum {
36 IMLIST_CHANGED_SIGNAL,
37 LAST_SIGNAL
38 };
39
40 static guint signals[LAST_SIGNAL] = {0};
41
42
43 G_DEFINE_TYPE(FcitxInputMethod, fcitx_inputmethod, G_TYPE_DBUS_PROXY);
44
45
46 static GDBusInterfaceInfo *
47 fcitx_inputmethod_get_interface_info(void);
48 static void _fcitx_inputmethod_item_foreach_cb(gpointer data, gpointer user_data);
49
50 static GDBusInterfaceInfo *
51 fcitx_inputmethod_get_interface_info(void)
52 {
53 static gsize has_info = 0;
54 static GDBusInterfaceInfo *info = NULL;
55 if (g_once_init_enter(&has_info)) {
56 GDBusNodeInfo *introspection_data;
57 introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
58 info = introspection_data->interfaces[0];
59 g_once_init_leave(&has_info, 1);
60 }
61 return info;
62 }
63
64 static void
65 fcitx_inputmethod_finalize(GObject *object)
66 {
67 G_GNUC_UNUSED FcitxInputMethod *im = FCITX_INPUTMETHOD(object);
68
69 if (G_OBJECT_CLASS(fcitx_inputmethod_parent_class)->finalize != NULL)
70 G_OBJECT_CLASS(fcitx_inputmethod_parent_class)->finalize(object);
71 }
72
73 static void
74 fcitx_inputmethod_init(FcitxInputMethod *im)
75 {
76 /* Sets the expected interface */
77 g_dbus_proxy_set_interface_info(G_DBUS_PROXY(im), fcitx_inputmethod_get_interface_info());
78 }
79
80 GPtrArray *
81 fcitx_inputmethod_get_imlist(FcitxInputMethod* im)
82 {
83 GPtrArray *array = NULL;
84 GVariant* value;
85 GVariantIter *iter;
86 gchar *name, *unique_name, *langcode;
87 gboolean enable;
88 value = g_dbus_proxy_get_cached_property(G_DBUS_PROXY(im), "IMList");
89
90 if (value == NULL) {
91 GError* error = NULL;
92 GVariant* result = g_dbus_connection_call_sync(g_dbus_proxy_get_connection(G_DBUS_PROXY(im)),
93 g_dbus_proxy_get_name(G_DBUS_PROXY(im)),
94 FCITX_IM_DBUS_PATH,
95 "org.freedesktop.DBus.Properties",
96 "Get",
97 g_variant_new("(ss)", FCITX_IM_DBUS_INTERFACE, "IMList"),
98 G_VARIANT_TYPE("(v)"),
99 G_DBUS_CALL_FLAGS_NONE,
100 -1, /* timeout */
101 NULL,
102 &error);
103
104 if (error) {
105 g_warning("%s", error->message);
106 g_error_free(error);
107 } else if (result) {
108 g_variant_get(result, "(v)", &value);
109 }
110 }
111
112 if (value) {
113 array = g_ptr_array_new();
114 g_variant_get(value, "a(sssb)", &iter);
115 while (g_variant_iter_next(iter, "(sssb)", &name, &unique_name, &langcode, &enable, NULL)) {
116 FcitxIMItem* item = g_malloc0(sizeof(FcitxIMItem));
117 item->enable = enable;
118 item->name = strdup(name);
119 item->unique_name = strdup(unique_name);
120 item->langcode = strdup(langcode);
121 g_ptr_array_add(array, item);
122 g_free(name);
123 g_free(unique_name);
124 g_free(langcode);
125 }
126 g_variant_iter_free(iter);
127
128 g_variant_unref(value);
129 }
130
131 return array;
132 }
133
134
135 void
136 fcitx_inputmethod_set_imlist(FcitxInputMethod *im, GPtrArray* array)
137 {
138 GVariantBuilder builder;
139 g_variant_builder_init(&builder, G_VARIANT_TYPE("a(sssb)"));
140 g_ptr_array_foreach(array, _fcitx_inputmethod_item_foreach_cb, &builder);
141 GVariant* value = g_variant_builder_end(&builder);
142 GError* error = NULL;
143 GVariant* result = g_dbus_connection_call_sync(g_dbus_proxy_get_connection(G_DBUS_PROXY(im)),
144 g_dbus_proxy_get_name(G_DBUS_PROXY(im)),
145 FCITX_IM_DBUS_PATH,
146 "org.freedesktop.DBus.Properties",
147 "Set",
148 g_variant_new("(ssv)", FCITX_IM_DBUS_INTERFACE, "IMList", value),
149 G_VARIANT_TYPE_UNIT,
150 G_DBUS_CALL_FLAGS_NONE,
151 -1, /* timeout */
152 NULL,
153 &error);
154
155 if (error) {
156 g_warning("%s", error->message);
157 g_error_free(error);
158 }
159
160 g_variant_unref(result);
161 g_variant_unref(value);
162 }
163
164 static void
165 fcitx_inputmethod_g_properties_changed(GDBusProxy *proxy,
166 GVariant *changed_properties,
167 const gchar* const *invalidated_properties)
168 {
169 FcitxInputMethod *user = FCITX_INPUTMETHOD(proxy);
170 GVariantIter *iter;
171 const gchar *key;
172
173 if (changed_properties != NULL) {
174 g_variant_get(changed_properties, "a{sv}", &iter);
175 while (g_variant_iter_next(iter, "{&sv}", &key, NULL)) {
176 if (g_strcmp0(key, "IMList") == 0)
177 g_signal_emit(user, signals[IMLIST_CHANGED_SIGNAL], 0);
178 }
179 g_variant_iter_free(iter);
180 }
181
182 if (invalidated_properties != NULL) {
183 const gchar*const* item = invalidated_properties;
184 while (*item) {
185 if (g_strcmp0(*item, "IMList") == 0)
186 g_signal_emit(user, signals[IMLIST_CHANGED_SIGNAL], 0);
187 item++;
188 }
189 }
190 }
191
192 static void
193 fcitx_inputmethod_g_signal(GDBusProxy *proxy,
194 const gchar *sender_name,
195 const gchar *signal_name,
196 GVariant *parameters)
197 {
198 }
199
200 static void
201 fcitx_inputmethod_class_init(FcitxInputMethodClass *klass)
202 {
203 GObjectClass *gobject_class;
204 GDBusProxyClass *proxy_class;
205
206 gobject_class = G_OBJECT_CLASS(klass);
207 gobject_class->finalize = fcitx_inputmethod_finalize;
208
209 proxy_class = G_DBUS_PROXY_CLASS(klass);
210 proxy_class->g_signal = fcitx_inputmethod_g_signal;
211 proxy_class->g_properties_changed = fcitx_inputmethod_g_properties_changed;
212
213 signals[IMLIST_CHANGED_SIGNAL] = g_signal_new("imlist-changed",
214 FCITX_TYPE_INPUT_METHOD,
215 G_SIGNAL_RUN_LAST,
216 G_STRUCT_OFFSET(FcitxInputMethod, imlist_changed),
217 NULL,
218 NULL,
219 g_cclosure_marshal_VOID__VOID,
220 G_TYPE_NONE,
221 0);
222 }
223
224 FcitxInputMethod*
225 fcitx_inputmethod_new(GBusType bus_type,
226 GDBusProxyFlags flags,
227 int display_number,
228 GCancellable *cancellable,
229 GError **error)
230 {
231 gchar servicename[64];
232 sprintf(servicename, "%s-%d", FCITX_DBUS_SERVICE, display_number);
233
234 char* name = servicename;
235 FcitxInputMethod* im = g_initable_new(FCITX_TYPE_INPUT_METHOD,
236 cancellable,
237 error,
238 "g-flags", flags,
239 "g-name", name,
240 "g-bus-type", bus_type,
241 "g-object-path", FCITX_IM_DBUS_PATH,
242 "g-interface-name", FCITX_IM_DBUS_INTERFACE,
243 NULL);
244
245 if (im != NULL)
246 return FCITX_INPUTMETHOD(im);
247 else
248 return NULL;
249 return im;
250 }
251
252 void fcitx_inputmethod_item_free(gpointer data)
253 {
254 FcitxIMItem* item = data;
255 g_free(item->name);
256 g_free(item->unique_name);
257 g_free(item->langcode);
258 g_free(data);
259 }
260
261 void _fcitx_inputmethod_item_foreach_cb(gpointer data,
262 gpointer user_data)
263 {
264 FcitxIMItem* item = data;
265 GVariantBuilder* builder = user_data;
266
267 g_variant_builder_add(builder, "(sssb)", item->name, item->unique_name, item->langcode, item->enable);
268 }
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #ifndef _IM_H_
20 #define _IM_H_
21
22 #include <gio/gio.h>
23
24 G_BEGIN_DECLS
25
26 typedef struct _FcitxInputMethod FcitxInputMethod;
27 typedef struct _FcitxInputMethodClass FcitxInputMethodClass;
28
29 #define FCITX_TYPE_INPUT_METHOD (fcitx_inputmethod_get_type ())
30 #define FCITX_INPUTMETHOD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FCITX_TYPE_INPUT_METHOD, FcitxInputMethod))
31 #define FCITX_INPUTMETHOD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), FCITX_TYPE_INPUT_METHOD, FcitxInputMethodClass))
32 #define FCITX_INPUTMETHOD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), FCITX_TYPE_INPUT_METHOD, FcitxInputMethodClass))
33
34 struct _FcitxInputMethod {
35 GDBusProxy parent_instance;
36 void (*imlist_changed)(FcitxInputMethod* im);
37 };
38
39 struct _FcitxInputMethodClass {
40 GDBusProxyClass parent_class;
41 };
42
43 typedef struct _FcitxIMItem {
44 gchar* name;
45 gchar* unique_name;
46 gchar* langcode;
47 gboolean enable;
48 } FcitxIMItem;
49
50
51 FcitxInputMethod* fcitx_inputmethod_new(GBusType bus_type,
52 GDBusProxyFlags flags,
53 int display_number,
54 GCancellable *cancellable,
55 GError **error);
56
57 GType fcitx_inputmethod_get_type(void) G_GNUC_CONST;
58
59 GPtrArray* fcitx_inputmethod_get_imlist(FcitxInputMethod* im);
60
61 void fcitx_inputmethod_set_imlist(FcitxInputMethod* im, GPtrArray* array);
62
63 void fcitx_inputmethod_item_free(gpointer data);
64
65 G_END_DECLS
66
67 #endif
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include <fcitx-utils/utils.h>
20 #include <fcitx/module/dbus/dbusstuff.h>
21 #include <fcitx/module/ipc/ipc.h>
22
23 #include "common.h"
24 #include "im_widget.h"
25 #include "im.h"
26 #include "gdm-languages.h"
27
28 G_DEFINE_TYPE(FcitxImWidget, fcitx_im_widget, GTK_TYPE_BOX)
29
30 enum {
31 AVAIL_TREE_IM_STRING,
32 AVAIL_TREE_IM,
33 AVAIL_TREE_LANG,
34 AVAIL_N_COLUMNS
35 };
36
37 enum {
38 IM_LIST_IM_STRING,
39 IM_LIST_IM,
40 IM_N_COLUMNS
41 };
42
43 typedef struct {
44 FcitxImWidget* widget;
45 GHashTable* langTable;
46 } foreach_ct;
47
48 static void fcitx_im_widget_finalize(GObject* object);
49 static void _fcitx_im_widget_connect(FcitxImWidget* self);
50 static void _fcitx_im_widget_load(FcitxImWidget* self);
51 static void _fcitx_inputmethod_insert_foreach_cb(gpointer data, gpointer user_data);
52 static void _fcitx_im_widget_availim_selection_changed(GtkTreeSelection *selection, gpointer data);
53 static void _fcitx_im_widget_im_selection_changed(GtkTreeSelection *selection, gpointer data);
54 static void _fcitx_im_widget_addim_button_clicked(GtkButton* button, gpointer user_data);
55 static void _fcitx_im_widget_delim_button_clicked(GtkButton* button, gpointer user_data);
56 static void _fcitx_im_widget_moveup_button_clicked(GtkButton* button, gpointer user_data);
57 static void _fcitx_im_widget_movedown_button_clicked(GtkButton* button, gpointer user_data);
58 static void _fcitx_im_widget_filtertext_changed(GtkEditable *editable, gpointer user_data);
59 static void _fcitx_im_widget_onlycurlangcheckbox_toggled(GtkToggleButton *button, gpointer user_data);
60 static gboolean _fcitx_im_widget_filter_func(GtkTreeModel *model,
61 GtkTreeIter *iter,
62 gpointer data);
63 static const gchar* _get_current_lang();
64 static void icon_press_cb (GtkEntry *entry,
65 gint position,
66 GdkEventButton *event,
67 gpointer data);
68
69 static void
70 fcitx_im_widget_class_init(FcitxImWidgetClass *klass)
71 {
72 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
73 gobject_class->finalize = fcitx_im_widget_finalize;
74 }
75
76 static void
77 fcitx_im_widget_init(FcitxImWidget* self)
78 {
79 self->availimstore = gtk_tree_store_new(AVAIL_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING);
80 self->filtermodel = gtk_tree_model_filter_new(GTK_TREE_MODEL(self->availimstore), NULL);
81
82 gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(self->filtermodel),
83 (GtkTreeModelFilterVisibleFunc) _fcitx_im_widget_filter_func,
84 self ,
85 NULL);
86 self->sortmodel = gtk_tree_model_sort_new_with_model(self->filtermodel);
87 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->sortmodel), AVAIL_TREE_IM_STRING, GTK_SORT_ASCENDING);
88 self->availimview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(self->sortmodel));
89
90 GtkWidget* label = gtk_label_new(_("Available Input Method"));
91 self->filterentry = gtk_entry_new();
92 gtk_entry_set_icon_from_stock (GTK_ENTRY (self->filterentry),
93 GTK_ENTRY_ICON_SECONDARY,
94 GTK_STOCK_CLEAR);
95 #if GTK_CHECK_VERSION(3,2,0)
96 gtk_entry_set_placeholder_text(GTK_ENTRY (self->filterentry), _("Search Input Method"));
97 #endif
98
99 GtkCellRenderer* renderer;
100 GtkTreeViewColumn* column;
101 renderer = gtk_cell_renderer_text_new();
102 column = gtk_tree_view_column_new_with_attributes(
103 _("Input Method"), renderer,
104 "text", AVAIL_TREE_IM_STRING,
105 NULL);
106 gtk_tree_view_append_column(GTK_TREE_VIEW(self->availimview), column);
107
108 GtkTreeSelection *selection;
109 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->availimview));
110 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
111 g_signal_connect(G_OBJECT(selection), "changed",
112 G_CALLBACK(_fcitx_im_widget_availim_selection_changed), self);
113
114 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(self->availimview), FALSE);
115
116 self->onlycurlangcheckbox = gtk_check_button_new_with_label(_("Only Show Current Language"));
117 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->onlycurlangcheckbox), TRUE);
118
119 GtkWidget* vbox;
120 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
121 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
122 gtk_box_pack_start(GTK_BOX(vbox), self->filterentry, FALSE, TRUE, 5);
123 GtkWidget* scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
124 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
125 gtk_container_add(GTK_CONTAINER(scrolledwindow), self->availimview);
126 gtk_box_pack_start(GTK_BOX(vbox), scrolledwindow, TRUE, TRUE, 5);
127 gtk_box_pack_start(GTK_BOX(vbox), self->onlycurlangcheckbox, FALSE, TRUE, 5);
128 gtk_box_pack_start(GTK_BOX(self), vbox, TRUE, TRUE, 5);
129
130 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
131
132 self->addimbutton = gtk_button_new();
133 gtk_button_set_image(GTK_BUTTON(self->addimbutton), gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON));
134 gtk_widget_set_sensitive(self->addimbutton, FALSE);
135
136 self->delimbutton = gtk_button_new();
137 gtk_button_set_image(GTK_BUTTON(self->delimbutton), gtk_image_new_from_stock(GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON));
138 gtk_widget_set_sensitive(self->delimbutton, FALSE);
139
140 gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(""), TRUE, TRUE, 0);
141 gtk_box_pack_start(GTK_BOX(vbox), self->addimbutton, FALSE, FALSE, 0);
142 gtk_box_pack_start(GTK_BOX(vbox), self->delimbutton, FALSE, FALSE, 0);
143 gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(""), TRUE, TRUE, 0);
144
145 gtk_box_pack_start(GTK_BOX(self), vbox, FALSE, TRUE, 5);
146
147 label = gtk_label_new(_("Current Input Method"));
148
149 self->imstore = gtk_list_store_new(IM_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
150 self->imview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(self->imstore));
151
152 renderer = gtk_cell_renderer_text_new();
153 column = gtk_tree_view_column_new_with_attributes(
154 _("Input Method"), renderer,
155 "text", IM_LIST_IM_STRING,
156 NULL);
157 gtk_tree_view_append_column(GTK_TREE_VIEW(self->imview), column);
158
159 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(self->imview), FALSE);
160 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->imview));
161 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
162 g_signal_connect(G_OBJECT(selection), "changed",
163 G_CALLBACK(_fcitx_im_widget_im_selection_changed), self);
164 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
165 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
166 scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
167 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
168 gtk_container_add(GTK_CONTAINER(scrolledwindow), self->imview);
169 gtk_box_pack_start(GTK_BOX(vbox), scrolledwindow, TRUE, TRUE, 5);
170
171 gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(vbox), TRUE, TRUE, 5);
172
173 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
174
175 self->moveupbutton = gtk_button_new();
176 gtk_button_set_image(GTK_BUTTON(self->moveupbutton), gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON));
177 gtk_widget_set_sensitive(self->moveupbutton, FALSE);
178
179 self->movedownbutton = gtk_button_new();
180 gtk_button_set_image(GTK_BUTTON(self->movedownbutton), gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON));
181 gtk_widget_set_sensitive(self->movedownbutton, FALSE);
182
183 gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(""), TRUE, TRUE, 0);
184 gtk_box_pack_start(GTK_BOX(vbox), self->moveupbutton, FALSE, FALSE, 0);
185 gtk_box_pack_start(GTK_BOX(vbox), self->movedownbutton, FALSE, FALSE, 0);
186 gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(""), TRUE, TRUE, 0);
187
188 gtk_box_pack_start(GTK_BOX(self), vbox, FALSE, TRUE, 5);
189
190 g_signal_connect(G_OBJECT(self->addimbutton), "clicked", G_CALLBACK(_fcitx_im_widget_addim_button_clicked), self);
191 g_signal_connect(G_OBJECT(self->delimbutton), "clicked", G_CALLBACK(_fcitx_im_widget_delim_button_clicked), self);
192 g_signal_connect(G_OBJECT(self->moveupbutton), "clicked", G_CALLBACK(_fcitx_im_widget_moveup_button_clicked), self);
193 g_signal_connect(G_OBJECT(self->movedownbutton), "clicked", G_CALLBACK(_fcitx_im_widget_movedown_button_clicked), self);
194 g_signal_connect(G_OBJECT(self->filterentry), "changed", G_CALLBACK(_fcitx_im_widget_filtertext_changed), self);
195 g_signal_connect(G_OBJECT(self->onlycurlangcheckbox), "toggled", G_CALLBACK(_fcitx_im_widget_onlycurlangcheckbox_toggled), self);
196 g_signal_connect(G_OBJECT(self->filterentry), "icon-press", G_CALLBACK (icon_press_cb), NULL);
197
198
199 _fcitx_im_widget_connect(self);
200 }
201
202 GtkWidget*
203 fcitx_im_widget_new(void)
204 {
205 FcitxImWidget* widget =
206 g_object_new(FCITX_TYPE_IM_WIDGET,
207 NULL);
208
209 return GTK_WIDGET(widget);
210 }
211
212 void fcitx_im_widget_finalize(GObject* object)
213 {
214 FcitxImWidget* self = FCITX_IM_WIDGET(object);
215 if (self->array) {
216 g_ptr_array_set_free_func(self->array, fcitx_inputmethod_item_free);
217 g_ptr_array_free(self->array, FALSE);
218 self->array = NULL;
219 }
220 g_free(self->focus);
221 }
222
223 void _fcitx_im_widget_imlist_changed_cb(FcitxInputMethod* im, gpointer user_data)
224 {
225 FcitxImWidget* self = user_data;
226 _fcitx_im_widget_load(self);
227 }
228
229 void _fcitx_im_widget_connect(FcitxImWidget* self)
230 {
231 GError* error = NULL;
232 self->improxy = fcitx_inputmethod_new(G_BUS_TYPE_SESSION,
233 G_DBUS_PROXY_FLAGS_NONE,
234 fcitx_utils_get_display_number(),
235 NULL,
236 &error
237 );
238 if (self->improxy == NULL) {
239 g_error_free(error);
240 return;
241 }
242 g_signal_connect(self->improxy, "imlist-changed", G_CALLBACK(_fcitx_im_widget_imlist_changed_cb), self);
243
244 _fcitx_im_widget_load(self);
245 }
246
247 void _fcitx_im_widget_load(FcitxImWidget* self)
248 {
249 gtk_tree_store_clear(self->availimstore);
250 gtk_list_store_clear(self->imstore);
251
252 if (self->array) {
253 g_ptr_array_set_free_func(self->array, fcitx_inputmethod_item_free);
254 g_ptr_array_free(self->array, FALSE);
255 self->array = NULL;
256 }
257
258 self->array = fcitx_inputmethod_get_imlist(self->improxy);
259
260 if (self->array) {
261 foreach_ct ct;
262 ct.widget = self;
263 ct.langTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
264 g_ptr_array_foreach(self->array, _fcitx_inputmethod_insert_foreach_cb, &ct);
265 g_hash_table_unref(ct.langTable);
266
267 _fcitx_im_widget_im_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(self->imview)), self);
268 g_free(self->focus);
269 self->focus = NULL;
270
271 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self->onlycurlangcheckbox)))
272 gtk_tree_view_expand_all (GTK_TREE_VIEW(self->availimview));
273 }
274 }
275
276 void _fcitx_inputmethod_insert_foreach_cb(gpointer data,
277 gpointer user_data)
278 {
279 foreach_ct* ct = user_data;
280 FcitxIMItem* item = data;
281 FcitxImWidget* self = ct->widget;
282 GtkTreeIter iter;
283
284 GtkTreeIter* langIter = g_hash_table_lookup(ct->langTable, item->langcode);
285
286 if (langIter == NULL) {
287 langIter = g_new(GtkTreeIter, 1);
288 gtk_tree_store_append(self->availimstore, langIter, NULL);
289
290 char* lang = NULL;
291 if (strlen(item->langcode) != 0)
292 lang = gdm_get_language_from_name(item->langcode, NULL);
293 if (!lang) {
294 if (strcmp(item->langcode, "*") == 0)
295 lang = g_strdup_printf("%s", _("Unknown"));
296 else
297 lang = g_strdup_printf("%s", _("Unknown"));
298 }
299 gtk_tree_store_set(self->availimstore, langIter, AVAIL_TREE_IM_STRING, lang, -1);
300 gtk_tree_store_set(self->availimstore, langIter, AVAIL_TREE_LANG, item->langcode, -1);
301 gtk_tree_store_set(self->availimstore, langIter, AVAIL_TREE_IM, NULL, -1);
302 g_free(lang);
303
304 g_hash_table_insert(ct->langTable, g_strdup(item->langcode), langIter);
305 }
306
307 if (item->enable) {
308 gtk_list_store_append(self->imstore, &iter);
309 gtk_list_store_set(self->imstore, &iter, IM_LIST_IM_STRING, item->name, -1);
310 gtk_list_store_set(self->imstore, &iter, IM_LIST_IM, item, -1);
311 if (g_strcmp0(self->focus, item->unique_name) == 0) {
312 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->imview));
313 gtk_tree_selection_select_iter(selection, &iter);
314 }
315 } else {
316
317 gtk_tree_store_append(self->availimstore, &iter, langIter);
318 gtk_tree_store_set(self->availimstore, &iter, AVAIL_TREE_IM_STRING, item->name, -1);
319 gtk_tree_store_set(self->availimstore, &iter, AVAIL_TREE_LANG, NULL, -1);
320 gtk_tree_store_set(self->availimstore, &iter, AVAIL_TREE_IM, item, -1);
321 }
322
323 }
324
325 void _fcitx_im_widget_im_selection_changed(GtkTreeSelection *selection, gpointer data)
326 {
327 FcitxImWidget* self = data;
328 GtkTreeView *treeView = gtk_tree_selection_get_tree_view(selection);
329 GtkTreeModel *model = gtk_tree_view_get_model(treeView);
330 GtkTreeIter iter;
331
332 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
333 gtk_widget_set_sensitive(self->delimbutton, TRUE);
334 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
335
336 gint* ind = gtk_tree_path_get_indices(path);
337
338 gint n = gtk_tree_model_iter_n_children(model, NULL);
339
340 if (ind) {
341 gtk_widget_set_sensitive(self->moveupbutton, (*ind != 0));
342 gtk_widget_set_sensitive(self->movedownbutton, (*ind != n - 1));
343 }
344
345 gtk_tree_path_free(path);
346 } else {
347 gtk_widget_set_sensitive(self->delimbutton, FALSE);
348 }
349 }
350
351 void _fcitx_im_widget_availim_selection_changed(GtkTreeSelection* selection, gpointer data)
352 {
353 FcitxImWidget* self = data;
354 GtkTreeView *treeView = gtk_tree_selection_get_tree_view(selection);
355 GtkTreeModel *model = gtk_tree_view_get_model(treeView);
356 GtkTreeIter iter;
357
358 FcitxIMItem* item = NULL;
359 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
360 gtk_tree_model_get(model,
361 &iter,
362 AVAIL_TREE_IM, &item,
363 -1);
364 }
365 if (item) {
366 gtk_widget_set_sensitive(self->addimbutton, TRUE);
367 } else {
368 gtk_widget_set_sensitive(self->addimbutton, FALSE);
369 }
370
371 }
372
373 void _fcitx_im_widget_addim_button_clicked(GtkButton* button, gpointer user_data)
374 {
375 FcitxImWidget* self = user_data;
376 GtkWidget *treeView = self->availimview;
377 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView));
378 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->availimview));
379 GtkTreeIter iter;
380
381 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
382 FcitxIMItem* item = NULL;
383 gtk_tree_model_get(model,
384 &iter,
385 AVAIL_TREE_IM, &item,
386 -1);
387 if (item == NULL)
388 return;
389 item->enable = true;
390
391 g_ptr_array_remove(self->array, item);
392 g_ptr_array_add(self->array, item);
393
394 g_free(self->focus);
395 self->focus = g_strdup(item->unique_name);
396
397 fcitx_inputmethod_set_imlist(self->improxy, self->array);
398 }
399 }
400
401 void _fcitx_im_widget_delim_button_clicked(GtkButton* button, gpointer user_data)
402 {
403 FcitxImWidget* self = user_data;
404 GtkWidget *treeView = self->imview;
405 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView));
406 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->imview));
407 GtkTreeIter iter;
408
409 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
410 FcitxIMItem* item = NULL;
411 gtk_tree_model_get(model,
412 &iter,
413 IM_LIST_IM, &item,
414 -1);
415 item->enable = false;
416
417 fcitx_inputmethod_set_imlist(self->improxy, self->array);
418 }
419
420 }
421
422 void _fcitx_im_widget_moveup_button_clicked(GtkButton* button, gpointer user_data)
423 {
424 FcitxImWidget* self = user_data;
425 GtkWidget *treeView = self->imview;
426 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView));
427 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->imview));
428 GtkTreeIter iter;
429
430 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
431 FcitxIMItem* item = NULL;
432 gtk_tree_model_get(model,
433 &iter,
434 IM_LIST_IM, &item,
435 -1);
436
437 int i;
438 int switch_index = self->array->len;
439 for (i = 0; i < self->array->len; i += 1) {
440 if (g_ptr_array_index(self->array, i) == item)
441 break;
442
443 FcitxIMItem* temp_item = g_ptr_array_index(self->array, i);
444 if (temp_item->enable)
445 switch_index = i;
446 }
447
448 if (i != self->array->len && switch_index != self->array->len) {
449 gpointer temp = g_ptr_array_index(self->array, i);
450 g_ptr_array_index(self->array, i) = g_ptr_array_index(self->array, switch_index);
451 g_ptr_array_index(self->array, switch_index) = temp;
452 g_free(self->focus);
453 self->focus = g_strdup(item->unique_name);
454
455 fcitx_inputmethod_set_imlist(self->improxy, self->array);
456 }
457 }
458 }
459
460 void _fcitx_im_widget_movedown_button_clicked(GtkButton* button, gpointer user_data)
461 {
462 FcitxImWidget* self = user_data;
463 GtkWidget *treeView = self->imview;
464 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView));
465 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->imview));
466 GtkTreeIter iter;
467
468 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
469 FcitxIMItem* item = NULL;
470 gtk_tree_model_get(model,
471 &iter,
472 IM_LIST_IM, &item,
473 -1);
474
475 int i;
476 int switch_index = -1;
477 for (i = self->array->len - 1; i >= 0; i -= 1) {
478 if (g_ptr_array_index(self->array, i) == item)
479 break;
480
481 FcitxIMItem* temp_item = g_ptr_array_index(self->array, i);
482 if (temp_item->enable)
483 switch_index = i;
484 }
485
486 if (i != -1 && switch_index != -1) {
487 gpointer temp = g_ptr_array_index(self->array, i);
488 g_ptr_array_index(self->array, i) = g_ptr_array_index(self->array, switch_index);
489 g_ptr_array_index(self->array, switch_index) = temp;
490 g_free(self->focus);
491 self->focus = g_strdup(item->unique_name);
492
493 fcitx_inputmethod_set_imlist(self->improxy, self->array);
494 }
495 }
496 }
497
498 void _fcitx_im_widget_filtertext_changed(GtkEditable* editable, gpointer user_data)
499 {
500 FcitxImWidget* self = user_data;
501 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->filtermodel));
502 }
503
504 void _fcitx_im_widget_onlycurlangcheckbox_toggled(GtkToggleButton* button, gpointer user_data)
505 {
506 FcitxImWidget* self = user_data;
507 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->filtermodel));
508 }
509
510
511 gboolean _fcitx_im_widget_filter_func(GtkTreeModel *model,
512 GtkTreeIter *iter,
513 gpointer data)
514 {
515 FcitxImWidget* self = data;
516 const gchar* filter_text = gtk_entry_get_text(GTK_ENTRY(self->filterentry));
517 FcitxIMItem* item = NULL;
518 gtk_tree_model_get(GTK_TREE_MODEL(self->availimstore),
519 iter,
520 AVAIL_TREE_IM, &item,
521 -1);
522
523 gboolean flag = TRUE;
524 if (item) {
525 flag = flag && (strlen(filter_text) == 0
526 || strstr(item->name, filter_text)
527 || strstr(item->unique_name, filter_text)
528 || strstr(item->langcode, filter_text));
529 flag = flag && (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self->onlycurlangcheckbox)) ?
530 strncmp(item->langcode, _get_current_lang() , 2) == 0 : TRUE) ;
531 return flag;
532 } else {
533 gchar* lang = NULL;
534 gtk_tree_model_get(GTK_TREE_MODEL(self->availimstore),
535 iter,
536 AVAIL_TREE_LANG, &lang,
537 -1);
538 flag = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self->onlycurlangcheckbox)) ?
539 lang != NULL && strncmp(lang, _get_current_lang() , 2) == 0 : TRUE) ;
540 g_free(lang);
541 return flag;
542 }
543 }
544
545 static const gchar* _get_current_lang()
546 {
547 const gchar* lang = g_getenv("LC_ALL");
548 if (!lang)
549 lang = g_getenv("LANG");
550 if (!lang)
551 lang = g_getenv("LC_MESSAGES");
552 if (!lang)
553 lang = "C";
554 return lang;
555 }
556
557 static void
558 icon_press_cb (GtkEntry *entry,
559 gint position,
560 GdkEventButton *event,
561 gpointer data)
562 {
563 gtk_entry_set_text (entry, "");
564 }
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #ifndef IM_WIDGET_H
20 #define IM_WIDGET_H
21
22 #include <gtk/gtk.h>
23 #include <gio/gio.h>
24 #include "im.h"
25
26 G_BEGIN_DECLS
27
28 #define FCITX_TYPE_IM_WIDGET fcitx_im_widget_get_type()
29
30 #define FCITX_IM_WIDGET(obj) \
31 (G_TYPE_CHECK_INSTANCE_CAST ((obj), FCITX_TYPE_IM_WIDGET, FcitxImWidget))
32
33 #define FCITX_IM_WIDGET_CLASS(klass) \
34 (G_TYPE_CHECK_CLASS_CAST ((klass), FCITX_TYPE_IM_WIDGET, FcitxImWidgetClass))
35
36 #define FCITX_IS_IM_WIDGET(obj) \
37 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FCITX_TYPE_IM_WIDGET))
38
39 #define FCITX_IS_IM_WIDGET_CLASS(klass) \
40 (G_TYPE_CHECK_CLASS_TYPE ((klass), FCITX_TYPE_IM_WIDGET))
41
42 #define FCITX_IM_WIDGET_GET_CLASS(obj) \
43 (G_TYPE_INSTANCE_GET_CLASS ((obj), FCITX_TYPE_IM_WIDGET, FcitxImWidgetClass))
44
45 #define IC_NAME_MAX 64
46
47 typedef struct {
48 GtkBox parent;
49 GtkTreeStore* availimstore;
50 GtkListStore* imstore;
51 GtkWidget* availimview;
52 GtkWidget* imview;
53 GtkWidget* addimbutton;
54 GtkWidget* delimbutton;
55 GtkWidget* moveupbutton;
56 GtkWidget* movedownbutton;
57 char servicename[IC_NAME_MAX];
58 FcitxInputMethod* improxy;
59 GPtrArray* array;
60 GtkWidget* filterentry;
61 GtkTreeModel* filtermodel;
62 GtkWidget* onlycurlangcheckbox;
63 GtkTreeModel* sortmodel;
64 gchar* focus;
65 } FcitxImWidget;
66
67 typedef struct {
68 GtkBoxClass parent_class;
69 } FcitxImWidgetClass;
70
71 GtkWidget*
72 fcitx_im_widget_new(void);
73
74 G_END_DECLS
75
76
77 #endif
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include <gtk/gtk.h>
20 #include <gdk/gdkkeysyms.h>
21 #include <libintl.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include "keygrab.h"
25 #include <fcitx-config/hotkey.h>
26
27 #define _(s) gettext(s)
28 //定义枚举类型,说明信号的名称和次序
29 enum {
30 KEYGRAB_BUTTON_CHANGED,
31 KEYGRAB_BUTTON_CURRENT_CHANGED,
32 LAST_SIGNAL
33 };
34 static gint keygrab_button_signals[LAST_SIGNAL] = { 0 };
35 static void keygrab_button_init(KeyGrabButton *keygrab_button);
36 static void keygrab_button_class_init(KeyGrabButtonClass *keygrabbuttonclass);
37 static void begin_key_grab(KeyGrabButton* self, gpointer v);
38 static void end_key_grab(KeyGrabButton *self);
39 static GtkWidget* popup_new(GtkWidget* parent, const gchar* text, gboolean mouse);
40 static void on_key_press_event(GtkWidget *self, GdkEventKey *event, gpointer v);
41
42 G_DEFINE_TYPE(KeyGrabButton, keygrab_button, GTK_TYPE_BUTTON)
43
44 static void keygrab_button_init(KeyGrabButton *keygrabbutton)
45 {
46 keygrab_button_set_key(keygrabbutton, 0, 0);
47 g_signal_connect(G_OBJECT(keygrabbutton), "clicked", (GCallback) begin_key_grab, NULL);
48 }
49
50 static void keygrab_button_class_init(KeyGrabButtonClass *keygrabbuttonclass)
51 {
52 GObjectClass *object_class;
53 object_class = (GObjectClass*)keygrabbuttonclass;
54 keygrab_button_signals[KEYGRAB_BUTTON_CHANGED] = g_signal_new("changed",
55 G_TYPE_FROM_CLASS(object_class),
56 G_SIGNAL_RUN_FIRST,
57 G_STRUCT_OFFSET(KeyGrabButtonClass, changed),
58 NULL, NULL,
59 g_cclosure_marshal_VOID__VOID,
60 G_TYPE_NONE, 0, NULL);
61 keygrab_button_signals[KEYGRAB_BUTTON_CURRENT_CHANGED] = g_signal_new("current-changed",
62 G_TYPE_FROM_CLASS(object_class),
63 G_SIGNAL_RUN_FIRST,
64 G_STRUCT_OFFSET(KeyGrabButtonClass, current_changed),
65 NULL, NULL,
66 g_cclosure_marshal_VOID__VOID,
67 G_TYPE_NONE, 0, NULL);
68 }
69 //创建新的自定义控件
70 GtkWidget* keygrab_button_new(void)
71 {
72 return GTK_WIDGET(g_object_new(TYPE_KEYGRAB_BUTTON, 0));
73 }
74
75
76 void begin_key_grab(KeyGrabButton* self, gpointer v)
77 {
78 gtk_widget_add_events(GTK_WIDGET(self), GDK_KEY_PRESS_MASK);
79 KeyGrabButton* b = KEYGRAB_BUTTON(self);
80 b->popup = popup_new(GTK_WIDGET(self), _("Please press the new key combination"), FALSE);
81 gtk_widget_show_all(b->popup);
82 b->handler = g_signal_connect(G_OBJECT(b->popup), "key-press-event", (GCallback)on_key_press_event, b);
83
84 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(b->popup));
85 GdkDisplay* display = gdk_window_get_display (window);
86 GdkDeviceManager* device_manager = gdk_display_get_device_manager (display);
87 GdkDevice* pointer = gdk_device_manager_get_client_pointer (device_manager);
88 GdkDevice* keyboard = gdk_device_get_associated_device (pointer);
89
90 while (gdk_device_grab(
91 keyboard,
92 window,
93 GDK_OWNERSHIP_NONE, FALSE,
94 GDK_KEY_PRESS | GDK_KEY_RELEASE,
95 NULL,
96 GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
97 usleep(100);
98 }
99
100 void end_key_grab(KeyGrabButton *self)
101 {
102 KeyGrabButton* b = KEYGRAB_BUTTON(self);
103 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(b->popup));
104 GdkDisplay* display = gdk_window_get_display (window);
105 GdkDeviceManager* device_manager = gdk_display_get_device_manager (display);
106 GdkDevice* pointer = gdk_device_manager_get_client_pointer (device_manager);
107 GdkDevice* keyboard = gdk_device_get_associated_device (pointer);
108 gdk_device_ungrab(keyboard, gtk_get_current_event_time());
109 g_signal_handler_disconnect(b->popup, b->handler);
110 gtk_widget_destroy(b->popup);
111 }
112
113 void on_key_press_event(GtkWidget *self, GdkEventKey *event, gpointer v)
114 {
115 KeyGrabButton* b = KEYGRAB_BUTTON(v);
116 guint key;
117 GdkModifierType mods = event->state & gtk_accelerator_get_default_mod_mask();
118
119 if ((event->keyval == GDK_KEY_Escape
120 || event->keyval == GDK_KEY_Return) && !mods) {
121 if (event->keyval == GDK_KEY_Escape)
122 g_signal_emit_by_name(G_OBJECT(b), "changed", b->key, b->mods);
123 end_key_grab(b);
124 keygrab_button_set_key(b, 0, 0);
125 return;
126 }
127
128 key = gdk_keyval_to_upper(event->keyval);
129 if (key == GDK_KEY_ISO_Left_Tab)
130 key = GDK_KEY_Tab;
131
132 if (gtk_accelerator_valid(key, mods)
133 || (key == GDK_KEY_Tab && mods)) {
134 keygrab_button_set_key(b, key, mods);
135 end_key_grab(b);
136 b->key = key;
137 b->mods = mods;
138 g_signal_emit_by_name(G_OBJECT(b), "changed", b->key, b->mods);
139 return;
140 }
141
142 keygrab_button_set_key(b, key, mods);
143 }
144
145 void keygrab_button_set_key(KeyGrabButton* self, guint key, GdkModifierType mods)
146 {
147 KeyGrabButton* b = KEYGRAB_BUTTON(self);
148 gchar *label;
149 b->key = key;
150 b->mods = mods;
151
152 label = FcitxHotkeyGetKeyString(key, mods);
153
154 if (label == NULL || strlen(label) == 0) {
155 gtk_button_set_label(GTK_BUTTON(b), _("Disabled"));
156 } else {
157 gchar* lb = label;
158 gtk_button_set_label(GTK_BUTTON(b), lb);
159 }
160
161 if (label)
162 free(label);
163 }
164
165 void keygrab_button_get_key(KeyGrabButton* self, guint* key, GdkModifierType* mods)
166 {
167 if (key)
168 *key = self->key;
169 if (mods)
170 *mods = self->mods;
171 }
172
173 GtkWidget* popup_new(GtkWidget* parent, const gchar* text, gboolean mouse)
174 {
175 GtkWidget* w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
176 gtk_window_set_type_hint(GTK_WINDOW(w), GDK_WINDOW_TYPE_HINT_UTILITY);
177 gtk_window_set_position(GTK_WINDOW(w), mouse ? GTK_WIN_POS_MOUSE : GTK_WIN_POS_CENTER_ALWAYS);
178 if (parent)
179 gtk_window_set_transient_for(GTK_WINDOW(w), GTK_WINDOW(gtk_widget_get_toplevel(parent)));
180 gtk_window_set_modal(GTK_WINDOW(w), TRUE);
181 gtk_window_set_decorated(GTK_WINDOW(w), TRUE);
182 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(w), TRUE);
183 if (text) {
184 GtkWidget* label = gtk_label_new(text);
185 GtkWidget* align = gtk_alignment_new(0, 0, 1, 1);
186 gtk_alignment_set_padding(GTK_ALIGNMENT(align), 20, 20, 20, 20);
187 gtk_container_add(GTK_CONTAINER(align), label);
188 gtk_container_add(GTK_CONTAINER(w), align);
189 }
190
191 return w;
192 }
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #ifndef KEYGRAB_H
20 #define KEYGRAB_H
21
22 #include <gtk/gtk.h>
23 //定义类型宏和转换宏
24 #define TYPE_KEYGRAB_BUTTON (keygrab_button_get_type())
25 #define KEYGRAB_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,TYPE_KEYGRAB_BUTTON,KeyGrabButton))
26 //定义实例结构和类结构
27 typedef struct _KeyGrabButton KeyGrabButton;
28 typedef struct _KeyGrabButtonClass KeyGrabButtonClass;
29 struct _KeyGrabButton {
30 GtkButton parent; //父控件为横向盒状容器
31 GtkWidget* popup;
32 gulong handler;
33 guint key;
34 GdkModifierType mods;
35 };
36 struct _KeyGrabButtonClass {
37 GtkButtonClass parent_class;
38 void (*changed)(int, int);
39 void (*current_changed)(int, int);
40 };
41
42 GType keygrab_button_get_type(void);
43 GtkWidget* keygrab_button_new(void);
44 gchar *accelerator_to_fcitx_hotkey(const gchar* str);
45 void keygrab_button_set_key(KeyGrabButton* self, guint key, GdkModifierType mods);
46 void keygrab_button_get_key(KeyGrabButton* self, guint* key, GdkModifierType* mods);
47
48 #endif
0 /* Definitions for locale archive handling.
1 Copyright (C) 2002 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library 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 GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
18
19 #ifndef _LOCARCHIVE_H
20 #define _LOCARCHIVE_H 1
21
22 #include <stdint.h>
23
24 #define AR_MAGIC 0xde020109
25
26 struct locarhead {
27 uint32_t magic;
28 /* Serial number. */
29 uint32_t serial;
30 /* Name hash table. */
31 uint32_t namehash_offset;
32 uint32_t namehash_used;
33 uint32_t namehash_size;
34 /* String table. */
35 uint32_t string_offset;
36 uint32_t string_used;
37 uint32_t string_size;
38 /* Table with locale records. */
39 uint32_t locrectab_offset;
40 uint32_t locrectab_used;
41 uint32_t locrectab_size;
42 /* MD5 sum hash table. */
43 uint32_t sumhash_offset;
44 uint32_t sumhash_used;
45 uint32_t sumhash_size;
46 };
47
48
49 struct namehashent {
50 /* Hash value of the name. */
51 uint32_t hashval;
52 /* Offset of the name in the string table. */
53 uint32_t name_offset;
54 /* Offset of the locale record. */
55 uint32_t locrec_offset;
56 };
57
58
59 struct sumhashent {
60 /* MD5 sum. */
61 char sum[16];
62 /* Offset of the file in the archive. */
63 uint32_t file_offset;
64 };
65
66 struct locrecent {
67 uint32_t refs; /* # of namehashent records that point here */
68 struct {
69 uint32_t offset;
70 uint32_t len;
71 } record[__LC_LAST];
72 };
73
74
75 struct locarhandle {
76 int fd;
77 void *addr;
78 size_t len;
79 };
80
81
82 /* In memory data for the locales with their checksums. */
83 typedef struct locale_category_data {
84 off_t size;
85 void *addr;
86 char sum[16];
87 } locale_data_t[__LC_LAST];
88
89 #endif /* locarchive.h */
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include <gtk/gtk.h>
20 #include <langinfo.h>
21 #include <libintl.h>
22 #include <locale.h>
23 #include "config.h"
24 #include "main_window.h"
25
26 static void
27 fcitx_config_app_activate (GApplication *application)
28 {
29 GList* list = gtk_application_get_windows (GTK_APPLICATION(application));
30 if (list)
31 {
32 gtk_window_present (GTK_WINDOW (list->data));
33 }
34 else {
35 GtkWidget *window;
36 window = fcitx_main_window_new();
37 gtk_application_add_window(GTK_APPLICATION(application), GTK_WINDOW(window));
38 gtk_widget_show_all (GTK_WIDGET (window));
39 }
40 }
41
42 typedef GtkApplication FcitxConfigApp;
43 typedef GtkApplicationClass FcitxConfigAppClass;
44
45 G_DEFINE_TYPE (FcitxConfigApp, fcitx_config_app, GTK_TYPE_APPLICATION)
46
47 static void
48 fcitx_config_app_finalize (GObject *object)
49 {
50 G_OBJECT_CLASS (fcitx_config_app_parent_class)->finalize (object);
51 }
52
53 static void
54 fcitx_config_app_init (FcitxConfigApp *app)
55 {
56 }
57
58 static void
59 fcitx_config_app_class_init (FcitxConfigAppClass *klass)
60 {
61 G_OBJECT_CLASS (klass)->finalize= fcitx_config_app_finalize;
62
63 G_APPLICATION_CLASS (klass)->activate = fcitx_config_app_activate;
64 }
65
66 FcitxConfigApp *
67 fcitx_config_app_new (void)
68 {
69 g_type_init ();
70
71 return g_object_new (fcitx_config_app_get_type (),
72 "application-id", "org.fcitx.FcitxConfigGtk3",
73 "flags", G_APPLICATION_FLAGS_NONE,
74 NULL);
75 }
76
77 int
78 main(int argc, char **argv)
79 {
80 setlocale(LC_ALL, "");
81 bindtextdomain("fcitx-configtool", LOCALEDIR);
82 bind_textdomain_codeset("fcitx-configtool", "UTF-8");
83 bindtextdomain("fcitx", LOCALEDIR);
84 bind_textdomain_codeset("fcitx", "UTF-8");
85 textdomain("fcitx-configtool");
86
87 GtkApplication* app = fcitx_config_app_new();
88
89 int status = g_application_run (G_APPLICATION (app), argc, argv);
90 g_object_unref (app);
91
92 return status;
93 }
94
95
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include <stdlib.h>
20 #include <libintl.h>
21 #include <errno.h>
22
23 #include <fcitx/addon.h>
24 #include <fcitx-utils/utarray.h>
25 #include <fcitx-config/fcitx-config.h>
26 #include <fcitx-config/xdg.h>
27
28 #include "config.h"
29 #include "main_window.h"
30 #include "config_widget.h"
31 #include "configdesc.h"
32 #include "im_widget.h"
33
34 enum {
35 LIST_ADDON,
36 N_COLUMNS
37 };
38
39 enum {
40 PAGE_LIST_NAME,
41 PAGE_LIST_PAGE,
42 PAGE_LIST_ICON,
43 PAGE_N_COLUMNS
44 };
45
46 G_DEFINE_TYPE(FcitxMainWindow, fcitx_main_window, GTK_TYPE_WINDOW)
47
48 static void fcitx_main_window_finalize(GObject* object);
49
50 static GtkListStore *_fcitx_main_window_create_model();
51
52 static void _fcitx_main_window_add_config_file_page(FcitxMainWindow* self);
53
54 static void _fcitx_main_window_add_addon_page(FcitxMainWindow* self);
55
56 static void _fcitx_main_window_add_im_page(FcitxMainWindow* self);
57
58 static void _fcitx_main_window_selection_changed_cb(GtkIconView *iconview, gpointer data);
59
60 static ConfigPage* _fcitx_main_window_add_page(FcitxMainWindow* self, const char* name, GtkWidget* widget, const char* stock);
61
62 static void _fcitx_main_window_addon_selection_changed(GtkTreeSelection *selection, gpointer data);
63
64 static void _fcitx_main_window_configure_button_clicked(GtkButton *button, gpointer data);
65
66 static void _fcitx_main_window_enabled_data_func(GtkCellLayout *cell_layout,
67 GtkCellRenderer *renderer,
68 GtkTreeModel *tree_model,
69 GtkTreeIter *iter,
70 gpointer user_data);
71
72 static void _fcitx_main_window_name_data_func(GtkCellLayout *cell_layout,
73 GtkCellRenderer *renderer,
74 GtkTreeModel *tree_model,
75 GtkTreeIter *iter,
76 gpointer user_data);
77
78 static void _fcitx_main_window_apply_button_clicked(GtkButton *button,
79 gpointer user_data);
80
81 static void _fcitx_main_window_toggled_cb(GtkCellRenderer *renderer,
82 gchar* str_path,
83 gpointer user_data);
84
85 const UT_icd addonicd = {sizeof(FcitxAddon), 0, 0, FcitxAddonFree};
86
87 static void
88 fcitx_main_window_class_init(FcitxMainWindowClass *klass)
89 {
90 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
91 gobject_class->finalize = fcitx_main_window_finalize;
92 }
93
94 static void
95 fcitx_main_window_init(FcitxMainWindow* self)
96 {
97 GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
98 GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
99
100 self->pagestore = _fcitx_main_window_create_model();
101 self->pageview = gtk_icon_view_new_with_model(GTK_TREE_MODEL(self->pagestore));
102
103 gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(self->pageview), PAGE_LIST_ICON);
104 gtk_icon_view_set_text_column(GTK_ICON_VIEW(self->pageview), PAGE_LIST_NAME);
105 gtk_icon_view_set_item_orientation(GTK_ICON_VIEW(self->pageview), GTK_ORIENTATION_VERTICAL);
106
107 _fcitx_main_window_add_im_page(self);
108 _fcitx_main_window_add_config_file_page(self);
109 _fcitx_main_window_add_addon_page(self);
110
111 gtk_widget_set_size_request(GTK_WIDGET(self), -1, 500);
112
113 self->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
114 self->pagelabel = gtk_label_new("");
115 gtk_label_set_use_markup(GTK_LABEL(self->pagelabel), true);
116 gtk_misc_set_alignment(GTK_MISC(self->pagelabel), 0, 0.5);
117
118 gtk_box_pack_start(GTK_BOX(self->vbox), self->pagelabel, FALSE, FALSE, 14);
119 GtkWidget* scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
120 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
121 gtk_container_add(GTK_CONTAINER(scrolledwindow), self->pageview);
122 gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow, FALSE, TRUE, 4);
123 gtk_box_pack_start(GTK_BOX(hbox), self->vbox, TRUE, TRUE, 8);
124 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 8);
125
126 gtk_container_add(GTK_CONTAINER(self), vbox);
127
128 gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(self->pageview), GTK_SELECTION_SINGLE);
129 gtk_icon_view_set_item_padding(GTK_ICON_VIEW(self->pageview), 0);
130 gtk_icon_view_set_margin(GTK_ICON_VIEW(self->pageview), 0);
131 gtk_icon_view_set_column_spacing(GTK_ICON_VIEW(self->pageview), 0);
132 gtk_icon_view_set_row_spacing(GTK_ICON_VIEW(self->pageview), 0);
133 gtk_icon_view_set_item_width(GTK_ICON_VIEW(self->pageview), 96);
134
135 g_signal_connect(G_OBJECT(self->pageview), "selection-changed",
136 G_CALLBACK(_fcitx_main_window_selection_changed_cb), self);
137
138 GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(self->pagestore), &self->impage->iter);
139 gtk_icon_view_select_path(GTK_ICON_VIEW(self->pageview), path);
140 gtk_tree_path_free(path);
141
142 gtk_window_set_icon_name(GTK_WINDOW(self), "fcitx-configtool");
143 gtk_window_set_title(GTK_WINDOW(self), _("Fcitx Config"));
144 }
145
146 GtkWidget*
147 fcitx_main_window_new()
148 {
149 FcitxMainWindow* widget =
150 g_object_new(FCITX_TYPE_MAIN_WINDOW,
151 NULL);
152
153 return GTK_WIDGET(widget);
154 }
155
156 void fcitx_main_window_finalize(GObject* object)
157 {
158 FcitxMainWindow* self = FCITX_MAIN_WINDOW(object);
159 utarray_free(self->addons);
160 }
161
162 ConfigPage* _fcitx_main_window_add_page(FcitxMainWindow* self, const char* name, GtkWidget* widget, const char* stock)
163 {
164 ConfigPage *page = (ConfigPage*) malloc(sizeof(ConfigPage));
165 memset(page, 0, sizeof(ConfigPage));
166
167 page->page = widget;
168
169 g_object_ref(page->page);
170
171 gtk_widget_show_all(widget);
172
173 gtk_list_store_append(self->pagestore, &page->iter);
174 gtk_list_store_set(self->pagestore, &page->iter,
175 0, name,
176 1, page,
177 2, gtk_widget_render_icon(self->pageview, stock, GTK_ICON_SIZE_DND, NULL),
178 -1);
179
180 return page;
181 }
182
183 void _fcitx_main_window_selection_changed_cb(GtkIconView* iconview, gpointer data)
184 {
185 GtkTreeModel *model = gtk_icon_view_get_model(iconview);
186 GtkTreeIter iter;
187 ConfigPage* page;
188 FcitxMainWindow* self = data;
189
190 GList* list = gtk_icon_view_get_selected_items(iconview);
191
192 if (list) {
193 gchar* title;
194 gtk_tree_model_get_iter(GTK_TREE_MODEL(self->pagestore), &iter, (GtkTreePath*)(list->data));
195 gtk_tree_model_get(model, &iter,
196 PAGE_LIST_NAME, &title,
197 PAGE_LIST_PAGE, &page,
198 -1);
199
200 gchar* text = g_strdup_printf("<b>%s</b>", title);
201 gtk_label_set_markup(GTK_LABEL(self->pagelabel), text);
202 g_free(text);
203 g_free(title);
204
205 if (self->lastpage)
206 gtk_container_remove(GTK_CONTAINER(self->vbox), self->lastpage->page);
207 gtk_box_pack_end(GTK_BOX(self->vbox), page->page, TRUE, TRUE, 0);
208 gtk_widget_show_all(GTK_WIDGET(self));
209
210 self->lastpage = page;
211 } else {
212 GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(self->pagestore), &self->impage->iter);
213 gtk_icon_view_select_path(GTK_ICON_VIEW(self->pageview), path);
214 gtk_tree_path_free(path);
215 }
216
217 g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
218 g_list_free (list);
219 }
220
221
222 void _fcitx_main_window_addon_selection_changed(GtkTreeSelection *selection, gpointer data)
223 {
224 GtkTreeView *treeView = gtk_tree_selection_get_tree_view(selection);
225 GtkTreeModel *model = gtk_tree_view_get_model(treeView);
226 GtkTreeIter iter;
227 FcitxAddon *addon = NULL;
228 FcitxMainWindow* self = data;
229
230 if (!self->button)
231 return;
232
233 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
234 gtk_tree_model_get(model, &iter,
235 LIST_ADDON, &addon,
236 -1);
237 gchar* config_desc_name = g_strdup_printf("%s.desc", addon->name);
238 FcitxConfigFileDesc* cfdesc = get_config_desc(config_desc_name);
239 g_free(config_desc_name);
240 gboolean configurable = (gboolean)(cfdesc != NULL || strlen(addon->subconfig) != 0);
241 gtk_widget_set_sensitive(self->button, configurable);
242 } else {
243 gtk_widget_set_sensitive(self->button, FALSE);
244 }
245 }
246
247 static GtkListStore *_fcitx_main_window_create_model()
248 {
249 GtkListStore* store = gtk_list_store_new(PAGE_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_PIXBUF);
250 return store;
251 }
252
253 void _fcitx_main_window_add_config_file_page(FcitxMainWindow* self)
254 {
255 GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
256
257 FcitxConfigWidget* config_widget = fcitx_config_widget_new(
258 get_config_desc("config.desc"),
259 "",
260 "config",
261 NULL
262 );
263 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(config_widget), TRUE, TRUE, 0);
264
265 GtkWidget* hbuttonbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
266 gtk_box_pack_start(GTK_BOX(vbox), hbuttonbox, FALSE, TRUE, 0);
267
268 GtkWidget* applybutton = gtk_button_new_from_stock(GTK_STOCK_APPLY);
269 gtk_box_pack_start(GTK_BOX(hbuttonbox), applybutton, TRUE, TRUE, 0);
270 g_signal_connect(G_OBJECT(applybutton), "clicked", G_CALLBACK(_fcitx_main_window_apply_button_clicked), config_widget);
271
272
273 self->configpage = _fcitx_main_window_add_page(self, _("Global Config"), vbox, GTK_STOCK_PREFERENCES);
274 }
275
276 void _fcitx_main_window_add_im_page(FcitxMainWindow* self)
277 {
278 GtkWidget* imwidget = fcitx_im_widget_new();
279 self->impage = _fcitx_main_window_add_page(self, _("Input Method"), imwidget, GTK_STOCK_EDIT);
280 }
281
282 void _fcitx_main_window_add_addon_page(FcitxMainWindow* self)
283 {
284 FcitxAddon* addon;
285 utarray_new(self->addons, &addonicd);
286 FcitxAddonsLoad(self->addons);
287
288 GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
289
290 GtkListStore *store;
291 store = gtk_list_store_new(N_COLUMNS, G_TYPE_POINTER);
292
293 GtkWidget* swin = gtk_scrolled_window_new(NULL, NULL);
294 gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
295 g_object_set(swin, "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
296 self->addonview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
297 g_object_set(self->addonview, "headers-visible", FALSE, NULL);
298 gtk_container_add(GTK_CONTAINER(swin), self->addonview);
299 GtkCellRenderer *renderer;
300 GtkTreeViewColumn *column;
301
302 renderer = gtk_cell_renderer_toggle_new();
303 column = gtk_tree_view_column_new_with_attributes("Enable", renderer, NULL);
304 gtk_tree_view_append_column(GTK_TREE_VIEW(self->addonview), column);
305 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(column),
306 renderer,
307 _fcitx_main_window_enabled_data_func,
308 self->addonview,
309 NULL);
310 g_signal_connect(G_OBJECT(renderer), "toggled",
311 G_CALLBACK(_fcitx_main_window_toggled_cb), GTK_TREE_MODEL(store));
312
313 renderer = gtk_cell_renderer_text_new();
314 column = gtk_tree_view_column_new_with_attributes("Name", renderer, NULL);
315 gtk_tree_view_append_column(GTK_TREE_VIEW(self->addonview), column);
316 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(column),
317 renderer,
318 _fcitx_main_window_name_data_func,
319 self->addonview,
320 NULL);
321
322 gtk_tree_view_set_model(GTK_TREE_VIEW(self->addonview),
323 GTK_TREE_MODEL(store));
324
325 g_object_unref(store);
326
327 for (addon = (FcitxAddon *) utarray_front(self->addons);
328 addon != NULL;
329 addon = (FcitxAddon *) utarray_next(self->addons, addon)) {
330 GtkTreeIter iter;
331 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(self->addonview)));
332 gtk_list_store_append(store, &iter);
333 gtk_list_store_set(store, &iter, LIST_ADDON, addon, -1);
334 }
335
336 GtkWidget* hbuttonbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
337 gtk_box_pack_start(GTK_BOX(vbox), hbuttonbox, FALSE, TRUE, 0);
338
339 self->button = gtk_button_new_with_label(_("Configure"));
340 gtk_widget_set_sensitive(self->button, FALSE);
341 gtk_button_set_image(GTK_BUTTON(self->button), gtk_image_new_from_stock(GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_BUTTON));
342 gtk_box_pack_start(GTK_BOX(hbuttonbox), self->button, TRUE, TRUE, 0);
343 g_signal_connect(G_OBJECT(self->button), "clicked", G_CALLBACK(_fcitx_main_window_configure_button_clicked), self);
344
345 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->addonview));
346 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
347 g_signal_connect(G_OBJECT(selection), "changed",
348 G_CALLBACK(_fcitx_main_window_addon_selection_changed), self);
349
350 self->addonpage = _fcitx_main_window_add_page(self, _("Addon"), vbox, GTK_STOCK_ADD);
351 }
352
353 static void
354 _fcitx_main_window_toggled_cb(GtkCellRenderer *renderer,
355 gchar* str_path,
356 gpointer user_data)
357 {
358 GtkTreeModel *model = (GtkTreeModel *)user_data;
359 GtkTreePath *path = gtk_tree_path_new_from_string(str_path);
360 GtkTreeIter iter;
361 gtk_tree_model_get_iter(model, &iter, path);
362 FcitxAddon* addon = NULL;
363 gtk_tree_path_free(path);
364 gtk_tree_model_get(model,
365 &iter,
366 LIST_ADDON, &addon,
367 -1);
368
369 if (!addon)
370 return;
371
372 addon->bEnabled = !addon->bEnabled;
373 char *buf;
374 asprintf(&buf, "%s.conf", addon->name);
375 FILE* fp = FcitxXDGGetFileUserWithPrefix("addon", buf, "w", NULL);
376 free(buf);
377 if (fp) {
378 fprintf(fp, "[Addon]\nEnabled=%s\n", addon->bEnabled ? "True" : "False");
379 fclose(fp);
380 }
381 g_object_set(renderer,
382 "active", (gboolean) addon->bEnabled,
383 NULL);
384 }
385
386 static void
387 _fcitx_main_window_enabled_data_func(GtkCellLayout *cell_layout,
388 GtkCellRenderer *renderer,
389 GtkTreeModel *tree_model,
390 GtkTreeIter *iter,
391 gpointer user_data)
392 {
393 FcitxAddon* addon;
394
395 gtk_tree_model_get(tree_model,
396 iter,
397 LIST_ADDON, &addon,
398 -1);
399 g_object_set(renderer,
400 "active", (gboolean) addon->bEnabled,
401 NULL);
402 }
403
404 static void
405 _fcitx_main_window_name_data_func(GtkCellLayout *cell_layout,
406 GtkCellRenderer *renderer,
407 GtkTreeModel *tree_model,
408 GtkTreeIter *iter,
409 gpointer user_data)
410 {
411 FcitxAddon* addon;
412
413 gtk_tree_model_get(tree_model,
414 iter,
415 LIST_ADDON, &addon,
416 -1);
417 gchar* string = g_strdup_printf("%s\n%s", addon->generalname, addon->comment);
418 g_object_set(renderer,
419 "text", string,
420 NULL);
421
422 g_free(string);
423 }
424
425
426 void _fcitx_main_window_apply_button_clicked(GtkButton* button, gpointer user_data)
427 {
428 FcitxConfigWidget* config_widget = user_data;
429 fcitx_config_widget_response(config_widget, CONFIG_WIDGET_SAVE);
430 }
431
432 void _fcitx_main_window_configure_button_clicked(GtkButton* button, gpointer data)
433 {
434 FcitxMainWindow* self = data;
435 GtkTreeView* view = GTK_TREE_VIEW(self->addonview);
436 GtkTreeSelection *selection = gtk_tree_view_get_selection(view);
437 GtkTreeModel *model = gtk_tree_view_get_model(view);
438 GtkTreeIter iter;
439 FcitxAddon *addon = NULL;
440 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
441 gtk_tree_model_get(model, &iter,
442 LIST_ADDON, &addon,
443 -1);
444 gchar* config_desc_name = g_strdup_printf("%s.desc", addon->name);
445 FcitxConfigFileDesc* cfdesc = get_config_desc(config_desc_name);
446 g_free(config_desc_name);
447 gboolean configurable = (gboolean)(cfdesc != NULL || strlen(addon->subconfig) != 0);
448 if (configurable) {
449 GtkWidget* dialog = gtk_dialog_new_with_buttons(addon->generalname,
450 GTK_WINDOW(self),
451 GTK_DIALOG_MODAL,
452 GTK_STOCK_OK,
453 GTK_RESPONSE_OK,
454 GTK_STOCK_CANCEL,
455 GTK_RESPONSE_CANCEL,
456 NULL
457 );
458
459 gchar* config_file_name = g_strdup_printf("%s.config", addon->name);
460 FcitxConfigWidget* config_widget = fcitx_config_widget_new(cfdesc, "conf", config_file_name, addon->subconfig);
461 GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
462 gtk_box_pack_start(GTK_BOX(content_area), GTK_WIDGET(config_widget), TRUE, TRUE, 0);
463 g_free(config_file_name);
464 gtk_widget_set_size_request(GTK_WIDGET(config_widget), -1, 400);
465
466 g_signal_connect(dialog, "response",
467 G_CALLBACK(fcitx_config_widget_response_cb),
468 config_widget);
469
470 gtk_widget_show_all(GTK_WIDGET(dialog));
471 }
472 }
473 }
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #ifndef MAIN_WINDOW_H
20
21 #define MAIN_WINDOW_H
22
23 #include <gtk/gtk.h>
24 #include <fcitx-config/fcitx-config.h>
25
26 #include "common.h"
27
28 G_BEGIN_DECLS
29
30 #define FCITX_TYPE_MAIN_WINDOW fcitx_main_window_get_type()
31
32 #define FCITX_MAIN_WINDOW(obj) \
33 (G_TYPE_CHECK_INSTANCE_CAST ((obj), FCITX_TYPE_MAIN_WINDOW, FcitxMainWindow))
34
35 #define FCITX_MAIN_WINDOW_CLASS(klass) \
36 (G_TYPE_CHECK_CLASS_CAST ((klass), FCITX_TYPE_MAIN_WINDOW, FcitxMainWindowClass))
37
38 #define FCITX_IS_MAIN_WINDOW(obj) \
39 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FCITX_TYPE_MAIN_WINDOW))
40
41 #define FCITX_IS_MAIN_WINDOW_CLASS(klass) \
42 (G_TYPE_CHECK_CLASS_TYPE ((klass), FCITX_TYPE_MAIN_WINDOW))
43
44 #define FCITX_MAIN_WINDOW_GET_CLASS(obj) \
45 (G_TYPE_INSTANCE_GET_CLASS ((obj), FCITX_TYPE_MAIN_WINDOW, FcitxMainWindowClass))
46
47 typedef struct {
48 GtkWidget* page;
49 GtkTreeIter iter;
50 } ConfigPage;
51
52 typedef struct {
53 GtkWindow parent;
54 GtkWidget* pageview;
55 GtkListStore *pagestore;
56 GtkWidget* vbox;
57 GtkWidget* pagelabel;
58 ConfigPage* impage;
59 ConfigPage* configpage;
60 ConfigPage* lastpage;
61 ConfigPage* addonpage;
62 GtkWidget* button;
63 GtkWidget* addonview;
64 UT_array* addons;
65
66 } FcitxMainWindow;
67
68 typedef struct {
69 GtkWindowClass parent_class;
70 } FcitxMainWindowClass;
71
72 GType fcitx_main_window_get_type(void);
73
74 GtkWidget* fcitx_main_window_new(void);
75
76 #endif
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include <limits.h>
20 #include <stdlib.h>
21 #include <dirent.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <glib.h>
25
26 #include <fcitx-config/xdg.h>
27 #include <fcitx-utils/log.h>
28
29 #include "config.h"
30
31 #include "sub_config_parser.h"
32
33 static void sub_config_pattern_free(void* pattern);
34 static GList* sub_config_pattern_get_filelist(FcitxSubConfigPattern* pattern);
35 static GList* get_files_by_pattern(const gchar* dirpath, FcitxSubConfigPattern* pattern, int index);
36 static void sub_file_list_free(gpointer data, gpointer user_data);
37
38 static SubConfigType parse_type(const gchar* str);
39
40 static SubConfigType parse_type(const gchar* str)
41 {
42 if (strcmp(str, "native") == 0) {
43 return SC_NativeFile;
44 }
45 if (strcmp(str, "configfile") == 0) {
46 return SC_ConfigFile;
47 }
48 return SC_None;
49 }
50
51 FcitxSubConfigParser* sub_config_parser_new(const gchar* subconfig)
52 {
53 if (subconfig == NULL)
54 return NULL;
55
56 FcitxSubConfigParser* parser = g_malloc0(sizeof(FcitxSubConfigParser));
57 parser->subconfigs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, sub_config_pattern_free);
58 gchar** strv = g_strsplit(subconfig, ",", 0);
59
60 gchar** str;
61 for (str = &strv[0]; *str != NULL; str++) {
62 if (strchr(*str, ':') == NULL)
63 continue;
64
65 gchar** items = g_strsplit(*str, ":", 0);
66
67 if (g_strv_length(items) < 2)
68 goto end;
69 if (strlen(items[0]) == 0)
70 goto end;
71
72 if (strcmp(items[1], "domain") == 0) {
73 parser->domain = g_strdup(items[0]);
74 goto end;
75 }
76
77 SubConfigType type = parse_type(items[1]);
78 if (type == SC_None)
79 goto end;
80 if (g_hash_table_lookup(parser->subconfigs, items[0]) != NULL)
81 continue;
82
83 if (type == SC_ConfigFile) {
84 if (g_strv_length(items) != 4)
85 goto end;
86 if (strlen(items[2]) == 0 || items[2][0] == '/')
87 goto end;
88 } else if (type == SC_NativeFile) {
89 if (g_strv_length(items) != 3)
90 goto end;
91 if (strchr(items[2], '*') != NULL)
92 goto end;
93 }
94
95 gchar** paths = g_strsplit(items[2], "/", 0);
96 if (paths[0] == 0) {
97 g_strfreev(paths);
98 goto end;
99 }
100 gchar** path;
101 for (path = &paths[0]; *path != NULL; path++) {
102 if (strlen(*path) == 0)
103 break;
104 if (strcmp(*path, ".") == 0)
105 break;
106 if (strcmp(*path, "..") == 0)
107 break;
108 }
109 if (*path != NULL) {
110 g_strfreev(paths);
111 goto end;
112 }
113 FcitxSubConfigPattern* pattern = g_malloc0(sizeof(FcitxSubConfigPattern));
114 pattern->type = type;
115 pattern->patternlist = paths;
116 if (type == SC_ConfigFile)
117 pattern->configdesc = g_strdup(items[3]);
118 else if (type == SC_NativeFile)
119 pattern->nativepath = g_strdup(items[2]);
120
121 g_hash_table_insert(parser->subconfigs, g_strdup(items[0]), pattern);
122 end:
123 g_strfreev(items);
124 }
125 g_strfreev(strv);
126 if (g_hash_table_size(parser->subconfigs) == 0 || parser->domain == NULL) {
127 sub_config_parser_free(parser);
128 parser = NULL;
129 }
130
131 return parser;
132 }
133
134 void sub_config_parser_free(FcitxSubConfigParser* parser)
135 {
136 if (parser == NULL)
137 return;
138
139 g_hash_table_destroy(parser->subconfigs);
140 if (parser->domain)
141 g_free(parser->domain);
142 }
143
144 void sub_config_pattern_free(void* data)
145 {
146 FcitxSubConfigPattern* pattern = data;
147 if (pattern->patternlist)
148 g_strfreev(pattern->patternlist);
149
150 if (pattern->configdesc)
151 g_free(pattern->configdesc);
152
153 if (pattern->nativepath)
154 g_free(pattern->nativepath);
155
156 g_free(pattern);
157 }
158
159 FcitxSubConfig* sub_config_new(const gchar* name, FcitxSubConfigPattern* pattern)
160 {
161 if (pattern->type == SC_None)
162 return NULL;
163
164 FcitxSubConfig* subconfig = g_malloc0(sizeof(FcitxSubConfig));
165 subconfig->type = pattern->type;
166 subconfig->configdesc = g_strdup(pattern->configdesc);
167 subconfig->nativepath = g_strdup(pattern->nativepath);
168 subconfig->name = g_strdup(name);
169 subconfig->filelist = sub_config_pattern_get_filelist(pattern);
170
171 return subconfig;
172 }
173
174 void sub_file_list_free(gpointer data, gpointer user_data)
175 {
176 g_free(data);
177 }
178
179 void sub_config_free(FcitxSubConfig* subconfig)
180 {
181 if (!subconfig)
182 return;
183
184 g_free(subconfig->configdesc);
185 g_free(subconfig->nativepath);
186 g_free(subconfig->name);
187 g_list_foreach(subconfig->filelist, sub_file_list_free, NULL);
188 g_list_free(subconfig->filelist);
189 g_free(subconfig);
190 }
191
192 GList* sub_config_pattern_get_filelist(FcitxSubConfigPattern* pattern)
193 {
194 size_t size, i;
195 GList* result = NULL;
196 #if FCITX_CHECK_VERSION(4,2,1)
197 char** xdgpath = FcitxXDGGetPathWithPrefix(&size, "");
198 #else
199 char** xdgpath = FcitxXDGGetPath(&size, "XDG_CONFIG_HOME", ".config" , PACKAGE , DATADIR, PACKAGE);
200 #endif
201
202 for (i = 0; i < size; i ++) {
203 char* dirpath = realpath(xdgpath[i], NULL);
204
205 if (!dirpath)
206 continue;
207
208 GList* list = get_files_by_pattern(dirpath, pattern, 0), *l;
209
210 for (l = g_list_first(list);
211 l != NULL;
212 l = l->next) {
213 if (strncmp(dirpath, (gchar*) l->data, strlen(dirpath)) == 0) {
214 gchar* filename = (gchar*) l->data;
215 gchar* name = filename + strlen(dirpath);
216 while (name[0] == '/')
217 name ++;
218 result = g_list_append(result, g_strdup(name));
219 }
220 }
221 g_list_foreach(list, sub_file_list_free, NULL);
222 g_list_free(list);
223
224 free(dirpath);
225 }
226
227 FcitxXDGFreePath(xdgpath);
228
229 return result;
230 }
231
232 GList* get_files_by_pattern(const gchar* dirpath, FcitxSubConfigPattern* pattern, int index)
233 {
234 GList* result = NULL;
235
236 DIR* dir = opendir(dirpath);
237 if (!dir)
238 return result;
239
240 gchar* filter = pattern->patternlist[index];
241
242 struct dirent* drt;
243 GPatternSpec * patternspec = g_pattern_spec_new(filter);
244 while ((drt = readdir(dir)) != NULL) {
245 if (strcmp(drt->d_name , ".") == 0 || strcmp(drt->d_name, "..") == 0)
246 continue;
247
248 if (!g_pattern_match_string(patternspec, drt->d_name))
249 continue;
250
251 if (pattern->patternlist[index + 1] == 0) {
252 char *path;
253 asprintf(&path, "%s/%s", dirpath, drt->d_name);
254 struct stat statbuf;
255 if (stat(path, &statbuf) == 0) {
256 result = g_list_append(result, realpath(path, NULL));
257 }
258 free(path);
259 } else {
260 char *path;
261 asprintf(&path, "%s/%s", dirpath, drt->d_name);
262 GList* r = get_files_by_pattern(path, pattern, index + 1);
263 result = g_list_concat(result, r);
264 free(path);
265 }
266 }
267
268 closedir(dir);
269 g_pattern_spec_free(patternspec);
270 return result;
271 }
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #ifndef _SUB_CONFIG_PARSER_H
20 #define _SUB_CONFIG_PARSER_H
21 #include <glib.h>
22
23 typedef enum {
24 SC_None,
25 SC_ConfigFile,
26 SC_NativeFile
27 } SubConfigType;
28
29 typedef struct {
30 SubConfigType type;
31 gchar* configdesc;
32 gchar* nativepath;
33 gchar** patternlist;
34 } FcitxSubConfigPattern;
35
36 typedef struct {
37 gchar* name;
38 SubConfigType type;
39 GList* filelist;
40 gchar* nativepath;
41 gchar* configdesc;
42 } FcitxSubConfig;
43
44 typedef struct {
45 GHashTable* subconfigs;
46 gchar* domain;
47 } FcitxSubConfigParser;
48
49 FcitxSubConfigParser* sub_config_parser_new(const gchar* subconfig);
50 void sub_config_parser_free(FcitxSubConfigParser* parser);
51 FcitxSubConfig* sub_config_new(const gchar* name, FcitxSubConfigPattern* pattern);
52 void sub_config_free(FcitxSubConfig* subconfig);
53
54 #endif
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #include <fcitx-config/xdg.h>
20 #include <stdlib.h>
21
22 #include "sub_config_widget.h"
23 #include "main_window.h"
24 #include "configdesc.h"
25 #include "config_widget.h"
26
27 G_DEFINE_TYPE(FcitxSubConfigWidget, fcitx_sub_config_widget, GTK_TYPE_BOX)
28
29 static void open_subconfig_file(GtkButton *button, gpointer user_data);
30 static void open_native_file(GtkButton *button, gpointer user_data);
31 static void push_into_store_cb(gpointer data, gpointer user_data);
32
33 static void
34 fcitx_sub_config_widget_get_property(GObject *object, guint property_id,
35 GValue *value, GParamSpec *pspec)
36 {
37 switch (property_id) {
38 default:
39 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
40 }
41 }
42
43 static void
44 fcitx_sub_config_widget_set_property(GObject *object, guint property_id,
45 const GValue *value, GParamSpec *pspec)
46 {
47 switch (property_id) {
48 default:
49 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
50 }
51 }
52
53 static void
54 fcitx_sub_config_widget_finalize(GObject *object)
55 {
56 FcitxSubConfigWidget* widget = FCITX_SUB_CONFIG_WIDGET(object);
57 sub_config_free(widget->subconfig);
58 G_OBJECT_CLASS(fcitx_sub_config_widget_parent_class)->finalize(object);
59 }
60
61 static void
62 fcitx_sub_config_widget_class_init(FcitxSubConfigWidgetClass *klass)
63 {
64 GObjectClass *object_class = G_OBJECT_CLASS(klass);
65
66
67 object_class->get_property = fcitx_sub_config_widget_get_property;
68 object_class->set_property = fcitx_sub_config_widget_set_property;
69 object_class->finalize = fcitx_sub_config_widget_finalize;
70 }
71
72 static void
73 fcitx_sub_config_widget_init(FcitxSubConfigWidget *self)
74 {
75 }
76
77 FcitxSubConfigWidget*
78 fcitx_sub_config_widget_new(FcitxSubConfig* subconfig)
79 {
80 FcitxSubConfigWidget* widget = g_object_new(FCITX_TYPE_SUB_CONFIG_WIDGET, NULL);
81
82 widget->subconfig = subconfig;
83 switch (subconfig->type) {
84 case SC_ConfigFile: {
85 GtkWidget* view = gtk_tree_view_new();
86 gtk_box_pack_start(GTK_BOX(widget), view, FALSE, FALSE, 0);
87
88 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
89 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", 0, NULL);
90 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
91 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
92 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
93
94 GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING);
95
96 gtk_tree_view_set_model(GTK_TREE_VIEW(view),
97 GTK_TREE_MODEL(store));
98
99 g_list_foreach(widget->subconfig->filelist, push_into_store_cb, store);
100
101 GtkWidget* button = gtk_button_new();
102 gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_BUTTON));
103 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(open_subconfig_file), widget);
104 gtk_box_pack_start(GTK_BOX(widget), button, FALSE, FALSE, 0);
105 widget->view = view;
106 }
107 break;
108 case SC_NativeFile: {
109 GtkWidget* button = gtk_button_new();
110 gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON));
111 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(open_native_file), widget);
112 gtk_box_pack_start(GTK_BOX(widget), button, FALSE, FALSE, 0);
113 }
114 break;
115 default:
116 break;
117 }
118
119 return widget;
120 }
121
122 void open_subconfig_file(GtkButton *button,
123 gpointer user_data)
124 {
125 FcitxSubConfigWidget* widget = (FcitxSubConfigWidget*) user_data;
126 GtkTreeView* view = GTK_TREE_VIEW(widget->view);
127 GtkTreeSelection *selection = gtk_tree_view_get_selection(view);
128 GtkTreeModel *model = gtk_tree_view_get_model(view);
129 GtkTreeIter iter;
130 gchar* configfile;
131 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
132 gtk_tree_model_get(model, &iter,
133 0, &configfile,
134 -1);
135 FcitxConfigFileDesc* cfdesc = get_config_desc(widget->subconfig->configdesc);
136 if (cfdesc) {
137 GtkWidget* dialog = gtk_dialog_new_with_buttons(configfile,
138 GTK_WINDOW(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)),
139 GTK_DIALOG_MODAL,
140 GTK_STOCK_OK,
141 GTK_RESPONSE_OK,
142 GTK_STOCK_CANCEL,
143 GTK_RESPONSE_CANCEL,
144 NULL
145 );
146 FcitxConfigWidget* config_widget = fcitx_config_widget_new(cfdesc, "", configfile, NULL);
147 GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
148 gtk_box_pack_start(GTK_BOX(content_area), GTK_WIDGET(config_widget), TRUE, TRUE, 0);
149 gtk_widget_set_size_request(GTK_WIDGET(config_widget), -1, 400);
150
151 g_signal_connect(dialog, "response",
152 G_CALLBACK(fcitx_config_widget_response_cb),
153 config_widget);
154
155 gtk_widget_show_all(GTK_WIDGET(dialog));
156 }
157 }
158 }
159
160 void open_native_file(GtkButton *button,
161 gpointer user_data)
162 {
163 FcitxSubConfigWidget* widget = (FcitxSubConfigWidget*) user_data;
164 char *newpath = NULL;
165 if (g_list_length(widget->subconfig->filelist) > 0) {
166 FILE* fp = FcitxXDGGetFileWithPrefix("", widget->subconfig->filelist->data, "r", &newpath);
167 if (fp)
168 fclose(fp);
169 } else {
170 FILE* fp = FcitxXDGGetFileUserWithPrefix("", widget->subconfig->nativepath, "w", &newpath);
171 if (fp) {
172 widget->subconfig->filelist = g_list_append(widget->subconfig->filelist, widget->subconfig->nativepath);
173 fclose(fp);
174 }
175 }
176
177 if (newpath) {
178 GError* error;
179 gchar* filename = newpath;
180 gchar* argv[3];
181 argv[0] = "xdg-open";
182 argv[1] = filename;
183 argv[2] = 0;
184 g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
185 free(newpath);
186 }
187 }
188
189
190 void push_into_store_cb(gpointer data,
191 gpointer user_data)
192 {
193 GtkListStore* store = user_data;
194
195 GtkTreeIter iter;
196
197 gtk_list_store_append(store, &iter);
198 gtk_list_store_set(store, &iter,
199 0, data,
200 -1);
201 }
0 /***************************************************************************
1 * Copyright (C) 2010~2012 by CSSlayer *
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
17 ***************************************************************************/
18
19 #ifndef _FCITX_SUB_CONFIG_WIDGET
20 #define _FCITX_SUB_CONFIG_WIDGET
21
22 #include <gtk/gtk.h>
23 #include "sub_config_parser.h"
24
25 G_BEGIN_DECLS
26
27 #define FCITX_TYPE_SUB_CONFIG_WIDGET fcitx_sub_config_widget_get_type()
28
29 #define FCITX_SUB_CONFIG_WIDGET(obj) \
30 (G_TYPE_CHECK_INSTANCE_CAST ((obj), FCITX_TYPE_SUB_CONFIG_WIDGET, FcitxSubConfigWidget))
31
32 #define FCITX_SUB_CONFIG_WIDGET_CLASS(klass) \
33 (G_TYPE_CHECK_CLASS_CAST ((klass), FCITX_TYPE_SUB_CONFIG_WIDGET, FcitxSubConfigWidgetClass))
34
35 #define FCITX_IS_SUB_CONFIG_WIDGET(obj) \
36 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FCITX_TYPE_SUB_CONFIG_WIDGET))
37
38 #define FCITX_IS_SUB_CONFIG_WIDGET_CLASS(klass) \
39 (G_TYPE_CHECK_CLASS_TYPE ((klass), FCITX_TYPE_SUB_CONFIG_WIDGET))
40
41 #define FCITX_SUB_CONFIG_WIDGET_GET_CLASS(obj) \
42 (G_TYPE_INSTANCE_GET_CLASS ((obj), FCITX_TYPE_SUB_CONFIG_WIDGET, FcitxSubConfigWidgetClass))
43
44 typedef struct {
45 GtkBox parent;
46 FcitxSubConfig* subconfig;
47 GtkWidget* view;
48 } FcitxSubConfigWidget;
49
50 typedef struct {
51 GtkBoxClass parent_class;
52 } FcitxSubConfigWidgetClass;
53
54 GType fcitx_sub_config_widget_get_type(void);
55
56 FcitxSubConfigWidget* fcitx_sub_config_widget_new(FcitxSubConfig* subconfig);
57
58 G_END_DECLS
59
60 #endif /* _FCITX_SUB_CONFIG_WIDGET */
00 file(GLOB PO_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.po)
1 file(RELATIVE_PATH REL_SOURCE_ROOT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR})
2 if ("${REL_SOURCE_ROOT}" STREQUAL "")
3 set(REL_SOURCE_ROOT ".")
4 endif("${REL_SOURCE_ROOT}" STREQUAL "")
15
2 set(POT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/fcitx-configtool.pot)
6 set(POT_FILE fcitx-configtool.pot)
37
4 add_custom_command(
5 OUTPUT ${POT_FILE}
6 COMMAND INTLTOOL_EXTRACT=${INTLTOOL_EXTRACT} srcdir=${CMAKE_CURRENT_SOURCE_DIR} ${INTLTOOL_UPDATE} --gettext-package fcitx-configtool --pot
7 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
8 )
8 configure_file(POTFILES.in.in ${CMAKE_CURRENT_BINARY_DIR}/POTFILES.in)
9
10 add_custom_target(
11 pot
12 COMMAND INTLTOOL_EXTRACT=${INTLTOOL_EXTRACT} srcdir=${CMAKE_CURRENT_BINARY_DIR} ${INTLTOOL_UPDATE} --gettext-package fcitx-configtool --pot
13 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
14 )
915
1016 # Update .po files and compile them to binary .gmo files
1117 gettext_create_translations(${POT_FILE} ALL ${PO_FILES})
+0
-18
po/POTFILES.in less more
0 gtk/common.h
1 gtk/configdesc.c
2 gtk/configdesc.h
3 gtk/config_widget.c
4 gtk/config_widget.h
5 gtk/im.c
6 gtk/im.h
7 gtk/im_widget.c
8 gtk/im_widget.h
9 gtk/keygrab.c
10 gtk/keygrab.h
11 gtk/main.c
12 gtk/main_window.c
13 gtk/main_window.h
14 gtk/sub_config_parser.c
15 gtk/sub_config_parser.h
16 gtk/sub_config_widget.c
17 gtk/sub_config_widget.h
0 ${REL_SOURCE_ROOT}/gtk/common.h
1 ${REL_SOURCE_ROOT}/gtk/configdesc.c
2 ${REL_SOURCE_ROOT}/gtk/configdesc.h
3 ${REL_SOURCE_ROOT}/gtk/config_widget.c
4 ${REL_SOURCE_ROOT}/gtk/config_widget.h
5 ${REL_SOURCE_ROOT}/gtk/im.c
6 ${REL_SOURCE_ROOT}/gtk/im.h
7 ${REL_SOURCE_ROOT}/gtk/im_widget.c
8 ${REL_SOURCE_ROOT}/gtk/im_widget.h
9 ${REL_SOURCE_ROOT}/gtk/keygrab.c
10 ${REL_SOURCE_ROOT}/gtk/keygrab.h
11 ${REL_SOURCE_ROOT}/gtk/main.c
12 ${REL_SOURCE_ROOT}/gtk/main_window.c
13 ${REL_SOURCE_ROOT}/gtk/main_window.h
14 ${REL_SOURCE_ROOT}/gtk/sub_config_parser.c
15 ${REL_SOURCE_ROOT}/gtk/sub_config_parser.h
16 ${REL_SOURCE_ROOT}/gtk/sub_config_widget.c
17 ${REL_SOURCE_ROOT}/gtk/sub_config_widget.h
18 ${REL_SOURCE_ROOT}/gtk3/common.h
19 ${REL_SOURCE_ROOT}/gtk3/configdesc.c
20 ${REL_SOURCE_ROOT}/gtk3/configdesc.h
21 ${REL_SOURCE_ROOT}/gtk3/config_widget.c
22 ${REL_SOURCE_ROOT}/gtk3/config_widget.h
23 ${REL_SOURCE_ROOT}/gtk3/im.c
24 ${REL_SOURCE_ROOT}/gtk3/im.h
25 ${REL_SOURCE_ROOT}/gtk3/im_widget.c
26 ${REL_SOURCE_ROOT}/gtk3/im_widget.h
27 ${REL_SOURCE_ROOT}/gtk3/keygrab.c
28 ${REL_SOURCE_ROOT}/gtk3/keygrab.h
29 ${REL_SOURCE_ROOT}/gtk3/main.c
30 ${REL_SOURCE_ROOT}/gtk3/main_window.c
31 ${REL_SOURCE_ROOT}/gtk3/main_window.h
32 ${REL_SOURCE_ROOT}/gtk3/sub_config_parser.c
33 ${REL_SOURCE_ROOT}/gtk3/sub_config_parser.h
34 ${REL_SOURCE_ROOT}/gtk3/sub_config_widget.c
35 ${REL_SOURCE_ROOT}/gtk3/sub_config_widget.h
77 msgstr ""
88 "Project-Id-Version: PACKAGE VERSION\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2012-01-30 16:13+0800\n"
10 "POT-Creation-Date: 2012-03-07 02:53+0800\n"
1111 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1212 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313 "Language-Team: LANGUAGE <LL@li.org>\n"
1616 "Content-Type: text/plain; charset=CHARSET\n"
1717 "Content-Transfer-Encoding: 8bit\n"
1818
19 #: /home/saber/Develop/fcitx-config/po/../gtk/config_widget.c:188
19 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/config_widget.c:188
20 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/config_widget.c:188
2021 msgid "Clear font setting"
2122 msgstr ""
2223
23 #: /home/saber/Develop/fcitx-config/po/../gtk/config_widget.c:245
24 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/config_widget.c:253
25 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/config_widget.c:253
2426 msgid "Other"
2527 msgstr ""
2628
27 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:75
29 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:91
30 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:91
2831 msgid "Available Input Method"
2932 msgstr ""
3033
31 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:82
32 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:133
34 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:101
35 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:152
36 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:289
37 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:102
38 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:153
39 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:289
3340 msgid "Input Method"
3441 msgstr ""
3542
36 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:95
43 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:114
44 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:115
3745 msgid "Only Show Current Language"
3846 msgstr ""
3947
40 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:126
48 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:145
49 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:146
4150 msgid "Current Input Method"
4251 msgstr ""
4352
44 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:252
53 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:293
54 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:295
55 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:294
56 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:296
4557 msgid "Unknown"
4658 msgstr ""
4759
48 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:254
49 #, c-format
50 msgid "%s - %s"
51 msgstr ""
52
53 #: /home/saber/Develop/fcitx-config/po/../gtk/keygrab.c:81
60 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/keygrab.c:81
61 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/keygrab.c:81
5462 msgid "Please press the new key combination"
5563 msgstr ""
5664
57 #: /home/saber/Develop/fcitx-config/po/../gtk/keygrab.c:139
65 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/keygrab.c:139
66 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/keygrab.c:139
5867 msgid "Disabled"
5968 msgstr ""
6069
61 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:103
62 msgid "Config"
63 msgstr ""
64
65 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:138
70 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:147
71 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:147
6672 msgid "Fcitx Config"
6773 msgstr ""
6874
69 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:256
75 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:283
76 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:283
7077 msgid "Global Config"
7178 msgstr ""
7279
73 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:262
74 msgid "Input Method Configuration"
75 msgstr ""
76
77 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:322
80 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:349
81 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:349
7882 msgid "Configure"
7983 msgstr ""
8084
81 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:333
82 msgid "Addon Configuration"
85 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:360
86 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:360
87 msgid "Addon"
8388 msgstr ""
89
90 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:96
91 msgid "Search Input Method"
92 msgstr ""
66 msgstr ""
77 "Project-Id-Version: fcitx\n"
88 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2012-01-30 16:13+0800\n"
10 "PO-Revision-Date: 2012-01-27 00:32+0800\n"
11 "Last-Translator: Weng Xuetian <wengxt@gmail.com>\n"
12 "Language-Team: Chinese Simplified <fcitx-dev@googlegroups.com>\n"
9 "POT-Creation-Date: 2012-03-07 02:53+0800\n"
10 "PO-Revision-Date: 2012-03-07 02:53+0800\n"
11 "Last-Translator: Xuetian Weng <wengxt@gmail.com>\n"
12 "Language-Team: Chinese Simplified <kde-i18n-doc@kde.org>\n"
1313 "Language: zh_CN\n"
1414 "MIME-Version: 1.0\n"
1515 "Content-Type: text/plain; charset=UTF-8\n"
1717 "Plural-Forms: nplurals=1; plural=0\n"
1818 "X-Generator: Lokalize 1.4\n"
1919
20 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:254
21 #, c-format
22 msgid "%s - %s"
23 msgstr "%s - %s"
20 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:360
21 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:360
22 msgid "Addon"
23 msgstr "附加组件"
2424
25 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:333
26 msgid "Addon Configuration"
27 msgstr "附加组件配置"
28
29 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:75
25 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:91
26 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:91
3027 msgid "Available Input Method"
3128 msgstr "可用的输入法"
3229
33 #: /home/saber/Develop/fcitx-config/po/../gtk/config_widget.c:188
30 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/config_widget.c:188
31 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/config_widget.c:188
3432 msgid "Clear font setting"
3533 msgstr "清除字体设置"
3634
37 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:103
38 msgid "Config"
39 msgstr "配置"
40
41 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:322
35 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:349
36 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:349
4237 msgid "Configure"
4338 msgstr "配置 "
4439
45 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:126
40 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:145
41 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:146
4642 msgid "Current Input Method"
4743 msgstr "当前的输入法"
4844
49 #: /home/saber/Develop/fcitx-config/po/../gtk/keygrab.c:139
45 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/keygrab.c:139
46 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/keygrab.c:139
5047 msgid "Disabled"
5148 msgstr "禁用"
5249
53 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:138
50 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:147
51 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:147
5452 msgid "Fcitx Config"
5553 msgstr "Fcitx配置"
5654
57 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:256
55 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:283
56 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:283
5857 msgid "Global Config"
5958 msgstr "全局配置"
6059
61 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:82
62 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:133
60 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:101
61 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:152
62 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:289
63 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:102
64 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:153
65 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:289
6366 msgid "Input Method"
6467 msgstr "输入法"
6568
66 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:262
67 msgid "Input Method Configuration"
68 msgstr "输入法配置"
69
70 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:95
69 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:114
70 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:115
7171 msgid "Only Show Current Language"
7272 msgstr "仅显示当前语言"
7373
74 #: /home/saber/Develop/fcitx-config/po/../gtk/config_widget.c:245
74 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/config_widget.c:253
75 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/config_widget.c:253
7576 msgid "Other"
7677 msgstr "其他"
7778
78 #: /home/saber/Develop/fcitx-config/po/../gtk/keygrab.c:81
79 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/keygrab.c:81
80 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/keygrab.c:81
7981 msgid "Please press the new key combination"
8082 msgstr "请按下新按键组合"
8183
82 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:252
84 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:96
85 msgid "Search Input Method"
86 msgstr "搜索输入法"
87
88 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:293
89 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:295
90 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:294
91 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:296
8392 msgid "Unknown"
8493 msgstr "未知"
94
95 #~ msgid "Addon Configuration"
96 #~ msgstr "附加组件配置"
97
98 #~ msgid "Config"
99 #~ msgstr "配置"
100
101 #~ msgid "Input Method Configuration"
102 #~ msgstr "输入法配置"
103
104 #~ msgid "Multilingual"
105 #~ msgstr "多语言"
0 # SOME DESCRIPTIVE TITLE.
10 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
21 # This file is distributed under the same license as the PACKAGE package.
32 #
43 # Translators:
4 # Weng Xuetian <wengxt@gmail.com>, 2012.
55 msgid ""
66 msgstr ""
77 "Project-Id-Version: fcitx\n"
88 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2012-01-30 16:13+0800\n"
10 "PO-Revision-Date: 2011-11-16 06:53+0000\n"
11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Language-Team: Chinese (Taiwan) (http://www.transifex.net/projects/p/fcitx/"
13 "team/zh_TW/)\n"
9 "POT-Creation-Date: 2012-03-07 02:53+0800\n"
10 "PO-Revision-Date: 2012-03-07 02:55+0800\n"
11 "Last-Translator: Xuetian Weng <wengxt@gmail.com>\n"
12 "Language-Team: Chinese Simplified <kde-i18n-doc@kde.org>\n"
1413 "Language: zh_TW\n"
1514 "MIME-Version: 1.0\n"
1615 "Content-Type: text/plain; charset=UTF-8\n"
1716 "Content-Transfer-Encoding: 8bit\n"
17 "team/zh_TW/)\n"
1818 "Plural-Forms: nplurals=1; plural=0\n"
19 "X-Generator: Lokalize 1.4\n"
1920
20 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:254
21 #, c-format
22 msgid "%s - %s"
23 msgstr ""
21 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:360
22 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:360
23 msgid "Addon"
24 msgstr "附加元件"
2425
25 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:333
26 msgid "Addon Configuration"
27 msgstr ""
26 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:91
27 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:91
28 msgid "Available Input Method"
29 msgstr "可用輸入法"
2830
29 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:75
30 msgid "Available Input Method"
31 msgstr ""
31 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/config_widget.c:188
32 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/config_widget.c:188
33 msgid "Clear font setting"
34 msgstr "清除字體設定"
3235
33 #: /home/saber/Develop/fcitx-config/po/../gtk/config_widget.c:188
34 msgid "Clear font setting"
35 msgstr ""
36 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:349
37 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:349
38 msgid "Configure"
39 msgstr "設定"
3640
37 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:103
38 msgid "Config"
39 msgstr ""
41 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:145
42 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:146
43 msgid "Current Input Method"
44 msgstr "目前輸入法"
4045
41 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:322
42 msgid "Configure"
43 msgstr ""
46 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/keygrab.c:139
47 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/keygrab.c:139
48 msgid "Disabled"
49 msgstr "禁用"
4450
45 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:126
46 msgid "Current Input Method"
47 msgstr ""
51 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:147
52 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:147
53 msgid "Fcitx Config"
54 msgstr "Fcitx 設定"
4855
49 #: /home/saber/Develop/fcitx-config/po/../gtk/keygrab.c:139
50 msgid "Disabled"
51 msgstr ""
56 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:283
57 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:283
58 msgid "Global Config"
59 msgstr "全局設定"
5260
53 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:138
54 msgid "Fcitx Config"
55 msgstr ""
61 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:101
62 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:152
63 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/main_window.c:289
64 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:102
65 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:153
66 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/main_window.c:289
67 msgid "Input Method"
68 msgstr "輸入法"
5669
57 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:256
58 msgid "Global Config"
59 msgstr ""
70 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:114
71 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:115
72 msgid "Only Show Current Language"
73 msgstr "僅顯示当前語言"
6074
61 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:82
62 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:133
63 msgid "Input Method"
64 msgstr ""
75 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/config_widget.c:253
76 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/config_widget.c:253
77 msgid "Other"
78 msgstr "其他"
6579
66 #: /home/saber/Develop/fcitx-config/po/../gtk/main_window.c:262
67 msgid "Input Method Configuration"
68 msgstr ""
80 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/keygrab.c:81
81 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/keygrab.c:81
82 msgid "Please press the new key combination"
83 msgstr "請按下新按鍵組合"
6984
70 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:95
71 msgid "Only Show Current Language"
72 msgstr ""
85 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:96
86 msgid "Search Input Method"
87 msgstr "搜尋輸入法"
7388
74 #: /home/saber/Develop/fcitx-config/po/../gtk/config_widget.c:245
75 msgid "Other"
76 msgstr ""
89 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:293
90 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk/im_widget.c:295
91 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:294
92 #: /home/saber/Develop/fcitx-config/build/po/../..//gtk3/im_widget.c:296
93 msgid "Unknown"
94 msgstr "未知"
7795
78 #: /home/saber/Develop/fcitx-config/po/../gtk/keygrab.c:81
79 msgid "Please press the new key combination"
80 msgstr ""
81
82 #: /home/saber/Develop/fcitx-config/po/../gtk/im_widget.c:252
83 msgid "Unknown"
84 msgstr ""
96 #~ msgid "Multilingual"
97 #~ msgstr "多語言"