
/*
 * Osmo - a handy personal organizer
 *
 * Copyright (C) 2007 Tomasz Maka <pasp@users.sourceforge.net>
 *
 * 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 of the License, 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 "gui.h"
#include "about.h"
#include "i18n.h"
#include "utils.h"
#include "utils_gui.h"
#include "utils_date.h"
#include "calendar.h"
#include "calendar_notes.h"
#include "calendar_fullyear.h"
#include "calendar_widget.h"
#include "calendar_jumpto.h"
#include "calendar_calc.h"
#ifdef HAVE_LIBICAL
#include "calendar_ical.h"
#endif  /* HAVE_LIBICAL */
#include "calendar_utils.h"
#include "notes.h"
#include "notes_items.h"
#include "tasks.h"
#include "tasks_items.h"
#include "tasks_utils.h"
#include "notes_items.h"
#include "contacts.h"
#include "contacts_items.h"
#include "options_prefs.h"
#include "check_events.h"
#include "stock_icons.h"
#include "preferences_gui.h"
#include "calendar_preferences_gui.h"
#include "config.h"

#ifndef WIN32
#include <glib-unix.h>
#endif /* WIN32 */

struct  osmo_prefs              config;
/*------------------------------------------------------------------------------*/

void
gui_quit_osmo_cb(GtkToolButton *toolbutton, gpointer data) {
    GUI *appGUI = (GUI *) data;
    gui_quit_osmo(appGUI);
}

/*------------------------------------------------------------------------------*/
void
gui_show_about_window_cb(GtkToolButton *toolbutton, gpointer data) {
    GUI *appGUI = (GUI *) data;
    GtkWidget *window = opt_create_about_window(appGUI);
    gtk_widget_show(window);
}

/*------------------------------------------------------------------------------*/
void
gui_save_data_and_run_command (gchar *command, GUI *appGUI) {
    gui_save_all_data (appGUI);
    utl_run_command (command, FALSE);
}

/*------------------------------------------------------------------------------*/

void
gui_save_all_data (GUI *appGUI) {

    cal_write_notes (appGUI);
#ifdef TASKS_ENABLED
    store_task_columns_info (appGUI);
    write_tasks_entries (appGUI);
#endif  /* TASKS_ENABLED */
#ifdef HAVE_LIBICAL
    write_ical_entries (appGUI);
    ics_calendar_refresh (appGUI);
#endif  /* HAVE_LIBICAL */
#ifdef CONTACTS_ENABLED
    store_contact_columns_info (appGUI);
    write_contacts_entries (appGUI);
#endif  /* CONTACTS_ENABLED */
#ifdef NOTES_ENABLED
    store_note_columns_info (appGUI);
    write_notes_entries (appGUI);
#endif  /* NOTES_ENABLED */
    prefs_write_config (appGUI);

}

/*------------------------------------------------------------------------------*/

void
gui_toggle_window_visibility (GUI *appGUI) {

    if (appGUI->no_tray == FALSE) {

        appGUI->window_visible = !appGUI->window_visible;

        if (appGUI->window_visible == TRUE) {
            gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NORMAL);
            gtk_window_set_default_size (GTK_WINDOW(appGUI->main_window), 
                                         config.window_size_x, config.window_size_y);
            gtk_window_move (GTK_WINDOW (appGUI->main_window), config.window_x, config.window_y);
            gtk_widget_show (appGUI->main_window);
        } else {
            if (appGUI->calendar_only == FALSE) {
                gui_save_all_data (appGUI);
                gtk_window_get_size (GTK_WINDOW(appGUI->main_window),
                                    &config.window_size_x, &config.window_size_y);
                gdk_window_get_root_origin (gtk_widget_get_window(appGUI->main_window),
                                    &config.window_x, &config.window_y);
            }
            gtk_widget_hide (appGUI->main_window);
        }
    }
}

/*------------------------------------------------------------------------------*/

void
gui_toggle_fullscreen (GUI *appGUI) {
    if (config.fullscreen == FALSE) {
        gtk_window_fullscreen (GTK_WINDOW(appGUI->main_window));
        config.fullscreen = TRUE;
    } else {
        gtk_window_unfullscreen (GTK_WINDOW(appGUI->main_window));
        config.fullscreen = FALSE;
    }
}

/*------------------------------------------------------------------------------*/

void
gui_quit_osmo (GUI *appGUI) {

#ifdef NOTES_ENABLED
    if (appGUI->nte->editor_active == TRUE) {
        editor_close_cb (NULL, appGUI);
    }
#endif  /* NOTES_ENABLED */

    if (appGUI->osmo_trayicon != NULL) {
        gtk_status_icon_set_visible (appGUI->osmo_trayicon, FALSE);
    }

    if (appGUI->calendar_only == FALSE) {
        if (appGUI->current_tab == PAGE_CALENDAR 
#ifdef TASKS_ENABLED
            || appGUI->current_tab == PAGE_TASKS 
#endif  /* TASKS ENABLED */
#if defined(NOTES_ENABLED) && defined(CONTACTS_ENABLED)
            || appGUI->current_tab == PAGE_CONTACTS || appGUI->current_tab == PAGE_NOTES) {
#elif CONTACTS_ENABLED
            || appGUI->current_tab == PAGE_CONTACTS) {
#else
            ) {
#endif  /* NOTES_ENABLED && CONTACTS_ENABLED */
            config.latest_tab = appGUI->current_tab;
        }

#ifdef CONTACTS_ENABLED
        config.find_mode = gtk_combo_box_get_active (GTK_COMBO_BOX(appGUI->cnt->contacts_find_combobox));
#endif  /* CONTACTS_ENABLED */

#ifdef TASKS_ENABLED
        config.current_category_in_tasks = gtk_combo_box_get_active (GTK_COMBO_BOX(appGUI->tsk->cf_combobox));
#endif  /* TASKS_ENABLED */

#ifdef NOTES_ENABLED
        config.current_category_in_notes = gtk_combo_box_get_active (GTK_COMBO_BOX(appGUI->nte->cf_combobox));
#endif  /* NOTES_ENABLED */

        gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON(appGUI->cal->notes_button), FALSE);

        if (appGUI->window_visible == TRUE) {
            if (!config.fullscreen) {
                gtk_window_get_size (GTK_WINDOW(appGUI->main_window),
                                    &config.window_size_x, &config.window_size_y);
            }
        }
    } 

    if (appGUI->window_visible == TRUE) {
        gdk_window_get_root_origin (gtk_widget_get_window(appGUI->main_window),
                            &config.window_x, &config.window_y);
    }

    pango_font_description_free(appGUI->cal->fd_day_name_font);
    pango_font_description_free(appGUI->cal->fd_cal_font);
    pango_font_description_free(appGUI->cal->fd_notes_font);

    if (appGUI->calendar_only == FALSE) {
        g_source_remove(appGUI->timer);
        config.lastrun_date = utl_date_get_current_julian ();
        config.lastrun_time = utl_time_get_current_seconds ();
        gui_save_all_data (appGUI);
#ifdef HAVE_LIBNOTIFY
#ifdef TASKS_ENABLED
        free_notifications_list (appGUI);
#endif  /* TASKS_ENABLED */
#endif  /* HAVE_LIBNOTIFY */
        cal_free_notes_list (appGUI);
    }

    utl_gui_url_remove_links (&appGUI->about_links_list, &appGUI->about_link_index);
    gtk_main_quit ();
}

/*------------------------------------------------------------------------------*/

void
gui_window_close_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) {

    GUI *appGUI = (GUI *)user_data;

    if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
        gui_toggle_window_visibility (appGUI);
    } else {
        gui_quit_osmo (appGUI);
    }
}

/*------------------------------------------------------------------------------*/

