#include <stdio.h>
#include "SunIM.h"
#include "vkb_aux.h"

enum {
    BUTTON_STATE_NORMAL = 0,
    BUTTON_STATE_FOCUSED,
    BUTTON_STATE_PRESSED,
};

static void vkb_window_init_attributes(vkb_window_t *vkb_window);
static void vkb_window_set_position(vkb_window_t *vkb_window,
					gint pos_x, gint pos_y);
static gboolean vkb_window_expose_event_handler(GtkWidget *widget,
					GdkEventExpose *event,
					vkb_window_t *vkb_window);
static gboolean vkb_window_configure_event_handler(GtkWidget *widget,
					GdkEventConfigure *event,
					vkb_window_t *vkb_window);
static gboolean vkb_window_leave_event_handler(GtkWidget *widget,
					GdkEventCrossing *event,
					vkb_window_t *vkb_window);
static gboolean vkb_window_pointer_motion_event_handler(GtkWidget *widget,
					GdkEventMotion *event,
					vkb_window_t *vkb_window);
static gboolean vkb_window_pointer_press_event_handler(GtkWidget *widget,
					GdkEventButton *event,
					vkb_window_t *vkb_window);
static gboolean vkb_window_pointer_release_event_handler(GtkWidget *widget,
					GdkEventButton *event,
					vkb_window_t *vkb_window);

#define DATA_VKB_AUX_WINDOW_INFO	"vkb_window_info"

vkb_window_t *vkb_window_new()
{
    vkb_window_t *vkb_window = NULL;

    vkb_window = (vkb_window_t *)calloc(1, sizeof (vkb_window_t));
    if (vkb_window == NULL)
        return NULL;

    vkb_window->window = gtk_window_new(GTK_WINDOW_POPUP);
    gtk_window_set_modal (GTK_WINDOW (vkb_window->window), FALSE);
    gtk_window_set_destroy_with_parent (GTK_WINDOW (vkb_window->window), TRUE);

    gtk_container_set_border_width(GTK_CONTAINER(vkb_window->window), 0);

    vkb_window->drawing_area = gtk_drawing_area_new();

    gtk_widget_set_events(vkb_window->drawing_area,
			  GDK_EXPOSURE_MASK |
			  GDK_LEAVE_NOTIFY_MASK |
			  GDK_BUTTON_PRESS_MASK |
			  GDK_BUTTON_RELEASE_MASK |
			  GDK_POINTER_MOTION_MASK);

    g_signal_connect(G_OBJECT(vkb_window->drawing_area),
		     "expose_event",
		     G_CALLBACK(vkb_window_expose_event_handler),
		     (gpointer)vkb_window);

    g_signal_connect(G_OBJECT(vkb_window->drawing_area),
		     "configure_event",
		     G_CALLBACK(vkb_window_configure_event_handler),
		     (gpointer)vkb_window);

    g_signal_connect(G_OBJECT(vkb_window->drawing_area),
		     "leave_notify_event",
		     G_CALLBACK(vkb_window_leave_event_handler),
		     (gpointer)vkb_window);

    g_signal_connect(G_OBJECT(vkb_window->drawing_area),
		     "button_press_event",
		     G_CALLBACK(vkb_window_pointer_press_event_handler),
		     (gpointer)vkb_window);

    g_signal_connect(G_OBJECT(vkb_window->drawing_area),
		     "button_release_event",
		     G_CALLBACK(vkb_window_pointer_release_event_handler),
		     (gpointer)vkb_window);

    g_signal_connect(G_OBJECT(vkb_window->drawing_area),
		     "motion-notify-event",
		     G_CALLBACK(vkb_window_pointer_motion_event_handler),
		     (gpointer)vkb_window);

    gtk_container_add(GTK_CONTAINER(vkb_window->window),
		      vkb_window->drawing_area);

    gtk_widget_realize(GTK_WIDGET(vkb_window->window));

    vkb_window_init_attributes(vkb_window);

    gtk_widget_set_size_request(GTK_WIDGET(vkb_window->drawing_area),
				vkb_window->width,
				vkb_window->height);

    gtk_window_move(GTK_WINDOW(vkb_window->window),
		    vkb_window->pos_x,
		    vkb_window->pos_y);

    return (vkb_window);
}

