Changeset 5f1602ef2512b6a907744ba59be88e0390453929

Show
Ignore:
Timestamp:
01/06/07 23:49:10 (6 years ago)
Author:
Philipp Kern <phil@…>
Parents:
f4fe94fc7580e639bec5d34dcc524a75c7f2105b
Children:
296b5a23bbf9b07a67acba878b659ab0bf800ef4
git-committer:
Philipp Kern <phil@0x539.de> / 2007-01-06T22:49:10Z+0000
Message:

[project @ Do not block when connecting to a remote host]

Original author: Armin Burgmeier <armin@…>
Date: 2005-10-04 21:08:41+00:00

Files:
8 modified

Legend:

Unmodified
Added
Removed
  • inc/hostprogressdialog.hpp

    r8140232 r5f1602e  
    3434                           const Glib::ustring& username, 
    3535                           const Gdk::Color& color); 
    36         ~HostProgressDialog(); 
    3736 
    3837        /** Never call this function twice because the auto_ptr of the 
     
    4342 
    4443private: 
    45         virtual void on_thread(); 
     44        virtual void on_thread(Thread& thread); 
    4645 
    4746        virtual void on_work(); 
  • inc/io/buffer_wrapper.hpp

    r2fe47ae r5f1602e  
    4545{ 
    4646public: 
     47        /** Creates a new client object. A connection may be established 
     48         * using the inherited connect() method. 
     49         */ 
     50#ifdef WIN32 
     51        client(Gtk::Window& window); 
     52#else 
     53        client(); 
     54#endif 
     55 
    4756        /** Establishes a new client connection to the given host. 
    4857         */ 
     
    5463        virtual ~client(); 
    5564 
     65        virtual void connect(const net6::address& addr); 
     66        virtual void disconnect(); 
     67 
    5668        /** Sends a packet to the server. 
    5769         */ 
     
    6173        virtual void on_send_event(); 
    6274 
    63         main_connection m_ioconn; 
     75        std::auto_ptr<main_connection> m_ioconn; 
     76#ifdef WIN32 
     77        Gtk::Window& m_window; 
     78#endif 
     79private: 
     80        void connect_impl(const net6::address& addr); 
     81        void disconnect_impl(); 
    6482}; 
    6583 
     
    222240        Gtk::Window& m_window; 
    223241#endif 
    224         virtual net_type* new_net(const std::string& host, unsigned int port); 
     242        virtual net_type* new_net(); 
    225243}; 
    226244 
  • inc/joinprogressdialog.hpp

    r230eee4 r5f1602e  
    3636                           const Glib::ustring& username, 
    3737                           const Gdk::Color& color); 
    38         ~JoinProgressDialog(); 
    3938 
    4039        /** Never call this function twice because the auto_ptr of the 
     
    4544 
    4645private: 
    47         virtual bool on_idle(); 
    48  
    49         virtual void on_thread(); 
     46        virtual void on_thread(Thread& thread); 
    5047        virtual void on_done(); 
    5148 
     
    6966        Gdk::Color m_color; 
    7067 
     68        Glib::ustring m_error; 
     69 
    7170        std::auto_ptr<obby::client_buffer> m_buffer; 
     71 
     72        // Got done signal from connection thread 
     73        bool m_got_done; 
     74        // Got welcome packet 
     75        bool m_got_welcome; 
    7276}; 
    7377 
  • inc/progressdialog.hpp

    r230eee4 r5f1602e  
    3030{ 
    3131public: 
     32        class Thread 
     33        { 
     34        public: 
     35                typedef sigc::slot<void, Thread&> entry_slot; 
     36 
     37                Thread(); 
     38                ~Thread(); 
     39 
     40                void launch(const entry_slot& entry_func); 
     41 
     42                /** Tells the thread to quit as soon as possible. This happens 
     43                 * if the user closed the dialog without waiting for the data 
     44                 * the thread is computing. This means that the user wants to 
     45                 * abort the operation. 
     46                 */ 
     47                void quit(); 
     48 
     49                /** Returns TRUE if the thread has to quit. This may be used 
     50                 * by the thread's entry point to determinate whether to go on 
     51                 * computing some data or whether to return. 
     52                 */ 
     53                bool quitting(); 
     54 
     55                /** Makes sure that the calling thread is this worker thread. 
     56                 */ 
     57                void assert_running() const; 
     58 
     59                /** Locks the thread's mutex. The thread itself must do this 
     60                 * while requesting any data from the dialog object because the 
     61                 * dialog may get destroyed if the user closes the dialog 
     62                 * while the thread is still working. 
     63                 */ 
     64                void lock(); 
     65 
     66                /** Unlocks the mutex mentioned above. 
     67                 */ 
     68                void unlock(); 
     69 
     70                Glib::Dispatcher& done_event(); 
     71                Glib::Dispatcher& work_event(); 
     72 
     73        protected: 
     74                Glib::Mutex m_mutex; 
     75                Glib::Thread* m_thread; 
     76                entry_slot m_entry_func; 
     77                Glib::Dispatcher m_disp_done; 
     78                Glib::Dispatcher m_disp_work; 
     79                bool m_quit; 
     80        private: 
     81                void on_thread_entry(); 
     82        }; 
     83 
    3284        ProgressDialog(const Glib::ustring& title, Gtk::Window& parent); 
    33         ~ProgressDialog(); 
     85        virtual ~ProgressDialog(); 
    3486 
    3587        void set_status_text(const Glib::ustring& text); 
    3688        void set_progress_fraction(double progress); 
    3789        void progress_pulse(); 
     90protected: 
     91        /** Emits the work dispatcher of the thread to tell the main thread 
     92         * that the thread has not hung up or something. 
     93         * @param thread Thread whose mutex to lock. We cannot just use 
     94         * m_thread because the dialog may already be destroyed. 
     95         */ 
     96        void work(Thread& thread); 
    3897 
    39         void work(); 
    40 protected: 
    41         virtual void on_thread(); 
     98        /** Locks the thread's mutex (as mentioned above) and throws 
     99         * Glib::Thread::Exit if the thread's quitting flag has been set. 
     100         * This causes the worker thread to exit if the dialog has been closed. 
     101         */ 
     102        void lock(Thread& thread); 
     103 
     104        /** Unlocks the thread's mutex. 
     105         */ 
     106        void unlock(Thread& thread); 
     107 
     108        virtual void on_thread(Thread& thread) = 0; 
    42109 
    43110        virtual void on_work(); 
     
    49116        Gtk::ProgressBar m_progress; 
    50117 
    51         Glib::Thread* m_thread; 
    52  
    53         Glib::Dispatcher m_disp_work; 
    54         Glib::Dispatcher m_disp_done; 
     118        Thread* m_thread; 
    55119 
    56120        Gtk::Window& m_parent; 
    57121 
    58         int m_quit; 
    59         virtual bool on_idle(); 
    60122private: 
    61         void thread_entry(); 
     123        bool on_idle(); 
    62124}; 
    63125 
  • src/hostprogressdialog.cpp

    r2fe47ae r5f1602e  
    3333} 
    3434 
    35 Gobby::HostProgressDialog::~HostProgressDialog() 
    36 { 
    37 } 
    38  
    3935std::auto_ptr<obby::host_buffer> Gobby::HostProgressDialog::get_buffer() 
    4036{ 
     
    4238} 
    4339 
    44 void Gobby::HostProgressDialog::on_thread() 
     40void Gobby::HostProgressDialog::on_thread(Thread& thread) 
    4541{ 
    46         // Get color components 
     42        // Lock the thread while retrieving data from the dialog because the 
     43        // dialog may no longer exist. 
     44        lock(thread); 
     45 
     46        // Put data that is stored with the dialog onto the stack to be 
     47        // allowed to use it without having locked the thread. 
     48#ifdef WIN32 
     49        Gtk::Window& parent = m_parent; // Parent window 
     50#endif 
     51        Glib::ustring username = m_username; // Local user name 
     52        unsigned int port = m_port; // Port to open the server on 
     53 
     54        // Local user colour 
    4755        unsigned int red = m_color.get_red() * 255 / 65535; 
    4856        unsigned int green = m_color.get_green() * 255 / 65535; 
    4957        unsigned int blue = m_color.get_blue() * 255 / 65535; 
    5058 
     59        // Dialog may now be closed 
     60        unlock(thread); 
     61 
     62        std::auto_ptr<obby::host_buffer> buffer; // Resulting obby buffer 
     63        Glib::ustring error; // Error message 
     64 
     65        // Try to open the server. 
    5166        try 
    5267        { 
    53                 // Create buffer 
    54                 m_buffer.reset( 
     68                // Create buffer, compute RSA key and stuff 
     69                buffer.reset( 
    5570                        new obby::io::host_buffer( 
    5671#ifdef WIN32 
    57                                 m_parent, 
     72                                parent, 
    5873#endif 
    59                                 m_username, 
    60                                 red, green, blue 
     74                                username, red, green, blue 
    6175                        ) 
    6276                ); 
    6377 
    64                 //set_status_text("Creating session..."); 
     78                work(thread); 
    6579 
    66                 m_buffer->open(m_port); 
     80                // Open the server on the given port 
     81                buffer->open(port); 
    6782        } 
    6883        catch(net6::error& e) 
    6984        { 
    7085                // Store error, if one occured 
    71                 m_error = e.what(); 
     86                error = e.what(); 
    7287        } 
     88 
     89        // Regain lock 
     90        lock(thread); 
     91        // Set resulting buffer 
     92        m_buffer = buffer; 
     93        // ... and error, if any 
     94        m_error = error; 
     95        // Unlock before exiting 
     96        unlock(thread); 
     97 
     98        // Resulting data has been transmitted, thread may exit 
    7399} 
    74100 
     
    81107void Gobby::HostProgressDialog::on_done() 
    82108{ 
    83         // Call base function (which joins the thread) 
     109        // Call base function (which removes references to the thread) 
    84110        ProgressDialog::on_done(); 
    85111 
  • src/io/buffer_wrapper.cpp

    r2fe47ae r5f1602e  
    2222 
    2323#ifdef WIN32 
     24obby::io::client::client(Gtk::Window& window) 
     25#else 
     26obby::io::client::client() 
     27#endif 
     28 : net6::client(), m_ioconn(NULL) 
     29#ifdef WIN32 
     30   , m_window(window) 
     31#endif 
     32{ 
     33} 
     34 
     35#ifdef WIN32 
    2436obby::io::client::client(Gtk::Window& window, const net6::address& addr) 
    2537#else 
    2638obby::io::client::client(const net6::address& addr) 
    2739#endif 
    28  : net6::client(addr), 
    29    m_ioconn( 
    30 #ifdef WIN32 
    31      window, 
    32 #endif 
    33      conn->get_socket(), 
    34  
    35      main_connection::IO_IN | main_connection::IO_ERROR 
    36    ) 
    37 { 
     40 : net6::client(addr), m_ioconn(NULL) 
     41#ifdef WIN32 
     42   , m_window(window) 
     43#endif 
     44{ 
     45        connect_impl(addr); 
    3846} 
    3947 
    4048obby::io::client::~client() 
    4149{ 
     50        if(is_connected() ) 
     51                disconnect_impl(); 
     52} 
     53 
     54void obby::io::client::connect(const net6::address& addr) 
     55{ 
     56        net6::client::connect(addr); 
     57        connect_impl(addr); 
     58} 
     59 
     60void obby::io::client::disconnect() 
     61{ 
     62        disconnect_impl(); 
     63        net6::client::disconnect(); 
    4264} 
    4365 
    4466void obby::io::client::send(const net6::packet& pack) 
    4567{ 
    46         m_ioconn.add_events(main_connection::IO_OUT); 
     68        m_ioconn->add_events(main_connection::IO_OUT); 
    4769        net6::client::send(pack); 
    4870} 
     
    5072void obby::io::client::on_send_event() 
    5173{ 
    52         m_ioconn.remove_events(main_connection::IO_OUT); 
     74        m_ioconn->remove_events(main_connection::IO_OUT); 
    5375        net6::client::on_send_event(); 
     76} 
     77 
     78void obby::io::client::connect_impl(const net6::address& addr) 
     79{ 
     80        m_ioconn.reset( 
     81                new main_connection( 
     82#ifdef WIN32 
     83                        m_window, 
     84#endif 
     85                        conn->get_socket(), 
     86                        main_connection::IO_IN | main_connection::IO_ERROR 
     87                ) 
     88        ); 
     89} 
     90 
     91void obby::io::client::disconnect_impl() 
     92{ 
     93        m_ioconn.reset(NULL); 
    5494} 
    5595 
     
    275315} 
    276316 
    277 obby::io::client_buffer::net_type* 
    278 obby::io::client_buffer::new_net(const std::string& host, unsigned int port) 
    279 { 
    280         net6::ipv4_address addr( 
    281                 net6::ipv4_address::create_from_hostname(host, port) 
    282         ); 
    283  
    284 #ifdef WIN32 
    285         return new net_type(m_window, addr); 
    286 #else 
    287         return new net_type(addr); 
     317obby::io::client_buffer::net_type* obby::io::client_buffer::new_net() 
     318{ 
     319#ifdef WIN32 
     320        return new net_type(m_window); 
     321#else 
     322        return new net_type; 
    288323#endif 
    289324} 
  • src/joinprogressdialog.cpp

    r2fe47ae r5f1602e  
    3131                                              const Gdk::Color& color) 
    3232 : ProgressDialog(_("Joining obby session..."), parent), m_config(config), 
    33    m_hostname(hostname), m_port(port), m_username(username), m_color(color) 
     33   m_hostname(hostname), m_port(port), m_username(username), m_color(color), 
     34   m_got_done(false), m_got_welcome(false) 
    3435{ 
    3536        obby::format_string str("Connecting to %0%..."); 
    3637        str << hostname; 
    3738        set_status_text(str.str() ); 
    38  
    39         m_thread = NULL; 
    40 } 
    41  
    42 Gobby::JoinProgressDialog::~JoinProgressDialog() 
    43 { 
    4439} 
    4540 
     
    4944} 
    5045 
    51 void Gobby::JoinProgressDialog::on_thread() 
    52 { 
    53         /*try 
    54         { 
    55                 m_buffer.reset( 
     46void Gobby::JoinProgressDialog::on_thread(Thread& thread) 
     47{ 
     48        // Get initial data from dialog 
     49        lock(thread); 
     50 
     51#ifdef WIN32 
     52        Gtk::Window& parent = m_parent; 
     53#endif 
     54        // Connection data 
     55        Glib::ustring hostname = m_hostname; // Remote host name 
     56        unsigned int port = m_port; // TCP port number 
     57 
     58        // Dialog may be closed now 
     59        unlock(thread); 
     60 
     61        std::auto_ptr<obby::client_buffer> buffer; // Resulting buffer 
     62        Glib::ustring error; // Error message 
     63 
     64        // Establish connection 
     65        try 
     66        { 
     67                buffer.reset( 
    5668                        new obby::io::client_buffer( 
    5769#ifdef WIN32 
    58                                 m_parent, 
     70                                parent 
    5971#endif 
    60                                 m_hostname, 
    61                                 m_port 
    62                         ) 
    63                 ); 
     72                        ) 
     73                ); 
     74 
     75                // Install signal handlers (notice that these get called within 
     76                // the main thread) 
     77                buffer->welcome_event().connect( 
     78                        sigc::mem_fun(*this, &JoinProgressDialog::on_welcome) ); 
     79 
     80                buffer->login_failed_event().connect( 
     81                        sigc::mem_fun( 
     82                                *this, 
     83                                &JoinProgressDialog::on_login_failed 
     84                        ) 
     85                ); 
     86 
     87                buffer->global_password_event().connect( 
     88                        sigc::mem_fun( 
     89                                *this, 
     90                                &JoinProgressDialog::on_global_password 
     91                        ) 
     92                ); 
     93 
     94                buffer->user_password_event().connect( 
     95                        sigc::mem_fun( 
     96                                *this, 
     97                                &JoinProgressDialog::on_user_password 
     98                        ) 
     99                ); 
     100 
     101                buffer->sync_init_event().connect( 
     102                        sigc::mem_fun( 
     103                                *this, 
     104                                &JoinProgressDialog::on_sync_init 
     105                        ) 
     106                ); 
     107 
     108                buffer->sync_final_event().connect( 
     109                        sigc::mem_fun( 
     110                                *this, 
     111                                &JoinProgressDialog::on_sync_final 
     112                        ) 
     113                ); 
     114 
     115                buffer->close_event().connect( 
     116                        sigc::mem_fun(*this, &JoinProgressDialog::on_close) ); 
     117 
     118                // Establish connection 
     119                buffer->connect(hostname, port); 
    64120        } 
    65121        catch(net6::error& e) 
    66122        { 
    67                 m_error = e.what(); 
    68         }*/ 
     123                // Store error message, if any 
     124                error = e.what(); 
     125        } 
     126 
     127        // Regain lock 
     128        lock(thread); 
     129        // Set resulting buffer 
     130        m_buffer = buffer; 
     131        m_error = error; 
     132        // Unlock before exiting 
     133        unlock(thread); 
     134 
     135        // Thread may finish now 
    69136} 
    70137 
    71138void Gobby::JoinProgressDialog::on_done() 
    72139{ 
    73         // Call base function joining the thread 
    74         //ProgressDialog::on_done(); 
    75  
    76         try 
    77         { 
    78                 // Create buffer 
    79                 m_buffer.reset( 
    80                         new obby::io::client_buffer( 
    81 #ifdef WIN32 
    82                                 m_parent 
    83 #endif 
    84                         ) 
    85                 ); 
    86  
    87                 // Connect to remote host 
    88                 m_buffer->connect(m_hostname, m_port); 
    89         } 
    90         catch(net6::error& e) 
    91         { 
    92                 // Display error 
    93                 display_error(e.what() ); 
    94                 // Return 
     140        ProgressDialog::on_done(); 
     141 
     142        // Did we get an error while connecting? 
     143        if(!m_error.empty() ) 
     144        { 
     145                // Display it 
     146                display_error(m_error); 
     147                // Bad response 
    95148                response(Gtk::RESPONSE_CANCEL); 
    96                 return; 
    97         } 
    98  
    99         m_buffer->welcome_event().connect( 
    100                 sigc::mem_fun(*this, &JoinProgressDialog::on_welcome) ); 
    101         m_buffer->login_failed_event().connect( 
    102                 sigc::mem_fun(*this, &JoinProgressDialog::on_login_failed) ); 
    103         m_buffer->global_password_event().connect( 
    104                 sigc::mem_fun(*this, &JoinProgressDialog::on_global_password) ); 
    105         m_buffer->user_password_event().connect( 
    106                 sigc::mem_fun(*this, &JoinProgressDialog::on_user_password) ); 
    107         m_buffer->sync_init_event().connect( 
    108                 sigc::mem_fun(*this, &JoinProgressDialog::on_sync_init) ); 
    109         m_buffer->sync_final_event().connect( 
    110                 sigc::mem_fun(*this, &JoinProgressDialog::on_sync_final) ); 
    111         m_buffer->close_event().connect( 
    112                 sigc::mem_fun(*this, &JoinProgressDialog::on_close) ); 
    113  
    114         // Wait for welcome packet 
     149        } 
     150 
     151        // Thread has established connection, wait for welcome packet 
    115152        set_status_text(_("Waiting for welcome packet...") ); 
    116153        set_progress_fraction(1.0/4.0); 
     154        m_got_done = true; 
     155 
     156        // on_welcome may be called before on_done is called if the 
     157        // server replies faster then the thread dispatches, this happens 
     158        // especially with connections to localhost. 
     159        // Recall on_welcome in this case now 
     160        if(m_got_welcome) 
     161                on_welcome(); 
    117162} 
    118163 
    119164void Gobby::JoinProgressDialog::on_welcome() 
    120165{ 
     166        m_got_welcome = true; 
     167 
     168        // Do nothing if we have not already got the done signal from the 
     169        // thread. 
     170        if(!m_got_done) 
     171                return; 
     172 
    121173        // TODO: Show key ID to user and allow him to deny connection 
    122174        // Got welcome packet, send login packet now 
     
    200252} 
    201253 
    202 bool Gobby::JoinProgressDialog::on_idle() 
    203 { 
    204         on_done(); 
    205         return false; 
    206 } 
    207  
  • src/progressdialog.cpp

    rab042e6 r5f1602e  
    1717 */ 
    1818 
     19#include <stdexcept> 
    1920#include <gtkmm/stock.h> 
    2021#include <gtkmm/main.h> 
     
    2223#include "progressdialog.hpp" 
    2324 
     25Gobby::ProgressDialog::Thread::Thread() 
     26 : m_thread(NULL), m_quit(false) 
     27{ 
     28} 
     29 
     30Gobby::ProgressDialog::Thread::~Thread() 
     31{ 
     32} 
     33 
     34void Gobby::ProgressDialog::Thread::launch(const entry_slot& entry_func) 
     35{ 
     36        // TODO: sigc::bind to on_thread_entry 
     37        m_entry_func = entry_func; 
     38        m_thread = Glib::Thread::create( 
     39                sigc::mem_fun(*this, &Thread::on_thread_entry), 
     40                false 
     41        ); 
     42} 
     43 
     44void Gobby::ProgressDialog::Thread::quit() 
     45{ 
     46        lock(); 
     47        m_quit = true; 
     48        unlock(); 
     49} 
     50 
     51bool Gobby::ProgressDialog::Thread::quitting() 
     52{ 
     53        return m_quit; 
     54} 
     55 
     56void Gobby::ProgressDialog::Thread::assert_running() const 
     57{ 
     58        if(Glib::Thread::self() != m_thread) 
     59        { 
     60                throw std::logic_error( 
     61                        "Gobby::ProgressDialog::Thread::assert_running" 
     62                ); 
     63        } 
     64} 
     65 
     66void Gobby::ProgressDialog::Thread::lock() 
     67{ 
     68        m_mutex.lock(); 
     69} 
     70 
     71void Gobby::ProgressDialog::Thread::unlock() 
     72{ 
     73        m_mutex.unlock(); 
     74} 
     75 
     76Glib::Dispatcher& Gobby::ProgressDialog::Thread::done_event() 
     77{ 
     78        return m_disp_done; 
     79} 
     80 
     81Glib::Dispatcher& Gobby::ProgressDialog::Thread::work_event() 
     82{ 
     83        return m_disp_work; 
     84} 
     85 
     86void Gobby::ProgressDialog::Thread::on_thread_entry() 
     87{ 
     88        try 
     89        { 
     90                // Call working function 
     91                m_entry_func(*this); 
     92        } 
     93        catch(Glib::Thread::Exit& e) 
     94        { 
     95                // No need to throw e futher, the thread exits anyhow 
     96        } 
     97 
     98        // If the caller told us to quit we remove us silently, otherwise we 
     99        // tell the caller that we have done what we were supposed to. 
     100        if(m_quit) 
     101        { 
     102                // TODO: The dispatcher's destructor writes an odd message to 
     103                // stdout, how to supress it? 
     104                //  - armin, 10-04-2005 
     105                delete this; 
     106        } 
     107        else 
     108        { 
     109                m_thread = NULL; // ??? 
     110                m_disp_done.emit(); 
     111        } 
     112} 
     113 
    24114Gobby::ProgressDialog::ProgressDialog(const Glib::ustring& title, 
    25115                                      Gtk::Window& parent) 
    26116 : Gtk::Dialog(title, parent, true, true),  
    27    m_lbl_state("", Gtk::ALIGN_CENTER), m_parent(parent) 
     117   m_lbl_state("", Gtk::ALIGN_CENTER), m_thread(NULL), 
     118   m_parent(parent) 
    28119{ 
    29120        get_vbox()->pack_start(m_lbl_state, Gtk::PACK_SHRINK); 
     
    38129        Glib::signal_idle().connect( 
    39130                sigc::mem_fun(*this, &ProgressDialog::on_idle) ); 
    40         m_disp_work.connect( 
    41                 sigc::mem_fun(*this, &ProgressDialog::on_work) ); 
    42         m_disp_done.connect( 
    43                 sigc::mem_fun(*this, &ProgressDialog::on_done) ); 
    44131 
    45132        show_all(); 
     
    48135Gobby::ProgressDialog::~ProgressDialog() 
    49136{ 
     137        // Tell the thread to terminate itself when the dialog has been closed 
     138        // before the thread has finsihed. 
     139        if(m_thread != NULL) 
     140                m_thread->quit(); 
    50141} 
    51142 
     
    65156} 
    66157 
    67 void Gobby::ProgressDialog::work() 
    68 { 
    69         m_disp_work.emit(); 
    70 } 
    71  
    72 void Gobby::ProgressDialog::on_thread() 
    73 { 
    74         // Exit thread if we have to quit 
    75         if(g_atomic_int_get(&m_quit) != 0) 
     158void Gobby::ProgressDialog::work(Thread& thread) 
     159{ 
     160        // Make sure that the calling thread is the worker thread 
     161        thread.assert_running(); 
     162        thread.work_event().emit(); 
     163} 
     164 
     165void Gobby::ProgressDialog::lock(Thread& thread) 
     166{ 
     167        // Make sure that the calling thread is the worker thread, the main 
     168        // thread does not have to call this function because it is used by 
     169        // the worker thread before querieng data from the dialog. The only 
     170        // time the main thread is locking the mutex is when the user closes 
     171        // the dialog. 
     172        thread.assert_running(); 
     173 
     174        thread.lock(); 
     175        if(thread.quitting() ) 
     176        { 
     177                // Exit from the thread if the dialog has been destroys, the 
     178                // user is no more interested in what we have done (otherwise, 
     179                // he would not have closed the dialog). 
     180                thread.unlock(); 
    76181                throw Glib::Thread::Exit(); 
     182        } 
     183} 
     184 
     185void Gobby::ProgressDialog::unlock(Thread& thread) 
     186{ 
     187        // Make sure that the calling thread is the worker thread. 
     188        thread.assert_running(); 
     189        thread.unlock(); 
    77190} 
    78191 
     
    83196void Gobby::ProgressDialog::on_done() 
    84197{ 
    85         m_thread->join(); 
     198        // Delete thread on termination 
     199        delete m_thread; 
    86200        m_thread = NULL; 
    87201} 
     
    89203void Gobby::ProgressDialog::on_response(int response_id) 
    90204{ 
    91         // Is the thread working? 
    92         if(m_thread) 
    93         { 
    94                 // Set text 
    95                 m_lbl_state.set_text(_("Waiting for thread to finish...") ); 
    96                 // Show text 
    97                 while(Gtk::Main::events_pending() ) 
    98                         Gtk::Main::iteration(); 
    99                 // Tell thread to quit 
    100                 g_atomic_int_add(&m_quit, 1); 
    101                 // Wait for the thread 
    102                 m_thread->join(); 
     205        // Tell the thread to terminate itself when the dialog has been closed 
     206        // before the thread has finsihed 
     207/*      if(m_thread != NULL) 
     208        { 
     209                m_thread->quit(); 
    103210                m_thread = NULL; 
    104         } 
     211        }*/ 
    105212 
    106213        // Response 
     
    110217bool Gobby::ProgressDialog::on_idle() 
    111218{ 
    112         // Launch the worker thread 
    113         m_quit = 0; 
    114         m_thread = Glib::Thread::create( 
    115                 sigc::mem_fun(*this, &ProgressDialog::thread_entry), 
    116                 true 
    117         ); 
    118  
     219        // Create the worker thread 
     220        m_thread = new Thread(); 
     221 
     222        // Connect dispatchers 
     223        m_thread->done_event().connect( 
     224                sigc::mem_fun(*this, &ProgressDialog::on_done) ); 
     225        m_thread->work_event().connect( 
     226                sigc::mem_fun(*this, &ProgressDialog::on_work) ); 
     227 
     228        // Launch the thread 
     229        m_thread->launch(sigc::mem_fun(*this, &ProgressDialog::on_thread) ); 
    119230        return false; 
    120231} 
    121232 
    122 void Gobby::ProgressDialog::thread_entry() 
    123 { 
    124         on_thread(); 
    125         m_disp_done.emit(); 
    126 } 
    127