void
gui_activate_find_fields (GUI *appGUI) {

#ifdef NOTES_ENABLED
    if (appGUI->current_tab == PAGE_NOTES) {
        gtk_widget_grab_focus (GTK_WIDGET(appGUI->nte->notes_find_entry));
    }
#endif  /* NOTES_ENABLED */

#ifdef TASKS_ENABLED
    if (appGUI->current_tab == PAGE_TASKS) {
        gtk_widget_grab_focus (GTK_WIDGET(appGUI->tsk->tasks_find_entry));
    }
#endif  /* TASKS_ENABLED */

#ifdef CONTACTS_ENABLED
    if (appGUI->current_tab == PAGE_CONTACTS) {
        gtk_widget_grab_focus (GTK_WIDGET(appGUI->cnt->contacts_find_entry));
    }
#endif  /* CONTACTS_ENABLED */

}

/*------------------------------------------------------------------------------*/

gint
get_first_active_page (GUI *appGUI) {

    if (!config.hide_calendar) 
        return PAGE_CALENDAR;
#ifdef TASKS_ENABLED
    if (!config.hide_tasks) 
        return PAGE_TASKS;
#endif  /* TASKS_ENABLED */
#ifdef CONTACTS_ENABLED
    if (!config.hide_contacts) 
        return PAGE_CONTACTS;
#endif  /* CONTACTS_ENABLED */
#ifdef NOTES_ENABLED
    if (!config.hide_notes) 
        return PAGE_NOTES;
#endif  /* NOTES_ENABLED */

    return PAGE_CALENDAR;
}

/*------------------------------------------------------------------------------*/

void
set_visible_page (gint page, gboolean dir, GUI *appGUI) {

gboolean flag;
gint n = 1;

    if (dir == FALSE) n = -1;

    page += n;
    flag = TRUE;

    while (flag) {

        flag = FALSE;

        switch (page) {
            case PAGE_CALENDAR:
                if (config.hide_calendar) {
                    page += n;
                    flag = TRUE;
                }
                break;
#ifdef TASKS_ENABLED
            case PAGE_TASKS:
                if (config.hide_tasks) {
                    page += n;
                    flag = TRUE;
                }
                break;
#endif  /* TASKS_ENABLED */
#ifdef CONTACTS_ENABLED
            case PAGE_CONTACTS:
                if (config.hide_contacts) {
                    page += n;
                    flag = TRUE;
                }
                break;
#endif  /* CONTACTS_ENABLED */
#ifdef NOTES_ENABLED
            case PAGE_NOTES:
                if (config.hide_notes) {
                    page += n;
                    flag = TRUE;
                }
                break;
#endif  /* NOTES_ENABLED */
        }
    }

    if (dir == FALSE) {
        appGUI->current_tab = (page < 0) ? appGUI->number_of_tabs-1:page;
    } else {
        appGUI->current_tab = (page == appGUI->number_of_tabs) ? get_first_active_page(appGUI):page;
    }
    gtk_notebook_set_current_page (GTK_NOTEBOOK (appGUI->notebook), appGUI->current_tab);

    gui_activate_find_fields (appGUI);

}

/*------------------------------------------------------------------------------*/

static gint
get_visible_tabs (GUI *appGUI)
{
    gint i = 0;

    if (!config.hide_calendar) i++;
#ifdef TASKS_ENABLED
    if (!config.hide_tasks) i++;
#endif  /* TASKS_ENABLED */
#ifdef CONTACTS_ENABLED
    if (!config.hide_contacts) i++;
#endif  /* CONTACTS_ENABLED */
#ifdef NOTES_ENABLED
    if (!config.hide_notes) i++;
#endif  /* NOTES_ENABLED */

    return i;
}

/*------------------------------------------------------------------------------*/

static void
select_tab (gint tab, GUI *appGUI)
{
    gint i, n = 0;

    if (tab >= get_visible_tabs (appGUI)) return;

    for (i = PAGE_CALENDAR; i < NUMBER_OF_TABS; i++) {

        if (i == PAGE_CALENDAR && !config.hide_calendar) n++;
#ifdef TASKS_ENABLED
        if (i == PAGE_TASKS && !config.hide_tasks) n++;
#endif  /* TASKS_ENABLED */
#ifdef CONTACTS_ENABLED
        if (i == PAGE_CONTACTS && !config.hide_contacts) n++;
#endif  /* CONTACTS_ENABLED */
#ifdef NOTES_ENABLED
        if (i == PAGE_NOTES && !config.hide_notes) n++;
#endif  /* NOTES_ENABLED */

        if (n == tab + 1) {
            gtk_notebook_set_current_page (GTK_NOTEBOOK (appGUI->notebook), i);
            break;
        }
    }

    gui_activate_find_fields (appGUI);
}

/*------------------------------------------------------------------------------*/

void
key_counter_add (gint value, GUI *appGUI) {

GtkWidget *dialog;
GtkWidget *image;
gchar *tmpbuff;

    appGUI->key_counter += value;

    if (appGUI->key_counter == 57) {
        tmpbuff = g_strdup_printf("<span size='xx-large'><b>%d times!</b></span>", config.run_counter);

        dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(appGUI->main_window),
                GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
                GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, tmpbuff, NULL);
        gtk_window_set_title (GTK_WINDOW(dialog), _("Counter"));
        image = gtk_image_new_from_icon_name(OSMO_STOCK_INFO_HELP, GTK_ICON_SIZE_DIALOG);
        gtk_widget_show (image);
        gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog), image);
        gtk_widget_show (dialog);
        gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_destroy(dialog);
        g_free(tmpbuff);
    } else if (appGUI->key_counter == 41) {
        appGUI->cal->datecal_bio = TRUE;
    }
}

/*------------------------------------------------------------------------------*/

