#include #include #include "gm-app.h" #include "gm-world-view.h" #include "gm-world-text-view.h" #include "gm-world-input-view.h" #include "gm-text-scroller.h" #include "gm-editor-view.h" #include "gm-embedded-view.h" #include "gm-external-view.h" #include "gm-log-view.h" #include "gm-debug.h" #include "gm-support.h" #include "gm-color-table.h" #include "mcp/gm-mcp-package.h" #include "mcp/gm-mcp-session.h" #include "gm-editor.h" #include "gm-searchable.h" #define GM_WORLD_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ GM_TYPE_WORLD_VIEW, GmWorldViewPrivate)) struct _GmWorldViewPrivate { GmWorld *world; GtkStatusbar *statusbar; GtkHPaned *hpaned; GmWorldTextView *text_view_world; GmWorldInputView *text_view_input; GmTextScroller *text_scroller_world; GList *external_editors; }; void on_gm_world_view_world_text_received(GmWorld *world, gchar *text, GmWorldView *view); void on_gm_world_view_world_error(GmWorld *world, gchar *text, gint code, GmWorldView *view); void on_gm_world_input_view_world_text_activate(GmWorldInputView *iview, gchar *text, GmWorldView *view); void on_gm_world_view_world_state_changing(GmWorld *world, guint state, GmWorldView *view); void on_gm_world_view_world_active_changed(GmWorld *world, GParamSpec *pspec, GmWorldView *view); void on_gm_world_view_world_highlight(GmWorld *world, gint start, gint end, gchar *color, GmWorldView *view); void on_gm_world_view_world_editor_added(GmWorld *world, GmEditor *editor, GmWorldView *view); void on_gm_world_view_world_editor_removed(GmWorld *world, GmEditor *editor, GmWorldView *view); void on_gm_world_view_world_mcp_package_created(GmMcpSession *session, GmMcpPackage *package, GmWorldView *view); void on_gm_world_view_editor_view_modified_changed(GmEditorView *editor_view, gboolean modified, GmWorldView *view); gboolean on_gm_world_view_world_text_view_scroll_event(GmWorldView *view, GdkEventScroll *event, GmWorldTextView *text); void on_gm_world_view_world_text_view_url_activate(GmWorldView *view, gchar const *url); void on_gm_world_view_editor_view_close_clicked(GtkButton *button, GtkWidget *view); void on_gm_world_view_log_view_close_clicked(GtkButton *button, GtkWidget *view); gboolean on_gm_world_view_world_input_view_key_pressed(GtkWidget *widget, GdkEventKey *event, GmWorldView *view); /* Signals enum { NUM_SIGNALS }; static guint gm_world_view_signals[NUM_SIGNALS] = {0};*/ static void gm_world_view_searchable_iface_init( GmSearchableInterface *iface); static GtkTextView *gm_world_view_searchable_get_text_view(GmSearchable *sea); G_DEFINE_TYPE_EXTENDED(GmWorldView, gm_world_view, GTK_TYPE_NOTEBOOK, 0, \ G_IMPLEMENT_INTERFACE(GM_TYPE_SEARCHABLE, \ gm_world_view_searchable_iface_init)) static void gm_world_view_searchable_iface_init(GmSearchableInterface *iface) { iface->get_text_view = gm_world_view_searchable_get_text_view; } static GtkTextView * gm_world_view_searchable_get_text_view(GmSearchable *sea) { GmWorldView *view = (GmWorldView *)(sea); g_return_val_if_fail(GM_IS_WORLD_VIEW(sea), NULL); return GTK_TEXT_VIEW(view->priv->text_view_world); } static void gm_world_view_finalize(GObject *object) { GmWorldView *view = GM_WORLD_VIEW(object); GList *ext; for (ext = view->priv->external_editors; ext; ext = ext->next) { gm_external_view_destroy(GM_EXTERNAL_VIEW(ext->data)); } g_list_free(view->priv->external_editors); g_signal_handlers_disconnect_by_func(view->priv->world, G_CALLBACK(on_gm_world_view_world_text_received), view); g_signal_handlers_disconnect_by_func(view->priv->world, G_CALLBACK(on_gm_world_view_world_error), view); g_signal_handlers_disconnect_by_func(view->priv->world, G_CALLBACK(on_gm_world_view_world_state_changing), view); g_signal_handlers_disconnect_by_func(view->priv->world, G_CALLBACK(on_gm_world_view_world_active_changed), view); g_signal_handlers_disconnect_by_func(view->priv->world, G_CALLBACK(on_gm_world_view_world_highlight), view); g_signal_handlers_disconnect_by_func(view->priv->world, G_CALLBACK(on_gm_world_view_world_editor_added), view); g_signal_handlers_disconnect_by_func(view->priv->world, G_CALLBACK(on_gm_world_view_world_editor_removed), view); g_signal_handlers_disconnect_by_func( gm_world_get_mcp_session(view->priv->world), G_CALLBACK(on_gm_world_view_world_mcp_package_created), view); g_object_unref(view->priv->world); G_OBJECT_CLASS(gm_world_view_parent_class)->finalize(object); } static void gm_world_view_destroy(GtkObject *object) { GmWorldView *view = GM_WORLD_VIEW(object); gm_options_set_int(gm_world_options(view->priv->world), "pane_position", GTK_WIDGET(view->priv->hpaned)->allocation.width - gtk_paned_get_position(GTK_PANED(view->priv->hpaned))); gm_options_save(gm_world_options(view->priv->world)); if (GTK_OBJECT_CLASS(gm_world_view_parent_class)->destroy) { GTK_OBJECT_CLASS(gm_world_view_parent_class)->destroy(object); } } static gboolean gm_world_view_input_grab_focus(GmWorldView *view) { gtk_widget_grab_focus(GTK_WIDGET(view->priv->text_view_input)); return FALSE; } static void gm_world_view_switch_page(GtkNotebook *notebook, GtkNotebookPage *page, guint page_num) { if (GTK_NOTEBOOK_CLASS(gm_world_view_parent_class)->switch_page) { GTK_NOTEBOOK_CLASS(gm_world_view_parent_class)->switch_page(notebook, page, page_num); } if (page_num == 0) { g_idle_add((GSourceFunc)gm_world_view_input_grab_focus, GM_WORLD_VIEW(notebook)); } } static void gm_world_view_remove_page(GtkContainer *container, GtkWidget *page) { GtkNotebook *notebook = GTK_NOTEBOOK(container); if (GTK_CONTAINER_CLASS(gm_world_view_parent_class)->remove) { GTK_CONTAINER_CLASS(gm_world_view_parent_class)->remove(container, page); } if (gtk_notebook_get_n_pages(notebook) == 1) { gtk_notebook_set_show_tabs(notebook, FALSE); } } static void gm_world_view_show(GtkWidget *widget) { GmWorldView *view = GM_WORLD_VIEW(widget); if (GTK_WIDGET_CLASS(gm_world_view_parent_class)->show) { GTK_WIDGET_CLASS(gm_world_view_parent_class)->show(widget); } gm_do_events(); gtk_paned_set_position(GTK_PANED(view->priv->hpaned), GTK_WIDGET(view->priv->hpaned)->allocation.width - gm_options_get_int(gm_world_options(view->priv->world), "pane_position")); } static void gm_world_view_class_init(GmWorldViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS(klass); GtkContainerClass *container_class = GTK_CONTAINER_CLASS(klass); object_class->finalize = gm_world_view_finalize; widget_class->show = gm_world_view_show; gtk_object_class->destroy = gm_world_view_destroy; GTK_NOTEBOOK_CLASS(klass)->switch_page = gm_world_view_switch_page; container_class->remove = gm_world_view_remove_page; g_type_class_add_private(object_class, sizeof(GmWorldViewPrivate)); } static void gm_world_view_ensure_show_tabs(GmWorldView *view) { if (!gtk_notebook_get_show_tabs(GTK_NOTEBOOK(view))) { gtk_notebook_set_show_tabs(GTK_NOTEBOOK(view), TRUE); } } /*gboolean timeout_text(gpointer user_data) { GtkTextView *view = GTK_TEXT_VIEW(user_data); GtkTextBuffer *buffer = gtk_text_view_get_buffer(view); GtkTextIter end, start; static GdkEvent *event_press = NULL; static GdkEvent *event_release = NULL; gboolean result; gtk_text_buffer_get_bounds(buffer, &start, &end); if (gtk_text_iter_get_offset(&end) > 80) { gtk_text_buffer_delete(buffer, &start, &end); } else { if (!event_press) { gtk_widget_realize(GTK_WIDGET(view)); event_press = gdk_event_new(GDK_KEY_PRESS); event_press->key.keyval = 119; event_press->key.window = gtk_text_view_get_window(view, GTK_TEXT_WINDOW_TEXT); event_release = gdk_event_new(GDK_KEY_RELEASE); event_release->key.keyval = 119; event_release->key.window = event_press->key.window; } event_press->key.time = gtk_get_current_event_time(); event_release->key.time = gtk_get_current_event_time(); g_signal_emit_by_name(GTK_WIDGET(view), "key_press_event", event_press, &result); g_signal_emit_by_name(GTK_WIDGET(view), "key_release_event", event_release, &result); } return TRUE; }*/ GtkWidget * gm_world_view_create_input_text_view(GmWorldView *view) { GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL); GtkWidget *input_text_view = gm_world_input_view_new_with_color_table( gm_app_color_table(gm_app_instance())); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(scrolled_window), input_text_view); view->priv->text_view_input = GM_WORLD_INPUT_VIEW(input_text_view); g_signal_connect(input_text_view, "key_press_event", G_CALLBACK(on_gm_world_view_world_input_view_key_pressed), view); return scrolled_window; } GtkWidget * gm_world_view_create_world_text_view(GmWorldView *view) { GtkWidget *world_text_view = gm_world_text_view_new_with_color_table( gm_app_color_table(gm_app_instance())); GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(scrolled_window), world_text_view); view->priv->text_view_world = GM_WORLD_TEXT_VIEW(world_text_view); // Create new text scroller, this object will take care of itself and will // destroy itself when the view dies, neat! view->priv->text_scroller_world = gm_text_scroller_new(GTK_TEXT_VIEW(view->priv->text_view_world)); g_signal_connect(world_text_view, "scroll_event", G_CALLBACK(on_gm_world_view_world_text_view_scroll_event), view); g_signal_connect(world_text_view, "url_activate", G_CALLBACK(on_gm_world_view_world_text_view_url_activate), view); return scrolled_window; } void gm_world_view_update_status(GmWorldView *view, gchar const *status) { gtk_statusbar_pop(view->priv->statusbar, 0); if (status == NULL) { gtk_statusbar_push(view->priv->statusbar, 0, _("Welcome to GnoeMoe, explorer of new worlds!")); } else { gtk_statusbar_push(view->priv->statusbar, 0, status); } } GtkWidget * gm_world_view_log_page_new(GmWorldView *view, gchar const *filename) { gchar *text = gm_read_file(filename); gchar *base; GmLabelInfo info; GtkWidget *log_view; GtkWidget *label; if (text == NULL) { return NULL; } base = g_path_get_basename(filename); label = gm_create_tab_label("editor_text.xpm", base, TRUE, &info); g_free(base); log_view = GTK_WIDGET(gm_log_view_new()); gtk_widget_show(log_view); gtk_notebook_append_page(GTK_NOTEBOOK(view), log_view, label); gm_world_view_ensure_show_tabs(view); gtk_notebook_set_current_page(GTK_NOTEBOOK(view), gtk_notebook_page_num(GTK_NOTEBOOK(view), log_view)); g_signal_connect(info.button_exit, "clicked", G_CALLBACK(on_gm_world_view_log_view_close_clicked), log_view); gm_log_view_set_text(GM_LOG_VIEW(log_view), text); g_free(text); return log_view; } GtkWidget * gm_world_view_editor_create_view(GmWorldView *view, GmEditor *editor) { GtkWidget *editor_view; GmOptions *options = gm_app_options(gm_app_instance()); if (strcmp(gm_options_get(options, "editor_alternative"), "0") != 0) { if (gm_options_get_int(options, "editor_embed")) { editor_view = GTK_WIDGET(gm_embedded_view_new(view->priv->world, editor)); } else { view->priv->external_editors = g_list_append( view->priv->external_editors, gm_external_view_new(view->priv->world, editor)); return NULL; } } else { editor_view = GTK_WIDGET(gm_editor_view_new(view->priv->world, editor)); g_signal_connect(editor_view, "modified-changed", G_CALLBACK(on_gm_world_view_editor_view_modified_changed), view); } gtk_widget_show(editor_view); return editor_view; } GtkWidget * gm_world_view_editor_page_new(GmWorldView *view, GmEditor *editor) { GtkWidget *label; GtkWidget *editor_view; GmLabelInfo info; gchar const *icon; if (gm_editor_is_code(editor)) { icon = "editor_verb.xpm"; } else { icon = "editor_text.xpm"; } label = gm_create_tab_label("editor_verb.xpm", gm_editor_name(editor), TRUE, &info); editor_view = gm_world_view_editor_create_view(view, editor); if (editor_view == NULL) { return NULL; } gm_world_view_ensure_show_tabs(view); gtk_notebook_append_page(GTK_NOTEBOOK(view), editor_view, label); gtk_notebook_set_current_page(GTK_NOTEBOOK(view), gtk_notebook_page_num(GTK_NOTEBOOK(view), editor_view)); g_signal_connect(info.button_exit, "clicked", G_CALLBACK(on_gm_world_view_editor_view_close_clicked), editor_view); return editor_view; } GtkWidget * gm_world_view_world_page_new(GmWorldView *view) { GtkWidget *vbox = gtk_vbox_new(FALSE, 0); GtkWidget *hpaned = gtk_hpaned_new(); GtkWidget *status = gtk_statusbar_new(); GtkWidget *vbox_world = gtk_vbox_new(FALSE, 3); gtk_box_pack_start(GTK_BOX(vbox_world), gm_world_view_create_world_text_view(view), TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_world), gm_world_view_create_input_text_view(view), FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(vbox_world), 3); gtk_paned_pack1(GTK_PANED(hpaned), vbox_world, TRUE, TRUE); gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), FALSE); gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), status, FALSE, FALSE, 0); view->priv->statusbar = GTK_STATUSBAR(status); view->priv->hpaned = GTK_HPANED(hpaned); gm_world_view_update_status(view, NULL); return vbox; } static void gm_world_view_init(GmWorldView *view) { GtkWidget *label; GmLabelInfo info; view->priv = GM_WORLD_VIEW_GET_PRIVATE(view); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(view), FALSE); gtk_notebook_set_show_border(GTK_NOTEBOOK(view), FALSE); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(view), GTK_POS_BOTTOM); gtk_notebook_set_scrollable(GTK_NOTEBOOK(view), TRUE); label = gm_create_tab_label("world.svg", _("World"), FALSE, &info); gtk_notebook_append_page(GTK_NOTEBOOK(view), gm_world_view_world_page_new(view), label); } GtkWidget * gm_world_view_new(GmWorld *world) { GmWorldView *view = GM_WORLD_VIEW(g_object_new(GM_TYPE_WORLD_VIEW, NULL)); view->priv->world = g_object_ref(world); gm_world_input_view_set_history(view->priv->text_view_input, gm_world_history(view->priv->world)); g_signal_connect(world, "text_received", G_CALLBACK(on_gm_world_view_world_text_received), view); g_signal_connect(world, "world_error", G_CALLBACK(on_gm_world_view_world_error), view); g_signal_connect(world, "state_changing", G_CALLBACK(on_gm_world_view_world_state_changing), view); g_signal_connect(world, "notify::active", G_CALLBACK(on_gm_world_view_world_active_changed), view); g_signal_connect(world, "highlight", G_CALLBACK(on_gm_world_view_world_highlight), view); g_signal_connect(world, "editor_added", G_CALLBACK(on_gm_world_view_world_editor_added), view); g_signal_connect(world, "editor_removed", G_CALLBACK(on_gm_world_view_world_editor_removed), view); g_signal_connect(gm_world_get_mcp_session(world), "package_created", G_CALLBACK(on_gm_world_view_world_mcp_package_created), view); g_signal_connect(view->priv->text_view_input, "text_activate", G_CALLBACK(on_gm_world_input_view_world_text_activate), view); return GTK_WIDGET(view); } gboolean gm_world_view_text_active(GmWorldView *view) { return gtk_notebook_get_current_page(GTK_NOTEBOOK(view)) == 0; } gboolean gm_world_view_page_can_find(GmWorldView *view, gint page_num) { GtkWidget *page; GmSearchable *sea; if (page_num == -1) { return FALSE; } else if (page_num == 0) { return gm_searchable_can_find(GM_SEARCHABLE(view)); } else { page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(view), page_num); if (GM_IS_SEARCHABLE(page)) { sea = GM_SEARCHABLE(page); return gm_searchable_can_find(sea); } } return FALSE; } gboolean gm_world_view_can_find(GmWorldView *view) { gint np = gtk_notebook_get_current_page(GTK_NOTEBOOK(view)); return gm_world_view_page_can_find(view, np); } gboolean gm_world_view_find_first(GmWorldView *view, const gchar *str, GmSearchableSearchFlags flags) { gint np = gtk_notebook_get_current_page(GTK_NOTEBOOK(view)); GtkWidget *page; GmSearchable *sea; if (np == 0) { return gm_searchable_find_first(GM_SEARCHABLE(view), str, flags); } else { page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(view), np); if (GM_IS_SEARCHABLE(page)) { sea = GM_SEARCHABLE(page); if (gm_searchable_can_find(sea)) { return gm_searchable_find_first(sea, str, flags); } } } return FALSE; } gboolean gm_world_view_find_next(GmWorldView *view, const gchar *str, GmSearchableSearchFlags flags) { gint np = gtk_notebook_get_current_page(GTK_NOTEBOOK(view)); GtkWidget *page; GmSearchable *sea; if (np == 0) { return gm_searchable_find_next(GM_SEARCHABLE(view), str, flags); } else { page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(view), np); if (GM_IS_SEARCHABLE(page)) { sea = GM_SEARCHABLE(page); if (gm_searchable_can_find(sea)) { return gm_searchable_find_next(sea, str, flags); } } } return FALSE; } gboolean gm_world_view_replace(GmWorldView *view, gchar const *replace) { gint np = gtk_notebook_get_current_page(GTK_NOTEBOOK(view)); GtkWidget *page; GmSearchable *sea; if (np == 0) { return FALSE; } else { page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(view), np); if (GM_IS_SEARCHABLE(page)) { sea = GM_SEARCHABLE(page); if (gm_searchable_can_replace(sea)) { return gm_searchable_replace(sea, replace); } } } return FALSE; } gboolean gm_world_view_replace_all(GmWorldView *view, gchar const *str, gchar const *replace, GmSearchableSearchFlags flags) { gint np = gtk_notebook_get_current_page(GTK_NOTEBOOK(view)); GtkWidget *page; GmSearchable *sea; if (np == 0) { return FALSE; } else { page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(view), np); if (GM_IS_SEARCHABLE(page)) { sea = GM_SEARCHABLE(page); if (gm_searchable_can_replace(sea)) { return gm_searchable_replace_all(sea, str, replace, flags); } } } return FALSE; } gboolean gm_world_view_can_replace(GmWorldView *view) { gint np = gtk_notebook_get_current_page(GTK_NOTEBOOK(view)); return gm_world_view_page_can_replace(view, np); } gboolean gm_world_view_page_can_replace(GmWorldView *view, gint page_num) { GtkWidget *page; GmSearchable *sea; if (page_num == -1) { return FALSE; } else if (page_num == 0) { return gm_searchable_can_replace(GM_SEARCHABLE(view)); } else { page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(view), page_num); if (GM_IS_SEARCHABLE(page)) { sea = GM_SEARCHABLE(page); return gm_searchable_can_replace(sea); } } return FALSE; } GmWorld * gm_world_view_world(GmWorldView *view) { return view->priv->world; } GmWorldInputView * gm_world_view_input(GmWorldView *view) { return view->priv->text_view_input; } GmWorldTextView * gm_world_view_text_view(GmWorldView *view) { return view->priv->text_view_world; } GtkTextBuffer * gm_world_view_buffer(GmWorldView *view) { return gtk_text_view_get_buffer(GTK_TEXT_VIEW(view->priv->text_view_world)); } GtkHPaned * gm_world_view_hpaned(GmWorldView *view) { return view->priv->hpaned; } void gm_world_view_open_log(GmWorldView *view, const gchar *filename) { gm_world_view_log_page_new(view, filename); } void gm_world_view_set_userlist_width(GmWorldView *view, gint width) { gtk_paned_set_position(GTK_PANED(view->priv->hpaned), GTK_WIDGET(view->priv->hpaned)->allocation.width - width); } void gm_world_view_set_focus(GmWorldView *view) { gtk_widget_grab_focus(GTK_WIDGET(view->priv->text_view_input)); } void gm_world_view_change_font_size(GmWorldView *view, gint size_change) { GtkStyle *style = gtk_widget_get_style(GTK_WIDGET(view)); PangoFontDescription *desc = style->font_desc; PangoFontDescription *copy = pango_font_description_copy(desc); gchar *new_font; pango_font_description_set_size(copy, pango_font_description_get_size(copy) + (size_change * PANGO_SCALE)); new_font = pango_font_description_to_string(copy); gm_color_table_set_font_description(gm_app_color_table(gm_app_instance()), new_font); pango_font_description_free(copy); g_free(new_font); } /* Callbacks */ void on_gm_world_input_view_world_text_activate(GmWorldInputView *iview, gchar *text, GmWorldView *view) { gm_world_process_input(view->priv->world, text); gm_text_scroller_scroll_end(view->priv->text_scroller_world); } void on_gm_world_view_world_text_received(GmWorld *world, gchar *text, GmWorldView *view) { gchar *inserted = gm_world_text_view_insert(view->priv->text_view_world, text); g_free(inserted); } void on_gm_world_view_editor_save(GmEditor *editor, GmWorldView *view) { gtk_notebook_set_current_page(GTK_NOTEBOOK(view), 0); gtk_widget_grab_focus(GTK_WIDGET(view->priv->text_view_input)); } void on_gm_world_view_editor_view_close_clicked(GtkButton *button, GtkWidget *view) { // TODO: make this into an interface if (GM_IS_EDITOR_VIEW(view)) { gm_editor_close(gm_editor_view_editor(GM_EDITOR_VIEW(view))); } else if (GM_IS_EMBEDDED_VIEW(view)) { gm_editor_close(gm_embedded_view_editor(GM_EMBEDDED_VIEW(view))); } } void on_gm_world_view_log_view_close_clicked(GtkButton *button, GtkWidget *view) { gtk_widget_destroy(view); } void on_gm_world_view_editor_view_modified_changed(GmEditorView *editor_view, gboolean modified, GmWorldView *view) { gint i, n = gtk_notebook_get_n_pages(GTK_NOTEBOOK(view)); GtkWidget *page; GtkLabel *label; gchar *str; // Find this view then for (i = 1; i < n; ++i) { page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(view), i); if (GM_IS_EDITOR_VIEW(page) && GM_EDITOR_VIEW(page) == editor_view) { label = GTK_LABEL(gm_container_item(GTK_CONTAINER( gtk_notebook_get_tab_label(GTK_NOTEBOOK(view), page)), GTK_TYPE_LABEL)); if (!modified) { gtk_label_set_label(label, gm_editor_name(gm_editor_view_editor( GM_EDITOR_VIEW(page)))); } else { str = g_strconcat(gm_editor_name(gm_editor_view_editor( GM_EDITOR_VIEW(page))), "*", NULL); gtk_label_set_label(label, str); g_free(str); } } } } void on_gm_world_view_world_editor_added(GmWorld *world, GmEditor *editor, GmWorldView *view) { gm_world_view_editor_page_new(view, editor); g_signal_connect(editor, "save", G_CALLBACK(on_gm_world_view_editor_save), view); } void on_gm_world_view_world_editor_removed(GmWorld *world, GmEditor *editor, GmWorldView *view) { gint i, n = gtk_notebook_get_n_pages(GTK_NOTEBOOK(view)); GtkWidget *page; gboolean found = FALSE; GList *ext; for (i = 1; i < n; ++i) { page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(view), i); found = GM_IS_EDITOR_VIEW(page) && gm_editor_view_editor( GM_EDITOR_VIEW(page)) == editor; found = found || (GM_IS_EMBEDDED_VIEW(page) && gm_embedded_view_editor( GM_EMBEDDED_VIEW(page)) == editor); if (found) { g_signal_handlers_disconnect_by_func(editor, on_gm_world_view_editor_save, view); gtk_widget_destroy(page); gtk_notebook_set_current_page(GTK_NOTEBOOK(view), 0); gtk_widget_grab_focus(GTK_WIDGET(view->priv->text_view_input)); break; } } if (!found) { // Might be an external editor? for (ext = view->priv->external_editors; ext; ext = ext->next) { if ((GM_EXTERNAL_VIEW(ext->data))->editor == editor) { g_signal_handlers_disconnect_by_func(editor, on_gm_world_view_editor_save, view); gm_external_view_destroy(GM_EXTERNAL_VIEW(ext->data)); view->priv->external_editors = g_list_remove_link(view->priv->external_editors, ext); g_list_free_1(ext); break; } } } } void on_gm_world_view_world_error(GmWorld *world, gchar *text, gint code, GmWorldView *view) { gchar *line; switch (code) { case GM_NET_ERROR_CONNECTING: line = g_strdup_printf(_("# Connect failed: %s"), text); break; case GM_NET_ERROR_DISCONNECTED: line = g_strdup_printf(_("# Connection lost... (%s)"), text); break; default: line = g_strdup_printf(_("# Error: %s"), text); break; } gm_world_writeln(world, line); g_free(line); } void on_gm_world_view_world_state_changing(GmWorld *world, guint state, GmWorldView *view) { gchar *line = NULL; GmNetState pstate = gm_world_state(world); switch (state) { case GM_NET_STATE_TRY_ADDRESS: line = g_strdup_printf(_("# Trying %s port %s"), gm_world_current_host(world), gm_world_current_port(world)); break; case GM_NET_STATE_CONNECTING: line = g_strdup_printf(_("# Connecting to %s port %s"), gm_world_current_host(world), gm_world_current_port(world)); break; case GM_NET_STATE_CONNECTED: line = g_strdup(_("# Connected")); break; case GM_NET_STATE_DISCONNECTED: if (pstate == GM_NET_STATE_CONNECTED || pstate == GM_NET_STATE_DISCONNECTING) { line = g_strdup(_("# Disconnected")); } gm_world_view_update_status(view, NULL); break; case GM_NET_STATE_DISCONNECTING: line = g_strdup(_("# Disconnecting")); break; default: break; } if (line) { gm_world_writeln(world, line); g_free(line); } } void on_gm_world_view_world_active_changed(GmWorld *world, GParamSpec *pspec, GmWorldView *view) { if (gm_world_active(world)) { gtk_widget_grab_focus(GTK_WIDGET(view->priv->text_view_input)); } } void on_gm_world_view_world_highlight(GmWorld *world, gint start, gint end, gchar *color, GmWorldView *view) { GtkTextIter istart, iend; GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(view->priv->text_view_world)); gtk_text_buffer_get_end_iter(buffer, &iend); istart = iend; gtk_text_iter_backward_line(&istart); if (start != -1) { gtk_text_iter_forward_chars(&istart, start); iend = istart; gtk_text_iter_forward_chars(&iend, end); } gtk_text_buffer_apply_tag_by_name(buffer, color, &istart, &iend); } gboolean on_gm_world_view_world_text_view_scroll_event(GmWorldView *view, GdkEventScroll *event, GmWorldTextView *text) { if (event->state & GDK_CONTROL_MASK) { switch (event->direction) { case GDK_SCROLL_UP: // Decrease font size gm_world_view_change_font_size(view, -1); break; case GDK_SCROLL_DOWN: // Increase font size gm_world_view_change_font_size(view, 1); break; default: break; } return TRUE; } else { return FALSE; } return FALSE; } gboolean on_gm_world_view_world_input_view_key_pressed(GtkWidget *widget, GdkEventKey *event, GmWorldView *view) { switch (event->keyval) { case GDK_Home: case GDK_End: if ((event->state | GDK_CONTROL_MASK) == event->state) { if (event->keyval == GDK_End) { gm_text_scroller_scroll_end( view->priv->text_scroller_world); } else { gm_text_scroller_scroll_begin( view->priv->text_scroller_world); } return TRUE; } break; case GDK_Page_Up: case GDK_Page_Down: if (!(event->state & GDK_CONTROL_MASK && !(event->state & GDK_SHIFT_MASK))) { if (event->keyval == GDK_Page_Up) { gm_text_scroller_scroll_page( view->priv->text_scroller_world, -1); } else { gm_text_scroller_scroll_page( view->priv->text_scroller_world, 1); } return TRUE; } default: break; } return FALSE; } void on_gm_world_view_world_mcp_package_created(GmMcpSession *session, GmMcpPackage *package, GmWorldView *view) { gm_mcp_package_create_view(package, G_OBJECT(view)); } void on_gm_world_view_world_text_view_url_activate(GmWorldView *view, gchar const *url) { gm_open_url(url); }