2003-01-26 Richard Hult <rhult@codefactory.se>
[platform/upstream/dbus.git] / glib / dbus-gmain.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gmain.c GLib main loop integration
3  *
4  * Copyright (C) 2002, 2003  CodeFactory AB
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-glib.h"
25 #include <glib.h>
26
27 typedef struct _DBusGSource DBusGSource;
28
29 struct _DBusGSource
30 {
31   GSource source;
32
33   DBusConnection *connection;
34
35   GList *poll_fds;
36   GHashTable *watches;
37 };
38
39 static gboolean dbus_connection_prepare  (GSource     *source,
40                                           gint        *timeout);
41 static gboolean dbus_connection_check    (GSource     *source);
42 static gboolean dbus_connection_dispatch (GSource     *source,
43                                           GSourceFunc  callback,
44                                           gpointer     user_data);
45
46
47 static GSourceFuncs dbus_funcs = {
48   dbus_connection_prepare,
49   dbus_connection_check,
50   dbus_connection_dispatch,
51   NULL
52 };
53
54 static gboolean
55 dbus_connection_prepare (GSource *source,
56                          gint    *timeout)
57 {
58   DBusConnection *connection = ((DBusGSource *)source)->connection;
59   
60   *timeout = -1;
61
62   return (dbus_connection_peek_message (connection) != NULL);  
63 }
64
65 static gboolean
66 dbus_connection_check (GSource *source)
67 {
68   DBusGSource *dbus_source = (DBusGSource *)source;
69   GList *list;
70
71   list = dbus_source->poll_fds;
72
73   while (list)
74     {
75       GPollFD *poll_fd = list->data;
76
77       if (poll_fd->revents != 0)
78         return TRUE;
79
80       list = list->next;
81     }
82
83   return FALSE;  
84 }
85
86 static gboolean
87 dbus_connection_dispatch (GSource     *source,
88                           GSourceFunc  callback,
89                           gpointer     user_data)
90 {
91    DBusGSource *dbus_source = (DBusGSource *)source;
92    GList *copy, *list;
93
94    /* We need to traverse a copy of the list, since it can change in
95       dbus_connect_handle_watch. */
96    copy = g_list_copy (dbus_source->poll_fds);
97
98    list = copy;
99    while (list)
100      {
101        GPollFD *poll_fd = list->data;
102
103        if (poll_fd->revents != 0)
104          {
105            DBusWatch *watch = g_hash_table_lookup (dbus_source->watches, poll_fd);
106            guint condition = 0;
107            
108            if (poll_fd->revents & G_IO_IN)
109              condition |= DBUS_WATCH_READABLE;
110            if (poll_fd->revents & G_IO_OUT)
111              condition |= DBUS_WATCH_WRITABLE;
112            if (poll_fd->revents & G_IO_ERR)
113              condition |= DBUS_WATCH_ERROR;
114            if (poll_fd->revents & G_IO_HUP)
115              condition |= DBUS_WATCH_HANGUP;
116            
117            dbus_connection_handle_watch (dbus_source->connection, watch, condition);
118          }
119
120        list = list->next;
121      }
122
123    g_list_free (copy);
124    
125    /* Dispatch messages */
126    while (dbus_connection_dispatch_message (dbus_source->connection));
127
128    return TRUE;
129 }
130
131 static void
132 add_watch (DBusWatch *watch,
133            gpointer   data)
134 {
135   GPollFD *poll_fd;
136   DBusGSource *dbus_source;
137   guint flags;
138   
139   dbus_source = data;
140   
141   poll_fd = g_new (GPollFD, 1);
142   poll_fd->fd = dbus_watch_get_fd (watch);
143   poll_fd->events = 0;
144   flags = dbus_watch_get_flags (watch);
145   dbus_watch_set_data (watch, poll_fd, NULL);
146
147   if (flags & DBUS_WATCH_READABLE)
148     poll_fd->events |= G_IO_IN;
149   if (flags & DBUS_WATCH_WRITABLE)
150     poll_fd->events |= G_IO_OUT;
151   if (flags & DBUS_WATCH_ERROR)
152     poll_fd->events |= G_IO_ERR;
153   if (flags & DBUS_WATCH_HANGUP)
154     poll_fd->events |= G_IO_HUP;
155
156   g_source_add_poll ((GSource *)dbus_source, poll_fd);
157
158   dbus_source->poll_fds = g_list_prepend (dbus_source->poll_fds, poll_fd);
159   g_hash_table_insert (dbus_source->watches, poll_fd, watch);
160 }
161
162 static void
163 remove_watch (DBusWatch *watch,
164               gpointer   data)
165 {
166   DBusGSource *dbus_source = data;
167   GPollFD *poll_fd;
168   
169   poll_fd = dbus_watch_get_data (watch);
170   
171   dbus_source->poll_fds = g_list_remove (dbus_source->poll_fds, poll_fd);
172   g_hash_table_remove (dbus_source->watches, poll_fd);
173   g_source_remove_poll ((GSource *)dbus_source, poll_fd);
174   
175   g_free (poll_fd);
176 }
177
178 static void
179 add_timeout (DBusTimeout *timeout,
180              void        *data)
181 {
182 }
183
184 static void
185 remove_timeout (DBusTimeout *timeout,
186                 void        *data)
187 {
188 }
189
190 void
191 dbus_connection_hookup_with_g_main (DBusConnection *connection)
192 {
193   GSource *source;
194   DBusGSource *dbus_source;
195
196   source = g_source_new (&dbus_funcs, sizeof (DBusGSource));
197   
198   dbus_source = (DBusGSource *)source;  
199   dbus_source->watches = g_hash_table_new (NULL, NULL);
200   dbus_source->connection = connection;
201
202   dbus_connection_set_watch_functions (connection,
203                                        add_watch,
204                                        remove_watch,
205                                        source, NULL);
206   dbus_connection_set_timeout_functions (connection,
207                                          add_timeout,
208                                          remove_timeout,
209                                          NULL, NULL);
210
211   g_source_attach (source, NULL);
212 }