void
vkb_window_destroy(vkb_window_t *vkb_window)
{
    if (!vkb_window)
	return;

    if (vkb_window->fontdesc_basekey)
	pango_font_description_free(vkb_window->fontdesc_basekey);

    if (vkb_window->fontdesc_ctrlkey)
	pango_font_description_free(vkb_window->fontdesc_ctrlkey);

    if (vkb_window->pango_layout)
	g_object_unref(vkb_window->pango_layout);

    if (vkb_window->moving_cursor)
	gdk_cursor_unref(vkb_window->moving_cursor);

    if (vkb_window->normal_cursor)
	gdk_cursor_unref(vkb_window->normal_cursor);

    if (vkb_window->pixmap)
        gdk_pixmap_unref(vkb_window->pixmap);

    if (vkb_window->window)
	gtk_widget_destroy(vkb_window->window);

    free ((char *)vkb_window);
}

static void
vkb_window_init_attributes(vkb_window_t *vkb_window)
{
    GdkRectangle *buttons;

    int pos_x, pos_y, margin_x, margin_y;
    int height, width, button_height, button_width;
    int delta_y = 1;
    int i, j;

    vkb_window->context = gtk_widget_get_pango_context(vkb_window->drawing_area);
    vkb_window->pango_layout = pango_layout_new(vkb_window->context);

    vkb_window->fontdesc_basekey = pango_font_description_from_string("sans 9");
    vkb_window->fontdesc_ctrlkey = pango_font_description_from_string("sans 10");

    vkb_window->pixmap = NULL;

    vkb_window->moving_cursor = gdk_cursor_new (GDK_FLEUR);
    vkb_window->normal_cursor = gdk_cursor_new (GDK_LEFT_PTR);

    vkb_window->button_id_pressed = -1;
    vkb_window->button_id_focused = -1;

    buttons = vkb_window->buttons;

    button_height = 27;
    button_width = button_height - 1;

    margin_x = 2;
    margin_y = 2;

    /* layout for the first line */
    pos_x = margin_x;
    pos_y = margin_y;

    for (i = VK_quotedbl; i <= VK_equal; i++) {
	width = button_width;
	buttons[i].x = pos_x;
	buttons[i].y = pos_y;
	buttons[i].width = width;
	buttons[i].height = button_height;
	pos_x += width;
    }

    i = VK_BackSpace + MAX_BASEKEY_NUM;
    width = button_width * 2;
    buttons[i].x = pos_x;
    buttons[i].y = pos_y;
    buttons[i].width = width;
    buttons[i].height = button_height;

    /* layout for the second line */
    pos_x = margin_x;
    pos_y += button_height + delta_y;

    i = VK_Tab + MAX_BASEKEY_NUM;
    width = button_width * 3 / 2;
    buttons[i].x = pos_x;
    buttons[i].y = pos_y;
    buttons[i].width = width;
    buttons[i].height = button_height;
    pos_x += width;

    for (i = VK_q; i <= VK_backslash; i++) {
	width = button_width;
	if (i == VK_backslash)
	    width = button_width * 3 / 2;

	buttons[i].x = pos_x;
	buttons[i].y = pos_y;
	buttons[i].width = width;
	buttons[i].height = button_height;
	pos_x += width;
    }

    /* layout for the third line */
    pos_x = margin_x;
    pos_y += button_height + delta_y;

    i = VK_CapsLock + MAX_BASEKEY_NUM;
    width = button_width * 2;
    buttons[i].x = pos_x;
    buttons[i].y = pos_y;
    buttons[i].width = width;
    buttons[i].height = button_height;
    pos_x += width;

    for (i = VK_a; i <= VK_apostrophe; i++) {
	width = button_width;
	buttons[i].x = pos_x;
	buttons[i].y = pos_y;
	buttons[i].width = width;
	buttons[i].height = button_height;
	pos_x += width;
    }

    i = VK_Enter + MAX_BASEKEY_NUM;
    width = button_width * 2;
    buttons[i].x = pos_x;
    buttons[i].y = pos_y;
    buttons[i].width = width;
    buttons[i].height = button_height;
    pos_x += width;

    /* layout for the fourth line */
    pos_x = margin_x;
    pos_y += button_height + delta_y;

    i = VK_Shift_L + MAX_BASEKEY_NUM;
    width = button_width * 5 / 2;
    buttons[i].x = pos_x;
    buttons[i].y = pos_y;
    buttons[i].width = width;
    buttons[i].height = button_height;
    pos_x += width;

    for (i = VK_z; i <= VK_slash; i++) {
	width = button_width;
	buttons[i].x = pos_x;
	buttons[i].y = pos_y;
	buttons[i].width = width;
	buttons[i].height = button_height;
	pos_x += width;
    }

    /* layout for the fifth line */
    pos_x = margin_x;
    pos_y += button_height + delta_y;

    for (i = VK_Control_L; i <= VK_Escape; i++) {
	width = 2 * button_width;
	if (i == VK_Space)
	    width = 7 * button_width;
	if (i == VK_Escape)
	    pos_x += 2 * button_width;
	j = i + MAX_BASEKEY_NUM;
	buttons[j].x = pos_x;
	buttons[j].y = pos_y;
	buttons[j].width = width;
	buttons[j].height = button_height;
	pos_x += width;
    }

    /* Calculate the frame dimension of the Virtual keyboard */
    width = 15 * button_width + 2 * margin_x;
    height = 5 * button_height + 2 * margin_y + 4 * delta_y;

    vkb_window->width = width;
    vkb_window->height = height;

    vkb_window->pos_x = gdk_screen_width() - vkb_window->width;
    vkb_window->pos_y = gdk_screen_height() - vkb_window->height - 70;

    vkb_window->draging = FALSE;
    vkb_window->draw_draging_frame = TRUE;
}

