Merge branch 'backport' into 3.4-working
authorDana Jansens <danakj@orodu.net>
Sun, 2 Mar 2008 08:47:02 +0000 (03:47 -0500)
committerDana Jansens <danakj@orodu.net>
Sun, 2 Mar 2008 08:47:02 +0000 (03:47 -0500)
Conflicts:

openbox/actions/all.h

Makefile.am
data/menu.xml
openbox/actions/all.c
openbox/actions/all.h
openbox/actions/exit.c
openbox/actions/session.c [new file with mode: 0644]
openbox/prompt.c
openbox/session.c
openbox/session.h
tools/gdm-control/Makefile [new file with mode: 0644]
tools/gdm-control/gdm-control.c [new file with mode: 0644]

index c0822f8..c8ae71d 100644 (file)
@@ -30,6 +30,7 @@ lib_LTLIBRARIES = \
 
 bin_PROGRAMS = \
        openbox/openbox \
+       tools/gdm-control/gdm-control \
        tools/gnome-panel-control/gnome-panel-control
 
 dist_secretbin_SCRIPTS = \
@@ -174,6 +175,7 @@ openbox_openbox_SOURCES = \
        openbox/actions/iconify.c \
        openbox/actions/kill.c \
        openbox/actions/layer.c \
+       openbox/actions/session.c \
        openbox/actions/lower.c \
        openbox/actions/maximize.c \
        openbox/actions/move.c \
@@ -286,6 +288,17 @@ tools_gnome_panel_control_gnome_panel_control_LDADD = \
 tools_gnome_panel_control_gnome_panel_control_SOURCES = \
        tools/gnome-panel-control/gnome-panel-control.c
 
+## gdm-control ##
+
+tools_gdm_control_gdm_control_CPPFLAGS = \
+       $(X_CFLAGS) \
+       $(GLIB_CFLAGS)
+tools_gdm_control_gdm_control_LDADD = \
+       $(X_LIBS) \
+       $(GLIB_LIBS)
+tools_gdm_control_gdm_control_SOURCES = \
+       tools/gdm-control/gdm-control.c
+
 
 ## default button masks ##
 dist_docxbm_DATA = \
index d19bda6..b37a552 100644 (file)
   </item>
 </menu>
 
+<menu id="system-menu" label="System">
+  <item label="Openbox Configuration Manager">
+    <action name="Execute">
+      <command>obconf</command>
+      <startupnotify><enabled>yes</enabled></startupnotify>
+    </action>
+  </item>
+  <item label="Gnome Control Center">
+    <action name="Execute">
+      <command>gnome-control-center</command>
+      <startupnotify><enabled>yes</enabled></startupnotify>
+    </action>
+  </item>
+  <item label="KDE Control Center">
+    <action name="Execute">
+      <command>kcontrol</command>
+      <startupnotify><enabled>yes</enabled></startupnotify>
+    </action>
+  </item>
+  <separator />
+  <item label="Reconfigure Openbox">
+    <action name="Reconfigure" />
+  </item>
+  <item label="Exit Openbox">
+    <action name="Exit">
+      <prompt>yes</prompt>
+    </action>
+  </item>
+</menu>
+
 <menu id="root-menu" label="Openbox 3">
   <separator label="Applications" />
   <menu id="apps-accessories-menu"/>
   <menu id="apps-term-menu"/>
   <menu id="apps-fileman-menu"/>
   <separator label="System" />
-  <item label="ObConf">
-    <action name="Execute">
-      <command>obconf</command>
-      <startupnotify><enabled>yes</enabled></startupnotify>
-    </action>
-  </item>
-  <item label="Reconfigure">
-    <action name="Reconfigure" />
-  </item>
+  <menu id="system-menu"/>
   <separator />
-  <item label="Exit">
-    <action name="Exit">
+  <item label="Logout">
+    <action name="SessionLogout">
       <prompt>yes</prompt>
     </action>
   </item>
index ac5b389..5a89997 100644 (file)
@@ -9,6 +9,7 @@ void action_all_startup(void)
     action_reconfigure_startup();
     action_exit_startup();
     action_restart_startup();
+    action_session_startup();
     action_cyclewindows_startup();
     action_breakchroot_startup();
     action_close_startup();
index c84322f..d6676a4 100644 (file)
@@ -10,6 +10,7 @@ void action_showdesktop_startup(void);
 void action_reconfigure_startup(void);
 void action_exit_startup(void);
 void action_restart_startup(void);
+void action_session_startup(void);
 void action_cyclewindows_startup(void);
 void action_breakchroot_startup(void);
 void action_close_startup(void);
index 19b78e9..747514f 100644 (file)
@@ -21,6 +21,7 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     Options *o;
 
     o = g_new0(Options, 1);