gint 
key_press_cb (GtkWidget *widget, GdkEventKey *event, GUI *appGUI)
{
    gint page;

    page = gtk_notebook_get_current_page (GTK_NOTEBOOK(appGUI->notebook));

    /************************************************************************/
    /*** CALENDAR PAGE                                                    ***/
    /************************************************************************/

    if(page == PAGE_CALENDAR) {

        if (!config.day_notes_visible) {

            switch (event->keyval) {
                case GDK_KEY_Left:
                    calendar_btn_prev_day(appGUI);
                    return TRUE;
                case GDK_KEY_Right:
                    calendar_btn_next_day(appGUI);
                    return TRUE;
                case GDK_KEY_Up:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Up */
                        utl_gui_sw_vscrollbar_move_position (appGUI->cal->day_info_scrolledwindow, SW_MOVE_UP);
                        return TRUE;
                    } else {
                        calendar_btn_prev_week(appGUI);
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Down:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Up */
                        utl_gui_sw_vscrollbar_move_position (appGUI->cal->day_info_scrolledwindow, SW_MOVE_DOWN);
                        return TRUE;
                    } else {
                        calendar_btn_next_week(appGUI);
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Home:
                    calendar_btn_prev_year(appGUI);
                    return TRUE;
                case GDK_KEY_End:
                    calendar_btn_next_year(appGUI);
                    return TRUE;
                case GDK_KEY_Return:
                    if (appGUI->calendar_only == FALSE) {
                        gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON(appGUI->cal->notes_button), 
                                                           !gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(appGUI->cal->notes_button)));
                    }
                    return TRUE;
                case GDK_KEY_space:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Space */
                        config.enable_day_mark = !config.enable_day_mark;
                        cal_refresh_marks (appGUI);
                        cal_set_day_info (appGUI);
                        update_aux_calendars (appGUI);
                        return TRUE;
                    } else {
                        calendar_set_today (appGUI);
                        return TRUE;
                    }
                case GDK_KEY_Delete:
                    if (appGUI->calendar_only == FALSE) {
                        calendar_clear_text_cb (NULL, appGUI);
                    }
                    return TRUE;
                case GDK_KEY_g:
                    calendar_create_jumpto_window (appGUI);
                    return TRUE;
                case GDK_KEY_f:
                    calendar_create_fullyear_window (appGUI);
                    return TRUE;
                case GDK_KEY_c:
                    calendar_create_color_selector_window (TRUE, appGUI);
                    key_counter_add (13, appGUI);
                    return TRUE;
                case GDK_KEY_d:
                    calendar_create_calc_window (appGUI);
                    return TRUE;
                case GDK_KEY_a:
                    if (!config.gui_layout) {
                        gtk_expander_set_expanded (GTK_EXPANDER (appGUI->cal->aux_cal_expander),
                                                   !gtk_expander_get_expanded (GTK_EXPANDER (appGUI->cal->aux_cal_expander)));
                    }
                    key_counter_add (5, appGUI);
                    return TRUE;
                case GDK_KEY_b:
                    if (appGUI->calendar_only == FALSE) {
                        cal_notes_browser (appGUI);
                    }
                    key_counter_add (11, appGUI);
                    return TRUE;
                case GDK_KEY_i:
                    key_counter_add (9, appGUI);
                    return TRUE;
                case GDK_KEY_o:
                    key_counter_add (21, appGUI);
                    return TRUE;
            }

        }

        switch (event->keyval) {

            case GDK_KEY_Escape:
                if (appGUI->calendar_only == FALSE) {
                    if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(appGUI->cal->notes_button)) == FALSE) {
                        if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
                            gui_toggle_window_visibility (appGUI);
                        }
                    } else {
                        gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appGUI->cal->notes_button), FALSE);
                    }
                }
                return TRUE;
            case GDK_KEY_Left:
                if (event->state & GDK_MOD1_MASK) {  /* ALT + Left */
                    calendar_btn_prev_day(appGUI);
                    return TRUE;
                }
                return FALSE;
            case GDK_KEY_Right:
                if (event->state & GDK_MOD1_MASK) {  /* ALT + Right */
                    calendar_btn_next_day(appGUI);
                    return TRUE;
                }
                return FALSE;
            case GDK_KEY_Up:
                if (event->state & GDK_MOD1_MASK) {  /* ALT + Up */
                    calendar_btn_prev_week(appGUI);
                    return TRUE;
                }
                return FALSE;
            case GDK_KEY_Down:
                if (event->state & GDK_MOD1_MASK) {  /* ALT + Down */
                    calendar_btn_next_week(appGUI);
                    return TRUE;
                }
                return FALSE;
            case GDK_KEY_b:
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + b */
                    g_signal_emit_by_name(G_OBJECT(appGUI->cal->ta_bold_button), "clicked");
                    return TRUE;
                }
                return FALSE;

            case GDK_KEY_i:
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + i */
                    g_signal_emit_by_name(G_OBJECT(appGUI->cal->ta_italic_button), "clicked");
                    return TRUE;
                }
                return FALSE;

            case GDK_KEY_m:
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + m */
                    g_signal_emit_by_name(G_OBJECT(appGUI->cal->ta_highlight_button), "clicked");
                    return TRUE;
                }
                return FALSE;

            case GDK_KEY_u:
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + u */
                    g_signal_emit_by_name(G_OBJECT(appGUI->cal->ta_underline_button), "clicked");
                    return TRUE;
                }
                return FALSE;

            case GDK_KEY_t:
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + t */
                    g_signal_emit_by_name(G_OBJECT(appGUI->cal->ta_strikethrough_button), "clicked");
                    return TRUE;
                }
                return FALSE;
        }

    }

#ifdef TASKS_ENABLED

    /************************************************************************/
    /*** TASKS PAGE                                                        ***/
    /************************************************************************/

    if(page == PAGE_TASKS) {

            switch (event->keyval) {

                case GDK_KEY_Escape:
                    if(gtk_widget_is_focus(appGUI->tsk->tasks_find_entry) == FALSE) {
                        if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
                            gui_toggle_window_visibility (appGUI);
                        }
                    } else {
                        if (strlen(gtk_entry_get_text(GTK_ENTRY(appGUI->tsk->tasks_find_entry)))) {
                            gtk_entry_set_text(GTK_ENTRY(appGUI->tsk->tasks_find_entry), "");
                        } else {
                            if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
                                gui_toggle_window_visibility (appGUI);
                            }
                        }
                    }
                    return TRUE;
                case GDK_KEY_Return:
                    if(gtk_widget_is_focus(appGUI->tsk->tasks_find_entry) == FALSE) {
                        if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Enter */
                            if (gtk_tree_selection_count_selected_rows (appGUI->tsk->tasks_list_selection) == 1) {
                                tasks_add_edit_dialog_show (TRUE, 0, utl_time_get_current_seconds (), appGUI);
                                return TRUE;
                            }
                        }
                        return TRUE;
                    } else {
                        gtk_widget_grab_focus(GTK_WIDGET(appGUI->tsk->tasks_list));
                        return TRUE;
                    }
                case GDK_KEY_space:     /* don't use space key for marking task as done */
                    if(gtk_widget_is_focus(appGUI->tsk->tasks_find_entry) == FALSE) {
                        return TRUE;
                    } else {
                        return FALSE;
                    }
                case GDK_KEY_h:
                    if(gtk_widget_is_focus(appGUI->tsk->tasks_find_entry) == FALSE) {
                        if (event->state & GDK_CONTROL_MASK) {  /* CTRL + h */
                            config.hide_completed = !config.hide_completed;
                            gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER(appGUI->tsk->tasks_filter));
                        }
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Delete:
                    if (gtk_widget_is_focus(appGUI->tsk->tasks_find_entry) == FALSE) {
                        if (gtk_tree_selection_count_selected_rows(appGUI->tsk->tasks_list_selection) > 0) {
                            tasks_remove_dialog_show(appGUI);
                            return TRUE;
                        }
                    }
                    return FALSE;
                case GDK_KEY_Insert:
                    if(gtk_widget_is_focus(appGUI->tsk->tasks_find_entry) == FALSE) {
                        tasks_add_edit_dialog_show (FALSE, 0, utl_time_get_current_seconds (), appGUI);
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Left:
                    if(gtk_widget_is_focus(appGUI->tsk->tasks_find_entry) == FALSE) {
                        if (appGUI->tsk->filter_index > 0) {
                            appGUI->tsk->filter_index--;
                            gtk_combo_box_set_active(GTK_COMBO_BOX(appGUI->tsk->cf_combobox), appGUI->tsk->filter_index);
                        }
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Right:
                    if(gtk_widget_is_focus(appGUI->tsk->tasks_find_entry) == FALSE) {
                        if (appGUI->tsk->filter_index < utl_gui_get_combobox_items(GTK_COMBO_BOX(appGUI->tsk->cf_combobox))-1) {
                            appGUI->tsk->filter_index++;
                            gtk_combo_box_set_active(GTK_COMBO_BOX(appGUI->tsk->cf_combobox), appGUI->tsk->filter_index);
                        }
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_y:
                    key_counter_add (26, appGUI);
                    return FALSE;
                case GDK_KEY_l:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + l */
                        gtk_widget_grab_focus(GTK_WIDGET(appGUI->tsk->tasks_find_entry));
                        return TRUE;
                    }
                    return FALSE;
            }
    }

#endif /* TASKS_ENABLED */