static void
vkb_window_draw_button(vkb_window_t *vkb_window,
		       int button_id,
		       int button_state)
{
    GdkGC *label_gc;
    GdkRectangle *rect;
    GtkShadowType shadow_type = GTK_SHADOW_OUT;
    GtkStateType  state_type = GTK_STATE_NORMAL;
    GdkRectangle *buttons = vkb_window->buttons;
    int pos_x, pos_y;

    gchar *str;

    if (!vkb_window || !vkb_window->pixmap)
	return;

    if (button_id < 0 || button_id >= MAX_VK_NUM)
	return;

    rect = &buttons[button_id];

    if (button_state == BUTTON_STATE_PRESSED) {
	state_type = GTK_STATE_ACTIVE;
	shadow_type = GTK_SHADOW_IN;
    } else if (button_state == BUTTON_STATE_FOCUSED) {
	state_type = GTK_STATE_PRELIGHT;
	shadow_type = GTK_SHADOW_OUT;
    }

    /* draw button frame */
    gtk_paint_box(vkb_window->drawing_area->style, vkb_window->pixmap,
		  state_type, shadow_type,
		  NULL, vkb_window->drawing_area, "button",
		  rect->x, rect->y, rect->width, rect->height);

    if (!vkb_window->layout)
	return;

    label_gc = vkb_window->drawing_area->style->text_gc[GTK_STATE_NORMAL];

    if (button_id >= MAX_BASEKEY_NUM) {
	/* if is Control Keys */
	str = vkb_window->layout->ctrlkey[button_id - MAX_BASEKEY_NUM].label_str;
	if (str && *str) {
	    PangoRectangle logical_rect;
	    int str_width, str_height;

	    pango_layout_set_font_description(vkb_window->pango_layout,
					      vkb_window->fontdesc_ctrlkey);
	    pango_layout_set_text(vkb_window->pango_layout, str, strlen(str));
	    pango_layout_get_extents(vkb_window->pango_layout, NULL, &logical_rect);

	    str_width = PANGO_PIXELS(logical_rect.width);
	    str_height = PANGO_PIXELS(logical_rect.height);
	    pos_x = rect->x + (rect->width - str_width)/2;
	    pos_y = rect->y + (rect->height - str_height)/2;
	    gdk_draw_layout(vkb_window->pixmap, label_gc,
			    pos_x, pos_y, vkb_window->pango_layout);
	}
    } else {
	/* if is Base Keys */
	str = vkb_window->layout->basekey[button_id].lower_str;
        if(!strcmp(str, "\\"))
	{
	        g_unichar_to_utf8(0x20a9, str);
                str[3] = '\0';
                str[4] = '\0';
	}
	pango_layout_set_font_description(vkb_window->pango_layout,
				 	  vkb_window->fontdesc_basekey);
	if (str && *str) {
	    pango_layout_set_text(vkb_window->pango_layout, str, strlen(str));
	    pos_x = rect->x + 2;
	    pos_y = rect->y + 11;
	    gdk_draw_layout(vkb_window->pixmap, label_gc,
			    pos_x, pos_y, vkb_window->pango_layout);
	}

	str = vkb_window->layout->basekey[button_id].upper_str;
	if (str && *str) {
	    pango_layout_set_text(vkb_window->pango_layout, str, strlen(str));
	    pos_x = rect->x + rect->width - 14;
	    pos_y = rect->y + 1;
	    gdk_draw_layout(vkb_window->pixmap, label_gc,
			    pos_x, pos_y, vkb_window->pango_layout);
	}
    }

    return;
}

