#include <stdio.h>
#include "palette_pixmap.h"
#include "palette_messages.h"
#include "palette_aux.h"

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

char **pixmaps[PIXMAPS_NUM] = {
    default_ime_xpm,
    dragarea_vertical_xpm,
    dragarea_horizontal_xpm,
    halfwidth_xpm,
    fullwidth_xpm,
    en_punct_xpm,
    ch_punct_xpm,
    keyboard_xpm,
    options_xpm
};

char *palette_tooltips[BUTTONS_NUM] = {
    TOOLTIPS_STR_FOR_GRAG_BUTTON,
    TOOLTIPS_STR_FOR_IME_BUTTON,
    TOOLTIPS_STR_FOR_QJBJ_BUTTON,
    TOOLTIPS_STR_FOR_PUNCT_BUTTON,
    TOOLTIPS_STR_FOR_VKB_BUTTON,
    TOOLTIPS_STR_FOR_UTILITY_BUTTON
};

#define TIMEOUT_SAVE_PROPERTIES  10000

void palette_window_update_layout(palette_window_t *palette_window);
void palette_window_hide_vkb_window(palette_window_t *palette_window);
static void palette_window_init_attributes(palette_window_t *palette_window);
gboolean palette_window_save_properties_timer_cb(palette_window_t *palette_window);
void palette_window_draw_layout(palette_window_t *palette_window);
GdkPixbuf *palette_window_new_pixbuf_from_xpm(char *xpm_file,
					const char **xpm,
                                        int width,
                                        int height,
                                        gboolean force_create);
void palette_window_set_position(palette_window_t *palette_window,
				 gint pos_x, gint pos_y);
static void palette_window_destroy_event_handler(GtkWidget *widget,
					palette_window_t *palette_window);
static gboolean palette_window_expose_event_handler(GtkWidget *widget,
					GdkEventExpose *event,
					palette_window_t *palette_window);
static gboolean palette_window_configure_event_handler(GtkWidget *widget,
					GdkEventConfigure *event,
					palette_window_t *palette_window);
static gboolean palette_window_leave_event_handler(GtkWidget *widget,
					GdkEventCrossing *event,
					palette_window_t *palette_window);
static gboolean palette_window_pointer_motion_event_handler(GtkWidget *widget,
					GdkEventMotion *event,
					palette_window_t *palette_window);
static gboolean palette_window_pointer_press_event_handler(GtkWidget *widget,
					GdkEventButton *event,
					palette_window_t *palette_window);
static gboolean palette_window_pointer_release_event_handler(GtkWidget *widget,
					GdkEventButton *event,
					palette_window_t *palette_window);

palette_window_t *palette_window_new()
{
    palette_window_t *palette_window = NULL;

    palette_window = (palette_window_t *)calloc(1, sizeof (palette_window_t));
    if (palette_window == NULL)
        return NULL;

    palette_window->window = gtk_window_new(GTK_WINDOW_POPUP);
    gtk_window_set_resizable(GTK_WINDOW(palette_window->window), FALSE);
    gtk_container_set_border_width(GTK_CONTAINER(palette_window->window), 0);

    palette_window->drawing_area = gtk_drawing_area_new();

    gtk_widget_set_events(palette_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(palette_window->window),
		     "destroy",
		     G_CALLBACK(palette_window_destroy_event_handler),
		     (gpointer)palette_window);

    g_signal_connect(G_OBJECT(palette_window->drawing_area),
		     "expose_event",
		     G_CALLBACK(palette_window_expose_event_handler),
		     (gpointer)palette_window);

    g_signal_connect(G_OBJECT(palette_window->drawing_area),
		     "configure_event",
		     G_CALLBACK(palette_window_configure_event_handler),
		     (gpointer)palette_window);

    g_signal_connect(G_OBJECT(palette_window->drawing_area),
		     "leave_notify_event",
		     G_CALLBACK(palette_window_leave_event_handler),
		     (gpointer)palette_window);

    g_signal_connect(G_OBJECT(palette_window->drawing_area),
		     "button_press_event",
		     G_CALLBACK (palette_window_pointer_press_event_handler),
		     (gpointer)palette_window);

    g_signal_connect(G_OBJECT(palette_window->drawing_area),
		     "button_release_event",
		     G_CALLBACK (palette_window_pointer_release_event_handler),
		     (gpointer)palette_window);

    g_signal_connect(G_OBJECT (palette_window->drawing_area),
		     "motion-notify-event",
		     G_CALLBACK (palette_window_pointer_motion_event_handler),
		     (gpointer)palette_window);

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

#ifndef STANDALONE_DEBUG
    gtk_widget_realize(GTK_WIDGET(palette_window->window));
#else
    gtk_widget_show_all(GTK_WIDGET(palette_window->window));
#endif

    palette_window_init_attributes(palette_window);

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

    return palette_window;
}

