2 /*************************************************************************/
3 /* Copyright (C) 2012 Jonathan Moore Liles */
5 /* Permission to use, copy, modify, and/or distribute this software for */
6 /* any purpose with or without fee is hereby granted, provided that the */
7 /* above copyright notice and this permission notice appear in all */
10 /* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL */
11 /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */
12 /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE */
13 /* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL */
14 /* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR */
15 /* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER */
16 /* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR */
17 /* PERFORMANCE OF THIS SOFTWARE. */
18 /*************************************************************************/
21 /*************************************************************/
22 /* A simple, callback based C API for NSM clients. */
24 /* Simplified Example: */
26 /* #include "nsm.h" */
29 /* cb_nsm_open ( const char *name, */
30 /* const char *display_name, */
31 /* const char *client_id, */
33 /* void *userdata ) */
35 /* do_open_stuff(); */
40 /* cb_nsm_save ( char **out_msg, */
41 /* void *userdata ) */
43 /* do_save_stuff(); */
47 /* static nsm_client_t *nsm = 0 */
49 /* int main( int argc, char **argv ) */
51 /* const char *nsm_url = getenv( "NSM_URL" ); */
55 /* nsm = nsm_new(); */
57 /* nsm_set_open_callback( nsm, cb_nsm_open, 0 ); */
58 /* nsm_set_save_callback( nsm, cb_nsm_save, 0 ); */
60 /* if ( 0 == nsm_init( nsm, nsm_url ) ) */
62 /* nsm_send_announce( nsm, "FOO", "", argv[0] ); */
66 /* nsm_free( nsm ); */
71 /*************************************************************/
76 #define NSM_API_VERSION_MAJOR 1
77 #define NSM_API_VERSION_MINOR 0
81 #include <sys/types.h>
86 typedef void * nsm_client_t
;
87 typedef int (nsm_open_callback
)( const char *name
, const char *display_name
, const char *client_id
, char **out_msg
, void *userdata
);
88 typedef int (nsm_save_callback
)( char **out_msg
, void *userdata
);
89 typedef void (nsm_active_callback
)( int b
, void *userdata
);
90 typedef void (nsm_session_is_loaded_callback
)( void *userdata
);
91 typedef int (nsm_broadcast_callback
)( const char *, lo_message m
, void *userdata
);
93 #define _NSM() ((struct _nsm_client_t*)nsm)
95 #define NSM_EXPORT __attribute__((unused)) static
103 lo_server_thread _st
;
108 char *_session_manager_name
;
110 nsm_open_callback
*open
;
113 nsm_save_callback
*save
;
116 nsm_active_callback
*active
;
117 void *active_userdata
;
119 nsm_session_is_loaded_callback
*session_is_loaded
;
120 void *session_is_loaded_userdata
;
122 nsm_broadcast_callback
*broadcast
;
123 void *broadcast_userdata
;
130 ERR_INCOMPATIBLE_API
= -2,
131 ERR_BLACKLISTED
= -3,
132 ERR_LAUNCH_FAILED
= -4,
133 ERR_NO_SUCH_FILE
= -5,
134 ERR_NO_SESSION_OPEN
= -6,
135 ERR_UNSAVED_CHANGES
= -7,
141 nsm_is_active ( nsm_client_t
*nsm
)
143 return _NSM()->nsm_is_active
;
148 nsm_get_session_manager_name ( nsm_client_t
*nsm
)
150 return _NSM()->_session_manager_name
;
157 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)malloc( sizeof( struct _nsm_client_t
) );
161 nsm
->nsm_is_active
= 0;
162 nsm
->nsm_client_id
= 0;
167 nsm
->_session_manager_name
= 0;
172 nsm
->session_is_loaded
= 0;
175 return (nsm_client_t
*)nsm
;
178 /*******************************************/
179 /* CLIENT TO SERVER INFORMATIONAL MESSAGES */
180 /*******************************************/
184 nsm_send_is_dirty ( nsm_client_t
*nsm
)
186 if ( _NSM()->nsm_is_active
)
187 lo_send_from( _NSM()->nsm_addr
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/client/is_dirty", "" );
192 nsm_send_is_clean ( nsm_client_t
*nsm
)
194 if ( _NSM()->nsm_is_active
)
195 lo_send_from( _NSM()->nsm_addr
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/client/is_clean", "" );
200 nsm_send_progress ( nsm_client_t
*nsm
, float p
)
202 if ( _NSM()->nsm_is_active
)
203 lo_send_from( _NSM()->nsm_addr
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/client/progress", "f", p
);
208 nsm_send_message ( nsm_client_t
*nsm
, int priority
, const char *msg
)
210 if ( _NSM()->nsm_is_active
)
211 lo_send_from( _NSM()->nsm_addr
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/client/message", "is", priority
, msg
);
215 nsm_send_announce ( nsm_client_t
*nsm
, const char *app_name
, const char *capabilities
, const char *process_name
)
217 lo_address to
= lo_address_new_from_url( _NSM()->nsm_url
);
221 fprintf( stderr
, "NSM: Bad address!" );
225 int pid
= (int)getpid();
227 lo_send_from( to
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/server/announce", "sssiii",
231 NSM_API_VERSION_MAJOR
,
232 NSM_API_VERSION_MINOR
,
235 lo_address_free( to
);
239 nsm_send_broadcast ( nsm_client_t
*nsm
, lo_message msg
)
241 if ( _NSM()->nsm_is_active
)
242 lo_send_message_from( _NSM()->nsm_addr
, _NSM()->_server
, "/nsm/server/broadcast", msg
);
249 nsm_check_wait ( nsm_client_t
*nsm
, int timeout
)
251 if ( lo_server_wait( _NSM()->_server
, timeout
) )
252 while ( lo_server_recv_noblock( _NSM()->_server
, 0 ) ) {}
257 nsm_check_nowait (nsm_client_t
*nsm
)
259 nsm_check_wait( nsm
, 0 );
265 nsm_thread_start ( nsm_client_t
*nsm
)
267 lo_server_thread_start( _NSM()->_st
);
273 nsm_thread_stop ( nsm_client_t
*nsm
)
275 lo_server_thread_stop( _NSM()->_st
);
281 nsm_free ( nsm_client_t
*nsm
)
284 nsm_thread_stop( nsm
);
287 lo_server_thread_free( _NSM()->_st
);
289 lo_server_free( _NSM()->_server
);
300 nsm_set_open_callback( nsm_client_t
*nsm
, nsm_open_callback
*open_callback
, void *userdata
)
302 _NSM()->open
= open_callback
;
303 _NSM()->open_userdata
= userdata
;
308 nsm_set_save_callback( nsm_client_t
*nsm
, nsm_save_callback
*save_callback
, void *userdata
)
310 _NSM()->save
= save_callback
;
311 _NSM()->save_userdata
= userdata
;
317 nsm_set_active_callback( nsm_client_t
*nsm
, nsm_active_callback
*active_callback
, void *userdata
)
319 _NSM()->active
= active_callback
;
320 _NSM()->active_userdata
= userdata
;
325 nsm_set_session_is_loaded_callback( nsm_client_t
*nsm
, nsm_session_is_loaded_callback
*session_is_loaded_callback
, void *userdata
)
327 _NSM()->session_is_loaded
= session_is_loaded_callback
;
328 _NSM()->session_is_loaded_userdata
= userdata
;
334 nsm_set_broadcast_callback( nsm_client_t
*nsm
, nsm_broadcast_callback
*broadcast_callback
, void *userdata
)
336 _NSM()->broadcast
= broadcast_callback
;
337 _NSM()->broadcast_userdata
= userdata
;
349 #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 )
351 #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 )
354 NSM_EXPORT
int _nsm_osc_open ( const char *path
, const char *types
, lo_arg
**argv
, int argc
, lo_message msg
, void *user_data
)
360 char *out_msg
= NULL
;
362 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
364 nsm
->nsm_client_id
= strdup( &argv
[2]->s
);
369 int r
= nsm
->open( &argv
[0]->s
, &argv
[1]->s
, &argv
[2]->s
, &out_msg
, nsm
->open_userdata
);
372 OSC_REPLY_ERR( r
, ( out_msg
? out_msg
: "") );
382 NSM_EXPORT
int _nsm_osc_save ( const char *path
, const char *types
, lo_arg
**argv
, int argc
, lo_message msg
, void *user_data
)
389 char *out_msg
= NULL
;
391 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
396 int r
= nsm
->save(&out_msg
, nsm
->save_userdata
);
399 OSC_REPLY_ERR( r
, ( out_msg
? out_msg
: "") );
409 NSM_EXPORT
int _nsm_osc_announce_reply ( const char *path
, const char *types
, lo_arg
**argv
, int argc
, lo_message msg
, void *user_data
)
415 if ( strcmp( &argv
[0]->s
, "/nsm/server/announce" ) )
418 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
420 fprintf( stderr
, "NSM: Successfully registered. NSM says: %s", &argv
[1]->s
);
422 nsm
->nsm_is_active
= 1;
423 nsm
->_session_manager_name
= strdup( &argv
[2]->s
);
424 nsm
->nsm_addr
= lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg
) ));
427 nsm
->active( nsm
->nsm_is_active
, nsm
->active_userdata
);
432 NSM_EXPORT
int _nsm_osc_error ( const char *path
, const char *types
, lo_arg
**argv
, int argc
, lo_message msg
, void *user_data
)
439 if ( strcmp( &argv
[0]->s
, "/nsm/server/announce" ) )
442 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
444 fprintf( stderr
, "NSM: Failed to register with NSM server: %s", &argv
[2]->s
);
446 nsm
->nsm_is_active
= 0;
449 nsm
->active( nsm
->nsm_is_active
, nsm
->active_userdata
);
454 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
)
462 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
464 if ( ! nsm
->session_is_loaded
)
467 nsm
->session_is_loaded( nsm
->session_is_loaded_userdata
);
472 NSM_EXPORT
int _nsm_osc_broadcast ( const char *path
, const char *types
, lo_arg
**argv
, int argc
, lo_message msg
, void *user_data
)
478 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
480 if ( ! nsm
->broadcast
)
483 return nsm
->broadcast( path
, msg
, nsm
->broadcast_userdata
);
490 nsm_init ( nsm_client_t
*nsm
, const char *nsm_url
)
492 _NSM()->nsm_url
= nsm_url
;
494 lo_address addr
= lo_address_new_from_url( nsm_url
);
495 int proto
= lo_address_get_protocol( addr
);
496 lo_address_free( addr
);
498 _NSM()->_server
= lo_server_new_with_proto( NULL
, proto
, NULL
);
500 if ( ! _NSM()->_server
)
503 lo_server_add_method( _NSM()->_server
, "/error", "sis", _nsm_osc_error
, _NSM() );
504 lo_server_add_method( _NSM()->_server
, "/reply", "ssss", _nsm_osc_announce_reply
, _NSM() );
505 lo_server_add_method( _NSM()->_server
, "/nsm/client/open", "sss", _nsm_osc_open
, _NSM() );
506 lo_server_add_method( _NSM()->_server
, "/nsm/client/save", "", _nsm_osc_save
, _NSM() );
507 lo_server_add_method( _NSM()->_server
, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded
, _NSM() );
508 lo_server_add_method( _NSM()->_server
, NULL
, NULL
, _nsm_osc_broadcast
, _NSM() );
516 nsm_init_thread ( nsm_client_t
*nsm
, const char *nsm_url
)
518 _NSM()->nsm_url
= nsm_url
;
520 lo_address addr
= lo_address_new_from_url( nsm_url
);
521 int proto
= lo_address_get_protocol( addr
);
522 lo_address_free( addr
);
524 _NSM()->_st
= lo_server_thread_new_with_proto( NULL
, proto
, NULL
);
525 _NSM()->_server
= lo_server_thread_get_server( _NSM()->_st
);
527 if ( ! _NSM()->_server
)
530 lo_server_thread_add_method( _NSM()->_st
, "/error", "sis", _nsm_osc_error
, _NSM() );
531 lo_server_thread_add_method( _NSM()->_st
, "/reply", "ssss", _nsm_osc_announce_reply
, _NSM() );
532 lo_server_thread_add_method( _NSM()->_st
, "/nsm/client/open", "sss", _nsm_osc_open
, _NSM() );
533 lo_server_thread_add_method( _NSM()->_st
, "/nsm/client/save", "", _nsm_osc_save
, _NSM() );
534 lo_server_thread_add_method( _NSM()->_st
, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded
, _NSM() );
535 lo_server_thread_add_method( _NSM()->_st
, NULL
, NULL
, _nsm_osc_broadcast
, _NSM() );