void vkb_window_draw_layout(vkb_window_t *vkb_window)
{

    gint button_id;
    gint ctrl_button_id;
    gint button_state;

    if (!vkb_window || !vkb_window->pixmap)
	return;

    gtk_paint_box(vkb_window->drawing_area->style, vkb_window->pixmap,
		  GTK_STATE_NORMAL, GTK_SHADOW_OUT,
		  NULL, vkb_window->drawing_area, "button",
		  0, 0,
		  vkb_window->width,
		  vkb_window->height);

    for (button_id = 0; button_id < MAX_VK_NUM; button_id ++) {
        button_state = BUTTON_STATE_NORMAL;

	if (button_id >= MAX_BASEKEY_NUM) {
	    /* if is Control Keys */
	    ctrl_button_id = button_id - MAX_BASEKEY_NUM;
	    if (ctrl_button_id == VK_CapsLock) {
		if (vkb_window->status_capslockkey)
		    button_state = BUTTON_STATE_PRESSED;
	    } else if (ctrl_button_id == VK_Control_L) {
		if (vkb_window->status_ctrlkey)
		    button_state = BUTTON_STATE_PRESSED;
	    } else if (ctrl_button_id == VK_Shift_L) {
		if (vkb_window->status_shiftkey)
		    button_state = BUTTON_STATE_PRESSED;
	    } else if (ctrl_button_id == VK_Alt_L) {
		if (vkb_window->status_altkey)
		    button_state = BUTTON_STATE_PRESSED;
	    }
	} else if (button_id == vkb_window->button_id_pressed) {
	    button_state = BUTTON_STATE_PRESSED;
	}

	vkb_window_draw_button(vkb_window, button_id, button_state);
    }
}

void vkb_window_update_layout(vkb_window_t *vkb_window,
			      vkb_layout_t *vkb_layout)
{
    if (!vkb_window)
	return;

    if (vkb_layout == NULL) {
	gtk_widget_hide(vkb_window->window);
	return;
    }

    vkb_window->layout = vkb_layout;

    vkb_window_draw_layout(vkb_window);

    gtk_widget_show_all(vkb_window->window);
    gtk_widget_queue_draw(vkb_window->drawing_area);
}

static gboolean vkb_window_rect_has_pos(GdkRectangle * rect, int x, int y)
{
    return ((rect->x <= x) && (rect->x + rect->width >= x) &&
	    (rect->y <= y) && (rect->y + rect->height >= y));
}

static gint vkb_window_get_button_id_from_pos(vkb_window_t *vkb_window, int x, int y)
{
    gint i;
    for (i = 0; i < MAX_VK_NUM; i++) {
	if (vkb_window_rect_has_pos(&vkb_window->buttons[i], x, y))
	    return i;
    }
    return -1;
}

static void
vkb_window_set_position(vkb_window_t *vkb_window,
			gint pos_x, gint pos_y)
{
    GtkRequisition ws;
    gint screen_width;
    gint screen_height;

    gtk_widget_size_request(vkb_window->window, &ws);

    screen_width = gdk_screen_width();
    screen_height = gdk_screen_height();

    if (pos_x < 0) {
        pos_x = 0;
    } else if (pos_x + ws.width > screen_width) {
        pos_x = screen_width - ws.width;
    }

    if (pos_y < 0) {
        pos_y = 0;
    } else if (pos_y + ws.height > screen_height) {
        pos_y = screen_height - ws.height;
    }

    if (vkb_window->pos_x != pos_x || vkb_window->pos_y != pos_y) {
        gtk_window_move(GTK_WINDOW(vkb_window->window), pos_x, pos_y);
        vkb_window->pos_x = pos_x;
        vkb_window->pos_y = pos_y;
    }
}

