diff options
Diffstat (limited to 'graphics/asymptote/picture.cc')
-rw-r--r-- | graphics/asymptote/picture.cc | 292 |
1 files changed, 214 insertions, 78 deletions
diff --git a/graphics/asymptote/picture.cc b/graphics/asymptote/picture.cc index 8ea6e3bf86..8374804aa1 100644 --- a/graphics/asymptote/picture.cc +++ b/graphics/asymptote/picture.cc @@ -16,11 +16,18 @@ #include "drawlayer.h" #include "drawsurface.h" #include "drawpath3.h" +#include "win32helpers.h" -#ifdef __MSDOS__ -#include "sys/cygwin.h" +#if defined(_WIN32) +#include <Windows.h> +#include <shellapi.h> +#include <cstdio> +#define unlink _unlink #endif +#include <thread> +#include <chrono> + using std::ifstream; using std::ofstream; using vm::array; @@ -518,7 +525,15 @@ bool picture::texprocess(const string& texname, const string& outname, string dvipsrc=getSetting<string>("dir"); if(dvipsrc.empty()) dvipsrc=systemDir; dvipsrc += dirsep+"nopapersize.ps"; +#if !defined(_WIN32) setenv("DVIPSRC",dvipsrc.c_str(),1); +#else + auto setEnvResult = SetEnvironmentVariableA("DVIPSRC",dvipsrc.c_str()); + if (!setEnvResult) + { + camp::reportError("Cannot set DVIPSRC environment variable"); + } +#endif string papertype=getSetting<string>("papertype") == "letter" ? "letterSize" : "a4size"; cmd.push_back(getSetting<string>("dvips")); @@ -786,21 +801,44 @@ int picture::epstosvg(const string& epsname, const string& outname, void htmlView(string name) { - mem::vector<string> cmd; - push_command(cmd,getSetting<string>("htmlviewer")); -#ifdef __MSDOS__ - ssize_t size=cygwin_conv_path(CCP_POSIX_TO_WIN_A, - locateFile(name,true).c_str(),NULL,0); - if(size <= 0) return; - char filename[size]; - size=cygwin_conv_path(CCP_POSIX_TO_WIN_A,locateFile(name,true).c_str(), - filename,size); - cmd.push_back("file://"+string(filename)); + string const browser=getSetting<string>("htmlviewer"); + string const htmlFile=locateFile(name, true); + + if (browser.empty()) + { +#if defined(_WIN32) + // for windows, no browser means to use the windows' default + auto const result = reinterpret_cast<INT_PTR>( + ShellExecuteA( + nullptr, + "open", + htmlFile.c_str(), + nullptr, + nullptr, + SW_SHOWNORMAL + )); + // see https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea + if (result <= 32) + { + // error code should be stored in GetLastError + w32::reportAndFailWithLastError( "Cannot open browser for viewing"); + } #else - cmd.push_back(locateFile(name,true)); + reportError("No browser specified; please specify your browser in htmlviewer"); #endif - push_split(cmd,getSetting<string>("htmlviewerOptions")); - System(cmd,2,false); + } + else + { + string const browserOptions= getSetting<string>("htmlviewerOptions"); + mem::vector<string> cmd; + push_command(cmd, browser); + cmd.push_back(htmlFile); + if (browserOptions.empty()) + { + push_split(cmd, browserOptions); + } + System(cmd, 2, false); + } } bool picture::postprocess(const string& prename, const string& outname, @@ -849,23 +887,21 @@ bool picture::postprocess(const string& prename, const string& outname, cmd.push_back("-sOutputFile="+outname); cmd.push_back(prename); status=System(cmd,0,true,"gs","Ghostscript"); - } else if(!svg && !getSetting<bool>("xasy")) { + } else if(!svg && !xasy) { double expand=antialias; if(expand < 2.0) expand=1.0; res *= expand; string s=getSetting<string>("convert"); cmd.push_back(s); - if(s != "convert") - cmd.push_back("convert"); cmd.push_back("-density"); cmd.push_back(String(res)+"x"+String(res)); + cmd.push_back(prename); if(expand == 1.0) cmd.push_back("+antialias"); push_split(cmd,getSetting<string>("convertOptions")); cmd.push_back("-resize"); cmd.push_back(String(100.0/expand)+"%x"); if(outputformat == "jpg") cmd.push_back("-flatten"); - cmd.push_back(prename); cmd.push_back(outputformat+":"+outname); status=System(cmd,0,true,"convert"); } @@ -884,55 +920,127 @@ bool picture::postprocess(const string& prename, const string& outname, bool picture::display(const string& outname, const string& outputformat, bool wait, bool view, bool epsformat) { - int status=0; static mem::map<CONST string,int> pids; - bool View=settings::view() && view; + if (settings::view() && view) + { + int status; - if(View) { - bool pdf=settings::pdf(getSetting<string>("tex")); - bool pdfformat=(pdf && outputformat == "") || outputformat == "pdf"; + bool const pdf=settings::pdf(getSetting<string>("tex")); + bool pdfformat=(pdf && outputformat.empty()) || outputformat == "pdf"; if(epsformat || pdfformat) { // Check to see if there is an existing viewer for this outname. - mem::map<CONST string,int>::iterator p=pids.find(outname); + mem::map<CONST string,int>::iterator const p=pids.find(outname); bool running=(p != pids.end()); - string Viewer=pdfformat ? getSetting<string>("pdfviewer") : - getSetting<string>("psviewer"); + string Viewer= + pdfformat ? + getSetting<string>("pdfviewer") : getSetting<string>("psviewer"); int pid; if(running) { pid=p->second; if(pid) - running=(waitpid(pid, &status, WNOHANG) != pid); + { +#if defined(_WIN32) + running=w32::isProcessRunning(pid); +#else + running= (waitpid(pid, &status, WNOHANG) != pid); +#endif + } } bool pdfreload=pdfformat && getSetting<bool>("pdfreload"); if(running) { +#if defined(_WIN32) + if (pdfreload) + { + reloadPDF(Viewer,outname); + } +#else // win32 does not support reload by sighup // Tell gv/acroread to reread file. - if(Viewer == "gv") kill(pid,SIGHUP); + if(Viewer == "gv") + { + kill(pid,SIGHUP); + } else if(pdfreload) + { reloadPDF(Viewer,outname); + } +#endif } else { - mem::vector<string> cmd; - push_command(cmd,Viewer); - string viewerOptions=getSetting<string>(pdfformat ? - "pdfviewerOptions" : - "psviewerOptions"); - if(!viewerOptions.empty()) - push_split(cmd,viewerOptions); - cmd.push_back(outname); - status=System(cmd,0,wait, - pdfformat ? "pdfviewer" : "psviewer", - pdfformat ? "your PDF viewer" : "your PostScript viewer", - &pid); - if(status != 0) return false; + // start new process + if (Viewer.empty()) + { +#if defined(_WIN32) + // no viewer, use default + + string const fullOutFilePath= locateFile(outname, true); + SHELLEXECUTEINFOA execInfo = {}; + execInfo.cbSize= sizeof(execInfo); + execInfo.hwnd = nullptr; + execInfo.lpVerb= "open"; + execInfo.lpFile= fullOutFilePath.c_str(); + execInfo.lpDirectory = nullptr; + execInfo.nShow= SW_SHOWNORMAL; + execInfo.fMask= SEE_MASK_NOCLOSEPROCESS; + + if (!ShellExecuteExA(&execInfo)) + { + return false; + } + + if (!w32::checkShellExecuteResult(reinterpret_cast<INT_PTR>(execInfo.hInstApp),false)) + { + // see https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-shellexecuteinfoa + return false; + } + + if (execInfo.hProcess!=nullptr) + { + // wait option does not always work, especially if a new process is not created + // for example, if an existing PDF viewer with multiple tabs open is the viewer, + // asymptote thinks no process is being created; + // in this case, treat it as "no wait" + pid=static_cast<int>(GetProcessId(execInfo.hProcess)); + CloseHandle(execInfo.hProcess); + } +#else + cerr << "No viewer specified" << endl; + return false; +#endif + } + else + { + string viewerOptions= getSetting<string>(pdfformat ? "pdfviewerOptions" : "psviewerOptions"); + mem::vector<string> cmd; + + push_command(cmd, Viewer); + if (!viewerOptions.empty()) push_split(cmd, viewerOptions); + cmd.push_back(outname); + + status=System(cmd, + 0, + wait, + pdfformat ? "pdfviewer" : "psviewer", + pdfformat ? "your PDF viewer" : "your PostScript viewer", + &pid); + + if (status != 0) return false; + } if(!wait) pids[outname]=pid; if(pdfreload) { // Work around race conditions in acroread initialization script - usleep(getSetting<Int>("pdfreloaddelay")); - // Only reload if pdf viewer process is already running. - if(waitpid(pid, &status, WNOHANG) == pid) + std::this_thread::sleep_for(std::chrono::microseconds( + getSetting<Int>("pdfreloaddelay") + )); + // Only reload if pdf viewer process is already running +#if defined(_WIN32) + bool processRunning=w32::isProcessRunning(pid); +#else + bool processRunning= waitpid(pid, &status, WNOHANG) == pid; +#endif + if (processRunning) reloadPDF(Viewer,outname); } } @@ -940,16 +1048,39 @@ bool picture::display(const string& outname, const string& outputformat, if(outputformat == "svg" || outputformat == "html") htmlView(outname); else { - mem::vector<string> cmd; - push_command(cmd,getSetting<string>("display")); - cmd.push_back(outname); - string application="your "+outputformat+" viewer"; - status=System(cmd,0,wait,"display",application.c_str()); - if(status != 0) return false; + string displayProgram=getSetting<string>("display"); + if (displayProgram.empty()) + { +#if defined(_WIN32) + + auto const result = reinterpret_cast<INT_PTR>(ShellExecuteA( + nullptr, + "open", + outname.c_str(), nullptr, + nullptr, SW_SHOWNORMAL)); + + if (result <= 32) + { + cerr << "Cannot start display viewer" << endl; + return false; + } +#else + cerr << "No viewer specified; please specify a viewer in 'display' setting" << endl; + return false; +#endif + } + else + { + mem::vector<string> cmd; + push_command(cmd, displayProgram); + cmd.push_back(outname); + string const application= "your " + outputformat + " viewer"; + status= System(cmd, 0, wait, "display", application.c_str()); + if (status != 0) return false; + } } } } - return true; } @@ -1310,26 +1441,7 @@ void picture::render(double size2, const triple& Min, const triple& Max, #endif } -struct Communicate : public gc { - string prefix; - picture* pic; - string format; - double width; - double height; - double angle; - double zoom; - triple m; - triple M; - pair shift; - pair margin; - double *t; - double *background; - size_t nlights; - triple *lights; - double *diffuse; - double *specular; - bool view; -}; +typedef gl::GLRenderArgs Communicate; Communicate com; @@ -1343,16 +1455,15 @@ void glrenderWrapper() endwait(initSignal,initLock); #endif if(allowRender) - glrender(com.prefix,com.pic,com.format,com.width,com.height,com.angle, - com.zoom,com.m,com.M,com.shift,com.margin,com.t,com.background, - com.nlights,com.lights,com.diffuse,com.specular,com.view); + glrender(com); #endif } bool picture::shipout3(const string& prefix, const string& format, double width, double height, double angle, double zoom, const triple& m, const triple& M, const pair& shift, - const pair& margin, double *t, double *background, + const pair& margin, double *t, double *tup, + double *background, size_t nlights, triple *lights, double *diffuse, double *specular, bool view) { @@ -1444,6 +1555,7 @@ bool picture::shipout3(const string& prefix, const string& format, com.shift=shift; com.margin=margin; com.t=t; + com.tup=tup; com.background=background; com.nlights=nlights; com.lights=lights; @@ -1470,6 +1582,7 @@ bool picture::shipout3(const string& prefix, const string& format, pthread_mutex_lock(&readyLock); #endif } else { +#if !defined(_WIN32) int pid=fork(); if(pid == -1) camp::reportError("Cannot fork process"); @@ -1478,13 +1591,36 @@ bool picture::shipout3(const string& prefix, const string& format, waitpid(pid,NULL,interact::interactive && View ? WNOHANG : 0); return true; } +#else +#pragma message("TODO: Check if (1) we need detach-based gl renderer") +#endif } #endif } #if HAVE_LIBGLM - glrender(prefix,pic,outputformat,width,height,angle,zoom,m,M,shift,margin,t, - background,nlights,lights,diffuse,specular,View,oldpid); + gl::GLRenderArgs args; + args.prefix=prefix; + args.pic=pic; + args.format=outputformat; + args.width=width; + args.height=height; + args.angle=angle; + args.zoom=zoom; + args.m=m; + args.M=M; + args.shift=shift; + args.margin=margin; + args.t=t; + args.tup=tup; + args.background=background; + args.nlights=nlights; + args.lights=lights; + args.diffuse=diffuse; + args.specular=specular; + args.view=View; + + glrender(args,oldpid); if(format3d) { string name=buildname(prefix,format); |