+    o->prompt = TRUE;
 
     if ((n = parse_find_node("prompt", node)))
         o->prompt = parse_bool(doc, n);
diff --git a/openbox/actions/session.c b/openbox/actions/session.c
new file mode 100644 (file)
index 0000000..0117e07
--- /dev/null
@@ -0,0 +1,71 @@
+#include "openbox/actions.h"
+#include "openbox/prompt.h"
+#include "openbox/session.h"
+#include "gettext.h"
+
+#ifndef USE_SM
+void action_logout_startup(void) {}
+#else
+
+typedef struct {
+    gboolean prompt;
+    gboolean silent;
+} Options;
+
+static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gboolean logout_func(ObActionsData *data, gpointer options);
+
+void action_session_startup(void)
+{
+    actions_register("SessionLogout", setup_func, NULL, logout_func,
+                     NULL, NULL);
+}
+
+static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+{
+    xmlNodePtr n;
+    Options *o;
+
+    o = g_new0(Options, 1);
+    o->prompt = TRUE;
+
+    if ((n = parse_find_node("prompt", node)))
+        o->prompt = parse_bool(doc, n);
+
+    return o;
+}
+
+static void prompt_cb(ObPrompt *p, gint result, gpointer data)
+{
+    Options *o = data;
+    if (result)
+        session_request_logout(o->silent);
+    g_free(o);
+    prompt_unref(p);
+}
+
+/* Always return FALSE because its not interactive */
+static gboolean logout_func(ObActionsData *data, gpointer options)
+{
+    Options *o = options;
+
+    if (o->prompt) {
+        Options *o2;
+        ObPrompt *p;
+        ObPromptAnswer answers[] = {
+            { _("Cancel"), 0 },
+            { _("Log out"), 1 }
+        };
+
+        o2 = g_memdup(o, sizeof(Options));
+        p = prompt_new(_("Are you sure you want to log out?"),
+                       answers, 2, 0, 0, prompt_cb, o2);
+        prompt_show(p, NULL, FALSE);
+    }
+    else
+        prompt_cb(NULL, 1, NULL);
+
+    return FALSE;
+}
+
+#endif
index d3a1ab7..0278757 100644 (file)
@@ -264,7 +264,6 @@ static void prompt_layout(ObPrompt *self)
         self->button[i].width = bw;
         self->button[i].height = bh;
         RrMinSize(prompt_a_focus, &bw, &bh);
-        g_print("button w %d h %d\n", bw, bh);
         self->button[i].width = MAX(self->button[i].width, bw);
         self->button[i].height = MAX(self->button[i].height, bh);
         RrMinSize(prompt_a_press, &bw, &bh);
@@ -388,8 +387,6 @@ static void setup_button_focus_tex(ObPromptElement *e, RrAppearance *a,
     a->texture[4].data.lineart.x2 = e->width - r - 1;
     a->texture[4].data.lineart.y1 = t;
     a->texture[4].data.lineart.y2 = e->height - b - 1;
-
-    g_print("setting x2 %d\n", e->width - r - 1);
 }
 
 static void render_button(ObPrompt *self, ObPromptElement *e)
@@ -508,8 +505,6 @@ gboolean prompt_key_event(ObPrompt *self, XEvent *e)
 
     if (e->type != KeyPress) return FALSE;
 
-    g_print("key 0x%x 0x%x\n", e->xkey.keycode, ob_keycode(OB_KEY_TAB));
-
     shift_mask = modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT);
     shift = !!(e->xkey.state & shift_mask);
 
index 80b4da4..59faa30 100644 (file)
@@ -33,6 +33,7 @@ GSList *session_desktop_names = NULL;
 void session_startup(gint argc, gchar **argv) {}
 void session_shutdown(gboolean permanent) {}
 GList* session_state_find(struct _ObClient *c) { return NULL; }
+void session_request_logout(gboolean silent) {}
 #else
 
 #include "debug.h"
@@ -804,4 +805,20 @@ static void session_load_file(const gchar *path)
     xmlFreeDoc(doc);
 }
 
+void session_request_logout(gboolean silent)
+{
+    if (sm_conn) {
+        SmcRequestSaveYourself(sm_conn,
+                               SmSaveBoth,
+                               TRUE, /* logout */
+                               (silent ?
+                                SmInteractStyleNone : SmInteractStyleAny),
+                               TRUE,  /* if false, with GSM, it shows the old
+                                         logout prompt */
+                               TRUE); /* global */
+    }
+    else
+        g_message(_("Not connected to a session manager"));
+}
+
 #endif
index b4ce6d9..e2307a6 100644 (file)
@@ -53,4 +53,6 @@ void session_shutdown(gboolean permanent);
 
 GList* session_state_find(struct _ObClient *c);
 
