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