static void inf_adopted_session_create_algorithm(InfAdoptedSession* session) { InfAdoptedSessionPrivate* priv; priv = INF_ADOPTED_SESSION_PRIVATE(session); g_assert(priv->algorithm == NULL); g_assert( inf_session_get_status(INF_SESSION(session)) == INF_SESSION_RUNNING ); priv->algorithm = inf_adopted_algorithm_new_full( inf_session_get_user_table(INF_SESSION(session)), inf_session_get_buffer(INF_SESSION(session)), priv->max_total_log_size ); g_signal_connect( G_OBJECT(priv->algorithm), "execute-request", G_CALLBACK(inf_adopted_session_execute_request_cb), session ); g_object_notify(G_OBJECT(session), "algorithm"); }
/* Breadcasts a request N times - makes only sense for undo and redo requests, * so that's the only thing we offer API for. */ static void inf_adopted_session_broadcast_n_requests(InfAdoptedSession* session, InfAdoptedRequest* request, guint n) { InfAdoptedSessionPrivate* priv; InfAdoptedSessionClass* session_class; InfUserTable* user_table; guint user_id; InfUser* user; InfAdoptedSessionLocalUser* local; xmlNodePtr xml; priv = INF_ADOPTED_SESSION_PRIVATE(session); session_class = INF_ADOPTED_SESSION_GET_CLASS(session); g_assert(session_class->request_to_xml != NULL); user_table = inf_session_get_user_table(INF_SESSION(session)); user_id = inf_adopted_request_get_user_id(request); user = inf_user_table_lookup_user_by_id(user_table, user_id); g_assert(user != NULL); local = inf_adopted_session_lookup_local_user( session, INF_ADOPTED_USER(user) ); g_assert(local != NULL); xml = xmlNewNode(NULL, (const xmlChar*)"request"); session_class->request_to_xml( session, xml, request, local->last_send_vector, FALSE ); if(n > 1) inf_xml_util_set_attribute_uint(xml, "num", n); inf_session_send_to_subscriptions(INF_SESSION(session), xml); inf_adopted_state_vector_free(local->last_send_vector); local->last_send_vector = inf_adopted_state_vector_copy( inf_adopted_request_get_vector(request) ); /* Add this request to last send vector if it increases vector time * (-> affects buffer). */ if(inf_adopted_request_affects_buffer(request) == TRUE) inf_adopted_state_vector_add(local->last_send_vector, user_id, n); inf_adopted_session_stop_noop_timer(session, local); }
/* Note plugin implementation */ static InfSession* infinoted_plugin_note_text_session_new(InfIo* io, InfCommunicationManager* manager, InfSessionStatus status, InfCommunicationGroup* sync_group, InfXmlConnection* sync_connection, const gchar* path, gpointer user_data) { InfTextSession* session; InfTextBuffer* buffer; buffer = INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8")); session = inf_text_session_new( manager, buffer, io, status, sync_group, sync_connection ); g_object_unref(buffer); return INF_SESSION(session); }
static InfAdoptedUser* inf_adopted_session_user_from_request_xml(InfAdoptedSession* session, xmlNodePtr xml, GError** error) { InfUserTable* user_table; InfUser* user; guint user_id; user_table = inf_session_get_user_table(INF_SESSION(session)); if(!inf_xml_util_get_attribute_uint_required(xml, "user", &user_id, error)) return FALSE; /* User ID 0 means no user */ if(user_id == 0) return NULL; user = inf_user_table_lookup_user_by_id(user_table, user_id); if(user == NULL) { g_set_error( error, inf_adopted_session_error_quark, INF_ADOPTED_SESSION_ERROR_NO_SUCH_USER, _("No such user with user ID '%u'"), user_id ); return NULL; } g_assert(INF_ADOPTED_IS_USER(user)); return INF_ADOPTED_USER(user); }
/* Note plugin implementation */ static InfSession* infinoted_plugin_note_chat_session_new(InfIo* io, InfCommunicationManager* manager, InfSessionStatus status, InfCommunicationGroup* sync_group, InfXmlConnection* sync_connection, const gchar* path, gpointer user_data) { InfChatBuffer* buffer; InfChatSession* session; buffer = inf_chat_buffer_new(256); session = inf_chat_session_new( manager, buffer, status, INF_COMMUNICATION_GROUP(sync_group), sync_connection ); g_object_unref(buffer); return INF_SESSION(session); }
static InfSession* inf_test_gtk_browser_session_new(InfIo* io, InfConnectionManager* manager, InfConnectionManagerGroup* sync_group, InfXmlConnection* sync_connection, gpointer user_data) { InfTextGtkBuffer* buffer; InfUserTable* user_table; GtkTextBuffer* textbuffer; InfTextSession* session; textbuffer = gtk_text_buffer_new(NULL); user_table = inf_user_table_new(); buffer = inf_text_gtk_buffer_new(textbuffer, user_table); session = inf_text_session_new_with_user_table( manager, INF_TEXT_BUFFER(buffer), io, user_table, sync_group, sync_connection ); return INF_SESSION(session); }
static void inf_adopted_session_dispose(GObject* object) { InfAdoptedSession* session; InfAdoptedSessionPrivate* priv; InfUserTable* user_table; session = INF_ADOPTED_SESSION(object); priv = INF_ADOPTED_SESSION_PRIVATE(session); user_table = inf_session_get_user_table(INF_SESSION(session)); inf_signal_handlers_disconnect_by_func( G_OBJECT(user_table), G_CALLBACK(inf_adopted_session_add_local_user_cb), session ); inf_signal_handlers_disconnect_by_func( G_OBJECT(user_table), G_CALLBACK(inf_adopted_session_remove_local_user_cb), session ); if(priv->noop_timeout != NULL) { inf_io_remove_timeout(priv->io, priv->noop_timeout); priv->noop_timeout = NULL; } /* This calls the close vfunc if the session is running, in which we * free the local users. */ G_OBJECT_CLASS(parent_class)->dispose(object); g_assert(priv->local_users == NULL); if(priv->algorithm != NULL) { inf_signal_handlers_disconnect_by_func( G_OBJECT(priv->algorithm), G_CALLBACK(inf_adopted_session_execute_request_cb), session ); g_object_unref(G_OBJECT(priv->algorithm)); priv->algorithm = NULL; } if(priv->io != NULL) { g_object_unref(G_OBJECT(priv->io)); priv->io = NULL; } }
void Gobby::ChatSessionView::set_active_user(InfUser* user) { g_assert( user == NULL || inf_user_table_lookup_user_by_id( inf_session_get_user_table(INF_SESSION(m_session)), inf_user_get_id(INF_USER(user))) == INF_USER(user)); inf_gtk_chat_set_active_user(m_chat, user); active_user_changed(user); }
Gobby::ChatSessionView::ChatSessionView(InfChatSession* session, const Glib::ustring& title, const Glib::ustring& path, const Glib::ustring& hostname, Preferences& preferences): SessionView(INF_SESSION(session), title, path, hostname), m_preferences(preferences), m_chat(INF_GTK_CHAT(inf_gtk_chat_new())) { inf_gtk_chat_set_session(m_chat, session); gtk_widget_show(GTK_WIDGET(m_chat)); gtk_box_pack_start(GTK_BOX(gobj()), GTK_WIDGET(m_chat), TRUE, TRUE, 0); }
Gobby::TextTabLabel::~TextTabLabel() { TextSessionView& text_view = dynamic_cast<TextSessionView&>(m_view); g_signal_handler_disconnect(text_view.get_text_buffer(), m_modified_changed_handle); InfTextBuffer* buffer = INF_TEXT_BUFFER( inf_session_get_buffer( INF_SESSION(m_view.get_session()))); g_signal_handler_disconnect(buffer, m_erase_text_handle); g_signal_handler_disconnect(buffer, m_insert_text_handle); }
static void infc_session_proxy_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) { InfcSessionProxy* proxy; InfcSessionProxyPrivate* priv; proxy = INFC_SESSION_PROXY(object); priv = INFC_SESSION_PROXY_PRIVATE(proxy); switch(prop_id) { case PROP_SESSION: g_assert(priv->session == NULL); /* construct only */ priv->session = INF_SESSION(g_value_dup_object(value)); g_signal_connect( G_OBJECT(priv->session), "close", G_CALLBACK(infc_session_proxy_session_close_cb), proxy ); g_signal_connect( G_OBJECT(priv->session), "synchronization-complete", G_CALLBACK(infc_session_proxy_session_synchronization_complete_cb), proxy ); g_signal_connect( G_OBJECT(priv->session), "synchronization-failed", G_CALLBACK(infc_session_proxy_session_synchronization_failed_cb), proxy ); break; case PROP_SUBSCRIPTION_GROUP: case PROP_CONNECTION: /* these are read-only because they can only be changed both at once, * refer to infc_session_proxy_set_connection(). */ default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } }
bool on_activation_timeout() { // The user activated this document, but did not something for // a while, so explicitely set the user active g_assert(m_active); g_assert(m_active_user != NULL); g_assert(inf_user_get_status(m_active_user) == INF_USER_INACTIVE); inf_session_set_user_status( INF_SESSION(m_view.get_session()), m_active_user, INF_USER_ACTIVE); return false; }
static InfSession* infinoted_plugin_note_text_session_read(InfdStorage* storage, InfIo* io, InfCommunicationManager* manager, const gchar* path, gpointer user_data, GError** error) { InfUserTable* user_table; InfTextBuffer* buffer; gboolean result; InfTextSession* session; g_assert(INFD_IS_FILESYSTEM_STORAGE(storage)); user_table = inf_user_table_new(); buffer = INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8")); result = inf_text_filesystem_format_read( INFD_FILESYSTEM_STORAGE(storage), path, user_table, buffer, error ); if(result == FALSE) { g_object_unref(user_table); g_object_unref(buffer); return NULL; } session = inf_text_session_new_with_user_table( manager, buffer, io, user_table, INF_SESSION_RUNNING, NULL, NULL ); g_object_unref(user_table); g_object_unref(buffer); return INF_SESSION(session); }
void Gobby::TextTabLabel::update_modified() { InfSession* session = INF_SESSION(m_view.get_session()); bool modified = inf_buffer_get_modified(inf_session_get_buffer(session)); InfSessionStatus status = inf_session_get_status(session); if(status == INF_SESSION_SYNCHRONIZING || status == INF_SESSION_PRESYNC) { modified = false; } if(modified) m_title.set_text("*" + m_view.get_title()); else m_title.set_text(m_view.get_title()); }
void Gobby::ViewCommands::on_hide_user_colors() { SessionView* view = m_text_folder.get_current_document(); TextSessionView* text_view = dynamic_cast<TextSessionView*>(view); g_assert(text_view != NULL); InfSession* session = INF_SESSION(text_view->get_session()); GtkTextBuffer* textbuffer = GTK_TEXT_BUFFER(text_view->get_text_buffer()); InfBuffer* buffer = inf_session_get_buffer(session); InfTextGtkBuffer* infbuffer = INF_TEXT_GTK_BUFFER(buffer); GtkTextIter start, end; gtk_text_buffer_get_start_iter(textbuffer, &start); gtk_text_buffer_get_end_iter(textbuffer, &end); inf_text_gtk_buffer_show_user_colors(infbuffer, FALSE, &start, &end); }
void Gobby::TextTabLabel::on_changed(InfTextUser* author) { if(!m_changed) { InfSession* session = INF_SESSION(m_view.get_session()); if(inf_session_get_status(session) == INF_SESSION_RUNNING) set_changed(); } if(m_folder.get_current_document() != &m_view) { // TODO: remove dot if all the user's // new contributions where undone if(std::find(m_changed_by.begin(), m_changed_by.end(), author) == m_changed_by.end()) { m_changed_by.push_back(UserWatcher(this, author)); update_dots(); } } }
static InfSession* infd_note_plugin_text_session_new(InfIo* io, InfCommunicationManager* manager, InfSessionStatus status, InfCommunicationHostedGroup* sync_group, InfXmlConnection* sync_connection, gpointer user_data) { InfTextSession* session; session = inf_text_session_new( manager, INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8")), io, status, INF_COMMUNICATION_GROUP(sync_group), sync_connection ); return INF_SESSION(session); }
static void inf_adopted_session_local_user_added(InfAdoptedSession* session, InfAdoptedUser* user) { InfAdoptedSessionPrivate* priv; InfSessionStatus status; InfAdoptedSessionLocalUser* local; InfAdoptedStateVector* current_state; priv = INF_ADOPTED_SESSION_PRIVATE(session); status = inf_session_get_status(INF_SESSION(session)); /* Cannot be local while synchronizing */ g_assert(status == INF_SESSION_RUNNING); local = g_slice_new(InfAdoptedSessionLocalUser); local->user = user; local->last_send_vector = inf_adopted_state_vector_copy( inf_adopted_user_get_vector(user) ); /* Set current vector for local user, this is kept up-to-date by * InfAdoptedAlgorithm. TODO: Also do this in InfAdoptedAlgorithm? */ inf_adopted_user_set_vector( user, inf_adopted_state_vector_copy( inf_adopted_algorithm_get_current(priv->algorithm) ) ); local->noop_time = 0; priv->local_users = g_slist_prepend(priv->local_users, local); /* Start noop timer if user is not up to date */ current_state = inf_adopted_algorithm_get_current(priv->algorithm); if(inf_adopted_state_vector_compare(current_state, local->last_send_vector)) inf_adopted_session_start_noop_timer(session, local); }
void Gobby::TabLabel::update_icon() { InfSession* session = INF_SESSION(m_view.get_session()); if(inf_session_get_subscription_group(session) == NULL) { m_icon.set_from_icon_name("network-offline", Gtk::ICON_SIZE_MENU); } else { switch(inf_session_get_status(session)) { case INF_SESSION_PRESYNC: case INF_SESSION_SYNCHRONIZING: // TODO: Switch to process-working, if/when m_icon can // show animations. m_icon.set_from_icon_name("system-run", Gtk::ICON_SIZE_MENU); break; case INF_SESSION_RUNNING: if(m_view.get_active_user() != NULL) { m_icon.set_from_icon_name(m_active_icon_name, Gtk::ICON_SIZE_MENU); } else { m_icon.set_from_icon_name("text-x-generic", Gtk::ICON_SIZE_MENU); } break; case INF_SESSION_CLOSED: m_icon.set_from_icon_name("network-offline", Gtk::ICON_SIZE_MENU); break; } } }
static InfSession* infinoted_plugin_note_chat_session_read(InfdStorage* storage, InfIo* io, InfCommunicationManager* manager, const gchar* path, gpointer user_data, GError** error) { InfChatBuffer* buffer; gboolean result; InfChatSession* session; g_assert(INFD_IS_FILESYSTEM_STORAGE(storage)); buffer = inf_chat_buffer_new(256); result = infd_chat_filesystem_format_read( INFD_FILESYSTEM_STORAGE(storage), path, buffer, error ); if(result == FALSE) { g_object_unref(buffer); return NULL; } session = inf_chat_session_new( manager, buffer, INF_SESSION_RUNNING, NULL, NULL ); g_object_unref(buffer); return INF_SESSION(session); }
void Gobby::TabLabel::update_color() { InfSession* session = INF_SESSION(m_view.get_session()); if(m_changed) { // Document has changed: awareness -> red m_title.override_color(Gdk::RGBA("#c00000")); } else if(inf_session_get_subscription_group(session) == NULL || inf_session_get_status(session) != INF_SESSION_RUNNING) { // Document disconnected or not yet running // (most probably synchronizing): not (yet) available -> grey m_title.override_color(Gdk::RGBA("#606060")); } else { // Otherwise default m_title.unset_color(); } }
Gobby::TextTabLabel::TextTabLabel(Folder& folder, TextSessionView& view): TabLabel(folder, view, Gtk::Stock::EDIT), m_dot_char(0) { update_modified(); update_dots(); m_modified_changed_handle = g_signal_connect_after( G_OBJECT(view.get_text_buffer()), "modified-changed", G_CALLBACK(on_modified_changed_static), this); InfTextBuffer* buffer = INF_TEXT_BUFFER( inf_session_get_buffer( INF_SESSION(view.get_session()))); m_insert_text_handle = g_signal_connect_after( G_OBJECT(buffer), "text-inserted", G_CALLBACK(on_text_inserted_static), this); m_erase_text_handle = g_signal_connect_after( G_OBJECT(buffer), "text-erased", G_CALLBACK(on_text_erased_static), this); m_extra.pack_start(m_dots, Gtk::PACK_SHRINK); }
void deactivate_user() { g_assert(m_active_user != NULL); switch(inf_user_get_status(m_active_user)) { case INF_USER_INACTIVE: g_assert(m_timeout_connection.connected()); m_timeout_connection.disconnect(); break; case INF_USER_ACTIVE: /* Flush pending requests, so user is not set active * again later. TODO: Maybe this should become a * virtual function in InfSession actually. */ flush(); inf_session_set_user_status( INF_SESSION(m_view.get_session()), m_active_user, INF_USER_INACTIVE); break; case INF_USER_UNAVAILABLE: // It can happen that the user is already unavailable // here, for example when we have lost the connection // to the server, so this is not an error. // If the user was active before we lost the // connection then cancel the activation timeout if(m_timeout_connection.connected()) m_timeout_connection.disconnect(); // TODO: Shouldn't local users stay available on // connection loss? We probably need to fix this // in infinote. break; } }
static GObject* inf_adopted_session_constructor(GType type, guint n_construct_properties, GObjectConstructParam* construct_properties) { GObject* object; InfAdoptedSession* session; InfAdoptedSessionPrivate* priv; InfSessionStatus status; InfUserTable* user_table; object = G_OBJECT_CLASS(parent_class)->constructor( type, n_construct_properties, construct_properties ); session = INF_ADOPTED_SESSION(object); priv = INF_ADOPTED_SESSION_PRIVATE(session); g_assert(priv->io != NULL); g_object_get(G_OBJECT(session), "status", &status, NULL); user_table = inf_session_get_user_table(INF_SESSION(session)); g_signal_connect( G_OBJECT(user_table), "add-local-user", G_CALLBACK(inf_adopted_session_add_local_user_cb), session ); g_signal_connect( G_OBJECT(user_table), "remove-local-user", G_CALLBACK(inf_adopted_session_remove_local_user_cb), session ); switch(status) { case INF_SESSION_PRESYNC: case INF_SESSION_SYNCHRONIZING: /* algorithm is created during initial synchronization when parameters * like initial vector time, max total log size etc. are known. */ break; case INF_SESSION_RUNNING: g_assert(inf_session_get_buffer(INF_SESSION(session)) != NULL); inf_adopted_session_create_algorithm(session); break; case INF_SESSION_CLOSED: /* Session should not be initially closed */ default: g_assert_not_reached(); break; } /* Add initial local users. Note that this requires the algorithm to exist, * though in synchronizing state no local users can exist. */ inf_user_table_foreach_local_user( user_table, inf_adopted_session_constructor_foreach_local_user_func, session ); return object; }
static InfSession* infd_note_plugin_text_session_read(InfdStorage* storage, InfIo* io, InfCommunicationManager* manager, const gchar* path, gpointer user_data, GError** error) { InfUserTable* user_table; InfTextBuffer* buffer; InfTextSession* session; FILE* stream; xmlDocPtr doc; xmlErrorPtr xmlerror; xmlNodePtr root; xmlNodePtr child; gboolean result; g_assert(INFD_IS_FILESYSTEM_STORAGE(storage)); user_table = inf_user_table_new(); buffer = INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8")); /* TODO: Use a SAX parser for better performance */ stream = infd_filesystem_storage_open( INFD_FILESYSTEM_STORAGE(storage), "InfText", path, "r", error ); if(stream == NULL) return FALSE; doc = xmlReadIO( infd_note_plugin_text_session_read_read_func, infd_note_plugin_text_sesison_read_close_func, stream, path, /* TODO: Get some "infinote-filesystem-storage://" URL? */ "UTF-8", XML_PARSE_NOWARNING | XML_PARSE_NOERROR ); if(doc == NULL) { xmlerror = xmlGetLastError(); g_set_error( error, g_quark_from_static_string("LIBXML2_PARSER_ERROR"), xmlerror->code, "Error parsing XML in file '%s': [%d]: %s", path, xmlerror->line, xmlerror->message ); result = FALSE; } else { root = xmlDocGetRootElement(doc); if(strcmp((const char*)root->name, "inf-text-session") != 0) { g_set_error( error, g_quark_from_static_string("INF_NOTE_PLUGIN_TEXT_ERROR"), INFD_NOTE_PLUGIN_TEXT_ERROR_NOT_A_TEXT_SESSION, "Error processing file '%s': %s", path, "The document is not a text session" ); result = FALSE; } else { for(child = root->children; child != NULL; child = child->next) { if(child->type != XML_ELEMENT_NODE) continue; if(strcmp((const char*)child->name, "user") == 0) { if(!infd_note_plugin_text_read_user(user_table, child, error)) { g_prefix_error(error, "Error processing file '%s': ", path); result = FALSE; break; } } else if(strcmp((const char*)child->name, "buffer") == 0) { if(!infd_note_plugin_text_read_buffer(buffer, user_table, child, error)) { g_prefix_error(error, "Error processing file '%s': ", path); result = FALSE; break; } } else { infd_note_plugin_text_session_unexpected_node(child, error); g_prefix_error(error, "Error processing file '%s': ", path); result = FALSE; break; } } if(child == NULL) result = TRUE; } xmlFreeDoc(doc); } if(result == FALSE) return NULL; session = inf_text_session_new_with_user_table( manager, buffer, io, user_table, INF_SESSION_RUNNING, NULL, NULL ); return INF_SESSION(session); }
int main(int argc, char* argv[]) { InfAdoptedSessionReplay* replay; InfAdoptedSession* session; GError* error; int i; int ret; InfBuffer* buffer; GSList* item; gint counter; if(argc < 2) { fprintf(stderr, "Usage: %s <record-file> [index]\n", argv[0]); return -1; } counter = 0; if(argc > 2) counter = atoi(argv[2]); error = NULL; if(!inf_init(&error)) { fprintf(stderr, "%s\n", error->message); g_error_free(error); return -1; } ret = 0; for(i = 1; i < 2; ++ i) { replay = inf_adopted_session_replay_new(); inf_adopted_session_replay_set_record( replay, argv[i], &INF_TEST_TEXT_RECOVER_TEXT_PLUGIN, &error ); if(error != NULL) { fprintf(stderr, "%s\n", error->message); g_error_free(error); error = NULL; ret = -1; } else { session = inf_adopted_session_replay_get_session(replay); buffer = inf_session_get_buffer(INF_SESSION(session)); g_signal_connect( buffer, "text-erased", G_CALLBACK(inf_test_text_recover_text_erased_cb), &counter ); if(!inf_adopted_session_replay_play_to_end(replay, &error)) { fprintf(stderr, "%s\n", error->message); g_error_free(error); error = NULL; ret = -1; } else if(counter == 0) { inf_test_util_print_buffer(INF_TEXT_BUFFER(buffer)); } } g_object_unref(replay); } return ret; }
void Gobby::OperationOpen::read_finish() { // If the last character is a newline character, remove it. GtkTextIter end_iter, test_iter; gtk_text_buffer_get_end_iter(m_content, &end_iter); test_iter = end_iter; if(gtk_text_iter_backward_char(&test_iter)) { if(gtk_text_iter_get_char(&test_iter) == '\n') { gtk_text_buffer_delete( m_content, &test_iter, &end_iter); } } gtk_text_buffer_set_modified(m_content, FALSE); GtkTextIter insert_iter; GtkTextMark* insert = gtk_text_buffer_get_insert(m_content); gtk_text_buffer_get_iter_at_mark(m_content, &insert_iter, insert); InfUser* user = INF_USER(g_object_new( INF_TEXT_TYPE_USER, "id", 1, "flags", INF_USER_LOCAL, "name", m_preferences.user.name.get().c_str(), /* The user is made active when the user * switches to the document. */ "status", INF_USER_INACTIVE, "hue", m_preferences.user.hue.get(), "caret-position", gtk_text_iter_get_offset(&insert_iter), static_cast<void*>(NULL))); InfUserTable* user_table = inf_user_table_new(); inf_user_table_add_user(user_table, user); g_object_unref(user); InfTextGtkBuffer* text_gtk_buffer = inf_text_gtk_buffer_new(m_content, user_table); g_object_unref(user_table); ConnectionManager& connection_manager = get_browser().get_connection_manager(); InfCommunicationManager* communication_manager = connection_manager.get_communication_manager(); InfBrowser* browser = m_parent.get_browser(); InfIo* io; g_object_get(G_OBJECT(browser), "io", &io, NULL); InfTextSession* session = inf_text_session_new_with_user_table( communication_manager, INF_TEXT_BUFFER(text_gtk_buffer), io, user_table, INF_SESSION_RUNNING, NULL, NULL); g_object_unref(io); g_object_unref(text_gtk_buffer); InfRequest* request = inf_browser_add_note( m_parent.get_browser(), m_parent.get_browser_iter(), m_name.c_str(), "InfText", NULL, INF_SESSION(session), TRUE, on_request_finished_static, this); g_object_unref(session); if(request != NULL) { m_request = request; g_object_ref(m_request); // TODO: We can remove the node watch here, but need to have // the browser available in on_request_finished then. Maybe // just disconnect the signal, or bind it. } }
void Gobby::EditCommands::on_document_changed(SessionView* view) { if(m_current_view != NULL) { InfTextSession* session = m_current_view->get_session(); InfAdoptedAlgorithm* algorithm = inf_adopted_session_get_algorithm( INF_ADOPTED_SESSION(session)); GtkTextBuffer* buffer = GTK_TEXT_BUFFER( m_current_view->get_text_buffer()); if(m_synchronization_complete_handler != 0) { g_signal_handler_disconnect( G_OBJECT(session), m_synchronization_complete_handler); } else { g_signal_handler_disconnect( G_OBJECT(algorithm), m_can_undo_changed_handler); g_signal_handler_disconnect( G_OBJECT(algorithm), m_can_redo_changed_handler); } g_signal_handler_disconnect(G_OBJECT(buffer), m_mark_set_handler); g_signal_handler_disconnect(G_OBJECT(buffer), m_changed_handler); m_active_user_changed_connection.disconnect(); } m_current_view = dynamic_cast<TextSessionView*>(view); if(m_current_view != NULL) { InfTextSession* session = m_current_view->get_session(); InfUser* active_user = m_current_view->get_active_user(); GtkTextBuffer* buffer = GTK_TEXT_BUFFER(m_current_view->get_text_buffer()); m_active_user_changed_connection = m_current_view->signal_active_user_changed().connect( sigc::mem_fun( *this, &EditCommands:: on_active_user_changed)); m_mark_set_handler = g_signal_connect_after( G_OBJECT(buffer), "mark-set", G_CALLBACK(&on_mark_set_static), this); // The selection might change without mark-set being emitted // when the document changes, for example when all // currently selected text is deleted. m_changed_handler = g_signal_connect_after( G_OBJECT(buffer), "changed", G_CALLBACK(&on_changed_static), this); if(inf_session_get_status(INF_SESSION(session)) == INF_SESSION_RUNNING) { // This connects to can-undo-changed and // can-redo-changed of the algorithm. Set // m_synchronization_complete_handler to zero so that // the function does not try to disconnect from it. m_synchronization_complete_handler = 0; on_sync_complete(); } else { // The InfAdoptedSession is created after // synchronization, so we wait until that finished. m_synchronization_complete_handler = g_signal_connect_after( G_OBJECT(session), "synchronization_complete", G_CALLBACK(&on_sync_complete_static), this); m_can_undo_changed_handler = 0; m_can_redo_changed_handler = 0; } // Set initial sensitivity for active user: on_active_user_changed(active_user); // Set initial sensitivity for cut/copy/paste: on_mark_set(); // Set initial sensitivity for find/replace/goto: m_header.action_edit_find->set_sensitive(true); if(m_find_dialog.get()) { on_find_text_changed(); } else { m_header.action_edit_find_next->set_sensitive(false); m_header.action_edit_find_prev->set_sensitive(false); } m_header.action_edit_find_replace->set_sensitive(true); m_header.action_edit_goto_line->set_sensitive(true); } else { m_header.action_edit_undo->set_sensitive(false); m_header.action_edit_redo->set_sensitive(false); m_header.action_edit_cut->set_sensitive(false); m_header.action_edit_copy->set_sensitive(false); m_header.action_edit_paste->set_sensitive(false); m_header.action_edit_find->set_sensitive(false); m_header.action_edit_find_next->set_sensitive(false); m_header.action_edit_find_prev->set_sensitive(false); m_header.action_edit_find_replace->set_sensitive(false); m_header.action_edit_goto_line->set_sensitive(false); } }