void
palette_window_destroy(palette_window_t *palette_window)
{
    int i;

    if (!palette_window)
	return;

    if (palette_window->font_desc)
	pango_font_description_free(palette_window->font_desc);

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

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

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

    if (palette_window->moving_cursor)
        gdk_cursor_unref (palette_window->normal_cursor);

    if (palette_window->ime_list_menu)
	gtk_widget_destroy(palette_window->ime_list_menu);

    if (palette_window->vkb_list_menu)
	gtk_widget_destroy(palette_window->vkb_list_menu);

    if (palette_window->vkb_layout_list)
	vkb_layout_list_destroy(palette_window->vkb_layout_list);

    if (palette_window->vkb_window)
	vkb_window_destroy(palette_window->vkb_window);

    if (palette_window->timer_save_properties)
	g_source_remove (palette_window->timer_save_properties);

    if (palette_window->property_data)
	property_data_destroy(palette_window->property_data);

    if (palette_window->property_window)
	property_window_destroy(palette_window->property_window);

    if (palette_window->utility_list_menu)
	gtk_widget_destroy(palette_window->utility_list_menu);

    if (palette_window->about_dialog)
	gtk_widget_destroy(palette_window->about_dialog);

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

    /* destroy the pixmaps for buttons. */
    for (i = 0; i < PIXMAPS_NUM; i++) {
	if (palette_window->pixbufs[i])
	    gdk_pixbuf_unref(palette_window->pixbufs[i]);
    }

    free ((char *)palette_window);
}

static void
palette_window_init_attributes(palette_window_t *palette_window)
{
    int i;
    palette_button_t *buttons;

    palette_window->context = gtk_widget_get_pango_context(palette_window->drawing_area);

    palette_window->font_desc = pango_font_description_from_string("sans 10");

    palette_window->pango_layout = pango_layout_new(palette_window->context);
    pango_layout_set_font_description(palette_window->pango_layout, palette_window->font_desc);

    palette_window->pixmap = NULL;

    palette_window->tooltips = gtk_tooltips_new();

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

    /* initialize the pixmaps for buttons. */
    for (i = 0; i < PIXMAPS_NUM; i++) {
        palette_window->pixbufs[i] = palette_window_new_pixbuf_from_xpm(NULL,
								(const char **)pixmaps[i],
								-1, -1, FALSE);
    }

    buttons = palette_window->buttons;
    for (i = 0; i < BUTTONS_NUM; i++) {
	buttons[i].button_id = i;
	buttons[i].enabled = TRUE;
	buttons[i].activated = TRUE;
    }

    palette_window->pressed_button = NULL;
    palette_window->focused_button = NULL;

    palette_window->ime_list_menu = NULL;
    palette_window->current_ime = NULL;
    palette_window->ime_draw_style = IME_DRAW_ICON_ONLY,

    palette_window->vkb_list_menu = NULL;
    palette_window->vkb_layout_list_inited = 0;
    palette_window->vkb_layout_list = NULL;
    palette_window->current_vkb_layout = NULL;
    palette_window->vkb_window = NULL;
    palette_window->vkb_show_status = 0;

    palette_window->utility_list_menu = NULL;

    palette_window->property_data = NULL;
    palette_window->property_window = NULL;
    palette_window->timer_save_properties = g_timeout_add(TIMEOUT_SAVE_PROPERTIES,
			(GSourceFunc) palette_window_save_properties_timer_cb, 
			(gpointer) palette_window);

    palette_window->about_dialog = NULL;

    palette_window->show_style = SHOW_STYLE_HORIZONTAL;

    palette_window->qjbj_status = 0;
    palette_window->punct_status = 0;

    palette_window->menu_popuped = 0;

    palette_window_update_layout(palette_window);

    palette_window->pos_x = gdk_screen_width() - palette_window->width - 110;
    palette_window->pos_y = gdk_screen_height() - palette_window->height - 40;

    palette_window->draging = FALSE;
    palette_window->draw_draging_frame = TRUE;
    return;
}

/********************************************************************/
/*       palette window utility functions                           */
/********************************************************************/
GdkPixbuf *palette_window_new_pixbuf_from_xpm(char *xpm_file,
					      const char **xpm,
                                              int width,
                                              int height,
                                              gboolean force_create)
{
    GdkPixbuf *pixbuf = NULL;
    int width_pixbuf;
    int height_pixbuf;

    if (xpm_file && *xpm_file) {
	pixbuf = gdk_pixbuf_new_from_file(xpm_file, 0);
    }

    if (!pixbuf && xpm) {
	pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
    }

    if (!pixbuf && !force_create)
        return 0;

    if (!pixbuf) {
        if (width <= 0 || height <= 0)
            return 0;

        pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
        if (!pixbuf)
            return 0;

        gdk_pixbuf_fill(pixbuf, 0);
    }

    width_pixbuf = gdk_pixbuf_get_width(pixbuf);
    height_pixbuf = gdk_pixbuf_get_height(pixbuf);

    if (width <= 0) width = width_pixbuf;
    if (height <= 0) height = height_pixbuf;

    if (width != width_pixbuf || height != height_pixbuf) {
        GdkPixbuf *dest;
	dest = gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_BILINEAR);
        gdk_pixbuf_unref(pixbuf);
        pixbuf = dest;
    }

    return pixbuf;
}