/********************************************************************/
/*       key status functions                                       */
/********************************************************************/
static int vkb_base_keycode[MAX_BASEKEY_NUM] = {
    IM_VK_BACK_QUOTE,
    IM_VK_1,
    IM_VK_2,
    IM_VK_3,
    IM_VK_4,
    IM_VK_5,
    IM_VK_6,
    IM_VK_7,
    IM_VK_8,
    IM_VK_9,
    IM_VK_0,
    IM_VK_MINUS,
    IM_VK_EQUALS,

    IM_VK_Q,
    IM_VK_W,
    IM_VK_E,
    IM_VK_R,
    IM_VK_T,
    IM_VK_Y,
    IM_VK_U,
    IM_VK_I,
    IM_VK_O,
    IM_VK_P,
    IM_VK_OPEN_BRACKET,
    IM_VK_CLOSE_BRACKET,
    IM_VK_BACK_SLASH,

    IM_VK_A,
    IM_VK_S,
    IM_VK_D,
    IM_VK_F,
    IM_VK_G,
    IM_VK_H,
    IM_VK_J,
    IM_VK_K,
    IM_VK_L,
    IM_VK_SEMICOLON,
    IM_VK_QUOTE,

    IM_VK_Z,
    IM_VK_X,
    IM_VK_C,
    IM_VK_V,
    IM_VK_B,
    IM_VK_N,
    IM_VK_M,
    IM_VK_COMMA,
    IM_VK_PERIOD, 
    IM_VK_SLASH,
};

static int vkb_ctrl_keycode[MAX_CTRLKEY_NUM] = {
    IM_VK_BACK_SPACE,
    IM_VK_TAB,
    IM_VK_CAPS_LOCK,
    IM_VK_ENTER,
    0,
    0,
    0,
    IM_VK_SPACE,
    IM_VK_ESCAPE
};

void vkb_window_clear_keystatus(vkb_window_t *vkb_window)
{
    vkb_window->status_ctrlkey = 0;
    vkb_window->status_shiftkey = 0;
    vkb_window->status_altkey = 0;

    return;
}

void vkb_window_get_keyevent(vkb_window_t *vkb_window,
			     int button_id,
			     int *keycode,
			     int *keychar,
			     int *keystatus)
{
    char *keychar_list;

    *keycode = 0;
    *keychar = 0;
    *keystatus = 0;

    if (button_id < 0 || button_id >= MAX_VK_NUM)
	return;

    if (button_id >= MAX_BASEKEY_NUM) {
	*keycode = vkb_ctrl_keycode[button_id - MAX_BASEKEY_NUM];
	*keychar = 0;
	if (button_id - MAX_BASEKEY_NUM == VK_Space)
	    *keychar = 0x20;
    } else {
	*keycode = vkb_base_keycode[button_id];

	keychar_list = (char *)KEYLIST_LOWER;
	if (vkb_window->status_capslockkey ^ vkb_window->status_shiftkey)
	    keychar_list = (char *)KEYLIST_UPPER;
	*keychar = *(keychar_list + button_id);
    } 

    if (vkb_window->status_ctrlkey)
	*keystatus |= IM_CTRL_MASK;
    if (vkb_window->status_shiftkey)
	*keystatus |= IM_SHIFT_MASK;
    if (vkb_window->status_altkey)
	*keystatus |= IM_ALT_MASK;

    return;
}

void vkb_window_redraw_ctrl_buttons(vkb_window_t *vkb_window)
{
    int button_id, button_state;

    for (button_id = MAX_BASEKEY_NUM; button_id < MAX_VK_NUM; button_id++) {
	button_state = BUTTON_STATE_NORMAL;
        if (button_id - MAX_BASEKEY_NUM == VK_CapsLock) {
	    if (vkb_window->status_capslockkey)
		button_state = BUTTON_STATE_PRESSED;
        } else if (button_id - MAX_BASEKEY_NUM == VK_Control_L) {
	    if (vkb_window->status_ctrlkey)
		button_state = BUTTON_STATE_PRESSED;
        } else if (button_id - MAX_BASEKEY_NUM == VK_Shift_L) {
	    if (vkb_window->status_shiftkey)
		button_state = BUTTON_STATE_PRESSED;
        } else if (button_id - MAX_BASEKEY_NUM == VK_Alt_L) {
	    if (vkb_window->status_altkey)
		button_state = BUTTON_STATE_PRESSED;
        }

	vkb_window_draw_button(vkb_window, button_id, button_state);
    }
    gtk_widget_queue_draw(vkb_window->drawing_area);
    return;
}

