Fix some widget unref issues
[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 "misc-utility.h"
29 #include "gtk-misc-utility.h"
30 #include "gtk-vkb-button.h"
31
32 #include "fvkbd-pop-win.h"
33 #include "fvkbd-key.h"
34
35
36 typedef struct _KeyUI KeyUI;
37 struct _KeyUI {
38         GtkWidget *main_label;
39         GtkWidget *sub_label;
40         GtkWidget *img;
41         GtkWidget *img_dn;
42
43         PangoFontDescription *font_desc;
44         PangoFontDescription *efont_desc;
45         PangoFontDescription *ofont_desc;
46 };
47
48
49 static gboolean key_mode_do_switch_lock = FALSE;
50
51 static guint longpress_timeout_id = 0;
52 static guint longpress_timeout_val = 800;
53 static guint pop_window_hide_timeout_id = 0;
54 static guint pop_window_hide_timeout_val = 5000;
55
56 static void settle_pop_window(FvkbdKey *key, gint number, gboolean reverse);
57 static void show_pop_window(FvkbdKey *key, gboolean longpress);
58 static void hide_pop_window(void);
59 static gboolean hide_pop_window_cb(FvkbdKey *key);
60 static gboolean longpress_detected_cb(FvkbdKey *key);
61 static PangoFontDescription * get_key_pango_font_description (FvkbdUnit *unit, KbdFontType type);
62
63 static void _toggle_key_img (FvkbdKey *unit, gboolean down);
64
65 static void
66 settle_pop_window(FvkbdKey *key, gint number, gboolean reverse)
67 {
68         GtkWidget *w = get_pop_window();
69         GdkWindow *keywindow;
70
71         int pop_w = 0, pop_h = 0;
72         int x, y;
73         int ux, uy, uw, uh;
74         int ww, wh;
75         gfloat x_ratio, y_ratio;
76         GtkWidget *key_widget;
77
78         key_widget = fvkbd_unit_get_widget(FVKBD_UNIT(key));
79         keywindow = gtk_widget_get_window(key_widget);
80
81         gdk_window_get_origin(keywindow, &x, &y);
82         gtk_window_get_size(GTK_WINDOW(w), &pop_w, &pop_h);
83
84         /* If key_widget don't have it's own gdk window, then gdk_window_get_origin will get the position
85             of it's parent window, say panel window, then we need to do some offset to gain the right position */
86         if (GTK_WIDGET_NO_WINDOW(key_widget)) {
87                 fvkbd_unit_get_position(FVKBD_UNIT(key), &ux, &uy);
88         } else {
89                 ux = 0;
90                 uy = 0;
91         }
92
93         if ((fvkbd_unit_get_size(FVKBD_UNIT(key), &uw, &uh) == 0) &&
94                 (fvkbd_unit_get_ratio(FVKBD_UNIT(key), &x_ratio, &y_ratio) == 0)) {
95
96                 gtk_window_get_size(GTK_WINDOW(w), &ww, &wh);
97
98                 if (!reverse) {
99                         x += (ux * x_ratio);
100                 } else {
101                         x += ((ux + uw) * x_ratio - ww);
102                 }
103
104                 y += ((uy * y_ratio) - (wh - (uh * y_ratio)) / 2);
105         }
106
107         gtk_window_move(GTK_WINDOW(w), x, y);
108 }
109
110
111 static void
112 show_pop_window(FvkbdKey *key, gboolean longpress)
113 {
114         FvkbdKeyAction *action;
115         GtkWidget *w = get_pop_window();
116         GdkColor bgcolor, fgcolor;
117         int item_number = 1;
118         int i;
119         int ux, uy, uw, uh, pw, ph;
120         gfloat x_ratio, y_ratio;
121         gboolean reverse = FALSE;
122
123         fvkbd_unit_get_size(fvkbd_unit_get_parent(FVKBD_UNIT(key)), &pw, &ph);
124         if ((fvkbd_unit_get_position(FVKBD_UNIT(key), &ux, &uy) == 0)) {
125                 if (ux <= (pw / 2))
126                         reverse = FALSE;
127                 else
128                         reverse = TRUE;
129         }
130
131         fvkbd_unit_get_ratio(FVKBD_UNIT(key), &x_ratio, &y_ratio);
132         fvkbd_unit_get_size(FVKBD_UNIT(key), &uw, &uh);
133
134         action = fvkbd_key_get_current_action(key);
135         KeyUI *ui_data = fvkbd_unit_get_ui_data(FVKBD_UNIT(key));
136         PangoFontDescription *desc;
137
138         if (!ui_data->ofont_desc) {
139                 desc = get_key_pango_font_description(FVKBD_UNIT(key), KBD_FONT_TYPE_POP);
140                 ui_data->ofont_desc = desc;
141         } else
142                 desc = ui_data->ofont_desc;
143
144         switch (action->type) {
145
146         case KEY_ACTION_STRING:
147                 update_pop_win_item_string(action->disp, action->u.string, desc, reverse);
148                 item_number = 2;
149                 break;
150
151         case KEY_ACTION_STRING_GROUP:
152                 if (!longpress) {
153                         update_pop_win_item_string(action->disp, action->u.string, desc, reverse);
154                         item_number = 2;
155                 } else {
156                         update_pop_win_item_string_group(action->u.string_group, desc, reverse);
157                         for (i = 0; (i < MAX_POP_WIN_ITEMS) && *(action->u.string_group + i); i++)
158                                 item_number++;
159                 }
160                 break;
161
162         case KEY_ACTION_SYM:
163                 update_pop_win_item_sym(action->disp, action->u.sym, desc, reverse);
164                 item_number = 2;
165                 break;
166
167         default:
168                 update_pop_win_item_none();
169                 hide_pop_window();
170                 return;
171         }
172
173         set_pop_win_items_size(uw * x_ratio, uh * y_ratio);
174
175         get_gdkcolor(FVKBD_UNIT(key), KBD_COLOR_TYPE_KEY_POP_BG, &bgcolor);
176         get_gdkcolor(FVKBD_UNIT(key), KBD_COLOR_TYPE_KEY_POP_FG, &fgcolor);
177
178         settle_pop_window_color(item_number, &bgcolor, &fgcolor);
179         // well, hiding pop window here, just wish the window size will be retrived
180         // correctly by gtk_window_get_size later in settle_pop_window.
181         hide_pop_window();
182         settle_pop_window(key, item_number, reverse);
183         if (!GTK_WIDGET_VISIBLE(w))
184                 gtk_widget_show(w);
185 }
186
187
188 static void
189 hide_pop_window(void)
190 {
191         GtkWidget *w = get_pop_window();
192         if (GTK_WIDGET_VISIBLE(w))
193                 gtk_widget_hide(w);
194 }
195
196
197 static gboolean
198 hide_pop_window_cb(FvkbdKey *key)
199 {
200         hide_pop_window();
201         pop_window_hide_timeout_id = 0;
202         
203         return FALSE;
204 }
205
206
207 static gboolean
208 longpress_detected_cb(FvkbdKey *key)
209 {
210         FvkbdKeyAction *action;
211
212         action = fvkbd_key_get_current_action(key);
213
214         switch (action->type) {
215
216         case KEY_ACTION_STRING:
217         case KEY_ACTION_SYM:
218                 show_pop_window(key, TRUE);
219                 break;
220
221         case KEY_ACTION_STRING_GROUP:
222                 show_pop_window(key, TRUE);
223                 pop_window_hide_timeout_id = g_timeout_add(pop_window_hide_timeout_val,
224                                                 (GSourceFunc)hide_pop_window_cb, key);
225
226                 break;
227
228         case KEY_ACTION_FUNC:
229                 switch (action->u.func.type) {
230                 case FVKBD_KEY_FUNC_MODE_SELECT:
231                         key_mode_do_switch_lock = TRUE;
232                         break;
233
234                 default:
235                         break;
236                 }
237
238                 break;
239         default:
240                 break;
241         }
242
243         longpress_timeout_id = 0;
244         
245         return FALSE;
246 }
247
248
249 static void
250 fvkbd_key_gtk_pressed_cb(GtkButton *button, FvkbdKey *key)
251 {
252         if (longpress_timeout_id != 0) {
253                 g_source_remove(longpress_timeout_id);
254                 longpress_timeout_id = 0;
255         }
256
257         if (pop_window_hide_timeout_id != 0) {
258                 g_source_remove(pop_window_hide_timeout_id);
259                 pop_window_hide_timeout_id = 0;
260                 hide_pop_window();
261         }
262
263         longpress_timeout_id = g_timeout_add(longpress_timeout_val,
264                                         (GSourceFunc)longpress_detected_cb, key);
265
266         _toggle_key_img(key, TRUE);
267         show_pop_window(key, FALSE);
268 }
269
270
271 static void
272 fvkbd_key_gtk_released_cb(GtkButton *button, FvkbdKey *key)
273 {
274         FvkbdKeyAction *action;
275         gboolean need_reset_default_mode = TRUE;
276
277         _toggle_key_img(key, FALSE);
278
279         /* if the candiate window is shown, then we do nothing and return */
280         if (pop_window_hide_timeout_id != 0) {
281                 return;
282         }
283
284         if (longpress_timeout_id != 0) {
285                 g_source_remove(longpress_timeout_id);
286                 longpress_timeout_id = 0;
287         }
288
289         hide_pop_window();
290
291         if ((action = fvkbd_key_get_current_action(key)) == NULL)
292                 return;
293
294         switch (action->type) {
295         case KEY_ACTION_STRING:
296                 fvkbd_key_send_utf8_string(action->u.string);
297                 break;
298
299         case KEY_ACTION_STRING_GROUP:
300                 fvkbd_key_send_utf8_string(action->u.string_group[0]);
301                 break;
302
303         case KEY_ACTION_SYM:
304                 fvkbd_key_send_xkeysym(action->u.sym);
305                 break;
306
307         case KEY_ACTION_FUNC:
308                 switch (action->u.func.type) {
309                 case FVKBD_KEY_FUNC_MODE_SELECT:
310                         fvkbd_key_func_handlers(key, action, &key_mode_do_switch_lock);
311                         need_reset_default_mode = FALSE;
312                         key_mode_do_switch_lock = FALSE;
313                         break;
314
315                 default:
316                         fvkbd_key_func_handlers(key, action, NULL);
317                 }
318
319                 break;
320
321         case KEY_ACTION_SCRIPT:
322                 fvkbd_do_script(action->u.string);
323                 break;
324
325         default:
326                 break;
327         }
328
329         if (fvkbd_in_temp_mode() && need_reset_default_mode)
330                 fvkbd_keyboard_resume_default_mode();
331
332 }
333
334
335 static void
336 fvkbd_key_settle_color (FvkbdUnit *unit, GtkWidget *key_widget, gboolean lock)
337 {
338         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
339         GdkColor color;
340         GtkWidget *label;
341
342         // set key background color
343         if (!lock) {
344                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
345                         vkb_button_set_bg(key_widget, GTK_STATE_NORMAL, &color);
346                         vkb_button_set_bg(key_widget, GTK_STATE_PRELIGHT, &color);
347                 }
348
349                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_FG, &color)) {
350                         vkb_button_set_bg(key_widget, GTK_STATE_ACTIVE, &color);
351                 }
352         } else {
353                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_FG, &color)) {
354                         vkb_button_set_bg(key_widget, GTK_STATE_NORMAL, &color);
355                         vkb_button_set_bg(key_widget, GTK_STATE_PRELIGHT, &color);
356                 }
357
358                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
359                         vkb_button_set_bg(key_widget, GTK_STATE_ACTIVE, &color);
360                 }
361         }
362
363         // set main label color
364         label = ui_data->main_label;
365         if (label) {
366                 if (!lock) {
367                         if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_FG, &color)) {
368                                 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
369                                 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
370                         }
371
372                         if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
373                                 gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &color);
374                         }
375                 } else {
376                         if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
377                                 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
378                                 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
379                         }
380
381                         if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_FG, &color)) {
382                                 gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &color);
383                         }
384                 }
385         }
386
387         // set sub label color
388         label = ui_data->sub_label;
389         if (label) {
390                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_EXTRA_FG, &color)) {
391                         gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
392                         gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
393                 }
394
395                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
396                         gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &color);
397                 }
398         }
399 }
400
401
402 static PangoFontDescription *
403 get_key_pango_font_description (FvkbdUnit *unit, KbdFontType type)
404 {
405         gfloat x_ratio, y_ratio, ratio;
406         int dpi_xres, dpi_yres;
407         FvkbdKeyAction *action = fvkbd_key_get_current_action(FVKBD_KEY(unit));
408         KbdFontInfo *font = NULL;
409
410         PangoFontDescription *desc = NULL;
411
412         if ((type < 0) || (type >= KBD_FONT_TYPE_NUMBER))
413                 return NULL;
414
415         if(G_UNLIKELY(action->unique_font == TRUE))
416                 font = action->font[type];
417
418         if (!font)
419                 font = fvkbd_unit_get_font(unit, type);
420
421         if (!font)
422                 return NULL;
423
424         fvkbd_unit_get_ratio(unit, &x_ratio, &y_ratio);
425         get_resolution(&dpi_xres, &dpi_yres);
426
427         x_ratio = x_ratio * DEFAULT_DPI / dpi_xres;
428         y_ratio = y_ratio * DEFAULT_DPI / dpi_yres;
429
430         ratio = (x_ratio < y_ratio) ? x_ratio : y_ratio;
431
432         desc = get_pango_font_description_from_info(
433                                 font->family,
434                                 font->weight,
435                                 font->size * ratio);
436
437         return desc;
438 }
439
440
441 static void
442 fvkbd_key_settle_font (FvkbdUnit *unit, GtkWidget *key_widget)
443 {
444         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
445         PangoFontDescription *desc;
446         GtkWidget *label;
447
448         // set main label font
449         label = ui_data->main_label;
450         if (label) {
451                 if (!ui_data->font_desc) {
452                         desc = get_key_pango_font_description(unit, KBD_FONT_TYPE_NORMAL);
453                         ui_data->font_desc = desc;
454                 } else
455                         desc = ui_data->font_desc;
456
457                 gtk_widget_modify_font(label, desc);
458         }
459
460         // set sub label font
461         label = ui_data->sub_label;
462         if (label) {
463                 if (!ui_data->efont_desc) {
464                         desc = get_key_pango_font_description(unit, KBD_FONT_TYPE_EXTRA);
465                         ui_data->efont_desc = desc;
466                 } else
467                         desc = ui_data->efont_desc;
468
469                         gtk_widget_modify_font(label, desc);
470         }
471 }
472
473
474 static GtkWidget *
475 _load_and_scale_img (const gchar *file, gfloat x_ratio, gfloat y_ratio)
476 {
477         GdkPixbuf *pixbuf = NULL;
478         GtkWidget *img;
479
480         pixbuf = gdk_pixbuf_new_from_file(file, NULL);
481
482         if (!pixbuf)
483                 return NULL;
484
485         if ((x_ratio > 1.05 || x_ratio < 0.95) ||
486                 (y_ratio > 1.05 || y_ratio < 0.95)) {
487                 int w,h;
488                 GdkPixbuf *tmp;
489
490                 w = gdk_pixbuf_get_width(pixbuf) * x_ratio;
491                 h = gdk_pixbuf_get_height(pixbuf) * y_ratio;
492                 tmp = gdk_pixbuf_scale_simple(pixbuf, w, h, GDK_INTERP_HYPER);
493                 g_object_unref(pixbuf);
494                 pixbuf = tmp;
495         }
496
497         img = gtk_image_new_from_pixbuf(pixbuf);
498         g_object_unref(pixbuf);
499         return img;
500 }
501
502
503 static GtkWidget *
504 _create_key_label (FvkbdUnit *unit, gint id)
505 {
506         FvkbdKey *key;
507         FvkbdKeyAction *action;
508         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
509         gint w,h;
510         gfloat x_ratio, y_ratio, ratio;
511         GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
512         GtkWidget *label = NULL, *sub_label = NULL;
513         GtkWidget *img = NULL, *img_dn = NULL;
514
515         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
516         key = FVKBD_KEY(unit);
517
518         fvkbd_unit_get_size(unit, &w, &h);
519
520         if ((action = fvkbd_key_get_current_action(key)) == NULL)
521                 goto done;
522
523         fvkbd_unit_get_ratio(unit, &x_ratio, &y_ratio);
524         ratio = (x_ratio < y_ratio) ? x_ratio : y_ratio;
525
526         if (action->img != NULL) {
527                 img = _load_and_scale_img(action->img, ratio, ratio);
528                 if (action->img_dn != NULL) {
529                         img_dn = _load_and_scale_img(action->img_dn, ratio, ratio);
530                 }
531
532                 ui_data->img = img;
533                 ui_data->img_dn = img_dn;
534                 
535                 if (ui_data->img) {
536                         g_object_ref_sink(ui_data->img);
537                         gtk_container_add(GTK_CONTAINER(vbox), img);
538                 }
539                 
540                 if (ui_data->img_dn) {
541                         g_object_ref_sink(ui_data->img_dn);
542                 }
543
544                 goto done;
545         }
546
547         if (action->type == KEY_ACTION_STRING_GROUP) {
548                 gchar *label_str = NULL;
549
550                 #if 0
551                 // show all the optional characters
552                 label_str = g_strjoinv(" ", &(action->u.string_group[1]));
553                 #else
554                 // only show the first optional character
555                 label_str = g_strdup(action->u.string_group[1]);
556                 #endif
557
558                 sub_label = gtk_label_new(label_str);
559                 g_free(label_str);
560                 label = gtk_label_new(fvkbd_key_get_disp(key, id));
561         } else if (action->type == KEY_ACTION_STRING ||
562                 action->type == KEY_ACTION_SYM ||
563                 action->type == KEY_ACTION_FUNC ||
564                 action->type == KEY_ACTION_SCRIPT) {
565
566                 sub_label = gtk_label_new(NULL);
567                 label = gtk_label_new(fvkbd_key_get_disp(key, id));
568         }
569
570
571         ui_data->sub_label = sub_label;
572         if (sub_label)
573                 gtk_box_pack_start(GTK_BOX(vbox), sub_label, FALSE, FALSE, 0);
574
575         ui_data->main_label = label;
576         if (label)
577                 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
578
579 done:
580
581         gtk_widget_show_all(vbox);
582         return vbox;
583 }
584
585
586 static void
587 _toggle_key_img (FvkbdKey *key, gboolean down)
588 {
589         GtkWidget *key_widget;
590         GtkWidget *key_label;
591         FvkbdUnit *unit;
592         KeyUI *ui_data;
593         FvkbdKeyAction *action;
594
595         if ((action = fvkbd_key_get_current_action(key)) == NULL)
596                 return;
597
598         if ((action->img == NULL) || (action->img_dn == NULL))
599                 return;
600
601         unit = FVKBD_UNIT(key);
602         ui_data = fvkbd_unit_get_ui_data(unit);
603
604         key_widget = fvkbd_unit_get_widget(unit);
605         
606         key_label = gtk_bin_get_child(GTK_BIN(key_widget));
607
608         if (down) {
609                 gtk_container_remove(GTK_CONTAINER(key_label), ui_data->img);
610                 gtk_container_add(GTK_CONTAINER(key_label), ui_data->img_dn);
611                 gtk_widget_show(ui_data->img_dn);
612         } else {
613                 gtk_container_remove(GTK_CONTAINER(key_label), ui_data->img_dn);
614                 gtk_container_add(GTK_CONTAINER(key_label), ui_data->img);
615                 gtk_widget_show(ui_data->img);
616         }
617 }
618
619
620 static void
621 _update_key_label (FvkbdUnit *unit, gint id)
622 {
623         GtkWidget *key_widget;
624         GtkWidget *key_label;
625         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
626
627         key_widget = fvkbd_unit_get_widget(unit);
628         
629         key_label = gtk_bin_get_child(GTK_BIN(key_widget));
630
631         if (key_label) {
632                 if (ui_data->img) {
633                         g_object_unref(ui_data->img);
634                         ui_data->img = NULL;
635                 }
636
637                 if (ui_data->img_dn) {
638                         g_object_unref(ui_data->img_dn);
639                         ui_data->img_dn = NULL;
640                 }
641
642                 gtk_widget_destroy(key_label);
643                 ui_data->main_label = NULL;
644                 ui_data->sub_label = NULL;
645
646                 key_label = NULL;
647         }
648
649         key_label = _create_key_label(unit, id);
650         gtk_container_add(GTK_CONTAINER(key_widget), key_label);
651 }
652
653
654 static void
655 _set_key_label_tmp_mode (FvkbdUnit *unit)
656 {
657         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
658         GtkWidget *label;
659         gchar *disp;
660
661         label = ui_data->main_label;
662         disp = g_strconcat("<u>", gtk_label_get_text(GTK_LABEL(label)), "</u>", NULL);
663         gtk_label_set_text(GTK_LABEL(label), disp);
664         gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
665         g_free(disp);
666 }
667
668
669 gboolean
670 fvkbd_key_build_ui (FvkbdUnit *unit, gpointer *widget)
671 {
672         FvkbdKey *key;
673         KeyUI *ui_data;
674         gint w,h;
675         gboolean ret = TRUE;
676
677         GtkWidget *key_widget;
678         GtkWidget *key_label;
679
680         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
681         key = FVKBD_KEY(unit);
682
683         key_widget = gtk_vkb_button_new();
684
685         ui_data = g_new0(KeyUI, 1);
686         fvkbd_unit_set_ui_data(unit, ui_data);
687         ui_data->main_label = NULL;
688         ui_data->sub_label = NULL;
689         ui_data->font_desc = NULL;
690         ui_data->efont_desc = NULL;
691         ui_data->ofont_desc = NULL;
692
693         fvkbd_unit_get_size(unit, &w, &h);
694         gtk_widget_set_size_request(key_widget, w, h);
695
696         key_label = _create_key_label(unit, 0);
697         gtk_container_add(GTK_CONTAINER(key_widget), key_label);
698
699         // set color
700         fvkbd_key_settle_color(unit, key_widget, FALSE);
701
702         // set font
703         fvkbd_key_settle_font(unit, key_widget);
704
705         g_signal_connect(G_OBJECT(key_widget), "pressed",
706                         G_CALLBACK(fvkbd_key_gtk_pressed_cb), key);
707         g_signal_connect(G_OBJECT(key_widget), "released",
708                         G_CALLBACK(fvkbd_key_gtk_released_cb), key);
709
710         if (widget != NULL)
711                 *widget = key_widget;
712         fvkbd_unit_set_widget(unit, key_widget);
713         return ret;
714 }
715
716
717 gboolean
718 fvkbd_key_resize_ui (FvkbdUnit *unit, gfloat x_ratio, gfloat y_ratio)
719 {
720         FvkbdKey *key;
721         KeyUI *ui_data;
722         GtkWidget *key_widget;
723         FvkbdKeyAction *action;
724         int tmp_w, tmp_h;
725         int new_w, new_h;
726
727         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
728         key = FVKBD_KEY(unit);
729
730         ui_data = fvkbd_unit_get_ui_data(unit);
731         key_widget = fvkbd_unit_get_widget(unit);
732
733         if (fvkbd_unit_get_size(unit, &tmp_w, &tmp_h) == 0) {
734                 new_w = tmp_w * x_ratio;
735                 new_h = tmp_h * y_ratio;
736                 gtk_widget_set_size_request(key_widget, new_w, new_h);
737
738         } else
739                 return FALSE;
740
741         if ((action = fvkbd_key_get_current_action(key)) == NULL)
742                 return FALSE;
743
744         fvkbd_unit_set_ratio(unit, x_ratio, y_ratio);
745
746         if (action->img != NULL) {
747                 _update_key_label(unit, fvkbd_keyboard_get_current_mode());
748         } else {
749
750                 if (ui_data->font_desc) {
751                         pango_font_description_free(ui_data->font_desc);
752                         ui_data->font_desc = NULL;
753                 }
754                 if (ui_data->efont_desc) {
755                         pango_font_description_free(ui_data->efont_desc);
756                         ui_data->efont_desc = NULL;
757                 }
758                 if (ui_data->ofont_desc) {
759                         pango_font_description_free(ui_data->ofont_desc);
760                         ui_data->ofont_desc = NULL;
761                 }
762
763                 fvkbd_key_settle_font(unit, key_widget);
764         }
765
766         return TRUE;
767 }
768
769
770 gboolean
771 fvkbd_key_destroy_ui (FvkbdUnit *unit)
772 {
773         FvkbdKey *key;
774         KeyUI *ui_data;
775         gboolean ret = TRUE;
776
777         GtkWidget *key_widget;
778
779         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
780         key = FVKBD_KEY(unit);
781
782         key_widget = fvkbd_unit_get_widget(unit);
783
784         gtk_widget_hide_all(key_widget);
785
786         ui_data = fvkbd_unit_get_ui_data(unit);
787         if (ui_data->font_desc)
788                 pango_font_description_free(ui_data->font_desc);
789         if (ui_data->efont_desc)
790                 pango_font_description_free(ui_data->efont_desc);
791         if (ui_data->ofont_desc)
792                 pango_font_description_free(ui_data->ofont_desc);
793         if (ui_data->img)
794                 g_object_unref(ui_data->img);
795         if (ui_data->img_dn)
796                 g_object_unref(ui_data->img_dn);
797
798         g_free(ui_data);
799         fvkbd_unit_set_ui_data(unit, NULL);
800
801         gtk_widget_destroy(key_widget);
802         fvkbd_unit_set_widget(unit, NULL);
803
804         return ret;
805 }
806
807
808 gint
809 fvkbd_key_set_mode (FvkbdUnit *unit, gint id)
810 {
811         FvkbdKey *key;
812         FvkbdKeyAction *action;
813         GtkWidget *key_widget;
814         gboolean show_lock_mode = FALSE;
815
816         g_return_val_if_fail(FVKBD_IS_KEY(unit), -1);
817         key = FVKBD_KEY(unit);
818
819         key_widget = fvkbd_unit_get_widget(unit);
820
821         // Yes, we get the default action here to handle disp diffirently for tmply mode change
822         action = fvkbd_key_get_action(key, 0);
823
824         if ((action->type == KEY_ACTION_FUNC) &&
825                 (action->u.func.type == FVKBD_KEY_FUNC_MODE_SELECT)) {
826                 if ((fvkbd_in_temp_mode()) && ((*((int *)action->u.func.data)) == id)) {
827                         _update_key_label(unit, 0);
828                         _set_key_label_tmp_mode(unit);
829                 } else {
830                         _update_key_label(unit, id);
831                         if ((*((int *)action->u.func.data)) == id)
832                                 show_lock_mode = TRUE;
833                 }
834         } else {
835                 _update_key_label(unit, id);
836         }
837
838         // set color
839         fvkbd_key_settle_color(unit, key_widget, show_lock_mode);
840
841         if (fvkbd_key_get_current_action(key)->unique_font ||
842                 fvkbd_key_get_action(key, fvkbd_keyboard_get_previous_mode())->unique_font) {
843
844                 KeyUI *ui_data;
845
846                 ui_data = fvkbd_unit_get_ui_data(unit);
847
848                 if (ui_data->font_desc) {
849                         pango_font_description_free(ui_data->font_desc);
850                         ui_data->font_desc = NULL;
851                 }
852                 if (ui_data->efont_desc) {
853                         pango_font_description_free(ui_data->efont_desc);
854                         ui_data->efont_desc = NULL;
855                 }
856                 if (ui_data->ofont_desc) {
857                         pango_font_description_free(ui_data->ofont_desc);
858                         ui_data->ofont_desc = NULL;
859                 }
860         }
861
862         // settle font
863         fvkbd_key_settle_font(unit, key_widget);
864
865         return 0;
866 }
867