/** * inf_text_gtk_viewport_set_active_user: * @viewport: A #InfTextGtkViewport. * @user: A user from @viewport's user table, or %NULL. * * Sets the user for which perspective to draw the viewport. The cursor * position for teh active user is not draws since it is assumed that the * viewport's "real" scrollbars match the active user's position. */ void inf_text_gtk_viewport_set_active_user(InfTextGtkViewport* viewport, InfTextUser* user) { InfTextGtkViewportPrivate* priv; InfTextUser* active_user; g_return_if_fail(INF_TEXT_GTK_IS_VIEWPORT(viewport)); g_return_if_fail(user == NULL || INF_TEXT_IS_USER(user)); priv = INF_TEXT_GTK_VIEWPORT_PRIVATE(viewport); g_return_if_fail( user == NULL || inf_user_table_lookup_user_by_id( priv->user_table, inf_user_get_id(INF_USER(user)) ) == INF_USER(user) ); if(priv->active_user != NULL) { active_user = priv->active_user; priv->active_user = NULL; inf_text_gtk_viewport_user_added(viewport, active_user); } if(user != NULL) { inf_text_gtk_viewport_user_removed(viewport, user); } priv->active_user = user; g_object_notify(G_OBJECT(viewport), "active-user"); }
/** * inf_text_buffer_insert_text: * @buffer: A #InfTextBuffer. * @pos: A character offset into @buffer. * @text (type=guint8*) (array length=bytes) (transfer none): A pointer to * the text to insert. * @len: The length (in characters) of @text. * @bytes: The length (in bytes) of @text. * @user: (allow-none): A #InfUser that has inserted the new text, or %NULL. * * Inserts @text into @buffer as written by @author. @text must be encoded in * the character encoding of the buffer, see inf_text_buffer_get_encoding(). **/ void inf_text_buffer_insert_text(InfTextBuffer* buffer, guint pos, gconstpointer text, gsize bytes, guint len, InfUser* user) { InfTextBufferInterface* iface; InfTextChunk* chunk; g_return_if_fail(INF_TEXT_IS_BUFFER(buffer)); g_return_if_fail(text != NULL); g_return_if_fail(user == NULL || INF_IS_USER(user)); iface = INF_TEXT_BUFFER_GET_IFACE(buffer); g_return_if_fail(iface->insert_text != NULL); chunk = inf_text_chunk_new(inf_text_buffer_get_encoding(buffer)); inf_text_chunk_insert_text( chunk, 0, text, bytes, len, user == NULL ? 0 : inf_user_get_id(user) ); iface->insert_text(buffer, pos, chunk, user); inf_text_chunk_free(chunk); }
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); }
static void inf_adopted_session_execute_request_cb(InfAdoptedAlgorithm* algorithm, InfAdoptedUser* user, InfAdoptedRequest* request, gboolean apply, gpointer user_data) { InfAdoptedSession* session; InfAdoptedSessionPrivate* priv; GSList* item; InfAdoptedSessionLocalUser* local; guint id; session = INF_ADOPTED_SESSION(user_data); priv = INF_ADOPTED_SESSION_PRIVATE(session); if(inf_adopted_request_affects_buffer(request)) { id = inf_adopted_request_get_user_id(request); /* A request has been executed, meaning we are no longer up to date. Send * a noop in some time, so that others know what we already processed. */ for(item = priv->local_users; item != NULL; item = g_slist_next(item)) { local = (InfAdoptedSessionLocalUser*)item->data; if(local->noop_time == 0) /* Except we issued the request ourselves, of course. */ if(inf_user_get_id(INF_USER(local->user)) != id) inf_adopted_session_start_noop_timer(session, local); } } /* Mark inactive users active if they do something */ /* Note: This behaviour is implicitly performed by both client and server, * and requires no further network traffic. However, users explictely have * to be set inactive. */ if(inf_adopted_request_get_request_type(request) != INF_ADOPTED_REQUEST_DO || !INF_ADOPTED_IS_NO_OPERATION(inf_adopted_request_get_operation(request))) { /* TODO: We should offer a virtual function to flush all requests for * local users, either here or even in InfSession via a vfunc, so that * we don't accidentally make local users active by a delayed request. */ if(inf_user_get_status(INF_USER(user)) == INF_USER_INACTIVE) g_object_set(G_OBJECT(user), "status", INF_USER_ACTIVE, NULL); } }
static void infd_note_plugin_text_session_write_foreach_user_func(InfUser* user, gpointer user_data) { xmlNodePtr parent; xmlNodePtr node; parent = (xmlNodePtr)user_data; node = xmlNewChild(parent, NULL, (const xmlChar*)"user", NULL); inf_xml_util_set_attribute_uint(node, "id", inf_user_get_id(user)); inf_xml_util_set_attribute(node, "name", inf_user_get_name(user)); inf_xml_util_set_attribute_double( node, "hue", inf_text_user_get_hue(INF_TEXT_USER(user)) ); }
static void inf_adopted_session_synchronization_complete_foreach_user_func(InfUser* user, gpointer data) { InfAdoptedRequestLog* log; log = inf_adopted_user_get_request_log(INF_ADOPTED_USER(user)); /* Set begin index of empty request logs. Algorithm relies on * inf_adopted_request_log_get_begin() to return the index of the request * that will first be added to the request log. */ if(inf_adopted_request_log_is_empty(log)) { inf_adopted_request_log_set_begin( log, inf_adopted_state_vector_get( inf_adopted_user_get_vector(INF_ADOPTED_USER(user)), inf_user_get_id(user) ) ); } }
static void inf_user_table_add_user_handler(InfUserTable* user_table, InfUser* user) { InfUserTablePrivate* priv; guint id; priv = INF_USER_TABLE_PRIVATE(user_table); id = inf_user_get_id(user); g_assert(id > 0); g_assert(g_hash_table_lookup(priv->table, GUINT_TO_POINTER(id)) == NULL); g_hash_table_insert(priv->table, GUINT_TO_POINTER(id), user); g_object_ref(user); g_signal_connect( G_OBJECT(user), "notify::status", G_CALLBACK(inf_user_table_check_local_cb), user_table ); g_signal_connect( G_OBJECT(user), "notify::flags", G_CALLBACK(inf_user_table_check_local_cb), user_table ); if(inf_user_table_is_local(user)) { g_signal_emit( G_OBJECT(user_table), user_table_signals[ADD_LOCAL_USER], 0, user ); } }
static void inf_user_table_remove_user_handler(InfUserTable* user_table, InfUser* user) { InfUserTablePrivate* priv; guint id; priv = INF_USER_TABLE_PRIVATE(user_table); id = inf_user_get_id(user); if(inf_user_table_is_local(user)) { g_signal_emit( G_OBJECT(user_table), user_table_signals[REMOVE_LOCAL_USER], 0, user ); } inf_user_table_unref_user(user_table, user); g_assert(g_hash_table_lookup(priv->table, GUINT_TO_POINTER(id)) == user); g_hash_table_remove(priv->table, GUINT_TO_POINTER(id)); }
static InfCommunicationScope inf_adopted_session_process_xml_run(InfSession* session, InfXmlConnection* connection, const xmlNodePtr xml, GError** error) { InfAdoptedSessionPrivate* priv; InfAdoptedSessionClass* session_class; InfAdoptedRequest* request; InfAdoptedUser* user; gboolean has_num; guint num; GError* local_error; InfAdoptedRequest* copy_req; guint i; priv = INF_ADOPTED_SESSION_PRIVATE(session); if(strcmp((const char*)xml->name, "request") == 0) { session_class = INF_ADOPTED_SESSION_GET_CLASS(session); g_assert(session_class->xml_to_request != NULL); user = inf_adopted_session_user_from_request_xml( INF_ADOPTED_SESSION(session), xml, error ); if(user == NULL) return INF_COMMUNICATION_SCOPE_PTP; if(inf_user_get_status(INF_USER(user)) == INF_USER_UNAVAILABLE || inf_user_get_connection(INF_USER(user)) != connection) { g_set_error( error, inf_user_error_quark(), INF_USER_ERROR_NOT_JOINED, "%s", _("User did not join from this connection") ); return INF_COMMUNICATION_SCOPE_PTP; } local_error = NULL; has_num = inf_xml_util_get_attribute_uint(xml, "num", &num, &local_error); if(local_error != NULL) { g_propagate_error(error, local_error); return INF_COMMUNICATION_SCOPE_PTP; } request = session_class->xml_to_request( INF_ADOPTED_SESSION(session), xml, inf_adopted_user_get_vector(user), FALSE, error ); if(request == NULL) return INF_COMMUNICATION_SCOPE_PTP; inf_adopted_algorithm_receive_request(priv->algorithm, request); /* Apply the request more than once if num is given. This is mostly used * for multiple undos and redos, but is in general allowed for any * request. */ if(has_num) { for(i = 1; i < num; ++i) { /* TODO: This is a bit of a hack since requests are normally * immutable. It avoids an additional vector copy here though. */ copy_req = inf_adopted_request_copy(request); inf_adopted_state_vector_add( inf_adopted_request_get_vector(copy_req), inf_user_get_id(INF_USER(user)), i ); inf_adopted_algorithm_receive_request(priv->algorithm, copy_req); g_object_unref(copy_req); } } g_object_unref(request); /* Requests can always be forwarded since user is given. */ return INF_COMMUNICATION_SCOPE_GROUP; } return INF_SESSION_CLASS(parent_class)->process_xml_run( session, connection, xml, error ); }
static gboolean infinoted_plugin_transformation_protection_check_request_cb(InfAdoptedSession* session, InfAdoptedRequest* request, InfAdoptedUser* user, gpointer user_data) { InfinotedPluginTransformationProtectionSessionInfo* info; guint vdiff; InfXmlConnection* connection; gchar* request_str; gchar* current_str; gchar* remote_id; gchar* path; info = (InfinotedPluginTransformationProtectionSessionInfo*)user_data; vdiff = inf_adopted_state_vector_vdiff( inf_adopted_request_get_vector(request), inf_adopted_algorithm_get_current( inf_adopted_session_get_algorithm(session) ) ); if(vdiff > info->plugin->max_vdiff) { connection = inf_user_get_connection(INF_USER(user)); /* Local requests do not need to be transformed, so always have a * zero vdiff. */ g_assert(connection != NULL); /* Kill the connection */ infd_session_proxy_unsubscribe( INFD_SESSION_PROXY(info->proxy), connection ); /* Write a log message */ path = inf_browser_get_path( INF_BROWSER( infinoted_plugin_manager_get_directory(info->plugin->manager) ), &info->iter ); request_str = inf_adopted_state_vector_to_string( inf_adopted_request_get_vector(request) ); current_str = inf_adopted_state_vector_to_string( inf_adopted_algorithm_get_current( inf_adopted_session_get_algorithm(session) ) ); g_object_get(G_OBJECT(connection), "remote-id", &remote_id, NULL); infinoted_log_warning( infinoted_plugin_manager_get_log(info->plugin->manager), _("In document \"%s\": Attempt to transform request \"%s\" to current state \"%s\" " "(vdiff=%u) by user \"%s\" (id=%u, conn=%s). Maximum allowed is %u; the " "connection has been unsubscribed."), path, request_str, current_str, vdiff, inf_user_get_name(INF_USER(user)), inf_user_get_id(INF_USER(user)), remote_id, info->plugin->max_vdiff ); g_free(path); g_free(request_str); g_free(current_str); g_free(remote_id); /* Prevent the request from being transformed */ return TRUE; } return FALSE; }