Signed-off-by: falkTX <falktx@falktx.com>tags/v1.3
@@ -23,11 +23,10 @@ liblodep = dependency('liblo') #and not 'lo' | |||
threaddep = dependency('threads') | |||
jackdep = dependency('jack') #and not 'libjack' | |||
executable('nsmd', | |||
sources: ['src/nsmd.cpp', 'src/debug.cpp', 'src/Endpoint.cpp', 'src/file.cpp', 'src/Thread.cpp'], | |||
dependencies: [liblodep, threaddep], | |||
install: true, | |||
) | |||
cc = meson.get_compiler('c') | |||
fluid = find_program('fluid') | |||
fltkdep = cc.find_library('fltk', required: true) | |||
fltkimagesdep = cc.find_library('fltk_images', required: true) | |||
executable('jackpatch', | |||
'src/jackpatch.c', | |||
@@ -35,5 +34,40 @@ executable('jackpatch', | |||
install: true, | |||
) | |||
executable('non-session-manager', | |||
sources: ['src/session-manager.cpp', 'src/debug.cpp', 'src/Endpoint.cpp', 'src/Thread.cpp', 'src/FL/Fl_Scalepack.C'], | |||
dependencies: [fltkimagesdep, fltkdep, liblodep, threaddep], | |||
install: true, | |||
) | |||
executable('nsm-proxy', | |||
sources: ['src/nsm-proxy.cpp', 'src/debug.cpp'], | |||
dependencies: [liblodep, threaddep], | |||
install: true, | |||
) | |||
NSM_Proxy_UI_cpp = custom_target( | |||
'NSM_Proxy_UI.cpp', | |||
output : 'NSM_Proxy_UI.cpp', | |||
input : 'src/NSM_Proxy_UI.fl', | |||
command : [fluid, '-c', '-o', '@OUTPUT@', '@INPUT@'], | |||
) | |||
NSM_Proxy_UI_h = custom_target( | |||
'NSM_Proxy_UI.h', | |||
output : 'NSM_Proxy_UI.h', | |||
input : 'src/NSM_Proxy_UI.fl', | |||
command : [fluid, '-c', '-h', '@OUTPUT@', '@INPUT@'], | |||
) | |||
executable('nsm-proxy-gui', | |||
sources: ['src/nsm-proxy-gui.cpp', [NSM_Proxy_UI_cpp, NSM_Proxy_UI_h]], | |||
dependencies: [fltkdep, liblodep, threaddep], | |||
install: true, | |||
) | |||
executable('nsmd', | |||
sources: ['src/nsmd.cpp', 'src/debug.cpp', 'src/Endpoint.cpp', 'src/file.cpp', 'src/Thread.cpp'], | |||
dependencies: [liblodep, threaddep], | |||
install: true, | |||
) |
@@ -0,0 +1,212 @@ | |||
/*******************************************************************************/ | |||
/* Copyright (C) 2010 Jonathan Moore Liles */ | |||
/* */ | |||
/* This program is free software; you can redistribute it and/or modify it */ | |||
/* under the terms of the GNU General Public License as published by the */ | |||
/* Free Software Foundation; either version 2 of the License, or (at your */ | |||
/* option) any later version. */ | |||
/* */ | |||
/* This program is distributed in the hope that it will be useful, but WITHOUT */ | |||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ | |||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ | |||
/* more details. */ | |||
/* */ | |||
/* You should have received a copy of the GNU General Public License along */ | |||
/* with This program; see the file COPYING. If not,write to the Free Software */ | |||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
/*******************************************************************************/ | |||
/* Scrolling group suitable for containing a single child (a | |||
* pack). When the Fl_Packscroller is resized, the child will be resized | |||
* too. No scrollbars are displayed, but the widget responds to | |||
* FL_MOUSEWHEEL events. */ | |||
#pragma once | |||
#include <FL/Fl_Group.H> | |||
#include <FL/fl_draw.H> | |||
#include <FL/Fl.H> | |||
/* FIXME: Optimize scroll */ | |||
class Fl_Packscroller : public Fl_Group | |||
{ | |||
int _increment; | |||
int _yposition; | |||
static const int sbh = 15; /* scroll button height */ | |||
public: | |||
Fl_Packscroller ( int X, int Y, int W, int H, const char *L = 0 ) : Fl_Group( X, Y, W, H, L ) | |||
{ | |||
_increment = 30; | |||
_yposition = 0; | |||
// color( FL_WHITE ); | |||
} | |||
int increment ( void ) const { return _increment; } | |||
void increment ( int v ) { _increment = v; } | |||
void yposition ( int v ) | |||
{ | |||
if ( ! children() ) | |||
return; | |||
int Y = v; | |||
if ( Y > 0 ) | |||
Y = 0; | |||
const int H = h(); | |||
// - (sbh * 2); | |||
Fl_Widget *o = child( 0 ); | |||
if ( o->h() > H && | |||
Y + o->h() < H ) | |||
Y = H - o->h(); | |||
else if ( o->h() < H ) | |||
Y = 0; | |||
if ( _yposition != Y ) | |||
{ | |||
_yposition = Y; | |||
damage( FL_DAMAGE_SCROLL ); | |||
} | |||
} | |||
int yposition ( void ) const | |||
{ | |||
if ( children() ) | |||
return child( 0 )->y() - (y() + sbh); | |||
return 0; | |||
} | |||
void bbox ( int &X, int &Y, int &W, int &H ) | |||
{ | |||
X = x(); | |||
Y = y() + ( sbh * top_sb_visible() ); | |||
W = w(); | |||
H = h() - ( sbh * ( top_sb_visible() + bottom_sb_visible() ) ); | |||
} | |||
int top_sb_visible ( void ) | |||
{ | |||
return children() && child(0)->y() != y() ? 1 : 0; | |||
} | |||
int bottom_sb_visible ( void ) | |||
{ | |||
if ( children() ) | |||
{ | |||
Fl_Widget *o = child( 0 ); | |||
if ( o->h() > h() && o->y() + o->h() != y() + h() ) | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
virtual void | |||
draw ( void ) | |||
{ | |||
if ( damage() & FL_DAMAGE_ALL ) | |||
{ | |||
fl_rectf( x(), y(), w(), h(), color() ); | |||
} | |||
if ( ! children() ) | |||
return; | |||
Fl_Widget *o = child( 0 ); | |||
o->position( x(), y() + _yposition ); | |||
const int top_sb = top_sb_visible(); | |||
const int bottom_sb = bottom_sb_visible(); | |||
fl_push_clip( x(), y() + ( sbh * top_sb ), w(), h() - (sbh * (top_sb + bottom_sb) )); | |||
draw_children(); | |||
fl_pop_clip(); | |||
fl_font( FL_HELVETICA, 12 ); | |||
if ( top_sb ) | |||
{ | |||
fl_draw_box( box(), x(), y(), w(), sbh, color() ); | |||
fl_color( fl_contrast( FL_FOREGROUND_COLOR, color() ) ); | |||
fl_draw( "@2<", x(), y(), w(), sbh, FL_ALIGN_CENTER ); | |||
} | |||
if ( bottom_sb ) | |||
{ | |||
fl_draw_box( box(), x(), y() + h() - sbh, w(), sbh, color() ); | |||
fl_color( fl_contrast( FL_FOREGROUND_COLOR, color() ) ); | |||
fl_draw( "@2>", x(), y() + h() - sbh, w(), sbh, FL_ALIGN_CENTER ); | |||
} | |||
} | |||
virtual int | |||
handle ( int m ) | |||
{ | |||
switch ( m ) | |||
{ | |||
case FL_PUSH: | |||
if ( top_sb_visible() && | |||
Fl::event_inside( x(), y(), w(), sbh ) ) | |||
{ | |||
return 1; | |||
} | |||
else if ( bottom_sb_visible() && | |||
Fl::event_inside( x(), y() + h() - sbh, w(), sbh ) ) | |||
{ | |||
return 1; | |||
} | |||
break; | |||
case FL_RELEASE: | |||
{ | |||
if ( top_sb_visible() && | |||
Fl::event_inside( x(), y(), w(), sbh ) ) | |||
{ | |||
yposition( yposition() + ( h() / 4 ) ); | |||
return 1; | |||
} | |||
else if ( bottom_sb_visible() && | |||
Fl::event_inside( x(), y() + h() - sbh, w(), sbh ) ) | |||
{ | |||
yposition( yposition() - (h() / 4 ) ); | |||
return 1; | |||
} | |||
break; | |||
} | |||
case FL_KEYBOARD: | |||
{ | |||
if ( Fl::event_key() == FL_Up ) | |||
{ | |||
yposition( yposition() + ( h() / 4 ) ); | |||
return 1; | |||
} | |||
else if ( Fl::event_key() == FL_Down ) | |||
{ | |||
yposition( yposition() - (h() / 4 ) ); | |||
return 1; | |||
} | |||
break; | |||
} | |||
case FL_MOUSEWHEEL: | |||
{ | |||
yposition( yposition() - ( Fl::event_dy() * _increment ) ); | |||
return 1; | |||
} | |||
} | |||
return Fl_Group::handle( m ); | |||
} | |||
}; |
@@ -0,0 +1,250 @@ | |||
/*******************************************************************************/ | |||
/* Copyright (C) 2008 Jonathan Moore Liles */ | |||
/* */ | |||
/* This program is free software; you can redistribute it and/or modify it */ | |||
/* under the terms of the GNU General Public License as published by the */ | |||
/* Free Software Foundation; either version 2 of the License, or (at your */ | |||
/* option) any later version. */ | |||
/* */ | |||
/* This program is distributed in the hope that it will be useful, but WITHOUT */ | |||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ | |||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ | |||
/* more details. */ | |||
/* */ | |||
/* You should have received a copy of the GNU General Public License along */ | |||
/* with This program; see the file COPYING. If not,write to the Free Software */ | |||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
/*******************************************************************************/ | |||
/* Fl_Scalepack | |||
This is similar to an Fl_Pack, but instead of the pack resizing | |||
itself to enclose its children, this pack resizes its children to | |||
fit itself. Of course, this only works well with highly flexible | |||
widgets, but the task comes up often enough to warrent this class. | |||
If and child happens to be the resizable() widget, then it will be | |||
resized so the all the other children can fit around it, with their | |||
current sizes (and the size of the Fl_Scalepack) maintained. | |||
NOTES: An Fl_Pack as a direct child will not work, because Fl_Pack | |||
changes its size in draw(), which throws off our resize | |||
calculation. The whole idea of widgets being able to resize | |||
themselves within draw() is horribly broken... | |||
*/ | |||
#include "Fl_Scalepack.H" | |||
#include <FL/Fl.H> | |||
#include <FL/fl_draw.H> | |||
#include <stdio.h> | |||
Fl_Scalepack::Fl_Scalepack ( int X, int Y, int W, int H, const char *L ) : | |||
Fl_Group( X, Y, W, H, L ) | |||
{ | |||
resizable( 0 ); | |||
_spacing = 0; | |||
} | |||
void | |||
Fl_Scalepack::resize ( int X, int Y, int W, int H ) | |||
{ | |||
/* Fl_Group's resize will change our child widget sizes, which | |||
interferes with our own resizing method. */ | |||
long dx = X - x(); | |||
long dy = Y - y(); | |||
bool r = W != w() || H != h(); | |||
Fl_Widget::resize( X, Y, W, H ); | |||
Fl_Widget*const* a = array(); | |||
for (int i=children(); i--;) | |||
{ | |||
Fl_Widget* o = *a++; | |||
o->position( o->x() + dx, o->y() + dy ); | |||
} | |||
if ( r ) | |||
redraw(); | |||
} | |||
void | |||
Fl_Scalepack::draw ( void ) | |||
{ | |||
if ( resizable() == this ) | |||
/* this resizable( this ) is the default for Fl_Group and is | |||
* reset by Fl_Group::clear(), but it is not our default... */ | |||
resizable( 0 ); | |||
int tx = x() + Fl::box_dx( box() ); | |||
int ty = y() + Fl::box_dy( box() ); | |||
int tw = w() - Fl::box_dw( box() ); | |||
int th = h() - Fl::box_dh( box() ); | |||
if ( damage() & FL_DAMAGE_ALL ) | |||
{ | |||
draw_box(); | |||
draw_label(); | |||
} | |||
int v = 0; | |||
int cth = 0; | |||
int ctw = 0; | |||
Fl_Widget * const * a = array(); | |||
for ( int i = children(); i--; ) | |||
{ | |||
Fl_Widget *o = *a++; | |||
if ( o->visible() ) | |||
{ | |||
++v; | |||
if ( o != this->resizable() ) | |||
{ | |||
cth += o->h(); | |||
ctw += o->w(); | |||
} | |||
cth += _spacing; | |||
ctw += _spacing; | |||
} | |||
} | |||
ctw -= _spacing; | |||
cth -= _spacing; | |||
if ( 0 == v ) | |||
return; | |||
if ( this->resizable() ) | |||
{ | |||
int pos = 0; | |||
Fl_Widget * const * a = array(); | |||
for ( int i = children(); i--; ) | |||
{ | |||
Fl_Widget *o = *a++; | |||
if ( o->visible() ) | |||
{ | |||
int X, Y, W, H; | |||
if ( type() == HORIZONTAL ) | |||
{ | |||
X = tx + pos; | |||
Y = ty; | |||
W = o->w(); | |||
H = th; | |||
} | |||
else | |||
{ | |||
X = tx; | |||
Y = ty + pos; | |||
W = tw; | |||
H = o->h(); | |||
} | |||
if ( this->resizable() == o ) | |||
{ | |||
if ( type() == HORIZONTAL ) | |||
W = tw - ctw - 3; | |||
else | |||
H = th - cth; | |||
} | |||
if (X != o->x() || Y != o->y() || W != o->w() || H != o->h() ) | |||
{ | |||
o->resize(X,Y,W,H); | |||
o->clear_damage(FL_DAMAGE_ALL); | |||
} | |||
if ( damage() & FL_DAMAGE_ALL ) | |||
{ | |||
draw_child( *o ); | |||
draw_outside_label( *o ); | |||
} | |||
else | |||
update_child( *o ); | |||
/* if ( this->resizable() == o ) */ | |||
/* fl_rect( o->x(), o->y(), o->w(), o->h(), type() == VERTICAL ? FL_GREEN : FL_BLUE ); */ | |||
if ( type() == HORIZONTAL ) | |||
pos += o->w() + spacing(); | |||
else | |||
pos += o->h() + spacing(); | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
int sz = 0; | |||
int pos = 0; | |||
if ( type() == HORIZONTAL ) | |||
sz = (tw - (_spacing * (v - 1))) / v; | |||
else | |||
sz = (th - (_spacing * (v - 1))) / v; | |||
Fl_Widget * const * a = array(); | |||
for ( int i = children(); i--; ) | |||
{ | |||
Fl_Widget *o = *a++; | |||
if ( o->visible() ) | |||
{ | |||
int X, Y, W, H; | |||
if ( type() == HORIZONTAL ) | |||
{ | |||
X = tx + pos; | |||
Y = ty; | |||
W = sz; | |||
H = th; | |||
} | |||
else | |||
{ | |||
X = tx; | |||
Y = ty + pos; | |||
W = tw; | |||
H = sz; | |||
} | |||
if (X != o->x() || Y != o->y() || W != o->w() || H != o->h() ) | |||
{ | |||
o->resize(X,Y,W,H); | |||
o->clear_damage(FL_DAMAGE_ALL); | |||
} | |||
if ( damage() & FL_DAMAGE_ALL ) | |||
{ | |||
draw_child( *o ); | |||
draw_outside_label( *o ); | |||
} | |||
else | |||
update_child( *o ); | |||
// fl_rect( o->x(), o->y(), o->w(), o->h(), type() == VERTICAL ? FL_RED : FL_YELLOW ); | |||
if ( type() == HORIZONTAL ) | |||
pos += o->w() + spacing(); | |||
else | |||
pos += o->h() + spacing(); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,43 @@ | |||
/*******************************************************************************/ | |||
/* Copyright (C) 2008 Jonathan Moore Liles */ | |||
/* */ | |||
/* This program is free software; you can redistribute it and/or modify it */ | |||
/* under the terms of the GNU General Public License as published by the */ | |||
/* Free Software Foundation; either version 2 of the License, or (at your */ | |||
/* option) any later version. */ | |||
/* */ | |||
/* This program is distributed in the hope that it will be useful, but WITHOUT */ | |||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ | |||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ | |||
/* more details. */ | |||
/* */ | |||
/* You should have received a copy of the GNU General Public License along */ | |||
/* with This program; see the file COPYING. If not,write to the Free Software */ | |||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
/*******************************************************************************/ | |||
#pragma once | |||
#include <FL/Fl_Group.H> | |||
class Fl_Scalepack : public Fl_Group | |||
{ | |||
int _spacing; | |||
public: | |||
enum { VERTICAL, HORIZONTAL }; | |||
Fl_Scalepack ( int X, int Y, int W, int H, const char *L = 0 ); | |||
virtual ~Fl_Scalepack ( ) { } | |||
int spacing ( void ) const { return _spacing; } | |||
void spacing ( int v ) { _spacing = v; redraw(); } | |||
virtual void resize ( int, int, int, int ); | |||
virtual void draw ( void ); | |||
}; |
@@ -0,0 +1,100 @@ | |||
# data file for the Fltk User Interface Designer (fluid) | |||
version 1.0300 | |||
header_name {.H} | |||
code_name {.C} | |||
class NSM_Proxy_UI {open | |||
} { | |||
Function {make_window()} {open | |||
} { | |||
Fl_Window {} { | |||
label {NSM Proxy} open selected | |||
xywh {644 190 635 665} type Double color 47 labelcolor 55 xclass {NSM-Proxy} visible | |||
} { | |||
Fl_Box {} { | |||
label {Command-line options are incompatible with robust session management for a variety of reasons, so the NSM server does not support them directly. This proxy exists to allow programs which require command-line options to be included in an NSM session. Be warned that referring to files outside of the session directory will impair your ability to reliably archive and transport sessions. Patching the program to use NSM natively will result in a better experience. | |||
The program will be started with its current directory being a uniquely named directory under the current session directory. It is recommended that you only refer to files in the current directory. | |||
} | |||
xywh {15 11 610 139} box BORDER_BOX color 41 labelfont 8 labelsize 12 labelcolor 55 align 128 | |||
} | |||
Fl_File_Input executable_input { | |||
label {Executable: } | |||
xywh {115 162 495 31} | |||
} | |||
Fl_Input arguments_input { | |||
label {Arguments:} | |||
xywh {110 310 350 28} | |||
} | |||
Fl_Input label_input { | |||
label {Label:} | |||
xywh {110 340 350 28} | |||
} | |||
Fl_Return_Button start_button { | |||
label Start | |||
xywh {535 630 88 25} | |||
} | |||
Fl_Button kill_button { | |||
label Kill | |||
xywh {295 625 80 25} color 72 hide | |||
} | |||
Fl_Choice save_signal_choice { | |||
label {Save Signal:} open | |||
xywh {110 468 170 25} down_box BORDER_BOX | |||
} { | |||
MenuItem {} { | |||
label None | |||
xywh {0 0 40 24} | |||
} | |||
MenuItem {} { | |||
label SIGUSR1 | |||
xywh {10 10 40 24} | |||
} | |||
MenuItem {} { | |||
label SIGUSR2 | |||
xywh {20 20 40 24} | |||
} | |||
MenuItem {} { | |||
label SIGINT | |||
xywh {30 30 40 24} | |||
} | |||
} | |||
Fl_Box {} { | |||
label {The environment variables $NSM_CLIENT_ID and $NSM_SESSION_NAME will contain the unique client ID (suitable for use as e.g. a JACK client name) and the display name for the session, respectively. The variable $CONFIG_FILE will contain the name of the config file selected above.} | |||
xywh {15 235 610 69} box BORDER_BOX color 41 labelfont 8 labelsize 12 labelcolor 55 align 128 | |||
} | |||
Fl_Box {} { | |||
label {Some (very few) programs may respond to a specific Unix signal by somehow saving their state. If 'Save Signal' is set to something other than 'None', then NSM Proxy will deliver the specified signal to the proxied process upon an NSM 'Save' event. Most programs will treat these signals just like SIGTERM and die. You have been warned.} | |||
xywh {15 378 610 79} box BORDER_BOX color 41 labelfont 8 labelsize 12 labelcolor 55 align 128 | |||
} | |||
Fl_Choice stop_signal_choice { | |||
label {Stop Signal:} open | |||
xywh {108 592 170 25} down_box BORDER_BOX | |||
} { | |||
MenuItem {} { | |||
label SIGTERM | |||
xywh {10 10 40 24} | |||
} | |||
MenuItem {} { | |||
label SIGINT | |||
xywh {40 40 40 24} | |||
} | |||
MenuItem {} { | |||
label SIGHUP | |||
xywh {50 50 40 24} | |||
} | |||
} | |||
Fl_Box {} { | |||
label {Most programs will shutdown gracefully when sent a SIGTERM or SIGINT signal. It's impossible to know which signal a specific program will respond to. A unhandled signal will simply kill the process, and may cause problems with the audio subsystem (e.g. JACK). Check the program's documentation or source code to determine which signal to use to stop it gracefully.} | |||
xywh {15 502 610 79} box BORDER_BOX color 41 labelfont 8 labelsize 12 labelcolor 55 align 128 | |||
} | |||
Fl_File_Input config_file_input { | |||
label {Config File:} | |||
xywh {114 195 406 31} | |||
} | |||
Fl_Button config_file_browse_button { | |||
label Browse | |||
xywh {530 195 85 25} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,291 @@ | |||
/*******************************************************************************/ | |||
/* Copyright (C) 2012 Jonathan Moore Liles */ | |||
/* */ | |||
/* This program is free software; you can redistribute it and/or modify it */ | |||
/* under the terms of the GNU General Public License as published by the */ | |||
/* Free Software Foundation; either version 2 of the License, or (at your */ | |||
/* option) any later version. */ | |||
/* */ | |||
/* This program is distributed in the hope that it will be useful, but WITHOUT */ | |||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ | |||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ | |||
/* more details. */ | |||
/* */ | |||
/* You should have received a copy of the GNU General Public License along */ | |||
/* with This program; see the file COPYING. If not,write to the Free Software */ | |||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
/*******************************************************************************/ | |||
#pragma GCC diagnostic ignored "-Wunused-parameter" | |||
#define _MODULE_ "nsm-proxy-gui" | |||
#define APP_NAME "NSM Proxy" | |||
#define APP_TITLE "NSM Proxy" | |||
#include <FL/Fl_File_Chooser.H> | |||
#include <FL/Fl_Text_Display.H> | |||
#include "NSM_Proxy_UI.H" | |||
#include <lo/lo.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
lo_server losrv; | |||
lo_address nsmp_addr; | |||
static NSM_Proxy_UI *ui; | |||
static char *client_error; | |||
int | |||
osc_update ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
printf( "Got update for %s\n", path ); | |||
Fl::lock(); | |||
if (!strcmp( path, "/nsm/proxy/label" )) | |||
ui->label_input->value( &argv[0]->s ); | |||
else if (!strcmp( path, "/nsm/proxy/arguments" )) | |||
ui->arguments_input->value( &argv[0]->s ); | |||
else if (!strcmp( path, "/nsm/proxy/executable" )) | |||
ui->executable_input->value( &argv[0]->s ); | |||
else if (!strcmp( path, "/nsm/proxy/config_file" )) | |||
ui->config_file_input->value( &argv[0]->s ); | |||
else if (!strcmp( path, "/nsm/proxy/save_signal" )) | |||
{ | |||
if ( argv[0]->i == SIGUSR1 ) | |||
ui->save_signal_choice->value( 1 ); | |||
else if ( argv[0]->i == SIGUSR2 ) | |||
ui->save_signal_choice->value( 2 ); | |||
else if ( argv[0]->i == SIGINT ) | |||
ui->save_signal_choice->value( 3 ); | |||
else | |||
ui->save_signal_choice->value( 0 ); | |||
} | |||
else if (!strcmp( path, "/nsm/proxy/stop_signal" )) | |||
{ | |||
if ( argv[0]->i == SIGTERM ) | |||
ui->stop_signal_choice->value( 0 ); | |||
else if ( argv[0]->i == SIGINT ) | |||
ui->stop_signal_choice->value( 1 ); | |||
else if ( argv[0]->i == SIGHUP ) | |||
ui->stop_signal_choice->value( 2 ); | |||
} | |||
if (!strcmp( path, "/nsm/proxy/client_error" )) | |||
{ | |||
if ( client_error != NULL ) | |||
free(client_error); | |||
client_error = NULL; | |||
if ( strlen(&argv[0]->s) > 0 ) | |||
client_error = strdup(&argv[0]->s); | |||
} | |||
Fl::unlock(); | |||
return 0; | |||
} | |||
void | |||
init_osc ( const char *osc_port ) | |||
{ | |||
lo_server_thread loth = lo_server_thread_new( osc_port, NULL ); | |||
losrv = lo_server_thread_get_server( loth ); | |||
//error_handler ); | |||
char *url = lo_server_get_url(losrv); | |||
printf("OSC: %s\n",url); | |||
free(url); | |||
/* GUI */ | |||
lo_server_thread_add_method( loth, "/nsm/proxy/executable", "s", osc_update, NULL ); | |||
lo_server_thread_add_method( loth, "/nsm/proxy/arguments", "s", osc_update, NULL ); | |||
lo_server_thread_add_method( loth, "/nsm/proxy/config_file", "s", osc_update, NULL ); | |||
lo_server_thread_add_method( loth, "/nsm/proxy/label", "s", osc_update, NULL ); | |||
lo_server_thread_add_method( loth, "/nsm/proxy/save_signal", "i", osc_update, NULL ); | |||
lo_server_thread_add_method( loth, "/nsm/proxy/stop_signal", "i", osc_update, NULL ); | |||
lo_server_thread_add_method( loth, "/nsm/proxy/client_error", "s", osc_update, NULL ); | |||
lo_server_thread_start( loth ); | |||
} | |||
/*****************/ | |||
/* GUI Callbacks */ | |||
/*****************/ | |||
void | |||
handle_kill ( Fl_Widget *o, void *v ) | |||
{ | |||
lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/kill", "" ); | |||
} | |||
void | |||
handle_start ( Fl_Widget *o, void *v ) | |||
{ | |||
lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/start", "sss", | |||
ui->executable_input->value(), | |||
ui->arguments_input->value(), | |||
ui->config_file_input->value() ); | |||
} | |||
void | |||
handle_label ( Fl_Widget *o, void *v ) | |||
{ | |||
lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/label", "s", | |||
ui->label_input->value() ); | |||
} | |||
void | |||
handle_executable ( Fl_Widget *o, void *v ) | |||
{ | |||
ui->label_input->value( ui->executable_input->value() ); | |||
} | |||
void | |||
handle_config_file ( Fl_Widget *o, void *v ) | |||
{ | |||
} | |||
void | |||
handle_config_file_browse ( Fl_Widget *o, void *v ) | |||
{ | |||
const char * file = fl_file_chooser( "Pick file", "*", NULL, 1 ); | |||
ui->config_file_input->value( file ); | |||
} | |||
void | |||
handle_save_signal ( Fl_Widget *o, void *v ) | |||
{ | |||
int sig = 0; | |||
const char* picked = ui->save_signal_choice->mvalue()->label(); | |||
if ( !strcmp( picked, "SIGUSR1" ) ) | |||
sig = SIGUSR1; | |||
else if ( !strcmp( picked, "SIGUSR2" ) ) | |||
sig = SIGUSR2; | |||
else if ( !strcmp( picked, "SIGINT" ) ) | |||
sig = SIGINT; | |||
lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE,"/nsm/proxy/save_signal", "i", | |||
sig ); | |||
} | |||
void | |||
handle_stop_signal ( Fl_Widget *o, void *v ) | |||
{ | |||
int sig = SIGTERM; | |||
const char* picked = ui->stop_signal_choice->mvalue()->label(); | |||
if ( !strcmp( picked, "SIGTERM" ) ) | |||
sig = SIGTERM; | |||
else if ( !strcmp( picked, "SIGINT" ) ) | |||
sig = SIGINT; | |||
else if ( !strcmp( picked, "SIGHUP" ) ) | |||
sig = SIGHUP; | |||
lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE,"/nsm/proxy/stop_signal", "i", | |||
sig ); | |||
} | |||
void | |||
connect_ui ( void ) | |||
{ | |||
ui->executable_input->callback( handle_executable, NULL ); | |||
ui->config_file_input->callback( handle_config_file, NULL ); | |||
ui->kill_button->callback( handle_kill, NULL ); | |||
ui->start_button->callback( handle_start, NULL ); | |||
ui->save_signal_choice->callback( handle_save_signal, NULL ); | |||
ui->stop_signal_choice->callback( handle_stop_signal, NULL ); | |||
ui->label_input->callback( handle_label, NULL ); | |||
ui->config_file_browse_button->callback( handle_config_file_browse, NULL ); | |||
} | |||
void cb_dismiss_button ( Fl_Widget *w, void *v ) | |||
{ | |||
w->window()->hide(); | |||
} | |||
void | |||
check_error ( void *v ) | |||
{ | |||
if ( client_error ) | |||
{ | |||
{ | |||
Fl_Double_Window *o = new Fl_Double_Window(600,300+15,"Abnormal Termination"); | |||
{ | |||
Fl_Box *o = new Fl_Box(0+15,0+15,600-30,50); | |||
o->box(FL_BORDER_BOX); | |||
o->color(FL_RED); | |||
o->labelcolor(FL_WHITE); | |||
o->align(FL_ALIGN_CENTER|FL_ALIGN_WRAP); | |||
o->copy_label( client_error ); | |||
} | |||
{ | |||
Fl_Text_Display *o = new Fl_Text_Display(0+15,50+15,600-30,300-75-30); | |||
o->buffer(new Fl_Text_Buffer()); | |||
o->buffer()->loadfile( "error.log" ); | |||
} | |||
{ | |||
Fl_Button *o = new Fl_Button(600-75-15,300-25,75,25,"Dismiss"); | |||
o->callback(cb_dismiss_button,0); | |||
} | |||
o->show(); | |||
} | |||
free(client_error); | |||
client_error = NULL; | |||
} | |||
Fl::repeat_timeout( 0.5f, check_error, v ); | |||
} | |||
int | |||
main ( int argc, char **argv ) | |||
{ | |||
if ( argc != 3 ) | |||
{ | |||
fprintf( stderr, "Usage: %s --connect-to url\n", argv[0] ); | |||
return 1; | |||
} | |||
init_osc( NULL ); | |||
nsmp_addr = lo_address_new_from_url( argv[2] ); | |||
printf( "Connecting to nsm-proxy at: %s\n", argv[2] ); | |||
ui = new NSM_Proxy_UI; | |||
Fl_Double_Window *w = ui->make_window(); | |||
connect_ui(); | |||
lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/update", "" ); | |||
w->show(); | |||
Fl::lock(); | |||
Fl::add_timeout( 0.5f, check_error, NULL ); | |||
Fl::run(); | |||
return 0; | |||
} |
@@ -0,0 +1,760 @@ | |||
/*******************************************************************************/ | |||
/* Copyright (C) 2012 Jonathan Moore Liles */ | |||
/* */ | |||
/* This program is free software; you can redistribute it and/or modify it */ | |||
/* under the terms of the GNU General Public License as published by the */ | |||
/* Free Software Foundation; either version 2 of the License, or (at your */ | |||
/* option) any later version. */ | |||
/* */ | |||
/* This program is distributed in the hope that it will be useful, but WITHOUT */ | |||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ | |||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ | |||
/* more details. */ | |||
/* */ | |||
/* You should have received a copy of the GNU General Public License along */ | |||
/* with This program; see the file COPYING. If not,write to the Free Software */ | |||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
/*******************************************************************************/ | |||
#pragma GCC diagnostic ignored "-Wunused-parameter" | |||
#define _MODULE_ "nsm-proxy" | |||
#define APP_NAME "NSM Proxy" | |||
#define APP_TITLE "NSM Proxy" | |||
#include "debug.h" | |||
#include <lo/lo.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#include <signal.h> | |||
#include <string.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <sys/signalfd.h> | |||
#include <sys/stat.h> | |||
#include <sys/wait.h> | |||
static lo_server losrv; | |||
static lo_address nsm_addr; | |||
static lo_address gui_addr; | |||
static int nsm_is_active; | |||
static char *project_file; | |||
static int die_now = 0; | |||
static int signal_fd; | |||
static char *nsm_client_id; | |||
static char *nsm_display_name; | |||
#define CONFIG_FILE_NAME "nsm-proxy.config" | |||
void show_gui ( void ); | |||
class NSM_Proxy { | |||
char *_label; | |||
char *_executable; | |||
char *_config_file; | |||
char *_arguments; | |||
int _save_signal; | |||
int _stop_signal; | |||
int _pid; | |||
char *_client_error; | |||
public: | |||
int stop_signal ( void ) {return _stop_signal;} | |||
NSM_Proxy ( ) | |||
{ | |||
_label = _executable = _arguments = _config_file = 0; | |||
_save_signal = 0; | |||
_stop_signal = SIGTERM; | |||
_pid = 0; | |||
_client_error = 0; | |||
} | |||
~NSM_Proxy ( ) | |||
{ | |||
} | |||
void handle_client_death ( int status ) | |||
{ | |||
printf( "proxied process died unexpectedly... not dying\n" ); | |||
/* proxied process died unexpectedly */ | |||
if ( _client_error != NULL ) | |||
free(_client_error); | |||
asprintf(&_client_error, "The proxied process terminated abnormally during invocation. Exit status: %i.", status ); | |||
show_gui(); | |||
_pid = 0; | |||
} | |||
void kill ( void ) | |||
{ | |||
if ( _pid ) | |||
{ | |||
::kill( _pid, _stop_signal ); | |||
} | |||
} | |||
bool start ( const char *executable, const char *arguments, const char *config_file ) | |||
{ | |||
if ( _executable ) | |||
free( _executable ); | |||
if ( _arguments ) | |||
free( _arguments ); | |||
if ( _config_file ) | |||
free( _config_file ); | |||
_executable = strdup( executable ); | |||
if ( arguments ) | |||
_arguments = strdup( arguments ); | |||
else | |||
_arguments = NULL; | |||
if ( config_file ) | |||
_config_file = strdup( config_file ); | |||
else | |||
_config_file = NULL; | |||
return start(); | |||
} | |||
bool start ( void ) | |||
{ | |||
dump( project_file ); | |||
if ( _pid ) | |||
/* already running */ | |||
return true; | |||
if ( !_executable ) | |||
{ | |||
WARNING( "Executable is null." ); | |||
return false; | |||
} | |||
int pid; | |||
if ( ! (pid = fork()) ) | |||
{ | |||
MESSAGE( "Launching %s\n", _executable ); | |||
// char *args[] = { strdup( executable ), NULL }; | |||
char *cmd; | |||
if ( _arguments ) | |||
asprintf( &cmd, "exec %s %s >error.log 2>&1", _executable, _arguments ); | |||
else | |||
asprintf( &cmd, "exec %s >error.log 2>&1", _executable ); | |||
char *args[] = { strdup("/bin/sh"), strdup( "-c" ), cmd, NULL }; | |||
setenv( "NSM_CLIENT_ID", nsm_client_id, 1 ); | |||
setenv( "NSM_SESSION_NAME", nsm_display_name, 1 ); | |||
if ( _config_file ) | |||
setenv( "CONFIG_FILE", _config_file, 1 ); | |||
unsetenv( "NSM_URL" ); | |||
if ( -1 == execvp( "/bin/sh", args ) ) | |||
{ | |||
WARNING( "Error starting process: %s", strerror( errno ) ); | |||
exit(1); | |||
} | |||
} | |||
_pid = pid; | |||
return _pid > 0; | |||
} | |||
void save_signal ( int s ) | |||
{ | |||
_save_signal = s; | |||
} | |||
void stop_signal ( int s ) | |||
{ | |||
_stop_signal = s; | |||
} | |||
void label ( const char *s ) | |||
{ | |||
if ( _label ) | |||
free( _label ); | |||
_label = strdup( s ); | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/label", "s", _label ); | |||
} | |||
void save ( void ) | |||
{ | |||
DMESSAGE( "Sending process save signal" ); | |||
if ( _pid ) | |||
::kill( _pid, _save_signal ); | |||
} | |||
bool dump ( const char *path ) | |||
{ | |||
char *fname; | |||
asprintf( &fname, "%s/%s", path, CONFIG_FILE_NAME ); | |||
FILE *fp = fopen( fname, "w" ); | |||
free( fname ); | |||
if ( !fp ) | |||
{ | |||
WARNING( "Error opening file for saving: %s", strerror( errno ) ); | |||
return false; | |||
} | |||
if ( _executable && strlen(_executable) ) | |||
fprintf( fp, "executable\n\t%s\n", _executable ); | |||
if ( _arguments && strlen(_arguments) ) | |||
fprintf( fp, "arguments\n\t%s\n", _arguments ); | |||
if ( _config_file && strlen(_config_file) ) | |||
fprintf( fp, "config file\n\t%s\n", _config_file ); | |||
fprintf( fp, "save signal\n\t%i\n", _save_signal ); | |||
fprintf( fp, "stop signal\n\t%i\n", _stop_signal ); | |||
if ( _label && strlen(_label) ) | |||
fprintf( fp, "label\n\t%s\n", _label ); | |||
fclose( fp ); | |||
return true; | |||
} | |||
bool restore ( const char *path ) | |||
{ | |||
FILE *fp = fopen( path, "r" ); | |||
if ( ! fp ) | |||
{ | |||
WARNING( "Error opening file for restore: %s", strerror( errno ) ); | |||
return false; | |||
} | |||
char *name; | |||
char *value; | |||
MESSAGE( "Loading file config \"%s\"", path ); | |||
while ( 2 == fscanf( fp, "%m[^\n]\n\t%m[^\n]\n", &name, &value ) ) | |||
{ | |||
DMESSAGE( "%s=%s", name, value ); | |||
if ( !strcmp( name, "executable" ) ) | |||
_executable = value; | |||
else if (!strcmp( name, "arguments" ) ) | |||
_arguments = value; | |||
else if (!strcmp( name, "config file" ) ) | |||
_config_file = value; | |||
else if ( !strcmp( name, "save signal" ) ) | |||
{ | |||
_save_signal = atoi( value ); | |||
free( value ); | |||
} | |||
else if ( !strcmp( name, "stop signal" ) ) | |||
{ | |||
_stop_signal = atoi( value ); | |||
free( value ); | |||
} | |||
else if ( !strcmp( name, "label" ) ) | |||
{ | |||
label( value ); | |||
free( value ); | |||
} | |||
else | |||
{ | |||
WARNING( "Unknown option \"%s\" in config file", name ); | |||
} | |||
free( name ); | |||
} | |||
fclose( fp ); | |||
start(); | |||
return true; | |||
} | |||
void update ( lo_address to ) | |||
{ | |||
DMESSAGE( "Sending update" ); | |||
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/save_signal", "i", _save_signal ); | |||
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/label", "s", _label ? _label : "" ); | |||
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/executable", "s", _executable ? _executable : "" ); | |||
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/arguments", "s", _arguments ? _arguments : "" ); | |||
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/config_file", "s", _config_file ? _config_file : "" ); | |||
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/stop_signal", "i", _stop_signal ); | |||
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/client_error", "s", _client_error ? _client_error : "" ); | |||
} | |||
}; | |||
NSM_Proxy *nsm_proxy; | |||
bool | |||
snapshot ( const char *file ) | |||
{ | |||
return nsm_proxy->dump(file); | |||
} | |||
void | |||
announce ( const char *nsm_url, const char *client_name, const char *process_name ) | |||
{ | |||
printf( "Announcing to NSM\n" ); | |||
lo_address to = lo_address_new_from_url( nsm_url ); | |||
int pid = (int)getpid(); | |||
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii", | |||
client_name, | |||
":optional-gui:", | |||
process_name, | |||
1, /* api_major_version */ | |||
0, /* api_minor_version */ | |||
pid ); | |||
lo_address_free( to ); | |||
} | |||
bool | |||
open ( const char *file ) | |||
{ | |||
char *path; | |||
asprintf( &path, "%s/%s", file, CONFIG_FILE_NAME ); | |||
bool r = nsm_proxy->restore( path ); | |||
free( path ); | |||
return r; | |||
} | |||
/****************/ | |||
/* OSC HANDLERS */ | |||
/****************/ | |||
/* NSM */ | |||
int | |||
osc_announce_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
if ( strcmp( types, "sis" ) ) | |||
return -1; | |||
if ( strcmp( "/nsm/server/announce", &argv[0]->s ) ) | |||
return -1; | |||
printf( "Failed to register with NSM: %s\n", &argv[2]->s ); | |||
nsm_is_active = 0; | |||
return 0; | |||
} | |||
int | |||
osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
if ( strcmp( "/nsm/server/announce", &argv[0]->s ) ) | |||
return -1; | |||
printf( "Successfully registered. NSM says: %s", &argv[1]->s ); | |||
nsm_is_active = 1; | |||
nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ) ); | |||
return 0; | |||
} | |||
int | |||
osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
bool r = snapshot( project_file ); | |||
nsm_proxy->save(); | |||
if ( r ) | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" ); | |||
else | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/error", "sis", path, -1, "Error saving project file" ); | |||
return 0; | |||
} | |||
static int gui_pid; | |||
void | |||
show_gui ( void ) | |||
{ | |||
int pid; | |||
if ( ! (pid = fork()) ) | |||
{ | |||
char executable[] = "nsm-proxy-gui"; | |||
MESSAGE( "Launching %s\n", executable ); | |||
char *url = lo_server_get_url( losrv ); | |||
char *args[] = { executable, strdup( "--connect-to" ), url, NULL }; | |||
if ( -1 == execvp( executable, args ) ) | |||
{ | |||
WARNING( "Error starting process: %s", strerror( errno ) ); | |||
exit(1); | |||
} | |||
} | |||
gui_pid = pid; | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/gui_is_shown", "" ); | |||
} | |||
int | |||
osc_show_gui ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
show_gui(); | |||
/* FIXME: detect errors */ | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" ); | |||
return 0; | |||
} | |||
void | |||
hide_gui ( void ) | |||
{ | |||
if ( gui_pid ) | |||
{ | |||
kill( gui_pid, SIGTERM ); | |||
} | |||
} | |||
int | |||
osc_hide_gui ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
hide_gui(); | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "" ); | |||
/* FIXME: detect errors */ | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" ); | |||
return 0; | |||
} | |||
int | |||
osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
const char *new_path = &argv[0]->s; | |||
const char *display_name = &argv[1]->s; | |||
const char *client_id = &argv[2]->s; | |||
if ( nsm_client_id ) | |||
free(nsm_client_id); | |||
nsm_client_id = strdup( client_id ); | |||
if ( nsm_display_name ) | |||
free( nsm_display_name ); | |||
nsm_display_name = strdup( display_name ); | |||
char *new_filename; | |||
mkdir( new_path, 0777 ); | |||
chdir( new_path ); | |||
asprintf( &new_filename, "%s/%s", new_path, CONFIG_FILE_NAME ); | |||
struct stat st; | |||
if ( 0 == stat( new_filename, &st ) ) | |||
{ | |||
if ( open( new_path ) ) | |||
{ | |||
} | |||
else | |||
{ | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/error", "sis", path, -1, "Could not open file" ); | |||
return 0; | |||
} | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "" ); | |||
} | |||
else | |||
{ | |||
show_gui(); | |||
} | |||
if ( project_file ) | |||
free( project_file ); | |||
project_file = strdup( new_path ); | |||
// new_filename; | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" ); | |||
if ( gui_addr ) | |||
nsm_proxy->update( gui_addr ); | |||
return 0; | |||
} | |||
/* GUI */ | |||
int | |||
osc_label ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
nsm_proxy->label( &argv[0]->s ); | |||
return 0; | |||
} | |||
int | |||
osc_save_signal ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
nsm_proxy->save_signal( argv[0]->i ); | |||
return 0; | |||
} | |||
int | |||
osc_stop_signal ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
nsm_proxy->stop_signal( argv[0]->i ); | |||
return 0; | |||
} | |||
int | |||
osc_start ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
snapshot( project_file ); | |||
if ( nsm_proxy->start( &argv[0]->s, &argv[1]->s, &argv[2]->s ) ) | |||
{ | |||
hide_gui(); | |||
} | |||
return 0; | |||
} | |||
int | |||
osc_kill ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
nsm_proxy->kill(); | |||
return 0; | |||
} | |||
int | |||
osc_update ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
{ | |||
lo_address to = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) )); | |||
nsm_proxy->update( to ); | |||
gui_addr = to; | |||
return 0; | |||
} | |||
void | |||
signal_handler ( int x ) | |||
{ | |||
die_now = 1; | |||
} | |||
void | |||
set_traps ( void ) | |||
{ | |||
signal( SIGHUP, signal_handler ); | |||
signal( SIGINT, signal_handler ); | |||
// signal( SIGQUIT, signal_handler ); | |||
// signal( SIGSEGV, signal_handler ); | |||
// signal( SIGPIPE, signal_handler ); | |||
signal( SIGTERM, signal_handler ); | |||
} | |||
void | |||
init_osc ( const char *osc_port ) | |||
{ | |||
losrv = lo_server_new( osc_port, NULL ); | |||
//error_handler ); | |||
char *url = lo_server_get_url(losrv); | |||
printf("OSC: %s\n",url); | |||
free(url); | |||
/* NSM */ | |||
lo_server_add_method( losrv, "/nsm/client/save", "", osc_save, NULL ); | |||
lo_server_add_method( losrv, "/nsm/client/open", "sss", osc_open, NULL ); | |||
lo_server_add_method( losrv, "/nsm/client/show_optional_gui", "", osc_show_gui, NULL ); | |||
lo_server_add_method( losrv, "/nsm/client/hide_optional_gui", "", osc_hide_gui, NULL ); | |||
lo_server_add_method( losrv, "/error", "sis", osc_announce_error, NULL ); | |||
lo_server_add_method( losrv, "/reply", "ssss", osc_announce_reply, NULL ); | |||
/* GUI */ | |||
lo_server_add_method( losrv, "/nsm/proxy/label", "s", osc_label, NULL ); | |||
lo_server_add_method( losrv, "/nsm/proxy/save_signal", "i", osc_save_signal, NULL ); | |||
lo_server_add_method( losrv, "/nsm/proxy/stop_signal", "i", osc_stop_signal, NULL ); | |||
lo_server_add_method( losrv, "/nsm/proxy/kill", "", osc_kill, NULL ); | |||
lo_server_add_method( losrv, "/nsm/proxy/start", "sss", osc_start, NULL ); | |||
lo_server_add_method( losrv, "/nsm/proxy/update", "", osc_update, NULL ); | |||
} | |||
void | |||
die ( void ) | |||
{ | |||
if ( gui_pid ) | |||
{ | |||
DMESSAGE( "Killing GUI" ); | |||
kill( gui_pid, SIGTERM ); | |||
} | |||
nsm_proxy->kill(); | |||
exit(0); | |||
} | |||
void handle_sigchld ( ) | |||
{ | |||
for ( ;; ) | |||
{ | |||
int status; | |||
pid_t pid = waitpid(-1, &status, WNOHANG); | |||
if (pid <= 0) | |||
break; | |||
if ( pid == gui_pid ) | |||
{ | |||
lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "" ); | |||
gui_pid = 0; | |||
/* don't care... */ | |||
continue; | |||
} | |||
if ( WIFSIGNALED(status) ) | |||
{ | |||
/* process was killed via signal */ | |||
if (WTERMSIG(status) == SIGTERM || | |||
WTERMSIG(status) == SIGHUP || | |||
WTERMSIG(status) == SIGINT || | |||
WTERMSIG(status) == SIGKILL ) | |||
{ | |||
/* process was killed via an appropriate signal */ | |||
MESSAGE( "child was killed (maybe by us)\n" ); | |||
die_now = 1; | |||
continue; | |||
} | |||
} | |||
else if ( WIFEXITED(status) ) | |||
{ | |||
/* child called exit() or returned from main() */ | |||
MESSAGE( "child exit status: %i", WEXITSTATUS(status) ); | |||
if ( WEXITSTATUS(status) == 0 ) | |||
{ | |||
/* apparently normal termination */ | |||
MESSAGE( "child exited without error."); | |||
die_now = 1; | |||
continue; | |||
} | |||
else | |||
{ | |||
MESSAGE("child exited abnormally."); | |||
nsm_proxy->handle_client_death(WEXITSTATUS(status)); | |||
} | |||
} | |||
} | |||
} | |||
int | |||
main ( int argc, char **argv ) | |||
{ | |||
set_traps(); | |||
sigset_t mask; | |||
sigemptyset( &mask ); | |||
sigaddset( &mask, SIGCHLD ); | |||
sigprocmask(SIG_BLOCK, &mask, NULL ); | |||
signal_fd = signalfd( -1, &mask, SFD_NONBLOCK ); | |||
nsm_proxy = new NSM_Proxy(); | |||
init_osc( NULL ); | |||
const char *nsm_url = getenv( "NSM_URL" ); | |||
if ( nsm_url ) | |||
{ | |||
announce( nsm_url, APP_TITLE, argv[0] ); | |||
} | |||
else | |||
{ | |||
fprintf( stderr, "Could not register as NSM client.\n" ); | |||
exit(1); | |||
} | |||
struct signalfd_siginfo fdsi; | |||
/* listen for sigchld signals and process OSC messages forever */ | |||
for ( ;; ) | |||
{ | |||
ssize_t s = read(signal_fd, &fdsi, sizeof(struct signalfd_siginfo)); | |||
if (s == sizeof(struct signalfd_siginfo)) | |||
{ | |||
if (fdsi.ssi_signo == SIGCHLD) | |||
handle_sigchld(); | |||
} | |||
lo_server_recv_noblock( losrv, 500 ); | |||
if ( die_now ) | |||
die(); | |||
} | |||
} |