Logo Search packages:      
Sourcecode: kazehakase version File versions

kz-window.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2002-2004 Hiroyuki Ikezoe
 *  Copyright (C) 2003 Takuro Ashie
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "kz-window.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>

#include "kz-marshalers.h"
#include "kz-history-action.h"
#include "kz-zoom-action.h"
#include "gobject-utils.h"
#include "gtk-utils.h"
#include "kz-actions.h"
#include "kz-actions-popup.h"
#include "kz-actions-tab.h"
#include "kz-bookmark-bar.h"
#include "kz-embed.h"
#include "kz-tab-label.h"
#include "kz-icons.h"
#include "kazehakase.h"
#include "utils.h"
#include "mozilla.h"
#include "kz-sidebar.h"
#include "kz-download-box.h"
#include "kz-bookmark-menu.h"
#include "kz-bookmark-tab-menu.h"
#include "kz-bookmark-file.h"
#include "kz-paned.h"
#include "kz-entry.h"
#include "kz-proxy-menu.h"
#include "kz-popup-tablist.h"

extern GtkWidget *kz_moz_embed_new (const gchar *url);
#ifdef ENABLE_GTK_WEBCORE
extern GtkWidget *kz_khtml_new     (const gchar *url);
#endif /* ENABLE_GTK_WEBCORE */

#define MAX_CLOSED_TABS 10

enum {
      APPEND_TAB_SIGNAL,
      REMOVE_TAB_SIGNAL,
      REORDER_TAB_SIGNAL,
      LAST_SIGNAL
};

struct _KzWindowPriv
{
      guint       merge_id;

      const char *status_msg;
      char       *temp_msg;

      /* for find keyword */
      gboolean    did_find;
      GtkTooltips *find_tips[2];

      KzEmbedEventMouse *event;

      /* for popup & gesture */
      KzGesture  *gesture;
      gint start_x, start_y;
      gboolean is_gesture;

      /* sidebar */
      gboolean sidebar_was_shown;

      /* tabs */
      GList *open_hist;
      GList *view_hist;
      GNode *tab_tree;
};

enum {
      STATUS_LINK_MESSAGE,
      STATUS_GESTURE,
      STATUS_SEARCH
};

enum {
      TARGET_KAZEHAKASE_TAB,
      TARGET_NETSCAPE_URL,
      TARGET_TEXT_URI_LIST,
      TARGET_TEXT_PLAIN,
      TARGET_STRING
};

static GtkTargetEntry url_drag_types [] =
{
        { "_KAZEHAKASE_TAB", 0, TARGET_KAZEHAKASE_TAB},
        { "_NETSCAPE_URL",   0, TARGET_NETSCAPE_URL},
      { "text/uri-list",   0, TARGET_TEXT_URI_LIST},
      { "text/plain",      0, TARGET_TEXT_PLAIN},
      { "STRING",          0, TARGET_STRING}
};

static struct {
      const gchar *pos;
      const gchar *tab_act;
      const gchar *sidebar_act;
} positems[] = {
      {"top",    "TabPosTop",    "SidebarPosTop"},
      {"bottom", "TabPosBottom", "SidebarPosBottom"},
      {"left",   "TabPosLeft",   "SidebarPosLeft"},
      {"right",  "TabPosRight",  "SidebarPosRight"},
};

static struct {
      const gint id;
      const gchar *name;
} modifier_map[] = {
      {KZ_ALT_KEY, "alt"},
      {KZ_CTRL_KEY, "ctrl"},
      {KZ_SHIFT_KEY,"shift"},
};

static gboolean key_theme_is_emacs = FALSE;

static void     kz_window_class_init     (KzWindowClass *klass);
static void     kz_window_init           (KzWindow      *kz);
static gboolean kz_window_delete_event   (GtkWidget     *widget,
                                GdkEventAny   *event);
static gboolean kz_window_key_press_event(GtkWidget     *widget,
                                GdkEventKey   *event);
static void     kz_window_destroy        (GtkObject     *object);
static void     kz_window_finalize       (GObject       *object);

static void     kz_window_append_tab     (KzWindow      *kz,
                                GtkWidget     *widget,
                                GtkWidget     *parent);
static void     kz_window_remove_tab     (KzWindow      *kz,
                                GtkWidget     *widget);

static KzEmbed *kz_window_create_embed   (KzWindow      *kz,
                                const gchar   *url);

static void     kz_window_set_gesture_items        (KzWindow   *kz);
static void     kz_window_set_cur_embed_callbacks  (KzWindow   *kz,
                                        KzEmbed    *kzembed);
static void     kz_window_unset_cur_embed_callbacks(KzWindow   *kz,
                                        KzEmbed    *kzembed);
static void     kz_window_set_embed_callbacks      (KzWindow   *kz,
                                        KzEmbed    *kzembed);
static void     kz_window_unset_embed_callbacks    (KzWindow   *kz,
                                        KzEmbed    *kzembed);

static void     kz_window_restore_session     (KzWindow  *kz);
static void     kz_window_store_session       (KzWindow  *kz);

/* callbacks */
static void     cb_profile_global_changed     (KzProfile       *profile,
                                     const gchar     *section,
                                     const gchar     *key,
                                     const gchar     *old_value,
                                     KzWindow        *kz);
static void     cb_profile_proxy_changed      (KzProfile       *profile,
                                     const gchar     *section,
                                     const gchar     *key,
                                     const gchar     *old_value,
                                     KzWindow        *kz);

static void     cb_profile_gesture_changed    (KzProfile       *profile,
                                     const gchar     *section,
                                     const gchar     *key,
                                     const gchar     *old_value,
                                     KzWindow        *kz);
static void     cb_bookmark_bars_insert_child (KzBookmark      *bookmark,
                                     KzBookmark      *child,
                                     KzBookmark      *sibling,
                                     KzWindow        *kz);
static void     cb_bookmark_bars_remove_child (KzBookmark      *bookmark,
                                     KzBookmark      *child,
                                     KzWindow        *kz);
static void     cb_bookmark_bars_reordered    (KzBookmark      *bookmark,
                                     KzWindow        *kz);
static void     cb_smartbookmark_insert_child (KzBookmark      *bookmark,
                                     KzBookmark      *child,
                                     KzBookmark      *sibling,
                                     KzWindow        *kz);
static void     cb_smartbookmark_remove_child (KzBookmark      *bookmark,
                                     KzBookmark      *child,
                                     KzWindow        *kz);
static void     cb_smartbookmark_reordered    (KzBookmark      *bookmark,
                                     KzWindow        *kz);
static void     cb_menu_merge_add_widget      (GtkUIManager    *merge,
                                     GtkWidget       *widget,
                                     GtkBox          *box);
static void     cb_clipboard_get_text         (GtkClipboard *clipboard,
                                     const gchar *text,
                                     gpointer data);
static void     cb_notebook_switch_page       (GtkNotebook     *notebook,
                                     GtkNotebookPage *page,
                                     guint            page_num,
                                     KzWindow        *kz);
static void     cb_find_keyword               (GtkWidget       *widget,
                                     KzWindow        *kz);
static gboolean cb_find_key_release           (GtkWidget       *widget,
                                     GdkEventKey     *event,
                                     KzWindow        *kz);
#if 0
static void     cb_find_grab_focus            (GtkWidget       *widget,
                                     KzWindow        *kz);
#endif
static void     cb_find_direction_toggle      (GtkToggleButton *button,
                                     KzWindow        *kz);
static void     cb_gesture_stack_motion       (KzGesture       *gesture,
                                     KzGestureMotion  motion,
                                     KzWindow        *kz);
static gboolean cb_notebook_scroll_event      (GtkWidget       *widget,
                                     GdkEventScroll  *event,
                                     KzWindow        *kz);
static void     cb_sidebar_map                (GtkWidget       *widget,
                                     GtkToggleAction *action);
static void     cb_sidebar_unmap              (GtkWidget       *widget,
                                     GtkToggleAction *action);
static gboolean cb_focus_out_event            (GtkWidget       *widget,
                                     GdkEventFocus   *event,
                                     KzWindow        *kz);
 
/* callbacks for embed */
static void     cb_embed_title_changed         (KzEmbed     *embed,
                                    KzWindow    *kz);
static void     cb_embed_location_changed      (KzEmbed     *embed,
                                    KzWindow    *kz);
static void     cb_embed_link_message          (KzEmbed     *embed,
                                    KzWindow    *kz);
static void     cb_embed_load_started          (KzEmbed     *embed,
                                    KzWindow    *kz);
static void     cb_embed_load_finished         (KzEmbed     *embed,
                                    KzWindow    *kz);
static void     cb_embed_new_window            (KzEmbed     *embed,
                                    KzEmbed    **new_embed,
                                    KzWindow    *kz);
static void     cb_embed_close_tab             (GtkObject   *obj,
                                    KzWindow    *kz);
static gint     cb_embed_dom_key_down          (KzEmbed     *embed,
                                    KzEmbedEventKey *event,
                                    KzWindow    *kz);
static gint     cb_embed_dom_key_up            (KzEmbed     *embed,
                                    KzEmbedEventKey *event,
                                    KzWindow    *kz);
static gint     cb_embed_dom_mouse_click       (KzEmbed     *embed,
                                    KzEmbedEventMouse *event,
                                    KzWindow    *kz);
static gint     cb_embed_dom_mouse_dbl_click   (KzEmbed     *embed,
                                    KzEmbedEventMouse *event,
                                    KzWindow    *kz);
static gint     cb_embed_dom_mouse_down        (KzEmbed     *embed,
                                    KzEmbedEventMouse *event,
                                    KzWindow    *kz);
static gint     cb_embed_dom_mouse_up          (KzEmbed *embed,
                                    KzEmbedEventMouse *event,
                                    KzWindow    *kz);

static gint     cb_embed_dom_mouse_over          (KzEmbed *embed,
                                    KzEmbedEventMouse *event,
                                    KzWindow    *kz);

/*
 * mozilla doesn't accept these signals, so we connect these funtions to
 * KzWindow instead of KzEmbed.
 */
static gboolean cb_window_motion_notify_event  (GtkWidget      *widget,
                                    GdkEventMotion *event,
                                    KzEmbed        *kzembed);
static gboolean cb_window_button_release_event (GtkWidget      *widget,
                                    GdkEventButton *event,
                                    KzEmbed        *kzembed);

/* notebook received dropped url */
static void     cb_notebook_drag_data_received (GtkWidget        *widget,
                                    GdkDragContext   *drag_context,
                                    gint              x,
                                    gint              y,
                                    GtkSelectionData *data,
                                    guint             info,
                                    guint             time,
                                    KzWindow         *kz);

static void     gtk_key_theme_changed_cb       (GtkSettings  *settings,
                                                GParamSpec   *pspec,
                                                gpointer dummy);

void kz_window_sync_ui_level (KzWindow *kz);
void kz_window_sync_proxy (KzWindow *kz);


static GtkWindowClass *parent_class = NULL;
static gint kz_window_signals[LAST_SIGNAL] = {0};
static GList *window_list = NULL;


KZ_OBJECT_GET_TYPE(kz_window, "KzWindow", KzWindow,
               kz_window_class_init, kz_window_init,
               GTK_TYPE_WINDOW)
KZ_OBJECT_FINALIZE(kz_window, KzWindow)


static void
kz_window_class_init (KzWindowClass *klass)
{
      GObjectClass *gobject_class;
      GtkObjectClass *object_class;
      GtkWidgetClass *widget_class;

      parent_class = g_type_class_peek_parent (klass);

      gobject_class = (GObjectClass *)   klass;
      object_class  = (GtkObjectClass *) klass;
      widget_class  = (GtkWidgetClass *) klass;

      kz_window_signals[APPEND_TAB_SIGNAL]
            = g_signal_new ("append-tab",
                        G_TYPE_FROM_CLASS (klass),
                        G_SIGNAL_RUN_FIRST,
                        G_STRUCT_OFFSET (KzWindowClass, append_tab),
                        NULL, NULL,
                        _kz_marshal_VOID__OBJECT_OBJECT,
                        G_TYPE_NONE, 2,
                        GTK_TYPE_WIDGET, GTK_TYPE_WIDGET);

      kz_window_signals[REMOVE_TAB_SIGNAL]
            = g_signal_new ("remove-tab",
                        G_TYPE_FROM_CLASS (klass),
                        G_SIGNAL_RUN_FIRST,
                        G_STRUCT_OFFSET (KzWindowClass, remove_tab),
                        NULL, NULL,
                        g_cclosure_marshal_VOID__OBJECT,
                        G_TYPE_NONE, 1,
                        GTK_TYPE_WIDGET);

      kz_window_signals[REORDER_TAB_SIGNAL]
            = g_signal_new ("reorder-tab",
                        G_TYPE_FROM_CLASS (klass),
                        G_SIGNAL_RUN_FIRST,
                        G_STRUCT_OFFSET (KzWindowClass, reorder_tab),
                        NULL, NULL,
                        _kz_marshal_VOID__OBJECT_INT,
                        G_TYPE_NONE, 2,
                        GTK_TYPE_WIDGET, G_TYPE_INT);

      /* GObjectClass */
      gobject_class->finalize = kz_window_finalize;

      /* GtkObject signals */
      object_class->destroy = kz_window_destroy;

      /* GtkWidget signals */
      widget_class->delete_event    = kz_window_delete_event;
      widget_class->key_press_event = kz_window_key_press_event;

      /* KzWindow signals */
      klass->append_tab = kz_window_append_tab;
      klass->remove_tab = kz_window_remove_tab;
}