void vkb_window_press_key(vkb_window_t *vkb_window,
			  int button_id_pressed)
{
    int keycode, keychar, keystatus;
    char *commit_str, *keylist_str, base_str[2];
    int ctrl_key_id;
    int button_state = BUTTON_STATE_NORMAL;

    DEBUG_printf("vkb_window_press_key() is called\n");

    if (vkb_window == NULL || vkb_window->layout == NULL)
        return;

    if (button_id_pressed < 0 || button_id_pressed >= MAX_VK_NUM)
        return;

    if (button_id_pressed >= MAX_BASEKEY_NUM) {
	/* if is Control Keys, set key status or commit as virtual key. */
	ctrl_key_id = button_id_pressed - MAX_BASEKEY_NUM;

	if (ctrl_key_id == VK_BackSpace ||
            ctrl_key_id == VK_Tab ||
            ctrl_key_id == VK_Enter ||
            ctrl_key_id == VK_Space ||
            ctrl_key_id == VK_Escape) {
            /* if not Control status key, commit as key event */
            vkb_window_get_keyevent(vkb_window, button_id_pressed,
				    &keycode, &keychar, &keystatus);
            palette_aux_Commit_Key_Request(keycode, keychar, keystatus);
            vkb_window_clear_keystatus(vkb_window);
        } else if (ctrl_key_id == VK_CapsLock) {
	    vkb_window->status_capslockkey = vkb_window->status_capslockkey ? 0 : 1;
        } else if (ctrl_key_id == VK_Control_L) {
	    vkb_window->status_ctrlkey = vkb_window->status_ctrlkey ? 0 : 1;
        } else if (ctrl_key_id == VK_Shift_L) {
	    vkb_window->status_shiftkey = vkb_window->status_shiftkey ? 0 : 1;
        } else if (ctrl_key_id == VK_Alt_L) {
	    vkb_window->status_altkey = vkb_window->status_altkey ? 0 : 1;
        }

	/* redraw the pressed button */
	vkb_window_redraw_ctrl_buttons(vkb_window);
	return;
    }

    if (vkb_window->layout->type == KEYBOARD_KEY_TYPE) {
        vkb_window_get_keyevent(vkb_window, button_id_pressed,
				&keycode, &keychar, &keystatus);
        palette_aux_Commit_Key_Request(keycode, keychar, keystatus);
    } else {
	if (vkb_window->status_ctrlkey || vkb_window->status_altkey) {
            vkb_window_get_keyevent(vkb_window, button_id_pressed,
				    &keycode, &keychar, &keystatus);
            palette_aux_Commit_Key_Request(keycode, keychar, keystatus);
	} else {
	    if (vkb_window->status_capslockkey ^ vkb_window->status_shiftkey) {
		/* commit upper string */
		commit_str = vkb_window->layout->basekey[button_id_pressed].upper_str;
		if (!commit_str || !*commit_str) {
		    keylist_str = (char *)KEYLIST_UPPER;
		    base_str[0] = *(keylist_str + button_id_pressed);
		    base_str[1] = 0;
		    commit_str = base_str;
		}
	    } else {
		/* commit lower string */
		commit_str = vkb_window->layout->basekey[button_id_pressed].lower_str;
		if (!commit_str || !*commit_str) {
		    keylist_str = (char *)KEYLIST_LOWER;
		    base_str[0] = *(keylist_str + button_id_pressed);
		    base_str[1] = 0;
		    commit_str = base_str;
		}
	    }
	    palette_aux_Commit_String_Request(commit_str);
	}
    }

    vkb_window_clear_keystatus(vkb_window);
    vkb_window_draw_button(vkb_window, button_id_pressed, BUTTON_STATE_NORMAL);
    vkb_window_redraw_ctrl_buttons(vkb_window);
    return;
}

/********************************************************************/
/*       draging functions                                          */
/********************************************************************/
static void
vkb_window_draw_draging_frame(vkb_window_t *vkb_window,
			      int pos_x, int pos_y)
{
    GdkGC *xor_gc;
    GdkGCValues values;
    GdkWindow *root_window;

    values.foreground = (vkb_window->drawing_area->style->white.pixel==0 ?
                         vkb_window->drawing_area->style->black:
			 vkb_window->drawing_area->style->white);
    values.function = GDK_XOR;
    values.subwindow_mode = GDK_INCLUDE_INFERIORS; 

    root_window = gtk_widget_get_root_window (vkb_window->drawing_area);
    xor_gc = gdk_gc_new_with_values (root_window,
                                     &values,
                                     GDK_GC_FOREGROUND |
                                     GDK_GC_FUNCTION |
                                     GDK_GC_SUBWINDOW);

    gdk_draw_rectangle (root_window, xor_gc, FALSE,
                        pos_x, pos_y,
                        vkb_window->width - 1,
                        vkb_window->height - 1);
}

