static void interact_request_callback (SmsConn conn, SmPointer manager_data, int dialog_type) { GsmXSMPClient *client = manager_data; #if 0 gboolean res; GError *error; #endif g_debug ("GsmXSMPClient: Client '%s' received InteractRequest(%s)", client->priv->description, dialog_type == SmDialogNormal ? "Dialog" : "Errors"); gsm_client_end_session_response (GSM_CLIENT (client), FALSE, FALSE, FALSE, _("This program is blocking logout.")); #if 0 /* Can't just call back with Interact because session client grabs the keyboard! So, we try to get it to release grabs by telling it we've cancelled the shutdown. This grabbing is clearly bullshit and is not supported by the client spec or protocol spec. */ res = xsmp_cancel_end_session (GSM_CLIENT (client), &error); if (! res) { g_warning ("Unable to cancel end session: %s", error->message); g_error_free (error); } #endif xsmp_interact (GSM_CLIENT (client)); }
static DBusHandlerResult client_dbus_filter_function (DBusConnection *connection, DBusMessage *message, void *user_data) { GsmDBusClient *client = GSM_DBUS_CLIENT (user_data); const char *path; g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); path = dbus_message_get_path (message); g_debug ("GsmDBusClient: obj_path=%s interface=%s method=%s", dbus_message_get_path (message), dbus_message_get_interface (message), dbus_message_get_member (message)); if (dbus_message_is_method_call (message, SM_DBUS_CLIENT_PRIVATE_INTERFACE, "EndSessionResponse")) { g_assert (gsm_client_peek_id (GSM_CLIENT (client)) != NULL); if (path != NULL && strcmp (path, gsm_client_peek_id (GSM_CLIENT (client))) != 0) { /* Different object path */ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } handle_end_session_response (client, message); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
static void delete_property (GsmXSMPClient *client, const char *name) { int index; SmProp *prop; prop = find_property (client, name, &index); if (!prop) { return; } #if 0 /* This is wrong anyway; we can't unconditionally run the current * discard command; if this client corresponds to a GsmAppResumed, * and the current discard command is identical to the app's * discard_command, then we don't run the discard command now, * because that would delete a saved state we may want to resume * again later. */ if (!strcmp (name, SmDiscardCommand)) { gsm_client_run_discard (GSM_CLIENT (client)); } #endif g_ptr_array_remove_index_fast (client->priv->props, index); SmFreeProperty (prop); }
static void save_yourself_done_callback (SmsConn conn, SmPointer manager_data, Bool success) { GsmXSMPClient *client = manager_data; g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfDone(success = %s)", client->priv->description, success ? "True" : "False"); if (client->priv->current_save_yourself != -1) { SmsSaveComplete (client->priv->conn); client->priv->current_save_yourself = -1; } /* If success is false then the application couldn't save data. Nothing * the session manager can do about, though. FIXME: we could display a * dialog about this, I guess. */ gsm_client_end_session_response (GSM_CLIENT (client), TRUE, FALSE, FALSE, NULL); if (client->priv->next_save_yourself) { int save_type = client->priv->next_save_yourself; gboolean allow_interact = client->priv->next_save_yourself_allow_interact; client->priv->next_save_yourself = -1; client->priv->next_save_yourself_allow_interact = -1; do_save_yourself (client, save_type, allow_interact); } }
static Status register_client_callback (SmsConn conn, SmPointer manager_data, char *previous_id) { GsmXSMPClient *client = manager_data; gboolean handled; char *id; g_debug ("GsmXSMPClient: Client '%s' received RegisterClient(%s)", client->priv->description, previous_id ? previous_id : "NULL"); /* There are three cases: * 1. id is NULL - we'll use a new one * 2. id is known - we'll use known one * 3. id is unknown - this is an error */ id = g_strdup (previous_id); handled = FALSE; g_signal_emit (client, signals[REGISTER_REQUEST], 0, &id, &handled); if (! handled) { g_debug ("GsmXSMPClient: RegisterClient not handled!"); g_free (id); free (previous_id); g_assert_not_reached (); return FALSE; } if (IS_STRING_EMPTY (id)) { g_debug ("GsmXSMPClient: rejected: invalid previous_id"); free (previous_id); return FALSE; } g_object_set (client, "startup-id", id, NULL); set_description (client); g_debug ("GsmXSMPClient: Sending RegisterClientReply to '%s'", client->priv->description); SmsRegisterClientReply (conn, id); if (IS_STRING_EMPTY (previous_id)) { /* Send the initial SaveYourself. */ g_debug ("GsmXSMPClient: Sending initial SaveYourself"); SmsSaveYourself (conn, SmSaveLocal, False, SmInteractStyleNone, False); client->priv->current_save_yourself = SmSaveLocal; } gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_REGISTERED); g_free (id); free (previous_id); return TRUE; }
static void close_connection_callback (SmsConn conn, SmPointer manager_data, int count, char **reason_msgs) { GsmXSMPClient *client = manager_data; int i; g_debug ("GsmXSMPClient: Client '%s' received CloseConnection", client->priv->description); for (i = 0; i < count; i++) { g_debug ("GsmXSMPClient: close reason: '%s'", reason_msgs[i]); } SmFreeReasons (count, reason_msgs); gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FINISHED); gsm_client_disconnected (GSM_CLIENT (client)); }
static void handle_end_session_response (GsmDBusClient *client, DBusMessage *message) { const char *sender; DBusMessage *reply; DBusError error; dbus_bool_t is_ok; const char *reason; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_BOOLEAN, &is_ok, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID)) { if (dbus_error_is_set (&error)) { g_warning ("Invalid method call: %s", error.message); dbus_error_free (&error); } raise_error (client->priv->connection, message, DBUS_ERROR_FAILED, "There is a syntax error in the invocation of the method EndSessionResponse"); return; } g_debug ("GsmDBusClient: got EndSessionResponse is-ok:%d reason=%s", is_ok, reason); /* make sure it is from our client */ sender = dbus_message_get_sender (message); if (sender == NULL || IS_STRING_EMPTY (client->priv->bus_name) || strcmp (sender, client->priv->bus_name) != 0) { raise_error (client->priv->connection, message, DBUS_ERROR_FAILED, "Caller not recognized as the client"); return; } reply = dbus_message_new_method_return (message); if (reply == NULL) { g_error ("No memory"); } gsm_client_end_session_response (GSM_CLIENT (client), is_ok, FALSE, FALSE, reason); if (! dbus_connection_send (client->priv->connection, reply, NULL)) { g_error ("No memory"); } dbus_message_unref (reply); }
GsmClient * gsm_xsmp_client_new (IceConn ice_conn) { GsmXSMPClient *xsmp; xsmp = g_object_new (GSM_TYPE_XSMP_CLIENT, "ice-connection", ice_conn, NULL); return GSM_CLIENT (xsmp); }
GsmClient * gsm_dbus_client_new (const char *startup_id, const char *bus_name) { GsmDBusClient *client; client = g_object_new (GSM_TYPE_DBUS_CLIENT, "startup-id", startup_id, "bus-name", bus_name, NULL); return GSM_CLIENT (client); }
static gboolean client_iochannel_watch (GIOChannel *channel, GIOCondition condition, GsmXSMPClient *client) { gboolean keep_going; g_object_ref (client); switch (IceProcessMessages (client->priv->ice_connection, NULL, NULL)) { case IceProcessMessagesSuccess: keep_going = TRUE; break; case IceProcessMessagesIOError: g_debug ("GsmXSMPClient: IceProcessMessagesIOError on '%s'", client->priv->description); gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FAILED); /* Emitting "disconnected" will eventually cause * IceCloseConnection() to be called. */ gsm_client_disconnected (GSM_CLIENT (client)); keep_going = FALSE; break; case IceProcessMessagesConnectionClosed: g_debug ("GsmXSMPClient: IceProcessMessagesConnectionClosed on '%s'", client->priv->description); client->priv->ice_connection = NULL; keep_going = FALSE; break; default: g_assert_not_reached (); } g_object_unref (client); return keep_going; }
static void interact_done_callback (SmsConn conn, SmPointer manager_data, Bool cancel_shutdown) { GsmXSMPClient *client = manager_data; g_debug ("GsmXSMPClient: Client '%s' received InteractDone(cancel_shutdown = %s)", client->priv->description, cancel_shutdown ? "True" : "False"); gsm_client_end_session_response (GSM_CLIENT (client), TRUE, FALSE, cancel_shutdown, NULL); }
static void save_yourself_phase2_request_callback (SmsConn conn, SmPointer manager_data) { GsmXSMPClient *client = manager_data; g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfPhase2Request", client->priv->description); client->priv->current_save_yourself = -1; /* this is a valid response to SaveYourself and therefore may be a response to a QES or ES */ gsm_client_end_session_response (GSM_CLIENT (client), TRUE, TRUE, FALSE, NULL); }
static void initiate_shutdown (GsmSession *session) { GSList *cl; session->phase = GSM_SESSION_PHASE_SHUTDOWN; if (session->clients == NULL) session_shutdown (session); for (cl = session->clients; cl; cl = cl->next) { GsmClient *client = GSM_CLIENT (cl->data); session->shutdown_clients = g_slist_prepend (session->shutdown_clients, client); gsm_client_save_yourself (client, FALSE); } }
static char * get_desktop_file_path (GsmXSMPClient *client) { SmProp *prop; char *desktop_file_path = NULL; char **dirs; const char *program_name; /* XSMP clients using eggsmclient defines a special property * pointing to their respective desktop entry file */ prop = find_property (client, GsmDesktopFile, NULL); if (prop) { GFile *file = g_file_new_for_uri (prop->vals[0].value); desktop_file_path = g_file_get_path (file); g_object_unref (file); goto out; } /* If we can't get desktop file from GsmDesktopFile then we * try to find the desktop file from its program name */ prop = find_property (client, SmProgram, NULL); program_name = prop->vals[0].value; dirs = gsm_util_get_autostart_dirs (); desktop_file_path = gsm_util_find_desktop_file_for_app_name (program_name, dirs); g_strfreev (dirs); out: g_debug ("GsmXSMPClient: desktop file for client %s is %s", gsm_client_peek_id (GSM_CLIENT (client)), desktop_file_path ? desktop_file_path : "(null)"); return desktop_file_path; }
static void set_description (GsmXSMPClient *client) { SmProp *prop; const char *id; prop = find_property (client, SmProgram, NULL); id = gsm_client_peek_startup_id (GSM_CLIENT (client)); g_free (client->priv->description); if (prop) { client->priv->description = g_strdup_printf ("%p [%.*s %s]", client, prop->vals[0].length, (char *)prop->vals[0].value, id); } else if (id != NULL) { client->priv->description = g_strdup_printf ("%p [%s]", client, id); } else { client->priv->description = g_strdup_printf ("%p", client); } }
char * gsm_session_register_client (GsmSession *session, GsmClient *client, const char *id) { GSList *a; char *client_id = NULL; /* If we're shutting down, we don't accept any new session clients. */ if (session->phase == GSM_SESSION_PHASE_SHUTDOWN) return FALSE; if (id == NULL) client_id = gsm_xsmp_generate_client_id (); else { for (a = session->clients; a; a = a->next) { GsmClient *client = GSM_CLIENT (a->data); /* We can't have two clients with the same id. */ if (!strcmp (id, gsm_client_get_client_id (client))) { return NULL; } } client_id = g_strdup (id); } g_debug ("Adding new client %s to session", id); g_signal_connect (client, "saved_state", G_CALLBACK (client_saved_state), session); g_signal_connect (client, "request_phase2", G_CALLBACK (client_request_phase2), session); g_signal_connect (client, "request_interaction", G_CALLBACK (client_request_interaction), session); g_signal_connect (client, "interaction_done", G_CALLBACK (client_interaction_done), session); g_signal_connect (client, "save_yourself_done", G_CALLBACK (client_save_yourself_done), session); g_signal_connect (client, "disconnected", G_CALLBACK (client_disconnected), session); session->clients = g_slist_prepend (session->clients, client); /* If it's a brand new client id, we just accept the client*/ if (id == NULL) return client_id; /* If we're starting up the session, try to match the new client * with one pending apps for the current phase. If not, try to match * with any of the autostarted apps. */ if (session->phase < GSM_SESSION_PHASE_APPLICATION) a = session->pending_apps; for (; a; a = a->next) { GsmApp *app = GSM_APP (a->data); if (!strcmp (client_id, app->client_id)) { gsm_app_registered (app); return client_id; } } g_free (client_id); return NULL; }