Loopp/src/nsm.h

544 lines
16 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*************************************************************************/
/* Copyright (C) 2012 Jonathan Moore Liles */
/* */
/* Permission to use, copy, modify, and/or distribute this software for */
/* any purpose with or without fee is hereby granted, provided that the */
/* above copyright notice and this permission notice appear in all */
/* copies. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL */
/* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE */
/* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL */
/* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR */
/* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER */
/* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR */
/* PERFORMANCE OF THIS SOFTWARE. */
/*************************************************************************/
/*************************************************************/
/* A simple, callback based C API for NSM clients. */
/* */
/* Simplified Example: */
/* */
/* #include "nsm.h" */
/* */
/* int */
/* cb_nsm_open ( const char *name, */
/* const char *display_name, */
/* const char *client_id, */
/* char **out_msg, */
/* void *userdata ) */
/* { */
/* do_open_stuff(); */
/* return ERR_OK; */
/* } */
/* */
/* int */
/* cb_nsm_save ( char **out_msg, */
/* void *userdata ) */
/* { */
/* do_save_stuff(); */
/* return ERR_OK; */
/* } */
/* */
/* static nsm_client_t *nsm = 0 */
/* */
/* int main( int argc, char **argv ) */
/* { */
/* const char *nsm_url = getenv( "NSM_URL" ); */
/* */
/* if ( nsm_url ) */
/* { */
/* nsm = nsm_new(); */
/* */
/* nsm_set_open_callback( nsm, cb_nsm_open, 0 ); */
/* nsm_set_save_callback( nsm, cb_nsm_save, 0 ); */
/* */
/* if ( 0 == nsm_init( nsm, nsm_url ) ) */
/* { */
/* nsm_send_announce( nsm, "FOO", "", argv[0] ); */
/* } */
/* else */
/* { */
/* nsm_free( nsm ); */
/* nsm = 0; */
/* } */
/* } */
/* } */
/*************************************************************/
#ifndef _NSM_H
#define _NSM_H
#define NSM_API_VERSION_MAJOR 1
#define NSM_API_VERSION_MINOR 0
#include <lo/lo.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
typedef void * nsm_client_t;
typedef int (nsm_open_callback)( const char *name, const char *display_name, const char *client_id, char **out_msg, void *userdata );
typedef int (nsm_save_callback)( char **out_msg, void *userdata );
typedef void (nsm_active_callback)( int b, void *userdata );
typedef void (nsm_session_is_loaded_callback)( void *userdata );
typedef int (nsm_broadcast_callback)( const char *, lo_message m, void *userdata );
#define _NSM() ((struct _nsm_client_t*)nsm)
#define NSM_EXPORT __attribute__((unused)) static
/* private parts */
struct _nsm_client_t
{
const char *nsm_url;
lo_server _server;
lo_server_thread _st;
lo_address nsm_addr;
int nsm_is_active;
char *nsm_client_id;
char *_session_manager_name;
nsm_open_callback *open;
void *open_userdata;
nsm_save_callback *save;
void *save_userdata;
nsm_active_callback *active;
void *active_userdata;
nsm_session_is_loaded_callback *session_is_loaded;
void *session_is_loaded_userdata;
nsm_broadcast_callback *broadcast;
void *broadcast_userdata;
};
enum
{
ERR_OK = 0,
ERR_GENERAL = -1,
ERR_INCOMPATIBLE_API = -2,
ERR_BLACKLISTED = -3,
ERR_LAUNCH_FAILED = -4,
ERR_NO_SUCH_FILE = -5,
ERR_NO_SESSION_OPEN = -6,
ERR_UNSAVED_CHANGES = -7,
ERR_NOT_NOW = -8
};
NSM_EXPORT
int
nsm_is_active ( nsm_client_t *nsm )
{
return _NSM()->nsm_is_active;
}
NSM_EXPORT
const char *
nsm_get_session_manager_name ( nsm_client_t *nsm )
{
return _NSM()->_session_manager_name;
}
NSM_EXPORT
nsm_client_t *
nsm_new ( void )
{
struct _nsm_client_t *nsm = (struct _nsm_client_t*)malloc( sizeof( struct _nsm_client_t ) );
nsm->nsm_url = 0;
nsm->nsm_is_active = 0;
nsm->nsm_client_id = 0;
nsm->_server = 0;
nsm->_st = 0;
nsm->nsm_addr = 0;
nsm->_session_manager_name = 0;
nsm->open = 0;
nsm->save = 0;
nsm->active = 0;
nsm->session_is_loaded = 0;
nsm->broadcast = 0;
return (nsm_client_t *)nsm;
}
/*******************************************/
/* CLIENT TO SERVER INFORMATIONAL MESSAGES */
/*******************************************/
NSM_EXPORT
void
nsm_send_is_dirty ( nsm_client_t *nsm )
{
if ( _NSM()->nsm_is_active )
lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/is_dirty", "" );
}
NSM_EXPORT
void
nsm_send_is_clean ( nsm_client_t *nsm )
{
if ( _NSM()->nsm_is_active )
lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/is_clean", "" );
}
NSM_EXPORT
void
nsm_send_progress ( nsm_client_t *nsm, float p )
{
if ( _NSM()->nsm_is_active )
lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/progress", "f", p );
}
NSM_EXPORT
void
nsm_send_message ( nsm_client_t *nsm, int priority, const char *msg )
{
if ( _NSM()->nsm_is_active )
lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/message", "is", priority, msg );
}
NSM_EXPORT void
nsm_send_announce ( nsm_client_t *nsm, const char *app_name, const char *capabilities, const char *process_name )
{
lo_address to = lo_address_new_from_url( _NSM()->nsm_url );
if ( ! to )
{
fprintf( stderr, "NSM: Bad address!" );
return;
}
int pid = (int)getpid();
lo_send_from( to, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
app_name,
capabilities,
process_name,
NSM_API_VERSION_MAJOR,
NSM_API_VERSION_MINOR,
pid );
lo_address_free( to );
}
NSM_EXPORT void
nsm_send_broadcast ( nsm_client_t *nsm, lo_message msg )
{
if ( _NSM()->nsm_is_active )
lo_send_message_from( _NSM()->nsm_addr, _NSM()->_server, "/nsm/server/broadcast", msg );
}
NSM_EXPORT
void
nsm_check_wait ( nsm_client_t *nsm, int timeout )
{
if ( lo_server_wait( _NSM()->_server, timeout ) )
while ( lo_server_recv_noblock( _NSM()->_server, 0 ) ) {}
}
NSM_EXPORT
void
nsm_check_nowait (nsm_client_t *nsm )
{
nsm_check_wait( nsm, 0 );
}
NSM_EXPORT
void
nsm_thread_start ( nsm_client_t *nsm )
{
lo_server_thread_start( _NSM()->_st );
}
NSM_EXPORT
void
nsm_thread_stop ( nsm_client_t *nsm )
{
lo_server_thread_stop( _NSM()->_st );
}
NSM_EXPORT void
nsm_free ( nsm_client_t *nsm )
{
if ( _NSM()->_st )
nsm_thread_stop( nsm );
if ( _NSM()->_st )
lo_server_thread_free( _NSM()->_st );
else
lo_server_free( _NSM()->_server );
free( _NSM() );
}
/*****************/
/* SET CALLBACKS */
/*****************/
NSM_EXPORT
void
nsm_set_open_callback( nsm_client_t *nsm, nsm_open_callback *open_callback, void *userdata )
{
_NSM()->open = open_callback;
_NSM()->open_userdata = userdata;
}
NSM_EXPORT
void
nsm_set_save_callback( nsm_client_t *nsm, nsm_save_callback *save_callback, void *userdata )
{
_NSM()->save = save_callback;
_NSM()->save_userdata = userdata;
}
NSM_EXPORT
void
nsm_set_active_callback( nsm_client_t *nsm, nsm_active_callback *active_callback, void *userdata )
{
_NSM()->active = active_callback;
_NSM()->active_userdata = userdata;
}
NSM_EXPORT
void
nsm_set_session_is_loaded_callback( nsm_client_t *nsm, nsm_session_is_loaded_callback *session_is_loaded_callback, void *userdata )
{
_NSM()->session_is_loaded = session_is_loaded_callback;
_NSM()->session_is_loaded_userdata = userdata;
}
NSM_EXPORT
void
nsm_set_broadcast_callback( nsm_client_t *nsm, nsm_broadcast_callback *broadcast_callback, void *userdata )
{
_NSM()->broadcast = broadcast_callback;
_NSM()->broadcast_userdata = userdata;
}
/****************/
/* OSC HANDLERS */
/****************/
#undef OSC_REPLY
#undef OSC_REPLY_ERR
#define OSC_REPLY( value ) lo_send_from( ((struct _nsm_client_t*)user_data)->nsm_addr, ((struct _nsm_client_t*)user_data)->_server, LO_TT_IMMEDIATE, "/reply", "ss", path, value )
#define OSC_REPLY_P( path, value ) lo_send_from( ((struct _nsm_client_t*)user_data)->nsm_addr, ((struct _nsm_client_t*)user_data)->_server, LO_TT_IMMEDIATE, "/reply", "ss", path, value )
#define OSC_REPLY_ERR( errcode, value ) lo_send_from( ((struct _nsm_client_t*)user_data)->nsm_addr, ((struct _nsm_client_t*)user_data)->_server, LO_TT_IMMEDIATE, "/error", "sis", path, errcode, value )
NSM_EXPORT int _nsm_osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
(void) types;
(void) argc;
(void) msg;
char *out_msg = NULL;
struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
nsm->nsm_client_id = strdup( &argv[2]->s );
if ( ! nsm->open )
return 0;
int r = nsm->open( &argv[0]->s, &argv[1]->s, &argv[2]->s, &out_msg, nsm->open_userdata );
if ( r )
OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
else
OSC_REPLY( "OK" );
if ( out_msg )
free( out_msg );
return 0;
}
NSM_EXPORT int _nsm_osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
(void) types;
(void) argv;
(void) argc;
(void) msg;
char *out_msg = NULL;
struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
if ( ! nsm->save )
return 0;
int r = nsm->save(&out_msg, nsm->save_userdata );
if ( r )
{
OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
}
else
{
OSC_REPLY( "OK" );
}
if ( out_msg )
free( out_msg );
return 0;
}
NSM_EXPORT int _nsm_osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
(void) path;
(void) types;
(void) argc;
if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
return -1;
struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
fprintf( stderr, "NSM: Successfully registered. NSM says: %s", &argv[1]->s );
nsm->nsm_is_active = 1;
nsm->_session_manager_name = strdup( &argv[2]->s );
nsm->nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
if ( nsm->active )
nsm->active( nsm->nsm_is_active, nsm->active_userdata );
return 0;
}
NSM_EXPORT int _nsm_osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
(void) path;
(void) types;
(void) argc;
(void) msg;
if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
return -1;
struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
fprintf( stderr, "NSM: Failed to register with NSM server: %s", &argv[2]->s );
nsm->nsm_is_active = 0;
if ( nsm->active )
nsm->active( nsm->nsm_is_active, nsm->active_userdata );
return 0;
}
NSM_EXPORT int _nsm_osc_session_is_loaded ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
(void) path;
(void) types;
(void) argv;
(void) argc;
(void) msg;
struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
if ( ! nsm->session_is_loaded )
return 0;
nsm->session_is_loaded( nsm->session_is_loaded_userdata );
return 0;
}
NSM_EXPORT int _nsm_osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
(void) types;
(void) argv;
(void) argc;
struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
if ( ! nsm->broadcast )
return 0;
return nsm->broadcast( path, msg, nsm->broadcast_userdata );
}
NSM_EXPORT
int
nsm_init ( nsm_client_t *nsm, const char *nsm_url )
{
_NSM()->nsm_url = nsm_url;
lo_address addr = lo_address_new_from_url( nsm_url );
int proto = lo_address_get_protocol( addr );
lo_address_free( addr );
_NSM()->_server = lo_server_new_with_proto( NULL, proto, NULL );
if ( ! _NSM()->_server )
return -1;
lo_server_add_method( _NSM()->_server, "/error", "sis", _nsm_osc_error, _NSM() );
lo_server_add_method( _NSM()->_server, "/reply", "ssss", _nsm_osc_announce_reply, _NSM() );
lo_server_add_method( _NSM()->_server, "/nsm/client/open", "sss", _nsm_osc_open, _NSM() );
lo_server_add_method( _NSM()->_server, "/nsm/client/save", "", _nsm_osc_save, _NSM() );
lo_server_add_method( _NSM()->_server, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded, _NSM() );
lo_server_add_method( _NSM()->_server, NULL, NULL, _nsm_osc_broadcast, _NSM() );
return 0;
}
NSM_EXPORT
int
nsm_init_thread ( nsm_client_t *nsm, const char *nsm_url )
{
_NSM()->nsm_url = nsm_url;
lo_address addr = lo_address_new_from_url( nsm_url );
int proto = lo_address_get_protocol( addr );
lo_address_free( addr );
_NSM()->_st = lo_server_thread_new_with_proto( NULL, proto, NULL );
_NSM()->_server = lo_server_thread_get_server( _NSM()->_st );
if ( ! _NSM()->_server )
return -1;
lo_server_thread_add_method( _NSM()->_st, "/error", "sis", _nsm_osc_error, _NSM() );
lo_server_thread_add_method( _NSM()->_st, "/reply", "ssss", _nsm_osc_announce_reply, _NSM() );
lo_server_thread_add_method( _NSM()->_st, "/nsm/client/open", "sss", _nsm_osc_open, _NSM() );
lo_server_thread_add_method( _NSM()->_st, "/nsm/client/save", "", _nsm_osc_save, _NSM() );
lo_server_thread_add_method( _NSM()->_st, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded, _NSM() );
lo_server_thread_add_method( _NSM()->_st, NULL, NULL, _nsm_osc_broadcast, _NSM() );
return 0;
}
#endif /* NSM_H */