static void
palette_window_draw_button_image(palette_window_t *palette_window,
				 palette_button_t *button,
				 GdkPixbuf *pixbuf,
				 int alignment)
{
    int x, y;
    int width_pixbuf;
    int height_pixbuf;

    if (!palette_window->pixmap || !pixbuf)
	return;

    width_pixbuf = gdk_pixbuf_get_width(pixbuf);
    height_pixbuf = gdk_pixbuf_get_height(pixbuf);

    if (alignment == GTK_JUSTIFY_CENTER) {
        x = button->x + (button->width - width_pixbuf)/2;
    } else if (alignment == GTK_JUSTIFY_LEFT) {
        x = button->x;
    } else if (alignment == GTK_JUSTIFY_RIGHT) {
        x = x = button->x + button->width - width_pixbuf;
    }

    y = button->y + (button->height - height_pixbuf)/2;

    gdk_draw_pixbuf (palette_window->pixmap,
	             palette_window->drawing_area->style->fg_gc[GTK_STATE_NORMAL],
		     pixbuf,
		     0, 0,
		     x, y,
                     width_pixbuf, height_pixbuf,
		     GDK_RGB_DITHER_NORMAL,
		     0, 0); 

    return;
}

static void
palette_window_draw_button(palette_window_t *palette_window,
			   palette_button_t *button,
			   int button_state)
{
    GdkPixbuf *pixbuf;

    if (!palette_window->pixmap)
	return;

    if (button == NULL || button->activated == FALSE)
	return;

    if (button->button_id != BUTTON_ID_DRAG && button_state != BUTTON_STATE_NORMAL) {
	GtkShadowType shadow_type = GTK_SHADOW_OUT;
	GtkStateType  state_type = GTK_STATE_NORMAL;

	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(palette_window->drawing_area->style, palette_window->pixmap,
		      state_type, shadow_type,
		      NULL, palette_window->drawing_area, "button",
		      button->x, button->y,
		      button->width, button->height);
    }

    if (button->button_id == BUTTON_ID_DRAG) {

        if (palette_window->show_style == SHOW_STYLE_HORIZONTAL) {
            pixbuf = palette_window->pixbufs[PIXMAP_ID_DRAGAREA_VERTICAL];
        } else {
            pixbuf = palette_window->pixbufs[PIXMAP_ID_DRAGAREA_HORIZONTAL];
        }
        palette_window_draw_button_image(palette_window, button, pixbuf, GTK_JUSTIFY_CENTER);

    } else if (button->button_id == BUTTON_ID_IME) {
	int ime_draw_style;
        GdkGC *label_gc;
        char *str;

	ime_draw_style = palette_window->ime_draw_style;

	pixbuf = NULL;
	if (palette_window->current_ime != NULL)
	    pixbuf = palette_window->current_ime->icon_pixbuf;

	if (pixbuf == NULL)
            pixbuf = palette_window->pixbufs[PIXMAP_ID_DEFAULT_IME];

	if (ime_draw_style == IME_DRAW_ICON_ONLY) {
            palette_window_draw_button_image(palette_window, button, pixbuf, GTK_JUSTIFY_CENTER);
	} else {
	    int x = button->x;
	    int y = button->y + 2;

	    if (ime_draw_style == IME_DRAW_BOTH_ICON_TEXT) {
                palette_window_draw_button_image(palette_window, button, pixbuf, GTK_JUSTIFY_LEFT);
		x  += gdk_pixbuf_get_width(pixbuf) + 1;
            }

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

	    if (palette_window->current_ime && palette_window->current_ime->name)
                str = palette_window->current_ime->name;
	    else
		str = "NoIME";
            if (str && *str) {
                pango_layout_set_text(palette_window->pango_layout, str, strlen(str));
                gdk_draw_layout(palette_window->pixmap, label_gc,
    			        x, y,
		                palette_window->pango_layout);
            }
	}

    } else if (button->button_id == BUTTON_ID_QJBJ) {

        if (palette_window->qjbj_status)
	    pixbuf = palette_window->pixbufs[PIXMAP_ID_FULLWIDTH];
        else
	    pixbuf = palette_window->pixbufs[PIXMAP_ID_HALFWIDTH];

        palette_window_draw_button_image(palette_window, button, pixbuf, GTK_JUSTIFY_CENTER);

    } else if (button->button_id == BUTTON_ID_PUNCT) {

        if (palette_window->punct_status)
	    pixbuf = palette_window->pixbufs[PIXMAP_ID_CNPUNCT];
        else
	    pixbuf = palette_window->pixbufs[PIXMAP_ID_ENPUNCT];

        palette_window_draw_button_image(palette_window, button, pixbuf, GTK_JUSTIFY_CENTER);

    } else if (button->button_id == BUTTON_ID_VKB) {

        pixbuf = palette_window->pixbufs[PIXMAP_ID_VKB];
        palette_window_draw_button_image(palette_window, button, pixbuf, GTK_JUSTIFY_CENTER);

    } else if (button->button_id == BUTTON_ID_UTILITY) {

        pixbuf = palette_window->pixbufs[PIXMAP_ID_UTILITY];
        palette_window_draw_button_image(palette_window, button, pixbuf, GTK_JUSTIFY_CENTER);

    }

    return;
}

