Update NTK.
[nondaw.git] / nonlib / nsm.h
blob6236e43eeb7b2771c3b837e8fcb44569ce3d2fe8
2 /*************************************************************************/
3 /* Copyright (C) 2012 Jonathan Moore Liles */
4 /* */
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 */
8 /* copies. */
9 /* */
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. */
23 /* */
24 /* Simplified Example: */
25 /* */
26 /* #include "nsm.h" */
27 /* */
28 /* int */
29 /* cb_nsm_open ( const char *name, */
30 /* const char *display_name, */
31 /* const char *client_id, */
32 /* char **out_msg, */
33 /* void *userdata ) */
34 /* { */
35 /* do_open_stuff(); */
36 /* return ERR_OK; */
37 /* } */
38 /* */
39 /* int */
40 /* cb_nsm_save ( char **out_msg, */
41 /* void *userdata ) */
42 /* { */
43 /* do_save_stuff(); */
44 /* return ERR_OK; */
45 /* } */
46 /* */
47 /* static nsm_client_t *nsm = 0 */
48 /* */
49 /* int main( int argc, char **argv ) */
50 /* { */
51 /* const char *nsm_url = getenv( "NSM_URL" ); */
52 /* */
53 /* if ( nsm_url ) */
54 /* { */
55 /* nsm = nsm_new(); */
56 /* */
57 /* nsm_set_open_callback( nsm, cb_nsm_open, 0 ); */
58 /* nsm_set_save_callback( nsm, cb_nsm_save, 0 ); */
59 /* */
60 /* if ( 0 == nsm_init( nsm, nsm_url ) ) */
61 /* { */
62 /* nsm_send_announce( nsm, "FOO", "", argv[0] ); */
63 /* } */
64 /* else */
65 /* { */
66 /* nsm_free( nsm ); */
67 /* nsm = 0; */
68 /* } */
69 /* } */
70 /* } */
71 /*************************************************************/
73 #ifndef _NSM_H
74 #define _NSM_H
76 #define NSM_API_VERSION_MAJOR 1
77 #define NSM_API_VERSION_MINOR 0
79 #include <lo/lo.h>
80 #include <string.h>
81 #include <sys/types.h>
82 #include <unistd.h>
83 #include <stdlib.h>
84 #include <stdio.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
97 /* private parts */
98 struct _nsm_client_t
100 const char *nsm_url;
102 lo_server _server;
103 lo_server_thread _st;
104 lo_address nsm_addr;
106 int nsm_is_active;
107 char *nsm_client_id;
108 char *_session_manager_name;
110 nsm_open_callback *open;
111 void *open_userdata;
113 nsm_save_callback *save;
114 void *save_userdata;
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;
126 enum
128 ERR_OK = 0,
129 ERR_GENERAL = -1,
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,
136 ERR_NOT_NOW = -8
139 NSM_EXPORT
141 nsm_is_active ( nsm_client_t *nsm )
143 return _NSM()->nsm_is_active;
146 NSM_EXPORT
147 const char *
148 nsm_get_session_manager_name ( nsm_client_t *nsm )
150 return _NSM()->_session_manager_name;
153 NSM_EXPORT
154 nsm_client_t *
155 nsm_new ( void )
157 struct _nsm_client_t *nsm = (struct _nsm_client_t*)malloc( sizeof( struct _nsm_client_t ) );
159 nsm->nsm_url = 0;
161 nsm->nsm_is_active = 0;
162 nsm->nsm_client_id = 0;
164 nsm->_server = 0;
165 nsm->_st = 0;
166 nsm->nsm_addr = 0;
167 nsm->_session_manager_name = 0;
169 nsm->open = 0;
170 nsm->save = 0;
171 nsm->active = 0;
172 nsm->session_is_loaded = 0;
173 nsm->broadcast = 0;
175 return (nsm_client_t *)nsm;
178 /*******************************************/
179 /* CLIENT TO SERVER INFORMATIONAL MESSAGES */
180 /*******************************************/
182 NSM_EXPORT
183 void
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", "" );
190 NSM_EXPORT
191 void
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", "" );
198 NSM_EXPORT
199 void
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 );
206 NSM_EXPORT
207 void
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 );
214 NSM_EXPORT void
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 );
219 if ( ! to )
221 fprintf( stderr, "NSM: Bad address!" );
222 return;
225 int pid = (int)getpid();
227 lo_send_from( to, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
228 app_name,
229 capabilities,
230 process_name,
231 NSM_API_VERSION_MAJOR,
232 NSM_API_VERSION_MINOR,
233 pid );
235 lo_address_free( to );
238 NSM_EXPORT void
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 );
247 NSM_EXPORT
248 void
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 ) ) {}
255 NSM_EXPORT
256 void
257 nsm_check_nowait (nsm_client_t *nsm )
259 nsm_check_wait( nsm, 0 );
263 NSM_EXPORT
264 void
265 nsm_thread_start ( nsm_client_t *nsm )
267 lo_server_thread_start( _NSM()->_st );
271 NSM_EXPORT
272 void
273 nsm_thread_stop ( nsm_client_t *nsm )
275 lo_server_thread_stop( _NSM()->_st );
280 NSM_EXPORT void
281 nsm_free ( nsm_client_t *nsm )
283 if ( _NSM()->_st )
284 nsm_thread_stop( nsm );
286 if ( _NSM()->_st )
287 lo_server_thread_free( _NSM()->_st );
288 else
289 lo_server_free( _NSM()->_server );
291 free( _NSM() );
294 /*****************/
295 /* SET CALLBACKS */
296 /*****************/
298 NSM_EXPORT
299 void
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;
306 NSM_EXPORT
307 void
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;
315 NSM_EXPORT
316 void
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;
323 NSM_EXPORT
324 void
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;
332 NSM_EXPORT
333 void
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;
342 /****************/
343 /* OSC HANDLERS */
344 /****************/
346 #undef OSC_REPLY
347 #undef OSC_REPLY_ERR
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 )
356 (void) types;
357 (void) argc;
358 (void) msg;
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 );
366 if ( ! nsm->open )
367 return 0;
369 int r = nsm->open( &argv[0]->s, &argv[1]->s, &argv[2]->s, &out_msg, nsm->open_userdata );
371 if ( r )
372 OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
373 else
374 OSC_REPLY( "OK" );
376 if ( out_msg )
377 free( out_msg );
379 return 0;
382 NSM_EXPORT int _nsm_osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
384 (void) types;
385 (void) argv;
386 (void) argc;
387 (void) msg;
389 char *out_msg = NULL;
391 struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
393 if ( ! nsm->save )
394 return 0;
396 int r = nsm->save(&out_msg, nsm->save_userdata );
398 if ( r )
399 OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
400 else
401 OSC_REPLY( "OK" );
403 if ( out_msg )
404 free( out_msg );
406 return 0;
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 )
411 (void) path;
412 (void) types;
413 (void) argc;
415 if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
416 return -1;
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 ) ));
426 if ( nsm->active )
427 nsm->active( nsm->nsm_is_active, nsm->active_userdata );
429 return 0;
432 NSM_EXPORT int _nsm_osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
434 (void) path;
435 (void) types;
436 (void) argc;
437 (void) msg;
439 if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
440 return -1;
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;
448 if ( nsm->active )
449 nsm->active( nsm->nsm_is_active, nsm->active_userdata );
451 return 0;
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 )
456 (void) path;
457 (void) types;
458 (void) argv;
459 (void) argc;
460 (void) msg;
462 struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
464 if ( ! nsm->session_is_loaded )
465 return 0;
467 nsm->session_is_loaded( nsm->session_is_loaded_userdata );
469 return 0;
472 NSM_EXPORT int _nsm_osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
474 (void) types;
475 (void) argv;
476 (void) argc;
478 struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
480 if ( ! nsm->broadcast )
481 return 0;
483 return nsm->broadcast( path, msg, nsm->broadcast_userdata );
488 NSM_EXPORT
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 )
501 return -1;
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() );
510 return 0;
514 NSM_EXPORT
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 )
528 return -1;
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() );
537 return 0;
540 #endif /* NSM_H */