static void
kz_window_init (KzWindow *kz)
{
      GtkWidget *menu_box;
      GtkSettings *setting;
      GtkWidget *vseparator;
      GList *children, *node;
      GtkAccelGroup *accel_group;
      GtkSettings *settings;

      g_object_set(G_OBJECT(kz), "allow-shrink", TRUE, NULL);

      gtk_window_set_title(GTK_WINDOW(kz), _("Kazehakase"));
      gtk_window_set_icon(GTK_WINDOW(kz), kz_icon);

      /* init member */
      kz->top_vbox           = gtk_vbox_new(FALSE, 0);

      kz->bookmark_bars_area = gtk_vbox_new(FALSE, 0);
      children = kz_bookmark_get_children(kz_bookmarks->bookmark_bars);
      for (node = children; node; node = g_list_next(node))
      {
            GtkWidget *bar = GTK_WIDGET(kz_bookmark_bar_new(kz, node->data));
            kz->bookmark_bars = g_list_append(kz->bookmark_bars, bar);
      }
      g_list_free(children);

      kz->statusbar          = gtk_statusbar_new();
      kz->notebook           = gtk_notebook_new();
      kz->statusbar_area     = gtk_hbox_new(FALSE, 0);
      kz->find_area          = kz_entry_new();
      kz->find_direction     = gtk_toggle_button_new();
      kz->dlbox              = kz_download_box_new(kz);

      kz->menu_merge         = gtk_ui_manager_new();
      accel_group            = gtk_ui_manager_get_accel_group(kz->menu_merge);

      kz->actions            = kz_actions_create_group(kz, accel_group);
      kz->popup_actions      = kz_actions_popup_create_group(kz, accel_group);
      kz->tabpop_actions     = kz_actions_tab_popup_create_group(kz, accel_group);
      
      kz->kzfav              = kz_favicon_get_instance();
      kz->popup              = kz_popup_preview_get_instance();
      kz->popup_tablist      = NULL;

      kz->priv               = g_new0(KzWindowPriv, 1);
      kz->priv->merge_id     = 0;
      kz->priv->status_msg   = NULL;
      kz->priv->temp_msg     = NULL;

      kz->priv->did_find     = FALSE;

      kz->priv->event        = NULL;

      kz->priv->gesture      = kz_gesture_new();
      kz->priv->start_x      = 0;
      kz->priv->start_y      = 0;
      kz->priv->is_gesture   = FALSE;

      kz->priv->sidebar_was_shown = FALSE;

      kz->priv->open_hist    = NULL;
      kz->priv->view_hist    = NULL;
      kz->priv->tab_tree     = NULL;

      kz->tabs   = kz_bookmark_pure_folder_new();
      kz->closed_tabs     = kz_bookmark_pure_folder_new();
      kz->history_search  = kz_bookmark_pure_folder_new();
      
      kz->is_closing_all  = FALSE;

      /* gesture */
      {
            kz_window_set_gesture_items(kz);
            g_signal_connect(kz->priv->gesture,
                         "stack_motion",
                         G_CALLBACK(cb_gesture_stack_motion), kz);
            g_signal_connect(kz_global_profile,
                         "changed::Gesture",
                         G_CALLBACK(cb_profile_gesture_changed), kz);
            g_signal_connect(kz,
                         "focus-out-event",
                         G_CALLBACK(cb_focus_out_event), kz);
      }

      /* top level vbox */
      {
            gtk_container_add(GTK_CONTAINER(kz),
                          kz->top_vbox);
            gtk_widget_show(kz->top_vbox);
      }

      /* menu & toolbar */
      {
            kz->menu_box = menu_box = gtk_vbox_new (FALSE, 0);
            gtk_box_pack_start(GTK_BOX(kz->top_vbox), menu_box,
                           FALSE, FALSE, 0);   
            gtk_widget_show(menu_box);

            gtk_ui_manager_insert_action_group(kz->menu_merge,
                                       kz->actions, 0);
            gtk_ui_manager_insert_action_group(kz->menu_merge,
                                       kz->popup_actions, 0);
            gtk_ui_manager_insert_action_group(kz->menu_merge,
                                       kz->tabpop_actions, 0);
            
            g_signal_connect(kz->menu_merge, "add_widget",
                         G_CALLBACK(cb_menu_merge_add_widget),
                         menu_box);
            gtk_window_add_accel_group(GTK_WINDOW(kz), 
                                 gtk_ui_manager_get_accel_group(kz->menu_merge));
      
            kz_window_sync_ui_level(kz);
            gtk_ui_manager_ensure_update(kz->menu_merge);
            g_signal_connect(kz_global_profile,
                         "changed::Global",
                         G_CALLBACK(cb_profile_global_changed), kz);
            g_signal_connect(kz_proxy,
                         "changed",
                         G_CALLBACK(cb_profile_proxy_changed), kz);


            /* FIXME */
            setting = gtk_settings_get_default();

            if (setting)
            {
                  gtk_settings_set_long_property (setting,
                                          "gtk-toolbar-style",
                                          GTK_TOOLBAR_ICONS,
                                          "");
            }

      }

      /* smart bookmark */
      g_signal_connect_after(kz_bookmarks->smarts,
                         "insert-child",
                         G_CALLBACK(cb_smartbookmark_insert_child), kz);
      g_signal_connect_after(kz_bookmarks->smarts,
                         "remove-child",
                         G_CALLBACK(cb_smartbookmark_remove_child), kz);
      g_signal_connect_after(kz_bookmarks->smarts,
                         "children-reordered",
                         G_CALLBACK(cb_smartbookmark_reordered), kz);
      kz_actions_update_smartbookmarks(kz, kz_bookmarks->smarts);

      /* bookmark bar */
      gtk_box_pack_start(GTK_BOX(kz->top_vbox), 
                     kz->bookmark_bars_area, FALSE, FALSE, 0);
      /* gtk_widget_show(kz->bookmark_bars_area); */

      for (node = kz->bookmark_bars;
           node;
           node = g_list_next(node))
      {
            gtk_box_pack_start(GTK_BOX(kz->bookmark_bars_area), 
                           node->data, FALSE, FALSE, 0);    
            gtk_widget_show(node->data);
      }

      g_signal_connect_after(kz_bookmarks->bookmark_bars,
                         "insert-child",
                         G_CALLBACK(cb_bookmark_bars_insert_child), kz);
      g_signal_connect_after(kz_bookmarks->bookmark_bars,
                         "remove-child",
                         G_CALLBACK(cb_bookmark_bars_remove_child), kz);
      g_signal_connect_after(kz_bookmarks->bookmark_bars,
                         "children-reordered",
                         G_CALLBACK(cb_bookmark_bars_reordered), kz);

      /* paned widget to separate sidebar and main contents */
      {
            kz->pane = kz_paned_new();
            gtk_container_add(GTK_CONTAINER(kz->top_vbox), kz->pane);
            gtk_widget_show(kz->pane);
      }

      /* main notebook widget */
      {
            gtk_notebook_set_show_tabs(GTK_NOTEBOOK(kz->notebook), TRUE);
            gtk_notebook_set_scrollable(GTK_NOTEBOOK(kz->notebook), TRUE);
            g_signal_connect(kz->notebook, "switch-page", 
                         G_CALLBACK(cb_notebook_switch_page), kz);
            g_signal_connect(kz->notebook, "scroll-event",
                         G_CALLBACK(cb_notebook_scroll_event), kz);

            gtk_drag_dest_set(GTK_WIDGET(kz->notebook),
                          GTK_DEST_DEFAULT_ALL,
                          url_drag_types, G_N_ELEMENTS (url_drag_types),
                          GDK_ACTION_MOVE);
            g_signal_connect(kz->notebook, "drag-data-received",
                         G_CALLBACK(cb_notebook_drag_data_received),
                         kz);
            gtk_paned_add2(GTK_PANED(kz->pane), kz->notebook);
            gtk_widget_show(kz->notebook);

            /* sidebar */
            kz->sidebar = kz_sidebar_new(kz);
            gtk_widget_set_size_request(kz->sidebar, 150, -1);
            gtk_paned_add1(GTK_PANED(kz->pane), kz->sidebar);
            /* gtk_widget_show(kz->sidebar); */
            {
                  GtkAction *action;
                  action = gtk_action_group_get_action(kz->actions,
                                               "ShowHideSidebar");
                  g_signal_connect(kz->sidebar, "map",
                               G_CALLBACK(cb_sidebar_map), action);
                  g_signal_connect(kz->sidebar, "unmap",
                               G_CALLBACK(cb_sidebar_unmap), action);
            }

            /* embed tab */
            /* curpage = kz_window_open_new_tab(kz, NULL); */
      }

      /* search area */
      {
            gtk_box_pack_start(GTK_BOX(kz->top_vbox), kz->statusbar_area,
                           FALSE, FALSE, 0);   
            gtk_widget_show(kz->statusbar_area);
      }

      /* find direction toggle */
      {
            GtkWidget *toggle, *arrow;
            GtkTooltips *tips = gtk_tooltips_new();

            toggle = kz->find_direction;
            arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
            gtk_container_add(GTK_CONTAINER(toggle), arrow);
            gtk_box_pack_start(GTK_BOX(kz->statusbar_area), toggle,
                           FALSE, FALSE, 0); 
            gtk_widget_show(arrow);
            gtk_widget_show(toggle);

            kz_entry_set_backtext(KZ_ENTRY(kz->find_area),
                              _("Find in this page"));
            kz_entry_set_icon_from_stock(KZ_ENTRY(kz->find_area),
                                   GTK_STOCK_FIND,
                                   GTK_ICON_SIZE_MENU);
            g_signal_connect(kz->find_area, "activate",
                         G_CALLBACK(cb_find_keyword), kz);
            g_signal_connect(toggle, "toggled",
                         G_CALLBACK(cb_find_direction_toggle), kz);

            g_object_ref(G_OBJECT(tips));
            gtk_object_sink(GTK_OBJECT(tips));
            gtk_tooltips_set_tip(tips, toggle,
                             _("Find direction"), NULL);
            kz->priv->find_tips[0] = tips;
      }

      /* find entry */
      {
            GtkTooltips *tips = gtk_tooltips_new();

            gtk_box_pack_start(GTK_BOX(kz->statusbar_area), kz->find_area,
                           FALSE, FALSE, 0); 
            g_signal_connect(kz->find_area, 
                         "key-release-event",
                         G_CALLBACK(cb_find_key_release), kz);
            /*
            g_signal_connect(kz->find_area, 
                         "grab-focus",
                         G_CALLBACK(cb_find_grab_focus), kz);
            */
            gtk_widget_show(kz->find_area);

            g_object_ref(G_OBJECT(tips));
            gtk_object_sink(GTK_OBJECT(tips));
            gtk_tooltips_set_tip(tips, kz->find_area,
                             _("Find a word or phrase in this page"), NULL);
            kz->priv->find_tips[1] = tips;
      }

      /* download box */
      {
            gtk_widget_set_size_request(kz->dlbox, 200, -1);
            gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(kz->dlbox),
                                      TRUE);
            gtk_statusbar_push(GTK_STATUSBAR(kz->dlbox), 0,
                           _("Drop link to download"));
            gtk_box_pack_end(GTK_BOX(kz->statusbar_area), kz->dlbox,  
                         FALSE, FALSE, 0);
            gtk_widget_show(kz->dlbox);
      }
      
      /* status bar */
      {
            vseparator = gtk_vseparator_new();
            gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(kz->statusbar),
                                      FALSE);
            gtk_box_pack_start(GTK_BOX(kz->statusbar_area), kz->statusbar,
                           TRUE, TRUE, 0);
            gtk_widget_show(kz->statusbar);
            gtk_box_pack_start(GTK_BOX(kz->statusbar_area),
                           vseparator,
                           FALSE, FALSE, 0);
            gtk_widget_show(vseparator);
      }

      /* from Galeon-1.3.18 */
      /* initialize the listener for the key theme */
      settings = gtk_settings_get_default();
      g_signal_connect (settings,
                    "notify::gtk-key-theme-name",
                    G_CALLBACK (gtk_key_theme_changed_cb),
                    NULL);
      gtk_key_theme_changed_cb (settings, 0, 0);

      window_list = g_list_append(window_list, kz);
      kz_bookmark_set_title(kz->tabs, "Window");
      kz_bookmark_append(kz_bookmarks->current_session, kz->tabs);

      /* kz_actions_set_sensitive(kz, KZ_EMBED(curpage)); */
      kz_window_restore_state(kz);

      kz_window_restore_session(kz); 
}


