PATCH: Make Abiword a front-end
- From: Julian Satchell <j satchell eris qinetiq com>
- To: Dashboard <dashboard-hackers gnome org>
- Subject: PATCH: Make Abiword a front-end
- Date: Fri, 29 Oct 2004 10:30:32 +0100
I now have permission to release my AbiDash patch. Here is the first
version. The patch applies in abiword-plugins/tools/abidash, against
either abiword-2.1.91 or abiword-2.96
This emits a textblock clue consisting of the paragraph text, when the
cursor moves into a paragraph.
There are few lines of work towards emitting document level meta-data as
clues at document open, but this does not yet emit a cluepacket.
Julian
diff -u -N xp-orig/AbiDash.cpp xp/AbiDash.cpp
--- xp-orig/AbiDash.cpp 2004-10-29 10:05:35.000000000 +0100
+++ xp/AbiDash.cpp 2004-10-29 10:11:40.000000000 +0100
@@ -2,6 +2,8 @@
* AbiDash - Abiword framework for the notification based notification based
* plugins. Designed in particular as a framework for Dashboard.
* Copyright (C) 2004 by Martin Sevior
+ * Copyright (C) 2004 QinetiQ Plc.
+ * Author Julian Satchell <j satchell eris qinetiq com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -20,9 +22,9 @@
*/
#ifdef ABI_PLUGIN_BUILTIN
-#define abi_plugin_register abipgn_abigimp_register
-#define abi_plugin_unregister abipgn_abigimp_unregister
-#define abi_plugin_supports_version abipgn_abigimp_supports_version
+#define abi_plugin_register abipgn_abidash_register
+#define abi_plugin_unregister abipgn_abidash_unregister
+#define abi_plugin_supports_version abipgn_abidash_supports_version
#endif
#include "ut_assert.h"
@@ -36,6 +38,7 @@
#include "fl_BlockLayout.h"
#include "pd_Document.h"
+#include "dashboard-frontend.c"
#include "ut_types.h"
#include "ut_misc.h"
@@ -88,14 +91,52 @@
}
virtual bool notify(AV_View * pAView, const AV_ChangeMask mask)
{
-// printf("I've been notified!! View = %x hint mask %d \n",pAView,mask);
+ UT_UTF8String sText = "";
+ const char *ptext;
+ PD_Document * arg_pCurDoc;
+ fl_BlockLayout * arg_pCurBlock;
+ //printf("I've been notified!! View = %x hint mask %d \n",pAView,mask);
FV_View * pView = static_cast<FV_View *>(pAView);
- if(m_pCurView == NULL)
+
+ m_pCurView = pView;
+ arg_pCurDoc = pView->getDocument();
+ if (arg_pCurDoc != m_pCurDoc)
+ {
+ char *clue, *cluepkt;
+ UT_UTF8String tText = "";
+ m_pCurDoc = arg_pCurDoc;
+ m_pCurDoc->getMetaDataProp (PD_META_KEY_TITLE, tText);
+ /* FIXME We should gather some more document
+ properties, and emit a clue packet
+ containing all these clues*/
+ }
+
+ m_iCurPoint = pView->getPoint();
+
+ arg_pCurBlock= pView->getCurrentBlock();
+ if (m_pCurBlock != arg_pCurBlock )
{
- m_pCurView = pView;
- m_pCurDoc = pView->getDocument();
- m_pCurBlock = pView->getCurrentBlock();
- m_iCurPoint = pView->getPoint();
+ m_pCurBlock = arg_pCurBlock;
+ if (m_pCurBlock!=NULL)
+ {
+ char *clue, *cluepkt;
+
+ m_pCurBlock->appendUTF8String(sText);
+ if (sText.byteLength()==0)
+ return true;
+ ptext = sText.utf8_str();
+ printf("I've been notified!! Text is |%s|\n", ptext );
+ /* Paragraph clue */
+ cluepkt = dashboard_build_cluepacket_then_free_clues
+ ("Abiword",
+ true,
+ "Abiword",/* FIXME This context argument
+ should probably be the filename or URL*/
+ dashboard_build_clue (ptext, "textblock", 10),
+ NULL);
+ printf("CP !%s!\n", cluepkt);
+ dashboard_send_raw_cluepacket(cluepkt);
+ }
}
return true;
}
diff -u -N xp-orig/dashboard-frontend.c xp/dashboard-frontend.c
--- xp-orig/dashboard-frontend.c 1970-01-01 01:00:00.000000000 +0100
+++ xp/dashboard-frontend.c 2004-10-29 10:13:22.000000000 +0100
@@ -0,0 +1,444 @@
+#ifndef __DASHBOARD_FRONTEND_H__
+#define __DASHBOARD_FRONTEND_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#if GLIB_CHECK_VERSION (2,0,0)
+#include <glib/giochannel.h>
+#endif
+
+#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");
+
+ if (close(*fd) < 0)
+ perror ("Dashboard: closing socket (1)");
+
+ 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");
+
+ if (close(*fd) < 0)
+ perror ("Dashboard: closing socket (2)");
+
+ 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");
+
+ if (close(*fd) < 0)
+ perror ("Dashboard: closing socket (3)");
+
+ return 0;
+ }
+ }
+
+ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+ fprintf (stderr, "Dashboard: Connection timed out.\n");
+
+ if (close(*fd) < 0)
+ perror ("Dashboard: closing socket (4)");
+
+ return 0;
+ }
+
+ }
+
+ return 1;
+}
+
+typedef struct {
+ char *rawcluepacket;
+ int bytes_written;
+} CluepacketInfo;
+
+#if GLIB_CHECK_VERSION(2,0,0)
+
+static gboolean
+cluepacket_write_cb (GIOChannel *channel,
+ GIOCondition cond,
+ gpointer user_data)
+{
+ CluepacketInfo *info = (CluepacketInfo *)user_data;
+ GIOError err;
+ gsize total_bytes;
+
+ total_bytes = strlen (info->rawcluepacket);
+
+ do {
+ gsize 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,
+ (GIOCondition)(G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL),
+ cluepacket_write_cb,
+ info);
+
+ g_io_channel_unref (channel);
+}
+
+#endif /* GLIB_CHECK_VERSION (2,0,0) */
+
+
+/*
+ * 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");
+}
+
+#if !GLIB_CHECK_VERSION (2,0,0)
+static char *
+lame_xml_quote (const char *str)
+{
+ char *retval;
+ const char *p;
+ char *q;
+
+ if (str == NULL || strlen (str) == 0)
+ return g_strdup ("");
+
+ retval = g_new (char, strlen (str) * 3);
+
+ q = retval;
+ for (p = str; *p != '\0'; p ++) {
+ switch (*p) {
+
+ case '<':
+ *q ++ = '&';
+ *q ++ = 'l';
+ *q ++ = 't';
+ *q ++ = ';';
+ break;
+
+ case '>':
+ *q ++ = '&';
+ *q ++ = 'g';
+ *q ++ = 't';
+ *q ++ = ';';
+ break;
+
+ case '&':
+ *q ++ = '&';
+ *q ++ = 'a';
+ *q ++ = 'm';
+ *q ++ = 'p';
+ *q ++ = ';';
+ break;
+ default:
+ *q ++ = *p;
+ break;
+ }
+ }
+
+ *q = '\0';
+
+ return retval;
+}
+#endif
+
+static char *
+dashboard_xml_quote (const char *str)
+{
+#if GLIB_CHECK_VERSION (2,0,0)
+ return g_markup_escape_text (str, strlen (str));
+#else
+ return lame_xml_quote (str);
+#endif
+}
+
+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 (" <Clue Type=\"%s\" Relevance=\"%d\">%s</Clue>\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 (
+ "<CluePacket>\n"
+ " <Frontend>%s</Frontend>\n"
+ " <Context>%s</Context>\n"
+ " <Focused>%s</Focused>\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, "</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__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]