Timeline: Add missing include of unistd.h.
[nondaw.git] / nonlib / nsm.h
blobe6adae4ee6f745ea7e27b5f2f94d26c189cf815c
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>
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
96 /* private parts */
97 struct _nsm_client_t
99 const char *nsm_url;
101 lo_server _server;
102 lo_server_thread _st;
103 lo_address nsm_addr;
105 int nsm_is_active;
106 char *nsm_client_id;
107 char *_session_manager_name;
109 nsm_open_callback *open;
110 void *open_userdata;
112 nsm_save_callback *save;
113 void *save_userdata;
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;
125 enum
127 ERR_OK = 0,
128 ERR_GENERAL = -1,
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,
135 ERR_NOT_NOW = -8
138 NSM_EXPORT
140 nsm_is_active ( nsm_client_t *nsm )
142 return _NSM()->nsm_is_active;
145 NSM_EXPORT
146 const char *
147 nsm_get_session_manager_name ( nsm_client_t *nsm )
149 return _NSM()->_session_manager_name;
152 NSM_EXPORT
153 nsm_client_t *
154 nsm_new ( void )
156 struct _nsm_client_t *nsm = (struct _nsm_client_t*)malloc( sizeof( struct _nsm_client_t ) );
158 nsm->nsm_url = 0;
160 nsm->nsm_is_active = 0;
161 nsm->nsm_client_id = 0;
163 nsm->_server = 0;
164 nsm->_st = 0;
165 nsm->nsm_addr = 0;
166 nsm->_session_manager_name = 0;
168 nsm->open = 0;
169 nsm->save = 0;
170 nsm->active = 0;
171 nsm->session_is_loaded = 0;
172 nsm->broadcast = 0;
174 return (nsm_client_t *)nsm;
177 /*******************************************/
178 /* CLIENT TO SERVER INFORMATIONAL MESSAGES */
179 /*******************************************/
181 NSM_EXPORT
182 void
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", "" );
189 NSM_EXPORT
190 void
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", "" );
197 NSM_EXPORT
198 void
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 );
205 NSM_EXPORT
206 void
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 );
213 NSM_EXPORT void
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 );
218 if ( ! to )
220 fprintf( stderr, "NSM: Bad address!" );
221 return;
224 int pid = (int)getpid();
226 lo_send_from( to, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
227 app_name,
228 capabilities,
229 process_name,
230 NSM_API_VERSION_MAJOR,
231 NSM_API_VERSION_MINOR,
232 pid );
234 lo_address_free( to );
237 NSM_EXPORT void
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 );
246 NSM_EXPORT
247 void
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 ) ) {}
254 NSM_EXPORT
255 void
256 nsm_check_nowait (nsm_client_t *nsm )
258 nsm_check_wait( nsm, 0 );
262 NSM_EXPORT
263 void
264 nsm_thread_start ( nsm_client_t *nsm )
266 lo_server_thread_start( _NSM()->_st );
270 NSM_EXPORT
271 void
272 nsm_thread_stop ( nsm_client_t *nsm )
274 lo_server_thread_stop( _NSM()->_st );
279 NSM_EXPORT void
280 nsm_free ( nsm_client_t *nsm )
282 if ( _NSM()->_st )
283 nsm_thread_stop( nsm );
285 if ( _NSM()->_st )
286 lo_server_thread_free( _NSM()->_st );
287 else
288 lo_server_free( _NSM()->_server );
290 free( _NSM() );
293 /*****************/
294 /* SET CALLBACKS */
295 /*****************/
297 NSM_EXPORT
298 void
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;
305 NSM_EXPORT
306 void
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;
314 NSM_EXPORT
315 void
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;
322 NSM_EXPORT
323 void
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;
331 NSM_EXPORT
332 void
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;
341 /****************/
342 /* OSC HANDLERS */
343 /****************/
345 #undef OSC_REPLY
346 #undef OSC_REPLY_ERR
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 );
361 if ( ! nsm->open )
362 return 0;
364 int r = nsm->open( &argv[0]->s, &argv[1]->s, &argv[2]->s, &out_msg, nsm->open_userdata );
366 if ( r )
367 OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
368 else
369 OSC_REPLY( "OK" );
371 if ( out_msg )
372 free( out_msg );
374 return 0;
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;
383 if ( ! nsm->save )
384 return 0;
386 int r = nsm->save(&out_msg, nsm->save_userdata );
388 if ( r )
389 OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
390 else
391 OSC_REPLY( "OK" );
393 if ( out_msg )
394 free( out_msg );
396 return 0;
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" ) )
402 return -1;
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 ) ));
412 if ( nsm->active )
413 nsm->active( nsm->nsm_is_active, nsm->active_userdata );
415 return 0;
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" ) )
421 return -1;
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;
429 if ( nsm->active )
430 nsm->active( nsm->nsm_is_active, nsm->active_userdata );
432 return 0;
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 )
440 return 0;
442 nsm->session_is_loaded( nsm->session_is_loaded_userdata );
444 return 0;
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 )
452 return 0;
454 return nsm->broadcast( path, msg, nsm->broadcast_userdata );
459 NSM_EXPORT
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 )
472 return -1;
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() );
481 return 0;
485 NSM_EXPORT
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 )
499 return -1;
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() );
508 return 0;
511 #endif /* NSM_H */