#ifdef CONTACTS_ENABLED

    /************************************************************************/
    /*** CONTACTS PAGE                                                    ***/
    /************************************************************************/

    if(page == PAGE_CONTACTS) {

            switch (event->keyval) {

                case GDK_KEY_Escape:
                    if (gtk_widget_is_focus(appGUI->cnt->contacts_find_entry) == FALSE) {
                        if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
                            gui_toggle_window_visibility (appGUI);
                        }
                    } else {
                        if (strlen(gtk_entry_get_text(GTK_ENTRY(appGUI->cnt->contacts_find_entry)))) {
                            gtk_entry_set_text(GTK_ENTRY(appGUI->cnt->contacts_find_entry), "");
                        } else {
                            if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
                                    gui_toggle_window_visibility (appGUI);
                            }
                        }
                    }
                    return TRUE;
                case GDK_KEY_Return:
                    if(gtk_widget_is_focus(appGUI->cnt->contacts_find_entry) == FALSE) {
                        if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Enter */
                            if (gtk_tree_selection_count_selected_rows (appGUI->cnt->contacts_list_selection) == 1) {
                                contacts_add_edit_dialog_show (TRUE, appGUI);
                                return TRUE;
                            }
                        }
                        if (gtk_widget_is_focus(appGUI->cnt->contacts_find_entry) == FALSE) {
                            utl_gui_sw_vscrollbar_move_position (appGUI->cnt->contacts_panel_scrolledwindow, SW_MOVE_DOWN);
                            return TRUE;
                        }
                        return TRUE;
                    } else {
                        gtk_widget_grab_focus(GTK_WIDGET(appGUI->cnt->contacts_list));
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_BackSpace:
                    if(gtk_widget_is_focus(appGUI->cnt->contacts_find_entry) == FALSE) {
                        utl_gui_sw_vscrollbar_move_position (appGUI->cnt->contacts_panel_scrolledwindow, SW_MOVE_UP);
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Delete:
                    if(gtk_widget_is_focus(appGUI->cnt->contacts_find_entry) == FALSE) {
                        if (gtk_tree_selection_count_selected_rows(appGUI->cnt->contacts_list_selection) > 0) {
                            contacts_remove_dialog_show(appGUI);
                            return TRUE;
                        }
                    }
                    return FALSE;
                case GDK_KEY_Insert:
                    if(gtk_widget_is_focus(appGUI->cnt->contacts_find_entry) == FALSE) {
                        contacts_add_edit_dialog_show (FALSE, appGUI);
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Down:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Down */
                        if (config.find_mode < CONTACTS_FF_ALL_FIELDS) {
                            config.find_mode++;
                        }
                        gtk_combo_box_set_active (GTK_COMBO_BOX (appGUI->cnt->contacts_find_combobox), config.find_mode);
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Up:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Up */
                        if (config.find_mode > CONTACTS_FF_FIRST_NAME) {
                            config.find_mode--;
                        }
                        gtk_combo_box_set_active (GTK_COMBO_BOX (appGUI->cnt->contacts_find_combobox), config.find_mode);
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_l:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + l */
                        gtk_widget_grab_focus(GTK_WIDGET(appGUI->cnt->contacts_find_entry));
                        return TRUE;
                    }
                    return FALSE;
            }
    }

#endif /* CONTACTS_ENABLED */

    /************************************************************************/
    /*** NOTES PAGE                                                       ***/
    /************************************************************************/

#ifdef NOTES_ENABLED
    if(page == PAGE_NOTES) {
        if (appGUI->nte->editor_active == FALSE) {

            /* SELECTOR */
            switch (event->keyval) {

                case GDK_KEY_Return:
                    if(gtk_widget_is_focus(appGUI->nte->notes_find_entry) == FALSE) {
                        if (gtk_tree_selection_count_selected_rows (appGUI->nte->notes_list_selection) == 1) {
                            if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Enter */
                                notes_edit_dialog_show(appGUI->nte->notes_list, appGUI->nte->notes_filter, appGUI);
                            } else {
                                notes_enter_password (appGUI);
                            }
                            return TRUE;
                        }
                        return FALSE;
                    } else {
                        gtk_widget_grab_focus(GTK_WIDGET(appGUI->nte->notes_list));
                        return TRUE;
                    }
                case GDK_KEY_Delete:
                    if (gtk_widget_is_focus(appGUI->nte->notes_find_entry) == FALSE) {
                        if (gtk_tree_selection_count_selected_rows(appGUI->nte->notes_list_selection) > 0) {
                            notes_remove_dialog_show(appGUI);
                            return TRUE;
                        }
                    }
                    return FALSE;
                case GDK_KEY_Insert:
                    if(gtk_widget_is_focus(appGUI->nte->notes_find_entry) == FALSE) {
                        notes_add_entry (appGUI);
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Left:
                    if(gtk_widget_is_focus(appGUI->nte->notes_find_entry) == FALSE) {
                        if (appGUI->nte->filter_index > 0) {
                            appGUI->nte->filter_index--;
                            gtk_combo_box_set_active(GTK_COMBO_BOX(appGUI->nte->cf_combobox), appGUI->nte->filter_index);
                        }
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Right:
                    if(gtk_widget_is_focus(appGUI->nte->notes_find_entry) == FALSE) {
                        if (appGUI->nte->filter_index < utl_gui_get_combobox_items(GTK_COMBO_BOX(appGUI->nte->cf_combobox))-1) {
                            appGUI->nte->filter_index++;
                            gtk_combo_box_set_active(GTK_COMBO_BOX(appGUI->nte->cf_combobox), appGUI->nte->filter_index);
                        }
                        return TRUE;
                    }
                    return FALSE;
                case GDK_KEY_Escape:
                    if(gtk_widget_is_focus(appGUI->nte->notes_find_entry) == FALSE) {
                        if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
                            gui_toggle_window_visibility (appGUI);
                        }
                    } else {
                        if (strlen(gtk_entry_get_text(GTK_ENTRY(appGUI->nte->notes_find_entry)))) {
                            gtk_entry_set_text(GTK_ENTRY(appGUI->nte->notes_find_entry), "");
                        } else {
                            if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
                                gui_toggle_window_visibility (appGUI);
                            }
                        }
                    }
                    return TRUE;
                case GDK_KEY_l:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + l */
                        gtk_widget_grab_focus(GTK_WIDGET(appGUI->nte->notes_find_entry));
                        return TRUE;
                    }
                    return FALSE;
            }

        } else {

            /* EDITOR */
            switch (event->keyval) {

                case GDK_KEY_w:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + w */
                        editor_close_cb (NULL, appGUI);
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_Escape:
                    if (appGUI->nte->find_hbox_visible == FALSE) {
                        editor_close_cb (NULL, appGUI);
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_b:
                    if ((event->state & GDK_CONTROL_MASK) && !appGUI->nte->note_read_only) {  /* CTRL + b */
                        g_signal_emit_by_name(G_OBJECT(appGUI->nte->bold_button), "clicked");
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_i:
                    if ((event->state & GDK_CONTROL_MASK) && !appGUI->nte->note_read_only) {  /* CTRL + i */
                        g_signal_emit_by_name(G_OBJECT(appGUI->nte->italic_button), "clicked");
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_m:
                    if ((event->state & GDK_CONTROL_MASK) && !appGUI->nte->note_read_only) {  /* CTRL + m */
                        g_signal_emit_by_name(G_OBJECT(appGUI->nte->highlight_button), "clicked");
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_u:
                    if ((event->state & GDK_CONTROL_MASK) && !appGUI->nte->note_read_only) {  /* CTRL + u */
                        g_signal_emit_by_name(G_OBJECT(appGUI->nte->underline_button), "clicked");
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_t:
                    if ((event->state & GDK_CONTROL_MASK) && !appGUI->nte->note_read_only) {  /* CTRL + t */
                        g_signal_emit_by_name(G_OBJECT(appGUI->nte->strikethrough_button), "clicked");
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_s:
                    if ((event->state & GDK_CONTROL_MASK) && !appGUI->nte->note_read_only) {  /* CTRL + s */
                        editor_save_buffer_cb (NULL, appGUI);
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_f:
                    if (event->state & GDK_CONTROL_MASK) {  /* CTRL + f */
                        editor_find_text_show_cb (NULL, appGUI);
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_n:
                    if ((event->state & GDK_CONTROL_MASK) && !appGUI->nte->note_read_only) {  /* CTRL + n */
                        clear_text_attributes_cb (NULL, appGUI);
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_o:
                    if ((event->state & GDK_CONTROL_MASK) && !appGUI->nte->note_read_only) {  /* CTRL + o */
                        open_url_links_cb (NULL, appGUI);
                        return TRUE;
                    }
                    return FALSE;

                case GDK_KEY_period:
                    if ((event->state & GDK_CONTROL_MASK)) {  /* CTRL + . */
                        text_info_cb (NULL, appGUI);
                        return TRUE;
                    }
                    return FALSE;
            }
        }
    }
#endif  /* NOTES_ENABLED */

    /************************************************************************/
    /*** GLOBAL SHORTCUTS                                                 ***/
    /************************************************************************/

    switch (event->keyval) {

        case GDK_KEY_Escape:
            if (config.enable_systray == TRUE && appGUI->no_tray == FALSE && appGUI->calendar_only == FALSE) {
                gui_toggle_window_visibility (appGUI);
            }
            return FALSE;

        case GDK_KEY_q:
            if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Q */
                gui_quit_osmo (appGUI);
            }
            return FALSE;

        case GDK_KEY_Page_Up:
#ifdef NOTES_ENABLED
            if (appGUI->nte->editor_active == FALSE) {
#endif  /* NOTES_ENABLED */
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Page_Up */
                    set_visible_page(appGUI->current_tab, FALSE, appGUI);
                    return TRUE;
                } else if (page == PAGE_CALENDAR) {
                    if (config.day_notes_visible) {
                        if (event->state & GDK_MOD1_MASK) {  /* ALT + Page_Up */
                            calendar_btn_prev_month(appGUI);
                            return TRUE;
                        }
                    } else {
                        calendar_btn_prev_month(appGUI);
                        return TRUE;
                    }
                }
#ifdef NOTES_ENABLED
            }
#endif  /* NOTES_ENABLED */
            return FALSE;

        case GDK_KEY_Page_Down:
#ifdef NOTES_ENABLED
            if (appGUI->nte->editor_active == FALSE) {
#endif  /* NOTES_ENABLED */
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + Page_Down */
                    set_visible_page(appGUI->current_tab, TRUE, appGUI);
                    return TRUE;
                } else if (page == PAGE_CALENDAR) {
                    if (config.day_notes_visible) {
                        if (event->state & GDK_MOD1_MASK) {  /* ALT + Page_Down */
                            calendar_btn_next_month(appGUI);
                            return TRUE;
                        }
                    } else {
                        calendar_btn_next_month(appGUI);
                        return TRUE;
                    }
                }
#ifdef NOTES_ENABLED
            }
#endif  /* NOTES_ENABLED */
            return FALSE;
        case GDK_KEY_F1:
            select_tab (0, appGUI);
            return TRUE;
        case GDK_KEY_1:
            if ((event->state & GDK_MOD1_MASK)) {  /* ALT + 1 */
#if defined(TASKS_ENABLED) || defined(CONTACTS_ENABLED) || defined(NOTES_ENABLED)
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + ALT + 1 */
                    opt_hide_modules (!config.hide_calendar, 
                                      config.hide_tasks, 
                                      config.hide_contacts, 
                                      config.hide_notes, 
                                      FALSE, appGUI);
                    select_tab (0, appGUI);
                } else {
#endif
                    select_tab (0, appGUI);
#if defined(TASKS_ENABLED) || defined(CONTACTS_ENABLED) || defined(NOTES_ENABLED)
                }
#endif
                return TRUE;
            }
            return FALSE;
        case GDK_KEY_F2:
            select_tab (1, appGUI);
            return TRUE;
        case GDK_KEY_2:
            if ((event->state & GDK_MOD1_MASK)) {  /* ALT + 2 */
#ifdef TASKS_ENABLED
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + ALT + 2 */
                    opt_hide_modules (config.hide_calendar, 
                                      !config.hide_tasks, 
                                      config.hide_contacts, 
                                      config.hide_notes, 
                                      FALSE, appGUI);
                    select_tab (0, appGUI);
                } else {
#endif  /* TASKS_ENABLED */
                    select_tab (1, appGUI);
#ifdef TASKS_ENABLED
                }
#endif  /* TASKS_ENABLED */
                return TRUE;
            }
            return FALSE;
        case GDK_KEY_F3:
            select_tab (2, appGUI);
            return TRUE;
        case GDK_KEY_3:
            if ((event->state & GDK_MOD1_MASK)) {  /* ALT + 3 */
#ifdef CONTACTS_ENABLED
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + ALT + 3 */
                    opt_hide_modules (config.hide_calendar, 
                                      config.hide_tasks, 
                                      !config.hide_contacts, 
                                      config.hide_notes, 
                                      FALSE, appGUI);
                    select_tab (0, appGUI);
                } else {
#endif  /* CONTACTS_ENABLED */
                    select_tab (2, appGUI);
#ifdef CONTACTS_ENABLED
                }
#endif  /* CONTACTS_ENABLED */
                return TRUE;
            }
            return FALSE;
        case GDK_KEY_F4:
            select_tab (3, appGUI);
            return TRUE;
        case GDK_KEY_4:
            if ((event->state & GDK_MOD1_MASK)) {  /* ALT + 4 */
#ifdef NOTES_ENABLED
                if (event->state & GDK_CONTROL_MASK) {  /* CTRL + ALT + 4 */
                    opt_hide_modules (config.hide_calendar, 
                                      config.hide_tasks, 
                                      config.hide_contacts, 
                                      !config.hide_notes, 
                                      FALSE, appGUI);
                    select_tab (0, appGUI);
                } else {
#endif  /* NOTES_ENABLED */
                   select_tab (3, appGUI);
#ifdef NOTES_ENABLED
                }
#endif  /* NOTES_ENABLED */
                return TRUE;
            }
            return FALSE;
        case GDK_KEY_F5:
            gtk_widget_show (GTK_WIDGET(opt_create_preferences_window (appGUI)));
            return TRUE;
        case GDK_KEY_F6:
            gtk_widget_show (GTK_WIDGET(opt_create_about_window (appGUI)));
            return TRUE;

        case GDK_KEY_F11:   /* full screen */
            gui_toggle_fullscreen (appGUI);
            return TRUE;
    }

    return FALSE;
}

/*------------------------------------------------------------------------------*/

void
notebook_sw_cb (GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data) {
 
    GUI *appGUI = (GUI *)user_data;

#ifdef NOTES_ENABLED
    if (appGUI->nte->editor_active == TRUE) {
        editor_close_cb (NULL, appGUI);
    }
#endif  /* NOTES_ENABLED */

    appGUI->current_tab = page_num;
}

/*------------------------------------------------------------------------------*/

gboolean
trayicon_clicked_cb (GtkStatusIcon *status_icon, GdkEventButton *event, gpointer user_data) {

    GUI *appGUI = (GUI *)user_data;

    if (event->button == 1) {   /* LMB */

        gui_toggle_window_visibility (appGUI);
        return TRUE;

    } else if (event->button == 2) {    /* MMB */

        gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NORMAL);
        return TRUE;
    }

    return FALSE;
}

/*------------------------------------------------------------------------------*/

