--- /dev/null
+/*
+ * $Id: wxt_gui.cpp,v 1.30.2.9 2008/07/29 22:19:05 sfeam Exp $
+ */
+
+/* GNUPLOT - wxt_gui.cpp */
+
+/*[
+ * Copyright 2005,2006 Timothee Lecomte
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the complete modified source code. Modifications are to
+ * be distributed as patches to the released version. Permission to
+ * distribute binaries produced by compiling modified sources is granted,
+ * provided you
+ * 1. distribute the corresponding source modifications from the
+ * released version in the form of a patch file along with the binaries,
+ * 2. add special version identification to distinguish your version
+ * in addition to the base release version number,
+ * 3. provide your name and address as the primary contact for the
+ * support of your modified version, and
+ * 4. retain our contact information in regard to use of the base
+ * software.
+ * Permission to distribute the released version of the source code along
+ * with corresponding source modifications in the form of a patch file is
+ * granted with same provisions 2 through 4 for binary distributions.
+ *
+ * This software is provided "as is" without express or implied warranty
+ * to the extent permitted by applicable law.
+ *
+ *
+ * Alternatively, the contents of this file, apart from one portion
+ * that originates from other gnuplot files and is designated as such,
+ * may be used under the terms of the GNU General Public License
+ * Version 2 or later (the "GPL"), in which case the provisions of GPL
+ * are applicable instead of those above. If you wish to allow
+ * use of your version of the appropriate portion of this file only
+ * under the terms of the GPL and not to allow others to use your version
+ * of this file under the above gnuplot license, indicate your decision
+ * by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL. If you do not
+ * delete the provisions above, a recipient may use your version of this file
+ * under either the GPL or the gnuplot license.
+]*/
+
+/* -----------------------------------------------------
+ * The following code uses the wxWidgets library, which is
+ * distributed under its own licence (derivated from the LGPL).
+ *
+ * You can read it at the following address :
+ * http://www.wxwidgets.org/licence.htm
+ * -----------------------------------------------------*/
+
+/* ------------------------------------------------------
+ * This file implements in C++ the functions which are called by wxt.trm :
+ *
+ * It depends on the generic cairo functions,
+ * declared in gp_cairo.h for all the drawing work.
+ *
+ * Here is the interactive part :
+ * - rescaling according to the window's size,
+ * - mouse support (cursor position, zoom, rotation, ruler, clipboard...),
+ * - a toolbar to give additionnal capabilities (similar to the OS/2 terminal),
+ * - multiple plot windows.
+ *
+ * ------------------------------------------------------*/
+
+/* PORTING NOTES
+ * Since it uses wxWidgets and Cairo routines, this code is mostly cross-platform.
+ * However some details have to be implemented or tweaked for each platform :
+ *
+ * 1) A generic 'image' surface is implemented as the destination surface
+ * for cairo drawing. But for optimal results, cairo should draw to a native
+ * surface corresponding to the graphical system.
+ * Examples :
+ * - a gdkpixmap when compiling for wxGTK (currently disabled because of a bug in CAIRO_OPERATOR_SATURATE),
+ * - a HDC when compiling for wxMSW
+ * - [insert your contribution here !]
+ *
+ * 2) You have to be careful with the gui main loop.
+ * As far as I understand :
+ * Some platforms (Windows ?) require that it is in the main thread.
+ * When compiling for Windows (wxMSW), the text window already implements it, so we
+ * don't have to do it, but wxWidgets still have to be initialized correctly.
+ * When compiling for Unix (wxGTK), we don't have one, so we launch it in a separate thread.
+ * For new platforms, it is necessary to figure out what is necessary.
+ */
+
+
+/* define DEBUG here to have debugging messages in stderr */
+#include "wxt_gui.h"
+
+/* frame icon composed of three icons of different resolutions */
+#include "bitmaps/xpm/icon16x16.xpm"
+#include "bitmaps/xpm/icon32x32.xpm"
+#include "bitmaps/xpm/icon64x64.xpm"
+/* cursors */
+#include "bitmaps/xpm/cross.xpm"
+#include "bitmaps/xpm/right.xpm"
+#include "bitmaps/xpm/rotate.xpm"
+#include "bitmaps/xpm/size.xpm"
+/* Toolbar icons
+ * Those are embedded PNG icons previously converted to an array.
+ * See bitmaps/png/README for details */
+#include "bitmaps/png/clipboard_png.h"
+#include "bitmaps/png/replot_png.h"
+#include "bitmaps/png/grid_png.h"
+#include "bitmaps/png/previouszoom_png.h"
+#include "bitmaps/png/nextzoom_png.h"
+#include "bitmaps/png/autoscale_png.h"
+#include "bitmaps/png/config_png.h"
+#include "bitmaps/png/help_png.h"
+
+/* ---------------------------------------------------------------------------
+ * event tables and other macros for wxWidgets
+ * --------------------------------------------------------------------------*/
+
+/* the event tables connect the wxWidgets events with the functions (event
+ * handlers) which process them. It can be also done at run-time, but for the
+ * simple menu events like this the static method is much simpler.
+ */
+
+BEGIN_EVENT_TABLE( wxtFrame, wxFrame )
+ EVT_COMMAND( wxID_ANY, wxExitLoopEvent, wxtApp::OnExitLoop )
+ EVT_CLOSE( wxtFrame::OnClose )
+ EVT_SIZE( wxtFrame::OnSize )
+ EVT_TOOL( Toolbar_CopyToClipboard, wxtFrame::OnCopy )
+#ifdef USE_MOUSE
+ EVT_TOOL( Toolbar_Replot, wxtFrame::OnReplot )
+ EVT_TOOL( Toolbar_ToggleGrid, wxtFrame::OnToggleGrid )
+ EVT_TOOL( Toolbar_ZoomPrevious, wxtFrame::OnZoomPrevious )
+ EVT_TOOL( Toolbar_ZoomNext, wxtFrame::OnZoomNext )
+ EVT_TOOL( Toolbar_Autoscale, wxtFrame::OnAutoscale )
+#endif /*USE_MOUSE*/
+ EVT_TOOL( Toolbar_Config, wxtFrame::OnConfig )
+ EVT_TOOL( Toolbar_Help, wxtFrame::OnHelp )
+END_EVENT_TABLE()
+
+BEGIN_EVENT_TABLE( wxtPanel, wxPanel )
+ EVT_PAINT( wxtPanel::OnPaint )
+ EVT_ERASE_BACKGROUND( wxtPanel::OnEraseBackground )
+ EVT_SIZE( wxtPanel::OnSize )
+#ifdef USE_MOUSE
+ EVT_MOTION( wxtPanel::OnMotion )
+ EVT_LEFT_DOWN( wxtPanel::OnLeftDown )
+ EVT_LEFT_UP( wxtPanel::OnLeftUp )
+ EVT_MIDDLE_DOWN( wxtPanel::OnMiddleDown )
+ EVT_MIDDLE_UP( wxtPanel::OnMiddleUp )
+ EVT_RIGHT_DOWN( wxtPanel::OnRightDown )
+ EVT_RIGHT_UP( wxtPanel::OnRightUp )
+ EVT_CHAR( wxtPanel::OnKeyDownChar )
+#endif /*USE_MOUSE*/
+END_EVENT_TABLE()
+
+BEGIN_EVENT_TABLE( wxtConfigDialog, wxDialog )
+ EVT_CLOSE( wxtConfigDialog::OnClose )
+ EVT_CHOICE( Config_Rendering, wxtConfigDialog::OnRendering )
+ EVT_COMMAND_RANGE( Config_OK, Config_CANCEL,
+ wxEVT_COMMAND_BUTTON_CLICKED, wxtConfigDialog::OnButton )
+END_EVENT_TABLE()
+
+
+#if defined(__WXGTK__)||defined(__WXMAC__)
+/* ----------------------------------------------------------------------------
+ * gui thread
+ * ----------------------------------------------------------------------------*/
+
+/* What really happens in the thread
+ * Just before it returns, wxEntry will call a whole bunch of wxWidgets-cleanup functions */
+void *wxtThread::Entry()
+{
+ FPRINTF((stderr,"gui_thread_entry\n"));
+
+ /* don't answer to SIGINT in this thread - avoids LONGJMP problems */
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ /* gui loop */
+ wxTheApp->OnRun();
+
+ /* Workaround for a deadlock when the main thread will Wait() for this one.
+ * This issue comes from the fact that our gui main loop is not in the
+ * main thread as wxWidgets was written for. */
+ wxt_MutexGuiLeave();
+
+ FPRINTF((stderr,"gui_thread_entry finishing\n"));
+ return NULL;
+}
+#elif defined (__WXMSW__)
+/* nothing to do here */
+#else
+# error "Not implemented."
+#endif
+
+
+
+/* ----------------------------------------------------------------------------
+ * `Main program' equivalent: the program execution "starts" here
+ * ----------------------------------------------------------------------------*/
+
+/* Create a new application object */
+IMPLEMENT_APP_NO_MAIN(wxtApp)
+
+bool wxtApp::OnInit()
+{
+ /* Usually wxWidgets apps create their main window here.
+ * However, in the context of multiple plot windows, the same code is written in wxt_init().
+ * So, to avoid duplication of the code, we do only what is strictly necessary.*/
+
+ /* initialize frames icons */
+ icon.AddIcon(wxIcon(icon16x16_xpm));
+ icon.AddIcon(wxIcon(icon32x32_xpm));
+ icon.AddIcon(wxIcon(icon64x64_xpm));
+
+ /* we load the image handlers, needed to copy the plot to clipboard, and to load icons */
+ ::wxInitAllImageHandlers();
+
+#ifdef __WXMSW__
+ /* allow the toolbar to display properly png icons with an alpha channel */
+ wxSystemOptions::SetOption(wxT("msw.remap"), 0);
+#endif /* __WXMSW__ */
+
+ /* load toolbar icons */
+ LoadPngIcon(clipboard_png, sizeof(clipboard_png), 0);
+ LoadPngIcon(replot_png, sizeof(replot_png), 1);
+ LoadPngIcon(grid_png, sizeof(grid_png), 2);
+ LoadPngIcon(previouszoom_png, sizeof(previouszoom_png), 3);
+ LoadPngIcon(nextzoom_png, sizeof(nextzoom_png), 4);
+ LoadPngIcon(autoscale_png, sizeof(autoscale_png), 5);
+ LoadPngIcon(config_png, sizeof(config_png), 6);
+ LoadPngIcon(help_png, sizeof(help_png), 7);
+
+ /* load cursors */
+ LoadCursor(wxt_cursor_cross, cross);
+ LoadCursor(wxt_cursor_right, right);
+ LoadCursor(wxt_cursor_rotate, rotate);
+ LoadCursor(wxt_cursor_size, size);
+
+ /* Initialize the config object */
+ /* application and vendor name are used by wxConfig to construct the name
+ * of the config file/registry key and must be set before the first call
+ * to Get() */
+ SetVendorName(wxT("gnuplot"));
+ SetAppName(wxT("gnuplot-wxt"));
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ /* this will force writing back of the defaults for all values
+ * if they're not present in the config - this can give the user an idea
+ * of all possible settings */
+ pConfig->SetRecordDefaults();
+
+ return true; /* means that process must continue */
+}
+
+/* load an icon from a PNG file embedded as a C array */
+void wxtApp::LoadPngIcon(const unsigned char *embedded_png, int length, int icon_number)
+{
+ wxMemoryInputStream pngstream(embedded_png, length);
+ toolBarBitmaps[icon_number] = new wxBitmap(wxImage(pngstream, wxBITMAP_TYPE_PNG));
+}
+
+/* load a cursor */
+void wxtApp::LoadCursor(wxCursor &cursor, const char* xpm_bits[])
+{
+ int hotspot_x, hotspot_y;
+ wxBitmap cursor_bitmap = wxBitmap(xpm_bits);
+ wxImage cursor_image = cursor_bitmap.ConvertToImage();
+ /* XPM spec : first string is :
+ * width height ncolors charperpixel hotspotx hotspoty */
+ sscanf(xpm_bits[0], "%*d %*d %*d %*d %d %d", &hotspot_x, &hotspot_y);
+ cursor_image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, hotspot_x);
+ cursor_image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, hotspot_y);
+ cursor = wxCursor(cursor_image);
+}
+
+/* cleanup on exit
+ * In a pure wxWidgets app, the returned int is the exit status of the app.
+ * Here it is not used. */
+int wxtApp::OnExit()
+{
+ FPRINTF((stderr,"wxtApp::OnExit\n"));
+ /* clean up: Set() returns the active config object as Get() does, but unlike
+ * Get() it doesn't try to create one if there is none (definitely not what
+ * we want here!) */
+ delete wxConfigBase::Set((wxConfigBase *) NULL);
+ return 0;
+}
+
+/* will gently terminate the gui thread */
+void wxtApp::OnExitLoop( wxCommandEvent& WXUNUSED(event) )
+{
+ FPRINTF((stderr,"wxtApp::OnExitLoop\n"));
+ wxTheApp->ExitMainLoop();
+}
+
+/* ---------------------------------------------------------------------------
+ * Frame : the main windows (one for each plot)
+ * ----------------------------------------------------------------------------*/
+
+/* frame constructor*/
+wxtFrame::wxtFrame( const wxString& title, wxWindowID id, int xpos, int ypos, int width, int height )
+ : wxFrame((wxFrame *)NULL, id, title, wxPoint(xpos,ypos),
+ wxSize(width,height), wxDEFAULT_FRAME_STYLE|wxWANTS_CHARS)
+{
+ FPRINTF((stderr,"wxtFrame constructor\n"));
+
+ /* used to check for panel initialization */
+ panel = NULL;
+
+ /* initialize the state of the configuration dialog */
+ config_displayed = false;
+
+ /* set up the window icon, in several resolutions */
+ SetIcons(icon);
+
+ /* set up the status bar, and fill it with an empty
+ * string. It will be immediately overriden by gnuplot. */
+ CreateStatusBar();
+ SetStatusText( wxT("") );
+
+ /* set up the toolbar */
+ wxToolBar * toolbar = CreateToolBar();
+ /* With wxMSW, default toolbar size is only 16x15. */
+ toolbar->SetToolBitmapSize(wxSize(16,16));
+
+ toolbar->AddTool(Toolbar_CopyToClipboard, wxT("Copy"),
+ *(toolBarBitmaps[0]), wxT("Copy the plot to clipboard"));
+#ifdef USE_MOUSE
+ toolbar->AddSeparator();
+ toolbar->AddTool(Toolbar_Replot, wxT("Replot"),
+ *(toolBarBitmaps[1]), wxT("Replot"));
+ toolbar->AddTool(Toolbar_ToggleGrid, wxT("Toggle grid"),
+ *(toolBarBitmaps[2]),wxNullBitmap,wxITEM_NORMAL, wxT("Toggle grid"));
+ toolbar->AddTool(Toolbar_ZoomPrevious, wxT("Previous zoom"),
+ *(toolBarBitmaps[3]), wxT("Apply the previous zoom settings"));
+ toolbar->AddTool(Toolbar_ZoomNext, wxT("Next zoom"),
+ *(toolBarBitmaps[4]), wxT("Apply the next zoom settings"));
+ toolbar->AddTool(Toolbar_Autoscale, wxT("Autoscale"),
+ *(toolBarBitmaps[5]), wxT("Apply autoscale"));
+#endif /*USE_MOUSE*/
+ toolbar->AddSeparator();
+ toolbar->AddTool(Toolbar_Config, wxT("Terminal configuration"),
+ *(toolBarBitmaps[6]), wxT("Open configuration dialog"));
+ toolbar->AddTool(Toolbar_Help, wxT("Help"),
+ *(toolBarBitmaps[7]), wxT("Open help dialog"));
+ toolbar->Realize();
+
+ FPRINTF((stderr,"wxtFrame constructor 2\n"));
+
+ /* build the panel, which will contain the visible device context */
+ panel = new wxtPanel( this, this->GetId(), this->GetClientSize() );
+
+ /* setting minimum height and width for the window */
+ SetSizeHints(100, 100);
+
+ FPRINTF((stderr,"wxtFrame constructor 3\n"));
+}
+
+
+/* toolbar event : Copy to clipboard
+ * We will copy the panel to a bitmap, using platform-independant wxWidgets functions */
+void wxtFrame::OnCopy( wxCommandEvent& WXUNUSED( event ) )
+{
+ FPRINTF((stderr,"Copy to clipboard\n"));
+ int width = panel->plot.device_xmax, height = panel->plot.device_ymax;
+ wxBitmap cp_bitmap(width,height);
+ wxMemoryDC cp_dc;
+ wxClientDC dc(panel);
+
+ cp_dc.SelectObject(cp_bitmap);
+ cp_dc.Blit(0,0,width,height,&dc,0,0);
+ cp_dc.SelectObject(wxNullBitmap);
+
+ wxTheClipboard->UsePrimarySelection(false);
+ /* SetData clears the clipboard */
+ if ( wxTheClipboard->Open() ) {
+ wxTheClipboard->SetData(new wxBitmapDataObject(cp_bitmap));
+ wxTheClipboard->Close();
+ }
+ wxTheClipboard->Flush();
+}
+
+#ifdef USE_MOUSE
+/* toolbar event : Replot */
+void wxtFrame::OnReplot( wxCommandEvent& WXUNUSED( event ) )
+{
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_keypress, 0, 0, 'e' , 0, this->GetId());
+}
+
+/* toolbar event : Toggle Grid */
+void wxtFrame::OnToggleGrid( wxCommandEvent& WXUNUSED( event ) )
+{
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_keypress, 0, 0, 'g', 0, this->GetId());
+}
+
+/* toolbar event : Previous Zoom in history */
+void wxtFrame::OnZoomPrevious( wxCommandEvent& WXUNUSED( event ) )
+{
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_keypress, 0, 0, 'p', 0, this->GetId());
+}
+
+/* toolbar event : Next Zoom in history */
+void wxtFrame::OnZoomNext( wxCommandEvent& WXUNUSED( event ) )
+{
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_keypress, 0, 0, 'n', 0, this->GetId());
+}
+
+/* toolbar event : Autoscale */
+void wxtFrame::OnAutoscale( wxCommandEvent& WXUNUSED( event ) )
+{
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_keypress, 0, 0, 'a', 0, this->GetId());
+}
+#endif /*USE_MOUSE*/
+
+/* toolbar event : Config */
+void wxtFrame::OnConfig( wxCommandEvent& WXUNUSED( event ) )
+{
+ /* if we have already opened a dialog, just raise it */
+ if (config_displayed) {
+ config_dialog->Raise();
+ return;
+ }
+
+ /* otherwise, open a dialog */
+ config_displayed = true;
+ config_dialog = new wxtConfigDialog(this);
+ config_dialog->Show(true);
+}
+
+
+/* toolbar event : Help */
+void wxtFrame::OnHelp( wxCommandEvent& WXUNUSED( event ) )
+{
+ wxMessageBox( wxString(wxT("You are using an interactive terminal "\
+ "based on wxWidgets for the interface, Cairo "\
+ "for the drawing facilities, and Pango for the text layouts.\n"\
+ "Please note that toolbar icons in the terminal "\
+ "don't reflect the whole range of mousing "\
+ "possibilities in the terminal.\n"\
+ "Hit 'h' in the plot window "\
+ "and a help message for mouse commands "\
+ "will appear in the gnuplot console.\n"\
+ "See also 'help mouse'.\n")),
+ wxT("wxWidgets terminal help"), wxOK | wxICON_INFORMATION, this );
+}
+
+/* called on Close() (menu or window manager) */
+void wxtFrame::OnClose( wxCloseEvent& event )
+{
+ FPRINTF((stderr,"OnClose\n"));
+ if ( event.CanVeto() ) {
+ /* Default behaviour when Quit is clicked, or the window cross X */
+ event.Veto();
+ this->Hide();
+ }
+ else /* Should not happen, but just in case */
+ this->Destroy();
+}
+
+/* when the window is resized,
+ * resize the panel to fit in the frame.
+ * Note : can't simply use "replot", as it doesn't work with multiplot mode */
+void wxtFrame::OnSize( wxSizeEvent& event )
+{
+ FPRINTF((stderr,"frame OnSize\n"));
+
+ /* Under Windows the frame receives an OnSize event before being completely initialized.
+ * So we must check for the panel to be properly initialized before.*/
+ if (panel)
+ panel->SetSize( this->GetClientSize() );
+}
+
+/* ---------------------------------------------------------------------------
+ * Panel : the space used for the plot, between the toolbar and the statusbar
+ * ----------------------------------------------------------------------------*/
+
+/* panel constructor
+ * Note : under Windows, wxDefaultPosition makes the panel hide the toolbar */
+wxtPanel::wxtPanel( wxWindow *parent, wxWindowID id, const wxSize& size )
+ : wxPanel( parent, id, wxPoint(0,0) /*wxDefaultPosition*/, size, wxWANTS_CHARS )
+{
+ FPRINTF((stderr,"panel constructor\n"));
+
+ /* initialisations */
+ gp_cairo_initialize_plot(&plot);
+ GetSize(&(plot.device_xmax),&(plot.device_ymax));
+
+ settings_queued = false;
+
+#ifdef USE_MOUSE
+ mouse_x = 0;
+ mouse_y = 0;
+ wxt_zoombox = false;
+ zoom_x1 = 0;
+ zoom_y1 = 0;
+ zoom_string1 = wxT("");
+ zoom_string2 = wxT("");
+
+ wxt_ruler = false;
+ wxt_ruler_x = 0;
+ wxt_ruler_y = 0;
+
+ modifier_mask = 0;
+#endif /*USE_MOUSE*/
+
+#if defined(GTK_SURFACE)
+ gdkpixmap = NULL;
+#elif defined(__WXMSW__)
+ hdc = NULL;
+ hbm = NULL;
+#else /* IMAGE_SURFACE */
+ cairo_bitmap = NULL;
+ data32 = NULL;
+#endif /* SURFACE */
+
+ FPRINTF((stderr,"panel constructor4\n"));
+
+ /* create the device context to be drawn */
+ wxt_cairo_create_context();
+
+ FPRINTF((stderr,"panel constructor5\n"));
+
+#ifdef IMAGE_SURFACE
+ wxt_cairo_create_bitmap();
+#endif
+ FPRINTF((stderr,"panel constructor6\n"));
+}
+
+
+/* destructor */
+wxtPanel::~wxtPanel()
+{
+ FPRINTF((stderr,"panel destructor\n"));
+ wxt_cairo_free_context();
+
+ /* clear the command list, free the allocated memory */
+ ClearCommandlist();
+}
+
+/* temporary store new settings values to be applied for the next plot */
+void wxtPanel::wxt_settings_queue(TBOOLEAN antialiasing,
+ TBOOLEAN oversampling,
+ int hinting_setting)
+{
+ mutex_queued.Lock();
+ settings_queued = true;
+ antialiasing_queued = antialiasing;
+ oversampling_queued = oversampling;
+ hinting_queued = hinting_setting;
+ mutex_queued.Unlock();
+}
+
+/* apply queued settings */
+void wxtPanel::wxt_settings_apply()
+{
+ mutex_queued.Lock();
+ if (settings_queued) {
+ plot.antialiasing = antialiasing_queued;
+ plot.oversampling = oversampling_queued;
+ plot.hinting = hinting_queued;
+ settings_queued = false;
+ }
+ mutex_queued.Unlock();
+}
+
+/* clear the command list, free the allocated memory */
+void wxtPanel::ClearCommandlist()
+{
+ command_list_mutex.Lock();
+
+ command_list_t::iterator iter; /*declare the iterator*/
+
+ /* run through the list, and free allocated memory */
+ for(iter = command_list.begin(); iter != command_list.end(); ++iter) {
+ if (iter->command == command_enhanced_put_text ||
+ iter->command == command_put_text ||
+ iter->command == command_set_font)
+ delete[] iter->string;
+ if (iter->command == command_filled_polygon)
+ delete[] iter->corners;
+#ifdef WITH_IMAGE
+ if (iter->command == command_image)
+ delete[] iter->image;
+#endif /* WITH_IMAGE */
+ }
+
+ command_list.clear();
+ command_list_mutex.Unlock();
+}
+
+
+/* method called when the panel has to be painted
+ * -> Refresh(), window dragged, dialogs over the window, etc. */
+void wxtPanel::OnPaint( wxPaintEvent &WXUNUSED(event) )
+{
+ /* Constructor of the device context */
+ wxPaintDC dc(this);
+ DrawToDC(dc, GetUpdateRegion());
+}
+
+/* same as OnPaint, but can be directly called by a user function */
+void wxtPanel::Draw()
+{
+ wxClientDC dc(this);
+ wxBufferedDC buffered_dc(&dc, wxSize(plot.device_xmax, plot.device_ymax));
+ wxRegion region(0, 0, plot.device_xmax, plot.device_ymax);
+ DrawToDC(buffered_dc, region);
+}
+
+/* copy the plot to the panel, draw zoombow and ruler needed */
+void wxtPanel::DrawToDC(wxDC &dc, wxRegion ®ion)
+{
+ wxPen tmp_pen;
+
+ /* TODO extend the region mechanism to surfaces other than GTK_SURFACE */
+#ifdef GTK_SURFACE
+ wxRegionIterator upd(region);
+ int vX,vY,vW,vH; /* Dimensions of client area in pixels */
+
+ while (upd) {
+ vX = upd.GetX();
+ vY = upd.GetY();
+ vW = upd.GetW();
+ vH = upd.GetH();
+
+ FPRINTF((stderr,"OnPaint %d,%d,%d,%d\n",vX,vY,vW,vH));
+ /* Repaint this rectangle */
+ if (gdkpixmap)
+ gdk_draw_drawable(dc.GetWindow(),
+ dc.m_penGC,
+ gdkpixmap,
+ vX,vY,
+ vX,vY,
+ vW,vH);
+ ++upd;
+ }
+#elif defined(__WXMSW__)
+ BitBlt((HDC) dc.GetHDC(), 0, 0, plot.device_xmax, plot.device_ymax, hdc, 0, 0, SRCCOPY);
+#else
+ dc.DrawBitmap(*cairo_bitmap, 0, 0, false);
+#endif
+
+ /* fill in gray when the aspect ratio conservation has let empty space in the panel */
+ if (plot.device_xmax*plot.ymax > plot.device_ymax*plot.xmax) {
+ dc.SetPen( *wxTRANSPARENT_PEN );
+ dc.SetBrush( wxBrush( wxT("LIGHT GREY"), wxSOLID ) );
+ dc.DrawRectangle((int) (plot.xmax/plot.oversampling_scale*plot.xscale),
+ 0,
+ plot.device_xmax - (int) (plot.xmax/plot.oversampling_scale*plot.xscale),
+ plot.device_ymax);
+ } else if (plot.device_xmax*plot.ymax < plot.device_ymax*plot.xmax) {
+ dc.SetPen( *wxTRANSPARENT_PEN );
+ dc.SetBrush( wxBrush( wxT("LIGHT GREY"), wxSOLID ) );
+ dc.DrawRectangle(0,
+ (int) (plot.ymax/plot.oversampling_scale*plot.yscale),
+ plot.device_xmax,
+ (int) (plot.device_ymax - plot.ymax/plot.oversampling_scale*plot.yscale));
+ }
+
+#ifdef USE_MOUSE
+ if (wxt_zoombox) {
+ tmp_pen = wxPen(wxT("black"), 1, wxSOLID);
+ tmp_pen.SetCap( wxCAP_ROUND );
+ dc.SetPen( tmp_pen );
+ dc.SetLogicalFunction( wxINVERT );
+ dc.DrawLine( zoom_x1, zoom_y1, mouse_x, zoom_y1 );
+ dc.DrawLine( mouse_x, zoom_y1, mouse_x, mouse_y );
+ dc.DrawLine( mouse_x, mouse_y, zoom_x1, mouse_y );
+ dc.DrawLine( zoom_x1, mouse_y, zoom_x1, zoom_y1 );
+ dc.SetPen( *wxTRANSPARENT_PEN );
+ dc.SetBrush( wxBrush( wxT("LIGHT BLUE"), wxSOLID ) );
+ dc.SetLogicalFunction( wxAND );
+ dc.DrawRectangle( zoom_x1, zoom_y1, mouse_x -zoom_x1, mouse_y -zoom_y1);
+ dc.SetLogicalFunction( wxCOPY );
+
+ dc.SetFont( wxFont( (int) plot.fontsize, wxFONTFAMILY_DEFAULT,
+ wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false,
+ wxString(plot.fontname, wxConvLocal) ) );
+
+ dc.DrawText( zoom_string1.BeforeFirst(wxT('\r')),
+ zoom_x1, zoom_y1 - term->v_char/plot.oversampling_scale);
+ dc.DrawText( zoom_string1.AfterFirst(wxT('\r')),
+ zoom_x1, zoom_y1);
+
+ dc.DrawText( zoom_string2.BeforeFirst(wxT('\r')),
+ mouse_x, mouse_y - term->v_char/plot.oversampling_scale);
+ dc.DrawText( zoom_string2.AfterFirst(wxT('\r')),
+ mouse_x, mouse_y);
+
+ /* if we have to redraw the zoombox, it is with another size,
+ * so it will be issued later and we can disable it now */
+ wxt_zoombox = false;
+ }
+
+ if (wxt_ruler) {
+ tmp_pen = wxPen(wxT("black"), 1, wxSOLID);
+ tmp_pen.SetCap(wxCAP_BUTT);
+ dc.SetPen( tmp_pen );
+ dc.SetLogicalFunction( wxINVERT );
+ dc.CrossHair( (int)wxt_ruler_x, (int)wxt_ruler_y );
+ dc.SetLogicalFunction( wxCOPY );
+ }
+
+ if (wxt_ruler && wxt_ruler_lineto) {
+ tmp_pen = wxPen(wxT("black"), 1, wxSOLID);
+ tmp_pen.SetCap(wxCAP_BUTT);
+ dc.SetPen( tmp_pen );
+ dc.SetLogicalFunction( wxINVERT );
+ dc.DrawLine((int)wxt_ruler_x, (int)wxt_ruler_y, mouse_x, mouse_y);
+ dc.SetLogicalFunction( wxCOPY );
+ }
+#endif /*USE_MOUSE*/
+
+}
+
+/* avoid flickering under win32 */
+void wxtPanel::OnEraseBackground( wxEraseEvent &WXUNUSED(event) )
+{
+}
+
+/* when the window is resized */
+void wxtPanel::OnSize( wxSizeEvent& event )
+{
+ /* don't do anything if term variables are not initialized */
+ if (plot.xmax == 0 || plot.ymax == 0)
+ return;
+
+ /* update window size, and scaling variables */
+ GetSize(&(plot.device_xmax),&(plot.device_ymax));
+
+ double new_xscale, new_yscale;
+
+ new_xscale = ((double) plot.device_xmax)*plot.oversampling_scale/((double) plot.xmax);
+ new_yscale = ((double) plot.device_ymax)*plot.oversampling_scale/((double) plot.ymax);
+
+ /* We will keep the aspect ratio constant */
+ if (new_yscale < new_xscale) {
+ plot.xscale = new_yscale;
+ plot.yscale = new_yscale;
+ } else {
+ plot.xscale = new_xscale;
+ plot.yscale = new_xscale;
+ }
+ FPRINTF((stderr,"panel OnSize %d %d %lf %lf\n",
+ plot.device_xmax, plot.device_ymax, plot.xscale,plot.yscale));
+
+ /* create a new cairo context of the good size */
+ wxt_cairo_create_context();
+ /* redraw the plot with the new scaling */
+ wxt_cairo_refresh();
+}
+
+#ifdef USE_MOUSE
+/* when the mouse is moved over the panel */
+void wxtPanel::OnMotion( wxMouseEvent& event )
+{
+ /* Get and store mouse position for _put_tmp_text() and key events (ruler) */
+ mouse_x = event.GetX();
+ mouse_y = event.GetY();
+
+ UpdateModifiers(event);
+
+ /* update the ruler_lineto thing */
+ if (wxt_ruler && wxt_ruler_lineto)
+ Draw();
+
+ /* informs gnuplot */
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_motion,
+ (int)gnuplot_x( &plot, mouse_x ),
+ (int)gnuplot_y( &plot, mouse_y ),
+ 0, 0, this->GetId());
+}
+
+/* mouse "click" event */
+void wxtPanel::OnLeftDown( wxMouseEvent& event )
+{
+ int x,y;
+ x = (int) gnuplot_x( &plot, event.GetX() );
+ y = (int) gnuplot_y( &plot, event.GetY() );
+
+ UpdateModifiers(event);
+
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_buttonpress, x, y, 1, 0, this->GetId());
+}
+
+/* mouse "click" event */
+void wxtPanel::OnLeftUp( wxMouseEvent& event )
+{
+ int x,y;
+ x = (int) gnuplot_x( &plot, event.GetX() );
+ y = (int) gnuplot_y( &plot, event.GetY() );
+
+ UpdateModifiers(event);
+
+ if ( this->GetId()==wxt_window_number ) {
+ wxt_exec_event(GE_buttonrelease, x, y, 1, (int) left_button_sw.Time(), this->GetId());
+ /* start a watch to send the time elapsed between up and down */
+ left_button_sw.Start();
+ }
+}
+
+/* mouse "click" event */
+void wxtPanel::OnMiddleDown( wxMouseEvent& event )
+{
+ int x,y;
+ x = (int) gnuplot_x( &plot, event.GetX() );
+ y = (int) gnuplot_y( &plot, event.GetY() );
+
+ UpdateModifiers(event);
+
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_buttonpress, x, y, 2, 0, this->GetId());
+}
+
+/* mouse "click" event */
+void wxtPanel::OnMiddleUp( wxMouseEvent& event )
+{
+ int x,y;
+ x = (int) gnuplot_x( &plot, event.GetX() );
+ y = (int) gnuplot_y( &plot, event.GetY() );
+
+ UpdateModifiers(event);
+
+ if ( this->GetId()==wxt_window_number ) {
+ wxt_exec_event(GE_buttonrelease, x, y, 2,
+ (int) middle_button_sw.Time(), this->GetId());
+ /* start a watch to send the time elapsed between up and down */
+ middle_button_sw.Start();
+ }
+}
+
+/* mouse "click" event */
+void wxtPanel::OnRightDown( wxMouseEvent& event )
+{
+ int x,y;
+ x = (int) gnuplot_x( &plot, event.GetX() );
+ y = (int) gnuplot_y( &plot, event.GetY() );
+
+ UpdateModifiers(event);
+
+ if ( this->GetId()==wxt_window_number )
+ wxt_exec_event(GE_buttonpress, x, y, 3, 0, this->GetId());
+}
+
+/* mouse "click" event */
+void wxtPanel::OnRightUp( wxMouseEvent& event )
+{
+ int x,y;
+ x = (int) gnuplot_x( &plot, event.GetX() );
+ y = (int) gnuplot_y( &plot, event.GetY() );
+
+ UpdateModifiers(event);
+
+ if ( this->GetId()==wxt_window_number ) {
+ wxt_exec_event(GE_buttonrelease, x, y, 3, (int) right_button_sw.Time(), this->GetId());
+ /* start a watch to send the time elapsed between up and down */
+ right_button_sw.Start();
+ }
+}
+
+/* the state of the modifiers is checked each time a key is pressed instead of
+ * tracking the press and release events of the modifiers keys, because the
+ * window manager catches some combinations, like ctrl+F1, and thus we do not
+ * receive a release event in this case */
+void wxtPanel::UpdateModifiers( wxMouseEvent& event )
+{
+ int current_modifier_mask = 0;
+
+ /* retrieve current modifier mask from the wxEvent */
+ current_modifier_mask |= (event.AltDown() ? (1<<2) : 0);
+ current_modifier_mask |= (event.ControlDown() ? (1<<1) : 0);
+ current_modifier_mask |= (event.ShiftDown() ? (1) : 0);
+
+ /* update if changed */
+ if (modifier_mask != current_modifier_mask) {
+ modifier_mask = current_modifier_mask;
+ wxt_exec_event(GE_modifier, 0, 0, modifier_mask, 0, this->GetId());
+ }
+}
+
+/* a key has been pressed, modifiers have already been handled.
+ * We receive keycodes here, and we send corresponding events to gnuplot main thread */
+void wxtPanel::OnKeyDownChar( wxKeyEvent &event )
+{
+ int keycode = event.GetKeyCode();
+ int gp_keycode;
+
+ /* this is the same code as in UpdateModifiers(), but the latter method cannot be
+ * used here because wxKeyEvent and wxMouseEvent are different classes, both of them
+ * derive from wxEvent, but wxEvent does not have the necessary AltDown() and friends */
+ int current_modifier_mask = 0;
+
+ /* retrieve current modifier mask from the wxEvent */
+ current_modifier_mask |= (event.AltDown() ? (1<<2) : 0);
+ current_modifier_mask |= (event.ControlDown() ? (1<<1) : 0);
+ current_modifier_mask |= (event.ShiftDown() ? (1) : 0);
+
+ /* update if changed */
+ if (modifier_mask != current_modifier_mask) {
+ modifier_mask = current_modifier_mask;
+ wxt_exec_event(GE_modifier, 0, 0, modifier_mask, 0, this->GetId());
+ }
+
+#define WXK_GPKEYCODE(wxkey,kcode) case wxkey : gp_keycode=kcode; break;
+
+ if (keycode<256) {
+ switch (keycode) {
+ case WXK_SPACE :
+ if ((wxt_ctrl==yes && event.ControlDown())
+ || wxt_ctrl!=yes) {
+ RaiseConsoleWindow();
+ return;
+ } else {
+ gp_keycode = ' ';
+ break;
+ }
+ case 'q' :
+ /* ctrl+q does not send 113 but 17 */
+ /* WARNING : may be the same for other combinations */
+ case 17 :
+ if ((wxt_ctrl==yes && event.ControlDown())
+ || wxt_ctrl!=yes) {
+ /* closes terminal window */
+ this->GetParent()->Close(false);
+ return;
+ } else {
+ gp_keycode = 'q';
+ break;
+ }
+ WXK_GPKEYCODE(WXK_BACK,GP_BackSpace);
+ WXK_GPKEYCODE(WXK_TAB,GP_Tab);
+ WXK_GPKEYCODE(WXK_RETURN,GP_Return);
+ WXK_GPKEYCODE(WXK_ESCAPE,GP_Escape);
+ WXK_GPKEYCODE(WXK_DELETE,GP_Delete);
+ default : gp_keycode = keycode; break; /* exact solution */
+ }
+ } else {
+ switch( keycode ) {
+ WXK_GPKEYCODE(WXK_PAUSE,GP_Pause);
+ WXK_GPKEYCODE(WXK_SCROLL,GP_Scroll_Lock);
+ WXK_GPKEYCODE(WXK_INSERT,GP_Insert);
+ WXK_GPKEYCODE(WXK_HOME,GP_Home);
+ WXK_GPKEYCODE(WXK_LEFT,GP_Left);
+ WXK_GPKEYCODE(WXK_UP,GP_Up);
+ WXK_GPKEYCODE(WXK_RIGHT,GP_Right);
+ WXK_GPKEYCODE(WXK_DOWN,GP_Down);
+ WXK_GPKEYCODE(WXK_PAGEUP,GP_PageUp);
+ WXK_GPKEYCODE(WXK_PAGEDOWN,GP_PageDown);
+ WXK_GPKEYCODE(WXK_END,GP_End);
+ WXK_GPKEYCODE(WXK_NUMPAD_SPACE,GP_KP_Space);
+ WXK_GPKEYCODE(WXK_NUMPAD_TAB,GP_KP_Tab);
+ WXK_GPKEYCODE(WXK_NUMPAD_ENTER,GP_KP_Enter);
+ WXK_GPKEYCODE(WXK_NUMPAD_F1,GP_KP_F1);
+ WXK_GPKEYCODE(WXK_NUMPAD_F2,GP_KP_F2);
+ WXK_GPKEYCODE(WXK_NUMPAD_F3,GP_KP_F3);
+ WXK_GPKEYCODE(WXK_NUMPAD_F4,GP_KP_F4);
+
+ WXK_GPKEYCODE(WXK_NUMPAD_INSERT,GP_KP_Insert);
+ WXK_GPKEYCODE(WXK_NUMPAD_END,GP_KP_End);
+ WXK_GPKEYCODE(WXK_NUMPAD_DOWN,GP_KP_Down);
+ WXK_GPKEYCODE(WXK_NUMPAD_PAGEDOWN,GP_KP_Page_Down);
+ WXK_GPKEYCODE(WXK_NUMPAD_LEFT,GP_KP_Left);
+ WXK_GPKEYCODE(WXK_NUMPAD_BEGIN,GP_KP_Begin);
+ WXK_GPKEYCODE(WXK_NUMPAD_RIGHT,GP_KP_Right);
+ WXK_GPKEYCODE(WXK_NUMPAD_HOME,GP_KP_Home);
+ WXK_GPKEYCODE(WXK_NUMPAD_UP,GP_KP_Up);
+ WXK_GPKEYCODE(WXK_NUMPAD_PAGEUP,GP_KP_Page_Up);
+
+ WXK_GPKEYCODE(WXK_NUMPAD_DELETE,GP_KP_Delete);
+ WXK_GPKEYCODE(WXK_NUMPAD_EQUAL,GP_KP_Equal);
+ WXK_GPKEYCODE(WXK_NUMPAD_MULTIPLY,GP_KP_Multiply);
+ WXK_GPKEYCODE(WXK_NUMPAD_ADD,GP_KP_Add);
+ WXK_GPKEYCODE(WXK_NUMPAD_SEPARATOR,GP_KP_Separator);
+ WXK_GPKEYCODE(WXK_NUMPAD_SUBTRACT,GP_KP_Subtract);
+ WXK_GPKEYCODE(WXK_NUMPAD_DECIMAL,GP_KP_Decimal);
+ WXK_GPKEYCODE(WXK_NUMPAD_DIVIDE,GP_KP_Divide);
+ WXK_GPKEYCODE(WXK_NUMPAD0,GP_KP_0);
+ WXK_GPKEYCODE(WXK_NUMPAD1,GP_KP_1);
+ WXK_GPKEYCODE(WXK_NUMPAD2,GP_KP_2);
+ WXK_GPKEYCODE(WXK_NUMPAD3,GP_KP_3);
+ WXK_GPKEYCODE(WXK_NUMPAD4,GP_KP_4);
+ WXK_GPKEYCODE(WXK_NUMPAD5,GP_KP_5);
+ WXK_GPKEYCODE(WXK_NUMPAD6,GP_KP_6);
+ WXK_GPKEYCODE(WXK_NUMPAD7,GP_KP_7);
+ WXK_GPKEYCODE(WXK_NUMPAD8,GP_KP_8);
+ WXK_GPKEYCODE(WXK_NUMPAD9,GP_KP_9);
+ WXK_GPKEYCODE(WXK_F1,GP_F1);
+ WXK_GPKEYCODE(WXK_F2,GP_F2);
+ WXK_GPKEYCODE(WXK_F3,GP_F3);
+ WXK_GPKEYCODE(WXK_F4,GP_F4);
+ WXK_GPKEYCODE(WXK_F5,GP_F5);
+ WXK_GPKEYCODE(WXK_F6,GP_F6);
+ WXK_GPKEYCODE(WXK_F7,GP_F7);
+ WXK_GPKEYCODE(WXK_F8,GP_F8);
+ WXK_GPKEYCODE(WXK_F9,GP_F9);
+ WXK_GPKEYCODE(WXK_F10,GP_F10);
+ WXK_GPKEYCODE(WXK_F11,GP_F11);
+ WXK_GPKEYCODE(WXK_F12,GP_F12);
+ default : return; /* probably not ideal */
+ }
+ }
+
+ /* only send char events to gnuplot if we are the active window */
+ if ( this->GetId()==wxt_window_number ) {
+ FPRINTF((stderr,"sending char event\n"));
+ wxt_exec_event(GE_keypress, (int) gnuplot_x( &plot, mouse_x ),
+ (int) gnuplot_y( &plot, mouse_y ), gp_keycode, 0, this->GetId());
+ }
+
+ /* The following wxWidgets keycodes are not mapped :
+ * WXK_ALT, WXK_CONTROL, WXK_SHIFT,
+ * WXK_LBUTTON, WXK_RBUTTON, WXK_CANCEL, WXK_MBUTTON,
+ * WXK_CLEAR, WXK_MENU,
+ * WXK_NUMPAD_PRIOR, WXK_NUMPAD_NEXT,
+ * WXK_CAPITAL, WXK_PRIOR, WXK_NEXT, WXK_SELECT,
+ * WXK_PRINT, WXK_EXECUTE, WXK_SNAPSHOT, WXK_HELP,
+ * WXK_MULTIPLY, WXK_ADD, WXK_SEPARATOR, WXK_SUBTRACT,
+ * WXK_DECIMAL, WXK_DIVIDE, WXK_NUMLOCK, WXK_WINDOWS_LEFT,
+ * WXK_WINDOWS_RIGHT, WXK_WINDOWS_MENU, WXK_COMMAND
+ * The following gnuplot keycodes are not mapped :
+ * GP_Linefeed, GP_Clear, GP_Sys_Req, GP_Begin
+ */
+}
+#endif /*USE_MOUSE*/
+
+/* ====license information====
+ * The following code originates from other gnuplot files,
+ * and is not subject to the alternative license statement.
+ */
+
+
+/* FIXME : this code should be deleted, and the feature removed or handled differently,
+ * because it is highly platform-dependant, is not reliable because
+ * of a lot of factors (WINDOWID not set, multiple tabs in gnome-terminal, mechanisms
+ * to prevent focus stealing) and is inconsistent with global bindings mechanism ) */
+void wxtPanel::RaiseConsoleWindow()
+{
+#ifdef USE_GTK
+ char *window_env;
+ unsigned long windowid = 0;
+ /* retrieve XID of gnuplot window */
+ window_env = getenv("WINDOWID");
+ if (window_env)
+ sscanf(window_env, "%lu", &windowid);
+
+ char *ptr = getenv("KONSOLE_DCOP_SESSION"); /* Try KDE's Konsole first. */
+ if (ptr) {
+ /* We are in KDE's Konsole, or in a terminal window detached from a Konsole.
+ * In order to active a tab:
+ * 1. get environmental variable KONSOLE_DCOP_SESSION: it includes konsole id and session name
+ * 2. if
+ * $WINDOWID is defined and it equals
+ * `dcop konsole-3152 konsole-mainwindow#1 getWinID`
+ * (KDE 3.2) or when $WINDOWID is undefined (KDE 3.1), then run commands
+ * dcop konsole-3152 konsole activateSession session-2; \
+ * dcop konsole-3152 konsole-mainwindow#1 raise
+ * Note: by $WINDOWID we mean gnuplot's text console WINDOWID.
+ * Missing: focus is not transferred unless $WINDOWID is defined (should be fixed in KDE 3.2).
+ *
+ * Implementation and tests on KDE 3.1.4: Petr Mikulik.
+ */
+ char *konsole_name = NULL;
+ char *cmd = NULL;
+ /* use 'while' to easily break out (aka catch exception) */
+ while (1) {
+ char *konsole_tab;
+ unsigned long w;
+ FILE *p;
+ ptr = strchr(ptr, '(');
+ /* the string for tab nb 4 looks like 'DCOPRef(konsole-2866, session-4)' */
+ if (!ptr) break;
+ konsole_name = strdup(ptr+1);
+ konsole_tab = strchr(konsole_name, ',');
+ if (!konsole_tab) break;
+ *konsole_tab++ = 0;
+ ptr = strchr(konsole_tab, ')');
+ if (ptr) *ptr = 0;
+ cmd = (char*) malloc(strlen(konsole_name) + strlen(konsole_tab) + 64);
+ sprintf(cmd, "dcop %s konsole-mainwindow#1 getWinID 2>/dev/null", konsole_name);
+ /* is 2>/dev/null portable among various shells? */
+ p = popen(cmd, "r");
+ if (p) {
+ fscanf(p, "%lu", &w);
+ pclose(p);
+ }
+ if (windowid) { /* $WINDOWID is known */
+ if (w != windowid) break;
+ /* `dcop getWinID`==$WINDOWID thus we are running in a window detached from Konsole */
+ } else {
+ windowid = w;
+ /* $WINDOWID has not been known (KDE 3.1), thus set it up */
+ }
+ sprintf(cmd, "dcop %s konsole activateSession %s", konsole_name, konsole_tab);
+ system(cmd);
+ }
+ if (konsole_name) free(konsole_name);
+ if (cmd) free(cmd);
+ }
+ /* now test for GNOME multitab console */
+ /* ... if somebody bothers to implement it ... */
+ /* we are not running in any known (implemented) multitab console */
+
+ if (windowid) {
+ gdk_window_raise(gdk_window_foreign_new(windowid));
+ gdk_window_focus(gdk_window_foreign_new(windowid), GDK_CURRENT_TIME);
+ }
+#endif /* USE_GTK */
+
+#ifdef _Windows
+ /* Make sure the text window is visible: */
+ ShowWindow(textwin.hWndParent, SW_SHOW);
+ /* and activate it (--> Keyboard focus goes there */
+ BringWindowToTop(textwin.hWndParent);
+#endif /* _Windows */
+
+#ifdef OS2
+ /* we assume that the console window is managed by PM, not by a X server */
+ HSWITCH hSwitch = 0;
+ SWCNTRL swGnu;
+ HWND hw;
+ /* get details of command-line window */
+ hSwitch = WinQuerySwitchHandle(0, getpid());
+ WinQuerySwitchEntry(hSwitch, &swGnu);
+ hw = WinQueryWindow(swGnu.hwnd, QW_BOTTOM);
+ WinSetFocus(HWND_DESKTOP, hw);
+ WinSwitchToProgram(hSwitch);
+#endif /* OS2 */
+}
+
+/* ====license information====
+ * End of the non-relicensable portion.
+ */
+
+
+/* ------------------------------------------------------
+ * Configuration dialog
+ * ------------------------------------------------------*/
+
+/* configuration dialog : handler for a close event */
+void wxtConfigDialog::OnClose( wxCloseEvent& WXUNUSED( event ) )
+{
+ wxtFrame *parent = (wxtFrame *) GetParent();
+ parent->config_displayed = false;
+ this->Destroy();
+}
+
+/* configuration dialog : handler for a button event */
+void wxtConfigDialog::OnButton( wxCommandEvent& event )
+{
+ TBOOLEAN antialiasing;
+ TBOOLEAN oversampling;
+
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ Validate();
+ TransferDataFromWindow();
+
+ wxtFrame *parent = (wxtFrame *) GetParent();
+
+ switch (event.GetId()) {
+ case Config_OK :
+ Close(true);
+ /* continue */
+ case Config_APPLY :
+ /* changes are applied immediately */
+ wxt_raise = raise_setting?yes:no;
+ wxt_persist = persist_setting?yes:no;
+ wxt_ctrl = ctrl_setting?yes:no;
+
+ switch (rendering_setting) {
+ case 0 :
+ antialiasing = FALSE;
+ oversampling = FALSE;
+ break;
+ case 1 :
+ antialiasing = TRUE;
+ oversampling = FALSE;
+ break;
+ case 2 :
+ default :
+ antialiasing = TRUE;
+ oversampling = TRUE;
+ break;
+ }
+
+ /* we cannot apply the new settings right away, because it would mess up
+ * the plot in case of a window resize.
+ * Instead, we queue the settings until the next plot. */
+ parent->panel->wxt_settings_queue(antialiasing, oversampling, hinting_setting);
+
+ if (!pConfig->Write(wxT("raise"), raise_setting))
+ wxLogError(wxT("Cannot write raise"));
+ if (!pConfig->Write(wxT("persist"), persist_setting))
+ wxLogError(wxT("Cannot write persist"));
+ if (!pConfig->Write(wxT("ctrl"), ctrl_setting))
+ wxLogError(wxT("Cannot write ctrl"));
+ if (!pConfig->Write(wxT("rendering"), rendering_setting))
+ wxLogError(wxT("Cannot write rendering_setting"));
+ if (!pConfig->Write(wxT("hinting"), hinting_setting))
+ wxLogError(wxT("Cannot write hinting_setting"));
+ break;
+ case Config_CANCEL :
+ default :
+ Close(true);
+ break;
+ }
+}
+
+/* Configuration dialog constructor */
+wxtConfigDialog::wxtConfigDialog(wxWindow* parent)
+ : wxDialog(parent, -1, wxT("Terminal configuration"), wxDefaultPosition, wxDefaultSize,
+ wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
+{
+/* wxStaticBox *sb = new wxStaticBox( this, wxID_ANY, _T("&Explanation"),
+ wxDefaultPosition, wxDefaultSize );
+ wxStaticBoxSizer *wrapping_sizer = new wxStaticBoxSizer( sb, wxVERTICAL );
+ wxStaticText *text1 = new wxStaticText(this, wxID_ANY,
+ wxT("Options remembered between sessions, ")
+ wxT("overriden by `set term wxt <options>`.\n\n"),
+ wxDefaultPosition, wxSize(300, wxDefaultCoord));
+ wrapping_sizer->Add(text1,wxSizerFlags(0).Align(0).Expand().Border(wxALL) );*/
+
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ pConfig->Read(wxT("raise"),&raise_setting);
+ pConfig->Read(wxT("persist"),&persist_setting);
+ pConfig->Read(wxT("ctrl"),&ctrl_setting);
+ pConfig->Read(wxT("rendering"),&rendering_setting);
+ pConfig->Read(wxT("hinting"),&hinting_setting);
+
+ wxCheckBox *check1 = new wxCheckBox (this, wxID_ANY,
+ _T("Put the window at the top of your desktop after each plot (raise)"),
+ wxDefaultPosition, wxDefaultSize, 0, wxGenericValidator(&raise_setting));
+ wxCheckBox *check2 = new wxCheckBox (this, wxID_ANY,
+ _T("Don't quit until all windows are closed (persist)"),
+ wxDefaultPosition, wxDefaultSize, 0, wxGenericValidator(&persist_setting));
+ wxCheckBox *check3 = new wxCheckBox (this, wxID_ANY,
+ _T("Replace 'q' by <ctrl>+'q' and <space> by <ctrl>+<space> (ctrl)"),
+ wxDefaultPosition, wxDefaultSize, 0, wxGenericValidator(&ctrl_setting));
+
+ wxString choices[3];
+ choices[0] = wxT("No antialiasing");
+ choices[1] = wxT("Antialiasing");
+ choices[2] = wxT("Antialiasing and oversampling");
+
+ wxStaticBox *sb2 = new wxStaticBox( this, wxID_ANY,
+ _T("Rendering options (applied to the next plot)"),
+ wxDefaultPosition, wxDefaultSize );
+ wxStaticBoxSizer *box_sizer2 = new wxStaticBoxSizer( sb2, wxVERTICAL );
+
+ wxStaticText *text_rendering = new wxStaticText(this, wxID_ANY,
+ wxT("Rendering method :"));
+ wxChoice *box = new wxChoice (this, Config_Rendering, wxDefaultPosition, wxDefaultSize,
+ 3, choices, 0, wxGenericValidator(&rendering_setting));
+
+ text_hinting = new wxStaticText(this, wxID_ANY,
+ wxT("Hinting (100=full,0=none) :"));
+
+ slider = new wxSlider(this, wxID_ANY, 0, 0, 100,
+ wxDefaultPosition, wxDefaultSize,
+ wxSL_HORIZONTAL|wxSL_LABELS,
+ wxGenericValidator(&hinting_setting));
+
+ if (rendering_setting != 2) {
+ slider->Enable(false);
+ text_hinting->Enable(false);
+ }
+ box_sizer2->Add(text_rendering,wxSizerFlags().Align(0).Border(wxALL));
+ box_sizer2->Add(box,wxSizerFlags().Align(0).Border(wxALL));
+ box_sizer2->Add(text_hinting,wxSizerFlags().Align(0).Expand().Border(wxALL));
+ box_sizer2->Add(slider,wxSizerFlags().Align(0).Expand().Border(wxALL));
+
+ wxBoxSizer *hsizer = new wxBoxSizer( wxHORIZONTAL );
+ hsizer->Add( new wxButton(this, Config_OK, wxT("OK")),
+ wxSizerFlags().Align(0).Expand().Border(wxALL));
+ hsizer->Add( new wxButton(this, Config_APPLY, wxT("Apply")),
+ wxSizerFlags().Align(0).Expand().Border(wxALL));
+ hsizer->Add( new wxButton(this, Config_CANCEL, wxT("Cancel")),
+ wxSizerFlags().Align(0).Expand().Border(wxALL));
+
+ wxBoxSizer *vsizer = new wxBoxSizer( wxVERTICAL );
+ vsizer->Add(check1,wxSizerFlags().Align(0).Expand().Border(wxALL));
+ vsizer->Add(check2,wxSizerFlags().Align(0).Expand().Border(wxALL));
+ vsizer->Add(check3,wxSizerFlags().Align(0).Expand().Border(wxALL));
+ vsizer->Add(box_sizer2,wxSizerFlags().Align(0).Expand().Border(wxALL));
+ /*vsizer->Add(CreateButtonSizer(wxOK|wxCANCEL),wxSizerFlags().Align(0).Expand().Border(wxALL));*/
+ vsizer->Add(hsizer,wxSizerFlags().Align(0).Expand().Border(wxALL));
+
+ /* use the sizer for layout */
+ SetSizer( vsizer );
+ /* set size hints to honour minimum size */
+ vsizer->SetSizeHints( this );
+}
+
+/* enable or disable the hinting slider depending on the selection of the oversampling method */
+void wxtConfigDialog::OnRendering( wxCommandEvent& event )
+{
+ if (event.GetInt() != 2) {
+ slider->Enable(false);
+ text_hinting->Enable(false);
+ } else {
+ slider->Enable(true);
+ text_hinting->Enable(true);
+ }
+}
+
+/* ------------------------------------------------------
+ * functions that are called by gnuplot
+ * ------------------------------------------------------*/
+
+/* "Called once, when the device is first selected."
+ * Is the 'main' function of the terminal. */
+void wxt_init()
+{
+ FPRINTF((stderr,"Init\n"));
+
+ if ( wxt_abort_init ) {
+ fprintf(stderr,"Previous attempt to initialize wxWidgets has failed. Not retrying.\n");
+ return;
+ }
+
+ wxt_sigint_init();
+
+ if ( wxt_status == STATUS_UNINITIALIZED ) {
+ FPRINTF((stderr,"First Init\n"));
+
+#ifdef __WXMSW__
+ /* the following is done in wxEntry() with wxMSW only */
+ wxSetInstance(GetModuleHandle(NULL));
+ wxApp::m_nCmdShow = SW_SHOW;
+#endif
+
+ if (!wxInitialize()) {
+ fprintf(stderr,"Failed to initialize wxWidgets.\n");
+ wxt_abort_init = true;
+ return;
+ }
+
+ /* app initialization */
+ wxTheApp->CallOnInit();
+
+#if defined(__WXGTK__)||defined(__WXMAC__)
+ /* Three commands to create the thread and run it.
+ * We do this at first init only.
+ * If the user sets another terminal and goes back to wxt,
+ * the gui thread is already in action. */
+ thread = new wxtThread();
+ thread->Create();
+ thread->Run();
+#elif defined (__WXMSW__)
+/* nothing to do */
+#else
+# error "Not implemented."
+#endif /*__WXMSW__*/
+
+
+#ifdef USE_MOUSE
+ /* initialize the gnuplot<->terminal event system state */
+ wxt_change_thread_state(RUNNING);
+#endif /*USE_MOUSE*/
+
+ FPRINTF((stderr,"First Init2\n"));
+#ifdef HAVE_LOCALE_H
+ /* when wxGTK is initialised, GTK+ also sets the locale of the program itself;
+ * we must revert it */
+ setlocale(LC_NUMERIC, "C");
+#endif /*have_locale_h*/
+
+ /* register call for "persist" effect and cleanup */
+ GP_ATEXIT(wxt_atexit);
+ }
+
+ wxt_sigint_check();
+
+ /* try to find the requested window in the list of existing ones */
+ wxt_current_window = wxt_findwindowbyid(wxt_window_number);
+
+ /* open a new plot window if it does not exist */
+ if ( wxt_current_window == NULL ) {
+ FPRINTF((stderr,"opening a new plot window\n"));
+
+ wxt_MutexGuiEnter();
+ wxt_window_t window;
+ window.id = wxt_window_number;
+ /* create a new plot window and show it */
+ wxString title;
+ if (strlen(wxt_title))
+ /* NOTE : this assumes that the title is encoded in the locale charset.
+ * This is probably a good assumption, but it is not guaranteed !
+ * May be improved by using gnuplot encoding setting. */
+ title << wxString(wxt_title, wxConvLocal);
+ else
+ title.Printf(wxT("Gnuplot (window id : %d)"), window.id);
+ window.frame = new wxtFrame( title, window.id, 50, 50, 640, 480 );
+ window.frame->Show(true);
+ FPRINTF((stderr,"new plot window opened\n"));
+ /* make the panel able to receive keyboard input */
+ window.frame->panel->SetFocus();
+ /* set the default crosshair cursor */
+ window.frame->panel->SetCursor(wxt_cursor_cross);
+ /* creating the true context (at initialization, it may be a fake one).
+ * Note : the frame must be shown for this to succeed */
+ if (!window.frame->panel->plot.success)
+ window.frame->panel->wxt_cairo_create_context();
+ wxt_MutexGuiLeave();
+ /* store the plot structure in the list and keep shortcuts */
+ wxt_window_list.push_back(window);
+ wxt_current_window = &(wxt_window_list.back());
+ }
+
+ /* initialize helper pointers */
+ wxt_current_panel = wxt_current_window->frame->panel;
+ wxt_current_plot = &(wxt_current_panel->plot);
+ wxt_current_command_list = &(wxt_current_panel->command_list);
+
+ wxt_sigint_check();
+
+ bool raise_setting;
+ bool persist_setting;
+ bool ctrl_setting;
+ int rendering_setting;
+ int hinting_setting;
+
+ /* if needed, restore the setting from the config file/registry keys.
+ * Unset values are set to default reasonable values. */
+ wxConfigBase *pConfig = wxConfigBase::Get();
+
+ if (!pConfig->Read(wxT("raise"), &raise_setting)) {
+ pConfig->Write(wxT("raise"), true);
+ raise_setting = true;
+ }
+ if (wxt_raise==UNSET)
+ wxt_raise = raise_setting?yes:no;
+
+ if (!pConfig->Read(wxT("persist"), &persist_setting))
+ pConfig->Write(wxT("persist"), false);
+
+ if (!pConfig->Read(wxT("ctrl"), &ctrl_setting)) {
+ pConfig->Write(wxT("ctrl"), false);
+ ctrl_setting = false;
+ }
+ if (wxt_ctrl==UNSET)
+ wxt_ctrl = ctrl_setting?yes:no;
+
+ if (!pConfig->Read(wxT("rendering"), &rendering_setting)) {
+ pConfig->Write(wxT("rendering"), 2);
+ rendering_setting = 2;
+ }
+ switch (rendering_setting) {
+ case 0 :
+ wxt_current_plot->antialiasing = FALSE;
+ wxt_current_plot->oversampling = FALSE;
+ break;
+ case 1 :
+ wxt_current_plot->antialiasing = TRUE;
+ wxt_current_plot->oversampling = FALSE;
+ break;
+ case 2 :
+ default :
+ wxt_current_plot->antialiasing = TRUE;
+ wxt_current_plot->oversampling = TRUE;
+ break;
+ }
+
+ if (!pConfig->Read(wxT("hinting"), &hinting_setting)) {
+ pConfig->Write(wxT("hinting"), 100);
+ hinting_setting = 100;
+ }
+ wxt_current_plot->hinting = hinting_setting;
+
+ /* accept the following commands from gnuplot */
+ wxt_status = STATUS_OK;
+ wxt_current_plot->interrupt = FALSE;
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+
+ FPRINTF((stderr,"Init finished \n"));
+}
+
+
+/* "Called just before a plot is going to be displayed."
+ * Should clear the terminal. */
+void wxt_graphics()
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+#ifdef DEBUG
+ /* performance watch - to be removed */
+ sw.Start();
+#endif
+
+ /* The sequence of gnuplot commands is critical as it involves mutexes.
+ * We replace the original interrupt handler with a custom one. */
+ wxt_sigint_init();
+
+ /* update the window scale factor first, cairo needs it */
+ wxt_current_plot->xscale = 1.0;
+ wxt_current_plot->yscale = 1.0;
+
+ /* apply the queued rendering settings */
+ wxt_current_panel->wxt_settings_apply();
+
+ FPRINTF((stderr,"Graphics1\n"));
+
+ wxt_MutexGuiEnter();
+ /* set the transformation matrix of the context, and other details */
+ /* depends on plot->xscale and plot->yscale */
+ gp_cairo_initialize_context(wxt_current_plot);
+
+ /* set or refresh terminal size according to the window size */
+ /* oversampling_scale is updated in gp_cairo_initialize_context */
+ term->xmax = (unsigned int) wxt_current_plot->device_xmax*wxt_current_plot->oversampling_scale;
+ term->ymax = (unsigned int) wxt_current_plot->device_ymax*wxt_current_plot->oversampling_scale;
+ wxt_current_plot->xmax = term->xmax;
+ wxt_current_plot->ymax = term->ymax;
+ /* initialize encoding */
+ wxt_current_plot->encoding = encoding;
+
+ wxt_MutexGuiLeave();
+
+ /* set font details (hchar, vchar, h_tic, v_tic) according to settings */
+ wxt_set_font("");
+
+ /* clear the command list, and free the allocated memory */
+ wxt_current_panel->ClearCommandlist();
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+
+ FPRINTF((stderr,"Graphics time %d xmax %d ymax %d v_char %d h_char %d\n",
+ sw.Time(), term->xmax, term->ymax, term->v_char, term->h_char));
+}
+
+void wxt_text()
+{
+ if (wxt_status != STATUS_OK) {
+#ifdef USE_MOUSE
+ /* Inform gnuplot that we have finished plotting.
+ * This avoids to lose the mouse after a interrupt.
+ * Do this immediately, instead of posting an event which may not be processed. */
+ event_plotdone();
+#endif
+ return;
+ }
+
+ wxt_sigint_init();
+
+ FPRINTF((stderr,"Text0 %d\n", sw.Time())); /*performance watch*/
+
+ /* translates the command list to a bitmap */
+ wxt_MutexGuiEnter();
+ wxt_current_panel->wxt_cairo_refresh();
+ wxt_MutexGuiLeave();
+
+ wxt_sigint_check();
+
+ /* raise the window, conditionnaly to the user choice */
+ wxt_MutexGuiEnter();
+ wxt_raise_window(wxt_current_window,false);
+ wxt_MutexGuiLeave();
+
+ FPRINTF((stderr,"Text2 %d\n", sw.Time())); /*performance watch*/
+
+#ifdef USE_MOUSE
+ /* Inform gnuplot that we have finished plotting */
+ wxt_exec_event(GE_plotdone, 0, 0, 0, 0, wxt_window_number );
+#endif /*USE_MOUSE*/
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+
+ FPRINTF((stderr,"Text finished %d\n", sw.Time())); /*performance watch*/
+}
+
+void wxt_reset()
+{
+ /* sent when gnuplot exits and when the terminal or the output change.*/
+ FPRINTF((stderr,"wxt_reset\n"));
+
+ if (wxt_status == STATUS_UNINITIALIZED)
+ return;
+
+#ifdef USE_MOUSE
+ if (wxt_status == STATUS_INTERRUPT) {
+ /* send "reset" event to restore the mouse system in a well-defined state.
+ * Send it directly, not with wxt_exec_event(), which would only enqueue it,
+ * but not process it. */
+ FPRINTF((stderr,"send reset event to the mouse system\n"));
+ event_reset((gp_event_t *)1); /* cancel zoombox etc. */
+
+ /* clear the event list */
+ wxt_clear_event_list();
+ }
+
+ /* stop sending mouse events */
+ FPRINTF((stderr,"change thread state\n"));
+ wxt_change_thread_state(RUNNING);
+#endif /*USE_MOUSE*/
+
+ FPRINTF((stderr,"wxt_reset ends\n"));
+}
+
+void wxt_move(unsigned int x, unsigned int y)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ gp_command temp_command;
+
+ temp_command.command = command_move;
+ temp_command.x1 = x;
+ temp_command.y1 = term->ymax - y;
+
+ wxt_command_push(temp_command);
+}
+
+void wxt_vector(unsigned int x, unsigned int y)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ gp_command temp_command;
+
+ temp_command.command = command_vector;
+ temp_command.x1 = x;
+ temp_command.y1 = term->ymax - y;
+
+ wxt_command_push(temp_command);
+}
+
+void wxt_put_text(unsigned int x, unsigned int y, const char * string)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ gp_command temp_command;
+
+ /* note : this test must be here, not when processing the command list,
+ * because the user may have toggled the terminal option between two window resizing.*/
+ /* if ignore_enhanced_text is set, draw with the normal routine.
+ * This is meant to avoid enhanced syntax when the enhanced mode is on */
+ if (wxt_enhanced_enabled && !ignore_enhanced_text)
+ temp_command.command = command_enhanced_put_text;
+ else
+ temp_command.command = command_put_text;
+
+ temp_command.x1 = x;
+ temp_command.y1 = term->ymax - y;
+ /* Note : we must take '\0' (EndOfLine) into account */
+ temp_command.string = new char[strlen(string)+1];
+ strcpy(temp_command.string, string);
+
+ wxt_command_push(temp_command);
+}
+
+void wxt_linetype(int lt)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ gp_command temp_command;
+ gp_command temp_command2;
+
+ temp_command.command = command_color;
+ temp_command.color = gp_cairo_linetype2color( lt );
+
+ temp_command2.command = command_linestyle;
+ if (lt == -1)
+ temp_command2.integer_value = GP_CAIRO_DASH;
+ else
+ temp_command2.integer_value = GP_CAIRO_SOLID;
+
+ wxt_command_push(temp_command);
+ wxt_command_push(temp_command2);
+}
+
+
+/* - fonts are selected as strings "name,size".
+ * - _set_font("") restores the terminal's default font.*/
+int wxt_set_font (const char *font)
+{
+ if (wxt_status != STATUS_OK)
+ return 1;
+
+ char fontname[MAX_ID_LEN + 1] = "";
+ gp_command temp_command;
+ int fontsize = 0;
+
+ temp_command.command = command_set_font;
+
+ if (!font || !(*font)) {
+ strncpy(fontname, "", sizeof(fontname));
+ fontsize = 0;
+ } else {
+ int sep;
+
+ sep = strcspn(font,",");
+ if (sep > 0) {
+ strncpy(fontname, font, sep);
+ fontname[sep] = '\0';
+ }
+ if (font[sep] == ',')
+ sscanf(&(font[sep+1]), "%d", &fontsize);
+ }
+
+ wxt_sigint_init();
+ wxt_MutexGuiEnter();
+
+ if ( strlen(fontname) == 0 ) {
+ if ( strlen(wxt_set_fontname) == 0 )
+ strncpy(fontname, "Sans", sizeof(fontname));
+ else
+ strncpy(fontname, wxt_set_fontname, sizeof(fontname));
+ }
+
+ if ( fontsize == 0 ) {
+ if ( wxt_set_fontsize == 0 )
+ fontsize = 10;
+ else
+ fontsize = wxt_set_fontsize;
+ }
+
+
+ /* Reset the term variables (hchar, vchar, h_tic, v_tic).
+ * They may be taken into account in next plot commands */
+ gp_cairo_set_font(wxt_current_plot, fontname, fontsize);
+ gp_cairo_set_termvar(wxt_current_plot);
+ wxt_MutexGuiLeave();
+ wxt_sigint_check();
+ wxt_sigint_restore();
+
+ /* Note : we must take '\0' (EndOfLine) into account */
+ temp_command.string = new char[strlen(fontname)+1];
+ strcpy(temp_command.string, fontname);
+ temp_command.integer_value = fontsize;
+
+ wxt_command_push(temp_command);
+ /* the returned int is not used anywhere */
+ return 1;
+}
+
+
+int wxt_justify_text(enum JUSTIFY mode)
+{
+ if (wxt_status != STATUS_OK)
+ return 1;
+
+ gp_command temp_command;
+
+ temp_command.command = command_justify;
+ temp_command.mode = mode;
+
+ wxt_command_push(temp_command);
+ return 1; /* we can justify */
+}
+
+void wxt_point(unsigned int x, unsigned int y, int pointstyle)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ gp_command temp_command;
+
+ temp_command.command = command_point;
+ temp_command.x1 = x;
+ temp_command.y1 = term->ymax - y;
+ temp_command.integer_value = pointstyle;
+
+ wxt_command_push(temp_command);
+}
+
+void wxt_pointsize(double ptsize)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ /* same behaviour as x11 terminal */
+ if (ptsize<0) ptsize = 1;
+
+ gp_command temp_command;
+ temp_command.command = command_pointsize;
+ temp_command.double_value = ptsize;
+
+ wxt_command_push(temp_command);
+}
+
+void wxt_linewidth(double lw)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ gp_command temp_command;
+
+ temp_command.command = command_linewidth;
+ temp_command.double_value = lw;
+
+ wxt_command_push(temp_command);
+}
+
+int wxt_text_angle(int angle)
+{
+ if (wxt_status != STATUS_OK)
+ return 1;
+
+ gp_command temp_command;
+
+ temp_command.command = command_text_angle;
+ /* a double is needed to compute cos, sin, etc. */
+ temp_command.double_value = (double) angle;
+
+ wxt_command_push(temp_command);
+ return 1; /* 1 means we can rotate */
+}
+
+void wxt_fillbox(int style, unsigned int x, unsigned int y, unsigned int width, unsigned int height)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ gp_command temp_command;
+
+ temp_command.command = command_fillbox;
+ temp_command.x1 = x;
+ temp_command.y1 = term->ymax - y;
+ temp_command.x2 = width;
+ temp_command.y2 = height;
+ temp_command.integer_value = style;
+
+ wxt_command_push(temp_command);
+}
+
+int wxt_make_palette(t_sm_palette * palette)
+{
+ /* we can do continuous colors */
+ return 0;
+}
+
+void wxt_set_color(t_colorspec *colorspec)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ rgb_color rgb1;
+ gp_command temp_command;
+
+ if (colorspec->type == TC_LT) {
+ wxt_linetype(colorspec->lt);
+ return;
+ } else if (colorspec->type == TC_FRAC)
+ rgb1maxcolors_from_gray( colorspec->value, &rgb1 );
+ else if (colorspec->type == TC_RGB) {
+ rgb1.r = (double) ((colorspec->lt >> 16) & 0xff)/255;
+ rgb1.g = (double) ((colorspec->lt >> 8) & 0xff)/255;
+ rgb1.b = (double) ((colorspec->lt) & 0xff)/255;
+ } else return;
+
+ temp_command.command = command_color;
+ temp_command.color = rgb1;
+
+ wxt_command_push(temp_command);
+}
+
+
+/* here we send the polygon command */
+void wxt_filled_polygon(int n, gpiPoint *corners)
+{
+ if (wxt_status != STATUS_OK)
+ return;
+
+ gp_command temp_command;
+
+ temp_command.command = command_filled_polygon;
+ temp_command.integer_value = n;
+ temp_command.corners = new gpiPoint[n];
+ /* can't use memcpy() here, as we have to mirror the y axis */
+ gpiPoint *corners_copy = temp_command.corners;
+ while (corners_copy < (temp_command.corners + n)) {
+ *corners_copy = *corners++;
+ corners_copy->y = term->ymax - corners_copy->y;
+ ++corners_copy;
+ }
+
+ wxt_command_push(temp_command);
+}
+
+#ifdef WITH_IMAGE
+void wxt_image(unsigned M, unsigned N, coordval * image, gpiPoint * corner, t_imagecolor color_mode)
+{
+ /* This routine is to plot a pixel-based image on the display device.
+ 'M' is the number of pixels along the y-dimension of the image and
+ 'N' is the number of pixels along the x-dimension of the image. The
+ coordval pointer 'image' is the pixel values normalized to the range
+ [0:1]. These values should be scaled accordingly for the output
+ device. They 'image' data starts in the upper left corner and scans
+ along rows finishing in the lower right corner. If 'color_mode' is
+ IC_PALETTE, the terminal is to use palette lookup to generate color
+ information. In this scenario the size of 'image' is M*N. If
+ 'color_mode' is IC_RGB, the terminal is to use RGB components. In
+ this scenario the size of 'image' is 3*M*N. The data appears in RGB
+ tripples, i.e., image[0] = R(1,1), image[1] = G(1,1), image[2] =
+ B(1,1), image[3] = R(1,2), image[4] = G(1,2), ..., image[3*M*N-1] =
+ B(M,N). The 'image' is actually an "input" image in the sense that
+ it must also be properly resampled for the output device. Many output
+ mediums, e.g., PostScript, do this work via various driver functions.
+ To determine the appropriate rescaling, the 'corner' information
+ should be used. There are four entries in the gpiPoint data array.
+ 'corner[0]' is the upper left corner (in terms of plot location) of
+ the outer edge of the image. Similarly, 'corner[1]' is the lower
+ right corner of the outer edge of the image. (Outer edge means the
+ outer extent of the corner pixels, not the middle of the corner
+ pixels.) 'corner[2]' is the upper left corner of the visible part
+ of the image, and 'corner[3]' is the lower right corner of the visible
+ part of the image. The information is provided in this way because
+ often it is necessary to clip a portion of the outer pixels of the
+ image. */
+
+ /* we will draw an image, scale and resize it, copy to bitmap,
+ * give a pointer to it in the list, and when processing the list we will use DrawBitmap */
+ /* FIXME add palette support ??? */
+
+ if (wxt_status != STATUS_OK)
+ return;
+
+ int imax;
+ gp_command temp_command;
+
+ temp_command.command = command_image;
+ temp_command.x1 = corner[0].x;
+ temp_command.y1 = term->ymax - corner[0].y;
+ temp_command.x2 = corner[1].x;
+ temp_command.y2 = term->ymax - corner[1].y;
+ temp_command.x3 = corner[2].x;
+ temp_command.y3 = term->ymax - corner[2].y;
+ temp_command.x4 = corner[3].x;
+ temp_command.y4 = term->ymax - corner[3].y;
+ temp_command.integer_value = M;
+ temp_command.integer_value2 = N;
+ temp_command.color_mode = color_mode;
+
+ if (color_mode == IC_RGB)
+ imax = 3*M*N;
+ else
+ imax = M*N;
+
+ temp_command.image = new coordval[imax];
+ memcpy(temp_command.image, image, imax*sizeof(coordval));
+
+ wxt_command_push(temp_command);
+}
+#endif /*WITH_IMAGE*/
+
+#ifdef USE_MOUSE
+/* Display temporary text, after
+ * erasing any temporary text displayed previously at this location.
+ * The int determines where: 0=statusline, 1,2: at corners of zoom
+ * box, with \r separating text above and below the point. */
+void wxt_put_tmptext(int n, const char str[])
+{
+ if (wxt_status == STATUS_UNINITIALIZED)
+ return;
+
+ wxt_sigint_init();
+ wxt_MutexGuiEnter();
+
+ switch ( n ) {
+ case 0:
+ wxt_current_window->frame->SetStatusText( wxString(str, wxConvLocal) );
+ break;
+ case 1:
+ wxt_current_panel->zoom_x1 = wxt_current_panel->mouse_x;
+ wxt_current_panel->zoom_y1 = wxt_current_panel->mouse_y;
+ wxt_current_panel->zoom_string1 = wxString(str, wxConvLocal);
+ break;
+ case 2:
+ if ( strlen(str)==0 )
+ wxt_current_panel->wxt_zoombox = false;
+ else {
+ wxt_current_panel->wxt_zoombox = true;
+ wxt_current_panel->zoom_string2 = wxString(str, wxConvLocal);
+ }
+ wxt_current_panel->Draw();
+ break;
+ default :
+ break;
+ }
+
+ wxt_MutexGuiLeave();
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* c selects the action:
+ * -4=don't draw (erase) line between ruler and current mouse position,
+ * -3=draw line between ruler and current mouse position,
+ * -2=warp the cursor to the given point,
+ * -1=start zooming,
+ * 0=standard cross-hair cursor,
+ * 1=cursor during rotation,
+ * 2=cursor during scaling,
+ * 3=cursor during zooming. */
+void wxt_set_cursor(int c, int x, int y)
+{
+ if (wxt_status == STATUS_UNINITIALIZED)
+ return;
+
+ wxt_sigint_init();
+ wxt_MutexGuiEnter();
+
+ switch ( c ) {
+ case -4:
+ wxt_current_panel->wxt_ruler_lineto = false;
+ wxt_current_panel->Draw();
+ break;
+ case -3:
+ wxt_current_panel->wxt_ruler_lineto = true;
+ wxt_current_panel->Draw();
+ break;
+ case -2: /* warp the pointer to the given position */
+ wxt_current_panel->WarpPointer(
+ (int) device_x(wxt_current_plot, x),
+ (int) device_y(wxt_current_plot, y) );
+ break;
+ case -1: /* start zooming */
+ wxt_current_panel->SetCursor(wxt_cursor_right);
+ break;
+ case 0: /* cross-hair cursor, also cancel zoombox when Echap is pressed */
+ wxt_current_panel->wxt_zoombox = false;
+ wxt_current_panel->SetCursor(wxt_cursor_cross);
+ wxt_current_panel->Draw();
+ break;
+ case 1: /* rotation */
+ wxt_current_panel->SetCursor(wxt_cursor_rotate);
+ break;
+ case 2: /* scaling */
+ wxt_current_panel->SetCursor(wxt_cursor_size);
+ break;
+ case 3: /* zooming */
+ wxt_current_panel->SetCursor(wxt_cursor_right);
+ break;
+ default:
+ wxt_current_panel->SetCursor(wxt_cursor_cross);
+ break;
+ }
+
+ wxt_MutexGuiLeave();
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+
+/* Draw a ruler (crosshairs) centered at the
+ * indicated screen coordinates. If x<0, switch ruler off. */
+void wxt_set_ruler(int x, int y)
+{
+ if (wxt_status == STATUS_UNINITIALIZED)
+ return;
+
+ wxt_sigint_init();
+ wxt_MutexGuiEnter();
+
+ if (x<0) {
+ wxt_current_panel->wxt_ruler = false;
+ wxt_current_panel->Draw();
+ } else {
+ wxt_current_panel->wxt_ruler = true;
+ wxt_current_panel->wxt_ruler_x = device_x(wxt_current_plot, x);
+ wxt_current_panel->wxt_ruler_y = device_y(wxt_current_plot, y);
+ wxt_current_panel->Draw();
+ }
+
+ wxt_MutexGuiLeave();
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* Write a string to the clipboard */
+void wxt_set_clipboard(const char s[])
+{
+ if (wxt_status == STATUS_UNINITIALIZED)
+ return;
+
+ wxt_sigint_init();
+ wxt_MutexGuiEnter();
+
+ if (wxTheClipboard->Open()) {
+ wxTheClipboard->SetData( new wxTextDataObject(wxString(s, wxConvLocal)) );
+ wxTheClipboard->Flush();
+ wxTheClipboard->Close();
+ }
+
+ wxt_MutexGuiLeave();
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+#endif /*USE_MOUSE*/
+
+
+/* ===================================================================
+ * Command list processing
+ * =================================================================*/
+
+/* push a command in the current commands list */
+void wxt_command_push(gp_command command)
+{
+ wxt_sigint_init();
+ wxt_current_panel->command_list_mutex.Lock();
+ wxt_current_command_list->push_back(command);
+ wxt_current_panel->command_list_mutex.Unlock();
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* refresh the plot by (re)processing the plot commands list */
+void wxtPanel::wxt_cairo_refresh()
+{
+ /* Clear background. */
+ gp_cairo_clear(&plot);
+
+ command_list_t::iterator wxt_iter; /*declare the iterator*/
+ for(wxt_iter = command_list.begin(); wxt_iter != command_list.end(); ++wxt_iter) {
+ if (wxt_status == STATUS_INTERRUPT_ON_NEXT_CHECK) {
+ FPRINTF((stderr,"interrupt detected inside drawing loop\n"));
+#ifdef IMAGE_SURFACE
+ wxt_cairo_create_bitmap();
+#endif /* IMAGE_SURFACE */
+ /* draw the pixmap to the screen */
+ Draw();
+ return;
+ }
+ wxt_cairo_exec_command( *wxt_iter );
+ }
+
+ /* don't forget to stroke the last path if vector was the last command */
+ gp_cairo_stroke(&plot);
+ /* and don't forget to draw the polygons if draw_polygon was the last command */
+ gp_cairo_end_polygon(&plot);
+
+/* the following is a test for a bug in cairo when drawing to a gdkpixmap */
+#if 0
+ cairo_set_source_rgb(plot.cr,1,1,1);
+ cairo_paint(plot.cr);
+
+ cairo_matrix_t matrix;
+ cairo_matrix_init(&matrix,
+ plot.xscale,
+ 0,
+ 0,
+ plot.yscale,
+ 0,
+ 0);
+ cairo_set_matrix(plot.cr, &matrix);
+
+ cairo_t *context;
+ cairo_surface_t *surface;
+ surface = cairo_surface_create_similar(cairo_get_target(plot.cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ plot.device_xmax,
+ plot.device_ymax);
+ context = cairo_create(surface);
+ cairo_set_operator(context,CAIRO_OPERATOR_SATURATE);
+
+ cairo_move_to(context, 300, 200);
+ cairo_rel_line_to(context, 100, 0);
+ cairo_rel_line_to(context, 0, 100);
+ cairo_close_path(context);
+ cairo_set_source_rgb(context,0,0,0);
+ cairo_fill(context);
+
+ cairo_move_to(context, 250, 170);
+ cairo_rel_line_to(context, 100, 0);
+ cairo_rel_line_to(context, 0, 100);
+ cairo_close_path(context);
+ cairo_set_source_rgb(context,0,0,0.5);
+ cairo_fill(context);
+
+ cairo_move_to(context, 360, 200);
+ cairo_rel_line_to(context, 30, 0);
+ cairo_rel_line_to(context, 0, -40);
+ cairo_close_path(context);
+ cairo_set_source_rgb(context,1,0,0);
+ cairo_fill(context);
+
+ cairo_move_to(context, 400, 100);
+ cairo_rel_line_to(context, 100, 0);
+ cairo_rel_line_to(context, -100, 300);
+ cairo_close_path(context);
+ cairo_set_source_rgb(context,0,1,0);
+ cairo_fill(context);
+
+ cairo_move_to(context, 400, 300);
+ cairo_rel_line_to(context, -80, -80);
+ cairo_rel_line_to(context, 0, 100);
+ cairo_close_path(context);
+ cairo_set_source_rgb(context,0.6,0.4,0);
+ cairo_fill(context);
+
+ cairo_pattern_t *pattern = cairo_pattern_create_for_surface( surface );
+ cairo_destroy( context );
+
+ cairo_surface_destroy( surface );
+ cairo_set_source( plot.cr, pattern );
+ cairo_pattern_destroy( pattern );
+ cairo_paint(plot.cr);
+
+ cairo_matrix_init(&matrix,
+ plot.xscale/plot.oversampling_scale,
+ 0,
+ 0,
+ plot.yscale/plot.oversampling_scale,
+ 0,
+ 0);
+ cairo_set_matrix(plot.cr, &matrix);
+#endif
+
+#ifdef IMAGE_SURFACE
+ wxt_cairo_create_bitmap();
+#endif /* !have_gtkcairo */
+
+ /* draw the pixmap to the screen */
+ Draw();
+ FPRINTF((stderr,"commands done, number of commands %d\n", command_list.size()));
+}
+
+
+void wxtPanel::wxt_cairo_exec_command(gp_command command)
+{
+ switch ( command.command ) {
+ case command_color :
+ gp_cairo_set_color(&plot,command.color);
+ return;
+ case command_filled_polygon :
+ gp_cairo_draw_polygon(&plot, command.integer_value, command.corners);
+ return;
+ case command_move :
+ gp_cairo_move(&plot, command.x1, command.y1);
+ return;
+ case command_vector :
+ gp_cairo_vector(&plot, command.x1, command.y1);
+ return;
+ case command_linestyle :
+ gp_cairo_set_linestyle(&plot, command.integer_value);
+ return;
+ case command_linetype :
+ gp_cairo_set_linetype(&plot, command.integer_value);
+ return;
+ case command_pointsize :
+ gp_cairo_set_pointsize(&plot, command.double_value);
+ return;
+ case command_point :
+ gp_cairo_draw_point(&plot, command.x1, command.y1, command.integer_value);
+ return;
+ case command_justify :
+ gp_cairo_set_justify(&plot,command.mode);
+ return;
+ case command_put_text :
+ gp_cairo_draw_text(&plot, command.x1, command.y1, command.string);
+ return;
+ case command_enhanced_put_text :
+ gp_cairo_draw_enhanced_text(&plot, command.x1, command.y1, command.string);
+ return;
+ case command_set_font :
+ gp_cairo_set_font(&plot, command.string, command.integer_value);
+ return;
+ case command_linewidth :
+ gp_cairo_set_linewidth(&plot, command.double_value);;
+ return;
+ case command_text_angle :
+ gp_cairo_set_textangle(&plot, command.double_value);
+ return;
+ case command_fillbox :
+ gp_cairo_draw_fillbox(&plot, command.x1, command.y1,
+ command.x2, command.y2,
+ command.integer_value);
+ return;
+#ifdef WITH_IMAGE
+ case command_image :
+ gp_cairo_draw_image(&plot, command.image,
+ command.x1, command.y1,
+ command.x2, command.y2,
+ command.x3, command.y3,
+ command.x4, command.y4,
+ command.integer_value, command.integer_value2,
+ command.color_mode);
+ return;
+#endif /*WITH_IMAGE*/
+ }
+}
+
+
+/* given a plot number (id), return the associated plot structure */
+wxt_window_t* wxt_findwindowbyid(wxWindowID id)
+{
+ size_t i;
+ for(i=0;i<wxt_window_list.size();++i) {
+ if (wxt_window_list[i].id == id)
+ return &(wxt_window_list[i]);
+ }
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------
+ * raise-lower functions
+ *----------------------------------------------------------------------------*/
+
+void wxt_raise_window(wxt_window_t* window, bool force)
+{
+ FPRINTF((stderr,"raise window\n"));
+
+ window->frame->Show(true);
+
+ if (wxt_raise != no||force) {
+#ifdef USE_GTK
+ /* Raise() in wxGTK call wxTopLevelGTK::Raise()
+ * which also gives the focus to the window.
+ * Refresh() also must be called, otherwise
+ * the raise won't happen immediately */
+ window->frame->panel->Refresh(false);
+ gdk_window_raise(window->frame->GetHandle()->window);
+#else
+ window->frame->Raise();
+#endif /*USE_GTK */
+ }
+}
+
+
+void wxt_lower_window(wxt_window_t* window)
+{
+#ifdef USE_GTK
+ window->frame->panel->Refresh(false);
+ gdk_window_lower(window->frame->GetHandle()->window);
+#else
+ window->frame->Lower();
+#endif /* USE_GTK */
+}
+
+
+/* raise the plot with given number */
+void wxt_raise_terminal_window(int number)
+{
+ wxt_window_t *window;
+
+ if (wxt_status != STATUS_OK)
+ return;
+
+ wxt_sigint_init();
+
+ wxt_MutexGuiEnter();
+ if ((window = wxt_findwindowbyid(number))) {
+ FPRINTF((stderr,"wxt : raise window %d\n",number));
+ window->frame->Show(true);
+ wxt_raise_window(window,true);
+ }
+ wxt_MutexGuiLeave();
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* raise the plot the whole group */
+void wxt_raise_terminal_group()
+{
+ /* declare the iterator */
+ std::vector<wxt_window_t>::iterator wxt_iter;
+
+ if (wxt_status != STATUS_OK)
+ return;
+
+ wxt_sigint_init();
+
+ wxt_MutexGuiEnter();
+ for(wxt_iter = wxt_window_list.begin(); wxt_iter != wxt_window_list.end(); wxt_iter++) {
+ FPRINTF((stderr,"wxt : raise window %d\n",wxt_iter->id));
+ wxt_iter->frame->Show(true);
+ /* FIXME Why does wxt_iter doesn't work directly ? */
+ wxt_raise_window(&(*wxt_iter),true);
+ }
+ wxt_MutexGuiLeave();
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* lower the plot with given number */
+void wxt_lower_terminal_window(int number)
+{
+ wxt_window_t *window;
+
+ if (wxt_status != STATUS_OK)
+ return;
+
+ wxt_sigint_init();
+
+ wxt_MutexGuiEnter();
+ if ((window = wxt_findwindowbyid(number))) {
+ FPRINTF((stderr,"wxt : lower window %d\n",number));
+ wxt_lower_window(window);
+ }
+ wxt_MutexGuiLeave();
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* lower the plot the whole group */
+void wxt_lower_terminal_group()
+{
+ /* declare the iterator */
+ std::vector<wxt_window_t>::iterator wxt_iter;
+
+ if (wxt_status != STATUS_OK)
+ return;
+
+ wxt_sigint_init();
+
+ wxt_MutexGuiEnter();
+ for(wxt_iter = wxt_window_list.begin(); wxt_iter != wxt_window_list.end(); wxt_iter++) {
+ FPRINTF((stderr,"wxt : lower window %d\n",wxt_iter->id));
+ wxt_lower_window(&(*wxt_iter));
+ }
+ wxt_MutexGuiLeave();
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* close the specified window */
+void wxt_close_terminal_window(int number)
+{
+ wxt_window_t *window;
+
+ if (wxt_status != STATUS_OK)
+ return;
+
+ wxt_sigint_init();
+
+ wxt_MutexGuiEnter();
+ if ((window = wxt_findwindowbyid(number))) {
+ FPRINTF((stderr,"wxt : close window %d\n",number));
+ window->frame->Close(false);
+ }
+ wxt_MutexGuiLeave();
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* update the window title */
+void wxt_update_title(int number)
+{
+ wxt_window_t *window;
+ wxString title;
+
+ if (wxt_status != STATUS_OK)
+ return;
+
+ wxt_sigint_init();
+
+ wxt_MutexGuiEnter();
+
+ if ((window = wxt_findwindowbyid(number))) {
+ FPRINTF((stderr,"wxt : close window %d\n",number));
+ if (strlen(wxt_title)) {
+ /* NOTE : this assumes that the title is encoded in the locale charset.
+ * This is probably a good assumption, but it is not guaranteed !
+ * May be improved by using gnuplot encoding setting. */
+ title << wxString(wxt_title, wxConvLocal);
+ } else
+ title.Printf(wxT("Gnuplot (window id : %d)"), window->id);
+
+ window->frame->SetTitle(title);
+ }
+
+ wxt_MutexGuiLeave();
+
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* --------------------------------------------------------
+ * Cairo stuff
+ * --------------------------------------------------------*/
+
+void wxtPanel::wxt_cairo_create_context()
+{
+ cairo_surface_t *fake_surface;
+
+ if ( plot.cr )
+ cairo_destroy(plot.cr);
+
+ if ( wxt_cairo_create_platform_context() ) {
+ /* we are not able to create a true cairo context,
+ * but will create a fake one to give proper initialisation */
+ FPRINTF((stderr,"creating temporary fake surface\n"));
+ fake_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ plot.cr = cairo_create( fake_surface );
+ cairo_surface_destroy( fake_surface );
+ /* this flag will make the program retry later */
+ plot.success = FALSE;
+ } else {
+ plot.success = TRUE;
+ }
+
+ /* set the transformation matrix of the context, and other details */
+ gp_cairo_initialize_context(&plot);
+}
+
+void wxtPanel::wxt_cairo_free_context()
+{
+ if (plot.cr)
+ cairo_destroy(plot.cr);
+
+ if (plot.success)
+ wxt_cairo_free_platform_context();
+}
+
+
+#ifdef GTK_SURFACE
+/* create a cairo context, where the plot will be drawn on
+ * If there is an error, return 1, otherwise return 0 */
+int wxtPanel::wxt_cairo_create_platform_context()
+{
+ cairo_surface_t *surface;
+ wxClientDC dc(this);
+
+ FPRINTF((stderr,"wxt_cairo_create_context\n"));
+
+ /* free gdkpixmap */
+ wxt_cairo_free_platform_context();
+
+ /* GetWindow is a wxGTK specific wxDC method that returns
+ * the GdkWindow on which painting should be done */
+
+ if ( !GDK_IS_DRAWABLE(dc.GetWindow()) )
+ return 1;
+
+
+ gdkpixmap = gdk_pixmap_new(dc.GetWindow(), plot.device_xmax, plot.device_ymax, -1);
+
+ if ( !GDK_IS_DRAWABLE(gdkpixmap) )
+ return 1;
+
+ plot.cr = gdk_cairo_create(gdkpixmap);
+ return 0;
+}
+
+void wxtPanel::wxt_cairo_free_platform_context()
+{
+ if (gdkpixmap)
+ g_object_unref(gdkpixmap);
+}
+
+#elif defined(__WXMSW__)
+/* create a cairo context, where the plot will be drawn on
+ * If there is an error, return 1, otherwise return 0 */
+int wxtPanel::wxt_cairo_create_platform_context()
+{
+ cairo_surface_t *surface;
+ wxClientDC dc(this);
+
+ FPRINTF((stderr,"wxt_cairo_create_context\n"));
+
+ /* free hdc and hbm */
+ wxt_cairo_free_platform_context();
+
+ /* GetHDC is a wxMSW specific wxDC method that returns
+ * the HDC on which painting should be done */
+
+ /* Create a compatible DC. */
+ hdc = CreateCompatibleDC( (HDC) dc.GetHDC() );
+
+ if (!hdc)
+ return 1;
+
+ /* Create a bitmap big enough for our client rectangle. */
+ hbm = CreateCompatibleBitmap((HDC) dc.GetHDC(), plot.device_xmax, plot.device_ymax);
+
+ if ( !hbm )
+ return 1;
+
+ /* Select the bitmap into the off-screen DC. */
+ SelectObject(hdc, hbm);
+ surface = cairo_win32_surface_create( hdc );
+ plot.cr = cairo_create(surface);
+ cairo_surface_destroy( surface );
+ return 0;
+}
+
+void wxtPanel::wxt_cairo_free_platform_context()
+{
+ if (hdc)
+ DeleteDC(hdc);
+ if (hbm)
+ DeleteObject(hbm);
+}
+
+#else /* generic image surface */
+/* create a cairo context, where the plot will be drawn on
+ * If there is an error, return 1, otherwise return 0 */
+int wxtPanel::wxt_cairo_create_platform_context()
+{
+ int width, height;
+ cairo_surface_t *surface;
+
+ FPRINTF((stderr,"wxt_cairo_create_context\n"));
+
+ if (data32)
+ delete[] data32;
+
+ width = plot.device_xmax;
+ height = plot.device_ymax;
+
+ if (width<1||height<1)
+ return 1;
+
+ data32 = new unsigned int[width*height];
+
+ surface = cairo_image_surface_create_for_data((unsigned char*) data32,
+ CAIRO_FORMAT_ARGB32, width, height, 4*width);
+ plot.cr = cairo_create(surface);
+ cairo_surface_destroy( surface );
+ return 0;
+}
+
+
+/* create a wxBitmap (to be painted to the screen) from the buffered cairo surface. */
+void wxtPanel::wxt_cairo_create_bitmap()
+{
+ int width, height;
+ unsigned char *data24;
+ wxImage *image;
+
+ if (!data32)
+ return;
+
+ width = plot.device_xmax;
+ height = plot.device_ymax;
+
+ data24 = new unsigned char[3*width*height];
+
+ /* data32 is the cairo image buffer, upper bits are alpha, then r, g and b
+ * Depends on endianess !
+ * It is converted to RGBRGB... in data24 */
+ for(int i=0;i<width*height;++i) {
+ *(data24+3*i)=*(data32+i)>>16;
+ *(data24+3*i+1)=*(data32+i)>>8;
+ *(data24+3*i+2)=*(data32+i);
+ }
+
+ /* create a wxImage from data24 */
+ image = new wxImage(width, height, data24, true);
+
+ if (cairo_bitmap)
+ delete cairo_bitmap;
+
+ /* create a wxBitmap from the wxImage. */
+ cairo_bitmap = new wxBitmap( *image );
+
+ /* free memory */
+ delete image;
+ delete[] data24;
+}
+
+
+void wxtPanel::wxt_cairo_free_platform_context()
+{
+ if (data32)
+ delete[] data32;
+ if (cairo_bitmap)
+ delete cairo_bitmap;
+}
+#endif /* IMAGE_SURFACE */
+
+/* --------------------------------------------------------
+ * events handling
+ * --------------------------------------------------------*/
+
+/* Debugging events and _waitforinput adds a lot of lines of output
+ * (~4 lines for an input character, and a few lines for each mouse move)
+ * To debug it, define DEBUG and WXTDEBUGINPUT */
+
+#ifdef WXTDEBUGINPUT
+# define FPRINTF2(a) FPRINTF(a)
+#else
+# define FPRINTF2(a)
+#endif
+
+#ifdef USE_MOUSE
+/* protected check for the state of the event list */
+bool wxt_check_eventlist_empty()
+{
+ bool result;
+ mutexProtectingEventList.Lock();
+ result = EventList.empty();
+ mutexProtectingEventList.Unlock();
+ return result;
+}
+
+/* protected check for the state of the main thread (running or waiting for input) */
+wxt_thread_state_t wxt_check_thread_state()
+{
+ wxt_thread_state_t result;
+ mutexProtectingThreadState.Lock();
+ result = wxt_thread_state;
+ mutexProtectingThreadState.Unlock();
+ return result;
+}
+
+/* multithread safe method to change thread state */
+void wxt_change_thread_state(wxt_thread_state_t state)
+{
+ wxt_sigint_init();
+ mutexProtectingThreadState.Lock();
+ wxt_thread_state = state;
+ mutexProtectingThreadState.Unlock();
+ wxt_sigint_check();
+ wxt_sigint_restore();
+}
+
+/* Similar to gp_exec_event(),
+ * put the event sent by the terminal in a list,
+ * to be processed by the main thread. */
+void wxt_exec_event(int type, int mx, int my, int par1, int par2, wxWindowID id)
+{
+ struct gp_event_t event;
+
+ event.type = type;
+ event.mx = mx;
+ event.my = my;
+ event.par1 = par1;
+ event.par2 = par2;
+ event.winid = id;
+
+#ifdef _Windows
+ FPRINTF2((stderr,"Processing event\n"));
+ do_event( &event );
+ FPRINTF2((stderr,"Event processed\n"));
+ if (event.type == GE_buttonrelease && (paused_for_mouse & PAUSE_CLICK)) {
+ int button = event.par1;
+ if (button == 1 && (paused_for_mouse & PAUSE_BUTTON1))
+ paused_for_mouse = 0;
+ if (button == 2 && (paused_for_mouse & PAUSE_BUTTON2))
+ paused_for_mouse = 0;
+ if (button == 3 && (paused_for_mouse & PAUSE_BUTTON3))
+ paused_for_mouse = 0;
+ }
+ if (event.type == GE_keypress && (paused_for_mouse & PAUSE_KEYSTROKE)) {
+ /* Ignore NULL keycode */
+ if (event.par1 > '\0')
+ paused_for_mouse = 0;
+ }
+#else
+ /* add the event to the event list */
+ if (wxt_check_thread_state() == WAITING_FOR_STDIN)
+ {
+ FPRINTF2((stderr,"Gui thread adds an event to the list\n"));
+ mutexProtectingEventList.Lock();
+ EventList.push_back(event);
+ mutexProtectingEventList.Unlock();
+ }
+#endif /* ! _Windows */
+}
+
+
+/* clear the event list, caring for the mutex */
+void wxt_clear_event_list()
+{
+ mutexProtectingEventList.Lock();
+ EventList.clear();
+ mutexProtectingEventList.Unlock();
+}
+
+
+/* wxt_process_events will process the contents of the event list
+ * until it is empty.
+ * It will return 1 if one event ends the pause */
+int wxt_process_events()
+{
+ struct gp_event_t wxt_event;
+ int button;
+
+ while ( !wxt_check_eventlist_empty() ) {
+ FPRINTF2((stderr,"Processing event\n"));
+ mutexProtectingEventList.Lock();
+ wxt_event = EventList.front();
+ EventList.pop_front();
+ mutexProtectingEventList.Unlock();
+ do_event( &wxt_event );
+ FPRINTF2((stderr,"Event processed\n"));
+ if (wxt_event.type == GE_buttonrelease && (paused_for_mouse & PAUSE_CLICK)) {
+ button = wxt_event.par1;
+ if (button == 1 && (paused_for_mouse & PAUSE_BUTTON1))
+ paused_for_mouse = 0;
+ if (button == 2 && (paused_for_mouse & PAUSE_BUTTON2))
+ paused_for_mouse = 0;
+ if (button == 3 && (paused_for_mouse & PAUSE_BUTTON3))
+ paused_for_mouse = 0;
+ if (paused_for_mouse == 0)
+ return 1;
+ }
+ if (wxt_event.type == GE_keypress && (paused_for_mouse & PAUSE_KEYSTROKE)) {
+ /* Ignore NULL keycode */
+ if (wxt_event.par1 > '\0') {
+ paused_for_mouse = 0;
+ return 1;
+ }
+ }
+ }
+ return 0;
+
+}
+
+#ifdef __WXMSW__
+/* Implements waitforinput used in wxt.trm
+ * the terminal events are directly processed when they are received */
+int wxt_waitforinput()
+{
+ return getch();
+}
+
+#elif defined(__WXGTK__)||defined(__WXMAC__)
+
+/* Implements waitforinput used in wxt.trm
+ * Returns the next input charachter, meanwhile treats terminal events */
+int wxt_waitforinput()
+{
+ /* wxt_waitforinput *is* launched immediately after the wxWidgets terminal
+ * is set using 'set term wxt' whereas wxt_init has not been called.
+ * So we must ensure that the library has been initialized
+ * before using any wxwidgets functions.
+ * When we just come back from SIGINT,
+ * we must process window events, so the check is not
+ * wxt_status != STATUS_OK */
+ if (wxt_status == STATUS_UNINITIALIZED)
+ return getc(stdin);
+
+ int ierr;
+ int fd = fileno(stdin);
+ struct timeval timeout;
+ fd_set fds;
+
+ wxt_change_thread_state(WAITING_FOR_STDIN);
+
+ do {
+ if (wxt_process_events()) {
+ wxt_change_thread_state(RUNNING);
+ return '\0';
+ }
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+ FD_ZERO(&fds);
+ FD_SET(0/*fd*/,&fds);
+
+ ierr = select(1, &fds, NULL, NULL, &timeout);
+
+ /* check for error on select and return immediately if any */
+ if (ierr<0) {
+ wxt_change_thread_state(RUNNING);
+ return '\0';
+ }
+ } while (!FD_ISSET(fd,&fds));
+
+ /* if we are paused_for_mouse, we should continue to wait for a mouse click */
+ if (paused_for_mouse)
+ while (true) {
+ if (wxt_process_events()) {
+ wxt_change_thread_state(RUNNING);
+ return '\0';
+ }
+ /* wait 10 microseconds */
+ wxMicroSleep(10);
+ }
+
+ wxt_change_thread_state(RUNNING);
+ return getchar();
+}
+#else /* !__WXMSW__ && !__WXGTK__ && !__WXMAC__*/
+#error "Not implemented"
+#endif
+
+#endif /*USE_MOUSE*/
+
+/* --------------------------------------------------------
+ * 'persist' option handling
+ * --------------------------------------------------------*/
+
+/* returns true if at least one plot window is opened.
+ * Used to handle 'persist' */
+bool wxt_window_opened()
+{
+ std::vector<wxt_window_t>::iterator wxt_iter; /*declare the iterator*/
+
+ wxt_MutexGuiEnter();
+ for(wxt_iter = wxt_window_list.begin(); wxt_iter != wxt_window_list.end(); wxt_iter++) {
+ if ( wxt_iter->frame->IsShown() ) {
+ wxt_MutexGuiLeave();
+ return true;
+ }
+ }
+ wxt_MutexGuiLeave();
+ return false;
+}
+
+/* Called when gnuplot exits.
+ * Handle the 'persist' setting, ie will continue
+ * to handle events and will return when
+ * all the plot windows are closed. */
+void wxt_atexit()
+{
+ int i;
+ int persist_setting;
+#ifdef _Windows
+ MSG msg;
+#endif /*_Windows*/
+
+ if (wxt_status == STATUS_UNINITIALIZED)
+ return;
+
+ /* first look for command_line setting */
+ if (wxt_persist==UNSET && persist_cl)
+ wxt_persist = TRUE;
+
+ wxConfigBase *pConfig = wxConfigBase::Get();
+
+ /* then look for persistent configuration setting */
+ if (wxt_persist==UNSET) {
+ if (pConfig->Read(wxT("persist"),&persist_setting))
+ wxt_persist = persist_setting?yes:no;
+ }
+
+ /* and let's go ! */
+ if (wxt_persist==UNSET|| wxt_persist==no) {
+ wxt_cleanup();
+ return;
+ }
+
+ /* if the user hits ctrl-c and quits again, really quit */
+ wxt_persist = no;
+
+ FPRINTF((stderr,"wxWidgets terminal handles 'persist' setting\n"));
+
+#ifdef _Windows
+ if (!interactive) {
+ interactive = TRUE;
+ /* be sure to show the text window */
+ ShowWindow(textwin.hWndParent, textwin.nCmdShow);
+ while (!com_line());
+ }
+
+ /* cleanup and quit */
+ wxt_cleanup();
+#else /*_Windows*/
+
+ /* if fork() is available, use it so that the initial gnuplot process
+ * exits (Maxima expects that since that's the way the x11 terminal
+ * does it) and the child process continues in the background. */
+ /* FIXME: int_error() should be changed here, it causes crashes (for example,
+ * zoom until an error occurs and then hit a key) */
+# ifdef HAVE_WORKING_FORK
+ /* send a message to exit the main loop */
+ wxCommandEvent event(wxExitLoopEvent);
+ std::vector<wxt_window_t>::iterator wxt_iter; /*declare the iterator*/
+ wxt_iter = wxt_window_list.begin();
+ wxt_iter->frame->GetEventHandler()->AddPendingEvent( event );
+
+ /* wait for the gui thread to exit */
+ thread->Wait();
+ delete thread;
+
+ /* fork */
+ pid_t pid = fork();
+
+ /* the parent just exits, the child keeps going */
+ if (!pid) {
+ /* create a new gui thread and run it */
+ /* have to close the previous main loop for this to succeed */
+ thread = new wxtThread();
+ thread->Create();
+ thread->Run();
+
+# endif /* HAVE_WORKING_FORK */
+
+# ifdef USE_MOUSE
+ wxt_change_thread_state(WAITING_FOR_STDIN);
+# endif /*USE_MOUSE*/
+
+ /* protect the following from interrupt */
+ wxt_sigint_init();
+
+ while (wxt_window_opened()) {
+# ifdef USE_MOUSE
+ if (!strcmp(term->name,"wxt"))
+ wxt_process_events();
+# endif /*USE_MOUSE*/
+ /* wait 10 microseconds and repeat */
+ /* such a polling is bad, putting the thread to sleep
+ * would be better */
+ wxMicroSleep(10);
+ wxt_sigint_check();
+ }
+
+ wxt_sigint_restore();
+
+# ifdef USE_MOUSE
+ wxt_change_thread_state(RUNNING);
+# endif /*USE_MOUSE*/
+
+ /* cleanup and quit */
+ wxt_cleanup();
+
+# ifdef HAVE_WORKING_FORK
+ }
+# endif /* HAVE_WORKING_FORK */
+#endif /* !_Windows */
+}
+
+
+/* destroy everything related to wxWidgets */
+void wxt_cleanup()
+{
+ std::vector<wxt_window_t>::iterator wxt_iter; /*declare the iterator*/
+
+ if (wxt_status == STATUS_UNINITIALIZED)
+ return;
+
+ FPRINTF((stderr,"cleanup before exit\n"));
+
+ /* prevent wxt_reset (for example) from doing anything bad after that */
+ wxt_status = STATUS_UNINITIALIZED;
+
+ /* protect the following from interrupt */
+ wxt_sigint_init();
+
+ /* Close all open terminal windows, this will make OnRun exit, and so will the gui thread */
+ wxt_MutexGuiEnter();
+ for(wxt_iter = wxt_window_list.begin(); wxt_iter != wxt_window_list.end(); wxt_iter++)
+ delete wxt_iter->frame;
+ wxt_MutexGuiLeave();
+
+#if defined(__WXGTK__)||defined(__WXMAC__)
+ FPRINTF((stderr,"waiting for gui thread to exit\n"));
+ FPRINTF((stderr,"gui thread status %d %d %d\n",
+ thread->IsDetached(),
+ thread->IsAlive(),
+ thread->IsRunning() ));
+
+ thread->Wait();
+ delete thread;
+ FPRINTF((stderr,"gui thread exited\n"));
+#endif /* __WXGTK || __WXMAC__*/
+
+ wxTheApp->OnExit();
+ wxUninitialize();
+
+ /* handle eventual interrupt, and restore original sigint handler */
+ wxt_sigint_check();
+ wxt_sigint_restore();
+
+ FPRINTF((stderr,"wxWidgets terminal properly cleaned-up\n"));
+}
+
+/* -------------------------------------
+ * GUI Mutex helper functions for porting
+ * ----------------------------------------*/
+
+void wxt_MutexGuiEnter()
+{
+ FPRINTF2((stderr,"locking gui mutex\n"));
+#if defined(__WXGTK__)||defined(__WXMAC__)
+ wxMutexGuiEnter();
+#elif defined(__WXMSW__)
+#else
+# error "No implementation"
+#endif
+}
+
+void wxt_MutexGuiLeave()
+{
+ FPRINTF2((stderr,"unlocking gui mutex\n"));
+#if defined(__WXGTK__)||defined(__WXMAC__)
+ wxMutexGuiLeave();
+#elif defined(__WXMSW__)
+#else
+# error "No implementation"
+#endif
+}
+
+/* ---------------------------------------------------
+ * SIGINT handling : as the terminal is multithreaded, it needs several mutexes.
+ * To avoid inconsistencies and deadlock when the user hits ctrl-c,
+ * each critical set of instructions (implying mutexes for example) should be written :
+ * wxt_sigint_init();
+ * < critical instructions >
+ * wxt_sigint_check();
+ * wxt_sigint_restore();
+ * Or, if the critical instructions are in a loop, wxt_sigint_check() should be
+ * called regularly in the loop.
+ * ---------------------------------------------------*/
+
+
+/* our custom SIGINT handler, that just sets a flag */
+void wxt_sigint_handler(int WXUNUSED(sig))
+{
+ FPRINTF((stderr,"custom interrupt handler called\n"));
+ signal(SIGINT, wxt_sigint_handler);
+ /* routines must check regularly for wxt_status,
+ * and abort cleanly on STATUS_INTERRUPT_ON_NEXT_CHECK */
+ wxt_status = STATUS_INTERRUPT_ON_NEXT_CHECK;
+ if (wxt_current_plot)
+ wxt_current_plot->interrupt = TRUE;
+}
+
+/* To be called when the function has finished cleaning after facing STATUS_INTERRUPT_ON_NEXT_CHECK */
+/* Provided for flexibility, but use wxt_sigint_check instead directly */
+void wxt_sigint_return()
+{
+ FPRINTF((stderr,"calling original interrupt handler\n"));
+ wxt_status = STATUS_INTERRUPT;
+ wxt_sigint_counter = 0;
+ /* call the original sigint handler */
+ /* this will not return !! */
+ (*original_siginthandler)(SIGINT);
+}
+
+/* A critical function should call this from a safe zone (no locked mutex, objects destroyed).
+ * If the interrupt is asked, this fonction will not return (longjmp) */
+void wxt_sigint_check()
+{
+ FPRINTF2((stderr,"checking interrupt status\n"));
+ if (wxt_status == STATUS_INTERRUPT_ON_NEXT_CHECK)
+ wxt_sigint_return();
+}
+
+/* initialize our custom SIGINT handler */
+/* this uses a usage counter, so that it can be encapsulated without problem */
+void wxt_sigint_init()
+{
+ /* put our custom sigint handler, store the original one */
+ if (wxt_sigint_counter == 0)
+ original_siginthandler = signal(SIGINT, wxt_sigint_handler);
+ ++wxt_sigint_counter;
+ FPRINTF2((stderr,"initialize custom interrupt handler %d\n",wxt_sigint_counter));
+}
+
+/* restore the original SIGINT handler */
+void wxt_sigint_restore()
+{
+ if (wxt_sigint_counter==1)
+ signal(SIGINT, original_siginthandler);
+ --wxt_sigint_counter;
+ FPRINTF2((stderr,"restore custom interrupt handler %d\n",wxt_sigint_counter));
+ if (wxt_sigint_counter<0)
+ fprintf(stderr,"sigint counter < 0 : error !\n");
+}