diff -u --recursive --exclude=CVS --new-file pristine/gthumb/src/Makefile.am gthumb/src/Makefile.am --- pristine/gthumb/src/Makefile.am 2003-02-24 19:01:33.000000000 +0000 +++ gthumb/src/Makefile.am 2003-07-07 20:06:17.000000000 +0100 @@ -44,6 +44,7 @@ catalog-list.h \ commands-impl.c \ commands-impl.h \ + dashboard-frontend.c \ dir-list.c \ dir-list.h \ dlg-bookmarks.c \ diff -u --recursive --exclude=CVS --new-file pristine/gthumb/src/dashboard-frontend.c gthumb/src/dashboard-frontend.c --- pristine/gthumb/src/dashboard-frontend.c 1970-01-01 01:00:00.000000000 +0100 +++ gthumb/src/dashboard-frontend.c 2003-07-07 20:06:31.000000000 +0100 @@ -0,0 +1,366 @@ +#ifndef __DASHBOARD_FRONTEND_H__ +#define __DASHBOARD_FRONTEND_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DASHBOARD_PORT 5913 +#define NATMIN(a,b) ((a) < (b) ? (a) : (b)) + +/* + * Open a connection to the dashboard. We never block and at + * the first sign of a problem we bail. + */ +static int +dashboard_connect_with_timeout (int *fd, + long timeout_usecs) +{ + struct sockaddr_in sock; + struct timeval timeout; + fd_set write_fds; + + *fd = socket (PF_INET, SOCK_STREAM, 0); + if (*fd < 0) { + perror ("Dashboard: socket"); + return 0; + } + + /* + * Set the socket to be non-blocking so that connect () + * doesn't block. + */ + if (fcntl (*fd, F_SETFL, O_NONBLOCK) < 0) { + perror ("Dashboard: setting O_NONBLOCK"); + return 0; + } + + bzero ((char *) &sock, sizeof (sock)); + sock.sin_family = AF_INET; + sock.sin_port = htons (DASHBOARD_PORT); + sock.sin_addr.s_addr = inet_addr ("127.0.0.1"); + + timeout.tv_sec = 0; + timeout.tv_usec = timeout_usecs; + + while (1) { + + /* + * Try to connect. + */ + if (connect (*fd, (struct sockaddr *) &sock, + sizeof (struct sockaddr_in)) < 0) { + + if (errno != EAGAIN && + errno != EINPROGRESS) { + perror ("Dashboard: connect"); + return 0; + } + + } else + return 1; + + /* + * We couldn't connect, so we select on the fd and + * wait for the timer to run out, or for the fd to be + * ready. + */ + FD_ZERO (&write_fds); + FD_SET (*fd, &write_fds); + + while (select (getdtablesize (), NULL, &write_fds, NULL, &timeout) < 0) { + if (errno != EINTR) { + perror ("Dashboard: select"); + return 0; + } + } + + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + fprintf (stderr, "Dashboard: Connection timed out.\n"); + return 0; + } + + } + + return 1; +} + +typedef struct { + char *rawcluepacket; + int bytes_written; +} CluepacketInfo; + +static gboolean +cluepacket_write_cb (GIOChannel *channel, + GIOCondition cond, + gpointer user_data) +{ + CluepacketInfo *info = user_data; + GIOError err; + int total_bytes; + + total_bytes = strlen (info->rawcluepacket); + + do { + int b; + + err = g_io_channel_write (channel, + info->rawcluepacket + info->bytes_written, + total_bytes - info->bytes_written, + &b); + info->bytes_written += b; + } while (info->bytes_written < total_bytes && err == G_IO_ERROR_NONE); + + if (err == G_IO_ERROR_NONE) { + /* We're all done sending */ + fprintf (stderr, "Dashboard: Sent.\n"); + goto cleanup; + } + + if (err == G_IO_ERROR_AGAIN) { + /* Hand control back to the main loop */ + return TRUE; + } + + /* Otherwise... */ + fprintf (stderr, "Dashboard: Error trying to send cluepacket.\n"); + +cleanup: + g_io_channel_close (channel); + g_free (info->rawcluepacket); + g_free (info); + + return FALSE; +} + +static void +dashboard_send_raw_cluepacket (const char *rawcluepacket) +{ + int fd; + GIOChannel *channel; + CluepacketInfo *info; + + fprintf (stderr, "Dashboard: Sending cluepacket...\n"); + + /* Connect. */ + if (! dashboard_connect_with_timeout (&fd, 200000)) + return; + + channel = g_io_channel_unix_new (fd); + + info = g_new0 (CluepacketInfo, 1); + info->rawcluepacket = g_strdup (rawcluepacket); + + g_io_add_watch (channel, + G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + cluepacket_write_cb, + info); + + g_io_channel_unref (channel); +} + +/* + * Sends a raw cluepacket to the dashboard. + */ +static void +dashboard_send_raw_cluepacket_sync (const char *rawcluepacket) +{ + int fd; + int total_bytes; + int bytes_written; + const char *p; + int eagain_count; + + fprintf (stderr, "Dashboard: Sending cluepacket...\n"); + fprintf (stderr, "Cluepacket: %s\n", rawcluepacket); + + /* Connect. */ + if (! dashboard_connect_with_timeout (&fd, 200000)) + return; + + /* Write out the cluepacket */ + total_bytes = strlen (rawcluepacket); + bytes_written = 0; + p = rawcluepacket; + eagain_count = 0; + while (bytes_written < total_bytes) { + int b; + + b = write (fd, p, total_bytes - bytes_written); + if (b < 0) { + fprintf (stderr, "Dashboard: Error writing: %s\n", strerror (errno)); + + if (errno != EAGAIN && errno != EWOULDBLOCK) { + close (fd); + return; + } + + eagain_count ++; + + if (eagain_count > 10) { + close (fd); + return; + } + } + + bytes_written += b; + p += b; + } + + close (fd); + + fprintf (stderr, "Dashboard: Sent.\n"); +} + +static char * +dashboard_xml_quote (const char *str) +{ + return g_markup_escape_text (str, strlen (str)); +} + +static char * +dashboard_build_clue (const char *text, + const char *type, + int relevance) +{ + char *text_xml; + char *clue; + + if (text == NULL || strlen (text) == 0) + return g_strdup (""); + + text_xml = dashboard_xml_quote (text); + + clue = g_strdup_printf (" %s\n", + type, relevance, text_xml); + + g_free (text_xml); + + return clue; +} + +static char * +dashboard_build_cluepacket_from_cluelist (const char *frontend, + gboolean focused, + const char *context, + GList *clues) +{ + char *cluepacket; + char *new_cluepacket; + GList *l; + + g_return_val_if_fail (frontend != NULL, NULL); + g_return_val_if_fail (clues != NULL, NULL); + + cluepacket = g_strdup_printf ( + "\n" + " %s\n" + " %s\n" + " %s\n", + frontend, + context, + focused ? "true" : "false"); + + for (l = clues; l != NULL; l = l->next) { + const char *clue = (const char *) l->data; + + new_cluepacket = g_strconcat (cluepacket, clue, NULL); + g_free (cluepacket); + + cluepacket = new_cluepacket; + } + + new_cluepacket = g_strconcat (cluepacket, "\n", NULL); + g_free (cluepacket); + + cluepacket = new_cluepacket; + + return cluepacket; +} + +static char * +dashboard_build_cluepacket_v (const char *frontend, + gboolean focused, + const char *context, + va_list args) +{ + char *cluep; + GList *clue_list; + char *retval; + + g_return_val_if_fail (frontend != NULL, NULL); + + cluep = va_arg (args, char *); + clue_list = NULL; + while (cluep) { + clue_list = g_list_append (clue_list, cluep); + cluep = va_arg (args, char *); + } + + retval = dashboard_build_cluepacket_from_cluelist (frontend, focused, context, clue_list); + + g_list_free (clue_list); + + return retval; +} + +static char * +dashboard_build_cluepacket (const char *frontend, + gboolean focused, + const char *context, + ...) +{ + char *retval; + va_list args; + + g_return_val_if_fail (frontend != NULL, NULL); + + va_start (args, context); + + retval = dashboard_build_cluepacket_v (frontend, focused, context, args); + + va_end (args); + + return retval; +} + + +static char * +dashboard_build_cluepacket_then_free_clues (const char *frontend, + gboolean focused, + const char *context, + ...) +{ + char *retval; + char *cluep; + va_list args; + + g_return_val_if_fail (frontend != NULL, NULL); + + /* Build the cluepacket */ + va_start (args, context); + retval = dashboard_build_cluepacket_v (frontend, focused, context, args); + va_end (args); + + /* Free the clues */ + va_start (args, context); + cluep = va_arg (args, char *); + while (cluep) { + g_free (cluep); + cluep = va_arg (args, char *); + } + + va_end (args); + + return retval; +} + +#endif /* ! __DASHBOARD_FRONTEND_H__ */ diff -u --recursive --exclude=CVS --new-file pristine/gthumb/src/gthumb-window.c gthumb/src/gthumb-window.c --- pristine/gthumb/src/gthumb-window.c 2003-07-06 19:03:59.000000000 +0100 +++ gthumb/src/gthumb-window.c 2003-07-07 20:48:40.000000000 +0100 @@ -65,6 +65,7 @@ #include "nav-window.h" #include "pixbuf-utils.h" #include "thumb-cache.h" +#include "dashboard-frontend.c" #include "icons/pixbufs.h" #include "icons/nav_button.xpm" @@ -723,6 +724,90 @@ comment_data_free (cdata); } +static void +dashboard_send_info (GThumbWindow *window) +{ + gchar *path, *utf8_name, *date_string, *clue, *new_clue, *packet; + gboolean has_focus; + CommentData* cdata; + GDate *date; + + path = window->image_path; + if (path != NULL) + { + /* send filename */ + utf8_name = g_locale_to_utf8 (file_name_from_path (path), -1, + NULL, NULL, NULL); + clue = dashboard_build_clue (utf8_name, "keyword", 10); + g_free (utf8_name); + + cdata = comments_load_comment (window->image_path); + if (cdata != NULL) + { + /* send date */ + if (cdata->time != 0) + { + date = g_date_new (); + g_date_set_time (date, cdata->time); + + date_string = g_strdup_printf ( + "%04d-%02d-%02d", + g_date_get_year (date), + g_date_get_month (date) + ); + + new_clue = g_strconcat ( + clue, + dashboard_build_clue (date_string, "date", 10), + NULL + ); + + g_free (date_string); + g_free (clue); + clue = new_clue; + g_date_free (date); + } + + /* send place */ + if (cdata->place != NULL) + { + new_clue = g_strconcat ( + clue, + dashboard_build_clue (cdata->place, "keyword", 10), + NULL + ); + g_free (clue); + clue = new_clue; + } + + /* send comment */ + if (cdata->comment != NULL) + { + new_clue = g_strconcat ( + clue, + dashboard_build_clue (cdata->comment, "textblock", 10), + NULL + ); + g_free (clue); + clue = new_clue; + } + } + + g_object_get (G_OBJECT (window->app), "has-toplevel-focus", &has_focus, NULL); + + packet = dashboard_build_cluepacket ( + "GThumb", + has_focus, + path, + clue, + NULL + ); + + dashboard_send_raw_cluepacket (packet); + g_free (clue); + g_free (packet); + } +} static void window_update_image_info (GThumbWindow *window) @@ -733,6 +818,7 @@ update_exif_data (window); #endif /* HAVE_LIBEXIF */ update_image_comment (window); + dashboard_send_info (window); }