void palette_window_update_layout(palette_window_t *palette_window)
{
    palette_button_t *buttons;

    int pos_x, pos_y;
    int margin_x, margin_y;
    int delta_x, delta_y;
    int width, height;
    int i;

    PangoRectangle logical_rect;

    margin_x = 2;
    margin_y = 2;

    if (palette_window->show_style == SHOW_STYLE_HORIZONTAL) {
        /* show the toolbar with horizontal style */

        int width_buttons[BUTTONS_NUM] = {
            10, 20, 20, 20, 20, 20
        };

        int button_height = 20;
        int delta_x = 0;

        if (palette_window->ime_draw_style == IME_DRAW_ICON_ONLY) {
	    width_buttons[BUTTON_ID_IME] = 18;
        } else {
	    width_buttons[BUTTON_ID_IME] = 0;
	    if (palette_window->ime_draw_style == IME_DRAW_BOTH_ICON_TEXT) {
	        width_buttons[BUTTON_ID_IME] += 18;
	    }

	    pango_layout_get_extents(palette_window->pango_layout, NULL, &logical_rect);
	    width_buttons[BUTTON_ID_IME] += PANGO_PIXELS(logical_rect.width);
        }

        pos_x = margin_x;
        pos_y = margin_y;

        buttons = palette_window->buttons;
        for (i = 0; i < BUTTONS_NUM; i++) {
	    if (buttons[i].activated == FALSE)
	        continue;

	    width = width_buttons[i];

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

	    pos_x += width + delta_x;
        }

        width = pos_x + margin_x;
        height = button_height + 2 * margin_y;
    } else {
        /* show the toolbar with vertical style */
        int height_buttons[BUTTONS_NUM] = {
            10, 18, 18, 18, 18, 18
        };

        int button_width = 20;
        int delta_y = 0;

        pos_x = margin_x;
        pos_y = margin_y;

        buttons = palette_window->buttons;
        for (i = 0; i < BUTTONS_NUM; i++) {
	    if (buttons[i].activated == FALSE)
	        continue;

	    height = height_buttons[i];

	    buttons[i].x = pos_x;
	    buttons[i].y = pos_y;
	    buttons[i].width = button_width;
	    buttons[i].height = height;

	    pos_y += height + delta_y;
        }

        width = button_width + 2 * margin_x;
        height = pos_y + margin_y;
    }

    palette_window->width = width;
    palette_window->height = height;

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

    gtk_widget_set_size_request(GTK_WIDGET(palette_window->window),
				palette_window->width,
				palette_window->height);

    palette_window_draw_layout(palette_window);

    return;
}

void palette_window_draw_layout(palette_window_t *palette_window)
{
    GtkShadowType shadow_type = GTK_SHADOW_NONE;
    GtkStateType  state_type = GTK_STATE_NORMAL;
    palette_button_t *button;
    int i;

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

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

    for (i = 0; i < BUTTONS_NUM; i ++) {
	int button_state = BUTTON_STATE_NORMAL;

	button = &palette_window->buttons[i];

	if (button == palette_window->focused_button)
	    button_state = BUTTON_STATE_FOCUSED;

        palette_window_draw_button(palette_window, button, button_state);
    }
    gtk_widget_queue_draw(palette_window->drawing_area);
}

static gboolean
palette_window_check_pos_in_button(palette_button_t *button, int x, int y)
{
    return ((button->x <= x) && (button->x + button->width >= x) &&
	    (button->y <= y) && (button->y + button->height >= y));
}

palette_button_t *palette_window_get_button_from_pos(palette_window_t *palette_window, int x, int y)
{
    palette_button_t *button;
    gint i;

    for (i = 0; i < BUTTONS_NUM; i++) {
	button = &palette_window->buttons[i];
	if (button->activated && palette_window_check_pos_in_button(button, x, y))
	    return button;
    }
    return NULL;
}

