Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

A bit of code cleanup, more comments here and there.

Major change, collabclient.c is now always built, but the body
of the functions are #ifdef guarded. This way code through the rest
of fontforge can call the collabclient_foo() functions without needing
any #ifdef guards. They simply do nothing when the zeromq + collab code
is not built.
  • Loading branch information...
commit e7626badf89579f0509e160d297ab36657a0a99a 1 parent 57689f5
@monkeyiq monkeyiq authored
View
6 Unicode/ustring.c
@@ -179,7 +179,7 @@ void u_strncat(unichar_t *to, const unichar_t *from, int len) {
}
-int u_strlen(register const unichar_t *str) {
+int u_strlen(register const unichar_t *str) {
register int len = 0;
while ( *str++!='\0' )
@@ -187,7 +187,7 @@ int u_strlen(register const unichar_t *str) {
return( len );
}
-int c_strlen(const char * p )
+int c_strlen( const char * p )
{
if(!p)
return 0;
@@ -967,7 +967,7 @@ int u_endswith(const unichar_t *haystack,const unichar_t *needle) {
return p == ( haystack + haylen - nedlen );
}
-char* c_itostr( int v )
+char* c_itostr( int v )
{
static char ret[100+1];
snprintf(ret,100,"%d",v );
View
81 collab/zmq_kvmsg.c
@@ -187,23 +187,17 @@ kvmsg_destroy (kvmsg_t **self_p)
kvmsg_t *
kvmsg_recv_full (void *socket, int sockopts )
{
- // This method is almost unchanged from kvsimple
- // .skip
assert (socket);
kvmsg_t *self = kvmsg_new (0);
-// printf("kvmsg_recv_full() top...\n");
-
// Read all frames off the wire, reject if bogus
int frame_nbr;
for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) {
-// printf("kvmsg_recv_full() frame_nbr:%d\n", frame_nbr );
if (self->present [frame_nbr])
zmq_msg_close (&self->frame [frame_nbr]);
zmq_msg_init (&self->frame [frame_nbr]);
self->present [frame_nbr] = 1;
if (zmq_msg_recv (&self->frame [frame_nbr], socket, sockopts ) == -1) {
-// printf("kvmsg_recv_full() can't get more\n");
kvmsg_destroy (&self);
break;
}
@@ -214,10 +208,8 @@ kvmsg_recv_full (void *socket, int sockopts )
break;
}
}
- // .until
if (self)
s_decode_props (self);
-// printf("kvmsg_recv_full() bottom...\n");
return self;
}
@@ -592,79 +584,6 @@ kvmsg_dump (kvmsg_t *self)
else
fprintf (stderr, "NULL message\n");
}
-// .until
-
-// .split test method
-// The selftest method is the same as in kvsimple with added support
-// for the uuid and property features of kvmsg:
-
-int
-kvmsg_test (int verbose)
-{
- // .skip
- kvmsg_t
- *kvmsg;
-
- printf (" * kvmsg: ");
-
- // Prepare our context and sockets
- zctx_t *ctx = zctx_new ();
- void *output = zsocket_new (ctx, ZMQ_DEALER);
- int rc = zmq_bind (output, "ipc://kvmsg_selftest.ipc");
- assert (rc == 0);
- void *input = zsocket_new (ctx, ZMQ_DEALER);
- rc = zmq_connect (input, "ipc://kvmsg_selftest.ipc");
- assert (rc == 0);
-
- zhash_t *kvmap = zhash_new ();
-
- // .until
- // Test send and receive of simple message
- kvmsg = kvmsg_new (1);
- kvmsg_set_key (kvmsg, "key");
- kvmsg_set_uuid (kvmsg);
- kvmsg_set_body (kvmsg, (byte *) "body", 4);
- if (verbose)
- kvmsg_dump (kvmsg);
- kvmsg_send (kvmsg, output);
- kvmsg_store (&kvmsg, kvmap);
-
- kvmsg = kvmsg_recv (input);
- if (verbose)
- kvmsg_dump (kvmsg);
- assert (streq (kvmsg_key (kvmsg), "key"));
- kvmsg_store (&kvmsg, kvmap);
-
- // Test send and receive of message with properties
- kvmsg = kvmsg_new (2);
- kvmsg_set_prop (kvmsg, "prop1", "value1");
- kvmsg_set_prop (kvmsg, "prop2", "value1");
- kvmsg_set_prop (kvmsg, "prop2", "value2");
- kvmsg_set_key (kvmsg, "key");
- kvmsg_set_uuid (kvmsg);
- kvmsg_set_body (kvmsg, (byte *) "body", 4);
- assert (streq (kvmsg_get_prop (kvmsg, "prop2"), "value2"));
- if (verbose)
- kvmsg_dump (kvmsg);
- kvmsg_send (kvmsg, output);
- kvmsg_destroy (&kvmsg);
-
- kvmsg = kvmsg_recv (input);
- if (verbose)
- kvmsg_dump (kvmsg);
- assert (streq (kvmsg_key (kvmsg), "key"));
- assert (streq (kvmsg_get_prop (kvmsg, "prop2"), "value2"));
- kvmsg_destroy (&kvmsg);
- // .skip
- // Shutdown and destroy all objects
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
-
- printf ("OK\n");
- return 0;
-}
-// .until
-
struct kvmap_visit_buildq_foreach_data
{
View
166 collab/zmq_kvmsg.h
@@ -1,6 +1,52 @@
-/* =====================================================================
- * kvmsg - key-value message class for example applications
- * ===================================================================== */
+/******************************************************************************
+*******************************************************************************
+*******************************************************************************
+
+ Copyright (C) 2013 Ben Martin
+
+ This file is part of FontForge.
+
+ FontForge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ FontForge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with FontForge. If not, see <http://www.gnu.org/licenses/>.
+
+ For more details see the COPYING.gplv3 file in the root directory of this
+ distribution.
+
+ Based on example code in the zguide:
+
+Copyright (c) 2010-2011 iMatix Corporation and Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+*******************************************************************************
+*******************************************************************************
+******************************************************************************/
#ifndef __KVMSG_H_INCLUDED__
#define __KVMSG_H_INCLUDED__
@@ -14,79 +60,99 @@ typedef struct _kvmsg kvmsg_t;
extern "C" {
#endif
-// Constructor, sets sequence as provided
-kvmsg_t * kvmsg_new (int64_t sequence);
+ enum { socket_offset_snapshot = 0,
+ socket_offset_subscriber,
+ socket_offset_publisher,
+ socket_offset_ping
+ };
+
+ enum { socket_srv_offset_snapshot = socket_offset_snapshot,
+ socket_srv_offset_publisher = socket_offset_subscriber,
+ socket_srv_offset_collector = socket_offset_publisher,
+ socket_srv_offset_ping = socket_offset_ping
+ };
+
+ // Constructor, sets sequence as provided
+ kvmsg_t * kvmsg_new (int64_t sequence);
-// Destructor
-void kvmsg_destroy (kvmsg_t **self_p);
+ // Destructor
+ void kvmsg_destroy (kvmsg_t **self_p);
-// Create duplicate of kvmsg
-kvmsg_t * kvmsg_dup (kvmsg_t *self);
+ // Create duplicate of kvmsg
+ kvmsg_t * kvmsg_dup (kvmsg_t *self);
-// Reads key-value message from socket, returns new kvmsg instance.
-kvmsg_t * kvmsg_recv (void *socket);
+ // Reads key-value message from socket, returns new kvmsg instance.
+ kvmsg_t * kvmsg_recv (void *socket);
-kvmsg_t * kvmsg_recv_full (void *socket, int sockopts );
+ kvmsg_t * kvmsg_recv_full (void *socket, int sockopts );
-// Send key-value message to socket; any empty frames are sent as such.
-void kvmsg_send (kvmsg_t *self, void *socket);
+ // Send key-value message to socket; any empty frames are sent as such.
+ void kvmsg_send (kvmsg_t *self, void *socket);
-// Return key from last read message, if any, else NULL
-char * kvmsg_key (kvmsg_t *self);
+ // Return key from last read message, if any, else NULL
+ char * kvmsg_key (kvmsg_t *self);
-// Return sequence nbr from last read message, if any
-int64_t kvmsg_sequence (kvmsg_t *self);
+ // Return sequence nbr from last read message, if any
+ int64_t kvmsg_sequence (kvmsg_t *self);
-// Return UUID from last read message, if any, else NULL
-byte * kvmsg_uuid (kvmsg_t *self);
+ // Return UUID from last read message, if any, else NULL
+ byte * kvmsg_uuid (kvmsg_t *self);
-// Return body from last read message, if any, else NULL
-byte * kvmsg_body (kvmsg_t *self);
+ // Return body from last read message, if any, else NULL
+ byte * kvmsg_body (kvmsg_t *self);
-// Return body size from last read message, if any, else zero
-size_t kvmsg_size (kvmsg_t *self);
+ // Return body size from last read message, if any, else zero
+ size_t kvmsg_size (kvmsg_t *self);
-// Set message key as provided
-void kvmsg_set_key (kvmsg_t *self, char *key);
+ // Set message key as provided
+ void kvmsg_set_key (kvmsg_t *self, char *key);
-// Set message sequence number
-void kvmsg_set_sequence (kvmsg_t *self, int64_t sequence);
+ // Set message sequence number
+ void kvmsg_set_sequence (kvmsg_t *self, int64_t sequence);
-// Set message UUID to generated value
-void kvmsg_set_uuid (kvmsg_t *self);
+ // Set message UUID to generated value
+ void kvmsg_set_uuid (kvmsg_t *self);
-// Set message body
-void kvmsg_set_body (kvmsg_t *self, byte *body, size_t size);
+ // Set message body
+ void kvmsg_set_body (kvmsg_t *self, byte *body, size_t size);
-// Set message key using printf format
-void kvmsg_fmt_key (kvmsg_t *self, char *format, ...);
+ // Set message key using printf format
+ void kvmsg_fmt_key (kvmsg_t *self, char *format, ...);
-// Set message body using printf format
-void kvmsg_fmt_body (kvmsg_t *self, char *format, ...);
+ // Set message body using printf format
+ void kvmsg_fmt_body (kvmsg_t *self, char *format, ...);
-// Get message property, if set, else ""
-char * kvmsg_get_prop (kvmsg_t *self, char *name);
+ // Get message property, if set, else ""
+ char * kvmsg_get_prop (kvmsg_t *self, char *name);
-// Set message property
-// Names cannot contain '='. Max length of value is 255 chars.
-void kvmsg_set_prop (kvmsg_t *self, char *name, char *format, ...);
+ // Set message property
+ // Names cannot contain '='. Max length of value is 255 chars.
+ void kvmsg_set_prop (kvmsg_t *self, char *name, char *format, ...);
-// Store entire kvmsg into hash map, if key/value are set
-// Nullifies kvmsg reference, and destroys automatically when no longer
-// needed.
-void kvmsg_store (kvmsg_t **self_p, zhash_t *hash);
+ // Store entire kvmsg into hash map, if key/value are set
+ // Nullifies kvmsg reference, and destroys automatically when no longer
+ // needed.
+ void kvmsg_store (kvmsg_t **self_p, zhash_t *hash);
-// Dump message to stderr, for debugging and tracing
-void kvmsg_dump (kvmsg_t *self);
+ // Dump message to stderr, for debugging and tracing
+ void kvmsg_dump (kvmsg_t *self);
-// Runs self test of class
-int kvmsg_test (int verbose);
+ // Runs self test of class
+ int kvmsg_test (int verbose);
-void kvmsg_free (void *ptr);
+ void kvmsg_free (void *ptr);
typedef int (kvmsg_visit_fn) (kvmsg_t* msg, void *argument);
+ /**
+ * Visit all entries in the kvmap with a sequence number
+ * greater than minsequence in the natural integer ordering
+ * of sequence numbers, ie: 5,6,7,8...n
+ *
+ * Each msg is passed to your callback function along with a
+ * given argument that you supply.
+ */
void kvmap_visit( zhash_t* kvmap, int64_t minsequence,
kvmsg_visit_fn* callback, void *argument );
View
5 fontforge/Makefile.am
@@ -96,9 +96,6 @@ fontforge_LDFLAGS = $(MY_CFLAGS) $(MY_LIBS) -export-dynamic
endif THE_PROGRAMS
-if LIBZMQ
-ZMQSRCS = collabclient.c collabclient.h
-endif
#--------------------------------------------------------------------------
libfontforge_la_SOURCES = asmfpst.c autohint.c autosave.c autotrace.c \
@@ -119,7 +116,7 @@ libfontforge_la_SOURCES = asmfpst.c autohint.c autosave.c autotrace.c \
ttfspecial.c ufo.c unicoderange.c utils.c winfonts.c zapfnomen.c \
groups.c langfreq.c ftdelta.c autowidth2.c woff.c stamp.c \
activeinui.c pluginloading.c is_LIGATURE.c flaglist.c strlist.c \
- $(ZMQSRCS)
+ collabclient.c collabclient.h
nodist_libfontforge_la_SOURCES = libstamp.c
EXTRA_libfontforge_la_SOURCES = splinerefigure.c
View
18 fontforge/baseviews.h
@@ -163,7 +163,12 @@ struct fvcontainer_funcs {
/* Resize the container so that fv fits */
};
-enum collabState_t { cs_neverConnected, cs_disconnected, cs_server, cs_client };
+enum collabState_t {
+ cs_neverConnected, //< No connection or Collab feature used this run
+ cs_disconnected, //< Was connected at some stage, not anymore
+ cs_server, //< The localhost is running a server process
+ cs_client //< Connected to somebody else's server process
+};
typedef struct fontviewbase {
struct fontviewbase *next; /* Next on list of open fontviews */
@@ -182,8 +187,10 @@ typedef struct fontviewbase {
void *python_fv_object;
#endif
struct fvcontainer *container;
- void* collabClient;
- enum collabState_t collabState;
+ void* collabClient; /* The data used to talk to the collab server process */
+ enum collabState_t collabState; /* Since we want to know if we are connected, or used to be
+ * we have to keep the state variable out of collabClient
+ * itself */
} FontViewBase;
@@ -614,6 +621,11 @@ extern void FVRevertGlyph(FontViewBase *fv);
extern int MMReblend(FontViewBase *fv, MMSet *mm);
extern FontViewBase *MMCreateBlendedFont(MMSet *mm,FontViewBase *fv,real blends[MmMax],int tonew );
extern void FVB_MakeNamelist(FontViewBase *fv, FILE *file);
+
+/**
+ * Code which wants the fontview to redraw it's title can call here to
+ * have that happen.
+ */
extern void FVTitleUpdate(FontViewBase *fv);
extern void AutoWidth2(FontViewBase *fv,int separation,int min_side,int max_side,
View
3  fontforge/charview.c
@@ -3910,6 +3910,9 @@ int CVTestSelectFromEvent(CharView *cv,GEvent *event) {
return( _CVTestSelectFromEvent(cv,&fs));
}
+/**
+ * A cache for the selected spline point or spiro control point
+ */
typedef struct lastselectedpoint
{
SplinePoint *lastselpt;
View
107 fontforge/collab/fontforge-internal-collab-server.c
@@ -117,22 +117,29 @@ typedef struct {
// socket.
void *collector;
+ // A REP socket to reply to client pings
+ void* ping;
+
} clonesrv_t;
-
-// .split send snapshots
-// We handle ICANHAZ? requests by sending snapshot data to the
-// client that requested it:
-
-// Routing information for a key-value snapshot
+/**
+ * Send Snapshots
+ *
+ * Handles ICANHAZ? requests by sending snapshot data to the
+ * client that requested it:
+ *
+ * Routing information for a key-value snapshot
+ */
typedef struct {
void *socket; // ROUTER socket to send to
zframe_t *identity; // Identity of peer who requested state
char *subtree; // Client subtree specification
} kvroute_t;
-// We call this function for each key-value pair in our hash table
+/**
+ * We call this function for each key-value pair in our hash table
+ */
static int
s_send_single (const char *key, void *data, void *args)
{
@@ -151,11 +158,12 @@ s_send_single (const char *key, void *data, void *args)
return 0;
}
-// .split snapshot handler
-// This is the reactor handler for the snapshot socket; it accepts
-// just the ICANHAZ? request and replies with a state snapshot ending
-// with a KTHXBAI message:
-
+/**
+ * Snapshot Handler
+ * This is the reactor handler for the snapshot socket; it accepts
+ * just the ICANHAZ? request and replies with a state snapshot ending
+ * with a KTHXBAI message:
+ */
static int
s_snapshots (zloop_t *loop, zmq_pollitem_t *poller, void *args)
{
@@ -195,10 +203,12 @@ s_snapshots (zloop_t *loop, zmq_pollitem_t *poller, void *args)
return 0;
}
-// .split collect updates
-// We store each update with a new sequence number, and if necessary, a
-// time-to-live. We publish updates immediately on our publisher socket:
-
+/**
+ * COllect Updates
+ *
+ * We store each update with a new sequence number, and if necessary, a
+ * time-to-live. We publish updates immediately on our publisher socket:
+ */
static int
s_collector (zloop_t *loop, zmq_pollitem_t *poller, void *args)
{
@@ -210,7 +220,7 @@ s_collector (zloop_t *loop, zmq_pollitem_t *poller, void *args)
kvmsg_fmt_key(kvmsg, "%s%d", SUBTREE, self->sequence-1 );
kvmsg_send (kvmsg, self->publisher);
- int ttl = atoi (kvmsg_get_prop (kvmsg, "ttl"));
+// int ttl = atoi (kvmsg_get_prop (kvmsg, "ttl"));
// if (ttl)
// kvmsg_set_prop (kvmsg, "ttl",
// "%" PRId64, zclock_time () + ttl * 1000);
@@ -223,34 +233,50 @@ s_collector (zloop_t *loop, zmq_pollitem_t *poller, void *args)
return 0;
}
-// .split flush ephemeral values
-// At regular intervals we flush ephemeral values that have expired. This
-// could be slow on very large data sets:
-
-// If key-value pair has expired, delete it and publish the
-// fact to listening clients.
+/**
+ * Reply to a ping request from FontForge on localhost
+ */
static int
-s_flush_single (const char *key, void *data, void *args)
+s_ping (zloop_t *loop, zmq_pollitem_t *poller, void *args)
{
clonesrv_t *self = (clonesrv_t *) args;
-
- kvmsg_t *kvmsg = (kvmsg_t *) data;
- int64_t ttl;
- sscanf (kvmsg_get_prop (kvmsg, "ttl"), "%" PRId64, &ttl);
- if (ttl && zclock_time () >= ttl) {
- kvmsg_set_sequence (kvmsg, ++self->sequence);
- kvmsg_set_body (kvmsg, (byte *) "", 0);
- kvmsg_send (kvmsg, self->publisher);
- kvmsg_store (&kvmsg, self->kvmap);
- DEBUG ("I: publishing delete=%d", (int) self->sequence);
+ char* p = zstr_recv_nowait( self->ping );
+ if( p && !strcmp(p,"quit"))
+ {
+ exit(0);
}
+ zstr_send( self->ping, "pong" );
return 0;
}
+// .split flush ephemeral values
+// At regular intervals we flush ephemeral values that have expired. This
+// could be slow on very large data sets:
+
+// If key-value pair has expired, delete it and publish the
+// fact to listening clients.
+/* static int */
+/* s_flush_single (const char *key, void *data, void *args) */
+/* { */
+/* clonesrv_t *self = (clonesrv_t *) args; */
+
+/* kvmsg_t *kvmsg = (kvmsg_t *) data; */
+/* int64_t ttl; */
+/* sscanf (kvmsg_get_prop (kvmsg, "ttl"), "%" PRId64, &ttl); */
+/* if (ttl && zclock_time () >= ttl) { */
+/* kvmsg_set_sequence (kvmsg, ++self->sequence); */
+/* kvmsg_set_body (kvmsg, (byte *) "", 0); */
+/* kvmsg_send (kvmsg, self->publisher); */
+/* kvmsg_store (&kvmsg, self->kvmap); */
+/* DEBUG ("I: publishing delete=%d", (int) self->sequence); */
+/* } */
+/* return 0; */
+/* } */
+
static int
s_flush_ttl (zloop_t *loop, zmq_pollitem_t *poller, void *args)
{
- clonesrv_t *self = (clonesrv_t *) args;
+// clonesrv_t *self = (clonesrv_t *) args;
// if (self->kvmap)
// zhash_foreach (self->kvmap, s_flush_single, args);
return 0;
@@ -261,7 +287,6 @@ int main (void)
{
int port = 5556;
-
clonesrv_t *self = (clonesrv_t *) zmalloc (sizeof (clonesrv_t));
self->port = port;
self->ctx = zctx_new ();
@@ -271,11 +296,13 @@ int main (void)
// Set up our clone server sockets
self->snapshot = zsocket_new (self->ctx, ZMQ_ROUTER);
- zsocket_bind (self->snapshot, "tcp://*:%d", self->port);
+ zsocket_bind (self->snapshot, "tcp://*:%d", self->port + socket_srv_offset_snapshot );
self->publisher = zsocket_new (self->ctx, ZMQ_PUB);
- zsocket_bind (self->publisher, "tcp://*:%d", self->port + 1);
+ zsocket_bind (self->publisher, "tcp://*:%d", self->port + socket_srv_offset_publisher );
self->collector = zsocket_new (self->ctx, ZMQ_PULL);
- zsocket_bind (self->collector, "tcp://*:%d", self->port + 2);
+ zsocket_bind (self->collector, "tcp://*:%d", self->port + socket_srv_offset_collector );
+ self->ping = zsocket_new (self->ctx, ZMQ_REP);
+ zsocket_bind (self->ping, "tcp://*:%d", self->port + socket_srv_offset_ping );
// Register our handlers with reactor
zmq_pollitem_t poller = { 0, 0, ZMQ_POLLIN };
@@ -284,6 +311,8 @@ int main (void)
poller.socket = self->collector;
zloop_poller (self->loop, &poller, s_collector, self);
zloop_timer (self->loop, 1000, 0, s_flush_ttl, self);
+ poller.socket = self->ping;
+ zloop_poller (self->loop, &poller, s_ping, self);
DEBUG ("I: server up and running...");
// Run reactor until process interrupted
View
558 fontforge/collabclient.c
@@ -32,14 +32,23 @@
#include "inc/ustring.h"
#include "collabclient.h"
-#include "czmq.h"
-#include "collab/zmq_kvmsg.h"
#include "inc/gfile.h"
#include "views.h"
#include "inc/gwidget.h"
+
+#ifndef _NO_LIBZMQ
+#define BUILD_COLLAB
+#endif
+
+#ifdef BUILD_COLLAB
+#include "collab/zmq_kvmsg.h"
+#include "czmq.h"
+#endif
+
+
#define MAGIC_VALUE 0xbeef
#define SUBTREE "/client/"
@@ -50,7 +59,10 @@
typedef struct {
+
int magic_number; // Magic number to test if the pointer is likely valid
+
+#ifdef BUILD_COLLAB
zctx_t *ctx; // Main zeromq Context
zloop_t *loop; // main zloop reactor
char* address; // address of the server
@@ -59,8 +71,17 @@ typedef struct {
zhash_t *kvmap; // Key-value store that we manage
int64_t sequence; // How many updates we're at
- Undoes* preserveUndo;
- BackgroundTimer_t* roundTripTimer;
+ Undoes* preserveUndo; //< Used by collabclient_sendRedo to only send an undo if one has
+ // been made
+
+ /*
+ * The roundTripTimer fires X milliseconds after we send a redo to
+ * the server. The roundTripTimerWaitingSeq is a cache of the
+ * sequence that we sent to the server. If we don't get a reply to
+ * the update that we sent on subscriber within the timeout then
+ * we assume there is a network problem and alert the user.
+ */
+ BackgroundTimer_t* roundTripTimer;
int roundTripTimerWaitingSeq;
//
@@ -79,10 +100,14 @@ typedef struct {
// to the publisher
int publisher_sendseq;
-
+#endif
} cloneclient_t;
+int collabclient_setHaveLocalServer( int v );
+
+#ifdef BUILD_COLLAB
+
static zctx_t* obtainMainZMQContext()
{
static zctx_t* ctx = 0;
@@ -97,7 +122,7 @@ static zctx_t* obtainMainZMQContext()
* Convert address + port to a string like
* tcp://localhost:5556
*
- * you do not own the return value, do not free it.
+ * you do not own the return value, do not free it.
*/
static char* makeAddressString( char* address, int port )
{
@@ -106,6 +131,18 @@ static char* makeAddressString( char* address, int port )
return ret;
}
+/**
+ * Process the given kvmsg from the server. If create is set and we do
+ * not have any charview for a changed glyph then we first create a
+ * charview for it. This allows the updates from a server to be
+ * processed at startup time, getting us up to speed with any glyphs
+ * that have changed.
+ *
+ * This function is mainly called in response to an update which is
+ * published from the server. However, in sessionJoin() we also call
+ * here to handle the incremental updates to glyphs that have occurred
+ * after the SFD was sent to the server.
+ */
static void zeromq_subscriber_process_update( cloneclient_t* cc, kvmsg_t *kvmsg, int create )
{
cc->sequence = kvmsg_sequence (kvmsg);
@@ -176,7 +213,13 @@ static void zeromq_subscriber_process_update( cloneclient_t* cc, kvmsg_t *kvmsg,
printf ("I: processed update=%d\n", (int) cc->sequence);
}
-
+/**
+ * A callback function that should be invoked when there is input in
+ * the zeromq fd zeromq_fd. The collabclient is taken as the user data
+ * pointer.
+ *
+ * Add this callback using GDrawAddReadFD()
+ */
static void zeromq_subscriber_fd_callback(int zeromq_fd, void* datas )
{
cloneclient_t* cc = (cloneclient_t*)datas;
@@ -203,67 +246,8 @@ static void zeromq_subscriber_fd_callback(int zeromq_fd, void* datas )
{
int create = 0;
zeromq_subscriber_process_update( cc, kvmsg, create );
-
- /* cc->sequence = kvmsg_sequence (kvmsg); */
-
- /* char* uuid = kvmsg_get_prop (kvmsg, "uuid" ); */
- /* byte* data = kvmsg_body (kvmsg); */
- /* size_t data_size = kvmsg_size (kvmsg); */
-
- /* printf("uuid:%s\n", uuid ); */
- /* FontView* fv = FontViewFind( FontViewFind_byXUID, uuid ); */
- /* printf("fv:%p\n", fv ); */
- /* if( fv ) */
- /* { */
- /* if( !data_size ) */
- /* { */
- /* printf("zero length message!\n" ); */
- /* continue; */
- /* } */
-
- /* SplineFont *sf = fv->b.sf; */
- /* char* pos = kvmsg_get_prop (kvmsg, "pos" ); */
- /* printf("pos:%s\n", pos ); */
- /* SplineChar *sc = sf->glyphs[ atoi(pos) ]; */
- /* printf("sc:%p\n", sc ); */
- /* printf("sc.name:%s\n", sc->name ); */
- /* printf("data.size:%d\n", data_size ); */
-
- /* int current_layer = 0; */
-
- /* for( CharViewBase* cv = sc->views; cv; cv = cv->next ) */
- /* { */
- /* char filename[PATH_MAX]; */
- /* snprintf(filename, PATH_MAX, "/tmp/fontforge-collab-inx.sfd"); */
- /* GFileWriteAll( filename, (char*)data); */
- /* FILE* file = fopen( filename, "r" ); */
- /* Undoes* undo = SFDGetUndo( sf, file, sc, */
- /* "UndoOperation", */
- /* "EndUndoOperation", */
- /* current_layer ); */
- /* fclose(file); */
- /* if( !undo ) */
- /* { */
- /* printf("ERROR reading back undo instance!\n"); */
- /* printf("data: %s\n\n", data ); */
- /* } */
- /* if( undo ) */
- /* { */
- /* undo->next = 0; */
- /* cv->layerheads[cv->drawmode]->redoes = undo; */
- /* CVDoRedo( cv ); */
- /* } */
-
- /* break; */
- /* } */
- /* } */
-
-
kvmsg_store (&kvmsg, cc->kvmap);
printf ("I: received update=%d\n", (int) cc->sequence);
-
-
-
}
else
{
@@ -277,7 +261,14 @@ static void zeromq_subscriber_fd_callback(int zeromq_fd, void* datas )
}
-
+/**
+ * A timeout function which is called after a given idle period to
+ * alert the user if we have not received a reply from the server yet.
+ *
+ * If we don't get a reply in time then the user experience will
+ * suffer greatly (UI elements jumping around etc) so we ask the user
+ * if they want to start again or disconnect.
+ */
static void collabclient_roundTripTimer( void* ccvp )
{
cloneclient_t *cc = (cloneclient_t*)ccvp;
@@ -304,41 +295,72 @@ static void collabclient_roundTripTimer( void* ccvp )
{
printf("fv:%p\n", fv );
fv->b.collabState = cs_disconnected;
+ fv->b.collabClient = 0;
FVTitleUpdate( &fv->b );
}
- collabclient_free( &cc );
+ collabclient_free( (void**)&cc );
return;
}
collabclient_sessionReconnect( cc );
}
}
+#endif
+
+void collabclient_sessionDisconnect( FontViewBase* fv )
+{
+#ifdef BUILD_COLLAB
+
+ cloneclient_t *cc = fv->collabClient;
+
+ fv->collabState = cs_disconnected;
+ fv->collabClient = 0;
+ FVTitleUpdate( fv );
+
+ collabclient_free( (void**)&cc );
+
+#endif
+}
+
+
+#ifdef BUILD_COLLAB
static void
collabclient_remakeSockets( cloneclient_t *cc )
{
cc->snapshot = zsocket_new (cc->ctx, ZMQ_DEALER);
- zsocket_connect (cc->snapshot, makeAddressString(cc->address,cc->port));
+ zsocket_connect (cc->snapshot,
+ makeAddressString( cc->address,
+ cc->port + socket_offset_snapshot));
cc->subscriber = zsocket_new (cc->ctx, ZMQ_SUB);
zsockopt_set_subscribe (cc->subscriber, "");
- zsocket_connect (cc->subscriber, makeAddressString(cc->address,cc->port+1));
+ zsocket_connect (cc->subscriber,
+ makeAddressString( cc->address,
+ cc->port + socket_offset_subscriber));
zsockopt_set_subscribe (cc->subscriber, SUBTREE);
cc->publisher = zsocket_new (cc->ctx, ZMQ_PUSH);
- zsocket_connect (cc->publisher, makeAddressString(cc->address,cc->port+2));
+ zsocket_connect (cc->publisher,
+ makeAddressString( cc->address,
+ cc->port + socket_offset_publisher));
int fd = 0;
size_t fdsz = sizeof(fd);
int rc = zmq_getsockopt( cc->subscriber, ZMQ_FD, &fd, &fdsz );
printf("rc:%d fd:%d\n", rc, fd );
- setZeroMQReadFD( 0, fd, cc, zeromq_subscriber_fd_callback );
+ GDrawAddReadFD( 0, fd, cc, zeromq_subscriber_fd_callback );
+
}
+#endif
+
void* collabclient_new( char* address, int port )
{
+#ifdef BUILD_COLLAB
+
cloneclient_t *cc = 0;
cc = (cloneclient_t *) zmalloc (sizeof (cloneclient_t));
cc->magic_number = MAGIC_VALUE;
@@ -354,35 +376,22 @@ void* collabclient_new( char* address, int port )
collabclient_remakeSockets( cc );
- /* cc->snapshot = zsocket_new (cc->ctx, ZMQ_DEALER); */
- /* zsocket_connect (cc->snapshot, makeAddressString(cc->address,cc->port)); */
-
- /* cc->subscriber = zsocket_new (cc->ctx, ZMQ_SUB); */
- /* zsockopt_set_subscribe (cc->subscriber, ""); */
- /* zsocket_connect (cc->subscriber, makeAddressString(cc->address,cc->port+1)); */
- /* zsockopt_set_subscribe (cc->subscriber, SUBTREE); */
-
- /* cc->publisher = zsocket_new (cc->ctx, ZMQ_PUSH); */
- /* zsocket_connect (cc->publisher, makeAddressString(cc->address,cc->port+2)); */
-
- /* int fd = 0; */
- /* size_t fdsz = sizeof(fd); */
- /* int rc = zmq_getsockopt( cc->subscriber, ZMQ_FD, &fd, &fdsz ); */
- /* printf("rc:%d fd:%d\n", rc, fd ); */
- /* setZeroMQReadFD( 0, fd, cc, zeromq_subscriber_fd_callback ); */
-
-
-
int32 roundTripTimerMS = 2000;
cc->roundTripTimer = BackgroundTimer_new( roundTripTimerMS,
collabclient_roundTripTimer,
cc );
return cc;
+
+#endif
+
+ return 0;
}
void collabclient_free( void** ccvp )
{
+#ifdef BUILD_COLLAB
+
cloneclient_t* cc = (cloneclient_t*)*ccvp;
if( !cc )
return;
@@ -393,11 +402,18 @@ void collabclient_free( void** ccvp )
}
cc->magic_number = MAGIC_VALUE + 1;
+ {
+ int fd = 0;
+ size_t fdsz = sizeof(fd);
+ int rc = zmq_getsockopt( cc->subscriber, ZMQ_FD, &fd, &fdsz );
+ GDrawRemoveReadFD( 0, fd, cc );
+ }
+
+
zsocket_destroy( cc->ctx, cc->snapshot );
zsocket_destroy( cc->ctx, cc->subscriber );
zsocket_destroy( cc->ctx, cc->publisher );
BackgroundTimer_remove( cc->roundTripTimer );
- setZeroMQReadFD( 0, 0, 0, zeromq_subscriber_fd_callback );
FontView* fv = FontViewFind( FontViewFind_byCollabPtr, cc );
if( fv )
@@ -409,8 +425,16 @@ void collabclient_free( void** ccvp )
free(cc->address);
free(cc);
*ccvp = 0;
+
+#endif
}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef BUILD_COLLAB
+
static void collabclient_sendSFD( void* ccvp, char* sfd )
{
cloneclient_t* cc = (cloneclient_t*)ccvp;
@@ -426,9 +450,94 @@ static void collabclient_sendSFD( void* ccvp, char* sfd )
free(sfd);
}
+static int collabclient_sessionJoin_processmsg_foreach_fn( kvmsg_t* msg, void *argument )
+{
+ cloneclient_t* cc = (cloneclient_t*)argument;
+ printf("processmsg_foreach() seq:%ld\n", kvmsg_sequence (msg) );
+ int create = 1;
+ zeromq_subscriber_process_update( cc, msg, create );
+
+ return 0;
+}
+
+static void
+collabclient_sendRedo_Internal( CharViewBase *cv, Undoes *undo )
+{
+ printf("collabclient_sendRedo_Internal()\n");
+ cloneclient_t* cc = cv->fv->collabClient;
+ if( !cc )
+ return;
+ char* uuid = cv->fv->sf->xuid;
+ printf("uuid:%s\n", uuid );
+
+ int idx = 0;
+ char filename[PATH_MAX];
+ snprintf(filename, PATH_MAX, "/tmp/fontforge-collab-x.sfd");
+ FILE* f = fopen( filename, "w" );
+ SFDDumpUndo( f, cv->sc, undo, "Undo", idx );
+ fclose(f);
+ char* sfd = GFileReadAll( filename );
+// printf("SENDING: %s\n\n", sfd );
+
+ cc->roundTripTimerWaitingSeq = cc->publisher_sendseq;
+ BackgroundTimer_touch( cc->roundTripTimer );
+
+ kvmsg_t *kvmsg = kvmsg_new(0);
+ kvmsg_fmt_key (kvmsg, "%s%d", SUBTREE, cc->publisher_sendseq++);
+ kvmsg_set_body (kvmsg, sfd, strlen(sfd) );
+ kvmsg_set_prop (kvmsg, "type", MSG_TYPE_UNDO );
+ kvmsg_set_prop (kvmsg, "uuid", uuid );
+ char pos[100];
+ sprintf(pos, "%d", cv->sc->orig_pos );
+ printf("pos:%s\n", pos );
+ printf("sc.name:%s\n", cv->sc->name );
+
+ size_t data_size = kvmsg_size (kvmsg);
+ printf("data.size:%ld\n", data_size );
+
+ kvmsg_set_prop (kvmsg, "pos", pos );
+ kvmsg_send (kvmsg, cc->publisher);
+ kvmsg_destroy (&kvmsg);
+ DEBUG("Sent a undo chunk of %d bytes to the server\n",strlen(sfd));
+ free(sfd);
+}
+
+typedef struct collabclient_sniffForLocalServer_struct
+{
+ void* socket;
+ BackgroundTimer_t* timer;
+ int haveServer;
+} collabclient_sniffForLocalServer_t;
+
+collabclient_sniffForLocalServer_t collabclient_sniffForLocalServer_singleton;
+
+static void collabclient_sniffForLocalServer_timer( void* udata )
+{
+ collabclient_sniffForLocalServer_t* cc = (collabclient_sniffForLocalServer_t*)udata;
+// printf("collabclient_sniffForLocalServer_timer()\n");
+
+ char* p = zstr_recv_nowait( cc->socket );
+ if( p )
+ {
+ printf("collabclient_sniffForLocalServer_timer() p:%s\n", p);
+ if( !strcmp(p,"pong"))
+ {
+ printf("******* have local server!\n");
+ cc->haveServer = 1;
+ }
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
void collabclient_sessionStart( void* ccvp, FontView *fv )
{
+#ifdef BUILD_COLLAB
+
cloneclient_t* cc = (cloneclient_t*)ccvp;
//
@@ -460,74 +569,21 @@ void collabclient_sessionStart( void* ccvp, FontView *fv )
GFileUnlink(filename);
printf("connecting to server...sent the sfd for session start.\n");
fv->b.collabState = cs_server;
- FVTitleUpdate( fv );
+ FVTitleUpdate( &fv->b );
+
+ collabclient_setHaveLocalServer( 1 );
+
+#endif
}
-/* static int collabclient_sessionJoin_findSFD_foreach_fn( const char *key, void *item, void *argumentpp ) */
-/* { */
-/* void** argument = (void**)argumentpp; */
-/* kvmsg_t* kvmsg = (kvmsg_t*)item; */
-
-/* printf("collabclient_sessionJoin_findSFD_foreach_fn() type:%s\n", kvmsg_get_prop (kvmsg, "type")); */
-/* if( !strcmp(kvmsg_get_prop (kvmsg, "type"), MSG_TYPE_SFD )) */
-/* { */
-/* if( *argument ) */
-/* { */
-/* kvmsg_t* current = (kvmsg_t*)*argument; */
-/* if( kvmsg_sequence (kvmsg) > kvmsg_sequence (current) ) */
-/* { */
-/* *argument = kvmsg; */
-/* } */
-/* } */
-/* else */
-/* { */
-/* *argument = kvmsg; */
-/* } */
-/* } */
-/* return 0; */
-/* } */
-
-
-/* struct collabclient_sessionJoin_processUpdates_foreach_args */
-/* { */
-/* cloneclient_t* cc; */
-/* kvmsg_t* lastSFD; */
-/* }; */
-/* static int collabclient_sessionJoin_processUpdates_foreach_fn( const char *key, void *item, void *argument ) */
-/* { */
-/* struct collabclient_sessionJoin_processUpdates_foreach_args* args = */
-/* (struct collabclient_sessionJoin_processUpdates_foreach_args*)argument; */
-/* cloneclient_t* cc = args->cc; */
-/* kvmsg_t* lastSFD = args->lastSFD; */
-/* kvmsg_t* kvmsg = (kvmsg_t*)item; */
-
-/* printf("collabclient_sessionJoin_processUpdates_foreach_fn() type:%s\n", kvmsg_get_prop (kvmsg, "type")); */
-/* if( !strcmp(kvmsg_get_prop (kvmsg, "type"), MSG_TYPE_UNDO )) */
-/* { */
-/* if( kvmsg_sequence (kvmsg) > kvmsg_sequence (lastSFD) ) */
-/* { */
-/* printf("processUpdates_foreach_fn() seq:%d\n", kvmsg_sequence(kvmsg)); */
-/* int create = 1; */
-/* zeromq_subscriber_process_update( cc, kvmsg, create ); */
-/* } */
-/* } */
-/* return 0; */
-/* } */
-static int collabclient_sessionJoin_processmsg_foreach_fn( kvmsg_t* msg, void *argument )
-{
- cloneclient_t* cc = (cloneclient_t*)argument;
- printf("processmsg_foreach() seq:%ld\n", kvmsg_sequence (msg) );
- int create = 1;
- zeromq_subscriber_process_update( cc, msg, create );
-
- return 0;
-}
void collabclient_sessionJoin( void* ccvp, FontView *fv )
{
+#ifdef BUILD_COLLAB
+
cloneclient_t* cc = (cloneclient_t*)ccvp;
printf("collabclient_sessionJoin(top)\n");
@@ -614,11 +670,15 @@ void collabclient_sessionJoin( void* ccvp, FontView *fv )
printf("collabclient_sessionJoin(complete)\n");
+
+#endif
}
void collabclient_sessionReconnect( void* ccvp )
{
+#ifdef BUILD_COLLAB
+
cloneclient_t* cc = (cloneclient_t*)ccvp;
zsocket_destroy( cc->ctx, cc->snapshot );
@@ -632,65 +692,32 @@ void collabclient_sessionReconnect( void* ccvp )
{
collabclient_sessionJoin( cc, fv );
}
-}
-
+#endif
+}
-static void
-collabclient_sendRedo_Internal( CharViewBase *cv, Undoes *undo )
-{
- printf("collabclient_sendRedo_Internal()\n");
- cloneclient_t* cc = cv->fv->collabClient;
- if( !cc )
- return;
- char* uuid = cv->fv->sf->xuid;
- printf("uuid:%s\n", uuid );
-
- int idx = 0;
- char filename[PATH_MAX];
- snprintf(filename, PATH_MAX, "/tmp/fontforge-collab-x.sfd");
- FILE* f = fopen( filename, "w" );
- SFDDumpUndo( f, cv->sc, undo, "Undo", idx );
- fclose(f);
- char* sfd = GFileReadAll( filename );
-// printf("SENDING: %s\n\n", sfd );
- cc->roundTripTimerWaitingSeq = cc->publisher_sendseq;
- BackgroundTimer_touch( cc->roundTripTimer );
- kvmsg_t *kvmsg = kvmsg_new(0);
- kvmsg_fmt_key (kvmsg, "%s%d", SUBTREE, cc->publisher_sendseq++);
- kvmsg_set_body (kvmsg, sfd, strlen(sfd) );
- kvmsg_set_prop (kvmsg, "type", MSG_TYPE_UNDO );
- kvmsg_set_prop (kvmsg, "uuid", uuid );
- char pos[100];
- sprintf(pos, "%d", cv->sc->orig_pos );
- printf("pos:%s\n", pos );
- printf("sc.name:%s\n", cv->sc->name );
-
- size_t data_size = kvmsg_size (kvmsg);
- printf("data.size:%ld\n", data_size );
-
- kvmsg_set_prop (kvmsg, "pos", pos );
- kvmsg_send (kvmsg, cc->publisher);
- kvmsg_destroy (&kvmsg);
- DEBUG("Sent a undo chunk of %d bytes to the server\n",strlen(sfd));
- free(sfd);
-}
void collabclient_CVPreserveStateCalled( CharViewBase *cv )
{
+#ifdef BUILD_COLLAB
+
cloneclient_t* cc = cv->fv->collabClient;
if( !cc )
return;
Undoes *undo = cv->layerheads[cv->drawmode]->undoes;
cc->preserveUndo = undo;
+
+#endif
}
void collabclient_sendRedo( CharViewBase *cv )
{
+#ifdef BUILD_COLLAB
+
cloneclient_t* cc = cv->fv->collabClient;
if( !cc )
return;
@@ -716,38 +743,61 @@ void collabclient_sendRedo( CharViewBase *cv )
UndoesFree( undo );
}
cc->preserveUndo = 0;
+
+#endif
}
int collabclient_inSession( CharViewBase *cv )
{
+#ifdef BUILD_COLLAB
+
if( !cv )
return 0;
if( !cv->fv )
return 0;
cloneclient_t* cc = cv->fv->collabClient;
return cc!=0;
+
+#endif
+ return 0;
}
int collabclient_inSessionFV( FontViewBase* fv )
{
+#ifdef BUILD_COLLAB
+
if( !fv )
return 0;
cloneclient_t* cc = fv->collabClient;
return cc!=0;
+
+#endif
+ return 0;
}
int collabclient_generatingUndoForWire( CharViewBase *cv )
{
+#ifdef BUILD_COLLAB
return collabclient_inSession( cv );
+#endif
+ return 0;
}
enum collabState_t
collabclient_getState( FontViewBase* fv )
{
+#ifdef BUILD_COLLAB
+
if( !fv )
return cs_neverConnected;
return fv->collabState;
+
+#else
+
+ return cs_neverConnected;
+
+#endif
}
char*
@@ -768,66 +818,76 @@ collabclient_stateToString( enum collabState_t s )
}
+int
+collabclient_setHaveLocalServer( int v )
+{
+#ifdef BUILD_COLLAB
+
+ collabclient_sniffForLocalServer_t* cc = &collabclient_sniffForLocalServer_singleton;
+ int oldv = cc->haveServer;
+ cc->haveServer = v;
+ return oldv;
+
+#else
+
+ return 0;
-#if 0
+#endif
+}
-int main (void)
+int
+collabclient_haveLocalServer( void )
{
- // Get state snapshot
- int64_t sequence = 0;
- zstr_sendm (snapshot, "ICANHAZ?");
- zstr_send (snapshot, SUBTREE);
- while (true) {
- kvmsg_t *kvmsg = kvmsg_recv (snapshot);
- if (!kvmsg)
- break; // Interrupted
- if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {
- sequence = kvmsg_sequence (kvmsg);
- printf ("I: received snapshot=%d\n", (int) sequence);
- kvmsg_destroy (&kvmsg);
- break; // Done
- }
- kvmsg_store (&kvmsg, kvmap);
- }
- int64_t alarm = zclock_time () + 1000;
- while (!zctx_interrupted) {
- zmq_pollitem_t items [] = { { subscriber, 0, ZMQ_POLLIN, 0 } };
- int tickless = (int) ((alarm - zclock_time ()));
- if (tickless < 0)
- tickless = 0;
- int rc = zmq_poll (items, 1, tickless * ZMQ_POLL_MSEC);
- if (rc == -1)
- break; // Context has been shut down
-
- if (items [0].revents & ZMQ_POLLIN) {
- kvmsg_t *kvmsg = kvmsg_recv (subscriber);
- if (!kvmsg)
- break; // Interrupted
-
- // Discard out-of-sequence kvmsgs, incl. heartbeats
- if (kvmsg_sequence (kvmsg) > sequence) {
- sequence = kvmsg_sequence (kvmsg);
- kvmsg_store (&kvmsg, kvmap);
- printf ("I: received update=%d\n", (int) sequence);
- }
- else
- kvmsg_destroy (&kvmsg);
- }
- // If we timed-out, generate a random kvmsg
- if (zclock_time () >= alarm) {
- kvmsg_t *kvmsg = kvmsg_new (0);
- kvmsg_fmt_key (kvmsg, "%s%d", SUBTREE, randof (10000));
- kvmsg_fmt_body (kvmsg, "%d", randof (1000000));
- kvmsg_set_prop (kvmsg, "ttl", "%d", randof (30));
- kvmsg_send (kvmsg, publisher);
- kvmsg_destroy (&kvmsg);
- alarm = zclock_time () + 1000;
- }
- }
- printf (" Interrupted\n%d messages in\n", (int) sequence);
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
+#ifdef BUILD_COLLAB
+
+ collabclient_sniffForLocalServer_t* cc = &collabclient_sniffForLocalServer_singleton;
+ return cc->haveServer;
+
+#else
return 0;
+#endif
}
+void
+collabclient_sniffForLocalServer( void )
+{
+#ifdef BUILD_COLLAB
+
+ memset( &collabclient_sniffForLocalServer_singleton, 0,
+ sizeof(collabclient_sniffForLocalServer_t));
+ collabclient_sniffForLocalServer_t* cc = &collabclient_sniffForLocalServer_singleton;
+
+ zctx_t* ctx = obtainMainZMQContext();
+ int port_default = 5556;
+
+ cc->socket = zsocket_new ( ctx, ZMQ_REQ );
+ zsocket_connect (cc->socket,
+ makeAddressString("localhost",
+ port_default + socket_offset_ping));
+ cc->timer = BackgroundTimer_new( 1000, collabclient_sniffForLocalServer_timer, cc );
+ zstr_send (cc->socket, "ping");
+
#endif
+}
+
+void
+collabclient_closeLocalServer( FontViewBase* fv )
+{
+#ifdef BUILD_COLLAB
+
+ collabclient_sniffForLocalServer_t* cc = &collabclient_sniffForLocalServer_singleton;
+ zctx_t* ctx = obtainMainZMQContext();
+ int port_default = 5556;
+
+ void* socket = zsocket_new ( ctx, ZMQ_REQ );
+ zsocket_connect ( socket,
+ makeAddressString("localhost",
+ port_default + socket_offset_ping));
+ zstr_send( socket, "quit" );
+ cc->haveServer = 0;
+
+#endif
+}
+
+
+
View
70 fontforge/collabclient.h
@@ -74,9 +74,21 @@ extern void collabclient_sessionStart( void* ccvp, FontView *fv );
*/
extern void collabclient_sessionJoin( void* ccvp, FontView *fv );
+/**
+ * Reconnect to the collab server. The sockets are all remade, and the
+ * SFD and updates will be downloaded from the server to start a fresh
+ * fontview.
+ */
extern void collabclient_sessionReconnect( void* ccvp );
/**
+ * Disconnect from the collab server. Sockets are cleaned up and the
+ * state is set to disconnected to remind the user that they are no
+ * longer collaborating.
+ */
+extern void collabclient_sessionDisconnect( FontViewBase* fv );
+
+/**
* Something of interest has happened in fontforge which can be
* undone. Send a "redo" event describing the local changes to the
* server. Thus the server will publish these changes to all clients.
@@ -111,11 +123,67 @@ extern void collabclient_CVPreserveStateCalled( CharViewBase *cv );
extern int collabclient_inSession( CharViewBase *cv );
extern int collabclient_inSessionFV( FontViewBase* fv );
+/**
+ * If an undo takes place, it needs to know if it should repaint
+ * the window to reflect the changes. If collabclient_generatingUndoForWire
+ * returns true, then we don't really want to repaint just yet.
+ *
+ * Consider the process of events
+ *
+ * (a) User performs moving the top node in A left a bit
+ * (b) the collab code runs "undo" so it can get the redo information
+ * (c) the undo repaints the window
+ * (d) the redo info is sent to the server
+ * (e) delay
+ * (f) server publishes this redo to all clients (including us)
+ * (g) we "redo" the information from the server
+ * (h) the redo repaints the window
+ *
+ * We would give a better user experience if (c) doesn't happen. So
+ * the user doesn't see the older state appear and cancelled out again
+ * moments later.
+ *
+ * So an undo should check this function and
+ * if( collabclient_generatingUndoForWire() )
+ * {
+ * dont repaint UI
+ * }
+ */
extern int collabclient_generatingUndoForWire( CharViewBase *cv );
-
+/**
+ * Get the state as a enum or string. This can tell the user if we
+ * have never connected, are running a local server, or are simply a
+ * client. Also we can let them know if we were once connected but are
+ * now disconnected.
+ */
extern enum collabState_t collabclient_getState( FontViewBase* fv );
extern char* collabclient_stateToString( enum collabState_t s );
+/**
+ * Is there a local fontforge collab server process running on this
+ * machine? This might take very short amount of time after startup to
+ * be set properly as we ask the server process to reply to a ping.
+ */
+extern int collabclient_haveLocalServer( void );
+
+/**
+ * At startup you should call this to sniff for a local fontforge
+ * server process.
+ */
+extern void collabclient_sniffForLocalServer( void );
+
+/**
+ * Close the local server process. Code would likely want to
+ * collabclient_sessionDisconnect() first and then call here to kill
+ * off the server itself.
+ *
+ * It is a good idea to warn the user that this is happening because
+ * the server process can normally outlive many fontforge clients and
+ * if fontforge itself crashes (on the server too). However, closing
+ * the server process will end it.
+ */
+extern void collabclient_closeLocalServer( FontViewBase* fv );
+
#endif
View
18 fontforge/cvpointer.c
@@ -510,9 +510,6 @@ void CVMouseDownPointer(CharView *cv, FindSel *fs, GEvent *event) {
/* selected, or if the user held the shift key down */
if ( ImgRefEdgeSelected(cv,fs,event))
return;
-
-// CVPreserveState(&cv->b);
-
dowidth = ( cv->showhmetrics && cv->p.cx>cv->b.sc->width-fs->fudge &&
cv->p.cx<cv->b.sc->width+fs->fudge && cv->b.container==NULL &&
usemymetrics==NULL );
@@ -543,7 +540,6 @@ return;
!(event->u.mouse.state&ksm_shift))
needsupdate = CVClearSel(cv);
if ( !fs->p->anysel ) {
- printf("xxxxxxxxxx5 dowidth:%d dovwidth:%d doic:%d dotah:%d nearcaret:%d\n",dowidth,dovwidth,doic,dotah,nearcaret);
/* Nothing else... unless they clicked on the width line, check that */
if ( dowidth ) {
if ( event->u.mouse.state&ksm_shift )
@@ -615,8 +611,6 @@ return;
}
else
{
- printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5.2 needsupdate:%d\n", needsupdate);
-
//
// Allow dragging a box around some points to send that information
// to the other clients in the collab session
@@ -632,12 +626,10 @@ return;
} else if ( fs->p->sp!=NULL ) {
if ( !fs->p->sp->selected ) needsupdate = true;
fs->p->sp->selected = true;
- printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1\n");
} else if ( fs->p->spiro!=NULL ) {
if ( !SPIRO_SELECTED(fs->p->spiro) ) needsupdate = true;
SPIRO_SELECT( fs->p->spiro );
} else if ( fs->p->spline!=NULL && (!cv->b.sc->inspiro || !hasspiro())) {
- printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1.2\n");
if ( !fs->p->spline->to->selected &&
!fs->p->spline->from->selected ) needsupdate = true;
fs->p->spline->to->selected = true;
@@ -659,7 +651,6 @@ return;
} else if ( fs->p->sp!=NULL ) {
needsupdate = true;
fs->p->sp->selected = !fs->p->sp->selected;
- printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2\n");
} else if ( fs->p->spiro!=NULL ) {
needsupdate = true;
@@ -718,18 +709,11 @@ return;
/* Select everything */
if ( CVSetSel(cv,-1)) needsupdate = true;
}
- printf("needsupdate:%d\n", needsupdate );
+
if ( needsupdate )
{
SCUpdateAll(cv->b.sc);
}
- else
- {
- /* // remove the redundant undo item from the stack */
- /* Undoes *undo = cv->b.layerheads[cv->b.drawmode]->undoes; */
- /* cv->b.layerheads[cv->b.drawmode]->undoes = undo->next; */
- /* UndoesFree( undo ); */
- }
/* lastselpt is set by our caller */
}
View
11 fontforge/cvundoes.c
@@ -653,13 +653,12 @@ return(NULL);
undo->u.state.dostroke = cv->layerheads[cv->drawmode]->dostroke;
undo->u.state.fillfirst = cv->layerheads[cv->drawmode]->fillfirst;
- printf("CVPreserveState() new undo is at %p\n", undo );
+ // printf("CVPreserveState() new undo is at %p\n", undo );
- // MIQ: Note, this is the wrong time to do this call
- // we are taking the undo state, after that the app will
- // modify the local state, and that modification is what
- // we are interested in sending on the wire, not the old
- // undo state.
+ // MIQ: Note, this is the wrong time to call sendRedo as we are
+ // currently taking the undo state snapshot, after that the app
+ // will modify the local state, and that modification is what we
+ // are interested in sending on the wire, not the old undo state.
// collabclient_sendRedo( cv );
return( CVAddUndo(cv,undo));
View
55 fontforge/fontview.c
@@ -1374,6 +1374,8 @@ static void FVMenuCondense(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNU
#define MID_CollabStart 22000
#define MID_CollabConnect 22001
+#define MID_CollabDisconnect 22002
+#define MID_CollabCloseLocalServer 22003
#define MID_Warnings 3000
@@ -5574,7 +5576,6 @@ static void FVWindowMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *e) {
static void FVMenuCollabStart(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
{
-#ifndef _NO_LIBZMQ
FontView *fv = (FontView *) GDrawGetUserData(gw);
printf("connecting to server and sending initial SFD to it...\n");
@@ -5615,12 +5616,10 @@ static void FVMenuCollabStart(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *
collabclient_sessionStart( cc, fv );
printf("connecting to server...sent the sfd for session start.\n");
}
-#endif
}
static void FVMenuCollabConnect(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
{
-#ifndef _NO_LIBZMQ
FontView *fv = (FontView *) GDrawGetUserData(gw);
printf("connecting to server...\n");
@@ -5643,18 +5642,64 @@ static void FVMenuCollabConnect(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent
}
printf("FVMenuCollabConnect(done)\n");
-#endif
+}
+
+static void FVMenuCollabDisconnect(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
+{
+ FontView *fv = (FontView *) GDrawGetUserData(gw);
+ collabclient_sessionDisconnect( &fv->b );
+}
+
+static void FVMenuCollabCloseLocalServer(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
+{
+ FontView *fv = (FontView *) GDrawGetUserData(gw);
+
+ enum collabState_t st = collabclient_getState( &fv->b );
+ if( st >= cs_server )
+ {
+ char *buts[3];
+ buts[0] = _("_OK");
+ buts[1] = _("_Cancel");
+ buts[2] = NULL;
+ if ( gwwv_ask(_("Close Server"),(const char **) buts,0,1,_("Please make sure you have saved the font before you close the server. Closing the server will force all clients which might be connected to it to also disconnect. Really close the local server"))==1 )
+ {
+ return;
+ }
+ }
+
+ collabclient_sessionDisconnect( &fv->b );
+ collabclient_closeLocalServer( fv );
}
static void collablistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e))
{
FontView *fv = (FontView *) GDrawGetUserData(gw);
- // nothing yet.
+
+ for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi )
+ {
+ switch ( mi->mid )
+ {
+ case MID_CollabDisconnect:
+ {
+ enum collabState_t st = collabclient_getState( &fv->b );
+ mi->ti.disabled = ( st < cs_server );
+ break;
+ }
+ case MID_CollabCloseLocalServer:
+ printf("can close local server: %d\n", collabclient_haveLocalServer() );
+ mi->ti.disabled = !collabclient_haveLocalServer();
+ break;
+ }
+ }
}
static GMenuItem2 collablist[] = {
{ { (unichar_t *) N_("_Start Session..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Start Session...|No Shortcut"), NULL, NULL, FVMenuCollabStart, MID_CollabStart },
{ { (unichar_t *) N_("_Connect to Session..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Connect to Session...|No Shortcut"), NULL, NULL, FVMenuCollabConnect, MID_CollabConnect },
+ { { (unichar_t *) N_("_Disconnect"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Disconnect|No Shortcut"), NULL, NULL, FVMenuCollabDisconnect, MID_CollabDisconnect },
+ GMENUITEM2_LINE,
+ { { (unichar_t *) N_("Close local server"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Close local server|No Shortcut"), NULL, NULL, FVMenuCollabCloseLocalServer, MID_CollabCloseLocalServer },
+
GMENUITEM2_EMPTY, /* Extra room to show sub-font names */
};
View
7 fontforge/startui.c
@@ -79,6 +79,8 @@ extern void RunApplicationEventLoop(void);
void sleep( int n ){ _sleep(n);}
#endif
+#include "collabclient.h"
+
extern int AutoSaveFrequency;
int splash = 1;
static int localsplash;
@@ -511,7 +513,7 @@ static OSErr install_apple_event_handlers(void) {
static pascal void DoRealStuff(EventLoopTimerRef timer,void *ignored_data) {
GDrawProcessPendingEvents(NULL);
- MacServiceZeroMQFDs();
+ MacServiceReadFDs();
}
static void install_mac_timer(void) {
@@ -1212,6 +1214,9 @@ exit( 0 );
}
if ( !any && !doopen )
any = ReopenLastFonts();
+
+ collabclient_sniffForLocalServer();
+
#if defined(__Mac)
if ( listen_to_apple_events ) {
install_apple_event_handlers();
View
122 gdraw/gdraw.c
@@ -944,23 +944,113 @@ return( NULL );
return( (gdisp->funcs->nativeDisplay)(gdisp) );
}
-void setZeroMQReadFD( GDisplay *gdisp,
- int zeromq_fd, void* zeromq_datas,
- void (*zeromq_fd_callback)(int zeromq_fd, void* datas ))
+/* void setZeroMQReadFD( GDisplay *gdisp, */
+/* int zeromq_fd, void* zeromq_datas, */
+/* void (*zeromq_fd_callback)(int zeromq_fd, void* datas )) */
+/* { */
+/* if ( gdisp==NULL ) */
+/* gdisp=screen_display; */
+
+/* gdisp->zeromq_fd = zeromq_fd; */
+/* gdisp->zeromq_datas = zeromq_datas; */
+/* gdisp->zeromq_fd_callback = zeromq_fd_callback; */
+/* } */
+
+void
+GDrawAddReadFD( GDisplay *gdisp,
+ int fd, void* udata,
+ void (*callback)(int fd, void* udata ))
{
if ( gdisp==NULL )
gdisp=screen_display;
+ if( gdisp->fd_callbacks_last >= gdisplay_fd_callbacks_size )
+ {
+ fprintf(stderr,"Error: FontForge has attempted to add more read FDs than it is equipt to handle\n");
+ fprintf(stderr," Please report this error!\n");
+ return;
+ }
- gdisp->zeromq_fd = zeromq_fd;
- gdisp->zeromq_datas = zeromq_datas;
- gdisp->zeromq_fd_callback = zeromq_fd_callback;
+ fd_callback_t* cb = &gdisp->fd_callbacks[ gdisp->fd_callbacks_last ];
+ gdisp->fd_callbacks_last++;
+
+ cb->fd = fd;
+ cb->udata = udata;
+ cb->callback = callback;
+}
+
+static void
+fd_callback_clear( fd_callback_t* cb )
+{
+ cb->fd = 0;
+ cb->callback = 0;
+ cb->udata = 0;
}
+
+void
+GDrawRemoveReadFD( GDisplay *gdisp,
+ int fd, void* udata )
+{
+ if ( gdisp==NULL )
+ gdisp=screen_display;
+ if( !fd )
+ return;
+
+ int idx = 0;
+ for( idx = 0; idx < gdisplay_fd_callbacks_size; ++idx )
+ {
+ fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
+ if( cb->fd == fd )
+ {
+ if( idx+1 >= gdisp->fd_callbacks_last )
+ {
+ gdisp->fd_callbacks_last--;
+ fd_callback_clear( cb );
+ return;
+ }
+ gdisp->fd_callbacks_last--;
+ fd_callback_t* last = &gdisp->fd_callbacks[ gdisp->fd_callbacks_last ];
+ memcpy( cb, last, sizeof(fd_callback_t) );
+ fd_callback_clear( last );
+ return;
+ }
+ }
+}
+
+
+
#ifndef MAX
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#endif
-void MacServiceZeroMQFDs()
+/* void MacServiceZeroMQFDs() */
+/* { */
+/* int ret = 0; */
+
+/* GDisplay *gdisp = GDrawGetDisplayOfWindow(0); */
+/* int fd = 0; */
+/* fd_set read, write, except; */
+/* FD_ZERO(&read); FD_ZERO(&write); FD_ZERO(&except); */
+/* struct timeval timeout; */
+/* timeout.tv_sec = 0; */
+/* timeout.tv_usec = 1; */
+
+/* if( gdisp->zeromq_fd > 0 ) */
+/* { */
+/* FD_SET(gdisp->zeromq_fd,&read); */
+/* fd = MAX( fd, gdisp->zeromq_fd ); */
+/* } */
+/* if( fd > 0 ) */
+/* ret = select(fd+1,&read,&write,&except,&timeout); */
+
+/* if( FD_ISSET(gdisp->zeromq_fd,&read)) */
+/* { */
+/* gdisp->zeromq_fd_callback( gdisp->zeromq_fd, gdisp->zeromq_datas ); */
+/* } */
+/* } */
+
+
+void MacServiceReadFDs()
{
int ret = 0;
@@ -971,22 +1061,28 @@ void MacServiceZeroMQFDs()
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 1;
-
- if( gdisp->zeromq_fd > 0 )
+
+ int idx = 0;
+ for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
{
- FD_SET(gdisp->zeromq_fd,&read);
- fd = MAX( fd, gdisp->zeromq_fd );
+ fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
+ FD_SET(cb->fd,&read);
+ fd = MAX( fd, cb->fd );
}
+
if( fd > 0 )
ret = select(fd+1,&read,&write,&except,&timeout);
- if( FD_ISSET(gdisp->zeromq_fd,&read))
+ for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
{
- gdisp->zeromq_fd_callback( gdisp->zeromq_fd, gdisp->zeromq_datas );
+ fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
+ if( FD_ISSET(cb->fd,&read))
+ cb->callback( cb->fd, cb->udata );
}
}
+
static int BackgroundTimer_eh( GWindow w, GEvent* ev )
{
if ( ev->type == et_timer )
View
15 gdraw/gdrawP.h
@@ -129,6 +129,16 @@ struct gtimer {
unsigned int active: 1;
};
+typedef struct fd_callback_struct
+{
+ int fd;
+ void* udata;
+ void (*callback)(int fd, void* udata );
+
+} fd_callback_t;
+
+enum { gdisplay_fd_callbacks_size = 64 };
+
struct gdisplay {
struct displayfuncs *funcs;
void *semaphore; /* To lock the display against multiple threads */
@@ -140,9 +150,8 @@ struct gdisplay {
uint16 mykey_state;
uint16 mykey_keysym;
uint16 mykey_mask;
- int zeromq_fd;
- void* zeromq_datas;
- void (*zeromq_fd_callback)(int zeromq_fd, void* datas );
+ fd_callback_t fd_callbacks[ gdisplay_fd_callbacks_size ];
+ int fd_callbacks_last;
unsigned int mykeybuild: 1;
/* display specific data */
};
View
33 gdraw/gxdraw.c
@@ -2918,6 +2918,7 @@ static void GXDrawWaitForEvent(GXDisplay *gdisp) {
struct timeval offset, *timeout;
fd_set read, write, except;
int fd,ret;
+ int idx = 0;
forever {
gettimeofday(&tv,NULL);
@@ -2965,19 +2966,23 @@ return;
fd = gdisp->wacom_fd;
}
#endif
- if( gdisp->zeromq_fd > 0 )
+
+ for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
{
- FD_SET(gdisp->zeromq_fd,&read);
- fd = MAX( fd, gdisp->zeromq_fd );
+ fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
+ FD_SET( cb->fd, &read );
+ fd = MAX( fd, cb->fd );
}
#ifndef __VMS
ret = select(fd+1,&read,&write,&except,timeout);
#endif
- if( FD_ISSET(gdisp->zeromq_fd,&read))
+ for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
{
- gdisp->zeromq_fd_callback( gdisp->zeromq_fd, gdisp->zeromq_datas );
+ fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
+ if( FD_ISSET(cb->fd,&read))
+ cb->callback( cb->fd, cb->udata );
}
}
}
@@ -3856,7 +3861,8 @@ static int GXDrawWaitForNotifyEvent(GXDisplay *gdisp,XEvent *event, Window w) {
struct timeval offset;
fd_set read, write, except;
int fd,ret;
-
+ int idx = 0;
+
gettimeofday(&giveup,NULL);
giveup.tv_sec += gdisp->SelNotifyTimeout;
@@ -3918,18 +3924,23 @@ return( false );
fd = gdisp->wacom_fd;
}
#endif
- if( gdisp->zeromq_fd > 0 )
+
+ for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
{
- FD_SET(gdisp->zeromq_fd,&read);
- fd = MAX( fd, gdisp->zeromq_fd );
+ fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
+ FD_SET( cb->fd, &read );
+ fd = MAX( fd, cb->fd );
}
#ifndef __VMS
ret = select(fd+1,&read,&write,&except,&offset);
#endif
- if( FD_ISSET(gdisp->zeromq_fd,&read))
+
+ for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
{
- gdisp->zeromq_fd_callback( gdisp->zeromq_fd, gdisp->zeromq_datas );
+ fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
+ if( FD_ISSET(cb->fd,&read))
+ cb->callback( cb->fd, cb->udata );
}
}
}
View
5 gdraw/gxdrawP.h
@@ -276,9 +276,8 @@ typedef struct gxdisplay /* : GDisplay */ {
uint16 mykey_state;
uint16 mykey_keysym;
uint16 mykey_mask;
- int zeromq_fd;
- void* zeromq_datas;
- void (*zeromq_fd_callback)(int zeromq_fd, void* datas );
+ fd_callback_t fd_callbacks[ gdisplay_fd_callbacks_size ];
+ int fd_callbacks_last;
unsigned int mykeybuild: 1;
unsigned int default_visual: 1;
unsigned int do_dithering: 1;
View
18 inc/gdraw.h
@@ -588,15 +588,23 @@ extern int GDrawKeyState(int keysym);
extern int GImageGetScaledWidth(GWindow gw, GImage *img);
extern int GImageGetScaledHeight(GWindow gw, GImage *img);
-extern void setZeroMQReadFD( GDisplay *disp,
- int zeromq_fd, void* zeromq_datas,
- void (*zeromq_fd_callback)(int zeromq_fd, void* datas ));
+
+/* extern void setZeroMQReadFD( GDisplay *disp, */
+/* int zeromq_fd, void* zeromq_datas, */
+/* void (*zeromq_fd_callback)(int zeromq_fd, void* datas )); */
+
+extern void GDrawAddReadFD( GDisplay *disp,
+ int fd, void* udata,
+ void (*callback)(int fd, void* udata ));
+extern void GDrawRemoveReadFD( GDisplay *disp,
+ int fd, void* udata );
/**
* The Mac OSX build doesn't use the same core event loop as the
* Linux/X build. So inside the timer we can use this to double check
- * if any zeromq fds have changed and if so service their messages.
+ * if any fds that we should monitor for input have changed and if so
+ * service their messages.
*/
-extern void MacServiceZeroMQFDs(void);
+extern void MacServiceReadFDs(void);
#endif
Please sign in to comment.
Something went wrong with that request. Please try again.