cs.cpp
来自「FreeFem++可以生成高质量的有限元网格。可以用于流体力学」· C++ 代码 · 共 804 行 · 第 1/2 页
CPP
804 行
// Integrated Development Environment for FreeFEM++ - Client/Server version// ------------------------------------------------------------------------// Antoine Le Hyaric - LJLL Paris 6 - lehyaric@ann.jussieu.fr - 21/10/04// $Id: cs.cpp,v 1.77 2005/07/15 12:11:48 lehyaric Exp $#ifdef CLIENT#include <FL/x.H>#endif#include <unistd.h>#include <cassert>#include <list>#include <iostream>using namespace std;// Graphical widgets are only needed in the client#ifdef CLIENT#include <FL/Fl_Round_Button.H>#include <FL/Fl_Menu_Bar.H>#include <FL/Fl_File_Chooser.H>#include "editor.hpp"#include "spawn.hpp"#include "images.hpp"#include "draw.hpp"#include "commands.hpp"#ifdef WIN32#include "windres.h"#endif#if defined(__linux__)#include <X11/xpm.h>#endif#include "highlight.hpp"#endif // CLIENT#ifdef SERVER#include "server.hpp"#endif#ifndef NOSOCKETS#include "socket.hpp"#endif#include "../fflib/strversionnumber.hpp"// Client-side// -----------// To display more messages about the client/server dialog on cerr//#define DIALOG_DEBUG#ifdef CLIENT// Takes care of all the bits and pieces of the graphical window when// redrawing the graphics.void flushgraphics(){ Fl::lock(); flushdrawings(); graphics->redraw(); // Graphics toolbar only useful if there is an image! if(drawings.size()!=0) graphicstoolbar->activate(); else graphicstoolbar->deactivate(); graphicstoolbar->redraw(); Fl::unlock(); // awake() is necessary to make the main thread aware that the // window should be updated. Fl::awake();}// Separate thread to communicate with the server through a socketTHREADFUNC(talktoserver,){#ifndef NDEBUG cout<<"client: talktoserver started id="<<talktoserverid<<endl;#endif // Catches many exceptions to prevent the IDE from crashing without // explanation. There should not be any error exit in the whole // IDE client code after the windows are displayed. bool error=false; bool stop=false; try{ // Create socket comunications#ifndef NOSOCKETS newswitchboard();#endif // Spawn a server process once we know that sockets work ok. assert(runserverprocessid==0); runserverprocessid=Thread::Start(runserverprocess,NULL); // Activate job control buttons only when we know what to control Fl::lock(); pausebutton->activate(); stopbutton->activate(); Fl::unlock(); Fl::awake(); freefemthreadcomm.WAIT(); freefemrunning=true; talkingthreadsetup=false; freefemthreadcomm.Free(); // Wait for that server to come online and talk to him only (the // socket code is able to talk to several processes through several // threads at once, but we don't need that yet).#ifndef NOSOCKETS clientsocket=switchboard->Listen();#endif // Past that point, this thread should be treatly humanly // (i.e. not killed) otherwise we risk leaving some semaphores in // a bizarre state. freefemthreadcomm.WAIT(); talkingthreadsetup=true; freefemthreadcomm.Free(); string message;#ifndef NOSOCKETS if(clientsocket.getremotehostname()=="unknown") message="FreeFem++ server connected\n"; else message=string("FreeFem++ server on ") +clientsocket.getremotehostname() +" connected\n";#else message="FreeFem++ server connected\n";#endif //NOSOCKETS Fl::lock(); output->insert(message.c_str()); output->show_insert_position(); messagebar->value("FreeFem++ server running..."); Fl::unlock(); // Loop on all messages sent by the server through the open socket // (this is mainly about drawing graphical objects).#ifdef DIALOG_DEBUG cerr<<"client: starting listening loop"<<endl;#endif // Pause and stop buttons management freefemthreadcomm.WAIT(); stop=freefemstop; freefemthreadcomm.Free(); resetzoomcenter(); bool serverended=false; // Loop waiting for commands coming from the server through a // socket#ifdef NOSOCKETS // If the server does not use sockets, we just wait for it to end freefemserverended.Decr(); freefemserverended.Incr();#else // When not in debug mode, try and reduce the amount of data // exchanged to a minimum. CMD_TYPE cmd; clientsocket>>cmd; while(!clientsocket.ateof() && !stop && !serverended){#ifdef DIALOG_DEBUG cerr<<"client: received command \""<<cmd<<"\""<<endl;#endif // Send the program text to the server when it asks for it. if(cmd==CMD_PROGRAM){#ifdef DIALOG_DEBUG cerr<<"client: sending program text"<<endl;#endif clientsocket<<cmd_program(); clientsocket.writeflush(); } // Detailing all possible graphical commands. The constructor of // each of the graphical objects below is able to read the // object's characteristics from the input socket. else if(cmd==CMD_COLOR){ // Read a color coming from the server. We need to store it // because FreeFem++ sets the color _before_ clearing the // graphics, and clearing the graphics in the client means // using the default color, which is white! color *c=new color; defaultcolor=new color(*c); backdrawings.push_back(c); } else if(cmd==CMD_POINT) backdrawings.push_back(new point); else if(cmd==CMD_LINE) backdrawings.push_back(new line); else if(cmd==CMD_TEXT) backdrawings.push_back(new text); else if(cmd==CMD_PEN) backdrawings.push_back(new pen); else if(cmd==CMD_POLYGON) backdrawings.push_back(new polygon); else if(cmd==CMD_CIRCLE) backdrawings.push_back(new circle); // Graphical queries else if(cmd==CMD_CLEAR) cmd_clear(); else if(cmd==CMD_FLUSH) cmd_flush(); else if(cmd==CMD_LINE_WIDTH){ string s; clientsocket>>s; clientsocket<<cmd_line_width(s); clientsocket.writeflush(); } else if(cmd==CMD_LINE_HEIGHT){ clientsocket<<cmd_line_height(); clientsocket.writeflush(); } else if(cmd==CMD_PAUSE){ cmd_pause(); clientsocket<<CMD_RESUME; clientsocket.writeflush(); } // Printing a message from the server process in the output window else if(cmd==CMD_STDOUT){ string message; clientsocket>>message; cmd_stdout(message); } // Final handshake else if(cmd==CMD_SERVER_DONE){ serverended=true; // Make sure that the server does not exit before we have read // all its output, otherwise we could face a "Connection reset // by peer" error. clientsocket<<"ok"; clientsocket.writeflush(); } else if(cmd==CMD_ERROR){ // Record the error code, just to let the user know string message; clientsocket>>message; throw message; } else{ throw string("Received unknown command from server: \"") +tostring(cmd)+"\""; } // Checks that we don't need to pause or stop (try and refrain // from throwing any exception from here, or we will have to // remember mutex states!) freefempause.Decr(); freefempause.Incr(); freefemthreadcomm.WAIT(); stop=freefemstop; freefemstop=false; freefemthreadcomm.Free(); // Wait for next command from the server if(!serverended) clientsocket>>cmd; }#endif // NOSOCKETS } catch(string explanation){ cmd_error(explanation); error=true; } // User-required stop#ifdef NOSOCKETS fl_alert("FreeFem++: User stop not implemented yet");#else // If we are stopping because the user asked so, we need to close // the socket to let the server know that we are not listening // anymore. // When we close the communication socket, this will in turn provoke // an internal error in the server, which will then shut down. clientsocket.Close(); // WIN32 does not like to close "switchboard" once clientsocket is // closed (strange! aren't they supposed to be different?).#ifndef __MINGW32__ switchboard->Close();#endif switchboard=NULL;#endif // Update IDE to reflect the fact that the computational server is // no more. Fl::lock(); if(error) messagebar->value("FreeFem++ computation ended with an error"); else if(stop) messagebar->value("FreeFem++ killed on request"); else messagebar->value("FreeFem++ computation ended"); // Deactivate job control buttons runbutton->activate(); pausebutton->deactivate(); pausebutton->clear(); stopbutton->deactivate(); freefemthreadcomm.WAIT(); freefemrunning=false; talkingthreadsetup=false; freefemthreadcomm.Free(); Fl::unlock(); Fl::awake(); // When the server is finished, this thread has no reason to carry // on.#ifndef NDEBUG cout<<"client: talktoserver ended id="<<talktoserverid<<endl;#endif talktoserverid=0; return 0;}// Called when the user clicks on the "Run FreeFEM++" button.void startfreefemserver(Fl_Widget*,void*){ // Can only run one server at a time (for the moment) runbutton->deactivate(); // Tell the user what is happening messagebar->value("FreeFem++ server starting..."); // Remove all previous outputs (for simplicity) outputbuffer->remove(0,outputbuffer->length()); // Remove any previous drawings (because it could very well be an // unfinished drawing from a previously killed computation). Call // flushdrawings() twice to empty both the front and the back // buffer. clearlist(drawings); clearlist(backdrawings); graphics->redraw(); // Leave first line blank, because characters are sometimes too high // and they bump into the top edge of the text widget. output->insert("\n"); // Communicates with the server in a different thread, to avoid any // delay in redrawing the windows. assert(talktoserverid==0); talktoserverid=Thread::Start(talktoserver,NULL);}void pausefreefemserver(Fl_Widget*,void*){ // Simply locks a mutex, blocking any reception of data from the socket. freefemthreadcomm.WAIT(); if(freefempaused) freefempause.Incr(); else freefempause.Decr(); freefempaused=!freefempaused; if(freefempaused) messagebar->value("FreeFem++ computation paused"); else messagebar->value("FreeFem++ computation resumed"); freefemthreadcomm.Free();}void stopfreefemserver(Fl_Widget*,void*){ freefemthreadcomm.WAIT(); // How to stop the server depends on what level of setup it has // reached if(talkingthreadsetup){ // Un-pause the server if necessary if(freefempaused) freefempause.Incr(); freefempaused=false; // Just stops the freefem server thread. The socket will be closed // and the server will shut down automatically. freefemstop=true; } else{ // In this situation, the server is not properly started up yet, // we need to kill off everything brutally and get back to a clean // state. mayday(); } freefemthreadcomm.Free();}// Syntax highlighting stylesFl_Text_Display::Style_Table_Entry styletable[]={ {FL_BLACK,FL_COURIER,FL_NORMAL_SIZE}, // A=plain {FL_DARK_GREEN,FL_COURIER_ITALIC,FL_NORMAL_SIZE}, // B=comments {FL_BLACK,FL_COURIER_BOLD,FL_NORMAL_SIZE}, // C=macros {FL_BLUE,FL_COURIER,FL_NORMAL_SIZE}, // D=strings {FL_DARK_GREEN,FL_COURIER_BOLD,FL_NORMAL_SIZE}, // E=parameters {FL_DARK_RED,FL_COURIER_BOLD,FL_NORMAL_SIZE}, // F=types {FL_BLUE,FL_COURIER_BOLD,FL_NORMAL_SIZE}, // G=keywords {FL_DARK_MAGENTA,FL_COURIER_BOLD,FL_NORMAL_SIZE}, // H=globals
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?