NSM: Add support for clients with optional GUIs.
This commit is contained in:
parent
fdcf74ddbe
commit
885ef30a88
|
@ -2,7 +2,7 @@
|
|||
! title Non Session Management API
|
||||
! author Jonathan Moore Liles #(email,male@tuxfamily.org)
|
||||
! date August 1, 2010
|
||||
! revision Version 1.0
|
||||
! revision Version 1.1
|
||||
! extra #(image,logo,icon.png)
|
||||
|
||||
-- Table Of Contents
|
||||
|
@ -156,6 +156,7 @@
|
|||
[[ dirty, client knows when it has unsaved changes
|
||||
[[ progress, client can send progress updates during time-consuming operations
|
||||
[[ message, client can send textual status updates
|
||||
[[ optional-gui, client has an optional GUI
|
||||
|
||||
:::: Response
|
||||
|
||||
|
@ -179,6 +180,7 @@
|
|||
[[ Name, Description
|
||||
[[ server_control, client-to-server control
|
||||
[[ broadcast, server responds to /nsm/server/broadcast message
|
||||
[[ optional-gui, server responds to optional-gui messages--if this capability is not present then clients with optional-guis MUST always keep them visible
|
||||
|
||||
A client should not consider itself to be under session management
|
||||
until it receives this response. For example, the Non applications
|
||||
|
@ -366,6 +368,22 @@
|
|||
|
||||
This message does not require a response.
|
||||
|
||||
:::: Show Optional Gui
|
||||
|
||||
If the client has specified the `optional-gui` capability, then it
|
||||
may receive this message from the server when the user wishes to
|
||||
change the visibility state of the GUI. It doesn't matter if the
|
||||
optional GUI is integrated with the program or if it is a separate
|
||||
program \(as is the case with SooperLooper\). When the GUI is
|
||||
hidden, there should be no window mapped and if the GUI is a
|
||||
separate program, it should be killed.
|
||||
|
||||
> /nsm/client/show_optional_gui
|
||||
|
||||
> /nsm/client/hide_optional_gui
|
||||
|
||||
No response is message is required.
|
||||
|
||||
::: Client to Server Informational Messages
|
||||
|
||||
These are optional messages which a client can send to the NSM
|
||||
|
@ -375,6 +393,20 @@
|
|||
appropriate value to its `capabilities` string when composing the
|
||||
`announce` message.
|
||||
|
||||
:::: Optional GUI
|
||||
|
||||
If the client has specified the `optional-gui` capability, then it
|
||||
*MUST* send this message whenever the state of visibility of the
|
||||
optional GUI has changed. It also *MUST* send this message after
|
||||
it's announce message to indicate the initial visibility state of
|
||||
the optional GUI.
|
||||
|
||||
> /nsm/client/gui_is_hidden
|
||||
|
||||
> /nsm/client/gui_is_shown
|
||||
|
||||
No response will be delivered.
|
||||
|
||||
:::: Progress
|
||||
|
||||
> /nsm/client/progress f:progress
|
||||
|
|
|
@ -36,9 +36,7 @@
|
|||
#include <sys/signalfd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <unistd.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <dirent.h>
|
||||
|
@ -97,6 +95,10 @@ private:
|
|||
int _pending_command; /* */
|
||||
struct timeval _command_sent_time;
|
||||
|
||||
bool _gui_visible;
|
||||
|
||||
char *_label;
|
||||
|
||||
public:
|
||||
|
||||
lo_address addr; /* */
|
||||
|
@ -105,7 +107,6 @@ public:
|
|||
int pid; /* PID of client process */
|
||||
float progress; /* */
|
||||
bool active; /* client has registered via announce */
|
||||
bool dead_because_we_said;
|
||||
// bool stopped; /* the client quit, but not because we told it to--user still has to decide to remove it from the session */
|
||||
char *client_id; /* short part of client ID */
|
||||
char *capabilities; /* client capabilities... will be null for dumb clients */
|
||||
|
@ -113,14 +114,32 @@ public:
|
|||
bool pre_existing;
|
||||
const char *status;
|
||||
|
||||
const char *label ( void ) const { return _label; }
|
||||
void label ( const char *l )
|
||||
{
|
||||
if ( _label )
|
||||
free( _label );
|
||||
_label = strdup( l );
|
||||
}
|
||||
|
||||
bool gui_visible ( void ) const
|
||||
{
|
||||
return _gui_visible;
|
||||
}
|
||||
|
||||
void gui_visible ( bool b )
|
||||
{
|
||||
_gui_visible = b;
|
||||
}
|
||||
|
||||
bool
|
||||
has_error ( void )
|
||||
has_error ( void ) const
|
||||
{
|
||||
return _reply_errcode != 0;
|
||||
}
|
||||
|
||||
int
|
||||
error_code ( void )
|
||||
error_code ( void ) const
|
||||
{
|
||||
return _reply_errcode;
|
||||
}
|
||||
|
@ -173,12 +192,20 @@ public:
|
|||
return _pending_command;
|
||||
}
|
||||
|
||||
// capability should be enclosed in colons. I.e. ":switch:"
|
||||
bool
|
||||
is_capable_of ( const char *capability ) const
|
||||
{
|
||||
return capabilities &&
|
||||
strstr( capabilities, capability );
|
||||
}
|
||||
|
||||
Client ( )
|
||||
{
|
||||
_gui_visible = true;
|
||||
addr = 0;
|
||||
_reply_errcode = 0;
|
||||
_reply_message = 0;
|
||||
dead_because_we_said = false;
|
||||
pid = 0;
|
||||
progress = -0;
|
||||
_pending_command = 0;
|
||||
|
@ -265,10 +292,12 @@ handle_client_process_death ( int pid )
|
|||
{
|
||||
MESSAGE( "Client %s died.", c->name );
|
||||
|
||||
bool dead_because_we_said = false;
|
||||
|
||||
if ( c->pending_command() == COMMAND_KILL ||
|
||||
c->pending_command() == COMMAND_QUIT )
|
||||
{
|
||||
c->dead_because_we_said = true;
|
||||
dead_because_we_said = true;
|
||||
}
|
||||
|
||||
c->pending_command( COMMAND_NONE );
|
||||
|
@ -276,7 +305,7 @@ handle_client_process_death ( int pid )
|
|||
c->active = false;
|
||||
c->pid = 0;
|
||||
|
||||
if ( c->dead_because_we_said )
|
||||
if ( dead_because_we_said )
|
||||
{
|
||||
if ( gui_is_active )
|
||||
osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status = "removed" );
|
||||
|
@ -770,6 +799,9 @@ OSC_HANDLER( announce )
|
|||
{
|
||||
osc_server->send( gui_addr, "/nsm/gui/client/new", c->client_id, c->name );
|
||||
osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status = "open" );
|
||||
|
||||
if ( c->is_capable_of( ":optional-gui:" ) )
|
||||
osc_server->send( gui_addr, "/nsm/gui/client/has_optional_gui", c->client_id );
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -824,13 +856,6 @@ client_by_name ( const char *name,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// capability should be enclosed in colons. I.e. ":switch:"
|
||||
bool
|
||||
client_is_capable_of ( Client *c, const char *capability )
|
||||
{
|
||||
return c->capabilities &&
|
||||
strstr( c->capabilities, capability );
|
||||
}
|
||||
|
||||
bool
|
||||
dumb_clients_are_alive ( )
|
||||
|
@ -1109,7 +1134,7 @@ load_session_file ( const char * path )
|
|||
i != client.end();
|
||||
++i )
|
||||
{
|
||||
if ( ! client_is_capable_of( *i, ":switch:" )
|
||||
if ( ! (*i)->is_capable_of( ":switch:" )
|
||||
||
|
||||
! client_by_name( (*i)->name, &new_clients ) )
|
||||
{
|
||||
|
@ -1636,6 +1661,39 @@ OSC_HANDLER( is_clean )
|
|||
return 0;
|
||||
}
|
||||
|
||||
OSC_HANDLER( gui_is_hidden )
|
||||
{
|
||||
MESSAGE( "Client sends gui hidden" );
|
||||
|
||||
Client *c = get_client_by_address( lo_message_get_source( msg ) );
|
||||
|
||||
if ( ! c )
|
||||
return 0;
|
||||
|
||||
c->gui_visible( false );
|
||||
|
||||
if ( gui_is_active )
|
||||
osc_server->send( gui_addr, "/nsm/gui/client/gui_visible", c->client_id, c->gui_visible() );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSC_HANDLER( gui_is_shown )
|
||||
{
|
||||
MESSAGE( "Client sends gui shown" );
|
||||
|
||||
Client *c = get_client_by_address( lo_message_get_source( msg ) );
|
||||
|
||||
if ( ! c )
|
||||
return 0;
|
||||
|
||||
c->gui_visible( true );
|
||||
|
||||
if ( gui_is_active )
|
||||
osc_server->send( gui_addr, "/nsm/gui/client/gui_visible", c->client_id, c->gui_visible() );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSC_HANDLER( message )
|
||||
{
|
||||
|
@ -1650,6 +1708,24 @@ OSC_HANDLER( message )
|
|||
return 0;
|
||||
}
|
||||
|
||||
OSC_HANDLER( label )
|
||||
{
|
||||
Client *c = get_client_by_address( lo_message_get_source( msg ) );
|
||||
|
||||
if ( ! c )
|
||||
return 0;
|
||||
|
||||
if ( strcmp( types, "s" ) )
|
||||
return -1;
|
||||
|
||||
c->label( &argv[0]->s );
|
||||
|
||||
if ( gui_is_active )
|
||||
osc_server->send( gui_addr, "/nsm/gui/client/label", c->client_id, &argv[0]->s );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Response Handlers */
|
||||
/**********************/
|
||||
|
@ -1779,6 +1855,38 @@ OSC_HANDLER( client_save )
|
|||
return 0;
|
||||
}
|
||||
|
||||
OSC_HANDLER( client_show_optional_gui )
|
||||
{
|
||||
Client *c = get_client_by_id( &client, &argv[0]->s );
|
||||
|
||||
/* FIXME: return error if no such client? */
|
||||
if ( c )
|
||||
{
|
||||
if ( c->active )
|
||||
{
|
||||
osc_server->send( c->addr, "/nsm/client/show_optional_gui" );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSC_HANDLER( client_hide_optional_gui )
|
||||
{
|
||||
Client *c = get_client_by_id( &client, &argv[0]->s );
|
||||
|
||||
/* FIXME: return error if no such client? */
|
||||
if ( c )
|
||||
{
|
||||
if ( c->active )
|
||||
{
|
||||
osc_server->send( c->addr, "/nsm/client/hide_optional_gui" );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
announce_gui( const char *url, bool is_reply )
|
||||
{
|
||||
|
@ -1927,12 +2035,17 @@ int main(int argc, char *argv[])
|
|||
osc_server->add_method( "/nsm/client/is_dirty", "", OSC_NAME( is_dirty ), NULL, "dirtiness" );
|
||||
osc_server->add_method( "/nsm/client/is_clean", "", OSC_NAME( is_clean ), NULL, "dirtiness" );
|
||||
osc_server->add_method( "/nsm/client/message", "is", OSC_NAME( message ), NULL, "message" );
|
||||
osc_server->add_method( "/nsm/client/gui_is_hidden", "", OSC_NAME( gui_is_hidden ), NULL, "message" );
|
||||
osc_server->add_method( "/nsm/client/gui_is_shown", "", OSC_NAME( gui_is_shown ), NULL, "message" );
|
||||
osc_server->add_method( "/nsm/client/label", "s", OSC_NAME( label ), NULL, "message" );
|
||||
|
||||
/* */
|
||||
osc_server->add_method( "/nsm/gui/gui_announce", "", OSC_NAME( gui_announce ), NULL, "" );
|
||||
osc_server->add_method( "/nsm/gui/client/remove", "s", OSC_NAME( remove ), NULL, "client_id" );
|
||||
osc_server->add_method( "/nsm/gui/client/resume", "s", OSC_NAME( resume ), NULL, "client_id" );
|
||||
osc_server->add_method( "/nsm/gui/client/save", "s", OSC_NAME( client_save ), NULL, "client_id" );
|
||||
osc_server->add_method( "/nsm/gui/client/show_optional_gui", "s", OSC_NAME( client_show_optional_gui ), NULL, "client_id" );
|
||||
osc_server->add_method( "/nsm/gui/client/hide_optional_gui", "s", OSC_NAME( client_hide_optional_gui ), NULL, "client_id" );
|
||||
|
||||
osc_server->add_method( "/osc/ping", "", OSC_NAME( ping ), NULL, "" );
|
||||
|
||||
|
|
|
@ -83,19 +83,56 @@ static std::list<Daemon*> daemon_list; /* list
|
|||
class NSM_Client : public Fl_Group
|
||||
{
|
||||
char *_client_id;
|
||||
char *_client_label;
|
||||
char *_client_name;
|
||||
|
||||
// Fl_Box *client_name;
|
||||
Fl_Progress *_progress;
|
||||
Fl_Light_Button *_dirty;
|
||||
Fl_Light_Button *_gui;
|
||||
Fl_Button *_remove_button;
|
||||
Fl_Button *_restart_button;
|
||||
|
||||
void
|
||||
set_label ( void )
|
||||
{
|
||||
char *l;
|
||||
|
||||
if ( _client_label )
|
||||
asprintf( &l, "%s (%s)", _client_name, _client_label );
|
||||
else
|
||||
l = strdup( _client_name );
|
||||
|
||||
if ( label() )
|
||||
free((char*)label());
|
||||
|
||||
label( l );
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void
|
||||
name ( const char *v )
|
||||
{
|
||||
label( strdup( v ) );
|
||||
if ( _client_name )
|
||||
free( _client_name );
|
||||
|
||||
_client_name = strdup( v );
|
||||
|
||||
set_label();
|
||||
}
|
||||
|
||||
void
|
||||
client_label ( const char *s )
|
||||
{
|
||||
if ( _client_label )
|
||||
free( _client_label );
|
||||
|
||||
_client_label = strdup( s );
|
||||
|
||||
set_label();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -121,6 +158,21 @@ public:
|
|||
_dirty->redraw();
|
||||
}
|
||||
|
||||
void
|
||||
gui_visible ( bool b )
|
||||
{
|
||||
_gui->value( b );
|
||||
_gui->redraw();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
has_optional_gui ( void )
|
||||
{
|
||||
_gui->show();
|
||||
_gui->redraw();
|
||||
}
|
||||
|
||||
void
|
||||
stopped ( bool b )
|
||||
{
|
||||
|
@ -193,7 +245,18 @@ public:
|
|||
osc->send( (*d)->addr, "/nsm/gui/client/save", _client_id );
|
||||
}
|
||||
}
|
||||
if ( o == _remove_button )
|
||||
else if ( o == _gui )
|
||||
{
|
||||
MESSAGE( "Sending hide/show GUI.");
|
||||
foreach_daemon ( d )
|
||||
{
|
||||
if ( !_gui->value() )
|
||||
osc->send( (*d)->addr, "/nsm/gui/client/show_optional_gui", _client_id );
|
||||
else
|
||||
osc->send( (*d)->addr, "/nsm/gui/client/hide_optional_gui", _client_id );
|
||||
}
|
||||
}
|
||||
else if ( o == _remove_button )
|
||||
{
|
||||
MESSAGE( "Sending remove.");
|
||||
foreach_daemon ( d )
|
||||
|
@ -221,46 +284,119 @@ public:
|
|||
{
|
||||
|
||||
_client_id = NULL;
|
||||
_client_name = NULL;
|
||||
_client_label = NULL;
|
||||
|
||||
align( FL_ALIGN_LEFT | FL_ALIGN_INSIDE );
|
||||
color( fl_darker( FL_RED ) );
|
||||
box( FL_UP_BOX );
|
||||
|
||||
int yy = Y + H * 0.25;
|
||||
int hh = H * 0.50;
|
||||
int xx = X + W - ( 200 + Fl::box_dw( box() ) );
|
||||
int ss = 2;
|
||||
|
||||
{ Fl_Progress *o = _progress = new Fl_Progress( ( X + W ) - ( W / 4) - 20, Y + 5, ( W / 4 ), H - 10, NULL );
|
||||
/* dummy group */
|
||||
{ Fl_Group *o = new Fl_Group( X, Y, 50, 50 );
|
||||
o->end();
|
||||
resizable( o );
|
||||
}
|
||||
|
||||
{ Fl_Progress *o = _progress = new Fl_Progress( xx, Y + H * 0.25, 200, H * 0.50, NULL );
|
||||
o->box( FL_FLAT_BOX );
|
||||
o->color( FL_BLACK );
|
||||
o->label( strdup( "launch" ) );
|
||||
o->minimum( 0.0f );
|
||||
o->maximum( 1.0f );
|
||||
}
|
||||
{ Fl_Light_Button *o = _dirty = new Fl_Light_Button( _progress->x() - 30, Y + 7, 25, 25 );
|
||||
o->box( FL_UP_BOX );
|
||||
o->type(0);
|
||||
o->color();
|
||||
o->selection_color( FL_YELLOW );
|
||||
o->value( 0 );
|
||||
o->callback( cb_button, this );
|
||||
|
||||
{ Fl_Group *o = new Fl_Group( X + W - 400, Y, 400, H );
|
||||
|
||||
xx -= 50 + ss;
|
||||
|
||||
{ Fl_Light_Button *o = _dirty = new Fl_Light_Button( xx, yy, 50, hh, "SAVE" );
|
||||
|
||||
o->align( FL_ALIGN_LEFT | FL_ALIGN_INSIDE );
|
||||
o->labelsize( 9 );
|
||||
o->box( FL_UP_BOX );
|
||||
o->type(0);
|
||||
o->color();
|
||||
o->selection_color( FL_YELLOW );
|
||||
o->value( 0 );
|
||||
o->callback( cb_button, this );
|
||||
}
|
||||
|
||||
xx -= 40 + ss;
|
||||
|
||||
{ Fl_Light_Button *o = _gui = new Fl_Light_Button( xx, yy, 40, hh, "GUI" );
|
||||
|
||||
o->align( FL_ALIGN_LEFT | FL_ALIGN_INSIDE );
|
||||
o->labelsize( 9 );
|
||||
o->box( FL_UP_BOX );
|
||||
o->type(0);
|
||||
o->color();
|
||||
o->selection_color( FL_YELLOW );
|
||||
o->value( 0 );
|
||||
o->hide();
|
||||
o->callback( cb_button, this );
|
||||
}
|
||||
|
||||
|
||||
xx -= 25 + ss;
|
||||
|
||||
{ Fl_Button *o = _restart_button = new Fl_Button( xx, yy, 25, hh );
|
||||
|
||||
|
||||
o->box( FL_UP_BOX );
|
||||
o->type(0);
|
||||
o->color( FL_GREEN );
|
||||
o->value( 0 );
|
||||
o->label( "@>" );
|
||||
o->tooltip( "Resume" );
|
||||
o->hide();
|
||||
o->callback( cb_button, this );
|
||||
}
|
||||
|
||||
xx -= 25 + ss;
|
||||
|
||||
{ Fl_Button *o = _remove_button = new Fl_Button( xx, yy, 25, hh );
|
||||
|
||||
|
||||
o->box( FL_UP_BOX );
|
||||
o->type(0);
|
||||
o->color( FL_RED );
|
||||
o->value( 0 );
|
||||
o->label( "X" );
|
||||
o->tooltip( "Remove" );
|
||||
o->hide();
|
||||
o->callback( cb_button, this );
|
||||
}
|
||||
|
||||
|
||||
o->end();
|
||||
}
|
||||
{ Fl_Button *o = _remove_button = new Fl_Button( _progress->x() - 60, Y + 7, 25, 25 );
|
||||
o->box( FL_UP_BOX );
|
||||
o->type(0);
|
||||
o->color( FL_RED );
|
||||
o->value( 0 );
|
||||
o->label( "X" );
|
||||
o->tooltip( "Remove" );
|
||||
o->hide();
|
||||
o->callback( cb_button, this );
|
||||
}
|
||||
{ Fl_Button *o = _restart_button = new Fl_Button( _progress->x() - 90, Y + 7, 25, 25 );
|
||||
o->box( FL_UP_BOX );
|
||||
o->type(0);
|
||||
o->color( FL_GREEN );
|
||||
o->value( 0 );
|
||||
o->label( "@>" );
|
||||
o->tooltip( "Resume" );
|
||||
o->hide();
|
||||
o->callback( cb_button, this );
|
||||
end();
|
||||
}
|
||||
|
||||
~NSM_Client ( )
|
||||
{
|
||||
if ( _client_name )
|
||||
{
|
||||
free( _client_name );
|
||||
_client_name = NULL;
|
||||
}
|
||||
|
||||
end();
|
||||
if ( _client_label )
|
||||
{
|
||||
free( _client_label );
|
||||
_client_label = NULL;
|
||||
}
|
||||
|
||||
if ( label() )
|
||||
{
|
||||
free( (char*)label() );
|
||||
label( NULL );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -735,6 +871,9 @@ public:
|
|||
osc->add_method( "/nsm/gui/client/switch", "ss", osc_handler, osc, "path,display_name" );
|
||||
osc->add_method( "/nsm/gui/client/progress", "sf", osc_handler, osc, "path,display_name" );
|
||||
osc->add_method( "/nsm/gui/client/dirty", "si", osc_handler, osc, "path,display_name" );
|
||||
osc->add_method( "/nsm/gui/client/has_optional_gui", "s", osc_handler, osc, "path,display_name" );
|
||||
osc->add_method( "/nsm/gui/client/gui_visible", "si", osc_handler, osc, "path,display_name" );
|
||||
osc->add_method( "/nsm/gui/client/label", "ss", osc_handler, osc, "path,display_name" );
|
||||
|
||||
osc->start();
|
||||
|
||||
|
@ -852,7 +991,7 @@ private:
|
|||
if ( !strncmp( path, "/nsm/gui/client/", strlen( "/nsm/gui/client/" ) ) )
|
||||
{
|
||||
if ( !strcmp( path, "/nsm/gui/client/new" ) &&
|
||||
!strcmp( types, "ss" ) )
|
||||
!strcmp( types, "ss" ) )
|
||||
{
|
||||
controller->client_new( &argv[0]->s, &argv[1]->s );
|
||||
}
|
||||
|
@ -877,6 +1016,21 @@ private:
|
|||
{
|
||||
c->dirty( argv[1]->i );
|
||||
}
|
||||
else if ( !strcmp( path, "/nsm/gui/client/gui_visible" ) &&
|
||||
!strcmp( types, "si" ))
|
||||
{
|
||||
c->gui_visible( argv[1]->i );
|
||||
}
|
||||
else if ( !strcmp( path, "/nsm/gui/client/label" ) &&
|
||||
!strcmp( types, "ss" ))
|
||||
{
|
||||
c->client_label( &argv[1]->s );
|
||||
}
|
||||
else if ( !strcmp( path, "/nsm/gui/client/has_optional_gui" ) &&
|
||||
!strcmp( types, "s" ))
|
||||
{
|
||||
c->has_optional_gui();
|
||||
}
|
||||
else if ( !strcmp( path, "/nsm/gui/client/switch" ) &&
|
||||
!strcmp( types, "ss" ))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue