Contents of /trunk/src/geotoad.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 196 - (hide 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 harbaum 193 /*
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 harbaum 196 #define GEOTOAD "/usr/bin/geotoad"
28    
29 harbaum 195 #define COLOR_ERR "red"
30     #define COLOR_OK "darkgreen"
31     #define COLOR_SYSTEM "darkblue"
32 harbaum 194
33 harbaum 195 #define BUFFER_SIZE 256
34 harbaum 193
35     typedef struct {
36 harbaum 194 appdata_t *appdata;
37    
38 harbaum 193 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 harbaum 194 struct log_s {
46     GtkTextBuffer *buffer;
47     GtkWidget *view;
48     } log;
49 harbaum 196
50     GtkWidget *username, *password;
51 harbaum 194
52 harbaum 193 } gt_context_t;
53    
54 harbaum 194 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 harbaum 195 printf("append: %s", buf);
62    
63 harbaum 194 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 harbaum 195 gtk_text_buffer_get_end_iter(log->buffer, &end);
79 harbaum 194 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),
80     &end, 0.0, FALSE, 0, 0);
81     }
82    
83 harbaum 193 /* watch child process and receive events */
84     static void child_state_cb(GPid pid, gint status, gpointer data) {
85 harbaum 195 gt_context_t *context = (gt_context_t*)data;
86 harbaum 193
87     puts("child state");
88    
89     if(WIFEXITED(status)) {
90 harbaum 194 printf("child exited with return code %d\n", WEXITSTATUS(status));
91     } else
92     printf("child failed\n");
93 harbaum 193
94     puts("gt exited");
95    
96 harbaum 195 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 harbaum 193 /* Reap child if needed. */
103     waitpid (pid, NULL, WNOHANG);
104     }
105    
106 harbaum 195 static gboolean child_input_cb(GIOChannel *source,
107     GIOCondition condition,
108     gpointer data) {
109 harbaum 193 gt_context_t *context = (gt_context_t*)data;
110 harbaum 195 int fd = g_io_channel_unix_get_fd(source);
111 harbaum 193 ssize_t bytes;
112    
113 harbaum 195 g_assert(condition == G_IO_IN);
114 harbaum 193
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 harbaum 195 char *color = NULL;
130     if(strstr(ptr, "Saved to ") != NULL)
131     color = COLOR_OK;
132 harbaum 193
133 harbaum 195 appendf(&context->log, color, "%s\n", ptr);
134    
135 harbaum 193 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 harbaum 195 return TRUE;
150 harbaum 193 }
151    
152 harbaum 194 static void run(gt_context_t *context) {
153 harbaum 193 /* 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 harbaum 194 /* build list of arguments to call geotoad */
162 harbaum 193 GPtrArray *gt_argv = g_ptr_array_new();
163 harbaum 196 g_ptr_array_add (gt_argv, GEOTOAD);
164 harbaum 195 g_ptr_array_add (gt_argv, "--distanceMax=1.0");
165 harbaum 194 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 harbaum 195 appendf(&context->log, COLOR_SYSTEM, "Using proxy: %s\n", proxy);
187 harbaum 194 g_ptr_array_add (gt_argv, proxy);
188     }
189    
190     g_ptr_array_add (gt_argv, "N49 00.000 E008 23.000");
191 harbaum 193 g_ptr_array_add (gt_argv, NULL);
192 harbaum 194
193 harbaum 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 harbaum 194 if(proxy) g_free(proxy);
210     appendf(&context->log, COLOR_ERR,
211 harbaum 195 _("GeoToad failed to start!\n%s\n"), error->message);
212 harbaum 193 g_error_free(error);
213     return;
214     }
215 harbaum 195
216 harbaum 193 g_ptr_array_free (gt_argv, TRUE);
217 harbaum 195 if(proxy) g_free(proxy);
218 harbaum 193
219     gt_watch = g_child_watch_source_new(pid);
220 harbaum 195 g_source_set_callback(gt_watch, (GSourceFunc) child_state_cb, context, NULL);
221 harbaum 193
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 harbaum 195 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 harbaum 193 }
242 harbaum 194
243 harbaum 196 /* 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 harbaum 194 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 harbaum 195 appendf(&context->log, COLOR_SYSTEM, "Running GeoToad\n");
289 harbaum 194 run(context);
290    
291     gtk_dialog_run(GTK_DIALOG(dialog));
292    
293     gtk_widget_destroy(dialog);
294     }
295 harbaum 196
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