2 * This file is part of DisOrder.
3 * Copyright (C) 2006, 2007, 2008 Richard Kettlewell
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /** @file disobedience/client.c
19 * @brief GLIB integration for @ref lib/eclient.c client
22 #include "disobedience.h"
24 /** @brief GSource subclass for disorder_eclient */
25 struct eclient_source
{
27 disorder_eclient
*client
;
32 /** @brief Called before FDs are polled to choose a timeout.
34 * We ask for a 3s timeout and every 10s or so we force a dispatch.
36 static gboolean
gtkclient_prepare(GSource
*source
,
38 const struct eclient_source
*esource
= (struct eclient_source
*)source
;
39 D(("gtkclient_prepare"));
40 if(time(0) > esource
->last_poll
+ 10)
41 return TRUE
; /* timed out */
42 *timeout
= 3000/*milliseconds*/;
43 return FALSE
; /* please poll */
46 /** @brief Check whether we're ready to dispatch */
47 static gboolean
gtkclient_check(GSource
*source
) {
48 const struct eclient_source
*esource
= (struct eclient_source
*)source
;
49 D(("gtkclient_check fd=%d events=%x revents=%x",
50 esource
->pollfd
.fd
, esource
->pollfd
.events
, esource
->pollfd
.revents
));
51 return esource
->pollfd
.fd
!= -1 && esource
->pollfd
.revents
!= 0;
54 /** @brief Called after poll() (or otherwise) to dispatch an event */
55 static gboolean
gtkclient_dispatch(GSource
*source
,
56 GSourceFunc
attribute((unused
)) callback
,
57 gpointer
attribute((unused
)) user_data
) {
58 struct eclient_source
*esource
= (struct eclient_source
*)source
;
59 unsigned revents
, mode
;
61 D(("gtkclient_dispatch"));
62 revents
= esource
->pollfd
.revents
& esource
->pollfd
.events
;
64 if(revents
& (G_IO_IN
|G_IO_HUP
|G_IO_ERR
))
65 mode
|= DISORDER_POLL_READ
;
66 if(revents
& (G_IO_OUT
|G_IO_HUP
|G_IO_ERR
))
67 mode
|= DISORDER_POLL_WRITE
;
68 time(&esource
->last_poll
);
69 disorder_eclient_polled(esource
->client
, mode
);
70 return TRUE
; /* ??? not documented */
73 /** @brief Table of callbacks for GSource subclass */
74 static const GSourceFuncs sourcefuncs
= {
83 /** @brief Tell the mainloop what we need */
84 static void gtkclient_poll(void *u
,
85 disorder_eclient
attribute((unused
)) *c
,
86 int fd
, unsigned mode
) {
87 struct eclient_source
*esource
= u
;
90 D(("gtkclient_poll fd=%d mode=%x", fd
, mode
));
91 /* deconfigure the source if currently configured */
92 if(esource
->pollfd
.fd
!= -1) {
93 D(("calling g_source_remove_poll"));
94 g_source_remove_poll(source
, &esource
->pollfd
);
95 esource
->pollfd
.fd
= -1;
96 esource
->pollfd
.events
= 0;
98 /* install new settings */
99 if(fd
!= -1 && mode
) {
100 esource
->pollfd
.fd
= fd
;
101 esource
->pollfd
.events
= 0;
102 if(mode
& DISORDER_POLL_READ
)
103 esource
->pollfd
.events
|= G_IO_IN
| G_IO_HUP
| G_IO_ERR
;
104 if(mode
& DISORDER_POLL_WRITE
)
105 esource
->pollfd
.events
|= G_IO_OUT
| G_IO_ERR
;
106 /* reconfigure the source */
107 D(("calling g_source_add_poll"));
108 g_source_add_poll(source
, &esource
->pollfd
);
112 /** @brief Report a communication-level error
114 * Any operations still outstanding are automatically replied by the underlying
115 * @ref lib/eclient.c code.
117 static void gtkclient_comms_error(void attribute((unused
)) *u
,
119 D(("gtkclient_comms_error %s", msg
));
120 gtk_label_set_text(GTK_LABEL(report_label
), msg
);
123 /** @brief Report a protocol-level error
125 * The error will not be retried. We offer a callback to the submitter of the
126 * original command and if none is supplied we drop the error message in the
129 static void gtkclient_protocol_error(void attribute((unused
)) *u
,
130 void attribute((unused
)) *v
,
131 int attribute((unused
)) code
,
133 D(("gtkclient_protocol_error %s", msg
));
134 gtk_label_set_text(GTK_LABEL(report_label
), msg
);
137 /** @brief Report callback from eclient */
138 static void gtkclient_report(void attribute((unused
)) *u
,
141 /* We're idle - clear the report line */
142 gtk_label_set_text(GTK_LABEL(report_label
), "");
145 /** @brief Repoort an unhandled protocol-level error to the user */
146 void popup_protocol_error(int attribute((unused
)) code
,
148 gtk_label_set_text(GTK_LABEL(report_label
), msg
);
149 popup_msg(GTK_MESSAGE_ERROR
, msg
);
152 /** @brief Table of eclient callbacks */
153 static const disorder_eclient_callbacks gtkclient_callbacks
= {
154 gtkclient_comms_error
,
155 gtkclient_protocol_error
,
160 /** @brief Create a @ref disorder_eclient using the GLib main loop */
161 disorder_eclient
*gtkclient(void) {
163 struct eclient_source
*esource
;
166 source
= g_source_new((GSourceFuncs
*)&sourcefuncs
,
167 sizeof (struct eclient_source
));
168 esource
= (struct eclient_source
*)source
;
169 esource
->pollfd
.fd
= -1;
170 esource
->client
= disorder_eclient_new(>kclient_callbacks
, source
);
171 if(!esource
->client
) {
172 g_source_destroy(source
);
175 g_source_attach(source
, 0);
176 return esource
->client
;