------------------------- dbus-interface.h ------------------------------ /** * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _DBUS_INTERFACE_H #define _DBUS_INTERFACE_H #include /* Interface to ConsoleKit for shutdown and reboot. */ extern gboolean dbus_ConsoleKit_CanStop(void); extern gboolean dbus_ConsoleKit_CanRestart(void); extern char * dbus_ConsoleKit_Stop(void); extern char * dbus_ConsoleKit_Restart(void); /* Interface to UPower for suspend and hibernate. */ extern gboolean dbus_UPower_CanSuspend(void); extern gboolean dbus_UPower_CanHibernate(void); extern char * dbus_UPower_Suspend(void); extern char * dbus_UPower_Hibernate(void); /* Interface to HAL for shutdown, reboot, suspend, and hibernate. * HAL is being replaced by the above two mechanisms; this support is legacy. */ extern gboolean dbus_HAL_CanShutdown(void); extern gboolean dbus_HAL_CanReboot(void); extern gboolean dbus_HAL_CanSuspend(void); extern gboolean dbus_HAL_CanHibernate(void); extern char * dbus_HAL_Shutdown(void); extern char * dbus_HAL_Reboot(void); 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 ----------------------------- dbus-interface.c ------------------------ /** * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #ifdef HAVE_DBUS #include #endif /*** Mechanism independent ***/ #ifdef HAVE_DBUS /* D-Bus context. */ static struct { int connection_tried : 1; /* True if connection has been tried */ DBusConnection * connection; /* Handle for connection */ } dbus_context; enum { DBUS_TIMEOUT = 2000 }; /* Reply timeout */ /* FORWARDS */ gboolean dbus_ConsoleKit_CanStop(void); gboolean dbus_ConsoleKit_CanRestart(void); char * dbus_ConsoleKit_Stop(void); char * dbus_ConsoleKit_Restart(void); gboolean dbus_UPower_CanSuspend(void); gboolean dbus_UPower_CanHibernate(void); char * dbus_UPower_Suspend(void); char * dbus_UPower_Hibernate(void); gboolean dbus_HAL_CanShutdown(void); gboolean dbus_HAL_CanReboot(void); gboolean dbus_HAL_CanSuspend(void); gboolean dbus_HAL_CanHibernate(void); char * dbus_HAL_Shutdown(void); 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_system(void) { DBusError error; dbus_error_init(&error); dbus_context.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); if (dbus_context.connection == NULL) { g_warning(G_STRLOC ": Failed to connect to the system message bus: %s", error.message); 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_system(DBusMessage * message, char * * error_text) { /* Get a connection handle. */ 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; /* 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; } /* Read a result for a method that returns void. */ static char * dbus_read_result_void(DBusMessage * reply) { if (reply != NULL) dbus_message_unref(reply); /* No result. Assume success. */ return NULL; } /* Read a result for a method that returns boolean. */ static gboolean dbus_read_result_boolean(DBusMessage * reply) { gboolean result = FALSE; if (reply != NULL) { /* Get the boolean result. */ DBusError error; dbus_error_init(&error); dbus_bool_t status = dbus_message_get_args( reply, &error, DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID); dbus_message_unref(reply); if ( ! status) { g_warning(G_STRLOC ": DBUS: %s", error.message); dbus_error_free(&error); return FALSE; } } 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 ***/ #ifdef HAVE_DBUS /* Formulate a message to the ConsoleKit Manager interface. */ static DBusMessage * dbus_ConsoleKit_formulate_message(const char * const query) { return dbus_message_new_method_call( "org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", query); } #endif /* Send a specified message to the ConsoleKit interface and process a boolean result. */ static gboolean dbus_ConsoleKit_query(const char * const query) { #ifdef HAVE_DBUS return dbus_read_result_boolean(dbus_send_message_system(dbus_ConsoleKit_formulate_message(query), NULL)); #else return FALSE; #endif } /* Send a specified message to the ConsoleKit interface and process a void result. */ static char * dbus_ConsoleKit_command(const char * const command) { #ifdef HAVE_DBUS char * error = NULL; dbus_read_result_void(dbus_send_message_system(dbus_ConsoleKit_formulate_message(command), &error)); return error; #else return NULL; #endif } /* Invoke the CanStop method on ConsoleKit. */ gboolean dbus_ConsoleKit_CanStop(void) { return dbus_ConsoleKit_query("CanStop"); } /* Invoke the CanRestart method on ConsoleKit. */ gboolean dbus_ConsoleKit_CanRestart(void) { return dbus_ConsoleKit_query("CanRestart"); } /* Invoke the Stop method on ConsoleKit. */ char * dbus_ConsoleKit_Stop(void) { return dbus_ConsoleKit_command("Stop"); } /* Invoke the Restart method on ConsoleKit. */ char * dbus_ConsoleKit_Restart(void) { return dbus_ConsoleKit_command("Restart"); } /*** UPower mechanism ***/ #ifdef HAVE_DBUS /* Formulate a message to the UPower interface. */ static DBusMessage * dbus_UPower_formulate_command(const char * const command) { return dbus_message_new_method_call( "org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", command); } #endif /* Send a specified message to the UPower interface and process a boolean result. */ static gboolean dbus_UPower_query(const char * const query) { #ifdef HAVE_DBUS /* Formulate a message to the Properties interface. */ DBusMessage * message = dbus_message_new_method_call( "org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", "Get"); const char * const interface_name = "org.freedesktop.UPower"; dbus_message_append_args(message, DBUS_TYPE_STRING, &interface_name, DBUS_TYPE_STRING, &query, DBUS_TYPE_INVALID); /* Send the message. */ DBusMessage * reply = dbus_send_message_system(message, NULL); if (reply == NULL) return FALSE; /* The return type is VARIANT expected to contain BOOLEAN. */ gboolean result = FALSE; DBusMessageIter iter; DBusMessageIter inner; dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) { dbus_message_iter_recurse(&iter, &inner); if (dbus_message_iter_get_arg_type(&inner) == DBUS_TYPE_BOOLEAN) dbus_message_iter_get_basic(&inner, &result); } dbus_message_unref(reply); return result; #else return FALSE; #endif } /* Send a specified message to the UPower interface and process a void result. */ static char * dbus_UPower_command(const char * const command) { #ifdef HAVE_DBUS char * error = NULL; dbus_read_result_void(dbus_send_message_system(dbus_UPower_formulate_command(command), &error)); return error; #else return NULL; #endif } /* Read the can-suspend property of UPower. */ gboolean dbus_UPower_CanSuspend(void) { return dbus_UPower_query("CanSuspend"); } /* Read the can-hibernate property of UPower. */ gboolean dbus_UPower_CanHibernate(void) { return dbus_UPower_query("CanHibernate"); } /* Invoke the Suspend method on UPower. */ char * dbus_UPower_Suspend(void) { return dbus_UPower_command("Suspend"); } /* Invoke the Hibernate method on UPower. */ char * dbus_UPower_Hibernate(void) { return dbus_UPower_command("Hibernate"); } /*** HAL mechanism ***/ #ifdef HAVE_DBUS /* Formulate a message to the HAL SystemPowerManagement interface. */ static DBusMessage * dbus_HAL_formulate_message(const char * const query) { return dbus_message_new_method_call( "org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer", "org.freedesktop.Hal.Device.SystemPowerManagement", query); } /* Formulate a message to the HAL SystemPowerManagement interface to query a property. */ static DBusMessage * dbus_HAL_formulate_property_query(const char * const method, const char * const property) { DBusMessage * message = dbus_message_new_method_call( "org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer", "org.freedesktop.Hal.Device", method); if (message != NULL) dbus_message_append_args(message, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); return message; } /* Formulate a message to the HAL SystemPowerManagement interface to query a boolean property. */ static DBusMessage * dbus_HAL_formulate_boolean_property_query(const char * const property) { return dbus_HAL_formulate_property_query("GetPropertyBoolean", property); } /* Formulate a message to the HAL SystemPowerManagement interface to query a string property. */ static DBusMessage * dbus_HAL_formulate_string_property_query(const char * const property) { return dbus_HAL_formulate_property_query("GetPropertyString", property); } #endif /* Send a specified property query to the HAL interface and process whether the result exists. */ static gboolean dbus_HAL_string_exists_query(const char * const property) { #ifdef HAVE_DBUS DBusMessage * message = dbus_HAL_formulate_string_property_query(property); if (message == NULL) return FALSE; DBusMessage * reply = dbus_send_message_system(message, NULL); if (reply == NULL) return FALSE; dbus_message_unref(reply); return TRUE; #else return FALSE; #endif } /* Send a specified property query to the HAL interface and process a boolean result. */ static gboolean dbus_HAL_boolean_query(const char * const property) { #ifdef HAVE_DBUS return dbus_read_result_boolean(dbus_send_message_system(dbus_HAL_formulate_boolean_property_query(property), NULL)); #else return FALSE; #endif } /* Send a specified message to the HAL interface and process a void result. */ static char * dbus_HAL_command(const char * const command) { #ifdef HAVE_DBUS /* Formulate the message. */ DBusMessage * message = dbus_HAL_formulate_message(command); if (message == NULL) return NULL; /* Suspend has an argument. */ if (strcmp(command, "Suspend") == 0) { dbus_int32_t suspend_arg = 0; dbus_message_append_args(message, DBUS_TYPE_INT32, &suspend_arg, DBUS_TYPE_INVALID); } /* Send the message and wait for a reply. */ char * error = NULL; dbus_read_result_void(dbus_send_message_system(message, &error)); return error; #else return NULL; #endif } /* Read the can-shutdown property of HAL. */ gboolean dbus_HAL_CanShutdown(void) { return dbus_HAL_string_exists_query("power_management.type"); } /* Read the can-reboot property of HAL. */ gboolean dbus_HAL_CanReboot(void) { return dbus_HAL_string_exists_query("power_management.type"); } /* Read the can-suspend property of HAL. */ gboolean dbus_HAL_CanSuspend(void) { return dbus_HAL_boolean_query("power_management.can_suspend"); } /* Read the can-hibernate property of HAL. */ gboolean dbus_HAL_CanHibernate(void) { return dbus_HAL_boolean_query("power_management.can_hibernate"); } /* Invoke the Shutdown method on HAL. */ char * dbus_HAL_Shutdown(void) { return dbus_HAL_command("Shutdown"); } /* Invoke the Reboot method on HAL. */ char * dbus_HAL_Reboot(void) { return dbus_HAL_command("Reboot"); } /* Invoke the Suspend method on HAL. */ char * dbus_HAL_Suspend(void) { return dbus_HAL_command("Suspend"); } /* Invoke the Hibernate method on HAL. */ char * dbus_HAL_Hibernate(void) { 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"); } --------------------------- lxsession-logout.c ----------------------------- /** * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dbus-interface.h" /* Command parameters. */ static char * prompt = NULL; static char * banner_side = NULL; static char * banner_path = NULL; static GOptionEntry opt_entries[] = { { "prompt", 'p', 0, G_OPTION_ARG_STRING, &prompt, N_("Custom message to show on the dialog"), N_("message") }, { "banner", 'b', 0, G_OPTION_ARG_STRING, &banner_path, N_("Banner to show on the dialog"), N_("image file") }, { "side", 's', 0, G_OPTION_ARG_STRING, &banner_side, N_("Position of the banner"), "top|left|right|bottom" }, { NULL } }; typedef struct { GPid lxsession_pid; /* Process ID of lxsession */ GtkWidget * error_label; /* Text of an error, if we get one */ int shutdown_available : 1; /* Shutdown is available */ int reboot_available : 1; /* Reboot is available */ int suspend_available : 1; /* Suspend is available */ int hibernate_available : 1; /* Hibernate is available */ int switch_user_available : 1; /* Switch User is available */ int shutdown_ConsoleKit : 1; /* Shutdown is available via ConsoleKit */ int reboot_ConsoleKit : 1; /* Reboot is available via ConsoleKit */ int suspend_UPower : 1; /* Suspend is available via UPower */ int hibernate_UPower : 1; /* Hibernate is available via UPower */ int shutdown_HAL : 1; /* Shutdown is available via HAL */ 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_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); static void shutdown_clicked(GtkButton * button, HandlerContext * handler_context); static void reboot_clicked(GtkButton * button, HandlerContext * handler_context); static void suspend_clicked(GtkButton * button, HandlerContext * handler_context); static void hibernate_clicked(GtkButton * button, HandlerContext * handler_context); static void switch_user_clicked(GtkButton * button, HandlerContext * handler_context); static void cancel_clicked(GtkButton * button, gpointer user_data); static GtkPositionType get_banner_position(void); static GdkPixbuf * get_background_pixbuf(void); gboolean expose_event(GtkWidget * widget, GdkEventExpose * event, GdkPixbuf * pixbuf); /* Try to run lxlock command in order to lock the screen, return TRUE on * success, FALSE if command execution failed */ static gboolean lock_screen(void) { 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) { /* See if the executable we need to run is in the path. */ gchar * full_path = g_find_program_in_path(executable); if (full_path != NULL) { g_free(full_path); /* Form the filespec of the pid file for the display manager. */ char buffer[PATH_MAX]; sprintf(buffer, "/var/run/%s.pid", display_manager); /* Open the pid file. */ int fd = open(buffer, O_RDONLY); if (fd >= 0) { /* Pid file exists. Read it. */ ssize_t length = read(fd, buffer, sizeof(buffer)); close(fd); if (length > 0) { /* Null terminate the buffer and convert the pid. */ buffer[length] = '\0'; pid_t pid = atoi(buffer); if (pid > 0) { /* Form the filespec of the command line file under /proc. * This is Linux specific. Should be conditionalized to the appropriate /proc layout for * other systems. Your humble developer has no way to test on other systems. */ sprintf(buffer, "/proc/%d/cmdline", pid); /* Open the file. */ int fd = open(buffer, O_RDONLY); if (fd >= 0) { /* Read the command line. */ ssize_t length = read(fd, buffer, sizeof(buffer)); close(fd); if (length > 0) { /* Null terminate the buffer and look for the display manager name in the command. * If found, return success. */ buffer[length] = '\0'; if (strstr(buffer, display_manager) != NULL) return TRUE; } } } } } } return FALSE; } /* Handler for "clicked" signal on Logout button. */ static void logout_clicked(GtkButton * button, HandlerContext * handler_context) { kill(handler_context->lxsession_pid, SIGTERM); gtk_main_quit(); } /* Replace a property on the root window. */ static void change_root_property(GtkWidget* w, const char* prop_name, const char* value) { GdkDisplay* dpy = gtk_widget_get_display(w); GdkWindow* root = gtk_widget_get_root_window(w); XChangeProperty(GDK_DISPLAY_XDISPLAY(dpy), GDK_WINDOW_XID(root), XInternAtom(GDK_DISPLAY_XDISPLAY(dpy), prop_name, False), XA_STRING, 8, PropModeReplace, (unsigned char*) value, strlen(value) + 1); } /* Handler for "clicked" signal on Shutdown button. */ static void shutdown_clicked(GtkButton * button, HandlerContext * handler_context) { char * error_result = NULL; gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL); if (handler_context->ltsp) { change_root_property(GTK_WIDGET(button), "LTSP_LOGOUT_ACTION", "HALT"); kill(handler_context->lxsession_pid, SIGTERM); } else if (handler_context->shutdown_ConsoleKit) 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); else gtk_main_quit(); } /* Handler for "clicked" signal on Reboot button. */ static void reboot_clicked(GtkButton * button, HandlerContext * handler_context) { char * error_result = NULL; gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL); if (handler_context->ltsp) { change_root_property(GTK_WIDGET(button), "LTSP_LOGOUT_ACTION", "REBOOT"); kill(handler_context->lxsession_pid, SIGTERM); } else if (handler_context->reboot_ConsoleKit) 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); else gtk_main_quit(); } /* Handler for "clicked" signal on Suspend button. */ static void suspend_clicked(GtkButton * button, HandlerContext * handler_context) { char * error_result = NULL; gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL); lock_screen(); if (handler_context->suspend_UPower) 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); else gtk_main_quit(); } /* Handler for "clicked" signal on Hibernate button. */ static void hibernate_clicked(GtkButton * button, HandlerContext * handler_context) { char * error_result = NULL; gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL); lock_screen(); if (handler_context->hibernate_UPower) 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); else gtk_main_quit(); } /* Handler for "clicked" signal on Switch User button. */ static void switch_user_clicked(GtkButton * button, HandlerContext * handler_context) { gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL); lock_screen(); if (handler_context->switch_user_GDM) 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(); } /* Handler for "clicked" signal on Cancel button. */ static void cancel_clicked(GtkButton * button, gpointer user_data) { gtk_main_quit(); } /* Convert the --side parameter to a GtkPositionType. */ static GtkPositionType get_banner_position(void) { if (banner_side != NULL) { if (strcmp(banner_side, "right") == 0) return GTK_POS_RIGHT; if (strcmp(banner_side, "top") == 0) return GTK_POS_TOP; if (strcmp(banner_side, "bottom") == 0) return GTK_POS_BOTTOM; } return GTK_POS_LEFT; } /* Get the background pixbuf. */ static GdkPixbuf * get_background_pixbuf(void) { /* Get the root window pixmap. */ GdkScreen * screen = gdk_screen_get_default(); #ifdef ENABLE_GTK3 GdkPixbuf * pixbuf = gdk_pixbuf_get_from_window( gdk_get_default_root_window(), 0, 0, gdk_screen_get_width(screen), /* Width */ gdk_screen_get_height(screen)); /* Height */ #else GdkPixbuf * pixbuf = gdk_pixbuf_get_from_drawable( NULL, /* Allocate a new pixbuf */ gdk_get_default_root_window(), /* The drawable */ NULL, /* Its colormap */ 0, 0, 0, 0, /* Coordinates */ gdk_screen_get_width(screen), /* Width */ gdk_screen_get_height(screen)); /* Height */ #endif /* Make the background darker. */ if (pixbuf != NULL) { unsigned char * pixels = gdk_pixbuf_get_pixels(pixbuf); int width = gdk_pixbuf_get_width(pixbuf); int height = gdk_pixbuf_get_height(pixbuf); int pixel_stride = ((gdk_pixbuf_get_has_alpha(pixbuf)) ? 4 : 3); int row_stride = gdk_pixbuf_get_rowstride(pixbuf); int y; for (y = 0; y < height; y += 1) { unsigned char * p = pixels; int x; for (x = 0; x < width; x += 1) { p[0] = p[0] / 2; p[1] = p[1] / 2; p[2] = p[2] / 2; p += pixel_stride; } pixels += row_stride; } } return pixbuf; } /* Handler for "expose_event" on background. */ gboolean expose_event(GtkWidget * widget, GdkEventExpose * event, GdkPixbuf * pixbuf) { if (pixbuf != NULL) { /* Copy the appropriate rectangle of the root window pixmap to the drawing area. * All drawing areas are immediate children of the toplevel window, so the allocation yields the source coordinates directly. */ #if GTK_CHECK_VERSION(2,14,0) cairo_t * cr = gdk_cairo_create (gtk_widget_get_window(widget)); #else cairo_t * cr = gdk_cairo_create (widget->window); #endif gdk_cairo_set_source_pixbuf ( cr, pixbuf, 0, 0); cairo_paint (cr); cairo_destroy(cr); } return FALSE; } /* Main program. */ int main(int argc, char * argv[]) { #ifdef ENABLE_NLS setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif /* Initialize GTK (via g_option_context_parse) and parse command line arguments. */ GOptionContext * context = g_option_context_new(""); g_option_context_add_main_entries(context, opt_entries, GETTEXT_PACKAGE); g_option_context_add_group(context, gtk_get_option_group(TRUE)); GError * err = NULL; if ( ! g_option_context_parse(context, &argc, &argv, &err)) { g_print(_("Error: %s\n"), err->message); g_error_free(err); return 1; } g_option_context_free(context); HandlerContext handler_context; memset(&handler_context, 0, sizeof(handler_context)); /* Ensure that we are running under lxsession. */ const char * p = g_getenv("_LXSESSION_PID"); if (p != NULL) handler_context.lxsession_pid = atoi(p); if (handler_context.lxsession_pid == 0) { g_print( _("Error: %s\n"), _("LXSession is not running.")); return 1; } /* Initialize capabilities of the ConsoleKit mechanism. */ if (dbus_ConsoleKit_CanStop()) { handler_context.shutdown_available = TRUE; handler_context.shutdown_ConsoleKit = TRUE; } if (dbus_ConsoleKit_CanRestart()) { handler_context.reboot_available = TRUE; handler_context.reboot_ConsoleKit = TRUE; } /* Initialize capabilities of the UPower mechanism. */ if (dbus_UPower_CanSuspend()) { handler_context.suspend_available = TRUE; handler_context.suspend_UPower = TRUE; } if (dbus_UPower_CanHibernate()) { handler_context.hibernate_available = TRUE; handler_context.hibernate_UPower = TRUE; } /* Initialize capabilities of the HAL mechanism. */ if (!handler_context.shutdown_available && dbus_HAL_CanShutdown()) { handler_context.shutdown_available = TRUE; handler_context.shutdown_HAL = TRUE; } if (!handler_context.reboot_available && dbus_HAL_CanReboot()) { handler_context.reboot_available = TRUE; handler_context.reboot_HAL = TRUE; } if (!handler_context.suspend_available && dbus_HAL_CanSuspend()) { handler_context.suspend_available = TRUE; handler_context.suspend_HAL = TRUE; } if (!handler_context.hibernate_available && dbus_HAL_CanHibernate()) { handler_context.hibernate_available = TRUE; 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")) { handler_context.switch_user_available = TRUE; 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")) { handler_context.switch_user_available = TRUE; handler_context.switch_user_KDM = TRUE; } /* 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"); /* Get the background pixbuf. */ GdkPixbuf * pixbuf = get_background_pixbuf(); /* Create the toplevel window. */ GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_decorated(GTK_WINDOW(window), FALSE); gtk_window_fullscreen(GTK_WINDOW(window)); GdkScreen* screen = gtk_widget_get_screen(window); gtk_window_set_default_size(GTK_WINDOW(window), gdk_screen_get_width(screen), gdk_screen_get_height(screen)); gtk_widget_set_app_paintable(window, TRUE); g_signal_connect(G_OBJECT(window), "expose_event", G_CALLBACK(expose_event), pixbuf); /* Toplevel container */ GtkWidget* alignment = gtk_alignment_new(0.5, 0.5, 0.0, 0.0); gtk_container_add(GTK_CONTAINER(window), alignment); GtkWidget* center_area = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(alignment), center_area); GtkWidget* center_vbox = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(center_vbox), 12); gtk_container_add(GTK_CONTAINER(center_area), center_vbox); GtkWidget* controls = gtk_vbox_new(FALSE, 6); /* If specified, apply a user-specified banner image. */ if (banner_path != NULL) { GtkWidget * banner_image = gtk_image_new_from_file(banner_path); GtkPositionType banner_position = get_banner_position(); switch (banner_position) { case GTK_POS_LEFT: case GTK_POS_RIGHT: { /* Create a horizontal box to contain the image and the controls. */ GtkWidget * box = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(center_vbox), box, FALSE, FALSE, 0); /* Pack the image and a separator. */ gtk_misc_set_alignment(GTK_MISC(banner_image), 0.5, 0.0); if (banner_position == GTK_POS_LEFT) { gtk_box_pack_start(GTK_BOX(box), banner_image, FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(box), gtk_vseparator_new(), FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(box), controls, FALSE, FALSE, 2); } else { gtk_box_pack_start(GTK_BOX(box), controls, FALSE, FALSE, 2); gtk_box_pack_end(GTK_BOX(box), gtk_vseparator_new(), FALSE, FALSE, 2); gtk_box_pack_end(GTK_BOX(box), banner_image, FALSE, FALSE, 2); } } break; case GTK_POS_TOP: gtk_box_pack_start(GTK_BOX(controls), banner_image, FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(controls), gtk_hseparator_new(), FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(center_vbox), controls, FALSE, FALSE, 0); break; case GTK_POS_BOTTOM: gtk_box_pack_end(GTK_BOX(controls), banner_image, FALSE, FALSE, 2); gtk_box_pack_end(GTK_BOX(controls), gtk_hseparator_new(), FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(center_vbox), controls, FALSE, FALSE, 0); break; } } else gtk_box_pack_start(GTK_BOX(center_vbox), controls, FALSE, FALSE, 0); /* Create the label. */ GtkWidget * label = gtk_label_new(""); if (prompt == NULL) { const char * session_name = g_getenv("DESKTOP_SESSION"); if (session_name == NULL) session_name = "LXDE"; prompt = g_strdup_printf(_("Logout %s session?"), session_name); } gtk_label_set_markup(GTK_LABEL(label), prompt); gtk_box_pack_start(GTK_BOX(controls), label, FALSE, FALSE, 4); /* Create the Shutdown button. */ if (handler_context.shutdown_available) { GtkWidget * shutdown_button = gtk_button_new_with_mnemonic(_("Sh_utdown")); GtkWidget * image = gtk_image_new_from_icon_name("system-shutdown", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(shutdown_button), image); gtk_button_set_alignment(GTK_BUTTON(shutdown_button), 0.0, 0.5); g_signal_connect(G_OBJECT(shutdown_button), "clicked", G_CALLBACK(shutdown_clicked), &handler_context); gtk_box_pack_start(GTK_BOX(controls), shutdown_button, FALSE, FALSE, 4); } /* Create the Reboot button. */ if (handler_context.reboot_available) { GtkWidget * reboot_button = gtk_button_new_with_mnemonic(_("_Reboot")); GtkWidget * image = gtk_image_new_from_icon_name("gnome-session-reboot", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(reboot_button), image); gtk_button_set_alignment(GTK_BUTTON(reboot_button), 0.0, 0.5); g_signal_connect(G_OBJECT(reboot_button), "clicked", G_CALLBACK(reboot_clicked), &handler_context); gtk_box_pack_start(GTK_BOX(controls), reboot_button, FALSE, FALSE, 4); } /* Create the Suspend button. */ if (handler_context.suspend_available && !handler_context.ltsp) { GtkWidget * suspend_button = gtk_button_new_with_mnemonic(_("_Suspend")); GtkWidget * image = gtk_image_new_from_icon_name("gnome-session-suspend", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(suspend_button), image); gtk_button_set_alignment(GTK_BUTTON(suspend_button), 0.0, 0.5); g_signal_connect(G_OBJECT(suspend_button), "clicked", G_CALLBACK(suspend_clicked), &handler_context); gtk_box_pack_start(GTK_BOX(controls), suspend_button, FALSE, FALSE, 4); } /* Create the Hibernate button. */ if (handler_context.hibernate_available && !handler_context.ltsp) { GtkWidget * hibernate_button = gtk_button_new_with_mnemonic(_("_Hibernate")); GtkWidget * image = gtk_image_new_from_icon_name("gnome-session-hibernate", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(hibernate_button), image); gtk_button_set_alignment(GTK_BUTTON(hibernate_button), 0.0, 0.5); g_signal_connect(G_OBJECT(hibernate_button), "clicked", G_CALLBACK(hibernate_clicked), &handler_context); gtk_box_pack_start(GTK_BOX(controls), hibernate_button, FALSE, FALSE, 4); } /* Create the Switch User button. */ if (handler_context.switch_user_available && !handler_context.ltsp) { GtkWidget * switch_user_button = gtk_button_new_with_mnemonic(_("S_witch User")); GtkWidget * image = gtk_image_new_from_icon_name("gnome-session-switch", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(switch_user_button), image); gtk_button_set_alignment(GTK_BUTTON(switch_user_button), 0.0, 0.5); g_signal_connect(G_OBJECT(switch_user_button), "clicked", G_CALLBACK(switch_user_clicked), &handler_context); 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); gtk_button_set_image(GTK_BUTTON(logout_button), image); gtk_button_set_alignment(GTK_BUTTON(logout_button), 0.0, 0.5); g_signal_connect(G_OBJECT(logout_button), "clicked", G_CALLBACK(logout_clicked), &handler_context); gtk_box_pack_start(GTK_BOX(controls), logout_button, FALSE, FALSE, 4); /* Create the Cancel button. */ GtkWidget * cancel_button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); gtk_button_set_alignment(GTK_BUTTON(cancel_button), 0.0, 0.5); g_signal_connect(G_OBJECT(cancel_button), "clicked", G_CALLBACK(cancel_clicked), NULL); gtk_box_pack_start(GTK_BOX(controls), cancel_button, FALSE, FALSE, 4); /* Create the error text. */ handler_context.error_label = gtk_label_new(""); gtk_label_set_justify(GTK_LABEL(handler_context.error_label), GTK_JUSTIFY_CENTER); gtk_box_pack_start(GTK_BOX(controls), handler_context.error_label, FALSE, FALSE, 4); /* Show everything. */ gtk_widget_show_all(window); /* Run the main event loop. */ gtk_main(); /* Return. */ return 0; }