static void
kz_window_append_tab (KzWindow *kz, GtkWidget *widget, GtkWidget *parent)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));
      kz_actions_set_tab_sensitive(kz, KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz)));
}


static void
kz_window_remove_tab (KzWindow *kz, GtkWidget *widget)
{

      g_return_if_fail(KZ_IS_WINDOW(kz));
      kz_actions_set_sensitive(kz, KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz)));
      kz_actions_set_tab_sensitive(kz, KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz)));
}


GList *
kz_window_get_window_list(void)
{
      return window_list;
}


GtkWidget *
kz_window_new(const gchar *url)
{
      KzWindow *kz = g_object_new(KZ_TYPE_WINDOW,
                           "type", GTK_WINDOW_TOPLEVEL,
                            NULL);
      
      if (url)
            kz_window_open_new_tab (kz, url);

      return GTK_WIDGET (kz);
}


void
kz_window_sync_ui_level (KzWindow *kz)
{
      GtkAction *action;
      const gchar *action_str;
      GError *err = NULL;
      gchar *ui_file;
      GtkWidget *widget;
      KzEmbed *kzembed;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      switch (kz_ui_level()) 
      {
      case KZ_UI_LEVEL_CUSTOM:
            action_str = "UILevelCustom";
            ui_file = g_build_filename(g_get_home_dir(),
                                   "."PACKAGE,
                                 "kz-ui.xml",
                                   NULL);
            break;
      case KZ_UI_LEVEL_EXPERT:
            action_str = "UILevelExpert";
            ui_file = g_strdup(KZ_SYSCONFDIR"/kz-ui-expert.xml");
            break;
      case KZ_UI_LEVEL_MEDIUM:
            action_str = "UILevelMedium";
            ui_file = g_strdup(KZ_SYSCONFDIR"/kz-ui-medium.xml");
            break;
      case KZ_UI_LEVEL_BEGINNER:
      default:
            action_str = "UILevelBeginner";
            ui_file = g_strdup(KZ_SYSCONFDIR"/kz-ui-beginner.xml");
            break;
      }

      action = gtk_action_group_get_action(kz->actions, action_str);
      if (!gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)))
            gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);

      if (kz->priv->merge_id != 0)
      {
            gtk_ui_manager_remove_ui(kz->menu_merge, kz->priv->merge_id);
            kz->priv->merge_id = 0;
            kz_actions_remove_smartbookmarks(kz, kz_bookmarks->smarts);
            gtk_ui_manager_ensure_update(kz->menu_merge);
      }

      kz->priv->merge_id
            = gtk_ui_manager_add_ui_from_file(kz->menu_merge,
                                      ui_file, &err);
      if (err)
      {
            g_warning("%s", err->message);
            g_error_free(err);
      }
        gtk_ui_manager_ensure_update(kz->menu_merge);

      /* update bookmarks */
      widget = gtk_ui_manager_get_widget(kz->menu_merge, 
                                 "/menubar/BookmarksMenu");
      if (GTK_IS_MENU_ITEM(widget))
            widget = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
      if (GTK_IS_MENU_SHELL(widget))
      {
            kz_bookmark_menu_remove_menuitems(GTK_MENU_SHELL(widget), kz);
            kz_bookmark_menu_append_menuitems(GTK_MENU_SHELL(widget), kz,
                                      kz_bookmarks->menu);
      }

      /* update clips */
      widget = gtk_ui_manager_get_widget(kz->menu_merge,
                                 "/menubar/ToolsMenu/ClipMenu");
      if (GTK_IS_MENU_ITEM(widget))
            widget = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
      if (GTK_IS_MENU_SHELL(widget))
      {
            kz_bookmark_menu_remove_menuitems(GTK_MENU_SHELL(widget), kz);
            kz_bookmark_menu_append_menuitems(GTK_MENU_SHELL(widget), kz,
                                      kz_bookmarks->clip);
      }

      /* append recent close tab menu */
      widget = gtk_ui_manager_get_widget(kz->menu_merge,
                                 "/menubar/TabMenu/RecentCloseTabMenu");

      if (GTK_IS_MENU_ITEM(widget))
      {
            GtkWidget *submenu;
            submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
            if (!submenu)
            {
                  submenu = gtk_menu_new();
                  gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), submenu);
            }
            if (GTK_IS_MENU_SHELL(submenu))
            {
                  kz_bookmark_menu_remove_tab_menuitems(GTK_MENU_SHELL(submenu), kz);
                  kz_bookmark_menu_append_tab_menuitems(GTK_MENU_SHELL(submenu), kz,
                                                kz->closed_tabs);
            }
      }
        
      /* update proxy */
      kz_window_sync_proxy(kz);

      /* for stop/reload button updating */
      kzembed = KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz));
      kz_actions_set_sensitive(kz, kzembed);

      /* smart bookmark */
      kz_actions_update_smartbookmarks(kz, kz_bookmarks->smarts);

      g_free(ui_file);
}

void
kz_window_sync_proxy (KzWindow *kz)
{
      GtkWidget *menuitem, *submenu = NULL;
      GtkAction *action;
      gboolean use_proxy = FALSE;

      KZ_CONF_GET("Global", "use_proxy", use_proxy, BOOL);
      
      action = gtk_action_group_get_action(kz->actions,
                                   "ToggleProxyUse");
      if (action)
            gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action),
                                   use_proxy);
      KZ_WINDOW_SET_VISIBLE(kz, "StockProxyMenu", use_proxy);
      if (!use_proxy) return;

      menuitem = gtk_ui_manager_get_widget(kz->menu_merge,
                                   "/menubar/EditMenu/ProxyMenu");
      if (!GTK_IS_MENU_ITEM(menuitem))
            return;
      
      submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));

      if (!submenu)
            submenu = gtk_menu_new();

      kz_proxy_menu_remove_menuitems(GTK_MENU_SHELL(submenu), kz);
      kz_proxy_menu_append_menuitems(GTK_MENU_SHELL(submenu), kz);

      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
}

GtkWidget *
kz_window_get_from_tab (GtkWidget *tab_widget)
{
      GList *node;

      for (node = window_list; node; node = g_list_next (node))
      {
            KzWindow *kz = node->data;
            GtkWidget *label;

            if (!KZ_IS_WINDOW(kz)) continue;

            label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                                       tab_widget);
            if (label)
                  return GTK_WIDGET(kz);
      }

      return NULL;
}


GtkWidget *
kz_window_open_new_tab (KzWindow *kz, const gchar *url)
{
      return kz_window_open_new_tab_with_parent (kz, url, NULL);
}


/* It's temporary implementation */
static KzEmbed *
kz_window_create_embed (KzWindow *kz, const gchar *url)
{
      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);

#ifdef ENABLE_GTK_WEBCORE
      {
            gchar *engine;
            engine = KZ_CONF_GET_STR("Global", "layout_engine");
            if (engine && !strcmp(engine, "gtk+-webcore"))
            {
                  g_free(engine);
                  return KZ_EMBED(kz_khtml_new(url));
            }
            else
            {
                  g_free(engine);
                  return KZ_EMBED(kz_moz_embed_new(url));
            }
      }
#else /* ENABLE_GTK_WEBCORE */
      return KZ_EMBED(kz_moz_embed_new(url));
#endif /* ENABLE_GTK_WEBCORE */
}


GtkWidget *
kz_window_open_new_tab_at_tail (KzWindow *kz, const gchar *url)
{
      KzEmbed *kzembed;
      KzTabLabel *kztab;
      GNode *node;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);

      kzembed = kz_window_create_embed(kz, url);
      kztab = KZ_TAB_LABEL(kz_tab_label_new(kz, kzembed));

      gtk_widget_show(GTK_WIDGET(kzembed));
      gtk_widget_show(GTK_WIDGET(kztab));
      gtk_notebook_append_page(GTK_NOTEBOOK(kz->notebook),
                         GTK_WIDGET(kzembed),
                         GTK_WIDGET(kztab));
      kz_window_set_embed_callbacks(kz, kzembed);

      /* add to this window's history */
      kz->priv->open_hist = g_list_prepend(kz->priv->open_hist, kzembed);

      /* root node */
      if (!kz->priv->tab_tree)
            kz->priv->tab_tree = g_node_new(NULL);

      /* insret node */
      node = g_node_new(kzembed);
      g_node_append(kz->priv->tab_tree, node);

      kz_bookmark_append(kz->tabs, kztab->history);

      g_signal_emit(kz, kz_window_signals[APPEND_TAB_SIGNAL],
                  0, kzembed, NULL);

      return GTK_WIDGET(kzembed);
}

static gint 
get_insert_tab_position (KzWindow *kz)
{
      gchar pos_str[256];
      gint pos = -1;

      KZ_CONF_GET("Tab", "new_tab_position", pos_str, STRING);
      
      if (!pos_str || !strcasecmp(pos_str, "last"))
      {
            pos = -1;
      }
      else if (!strcasecmp(pos_str, "first"))
      {
            pos = 0;
      }
      else if (!strcasecmp(pos_str, "left"))
      {
            pos = gtk_notebook_get_current_page(GTK_NOTEBOOK(kz->notebook));
      }
      else if (!strcasecmp(pos_str, "right"))
      {
            pos = 1 + gtk_notebook_get_current_page(GTK_NOTEBOOK(kz->notebook));
      }
      else if (!strcasecmp(pos_str, "unread_right"))
      {
            gint i = 1 + gtk_notebook_get_current_page(GTK_NOTEBOOK(kz->notebook));
            gint num = gtk_notebook_get_n_pages(GTK_NOTEBOOK(kz->notebook));
            
            if (i > num)
            {
                  pos = -1;
            }
            else
            {
                  while (i < num)
                  {
                        GtkWidget *kzembed;
                        GtkWidget *label;
                        KzTabLabelState state;

                        kzembed = GTK_WIDGET(KZ_WINDOW_NTH_PAGE(kz, i));
                        label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                                                   kzembed);
                        state = kz_tab_label_get_state(KZ_TAB_LABEL(label));
                        if (state == KZ_TAB_LABEL_STATE_NORMAL)
                              break;
                        i++;
                  }
                  pos = i;
            }
      }

      return pos;
}


GtkWidget *
kz_window_open_new_tab_with_parent (KzWindow *kz, const gchar *url,
                            GtkWidget *parent)
{
      KzEmbed *kzembed;
      GtkWidget *sibembed;
      KzTabLabel *kztab, *sibtab;
      GNode *node, *parent_node;
      gint pos;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);
      if (url) g_return_val_if_fail(g_utf8_validate(url, strlen(url), NULL), NULL);

      kzembed = kz_window_create_embed(kz, url);
      kztab = KZ_TAB_LABEL(kz_tab_label_new(kz, kzembed));

      gtk_widget_show(GTK_WIDGET(kzembed));
      gtk_widget_show(GTK_WIDGET(kztab));

      pos = get_insert_tab_position (kz);

      gtk_notebook_insert_page(GTK_NOTEBOOK(kz->notebook),
                         GTK_WIDGET(kzembed),
                         GTK_WIDGET (kztab),
                         pos);                  

      /* insert tab bookmark */
      sibembed = gtk_notebook_get_nth_page(GTK_NOTEBOOK(kz->notebook), pos);
      sibtab = KZ_TAB_LABEL(gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                        sibembed));

      kz_bookmark_insert_before(kz->tabs, 
                          kztab->history,
                          sibtab->history);

      kz_window_set_embed_callbacks(kz, kzembed);

      /* add to this window's history */
      kz->priv->open_hist = g_list_prepend(kz->priv->open_hist, kzembed);

      /* root node */
      if (!kz->priv->tab_tree)
            kz->priv->tab_tree = g_node_new(NULL);

      /* insret node */
      node = g_node_new(kzembed);
      parent_node = g_node_find(kz->priv->tab_tree,
                          G_IN_ORDER, G_TRAVERSE_ALL, parent);
      if (parent_node)
            g_node_append(parent_node, node);
      else
            g_node_append(kz->priv->tab_tree, node);

      g_signal_emit(kz, kz_window_signals[APPEND_TAB_SIGNAL],
                  0, kzembed, parent);

      return GTK_WIDGET(kzembed);
}