void
palette_window_set_position(palette_window_t *palette_window,
			    gint pos_x, gint pos_y)
{
    GtkRequisition ws;
    gint screen_width;
    gint screen_height;

    gtk_widget_size_request(palette_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 (palette_window->pos_x != pos_x || palette_window->pos_y != pos_y) {
        gtk_window_move(GTK_WINDOW(palette_window->window), pos_x, pos_y);
        palette_window->pos_x = pos_x;
        palette_window->pos_y = pos_y;
    }
}

static void palette_window_set_tooltips(palette_window_t *palette_window,
					palette_button_t *button)
{
    if (palette_window == NULL)
	return;

    if (button == NULL ||
	button->activated == FALSE) {
	return;
    }

    gtk_tooltips_set_tip(palette_window->tooltips, palette_window->window,
			 palette_tooltips[button->button_id], NULL);
    return;
}

void palette_window_enable_tooltips(palette_window_t *palette_window)
{
    if (palette_window == NULL)
	return;

    gtk_tooltips_enable(palette_window->tooltips);
    return;
}

void palette_window_disable_tooltips(palette_window_t *palette_window)
{
    if (palette_window == NULL)
	return;

    gtk_tooltips_disable(palette_window->tooltips);
    return;
}

static void
palette_window_get_menu_popup_pos(GtkMenu * menu,
                                  gint * x, gint * y, 
                                  gboolean * push_in,
                                  gpointer func_data)
{
    palette_button_t *button = (palette_button_t *) func_data;
    GtkRequisition size_menu, size_widget;
    gint menu_pos_x, menu_pos_y;

    palette_window_t *palette_window = NULL;

    palette_window = (palette_window_t *)g_object_get_data(G_OBJECT(menu),
                                                           DATA_PALETTE_AUX_WINDOW_INFO);
    if (palette_window == NULL)
        return;

    gtk_widget_size_request((GtkWidget *) menu, &size_menu);

    menu_pos_x = 0;
    menu_pos_y = 0;
    if (palette_window->show_style == SHOW_STYLE_HORIZONTAL) {
        if (palette_window->pos_y - size_menu.height > 0) {
            menu_pos_y = palette_window->pos_y - size_menu.height;
        } else {
            gtk_widget_size_request((GtkWidget *) palette_window->window,
                                     &size_widget);
            menu_pos_y = palette_window->pos_y + size_widget.height;
        }

        menu_pos_x = palette_window->pos_x + button->x;
    } else {
        int screen_height = gdk_screen_height();
        int screen_width  = gdk_screen_width();

        menu_pos_x = palette_window->pos_x + palette_window->width;
        if (menu_pos_x + size_menu.width > screen_width)
            menu_pos_x = palette_window->pos_x - size_menu.width;

        menu_pos_y = palette_window->pos_y + button->y;
        if (menu_pos_y + size_menu.height > screen_height)
            menu_pos_y = screen_height - size_menu.height;
    }

    *x = menu_pos_x;
    *y = menu_pos_y;
}

void
palette_window_set_show_style(palette_window_t *palette_window,
			      int show_style)
{
    if (palette_window == NULL)
	return;

    palette_window->show_style = show_style;
    palette_window_update_layout(palette_window);
    palette_window_set_position(palette_window, palette_window->pos_x, palette_window->pos_y);
}

void
palette_window_set_qjbj_status(palette_window_t *palette_window,
			       int qjbj_status)
{
    DEBUG_printf("qjbj_status: %d\n", qjbj_status);
    if (palette_window->qjbj_status == qjbj_status)
        return;

    palette_window->qjbj_status = qjbj_status;

    palette_window_update_layout(palette_window);
}

void
palette_window_set_punct_status(palette_window_t *palette_window,
			        int punct_status)
{
    if (palette_window->punct_status == punct_status)
        return;

    palette_window->punct_status = punct_status;

    palette_window_update_layout(palette_window);
}

static void
palette_window_set_focused_button(palette_window_t *palette_window,
				  palette_button_t *button)
{
    palette_button_t *focused_button_old = NULL;

    focused_button_old = palette_window->focused_button;

    if (focused_button_old == button)
	return;

    if (button && button->button_id == BUTTON_ID_DRAG) {
	gdk_window_set_cursor(palette_window->drawing_area->window,
			      palette_window->moving_cursor);
    } else {
	gdk_window_set_cursor(palette_window->drawing_area->window,
			      palette_window->normal_cursor);
    }

    palette_window->focused_button = button;
    palette_window_draw_layout(palette_window);
}

static void
palette_window_set_pressed_button(palette_window_t *palette_window,
				  palette_button_t *button)
{
    palette_button_t *pressed_button_old = NULL;

    pressed_button_old = palette_window->pressed_button;

    palette_window->pressed_button = button;
    palette_window_draw_layout(palette_window);
    palette_window_draw_button(palette_window, button, BUTTON_STATE_PRESSED);
    gtk_widget_queue_draw(palette_window->drawing_area);
}

void
palette_window_update_layout_with_property_data(palette_window_t *palette_window,
						property_data_t *property_data)
{
    char *ime_uuid;
    ime_module_t *current_ime;

    if (palette_window == NULL || property_data == NULL)
	return;

    palette_window->buttons[BUTTON_ID_IME].activated = TRUE;
    if (property_data->show_ime_button == FALSE)
	palette_window->buttons[BUTTON_ID_IME].activated = FALSE;

    palette_window->buttons[BUTTON_ID_QJBJ].activated = TRUE;
    if (property_data->show_qjbj_button == FALSE)
	palette_window->buttons[BUTTON_ID_QJBJ].activated = FALSE;

    palette_window->buttons[BUTTON_ID_PUNCT].activated = TRUE;
    if (property_data->show_punct_button == FALSE)
	palette_window->buttons[BUTTON_ID_PUNCT].activated = FALSE;

    palette_window->buttons[BUTTON_ID_VKB].activated = TRUE;
    if (property_data->show_vkb_button == FALSE)
	palette_window->buttons[BUTTON_ID_VKB].activated = FALSE;

    palette_window->buttons[BUTTON_ID_UTILITY].activated = TRUE;
    if (property_data->show_utility_button == FALSE)
	palette_window->buttons[BUTTON_ID_UTILITY].activated = FALSE;

    palette_window->show_style = SHOW_STYLE_HORIZONTAL;
    if (property_data->show_with_vertical)
	palette_window->show_style = SHOW_STYLE_VERTICAL;

    current_ime = palette_window->current_ime;
    ime_uuid = "NoIme";
    if (current_ime != NULL)
        ime_uuid = current_ime->uuid;

    palette_window->current_ime = (ime_module_t *)property_data_get_ime_module_by_uuid(
                                                        property_data, ime_uuid);

    if (palette_window->ime_list_menu)
        gtk_widget_destroy(palette_window->ime_list_menu);

    palette_window->ime_list_menu = (GtkWidget *)palette_window_create_ime_list_menu(palette_window, property_data);

    palette_window_update_layout(palette_window);
    palette_window_set_position(palette_window, palette_window->pos_x, palette_window->pos_y);

    return;
}

void palette_window_hide(palette_window_t *palette_window)
{
    if (palette_window == NULL)
        return;

    gtk_widget_hide(palette_window->window);
    palette_window_hide_vkb_window(palette_window);

    return;
}

gboolean palette_window_save_properties_timer_cb(palette_window_t *palette_window)
{
    property_data_t *property_data;

    DEBUG_printf("Timer:  palette_window_save_properties_timer_cb\n");
    if (palette_window == NULL)
	return TRUE;

    property_data = palette_window->property_data;
    if (property_data == NULL)
        return TRUE;

    if (property_data->modified_flag == 0)
        return TRUE;

    property_data_save_to_profile(property_data);
    return TRUE;
}

/********************************************************************/
/*       draging functions                                          */
/********************************************************************/
static void
palette_window_draw_draging_frame(palette_window_t *palette_window,
				  int pos_x, int pos_y)
{
    GdkGC *xor_gc;
    GdkGCValues values;
    GdkWindow *root_window;

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

    root_window = gtk_widget_get_root_window (palette_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,
                        palette_window->width - 1,
                        palette_window->height - 1);
}

static void
palette_window_begin_draging(palette_window_t *palette_window,
			     GdkEventButton *event)
{
    /* begin draging */
    palette_window->drag_x_start = (gint) event->x_root;
    palette_window->drag_y_start = (gint) event->y_root;
    palette_window->drag_x_save = (gint) event->x_root;
    palette_window->drag_y_save = (gint) event->y_root;

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

    palette_window_draw_draging_frame(palette_window,
				      palette_window->pos_x,
				      palette_window->pos_y);

    return;
}

static void
palette_window_end_draging(palette_window_t *palette_window,
			   GdkEventButton *event)
{
    gint pos_x, pos_y;

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

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

        palette_window_set_position(palette_window, pos_x, pos_y);
        gtk_widget_queue_draw(palette_window->drawing_area);
    }

    gdk_pointer_ungrab(event->time);

    return;
}

