1 /*
2  *                           0BSD
3  *
4  *                    BSD Zero Clause License
5  *
6  *  Copyright (c) 2020 Hermann Meyer
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted.
10 
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  *
19  */
20 
21 
22 #include "NsmHandler.h"
23 
24 
25 namespace nsmhandler {
26 
27 
28 /****************************************************************
29  ** class NsmWatchDog
30  **
31  ** Watch for incomming messages from NSM server in a extra timeout thread
32  **
33  */
34 
NsmWatchDog()35 NsmWatchDog::NsmWatchDog()
36     :_execute(false) {
37 }
38 
~NsmWatchDog()39 NsmWatchDog::~NsmWatchDog() {
40     if( _execute.load(std::memory_order_acquire) ) {
41         stop();
42     };
43 }
44 
stop()45 void NsmWatchDog::stop() {
46     _execute.store(false, std::memory_order_release);
47     if (_thd.joinable()) {
48         _thd.join();
49     }
50 }
51 
start(int interval,std::function<void (void)> func)52 void NsmWatchDog::start(int interval, std::function<void(void)> func) {
53     if( _execute.load(std::memory_order_acquire) ) {
54         stop();
55     };
56     _execute.store(true, std::memory_order_release);
57     _thd = std::thread([this, interval, func]() {
58         while (_execute.load(std::memory_order_acquire)) {
59             func();
60             std::this_thread::sleep_for(
61                 std::chrono::milliseconds(interval));
62         }
63     });
64 }
65 
is_running() const66 bool NsmWatchDog::is_running() const noexcept {
67     return ( _execute.load(std::memory_order_acquire) &&
68              _thd.joinable() );
69 }
70 
71 
72 /****************************************************************
73  ** class NsmHandler
74  **
75  ** Check if NSM server response, if so, connect the handlers
76  ** and signal the UI thread to set up the variables
77  */
78 
NsmHandler(NsmSignalHandler * nsmsig_)79 NsmHandler::NsmHandler(NsmSignalHandler *nsmsig_)
80     : poll(),
81     nsmsig(nsmsig_),
82     nsm(0),
83     wait_id(true),
84     optional_gui(false) {
85 
86     nsmsig->signal_trigger_nsm_gui_is_shown().connect(
87         sigc::mem_fun(this, &NsmHandler::_on_nsm_is_shown));
88 
89     nsmsig->signal_trigger_nsm_gui_is_hidden().connect(
90         sigc::mem_fun(this, &NsmHandler::_on_nsm_is_hidden));
91 }
92 
~NsmHandler()93 NsmHandler::~NsmHandler() {
94     if (nsm) {
95         nsm_free(nsm);
96         nsm = 0;
97     }
98 }
99 
check_nsm(const char * name,char * argv[])100 bool NsmHandler::check_nsm(const char *name, char *argv[]) {
101 
102     const char *nsm_url = getenv( "NSM_URL" );
103 
104     if (nsm_url) {
105         nsm = nsm_new();
106         nsm_set_open_callback( nsm, nsm_open, static_cast<void*>(this));
107         nsm_set_save_callback( nsm, nsm_save, static_cast<void*>(this));
108         nsm_set_show_callback( nsm, nsm_show, static_cast<void*>(this));
109         nsm_set_hide_callback( nsm, nsm_hide, static_cast<void*>(this));
110         if ( 0 == nsm_init( nsm, nsm_url)) {
111             nsm_send_announce( nsm, name, ":optional-gui:", argv[0]);
112             int wait_count = 0;
113             while(wait_id) {
114                 nsm_check_wait(nsm,500);
115                 wait_count +=1;
116                 if (wait_count > 200) {
117                         fprintf (stderr, "\n NSM didn't response, exiting ...\n");
118                         exit (1);
119                 }
120             }
121             return true;
122         } else {
123             nsm_free(nsm);
124             nsm = 0;
125         }
126     }
127     return false;
128 }
129 
_poll_nsm(void * arg)130 void NsmHandler::_poll_nsm(void* arg) {
131     NsmHandler *nsmh = static_cast<NsmHandler*>(arg);
132     nsm_check_nowait(nsmh->nsm);
133 }
134 
_nsm_start_poll()135 void NsmHandler::_nsm_start_poll() {
136     poll.start(200, std::bind(_poll_nsm,this));
137 }
138 
_nsm_open(const char * name,const char * display_name,const char * client_id,char ** out_msg)139 int NsmHandler::_nsm_open (const char *name, const char *display_name,
140                             const char *client_id, char **out_msg ) {
141 
142     if (strstr(nsm_get_session_manager_features(nsm), ":optional-gui:")) {
143         optional_gui = true;
144     }
145     nsmsig->trigger_nsm_gui_open(name, client_id, optional_gui);
146     wait_id = false;
147 
148     _nsm_start_poll();
149 
150     return ERR_OK;
151 }
152 
_nsm_save(char ** out_msg)153 int NsmHandler::_nsm_save ( char **out_msg) {
154     nsmsig->trigger_nsm_save_gui();
155     return ERR_OK;
156 }
157 
_nsm_show()158 void NsmHandler::_nsm_show () {
159     nsmsig->trigger_nsm_show_gui();
160 }
161 
_nsm_hide()162 void NsmHandler::_nsm_hide () {
163     nsmsig->trigger_nsm_hide_gui();
164 }
165 
_on_nsm_is_shown()166 void NsmHandler::_on_nsm_is_shown () {
167     nsm_send_is_shown(nsm);
168 }
169 
_on_nsm_is_hidden()170 void NsmHandler::_on_nsm_is_hidden () {
171     nsm_send_is_hidden(nsm);
172 }
173 
174 //static
nsm_open(const char * name,const char * display_name,const char * client_id,char ** out_msg,void * userdata)175 int NsmHandler::nsm_open (const char *name, const char *display_name,
176             const char *client_id, char **out_msg, void *userdata ) {
177     NsmHandler * nsmhandler = static_cast<NsmHandler*>(userdata);
178     return nsmhandler->_nsm_open (name, display_name, client_id, out_msg);
179 }
180 
181 //static
nsm_save(char ** out_msg,void * userdata)182 int NsmHandler::nsm_save ( char **out_msg, void *userdata ) {
183     NsmHandler * nsmhandler = static_cast<NsmHandler*>(userdata);
184     return nsmhandler->_nsm_save(out_msg);
185 }
186 
187 //static
nsm_show(void * userdata)188 void NsmHandler::nsm_show (void *userdata ) {
189     NsmHandler * nsmhandler = static_cast<NsmHandler*>(userdata);
190     return nsmhandler->_nsm_show();
191 }
192 
193 //static
nsm_hide(void * userdata)194 void NsmHandler::nsm_hide (void *userdata ) {
195     NsmHandler * nsmhandler = static_cast<NsmHandler*>(userdata);
196     return nsmhandler->_nsm_hide();
197 }
198 
199 } // namespace nsmhandler
200 
201