void
kz_window_close_tab (KzWindow *kz, GtkWidget *widget)
{
      gchar *ret_page = NULL;
      KzEmbed *next = NULL;
      KzTabLabel *kztab = NULL;

      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_return_if_fail(GTK_IS_WIDGET(widget));

      kztab = KZ_TAB_LABEL(gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                                          widget));
      if (kztab && kz_tab_label_get_lock(kztab)) {
/* kztab is locked, so return without closing tab */
            return;

      } else if (KZ_WINDOW_CURRENT_PAGE(kz) != widget) {
/* close tab which is not current , so there is nothing to consider */
            goto CLOSE_TAB;

      }

      ret_page = KZ_CONF_GET_STR("Tab", "page_to_return_when_close");
      if (ret_page && !strcmp(ret_page, "last_shown"))
      {
            GList *node;

            if (kz->priv->view_hist &&
                (node = g_list_next(kz->priv->view_hist)))
            {
                  next = node->data;
            }
      }
      else if (ret_page && !strcmp(ret_page, "last_created"))
      {
            GList *node;

            node = kz->priv->open_hist;
            for (; node && !next; node = g_list_next(node))
            {
                  if (KZ_WINDOW_CURRENT_PAGE(kz) != node->data)
                        next = node->data;
            }
      }
      else if (ret_page && !strcmp(ret_page, "prev_tab"))
      {
            gtk_notebook_prev_page(GTK_NOTEBOOK(kz->notebook));
      }
      else if (ret_page && !strcmp(ret_page, "next_tab"))
      {
            gtk_notebook_next_page(GTK_NOTEBOOK(kz->notebook));
      }

      if (next)
      {
            gint num;

            num = gtk_notebook_page_num
                  (GTK_NOTEBOOK(kz->notebook),
                   GTK_WIDGET(next));
            gtk_notebook_set_current_page
                  (GTK_NOTEBOOK(kz->notebook), num);
      }

CLOSE_TAB:
      g_free(ret_page);
      gtk_widget_destroy(widget);
}


void
kz_window_close_all_tab(KzWindow *kz)
{
      gint n_pages, i;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz->is_closing_all = TRUE;
      n_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(kz->notebook));
      for (i = n_pages - 1; i >= 0; i--)
      {
            KzTabLabel *kztab;
            GtkWidget *widget = GTK_WIDGET(KZ_WINDOW_NTH_PAGE(kz, i));
            /* FIXME! silly! */
            kztab = KZ_TAB_LABEL(gtk_notebook_get_tab_label(
                              GTK_NOTEBOOK(kz->notebook),
                              widget));

            gtk_widget_destroy(widget);
      }
      kz->is_closing_all = FALSE;
}


void
kz_window_reorder_tab (KzWindow *kz, GtkWidget *widget, gint pos)
{
      gint n_pages, cur_pos, sib_pos = pos;
      KzTabLabel *kztab, *sibtab;
      KzBookmark *sib_bookmark = NULL;

      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_return_if_fail(GTK_IS_WIDGET(widget));

      n_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(kz->notebook));
      g_return_if_fail(pos >= 0 && pos < n_pages);

      cur_pos = gtk_notebook_page_num(GTK_NOTEBOOK(kz->notebook), widget);
      if (cur_pos == pos)
            return;

      if (cur_pos < pos)
            sib_pos = sib_pos + 1;

      kztab = KZ_TAB_LABEL(gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                                          widget));
      if (sib_pos < n_pages)
      {
            sibtab = KZ_TAB_LABEL(gtk_notebook_get_tab_label(
                              GTK_NOTEBOOK(kz->notebook),
                              KZ_WINDOW_NTH_PAGE(kz, sib_pos)));
            sib_bookmark = sibtab->history;
      }

      gtk_notebook_reorder_child (GTK_NOTEBOOK(kz->notebook),
                            widget, pos);
      
      g_object_ref(kztab->history);
      kz_bookmark_remove(kz->tabs, kztab->history);
      kz_bookmark_insert_before(kz->tabs, 
                          kztab->history,
                          sib_bookmark);
      g_object_unref(kztab->history);

      kz_window_store_session(kz);

      g_signal_emit(kz, kz_window_signals[REORDER_TAB_SIGNAL],
                  0, widget, pos);
}


/* FIXME!! It's a hacky way. */
void
kz_window_move_tab (KzWindow *kz, GtkWidget *widget)
{
      GtkNotebook *src_notebook;
      GtkWidget *label;
      KzWindow *src_kz;
      KzEmbed *kzembed;
      KzTabLabel *new_kztab;
      GNode *node, *child;

      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_return_if_fail(KZ_IS_EMBED(widget));

      kzembed = KZ_EMBED(widget);

      src_kz = KZ_WINDOW(kz_window_get_from_tab(widget));
      if (!src_kz) return;

      label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                                 widget);

      /* the kzembed is already the kz's child */
      if (label) return;

      src_notebook = GTK_NOTEBOOK(src_kz->notebook);
      label = gtk_notebook_get_tab_label(src_notebook,
                                 widget);
      g_return_if_fail(label);

      /* create new tab label */
      new_kztab = KZ_TAB_LABEL(kz_tab_label_new(kz, kzembed));

      /* move the page to this window */
      kz_window_unset_cur_embed_callbacks(src_kz, kzembed);
      kz_window_unset_embed_callbacks(src_kz, kzembed);
      g_object_ref(widget);
      gtk_container_remove(GTK_CONTAINER(src_kz->notebook), widget);
      gtk_notebook_prepend_page(GTK_NOTEBOOK(kz->notebook),
                          widget,
                          GTK_WIDGET(new_kztab));
      kz_bookmark_prepend(kz->tabs, new_kztab->history);
      kz_window_set_embed_callbacks(kz, kzembed);

      /* remove view_hist */
      src_kz->priv->view_hist = g_list_remove(src_kz->priv->view_hist,
                                    kzembed);
      /* move open_hist */
      src_kz->priv->open_hist = g_list_remove(src_kz->priv->open_hist,
                                    kzembed);
      kz->priv->open_hist = g_list_prepend(kz->priv->open_hist,
                                   kzembed);

      /* move tab tree */
      node = g_node_find(src_kz->priv->tab_tree,
                     G_IN_ORDER, G_TRAVERSE_ALL, widget);
      if (node)
      {
            /* move children */
            child = g_node_first_child(node);
            while (child)
            {
                  GNode *next = g_node_next_sibling(child);
                  g_node_unlink(child);
                  g_node_append(src_kz->priv->tab_tree,
                              child);
                  child = next;
            }

            /* move node */
            g_node_unlink(node);
            if (!kz->priv->tab_tree)
                  kz->priv->tab_tree = g_node_new(NULL);
            g_node_append(kz->priv->tab_tree, node);
            
            g_signal_emit(src_kz,
                        kz_window_signals[REMOVE_TAB_SIGNAL],
                        0, kzembed);
            g_signal_emit(kz,
                        kz_window_signals[APPEND_TAB_SIGNAL],
                        0, kzembed, NULL);
      }
      else
      {
            g_warning("KzWindow: cannot find tab node!");
      }
}


static gboolean
kz_window_delete_event (GtkWidget *widget, GdkEventAny *event)
{
      KzWindow *kz;

      kz = KZ_WINDOW(widget);

      kz_window_store_state(kz);
      kz_window_close_all_tab(kz);

      return FALSE;
}


/* from Galeon-1.3.18 */
static void
gtk_key_theme_changed_cb (GtkSettings  *settings,
                          GParamSpec   *pspec,
                          gpointer dummy)
{
      gchar *key_theme_name;

      g_object_get (settings,
                  "gtk-key-theme-name", &key_theme_name,
                  NULL);
      if (key_theme_name && g_ascii_strcasecmp (key_theme_name, "Emacs") == 0)
      {
            key_theme_is_emacs = TRUE;
      }
      else
      {
            key_theme_is_emacs = FALSE;
      }
      g_free (key_theme_name);
}

static gboolean
kz_window_key_press_event(GtkWidget *widget, GdkEventKey *event)
{
      KzWindow *kz;

      gboolean shortcircuit;
      gboolean force_chain;
      gboolean handled;
      guint modifier;

      kz = KZ_WINDOW(widget);

      /* In an attempt to get the mozembed playing nice with things like emacs keybindings
       * we are passing important events to the focused child widget before letting the window's
       * base handler see them. This is *completely against* stated gtk2 policy but the 
       * 'correct' behaviour is exceptionally useless. We need to keep an eye out for 
       * unexpected consequences of this decision. IME's should be a high concern, but 
       * considering that the IME folks complained about the upside-down event propagation
       * rules, we might be doing them a favour.
       */

      shortcircuit = FALSE;
      force_chain  = FALSE;
      handled = FALSE;
      modifier = event->state & gtk_accelerator_get_default_mod_mask ();
      /* guint i; */

      if (event->keyval == GDK_Escape)
      {
            /* Always pass Escape to both the widget, and the parent */
            shortcircuit = TRUE;
            force_chain = TRUE;
      }
      else if (key_theme_is_emacs && 
             (modifier == GDK_CONTROL_MASK) && event->length > 0 &&
             /* But don't pass Ctrl+Enter twice */
             event->keyval != GDK_Return)
      {
            /* Pass CTRL+letter characters to the widget */
            shortcircuit = TRUE;
      }

      if (shortcircuit)
      {
            GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (kz));

            if (GTK_IS_WIDGET (widget))
            {
                  handled = gtk_widget_event (widget, (GdkEvent*)event);
            }

            if (handled && !force_chain)
            {
                  return handled;
            }
      }
#if 0
      /* Handle accelerators that we want bound, but aren't associated with
       * an action */
      for (i = 0; i < G_N_ELEMENTS (extra_keybindings); i++)
      {
            if (modifier == extra_keybindings[i].modifier &&
                event->keyval == extra_keybindings[i].keyval)
            {
                  GtkAction *action;
                  action = gtk_action_group_get_action 
                        (kz->actions, 
                         extra_keybindings[i].action);
                  gtk_action_activate(action);
                  return TRUE;
            }
      }
#endif
#if 0
      if (event->keyval == GDK_F10 && modifier == 0 &&
          priv->menubar && priv->menubar->parent &&
          !GTK_WIDGET_VISIBLE(priv->menubar->parent))
      {
            /* When F10 is pressed gtk+ automatically opens the menu if the
             * menubar is visible, but when the menubar is not visible
             * (think fullscreen or popup windows) we show it manually and
             * hide again when the user activates or otherwise dismisses
             * the menu.
             */

            gulong *handler_id = g_new(gulong, 1);

            *handler_id = g_signal_connect_data (priv->menubar, "deactivate",
                                         G_CALLBACK(menubar_deactivate_cb),
                                         handler_id, (GClosureNotify)g_free, 0);
            gtk_widget_show (GTK_WIDGET(priv->menubar->parent));
            gtk_menu_shell_select_first (GTK_MENU_SHELL(priv->menubar),
                                     FALSE);
            return TRUE;
      }
#endif
      return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
}