static void
vkb_window_begin_draging(vkb_window_t *vkb_window,
			     GdkEventButton *event)
{
    /* begin draging */
    vkb_window->drag_x_start = (gint) event->x_root;
    vkb_window->drag_y_start = (gint) event->y_root;
    vkb_window->drag_x_save = (gint) event->x_root;
    vkb_window->drag_y_save = (gint) event->y_root;

    /* Grab the cursor to prevent losing events. */
    gdk_pointer_grab (vkb_window->drawing_area->window, FALSE,
		      GDK_BUTTON_RELEASE_MASK |
		      GDK_POINTER_MOTION_MASK,
		      NULL, vkb_window->moving_cursor, event->time);

    vkb_window_draw_draging_frame(vkb_window,
                                  vkb_window->pos_x,
                                  vkb_window->pos_y);

    return;
}

static void
vkb_window_end_draging(vkb_window_t *vkb_window,
		       GdkEventButton *event)
{
    gint pos_x, pos_y;

    if (vkb_window->draw_draging_frame) {
        pos_x = vkb_window->pos_x;
        pos_y = vkb_window->pos_y;

        pos_x += ((gint) event->x_root - vkb_window->drag_x_start);
        pos_y += ((gint) event->y_root - vkb_window->drag_y_start);

        vkb_window_set_position(vkb_window, pos_x, pos_y);
        gtk_widget_queue_draw(vkb_window->drawing_area);
    }

    gdk_pointer_ungrab(event->time);

    return;
}

static void
vkb_window_do_draging(vkb_window_t *vkb_window,
		      GdkEventMotion *event)
{
    gint pos_x, pos_y;

    pos_x = vkb_window->pos_x;
    pos_y = vkb_window->pos_y;

    if (vkb_window->draw_draging_frame) {
	/* remove the old draging frame */
        pos_x += (vkb_window->drag_x_save - vkb_window->drag_x_start);
        pos_y += (vkb_window->drag_y_save - vkb_window->drag_y_start);
        vkb_window_draw_draging_frame(vkb_window,
				          pos_x, pos_y);

	/* draw the new draging frame */
        pos_x += (event->x_root - vkb_window->drag_x_save);
        pos_y += (event->y_root - vkb_window->drag_y_save);
        vkb_window_draw_draging_frame(vkb_window,
				          pos_x, pos_y);
    } else {
        pos_x += ((gint) event->x_root - vkb_window->drag_x_start);
        pos_y += ((gint) event->y_root - vkb_window->drag_y_start);

	vkb_window->drag_x_start = event->x_root;
	vkb_window->drag_y_start = event->y_root;

	/* directly move the vkb window */
        vkb_window_set_position(vkb_window, pos_x, pos_y);
    }

    /* save the curent draging pointer position */
    vkb_window->drag_x_save = event->x_root;
    vkb_window->drag_y_save = event->y_root;
}

/********************************************************************/
/*            event functions                                       */
/********************************************************************/
static gboolean
vkb_window_expose_event_handler(GtkWidget *widget,
				GdkEventExpose *event,
				vkb_window_t *vkb_window)
{
    DEBUG_printf("vkb_window_expose_event_handler =\n");
    if (!vkb_window->pixmap)
	return FALSE;

    gdk_draw_drawable(vkb_window->drawing_area->window,
		      widget->style->base_gc[GTK_STATE_NORMAL],
		      vkb_window->pixmap,
		      event->area.x, event->area.y,
		      event->area.x, event->area.y,
		      event->area.width, event->area.height);
    return FALSE;
}

static gboolean
vkb_window_configure_event_handler(GtkWidget *widget,
				   GdkEventConfigure *event,
				   vkb_window_t *vkb_window)
{
    DEBUG_printf("vkb_window_configure_event_handler =\n");
    if (vkb_window->pixmap)
        gdk_pixmap_unref(vkb_window->pixmap);

    vkb_window->pixmap = gdk_pixmap_new(widget->window,
                            widget->allocation.width,
                            widget->allocation.height,
                            -1);

    vkb_window_draw_layout(vkb_window);

    return TRUE;
}

