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