--- src/lxsession-0.4.6.1/lxsession-logout/dbus-interface.c 2011-07-27 21:26:36.000000000 +0200 +++ src/lxsession-0.4.6.1/lxsession-logout-logind/dbus-interface.c 2012-11-13 17:26:30.807070976 +0100 @@ -51,13 +51,20 @@ char * dbus_HAL_Reboot(void); char * dbus_HAL_Suspend(void); char * dbus_HAL_Hibernate(void); +gboolean dbus_logind_CanPowerOff(void); +gboolean dbus_logind_CanReboot(void); +gboolean dbus_logind_CanSuspend(void); +gboolean dbus_logind_CanHibernate(void); +char * dbus_logind_PowerOff(void); +char * dbus_logind_Reboot(void); +char * dbus_logind_Suspend(void); +char * dbus_logind_Hibernate(void); +char * dbus_LXDE_Logout(void); /* End FORWARDS */ /* Connect to the system bus. Once a connection is made, it is saved for reuse. */ -static DBusConnection * dbus_connect(void) +static DBusConnection * dbus_connect_system(void) { - if ((dbus_context.connection == NULL) && ( ! dbus_context.connection_tried)) - { DBusError error; dbus_error_init(&error); dbus_context.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); @@ -67,16 +74,57 @@ dbus_error_free(&error); } dbus_context.connection_tried = TRUE; - } return dbus_context.connection; } +static DBusConnection * dbus_connect_session(void) +{ + DBusError error; + dbus_error_init(&error); + dbus_context.connection = dbus_bus_get(DBUS_BUS_SESSION, &error); + if (dbus_context.connection == NULL) + { + g_warning(G_STRLOC ": Failed to connect to the session message bus: %s", error.message); + dbus_error_free(&error); + } + dbus_context.connection_tried = TRUE; + + return dbus_context.connection; +} + + /* Send a message. */ -static DBusMessage * dbus_send_message(DBusMessage * message, char * * error_text) +static DBusMessage * dbus_send_message_system(DBusMessage * message, char * * error_text) { /* Get a connection handle. */ - DBusConnection * connection = dbus_connect(); + DBusConnection * connection = dbus_connect_system(); + if (connection == NULL) + return FALSE; + + /* Send the message. */ + DBusError error; + dbus_error_init(&error); + DBusMessage * reply = dbus_connection_send_with_reply_and_block(connection, message, DBUS_TIMEOUT, &error); + dbus_message_unref(message); + if (reply == NULL) + { + if ((error.name == NULL) || (strcmp(error.name, DBUS_ERROR_NO_REPLY) != 0)) + { + if (error_text != NULL) + *error_text = g_strdup(error.message); + g_warning(G_STRLOC ": DBUS: %s", error.message); + } + dbus_error_free(&error); + } + return reply; +} + +/* Send a message. */ +static DBusMessage * dbus_send_message_session(DBusMessage * message, char * * error_text) +{ + /* Get a connection handle. */ + DBusConnection * connection = dbus_connect_session(); if (connection == NULL) return FALSE; @@ -132,6 +180,36 @@ } return result; } + +/* Read a result for a method that returns a string encoded boolean. */ +static gboolean dbus_read_result_sboolean(DBusMessage * reply) +{ + gboolean result = FALSE; + char* string_result; + if (reply != NULL) + { + /* Get the string result. */ + DBusError error; + dbus_error_init(&error); + dbus_bool_t status = dbus_message_get_args( + reply, + &error, + DBUS_TYPE_STRING, &string_result, + DBUS_TYPE_INVALID); + if ( ! status) + { + g_warning(G_STRLOC ": DBUS: %s", error.message); + dbus_error_free(&error); + } + else + { + if (!strcmp(string_result, "yes")) + result = TRUE; + } + dbus_message_unref(reply); + } + return result; +} #endif /*** ConsoleKit mechanism ***/ @@ -152,7 +230,7 @@ static gboolean dbus_ConsoleKit_query(const char * const query) { #ifdef HAVE_DBUS - return dbus_read_result_boolean(dbus_send_message(dbus_ConsoleKit_formulate_message(query), NULL)); + return dbus_read_result_boolean(dbus_send_message_system(dbus_ConsoleKit_formulate_message(query), NULL)); #else return FALSE; #endif @@ -163,7 +241,7 @@ { #ifdef HAVE_DBUS char * error = NULL; - dbus_read_result_void(dbus_send_message(dbus_ConsoleKit_formulate_message(command), &error)); + dbus_read_result_void(dbus_send_message_system(dbus_ConsoleKit_formulate_message(command), &error)); return error; #else return NULL; @@ -225,7 +303,7 @@ DBUS_TYPE_INVALID); /* Send the message. */ - DBusMessage * reply = dbus_send_message(message, NULL); + DBusMessage * reply = dbus_send_message_system(message, NULL); if (reply == NULL) return FALSE; @@ -252,7 +330,7 @@ { #ifdef HAVE_DBUS char * error = NULL; - dbus_read_result_void(dbus_send_message(dbus_UPower_formulate_command(command), &error)); + dbus_read_result_void(dbus_send_message_system(dbus_UPower_formulate_command(command), &error)); return error; #else return NULL; @@ -329,7 +407,7 @@ DBusMessage * message = dbus_HAL_formulate_string_property_query(property); if (message == NULL) return FALSE; - DBusMessage * reply = dbus_send_message(message, NULL); + DBusMessage * reply = dbus_send_message_system(message, NULL); if (reply == NULL) return FALSE; dbus_message_unref(reply); @@ -343,7 +421,7 @@ static gboolean dbus_HAL_boolean_query(const char * const property) { #ifdef HAVE_DBUS - return dbus_read_result_boolean(dbus_send_message(dbus_HAL_formulate_boolean_property_query(property), NULL)); + return dbus_read_result_boolean(dbus_send_message_system(dbus_HAL_formulate_boolean_property_query(property), NULL)); #else return FALSE; #endif @@ -367,7 +445,7 @@ /* Send the message and wait for a reply. */ char * error = NULL; - dbus_read_result_void(dbus_send_message(message, &error)); + dbus_read_result_void(dbus_send_message_system(message, &error)); return error; #else return NULL; @@ -421,3 +499,185 @@ { return dbus_HAL_command("Hibernate"); } + +/*** logind mechanism ***/ + +#ifdef HAVE_DBUS +/* Formulate a message to the logind Manager interface to query a property. */ +static DBusMessage * dbus_logind_formulate_query(const char * const query) +{ + return dbus_message_new_method_call( + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + query); +} + +/* Formulate a message to the logind Manager interface. */ +static DBusMessage * dbus_logind_formulate_message(const char * const method) +{ + static dbus_bool_t interactive = FALSE; + DBusMessage * message = dbus_message_new_method_call( + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + method); + if (message != NULL) + dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &interactive, DBUS_TYPE_INVALID); + return message; +} +#endif + +/* Send a specified query to the logind interface and process a boolean result. */ +static gboolean dbus_logind_query(const char * const query) +{ +#ifdef HAVE_DBUS + return dbus_read_result_sboolean(dbus_send_message_system(dbus_logind_formulate_query(query), NULL)); +#else + return FALSE; +#endif +} + +/* Send a specified command to the logind interface and process a void result. */ +static char * dbus_logind_command(const char * const command) +{ +#ifdef HAVE_DBUS + char * error = NULL; + dbus_read_result_void(dbus_send_message_system(dbus_logind_formulate_message(command), &error)); + return error; +#else + return NULL; +#endif +} + +/* Read the can-poweroff property of logind. */ +gboolean dbus_logind_CanPowerOff(void) +{ + return dbus_logind_query("CanPowerOff"); +} + +/* Read the can-reboot property of logind. */ +gboolean dbus_logind_CanReboot(void) +{ + return dbus_logind_query("CanReboot"); +} + +/* Read the can-suspend property of logind. */ +gboolean dbus_logind_CanSuspend(void) +{ + return dbus_logind_query("CanSuspend"); +} + +/* Read the can-hibernate property of logind. */ +gboolean dbus_logind_CanHibernate(void) +{ + return dbus_logind_query("CanHibernate"); +} + +/* Invoke the PowerOff method on logind. */ +char * dbus_logind_PowerOff(void) +{ + return dbus_logind_command("PowerOff"); +} + +/* Invoke the Reboot method on logind. */ +char * dbus_logind_Reboot(void) +{ + return dbus_logind_command("Reboot"); +} + +/* Invoke the Suspend method on logind. */ +char * dbus_logind_Suspend(void) +{ + return dbus_logind_command("Suspend"); +} + +/* Invoke the Hibernate method on logind. */ +char * dbus_logind_Hibernate(void) +{ + return dbus_logind_command("Hibernate"); +} + +/*** LXDE mechanism ***/ + +#ifdef HAVE_DBUS +/* Formulate a message to the LXDE Session Manager interface. */ +static DBusMessage * dbus_LXDE_formulate_message(const char * const query) +{ + return dbus_message_new_method_call( + "org.lxde.SessionManager", + "/org/lxde/SessionManager", + "org.lxde.SessionManager", + query); +} +#endif + +/* Send a specified message to the LXDE interface and process a boolean result. */ +static gboolean dbus_LXDE_query(const char * const query) +{ +#ifdef HAVE_DBUS + return dbus_read_result_boolean(dbus_send_message_session(dbus_LXDE_formulate_message(query), NULL)); +#else + return FALSE; +#endif +} + +/* Send a specified message to the LXDE interface and process a void result. */ +static char * dbus_LXDE_command(const char * const command) +{ +#ifdef HAVE_DBUS + char * error = NULL; + dbus_read_result_void(dbus_send_message_session(dbus_LXDE_formulate_message(command), &error)); + return error; +#else + return NULL; +#endif +} + +/* Invoke the Logout method on LXDE. */ +char * dbus_LXDE_Logout(void) +{ + return dbus_LXDE_command("Logout"); +} + +/*** Lightdm mechanism ***/ + +#ifdef HAVE_DBUS +/* Formulate a message to the Lightdm interface. */ +static DBusMessage * dbus_Lightdm_formulate_message(const char * const query) +{ + return dbus_message_new_method_call( + "org.freedesktop.DisplayManager", + g_getenv ("XDG_SEAT_PATH"), + "org.freedesktop.DisplayManager.Seat", + query); +} +#endif + +/* Send a specified message to the Lightdm interface and process a boolean result. */ +static gboolean dbus_Lightdm_query(const char * const query) +{ +#ifdef HAVE_DBUS + return dbus_read_result_boolean(dbus_send_message_session(dbus_Lightdm_formulate_message(query), NULL)); +#else + return FALSE; +#endif +} + +/* Send a specified message to the Lightdm interface and process a void result. */ +static char * dbus_Lightdm_command(const char * const command) +{ +#ifdef HAVE_DBUS + char * error = NULL; + dbus_read_result_void(dbus_send_message_session(dbus_Lightdm_formulate_message(command), &error)); + return error; +#else + return NULL; +#endif +} + +/* Invoke the Logout method on LXDE. */ +char * dbus_Lightdm_SwitchToGreeter(void) +{ + return dbus_Lightdm_command("SwitchToGreeter"); +} --- src/lxsession-0.4.6.1/lxsession-logout/dbus-interface.h 2011-07-27 21:26:36.000000000 +0200 +++ src/lxsession-0.4.6.1/lxsession-logout-logind/dbus-interface.h 2012-11-13 17:26:30.807070976 +0100 @@ -44,4 +44,18 @@ extern char * dbus_HAL_Suspend(void); extern char * dbus_HAL_Hibernate(void); +/* Interface to logind for shutdown, reboot, suspend, and hibernate. */ +extern gboolean dbus_logind_CanPowerOff(void); +extern gboolean dbus_logind_CanRestart(void); +extern char * dbus_logind_PowerOff(void); +extern char * dbus_logind_Restart(void); +extern gboolean dbus_logind_CanSuspend(void); +extern gboolean dbus_logind_CanHibernate(void); +extern char * dbus_logind_Suspend(void); +extern char * dbus_logind_Hibernate(void); + +extern char * dbus_LXDE_Logout(void); + +extern char * dbus_Lightdm_SwitchToGreeter(); + #endif --- src/lxsession-0.4.6.1/lxsession-logout/lxsession-logout.c 2011-07-27 21:26:36.000000000 +0200 +++ src/lxsession-0.4.6.1/lxsession-logout-logind/lxsession-logout.c 2012-11-13 17:26:30.807070976 +0100 @@ -69,12 +69,21 @@ int reboot_HAL : 1; /* Reboot is available via HAL */ int suspend_HAL : 1; /* Suspend is available via HAL */ int hibernate_HAL : 1; /* Hibernate is available via HAL */ + int shutdown_logind : 1; /* Shutdown is available via logind */ + int reboot_logind : 1; /* Reboot is available via logind */ + int suspend_logind : 1; /* Suspend is available via logind */ + int hibernate_logind : 1; /* Hibernate is available via logind */ int switch_user_GDM : 1; /* Switch User is available via GDM */ - int switch_user_KDM : 1; /* Switch User is available via KDM */ + int switch_user_LIGHTDM : 1; /* Switch User is available via GDM */ + int switch_user_KDM : 1; /* Switch User is available via LIGHTDM */ int ltsp : 1; /* Shutdown and reboot is accomplished via LTSP */ + + int lock_screen : 1; /* Lock screen available */ + } HandlerContext; static gboolean lock_screen(void); +static const gchar* determine_lock_screen(void); static gboolean verify_running(const char * display_manager, const char * executable); static void logout_clicked(GtkButton * button, HandlerContext * handler_context); static void change_root_property(GtkWidget* w, const char* prop_name, const char* value); @@ -93,13 +102,32 @@ */ static gboolean lock_screen(void) { - if (!g_spawn_command_line_async("lxlock", NULL)) + const gchar* program = determine_lock_screen(); + + if (program) { + g_spawn_command_line_async(program, NULL); return TRUE; } return FALSE; } +static const gchar* determine_lock_screen(void) +{ + const gchar* program = NULL; + + if (g_find_program_in_path("xdg-screensaver")) + { + program = "xdg-screensaver lock"; + } + else if (g_find_program_in_path("lxlock")) + { + program = "lxlock"; + } + return program; +} + + /* Verify that a program is running and that an executable is available. */ static gboolean verify_running(const char * display_manager, const char * executable) { @@ -187,6 +215,8 @@ error_result = dbus_ConsoleKit_Stop(); else if (handler_context->shutdown_HAL) error_result = dbus_HAL_Shutdown(); + else if (handler_context->shutdown_logind) + error_result = dbus_logind_PowerOff(); if (error_result != NULL) gtk_label_set_text(GTK_LABEL(handler_context->error_label), error_result); @@ -208,6 +238,8 @@ error_result = dbus_ConsoleKit_Restart(); else if (handler_context->reboot_HAL) error_result = dbus_HAL_Reboot(); + else if (handler_context->reboot_logind) + error_result = dbus_logind_Reboot(); if (error_result != NULL) gtk_label_set_text(GTK_LABEL(handler_context->error_label), error_result); @@ -225,6 +257,8 @@ error_result = dbus_UPower_Suspend(); else if (handler_context->suspend_HAL) error_result = dbus_HAL_Suspend(); + else if (handler_context->suspend_logind) + error_result = dbus_logind_Suspend(); if (error_result != NULL) gtk_label_set_text(GTK_LABEL(handler_context->error_label), error_result); @@ -242,6 +276,8 @@ error_result = dbus_UPower_Hibernate(); else if (handler_context->hibernate_HAL) error_result = dbus_HAL_Hibernate(); + else if (handler_context->hibernate_logind) + error_result = dbus_logind_Hibernate(); if (error_result != NULL) gtk_label_set_text(GTK_LABEL(handler_context->error_label), error_result); @@ -258,6 +294,17 @@ g_spawn_command_line_sync("gdmflexiserver --startnew", NULL, NULL, NULL, NULL); else if (handler_context->switch_user_KDM) g_spawn_command_line_sync("kdmctl reserve", NULL, NULL, NULL, NULL); + else if (handler_context->switch_user_LIGHTDM) + dbus_Lightdm_SwitchToGreeter(); + gtk_main_quit(); +} + +/* Handler for "clicked" signal on Lock button. */ +static void lock_screen_clicked(GtkButton * button, HandlerContext * handler_context) +{ + gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL); + + lock_screen(); gtk_main_quit(); } @@ -435,6 +482,28 @@ handler_context.hibernate_HAL = TRUE; } + /* Initialize capabilities of the logind mechanism. */ + if (!handler_context.shutdown_available && dbus_logind_CanPowerOff()) + { + handler_context.shutdown_available = TRUE; + handler_context.shutdown_logind = TRUE; + } + if (!handler_context.reboot_available && dbus_logind_CanReboot()) + { + handler_context.reboot_available = TRUE; + handler_context.reboot_logind = TRUE; + } + if (!handler_context.suspend_available && dbus_logind_CanSuspend()) + { + handler_context.suspend_available = TRUE; + handler_context.suspend_logind = TRUE; + } + if (!handler_context.hibernate_available && dbus_logind_CanHibernate()) + { + handler_context.hibernate_available = TRUE; + handler_context.hibernate_logind = TRUE; + } + /* If we are under GDM, its "Switch User" is available. */ if (verify_running("gdm", "gdmflexiserver")) { @@ -442,6 +511,34 @@ handler_context.switch_user_GDM = TRUE; } + /* If we are under GDM3, its "Switch User" is available. */ + if (verify_running("gdm3", "gdmflexiserver")) + { + handler_context.switch_user_available = TRUE; + handler_context.switch_user_GDM = TRUE; + } + + /* lightdm also use gdmflexiserver */ + if (verify_running("lightdm", "gdmflexiserver")) + { + handler_context.switch_user_available = TRUE; + handler_context.switch_user_GDM = TRUE; + } + + /* lightdm also use gdmflexiserver */ + if (verify_running("lightdm", "gdmflexiserver")) + { + handler_context.switch_user_available = TRUE; + handler_context.switch_user_GDM = TRUE; + } + + /* lightdm can also be find by the env */ + if (g_getenv("XDG_SEAT_PATH")) + { + handler_context.switch_user_available = TRUE; + handler_context.switch_user_LIGHTDM = TRUE; + } + /* If we are under KDM, its "Switch User" is available. */ if (verify_running("kdm", "kdmctl")) { @@ -451,7 +548,18 @@ /* LTSP support */ if (g_getenv("LTSP_CLIENT")) + { handler_context.ltsp = TRUE; + handler_context.shutdown_available = TRUE; + handler_context.reboot_available = TRUE; + } + + /* Lock screen */ + const gchar* very_lock_screen = determine_lock_screen(); + if (very_lock_screen) + { + handler_context.lock_screen = TRUE; + } /* Make the button images accessible. */ gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/lxsession/images"); @@ -596,6 +704,17 @@ gtk_box_pack_start(GTK_BOX(controls), switch_user_button, FALSE, FALSE, 4); } + /* Create the Lock Screen button. */ + if (handler_context.lock_screen && !handler_context.ltsp) + { + GtkWidget * lock_screen_button = gtk_button_new_with_mnemonic(_("L_ock Screen")); + GtkWidget * image = gtk_image_new_from_icon_name("system-lock-screen", GTK_ICON_SIZE_BUTTON); + gtk_button_set_image(GTK_BUTTON(lock_screen_button), image); + gtk_button_set_alignment(GTK_BUTTON(lock_screen_button), 0.0, 0.5); + g_signal_connect(G_OBJECT(lock_screen_button), "clicked", G_CALLBACK(lock_screen_clicked), &handler_context); + gtk_box_pack_start(GTK_BOX(controls), lock_screen_button, FALSE, FALSE, 4); + } + /* Create the Logout button. */ GtkWidget * logout_button = gtk_button_new_with_mnemonic(_("_Logout")); GtkWidget * image = gtk_image_new_from_icon_name("system-log-out", GTK_ICON_SIZE_BUTTON);