static void* pyFF_maybeCallCVPreserveState( PyFF_Glyph *self ) { if( !inPythonStartedCollabSession ) return 0; #ifndef BUILD_COLLAB return 0; #else CharView* cv = 0; static GHashTable* ht = 0; if( !ht ) { ht = g_hash_table_new( g_direct_hash, g_direct_equal ); } fprintf(stderr,"hash size:%d\n", g_hash_table_size(ht)); gpointer cache = g_hash_table_lookup( ht, self->sc ); if( cache ) { return cache; } SplineFont *sf = self->sc->parent; FontView* fv = (FontView*)FontViewFind( FontViewFind_bySplineFont, sf ); if( !fv ) { fprintf(stderr,"Collab error: can not find fontview for the SplineFont of the active char\n"); } else { int old_no_windowing_ui = no_windowing_ui; no_windowing_ui = 0; // FIXME: need to find the existing cv if available! cv = CharViewCreate( self->sc, fv, -1 ); g_hash_table_insert( ht, self->sc, cv ); fprintf(stderr,"added... hash size:%d\n", g_hash_table_size(ht)); CVPreserveState( &cv->b ); collabclient_CVPreserveStateCalled( &cv->b ); no_windowing_ui = old_no_windowing_ui; printf("called CVPreserveState()\n"); } return cv; #endif }
void collabclient_free( void** ccvp ) { #ifdef BUILD_COLLAB cloneclient_t* cc = (cloneclient_t*)*ccvp; if( !cc ) return; if( cc->magic_number != MAGIC_VALUE ) { fprintf(stderr,"collabclient_free() called on an invalid client object!\n"); return; } 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 ); FontView* fv = FontViewFind( FontViewFind_byCollabPtr, cc ); if( fv ) { fv->b.collabClient = 0; } zhash_destroy (&cc->kvmap); free(cc->address); free(cc); *ccvp = 0; #endif }
/** * 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; // printf("collabclient_roundTripTimer() cc: %p\n", cc ); // printf("collabclient_roundTripTimer() waitingseq: %d\n", cc->roundTripTimerWaitingSeq ); if( cc->roundTripTimerWaitingSeq ) { cc->roundTripTimerWaitingSeq = 0; char *buts[3]; buts[0] = _("_Reconnect"); buts[1] = _("_Disconnect"); buts[2] = NULL; if ( gwwv_ask(_("Network Issue"), (const char **) buts,0,1, _("FontForge expected some input from the server by now.\nWould you like to try to reconnect to the collaboration session?"))==1 ) { // break session FontView* fv = FontViewFind( FontViewFind_byCollabPtr, cc ); if( fv ) { printf("fv:%p\n", fv ); fv->b.collabState = cs_disconnected; fv->b.collabClient = 0; FVTitleUpdate( &fv->b ); } collabclient_free( (void**)&cc ); return; } collabclient_sessionReconnect( cc ); } }
/** * 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); if( cc->sequence >= cc->roundTripTimerWaitingSeq ) cc->roundTripTimerWaitingSeq = 0; char* uuid = kvmsg_get_prop (kvmsg, "uuid" ); byte* data = kvmsg_body (kvmsg); size_t data_size = kvmsg_size (kvmsg); printf("cc process_update() uuid:%s\n", uuid ); FontView* fv = FontViewFind( FontViewFind_byXUIDConnected, uuid ); printf("fv:%p\n", fv ); if( fv ) { if( !data_size ) { printf("WARNING: zero length message!\n" ); return; } SplineFont *sf = fv->b.sf; if( !sf ) { printf("ERROR: font view does not have the splinefont set!\n" ); return; } char* pos = kvmsg_get_prop (kvmsg, "pos" ); char* name = kvmsg_get_prop (kvmsg, "name" ); printf("pos:%s\n", pos ); // SplineChar *sc = sf->glyphs[ atoi(pos) ]; SplineChar* sc = SFGetOrMakeChar( sf, -1, name ); printf("sc:%p\n", sc ); if( !sc ) { printf("WARNING: font view does not have a glyph for pos:%s\n", pos ); printf("WARNING: font view does not have a glyph for name:%s\n", name ); return; } printf("sc.name:%s\n", sc->name ); printf("data.size:%ld\n", data_size ); if( DEBUG_SHOW_SFD_CHUNKS ) printf("data:%s\n", data ); int current_layer = 0; if( !sc->views && create ) { int show = 0; CharView* cv = CharViewCreateExtended( sc, fv, -1, show ); printf("created charview:%p\n", cv ); } for( CharViewBase* cv = sc->views; cv; cv = cv->next ) { printf("have charview:%p\n", cv ); char filename[PATH_MAX]; snprintf(filename, PATH_MAX, "%s/fontforge-collab-inx-%d.sfd", getTempDir(), getpid() ); GFileWriteAll( filename, (char*)data); FILE* file = fopen( filename, "rb" ); 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 ) { // NOT HANDLED! if( undo->undotype == ut_statehint ) { printf("*** warning ut_statehint not handled\n"); break; } printf("________________________ READ undo.layer: %d dm:%d layer_sz:%d\n", undo->layer, cv->drawmode, cv->sc->layer_cnt ); int selectedlayer = cv->drawmode; if( undo->layer != UNDO_LAYER_UNKNOWN ) selectedlayer = undo->layer; // use oldlayer to store current setting and switch to the // selected layer for this block. int oldlayer = cv->drawmode; cv->drawmode = selectedlayer; undo->next = 0; undo->next = cv->layerheads[selectedlayer]->redoes; cv->layerheads[selectedlayer]->redoes = undo; CVDoRedo( cv ); char* isLocalUndo = kvmsg_get_prop (kvmsg, "isLocalUndo" ); if( isLocalUndo ) { if( isLocalUndo[0] == '1' ) { Undoes* undo = cv->layerheads[selectedlayer]->undoes; if( undo ) { cv->layerheads[selectedlayer]->undoes = undo->next; undo->next = cv->layerheads[selectedlayer]->redoes; cv->layerheads[selectedlayer]->redoes = undo; } } } if( cv->drawmode != oldlayer ) { cv->drawmode = oldlayer; CVCharChangedUpdate( cv ); } } break; } } printf ("I: processed update=%d\n", (int) cc->sequence); }