void 
trayicon_popup_cb (GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data) {

    GUI *appGUI = (GUI *)user_data;

    gtk_menu_popup(GTK_MENU(appGUI->trayicon_popup_menu), NULL, NULL, NULL, NULL, 
                   button, activate_time);
}

void
systray_popup_menu_quit_selected_cb (gpointer user_data) {
    GUI *appGUI = (GUI *)user_data;
    gui_quit_osmo (appGUI);
}

void
systray_popup_menu_show_calendar_selected_cb (gpointer user_data) {
    GUI *appGUI = (GUI *)user_data;
    if (appGUI->window_visible == FALSE) {
        gtk_widget_show (appGUI->main_window);
        appGUI->window_visible = TRUE;
    }
    gtk_window_deiconify (GTK_WINDOW(appGUI->main_window));
    gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NORMAL);
    gtk_notebook_set_current_page (GTK_NOTEBOOK (appGUI->notebook), PAGE_CALENDAR);
}

#ifdef TASKS_ENABLED
void
systray_popup_menu_show_tasks_selected_cb (gpointer user_data) {
    GUI *appGUI = (GUI *)user_data;
    if (appGUI->window_visible == FALSE) {
        gtk_widget_show (appGUI->main_window);
        appGUI->window_visible = TRUE;
    }
    gtk_window_deiconify (GTK_WINDOW(appGUI->main_window));
    gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NORMAL);
    gtk_notebook_set_current_page (GTK_NOTEBOOK (appGUI->notebook), PAGE_TASKS);
}
#endif  /* TASKS_ENABLED */

#ifdef CONTACTS_ENABLED
void
systray_popup_menu_show_contacts_selected_cb (gpointer user_data) {
    GUI *appGUI = (GUI *)user_data;
    if (appGUI->window_visible == FALSE) {
        gtk_widget_show (appGUI->main_window);
        appGUI->window_visible = TRUE;
    }
    gtk_window_deiconify (GTK_WINDOW(appGUI->main_window));
    gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NORMAL);
    gtk_notebook_set_current_page (GTK_NOTEBOOK (appGUI->notebook), PAGE_CONTACTS);
}
#endif  /* CONTACTS_ENABLED */

#ifdef NOTES_ENABLED
void
systray_popup_menu_show_notes_selected_cb (gpointer user_data) {
    GUI *appGUI = (GUI *)user_data;
    if (appGUI->window_visible == FALSE) {
        gtk_widget_show (appGUI->main_window);
        appGUI->window_visible = TRUE;
    }
    gtk_window_deiconify (GTK_WINDOW(appGUI->main_window));
    gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NORMAL);
    gtk_notebook_set_current_page (GTK_NOTEBOOK (appGUI->notebook), PAGE_NOTES);
}
#endif  /* NOTES_ENABLED */

void
systray_popup_menu_show_options_selected_cb (GUI *appGUI)
{
    if (appGUI->window_visible == FALSE) {
        gtk_widget_show (appGUI->main_window);
        appGUI->window_visible = TRUE;
    }
    gtk_window_deiconify (GTK_WINDOW (appGUI->main_window));
    gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NORMAL);
    gtk_widget_show (opt_create_preferences_window (appGUI));
}

/*------------------------------------------------------------------------------*/

void
gui_systray_tooltip_update (GUI *appGUI)
{
    gchar *tstr, *dstr, *text;

    if (appGUI->osmo_trayicon == NULL) return;

    dstr = utl_date_print_j (utl_date_get_current_julian (), DATE_FULL,
                             config.override_locale_settings);

    tstr = utl_time_print_default (utl_time_get_current_seconds (), FALSE);

    text = g_strdup_printf ("%s, %s", dstr, tstr);
    gtk_status_icon_set_tooltip_text (appGUI->osmo_trayicon, text);

    g_free (tstr);
    g_free (dstr);
    g_free (text);
}

/*------------------------------------------------------------------------------*/

void
gui_systray_update_icon (GUI *appGUI) {

guint32 julian_day;
gboolean flag = FALSE;
        
    if (appGUI->window_visible == TRUE) return;

    julian_day = utl_date_get_current_julian ();

    if (config.ignore_day_note_events == FALSE) {
        if (cal_check_note (julian_day, appGUI) == TRUE) {
            gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NOTE);
            flag = TRUE;
        }
    }

#ifdef TASKS_ENABLED
    if (tsk_check_tasks (julian_day, julian_day, STATE_NONE, appGUI)) {
        gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_TASK);
        flag = TRUE;
    }
#endif  /* TASKS_ENABLED */

#ifdef CONTACTS_ENABLED
    if (check_contacts(julian_day, appGUI) == TRUE) {
        gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_BIRTHDAY);
        flag = TRUE;
    }
#endif  /* CONTACTS_ENABLED */

    if (flag == FALSE) {
            gtk_status_icon_set_from_icon_name (appGUI->osmo_trayicon, OSMO_STOCK_SYSTRAY_NORMAL);
    }
}
/*------------------------------------------------------------------------------*/
static GtkWidget *
create_menu_item(const gchar *text, GtkWidget *image) {
    GtkWidget *menu_item = gtk_menu_item_new();
    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    GtkWidget *label = gtk_label_new(text);

    gtk_widget_set_margin_left(label, 6);
    gtk_widget_set_halign(label, GTK_ALIGN_START);
    gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
    gtk_box_pack_end(GTK_BOX(box), label, TRUE, TRUE, 0);
    gtk_container_add(GTK_CONTAINER(menu_item), box);
    gtk_widget_show_all(menu_item);

    return menu_item;
}

/*------------------------------------------------------------------------------*/

