#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "gm-app-view.h" #include "gm-ui.h" #include "gm-world-view.h" #include "gm-world.h" #include "gm-world-info-dialog.h" #include "gm-worlds-list-dialog.h" #include "gm-world-logs-dialog.h" #include "gm-world-properties-dialog.h" #include "gm-scripts-dialog.h" #include "gm-world-tab.h" //#include "if_world.h" //#include "if_worlds_listing.h" //#include "if_preferences.h" //#include "if_mcpconsole.h" #include "gm-pixbuf.h" #include "gm-support.h" //#include "term.h" //#include "world.h" //#include "net.h" //#include "main.h" void on_gm_app_view_destroy(GtkWidget * caller, gpointer user_data); gboolean on_gm_app_view_focus_in(GtkWidget *widget, GdkEventFocus *event, gpointer user_data); void on_gm_app_view_entry_find_activate(GtkEntry *entry, GmAppView *view); void on_gm_app_view_entry_find_changed(GtkEditable *editable, GmAppView *view); gboolean on_gm_app_view_entry_find_key_press(GtkWidget *widget, GdkEventKey *event, GmAppView *view); void on_gm_app_view_button_find_close_clicked(GtkButton *button, GmAppView *view); void on_gm_app_view_notebook_switch_page(GtkNotebook * notebook, GtkNotebookPage * page, guint page_num, GmAppView *view); gboolean on_gm_app_view_notebook_button_press(GtkNotebook *notebook, GdkEventButton *event, GmAppView *view); gboolean on_gm_app_view_notebook_button_release(GtkNotebook *notebook, GdkEventButton *event, GmAppView *view); void on_gm_app_view_check_button_search_direction_toggled( GtkToggleButton *button, GmAppView *view); typedef struct _AccelInfo AccelInfo; struct _AccelInfo { int num; GmAppView *view; }; void on_gm_app_view_accel_switch_page(GtkAccelGroup * accelgroup, GObject * arg1, guint arg2, GdkModifierType arg3, AccelInfo *info); void on_gm_app_view_accel_switch_edit(GtkAccelGroup * accelgroup, GObject * arg1, guint arg2, GdkModifierType arg3, AccelInfo *info); void on_gm_app_view_accel_cycle_page(GtkAccelGroup * accelgroup, GObject * arg1, guint arg2, GdkModifierType arg3, AccelInfo *info); void on_gm_app_view_world_added(GmApp *app, GmWorld *world, GmAppView *view); void on_gm_app_view_world_removed(GmApp *app, GmWorld *world, GmAppView *view); void on_gm_app_view_world_activate(GtkAction * action, GmWorld *world); void on_gm_app_view_world_load(GmWorld *world, GmAppView *view); void on_gm_app_view_world_unload(GmWorld *world, GmAppView *view); void on_gm_app_view_world_activate_request(GmWorld *world, GmAppView *view); void on_gm_app_view_world_name_changed(GmWorld *world, const gchar *name, GmAppView *view); void on_gm_app_view_world_state_changing(GmWorld *world, GmNetState state, GmAppView *view); void on_gm_app_view_world_active_changed(GmWorld *world, gboolean active, GmAppView *view); #define GM_APP_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ GM_TYPE_APP_VIEW, GmAppViewPrivate)) typedef struct _GmAppViewWorldMenuItem GmAppViewWorldMenuItem; struct _GmAppViewWorldMenuItem { guint merge_id; GtkAction *action; }; void gm_app_view_destroy_world_menu_item(GmAppViewWorldMenuItem *item); struct _GmAppViewPrivate { GmApp *application; GtkUIManager *manager; GtkActionGroup *sensitive_action_group; GtkActionGroup *action_group; GtkActionGroup *worlds_action_group; GHashTable *world_menu_items; GtkNotebook *notebook; GmWorld *active_world; GtkMenuBar *menu; GtkEntry *entry_find; GtkVBox *vbox_find; GtkCheckButton *check_button_search_direction; gboolean drag_in_progress; gint motion_notify_handler_id; gint x_start; gint y_start; GdkCursor *cursor; }; /* Signals */ /*enum { NUM_SIGNALS }; static guint app_view_signals[NUM_SIGNALS] = {0};*/ G_DEFINE_TYPE(GmAppView, gm_app_view, GTK_TYPE_WINDOW) static void gm_app_view_finalize(GObject *object) { GmAppView *view = GM_APP_VIEW(object); gm_scripts_dialog_fini(); g_hash_table_destroy(view->priv->world_menu_items); G_OBJECT_CLASS(gm_app_view_parent_class)->finalize(object); } static void gm_app_view_class_init(GmAppViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->finalize = gm_app_view_finalize; g_type_class_add_private(object_class, sizeof(GmAppViewPrivate)); } GtkWidget * gm_app_view_create_menu(GmAppView *view) { GError *error = NULL; GtkActionGroup *action_group; view->priv->manager = gtk_ui_manager_new(); gtk_window_add_accel_group(GTK_WINDOW(view), gtk_ui_manager_get_accel_group(view->priv->manager)); gtk_ui_manager_add_ui_from_file(view->priv->manager, PACKAGE_DATA_DIR "/" PACKAGE "/ui/gm-ui.xml", &error); if (error) { debug_msg(1, "Could not merge UI file"); g_error_free(error); } action_group = gtk_action_group_new("GmAppViewSensitiveActions"); gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions(action_group, gm_sensitive_menu_entries, G_N_ELEMENTS(gm_sensitive_menu_entries), view); gtk_ui_manager_insert_action_group(view->priv->manager, action_group, 0); view->priv->sensitive_action_group = action_group; gtk_action_group_set_sensitive(action_group, TRUE); action_group = gtk_action_group_new("GmAppViewActions"); gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions(action_group, gm_menu_entries, G_N_ELEMENTS(gm_menu_entries), view); gtk_ui_manager_insert_action_group(view->priv->manager, action_group, 0); view->priv->action_group = action_group; gtk_action_group_set_sensitive(action_group, FALSE); view->priv->worlds_action_group = gtk_action_group_new("GmAppViewWorldsActions"); gtk_action_group_set_translation_domain(view->priv->worlds_action_group, GETTEXT_PACKAGE); gtk_ui_manager_insert_action_group(view->priv->manager, view->priv->worlds_action_group, 0); #ifndef HAVE_RUBY gtk_widget_set_sensitive(gtk_ui_manager_get_widget(view->priv->manager, "/MenuBar/ViewMenu/ViewScriptsMenu"), FALSE); #endif return gtk_ui_manager_get_widget(view->priv->manager, "/MenuBar"); } GtkWidget * gm_app_view_create_search_box(GmAppView *view) { GtkWidget *vbox = gtk_vbox_new(FALSE, 3); GtkWidget *hbox = gtk_hbox_new(FALSE, 6); GtkWidget *lbl = gtk_label_new(_("Find:")); GtkWidget *entry = gtk_entry_new(); GtkWidget *button = gtk_button_new(); GtkWidget *hbox_button = gtk_hbox_new(FALSE, 2); GtkWidget *align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0); GtkWidget *check_button = gtk_check_button_new_with_label(_("Search backwards")); GtkWidget *button_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE); GtkWidget *separator = gtk_hseparator_new(); gtk_container_set_border_width(GTK_CONTAINER(hbox), 3); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, TRUE, 0); gtk_container_add(GTK_CONTAINER(button), align); gtk_container_add(GTK_CONTAINER(align), hbox_button); gtk_box_pack_start(GTK_BOX(hbox_button), gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_BUTTON), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox_button), gtk_label_new(_("Find next")), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), check_button, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(hbox), button_close, FALSE, FALSE, 0); view->priv->vbox_find = GTK_VBOX(vbox); view->priv->entry_find = GTK_ENTRY(entry); view->priv->check_button_search_direction = GTK_CHECK_BUTTON(check_button); gtk_widget_show_all(vbox); gtk_widget_hide(vbox); g_signal_connect(entry, "activate", G_CALLBACK(on_gm_app_view_entry_find_activate), view); g_signal_connect(entry, "changed", G_CALLBACK(on_gm_app_view_entry_find_changed), view); g_signal_connect(entry, "key_press_event", G_CALLBACK(on_gm_app_view_entry_find_key_press), view); g_signal_connect(button_close, "clicked", G_CALLBACK(on_gm_app_view_button_find_close_clicked), view); g_signal_connect(check_button, "toggled", G_CALLBACK(on_gm_app_view_check_button_search_direction_toggled), view); return vbox; } void gm_app_view_create_keybindings(GmAppView *view) { GtkAccelGroup *grp; GClosure *closure; int i; gchar num[2] = { 0, 0 }; AccelInfo *info; grp = gtk_accel_group_new(); // Setting up Alt-1/Ctrl-1 -> Alt-9/Ctrl-9 accelerators for (i = 0; i < 9; i++) { info = g_new0(AccelInfo, 1); info->num = i; info->view = view; num[0] = '1' + i; closure = g_cclosure_new(G_CALLBACK(on_gm_app_view_accel_switch_page), info, NULL); gtk_accel_group_connect(grp, gdk_keyval_from_name(num), GDK_MOD1_MASK, GTK_ACCEL_VISIBLE, closure); g_closure_unref(closure); closure = g_cclosure_new(G_CALLBACK(on_gm_app_view_accel_switch_edit), info, NULL); gtk_accel_group_connect(grp, gdk_keyval_from_name(num), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, closure); g_closure_unref(closure); } info = g_new0(AccelInfo, 1); info->num = 1; info->view = view; // Next page closure = g_cclosure_new(G_CALLBACK(on_gm_app_view_accel_cycle_page), info, NULL); gtk_accel_group_connect(grp, GDK_Page_Up, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, closure); g_closure_unref(closure); info = g_new0(AccelInfo, 1); info->num = -1; info->view = view; // Previous page closure = g_cclosure_new(G_CALLBACK(on_gm_app_view_accel_cycle_page), info, NULL); gtk_accel_group_connect(grp, GDK_Page_Down, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, closure); g_closure_unref(closure); gtk_window_add_accel_group(GTK_WINDOW(view), grp); } static void gm_app_view_init(GmAppView *view) { GtkWidget *menu; GtkWidget *search; GtkWidget *vbox; GtkWidget *note; view->priv = GM_APP_VIEW_GET_PRIVATE(view); vbox = gtk_vbox_new(FALSE, 3); gtk_widget_show(vbox); gtk_container_add(GTK_CONTAINER(view), vbox); menu = gm_app_view_create_menu(view); gtk_widget_show(menu); gtk_box_pack_start(GTK_BOX(vbox), menu, FALSE, TRUE, 0); search = gm_app_view_create_search_box(view); gtk_box_pack_start(GTK_BOX(vbox), search, FALSE, TRUE, 0); note = gtk_notebook_new(); gtk_widget_show(note); gtk_container_set_border_width(GTK_CONTAINER(note), 3); gtk_notebook_set_show_border(GTK_NOTEBOOK(note), FALSE); GTK_WIDGET_UNSET_FLAGS(note, GTK_CAN_FOCUS); gtk_widget_add_events(GTK_WIDGET(note), GDK_BUTTON1_MOTION_MASK); gtk_box_pack_start(GTK_BOX(vbox), note, TRUE, TRUE, 0); gm_app_view_create_keybindings(view); view->priv->menu = GTK_MENU_BAR(menu); view->priv->notebook = GTK_NOTEBOOK(note); gtk_window_set_title(GTK_WINDOW(view), "GnoeMoe"); gtk_window_set_icon(GTK_WINDOW(view), gm_pixbuf_get("gnoemoe_logo.svg")); g_signal_connect(view, "destroy", G_CALLBACK(on_gm_app_view_destroy), NULL); g_signal_connect(view, "focus_in_event", G_CALLBACK(on_gm_app_view_focus_in), NULL); /* Signals for tab reordering */ g_signal_connect_after(note, "switch-page", G_CALLBACK(on_gm_app_view_notebook_switch_page), view); g_signal_connect(note, "button-press-event", G_CALLBACK(on_gm_app_view_notebook_button_press), view); g_signal_connect(note, "button-release-event", G_CALLBACK(on_gm_app_view_notebook_button_release), view); view->priv->world_menu_items = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)gm_app_view_destroy_world_menu_item); view->priv->drag_in_progress = FALSE; view->priv->motion_notify_handler_id = 0; view->priv->x_start = 0; view->priv->y_start = 0; view->priv->cursor = NULL; gm_scripts_dialog_init(); } // Public functions GmAppView * gm_app_view_new(GmApp *application) { GmAppView *view = GM_APP_VIEW(g_object_new(GM_TYPE_APP_VIEW, NULL)); gboolean dir; view->priv->application = application; view->priv->active_world = NULL; // Toggle search direction dir = gm_options_get_int(gm_app_options(application), "search_direction") == 1; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( view->priv->check_button_search_direction), dir); g_signal_connect(application, "world_added", G_CALLBACK(on_gm_app_view_world_added), view); g_signal_connect(application, "world_removed", G_CALLBACK(on_gm_app_view_world_removed), view); return view; } void notebook_focus_with_label(GtkNotebook * note, gchar * caption) { int p = gtk_notebook_get_n_pages(note); int i; GtkWidget *child; for (i = 0; i < p; i++) { child = gtk_notebook_get_nth_page(note, i); if (!g_strcasecmp(gtk_notebook_get_tab_label_text(note, child), caption)) { gtk_notebook_set_current_page(note, i); break; } } } void gm_app_view_destroy_world_menu_item(GmAppViewWorldMenuItem *item) { g_object_unref(item->action); g_free(item); } void on_gm_app_view_world_removed(GmApp *app, GmWorld *world, GmAppView *view) { GmAppViewWorldMenuItem *item = (GmAppViewWorldMenuItem *) g_hash_table_lookup(view->priv->world_menu_items, world); gtk_ui_manager_remove_ui(view->priv->manager, item->merge_id); gtk_action_group_remove_action(view->priv->worlds_action_group, item->action); g_hash_table_remove(view->priv->world_menu_items, world); } void gm_app_view_set_sensitivity(GmAppView *view, gboolean sens) { gtk_action_group_set_sensitive(view->priv->action_group, sens); if (sens) { /* TODO: set world info menu item not sensitive if no world info avail First fix MCP gtk_widget_set_sensitive(if_main_get_widget("mnuWorldInfo"), sens); */ } else { gtk_widget_hide(GTK_WIDGET(view->priv->vbox_find)); } } GmWorldView * gm_app_view_active_world_view(GmAppView *view) { gint n; n = gtk_notebook_get_current_page(view->priv->notebook); if (n == -1) { return NULL; } return GM_WORLD_VIEW(gtk_notebook_get_nth_page(view->priv->notebook, n)); } GmWorld * gm_app_view_active_world(GmAppView *view) { GmWorldView *world_view = gm_app_view_active_world_view(view); if (world_view != NULL) { return gm_world_view_world(world_view); } else { return NULL; } } void gm_app_view_update_title(GmAppView *view) { gchar *title; GmWorld *world = gm_app_view_active_world(view); if (world == NULL) { gtk_window_set_title(GTK_WINDOW(view), "GnoeMoe"); } else { title = g_strconcat(gm_world_name(world), " - GnoeMoe", NULL); gtk_window_set_title(GTK_WINDOW(view), title); g_free(title); } } GtkWidget * gm_app_view_container_item(GtkContainer *cnt, GType type) { GList *childFirst = gtk_container_get_children(cnt); GList *child; GtkWidget *result = NULL; for (child = childFirst; child; child = child->next) { if (G_TYPE_CHECK_INSTANCE_TYPE(child->data, type)) { result = GTK_WIDGET(child->data); break; } else if (GTK_IS_CONTAINER(child->data)) { if ((result = gm_app_view_container_item( GTK_CONTAINER(child->data), type))) { break; } } } g_list_free(childFirst); return result; } void gm_app_view_update_connect_button(GmAppView *view, gboolean connected) { GtkImageMenuItem *img = GTK_IMAGE_MENU_ITEM( gtk_ui_manager_get_widget(view->priv->manager, "/MenuBar/WorldMenu/WorldConnectMenu")); GtkLabel *label = GTK_LABEL(gm_app_view_container_item(GTK_CONTAINER(img), GTK_TYPE_LABEL)); GtkWidget *im; if (!connected) { im = gtk_image_new_from_stock("gtk-network", GTK_ICON_SIZE_MENU); gtk_label_set_text(label, _("Connect")); } else { im = gtk_image_new_from_stock("gtk-stop", GTK_ICON_SIZE_MENU); gtk_label_set_text(label, _("Disconnect")); } gtk_image_menu_item_set_image(img, im); gtk_widget_show(im); } void gm_app_view_worlds_unloaded(GmAppView *view) { gm_app_view_set_sensitivity(view, FALSE); gm_app_view_update_connect_button(view, FALSE); gm_app_view_update_title(view); } void gm_app_view_worlds_loaded(GmAppView *view) { gm_app_view_set_sensitivity(view, TRUE); } /* TODO: move to custom widget thingie, and put control in gm-app instead of gm-app-view static gboolean have_tray(void) { Screen *xscreen = DefaultScreenOfDisplay(gdk_display); Atom selection_atom; char *selection_atom_name; selection_atom_name = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen(xscreen)); selection_atom = XInternAtom(DisplayOfScreen(xscreen), selection_atom_name, False); g_free(selection_atom_name); if (XGetSelectionOwner(DisplayOfScreen(xscreen), selection_atom)) { return TRUE; } else { return FALSE; } } static gboolean tray_flash_restore_func(gpointer data) { switch (app_tray_info.iconnr) { case TRAY_ICON_ACTIVE: gtk_image_set_from_pixbuf(GTK_IMAGE(app_tray_info.image), gnoe_pixbuf_get("tray/active.svg")); break; case TRAY_ICON_DEFAULT: gtk_image_set_from_pixbuf(GTK_IMAGE(app_tray_info.image), gnoe_pixbuf_get("tray/default.svg")); break; case TRAY_ICON_NOTIFY: gtk_image_set_from_pixbuf(GTK_IMAGE(app_tray_info.image), gnoe_pixbuf_get("tray/notify.svg")); break; } app_tray_info.flash_timeout = -1; return FALSE; } void tray_activate() { if (app_tray_info.flash_timeout != 0) { g_source_remove(app_tray_info.flash_timeout); } gtk_image_set_from_pixbuf(GTK_IMAGE(app_tray_info.image), gnoe_pixbuf_get("tray/activate.svg")); app_tray_info.flash_timeout = g_timeout_add(1000, tray_flash_restore_func, NULL); } void tray_set_notify(gchar *text) { gboolean active = gtk_window_is_active(GTK_WINDOW(wndMain)); if (!active) { app_tray_info.iconnr = TRAY_ICON_NOTIFY; tray_flash_restore_func(NULL); egg_tray_icon_send_message(app_tray_info.icon, 2000, text, g_utf8_strlen(text, -1)); gtk_tooltips_set_tip(app_tray_info.tooltips, app_tray_info.event_box, text, text); } } void tray_update() { GList *wlds; world *wld; gchar *tmp = NULL, *tmp2 = NULL; gboolean active = gtk_window_is_active(GTK_WINDOW(wndMain)); if (!active) { for (wlds = world_get_worlds(); wlds; wlds = wlds->next) { wld = (world *)(wlds->data); if (wld->loaded && wld->inactive > 0) { if (tmp == NULL) { tmp = g_strdup_printf(_("Activity in:\n%s (%d)"), options_get_str( wld->settings, "name"), wld->inactive); } else { tmp2 = g_strdup_printf("%s, %s (%d)", tmp, options_get_str( wld->settings, "name"), wld->inactive); g_free(tmp); tmp = g_strdup(tmp2); g_free(tmp2); tmp2 = NULL; } } } if (tmp) { app_tray_info.iconnr = TRAY_ICON_ACTIVE; tray_activate(); } else if (app_tray_info.iconnr != TRAY_ICON_NOTIFY) { app_tray_info.iconnr = TRAY_ICON_DEFAULT; tray_flash_restore_func(NULL); } if (app_tray_info.iconnr != TRAY_ICON_NOTIFY) { gtk_tooltips_set_tip(app_tray_info.tooltips, app_tray_info.event_box, tmp, tmp); } g_free(tmp); } else { app_tray_info.iconnr = TRAY_ICON_DEFAULT; tray_flash_restore_func(NULL); gtk_tooltips_set_tip(app_tray_info.tooltips, app_tray_info.event_box, NULL, NULL); } } void if_main_show_hide(gboolean show) { world *wld; if (show || !gtk_window_is_active(GTK_WINDOW(wndMain))) { gtk_widget_show(wndMain); gtk_window_present(GTK_WINDOW(wndMain)); wld = world_get_active(); if (wld) { wld->inactive = 0; } tray_update(); } else { gtk_widget_hide(wndMain); } }*/ void gm_app_view_update_world_info(gboolean hasInfo) { /* TODO: do this some other way */ /*GtkWidget *image; world *wld = world_get_active(); gtk_widget_set_sensitive(if_main_get_widget("mnuWorldInfo"), hasInfo); if (options_get_str(wld->settings, "logo")) { image = gtk_image_new_from_pixbuf(gnoe_pixbuf_get_at_size(options_get_str(wld->settings, "logo"), 16, 16)); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(wld->widgets.menuItem), image); }*/ } GmWorldView * gm_app_view_world_view_from_world(GmAppView *view, GmWorld *world) { GtkNotebook *book = view->priv->notebook; GmWorldView *current_view; gint i; for (i = 0; i < gtk_notebook_get_n_pages(book); i++) { current_view = GM_WORLD_VIEW(gtk_notebook_get_nth_page(book, i)); if (gm_world_view_world(current_view) == world) { return current_view; } } return NULL; } /* Callbacks */ void on_gm_app_view_destroy(GtkWidget * caller, gpointer user_data) { gtk_main_quit(); } void on_gm_app_view_world_close(GtkMenuItem * menuitem, GmAppView *view) { GmWorld *world = gm_app_view_active_world(view); if (world) { gm_world_unload(world); } } void on_gm_app_view_world_close_from_tab(GmWorldTab *tab, GmWorld *world) { gm_world_unload(world); } void on_gm_app_view_world_name_changed(GmWorld *world, const gchar *name, GmAppView *view) { GmAppViewWorldMenuItem *item = (GmAppViewWorldMenuItem *) g_hash_table_lookup(view->priv->world_menu_items, world); g_object_set(G_OBJECT(item->action), "label", name, NULL); if (world == gm_app_view_active_world(view)) { gm_app_view_update_title(view); } } void on_gm_app_view_world_added(GmApp *app, GmWorld *world, GmAppView *view) { static guint id = 0; GmAppViewWorldMenuItem *item = g_new0(GmAppViewWorldMenuItem, 1); gchar *name = g_strdup_printf("WorldItem%d", id); gchar *tooltip = g_strconcat(_("Open world "), gm_world_name(world), NULL); id++; /* TODO: add custom icon from logo */ item->merge_id = gtk_ui_manager_new_merge_id(view->priv->manager); item->action = gtk_action_new(name, gm_world_name(world), tooltip, NULL); gtk_action_group_add_action(view->priv->worlds_action_group, item->action); gtk_ui_manager_add_ui(view->priv->manager, item->merge_id, "/MenuBar/WorldMenu/WorldMenuAdditions", name, name, GTK_UI_MANAGER_MENUITEM, FALSE); g_signal_connect(item->action, "activate", G_CALLBACK(on_gm_app_view_world_activate), world); g_signal_connect(world, "load", G_CALLBACK(on_gm_app_view_world_load), view); g_signal_connect(world, "unload", G_CALLBACK(on_gm_app_view_world_unload), view); g_signal_connect(world, "activate_request", G_CALLBACK(on_gm_app_view_world_activate_request), view); g_signal_connect(world, "name_changed", G_CALLBACK(on_gm_app_view_world_name_changed), view); g_signal_connect(world, "state_changing", G_CALLBACK(on_gm_app_view_world_state_changing), view); g_signal_connect(world, "active_changed", G_CALLBACK(on_gm_app_view_world_active_changed), view); g_hash_table_insert(view->priv->world_menu_items, world, item); g_free(name); g_free(tooltip); } void on_gm_app_view_world_state_changing(GmWorld *world, GmNetState state, GmAppView *view) { if (world == gm_app_view_active_world(view)) { switch (state) { case GM_NET_STATE_CONNECTED: gm_app_view_update_connect_button(view, TRUE); break; case GM_NET_STATE_DISCONNECTED: gm_app_view_update_connect_button(view, FALSE); break; default: break; } } } void on_gm_app_view_world_load(GmWorld *world, GmAppView *view) { GtkWidget *world_view = gm_world_view_new(world); GmWorldTab *tab = gm_world_tab_new(world); g_signal_connect(tab, "close", G_CALLBACK(on_gm_app_view_world_close_from_tab), world); gtk_notebook_append_page(view->priv->notebook, world_view, GTK_WIDGET(tab)); gtk_widget_show_all(world_view); gm_world_view_set_userlist_width(GM_WORLD_VIEW(world_view), gm_options_get_int(gm_world_options(world), "pane_position")); if (gtk_notebook_get_n_pages(view->priv->notebook) == 1) { gm_app_view_worlds_loaded(view); } } void on_gm_app_view_world_unload(GmWorld *world, GmAppView *view) { GmWorldView *world_view = gm_app_view_world_view_from_world(view, world); gtk_notebook_remove_page(view->priv->notebook, gtk_notebook_page_num(view->priv->notebook, GTK_WIDGET(world_view))); if (gtk_notebook_get_n_pages(view->priv->notebook) == 0) { gm_app_view_worlds_unloaded(view); } } void on_gm_app_view_world_activate_request(GmWorld *world, GmAppView *view) { gm_world_set_active(world, TRUE); } void on_gm_app_view_world_quit(GtkMenuItem * menuitem, GmAppView *view) { gtk_widget_destroy(GTK_WIDGET(view)); } void on_gm_app_view_edit_worlds(GtkMenuItem * menuitem, GmAppView *view) { gm_worlds_list_dialog_run(); } void on_gm_app_view_accel_switch_page(GtkAccelGroup * accelgroup, GObject * arg1, guint arg2, GdkModifierType arg3, AccelInfo *info) { gtk_notebook_set_current_page(info->view->priv->notebook, info->num); } void on_gm_app_view_accel_switch_edit(GtkAccelGroup * accelgroup, GObject * arg1, guint arg2, GdkModifierType arg3, AccelInfo *info) { GmWorld *world = gm_app_view_active_world(info->view); if (world) { gtk_notebook_set_current_page(info->view->priv->notebook, info->num); } } void on_gm_app_view_accel_cycle_page(GtkAccelGroup * accelgroup, GObject * arg1, guint arg2, GdkModifierType arg3, AccelInfo *info) { GtkNotebook *note = info->view->priv->notebook; int p = gtk_notebook_get_current_page(note) + info->num; if (p < 0) { gtk_notebook_set_current_page(note, gtk_notebook_get_n_pages(note) - 1); } else if (p > gtk_notebook_get_n_pages(note) - 1) { gtk_notebook_set_current_page(note, 0); } else { gtk_notebook_set_current_page(note, p); } } void on_gm_app_view_world_activate(GtkAction * action, GmWorld *world) { gm_world_load(world); } GmWorldViewSearchFlags gm_app_view_search_flags(GmAppView *view) { gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( view->priv->check_button_search_direction)); if (active) { return GM_WORLD_VIEW_SEARCH_BACKWARDS; } else { return GM_WORLD_VIEW_SEARCH_FORWARDS; } } gboolean gm_app_view_find_first(GmAppView *view) { GmWorldView *world_view = gm_app_view_active_world_view(view); GdkColor red; GtkEntry *entry = view->priv->entry_find; if (world_view) { gdk_color_parse ("#ff6666", &red); //gdk_color_parse ("white", &white); if (g_utf8_strlen(gtk_entry_get_text(entry), -1) == 0 || gm_world_view_find_first(world_view, gtk_entry_get_text(entry), gm_app_view_search_flags(view))) { gtk_widget_modify_base(GTK_WIDGET(entry), GTK_STATE_NORMAL, NULL); } else { gtk_widget_modify_base(GTK_WIDGET(entry), GTK_STATE_NORMAL, &red); } } return FALSE; } void on_gm_app_view_entry_find_changed(GtkEditable *editable, GmAppView *view) { g_idle_add((GSourceFunc)gm_app_view_find_first, view); } void on_gm_app_view_entry_find_activate(GtkEntry *entry, GmAppView *view) { on_gm_app_view_edit_find_next(NULL, view); } void gm_app_view_show_find_box(GmAppView *view) { GmWorldView *world_view; int i, n; if (!GTK_WIDGET_VISIBLE(view->priv->vbox_find)) { n = gtk_notebook_get_n_pages(view->priv->notebook); for (i = 0; i < gtk_notebook_get_n_pages(view->priv->notebook); i++) { world_view = GM_WORLD_VIEW(gtk_notebook_get_nth_page( view->priv->notebook, i)); gm_world_view_scroll_end_prepare(world_view); } gtk_widget_show(GTK_WIDGET(view->priv->vbox_find)); gm_do_events(); for (i = 0; i < gtk_notebook_get_n_pages(view->priv->notebook); i++) { world_view = GM_WORLD_VIEW(gtk_notebook_get_nth_page( view->priv->notebook, i)); gm_world_view_scroll_end(world_view); } } } void on_gm_app_view_edit_find(GtkMenuItem * menuitem, GmAppView *view) { GtkWidget *entry = GTK_WIDGET(view->priv->entry_find); gm_app_view_show_find_box(view); gtk_widget_grab_focus(entry); gtk_widget_modify_base(entry, GTK_STATE_NORMAL, NULL); } void on_gm_app_view_edit_find_next(GtkMenuItem * menuitem, GmAppView *view) { gm_app_view_show_find_box(view); gm_world_view_find_next(gm_app_view_active_world_view(view), gtk_entry_get_text(view->priv->entry_find), gm_app_view_search_flags(view)); } void on_gm_app_view_button_find_clicked(GtkButton *button, gpointer user_data) { on_gm_app_view_edit_find_next(NULL, NULL); } gboolean on_gm_app_view_entry_find_key_press(GtkWidget *widget, GdkEventKey *event, GmAppView *view) { if (event->keyval == GDK_Escape) { on_gm_app_view_button_find_close_clicked(NULL, view); gtk_widget_grab_focus(GTK_WIDGET(gm_app_view_active_world_view(view))); return TRUE; } else { return FALSE; } } void on_gm_app_view_button_find_close_clicked(GtkButton *button, GmAppView *view) { GmWorldView *world_view = gm_app_view_active_world_view(view); gtk_widget_hide(GTK_WIDGET(view->priv->vbox_find)); if (world_view) { gm_world_view_set_focus(world_view); } } void on_gm_app_view_check_button_search_direction_toggled(GtkToggleButton *button, GmAppView *view) { gboolean active = gtk_toggle_button_get_active(button); gm_options_set_int(gm_app_options(view->priv->application), "search_direction", active ? 1 : 0); } void on_gm_app_view_edit_preferences(GtkMenuItem * menuitem, GmAppView *view) { /* TODO: implementation */ //create_preferences(main_get_options()); } /* Tab moving from gedit */ gint gm_app_view_find_tab_num_at_pos(GmAppView *view, gint abs_x, gint abs_y) { GtkNotebook *notebook = view->priv->notebook; GtkPositionType tab_pos; int page_num = 0; GtkWidget *page; tab_pos = gtk_notebook_get_tab_pos(notebook); if (notebook->first_tab == NULL) { return -1; } /* For some reason unfullscreen + quick click can cause a wrong click event to be reported to the tab */ /*if (!is_in_notebook_window(notebook, abs_x, abs_y)) { return -1; }*/ while ((page = gtk_notebook_get_nth_page(notebook, page_num)) != NULL) { GtkWidget *tab; gint max_x, max_y; gint x_root, y_root; tab = gtk_notebook_get_tab_label(notebook, page); g_return_val_if_fail(tab != NULL, -1); if (!GTK_WIDGET_MAPPED(GTK_WIDGET(tab))) { ++page_num; continue; } gdk_window_get_origin(GDK_WINDOW(tab->window), &x_root, &y_root); max_x = x_root + tab->allocation.x + tab->allocation.width; max_y = y_root + tab->allocation.y + tab->allocation.height; if (((tab_pos == GTK_POS_TOP) || (tab_pos == GTK_POS_BOTTOM)) && (abs_x <= max_x)) { return page_num; } else if (((tab_pos == GTK_POS_LEFT) || (tab_pos == GTK_POS_RIGHT)) && (abs_y <= max_y)) { return page_num; } ++page_num; } return -1; } void gm_app_view_drag_stop(GmAppView *view) { view->priv->drag_in_progress = FALSE; if (view->priv->motion_notify_handler_id != 0) { g_signal_handler_disconnect(G_OBJECT(view->priv->notebook), view->priv->motion_notify_handler_id); view->priv->motion_notify_handler_id = 0; } } void gm_app_view_drag_start(GmAppView *view, guint32 time) { view->priv->drag_in_progress = TRUE; /* get a new cursor, if necessary */ /* FIXME multi-head */ if (view->priv->cursor == NULL) view->priv->cursor = gdk_cursor_new(GDK_FLEUR); /* grab the pointer */ gtk_grab_add(GTK_WIDGET(view->priv->notebook)); /* FIXME multi-head */ if (!gdk_pointer_is_grabbed()) { gdk_pointer_grab(GTK_WIDGET(view->priv->notebook)->window, FALSE, GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, view->priv->cursor, time); } } void gm_app_view_move_current_tab(GmAppView *view, gint dest_position) { gint cur_page_num; cur_page_num = gtk_notebook_get_current_page(view->priv->notebook); if (dest_position != cur_page_num) { GtkWidget *cur_tab; cur_tab = gtk_notebook_get_nth_page(view->priv->notebook, cur_page_num); gtk_notebook_reorder_child(view->priv->notebook, cur_tab, dest_position); } } gboolean on_gm_app_view_motion_notify(GmAppView *view, GdkEventMotion *event, gpointer data) { gint page_num; if (view->priv->drag_in_progress == FALSE) { if (gtk_drag_check_threshold(GTK_WIDGET(view->priv->notebook), view->priv->x_start, view->priv->y_start, event->x_root, event->y_root)) { gm_app_view_drag_start(view, event->time); return TRUE; } return FALSE; } page_num = gm_app_view_find_tab_num_at_pos(view, event->x_root, event->y_root); if (page_num != -1) { gm_app_view_move_current_tab(view, page_num); } return FALSE; } gboolean on_gm_app_view_notebook_button_press(GtkNotebook *notebook, GdkEventButton *event, GmAppView *view) { gint tab_clicked; if (view->priv->drag_in_progress) return TRUE; tab_clicked = gm_app_view_find_tab_num_at_pos(view, event->x_root, event->y_root); if ((event->button == 1) && (event->type == GDK_BUTTON_PRESS) && (tab_clicked >= 0)) { view->priv->x_start = event->x_root; view->priv->y_start = event->y_root; view->priv->motion_notify_handler_id = g_signal_connect(G_OBJECT(notebook), "motion-notify-event", G_CALLBACK(on_gm_app_view_motion_notify), NULL); } else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) { /* Switch to the page the mouse is over, but don't consume the event */ //gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), tab_clicked); } return FALSE; } gboolean on_gm_app_view_notebook_button_release(GtkNotebook *notebook, GdkEventButton *event, GmAppView *view) { if (view->priv->drag_in_progress) { gint cur_page_num; GtkWidget *cur_page; cur_page_num = gtk_notebook_get_current_page(notebook); cur_page = gtk_notebook_get_nth_page(notebook, cur_page_num); /* ungrab the pointer if it's grabbed */ if (gdk_pointer_is_grabbed()) { gdk_pointer_ungrab(event->time); } gtk_grab_remove(GTK_WIDGET(notebook)); } /* This must be called even if a drag isn't happening */ gm_app_view_drag_stop(view); return FALSE; } void on_gm_app_view_notebook_switch_page(GtkNotebook * notebook, GtkNotebookPage * page, guint page_num, GmAppView *view) { GmWorld *world = gm_app_view_active_world(view); debug_msg(0, "%d", page_num); if (view->priv->active_world == world) { return; } if (view->priv->active_world) { gm_world_set_active(view->priv->active_world, FALSE); } if (world) { view->priv->active_world = world; gm_world_set_active(view->priv->active_world, TRUE); } } static const gchar *authors[] = { N_("Jesse van den Kieboom"), N_("Sjoerd Simons (debian package)"), NULL }; static const gchar *artists[] = { N_("Simon Gijsen"), NULL }; void on_gm_app_view_help_about(GtkMenuItem *menuitem, GmAppView *view) { gtk_show_about_dialog(GTK_WINDOW(view), "name", _("GnoeMoe"), "version", IVERSION, "copyright", _("(C) 2004-2005 Icecrew.nl"), "comments", _("GnoeMoe Gnome MOO Client"), "authors", authors, "artists", artists, "logo", gm_pixbuf_get("gnoemoe_logo.svg"), NULL); } void on_gm_app_view_edit_cut(GtkMenuItem * menuitem, GmAppView *view) { GtkWidget *active = gtk_window_get_focus(GTK_WINDOW(view)); GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); GtkTextBuffer *buf; if (active && GTK_IS_TEXT_VIEW(active)) { buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(active)); gtk_text_buffer_cut_clipboard(buf, clip, TRUE); } } void on_gm_app_view_edit_copy(GtkMenuItem * menuitem, GmAppView *view) { GtkWidget *active = gtk_window_get_focus(GTK_WINDOW(view)); GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); GtkTextBuffer *buf; GtkTextIter start, end; GmWorldView *world_view; world_view = gm_app_view_active_world_view(view); if (world_view && active == GTK_WIDGET(gm_world_view_input(world_view))) { buf = gm_world_view_buffer(world_view); if (gtk_text_buffer_get_selection_bounds(buf, &start, &end)) { gtk_text_buffer_copy_clipboard(buf, clip); return; } } if (active && GTK_IS_TEXT_VIEW(active)) { buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(active)); gtk_text_buffer_copy_clipboard(buf, clip); } } void on_gm_app_view_edit_paste(GtkMenuItem * menuitem, GmAppView *view) { GtkWidget *active = gtk_window_get_focus(GTK_WINDOW(view)); GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); GtkTextBuffer *buf; if (active && GTK_IS_TEXT_VIEW(active)) { buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(active)); gtk_text_buffer_paste_clipboard(buf, clip, NULL, TRUE); } } void on_gm_app_view_world_new(GtkMenuItem * menuitem, GmAppView *view) { gm_world_properties_dialog_run_new(NULL); } void on_gm_app_view_edit_world(GtkMenuItem * menuitem, GmAppView *view) { GmWorld *active = gm_app_view_active_world(view); gm_world_properties_dialog_run(active); } void on_gm_app_view_world_connect(GtkMenuItem * menuitem, GmAppView *view) { GmWorld *world = gm_app_view_active_world(view); if (world != NULL) { if (gm_world_connected(world)) { gm_world_disconnect(world); } else if (gm_world_disconnected(world)) { gm_world_connect(world); } } } void on_gm_app_view_world_info(GtkMenuItem *menuitem, GmAppView *view) { GmWorld *world = gm_app_view_active_world(view); if (world) { gm_world_info_dialog_new(gm_world_info(world)); } else { gm_app_view_update_world_info(FALSE); } } void on_gm_app_view_view_mcp(GtkMenuItem * menuitem, GmAppView *view) { /* TODO: implementation */ //if_mcpconsole_create(); } void on_gm_app_view_view_scripts(GtkMenuItem * menuitem, GmAppView *view) { #ifdef HAVE_RUBY gm_scripts_dialog_run(view); #endif } void gm_app_view_open_log_progress(long bytes_read, long bytes_total, gchar *buf, GtkProgressBar *progress) { gtk_progress_bar_set_fraction(progress, (double)bytes_read / (double)bytes_total); gm_do_events(); } void on_gm_app_view_world_logs(GtkMenuItem * menuitem, GmAppView *view) { GtkDialog *dlg; GtkTreeView *tview; GtkTreeModel *smodel; gchar *tmp, *tmp2; GtkTreeIter iter; gboolean done = FALSE; static GdkCursor *wait_cursor = NULL; GmWorld *world = gm_app_view_active_world(view); GtkProgressBar *pgs; dlg = gm_world_logs_dialog_new(gm_app_view_active_world(view), &tview, &pgs); if (dlg != NULL) { smodel = gtk_tree_view_get_model(tview); while (!done) { done = TRUE; switch (gtk_dialog_run(dlg)) { case GTK_RESPONSE_OK: if (gtk_tree_selection_get_selected( gtk_tree_view_get_selection(tview), &smodel, &iter)) { gtk_tree_model_get(smodel, &iter, 0, &tmp, -1); tmp2 = g_strconcat(gm_world_path(world), tmp, NULL); gtk_widget_set_sensitive(GTK_WIDGET(dlg), FALSE); if (wait_cursor == NULL) { wait_cursor = gdk_cursor_new(GDK_WATCH); } gdk_window_set_cursor(GTK_WIDGET(dlg)->window, wait_cursor); gtk_widget_show(GTK_WIDGET(pgs)); gm_world_view_open_log(gm_app_view_active_world_view(view), tmp2, (OpenLogProgress)gm_app_view_open_log_progress, pgs); gtk_widget_hide(GTK_WIDGET(pgs)); gdk_window_set_cursor(GTK_WIDGET(dlg)->window, NULL); g_free(tmp2); g_free(tmp); } else { gm_error_dialog(_("You didn't select a log file"), NULL); done = FALSE; } break; default: break; } } gtk_widget_destroy(GTK_WIDGET(dlg)); } } void on_gm_app_view_world_active_changed(GmWorld *world, gboolean active, GmAppView *view) { GmWorldView *world_view = gm_app_view_world_view_from_world(view, world); if (active) { gtk_notebook_set_current_page(view->priv->notebook, gtk_notebook_page_num(view->priv->notebook, GTK_WIDGET(world_view))); gm_app_view_update_title(view); } } gboolean on_gm_app_view_focus_in(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { /* TODO: implementation world *wld; wld = world_get_active(); if (wld) { world_activated(wld); } app_tray_info.iconnr = TRAY_ICON_DEFAULT; tray_flash_restore_func(NULL);*/ return FALSE; }