00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "fuse_image_list_widget.h"
00024
00025 #include <fvutils/net/fuse_message.h>
00026 #include <fvutils/net/fuse_imagelist_content.h>
00027
00028 #include <netinet/in.h>
00029 #include <cstring>
00030 #include <sstream>
00031
00032 using namespace fawkes;
00033
00034
00035
00036
00037
00038
00039
00040
00041 FuseImageListWidget::FuseImageListWidget()
00042 {
00043 m_chk_compression = NULL;
00044 m_chk_auto_update = NULL;
00045
00046 m_cur_client.active = false;
00047
00048 m_new_clients.clear();
00049 m_delete_clients.clear();
00050
00051 m_image_list = Gtk::TreeStore::create(m_image_record);
00052
00053 m_signal_get_image_list.connect( sigc::mem_fun( *this, &FuseImageListWidget::get_image_list) );
00054 m_signal_delete_clients.connect( sigc::mem_fun( *this, &FuseImageListWidget::delete_clients) );
00055 m_signal_update_image_l.connect( sigc::mem_fun( *this, &FuseImageListWidget::update_image_list) );
00056
00057 m_popup_menu = Gtk::manage( new Gtk::Menu() );
00058 Gtk::Menu::MenuList& menulist = m_popup_menu->items();
00059 menulist.push_back( Gtk::Menu_Helpers::MenuElem("Update now", sigc::mem_fun( *this, &FuseImageListWidget::update_image_list) ) );
00060 menulist.push_back( Gtk::Menu_Helpers::SeparatorElem() );
00061 menulist.push_back( Gtk::Menu_Helpers::MenuElem("Add host manually", sigc::mem_fun( *this, &FuseImageListWidget::on_add_host_manually) ) );
00062
00063 set_image_list_trv(this);
00064 }
00065
00066
00067 FuseImageListWidget::~FuseImageListWidget()
00068 {
00069 FuseClient* c;
00070 m_new_clients.lock();
00071 while (m_new_clients.size() != 0)
00072 {
00073 c = m_new_clients.front().client;
00074 m_new_clients.pop_front();
00075 c->disconnect();
00076 c->cancel();
00077 c->join();
00078 delete c;
00079 }
00080 m_new_clients.unlock();
00081
00082 if (m_cur_client.active)
00083 {
00084 m_cur_client.active = false;
00085 m_delete_clients.push_locked(m_cur_client.client);
00086 }
00087 delete_clients();
00088 }
00089
00090
00091
00092
00093
00094
00095 void
00096 FuseImageListWidget::add_fountain_service( const char* name,
00097 const char* host_name,
00098 uint32_t port )
00099 {
00100
00101 m_img_list_mutex.lock();
00102 Gtk::TreeModel::Children children = m_image_list->children();
00103 for ( Gtk::TreeModel::Children::iterator iter = children.begin();
00104 iter != children.end(); ++iter )
00105 {
00106 Gtk::TreeModel::Row row = *iter;
00107 if ( row[m_image_record.service_name] == Glib::ustring(name) )
00108 {
00109 m_img_list_mutex.unlock();
00110 return;
00111 }
00112 }
00113 m_img_list_mutex.unlock();
00114
00115
00116 m_new_clients.lock();
00117 for ( LockList<ClientData>::iterator iter = m_new_clients.begin();
00118 iter != m_new_clients.end(); ++iter )
00119 {
00120 if (name == iter->service_name)
00121 {
00122 m_new_clients.unlock();
00123 return;
00124 }
00125 }
00126 m_new_clients.unlock();
00127
00128 ClientData data;
00129 data.client = 0;
00130 data.service_name = std::string(name);
00131 data.host_name = std::string(host_name);
00132 data.port = port;
00133 data.active = false;
00134
00135 m_new_clients.push_back_locked(data);
00136 m_signal_get_image_list();
00137 }
00138
00139
00140
00141
00142 void
00143 FuseImageListWidget::remove_fountain_service(const char* name)
00144 {
00145 m_img_list_mutex.lock();
00146 Gtk::TreeModel::Children children = m_image_list->children();
00147 Gtk::TreeModel::Children::iterator iter = children.begin();
00148 while ( iter != children.end() )
00149 {
00150 Gtk::TreeModel::Row row = *iter;
00151 if ( row[m_image_record.service_name] == Glib::ustring(name) )
00152 {
00153 iter = m_image_list->erase(iter);
00154 m_image_list->row_deleted( m_image_list->get_path(iter) );
00155 }
00156 else
00157 {
00158 ++iter;
00159 }
00160 }
00161 m_img_list_mutex.unlock();
00162 }
00163
00164
00165
00166
00167 void
00168 FuseImageListWidget::set_image_list_trv(Gtk::TreeView* trv)
00169 {
00170 m_img_list_mutex.lock();
00171 m_trv_image_list = trv;
00172 m_trv_image_list->set_model(m_image_list);
00173 m_trv_image_list->append_column("asdf", m_image_record.display_text);
00174 m_trv_image_list->set_headers_visible(false);
00175 m_trv_image_list->signal_event().connect( sigc::mem_fun(*this, &FuseImageListWidget::on_image_event) );
00176 m_trv_image_list->signal_cursor_changed().connect( sigc::mem_fun(*this, &FuseImageListWidget::on_image_selected) );
00177 m_img_list_mutex.unlock();
00178 }
00179
00180
00181
00182
00183 void
00184 FuseImageListWidget::set_toggle_compression_chk(Gtk::CheckButton* chk)
00185 {
00186 m_chk_compression = chk;
00187 m_chk_compression->signal_toggled().connect( sigc::mem_fun(*this, &FuseImageListWidget::on_compression_toggled) );
00188 }
00189
00190
00191
00192
00193 void
00194 FuseImageListWidget::set_auto_update_chk(Gtk::CheckButton* chk)
00195 {
00196 m_chk_auto_update = chk;
00197 m_chk_auto_update->signal_toggled().connect( sigc::mem_fun(*this, &FuseImageListWidget::on_auto_update_toggled) );
00198 }
00199
00200
00201
00202
00203
00204
00205 Glib::Dispatcher&
00206 FuseImageListWidget::image_selected()
00207 {
00208 return m_signal_image_selected;
00209 }
00210
00211
00212
00213
00214 bool
00215 FuseImageListWidget::auto_update()
00216 {
00217 return m_auto_update;
00218 }
00219
00220
00221
00222
00223
00224 void
00225 FuseImageListWidget::set_auto_update(bool active, unsigned int interval_sec)
00226 {
00227 m_auto_update = active;
00228 m_interval_sec = interval_sec;
00229
00230 if (m_auto_update)
00231 {
00232 m_timeout_conn = Glib::signal_timeout().connect_seconds( sigc::mem_fun(*this, &FuseImageListWidget::on_update_timeout),
00233 m_interval_sec);
00234 }
00235 else m_timeout_conn.disconnect();
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245 bool
00246 FuseImageListWidget::get_selected_image( std::string& host_name, unsigned short& port,
00247 std::string& image_id, bool& compression )
00248 {
00249 if ( !m_trv_image_list )
00250 { return false; }
00251
00252 m_img_list_mutex.lock();
00253 Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_image_list->get_selection();
00254
00255 if ( selection->count_selected_rows() != 1 )
00256 {
00257 m_img_list_mutex.unlock();
00258 return false;
00259 }
00260
00261 Gtk::TreeModel::iterator iter = selection->get_selected();
00262 host_name = iter->get_value(m_image_record.host_name);
00263 port = iter->get_value(m_image_record.port);
00264 image_id = iter->get_value(m_image_record.image_id);
00265 m_img_list_mutex.unlock();
00266
00267 if (m_chk_compression)
00268 { compression = m_chk_compression->get_active(); }
00269 else
00270 { compression = false; }
00271
00272 return true;
00273 }
00274
00275
00276 bool
00277 FuseImageListWidget::on_image_event(GdkEvent *event)
00278 {
00279 GdkEventButton btn = event->button;
00280 if (btn.type == GDK_BUTTON_PRESS && btn.button == 3) {
00281 m_popup_menu->popup(btn.button, btn.time);
00282 return true;
00283 }
00284 return false;
00285 }
00286
00287 void
00288 FuseImageListWidget::on_image_selected()
00289 {
00290 m_img_list_mutex.lock();
00291 Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_image_list->get_selection();
00292
00293 Gtk::TreeModel::iterator iter = selection->get_selected();
00294 Glib::ustring image_id;
00295 image_id = (*iter)[m_image_record.image_id];
00296 m_img_list_mutex.unlock();
00297
00298 if ((image_id != m_cur_image_id) && (image_id != "invalid"))
00299 {
00300 m_cur_image_id = image_id;
00301 m_signal_image_selected();
00302 }
00303 }
00304
00305 void
00306 FuseImageListWidget::on_auto_update_toggled()
00307 {
00308 set_auto_update( m_chk_auto_update->get_active() );
00309 }
00310
00311 void
00312 FuseImageListWidget::on_compression_toggled()
00313 {
00314 m_signal_image_selected();
00315 }
00316
00317 void
00318 FuseImageListWidget::get_image_list()
00319 {
00320 if (m_cur_client.active)
00321
00322 { return; }
00323
00324 m_new_clients.lock();
00325 if (m_new_clients.size() == 0)
00326 {
00327 if (m_auto_update)
00328 {
00329 m_timeout_conn = Glib::signal_timeout().connect_seconds( sigc::mem_fun(*this, &FuseImageListWidget::on_update_timeout),
00330 m_interval_sec);
00331 }
00332 m_new_clients.unlock();
00333 return;
00334 }
00335
00336 m_cur_client = m_new_clients.front();
00337 m_cur_client.active = true;
00338 m_new_clients.pop_front();
00339 m_new_clients.unlock();
00340
00341 try
00342 {
00343 m_cur_client.client = new FuseClient( m_cur_client.host_name.c_str(),
00344 m_cur_client.port, this );
00345 m_cur_client.client->connect();
00346 m_cur_client.client->start();
00347 m_cur_client.client->enqueue(FUSE_MT_GET_IMAGE_LIST);
00348 }
00349 catch (Exception& e)
00350 {
00351 e.print_trace();
00352 m_cur_client.client->cancel();
00353 m_cur_client.client->join();
00354 delete m_cur_client.client;
00355 m_cur_client.active = false;
00356 }
00357 }
00358
00359 void
00360 FuseImageListWidget::delete_clients()
00361 {
00362 FuseClient* c = 0;
00363
00364 m_delete_clients.lock();
00365 while (m_delete_clients.size() != 0)
00366 {
00367 c = m_delete_clients.front();
00368 m_delete_clients.pop();
00369
00370 c->disconnect();
00371 c->cancel();
00372 c->join();
00373 delete c;
00374 }
00375 m_delete_clients.unlock();
00376 }
00377
00378 bool
00379 FuseImageListWidget::on_update_timeout()
00380 {
00381 m_signal_update_image_l();
00382 return m_auto_update;
00383 }
00384
00385 void
00386 FuseImageListWidget::update_image_list()
00387 {
00388 m_timeout_conn.disconnect();
00389 if (m_img_list_mutex.try_lock())
00390 {
00391 Gtk::TreeModel::Children children = m_image_list->children();
00392 for ( Gtk::TreeModel::Children::iterator iter = children.begin();
00393 iter != children.end(); ++iter )
00394 {
00395 if ( (*iter)[m_image_record.image_id] == "invalid" )
00396 {
00397 ClientData data;
00398 data.client = 0;
00399 Glib::ustring service_name = (*iter)[m_image_record.service_name];
00400 Glib::ustring host_name = (*iter)[m_image_record.host_name];
00401 data.service_name = std::string( service_name.c_str() );
00402 data.host_name = std::string( host_name.c_str() );
00403 data.port = (*iter)[m_image_record.port];
00404 data.active = false;
00405
00406 m_new_clients.push_back_locked(data);
00407 }
00408 }
00409 m_img_list_mutex.unlock();
00410 }
00411
00412 m_signal_get_image_list();
00413 }
00414
00415 void
00416 FuseImageListWidget::fuse_invalid_server_version(uint32_t local_version,
00417 uint32_t remote_version) throw()
00418 {
00419 printf("Invalid versions: local: %u remote: %u\n", local_version, remote_version);
00420 }
00421
00422 void
00423 FuseImageListWidget::fuse_connection_established () throw()
00424 {
00425 }
00426
00427 void
00428 FuseImageListWidget::fuse_connection_died() throw()
00429 {
00430 if (m_cur_client.active)
00431 {
00432 m_delete_clients.push_locked(m_cur_client.client);
00433 m_cur_client.active = false;
00434 }
00435
00436 m_signal_delete_clients();
00437 }
00438
00439 void
00440 FuseImageListWidget::fuse_inbound_received (FuseNetworkMessage *m) throw()
00441 {
00442 switch ( m->type() )
00443 {
00444 case FUSE_MT_IMAGE_LIST:
00445 {
00446
00447 m_img_list_mutex.lock();
00448 Gtk::TreeModel::Children children = m_image_list->children();
00449 Gtk::TreeModel::Children::iterator iter = children.begin();
00450 while ( iter != children.end() )
00451 {
00452 Gtk::TreeModel::Row row = *iter;
00453 if ( row[m_image_record.service_name] == Glib::ustring(m_cur_client.service_name) )
00454 {
00455 iter = m_image_list->erase(iter);
00456 }
00457 else
00458 {
00459 ++iter;
00460 }
00461 }
00462
00463 try
00464 {
00465 FuseImageListContent* content = m->msgc<FuseImageListContent>();
00466 if ( content->has_next() )
00467 {
00468 Gtk::TreeModel::Row row = *m_image_list->append();
00469 row[m_image_record.display_text] = Glib::ustring(m_cur_client.host_name);
00470 row[m_image_record.service_name] = Glib::ustring(m_cur_client.service_name);
00471 row[m_image_record.host_name] = Glib::ustring(m_cur_client.host_name);
00472 row[m_image_record.port] = m_cur_client.port;
00473 row[m_image_record.colorspace] = 0;
00474 row[m_image_record.image_id] = "invalid";
00475 row[m_image_record.width] = 0;
00476 row[m_image_record.height] = 0;
00477 row[m_image_record.buffer_size] = 0;
00478
00479 Gtk::TreeModel::Path path = m_image_list->get_path(row);
00480
00481 while ( content->has_next() )
00482 {
00483 FUSE_imageinfo_t* image_info = content->next();
00484 char image_id[IMAGE_ID_MAX_LENGTH + 1];
00485 image_id[IMAGE_ID_MAX_LENGTH] = '\0';
00486 strncpy(image_id, image_info->image_id, IMAGE_ID_MAX_LENGTH);
00487
00488 Gtk::TreeModel::Row childrow = *m_image_list->append( row.children() );
00489 childrow[m_image_record.display_text] = Glib::ustring(image_id);
00490 childrow[m_image_record.service_name] = Glib::ustring(m_cur_client.service_name);
00491 childrow[m_image_record.host_name] = Glib::ustring(m_cur_client.host_name);
00492 childrow[m_image_record.port] = m_cur_client.port;
00493 childrow[m_image_record.colorspace] = ntohl(image_info->colorspace);
00494 childrow[m_image_record.image_id] = Glib::ustring(image_id);
00495 childrow[m_image_record.width] = ntohl(image_info->width);
00496 childrow[m_image_record.height] = ntohl(image_info->height);
00497 childrow[m_image_record.buffer_size] = ntohl(image_info->buffer_size);
00498 }
00499
00500 m_trv_image_list->expand_row(path, false);
00501 }
00502
00503 delete content;
00504 }
00505 catch (Exception& e)
00506 {
00507 e.print_trace();
00508 }
00509
00510 m_img_list_mutex.unlock();
00511
00512 m_delete_clients.push_locked(m_cur_client.client);
00513 m_cur_client.active = false;
00514
00515 m_signal_get_image_list();
00516 m_signal_delete_clients();
00517
00518 break;
00519 }
00520
00521 default:
00522 printf("Unhandled message type\n");
00523 }
00524 }
00525
00526 void
00527 FuseImageListWidget::on_add_host_manually()
00528 {
00529 Gtk::Dialog* add_host = new Gtk::Dialog("Add host manually", this->get_window(), true);
00530 add_host->add_button(Gtk::Stock::ADD, Gtk::RESPONSE_OK);
00531 add_host->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
00532
00533 Gtk::Table* tab = Gtk::manage( new Gtk::Table(2, 2, false) );
00534 Gtk::Label* hlab = Gtk::manage( new Gtk::Label("Host:") );
00535 Gtk::Label* plab = Gtk::manage( new Gtk::Label("Port:") );
00536 Gtk::Entry* hent = Gtk::manage( new Gtk::Entry() );
00537 Gtk::HBox* pbox = Gtk::manage( new Gtk::HBox() );
00538
00539 Gtk::Adjustment prange(2208, 1, 65535);
00540 Gtk::SpinButton *pent = Gtk::manage( new Gtk::SpinButton(prange) );
00541
00542 char * fawkes_ip = getenv("FAWKES_IP");
00543 if (fawkes_ip) hent->set_text(std::string(fawkes_ip).append(":2208"));
00544 else hent->set_text("localhost:2208");
00545
00546 pbox->pack_start(*pent, false, false, 0);
00547 tab->attach(*hlab, 1, 2, 1, 2);
00548 tab->attach(*plab, 1, 2, 2, 3);
00549 tab->attach(*hent, 2, 3, 1, 2);
00550 tab->attach(*pbox, 2, 3, 2, 3);
00551
00552 add_host->get_vbox()->pack_start(*tab, false, true, 0);
00553 add_host->get_vbox()->show_all_children(true);
00554
00555 if (add_host->run() == Gtk::RESPONSE_OK) {
00556 std::string name = "fountain on ";
00557 std::string host = hent->get_text();
00558 unsigned short port = 2208;
00559
00560 Glib::ustring::size_type pos;
00561 if ((pos = host.find(':')) != Glib::ustring::npos)
00562 {
00563 Glib::ustring tmp_host = "";
00564 unsigned int tmp_port = 1234567;
00565 std::istringstream is(host.replace(pos, 1, " "));
00566 is >> tmp_host;
00567 is >> tmp_port;
00568
00569 if (tmp_port != 1234567 && tmp_host.size())
00570 {
00571 host = tmp_host;
00572 port = tmp_port;
00573 }
00574 }
00575
00576 name.append(host);
00577 add_fountain_service(name.c_str(), host.c_str(), port);
00578 }
00579
00580 add_host->hide();
00581 delete add_host;
00582 }