static void
kz_window_destroy (GtkObject *object)
{
      KzWindow *kz = KZ_WINDOW(object);

      if (GTK_OBJECT_CLASS (parent_class)->destroy)
            GTK_OBJECT_CLASS (parent_class)->destroy(object);

      window_list = g_list_remove(window_list, kz);

      if (kz->priv->gesture)
            g_object_unref(kz->priv->gesture);
      kz->priv->gesture = NULL;

      g_free(kz->priv->temp_msg);
        kz->priv->temp_msg = NULL;

      if (kz->priv->event)
            kz_embed_event_free((KzEmbedEvent *) kz->priv->event);
      kz->priv->event = NULL;

      if (kz->priv->find_tips[0])
            g_object_unref(kz->priv->find_tips[0]);
      kz->priv->find_tips[0] = NULL;
      if (kz->priv->find_tips[1])
            g_object_unref(kz->priv->find_tips[1]);
      kz->priv->find_tips[1] = NULL;

      if (kz->menu_merge)
            g_object_unref(kz->menu_merge);
      kz->menu_merge = NULL;

      if (kz->actions)
            g_object_unref(kz->actions);
      kz->actions = NULL;

      if (kz->popup_actions)
            g_object_unref(kz->popup_actions);
      kz->popup_actions = NULL;

      if (kz->tabpop_actions)
            g_object_unref(kz->tabpop_actions);
      kz->tabpop_actions = NULL;

      if (kz->kzfav)
            g_object_unref(kz->kzfav);
      kz->kzfav = NULL;

      if (kz->popup)
            g_object_unref(kz->popup);
      kz->popup = NULL;

      if (kz->popup_tablist)
            gtk_widget_destroy(kz->popup_tablist);
      kz->popup_tablist = NULL;

      if (kz->tabs)
      {
            kz_bookmark_remove(kz_bookmarks->current_session, kz->tabs);
            g_object_unref(kz->tabs);
            kz->tabs = NULL;
            
            if (g_list_length(window_list) >0)
                  kz_window_store_session(kz);
      }
      if (kz->closed_tabs)
            g_object_unref(kz->closed_tabs);
      kz->closed_tabs = NULL;
      if (kz->history_search)
            g_object_unref(kz->history_search);
      kz->history_search = NULL;

      g_signal_handlers_disconnect_by_func
            (kz_bookmarks->bookmark_bars,
             G_CALLBACK(cb_bookmark_bars_insert_child), kz);
      g_signal_handlers_disconnect_by_func
            (kz_bookmarks->bookmark_bars,
             G_CALLBACK(cb_bookmark_bars_remove_child), kz);
      g_signal_handlers_disconnect_by_func
            (kz_bookmarks->bookmark_bars,
             G_CALLBACK(cb_bookmark_bars_reordered), kz);

      g_signal_handlers_disconnect_by_func
            (kz_bookmarks->smarts,
             G_CALLBACK(cb_smartbookmark_insert_child), kz);
      g_signal_handlers_disconnect_by_func
            (kz_bookmarks->smarts,
             G_CALLBACK(cb_smartbookmark_remove_child), kz);
      g_signal_handlers_disconnect_by_func
            (kz_bookmarks->smarts,
             G_CALLBACK(cb_smartbookmark_reordered), kz);

      g_signal_handlers_disconnect_by_func
            (kz_global_profile,
             G_CALLBACK(cb_profile_global_changed), kz);
      g_signal_handlers_disconnect_by_func
            (kz_global_profile,
             G_CALLBACK(cb_profile_gesture_changed), kz);
      g_signal_handlers_disconnect_by_func
            (kz_proxy,
             G_CALLBACK(cb_profile_proxy_changed), kz);

      if (!kz_window_get_window_list())
      {
            static gboolean main_quited = FALSE;
            if (!main_quited)
            {
                  gtk_main_quit();
                  main_quited = TRUE;
            }
      }
}


static void
kz_window_set_gesture_items (KzWindow *kz)
{
      GtkAction *action;
      KzGestureItems *items;
      GList *list, *node;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      items = kz_gesture_items_new();

      list = kz_profile_enum_key(kz_global_profile, "Gesture", FALSE);

      for (node = list; node; node = g_list_next(node))
      {
            const gchar *action_name = node->data;
            gchar *gesture;

            action = gtk_action_group_get_action(kz->actions,
                                         action_name);
            if (!action) continue;

            gesture = KZ_CONF_GET_STR("Gesture", action_name);
            if (!gesture) continue;
            if (!*gesture)
            {
                  g_free(gesture);
                  continue;
            }

            kz_gesture_items_set_action(items, action,
                                  0, gesture);

            g_free(gesture);
      }

      kz_gesture_set_items(kz->priv->gesture, items);
      kz_gesture_items_unref(items);

      g_list_free(list);
}


static void
cb_window_map (KzWindow *kz, GtkAction *action)
{
      gtk_action_activate(action);
      g_signal_handlers_disconnect_by_func
            (kz, G_CALLBACK(cb_window_map), action);
}


static void
kz_window_store_session (KzWindow *kz)
{
      gboolean save_session = FALSE;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      KZ_CONF_GET("Session", "save", save_session, BOOL);
      if (save_session)
            kz_bookmark_file_save(KZ_BOOKMARK_FILE(kz_bookmarks->current_session));
}


static void
kz_window_restore_session (KzWindow *kz)
{
      GtkAction *action;
      gboolean restore_session = FALSE;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      KZ_CONF_GET("Session", "restore",
                restore_session, BOOL);
      if (restore_session && g_list_length(window_list) == 1)
      {
            action = gtk_action_group_get_action(kz->actions,
                                         "RestoreSession");
            if (GTK_WIDGET_MAPPED(kz))
                  gtk_action_activate(action);
            else
                  g_signal_connect(kz, "map",
                               G_CALLBACK(cb_window_map), action);
      }
}


void
kz_window_store_state (KzWindow *kz)
{
      GtkAction *action;
      gint i, client_x, client_y, width, height;
      const gchar *label;
      gboolean active;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_profile_set_save_each_time(kz_global_profile, FALSE);
      /*
       * window size
       */

      gdk_window_get_geometry (GTK_WIDGET(kz)->window,
                         &client_x, &client_y,
                         &width, &height, NULL);
      KZ_CONF_SET("MainWindow", "width",  width,  INT);
      KZ_CONF_SET("MainWindow", "height", height, INT);

      /*
       * sidebar
       */
      for (i = 0; i < G_N_ELEMENTS(positems); i++)
      {
            action = gtk_action_group_get_action(kz->actions,
                                         positems[i].sidebar_act);
            active = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
            if (active)
            {
                  KZ_CONF_SET_STR("MainWindow", "sidebar_pos",
                              positems[i].pos);
                  /* width */
                  /*
                   * On startup time, allocation.width and allocation.height are
                   * not set correctly(maybe both 1), so we should use 
                   * sidebar or notebook width according to sidebar position.
                   */
                  if (kz->priv->sidebar_was_shown)
                  {
                        if (!strcmp(positems[i].pos, "top"))
                              width = kz->sidebar->allocation.height;
                        else if (!strcmp(positems[i].pos, "bottom"))
                              width = kz->notebook->allocation.height;
                        else if (!strcmp(positems[i].pos, "left"))
                              width = kz->sidebar->allocation.width;
                        else if (!strcmp(positems[i].pos, "right"))
                              width = kz->notebook->allocation.width;
                        KZ_CONF_SET("MainWindow", "sidebar_width", width, INT);
                  }
                  break;
            }
      }

      /* content */
      label = kz_sidebar_get_current(KZ_SIDEBAR(kz->sidebar));
      if (label && *label)
            KZ_CONF_SET_STR("MainWindow", "sidebar", label);

      /* visible */
      action = gtk_action_group_get_action(kz->actions,
                                   "ShowHideSidebar");
      active = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
      KZ_CONF_SET("MainWindow", "show_sidebar", active, BOOL);

      /* bookmarkbar */
      action = gtk_action_group_get_action(kz->actions,
                                   "ShowHideBookmarkbars");
      active = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
      KZ_CONF_SET("MainWindow", "show_bookmarkbars", active, BOOL);


      /*
       * tab position
       */

      for (i = 0; i < G_N_ELEMENTS(positems); i++)
      {
            action = gtk_action_group_get_action(kz->actions,
                                         positems[i].tab_act);
            active = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
            if (active)
            {
                  KZ_CONF_SET_STR("MainWindow", "tab_pos",
                              positems[i].pos);
                  break;
            }
      }

      kz_profile_set_save_each_time(kz_global_profile, TRUE);
      kz_profile_save(kz_global_profile);

      /*
       *  Session
       */

      /* kz_window_store_session(kz); */
}


void
kz_window_restore_state (KzWindow *kz)
{
      GtkAction *action = NULL;
      gint width = 640, height = 450, sidebar_width = 150;
      gboolean active = FALSE, bookmarkbar = TRUE;
      gchar *tab_pos, *label, *sidebar_pos;
      gint i;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      /*
       * window size
       */

      KZ_CONF_GET("MainWindow", "width",  width,  INT);
      KZ_CONF_GET("MainWindow", "height", height, INT);

      gtk_window_set_default_size(GTK_WINDOW(kz), width, height);

      /*
       * sidebar
       */
      /* content */
      label = KZ_CONF_GET_STR("MainWindow", "sidebar");
      if (label && *label)
            kz_sidebar_set_current(KZ_SIDEBAR(kz->sidebar), label);
      g_free(label);

      /* visible */
      KZ_CONF_GET("MainWindow", "show_sidebar", active, BOOL);
      action = gtk_action_group_get_action(kz->actions,
                                   "ShowHideSidebar");
      gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), active);
      if (active)
      {
            sidebar_pos = KZ_CONF_GET_STR("MainWindow", "sidebar_pos");
            for (i = 0; sidebar_pos && i < G_N_ELEMENTS(positems); i++)
            {
                  if (strcasecmp(sidebar_pos, positems[i].pos)) continue;

                  /* width */
                  KZ_CONF_GET("MainWindow", "sidebar_width", sidebar_width, INT);
                  action = gtk_action_group_get_action(kz->actions,
                                               positems[i].sidebar_act);
                  gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action),
                                         TRUE);
                  /*
                   * On startup time, allocation.width and allocation.height are not set
                   * correctly(maybe both 1), so we should use sidebar or notebook width
                   * according to sidebar position.
                   */
                  gtk_paned_set_position(GTK_PANED(kz->pane), sidebar_width);
            }
            g_free(sidebar_pos);
      }
      KZ_CONF_GET("MainWindow", "show_bookmarkbars", bookmarkbar, BOOL);
      action = gtk_action_group_get_action(kz->actions,
                                   "ShowHideBookmarkbars");
      gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), bookmarkbar);
      
      /*
       * tab position
       */

      tab_pos = KZ_CONF_GET_STR("MainWindow", "tab_pos");
      for (i = 0; tab_pos && i < G_N_ELEMENTS(positems); i++)
      {
            if (strcasecmp(tab_pos, positems[i].pos)) continue;

            action = gtk_action_group_get_action(kz->actions,
                                         positems[i].tab_act);
            gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action),
                                   TRUE);
      }
      g_free(tab_pos);
}


static void
kz_window_set_cur_embed_callbacks(KzWindow *kz, KzEmbed *kzembed)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_return_if_fail(KZ_IS_EMBED(kzembed));

      g_signal_connect(kz,
                   "motion_notify_event",
                   G_CALLBACK(cb_window_motion_notify_event), kzembed);
      g_signal_connect(kz,
                   "button_release_event",
                   G_CALLBACK(cb_window_button_release_event), kzembed);

      /*
       * key event signal
       */
      g_signal_connect(kzembed,
                   "kz-dom-key-down",
                   G_CALLBACK(cb_embed_dom_key_down), kz);
      g_signal_connect(kzembed,
                   "kz-dom-key-up",
                   G_CALLBACK(cb_embed_dom_key_up), kz);

      /*
       * mouse event signal
       */
      g_signal_connect(kzembed,
                   "kz-dom-mouse-down",
                   G_CALLBACK(cb_embed_dom_mouse_down), kz);
      g_signal_connect(kzembed,
                   "kz-dom-mouse-up",
                   G_CALLBACK(cb_embed_dom_mouse_up), kz);
      g_signal_connect(kzembed,
                   "kz-dom-mouse-over",
                   G_CALLBACK(cb_embed_dom_mouse_over), kz);
      g_signal_connect(kzembed, "kz-dom-mouse-click",
                   G_CALLBACK(cb_embed_dom_mouse_click), kz);
      g_signal_connect(kzembed, "kz-dom-mouse-dbl-click",
                   G_CALLBACK(cb_embed_dom_mouse_dbl_click), kz);

      /*
       * other callbacks
       */
      g_signal_connect(kzembed, "kz-title",
                   G_CALLBACK(cb_embed_title_changed), kz);
      g_signal_connect(kzembed, "kz-location",
                   G_CALLBACK(cb_embed_location_changed), kz);
      g_signal_connect(kzembed, "kz-link-message",
                   G_CALLBACK(cb_embed_link_message), kz);
}


