wesnoth-cvs-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Wesnoth-cvs-commits] wesnoth ./changelog src/game.cpp src/multiplaye...


From: David White
Subject: [Wesnoth-cvs-commits] wesnoth ./changelog src/game.cpp src/multiplaye...
Date: Thu, 02 Jun 2005 19:10:55 -0400

CVSROOT:        /cvsroot/wesnoth
Module name:    wesnoth
Branch:         
Changes by:     David White <address@hidden>    05/06/02 23:10:55

Modified files:
        .              : changelog 
        src            : game.cpp multiplayer.cpp network.cpp 
                         network.hpp show_dialog.cpp show_dialog.hpp 
                         thread.cpp thread.hpp 

Log message:
        made connecting to a server show a dialog that allows the user to 
cancel, rather than blocking

CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/changelog.diff?tr1=1.704&tr2=1.705&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/game.cpp.diff?tr1=1.246&tr2=1.247&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer.cpp.diff?tr1=1.158&tr2=1.159&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/network.cpp.diff?tr1=1.61&tr2=1.62&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/network.hpp.diff?tr1=1.24&tr2=1.25&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/show_dialog.cpp.diff?tr1=1.130&tr2=1.131&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/show_dialog.hpp.diff?tr1=1.49&tr2=1.50&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/thread.cpp.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/thread.hpp.diff?tr1=1.2&tr2=1.3&r1=text&r2=text

Patches:
Index: wesnoth/changelog
diff -u wesnoth/changelog:1.704 wesnoth/changelog:1.705
--- wesnoth/changelog:1.704     Thu Jun  2 21:10:47 2005
+++ wesnoth/changelog   Thu Jun  2 23:10:55 2005
@@ -1,5 +1,6 @@
 CVS HEAD:
  * user interface improvements:
+   * made connecting to a server show a dialog that allows the user to cancel 
it rather than blocking
    * added hotkey for cycle to previous unit (shift-N) (part of #10703)
    * added hotkey for hold position (shift-space) (patch 3994)
    * made the right Command key on Mac OS X work like the left one
Index: wesnoth/src/game.cpp
diff -u wesnoth/src/game.cpp:1.246 wesnoth/src/game.cpp:1.247
--- wesnoth/src/game.cpp:1.246  Mon May 16 22:44:19 2005
+++ wesnoth/src/game.cpp        Thu Jun  2 23:10:55 2005
@@ -1,4 +1,4 @@
-/* $Id: game.cpp,v 1.246 2005/05/16 22:44:19 ydirson Exp $ */
+/* $Id: game.cpp,v 1.247 2005/06/02 23:10:55 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -46,7 +46,8 @@
 #include "show_dialog.hpp"
 #include "sound.hpp"
 #include "statistics.hpp"
-#include "team.hpp"
+#include "team.hpp"
+#include "thread.hpp"
 #include "titlescreen.hpp"
 #include "util.hpp"
 #include "unit_types.hpp"
@@ -123,7 +124,8 @@
        const char* const * const argv_;
 
        CVideo video_;
-
+
+       const threading::manager thread_manager;
        const font::manager font_manager_;
        const sound::manager sound_manager_;
        const preferences::manager prefs_manager_;
@@ -1008,7 +1010,7 @@
        request_terms.add_child("request_terms");
        network::send_data(request_terms,sock);
        config data;
-       sock = network::receive_data(data,sock,60000);
+       sock = network::receive_data(data,sock,5000);
        if(!sock) {
                gui::show_error_message(disp(), _("Connection timed out"));
                return;
@@ -1048,7 +1050,7 @@
        std::cerr << "uploading campaign...\n";
        network::send_data(data,sock);
        
-       sock = network::receive_data(data,sock,60000);
+       sock = network::receive_data(data,sock,5000);
        if(!sock) {
                gui::show_error_message(disp(), _("Connection timed out"));
        } else if(data.child("error")) {
@@ -1073,7 +1075,7 @@
 
        network::send_data(data,sock);
 
-       sock = network::receive_data(data,sock,60000);
+       sock = network::receive_data(data,sock,5000);
        if(!sock) {
                gui::show_error_message(disp(), _("Connection timed out"));
        } else if(data.child("error")) {
Index: wesnoth/src/multiplayer.cpp
diff -u wesnoth/src/multiplayer.cpp:1.158 wesnoth/src/multiplayer.cpp:1.159
--- wesnoth/src/multiplayer.cpp:1.158   Wed Apr 27 21:11:44 2005
+++ wesnoth/src/multiplayer.cpp Thu Jun  2 23:10:55 2005
@@ -1,4 +1,4 @@
-/* $Id: multiplayer.cpp,v 1.158 2005/04/27 21:11:44 gruikya Exp $ */
+/* $Id: multiplayer.cpp,v 1.159 2005/06/02 23:10:55 Sirp Exp $ */
 /*
    Copyright (C)
    Part of the Battle for Wesnoth Project http://www.wesnoth.org
@@ -120,7 +120,7 @@
 
        config::child_list redirects;
        config data;
-       sock = network::connect(host, port);
+       sock = gui::network_connect_dialog(disp,_("Connecting to 
Server..."),host,port);
 
        do {
 
@@ -156,8 +156,8 @@
                        shown_hosts.insert(hostpair(host, port));
 
                        if(network::nconnections() > 0)
-                               network::disconnect();
-                       sock = network::connect(host, port);
+                               network::disconnect();
+                       sock = gui::network_connect_dialog(disp,_("Connecting 
to Server..."),host,port);
                        continue;
                }
 
Index: wesnoth/src/network.cpp
diff -u wesnoth/src/network.cpp:1.61 wesnoth/src/network.cpp:1.62
--- wesnoth/src/network.cpp:1.61        Mon May  2 23:48:57 2005
+++ wesnoth/src/network.cpp     Thu Jun  2 23:10:55 2005
@@ -4,7 +4,8 @@
 #include "config.hpp"
 #include "log.hpp"
 #include "network.hpp"
-#include "network_worker.hpp"
+#include "network_worker.hpp"
+#include "thread.hpp"
 #include "util.hpp"
 #include "wassert.hpp"
 
@@ -230,55 +231,117 @@
 {
        return server_socket != 0;
 }
+
+namespace {
+
+class connect_operation : public threading::async_operation
+{
+public:
+       connect_operation(const std::string& host, int port) : host_(host), 
port_(port), error_(NULL), connect_(0)
+       {}
+
+       void check_error();
+       void run();
+
+       network::connection result() const { return connect_; }
+
+private:
+       std::string host_;
+       int port_;
+       const char* error_;
+       network::connection connect_;
+};
+
+void connect_operation::check_error()
+{
+       if(error_ != NULL) {
+               throw error(error_);
+       }
+}
+
+void connect_operation::run()
+{
+       char* const hostname = host_.empty() ? NULL : 
const_cast<char*>(host_.c_str());
+       IPaddress ip;
+       if(SDLNet_ResolveHost(&ip,hostname,port_) == -1) {
+               error_ = "Could not connect to host";
+               return;
+       }
+
+       TCPsocket sock = SDLNet_TCP_Open(&ip);
+       if(!sock) {
+               error_ = hostname == NULL ? "Could not bind to port" :
+                                           "Could not connect to host";
+               return;
+       }
+
+       //if this is a server socket
+       if(hostname == NULL) {
+               const threading::lock l(get_mutex());
+               connect_ = create_connection(sock,"",port_);
+               return;
+       }
+
+       //send data telling the remote host that this is a new connection
+       char buf[4];
+       SDLNet_Write32(0,buf);
+       const int nbytes = SDLNet_TCP_Send(sock,buf,4);
+       if(nbytes != 4) {
+               SDLNet_TCP_Close(sock);
+
+               error_ = "Could not send initial handshake";
+               return;
+       }
+
+       //no blocking operations from here on
+       const threading::lock l(get_mutex());
+       LOG_NW << "sent handshake...\n";
+
+       if(is_aborted()) {
+               LOG_NW << "connect operation aborted by calling thread\n";
+               SDLNet_TCP_Close(sock);
+               return;
+       }
+
+       //allocate this connection a connection handle
+       connect_ = create_connection(sock,host_,port_);
+
+       const int res = SDLNet_TCP_AddSocket(socket_set,sock);
+       if(res == -1) {
+               SDLNet_TCP_Close(sock);
+               error_ = "Could not add socket to socket set";
+               return;
+       }
+
+       waiting_sockets.insert(connect_);
+
+       sockets.push_back(connect_);
+       wassert(schemas.count(connect_) == 0);
+       
schemas.insert(std::pair<network::connection,schema_pair>(connect_,schema_pair()));
+
+       notify_finished();
+}
+
+}
 
 connection connect(const std::string& host, int port)
-{
-       char* const hostname = host.empty() ? 
NULL:const_cast<char*>(host.c_str());
-       IPaddress ip;
-       if(SDLNet_ResolveHost(&ip,hostname,port) == -1) {
-               throw error("Could not connect to host");
-       }
-
-       TCPsocket sock = SDLNet_TCP_Open(&ip);
-       if(!sock) {
-               throw error(hostname == NULL ? "Could not bind to port" :
-                                              "Could not connect to host");
-       } else {
-               //TODO: add code in here which sets the socket to non-blocking
-       }
-
-       //if this is a server socket
-       if(hostname == NULL) {
-               return create_connection(sock,"",port);
-       }
-
-       LOG_NW << "sending handshake...\n";
-       //send data telling the remote host that this is a new connection
-       char buf[4];
-       SDLNet_Write32(0,buf);
-       const int nbytes = SDLNet_TCP_Send(sock,buf,4);
-       if(nbytes != 4) {
-               SDLNet_TCP_Close(sock);
-               throw network::error("Could not send initial handshake");
-       }
-       LOG_NW << "sent handshake...\n";
-
-       //allocate this connection a connection handle
-       const network::connection connect = create_connection(sock,host,port);
-
-       const int res = SDLNet_TCP_AddSocket(socket_set,sock);
-       if(res == -1) {
-               SDLNet_TCP_Close(sock);
-               throw network::error("Could not add socket to socket set");
-       }
-
-       waiting_sockets.insert(connect);
-
-       sockets.push_back(connect);
-       wassert(schemas.count(connect) == 0);
-       
schemas.insert(std::pair<network::connection,schema_pair>(connect,schema_pair()));
-
-       return connect;
+{
+       connect_operation op(host,port);
+       op.run();
+       op.check_error();
+       return op.result();
+}
+
+connection connect(const std::string& host, int port, threading::waiter& 
waiter)
+{
+       connect_operation op(host,port);
+       const connect_operation::RESULT res = op.execute(waiter);
+       if(res == connect_operation::ABORTED) {
+               return 0;
+       }
+
+       op.check_error();
+       return op.result();
 }
 
 connection accept_connection()
Index: wesnoth/src/network.hpp
diff -u wesnoth/src/network.hpp:1.24 wesnoth/src/network.hpp:1.25
--- wesnoth/src/network.hpp:1.24        Thu Mar 10 20:06:20 2005
+++ wesnoth/src/network.hpp     Thu Jun  2 23:10:55 2005
@@ -5,7 +5,12 @@
 
 #include "SDL_net.h"
 
-#include <string>
+#include <string>
+
+namespace threading
+{
+       class waiter;
+}
 
 //this module wraps the network interface.
 
@@ -57,7 +62,9 @@
 //function to attempt to connect to a remote host. Returns
 //the new connection on success, or 0 on failure.
 //throws error.
-connection connect(const std::string& host, int port=15000);
+connection connect(const std::string& host, int port=15000);
+
+connection connect(const std::string& host, int port, threading::waiter& 
waiter);
 
 //function to accept a connection from a remote host. If no
 //host is attempting to connect, it will return 0 immediately.
Index: wesnoth/src/show_dialog.cpp
diff -u wesnoth/src/show_dialog.cpp:1.130 wesnoth/src/show_dialog.cpp:1.131
--- wesnoth/src/show_dialog.cpp:1.130   Tue May 17 22:19:40 2005
+++ wesnoth/src/show_dialog.cpp Thu Jun  2 23:10:55 2005
@@ -1,4 +1,4 @@
-/* $Id: show_dialog.cpp,v 1.130 2005/05/17 22:19:40 ydirson Exp $ */
+/* $Id: show_dialog.cpp,v 1.131 2005/06/02 23:10:55 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -27,7 +27,8 @@
 #include "key.hpp"
 #include "log.hpp"
 #include "playlevel.hpp"
-#include "show_dialog.hpp"
+#include "show_dialog.hpp"
+#include "thread.hpp"
 #include "language.hpp"
 #include "sdl_utils.hpp"
 #include "tooltips.hpp"
@@ -888,6 +889,55 @@
                        return res;
                }
        }
+}
+
+namespace {
+
+class connect_waiter : public threading::waiter
+{
+public:
+       connect_waiter(display& disp, gui::button& button) : disp_(disp), 
button_(button)
+       {}
+       ACTION process();
+
+private:
+       display& disp_;
+       gui::button& button_;
+};
+
+connect_waiter::ACTION connect_waiter::process()
+{
+       events::raise_draw_event();
+       disp_.flip();
+       events::pump();
+       if(button_.pressed()) {
+               return ABORT;
+       } else {
+               return WAIT;
+       }
+}
+
+}
+
+network::connection network_connect_dialog(display& disp, const std::string& 
msg, const std::string& hostname, int port)
+{
+       const size_t width = 250;
+       const size_t height = 20;
+       const size_t border = 20;
+       const int left = disp.x()/2 - width/2;
+       const int top = disp.y()/2 - height/2;
+
+       gui::button cancel_button(disp.video(),_("Cancel"));
+       std::vector<gui::button*> buttons_ptr(1,&cancel_button);
+
+       surface_restorer restorer;
+       
gui::draw_dialog(left,top,width,height,disp.video(),msg,NULL,&buttons_ptr,&restorer);
+
+       events::raise_draw_event();
+       disp.flip();
+
+       connect_waiter waiter(disp,cancel_button);
+       return network::connect(hostname,port,waiter);
 }
 
 } //end namespace gui
Index: wesnoth/src/show_dialog.hpp
diff -u wesnoth/src/show_dialog.hpp:1.49 wesnoth/src/show_dialog.hpp:1.50
--- wesnoth/src/show_dialog.hpp:1.49    Mon May 16 22:44:20 2005
+++ wesnoth/src/show_dialog.hpp Thu Jun  2 23:10:55 2005
@@ -1,4 +1,4 @@
-/* $Id: show_dialog.hpp,v 1.49 2005/05/16 22:44:20 ydirson Exp $ */
+/* $Id: show_dialog.hpp,v 1.50 2005/06/02 23:10:55 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -141,6 +141,7 @@
 void show_error_message(display &disp, std::string const &message);
 
 network::connection network_data_dialog(display& disp, const std::string& msg, 
config& cfg, network::connection connection_num=0);
+network::connection network_connect_dialog(display& disp, const std::string& 
msg, const std::string& hostname, int port);
 
 void check_quit(CVideo &video);
 
Index: wesnoth/src/thread.cpp
diff -u wesnoth/src/thread.cpp:1.4 wesnoth/src/thread.cpp:1.5
--- wesnoth/src/thread.cpp:1.4  Sun Dec  5 19:09:47 2004
+++ wesnoth/src/thread.cpp      Thu Jun  2 23:10:55 2005
@@ -1,8 +1,33 @@
 #include "global.hpp"
 
-#include "thread.hpp"
+#include "thread.hpp"
+
+#include <iostream>
+#include <vector>
+
+namespace {
+
+int run_async_operation(void* data)
+{
+       threading::async_operation* const op = 
reinterpret_cast<threading::async_operation*>(data);
+       op->run();
+       op->notify_finished(); //in case the operation didn't notify of 
finishing
+
+       return 0;
+}
+
+std::vector<SDL_Thread*> detached_threads;
+
+}
 
 namespace threading {
+
+manager::~manager()
+{
+       for(std::vector<SDL_Thread*>::iterator i = detached_threads.begin(); i 
!= detached_threads.end(); ++i) {
+               SDL_WaitThread(*i,NULL);
+       }
+}
 
 thread::thread(int (*f)(void*), void* data) : thread_(SDL_CreateThread(f,data))
 {}
@@ -26,6 +51,12 @@
                SDL_WaitThread(thread_,NULL);
                thread_ = NULL;
        }
+}
+
+void thread::detach()
+{
+       detached_threads.push_back(thread_);
+       thread_ = NULL;
 }
 
 mutex::mutex() : m_(SDL_CreateMutex())
@@ -59,12 +90,16 @@
        return SDL_CondWait(cond_,m.m_) == 0;
 }
 
-#if 0
-bool condition::wait_timeout(const mutex& m, unsigned int timeout)
+condition::WAIT_TIMEOUT_RESULT condition::wait_timeout(const mutex& m, 
unsigned int timeout)
 {
-       return SDL_CondWaitTimeout(cond_,m.m_,timeout) == 0;
+       const int res = SDL_CondWaitTimeout(cond_,m.m_,timeout) == 0;
+       switch(res) {
+       //the SDL documentation appears backward on when these results are 
returned
+       case 0: return WAIT_TIMEOUT;
+       case SDL_MUTEX_TIMEDOUT: return WAIT_OK;
+       default: return WAIT_ERROR;
+       }
 }
-#endif
 
 void condition::notify_one()
 {
@@ -75,5 +110,31 @@
 {
        SDL_CondBroadcast(cond_);
 }
+
+void async_operation::notify_finished()
+{
+       finished_.notify_one();
+}
+
+async_operation::RESULT async_operation::execute(waiter& wait)
+{
+       const lock l(get_mutex());
+       thread t(run_async_operation,this);
+
+       while(wait.process() == waiter::WAIT) {
+               std::cerr << "process...\n";
+               const condition::WAIT_TIMEOUT_RESULT res = 
finished_.wait_timeout(get_mutex(),20);
+               if(res == condition::WAIT_OK) {
+                       return COMPLETED;
+               } else if(res == condition::WAIT_ERROR) {
+                       break;
+               }
+       }
+
+       aborted_ = true;
+       t.detach();
+       return ABORTED;
+}
+
 
 }
Index: wesnoth/src/thread.hpp
diff -u wesnoth/src/thread.hpp:1.2 wesnoth/src/thread.hpp:1.3
--- wesnoth/src/thread.hpp:1.2  Sun Dec  5 19:09:47 2004
+++ wesnoth/src/thread.hpp      Thu Jun  2 23:10:55 2005
@@ -9,7 +9,12 @@
 // This module defines primitives for wrapping C++ around SDL's threading
 // interface
 namespace threading
-{
+{
+
+struct manager
+{
+       ~manager();
+};
 
 // Threading object.
 //
@@ -42,7 +47,9 @@
        // Join (wait) on the thread to finish. When the thread finishes,
        // the function will return. calling wait() on an already killed
        // thread is a no-op.
-       void join();
+       void join();
+
+       void detach();
 private:
        thread(const thread&);
        void operator=(const thread&);
@@ -125,20 +132,19 @@
        //
        // \pre You have already aquired a lock on mutex m
        // 
-       bool wait(const mutex& m);
+       bool wait(const mutex& m);
+
+       enum WAIT_TIMEOUT_RESULT { WAIT_OK, WAIT_TIMEOUT, WAIT_ERROR };
+
        // wait on the condition with a timeout. Basically the same as the
        // wait() function, but if the lock is not aquired before the 
        // timeout, the function returns with an error.
        //
        // \param m the mutex you wish free the lock for. 
        // \param timeout the allowed timeout in milliseconds (ms)
-       // \returns true: success, false: an error occurred
-       //
-       // \todo This function cannot check for timeout, which is to
-       // check on the SDL constant SDL_MUTEX_TIMEDOUT. Thus this 
-       // function cannot check if the error was due to something malformed
-       // or if the time ran out.
-       bool wait_timeout(const mutex& m, unsigned int timeout);
+       // \returns result based on whether condition was met, it timed out,
+       // or there was an error
+       WAIT_TIMEOUT_RESULT wait_timeout(const mutex& m, unsigned int timeout);
        // signal the condition and wake up one thread waiting on the 
        // condition. If no thread is waiting, notify_one() is a no-op.
        // Does not unlock the mutex.
@@ -160,6 +166,46 @@
        void operator=(const condition&);
 
        SDL_cond* const cond_;
+};
+
+class waiter {
+public:
+       enum ACTION { WAIT, ABORT };
+
+       virtual ~waiter() {}
+       virtual ACTION process() = 0;
+};
+
+class async_operation
+{
+public:
+
+       enum RESULT { COMPLETED, ABORTED };
+
+       async_operation() : aborted_(false) {}
+       virtual ~async_operation() {}
+
+       RESULT execute(waiter& wait);
+
+       mutex& get_mutex() { return mutex_; }
+
+       virtual void run() = 0;
+
+       //notify that the operation is finished. Can be called from within the 
thread
+       //while holding the mutex and after checking is_aborted()
+       //if we want to be sure that if the operation is completed, the caller 
is notified.
+       //will be called in any case after the operation returns
+       void notify_finished();
+
+protected:
+
+       //must hold the mutex before calling this function
+       bool is_aborted() const { return aborted_; }
+
+private:
+       bool aborted_;
+       condition finished_;
+       mutex mutex_;
 };
 
 }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]