static void
palette_window_do_draging(palette_window_t *palette_window,
			  GdkEventMotion *event)
{
    gint pos_x, pos_y;

    pos_x = palette_window->pos_x;
    pos_y = palette_window->pos_y;

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

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

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

	/* directly move the palette window */
        palette_window_set_position(palette_window, pos_x, pos_y);
    }

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

/********************************************************************/
/*       vkb_layout functions                                       */
/********************************************************************/
void palette_window_init_vkb_window(palette_window_t *palette_window)
{
    if (palette_window->vkb_window == NULL)
        palette_window->vkb_window = (vkb_window_t *)vkb_window_new();

    return;
}

vkb_layout_t **palette_window_get_vkb_layout_list(palette_window_t *palette_window)
{
    char file_name[256];

    if (palette_window == NULL)
        return NULL;

    if (palette_window->vkb_layout_list_inited == 0) {
        snprintf(file_name, 256, "%s/gtk2/%s", LE_AUX_MODULES_DIR, PALETTE_AUX_VKB_LAYOUT_FILE);

        palette_window->vkb_layout_list = (vkb_layout_t **)
            vkb_layout_list_read_from_layout_file(file_name);

#ifdef DEBUG
        vkb_layout_list_print(palette_window->vkb_layout_list);
#endif

        palette_window->vkb_layout_list_inited = 1;
    }

    return (palette_window->vkb_layout_list);
}

