Contents of /trunk/src/geotoad.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 196 - (show annotations)
Thu Nov 19 07:39:00 2009 UTC (14 years, 6 months ago) by harbaum
File MIME type: text/plain
File size: 11622 byte(s)
Geotoad gui started
1 /*
2 * Copyright (C) 2009 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of GPXView.
5 *
6 * GPXView is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GPXView is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GPXView. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "gpxview.h"
21
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <errno.h>
26
27 #define GEOTOAD "/usr/bin/geotoad"
28
29 #define COLOR_ERR "red"
30 #define COLOR_OK "darkgreen"
31 #define COLOR_SYSTEM "darkblue"
32
33 #define BUFFER_SIZE 256
34
35 typedef struct {
36 appdata_t *appdata;
37
38 char buf[BUFFER_SIZE];
39 int bused;
40
41 /** gdk input tag for async IO */
42 gint stdout_tag, stderr_tag;
43 gint stdin_fd, stdout_fd, stderr_fd;
44
45 struct log_s {
46 GtkTextBuffer *buffer;
47 GtkWidget *view;
48 } log;
49
50 GtkWidget *username, *password;
51
52 } gt_context_t;
53
54 static void appendf(struct log_s *log, char *colname,
55 const char *fmt, ...) {
56 va_list args;
57 va_start( args, fmt );
58 char *buf = g_strdup_vprintf(fmt, args);
59 va_end( args );
60
61 printf("append: %s", buf);
62
63 GtkTextTag *tag = NULL;
64 if(colname)
65 tag = gtk_text_buffer_create_tag(log->buffer, NULL,
66 "foreground", colname,
67 NULL);
68
69 GtkTextIter end;
70 gtk_text_buffer_get_end_iter(log->buffer, &end);
71 if(tag)
72 gtk_text_buffer_insert_with_tags(log->buffer, &end, buf, -1, tag, NULL);
73 else
74 gtk_text_buffer_insert(log->buffer, &end, buf, -1);
75
76 g_free(buf);
77
78 gtk_text_buffer_get_end_iter(log->buffer, &end);
79 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),
80 &end, 0.0, FALSE, 0, 0);
81 }
82
83 /* watch child process and receive events */
84 static void child_state_cb(GPid pid, gint status, gpointer data) {
85 gt_context_t *context = (gt_context_t*)data;
86
87 puts("child state");
88
89 if(WIFEXITED(status)) {
90 printf("child exited with return code %d\n", WEXITSTATUS(status));
91 } else
92 printf("child failed\n");
93
94 puts("gt exited");
95
96 appendf(&context->log, COLOR_SYSTEM, "GeoToad finished\n");
97
98 appendf(&context->log, COLOR_SYSTEM, "TODO: free context!!!\n");
99 // printf("freeing context\n");
100 // g_free(context);
101
102 /* Reap child if needed. */
103 waitpid (pid, NULL, WNOHANG);
104 }
105
106 static gboolean child_input_cb(GIOChannel *source,
107 GIOCondition condition,
108 gpointer data) {
109 gt_context_t *context = (gt_context_t*)data;
110 int fd = g_io_channel_unix_get_fd(source);
111 ssize_t bytes;
112
113 g_assert(condition == G_IO_IN);
114
115 /* append to current buffer content */
116 while( (bytes = read(fd, context->buf+context->bused,
117 sizeof(context->buf) - context->bused - 1)) > 0) {
118 context->bused += bytes;
119 context->buf[context->bused]='\0';
120
121 /* consume line by line */
122 gchar *ptr = context->buf;
123
124 /* parse as long as the buffer contains a newline */
125 while( strchr(ptr, '\n') != NULL) {
126 char *p = strchr(ptr, '\n');
127 *p = '\0';
128
129 char *color = NULL;
130 if(strstr(ptr, "Saved to ") != NULL)
131 color = COLOR_OK;
132
133 appendf(&context->log, color, "%s\n", ptr);
134
135 ptr = p+1;
136 }
137
138 /* move remaining bytes down the buffer */
139 memmove(context->buf, ptr, sizeof(context->buf)-(ptr-context->buf));
140 context->bused -= ptr - context->buf;
141
142 /* check if buffer is full but doesn't contain any newline */
143 if(context->bused >= sizeof(context->buf)-1) {
144 printf("ERROR: reply buffer overflow\n");
145 context->bused = 0;
146 }
147 }
148
149 return TRUE;
150 }
151
152 static void run(gt_context_t *context) {
153 /* setup context */
154 context->bused = 0;
155 context->stdout_tag = -1;
156 context->stderr_tag = -1;
157 context->stdin_fd = -1;
158 context->stderr_fd = -1;
159 context->stderr_fd = -1;
160
161 /* build list of arguments to call geotoad */
162 GPtrArray *gt_argv = g_ptr_array_new();
163 g_ptr_array_add (gt_argv, GEOTOAD);
164 g_ptr_array_add (gt_argv, "--distanceMax=1.0");
165 g_ptr_array_add (gt_argv, "--output=gtoad.gpx");
166 g_ptr_array_add (gt_argv, "--password=winterblume");
167 g_ptr_array_add (gt_argv, "--queryType=coord");
168 g_ptr_array_add (gt_argv, "--user=Tantil");
169
170 /* check if we need to add proxy config */
171 char *proxy = NULL;
172 if(context->appdata->proxy && context->appdata->proxy->host) {
173 if(context->appdata->proxy->use_authentication &&
174 context->appdata->proxy->authentication_user &&
175 context->appdata->proxy->authentication_password)
176 proxy = g_strdup_printf("--proxy=http://%s:%s@%s:%d",
177 context->appdata->proxy->authentication_user,
178 context->appdata->proxy->authentication_password,
179 context->appdata->proxy->host,
180 context->appdata->proxy->port);
181 else
182 proxy = g_strdup_printf("--proxy=http://%s:%d",
183 context->appdata->proxy->host,
184 context->appdata->proxy->port);
185
186 appendf(&context->log, COLOR_SYSTEM, "Using proxy: %s\n", proxy);
187 g_ptr_array_add (gt_argv, proxy);
188 }
189
190 g_ptr_array_add (gt_argv, "N49 00.000 E008 23.000");
191 g_ptr_array_add (gt_argv, NULL);
192
193 GError *error=NULL;
194 GPid pid;
195 GSource *gt_watch;
196
197 if (!g_spawn_async_with_pipes (NULL, /* CWD */
198 (char **) gt_argv->pdata, /* argv */
199 NULL, /* envp */
200 G_SPAWN_DO_NOT_REAP_CHILD, /* flags */
201 NULL, /* child setup */
202 NULL, /* user data */
203 &pid,
204 &context->stdin_fd,
205 &context->stdout_fd,
206 &context->stderr_fd,
207 &error)) {
208 g_ptr_array_free(gt_argv, TRUE);
209 if(proxy) g_free(proxy);
210 appendf(&context->log, COLOR_ERR,
211 _("GeoToad failed to start!\n%s\n"), error->message);
212 g_error_free(error);
213 return;
214 }
215
216 g_ptr_array_free (gt_argv, TRUE);
217 if(proxy) g_free(proxy);
218
219 gt_watch = g_child_watch_source_new(pid);
220 g_source_set_callback(gt_watch, (GSourceFunc) child_state_cb, context, NULL);
221
222 g_source_attach(gt_watch, NULL);
223 g_source_unref(gt_watch);
224
225 /* make nonblocking */
226 if(fcntl(context->stdout_fd, F_SETFL, O_NONBLOCK) == -1)
227 perror("fcntl failed");
228
229 if(fcntl(context->stderr_fd, F_SETFL, O_NONBLOCK) == -1)
230 perror("fcntl failed");
231
232 GIOChannel *ioc = g_io_channel_unix_new(context->stdout_fd);
233 g_io_channel_set_close_on_unref (ioc, TRUE);
234 g_io_channel_set_encoding (ioc, NULL, NULL);
235 g_io_add_watch(ioc, G_IO_IN, child_input_cb, context);
236 g_io_channel_unref(ioc);
237
238 // ioc = g_io_channel_unix_new(context->stderr_fd);
239 // g_io_add_watch(ioc, G_IO_IN, child_input_cb, context);
240 // g_io_channel_unref(ioc);
241 }
242
243 /* show text window and display output of running geotoad */
244 static void gui_run(gt_context_t *context) {
245 GtkWidget *dialog = gtk_dialog_new_with_buttons(_("GeoToad - Run"),
246 GTK_WINDOW(context->appdata->window),
247 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
248 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
249 NULL);
250
251 gtk_window_set_default_size(GTK_WINDOW(dialog), 640, 480);
252
253 #ifndef USE_PANNABLE_AREA
254 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
255 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
256 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
257 #else
258 GtkWidget *pannable_area = hildon_pannable_area_new();
259 #endif
260
261 context->log.buffer = gtk_text_buffer_new(NULL);
262
263 #ifndef USE_HILDON_TEXT_VIEW
264 context->log.view = gtk_text_view_new_with_buffer(context->log.buffer);
265 #else
266 context->log.view = hildon_text_view_new();
267 hildon_text_view_set_buffer(HILDON_TEXT_VIEW(context->log.view),
268 context->log.buffer);
269 #endif
270
271 #ifndef USE_PANNABLE_AREA
272 gtk_container_add(GTK_CONTAINER(scrolled_window), context->log.view);
273 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scrolled_window),
274 GTK_SHADOW_IN);
275
276 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
277 scrolled_window, TRUE, TRUE, 0);
278 #else
279 gtk_container_add(GTK_CONTAINER(pannable_area), context->log.view);
280 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
281 pannable_area, TRUE, TRUE, 0);
282 #endif
283
284 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
285
286 gtk_widget_show_all(dialog);
287
288 appendf(&context->log, COLOR_SYSTEM, "Running GeoToad\n");
289 run(context);
290
291 gtk_dialog_run(GTK_DIALOG(dialog));
292
293 gtk_widget_destroy(dialog);
294 }
295
296 static gboolean gui_setup(gt_context_t *context) {
297 gboolean ok = FALSE;
298
299 GtkWidget *dialog = gtk_dialog_new_with_buttons(_("GeoToad - Setup"),
300 GTK_WINDOW(context->appdata->window),
301 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
302 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
303 GTK_STOCK_OK, GTK_RESPONSE_OK,
304 NULL);
305
306 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
307 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
308 gtk_box_pack_start_defaults(GTK_BOX(vbox), gtk_label_new(_("Username:")));
309 gtk_box_pack_start_defaults(GTK_BOX(vbox), gtk_label_new(_("Password:")));
310 gtk_box_pack_start_defaults(GTK_BOX(hbox), vbox);
311
312 vbox = gtk_vbox_new(FALSE, 0);
313 #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
314 context->username = gtk_entry_new();
315 context->password = gtk_entry_new();
316 #else
317 context->username = hildon_entry_new(HILDON_SIZE_AUTO);
318 hildon_gtk_entry_set_input_mode(GTK_ENTRY(context->username),
319 HILDON_GTK_INPUT_MODE_FULL);
320 context->password = hildon_entry_new(HILDON_SIZE_AUTO);
321 hildon_gtk_entry_set_input_mode(GTK_ENTRY(context->password),
322 HILDON_GTK_INPUT_MODE_FULL);
323 #endif
324 gtk_entry_set_visibility(GTK_ENTRY(context->password), FALSE);
325
326 /* set saved defaults */
327 if(context->appdata->gt.username)
328 gtk_entry_set_text(GTK_ENTRY(context->username),
329 context->appdata->gt.username);
330
331 if(context->appdata->gt.password)
332 gtk_entry_set_text(GTK_ENTRY(context->password),
333 context->appdata->gt.password);
334
335 gtk_box_pack_start_defaults(GTK_BOX(vbox), context->username);
336 gtk_box_pack_start_defaults(GTK_BOX(vbox), context->password);
337 gtk_box_pack_start_defaults(GTK_BOX(hbox), vbox);
338
339 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
340
341 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
342
343 gtk_widget_show_all(dialog);
344
345 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
346
347 /* save values */
348 if(context->appdata->gt.username) g_free(context->appdata->gt.username);
349 context->appdata->gt.username =
350 g_strdup(gtk_entry_get_text(GTK_ENTRY(context->username)));
351
352 if(context->appdata->gt.password) g_free(context->appdata->gt.password);
353 context->appdata->gt.password =
354 g_strdup(gtk_entry_get_text(GTK_ENTRY(context->password)));
355
356 ok = TRUE;
357 }
358
359 gtk_widget_destroy(dialog);
360
361 return ok;
362 }
363
364 void geotoad(appdata_t *appdata) {
365 if(!geotoad_available()) {
366 errorf(_("GeoToad is not installed on this device.\n"
367 "You need to install it in order to be able to use it."));
368 return;
369 }
370
371 gt_context_t *context = g_new0(gt_context_t, 1);
372 context->appdata = appdata;
373
374 printf("geoToad\n");
375
376 if(gui_setup(context))
377 gui_run(context);
378 }
379
380 gboolean geotoad_available(void) {
381 /* before doing anything make sure geotoad is installed */
382 return g_file_test(GEOTOAD, G_FILE_TEST_IS_EXECUTABLE);
383 }
384
385