1 /*-
2 * Copyright (C) 2012 Nick Schermer <nick@xfce.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #ifdef HAVE_MEMORY_H
23 #include <memory.h>
24 #endif
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #endif
28
29 #include <libxfce4util/libxfce4util.h>
30
31 #include <terminal/terminal-encoding-action.h>
32 #include <terminal/terminal-private.h>
33
34
35
36 /* Signal identifiers */
37 enum
38 {
39 ENCODING_CHANGED,
40 LAST_SIGNAL,
41 };
42
43
44
45 static void terminal_encoding_action_finalize (GObject *object);
46 static GtkWidget *terminal_encoding_action_create_menu_item (GtkAction *action);
47 static void terminal_encoding_action_menu_shown (GtkWidget *menu,
48 TerminalEncodingAction *action);
49
50
51
52 struct _TerminalEncodingActionClass
53 {
54 GtkActionClass parent_class;
55 };
56
57 struct _TerminalEncodingAction
58 {
59 GtkAction parent_instance;
60 gchar *current;
61 };
62
63
64
65 /* group names for the charsets below, order matters! */
66 static const gchar *terminal_encodings_names[] =
67 {
68 N_("Western European"),
69 N_("Central European"),
70 N_("Baltic"),
71 N_("South-Eastern Europe"),
72 N_("Turkish"),
73 N_("Cyrillic"),
74 N_("Chinese Traditional"),
75 N_("Chinese Simplified"),
76 N_("Korean"),
77 N_("Japanese"),
78 N_("Greek"),
79 N_("Arabic"),
80 N_("Hebrew"),
81 N_("Thai"),
82 N_("Vietnamese"),
83 N_("Nordic"),
84 N_("Celtic"),
85 N_("Romanian"),
86 N_("Armenian"),
87 N_("Georgian"),
88 N_("Unicode"),
89 N_("Other"),
90 };
91
92 /* charsets for the groups above, order matters! */
93 static const gchar *terminal_encodings_charsets[][8] =
94 {
95 /* Western European */
96 { "ISO-8859-1", "ISO-8859-15", "WINDOWS-1252", "IBM850", NULL },
97 /* Central European */
98 { "ISO-8859-2", "ISO-8859-3", "WINDOWS-1250", "IBM852", NULL },
99 /* Baltic */
100 { "ISO-8859-4", "ISO-8859-13", "WINDOWS-1257", NULL },
101 /* South-Eastern Europe */
102 { "ISO-8859-16", NULL },
103 /* Turkish */
104 { "ISO-8859-9", "WINDOWS-1254", "IBM857", NULL },
105 /* Cyrillic */
106 { "CP866", "KOI8-R", "ISO-8859-5", "WINDOWS-1251", "KOI8-U", "IBM855", "ISO-IR-111", NULL },
107 /* Chinese Traditional */
108 { "BIG5", "BIG5-HKSCS", "EUC-TW", NULL },
109 /* Chinese Simplified */
110 { "GB18030", "GBK", "GB2312", NULL },
111 /* Korean */
112 { "EUC-KR", "ISO-2022-KR", "UHC", NULL },
113 /* Japanese */
114 { "SHIFT_JIS", "JIS7", "EUC-JP", "ISO-2022-JP", NULL },
115 /* Greek */
116 { "ISO-8859-7", "WINDOWS-1253", NULL },
117 /* Arabic */
118 { "ISO-8859-6", "IBM864", "WINDOWS-1256", NULL },
119 /* Hebrew */
120 { "ISO-8859-8", "ISO-8859-8-I", "IBM862", "WINDOWS-1255", NULL },
121 /* Thai */
122 { "TIS-620", "ISO-8859-11", NULL },
123 /* Vietnamese */
124 { "TCVN", "VISCII", "WINDOWS-1258", NULL },
125 /* Nordic */
126 { "ISO-8859-10", NULL },
127 /* Celtic */
128 { "ISO-8859-14", NULL },
129 /* Romanian */
130 { "ISO-8859-16", NULL },
131 /* Armenian */
132 { "ARMSCII-8", NULL },
133 /* Georgian */
134 { "GEORGIAN-PS", NULL },
135 /* Unicode */
136 { "UTF-8", NULL },
137 /* Other */
138 { "IBM874", "TSCII", NULL },
139 };
140
141
142
143 static guint encoding_action_signals[LAST_SIGNAL];
144 static GQuark encoding_action_quark = 0;
145
146
147
148 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
G_DEFINE_TYPE(TerminalEncodingAction,terminal_encoding_action,GTK_TYPE_ACTION)149 G_DEFINE_TYPE (TerminalEncodingAction, terminal_encoding_action, GTK_TYPE_ACTION)
150 G_GNUC_END_IGNORE_DEPRECATIONS
151
152
153
154 static void
155 terminal_encoding_action_class_init (TerminalEncodingActionClass *klass)
156 {
157 GtkActionClass *gtkaction_class;
158 GObjectClass *gobject_class;
159
160 gobject_class = G_OBJECT_CLASS (klass);
161 gobject_class->finalize = terminal_encoding_action_finalize;
162
163 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
164 gtkaction_class = GTK_ACTION_CLASS (klass);
165 G_GNUC_END_IGNORE_DEPRECATIONS
166 gtkaction_class->create_menu_item = terminal_encoding_action_create_menu_item;
167
168 encoding_action_quark = g_quark_from_static_string ("encoding-action-quark");
169
170 encoding_action_signals[ENCODING_CHANGED] =
171 g_signal_new (I_("encoding-changed"),
172 G_TYPE_FROM_CLASS (klass),
173 G_SIGNAL_RUN_LAST,
174 0, NULL, NULL,
175 g_cclosure_marshal_VOID__STRING,
176 G_TYPE_NONE, 1, G_TYPE_STRING);
177 }
178
179
180
181 static void
terminal_encoding_action_init(TerminalEncodingAction * action)182 terminal_encoding_action_init (TerminalEncodingAction *action)
183 {
184
185 }
186
187
188
189 static void
terminal_encoding_action_finalize(GObject * object)190 terminal_encoding_action_finalize (GObject *object)
191 {
192 TerminalEncodingAction *action = TERMINAL_ENCODING_ACTION (object);
193
194 g_free (action->current);
195
196 (*G_OBJECT_CLASS (terminal_encoding_action_parent_class)->finalize) (object);
197 }
198
199
200
201 static GtkWidget *
terminal_encoding_action_create_menu_item(GtkAction * action)202 terminal_encoding_action_create_menu_item (GtkAction *action)
203 {
204 GtkWidget *item;
205 GtkWidget *menu;
206
207 terminal_return_val_if_fail (TERMINAL_IS_ENCODING_ACTION (action), NULL);
208
209 /* let GtkAction allocate the menu item */
210 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
211 item = (*GTK_ACTION_CLASS (terminal_encoding_action_parent_class)->create_menu_item) (action);
212 G_GNUC_END_IGNORE_DEPRECATIONS
213
214 /* associate an empty submenu with the item (will be filled when shown) */
215 menu = gtk_menu_new ();
216 g_signal_connect (G_OBJECT (menu), "show", G_CALLBACK (terminal_encoding_action_menu_shown), action);
217 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
218
219 return item;
220 }
221
222
223
224 static void
terminal_encoding_action_activated(GtkWidget * item,TerminalEncodingAction * encoding_action)225 terminal_encoding_action_activated (GtkWidget *item,
226 TerminalEncodingAction *encoding_action)
227 {
228 const gchar *charset;
229
230 terminal_return_if_fail (GTK_IS_CHECK_MENU_ITEM (item));
231
232 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
233 return;
234
235 /* menu charset or null to reset */
236 charset = g_object_get_qdata (G_OBJECT (item), encoding_action_quark);
237 g_signal_emit (G_OBJECT (encoding_action),
238 encoding_action_signals[ENCODING_CHANGED], 0, charset);
239 }
240
241
242
243 static void
terminal_encoding_action_menu_shown(GtkWidget * menu,TerminalEncodingAction * action)244 terminal_encoding_action_menu_shown (GtkWidget *menu,
245 TerminalEncodingAction *action)
246 {
247 GList *children;
248 guint n, k;
249 GtkWidget *item;
250 GtkWidget *item2;
251 GtkWidget *submenu;
252 const gchar *charset;
253 GSList *groups = NULL;
254 gboolean found;
255 GtkWidget *label;
256 GtkWidget *bold_item = NULL;
257 PangoAttrList *attrs;
258 const gchar *default_charset;
259 gchar *default_label;
260
261 terminal_return_if_fail (TERMINAL_IS_ENCODING_ACTION (action));
262 terminal_return_if_fail (GTK_IS_MENU_SHELL (menu));
263
264 /* drop all existing children of the menu first */
265 children = gtk_container_get_children (GTK_CONTAINER (menu));
266 g_list_free_full (children, (GDestroyNotify) gtk_widget_destroy);
267
268 g_get_charset (&default_charset);
269 found = (action->current == NULL
270 || g_strcmp0 (default_charset, action->current) == 0);
271
272 /* action to reset to the default */
273 default_label = g_strdup_printf (_("Default (%s)"), default_charset);
274 item = gtk_radio_menu_item_new_with_label (groups, default_label);
275 groups = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
276 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
277 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), found);
278 g_signal_connect (G_OBJECT (item), "activate",
279 G_CALLBACK (terminal_encoding_action_activated), action);
280 g_free (default_label);
281
282 /*add the groups */
283 for (n = 0; n < G_N_ELEMENTS (terminal_encodings_names); n++)
284 {
285 /* category item */
286 item = gtk_menu_item_new_with_label (_(terminal_encodings_names[n]));
287 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
288
289 submenu = gtk_menu_new ();
290 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
291
292 /* submenu with charset */
293 for (k = 0; k < G_N_ELEMENTS (*terminal_encodings_charsets); k++)
294 {
295 charset = terminal_encodings_charsets[n][k];
296 if (charset == NULL)
297 break;
298
299 item2 = gtk_radio_menu_item_new_with_label (groups, charset);
300 groups = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item2));
301 gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item2);
302 g_object_set_qdata (G_OBJECT (item2), encoding_action_quark, (gchar *) charset);
303
304 if (!found
305 && strcmp (action->current, charset) == 0)
306 {
307 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item2), TRUE);
308
309 found = TRUE;
310 bold_item = item;
311 }
312
313 g_signal_connect (G_OBJECT (item2), "activate",
314 G_CALLBACK (terminal_encoding_action_activated), action);
315 }
316 }
317
318 if (!found)
319 {
320 /* add an action with the unknown charset */
321 item2 = gtk_radio_menu_item_new_with_label (groups, action->current);
322 groups = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item2));
323 g_object_set_qdata_full (G_OBJECT (item2), encoding_action_quark,
324 g_strdup (action->current), g_free);
325 gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item2);
326 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item2), TRUE);
327 g_signal_connect (G_OBJECT (item2), "activate",
328 G_CALLBACK (terminal_encoding_action_activated), action);
329
330 /* other group */
331 bold_item = item;
332 }
333
334 if (bold_item != NULL)
335 {
336 attrs = pango_attr_list_new ();
337 pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
338 label = gtk_bin_get_child (GTK_BIN (bold_item));
339 gtk_label_set_attributes (GTK_LABEL (label), attrs);
340 pango_attr_list_unref (attrs);
341 }
342
343 gtk_widget_show_all (menu);
344 }
345
346
347
348 GtkAction*
terminal_encoding_action_new(const gchar * name,const gchar * label)349 terminal_encoding_action_new (const gchar *name,
350 const gchar *label)
351 {
352 terminal_return_val_if_fail (name != NULL, NULL);
353 terminal_return_val_if_fail (label != NULL, NULL);
354
355 return g_object_new (TERMINAL_TYPE_ENCODING_ACTION,
356 "hide-if-empty", FALSE,
357 "label", label,
358 "name", name,
359 NULL);
360 }
361
362
363
364 void
terminal_encoding_action_set_charset(GtkAction * gtkaction,const gchar * charset)365 terminal_encoding_action_set_charset (GtkAction *gtkaction,
366 const gchar *charset)
367 {
368 TerminalEncodingAction *action = TERMINAL_ENCODING_ACTION (gtkaction);
369
370 terminal_return_if_fail (TERMINAL_IS_ENCODING_ACTION (action));
371
372 g_free (action->current);
373 action->current = g_strdup (charset);
374 }
375
376
377
378
379
380
381
382 GtkTreeModel *
terminal_encoding_model_new(const gchar * current,GtkTreeIter * current_iter)383 terminal_encoding_model_new (const gchar *current,
384 GtkTreeIter *current_iter)
385 {
386 GtkTreeStore *store;
387 guint n;
388 guint k;
389 GtkTreeIter parent;
390 const gchar *charset;
391 gboolean found;
392 GtkTreeIter iter;
393 gchar *default_label;
394
395 store = gtk_tree_store_new (N_ENCODING_COLUMNS,
396 G_TYPE_STRING,
397 G_TYPE_BOOLEAN,
398 G_TYPE_STRING);
399
400 /* default */
401 g_get_charset (&charset);
402 default_label = g_strdup_printf (_("Default (%s)"), charset);
403 gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
404 ENCODING_COLUMN_TITLE, default_label,
405 ENCODING_COLUMN_VALUE, NULL,
406 ENCODING_COLUMN_IS_CHARSET, TRUE,
407 -1);
408 g_free (default_label);
409 found = (current == NULL || g_strcmp0 (current, charset) == 0);
410 if (found)
411 *current_iter = iter;
412
413 /*add the groups */
414 for (n = 0; n < G_N_ELEMENTS (terminal_encodings_names); n++)
415 {
416 /* category item */
417 gtk_tree_store_insert_with_values (store, &parent, NULL, n + 1,
418 ENCODING_COLUMN_TITLE, _(terminal_encodings_names[n]),
419 -1);
420
421 /* submenu with charset */
422 for (k = 0; k < G_N_ELEMENTS (*terminal_encodings_charsets); k++)
423 {
424 charset = terminal_encodings_charsets[n][k];
425 if (charset == NULL)
426 break;
427
428 gtk_tree_store_insert_with_values (store, &iter, &parent, k,
429 ENCODING_COLUMN_TITLE, charset,
430 ENCODING_COLUMN_VALUE, charset,
431 -1);
432
433 if (!found && g_strcmp0 (charset, current) == 0)
434 {
435 *current_iter = iter;
436 found = TRUE;
437 }
438 }
439 }
440
441 if (!found)
442 {
443 /* add custom in other menu */
444 gtk_tree_store_insert_with_values (store, current_iter, &parent, k,
445 ENCODING_COLUMN_TITLE, current,
446 ENCODING_COLUMN_IS_CHARSET, TRUE,
447 ENCODING_COLUMN_VALUE, current,
448 -1);
449 }
450
451 return GTK_TREE_MODEL (store);
452 }
453
454