vkb_layout_t *palette_window_get_current_ime_vkb_layout(palette_window_t *palette_window)
{
    int i;
    ime_module_t *current_ime;
    ImePropertyListRec *ime_property_list;

    if (palette_window == NULL)
	return NULL;

    current_ime = palette_window->current_ime;
    if (current_ime == NULL)
	return NULL;

    if (current_ime->num_vkbs <= 0 || current_ime->vkbs == NULL)
	return NULL;

    ime_property_list = current_ime->property_list;
    if (current_ime->num_vkbs == 1 ||
        ime_property_list == NULL ||
        ime_property_list->count <= 0 ||
        ime_property_list->properties == NULL)
        return (current_ime->vkbs[0]);

    for (i = 0; i < ime_property_list->count; i++) {
        int vkb_id = 0;
	ImePropertyRec *p = &(ime_property_list->properties[i]);
        if (!strcasecmp(p->key, "/keymapping")) {
            vkb_id = p->value.int_value;
            if (vkb_id < 0 || vkb_id >= current_ime->num_vkbs)
                vkb_id = 0;
            return (current_ime->vkbs[vkb_id]);
        }
    }

    return NULL;
}

void palette_window_hide_vkb_window(palette_window_t *palette_window)
{
    if (palette_window == NULL)
        return;

    palette_window->vkb_show_status = 0;
    vkb_window_hide(palette_window->vkb_window);
    return;
}

void palette_window_show_vkb_window_with_layout(palette_window_t *palette_window,
						vkb_layout_t *vkb_layout)
{
    if (vkb_layout == NULL)
        return;

    palette_window_init_vkb_window(palette_window);

    if (palette_window->vkb_window == NULL)
        return;

    palette_window->vkb_show_status = 1;
    vkb_window_update_layout(palette_window->vkb_window, vkb_layout);

    return;
}

void palette_window_toggle_vkb_window(palette_window_t *palette_window)
{
    vkb_layout_t **vkb_layout_list;
    vkb_layout_t *vkb_layout = NULL;

    if (palette_window == NULL)
        return;

    if (palette_window->vkb_show_status == 1) {
        palette_window_hide_vkb_window(palette_window);
        return;
    }

    /* need draw the current vkb layout */
    vkb_layout = palette_window->current_vkb_layout;
    if (vkb_layout == NULL) {
        /* get current IME vkb */
        vkb_layout = (vkb_layout_t *)palette_window_get_current_ime_vkb_layout(palette_window);
    }

    if (vkb_layout == NULL) {
        /* get the first vkb in vkb_layout_list */
        vkb_layout_list = (vkb_layout_t **) palette_window_get_vkb_layout_list(palette_window);
        if (vkb_layout_list != NULL)
            vkb_layout = vkb_layout_list[0];
    }

    palette_window_show_vkb_window_with_layout(palette_window, vkb_layout);
    return;
}

/********************************************************************/
/*            event functions                                       */
/********************************************************************/
static void
palette_window_destroy_event_handler(GtkWidget *widget,
				     palette_window_t *palette_window)
{
    palette_window_destroy(palette_window);
}

static gboolean
palette_window_expose_event_handler(GtkWidget *widget,
				    GdkEventExpose *event,
				    palette_window_t *palette_window)
{
    if (!palette_window->pixmap)
	return FALSE;

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

static gboolean
palette_window_configure_event_handler(GtkWidget *widget,
				       GdkEventConfigure *event,
				       palette_window_t *palette_window)
{
    DEBUG_printf("palette_window_configure_event_handler =\n");
    if (palette_window->pixmap)
        gdk_pixmap_unref(palette_window->pixmap);

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

    palette_window_draw_layout(palette_window);

    return TRUE;
}

static gboolean
palette_window_leave_event_handler(GtkWidget *widget,
				   GdkEventCrossing *event,
				   palette_window_t *palette_window)
{
    DEBUG_printf("palette_window_leave_event_handler =\n");

    /* if any button already pressed then do nothing */
    if (palette_window->pressed_button != NULL)
        return TRUE;

    palette_window->focused_button = NULL;
    palette_window_draw_layout(palette_window);

    return TRUE;
}

static gboolean
palette_window_pointer_press_event_handler(GtkWidget *widget,
					   GdkEventButton *event,
					   palette_window_t *palette_window)
{
    GtkWidget *menu = NULL;
    palette_button_t *button;

    DEBUG_printf("palette_window_pointer_press_event_handler =\n");
    if (palette_window == NULL)
       return TRUE;

    if (palette_window->draging)
	return TRUE;

    button = palette_window_get_button_from_pos(palette_window, event->x, event->y);
    palette_window->pressed_button = button;
    if (button == NULL)
	return TRUE;

    if (event->button > 1) {
	if (button->button_id == BUTTON_ID_VKB) {
	    if (palette_window->vkb_list_menu == NULL)
		palette_window->vkb_list_menu = (GtkWidget *)palette_window_create_vkb_list_menu(palette_window);
	    if (palette_window->vkb_list_menu != NULL) {
		palette_window->menu_popuped = 1;
		gtk_menu_popup(GTK_MENU(palette_window->vkb_list_menu), NULL, NULL,
                           NULL,
                           NULL,
                           event->button, event->time);
	    }
	} else {
            if (palette_window->utility_list_menu == NULL) {
                palette_window->utility_list_menu = (GtkWidget *)palette_window_create_utility_list_menu(palette_window);
            } else {
                palette_window->utility_list_menu = (GtkWidget *)palette_window_update_utility_list_menu(palette_window);
	    }
            if (palette_window->utility_list_menu != NULL) {
		palette_window->menu_popuped = 1;
                gtk_menu_popup(GTK_MENU(palette_window->utility_list_menu), NULL, NULL,
                           NULL,
                           NULL,
                           event->button, event->time);
	    } 
	}
	return TRUE;
    }
    
    if (button->button_id == BUTTON_ID_DRAG) {
        palette_window->draging = TRUE;
	palette_window_begin_draging(palette_window, event);
	return TRUE;
    } else if (button->button_id == BUTTON_ID_IME) {
        menu = palette_window->ime_list_menu;
        if (menu != NULL) {
	    palette_window->menu_popuped = 1;
            gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
                           palette_window_get_menu_popup_pos,
                           button,
                           event->button, event->time);
        }
    } else if (button->button_id == BUTTON_ID_UTILITY) {
        if (palette_window->utility_list_menu == NULL) {
            palette_window->utility_list_menu = (GtkWidget *)palette_window_create_utility_list_menu(palette_window);
        } else {
            palette_window->utility_list_menu = (GtkWidget *)palette_window_update_utility_list_menu(palette_window);
	}
        if (palette_window->utility_list_menu != NULL) {
	    palette_window->menu_popuped = 1;
            gtk_menu_popup(GTK_MENU(palette_window->utility_list_menu), NULL, NULL,
                           palette_window_get_menu_popup_pos,
                           button,
                           event->button, event->time);
        }
    }
    
    palette_window_draw_button(palette_window, button, BUTTON_STATE_PRESSED);
    gtk_widget_queue_draw(palette_window->drawing_area);
    return TRUE;
}

