Make font configurable in XML
[fvkbd:fvkbd.git] / ui / gtk / fvkbd-key-ui-gtk.c
1 /*
2  * fvkbd-key-ui-gtk.c key unit gtk ui for fvkbd  
3  *
4  * Copyright (C) 2009, Intel Corporation.
5  *
6  * Author: Raymond Liu <raymond.liu@intel.com>
7  * 
8  * 
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * version 2.1 as published by the Free Software Foundation.
12  * 
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  * 
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23
24
25 #include <gtk/gtk.h>
26 #include "fvkbd.h"
27 #include "fvkbd-keyboard.h"
28 #include "gtk-misc-utility.h"
29
30 #include "fvkbd-key.h"
31
32 typedef struct _KeyUI KeyUI;
33 struct _KeyUI {
34         GtkWidget *main_label;
35         GtkWidget *sub_label;
36
37         PangoFontDescription *font_desc;
38         PangoFontDescription *efont_desc;
39         PangoFontDescription *ofont_desc;
40 };
41
42 typedef struct _CandidateItem CandidateItem;
43 struct _CandidateItem {
44         GtkWidget *widget;
45         KeyActionType type;
46         gchar *disp;
47         union 
48         {
49                 gchar *string;
50                 KeySym sym;
51                 FvkbdKeyFunc func;
52         } u;
53 };
54
55 #define MAX_CANDIDATE_ITEMS 10
56 #define CANDIDATE_ITEM_DEF_WIDTH 80
57 #define CANDIDATE_ITEM_DEF_HEIGHT 80
58
59 static guint longpress_timeout_id = 0;
60 static guint longpress_timeout_val = 800;
61 static guint pop_window_hide_timeout_id = 0;
62 static guint pop_window_hide_timeout_val = 5000;
63
64 static GtkWidget *pop_window = NULL;
65 static CandidateItem candidate_items[MAX_CANDIDATE_ITEMS];
66
67 static gboolean key_mode_do_switch_lock = FALSE;
68
69
70 static void set_candidate_item_string(gint n, gchar *disp, gchar *str);
71 static void candidate_item_clicked_cb(GtkButton *button, CandidateItem *item);
72 static void init_candidate_items(void);
73 static void update_candidate_item_none(void);
74 static void update_candidate_item_string(gchar *disp, gchar *str);
75 static void update_candidate_item_string_group(gchar **strs);
76 static void update_candidate_item_sym(gchar *disp, KeySym sym);
77 static GtkWidget *get_pop_window(void);
78 static void settle_pop_window(FvkbdKey *key);
79 static void show_pop_window(FvkbdKey *key, gboolean longpress);
80 static void hide_pop_window(void);
81 static gboolean hide_pop_window_cb(FvkbdKey *key);
82 static gboolean longpress_detected_cb(FvkbdKey *key);
83
84
85 static void
86 set_candidate_item_string(gint n, gchar *disp, gchar *str)
87 {
88         GtkWidget *button;
89         if (str == NULL || n >= MAX_CANDIDATE_ITEMS)
90                 return;
91
92         candidate_items[n].type = KEY_ACTION_STRING;
93         candidate_items[n].u.string = str;
94         button = candidate_items[n].widget;
95         gtk_button_set_label(GTK_BUTTON(button), disp);
96 }
97
98
99 static void
100 candidate_item_clicked_cb(GtkButton *button, CandidateItem *item)
101 {
102         switch (item->type) {
103
104         case KEY_ACTION_STRING:
105                 fvkbd_key_send_utf8_string(item->u.string);
106                 break;
107
108         case KEY_ACTION_SYM:
109                 fvkbd_key_send_xkeysym(item->u.sym);
110                 break;
111
112         default:
113                 break;
114         }
115
116         if (pop_window_hide_timeout_id != 0) {
117                 g_source_remove(pop_window_hide_timeout_id);
118                 pop_window_hide_timeout_id = 0;
119                 hide_pop_window();
120         }
121
122         if (fvkbd_in_temp_mode())
123                 fvkbd_keyboard_resume_default_mode();
124 }
125
126
127 static void
128 init_candidate_items(void)
129 {
130         int i;
131         for (i = 0; i < MAX_CANDIDATE_ITEMS; i++) {
132                 candidate_items[i].widget = gtk_button_new();
133                 gtk_widget_set_size_request(candidate_items[i].widget,
134                                                 CANDIDATE_ITEM_DEF_WIDTH,
135                                                 CANDIDATE_ITEM_DEF_HEIGHT);
136                 g_signal_connect(G_OBJECT(candidate_items[i].widget), "clicked",
137                         G_CALLBACK(candidate_item_clicked_cb), &candidate_items[i]);
138         }
139 }
140
141
142 static void
143 update_candidate_item_none(void)
144 {
145         int i;
146
147         for (i = 0; i < MAX_CANDIDATE_ITEMS; i++)
148                 gtk_widget_hide(candidate_items[i].widget);
149 }
150
151
152 static void
153 update_candidate_item_string(gchar *disp, gchar *str)
154 {
155         int i;
156
157         set_candidate_item_string(0, disp, str);
158         gtk_widget_show(candidate_items[0].widget);
159
160         for (i = 1; i < MAX_CANDIDATE_ITEMS; i++)
161                 gtk_widget_hide(candidate_items[i].widget);
162
163 }
164
165
166 static void
167 update_candidate_item_string_group(gchar **strs)
168 {
169         int i;
170         if (strs == NULL)
171                 return;
172
173         for (i = 0; (i < MAX_CANDIDATE_ITEMS) && *strs; i++, strs++) {
174                 set_candidate_item_string(i, *strs, *strs);
175                 gtk_widget_show(candidate_items[i].widget);
176         }
177
178         for (; i < MAX_CANDIDATE_ITEMS; i++)
179                 gtk_widget_hide(candidate_items[i].widget);
180 }
181
182
183 static void
184 update_candidate_item_sym(gchar *disp, KeySym sym)
185 {
186         int i;
187         GtkWidget *button;
188
189         candidate_items[0].type = KEY_ACTION_SYM;
190         candidate_items[0].u.sym = sym;
191         button = candidate_items[0].widget;
192         gtk_button_set_label(GTK_BUTTON(button), disp);
193         gtk_widget_show(button);
194
195         for (i = 1; i < MAX_CANDIDATE_ITEMS; i++)
196                 gtk_widget_hide(candidate_items[i].widget);
197 }
198
199
200 static GtkWidget *
201 get_pop_window(void)
202 {
203         if (pop_window == NULL) {
204                 GtkWidget *hbox, *frame;
205                 int i;
206
207                 pop_window = gtk_window_new(GTK_WINDOW_POPUP);
208                 gtk_window_set_accept_focus(GTK_WINDOW(pop_window), FALSE);
209                 gtk_window_set_resizable(GTK_WINDOW(pop_window), FALSE);
210
211                 frame = gtk_frame_new(NULL);
212                 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
213
214                 hbox = gtk_hbox_new(FALSE, 0);
215
216                 gtk_container_add (GTK_CONTAINER (frame), hbox);
217
218                 init_candidate_items();
219                 for (i = 0; i < MAX_CANDIDATE_ITEMS; i++) {
220                         gtk_box_pack_start(GTK_BOX(hbox), candidate_items[i].widget,
221                                                 FALSE, FALSE, 0);
222                 }
223
224                 gtk_widget_show_all(frame);
225
226                 gtk_container_add (GTK_CONTAINER (pop_window), frame);
227         }
228
229         return pop_window;
230 }
231
232
233 static void
234 settle_pop_window(FvkbdKey *key)
235 {
236         GtkWidget *w = get_pop_window();
237         GdkScreen *screen;
238         int pointer_x = 0, pointer_y = 0;
239         int pop_w = 0, pop_h = 0;
240         int x, y;
241         GtkWidget *key_widget;
242
243         key_widget = fvkbd_unit_get_widget(FVKBD_UNIT(key));
244
245         screen = gtk_widget_get_screen (key_widget);
246         gdk_display_get_pointer (gdk_screen_get_display (screen),
247                                  NULL, &pointer_x, &pointer_y, NULL);
248
249         gtk_window_get_size(GTK_WINDOW(w), &pop_w, &pop_h);
250
251         if ((y = (pointer_y - pop_h)) < 0)
252                 y = pointer_y + 2;
253         x = pointer_x + 2;
254
255         gtk_window_move(GTK_WINDOW(w), x, y);
256 }
257
258
259 static void
260 show_pop_window(FvkbdKey *key, gboolean longpress)
261 {
262         FvkbdKeyAction *action;
263         GtkWidget *w = get_pop_window();
264
265         action = fvkbd_key_get_current_action(key);
266
267         switch (action->type) {
268
269         case KEY_ACTION_STRING:
270                 update_candidate_item_string(action->disp, action->u.string);
271                 break;
272
273         case KEY_ACTION_STRING_GROUP:
274                 if (!longpress)
275                         update_candidate_item_string(action->disp, action->u.string);
276                 else
277                         update_candidate_item_string_group(action->u.string_group);
278                 break;
279
280         case KEY_ACTION_SYM:
281                 update_candidate_item_sym(action->disp, action->u.sym);
282                 break;
283
284         default:
285                 update_candidate_item_none();
286                 hide_pop_window();
287                 return;
288         }
289
290         settle_pop_window(key);
291         if (!GTK_WIDGET_VISIBLE(w))
292                 gtk_widget_show(w);
293 }
294
295
296 static void
297 hide_pop_window(void)
298 {
299         GtkWidget *w = get_pop_window();
300         if (GTK_WIDGET_VISIBLE(w))
301                 gtk_widget_hide(w);
302 }
303
304
305 static gboolean
306 hide_pop_window_cb(FvkbdKey *key)
307 {
308         hide_pop_window();
309         pop_window_hide_timeout_id = 0;
310         
311         return FALSE;
312 }
313
314
315 static gboolean
316 longpress_detected_cb(FvkbdKey *key)
317 {
318         FvkbdKeyAction *action;
319
320         action = fvkbd_key_get_current_action(key);
321
322         switch (action->type) {
323
324         case KEY_ACTION_STRING:
325         case KEY_ACTION_STRING_GROUP:
326         case KEY_ACTION_SYM:
327                 show_pop_window(key, TRUE);
328                 pop_window_hide_timeout_id = g_timeout_add(pop_window_hide_timeout_val,
329                                                 (GSourceFunc)hide_pop_window_cb, key);
330
331                 break;
332         case KEY_ACTION_FUNC:
333                 switch (action->u.func.type) {
334                 case FVKBD_KEY_FUNC_MODE_SELECT:
335                         key_mode_do_switch_lock = TRUE;
336                         break;
337
338                 default:
339                         break;
340                 }
341
342                 break;
343         default:
344                 break;
345         }
346
347         longpress_timeout_id = 0;
348         
349         return FALSE;
350 }
351
352
353 static void
354 fvkbd_key_gtk_pressed_cb(GtkButton *button, FvkbdKey *key)
355 {
356         if (longpress_timeout_id != 0) {
357                 g_source_remove(longpress_timeout_id);
358                 longpress_timeout_id = 0;
359         }
360
361         if (pop_window_hide_timeout_id != 0) {
362                 g_source_remove(pop_window_hide_timeout_id);
363                 pop_window_hide_timeout_id = 0;
364         }
365
366         longpress_timeout_id = g_timeout_add(longpress_timeout_val,
367                                         (GSourceFunc)longpress_detected_cb, key);
368
369         show_pop_window(key, FALSE);
370 }
371
372
373 static void
374 fvkbd_key_gtk_released_cb(GtkButton *button, FvkbdKey *key)
375 {
376         FvkbdKeyAction *action;
377         gboolean need_reset_default_mode = TRUE;
378
379         /* if the candiate window is shown, then we do nothing and return */
380         if (pop_window_hide_timeout_id != 0) {
381                 return;
382         }
383
384         if (longpress_timeout_id != 0) {
385                 g_source_remove(longpress_timeout_id);
386                 longpress_timeout_id = 0;
387         }
388
389         hide_pop_window();
390
391         if ((action = fvkbd_key_get_current_action(key)) == NULL)
392                 return;
393
394         switch (action->type) {
395         case KEY_ACTION_STRING:
396                 fvkbd_key_send_utf8_string(action->u.string);
397                 break;
398
399         case KEY_ACTION_STRING_GROUP:
400                 fvkbd_key_send_utf8_string(action->u.string_group[0]);
401                 break;
402
403         case KEY_ACTION_SYM:
404                 fvkbd_key_send_xkeysym(action->u.sym);
405                 break;
406
407         case KEY_ACTION_FUNC:
408                 switch (action->u.func.type) {
409                 case FVKBD_KEY_FUNC_MODE_SELECT:
410                         fvkbd_key_func_handlers(key, action, &key_mode_do_switch_lock);
411                         need_reset_default_mode = FALSE;
412                         key_mode_do_switch_lock = FALSE;
413                         break;
414
415                 default:
416                         fvkbd_key_func_handlers(key, action, NULL);
417                 }
418
419                 break;
420
421         case KEY_ACTION_SCRIPT:
422                 break;
423
424         default:
425                 break;
426         }
427
428         if (fvkbd_in_temp_mode() && need_reset_default_mode)
429                 fvkbd_keyboard_resume_default_mode();
430
431 }
432
433
434 static gboolean
435 get_key_gdkcolor (FvkbdUnit *unit, KeyColorType type, GdkColor *color)
436 {
437         KbdColor kc;
438
439         if (!fvkbd_key_get_color(unit, type, &kc))
440                 return FALSE;
441
442         if (!color)
443                 return FALSE;
444
445         kbdcolor_to_gdkcolor(kc,color);
446         return TRUE;
447 }
448
449
450 static gboolean
451 get_key_gdkcolor_reverse (FvkbdUnit *unit, KeyColorType type, GdkColor *color)
452 {
453         KbdColor kc;
454
455         if (!fvkbd_key_get_color(unit, type, &kc))
456                 return FALSE;
457
458         kc.r = 255 - kc.r;
459         kc.g = 255 - kc.g;
460         kc.b = 255 - kc.b;
461
462         if (!color)
463                 return FALSE;
464
465         kbdcolor_to_gdkcolor(kc,color);
466         return TRUE;
467 }
468
469
470 static void
471 fvkbd_key_settle_color (FvkbdUnit *unit, GtkWidget *key_widget, gboolean lock)
472 {
473         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
474         GdkColor color;
475         GtkWidget *label;
476
477         // set key background color
478         if (!lock) {
479                 if (get_key_gdkcolor(unit, KEY_COLOR_TYPE_BG, &color)) {
480                         gtk_widget_modify_bg(key_widget, GTK_STATE_NORMAL, &color);
481                         gtk_widget_modify_bg(key_widget, GTK_STATE_PRELIGHT, &color);
482                 }
483
484                 if (get_key_gdkcolor_reverse(unit, KEY_COLOR_TYPE_BG, &color)) {
485                         gtk_widget_modify_bg(key_widget, GTK_STATE_ACTIVE, &color);
486                 }
487         } else {
488                 if (get_key_gdkcolor(unit, KEY_COLOR_TYPE_FG, &color)) {
489                         gtk_widget_modify_bg(key_widget, GTK_STATE_NORMAL, &color);
490                         gtk_widget_modify_bg(key_widget, GTK_STATE_PRELIGHT, &color);
491                 }
492
493                 if (get_key_gdkcolor_reverse(unit, KEY_COLOR_TYPE_FG, &color)) {
494                         gtk_widget_modify_bg(key_widget, GTK_STATE_ACTIVE, &color);
495                 }
496         }
497         
498         // set main label color
499         label = ui_data->main_label;
500
501         if (!lock) {
502                 if (get_key_gdkcolor(unit, KEY_COLOR_TYPE_FG, &color)) {
503                         gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
504                         gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
505                 }
506
507                 if (get_key_gdkcolor_reverse(unit, KEY_COLOR_TYPE_FG, &color)) {
508                         gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &color);
509                 }
510         } else {
511                 if (get_key_gdkcolor(unit, KEY_COLOR_TYPE_BG, &color)) {
512                         gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
513                         gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
514                 }
515
516                 if (get_key_gdkcolor_reverse(unit, KEY_COLOR_TYPE_BG, &color)) {
517                         gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &color);
518                 }
519         }
520
521         // set sub label color
522         label = ui_data->sub_label;
523
524         if (get_key_gdkcolor(unit, KEY_COLOR_TYPE_EXTRA_FG, &color)) {
525                 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
526                 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
527         }
528 }
529
530
531 static PangoFontDescription *
532 get_key_pango_font_description (FvkbdUnit *unit, KbdFontType type)
533 {
534         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
535         gchar *font_family = fvkbd_key_get_font_family(unit, type);
536         gchar *font_weight = fvkbd_key_get_font_weight(unit, type);
537         gint font_size = fvkbd_key_get_font_size(unit, type);
538
539         switch (type) {
540                 case KBD_FONT_TYPE_NORMAL: {
541                         if (ui_data->font_desc)
542                                 return ui_data->font_desc;
543                         else {
544                                 ui_data->font_desc = get_pango_font_description_from_info (font_family, font_weight, font_size);
545                                 return ui_data->font_desc;
546                         }
547                 }
548                 case KBD_FONT_TYPE_EXTRA: {
549                         if (ui_data->efont_desc)
550                                 return ui_data->efont_desc;
551                         else {
552                                 ui_data->efont_desc = get_pango_font_description_from_info (font_family, font_weight, font_size);
553                                 return ui_data->efont_desc;
554                         }
555                 }
556                 case KBD_FONT_TYPE_POP: {
557                         if (ui_data->ofont_desc)
558                                 return ui_data->ofont_desc;
559                         else {
560                                 ui_data->ofont_desc = get_pango_font_description_from_info (font_family, font_weight, font_size);
561                                 return ui_data->ofont_desc;
562                         }
563                 }
564                 default:
565                         return NULL;
566         }
567         return NULL;
568 }
569
570
571 static void
572 fvkbd_key_settle_font (FvkbdUnit *unit, GtkWidget *key_widget)
573 {
574         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
575         PangoFontDescription *desc;
576         GtkWidget *label;
577
578         // set main label font
579         label = ui_data->main_label;
580         if (!ui_data->font_desc) {
581                 desc = get_key_pango_font_description (unit, KBD_FONT_TYPE_NORMAL);
582         } else
583                 desc = ui_data->font_desc;
584         gtk_widget_modify_font(label, desc);
585
586         label = ui_data->sub_label;
587         if (!ui_data->efont_desc) {
588                 desc = get_key_pango_font_description (unit, KBD_FONT_TYPE_EXTRA);
589         } else
590                 desc = ui_data->efont_desc;
591         gtk_widget_modify_font(label, desc);
592
593 }
594
595
596 static GtkWidget *
597 _create_key_label (FvkbdUnit *unit, gint id)
598 {
599         FvkbdKey *key;
600         FvkbdKeyAction *action;
601         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
602         gint w,h;
603         GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
604         GtkWidget *label = NULL, *sub_label = NULL;
605
606         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
607         key = FVKBD_KEY(unit);
608
609         fvkbd_unit_get_size(unit, &w, &h);
610
611         if ((action = fvkbd_key_get_current_action(key)) == NULL)
612                 goto done;
613
614         if (action->type == KEY_ACTION_STRING_GROUP) {
615                 gchar *label_str = NULL;
616
617                 label_str = g_strjoinv(" ", &(action->u.string_group[1]));
618                 sub_label = gtk_label_new(label_str);
619                 g_free(label_str);
620                 label = gtk_label_new(fvkbd_key_get_disp(key, id));
621         } else if (action->type == KEY_ACTION_STRING ||
622                 action->type == KEY_ACTION_STRING_GROUP ||
623                 action->type == KEY_ACTION_SYM ||
624                 action->type == KEY_ACTION_FUNC) {
625
626                 sub_label = gtk_label_new(NULL);
627                 label = gtk_label_new(fvkbd_key_get_disp(key, id));
628         }
629
630         ui_data->sub_label = sub_label;
631         if (sub_label)
632                 gtk_box_pack_start(GTK_BOX(vbox), sub_label, FALSE, FALSE, 0);
633
634         ui_data->main_label = label;
635         gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
636
637 done:
638         gtk_widget_show_all(vbox);
639         return vbox;
640 }
641
642
643 static void
644 _update_key_label (FvkbdUnit *unit, gint id)
645 {
646         GtkWidget *key_widget;
647         GtkWidget *key_label;
648
649         key_widget = fvkbd_unit_get_widget(unit);
650         
651         key_label = gtk_bin_get_child(GTK_BIN(key_widget));
652
653         if (key_label) {
654                 gtk_widget_destroy(key_label);
655                 key_label = NULL;
656         }
657
658         key_label = _create_key_label(unit, id);
659         gtk_container_add(GTK_CONTAINER(key_widget), key_label);
660 }
661
662
663 static void
664 _set_key_label_tmp_mode (FvkbdUnit *unit)
665 {
666         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
667         GtkWidget *label;
668         gchar *disp;
669
670         label = ui_data->main_label;
671         disp = g_strconcat("<u>", gtk_label_get_text(GTK_LABEL(label)), "</u>", NULL);
672         gtk_label_set_text(GTK_LABEL(label), disp);
673         gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
674         g_free(disp);
675 }
676
677
678 gboolean
679 fvkbd_key_build_ui (FvkbdUnit *unit, gpointer *widget)
680 {
681         FvkbdKey *key;
682         KeyUI *ui_data;
683         gint w,h;
684         gboolean ret = TRUE;
685
686         GtkWidget *key_widget;
687         GtkWidget *key_label;
688
689         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
690         key = FVKBD_KEY(unit);
691
692         key_widget = gtk_button_new();
693
694         ui_data = g_new0(KeyUI, 1);
695         fvkbd_unit_set_ui_data(unit, ui_data);
696         ui_data->main_label = NULL;
697         ui_data->sub_label = NULL;
698         ui_data->font_desc = NULL;
699         ui_data->efont_desc = NULL;
700         ui_data->ofont_desc = NULL;
701
702         fvkbd_unit_get_size(unit, &w, &h);
703         gtk_widget_set_size_request(key_widget, w, h);
704
705         key_label = _create_key_label(unit, 0);
706         gtk_container_add(GTK_CONTAINER(key_widget), key_label);
707
708         // set color
709         fvkbd_key_settle_color(unit, key_widget, FALSE);
710
711         // set font
712         fvkbd_key_settle_font(unit, key_widget);
713
714         g_signal_connect(G_OBJECT(key_widget), "pressed",
715                         G_CALLBACK(fvkbd_key_gtk_pressed_cb), key);
716         g_signal_connect(G_OBJECT(key_widget), "released",
717                         G_CALLBACK(fvkbd_key_gtk_released_cb), key);
718
719         if (widget != NULL)
720                 *widget = key_widget;
721         fvkbd_unit_set_widget(unit, key_widget);
722         return ret;
723 }
724
725
726 gboolean
727 fvkbd_key_destroy_ui (FvkbdUnit *unit)
728 {
729         FvkbdKey *key;
730         KeyUI *ui_data;
731         gboolean ret = TRUE;
732
733         GtkWidget *key_widget;
734
735         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
736         key = FVKBD_KEY(unit);
737
738         key_widget = fvkbd_unit_get_widget(unit);
739
740         gtk_widget_hide_all(key_widget);
741         gtk_widget_destroy(key_widget);
742
743         fvkbd_unit_set_widget(unit, NULL);
744
745         ui_data = fvkbd_unit_get_ui_data(unit);
746         if (ui_data->font_desc)
747                 pango_font_description_free (ui_data->font_desc);
748         if (ui_data->efont_desc)
749                 pango_font_description_free (ui_data->efont_desc);
750         if (ui_data->ofont_desc)
751                 pango_font_description_free (ui_data->ofont_desc);
752         g_free(ui_data);
753         fvkbd_unit_set_ui_data(unit, NULL);
754
755         return ret;
756 }
757
758
759 gint
760 fvkbd_key_set_mode (FvkbdUnit *unit, gint id)
761 {
762         FvkbdKey *key;
763         FvkbdKeyAction *action;
764         GtkWidget *key_widget;
765         gboolean show_lock_mode = FALSE;
766
767         g_return_val_if_fail(FVKBD_IS_KEY(unit), -1);
768         key = FVKBD_KEY(unit);
769
770         key_widget = fvkbd_unit_get_widget(unit);
771
772         // Yes, we get the default action here to handle disp diffirently for tmply mode change
773         action = fvkbd_key_get_action(key, 0);
774
775         if ((action->type == KEY_ACTION_FUNC) &&
776                 (action->u.func.type == FVKBD_KEY_FUNC_MODE_SELECT)) {
777                 if ((fvkbd_in_temp_mode()) && ((*((int *)action->u.func.data)) == id)) {
778                         _update_key_label(unit, 0);
779                         _set_key_label_tmp_mode(unit);
780                 } else {
781                         _update_key_label(unit, id);
782                         if ((*((int *)action->u.func.data)) == id)
783                                 show_lock_mode = TRUE;
784                 }
785         } else {
786                 _update_key_label(unit, id);
787         }
788
789         // set color
790         fvkbd_key_settle_color(unit, key_widget, show_lock_mode);
791
792         // set font
793         fvkbd_key_settle_font(unit, key_widget);
794
795         return 0;
796 }
797