[mousetweaks] Integrate unix signals into the main loop



commit 4fe76b4312014bf1818a5ea00c9cc9b5af69037c
Author: Gerd Kohlberger <gerdk src gnome org>
Date:   Tue Jun 22 18:50:10 2010 +0200

    Integrate unix signals into the main loop

 src/Makefile.am      |    4 +-
 src/mt-main.c        |   39 ++++++++--
 src/mt-sig-handler.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mt-sig-handler.h |   51 ++++++++++++
 4 files changed, 296 insertions(+), 7 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index e3cd2ee..19fd5d4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,7 +32,9 @@ mousetweaks_SOURCES =	    \
 	mt-cursor-manager.c \
 	mt-cursor-manager.h \
 	mt-listener.c	    \
-	mt-listener.h
+	mt-listener.h       \
+    mt-sig-handler.c    \
+    mt-sig-handler.h
 
 mousetweaks_CFLAGS =		\
 	$(AM_CFLAGS)		\
diff --git a/src/mt-main.c b/src/mt-main.c
index 6ef785b..46faff6 100644
--- a/src/mt-main.c
+++ b/src/mt-main.c
@@ -34,6 +34,7 @@
 #include "mt-cursor.h"
 #include "mt-main.h"
 #include "mt-listener.h"
+#include "mt-sig-handler.h"
 
 enum
 {
@@ -606,12 +607,20 @@ cursor_changed (MtCursorManager *manager,
 }
 
 static void
-signal_handler (int sig)
+signal_handler (int signal_id)
 {
     gtk_main_quit ();
 }
 
 static void
+mt_main_sig_handler (MtSigHandler *sigh,
+                     gint          signal_id,
+                     gpointer      data)
+{
+    signal_handler (signal_id);
+}
+
+static void
 gconf_value_changed (GConfClient *client,
                      const gchar *key,
                      GConfValue  *value,
@@ -853,6 +862,7 @@ mt_main (int argc, char **argv, MtCliArgs cli_args)
     MtData *mt;
     MtCursorManager *manager;
     MtListener *listener;
+    MtSigHandler *sigh;
 
     if (mt_pidfile_create () < 0)
     {
@@ -860,13 +870,29 @@ mt_main (int argc, char **argv, MtCliArgs cli_args)
         return;
     }
 
-    signal (SIGINT, signal_handler);
-    signal (SIGTERM, signal_handler);
-    signal (SIGQUIT, signal_handler);
-    signal (SIGHUP, signal_handler);
-
     gtk_init (&argc, &argv);
 
+    sigh = mt_sig_handler_get_default ();
+    if (mt_sig_handler_setup_pipe (sigh))
+    {
+        mt_sig_handler_catch (sigh, SIGINT);
+        mt_sig_handler_catch (sigh, SIGTERM);
+        mt_sig_handler_catch (sigh, SIGQUIT);
+        mt_sig_handler_catch (sigh, SIGHUP);
+
+        g_signal_connect (sigh, "signal",
+                          G_CALLBACK (mt_main_sig_handler), NULL);
+    }
+    else
+    {
+        g_warning ("Couldn't create pipe for signal handling. Using fallback.");
+
+        signal (SIGINT, signal_handler);
+        signal (SIGTERM, signal_handler);
+        signal (SIGQUIT, signal_handler);
+        signal (SIGHUP, signal_handler);
+    }
+
     mt = mt_data_init ();
     if (!mt)
         goto FINISH;
@@ -923,6 +949,7 @@ mt_main (int argc, char **argv, MtCliArgs cli_args)
     mt_cursor_manager_restore_all (manager);
     g_object_unref (manager);
     g_object_unref (listener);
+    g_object_unref (sigh);
 
 CLEANUP:
     mt_data_free (mt);
diff --git a/src/mt-sig-handler.c b/src/mt-sig-handler.c
new file mode 100644
index 0000000..2964474
--- /dev/null
+++ b/src/mt-sig-handler.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2010 Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <signal.h>
+
+#include "mt-sig-handler.h"
+
+enum
+{
+    SIGNAL,
+    LAST_SIGNAL
+};
+
+struct _MtSigHandlerPrivate
+{
+    GIOChannel *read_chan;
+    guint       pipe_set_up : 1;
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static int _write_fd;
+static int _block_cnt;
+static sigset_t _old_mask;
+
+G_DEFINE_TYPE (MtSigHandler, mt_sig_handler, G_TYPE_OBJECT)
+
+static void
+mt_sig_handler_init (MtSigHandler *sigh)
+{
+    sigh->priv = G_TYPE_INSTANCE_GET_PRIVATE (sigh,
+                                              MT_TYPE_SIG_HANDLER,
+                                              MtSigHandlerPrivate);
+    _write_fd = 0;
+    _block_cnt = 0;
+    sigemptyset (&_old_mask);
+}
+
+static void
+mt_sig_handler_finalize (GObject *object)
+{
+    MtSigHandlerPrivate *priv = MT_SIG_HANDLER (object)->priv;
+
+    if (priv->pipe_set_up)
+    {
+        g_io_channel_unref (priv->read_chan);
+        close (_write_fd);
+    }
+
+    G_OBJECT_CLASS (mt_sig_handler_parent_class)->finalize (object);
+}
+
+static void
+mt_sig_handler_class_init (MtSigHandlerClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = mt_sig_handler_finalize;
+
+    signals[SIGNAL] =
+        g_signal_new (g_intern_static_string ("signal"),
+                      G_OBJECT_CLASS_TYPE (klass),
+                      G_SIGNAL_RUN_LAST,
+                      0, NULL, NULL,
+                      g_cclosure_marshal_VOID__INT,
+                      G_TYPE_NONE, 1, G_TYPE_INT);
+
+    g_type_class_add_private (klass, sizeof (MtSigHandlerPrivate));
+}
+
+static void
+signal_handler (int signal_id)
+{
+    unsigned char sid;
+    int whtevr;
+
+    sid = (unsigned char) signal_id;
+    whtevr = write (_write_fd, &sid, 1);
+}
+
+static void
+mt_sig_handler_block_signals (void)
+{
+    _block_cnt++;
+
+    if (_block_cnt == 1)
+    {
+        sigset_t mask;
+
+        sigfillset (&mask);
+        sigprocmask (SIG_BLOCK, &mask, &_old_mask);
+    }
+}
+
+static void
+mt_sig_handler_unblock_signals (void)
+{
+    _block_cnt--;
+
+    if (_block_cnt == 0)
+        sigprocmask (SIG_SETMASK, &_old_mask, NULL);
+}
+
+static gboolean
+mt_sig_handler_io_watch (GIOChannel   *read_chan,
+                         GIOCondition  condition,
+                         MtSigHandler *sigh)
+{
+    gchar buf[256];
+    gsize bytes_read;
+
+    mt_sig_handler_block_signals ();
+
+    if (g_io_channel_read_chars (read_chan, buf, sizeof (buf),
+                                 &bytes_read, NULL) == G_IO_STATUS_NORMAL)
+    {
+        gint i, sig_id;
+
+        for (i = 0; i < bytes_read; i++)
+        {
+            sig_id = buf[i];
+            g_signal_emit (sigh, signals[SIGNAL], 0, &sig_id);
+        }
+    }
+
+    mt_sig_handler_unblock_signals ();
+
+    return TRUE;
+}
+
+MtSigHandler *
+mt_sig_handler_get_default (void)
+{
+    static MtSigHandler *sigh = NULL;
+
+    if (!sigh)
+    {
+        sigh = g_object_new (MT_TYPE_SIG_HANDLER, NULL);
+        g_object_add_weak_pointer (G_OBJECT (sigh), (gpointer *) &sigh);
+    }
+    return sigh;
+}
+
+gboolean
+mt_sig_handler_setup_pipe (MtSigHandler *sigh)
+{
+    MtSigHandlerPrivate *priv;
+    int sig_pipe[2];
+
+    g_return_val_if_fail (MT_IS_SIG_HANDLER (sigh), FALSE);
+
+    priv = sigh->priv;
+
+    if (priv->pipe_set_up)
+    {
+        return TRUE;
+    }
+
+    if (pipe (sig_pipe) != 0)
+    {
+        return FALSE;
+    }
+
+    priv->pipe_set_up = TRUE;
+
+    _write_fd = sig_pipe[1];
+
+    priv->read_chan = g_io_channel_unix_new (sig_pipe[0]);
+    g_io_channel_set_flags (priv->read_chan, G_IO_FLAG_NONBLOCK, NULL);
+    g_io_channel_set_encoding (priv->read_chan, NULL, NULL);
+    g_io_channel_set_close_on_unref (priv->read_chan, TRUE);
+    g_io_add_watch (priv->read_chan, G_IO_IN,
+                    (GIOFunc) mt_sig_handler_io_watch, sigh);
+
+    g_io_channel_unref (priv->read_chan);
+
+    return TRUE;
+}
+
+void
+mt_sig_handler_catch (MtSigHandler *sigh, int signal_id)
+{
+    struct sigaction action, old;
+
+    g_return_if_fail (MT_IS_SIG_HANDLER (sigh));
+
+    sigemptyset (&action.sa_mask);
+    action.sa_handler = signal_handler;
+    action.sa_flags = 0;
+
+    sigaction (signal_id, &action, &old);
+}
diff --git a/src/mt-sig-handler.h b/src/mt-sig-handler.h
new file mode 100644
index 0000000..dd5eff9
--- /dev/null
+++ b/src/mt-sig-handler.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2010 Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MT_SIG_HANDLER_H__
+#define __MT_SIG_HANDLER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MT_TYPE_SIG_HANDLER  (mt_sig_handler_get_type ())
+#define MT_SIG_HANDLER(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), MT_TYPE_SIG_HANDLER, MtSigHandler))
+#define MT_IS_SIG_HANDLER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MT_TYPE_SIG_HANDLER))
+
+typedef GObjectClass                MtSigHandlerClass;
+typedef struct _MtSigHandler        MtSigHandler;
+typedef struct _MtSigHandlerPrivate MtSigHandlerPrivate;
+
+struct _MtSigHandler
+{
+    GObject              parent;
+    MtSigHandlerPrivate *priv;
+};
+
+GType              mt_sig_handler_get_type        (void) G_GNUC_CONST;
+
+MtSigHandler *     mt_sig_handler_get_default     (void);
+gboolean           mt_sig_handler_setup_pipe      (MtSigHandler *sigh);
+
+void               mt_sig_handler_catch           (MtSigHandler *sigh,
+                                                   int           signal_id);
+
+G_END_DECLS
+
+#endif /* __MT_SIG_HANDLER_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]