static gboolean
vkb_window_leave_event_handler(GtkWidget *widget,
			       GdkEventCrossing *event,
			       vkb_window_t *vkb_window)
{
    DEBUG_printf("vkb_window_leave_event_handler =\n");

    /* if any button already pressed then do nothing */
    if (vkb_window->button_id_pressed != -1)
	return TRUE;

    /* reset the old focus button */
    if (vkb_window->button_id_focused != -1) {
        vkb_window_draw_button(vkb_window, vkb_window->button_id_focused,
			       BUTTON_STATE_NORMAL);
        gtk_widget_queue_draw(vkb_window->drawing_area);
    }

    vkb_window->button_id_focused = -1;

    return TRUE;
}

static gboolean
vkb_window_pointer_press_event_handler(GtkWidget *widget,
				       GdkEventButton *event,
				       vkb_window_t *vkb_window)
{
    gint button_id_pressed;

    DEBUG_printf("vkb_window_pointer_press_event_handler =\n");
    if (!vkb_window)
	return TRUE;

    if (event->button > 1)
	return TRUE;
    
    if (vkb_window->draging)
	return TRUE;

    button_id_pressed = vkb_window_get_button_id_from_pos(vkb_window, event->x, event->y);
    if (button_id_pressed == -1) {
        vkb_window->draging = TRUE;
	vkb_window_begin_draging(vkb_window, event);
    } else {
        vkb_window->button_id_pressed = button_id_pressed;
        vkb_window_draw_button(vkb_window, button_id_pressed, BUTTON_STATE_PRESSED);
        gtk_widget_queue_draw(vkb_window->drawing_area);
    }

    return TRUE;
}

static gboolean
vkb_window_pointer_release_event_handler(GtkWidget *widget,
					 GdkEventButton *event,
					 vkb_window_t *vkb_window)
{
    int button_id_pressed;
    int button_id_released;

    DEBUG_printf("vkb_window_pointer_release_event_handler =\n");
    if (!vkb_window)
	return TRUE;

    if (event->button > 1)
	return TRUE;
    
    /* button released */
    if (vkb_window->draging == TRUE) {
        vkb_window->draging = FALSE;
	vkb_window_end_draging(vkb_window, event);
	return TRUE;
    }

    button_id_pressed = vkb_window->button_id_pressed;
    button_id_released = vkb_window_get_button_id_from_pos(vkb_window, event->x, event->y);

    vkb_window->draging = FALSE;
    vkb_window->button_id_pressed = -1;

    if (button_id_pressed == button_id_released) {
	/* begin process the key release event on the button */
	vkb_window_press_key(vkb_window, button_id_pressed);
    } else {
	/* redraw the pressed and released buttons */
        vkb_window_draw_button(vkb_window, button_id_pressed, BUTTON_STATE_NORMAL);
        vkb_window_draw_button(vkb_window, button_id_released, BUTTON_STATE_FOCUSED);
        gtk_widget_queue_draw(vkb_window->drawing_area);
    }

    return TRUE;
}

static gboolean
vkb_window_pointer_motion_event_handler(GtkWidget *widget,
					GdkEventMotion *event,
					vkb_window_t *vkb_window)
{
    if (!vkb_window)
	return TRUE;

    if ((event->state & GDK_BUTTON1_MASK) != 0 &&
        vkb_window->draging) {
	/* in draging status */
        vkb_window_do_draging(vkb_window, event);
    } else {
	int button_id;

	/* if any button already pressed then do nothing */
	if (vkb_window->button_id_pressed != -1)
	    return TRUE;

        button_id = vkb_window_get_button_id_from_pos(vkb_window, event->x, event->y);
	if (button_id == vkb_window->button_id_focused)
	    return TRUE;

	/* set the cursor for button/draging area */
	if (button_id == -1) {
            gdk_window_set_cursor(vkb_window->drawing_area->window,
                                  vkb_window->moving_cursor);
        } else {
            gdk_window_set_cursor(vkb_window->drawing_area->window,
                                  vkb_window->normal_cursor);
        }

	/* reset the old focus button */
	if (vkb_window->button_id_focused != -1)
	    vkb_window_draw_button(vkb_window, vkb_window->button_id_focused,
				   BUTTON_STATE_NORMAL);

	/* draw the new focus button */
	if (button_id != -1)
	    vkb_window_draw_button(vkb_window, button_id,
				   BUTTON_STATE_FOCUSED);

        vkb_window_redraw_ctrl_buttons(vkb_window);
	vkb_window->button_id_focused = button_id;
    }

    return TRUE;
}