static void
kz_window_unset_cur_embed_callbacks(KzWindow *kz, KzEmbed *kzembed)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_return_if_fail(KZ_IS_EMBED(kzembed));

      g_signal_handlers_disconnect_by_func
            (kz,
             G_CALLBACK(cb_window_motion_notify_event), kzembed);
      g_signal_handlers_disconnect_by_func
            (kz,
             G_CALLBACK(cb_window_button_release_event), kzembed);

      /*
       * key event signal
       */
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_dom_key_down), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_dom_key_up), kz);

      /*
       * mouse event signal
       */
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_dom_mouse_down), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_dom_mouse_up), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_dom_mouse_over), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_dom_mouse_click), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_dom_mouse_dbl_click), kz);

      /*
       * other callbacks
       */
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_title_changed), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_location_changed), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_link_message), kz);
}


static void
kz_window_set_embed_callbacks(KzWindow *kz, KzEmbed *kzembed)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_return_if_fail(KZ_IS_EMBED(kzembed));

      /*
       * other callbacks
       */
      g_signal_connect(kzembed, "kz-net-start",
                   G_CALLBACK(cb_embed_load_started), kz);
      g_signal_connect(kzembed, "kz-net-stop",
                   G_CALLBACK(cb_embed_load_finished), kz);
      g_signal_connect(kzembed, "kz-new-window",
                   G_CALLBACK(cb_embed_new_window), kz);
      g_signal_connect(kzembed, "destroy",
                   G_CALLBACK(cb_embed_close_tab), kz);
}


static void
kz_window_unset_embed_callbacks(KzWindow *kz, KzEmbed *kzembed)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_return_if_fail(KZ_IS_EMBED(kzembed));

      /*
       * other callbacks
       */
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_load_started), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_load_finished), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_new_window), kz);
      g_signal_handlers_disconnect_by_func
            (kzembed,
             G_CALLBACK(cb_embed_close_tab), kz);
}


void
kz_window_load_url (KzWindow *kz, const gchar *url)
{
      GtkWidget *widget = KZ_WINDOW_CURRENT_PAGE(kz);
      KzTabLabel *kztab = NULL;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      if (widget)
            kztab = KZ_TAB_LABEL
                  (gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                                        widget));

      if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(kz->notebook)) < 1 ||
          !KZ_IS_EMBED(widget))
      {
            kz_window_open_new_tab(kz, url);
      }
      else
      {
            kz_embed_load_url(KZ_EMBED(widget), url);
      }
}


const gchar *
kz_window_get_title (KzWindow *kz)
{
      GtkWidget *widget = KZ_WINDOW_CURRENT_PAGE(kz);

      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);

      if (KZ_IS_EMBED(widget))
            return kz_embed_get_title(KZ_EMBED(widget));
      else
            return NULL;
}


const gchar *
kz_window_get_uri (KzWindow *kz)
{
      GtkWidget *widget = KZ_WINDOW_CURRENT_PAGE(kz);

      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);

      if (KZ_IS_EMBED(widget))
            return kz_embed_get_location(KZ_EMBED(widget));
      else
            return NULL;
}


GtkWidget *
kz_window_get_tab_label (KzWindow *kz, GtkWidget *widget)
{
      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);
      g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);

      return gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                                widget);
}


GNode *
kz_window_get_tree (KzWindow *kz)
{
      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);
      return kz->priv->tab_tree;
}


const KzEmbedEventMouse *
kz_window_get_mouse_event_info (KzWindow *kz)
{
      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);
      return kz->priv->event;
}



/*****************************************************************************
 *                                                                           *
 *                                Callbacks                                  *
 *                                                                           *
 *****************************************************************************/
static void
cb_profile_global_changed (KzProfile *profile,
                     const gchar *section, const gchar *key,
                     const gchar *old_value,
                     KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      switch (key[0])
      {
      case 'u':/* ui_level */
            if (strcmp(key, "ui_level") == 0)
            {
                  kz_window_sync_ui_level(kz);
            }
            if (strcmp(key, "use_proxy") == 0)
            {
                  kz_window_sync_proxy(kz);
            }
            break;
      case 'p':
            if (strcmp(key, "proxy_name") == 0)
            {
                  kz_window_sync_proxy(kz);
            }
            break;
      default:
            break;
      }
}

static void
cb_profile_proxy_changed (KzProfile *profile,
                    const gchar *section, const gchar *key,
                    const gchar *old_value,
                    KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_window_sync_proxy(kz);
}

static void
cb_profile_gesture_changed (KzProfile *profile,
                     const gchar *section, const gchar *key,
                     const gchar *old_value,
                     KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_window_set_gesture_items(kz);
}


static void
cb_bookmark_bars_insert_child (KzBookmark *bookmark,
                         KzBookmark *child, KzBookmark *sibling,
                         KzWindow *kz)
{
      GtkWidget *bar;
      GList *children;
      gint pos;

      g_return_if_fail(KZ_IS_BOOKMARK(child));
      g_return_if_fail(KZ_IS_BOOKMARK(sibling));
      g_return_if_fail(KZ_IS_WINDOW(kz));

      bar = kz_bookmark_bar_new(kz, child);
      gtk_box_pack_start(GTK_BOX(kz->bookmark_bars_area), 
                     bar, FALSE, FALSE, 0);    
      gtk_widget_show(bar);

      /* reorder */
      children = kz_bookmark_get_children(bookmark);
      pos = g_list_index(children, child);
      gtk_box_reorder_child(GTK_BOX(kz->bookmark_bars_area),
                        bar, pos);
      g_list_free(children);
}


static void
cb_bookmark_bars_remove_child (KzBookmark *bookmark, KzBookmark *child,
                         KzWindow *kz)
{
      GList *node;

      g_return_if_fail(KZ_IS_BOOKMARK(child));
      g_return_if_fail(KZ_IS_WINDOW(kz));

      for (node = kz->bookmark_bars;
           node;
           node = g_list_next(node))
      {
            if (KZ_BOOKMARK(KZ_BOOKMARK_BAR(node->data)->folder) == child)
            {
                  gtk_widget_destroy(node->data);
                  break;
            }
      }
}


static GtkWidget *
find_bookmark_bar (KzWindow *kz, KzBookmark *folder)
{
      GList *node;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);
      g_return_val_if_fail(KZ_IS_BOOKMARK(folder), NULL);

      for (node = kz->bookmark_bars;
           node;
           node = g_list_next(node))
      {
            KzBookmarkBar *bar;

            if (!KZ_IS_BOOKMARK_BAR(node->data))
            {
                  g_warning("KzWindow: find_bookmark_bar: "
                          "Invalid bookmark bar!: %p", node->data);
                  continue;
            }

            bar = KZ_BOOKMARK_BAR(node->data);
            if (folder == bar->folder)
                  return GTK_WIDGET(bar);
      }

      return NULL;
}


static void
cb_bookmark_bars_reordered (KzBookmark *bookmark, KzWindow *kz)
{
      GList *children, *node;
      gint pos = 0;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      children = kz_bookmark_get_children(bookmark);
      for (node = children; node; node = g_list_next(node))
      {
            GtkWidget *bar;

            bar = find_bookmark_bar(kz, node->data);
            if (!bar)
            {
                  g_warning("KzWindow: reorder bookmark bars: "
                          "bookmark bar for %p is not exist!",
                          node->data);
                  continue; /* create? */
            }

            gtk_box_reorder_child(GTK_BOX(kz->bookmark_bars_area),
                              bar, pos);
            pos++;
      }
      g_list_free(children);
}


static void
cb_smartbookmark_insert_child (KzBookmark *bookmark,
                         KzBookmark *child, KzBookmark *sibling,
                         KzWindow *kz)
{
      g_return_if_fail(KZ_IS_BOOKMARK(child));
      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_actions_insert_smartbookmark(kz, bookmark, child, sibling);
}


static void
cb_smartbookmark_remove_child (KzBookmark *bookmark, KzBookmark *child,
                         KzWindow *kz)
{
      g_return_if_fail(KZ_IS_BOOKMARK(child));
      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_actions_remove_smartbookmark(kz, bookmark, child); 
}


static void
cb_smartbookmark_reordered (KzBookmark *bookmark, KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_actions_update_smartbookmarks(kz, bookmark); 
}



static void
cb_menu_merge_add_widget (GtkUIManager *merge, GtkWidget *widget, GtkBox *box)
{
      gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
}


static gboolean
idle_focus_location_entry(gpointer data)
{
      KzWindow *kz = KZ_WINDOW(data);
      GtkAction *action;
      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);
      action = gtk_action_group_get_action(kz->actions,
                                   "FocusLocationEntry");
      if(action)
            gtk_action_activate(action);
      return FALSE;
}


static void
cb_clipboard_get_text(GtkClipboard *clipboard, const gchar *text, gpointer data)
{
      char **received_text = data;
      *received_text = g_strdup(text);
}


static void
cb_notebook_switch_page (GtkNotebook *notebook, GtkNotebookPage *page,
                   guint page_num, KzWindow *kz)
{
      KzEmbed *kzembed = KZ_EMBED(KZ_WINDOW_NTH_PAGE(kz, page_num));
      KzEmbed *cur = KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz));
      gchar *title;
      const gchar *location;
      GtkAction *action;
      KzTabLabel *tab;
      gboolean focus;

      g_return_if_fail(KZ_IS_EMBED(cur));
      g_return_if_fail(KZ_IS_EMBED(kzembed));

      kz_window_unset_cur_embed_callbacks(kz, cur);
      kz_window_set_cur_embed_callbacks(kz, kzembed);

      title = kz_embed_ensure_title(kzembed);
      location = kz_embed_get_location(kzembed);
      if (title)
      {
            gtk_window_set_title(GTK_WINDOW(kz), title);
            g_free(title);
      }
      else
      {
            gtk_window_set_title(GTK_WINDOW(kz), _("Kazehakase"));
      }

      action = gtk_action_group_get_action(kz->actions, "LocationEntry");
      if (KZ_IS_ENTRY_ACTION(action))
      {
            GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
            GObject *owner = gtk_clipboard_get_owner(clipboard);
            gchar *text = NULL;
            if (GTK_IS_ENTRY(owner)) 
                {
                  gtk_clipboard_request_text(clipboard,
                                       cb_clipboard_get_text,
                                       (gpointer)&text);
            }
            if (location)
                  kz_entry_action_set_text(KZ_ENTRY_ACTION(action),
                                      location);
            else
                  kz_entry_action_set_text(KZ_ENTRY_ACTION(action), "");

            if (text) 
                {
                  gtk_clipboard_set_text(clipboard, text, -1);
                  g_free(text);
            }
      }
      
      action = gtk_action_group_get_action(kz->actions, "Zoom");
      if (KZ_IS_ZOOM_ACTION(action))
      {
            gint ratio;
            ratio = kz_embed_zoom_get(kzembed);
            kz_zoom_action_set_ratio(KZ_ZOOM_ACTION(action), ratio);
      }

      tab = KZ_TAB_LABEL(kz_window_get_tab_label(kz, GTK_WIDGET(kzembed)));
      g_return_if_fail(tab);

      if(kz_tab_label_get_state(tab) == KZ_TAB_LABEL_STATE_LOADED)
      {
            kz_tab_label_set_state(tab, KZ_TAB_LABEL_STATE_NORMAL);
            if((!location || *location == 0 ) &&
               KZ_CONF_GET("Tab","focus_loc_ent_new", focus, BOOL) &&
               focus)
            {
                  g_idle_add(idle_focus_location_entry, kz);
            }
      }

      kz_actions_set_sensitive(kz, kzembed);
      kz_actions_set_tab_sensitive(kz, kzembed);

      kz->priv->view_hist = g_list_remove(kz->priv->view_hist, kzembed);
      kz->priv->view_hist = g_list_prepend(kz->priv->view_hist, kzembed);

      /* set current_position in history */
      if (!kz->is_closing_all && !is_restoring_session)
      {
            kz_bookmark_set_current(kz->tabs, page_num);
            kz_window_store_session(kz);
      }
}

static void
search_found(GtkWidget* widget, KzWindow *kz)
{
      static const GdkColor white = { 0, 0xffff, 0xffff, 0xffff };
      static const GdkColor black = { 0, 0x0000, 0x0000, 0x0000 };

      g_return_if_fail(KZ_IS_WINDOW(kz));

      if(kz->statusbar)
            gtk_statusbar_pop(GTK_STATUSBAR(kz->statusbar),
                          STATUS_SEARCH);
      gtk_widget_modify_base(widget, GTK_STATE_NORMAL, &white);
      gtk_widget_modify_text(widget, GTK_STATE_NORMAL, &black);
}

static void
search_not_found(GtkWidget* widget, KzWindow *kz)
{
      static const GdkColor white = { 0, 0xffff, 0xffff, 0xffff };
      static const GdkColor red = { 0, 0xffff, 0x6666, 0x6666 };
      const gchar *search_word;
      gchar *message;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      search_word = gtk_entry_get_text(GTK_ENTRY(widget));
      message = g_strdup_printf(_("%s not found"), search_word);
      if(kz->statusbar) 
      {
            gtk_statusbar_pop(GTK_STATUSBAR(kz->statusbar),
                          STATUS_SEARCH);
            gtk_statusbar_push(GTK_STATUSBAR(kz->statusbar),
                           STATUS_SEARCH,
                           message);
      }
      g_free(message);

      gtk_widget_modify_base(widget, GTK_STATE_NORMAL, &red);
      gtk_widget_modify_text(widget, GTK_STATE_NORMAL, &white);
}

static void
cb_find_keyword (GtkWidget *widget, KzWindow *kz)
{
      KzEmbed *embed = KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz));
      GtkToggleButton *toggle = GTK_TOGGLE_BUTTON(kz->find_direction);
      const gchar *text = gtk_entry_get_text(GTK_ENTRY(widget));
      gboolean back = gtk_toggle_button_get_active(toggle);

      if (!embed) return;

      if (!text || !(*text))
      {
            search_found(widget, kz);
            return;
      }

      kz->priv->did_find = kz_embed_find(embed, text, back);
      if(kz->priv->did_find)
            search_found(widget, kz);
      else
            search_not_found(widget, kz);
}

static gboolean
cb_find_key_release (GtkWidget *widget, GdkEventKey *event, KzWindow *kz)
{
      KzEmbed *embed ;
      GtkToggleButton *toggle;
      const gchar *text;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      embed = KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz));
      if (!embed) return FALSE;

      toggle = GTK_TOGGLE_BUTTON(kz->find_direction);
      text = gtk_entry_get_text(GTK_ENTRY(widget));
      if (!text || !(*text))
      {
            search_found(widget,kz);
            return FALSE;
      }

      if (event->keyval == GDK_Return || event->keyval == GDK_ISO_Enter)
      {
            if (event->state & GDK_SHIFT_MASK)
            {
                  gboolean back;
                  back = !gtk_toggle_button_get_active(toggle);
                  kz->priv->did_find
                        = kz_embed_find(embed, text, back);
            }
      }
      else
      {
            if (!(event->state & GDK_SHIFT_MASK))
            {
                  gboolean back;
                  back = gtk_toggle_button_get_active(toggle);
                  kz->priv->did_find
                        = kz_embed_incremental_search(embed, text, back);
            }
      }

      if(kz->priv->did_find)
            search_found(widget, kz);
      else
            search_not_found(widget, kz);
      return FALSE;
}

#if 0
static void
cb_find_grab_focus (GtkWidget *widget, KzWindow *kz)
{
      KzEmbed *embed ;

      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_warning("grab");
}
#endif

static void
cb_find_direction_toggle (GtkToggleButton *button, KzWindow *kz)
{
      GtkArrow *arrow;
      gboolean active;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      arrow = GTK_ARROW(GTK_BIN(button)->child);
      g_return_if_fail(GTK_IS_ARROW(arrow));

      active = gtk_toggle_button_get_active(button);
      if (active)
            gtk_arrow_set(arrow, GTK_ARROW_UP, GTK_SHADOW_NONE);
      else
            gtk_arrow_set(arrow, GTK_ARROW_DOWN, GTK_SHADOW_NONE);
}


static void
cb_gesture_stack_motion (KzGesture *gesture, KzGestureMotion motion,
                   KzWindow *kz)
{
      const gchar *label;
      gchar buf1[256], buf2[256];

      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_gesture_create_gesture_string(gesture, buf1, G_N_ELEMENTS(buf1));
      label = kz_gesture_get_matched_label(gesture);
      if (label)
            g_snprintf(buf2, G_N_ELEMENTS(buf2),
                     _("Gesture: %s(Action: %s)"), buf1, label);
      else
            g_snprintf(buf2, G_N_ELEMENTS(buf2),
                     _("Gesture: %s"), buf1);

      gtk_statusbar_pop(GTK_STATUSBAR(kz->statusbar), STATUS_GESTURE);
      gtk_statusbar_push(GTK_STATUSBAR(kz->statusbar),
                     STATUS_GESTURE, buf2);
}


static gboolean
cb_notebook_scroll_event (GtkWidget *widget, GdkEventScroll *event,
                    KzWindow *kz)
{
      GtkNotebook *notebook;
      gboolean circulation = FALSE;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      notebook = GTK_NOTEBOOK(kz->notebook);
      KZ_CONF_GET("Tab", "wheel_circulation", circulation, BOOL);

      switch (event->direction) {
      case GDK_SCROLL_UP:
      case GDK_SCROLL_LEFT:
            if (circulation &&
                gtk_notebook_get_current_page(notebook) == 0) 
            {
                  gtk_notebook_set_current_page
                        (notebook, gtk_notebook_get_n_pages(notebook) - 1);
            }
            else
            {
                  gtk_notebook_prev_page(notebook);
            }
            return TRUE;
            break;
      case GDK_SCROLL_DOWN:
      case GDK_SCROLL_RIGHT:
            if (circulation && 
                gtk_notebook_get_current_page(notebook) == 
                gtk_notebook_get_n_pages(notebook) - 1) 
            {
                  gtk_notebook_set_current_page(notebook, 0);
            }
            else
            {
                  gtk_notebook_next_page(notebook);
            }
            return TRUE;
            break;
      default:
            g_warning ("Invalid scroll direction!");
            break;
      }

      return FALSE;
}


static void
cb_sidebar_map (GtkWidget *widget, GtkToggleAction *action)
{
      g_return_if_fail(GTK_IS_TOGGLE_ACTION(action));

      KZ_SIDEBAR(widget)->kz->priv->sidebar_was_shown = TRUE;

      gtk_toggle_action_set_active(action, TRUE);
}


static void
cb_sidebar_unmap (GtkWidget *widget, GtkToggleAction *action)
{
      g_return_if_fail(GTK_IS_TOGGLE_ACTION(action));

      gtk_toggle_action_set_active(action, FALSE);
}


/*****************************************************************************
 *                                                                           *
 *                        Callbacks for Embed                                *
 *                                                                           *
 *****************************************************************************/
static void
cb_embed_title_changed (KzEmbed *embed, KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      if (embed == KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz)))
      {
            const gchar *title
                  = kz_embed_get_title(KZ_EMBED(embed));
            gtk_window_set_title(GTK_WINDOW(kz), (gchar *) title);
      }
}


static void
cb_embed_location_changed (KzEmbed *embed, KzWindow *kz)
{
      const char *newLocation;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      newLocation = kz_embed_get_location(KZ_EMBED(embed));
      if (newLocation)
      {
            GtkAction *action
                  = gtk_action_group_get_action(kz->actions,
                                          "LocationEntry");
            if (embed == KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz))
                && KZ_IS_ENTRY_ACTION(action))
            {
                  kz_entry_action_set_text(KZ_ENTRY_ACTION(action),
                                     newLocation);
            }
      }
      else
      {
            /* g_print("failed to get location!\n"); */
      }

      kz_actions_set_sensitive(kz, embed);
}


static void
cb_embed_link_message (KzEmbed *embed, KzWindow *kz)
{
      gchar *newMessage;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      newMessage = kz_embed_get_link_message(KZ_EMBED(embed));
      if(kz->statusbar) 
      {
            gtk_statusbar_pop(GTK_STATUSBAR(kz->statusbar),
                          STATUS_LINK_MESSAGE);
            gtk_statusbar_push(GTK_STATUSBAR(kz->statusbar),
                           STATUS_LINK_MESSAGE, newMessage);
      }

      g_free(newMessage);
}


static void
cb_embed_load_started (KzEmbed *embed, KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_actions_set_sensitive(kz, KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz)));
}


static void
cb_embed_load_finished (KzEmbed *embed, KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      kz_actions_set_sensitive(kz, KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz)));
}


static void
cb_embed_new_window (KzEmbed *embed, KzEmbed **newEmbed,
                 KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      *newEmbed = KZ_EMBED(kz_window_open_new_tab(kz, NULL));
      gtk_widget_show (GTK_WIDGET(*newEmbed));
}


static void
cb_embed_close_tab (GtkObject *obj, KzWindow *kz)
{
      KzEmbed *kzembed;
      GNode *node, *child;

      g_return_if_fail(KZ_IS_WINDOW(kz));
      g_return_if_fail(kz->priv->tab_tree);

      kzembed = KZ_EMBED(obj);

      kz_window_unset_cur_embed_callbacks(kz, kzembed);
      kz_window_unset_embed_callbacks(kz, kzembed);

      kz->priv->view_hist = g_list_remove(kz->priv->view_hist, kzembed);
      kz->priv->open_hist = g_list_remove(kz->priv->open_hist, kzembed);

      gtk_statusbar_pop(GTK_STATUSBAR(kz->statusbar), STATUS_LINK_MESSAGE);

      node = g_node_find(kz->priv->tab_tree,
                     G_IN_ORDER, G_TRAVERSE_ALL, kzembed);
      /* probably destroy handler is already called */
      if (!node) return;

      /* move children */
      child = g_node_first_child(node);
      while (child)
      {
            GNode *next = g_node_next_sibling(child);
            g_node_unlink(child);
            g_node_append(kz->priv->tab_tree, child);
            child = next;
      }
      
      /* FIXME! should move to specifing tab like kz_window_close_tab() */
      g_node_destroy(node);
      gtk_widget_destroy(GTK_WIDGET(kzembed));
      g_signal_emit(kz, kz_window_signals[REMOVE_TAB_SIGNAL],
                  0, kzembed);
}


static gint
cb_embed_dom_key_down (KzEmbed *embed, KzEmbedEventKey *event, KzWindow *kz)
{

      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      kz_actions_set_sensitive(kz, embed);

      return FALSE;
}


static gint
cb_embed_dom_key_up (KzEmbed *embed, KzEmbedEventKey *event, KzWindow *kz)
{
      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      kz_actions_set_sensitive(kz, embed);

      return FALSE;
}


#warning FIXME
static gint
cb_embed_dom_mouse_click (KzEmbed *embed, KzEmbedEventMouse *event,
                    KzWindow *kz)
{
      gint button;
      guint32 time;
      glong type;
      KzTabLabel *kztab = NULL;
      GtkWidget *widget = KZ_WINDOW_CURRENT_PAGE(kz);

      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      time = GDK_CURRENT_TIME;
      
      type = event->cinfo.context;
      button = event->button;

      switch (button) {
      case 0:
            if ((type & KZ_CONTEXT_LINK) && event->cinfo.link)
            {
                  const gchar *location;

                  kztab = KZ_TAB_LABEL
                        (gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook),
                                              widget));

                  /* with Shift key or in locked tab, open new tab */
                  if ((event->modifier & KZ_SHIFT_KEY) ||
                      (kztab && kz_tab_label_get_lock(kztab)))
                  {
                        kz_window_open_new_tab_with_parent
                              (kz, event->cinfo.link, GTK_WIDGET(embed));
                        return TRUE;
                  }
                  location = kz_embed_get_location(KZ_EMBED(embed));
                  if (!strncmp(location, "history-search:", 15))
                  {
                        kz_embed_load_url(KZ_EMBED(embed), 
                                      event->cinfo.link);
                  }
            }
            break;
      case 1:
            if ((type & KZ_CONTEXT_LINK) && event->cinfo.link)
            {
                  gboolean focus_mid_click_link = FALSE;
                  KZ_CONF_GET("Tab", "focus_mid_click_link", focus_mid_click_link, BOOL);

                  widget = kz_window_open_new_tab_with_parent(kz, event->cinfo.link,
                                                    GTK_WIDGET(embed));

                  if(((event->modifier & KZ_SHIFT_KEY) != 0) ^ focus_mid_click_link)
                  {
                        gtk_notebook_set_current_page(GTK_NOTEBOOK(kz->notebook),
                                                gtk_notebook_page_num(GTK_NOTEBOOK(kz->notebook), widget));
                  }
            }
            else if (!(type & KZ_CONTEXT_INPUT))
            {
                  GtkAction *action;

                  action = gtk_action_group_get_action(kz->actions,
                                               "OpenSelection");

                  /* what about uri list? */
                  if (action)
                        gtk_action_activate(action);

                  break;
            }
            break;
      default:
            break;
      }

      return FALSE;
}


static gint
cb_embed_dom_mouse_dbl_click (KzEmbed *embed, KzEmbedEventMouse *event,
                        KzWindow *kz)
{
#if 0
      KzEmbedEventMouse *info;
      gint button;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      type = kz_embed_get_mouse_event_info(KZ_MOZ_EMBED(embed), event, &info);
      button = info->button;
      kz_embed_event_free(info);
      switch (button) {
       case 0:
             gtk_notebook_prev_page(GTK_NOTEBOOK(kz->notebook));
             break;
       case 2:    
             gtk_notebook_next_page(GTK_NOTEBOOK(kz->notebook));
             break;
      }
#endif

      return FALSE;
}


static gint
cb_embed_dom_mouse_down (KzEmbed *kzembed, KzEmbedEventMouse *event,
                   KzWindow *kz)
{
      gint button;
      glong type;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      type = event->cinfo.context;
      button = event->button;
      if (kz->priv->event)
            kz_embed_event_free((KzEmbedEvent *) kz->priv->event);
      kz->priv->event = (KzEmbedEventMouse *) kz_embed_event_copy((KzEmbedEvent *) event);

      switch (button)
      {
      case 0:
            break;
      case 1:
      {
            gchar *modifier_name = NULL;
            gchar *tmp_name = NULL;
            tmp_name = KZ_CONF_GET_STR("Global", "autoscroll_modifier");

            if(tmp_name)
            {
                  modifier_name = g_ascii_strdown(tmp_name, -1);
                  g_free(tmp_name);
            }

            if(modifier_name) 
            {
                  gint i;
                  gint modifier_id = 2;
                  for (i = 0; i < G_N_ELEMENTS(modifier_map); i++)
                  {
                        if(!strcmp(modifier_name, modifier_map[i].name))
                        {
                              modifier_id = modifier_map[i].id;
                              break;
                        }
                  }

                  if((event->modifier & modifier_id) && 
                     (!((KzEmbedEvent*)event)->link))
                  {
                        GtkAction *action;
                        action = gtk_action_group_get_action(kz->actions,
                                                     "AutoScrollMode");
                        if (action)
                              gtk_action_activate(action);
                  }
                  g_free(modifier_name);
            }
            else
            {
                  if (!((KzEmbedEvent*)event)->link)
                  {
                        GtkAction *action;
                        action = gtk_action_group_get_action(kz->actions,
                                                     "AutoScrollMode");
                        if (action)
                              gtk_action_activate(action);
                  }
                  break;
            }
            break;
      }
      case 2:
      {
            static GdkCursor *cursor = NULL;
            gboolean use_gesture = TRUE;
            gint x, y, win_x, win_y, win_x_pos, win_y_pos;

            kz->priv->is_gesture = FALSE;
            KZ_CONF_GET("Gesture", "use_gesture", use_gesture, BOOL);
            if (!use_gesture)
            {
                  gdk_pointer_grab (GTK_WIDGET(kz)->window,
                                FALSE,
                                GDK_BUTTON_RELEASE_MASK |
                                GDK_BUTTON_PRESS_MASK,
                                NULL,     cursor, gtk_get_current_event_time ());
                  break;
            }
            /* start gesture */

            gtk_widget_get_pointer (GTK_WIDGET(kzembed), &x, &y);

            kz->priv->start_x = x;
            kz->priv->start_y = y;

            gdk_window_get_root_origin (GTK_WIDGET(kzembed)->window,
                                  &win_x, &win_y);
            gdk_window_get_position (GTK_WIDGET(kzembed)->window,
                               &win_x_pos, &win_y_pos);

            gtk_widget_get_pointer (GTK_WIDGET(kzembed),
                              &x, &y);
            kz_gesture_start(kz->priv->gesture, 0, x, y);

            if (!cursor) cursor = gdk_cursor_new (GDK_HAND1);
            gdk_pointer_grab (GTK_WIDGET(kz)->window,
                          FALSE,
                          GDK_POINTER_MOTION_MASK |
                          GDK_BUTTON_RELEASE_MASK |
                          GDK_BUTTON_PRESS_MASK,
                          NULL, cursor, gtk_get_current_event_time ());
            gtk_statusbar_push(GTK_STATUSBAR(kz->statusbar),
                           STATUS_GESTURE, _("Gesture:"));
            break;
      }
      default:
            break;
      }

      kz_actions_set_selection_sensitive(kz, kzembed);

      return FALSE;
}


static gint
cb_embed_dom_mouse_up (KzEmbed *embed, KzEmbedEventMouse *event,
                   KzWindow *kz)
{
      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      kz_actions_set_selection_sensitive(kz, embed);

      return FALSE;
}

static gint
cb_embed_dom_mouse_over (KzEmbed *embed, KzEmbedEventMouse *event,
                     KzWindow *kz)
{
      static glong previous_event_context = KZ_CONTEXT_NONE;
      glong type;
      gboolean popup_thumbnail;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      KZ_CONF_GET("Global", "popup_thumbnail", popup_thumbnail, BOOL);
      if (!popup_thumbnail) return FALSE;

      type = event->cinfo.context;
      if ((type & KZ_CONTEXT_LINK) && event->cinfo.link)
      {
            GtkWidget *widget = KZ_WINDOW_CURRENT_PAGE(kz);
            GdkDisplay *display = gtk_widget_get_display (widget);
            gint x, y;

            display = gtk_widget_get_display (widget);
            gdk_display_get_pointer (display, NULL, &x, &y, NULL);

            kz_popup_preview_start(kz->popup, event->cinfo.link, event->cinfo.img, x, y);
      }
      else if(!(type & KZ_CONTEXT_LINK) && (previous_event_context & KZ_CONTEXT_LINK))
      {
            kz_popup_preview_reset(kz->popup);
      }

      previous_event_context = type;
      kz_actions_set_selection_sensitive(kz, embed);

      return FALSE;
}

static gboolean
cb_window_motion_notify_event (GtkWidget *widget,
                         GdkEventMotion *event,
                         KzEmbed *kzembed)
{
      KzWindow *kz;
      gint x, y;
      /* GdkModifierType state; */

      g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);

      kz = KZ_WINDOW(widget);

      /*gdk_window_get_pointer (GTK_WIDGET(kzembed)->window, &x, &y, &state);*/
      gtk_widget_get_pointer (GTK_WIDGET(kzembed), &x, &y);

      if (abs(x - kz->priv->start_x) > 2 ||
          abs(y - kz->priv->start_y) > 2)
      {
            kz->priv->is_gesture = TRUE;
      }

      if (kz_gesture_is_started(kz->priv->gesture))
      {
            /* if(state == GDK_BUTTON3_MASK) */
            kz_gesture_update_position(kz->priv->gesture, x, y);
            /*
            else
            {
                  if (gdk_pointer_is_grabbed ())
                  {
                        gdk_pointer_ungrab (gtk_get_current_event_time ());
                  }
                  kz_gesture_perform(kz->priv->gesture);
                  gtk_statusbar_push(GTK_STATUSBAR(KZ_WINDOW(widget)->statusbar),
                           STATUS_GESTURE, "");
                  kz->priv->start_x = 0;
                  kz->priv->start_y = 0;
                  kz->priv->is_gesture = FALSE;

                  if (kz->priv->event)
                        kz_embed_event_free((KzEmbedEvent *) kz->priv->event);
                  kz->priv->event = NULL;
            }
            */
      }

      kz_actions_set_selection_sensitive(kz, kzembed);

      return FALSE;
}


static gboolean
cb_window_button_release_event (GtkWidget *widget,
                        GdkEventButton *event,
                        KzEmbed *kzembed)
{
      KzWindow *kz;
      gboolean retval = FALSE;

      g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);

      kz = KZ_WINDOW(widget);

        if (gdk_pointer_is_grabbed ())
        {
                gdk_pointer_ungrab (gtk_get_current_event_time ());
        }

      if (kz_gesture_is_started(kz->priv->gesture))
      {
            if (event->button == 3)
                  kz_gesture_perform(kz->priv->gesture);
            else
                  kz_gesture_cancel(kz->priv->gesture);
            gtk_statusbar_pop(GTK_STATUSBAR(KZ_WINDOW(widget)->statusbar),
                          STATUS_GESTURE);
      }

      if (!kz->priv->is_gesture && event->button == 3)
      {
            kz_actions_popup_menu_modal (kz, event->button, event->time);
            retval = TRUE;
      }

      kz->priv->start_x = 0;
      kz->priv->start_y = 0;
      kz->priv->is_gesture = FALSE;

      if (kz->priv->event)
            kz_embed_event_free((KzEmbedEvent *) kz->priv->event);
      kz->priv->event = NULL;

      return retval;
}


static void
cb_notebook_drag_data_received (GtkWidget *widget,
                        GdkDragContext *drag_context,
                        gint x, gint y,
                        GtkSelectionData *data,
                        guint info,
                        guint time,
                        KzWindow *kz)
{
      g_return_if_fail(KZ_IS_WINDOW(kz));

      switch (info)
      {
      case TARGET_KAZEHAKASE_TAB:
      {
            GtkWidget *src_widget;
            KzWindow *src_kz;
            KzTabLabel *src_kztab;

            src_widget = gtk_drag_get_source_widget(drag_context);

            if (!KZ_IS_TAB_LABEL(src_widget)) return;
            src_kztab = KZ_TAB_LABEL(src_widget);

            src_kz = KZ_WINDOW(kz_window_get_from_tab(GTK_WIDGET(src_kztab->kzembed)));
            if (kz == src_kz)
            {
                  gint n;

                  n = gtk_notebook_get_n_pages(GTK_NOTEBOOK(kz->notebook));
                  kz_window_reorder_tab(kz, GTK_WIDGET(src_kztab->kzembed),
                                    n - 1);
                  kz_actions_set_sensitive
                        (kz, KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz)));
                  kz_actions_set_tab_sensitive
                        (kz, KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kz)));
            }
            else
            {
                  kz_window_move_tab(kz, GTK_WIDGET(src_kztab->kzembed));
            }

            break;
      }

      case TARGET_NETSCAPE_URL:
      case TARGET_TEXT_URI_LIST:
      case TARGET_TEXT_PLAIN:
      case TARGET_STRING:
      {
            gchar *string, **strings;

            if (data->length < 0) return;
            string = g_alloca (data->length + 1);

            memcpy (string, data->data, data->length);
            string[data->length] = '\0';

            strings = g_strsplit(string, "\n", 2);
            kz_window_open_new_tab(kz, strings[0]);
            g_strfreev(strings);
            break;

      }
      default:
            break;
      }
}

static gboolean 
cb_focus_out_event            (GtkWidget       *widget,
                         GdkEventFocus   *event,
                         KzWindow        *kz)
{
      if(!event->in) 
      {
            /* focus is out */
            if (kz_gesture_is_started(kz->priv->gesture))
            {
                  kz_gesture_cancel(kz->priv->gesture);
                  gtk_statusbar_pop(GTK_STATUSBAR(KZ_WINDOW(widget)->statusbar),
                                STATUS_GESTURE);
            }

            if (gdk_pointer_is_grabbed ())
            {
                  gdk_pointer_ungrab (gtk_get_current_event_time ());
            }
      }
      return FALSE;
}

void
kz_window_append_closed_tab (KzWindow *kz, KzBookmark *bookmark)
{
      GList *children;
      KzBookmark *last;

      kz_bookmark_prepend(kz->closed_tabs, bookmark);

      /* removed the oldest one */
      children = kz_bookmark_get_children(kz->closed_tabs);
      if (children)
      {
            last = g_list_nth_data(children, MAX_CLOSED_TABS);
            if (last)
                  kz_bookmark_remove(kz->closed_tabs, last);
            g_list_free(children);
      }
}


Generated by  Doxygen 1.6.0   Back to index