+void session_request_logout(gboolean silent);
+
 #endif
diff --git a/tools/gdm-control/Makefile b/tools/gdm-control/Makefile
new file mode 100644 (file)
index 0000000..cfc4653
--- /dev/null
@@ -0,0 +1,4 @@
+all clean install:
+       $(MAKE) -C ../.. -$(MAKEFLAGS) $@
+
+.PHONY: all clean install
diff --git a/tools/gdm-control/gdm-control.c b/tools/gdm-control/gdm-control.c
new file mode 100644 (file)
index 0000000..b3178e5
--- /dev/null
@@ -0,0 +1,295 @@
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xauth.h>
+
+#include <glib.h>
+
+typedef enum
+{
+    INVALID,
+    NONE,
+    SHUTDOWN,
+    REBOOT,
+    SUSPEND,
+    SWITCHUSER
+} Action;
+
+#define GDM_PROTOCOL_SOCKET_PATH1 "/var/run/gdm_socket"
+#define GDM_PROTOCOL_SOCKET_PATH2 "/tmp/.gdm_socket"
+
+#define GDM_PROTOCOL_MSG_CLOSE         "CLOSE"
+#define GDM_PROTOCOL_MSG_VERSION       "VERSION"
+#define GDM_PROTOCOL_MSG_AUTHENTICATE  "AUTH_LOCAL"
+#define GDM_PROTOCOL_MSG_QUERY_ACTION  "QUERY_LOGOUT_ACTION"
+#define GDM_PROTOCOL_MSG_SET_ACTION    "SET_SAFE_LOGOUT_ACTION"
+#define GDM_PROTOCOL_MSG_FLEXI_XSERVER "FLEXI_XSERVER"
+
+#define GDM_ACTION_STR_NONE     GDM_PROTOCOL_MSG_SET_ACTION" NONE"
+#define GDM_ACTION_STR_SHUTDOWN GDM_PROTOCOL_MSG_SET_ACTION" HALT"
+#define GDM_ACTION_STR_REBOOT   GDM_PROTOCOL_MSG_SET_ACTION" REBOOT"
+#define GDM_ACTION_STR_SUSPEND  GDM_PROTOCOL_MSG_SET_ACTION" SUSPEND"
+
+#define GDM_MIT_MAGIC_COOKIE_LEN 16
+
+static int fd = 0;
+
+static void gdm_disconnect()
+{
+    if (fd > 0)
+        close(fd);
+    fd = 0;
+}
+
+static char* get_display_number(void)
+{
+    char *display_name;
+    char *retval;
+    char *p;
+
+    display_name = XDisplayName(NULL);
+
+    p = strchr(display_name, ':');
+    if (!p)
+        return g_strdup ("0");
+
+    while (*p == ':') p++;
+
+    retval = g_strdup (p);
+
+    p = strchr (retval, '.');
+    if (p != NULL)
+        *p = '\0';
+
+    return retval;
+}
+
+static char* gdm_send_protocol_msg (const char *msg)
+{
+    GString *retval;
+    char     buf[256];
+    char    *p;
+    int      len;
+
+    p = g_strconcat(msg, "\n", NULL);
+    if (write (fd, p, strlen(p)) < 0) {
+        g_free (p);
+
+        g_warning ("Failed to send message to GDM: %s",
+                   g_strerror (errno));
+        return NULL;
+    }
+    g_free (p);
+
+    p = NULL;
+    retval = NULL;
+    while ((len = read(fd, buf, sizeof(buf) - 1)) > 0) {
+        buf[len] = '\0';
+
+        if (!retval)
+            retval = g_string_new(buf);
+        else
+            retval = g_string_append(retval, buf);
+
+        if ((p = strchr(retval->str, '\n')))
+            break;
+    }
+
+    if (p) *p = '\0';
+
+    return retval ? g_string_free(retval, FALSE) : NULL;
+}
+
+static gboolean gdm_authenticate()
+{
+    FILE       *f;
+    Xauth      *xau;
+    const char *xau_path;
+    char       *display_number;
+    gboolean    retval;
+
+    if (!(xau_path = XauFileName()))
+        return FALSE;
+
+    if (!(f = fopen(xau_path, "r")))
+        return FALSE;
+
+    retval = FALSE;
+    display_number = get_display_number();
+
+    while ((xau = XauReadAuth(f))) {
+        char  buffer[40]; /* 2*16 == 32, so 40 is enough */
+        char *msg;
+        char *response;
+        int   i;
+
+        if (xau->family != FamilyLocal ||
+            strncmp (xau->number, display_number, xau->number_length) ||
+            strncmp (xau->name, "MIT-MAGIC-COOKIE-1", xau->name_length) ||
+            xau->data_length != GDM_MIT_MAGIC_COOKIE_LEN)
+        {
+            XauDisposeAuth(xau);
+            continue;
+        }
+
+        for (i = 0; i < GDM_MIT_MAGIC_COOKIE_LEN; i++)
+            g_snprintf(buffer + 2*i, 3, "%02x", (guint)(guchar)xau->data[i]);
+
+        XauDisposeAuth(xau);
+
+        msg = g_strdup_printf(GDM_PROTOCOL_MSG_AUTHENTICATE " %s", buffer);
+        response = gdm_send_protocol_msg(msg);
+        g_free (msg);
+
+        if (response && !strcmp(response, "OK")) {
+            /*auth_cookie = g_strdup(buffer);*/
+            g_free(response);
+            retval = TRUE;
+            break;
+        }
+
+        g_free (response);
+    }
+
+    fclose(f);
+    return retval;
+}
+
+static gboolean gdm_connect()
+{
+    struct sockaddr_un  addr;
+    char               *response;
+
+    assert(fd <= 0);
+
+    fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (fd < 0) {
+        g_warning("Failed to create GDM socket: %s", g_strerror (errno));
+        gdm_disconnect();
+        return FALSE;
+    }
+
+    if (g_file_test(GDM_PROTOCOL_SOCKET_PATH1, G_FILE_TEST_EXISTS))
+        strcpy(addr.sun_path, GDM_PROTOCOL_SOCKET_PATH1);
+    else
+        strcpy(addr.sun_path, GDM_PROTOCOL_SOCKET_PATH2);
+
+    addr.sun_family = AF_UNIX;
+
+    if (connect(fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
+        g_warning("Failed to establish a connection with GDM: %s",
+                  g_strerror(errno));
+        gdm_disconnect();
+        return FALSE;
+    }
+
+    response = gdm_send_protocol_msg(GDM_PROTOCOL_MSG_VERSION);
+    if (!response || strncmp(response, "GDM ", strlen("GDM ") != 0)) {
+        g_free(response);
+
+        g_warning("Failed to get protocol version from GDM");
+        gdm_disconnect();
+        return FALSE;
+    }
+    g_free(response);
+
+    if (!gdm_authenticate()) {
+        g_warning("Failed to authenticate with GDM");
+        gdm_disconnect();
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+int main(int argc, char **argv)
+{
+    int i;
+    Action a = INVALID;
+
+    for (i = 1; i < argc; ++i) {
+        if (!strcmp(argv[i], "--help")) {
+            a = INVALID;
+            break;
+        }
+        if (!strcmp(argv[i], "--none")) {
+            a = NONE;
+            break;
+        }
+        if (!strcmp(argv[i], "--shutdown")) {
+            a = SHUTDOWN;
+            break;
+        }
+        if (!strcmp(argv[i], "--reboot")) {
+            a = REBOOT;
+            break;
+        }
+        if (!strcmp(argv[i], "--suspend")) {
+            a = SUSPEND;
+            break;
+        }
+        if (!strcmp(argv[i], "--switch-user")) {
+            a = SWITCHUSER;
+            break;
+        }
+    }
+
+    if (!a) {
+        printf("Usage: gdm-control ACTION\n\n");
+        printf("Actions:\n");
+        printf("    --help        Display this help and exit\n");
+        printf("    --none        Do nothing special when the current session ends\n");
+        printf("    --shutdown    Shutdown the computer when the current session ends\n");
+        printf("    --reboot      Reboot the computer when the current session ends\n");
+        printf("    --suspend     Suspend the computer when the current session ends\n");
+        printf("    --switch-user Log in as a new user (this works immediately)\n\n");
+        return 0;
+    }
+
+    {
+        char *d, *response;
+        const char *action_string;
+
+        d = XDisplayName(NULL);
+        if (!d) {
+            fprintf(stderr,
+                    "Unable to fina an X display specified by the DISPLAY "
+                    "environment variable. Ensure that it is set correctly.");
+            return 1;
+        }
+
+        switch (a) {
+        case NONE:
+            action_string = GDM_ACTION_STR_NONE;
+            break;
+        case SHUTDOWN:
+            action_string = GDM_ACTION_STR_SHUTDOWN;
+            break;
+        case REBOOT:
+            action_string = GDM_ACTION_STR_REBOOT;
+            break;
+        case SUSPEND:
+            action_string = GDM_ACTION_STR_SUSPEND;
+            break;
+        case SWITCHUSER:
+            action_string = GDM_PROTOCOL_MSG_FLEXI_XSERVER;
+            break;
+        default:
+            assert(0);
+        }
+
+        if (gdm_connect()) {
+            response = gdm_send_protocol_msg(action_string);
+            g_free(response);
+            gdm_disconnect();
+        }
+    }
+
+    return 0;
+}