static gboolean
palette_window_pointer_release_event_handler(GtkWidget *widget,
					     GdkEventButton *event,
					     palette_window_t *palette_window)
{
    palette_button_t *pressed_button;
    palette_button_t *released_button;

    DEBUG_printf("palette_window_pointer_release_event_handler =\n");
    if (palette_window == NULL)
       return TRUE;

    if (event->button > 1)
	return TRUE;
    
    /* button released */
    if (palette_window->draging == TRUE) {
        palette_window->draging = FALSE;
	palette_window_end_draging(palette_window, event);
        palette_window->pressed_button = NULL;
        return TRUE;
    }

    pressed_button = palette_window->pressed_button;
    released_button = palette_window_get_button_from_pos(palette_window,
							 event->x, event->y);

    palette_window->draging = FALSE;
    palette_window->pressed_button = NULL;

    if (pressed_button != released_button) {
	/* do nothing and just redraw the focus button */
        palette_window->focused_button = released_button;
	palette_window_draw_layout(palette_window);
	return TRUE;
    }

    if (pressed_button == NULL)
	return TRUE;

    /* if pressed_button == released_button */
    if (pressed_button->button_id == BUTTON_ID_QJBJ) {
        palette_window_set_qjbj_status(palette_window, !palette_window->qjbj_status);
        palette_aux_Switch_LE_QjBj_Request(palette_window->qjbj_status);
    } else if (pressed_button->button_id == BUTTON_ID_PUNCT) {
        palette_window_set_punct_status(palette_window, !palette_window->punct_status);
        palette_aux_Switch_LE_Punct_Request(palette_window->punct_status);
    } else if (pressed_button->button_id == BUTTON_ID_VKB) {
	palette_window_toggle_vkb_window(palette_window);

	/* redraw the focused button */
	palette_window_draw_layout(palette_window);
    }

    return TRUE;
}

static gboolean
palette_window_pointer_motion_event_handler(GtkWidget *widget,
					    GdkEventMotion *event,
					    palette_window_t *palette_window)
{
    if (palette_window == NULL)
	return TRUE;

    DEBUG_printf("palette_window_pointer_motion_event_handler\n");
    if ((event->state & GDK_BUTTON1_MASK) != 0 &&
        palette_window->draging) {
	palette_window_do_draging(palette_window, event);
    } else {
        palette_button_t *button;
        DEBUG_printf("begin set focused button\n");

	/* if any button already pressed then do nothing */
	if (palette_window->pressed_button != NULL)
	    return TRUE;

	button = palette_window_get_button_from_pos(palette_window, event->x, event->y);
	if (button == palette_window->focused_button)
	    return TRUE;

	if (button && button->button_id == BUTTON_ID_DRAG) {
	    gdk_window_set_cursor(palette_window->drawing_area->window,
				  palette_window->moving_cursor);
	} else {
	    gdk_window_set_cursor(palette_window->drawing_area->window,
				  palette_window->normal_cursor);
	}

	palette_window_set_tooltips(palette_window, button);
	palette_window->focused_button = button;
	palette_window_draw_layout(palette_window);
    }

    return TRUE;
}
