Skip to content
Snippets Groups Projects
Commit 2723b23a authored by edgrif's avatar edgrif
Browse files

tidy up quit from client program, remove timer to more general quit code,...

tidy up quit from client program, remove timer to more general quit code, setup idle func. to issue final quit.
parent da331249
No related branches found
No related tags found
No related merge requests found
......@@ -27,9 +27,9 @@
*
* Exported functions: None
* HISTORY:
* Last edited: Mar 7 17:12 2007 (rds)
* Last edited: Mar 9 11:19 2007 (edgrif)
* Created: Thu May 5 18:19:30 2005 (rds)
* CVS info: $Id: zmapAppremote.c,v 1.24 2007-03-08 11:47:46 rds Exp $
* CVS info: $Id: zmapAppremote.c,v 1.25 2007-03-09 11:41:09 edgrif Exp $
*-------------------------------------------------------------------
*/
......@@ -43,13 +43,15 @@ typedef enum {
ZMAP_APP_REMOTE_ALL = 1
} appObjType;
typedef enum {
ZMAP_APP_REMOTE_UNKNOWN,
ZMAP_APP_REMOTE_OPEN_ZMAP,
ZMAP_APP_REMOTE_CLOSE_ZMAP
} appValidActions;
/* Requests that come to us from an external program. */
typedef enum
{
ZMAP_APP_REMOTE_UNKNOWN,
ZMAP_APP_REMOTE_OPEN_ZMAP, /* Open a new zmap window. */
ZMAP_APP_REMOTE_CLOSE_ZMAP, /* Close a window. */
} appValidActions;
typedef enum {KILLING_ALL_ZMAPS = 1} ZMapAppContextState;
typedef enum {RUNNING_ZMAPS, KILLING_ALL_ZMAPS = 1} ZMapAppContextState;
/* This should be somewhere else ...
or we should be making other objects */
......@@ -70,32 +72,19 @@ typedef struct
GString *message;
}ResponseContextStruct, *ResponseContext;
typedef struct
{
GTimer *timer;
ZMapAppContext app_context;
ZMapAppContextState state_flag;
} TimerContextStruct, *TimerContext;
static gboolean start(void *userData,
ZMapXMLElement element,
ZMapXMLParser parser);
static gboolean end(void *userData,
ZMapXMLElement element,
ZMapXMLParser parser);
static void destroyNotifyData(gpointer destroy_data);
static char *appexecuteCommand(char *command_text, gpointer app_context, int *statusCode);
static gboolean start(void *userData, ZMapXMLElement element, ZMapXMLParser parser);
static gboolean end(void *userData, ZMapXMLElement element, ZMapXMLParser parser);
static gboolean createZMap(ZMapAppContext app, AppRemoteAll obj, ResponseContext response);
static void destroyNotifyData(gpointer destroy_data);
static gboolean finalExit(gpointer data) ;
/* closing from remote */
static gboolean closingTimedOut(GTimer *timer);
static gboolean setupRemoteCloseHandler(ZMapAppContext app_context, AppRemoteAll request, ResponseContext response);
static gboolean remoteCloseHandler(gpointer data);
static gboolean confirmCloseRequestResponseReceived(ZMapAppContext app_context);
static void remoteCloseDestroyNotify(gpointer data);
/* Installs the handlers to monitor/handle requests to/from an external program. */
void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
{
ZMapAppContext app_context = (ZMapAppContext)app_context_data;
......@@ -106,6 +95,7 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
id = (Window)GDK_DRAWABLE_XID(widget->window);
/* Set ourselves up to receive requests _from_ an external program. */
if((xremote = zMapXRemoteNew()) != NULL)
{
zMapXRemoteNotifyData notifyData;
......@@ -115,11 +105,13 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
notifyData->callback = ZMAPXREMOTE_CALLBACK(appexecuteCommand);
notifyData->data = app_context_data;
zMapXRemoteInitServer(xremote, id, PACKAGE_NAME, ZMAP_DEFAULT_REQUEST_ATOM_NAME, ZMAP_DEFAULT_RESPONSE_ATOM_NAME);
zMapXRemoteInitServer(xremote, id, PACKAGE_NAME,
ZMAP_DEFAULT_REQUEST_ATOM_NAME, ZMAP_DEFAULT_RESPONSE_ATOM_NAME);
zMapConfigDirWriteWindowIdFile(id, "main");
/* Makes sure we actually get the events!!!! Use add-events as set_events needs to be done BEFORE realize */
gtk_widget_add_events(widget, GDK_PROPERTY_CHANGE_MASK) ;
/* probably need g_signal_connect_data here so we can destroy when disconnected */
app_context->propertyNotifyEventId =
g_signal_connect_data(G_OBJECT(widget), "property_notify_event",
......@@ -130,35 +122,44 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
app_context->propertyNotifyData = notifyData; /* So we can free it */
}
/* Set ourselves up to send requests _to_ an external program. */
if (zMapCmdLineArgsValue(ZMAPARG_WINDOW_ID, &value))
{
unsigned long clientId = 0;
char *win_id = NULL;
win_id = value.s ;
clientId = strtoul(win_id, (char **)NULL, 16);
if(clientId)
if (clientId)
{
zMapXRemoteObj client = NULL;
if((app_context->xremoteClient = client = zMapXRemoteNew()) != NULL)
if((app_context->xremote_client = client = zMapXRemoteNew()) != NULL)
{
char *req = NULL;
int ret_code = 0;
zMapXRemoteInitClient(client, clientId);
zMapXRemoteSetRequestAtomName(client, ZMAP_CLIENT_REQUEST_ATOM_NAME);
zMapXRemoteSetResponseAtomName(client, ZMAP_CLIENT_RESPONSE_ATOM_NAME);
req = g_strdup_printf("<zmap action=\"register_client\"><client xwid=\"0x%lx\" request_atom=\"%s\" response_atom=\"%s\" /></zmap>",
id,
ZMAP_DEFAULT_REQUEST_ATOM_NAME,
ZMAP_DEFAULT_RESPONSE_ATOM_NAME
);
zMapXRemoteInitClient(client, clientId);
zMapXRemoteSetRequestAtomName(client, ZMAP_CLIENT_REQUEST_ATOM_NAME);
zMapXRemoteSetResponseAtomName(client, ZMAP_CLIENT_RESPONSE_ATOM_NAME);
if((ret_code = zMapXRemoteSendRemoteCommand(client, req, NULL)) != 0)
if ((ret_code = zMapXRemoteSendRemoteCommand(client, req, NULL)) != 0)
{
zMapLogWarning("Could not communicate with client '0x%lx'. code %d", clientId, ret_code);
app_context->xremoteClient = NULL;
app_context->xremote_client = NULL;
zMapXRemoteDestroy(client);
}
if(req)
g_free(req);
g_free(req);
}
}
else
......@@ -168,124 +169,11 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
}
else
zMapLogWarning("%s", "--win_id option not specified.");
return;
}
static gboolean confirmCloseRequestResponseReceived(ZMapAppContext app_context)
{
gboolean received = TRUE;
char *response = NULL;
received = FALSE;
if(app_context->xremoteClient)
{
char *request = "<zmap action=\"finalised\" />";
zMapXRemoteSendRemoteCommand(app_context->xremoteClient, request, &response);
received = TRUE;
/* I'm not sure on the library call to get the response, did I write one?
* Not super important though... */
}
else
received = TRUE; /* This is the best we can do here. */
return received;
}
static gboolean closingTimedOut(GTimer *timer)
{
gdouble limit = 10.0, clock; /* 10 secs */
gulong microsecs;
gboolean timed_out = FALSE;
if((clock = g_timer_elapsed(timer, &microsecs)) &&
clock > limit)
timed_out = TRUE;
return timed_out;
}
/* A GSourceFunc, should return FALSE when it is time to remove */
static gboolean remoteCloseHandler(gpointer data)
{
ZMapAppContext app_context = NULL;
TimerContext tc = (TimerContext)data;
gboolean remove = FALSE;
app_context = tc->app_context;
if(tc->state_flag != KILLING_ALL_ZMAPS)
{
tc->state_flag = KILLING_ALL_ZMAPS;
zMapManagerKillAllZMaps(app_context->zmap_manager);
}
else if( (remove = ( zMapManagerCount(app_context->zmap_manager) == 0 )) )
remove = TRUE;
else if(closingTimedOut(tc->timer))
remove = TRUE;
return !remove;
}
static void remoteCloseDestroyNotify(gpointer data)
{
TimerContext tc = (TimerContext)data;
ZMapAppContext app_context = NULL;
app_context = tc->app_context;
if(closingTimedOut(tc->timer) ||
((zMapManagerCount(app_context->zmap_manager) == 0) &&
confirmCloseRequestResponseReceived(app_context)))
{
/* first clean up the TimerContext */
g_timer_destroy(tc->timer);
tc->app_context = NULL;
g_free(tc);
zmapAppExit(app_context) ;
}
return ;
return ;
}
static gboolean setupRemoteCloseHandler(ZMapAppContext app_context,
AppRemoteAll request_data,
ResponseContext response_data)
{
TimerContext timer_data;
guint timeoutId = 0, interval = 1000;
gboolean handled = FALSE;
/* possibly a good idea to check whether we have a client, although
* it goes on latter before sending the request, but also to stop
* random close requests... i.e. zmap must have been started as
* zmap --win_id 0xNNNNNNN
*/
if(app_context->xremoteClient != NULL &&
(timer_data = g_new0(TimerContextStruct, 1)))
{
timer_data->app_context = app_context;
timer_data->timer = g_timer_new();
if((timeoutId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,
interval,
remoteCloseHandler,
(gpointer)timer_data,
remoteCloseDestroyNotify)))
{
if(app_context->propertyNotifyEventId)
g_signal_handler_disconnect(app_context->app_widg,
app_context->propertyNotifyEventId);
app_context->propertyNotifyEventId = timer_data->state_flag = 0;
g_string_append_printf(response_data->message, "zmap is closing, wait for finalised request.");
response_data->handled = handled = TRUE;
}
}
return handled;
}
/* This should just be a filter command passing to the correct
function defined by the action="value" of the request */
......@@ -307,6 +195,7 @@ static char *appexecuteCommand(char *command_text, gpointer app_context_data, in
{NULL, NULL}
};
parser = zMapXMLParserCreate(&request_data, FALSE, cmd_debug);
zMapXMLParserSetMarkupObjectTagHandlers(parser, startH, endH);
......@@ -314,26 +203,34 @@ static char *appexecuteCommand(char *command_text, gpointer app_context_data, in
response_data.code = ZMAPXREMOTE_INTERNAL; /* unknown command if this isn't changed */
response_data.message = g_string_sized_new(256);
if((parse_ok = zMapXMLParserParseBuffer(parser, command_text, strlen(command_text))))
if ((parse_ok = zMapXMLParserParseBuffer(parser, command_text, strlen(command_text))))
{
switch(request_data.action)
{
case ZMAP_APP_REMOTE_OPEN_ZMAP:
if((response_data.handled = createZMap(app_context_data, &request_data, &response_data)))
response_data.code = ZMAPXREMOTE_OK;
else
response_data.code = ZMAPXREMOTE_BADREQUEST;
break;
{
if((response_data.handled = createZMap(app_context_data, &request_data, &response_data)))
response_data.code = ZMAPXREMOTE_OK;
else
response_data.code = ZMAPXREMOTE_BADREQUEST;
break;
}
case ZMAP_APP_REMOTE_CLOSE_ZMAP:
if((response_data.handled = setupRemoteCloseHandler(app_context, &request_data, &response_data)))
response_data.code = ZMAPXREMOTE_OK;
else
{
response_data.code = ZMAPXREMOTE_FORBIDDEN;
g_string_append_printf(response_data.message,
"closing zmap is not allowed via xremote");
}
break;
{
guint handler_id ;
/* Send a response to the external program that we got the CLOSE. */
g_string_append_printf(response_data.message, "zmap is closing, wait for finalised request.") ;
response_data.handled = TRUE ;
response_data.code = ZMAPXREMOTE_OK;
/* Attach an idle handler from which we send the final quit, we must do this because
* otherwise we end up exitting before the external program sees the final quit. */
handler_id = g_idle_add(finalExit, app_context) ;
break;
}
default:
break;
}
......@@ -403,6 +300,20 @@ static char *appexecuteCommand(char *command_text, gpointer app_context_data, in
return xml_reply;
}
static void destroyNotifyData(gpointer destroy_data)
{
ZMapAppContext app;
zMapXRemoteNotifyData destroy_me = (zMapXRemoteNotifyData) destroy_data;
app = destroy_me->data;
app->propertyNotifyData = NULL;
g_free(destroy_me);
return ;
}
static gboolean createZMap(ZMapAppContext app, AppRemoteAll obj, ResponseContext response_data)
{
......@@ -423,56 +334,68 @@ static gboolean createZMap(ZMapAppContext app, AppRemoteAll obj, ResponseContext
}
static void destroyNotifyData(gpointer destroy_data)
/* A GSourceFunc() called from an idle handler to do the final clear up. */
static gboolean finalExit(gpointer data)
{
ZMapAppContext app;
zMapXRemoteNotifyData destroy_me = (zMapXRemoteNotifyData) destroy_data;
ZMapAppContext app_context = (ZMapAppContext)data ;
char *request = "<zmap action=\"finalised\" />";
char *response = NULL;
app = destroy_me->data;
/* Send the final quit, after this we can exit. */
if (!zMapXRemoteSendRemoteCommand(app_context->xremote_client, request, &response))
zMapLogWarning("Final Quit to client program failed: \"%s\"", response) ;
app->propertyNotifyData = NULL;
/* Remove the notify handler. */
if(app_context->propertyNotifyEventId)
g_signal_handler_disconnect(app_context->app_widg, app_context->propertyNotifyEventId);
app_context->propertyNotifyEventId = 0 ;
g_free(destroy_me);
/* Signal zmap we want to exit now. */
zmapAppExit(app_context) ;
return ;
return FALSE ;
}
static gboolean start(void *user_data,
ZMapXMLElement element,
ZMapXMLParser parser)
{
AppRemoteAll all_data = (AppRemoteAll)user_data;
gboolean handled = FALSE;
AppRemoteAll all_data = (AppRemoteAll)user_data;
ZMapXMLAttribute attr = NULL;
if((attr = zMapXMLElementGetAttributeByName(element, "action")) != NULL)
if ((attr = zMapXMLElementGetAttributeByName(element, "action")) != NULL)
{
GQuark action = zMapXMLAttributeGetValue(attr);
if(action == g_quark_from_string("new"))
all_data->action = ZMAP_APP_REMOTE_OPEN_ZMAP;
if(action == g_quark_from_string("close") ||
action == g_quark_from_string("shutdown"))
all_data->action = ZMAP_APP_REMOTE_CLOSE_ZMAP;
if (action == g_quark_from_string("new"))
{
all_data->action = ZMAP_APP_REMOTE_OPEN_ZMAP ;
handled = TRUE ;
}
else if (action == g_quark_from_string("close") || action == g_quark_from_string("shutdown"))
{
all_data->action = ZMAP_APP_REMOTE_CLOSE_ZMAP ;
handled = TRUE ;
}
}
else
zMapXMLParserRaiseParsingError(parser, "Attribute 'action' is required for element 'zmap'.");
return handled;
return handled ;
}
static gboolean end(void *user_data,
ZMapXMLElement element,
ZMapXMLParser parser)
{
gboolean handled = TRUE ;
AppRemoteAll all_data = (AppRemoteAll)user_data;
gboolean handled = TRUE;
ZMapXMLElement child ;
ZMapXMLAttribute attr;
if((child = zMapXMLElementGetChildByName(element, "segment")) != NULL)
if ((child = zMapXMLElementGetChildByName(element, "segment")) != NULL)
{
if((attr = zMapXMLElementGetAttributeByName(child, "sequence")) != NULL)
all_data->sequence = zMapXMLAttributeGetValue(attr);
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment