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>
85 typedef void * nsm_client_t
;
86 typedef int (nsm_open_callback
)( const char *name
, const char *display_name
, const char *client_id
, char **out_msg
, void *userdata
);
87 typedef int (nsm_save_callback
)( char **out_msg
, void *userdata
);
88 typedef void (nsm_active_callback
)( int b
, void *userdata
);
89 typedef void (nsm_session_is_loaded_callback
)( void *userdata
);
90 typedef int (nsm_broadcast_callback
)( const char *, lo_message m
, void *userdata
);
92 #define _NSM() ((_nsm_client_t*)nsm)
94 #define NSM_EXPORT __attribute__((unused)) static
102 lo_server_thread _st
;
107 char *_session_manager_name
;
109 nsm_open_callback
*open
;
112 nsm_save_callback
*save
;
115 nsm_active_callback
*active
;
116 void *active_userdata
;
118 nsm_session_is_loaded_callback
*session_is_loaded
;
119 void *session_is_loaded_userdata
;
121 nsm_broadcast_callback
*broadcast
;
122 void *broadcast_userdata
;
129 ERR_INCOMPATIBLE_API
= -2,
130 ERR_BLACKLISTED
= -3,
131 ERR_LAUNCH_FAILED
= -4,
132 ERR_NO_SUCH_FILE
= -5,
133 ERR_NO_SESSION_OPEN
= -6,
134 ERR_UNSAVED_CHANGES
= -7,
140 nsm_is_active ( nsm_client_t
*nsm
)
142 return _NSM()->nsm_is_active
;
147 nsm_get_session_manager_name ( nsm_client_t
*nsm
)
149 return _NSM()->_session_manager_name
;
156 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)malloc( sizeof( struct _nsm_client_t
) );
160 nsm
->nsm_is_active
= 0;
161 nsm
->nsm_client_id
= 0;
166 nsm
->_session_manager_name
= 0;
171 nsm
->session_is_loaded
= 0;
174 return (nsm_client_t
*)nsm
;
177 /*******************************************/
178 /* CLIENT TO SERVER INFORMATIONAL MESSAGES */
179 /*******************************************/
183 nsm_send_is_dirty ( nsm_client_t
*nsm
)
185 if ( _NSM()->nsm_is_active
)
186 lo_send_from( _NSM()->nsm_addr
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/client/is_dirty", "" );
191 nsm_send_is_clean ( nsm_client_t
*nsm
)
193 if ( _NSM()->nsm_is_active
)
194 lo_send_from( _NSM()->nsm_addr
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/client/is_clean", "" );
199 nsm_send_progress ( nsm_client_t
*nsm
, float p
)
201 if ( _NSM()->nsm_is_active
)
202 lo_send_from( _NSM()->nsm_addr
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/client/progress", "f", p
);
207 nsm_send_message ( nsm_client_t
*nsm
, int priority
, const char *msg
)
209 if ( _NSM()->nsm_is_active
)
210 lo_send_from( _NSM()->nsm_addr
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/client/message", "is", priority
, msg
);
214 nsm_send_announce ( nsm_client_t
*nsm
, const char *app_name
, const char *capabilities
, const char *process_name
)
216 lo_address to
= lo_address_new_from_url( _NSM()->nsm_url
);
220 fprintf( stderr
, "NSM: Bad address!" );
224 int pid
= (int)getpid();
226 lo_send_from( to
, _NSM()->_server
, LO_TT_IMMEDIATE
, "/nsm/server/announce", "sssiii",
230 NSM_API_VERSION_MAJOR
,
231 NSM_API_VERSION_MINOR
,
234 lo_address_free( to
);
238 nsm_send_broadcast ( nsm_client_t
*nsm
, lo_message msg
)
240 if ( _NSM()->nsm_is_active
)
241 lo_send_message_from( _NSM()->nsm_addr
, _NSM()->_server
, "/nsm/server/broadcast", msg
);
248 nsm_check_wait ( nsm_client_t
*nsm
, int timeout
)
250 if ( lo_server_wait( _NSM()->_server
, timeout
) )
251 while ( lo_server_recv_noblock( _NSM()->_server
, 0 ) ) {}
256 nsm_check_nowait (nsm_client_t
*nsm
)
258 nsm_check_wait( nsm
, 0 );
264 nsm_thread_start ( nsm_client_t
*nsm
)
266 lo_server_thread_start( _NSM()->_st
);
272 nsm_thread_stop ( nsm_client_t
*nsm
)
274 lo_server_thread_stop( _NSM()->_st
);
280 nsm_free ( nsm_client_t
*nsm
)
283 nsm_thread_stop( nsm
);
286 lo_server_thread_free( _NSM()->_st
);
288 lo_server_free( _NSM()->_server
);
299 nsm_set_open_callback( nsm_client_t
*nsm
, nsm_open_callback
*open_callback
, void *userdata
)
301 _NSM()->open
= open_callback
;
302 _NSM()->open_userdata
= userdata
;
307 nsm_set_save_callback( nsm_client_t
*nsm
, nsm_save_callback
*save_callback
, void *userdata
)
309 _NSM()->save
= save_callback
;
310 _NSM()->save_userdata
= userdata
;
316 nsm_set_active_callback( nsm_client_t
*nsm
, nsm_active_callback
*active_callback
, void *userdata
)
318 _NSM()->active
= active_callback
;
319 _NSM()->active_userdata
= userdata
;
324 nsm_set_session_is_loaded_callback( nsm_client_t
*nsm
, nsm_session_is_loaded_callback
*session_is_loaded_callback
, void *userdata
)
326 _NSM()->session_is_loaded
= session_is_loaded_callback
;
327 _NSM()->session_is_loaded_userdata
= userdata
;
333 nsm_set_broadcast_callback( nsm_client_t
*nsm
, nsm_broadcast_callback
*broadcast_callback
, void *userdata
)
335 _NSM()->broadcast
= broadcast_callback
;
336 _NSM()->broadcast_userdata
= userdata
;
348 #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 )
350 #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 )
353 NSM_EXPORT
int _nsm_osc_open ( const char *path
, const char *, lo_arg
**argv
, int , lo_message
, void *user_data
)
355 char *out_msg
= NULL
;
357 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
359 nsm
->nsm_client_id
= strdup( &argv
[2]->s
);
364 int r
= nsm
->open( &argv
[0]->s
, &argv
[1]->s
, &argv
[2]->s
, &out_msg
, nsm
->open_userdata
);
367 OSC_REPLY_ERR( r
, ( out_msg
? out_msg
: "") );
377 NSM_EXPORT
int _nsm_osc_save ( const char *path
, const char *, lo_arg
**, int , lo_message
, void *user_data
)
379 char *out_msg
= NULL
;
381 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
386 int r
= nsm
->save(&out_msg
, nsm
->save_userdata
);
389 OSC_REPLY_ERR( r
, ( out_msg
? out_msg
: "") );
399 NSM_EXPORT
int _nsm_osc_announce_reply ( const char *, const char *, lo_arg
**argv
, int , lo_message msg
, void *user_data
)
401 if ( strcmp( &argv
[0]->s
, "/nsm/server/announce" ) )
404 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
406 fprintf( stderr
, "NSM: Successfully registered. NSM says: %s", &argv
[1]->s
);
408 nsm
->nsm_is_active
= 1;
409 nsm
->_session_manager_name
= strdup( &argv
[2]->s
);
410 nsm
->nsm_addr
= lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg
) ));
413 nsm
->active( nsm
->nsm_is_active
, nsm
->active_userdata
);
418 NSM_EXPORT
int _nsm_osc_error ( const char *, const char *, lo_arg
**argv
, int , lo_message
, void *user_data
)
420 if ( strcmp( &argv
[0]->s
, "/nsm/server/announce" ) )
423 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
425 fprintf( stderr
, "NSM: Failed to register with NSM server: %s", &argv
[2]->s
);
427 nsm
->nsm_is_active
= 0;
430 nsm
->active( nsm
->nsm_is_active
, nsm
->active_userdata
);
435 NSM_EXPORT
int _nsm_osc_session_is_loaded ( const char *, const char *, lo_arg
**, int , lo_message
, void *user_data
)
437 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
439 if ( ! nsm
->session_is_loaded
)
442 nsm
->session_is_loaded( nsm
->session_is_loaded_userdata
);
447 NSM_EXPORT
int _nsm_osc_broadcast ( const char *path
, const char *, lo_arg
**, int , lo_message msg
, void *user_data
)
449 struct _nsm_client_t
*nsm
= (struct _nsm_client_t
*)user_data
;
451 if ( ! nsm
->broadcast
)
454 return nsm
->broadcast( path
, msg
, nsm
->broadcast_userdata
);
461 nsm_init ( nsm_client_t
*nsm
, const char *nsm_url
)
463 _NSM()->nsm_url
= nsm_url
;
465 lo_address addr
= lo_address_new_from_url( nsm_url
);
466 int proto
= lo_address_get_protocol( addr
);
467 lo_address_free( addr
);
469 _NSM()->_server
= lo_server_new_with_proto( NULL
, proto
, NULL
);
471 if ( ! _NSM()->_server
)
474 lo_server_add_method( _NSM()->_server
, "/error", "sis", _nsm_osc_error
, _NSM() );
475 lo_server_add_method( _NSM()->_server
, "/reply", "ssss", _nsm_osc_announce_reply
, _NSM() );
476 lo_server_add_method( _NSM()->_server
, "/nsm/client/open", "sss", _nsm_osc_open
, _NSM() );
477 lo_server_add_method( _NSM()->_server
, "/nsm/client/save", "", _nsm_osc_save
, _NSM() );
478 lo_server_add_method( _NSM()->_server
, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded
, _NSM() );
479 lo_server_add_method( _NSM()->_server
, NULL
, NULL
, _nsm_osc_broadcast
, _NSM() );
487 nsm_init_thread ( nsm_client_t
*nsm
, const char *nsm_url
)
489 _NSM()->nsm_url
= nsm_url
;
491 lo_address addr
= lo_address_new_from_url( nsm_url
);
492 int proto
= lo_address_get_protocol( addr
);
493 lo_address_free( addr
);
495 _NSM()->_st
= lo_server_thread_new_with_proto( NULL
, proto
, NULL
);
496 _NSM()->_server
= lo_server_thread_get_server( _NSM()->_st
);
498 if ( ! _NSM()->_server
)
501 lo_server_thread_add_method( _NSM()->_st
, "/error", "sis", _nsm_osc_error
, _NSM() );
502 lo_server_thread_add_method( _NSM()->_st
, "/reply", "ssss", _nsm_osc_announce_reply
, _NSM() );
503 lo_server_thread_add_method( _NSM()->_st
, "/nsm/client/open", "sss", _nsm_osc_open
, _NSM() );
504 lo_server_thread_add_method( _NSM()->_st
, "/nsm/client/save", "", _nsm_osc_save
, _NSM() );
505 lo_server_thread_add_method( _NSM()->_st
, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded
, _NSM() );
506 lo_server_thread_add_method( _NSM()->_st
, NULL
, NULL
, _nsm_osc_broadcast
, _NSM() );