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 @@ ...@@ -27,9 +27,9 @@
* *
* Exported functions: None * Exported functions: None
* HISTORY: * 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) * 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 { ...@@ -43,13 +43,15 @@ typedef enum {
ZMAP_APP_REMOTE_ALL = 1 ZMAP_APP_REMOTE_ALL = 1
} appObjType; } appObjType;
typedef enum { /* Requests that come to us from an external program. */
ZMAP_APP_REMOTE_UNKNOWN, typedef enum
ZMAP_APP_REMOTE_OPEN_ZMAP, {
ZMAP_APP_REMOTE_CLOSE_ZMAP ZMAP_APP_REMOTE_UNKNOWN,
} appValidActions; 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 ... /* This should be somewhere else ...
or we should be making other objects */ or we should be making other objects */
...@@ -70,32 +72,19 @@ typedef struct ...@@ -70,32 +72,19 @@ typedef struct
GString *message; GString *message;
}ResponseContextStruct, *ResponseContext; }ResponseContextStruct, *ResponseContext;
typedef struct
{
GTimer *timer;
ZMapAppContext app_context;
ZMapAppContextState state_flag;
} TimerContextStruct, *TimerContext;
static gboolean start(void *userData, static void destroyNotifyData(gpointer destroy_data);
ZMapXMLElement element,
ZMapXMLParser parser);
static gboolean end(void *userData,
ZMapXMLElement element,
ZMapXMLParser parser);
static char *appexecuteCommand(char *command_text, gpointer app_context, int *statusCode); 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 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) void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
{ {
ZMapAppContext app_context = (ZMapAppContext)app_context_data; ZMapAppContext app_context = (ZMapAppContext)app_context_data;
...@@ -106,6 +95,7 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data) ...@@ -106,6 +95,7 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
id = (Window)GDK_DRAWABLE_XID(widget->window); id = (Window)GDK_DRAWABLE_XID(widget->window);
/* Set ourselves up to receive requests _from_ an external program. */
if((xremote = zMapXRemoteNew()) != NULL) if((xremote = zMapXRemoteNew()) != NULL)
{ {
zMapXRemoteNotifyData notifyData; zMapXRemoteNotifyData notifyData;
...@@ -115,11 +105,13 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data) ...@@ -115,11 +105,13 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
notifyData->callback = ZMAPXREMOTE_CALLBACK(appexecuteCommand); notifyData->callback = ZMAPXREMOTE_CALLBACK(appexecuteCommand);
notifyData->data = app_context_data; 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"); zMapConfigDirWriteWindowIdFile(id, "main");
/* Makes sure we actually get the events!!!! Use add-events as set_events needs to be done BEFORE realize */ /* 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) ; gtk_widget_add_events(widget, GDK_PROPERTY_CHANGE_MASK) ;
/* probably need g_signal_connect_data here so we can destroy when disconnected */ /* probably need g_signal_connect_data here so we can destroy when disconnected */
app_context->propertyNotifyEventId = app_context->propertyNotifyEventId =
g_signal_connect_data(G_OBJECT(widget), "property_notify_event", g_signal_connect_data(G_OBJECT(widget), "property_notify_event",
...@@ -130,35 +122,44 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data) ...@@ -130,35 +122,44 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
app_context->propertyNotifyData = notifyData; /* So we can free it */ 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)) if (zMapCmdLineArgsValue(ZMAPARG_WINDOW_ID, &value))
{ {
unsigned long clientId = 0; unsigned long clientId = 0;
char *win_id = NULL; char *win_id = NULL;
win_id = value.s ; win_id = value.s ;
clientId = strtoul(win_id, (char **)NULL, 16); clientId = strtoul(win_id, (char **)NULL, 16);
if(clientId)
if (clientId)
{ {
zMapXRemoteObj client = NULL; zMapXRemoteObj client = NULL;
if((app_context->xremoteClient = client = zMapXRemoteNew()) != NULL)
if((app_context->xremote_client = client = zMapXRemoteNew()) != NULL)
{ {
char *req = NULL; char *req = NULL;
int ret_code = 0; 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>", req = g_strdup_printf("<zmap action=\"register_client\"><client xwid=\"0x%lx\" request_atom=\"%s\" response_atom=\"%s\" /></zmap>",
id, id,
ZMAP_DEFAULT_REQUEST_ATOM_NAME, ZMAP_DEFAULT_REQUEST_ATOM_NAME,
ZMAP_DEFAULT_RESPONSE_ATOM_NAME ZMAP_DEFAULT_RESPONSE_ATOM_NAME
); );
zMapXRemoteInitClient(client, clientId);
zMapXRemoteSetRequestAtomName(client, ZMAP_CLIENT_REQUEST_ATOM_NAME); if ((ret_code = zMapXRemoteSendRemoteCommand(client, req, NULL)) != 0)
zMapXRemoteSetResponseAtomName(client, ZMAP_CLIENT_RESPONSE_ATOM_NAME);
if((ret_code = zMapXRemoteSendRemoteCommand(client, req, NULL)) != 0)
{ {
zMapLogWarning("Could not communicate with client '0x%lx'. code %d", clientId, ret_code); zMapLogWarning("Could not communicate with client '0x%lx'. code %d", clientId, ret_code);
app_context->xremoteClient = NULL; app_context->xremote_client = NULL;
zMapXRemoteDestroy(client); zMapXRemoteDestroy(client);
} }
if(req)
g_free(req); g_free(req);
} }
} }
else else
...@@ -168,124 +169,11 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data) ...@@ -168,124 +169,11 @@ void zmapAppRemoteInstaller(GtkWidget *widget, gpointer app_context_data)
} }
else else
zMapLogWarning("%s", "--win_id option not specified."); 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 /* This should just be a filter command passing to the correct
function defined by the action="value" of the request */ function defined by the action="value" of the request */
...@@ -307,6 +195,7 @@ static char *appexecuteCommand(char *command_text, gpointer app_context_data, in ...@@ -307,6 +195,7 @@ static char *appexecuteCommand(char *command_text, gpointer app_context_data, in
{NULL, NULL} {NULL, NULL}
}; };
parser = zMapXMLParserCreate(&request_data, FALSE, cmd_debug); parser = zMapXMLParserCreate(&request_data, FALSE, cmd_debug);
zMapXMLParserSetMarkupObjectTagHandlers(parser, startH, endH); zMapXMLParserSetMarkupObjectTagHandlers(parser, startH, endH);
...@@ -314,26 +203,34 @@ static char *appexecuteCommand(char *command_text, gpointer app_context_data, in ...@@ -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.code = ZMAPXREMOTE_INTERNAL; /* unknown command if this isn't changed */
response_data.message = g_string_sized_new(256); 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) switch(request_data.action)
{ {
case ZMAP_APP_REMOTE_OPEN_ZMAP: case ZMAP_APP_REMOTE_OPEN_ZMAP:
if((response_data.handled = createZMap(app_context_data, &request_data, &response_data))) {
response_data.code = ZMAPXREMOTE_OK; if((response_data.handled = createZMap(app_context_data, &request_data, &response_data)))
else response_data.code = ZMAPXREMOTE_OK;
response_data.code = ZMAPXREMOTE_BADREQUEST; else
break; response_data.code = ZMAPXREMOTE_BADREQUEST;
break;
}
case ZMAP_APP_REMOTE_CLOSE_ZMAP: case ZMAP_APP_REMOTE_CLOSE_ZMAP:
if((response_data.handled = setupRemoteCloseHandler(app_context, &request_data, &response_data))) {
response_data.code = ZMAPXREMOTE_OK; guint handler_id ;
else
{ /* Send a response to the external program that we got the CLOSE. */
response_data.code = ZMAPXREMOTE_FORBIDDEN; g_string_append_printf(response_data.message, "zmap is closing, wait for finalised request.") ;
g_string_append_printf(response_data.message, response_data.handled = TRUE ;
"closing zmap is not allowed via xremote"); response_data.code = ZMAPXREMOTE_OK;
}
break; /* 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: default:
break; break;
} }
...@@ -403,6 +300,20 @@ static char *appexecuteCommand(char *command_text, gpointer app_context_data, in ...@@ -403,6 +300,20 @@ static char *appexecuteCommand(char *command_text, gpointer app_context_data, in
return xml_reply; 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) static gboolean createZMap(ZMapAppContext app, AppRemoteAll obj, ResponseContext response_data)
{ {
...@@ -423,56 +334,68 @@ static gboolean createZMap(ZMapAppContext app, AppRemoteAll obj, ResponseContext ...@@ -423,56 +334,68 @@ static gboolean createZMap(ZMapAppContext app, AppRemoteAll obj, ResponseContext
} }
/* A GSourceFunc() called from an idle handler to do the final clear up. */
static void destroyNotifyData(gpointer destroy_data) static gboolean finalExit(gpointer data)
{ {
ZMapAppContext app; ZMapAppContext app_context = (ZMapAppContext)data ;
zMapXRemoteNotifyData destroy_me = (zMapXRemoteNotifyData) destroy_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, static gboolean start(void *user_data,
ZMapXMLElement element, ZMapXMLElement element,
ZMapXMLParser parser) ZMapXMLParser parser)
{ {
AppRemoteAll all_data = (AppRemoteAll)user_data;
gboolean handled = FALSE; gboolean handled = FALSE;
AppRemoteAll all_data = (AppRemoteAll)user_data;
ZMapXMLAttribute attr = NULL; ZMapXMLAttribute attr = NULL;
if((attr = zMapXMLElementGetAttributeByName(element, "action")) != NULL) if ((attr = zMapXMLElementGetAttributeByName(element, "action")) != NULL)
{ {
GQuark action = zMapXMLAttributeGetValue(attr); 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("new"))
if(action == g_quark_from_string("close") || {
action == g_quark_from_string("shutdown")) all_data->action = ZMAP_APP_REMOTE_OPEN_ZMAP ;
all_data->action = ZMAP_APP_REMOTE_CLOSE_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 else
zMapXMLParserRaiseParsingError(parser, "Attribute 'action' is required for element 'zmap'."); zMapXMLParserRaiseParsingError(parser, "Attribute 'action' is required for element 'zmap'.");
return handled; return handled ;
} }
static gboolean end(void *user_data, static gboolean end(void *user_data,
ZMapXMLElement element, ZMapXMLElement element,
ZMapXMLParser parser) ZMapXMLParser parser)
{ {
gboolean handled = TRUE ;
AppRemoteAll all_data = (AppRemoteAll)user_data; AppRemoteAll all_data = (AppRemoteAll)user_data;
gboolean handled = TRUE;
ZMapXMLElement child ; ZMapXMLElement child ;
ZMapXMLAttribute attr; ZMapXMLAttribute attr;
if((child = zMapXMLElementGetChildByName(element, "segment")) != NULL) if ((child = zMapXMLElementGetChildByName(element, "segment")) != NULL)
{ {
if((attr = zMapXMLElementGetAttributeByName(child, "sequence")) != NULL) if((attr = zMapXMLElementGetAttributeByName(child, "sequence")) != NULL)
all_data->sequence = zMapXMLAttributeGetValue(attr); 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