void
gui_systray_initialize (GUI *appGUI) {

GtkWidget   *menu_entry;
GtkWidget   *systray_menu_separator;

    if (appGUI->calendar_only == TRUE) {
        return;
    }

    appGUI->trayicon_popup_menu = gtk_menu_new();

    appGUI->trayicon_menu_calendar_item = create_menu_item (_("Show calendar"),
            gtk_image_new_from_icon_name(OSMO_STOCK_SYSTRAY_MENU_CALENDAR, GTK_ICON_SIZE_MENU));
    gtk_menu_shell_append (GTK_MENU_SHELL(appGUI->trayicon_popup_menu), appGUI->trayicon_menu_calendar_item);
    g_signal_connect_swapped (G_OBJECT(appGUI->trayicon_menu_calendar_item), "activate", 
                              G_CALLBACK(systray_popup_menu_show_calendar_selected_cb), appGUI);
    if (config.hide_calendar == FALSE) {
        gtk_widget_show (appGUI->trayicon_menu_calendar_item);
    }

#ifdef TASKS_ENABLED
    appGUI->trayicon_menu_tasks_item = create_menu_item (_("Show tasks"),
            gtk_image_new_from_icon_name(OSMO_STOCK_SYSTRAY_MENU_TASKS, GTK_ICON_SIZE_MENU));
    gtk_menu_shell_append (GTK_MENU_SHELL(appGUI->trayicon_popup_menu), appGUI->trayicon_menu_tasks_item);
    g_signal_connect_swapped (G_OBJECT(appGUI->trayicon_menu_tasks_item), "activate", 
                              G_CALLBACK(systray_popup_menu_show_tasks_selected_cb), appGUI);
    
    if (config.hide_tasks == FALSE) {
        gtk_widget_show (appGUI->trayicon_menu_tasks_item);
    }
#endif  /* TASKS_ENABLED */

#ifdef CONTACTS_ENABLED
    appGUI->trayicon_menu_contacts_item = create_menu_item (_("Show contacts"),
            gtk_image_new_from_icon_name(OSMO_STOCK_SYSTRAY_MENU_CONTACTS, GTK_ICON_SIZE_MENU));
    gtk_menu_shell_append (GTK_MENU_SHELL(appGUI->trayicon_popup_menu), appGUI->trayicon_menu_contacts_item);
    g_signal_connect_swapped (G_OBJECT(appGUI->trayicon_menu_contacts_item), "activate", 
                              G_CALLBACK(systray_popup_menu_show_contacts_selected_cb), appGUI);
    if (config.hide_contacts == FALSE) {
        gtk_widget_show (appGUI->trayicon_menu_contacts_item);
    }
#endif  /* CONTACTS_ENABLED */

#ifdef NOTES_ENABLED
    appGUI->trayicon_menu_notes_item = create_menu_item (_("Show notes"),
            gtk_image_new_from_icon_name(OSMO_STOCK_SYSTRAY_MENU_NOTES, GTK_ICON_SIZE_MENU));
    gtk_menu_shell_append (GTK_MENU_SHELL(appGUI->trayicon_popup_menu), appGUI->trayicon_menu_notes_item);
    g_signal_connect_swapped (G_OBJECT(appGUI->trayicon_menu_notes_item), "activate", 
                              G_CALLBACK(systray_popup_menu_show_notes_selected_cb), appGUI);
    if (config.hide_notes == FALSE) {
        gtk_widget_show (appGUI->trayicon_menu_notes_item);
    }
#endif  /* NOTES_ENABLED */

    systray_menu_separator = gtk_separator_menu_item_new();
    gtk_menu_shell_append(GTK_MENU_SHELL(appGUI->trayicon_popup_menu), systray_menu_separator);
    gtk_widget_show(systray_menu_separator);

    menu_entry = create_menu_item (_("Show options"),
                gtk_image_new_from_icon_name("preferences-system", GTK_ICON_SIZE_MENU));
    gtk_menu_shell_append(GTK_MENU_SHELL(appGUI->trayicon_popup_menu), menu_entry);
    g_signal_connect_swapped(G_OBJECT(menu_entry), "activate", 
                             G_CALLBACK(systray_popup_menu_show_options_selected_cb), appGUI);
    gtk_widget_show(menu_entry);

    systray_menu_separator = gtk_separator_menu_item_new();
    gtk_menu_shell_append(GTK_MENU_SHELL(appGUI->trayicon_popup_menu), systray_menu_separator);
    gtk_widget_show(systray_menu_separator);

    menu_entry = create_menu_item (_("Quit"),
                gtk_image_new_from_icon_name("application-exit", GTK_ICON_SIZE_MENU));
    gtk_menu_shell_append(GTK_MENU_SHELL(appGUI->trayicon_popup_menu), menu_entry);
    g_signal_connect_swapped(G_OBJECT(menu_entry), "activate", 
                             G_CALLBACK(systray_popup_menu_quit_selected_cb), appGUI);
    gtk_widget_show(menu_entry);

    /* create tray icon */

    appGUI->osmo_trayicon = gtk_status_icon_new_from_icon_name(OSMO_STOCK_SYSTRAY_NORMAL);
    g_signal_connect(G_OBJECT(appGUI->osmo_trayicon), "button-release-event", 
                     G_CALLBACK(trayicon_clicked_cb), appGUI);

    g_signal_connect(G_OBJECT(appGUI->osmo_trayicon), "popup-menu",
                     G_CALLBACK(trayicon_popup_cb), appGUI);

    appGUI->window_visible = TRUE;

    if (config.enable_systray == TRUE) {
        gtk_status_icon_set_visible (appGUI->osmo_trayicon, TRUE);
        while (g_main_context_iteration (NULL, FALSE));

        if (gtk_status_icon_is_embedded (appGUI->osmo_trayicon) == FALSE) {
            appGUI->no_tray = TRUE;
            gtk_status_icon_set_visible (appGUI->osmo_trayicon, FALSE);
            gtk_widget_show(appGUI->main_window);
        } else {
            appGUI->no_tray = FALSE;
            gtk_status_icon_set_visible (appGUI->osmo_trayicon, TRUE);
            if (config.start_minimised_in_systray) {
                appGUI->window_visible = FALSE;
            } else {
                gtk_widget_show (appGUI->main_window);
            }
        }
    } else {
        gtk_status_icon_set_visible (appGUI->osmo_trayicon, FALSE);
        gtk_widget_show (appGUI->main_window);
    }

    gui_systray_update_icon (appGUI);
    gui_systray_tooltip_update (appGUI);
}

/*------------------------------------------------------------------------------*/
#ifndef WIN32
static gboolean
deliver_signal(gpointer data)
{
    GUI *appGUI = data;
    gui_quit_osmo(appGUI);
    return G_SOURCE_CONTINUE;
}

static void
register_signal_handler(GUI *appGUI) {
    if(g_unix_signal_add(SIGINT, deliver_signal, appGUI) <= 0
            || g_unix_signal_add(SIGTERM, deliver_signal, appGUI) <= 0
            || g_unix_signal_add(SIGHUP, deliver_signal, appGUI) <= 0) {
        g_warning("Failed to install the signal handler");
    }
}
#endif /* WIN32 */
/*------------------------------------------------------------------------------*/

