void on_user_notify_status(InfUser* user) { // User cannot be activated when we are not active g_assert(m_active || inf_user_get_status(user) != INF_USER_ACTIVE); if(inf_user_get_status(user) == INF_USER_ACTIVE && m_active) { // The user did something (therefore becoming active), // so we do not need to explictely activate the user. g_assert(m_timeout_connection.connected()); m_timeout_connection.disconnect(); } }
static void inf_text_gtk_viewport_user_removed(InfTextGtkViewport* viewport, InfTextUser* user) { InfTextGtkViewportPrivate* priv; InfTextGtkViewportUser* viewport_user; priv = INF_TEXT_GTK_VIEWPORT_PRIVATE(viewport); if(user == priv->active_user) { priv->active_user = NULL; g_object_notify(G_OBJECT(viewport), "active-user"); } else { inf_signal_handlers_disconnect_by_func( user, G_CALLBACK(inf_text_gtk_viewport_user_notify_status_cb), viewport ); if(inf_user_get_status(INF_USER(user)) == INF_USER_ACTIVE) { viewport_user = inf_text_gtk_viewport_find_user(viewport, user); g_assert(viewport_user != NULL); inf_text_gtk_viewport_remove_user(viewport_user); } } }
static void inf_text_gtk_viewport_user_notify_status_cb(GObject* object, GParamSpec* pspec, gpointer user_data) { InfTextGtkViewport* viewport; InfTextGtkViewportPrivate* priv; InfTextUser* user; InfTextGtkViewportUser* viewport_user; viewport = INF_TEXT_GTK_VIEWPORT(user_data); priv = INF_TEXT_GTK_VIEWPORT_PRIVATE(viewport); user = INF_TEXT_USER(object); g_assert(user != priv->active_user); viewport_user = inf_text_gtk_viewport_find_user(viewport, user); if(inf_user_get_status(INF_USER(user)) == INF_USER_ACTIVE) { if(!viewport_user) inf_text_gtk_viewport_add_user(viewport, user); } else { if(viewport_user) inf_text_gtk_viewport_remove_user(viewport_user); } }
void activate_user() { g_assert(!m_timeout_connection.connected()); g_assert(m_active_user != NULL); g_assert(inf_user_get_status(m_active_user) == INF_USER_INACTIVE); m_timeout_connection = Glib::signal_timeout().connect( sigc::mem_fun(*this, &DocInfo::on_activation_timeout), ACTIVATION_DELAY); }
static gboolean inf_user_table_is_local(InfUser* user) { /* User counts as local when it has the local flag set and is available */ if( (inf_user_get_flags(user) & INF_USER_LOCAL) == 0) return FALSE; if(inf_user_get_status(user) == INF_USER_UNAVAILABLE) return FALSE; return TRUE; }
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 void infinoted_plugin_linekeeper_has_available_users_foreach_func(InfUser* user, gpointer udata) { InfinotedPluginLinekeeperHasAvailableUsersData* data; data = (InfinotedPluginLinekeeperHasAvailableUsersData*)udata; /* Return TRUE if there are non-local users connected */ if(user != data->own_user && inf_user_get_status(user) != INF_USER_UNAVAILABLE && (inf_user_get_flags(user) & INF_USER_LOCAL) == 0) { data->has_available_user = TRUE; } }
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 user_name_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, GeditCollaborationWindowHelper *helper) { InfUser *user; InfUserStatus status; const gchar *name; GtkStyle *style; GdkColor *color; PangoStyle user_style; gtk_tree_model_get (tree_model, iter, GEDIT_COLLABORATION_USER_STORE_COLUMN_USER, &user, -1); name = inf_user_get_name (user); status = inf_user_get_status (user); style = gtk_widget_get_style (helper->priv->tree_view_user_view); if (status == INF_USER_ACTIVE) { color = &style->fg[GTK_STATE_NORMAL]; user_style = PANGO_STYLE_NORMAL; } else { color = &style->fg[GTK_STATE_INSENSITIVE]; user_style = PANGO_STYLE_ITALIC; } g_object_set (cell, "text", name, "style", user_style, "foreground-gdk", color, NULL); g_object_unref (user); }
static void inf_text_gtk_viewport_user_added(InfTextGtkViewport* viewport, InfTextUser* user) { InfTextGtkViewportPrivate* priv; priv = INF_TEXT_GTK_VIEWPORT_PRIVATE(viewport); /* Active user is guaranteed to be contained in user table, so if user was * just added then it can't be set as active user already. */ g_assert(user != priv->active_user); g_signal_connect( user, "notify::status", G_CALLBACK(inf_text_gtk_viewport_user_notify_status_cb), viewport ); if(inf_user_get_status(INF_USER(user)) == INF_USER_ACTIVE) inf_text_gtk_viewport_add_user(viewport, user); }
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; } }
void on_active_user_changed(InfUser* user) { if(m_active_user != NULL) { if(m_active) deactivate_user(); g_signal_handler_disconnect(G_OBJECT(m_active_user), m_notify_status_handle); } m_active_user = user; if(user != NULL) { InfUserStatus user_status = inf_user_get_status(INF_USER(user)); g_assert(user_status != INF_USER_UNAVAILABLE); m_notify_status_handle = g_signal_connect( G_OBJECT(user), "notify::status", G_CALLBACK(&on_user_notify_status_static), this ); if( (user_status == INF_USER_ACTIVE && !m_active)) { deactivate_user(); } else if(user_status == INF_USER_INACTIVE && m_active) { activate_user(); } } }
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 ); }