gboolean
gui_create_window (GUI *appGUI)
{
    GdkScreen *screen;
    gint sw, sh;
    gint fdSTDERR, fdSTDERRn;

    /* disable STDERR temporary - to suppress messages from webkit */
    fdSTDERR = dup (STDERR_FILENO);
    fdSTDERRn = open("/dev/null", O_WRONLY);
    dup2 (fdSTDERRn, STDERR_FILENO);
    close (fdSTDERRn);

    appGUI->all_pages_added = FALSE;

    appGUI->cal->fd_day_name_font = pango_font_description_from_string(config.day_name_font);
    appGUI->cal->fd_cal_font = pango_font_description_from_string(config.calendar_font);
    appGUI->cal->fd_notes_font = pango_font_description_from_string(config.notes_font);

    appGUI->main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

#ifndef REV
    gtk_window_set_title (GTK_WINDOW (appGUI->main_window), "Osmo " VERSION_MAJOR "." VERSION_MINOR "." VERSION_MICRO);
#else
    gtk_window_set_title (GTK_WINDOW (appGUI->main_window), "Osmo (development)");
#endif

    gtk_widget_set_events(appGUI->main_window, GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);

    gtk_window_set_icon_name(GTK_WINDOW(appGUI->main_window), OSMO_STOCK_LOGO);

    screen = gdk_screen_get_default ();
    if (screen != NULL) {
        sw = gdk_screen_get_width (screen);
        sh = gdk_screen_get_height (screen);
        if (config.window_x >= sw || config.window_x < 0)
            config.window_x = 0;
        if (config.window_y >= sh || config.window_y < 0)
            config.window_y = 0;
    }

    gtk_window_move (GTK_WINDOW (appGUI->main_window), config.window_x, config.window_y);

    gtk_widget_realize (appGUI->main_window);

    if (appGUI->calendar_only == FALSE) {
        gtk_window_set_default_size (GTK_WINDOW(appGUI->main_window), config.window_size_x, config.window_size_y);
    } else {
        gtk_window_set_default_size (GTK_WINDOW(appGUI->main_window), 500, -1);
    }
    gtk_window_set_resizable (GTK_WINDOW (appGUI->main_window), TRUE);

    g_signal_connect (G_OBJECT (appGUI->main_window), "delete-event",
                      G_CALLBACK(gui_window_close_cb), appGUI);
    g_signal_connect (G_OBJECT (appGUI->main_window), "key_press_event",
                      G_CALLBACK (key_press_cb), appGUI);

    osmo_register_theme_icons ();
    utl_gui_url_initialize (appGUI);

    appGUI->notebook = gtk_notebook_new ();
    gtk_widget_set_can_focus (appGUI->notebook, FALSE);
    gtk_widget_show (appGUI->notebook);
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK(appGUI->notebook), config.tabs_position);
    gtk_container_add (GTK_CONTAINER(appGUI->main_window), appGUI->notebook);
    g_signal_connect (G_OBJECT(appGUI->notebook), "switch-page", 
                      G_CALLBACK(notebook_sw_cb), appGUI);

    gtk_notebook_set_scrollable (GTK_NOTEBOOK(appGUI->notebook), FALSE);

    if (appGUI->calendar_only == TRUE) {
        gtk_notebook_set_show_tabs (GTK_NOTEBOOK(appGUI->notebook), FALSE);
    }

    appGUI->opt->calendar_ical_files_store =
        gtk_list_store_new (ICAL_NUMBER_OF_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
                            G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
                            G_TYPE_BOOLEAN);
    appGUI->opt->calendar_category_store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);

    gui_create_calendar(appGUI->notebook, appGUI);

    if (appGUI->calendar_only == FALSE) {

#ifdef TASKS_ENABLED
        appGUI->opt->tasks_category_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
        gui_create_tasks (appGUI);
#endif  /* TASKS_ENABLED */

#ifdef CONTACTS_ENABLED
        appGUI->opt->contacts_group_store = gtk_list_store_new (1, G_TYPE_STRING);
        gui_create_contacts (appGUI);
#endif  /* CONTACTS_ENABLED */

#ifdef NOTES_ENABLED
        gui_create_notes (appGUI);
#endif  /* NOTES_ENABLED */

    if (!config.gui_layout) {
        if (config.enable_auxiliary_calendars == TRUE) {
            gtk_widget_show (appGUI->cal->aux_cal_expander);
        } else {
            gtk_widget_hide (appGUI->cal->aux_cal_expander);
        }
    }

        cal_read_notes (appGUI);

#ifdef HAVE_LIBICAL
        ics_initialize_timezone ();
        read_ical_entries (appGUI);
#endif  /* HAVE_LIBICAL */

#ifdef TASKS_ENABLED
        read_tasks_entries (appGUI);
        set_categories (appGUI);
        refresh_tasks (appGUI);
#endif  /* TASKS_ENABLED */

#ifdef CONTACTS_ENABLED
        read_contacts_entries (appGUI);
        set_export_active (appGUI);
#endif  /* CONTACTS_ENABLED */

#ifdef NOTES_ENABLED
        appGUI->opt->notes_category_store = gtk_list_store_new (1, G_TYPE_STRING);
        read_notes_entries (appGUI);

        utl_gui_create_category_combobox (GTK_COMBO_BOX (appGUI->nte->cf_combobox), 
                                          appGUI->opt->notes_category_store, FALSE);

        if (config.remember_category_in_notes == TRUE) {
            gtk_combo_box_set_active (GTK_COMBO_BOX(appGUI->nte->cf_combobox), config.current_category_in_notes);
        } else {
            gtk_combo_box_set_active (GTK_COMBO_BOX(appGUI->nte->cf_combobox), 0);
        }
#endif  /* NOTES_ENABLED */
#ifndef WIN32
        register_signal_handler(appGUI);
#endif /* WIN32 */
#ifdef TASKS_ENABLED
        refresh_tasks (appGUI);
        appGUI->tsk->notifications_enable = TRUE;
#endif  /* TASKS_ENABLED */

        appGUI->number_of_tabs = NUMBER_OF_TABS;

        if(config.remember_latest_tab == TRUE) {
            appGUI->current_tab = config.latest_tab;
        } else {
            appGUI->current_tab = PAGE_CALENDAR;
        }
    } else {
        appGUI->number_of_tabs = 1;
        appGUI->current_tab = 0;
    }

    appGUI->all_pages_added = TRUE;
    cal_refresh_notes(appGUI);

    if (config.toolbar_exit_button == FALSE) {
        if (appGUI->calendar_only == FALSE) {
            gtk_widget_hide (GTK_WIDGET(appGUI->cal->quit_button));
#ifdef CONTACTS_ENABLED
            gtk_widget_hide (GTK_WIDGET(appGUI->cnt->quit_toolbar_button));
#endif /* CONTACTS_ENABLED */
#ifdef NOTES_ENABLED
            gtk_widget_hide (GTK_WIDGET(appGUI->nte->quit_button));
#endif /* NOTES_ENABLED */
#ifdef TASKS_ENABLED
            gtk_widget_hide (GTK_WIDGET(appGUI->tsk->quit_button));
#endif /* TASKS_ENABLED */
        }
    }
            
    if (config.fullscreen == TRUE) {
        gtk_window_fullscreen (GTK_WINDOW(appGUI->main_window));
    }

    if (appGUI->check_events == TRUE) {
        return create_event_checker_window (appGUI);
    } else {
        gui_systray_initialize (appGUI);
    }
 
    if (appGUI->calendar_only == TRUE) {
        gtk_widget_show (appGUI->main_window);
    }

    gtk_notebook_set_current_page(GTK_NOTEBOOK(appGUI->notebook), appGUI->current_tab);

    /* enable STDERR */
    dup2 (fdSTDERR, STDERR_FILENO);
    close (fdSTDERR);

    return TRUE;
}

/*------------------------------------------------------------------------------*/

void
gui_add_to_notebook (GtkWidget *widget, gchar *text, GUI *appGUI) {

GtkWidget *label;

    label = gtk_label_new(NULL);

    if (config.tabs_position == GTK_POS_LEFT) {
        gtk_label_set_angle (GTK_LABEL(label), 90.0);
    } else if (config.tabs_position == GTK_POS_RIGHT) {
        gtk_label_set_angle (GTK_LABEL(label), -90.0);
    }
    gtk_label_set_markup (GTK_LABEL (label), text);

    gtk_notebook_append_page(GTK_NOTEBOOK(appGUI->notebook), widget, label);

}

/*------------------------------------------------------------------------------*/
GtkToolItem *
gui_create_toolbar_button(GUI *appGUI, const gchar *icon_name, const gchar *label,
        void(*click_callback) (GtkToolButton *, gpointer)) {
    GtkToolItem *button = gtk_tool_button_new (NULL, NULL);
    gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (button), icon_name);
    gtk_tool_button_set_label (GTK_TOOL_BUTTON (button), label);
    gtk_widget_set_tooltip_text(GTK_WIDGET(button), label);
    gtk_widget_show(GTK_WIDGET(button));
    g_signal_connect(button, "clicked", G_CALLBACK(click_callback), appGUI);
    return button;
}

/*------------------------------------------------------------------------------*/
GtkToolItem *
gui_create_toolbar_toggle_button(GUI *appGUI, const gchar *icon_name, const gchar *label,
        void(*toggle_callback) (GtkToggleToolButton *, gpointer)) {
    GtkToolItem *button = gtk_toggle_tool_button_new ();
    gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (button), icon_name);
    gtk_tool_button_set_label (GTK_TOOL_BUTTON (button), label);
    gtk_widget_set_tooltip_text(GTK_WIDGET(button), label);
    gtk_widget_show(GTK_WIDGET(button));
    g_signal_connect(button, "toggled", G_CALLBACK(toggle_callback), appGUI);
    return button;
}

/*------------------------------------------------------------------------------*/
void
gui_append_toolbar_spring(GtkToolbar *toolbar) {
    GValue expand = G_VALUE_INIT;
    GtkToolItem *spring = gtk_separator_tool_item_new();
    g_value_init(&expand, G_TYPE_BOOLEAN);
    g_value_set_boolean(&expand, TRUE);
    gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(spring), FALSE);
    gtk_container_child_set_property(GTK_CONTAINER(toolbar), GTK_WIDGET(spring), "expand", &expand);
    gtk_toolbar_insert(toolbar, spring, -1);
}

/*------------------------------------------------------------------------------*/
