2 * $Id: wxt_gui.cpp,v 1.30.2.9 2008/07/29 22:19:05 sfeam Exp $
5 /* GNUPLOT - wxt_gui.cpp */
8 * Copyright 2005,2006 Timothee Lecomte
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
37 * Alternatively, the contents of this file, apart from one portion
38 * that originates from other gnuplot files and is designated as such,
39 * may be used under the terms of the GNU General Public License
40 * Version 2 or later (the "GPL"), in which case the provisions of GPL
41 * are applicable instead of those above. If you wish to allow
42 * use of your version of the appropriate portion of this file only
43 * under the terms of the GPL and not to allow others to use your version
44 * of this file under the above gnuplot license, indicate your decision
45 * by deleting the provisions above and replace them with the notice
46 * and other provisions required by the GPL. If you do not
47 * delete the provisions above, a recipient may use your version of this file
48 * under either the GPL or the gnuplot license.
51 /* -----------------------------------------------------
52 * The following code uses the wxWidgets library, which is
53 * distributed under its own licence (derivated from the LGPL).
55 * You can read it at the following address :
56 * http://www.wxwidgets.org/licence.htm
57 * -----------------------------------------------------*/
59 /* ------------------------------------------------------
60 * This file implements in C++ the functions which are called by wxt.trm :
62 * It depends on the generic cairo functions,
63 * declared in gp_cairo.h for all the drawing work.
65 * Here is the interactive part :
66 * - rescaling according to the window's size,
67 * - mouse support (cursor position, zoom, rotation, ruler, clipboard...),
68 * - a toolbar to give additionnal capabilities (similar to the OS/2 terminal),
69 * - multiple plot windows.
71 * ------------------------------------------------------*/
74 * Since it uses wxWidgets and Cairo routines, this code is mostly cross-platform.
75 * However some details have to be implemented or tweaked for each platform :
77 * 1) A generic 'image' surface is implemented as the destination surface
78 * for cairo drawing. But for optimal results, cairo should draw to a native
79 * surface corresponding to the graphical system.
81 * - a gdkpixmap when compiling for wxGTK (currently disabled because of a bug in CAIRO_OPERATOR_SATURATE),
82 * - a HDC when compiling for wxMSW
83 * - [insert your contribution here !]
85 * 2) You have to be careful with the gui main loop.
86 * As far as I understand :
87 * Some platforms (Windows ?) require that it is in the main thread.
88 * When compiling for Windows (wxMSW), the text window already implements it, so we
89 * don't have to do it, but wxWidgets still have to be initialized correctly.
90 * When compiling for Unix (wxGTK), we don't have one, so we launch it in a separate thread.
91 * For new platforms, it is necessary to figure out what is necessary.
95 /* define DEBUG here to have debugging messages in stderr */
98 /* frame icon composed of three icons of different resolutions */
99 #include "bitmaps/xpm/icon16x16.xpm"
100 #include "bitmaps/xpm/icon32x32.xpm"
101 #include "bitmaps/xpm/icon64x64.xpm"
103 #include "bitmaps/xpm/cross.xpm"
104 #include "bitmaps/xpm/right.xpm"
105 #include "bitmaps/xpm/rotate.xpm"
106 #include "bitmaps/xpm/size.xpm"
108 * Those are embedded PNG icons previously converted to an array.
109 * See bitmaps/png/README for details */
110 #include "bitmaps/png/clipboard_png.h"
111 #include "bitmaps/png/replot_png.h"
112 #include "bitmaps/png/grid_png.h"
113 #include "bitmaps/png/previouszoom_png.h"
114 #include "bitmaps/png/nextzoom_png.h"
115 #include "bitmaps/png/autoscale_png.h"
116 #include "bitmaps/png/config_png.h"
117 #include "bitmaps/png/help_png.h"
119 /* ---------------------------------------------------------------------------
120 * event tables and other macros for wxWidgets
121 * --------------------------------------------------------------------------*/
123 /* the event tables connect the wxWidgets events with the functions (event
124 * handlers) which process them. It can be also done at run-time, but for the
125 * simple menu events like this the static method is much simpler.
128 BEGIN_EVENT_TABLE( wxtFrame, wxFrame )
129 EVT_COMMAND( wxID_ANY, wxExitLoopEvent, wxtApp::OnExitLoop )
130 EVT_CLOSE( wxtFrame::OnClose )
131 EVT_SIZE( wxtFrame::OnSize )
132 EVT_TOOL( Toolbar_CopyToClipboard, wxtFrame::OnCopy )
134 EVT_TOOL( Toolbar_Replot, wxtFrame::OnReplot )
135 EVT_TOOL( Toolbar_ToggleGrid, wxtFrame::OnToggleGrid )
136 EVT_TOOL( Toolbar_ZoomPrevious, wxtFrame::OnZoomPrevious )
137 EVT_TOOL( Toolbar_ZoomNext, wxtFrame::OnZoomNext )
138 EVT_TOOL( Toolbar_Autoscale, wxtFrame::OnAutoscale )
140 EVT_TOOL( Toolbar_Config, wxtFrame::OnConfig )
141 EVT_TOOL( Toolbar_Help, wxtFrame::OnHelp )
144 BEGIN_EVENT_TABLE( wxtPanel, wxPanel )
145 EVT_PAINT( wxtPanel::OnPaint )
146 EVT_ERASE_BACKGROUND( wxtPanel::OnEraseBackground )
147 EVT_SIZE( wxtPanel::OnSize )
149 EVT_MOTION( wxtPanel::OnMotion )
150 EVT_LEFT_DOWN( wxtPanel::OnLeftDown )
151 EVT_LEFT_UP( wxtPanel::OnLeftUp )
152 EVT_MIDDLE_DOWN( wxtPanel::OnMiddleDown )
153 EVT_MIDDLE_UP( wxtPanel::OnMiddleUp )
154 EVT_RIGHT_DOWN( wxtPanel::OnRightDown )
155 EVT_RIGHT_UP( wxtPanel::OnRightUp )
156 EVT_CHAR( wxtPanel::OnKeyDownChar )
160 BEGIN_EVENT_TABLE( wxtConfigDialog, wxDialog )
161 EVT_CLOSE( wxtConfigDialog::OnClose )
162 EVT_CHOICE( Config_Rendering, wxtConfigDialog::OnRendering )
163 EVT_COMMAND_RANGE( Config_OK, Config_CANCEL,
164 wxEVT_COMMAND_BUTTON_CLICKED, wxtConfigDialog::OnButton )
168 #if defined(__WXGTK__)||defined(__WXMAC__)
169 /* ----------------------------------------------------------------------------
171 * ----------------------------------------------------------------------------*/
173 /* What really happens in the thread
174 * Just before it returns, wxEntry will call a whole bunch of wxWidgets-cleanup functions */
175 void *wxtThread::Entry()
177 FPRINTF((stderr,"gui_thread_entry\n"));
179 /* don't answer to SIGINT in this thread - avoids LONGJMP problems */
182 sigaddset(&set, SIGINT);
183 pthread_sigmask(SIG_BLOCK, &set, NULL);
188 /* Workaround for a deadlock when the main thread will Wait() for this one.
189 * This issue comes from the fact that our gui main loop is not in the
190 * main thread as wxWidgets was written for. */
193 FPRINTF((stderr,"gui_thread_entry finishing\n"));
196 #elif defined (__WXMSW__)
197 /* nothing to do here */
199 # error "Not implemented."
204 /* ----------------------------------------------------------------------------
205 * `Main program' equivalent: the program execution "starts" here
206 * ----------------------------------------------------------------------------*/
208 /* Create a new application object */
209 IMPLEMENT_APP_NO_MAIN(wxtApp)
211 bool wxtApp::OnInit()
213 /* Usually wxWidgets apps create their main window here.
214 * However, in the context of multiple plot windows, the same code is written in wxt_init().
215 * So, to avoid duplication of the code, we do only what is strictly necessary.*/
217 /* initialize frames icons */
218 icon.AddIcon(wxIcon(icon16x16_xpm));
219 icon.AddIcon(wxIcon(icon32x32_xpm));
220 icon.AddIcon(wxIcon(icon64x64_xpm));
222 /* we load the image handlers, needed to copy the plot to clipboard, and to load icons */
223 ::wxInitAllImageHandlers();
226 /* allow the toolbar to display properly png icons with an alpha channel */
227 wxSystemOptions::SetOption(wxT("msw.remap"), 0);
228 #endif /* __WXMSW__ */
230 /* load toolbar icons */
231 LoadPngIcon(clipboard_png, sizeof(clipboard_png), 0);
232 LoadPngIcon(replot_png, sizeof(replot_png), 1);
233 LoadPngIcon(grid_png, sizeof(grid_png), 2);
234 LoadPngIcon(previouszoom_png, sizeof(previouszoom_png), 3);
235 LoadPngIcon(nextzoom_png, sizeof(nextzoom_png), 4);
236 LoadPngIcon(autoscale_png, sizeof(autoscale_png), 5);
237 LoadPngIcon(config_png, sizeof(config_png), 6);
238 LoadPngIcon(help_png, sizeof(help_png), 7);
241 LoadCursor(wxt_cursor_cross, cross);
242 LoadCursor(wxt_cursor_right, right);
243 LoadCursor(wxt_cursor_rotate, rotate);
244 LoadCursor(wxt_cursor_size, size);
246 /* Initialize the config object */
247 /* application and vendor name are used by wxConfig to construct the name
248 * of the config file/registry key and must be set before the first call
250 SetVendorName(wxT("gnuplot"));
251 SetAppName(wxT("gnuplot-wxt"));
252 wxConfigBase *pConfig = wxConfigBase::Get();
253 /* this will force writing back of the defaults for all values
254 * if they're not present in the config - this can give the user an idea
255 * of all possible settings */
256 pConfig->SetRecordDefaults();
258 return true; /* means that process must continue */
261 /* load an icon from a PNG file embedded as a C array */
262 void wxtApp::LoadPngIcon(const unsigned char *embedded_png, int length, int icon_number)
264 wxMemoryInputStream pngstream(embedded_png, length);
265 toolBarBitmaps[icon_number] = new wxBitmap(wxImage(pngstream, wxBITMAP_TYPE_PNG));
269 void wxtApp::LoadCursor(wxCursor &cursor, const char* xpm_bits[])
271 int hotspot_x, hotspot_y;
272 wxBitmap cursor_bitmap = wxBitmap(xpm_bits);
273 wxImage cursor_image = cursor_bitmap.ConvertToImage();
274 /* XPM spec : first string is :
275 * width height ncolors charperpixel hotspotx hotspoty */
276 sscanf(xpm_bits[0], "%*d %*d %*d %*d %d %d", &hotspot_x, &hotspot_y);
277 cursor_image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, hotspot_x);
278 cursor_image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, hotspot_y);
279 cursor = wxCursor(cursor_image);
283 * In a pure wxWidgets app, the returned int is the exit status of the app.
284 * Here it is not used. */
287 FPRINTF((stderr,"wxtApp::OnExit\n"));
288 /* clean up: Set() returns the active config object as Get() does, but unlike
289 * Get() it doesn't try to create one if there is none (definitely not what
291 delete wxConfigBase::Set((wxConfigBase *) NULL);
295 /* will gently terminate the gui thread */
296 void wxtApp::OnExitLoop( wxCommandEvent& WXUNUSED(event) )
298 FPRINTF((stderr,"wxtApp::OnExitLoop\n"));
299 wxTheApp->ExitMainLoop();
302 /* ---------------------------------------------------------------------------
303 * Frame : the main windows (one for each plot)
304 * ----------------------------------------------------------------------------*/
306 /* frame constructor*/
307 wxtFrame::wxtFrame( const wxString& title, wxWindowID id, int xpos, int ypos, int width, int height )
308 : wxFrame((wxFrame *)NULL, id, title, wxPoint(xpos,ypos),
309 wxSize(width,height), wxDEFAULT_FRAME_STYLE|wxWANTS_CHARS)
311 FPRINTF((stderr,"wxtFrame constructor\n"));
313 /* used to check for panel initialization */
316 /* initialize the state of the configuration dialog */
317 config_displayed = false;
319 /* set up the window icon, in several resolutions */
322 /* set up the status bar, and fill it with an empty
323 * string. It will be immediately overriden by gnuplot. */
325 SetStatusText( wxT("") );
327 /* set up the toolbar */
328 wxToolBar * toolbar = CreateToolBar();
329 /* With wxMSW, default toolbar size is only 16x15. */
330 toolbar->SetToolBitmapSize(wxSize(16,16));
332 toolbar->AddTool(Toolbar_CopyToClipboard, wxT("Copy"),
333 *(toolBarBitmaps[0]), wxT("Copy the plot to clipboard"));
335 toolbar->AddSeparator();
336 toolbar->AddTool(Toolbar_Replot, wxT("Replot"),
337 *(toolBarBitmaps[1]), wxT("Replot"));
338 toolbar->AddTool(Toolbar_ToggleGrid, wxT("Toggle grid"),
339 *(toolBarBitmaps[2]),wxNullBitmap,wxITEM_NORMAL, wxT("Toggle grid"));
340 toolbar->AddTool(Toolbar_ZoomPrevious, wxT("Previous zoom"),
341 *(toolBarBitmaps[3]), wxT("Apply the previous zoom settings"));
342 toolbar->AddTool(Toolbar_ZoomNext, wxT("Next zoom"),
343 *(toolBarBitmaps[4]), wxT("Apply the next zoom settings"));
344 toolbar->AddTool(Toolbar_Autoscale, wxT("Autoscale"),
345 *(toolBarBitmaps[5]), wxT("Apply autoscale"));
347 toolbar->AddSeparator();
348 toolbar->AddTool(Toolbar_Config, wxT("Terminal configuration"),
349 *(toolBarBitmaps[6]), wxT("Open configuration dialog"));
350 toolbar->AddTool(Toolbar_Help, wxT("Help"),
351 *(toolBarBitmaps[7]), wxT("Open help dialog"));
354 FPRINTF((stderr,"wxtFrame constructor 2\n"));
356 /* build the panel, which will contain the visible device context */
357 panel = new wxtPanel( this, this->GetId(), this->GetClientSize() );
359 /* setting minimum height and width for the window */
360 SetSizeHints(100, 100);
362 FPRINTF((stderr,"wxtFrame constructor 3\n"));
366 /* toolbar event : Copy to clipboard
367 * We will copy the panel to a bitmap, using platform-independant wxWidgets functions */
368 void wxtFrame::OnCopy( wxCommandEvent& WXUNUSED( event ) )
370 FPRINTF((stderr,"Copy to clipboard\n"));
371 int width = panel->plot.device_xmax, height = panel->plot.device_ymax;
372 wxBitmap cp_bitmap(width,height);
374 wxClientDC dc(panel);
376 cp_dc.SelectObject(cp_bitmap);
377 cp_dc.Blit(0,0,width,height,&dc,0,0);
378 cp_dc.SelectObject(wxNullBitmap);
380 wxTheClipboard->UsePrimarySelection(false);
381 /* SetData clears the clipboard */
382 if ( wxTheClipboard->Open() ) {
383 wxTheClipboard->SetData(new wxBitmapDataObject(cp_bitmap));
384 wxTheClipboard->Close();
386 wxTheClipboard->Flush();
390 /* toolbar event : Replot */
391 void wxtFrame::OnReplot( wxCommandEvent& WXUNUSED( event ) )
393 if ( this->GetId()==wxt_window_number )
394 wxt_exec_event(GE_keypress, 0, 0, 'e' , 0, this->GetId());
397 /* toolbar event : Toggle Grid */
398 void wxtFrame::OnToggleGrid( wxCommandEvent& WXUNUSED( event ) )
400 if ( this->GetId()==wxt_window_number )
401 wxt_exec_event(GE_keypress, 0, 0, 'g', 0, this->GetId());
404 /* toolbar event : Previous Zoom in history */
405 void wxtFrame::OnZoomPrevious( wxCommandEvent& WXUNUSED( event ) )
407 if ( this->GetId()==wxt_window_number )
408 wxt_exec_event(GE_keypress, 0, 0, 'p', 0, this->GetId());
411 /* toolbar event : Next Zoom in history */
412 void wxtFrame::OnZoomNext( wxCommandEvent& WXUNUSED( event ) )
414 if ( this->GetId()==wxt_window_number )
415 wxt_exec_event(GE_keypress, 0, 0, 'n', 0, this->GetId());
418 /* toolbar event : Autoscale */
419 void wxtFrame::OnAutoscale( wxCommandEvent& WXUNUSED( event ) )
421 if ( this->GetId()==wxt_window_number )
422 wxt_exec_event(GE_keypress, 0, 0, 'a', 0, this->GetId());
426 /* toolbar event : Config */
427 void wxtFrame::OnConfig( wxCommandEvent& WXUNUSED( event ) )
429 /* if we have already opened a dialog, just raise it */
430 if (config_displayed) {
431 config_dialog->Raise();
435 /* otherwise, open a dialog */
436 config_displayed = true;
437 config_dialog = new wxtConfigDialog(this);
438 config_dialog->Show(true);
442 /* toolbar event : Help */
443 void wxtFrame::OnHelp( wxCommandEvent& WXUNUSED( event ) )
445 wxMessageBox( wxString(wxT("You are using an interactive terminal "\
446 "based on wxWidgets for the interface, Cairo "\
447 "for the drawing facilities, and Pango for the text layouts.\n"\
448 "Please note that toolbar icons in the terminal "\
449 "don't reflect the whole range of mousing "\
450 "possibilities in the terminal.\n"\
451 "Hit 'h' in the plot window "\
452 "and a help message for mouse commands "\
453 "will appear in the gnuplot console.\n"\
454 "See also 'help mouse'.\n")),
455 wxT("wxWidgets terminal help"), wxOK | wxICON_INFORMATION, this );
458 /* called on Close() (menu or window manager) */
459 void wxtFrame::OnClose( wxCloseEvent& event )
461 FPRINTF((stderr,"OnClose\n"));
462 if ( event.CanVeto() ) {
463 /* Default behaviour when Quit is clicked, or the window cross X */
467 else /* Should not happen, but just in case */
471 /* when the window is resized,
472 * resize the panel to fit in the frame.
473 * Note : can't simply use "replot", as it doesn't work with multiplot mode */
474 void wxtFrame::OnSize( wxSizeEvent& event )
476 FPRINTF((stderr,"frame OnSize\n"));
478 /* Under Windows the frame receives an OnSize event before being completely initialized.
479 * So we must check for the panel to be properly initialized before.*/
481 panel->SetSize( this->GetClientSize() );
484 /* ---------------------------------------------------------------------------
485 * Panel : the space used for the plot, between the toolbar and the statusbar
486 * ----------------------------------------------------------------------------*/
489 * Note : under Windows, wxDefaultPosition makes the panel hide the toolbar */
490 wxtPanel::wxtPanel( wxWindow *parent, wxWindowID id, const wxSize& size )
491 : wxPanel( parent, id, wxPoint(0,0) /*wxDefaultPosition*/, size, wxWANTS_CHARS )
493 FPRINTF((stderr,"panel constructor\n"));
495 /* initialisations */
496 gp_cairo_initialize_plot(&plot);
497 GetSize(&(plot.device_xmax),&(plot.device_ymax));
499 settings_queued = false;
507 zoom_string1 = wxT("");
508 zoom_string2 = wxT("");
517 #if defined(GTK_SURFACE)
519 #elif defined(__WXMSW__)
522 #else /* IMAGE_SURFACE */
527 FPRINTF((stderr,"panel constructor4\n"));
529 /* create the device context to be drawn */
530 wxt_cairo_create_context();
532 FPRINTF((stderr,"panel constructor5\n"));
535 wxt_cairo_create_bitmap();
537 FPRINTF((stderr,"panel constructor6\n"));
542 wxtPanel::~wxtPanel()
544 FPRINTF((stderr,"panel destructor\n"));
545 wxt_cairo_free_context();
547 /* clear the command list, free the allocated memory */
551 /* temporary store new settings values to be applied for the next plot */
552 void wxtPanel::wxt_settings_queue(TBOOLEAN antialiasing,
553 TBOOLEAN oversampling,
557 settings_queued = true;
558 antialiasing_queued = antialiasing;
559 oversampling_queued = oversampling;
560 hinting_queued = hinting_setting;
561 mutex_queued.Unlock();
564 /* apply queued settings */
565 void wxtPanel::wxt_settings_apply()
568 if (settings_queued) {
569 plot.antialiasing = antialiasing_queued;
570 plot.oversampling = oversampling_queued;
571 plot.hinting = hinting_queued;
572 settings_queued = false;
574 mutex_queued.Unlock();
577 /* clear the command list, free the allocated memory */
578 void wxtPanel::ClearCommandlist()
580 command_list_mutex.Lock();
582 command_list_t::iterator iter; /*declare the iterator*/
584 /* run through the list, and free allocated memory */
585 for(iter = command_list.begin(); iter != command_list.end(); ++iter) {
586 if (iter->command == command_enhanced_put_text ||
587 iter->command == command_put_text ||
588 iter->command == command_set_font)
589 delete[] iter->string;
590 if (iter->command == command_filled_polygon)
591 delete[] iter->corners;
593 if (iter->command == command_image)
594 delete[] iter->image;
595 #endif /* WITH_IMAGE */
598 command_list.clear();
599 command_list_mutex.Unlock();
603 /* method called when the panel has to be painted
604 * -> Refresh(), window dragged, dialogs over the window, etc. */
605 void wxtPanel::OnPaint( wxPaintEvent &WXUNUSED(event) )
607 /* Constructor of the device context */
609 DrawToDC(dc, GetUpdateRegion());
612 /* same as OnPaint, but can be directly called by a user function */
613 void wxtPanel::Draw()
616 wxBufferedDC buffered_dc(&dc, wxSize(plot.device_xmax, plot.device_ymax));
617 wxRegion region(0, 0, plot.device_xmax, plot.device_ymax);
618 DrawToDC(buffered_dc, region);
621 /* copy the plot to the panel, draw zoombow and ruler needed */
622 void wxtPanel::DrawToDC(wxDC &dc, wxRegion ®ion)
626 /* TODO extend the region mechanism to surfaces other than GTK_SURFACE */
628 wxRegionIterator upd(region);
629 int vX,vY,vW,vH; /* Dimensions of client area in pixels */
637 FPRINTF((stderr,"OnPaint %d,%d,%d,%d\n",vX,vY,vW,vH));
638 /* Repaint this rectangle */
640 gdk_draw_drawable(dc.GetWindow(),
648 #elif defined(__WXMSW__)
649 BitBlt((HDC) dc.GetHDC(), 0, 0, plot.device_xmax, plot.device_ymax, hdc, 0, 0, SRCCOPY);
651 dc.DrawBitmap(*cairo_bitmap, 0, 0, false);
654 /* fill in gray when the aspect ratio conservation has let empty space in the panel */
655 if (plot.device_xmax*plot.ymax > plot.device_ymax*plot.xmax) {
656 dc.SetPen( *wxTRANSPARENT_PEN );
657 dc.SetBrush( wxBrush( wxT("LIGHT GREY"), wxSOLID ) );
658 dc.DrawRectangle((int) (plot.xmax/plot.oversampling_scale*plot.xscale),
660 plot.device_xmax - (int) (plot.xmax/plot.oversampling_scale*plot.xscale),
662 } else if (plot.device_xmax*plot.ymax < plot.device_ymax*plot.xmax) {
663 dc.SetPen( *wxTRANSPARENT_PEN );
664 dc.SetBrush( wxBrush( wxT("LIGHT GREY"), wxSOLID ) );
666 (int) (plot.ymax/plot.oversampling_scale*plot.yscale),
668 (int) (plot.device_ymax - plot.ymax/plot.oversampling_scale*plot.yscale));
673 tmp_pen = wxPen(wxT("black"), 1, wxSOLID);
674 tmp_pen.SetCap( wxCAP_ROUND );
675 dc.SetPen( tmp_pen );
676 dc.SetLogicalFunction( wxINVERT );
677 dc.DrawLine( zoom_x1, zoom_y1, mouse_x, zoom_y1 );
678 dc.DrawLine( mouse_x, zoom_y1, mouse_x, mouse_y );
679 dc.DrawLine( mouse_x, mouse_y, zoom_x1, mouse_y );
680 dc.DrawLine( zoom_x1, mouse_y, zoom_x1, zoom_y1 );
681 dc.SetPen( *wxTRANSPARENT_PEN );
682 dc.SetBrush( wxBrush( wxT("LIGHT BLUE"), wxSOLID ) );
683 dc.SetLogicalFunction( wxAND );
684 dc.DrawRectangle( zoom_x1, zoom_y1, mouse_x -zoom_x1, mouse_y -zoom_y1);
685 dc.SetLogicalFunction( wxCOPY );
687 dc.SetFont( wxFont( (int) plot.fontsize, wxFONTFAMILY_DEFAULT,
688 wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false,
689 wxString(plot.fontname, wxConvLocal) ) );
691 dc.DrawText( zoom_string1.BeforeFirst(wxT('\r')),
692 zoom_x1, zoom_y1 - term->v_char/plot.oversampling_scale);
693 dc.DrawText( zoom_string1.AfterFirst(wxT('\r')),
696 dc.DrawText( zoom_string2.BeforeFirst(wxT('\r')),
697 mouse_x, mouse_y - term->v_char/plot.oversampling_scale);
698 dc.DrawText( zoom_string2.AfterFirst(wxT('\r')),
701 /* if we have to redraw the zoombox, it is with another size,
702 * so it will be issued later and we can disable it now */
707 tmp_pen = wxPen(wxT("black"), 1, wxSOLID);
708 tmp_pen.SetCap(wxCAP_BUTT);
709 dc.SetPen( tmp_pen );
710 dc.SetLogicalFunction( wxINVERT );
711 dc.CrossHair( (int)wxt_ruler_x, (int)wxt_ruler_y );
712 dc.SetLogicalFunction( wxCOPY );
715 if (wxt_ruler && wxt_ruler_lineto) {
716 tmp_pen = wxPen(wxT("black"), 1, wxSOLID);
717 tmp_pen.SetCap(wxCAP_BUTT);
718 dc.SetPen( tmp_pen );
719 dc.SetLogicalFunction( wxINVERT );
720 dc.DrawLine((int)wxt_ruler_x, (int)wxt_ruler_y, mouse_x, mouse_y);
721 dc.SetLogicalFunction( wxCOPY );
727 /* avoid flickering under win32 */
728 void wxtPanel::OnEraseBackground( wxEraseEvent &WXUNUSED(event) )
732 /* when the window is resized */
733 void wxtPanel::OnSize( wxSizeEvent& event )
735 /* don't do anything if term variables are not initialized */
736 if (plot.xmax == 0 || plot.ymax == 0)
739 /* update window size, and scaling variables */
740 GetSize(&(plot.device_xmax),&(plot.device_ymax));
742 double new_xscale, new_yscale;
744 new_xscale = ((double) plot.device_xmax)*plot.oversampling_scale/((double) plot.xmax);
745 new_yscale = ((double) plot.device_ymax)*plot.oversampling_scale/((double) plot.ymax);
747 /* We will keep the aspect ratio constant */
748 if (new_yscale < new_xscale) {
749 plot.xscale = new_yscale;
750 plot.yscale = new_yscale;
752 plot.xscale = new_xscale;
753 plot.yscale = new_xscale;
755 FPRINTF((stderr,"panel OnSize %d %d %lf %lf\n",
756 plot.device_xmax, plot.device_ymax, plot.xscale,plot.yscale));
758 /* create a new cairo context of the good size */
759 wxt_cairo_create_context();
760 /* redraw the plot with the new scaling */
765 /* when the mouse is moved over the panel */
766 void wxtPanel::OnMotion( wxMouseEvent& event )
768 /* Get and store mouse position for _put_tmp_text() and key events (ruler) */
769 mouse_x = event.GetX();
770 mouse_y = event.GetY();
772 UpdateModifiers(event);
774 /* update the ruler_lineto thing */
775 if (wxt_ruler && wxt_ruler_lineto)
778 /* informs gnuplot */
779 if ( this->GetId()==wxt_window_number )
780 wxt_exec_event(GE_motion,
781 (int)gnuplot_x( &plot, mouse_x ),
782 (int)gnuplot_y( &plot, mouse_y ),
783 0, 0, this->GetId());
786 /* mouse "click" event */
787 void wxtPanel::OnLeftDown( wxMouseEvent& event )
790 x = (int) gnuplot_x( &plot, event.GetX() );
791 y = (int) gnuplot_y( &plot, event.GetY() );
793 UpdateModifiers(event);
795 if ( this->GetId()==wxt_window_number )
796 wxt_exec_event(GE_buttonpress, x, y, 1, 0, this->GetId());
799 /* mouse "click" event */
800 void wxtPanel::OnLeftUp( wxMouseEvent& event )
803 x = (int) gnuplot_x( &plot, event.GetX() );
804 y = (int) gnuplot_y( &plot, event.GetY() );
806 UpdateModifiers(event);
808 if ( this->GetId()==wxt_window_number ) {
809 wxt_exec_event(GE_buttonrelease, x, y, 1, (int) left_button_sw.Time(), this->GetId());
810 /* start a watch to send the time elapsed between up and down */
811 left_button_sw.Start();
815 /* mouse "click" event */
816 void wxtPanel::OnMiddleDown( wxMouseEvent& event )
819 x = (int) gnuplot_x( &plot, event.GetX() );
820 y = (int) gnuplot_y( &plot, event.GetY() );
822 UpdateModifiers(event);
824 if ( this->GetId()==wxt_window_number )
825 wxt_exec_event(GE_buttonpress, x, y, 2, 0, this->GetId());
828 /* mouse "click" event */
829 void wxtPanel::OnMiddleUp( wxMouseEvent& event )
832 x = (int) gnuplot_x( &plot, event.GetX() );
833 y = (int) gnuplot_y( &plot, event.GetY() );
835 UpdateModifiers(event);
837 if ( this->GetId()==wxt_window_number ) {
838 wxt_exec_event(GE_buttonrelease, x, y, 2,
839 (int) middle_button_sw.Time(), this->GetId());
840 /* start a watch to send the time elapsed between up and down */
841 middle_button_sw.Start();
845 /* mouse "click" event */
846 void wxtPanel::OnRightDown( wxMouseEvent& event )
849 x = (int) gnuplot_x( &plot, event.GetX() );
850 y = (int) gnuplot_y( &plot, event.GetY() );
852 UpdateModifiers(event);
854 if ( this->GetId()==wxt_window_number )
855 wxt_exec_event(GE_buttonpress, x, y, 3, 0, this->GetId());
858 /* mouse "click" event */
859 void wxtPanel::OnRightUp( wxMouseEvent& event )
862 x = (int) gnuplot_x( &plot, event.GetX() );
863 y = (int) gnuplot_y( &plot, event.GetY() );
865 UpdateModifiers(event);
867 if ( this->GetId()==wxt_window_number ) {
868 wxt_exec_event(GE_buttonrelease, x, y, 3, (int) right_button_sw.Time(), this->GetId());
869 /* start a watch to send the time elapsed between up and down */
870 right_button_sw.Start();
874 /* the state of the modifiers is checked each time a key is pressed instead of
875 * tracking the press and release events of the modifiers keys, because the
876 * window manager catches some combinations, like ctrl+F1, and thus we do not
877 * receive a release event in this case */
878 void wxtPanel::UpdateModifiers( wxMouseEvent& event )
880 int current_modifier_mask = 0;
882 /* retrieve current modifier mask from the wxEvent */
883 current_modifier_mask |= (event.AltDown() ? (1<<2) : 0);
884 current_modifier_mask |= (event.ControlDown() ? (1<<1) : 0);
885 current_modifier_mask |= (event.ShiftDown() ? (1) : 0);
887 /* update if changed */
888 if (modifier_mask != current_modifier_mask) {
889 modifier_mask = current_modifier_mask;
890 wxt_exec_event(GE_modifier, 0, 0, modifier_mask, 0, this->GetId());
894 /* a key has been pressed, modifiers have already been handled.
895 * We receive keycodes here, and we send corresponding events to gnuplot main thread */
896 void wxtPanel::OnKeyDownChar( wxKeyEvent &event )
898 int keycode = event.GetKeyCode();
901 /* this is the same code as in UpdateModifiers(), but the latter method cannot be
902 * used here because wxKeyEvent and wxMouseEvent are different classes, both of them
903 * derive from wxEvent, but wxEvent does not have the necessary AltDown() and friends */
904 int current_modifier_mask = 0;
906 /* retrieve current modifier mask from the wxEvent */
907 current_modifier_mask |= (event.AltDown() ? (1<<2) : 0);
908 current_modifier_mask |= (event.ControlDown() ? (1<<1) : 0);
909 current_modifier_mask |= (event.ShiftDown() ? (1) : 0);
911 /* update if changed */
912 if (modifier_mask != current_modifier_mask) {
913 modifier_mask = current_modifier_mask;
914 wxt_exec_event(GE_modifier, 0, 0, modifier_mask, 0, this->GetId());
917 #define WXK_GPKEYCODE(wxkey,kcode) case wxkey : gp_keycode=kcode; break;
922 if ((wxt_ctrl==yes && event.ControlDown())
924 RaiseConsoleWindow();
931 /* ctrl+q does not send 113 but 17 */
932 /* WARNING : may be the same for other combinations */
934 if ((wxt_ctrl==yes && event.ControlDown())
936 /* closes terminal window */
937 this->GetParent()->Close(false);
943 WXK_GPKEYCODE(WXK_BACK,GP_BackSpace);
944 WXK_GPKEYCODE(WXK_TAB,GP_Tab);
945 WXK_GPKEYCODE(WXK_RETURN,GP_Return);
946 WXK_GPKEYCODE(WXK_ESCAPE,GP_Escape);
947 WXK_GPKEYCODE(WXK_DELETE,GP_Delete);
948 default : gp_keycode = keycode; break; /* exact solution */
952 WXK_GPKEYCODE(WXK_PAUSE,GP_Pause);
953 WXK_GPKEYCODE(WXK_SCROLL,GP_Scroll_Lock);
954 WXK_GPKEYCODE(WXK_INSERT,GP_Insert);
955 WXK_GPKEYCODE(WXK_HOME,GP_Home);
956 WXK_GPKEYCODE(WXK_LEFT,GP_Left);
957 WXK_GPKEYCODE(WXK_UP,GP_Up);
958 WXK_GPKEYCODE(WXK_RIGHT,GP_Right);
959 WXK_GPKEYCODE(WXK_DOWN,GP_Down);
960 WXK_GPKEYCODE(WXK_PAGEUP,GP_PageUp);
961 WXK_GPKEYCODE(WXK_PAGEDOWN,GP_PageDown);
962 WXK_GPKEYCODE(WXK_END,GP_End);
963 WXK_GPKEYCODE(WXK_NUMPAD_SPACE,GP_KP_Space);
964 WXK_GPKEYCODE(WXK_NUMPAD_TAB,GP_KP_Tab);
965 WXK_GPKEYCODE(WXK_NUMPAD_ENTER,GP_KP_Enter);
966 WXK_GPKEYCODE(WXK_NUMPAD_F1,GP_KP_F1);
967 WXK_GPKEYCODE(WXK_NUMPAD_F2,GP_KP_F2);
968 WXK_GPKEYCODE(WXK_NUMPAD_F3,GP_KP_F3);
969 WXK_GPKEYCODE(WXK_NUMPAD_F4,GP_KP_F4);
971 WXK_GPKEYCODE(WXK_NUMPAD_INSERT,GP_KP_Insert);
972 WXK_GPKEYCODE(WXK_NUMPAD_END,GP_KP_End);
973 WXK_GPKEYCODE(WXK_NUMPAD_DOWN,GP_KP_Down);
974 WXK_GPKEYCODE(WXK_NUMPAD_PAGEDOWN,GP_KP_Page_Down);
975 WXK_GPKEYCODE(WXK_NUMPAD_LEFT,GP_KP_Left);
976 WXK_GPKEYCODE(WXK_NUMPAD_BEGIN,GP_KP_Begin);
977 WXK_GPKEYCODE(WXK_NUMPAD_RIGHT,GP_KP_Right);
978 WXK_GPKEYCODE(WXK_NUMPAD_HOME,GP_KP_Home);
979 WXK_GPKEYCODE(WXK_NUMPAD_UP,GP_KP_Up);
980 WXK_GPKEYCODE(WXK_NUMPAD_PAGEUP,GP_KP_Page_Up);
982 WXK_GPKEYCODE(WXK_NUMPAD_DELETE,GP_KP_Delete);
983 WXK_GPKEYCODE(WXK_NUMPAD_EQUAL,GP_KP_Equal);
984 WXK_GPKEYCODE(WXK_NUMPAD_MULTIPLY,GP_KP_Multiply);
985 WXK_GPKEYCODE(WXK_NUMPAD_ADD,GP_KP_Add);
986 WXK_GPKEYCODE(WXK_NUMPAD_SEPARATOR,GP_KP_Separator);
987 WXK_GPKEYCODE(WXK_NUMPAD_SUBTRACT,GP_KP_Subtract);
988 WXK_GPKEYCODE(WXK_NUMPAD_DECIMAL,GP_KP_Decimal);
989 WXK_GPKEYCODE(WXK_NUMPAD_DIVIDE,GP_KP_Divide);
990 WXK_GPKEYCODE(WXK_NUMPAD0,GP_KP_0);
991 WXK_GPKEYCODE(WXK_NUMPAD1,GP_KP_1);
992 WXK_GPKEYCODE(WXK_NUMPAD2,GP_KP_2);
993 WXK_GPKEYCODE(WXK_NUMPAD3,GP_KP_3);
994 WXK_GPKEYCODE(WXK_NUMPAD4,GP_KP_4);
995 WXK_GPKEYCODE(WXK_NUMPAD5,GP_KP_5);
996 WXK_GPKEYCODE(WXK_NUMPAD6,GP_KP_6);
997 WXK_GPKEYCODE(WXK_NUMPAD7,GP_KP_7);
998 WXK_GPKEYCODE(WXK_NUMPAD8,GP_KP_8);
999 WXK_GPKEYCODE(WXK_NUMPAD9,GP_KP_9);
1000 WXK_GPKEYCODE(WXK_F1,GP_F1);
1001 WXK_GPKEYCODE(WXK_F2,GP_F2);
1002 WXK_GPKEYCODE(WXK_F3,GP_F3);
1003 WXK_GPKEYCODE(WXK_F4,GP_F4);
1004 WXK_GPKEYCODE(WXK_F5,GP_F5);
1005 WXK_GPKEYCODE(WXK_F6,GP_F6);
1006 WXK_GPKEYCODE(WXK_F7,GP_F7);
1007 WXK_GPKEYCODE(WXK_F8,GP_F8);
1008 WXK_GPKEYCODE(WXK_F9,GP_F9);
1009 WXK_GPKEYCODE(WXK_F10,GP_F10);
1010 WXK_GPKEYCODE(WXK_F11,GP_F11);
1011 WXK_GPKEYCODE(WXK_F12,GP_F12);
1012 default : return; /* probably not ideal */
1016 /* only send char events to gnuplot if we are the active window */
1017 if ( this->GetId()==wxt_window_number ) {
1018 FPRINTF((stderr,"sending char event\n"));
1019 wxt_exec_event(GE_keypress, (int) gnuplot_x( &plot, mouse_x ),
1020 (int) gnuplot_y( &plot, mouse_y ), gp_keycode, 0, this->GetId());
1023 /* The following wxWidgets keycodes are not mapped :
1024 * WXK_ALT, WXK_CONTROL, WXK_SHIFT,
1025 * WXK_LBUTTON, WXK_RBUTTON, WXK_CANCEL, WXK_MBUTTON,
1026 * WXK_CLEAR, WXK_MENU,
1027 * WXK_NUMPAD_PRIOR, WXK_NUMPAD_NEXT,
1028 * WXK_CAPITAL, WXK_PRIOR, WXK_NEXT, WXK_SELECT,
1029 * WXK_PRINT, WXK_EXECUTE, WXK_SNAPSHOT, WXK_HELP,
1030 * WXK_MULTIPLY, WXK_ADD, WXK_SEPARATOR, WXK_SUBTRACT,
1031 * WXK_DECIMAL, WXK_DIVIDE, WXK_NUMLOCK, WXK_WINDOWS_LEFT,
1032 * WXK_WINDOWS_RIGHT, WXK_WINDOWS_MENU, WXK_COMMAND
1033 * The following gnuplot keycodes are not mapped :
1034 * GP_Linefeed, GP_Clear, GP_Sys_Req, GP_Begin
1037 #endif /*USE_MOUSE*/
1039 /* ====license information====
1040 * The following code originates from other gnuplot files,
1041 * and is not subject to the alternative license statement.
1045 /* FIXME : this code should be deleted, and the feature removed or handled differently,
1046 * because it is highly platform-dependant, is not reliable because
1047 * of a lot of factors (WINDOWID not set, multiple tabs in gnome-terminal, mechanisms
1048 * to prevent focus stealing) and is inconsistent with global bindings mechanism ) */
1049 void wxtPanel::RaiseConsoleWindow()
1053 unsigned long windowid = 0;
1054 /* retrieve XID of gnuplot window */
1055 window_env = getenv("WINDOWID");
1057 sscanf(window_env, "%lu", &windowid);
1059 char *ptr = getenv("KONSOLE_DCOP_SESSION"); /* Try KDE's Konsole first. */
1061 /* We are in KDE's Konsole, or in a terminal window detached from a Konsole.
1062 * In order to active a tab:
1063 * 1. get environmental variable KONSOLE_DCOP_SESSION: it includes konsole id and session name
1065 * $WINDOWID is defined and it equals
1066 * `dcop konsole-3152 konsole-mainwindow#1 getWinID`
1067 * (KDE 3.2) or when $WINDOWID is undefined (KDE 3.1), then run commands
1068 * dcop konsole-3152 konsole activateSession session-2; \
1069 * dcop konsole-3152 konsole-mainwindow#1 raise
1070 * Note: by $WINDOWID we mean gnuplot's text console WINDOWID.
1071 * Missing: focus is not transferred unless $WINDOWID is defined (should be fixed in KDE 3.2).
1073 * Implementation and tests on KDE 3.1.4: Petr Mikulik.
1075 char *konsole_name = NULL;
1077 /* use 'while' to easily break out (aka catch exception) */
1082 ptr = strchr(ptr, '(');
1083 /* the string for tab nb 4 looks like 'DCOPRef(konsole-2866, session-4)' */
1085 konsole_name = strdup(ptr+1);
1086 konsole_tab = strchr(konsole_name, ',');
1087 if (!konsole_tab) break;
1089 ptr = strchr(konsole_tab, ')');
1091 cmd = (char*) malloc(strlen(konsole_name) + strlen(konsole_tab) + 64);
1092 sprintf(cmd, "dcop %s konsole-mainwindow#1 getWinID 2>/dev/null", konsole_name);
1093 /* is 2>/dev/null portable among various shells? */
1094 p = popen(cmd, "r");
1096 fscanf(p, "%lu", &w);
1099 if (windowid) { /* $WINDOWID is known */
1100 if (w != windowid) break;
1101 /* `dcop getWinID`==$WINDOWID thus we are running in a window detached from Konsole */
1104 /* $WINDOWID has not been known (KDE 3.1), thus set it up */
1106 sprintf(cmd, "dcop %s konsole activateSession %s", konsole_name, konsole_tab);
1109 if (konsole_name) free(konsole_name);
1112 /* now test for GNOME multitab console */
1113 /* ... if somebody bothers to implement it ... */
1114 /* we are not running in any known (implemented) multitab console */
1117 gdk_window_raise(gdk_window_foreign_new(windowid));
1118 gdk_window_focus(gdk_window_foreign_new(windowid), GDK_CURRENT_TIME);
1120 #endif /* USE_GTK */
1123 /* Make sure the text window is visible: */
1124 ShowWindow(textwin.hWndParent, SW_SHOW);
1125 /* and activate it (--> Keyboard focus goes there */
1126 BringWindowToTop(textwin.hWndParent);
1127 #endif /* _Windows */
1130 /* we assume that the console window is managed by PM, not by a X server */
1131 HSWITCH hSwitch = 0;
1134 /* get details of command-line window */
1135 hSwitch = WinQuerySwitchHandle(0, getpid());
1136 WinQuerySwitchEntry(hSwitch, &swGnu);
1137 hw = WinQueryWindow(swGnu.hwnd, QW_BOTTOM);
1138 WinSetFocus(HWND_DESKTOP, hw);
1139 WinSwitchToProgram(hSwitch);
1143 /* ====license information====
1144 * End of the non-relicensable portion.
1148 /* ------------------------------------------------------
1149 * Configuration dialog
1150 * ------------------------------------------------------*/
1152 /* configuration dialog : handler for a close event */
1153 void wxtConfigDialog::OnClose( wxCloseEvent& WXUNUSED( event ) )
1155 wxtFrame *parent = (wxtFrame *) GetParent();
1156 parent->config_displayed = false;
1160 /* configuration dialog : handler for a button event */
1161 void wxtConfigDialog::OnButton( wxCommandEvent& event )
1163 TBOOLEAN antialiasing;
1164 TBOOLEAN oversampling;
1166 wxConfigBase *pConfig = wxConfigBase::Get();
1168 TransferDataFromWindow();
1170 wxtFrame *parent = (wxtFrame *) GetParent();
1172 switch (event.GetId()) {
1177 /* changes are applied immediately */
1178 wxt_raise = raise_setting?yes:no;
1179 wxt_persist = persist_setting?yes:no;
1180 wxt_ctrl = ctrl_setting?yes:no;
1182 switch (rendering_setting) {
1184 antialiasing = FALSE;
1185 oversampling = FALSE;
1188 antialiasing = TRUE;
1189 oversampling = FALSE;
1193 antialiasing = TRUE;
1194 oversampling = TRUE;
1198 /* we cannot apply the new settings right away, because it would mess up
1199 * the plot in case of a window resize.
1200 * Instead, we queue the settings until the next plot. */
1201 parent->panel->wxt_settings_queue(antialiasing, oversampling, hinting_setting);
1203 if (!pConfig->Write(wxT("raise"), raise_setting))
1204 wxLogError(wxT("Cannot write raise"));
1205 if (!pConfig->Write(wxT("persist"), persist_setting))
1206 wxLogError(wxT("Cannot write persist"));
1207 if (!pConfig->Write(wxT("ctrl"), ctrl_setting))
1208 wxLogError(wxT("Cannot write ctrl"));
1209 if (!pConfig->Write(wxT("rendering"), rendering_setting))
1210 wxLogError(wxT("Cannot write rendering_setting"));
1211 if (!pConfig->Write(wxT("hinting"), hinting_setting))
1212 wxLogError(wxT("Cannot write hinting_setting"));
1214 case Config_CANCEL :
1221 /* Configuration dialog constructor */
1222 wxtConfigDialog::wxtConfigDialog(wxWindow* parent)
1223 : wxDialog(parent, -1, wxT("Terminal configuration"), wxDefaultPosition, wxDefaultSize,
1224 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1226 /* wxStaticBox *sb = new wxStaticBox( this, wxID_ANY, _T("&Explanation"),
1227 wxDefaultPosition, wxDefaultSize );
1228 wxStaticBoxSizer *wrapping_sizer = new wxStaticBoxSizer( sb, wxVERTICAL );
1229 wxStaticText *text1 = new wxStaticText(this, wxID_ANY,
1230 wxT("Options remembered between sessions, ")
1231 wxT("overriden by `set term wxt <options>`.\n\n"),
1232 wxDefaultPosition, wxSize(300, wxDefaultCoord));
1233 wrapping_sizer->Add(text1,wxSizerFlags(0).Align(0).Expand().Border(wxALL) );*/
1235 wxConfigBase *pConfig = wxConfigBase::Get();
1236 pConfig->Read(wxT("raise"),&raise_setting);
1237 pConfig->Read(wxT("persist"),&persist_setting);
1238 pConfig->Read(wxT("ctrl"),&ctrl_setting);
1239 pConfig->Read(wxT("rendering"),&rendering_setting);
1240 pConfig->Read(wxT("hinting"),&hinting_setting);
1242 wxCheckBox *check1 = new wxCheckBox (this, wxID_ANY,
1243 _T("Put the window at the top of your desktop after each plot (raise)"),
1244 wxDefaultPosition, wxDefaultSize, 0, wxGenericValidator(&raise_setting));
1245 wxCheckBox *check2 = new wxCheckBox (this, wxID_ANY,
1246 _T("Don't quit until all windows are closed (persist)"),
1247 wxDefaultPosition, wxDefaultSize, 0, wxGenericValidator(&persist_setting));
1248 wxCheckBox *check3 = new wxCheckBox (this, wxID_ANY,
1249 _T("Replace 'q' by <ctrl>+'q' and <space> by <ctrl>+<space> (ctrl)"),
1250 wxDefaultPosition, wxDefaultSize, 0, wxGenericValidator(&ctrl_setting));
1252 wxString choices[3];
1253 choices[0] = wxT("No antialiasing");
1254 choices[1] = wxT("Antialiasing");
1255 choices[2] = wxT("Antialiasing and oversampling");
1257 wxStaticBox *sb2 = new wxStaticBox( this, wxID_ANY,
1258 _T("Rendering options (applied to the next plot)"),
1259 wxDefaultPosition, wxDefaultSize );
1260 wxStaticBoxSizer *box_sizer2 = new wxStaticBoxSizer( sb2, wxVERTICAL );
1262 wxStaticText *text_rendering = new wxStaticText(this, wxID_ANY,
1263 wxT("Rendering method :"));
1264 wxChoice *box = new wxChoice (this, Config_Rendering, wxDefaultPosition, wxDefaultSize,
1265 3, choices, 0, wxGenericValidator(&rendering_setting));
1267 text_hinting = new wxStaticText(this, wxID_ANY,
1268 wxT("Hinting (100=full,0=none) :"));
1270 slider = new wxSlider(this, wxID_ANY, 0, 0, 100,
1271 wxDefaultPosition, wxDefaultSize,
1272 wxSL_HORIZONTAL|wxSL_LABELS,
1273 wxGenericValidator(&hinting_setting));
1275 if (rendering_setting != 2) {
1276 slider->Enable(false);
1277 text_hinting->Enable(false);
1279 box_sizer2->Add(text_rendering,wxSizerFlags().Align(0).Border(wxALL));
1280 box_sizer2->Add(box,wxSizerFlags().Align(0).Border(wxALL));
1281 box_sizer2->Add(text_hinting,wxSizerFlags().Align(0).Expand().Border(wxALL));
1282 box_sizer2->Add(slider,wxSizerFlags().Align(0).Expand().Border(wxALL));
1284 wxBoxSizer *hsizer = new wxBoxSizer( wxHORIZONTAL );
1285 hsizer->Add( new wxButton(this, Config_OK, wxT("OK")),
1286 wxSizerFlags().Align(0).Expand().Border(wxALL));
1287 hsizer->Add( new wxButton(this, Config_APPLY, wxT("Apply")),
1288 wxSizerFlags().Align(0).Expand().Border(wxALL));
1289 hsizer->Add( new wxButton(this, Config_CANCEL, wxT("Cancel")),
1290 wxSizerFlags().Align(0).Expand().Border(wxALL));
1292 wxBoxSizer *vsizer = new wxBoxSizer( wxVERTICAL );
1293 vsizer->Add(check1,wxSizerFlags().Align(0).Expand().Border(wxALL));
1294 vsizer->Add(check2,wxSizerFlags().Align(0).Expand().Border(wxALL));
1295 vsizer->Add(check3,wxSizerFlags().Align(0).Expand().Border(wxALL));
1296 vsizer->Add(box_sizer2,wxSizerFlags().Align(0).Expand().Border(wxALL));
1297 /*vsizer->Add(CreateButtonSizer(wxOK|wxCANCEL),wxSizerFlags().Align(0).Expand().Border(wxALL));*/
1298 vsizer->Add(hsizer,wxSizerFlags().Align(0).Expand().Border(wxALL));
1300 /* use the sizer for layout */
1302 /* set size hints to honour minimum size */
1303 vsizer->SetSizeHints( this );
1306 /* enable or disable the hinting slider depending on the selection of the oversampling method */
1307 void wxtConfigDialog::OnRendering( wxCommandEvent& event )
1309 if (event.GetInt() != 2) {
1310 slider->Enable(false);
1311 text_hinting->Enable(false);
1313 slider->Enable(true);
1314 text_hinting->Enable(true);
1318 /* ------------------------------------------------------
1319 * functions that are called by gnuplot
1320 * ------------------------------------------------------*/
1322 /* "Called once, when the device is first selected."
1323 * Is the 'main' function of the terminal. */
1326 FPRINTF((stderr,"Init\n"));
1328 if ( wxt_abort_init ) {
1329 fprintf(stderr,"Previous attempt to initialize wxWidgets has failed. Not retrying.\n");
1335 if ( wxt_status == STATUS_UNINITIALIZED ) {
1336 FPRINTF((stderr,"First Init\n"));
1339 /* the following is done in wxEntry() with wxMSW only */
1340 wxSetInstance(GetModuleHandle(NULL));
1341 wxApp::m_nCmdShow = SW_SHOW;
1344 if (!wxInitialize()) {
1345 fprintf(stderr,"Failed to initialize wxWidgets.\n");
1346 wxt_abort_init = true;
1350 /* app initialization */
1351 wxTheApp->CallOnInit();
1353 #if defined(__WXGTK__)||defined(__WXMAC__)
1354 /* Three commands to create the thread and run it.
1355 * We do this at first init only.
1356 * If the user sets another terminal and goes back to wxt,
1357 * the gui thread is already in action. */
1358 thread = new wxtThread();
1361 #elif defined (__WXMSW__)
1364 # error "Not implemented."
1365 #endif /*__WXMSW__*/
1369 /* initialize the gnuplot<->terminal event system state */
1370 wxt_change_thread_state(RUNNING);
1371 #endif /*USE_MOUSE*/
1373 FPRINTF((stderr,"First Init2\n"));
1374 #ifdef HAVE_LOCALE_H
1375 /* when wxGTK is initialised, GTK+ also sets the locale of the program itself;
1376 * we must revert it */
1377 setlocale(LC_NUMERIC, "C");
1378 #endif /*have_locale_h*/
1380 /* register call for "persist" effect and cleanup */
1381 GP_ATEXIT(wxt_atexit);
1386 /* try to find the requested window in the list of existing ones */
1387 wxt_current_window = wxt_findwindowbyid(wxt_window_number);
1389 /* open a new plot window if it does not exist */
1390 if ( wxt_current_window == NULL ) {
1391 FPRINTF((stderr,"opening a new plot window\n"));
1393 wxt_MutexGuiEnter();
1394 wxt_window_t window;
1395 window.id = wxt_window_number;
1396 /* create a new plot window and show it */
1398 if (strlen(wxt_title))
1399 /* NOTE : this assumes that the title is encoded in the locale charset.
1400 * This is probably a good assumption, but it is not guaranteed !
1401 * May be improved by using gnuplot encoding setting. */
1402 title << wxString(wxt_title, wxConvLocal);
1404 title.Printf(wxT("Gnuplot (window id : %d)"), window.id);
1405 window.frame = new wxtFrame( title, window.id, 50, 50, 640, 480 );
1406 window.frame->Show(true);
1407 FPRINTF((stderr,"new plot window opened\n"));
1408 /* make the panel able to receive keyboard input */
1409 window.frame->panel->SetFocus();
1410 /* set the default crosshair cursor */
1411 window.frame->panel->SetCursor(wxt_cursor_cross);
1412 /* creating the true context (at initialization, it may be a fake one).
1413 * Note : the frame must be shown for this to succeed */
1414 if (!window.frame->panel->plot.success)
1415 window.frame->panel->wxt_cairo_create_context();
1416 wxt_MutexGuiLeave();
1417 /* store the plot structure in the list and keep shortcuts */
1418 wxt_window_list.push_back(window);
1419 wxt_current_window = &(wxt_window_list.back());
1422 /* initialize helper pointers */
1423 wxt_current_panel = wxt_current_window->frame->panel;
1424 wxt_current_plot = &(wxt_current_panel->plot);
1425 wxt_current_command_list = &(wxt_current_panel->command_list);
1430 bool persist_setting;
1432 int rendering_setting;
1433 int hinting_setting;
1435 /* if needed, restore the setting from the config file/registry keys.
1436 * Unset values are set to default reasonable values. */
1437 wxConfigBase *pConfig = wxConfigBase::Get();
1439 if (!pConfig->Read(wxT("raise"), &raise_setting)) {
1440 pConfig->Write(wxT("raise"), true);
1441 raise_setting = true;
1443 if (wxt_raise==UNSET)
1444 wxt_raise = raise_setting?yes:no;
1446 if (!pConfig->Read(wxT("persist"), &persist_setting))
1447 pConfig->Write(wxT("persist"), false);
1449 if (!pConfig->Read(wxT("ctrl"), &ctrl_setting)) {
1450 pConfig->Write(wxT("ctrl"), false);
1451 ctrl_setting = false;
1453 if (wxt_ctrl==UNSET)
1454 wxt_ctrl = ctrl_setting?yes:no;
1456 if (!pConfig->Read(wxT("rendering"), &rendering_setting)) {
1457 pConfig->Write(wxT("rendering"), 2);
1458 rendering_setting = 2;
1460 switch (rendering_setting) {
1462 wxt_current_plot->antialiasing = FALSE;
1463 wxt_current_plot->oversampling = FALSE;
1466 wxt_current_plot->antialiasing = TRUE;
1467 wxt_current_plot->oversampling = FALSE;
1471 wxt_current_plot->antialiasing = TRUE;
1472 wxt_current_plot->oversampling = TRUE;
1476 if (!pConfig->Read(wxT("hinting"), &hinting_setting)) {
1477 pConfig->Write(wxT("hinting"), 100);
1478 hinting_setting = 100;
1480 wxt_current_plot->hinting = hinting_setting;
1482 /* accept the following commands from gnuplot */
1483 wxt_status = STATUS_OK;
1484 wxt_current_plot->interrupt = FALSE;
1487 wxt_sigint_restore();
1489 FPRINTF((stderr,"Init finished \n"));
1493 /* "Called just before a plot is going to be displayed."
1494 * Should clear the terminal. */
1497 if (wxt_status != STATUS_OK)
1501 /* performance watch - to be removed */
1505 /* The sequence of gnuplot commands is critical as it involves mutexes.
1506 * We replace the original interrupt handler with a custom one. */
1509 /* update the window scale factor first, cairo needs it */
1510 wxt_current_plot->xscale = 1.0;
1511 wxt_current_plot->yscale = 1.0;
1513 /* apply the queued rendering settings */
1514 wxt_current_panel->wxt_settings_apply();
1516 FPRINTF((stderr,"Graphics1\n"));
1518 wxt_MutexGuiEnter();
1519 /* set the transformation matrix of the context, and other details */
1520 /* depends on plot->xscale and plot->yscale */
1521 gp_cairo_initialize_context(wxt_current_plot);
1523 /* set or refresh terminal size according to the window size */
1524 /* oversampling_scale is updated in gp_cairo_initialize_context */
1525 term->xmax = (unsigned int) wxt_current_plot->device_xmax*wxt_current_plot->oversampling_scale;
1526 term->ymax = (unsigned int) wxt_current_plot->device_ymax*wxt_current_plot->oversampling_scale;
1527 wxt_current_plot->xmax = term->xmax;
1528 wxt_current_plot->ymax = term->ymax;
1529 /* initialize encoding */
1530 wxt_current_plot->encoding = encoding;
1532 wxt_MutexGuiLeave();
1534 /* set font details (hchar, vchar, h_tic, v_tic) according to settings */
1537 /* clear the command list, and free the allocated memory */
1538 wxt_current_panel->ClearCommandlist();
1541 wxt_sigint_restore();
1543 FPRINTF((stderr,"Graphics time %d xmax %d ymax %d v_char %d h_char %d\n",
1544 sw.Time(), term->xmax, term->ymax, term->v_char, term->h_char));
1549 if (wxt_status != STATUS_OK) {
1551 /* Inform gnuplot that we have finished plotting.
1552 * This avoids to lose the mouse after a interrupt.
1553 * Do this immediately, instead of posting an event which may not be processed. */
1561 FPRINTF((stderr,"Text0 %d\n", sw.Time())); /*performance watch*/
1563 /* translates the command list to a bitmap */
1564 wxt_MutexGuiEnter();
1565 wxt_current_panel->wxt_cairo_refresh();
1566 wxt_MutexGuiLeave();
1570 /* raise the window, conditionnaly to the user choice */
1571 wxt_MutexGuiEnter();
1572 wxt_raise_window(wxt_current_window,false);
1573 wxt_MutexGuiLeave();
1575 FPRINTF((stderr,"Text2 %d\n", sw.Time())); /*performance watch*/
1578 /* Inform gnuplot that we have finished plotting */
1579 wxt_exec_event(GE_plotdone, 0, 0, 0, 0, wxt_window_number );
1580 #endif /*USE_MOUSE*/
1583 wxt_sigint_restore();
1585 FPRINTF((stderr,"Text finished %d\n", sw.Time())); /*performance watch*/
1590 /* sent when gnuplot exits and when the terminal or the output change.*/
1591 FPRINTF((stderr,"wxt_reset\n"));
1593 if (wxt_status == STATUS_UNINITIALIZED)
1597 if (wxt_status == STATUS_INTERRUPT) {
1598 /* send "reset" event to restore the mouse system in a well-defined state.
1599 * Send it directly, not with wxt_exec_event(), which would only enqueue it,
1600 * but not process it. */
1601 FPRINTF((stderr,"send reset event to the mouse system\n"));
1602 event_reset((gp_event_t *)1); /* cancel zoombox etc. */
1604 /* clear the event list */
1605 wxt_clear_event_list();
1608 /* stop sending mouse events */
1609 FPRINTF((stderr,"change thread state\n"));
1610 wxt_change_thread_state(RUNNING);
1611 #endif /*USE_MOUSE*/
1613 FPRINTF((stderr,"wxt_reset ends\n"));
1616 void wxt_move(unsigned int x, unsigned int y)
1618 if (wxt_status != STATUS_OK)
1621 gp_command temp_command;
1623 temp_command.command = command_move;
1624 temp_command.x1 = x;
1625 temp_command.y1 = term->ymax - y;
1627 wxt_command_push(temp_command);
1630 void wxt_vector(unsigned int x, unsigned int y)
1632 if (wxt_status != STATUS_OK)
1635 gp_command temp_command;
1637 temp_command.command = command_vector;
1638 temp_command.x1 = x;
1639 temp_command.y1 = term->ymax - y;
1641 wxt_command_push(temp_command);
1644 void wxt_put_text(unsigned int x, unsigned int y, const char * string)
1646 if (wxt_status != STATUS_OK)
1649 gp_command temp_command;
1651 /* note : this test must be here, not when processing the command list,
1652 * because the user may have toggled the terminal option between two window resizing.*/
1653 /* if ignore_enhanced_text is set, draw with the normal routine.
1654 * This is meant to avoid enhanced syntax when the enhanced mode is on */
1655 if (wxt_enhanced_enabled && !ignore_enhanced_text)
1656 temp_command.command = command_enhanced_put_text;
1658 temp_command.command = command_put_text;
1660 temp_command.x1 = x;
1661 temp_command.y1 = term->ymax - y;
1662 /* Note : we must take '\0' (EndOfLine) into account */
1663 temp_command.string = new char[strlen(string)+1];
1664 strcpy(temp_command.string, string);
1666 wxt_command_push(temp_command);
1669 void wxt_linetype(int lt)
1671 if (wxt_status != STATUS_OK)
1674 gp_command temp_command;
1675 gp_command temp_command2;
1677 temp_command.command = command_color;
1678 temp_command.color = gp_cairo_linetype2color( lt );
1680 temp_command2.command = command_linestyle;
1682 temp_command2.integer_value = GP_CAIRO_DASH;
1684 temp_command2.integer_value = GP_CAIRO_SOLID;
1686 wxt_command_push(temp_command);
1687 wxt_command_push(temp_command2);
1691 /* - fonts are selected as strings "name,size".
1692 * - _set_font("") restores the terminal's default font.*/
1693 int wxt_set_font (const char *font)
1695 if (wxt_status != STATUS_OK)
1698 char fontname[MAX_ID_LEN + 1] = "";
1699 gp_command temp_command;
1702 temp_command.command = command_set_font;
1704 if (!font || !(*font)) {
1705 strncpy(fontname, "", sizeof(fontname));
1710 sep = strcspn(font,",");
1712 strncpy(fontname, font, sep);
1713 fontname[sep] = '\0';
1715 if (font[sep] == ',')
1716 sscanf(&(font[sep+1]), "%d", &fontsize);
1720 wxt_MutexGuiEnter();
1722 if ( strlen(fontname) == 0 ) {
1723 if ( strlen(wxt_set_fontname) == 0 )
1724 strncpy(fontname, "Sans", sizeof(fontname));
1726 strncpy(fontname, wxt_set_fontname, sizeof(fontname));
1729 if ( fontsize == 0 ) {
1730 if ( wxt_set_fontsize == 0 )
1733 fontsize = wxt_set_fontsize;
1737 /* Reset the term variables (hchar, vchar, h_tic, v_tic).
1738 * They may be taken into account in next plot commands */
1739 gp_cairo_set_font(wxt_current_plot, fontname, fontsize);
1740 gp_cairo_set_termvar(wxt_current_plot);
1741 wxt_MutexGuiLeave();
1743 wxt_sigint_restore();
1745 /* Note : we must take '\0' (EndOfLine) into account */
1746 temp_command.string = new char[strlen(fontname)+1];
1747 strcpy(temp_command.string, fontname);
1748 temp_command.integer_value = fontsize;
1750 wxt_command_push(temp_command);
1751 /* the returned int is not used anywhere */
1756 int wxt_justify_text(enum JUSTIFY mode)
1758 if (wxt_status != STATUS_OK)
1761 gp_command temp_command;
1763 temp_command.command = command_justify;
1764 temp_command.mode = mode;
1766 wxt_command_push(temp_command);
1767 return 1; /* we can justify */
1770 void wxt_point(unsigned int x, unsigned int y, int pointstyle)
1772 if (wxt_status != STATUS_OK)
1775 gp_command temp_command;
1777 temp_command.command = command_point;
1778 temp_command.x1 = x;
1779 temp_command.y1 = term->ymax - y;
1780 temp_command.integer_value = pointstyle;
1782 wxt_command_push(temp_command);
1785 void wxt_pointsize(double ptsize)
1787 if (wxt_status != STATUS_OK)
1790 /* same behaviour as x11 terminal */
1791 if (ptsize<0) ptsize = 1;
1793 gp_command temp_command;
1794 temp_command.command = command_pointsize;
1795 temp_command.double_value = ptsize;
1797 wxt_command_push(temp_command);
1800 void wxt_linewidth(double lw)
1802 if (wxt_status != STATUS_OK)
1805 gp_command temp_command;
1807 temp_command.command = command_linewidth;
1808 temp_command.double_value = lw;
1810 wxt_command_push(temp_command);
1813 int wxt_text_angle(int angle)
1815 if (wxt_status != STATUS_OK)
1818 gp_command temp_command;
1820 temp_command.command = command_text_angle;
1821 /* a double is needed to compute cos, sin, etc. */
1822 temp_command.double_value = (double) angle;
1824 wxt_command_push(temp_command);
1825 return 1; /* 1 means we can rotate */
1828 void wxt_fillbox(int style, unsigned int x, unsigned int y, unsigned int width, unsigned int height)
1830 if (wxt_status != STATUS_OK)
1833 gp_command temp_command;
1835 temp_command.command = command_fillbox;
1836 temp_command.x1 = x;
1837 temp_command.y1 = term->ymax - y;
1838 temp_command.x2 = width;
1839 temp_command.y2 = height;
1840 temp_command.integer_value = style;
1842 wxt_command_push(temp_command);
1845 int wxt_make_palette(t_sm_palette * palette)
1847 /* we can do continuous colors */
1851 void wxt_set_color(t_colorspec *colorspec)
1853 if (wxt_status != STATUS_OK)
1857 gp_command temp_command;
1859 if (colorspec->type == TC_LT) {
1860 wxt_linetype(colorspec->lt);
1862 } else if (colorspec->type == TC_FRAC)
1863 rgb1maxcolors_from_gray( colorspec->value, &rgb1 );
1864 else if (colorspec->type == TC_RGB) {
1865 rgb1.r = (double) ((colorspec->lt >> 16) & 0xff)/255;
1866 rgb1.g = (double) ((colorspec->lt >> 8) & 0xff)/255;
1867 rgb1.b = (double) ((colorspec->lt) & 0xff)/255;
1870 temp_command.command = command_color;
1871 temp_command.color = rgb1;
1873 wxt_command_push(temp_command);
1877 /* here we send the polygon command */
1878 void wxt_filled_polygon(int n, gpiPoint *corners)
1880 if (wxt_status != STATUS_OK)
1883 gp_command temp_command;
1885 temp_command.command = command_filled_polygon;
1886 temp_command.integer_value = n;
1887 temp_command.corners = new gpiPoint[n];
1888 /* can't use memcpy() here, as we have to mirror the y axis */
1889 gpiPoint *corners_copy = temp_command.corners;
1890 while (corners_copy < (temp_command.corners + n)) {
1891 *corners_copy = *corners++;
1892 corners_copy->y = term->ymax - corners_copy->y;
1896 wxt_command_push(temp_command);
1900 void wxt_image(unsigned M, unsigned N, coordval * image, gpiPoint * corner, t_imagecolor color_mode)
1902 /* This routine is to plot a pixel-based image on the display device.
1903 'M' is the number of pixels along the y-dimension of the image and
1904 'N' is the number of pixels along the x-dimension of the image. The
1905 coordval pointer 'image' is the pixel values normalized to the range
1906 [0:1]. These values should be scaled accordingly for the output
1907 device. They 'image' data starts in the upper left corner and scans
1908 along rows finishing in the lower right corner. If 'color_mode' is
1909 IC_PALETTE, the terminal is to use palette lookup to generate color
1910 information. In this scenario the size of 'image' is M*N. If
1911 'color_mode' is IC_RGB, the terminal is to use RGB components. In
1912 this scenario the size of 'image' is 3*M*N. The data appears in RGB
1913 tripples, i.e., image[0] = R(1,1), image[1] = G(1,1), image[2] =
1914 B(1,1), image[3] = R(1,2), image[4] = G(1,2), ..., image[3*M*N-1] =
1915 B(M,N). The 'image' is actually an "input" image in the sense that
1916 it must also be properly resampled for the output device. Many output
1917 mediums, e.g., PostScript, do this work via various driver functions.
1918 To determine the appropriate rescaling, the 'corner' information
1919 should be used. There are four entries in the gpiPoint data array.
1920 'corner[0]' is the upper left corner (in terms of plot location) of
1921 the outer edge of the image. Similarly, 'corner[1]' is the lower
1922 right corner of the outer edge of the image. (Outer edge means the
1923 outer extent of the corner pixels, not the middle of the corner
1924 pixels.) 'corner[2]' is the upper left corner of the visible part
1925 of the image, and 'corner[3]' is the lower right corner of the visible
1926 part of the image. The information is provided in this way because
1927 often it is necessary to clip a portion of the outer pixels of the
1930 /* we will draw an image, scale and resize it, copy to bitmap,
1931 * give a pointer to it in the list, and when processing the list we will use DrawBitmap */
1932 /* FIXME add palette support ??? */
1934 if (wxt_status != STATUS_OK)
1938 gp_command temp_command;
1940 temp_command.command = command_image;
1941 temp_command.x1 = corner[0].x;
1942 temp_command.y1 = term->ymax - corner[0].y;
1943 temp_command.x2 = corner[1].x;
1944 temp_command.y2 = term->ymax - corner[1].y;
1945 temp_command.x3 = corner[2].x;
1946 temp_command.y3 = term->ymax - corner[2].y;
1947 temp_command.x4 = corner[3].x;
1948 temp_command.y4 = term->ymax - corner[3].y;
1949 temp_command.integer_value = M;
1950 temp_command.integer_value2 = N;
1951 temp_command.color_mode = color_mode;
1953 if (color_mode == IC_RGB)
1958 temp_command.image = new coordval[imax];
1959 memcpy(temp_command.image, image, imax*sizeof(coordval));
1961 wxt_command_push(temp_command);
1963 #endif /*WITH_IMAGE*/
1966 /* Display temporary text, after
1967 * erasing any temporary text displayed previously at this location.
1968 * The int determines where: 0=statusline, 1,2: at corners of zoom
1969 * box, with \r separating text above and below the point. */
1970 void wxt_put_tmptext(int n, const char str[])
1972 if (wxt_status == STATUS_UNINITIALIZED)
1976 wxt_MutexGuiEnter();
1980 wxt_current_window->frame->SetStatusText( wxString(str, wxConvLocal) );
1983 wxt_current_panel->zoom_x1 = wxt_current_panel->mouse_x;
1984 wxt_current_panel->zoom_y1 = wxt_current_panel->mouse_y;
1985 wxt_current_panel->zoom_string1 = wxString(str, wxConvLocal);
1988 if ( strlen(str)==0 )
1989 wxt_current_panel->wxt_zoombox = false;
1991 wxt_current_panel->wxt_zoombox = true;
1992 wxt_current_panel->zoom_string2 = wxString(str, wxConvLocal);
1994 wxt_current_panel->Draw();
2000 wxt_MutexGuiLeave();
2002 wxt_sigint_restore();
2005 /* c selects the action:
2006 * -4=don't draw (erase) line between ruler and current mouse position,
2007 * -3=draw line between ruler and current mouse position,
2008 * -2=warp the cursor to the given point,
2010 * 0=standard cross-hair cursor,
2011 * 1=cursor during rotation,
2012 * 2=cursor during scaling,
2013 * 3=cursor during zooming. */
2014 void wxt_set_cursor(int c, int x, int y)
2016 if (wxt_status == STATUS_UNINITIALIZED)
2020 wxt_MutexGuiEnter();
2024 wxt_current_panel->wxt_ruler_lineto = false;
2025 wxt_current_panel->Draw();
2028 wxt_current_panel->wxt_ruler_lineto = true;
2029 wxt_current_panel->Draw();
2031 case -2: /* warp the pointer to the given position */
2032 wxt_current_panel->WarpPointer(
2033 (int) device_x(wxt_current_plot, x),
2034 (int) device_y(wxt_current_plot, y) );
2036 case -1: /* start zooming */
2037 wxt_current_panel->SetCursor(wxt_cursor_right);
2039 case 0: /* cross-hair cursor, also cancel zoombox when Echap is pressed */
2040 wxt_current_panel->wxt_zoombox = false;
2041 wxt_current_panel->SetCursor(wxt_cursor_cross);
2042 wxt_current_panel->Draw();
2044 case 1: /* rotation */
2045 wxt_current_panel->SetCursor(wxt_cursor_rotate);
2047 case 2: /* scaling */
2048 wxt_current_panel->SetCursor(wxt_cursor_size);
2050 case 3: /* zooming */
2051 wxt_current_panel->SetCursor(wxt_cursor_right);
2054 wxt_current_panel->SetCursor(wxt_cursor_cross);
2058 wxt_MutexGuiLeave();
2060 wxt_sigint_restore();
2064 /* Draw a ruler (crosshairs) centered at the
2065 * indicated screen coordinates. If x<0, switch ruler off. */
2066 void wxt_set_ruler(int x, int y)
2068 if (wxt_status == STATUS_UNINITIALIZED)
2072 wxt_MutexGuiEnter();
2075 wxt_current_panel->wxt_ruler = false;
2076 wxt_current_panel->Draw();
2078 wxt_current_panel->wxt_ruler = true;
2079 wxt_current_panel->wxt_ruler_x = device_x(wxt_current_plot, x);
2080 wxt_current_panel->wxt_ruler_y = device_y(wxt_current_plot, y);
2081 wxt_current_panel->Draw();
2084 wxt_MutexGuiLeave();
2086 wxt_sigint_restore();
2089 /* Write a string to the clipboard */
2090 void wxt_set_clipboard(const char s[])
2092 if (wxt_status == STATUS_UNINITIALIZED)
2096 wxt_MutexGuiEnter();
2098 if (wxTheClipboard->Open()) {
2099 wxTheClipboard->SetData( new wxTextDataObject(wxString(s, wxConvLocal)) );
2100 wxTheClipboard->Flush();
2101 wxTheClipboard->Close();
2104 wxt_MutexGuiLeave();
2106 wxt_sigint_restore();
2108 #endif /*USE_MOUSE*/
2111 /* ===================================================================
2112 * Command list processing
2113 * =================================================================*/
2115 /* push a command in the current commands list */
2116 void wxt_command_push(gp_command command)
2119 wxt_current_panel->command_list_mutex.Lock();
2120 wxt_current_command_list->push_back(command);
2121 wxt_current_panel->command_list_mutex.Unlock();
2123 wxt_sigint_restore();
2126 /* refresh the plot by (re)processing the plot commands list */
2127 void wxtPanel::wxt_cairo_refresh()
2129 /* Clear background. */
2130 gp_cairo_clear(&plot);
2132 command_list_t::iterator wxt_iter; /*declare the iterator*/
2133 for(wxt_iter = command_list.begin(); wxt_iter != command_list.end(); ++wxt_iter) {
2134 if (wxt_status == STATUS_INTERRUPT_ON_NEXT_CHECK) {
2135 FPRINTF((stderr,"interrupt detected inside drawing loop\n"));
2136 #ifdef IMAGE_SURFACE
2137 wxt_cairo_create_bitmap();
2138 #endif /* IMAGE_SURFACE */
2139 /* draw the pixmap to the screen */
2143 wxt_cairo_exec_command( *wxt_iter );
2146 /* don't forget to stroke the last path if vector was the last command */
2147 gp_cairo_stroke(&plot);
2148 /* and don't forget to draw the polygons if draw_polygon was the last command */
2149 gp_cairo_end_polygon(&plot);
2151 /* the following is a test for a bug in cairo when drawing to a gdkpixmap */
2153 cairo_set_source_rgb(plot.cr,1,1,1);
2154 cairo_paint(plot.cr);
2156 cairo_matrix_t matrix;
2157 cairo_matrix_init(&matrix,
2164 cairo_set_matrix(plot.cr, &matrix);
2167 cairo_surface_t *surface;
2168 surface = cairo_surface_create_similar(cairo_get_target(plot.cr),
2169 CAIRO_CONTENT_COLOR_ALPHA,
2172 context = cairo_create(surface);
2173 cairo_set_operator(context,CAIRO_OPERATOR_SATURATE);
2175 cairo_move_to(context, 300, 200);
2176 cairo_rel_line_to(context, 100, 0);
2177 cairo_rel_line_to(context, 0, 100);
2178 cairo_close_path(context);
2179 cairo_set_source_rgb(context,0,0,0);
2180 cairo_fill(context);
2182 cairo_move_to(context, 250, 170);
2183 cairo_rel_line_to(context, 100, 0);
2184 cairo_rel_line_to(context, 0, 100);
2185 cairo_close_path(context);
2186 cairo_set_source_rgb(context,0,0,0.5);
2187 cairo_fill(context);
2189 cairo_move_to(context, 360, 200);
2190 cairo_rel_line_to(context, 30, 0);
2191 cairo_rel_line_to(context, 0, -40);
2192 cairo_close_path(context);
2193 cairo_set_source_rgb(context,1,0,0);
2194 cairo_fill(context);
2196 cairo_move_to(context, 400, 100);
2197 cairo_rel_line_to(context, 100, 0);
2198 cairo_rel_line_to(context, -100, 300);
2199 cairo_close_path(context);
2200 cairo_set_source_rgb(context,0,1,0);
2201 cairo_fill(context);
2203 cairo_move_to(context, 400, 300);
2204 cairo_rel_line_to(context, -80, -80);
2205 cairo_rel_line_to(context, 0, 100);
2206 cairo_close_path(context);
2207 cairo_set_source_rgb(context,0.6,0.4,0);
2208 cairo_fill(context);
2210 cairo_pattern_t *pattern = cairo_pattern_create_for_surface( surface );
2211 cairo_destroy( context );
2213 cairo_surface_destroy( surface );
2214 cairo_set_source( plot.cr, pattern );
2215 cairo_pattern_destroy( pattern );
2216 cairo_paint(plot.cr);
2218 cairo_matrix_init(&matrix,
2219 plot.xscale/plot.oversampling_scale,
2222 plot.yscale/plot.oversampling_scale,
2225 cairo_set_matrix(plot.cr, &matrix);
2228 #ifdef IMAGE_SURFACE
2229 wxt_cairo_create_bitmap();
2230 #endif /* !have_gtkcairo */
2232 /* draw the pixmap to the screen */
2234 FPRINTF((stderr,"commands done, number of commands %d\n", command_list.size()));
2238 void wxtPanel::wxt_cairo_exec_command(gp_command command)
2240 switch ( command.command ) {
2241 case command_color :
2242 gp_cairo_set_color(&plot,command.color);
2244 case command_filled_polygon :
2245 gp_cairo_draw_polygon(&plot, command.integer_value, command.corners);
2248 gp_cairo_move(&plot, command.x1, command.y1);
2250 case command_vector :
2251 gp_cairo_vector(&plot, command.x1, command.y1);
2253 case command_linestyle :
2254 gp_cairo_set_linestyle(&plot, command.integer_value);
2256 case command_linetype :
2257 gp_cairo_set_linetype(&plot, command.integer_value);
2259 case command_pointsize :
2260 gp_cairo_set_pointsize(&plot, command.double_value);
2262 case command_point :
2263 gp_cairo_draw_point(&plot, command.x1, command.y1, command.integer_value);
2265 case command_justify :
2266 gp_cairo_set_justify(&plot,command.mode);
2268 case command_put_text :
2269 gp_cairo_draw_text(&plot, command.x1, command.y1, command.string);
2271 case command_enhanced_put_text :
2272 gp_cairo_draw_enhanced_text(&plot, command.x1, command.y1, command.string);
2274 case command_set_font :
2275 gp_cairo_set_font(&plot, command.string, command.integer_value);
2277 case command_linewidth :
2278 gp_cairo_set_linewidth(&plot, command.double_value);;
2280 case command_text_angle :
2281 gp_cairo_set_textangle(&plot, command.double_value);
2283 case command_fillbox :
2284 gp_cairo_draw_fillbox(&plot, command.x1, command.y1,
2285 command.x2, command.y2,
2286 command.integer_value);
2289 case command_image :
2290 gp_cairo_draw_image(&plot, command.image,
2291 command.x1, command.y1,
2292 command.x2, command.y2,
2293 command.x3, command.y3,
2294 command.x4, command.y4,
2295 command.integer_value, command.integer_value2,
2296 command.color_mode);
2298 #endif /*WITH_IMAGE*/
2303 /* given a plot number (id), return the associated plot structure */
2304 wxt_window_t* wxt_findwindowbyid(wxWindowID id)
2307 for(i=0;i<wxt_window_list.size();++i) {
2308 if (wxt_window_list[i].id == id)
2309 return &(wxt_window_list[i]);
2314 /*----------------------------------------------------------------------------
2315 * raise-lower functions
2316 *----------------------------------------------------------------------------*/
2318 void wxt_raise_window(wxt_window_t* window, bool force)
2320 FPRINTF((stderr,"raise window\n"));
2322 window->frame->Show(true);
2324 if (wxt_raise != no||force) {
2326 /* Raise() in wxGTK call wxTopLevelGTK::Raise()
2327 * which also gives the focus to the window.
2328 * Refresh() also must be called, otherwise
2329 * the raise won't happen immediately */
2330 window->frame->panel->Refresh(false);
2331 gdk_window_raise(window->frame->GetHandle()->window);
2333 window->frame->Raise();
2339 void wxt_lower_window(wxt_window_t* window)
2342 window->frame->panel->Refresh(false);
2343 gdk_window_lower(window->frame->GetHandle()->window);
2345 window->frame->Lower();
2346 #endif /* USE_GTK */
2350 /* raise the plot with given number */
2351 void wxt_raise_terminal_window(int number)
2353 wxt_window_t *window;
2355 if (wxt_status != STATUS_OK)
2360 wxt_MutexGuiEnter();
2361 if ((window = wxt_findwindowbyid(number))) {
2362 FPRINTF((stderr,"wxt : raise window %d\n",number));
2363 window->frame->Show(true);
2364 wxt_raise_window(window,true);
2366 wxt_MutexGuiLeave();
2369 wxt_sigint_restore();
2372 /* raise the plot the whole group */
2373 void wxt_raise_terminal_group()
2375 /* declare the iterator */
2376 std::vector<wxt_window_t>::iterator wxt_iter;
2378 if (wxt_status != STATUS_OK)
2383 wxt_MutexGuiEnter();
2384 for(wxt_iter = wxt_window_list.begin(); wxt_iter != wxt_window_list.end(); wxt_iter++) {
2385 FPRINTF((stderr,"wxt : raise window %d\n",wxt_iter->id));
2386 wxt_iter->frame->Show(true);
2387 /* FIXME Why does wxt_iter doesn't work directly ? */
2388 wxt_raise_window(&(*wxt_iter),true);
2390 wxt_MutexGuiLeave();
2393 wxt_sigint_restore();
2396 /* lower the plot with given number */
2397 void wxt_lower_terminal_window(int number)
2399 wxt_window_t *window;
2401 if (wxt_status != STATUS_OK)
2406 wxt_MutexGuiEnter();
2407 if ((window = wxt_findwindowbyid(number))) {
2408 FPRINTF((stderr,"wxt : lower window %d\n",number));
2409 wxt_lower_window(window);
2411 wxt_MutexGuiLeave();
2414 wxt_sigint_restore();
2417 /* lower the plot the whole group */
2418 void wxt_lower_terminal_group()
2420 /* declare the iterator */
2421 std::vector<wxt_window_t>::iterator wxt_iter;
2423 if (wxt_status != STATUS_OK)
2428 wxt_MutexGuiEnter();
2429 for(wxt_iter = wxt_window_list.begin(); wxt_iter != wxt_window_list.end(); wxt_iter++) {
2430 FPRINTF((stderr,"wxt : lower window %d\n",wxt_iter->id));
2431 wxt_lower_window(&(*wxt_iter));
2433 wxt_MutexGuiLeave();
2436 wxt_sigint_restore();
2439 /* close the specified window */
2440 void wxt_close_terminal_window(int number)
2442 wxt_window_t *window;
2444 if (wxt_status != STATUS_OK)
2449 wxt_MutexGuiEnter();
2450 if ((window = wxt_findwindowbyid(number))) {
2451 FPRINTF((stderr,"wxt : close window %d\n",number));
2452 window->frame->Close(false);
2454 wxt_MutexGuiLeave();
2457 wxt_sigint_restore();
2460 /* update the window title */
2461 void wxt_update_title(int number)
2463 wxt_window_t *window;
2466 if (wxt_status != STATUS_OK)
2471 wxt_MutexGuiEnter();
2473 if ((window = wxt_findwindowbyid(number))) {
2474 FPRINTF((stderr,"wxt : close window %d\n",number));
2475 if (strlen(wxt_title)) {
2476 /* NOTE : this assumes that the title is encoded in the locale charset.
2477 * This is probably a good assumption, but it is not guaranteed !
2478 * May be improved by using gnuplot encoding setting. */
2479 title << wxString(wxt_title, wxConvLocal);
2481 title.Printf(wxT("Gnuplot (window id : %d)"), window->id);
2483 window->frame->SetTitle(title);
2486 wxt_MutexGuiLeave();
2489 wxt_sigint_restore();
2492 /* --------------------------------------------------------
2494 * --------------------------------------------------------*/
2496 void wxtPanel::wxt_cairo_create_context()
2498 cairo_surface_t *fake_surface;
2501 cairo_destroy(plot.cr);
2503 if ( wxt_cairo_create_platform_context() ) {
2504 /* we are not able to create a true cairo context,
2505 * but will create a fake one to give proper initialisation */
2506 FPRINTF((stderr,"creating temporary fake surface\n"));
2507 fake_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
2508 plot.cr = cairo_create( fake_surface );
2509 cairo_surface_destroy( fake_surface );
2510 /* this flag will make the program retry later */
2511 plot.success = FALSE;
2513 plot.success = TRUE;
2516 /* set the transformation matrix of the context, and other details */
2517 gp_cairo_initialize_context(&plot);
2520 void wxtPanel::wxt_cairo_free_context()
2523 cairo_destroy(plot.cr);
2526 wxt_cairo_free_platform_context();
2531 /* create a cairo context, where the plot will be drawn on
2532 * If there is an error, return 1, otherwise return 0 */
2533 int wxtPanel::wxt_cairo_create_platform_context()
2535 cairo_surface_t *surface;
2536 wxClientDC dc(this);
2538 FPRINTF((stderr,"wxt_cairo_create_context\n"));
2540 /* free gdkpixmap */
2541 wxt_cairo_free_platform_context();
2543 /* GetWindow is a wxGTK specific wxDC method that returns
2544 * the GdkWindow on which painting should be done */
2546 if ( !GDK_IS_DRAWABLE(dc.GetWindow()) )
2550 gdkpixmap = gdk_pixmap_new(dc.GetWindow(), plot.device_xmax, plot.device_ymax, -1);
2552 if ( !GDK_IS_DRAWABLE(gdkpixmap) )
2555 plot.cr = gdk_cairo_create(gdkpixmap);
2559 void wxtPanel::wxt_cairo_free_platform_context()
2562 g_object_unref(gdkpixmap);
2565 #elif defined(__WXMSW__)
2566 /* create a cairo context, where the plot will be drawn on
2567 * If there is an error, return 1, otherwise return 0 */
2568 int wxtPanel::wxt_cairo_create_platform_context()
2570 cairo_surface_t *surface;
2571 wxClientDC dc(this);
2573 FPRINTF((stderr,"wxt_cairo_create_context\n"));
2575 /* free hdc and hbm */
2576 wxt_cairo_free_platform_context();
2578 /* GetHDC is a wxMSW specific wxDC method that returns
2579 * the HDC on which painting should be done */
2581 /* Create a compatible DC. */
2582 hdc = CreateCompatibleDC( (HDC) dc.GetHDC() );
2587 /* Create a bitmap big enough for our client rectangle. */
2588 hbm = CreateCompatibleBitmap((HDC) dc.GetHDC(), plot.device_xmax, plot.device_ymax);
2593 /* Select the bitmap into the off-screen DC. */
2594 SelectObject(hdc, hbm);
2595 surface = cairo_win32_surface_create( hdc );
2596 plot.cr = cairo_create(surface);
2597 cairo_surface_destroy( surface );
2601 void wxtPanel::wxt_cairo_free_platform_context()
2609 #else /* generic image surface */
2610 /* create a cairo context, where the plot will be drawn on
2611 * If there is an error, return 1, otherwise return 0 */
2612 int wxtPanel::wxt_cairo_create_platform_context()
2615 cairo_surface_t *surface;
2617 FPRINTF((stderr,"wxt_cairo_create_context\n"));
2622 width = plot.device_xmax;
2623 height = plot.device_ymax;
2625 if (width<1||height<1)
2628 data32 = new unsigned int[width*height];
2630 surface = cairo_image_surface_create_for_data((unsigned char*) data32,
2631 CAIRO_FORMAT_ARGB32, width, height, 4*width);
2632 plot.cr = cairo_create(surface);
2633 cairo_surface_destroy( surface );
2638 /* create a wxBitmap (to be painted to the screen) from the buffered cairo surface. */
2639 void wxtPanel::wxt_cairo_create_bitmap()
2642 unsigned char *data24;
2648 width = plot.device_xmax;
2649 height = plot.device_ymax;
2651 data24 = new unsigned char[3*width*height];
2653 /* data32 is the cairo image buffer, upper bits are alpha, then r, g and b
2654 * Depends on endianess !
2655 * It is converted to RGBRGB... in data24 */
2656 for(int i=0;i<width*height;++i) {
2657 *(data24+3*i)=*(data32+i)>>16;
2658 *(data24+3*i+1)=*(data32+i)>>8;
2659 *(data24+3*i+2)=*(data32+i);
2662 /* create a wxImage from data24 */
2663 image = new wxImage(width, height, data24, true);
2666 delete cairo_bitmap;
2668 /* create a wxBitmap from the wxImage. */
2669 cairo_bitmap = new wxBitmap( *image );
2677 void wxtPanel::wxt_cairo_free_platform_context()
2682 delete cairo_bitmap;
2684 #endif /* IMAGE_SURFACE */
2686 /* --------------------------------------------------------
2688 * --------------------------------------------------------*/
2690 /* Debugging events and _waitforinput adds a lot of lines of output
2691 * (~4 lines for an input character, and a few lines for each mouse move)
2692 * To debug it, define DEBUG and WXTDEBUGINPUT */
2694 #ifdef WXTDEBUGINPUT
2695 # define FPRINTF2(a) FPRINTF(a)
2697 # define FPRINTF2(a)
2701 /* protected check for the state of the event list */
2702 bool wxt_check_eventlist_empty()
2705 mutexProtectingEventList.Lock();
2706 result = EventList.empty();
2707 mutexProtectingEventList.Unlock();
2711 /* protected check for the state of the main thread (running or waiting for input) */
2712 wxt_thread_state_t wxt_check_thread_state()
2714 wxt_thread_state_t result;
2715 mutexProtectingThreadState.Lock();
2716 result = wxt_thread_state;
2717 mutexProtectingThreadState.Unlock();
2721 /* multithread safe method to change thread state */
2722 void wxt_change_thread_state(wxt_thread_state_t state)
2725 mutexProtectingThreadState.Lock();
2726 wxt_thread_state = state;
2727 mutexProtectingThreadState.Unlock();
2729 wxt_sigint_restore();
2732 /* Similar to gp_exec_event(),
2733 * put the event sent by the terminal in a list,
2734 * to be processed by the main thread. */
2735 void wxt_exec_event(int type, int mx, int my, int par1, int par2, wxWindowID id)
2737 struct gp_event_t event;
2747 FPRINTF2((stderr,"Processing event\n"));
2749 FPRINTF2((stderr,"Event processed\n"));
2750 if (event.type == GE_buttonrelease && (paused_for_mouse & PAUSE_CLICK)) {
2751 int button = event.par1;
2752 if (button == 1 && (paused_for_mouse & PAUSE_BUTTON1))
2753 paused_for_mouse = 0;
2754 if (button == 2 && (paused_for_mouse & PAUSE_BUTTON2))
2755 paused_for_mouse = 0;
2756 if (button == 3 && (paused_for_mouse & PAUSE_BUTTON3))
2757 paused_for_mouse = 0;
2759 if (event.type == GE_keypress && (paused_for_mouse & PAUSE_KEYSTROKE)) {
2760 /* Ignore NULL keycode */
2761 if (event.par1 > '\0')
2762 paused_for_mouse = 0;
2765 /* add the event to the event list */
2766 if (wxt_check_thread_state() == WAITING_FOR_STDIN)
2768 FPRINTF2((stderr,"Gui thread adds an event to the list\n"));
2769 mutexProtectingEventList.Lock();
2770 EventList.push_back(event);
2771 mutexProtectingEventList.Unlock();
2773 #endif /* ! _Windows */
2777 /* clear the event list, caring for the mutex */
2778 void wxt_clear_event_list()
2780 mutexProtectingEventList.Lock();
2782 mutexProtectingEventList.Unlock();
2786 /* wxt_process_events will process the contents of the event list
2787 * until it is empty.
2788 * It will return 1 if one event ends the pause */
2789 int wxt_process_events()
2791 struct gp_event_t wxt_event;
2794 while ( !wxt_check_eventlist_empty() ) {
2795 FPRINTF2((stderr,"Processing event\n"));
2796 mutexProtectingEventList.Lock();
2797 wxt_event = EventList.front();
2798 EventList.pop_front();
2799 mutexProtectingEventList.Unlock();
2800 do_event( &wxt_event );
2801 FPRINTF2((stderr,"Event processed\n"));
2802 if (wxt_event.type == GE_buttonrelease && (paused_for_mouse & PAUSE_CLICK)) {
2803 button = wxt_event.par1;
2804 if (button == 1 && (paused_for_mouse & PAUSE_BUTTON1))
2805 paused_for_mouse = 0;
2806 if (button == 2 && (paused_for_mouse & PAUSE_BUTTON2))
2807 paused_for_mouse = 0;
2808 if (button == 3 && (paused_for_mouse & PAUSE_BUTTON3))
2809 paused_for_mouse = 0;
2810 if (paused_for_mouse == 0)
2813 if (wxt_event.type == GE_keypress && (paused_for_mouse & PAUSE_KEYSTROKE)) {
2814 /* Ignore NULL keycode */
2815 if (wxt_event.par1 > '\0') {
2816 paused_for_mouse = 0;
2826 /* Implements waitforinput used in wxt.trm
2827 * the terminal events are directly processed when they are received */
2828 int wxt_waitforinput()
2833 #elif defined(__WXGTK__)||defined(__WXMAC__)
2835 /* Implements waitforinput used in wxt.trm
2836 * Returns the next input charachter, meanwhile treats terminal events */
2837 int wxt_waitforinput()
2839 /* wxt_waitforinput *is* launched immediately after the wxWidgets terminal
2840 * is set using 'set term wxt' whereas wxt_init has not been called.
2841 * So we must ensure that the library has been initialized
2842 * before using any wxwidgets functions.
2843 * When we just come back from SIGINT,
2844 * we must process window events, so the check is not
2845 * wxt_status != STATUS_OK */
2846 if (wxt_status == STATUS_UNINITIALIZED)
2850 int fd = fileno(stdin);
2851 struct timeval timeout;
2854 wxt_change_thread_state(WAITING_FOR_STDIN);
2857 if (wxt_process_events()) {
2858 wxt_change_thread_state(RUNNING);
2863 timeout.tv_usec = 10000;
2865 FD_SET(0/*fd*/,&fds);
2867 ierr = select(1, &fds, NULL, NULL, &timeout);
2869 /* check for error on select and return immediately if any */
2871 wxt_change_thread_state(RUNNING);
2874 } while (!FD_ISSET(fd,&fds));
2876 /* if we are paused_for_mouse, we should continue to wait for a mouse click */
2877 if (paused_for_mouse)
2879 if (wxt_process_events()) {
2880 wxt_change_thread_state(RUNNING);
2883 /* wait 10 microseconds */
2887 wxt_change_thread_state(RUNNING);
2890 #else /* !__WXMSW__ && !__WXGTK__ && !__WXMAC__*/
2891 #error "Not implemented"
2894 #endif /*USE_MOUSE*/
2896 /* --------------------------------------------------------
2897 * 'persist' option handling
2898 * --------------------------------------------------------*/
2900 /* returns true if at least one plot window is opened.
2901 * Used to handle 'persist' */
2902 bool wxt_window_opened()
2904 std::vector<wxt_window_t>::iterator wxt_iter; /*declare the iterator*/
2906 wxt_MutexGuiEnter();
2907 for(wxt_iter = wxt_window_list.begin(); wxt_iter != wxt_window_list.end(); wxt_iter++) {
2908 if ( wxt_iter->frame->IsShown() ) {
2909 wxt_MutexGuiLeave();
2913 wxt_MutexGuiLeave();
2917 /* Called when gnuplot exits.
2918 * Handle the 'persist' setting, ie will continue
2919 * to handle events and will return when
2920 * all the plot windows are closed. */
2924 int persist_setting;
2929 if (wxt_status == STATUS_UNINITIALIZED)
2932 /* first look for command_line setting */
2933 if (wxt_persist==UNSET && persist_cl)
2936 wxConfigBase *pConfig = wxConfigBase::Get();
2938 /* then look for persistent configuration setting */
2939 if (wxt_persist==UNSET) {
2940 if (pConfig->Read(wxT("persist"),&persist_setting))
2941 wxt_persist = persist_setting?yes:no;
2944 /* and let's go ! */
2945 if (wxt_persist==UNSET|| wxt_persist==no) {
2950 /* if the user hits ctrl-c and quits again, really quit */
2953 FPRINTF((stderr,"wxWidgets terminal handles 'persist' setting\n"));
2958 /* be sure to show the text window */
2959 ShowWindow(textwin.hWndParent, textwin.nCmdShow);
2960 while (!com_line());
2963 /* cleanup and quit */
2967 /* if fork() is available, use it so that the initial gnuplot process
2968 * exits (Maxima expects that since that's the way the x11 terminal
2969 * does it) and the child process continues in the background. */
2970 /* FIXME: int_error() should be changed here, it causes crashes (for example,
2971 * zoom until an error occurs and then hit a key) */
2972 # ifdef HAVE_WORKING_FORK
2973 /* send a message to exit the main loop */
2974 wxCommandEvent event(wxExitLoopEvent);
2975 std::vector<wxt_window_t>::iterator wxt_iter; /*declare the iterator*/
2976 wxt_iter = wxt_window_list.begin();
2977 wxt_iter->frame->GetEventHandler()->AddPendingEvent( event );
2979 /* wait for the gui thread to exit */
2986 /* the parent just exits, the child keeps going */
2988 /* create a new gui thread and run it */
2989 /* have to close the previous main loop for this to succeed */
2990 thread = new wxtThread();
2994 # endif /* HAVE_WORKING_FORK */
2997 wxt_change_thread_state(WAITING_FOR_STDIN);
2998 # endif /*USE_MOUSE*/
3000 /* protect the following from interrupt */
3003 while (wxt_window_opened()) {
3005 if (!strcmp(term->name,"wxt"))
3006 wxt_process_events();
3007 # endif /*USE_MOUSE*/
3008 /* wait 10 microseconds and repeat */
3009 /* such a polling is bad, putting the thread to sleep
3010 * would be better */
3015 wxt_sigint_restore();
3018 wxt_change_thread_state(RUNNING);
3019 # endif /*USE_MOUSE*/
3021 /* cleanup and quit */
3024 # ifdef HAVE_WORKING_FORK
3026 # endif /* HAVE_WORKING_FORK */
3027 #endif /* !_Windows */
3031 /* destroy everything related to wxWidgets */
3034 std::vector<wxt_window_t>::iterator wxt_iter; /*declare the iterator*/
3036 if (wxt_status == STATUS_UNINITIALIZED)
3039 FPRINTF((stderr,"cleanup before exit\n"));
3041 /* prevent wxt_reset (for example) from doing anything bad after that */
3042 wxt_status = STATUS_UNINITIALIZED;
3044 /* protect the following from interrupt */
3047 /* Close all open terminal windows, this will make OnRun exit, and so will the gui thread */
3048 wxt_MutexGuiEnter();
3049 for(wxt_iter = wxt_window_list.begin(); wxt_iter != wxt_window_list.end(); wxt_iter++)
3050 delete wxt_iter->frame;
3051 wxt_MutexGuiLeave();
3053 #if defined(__WXGTK__)||defined(__WXMAC__)
3054 FPRINTF((stderr,"waiting for gui thread to exit\n"));
3055 FPRINTF((stderr,"gui thread status %d %d %d\n",
3056 thread->IsDetached(),
3058 thread->IsRunning() ));
3062 FPRINTF((stderr,"gui thread exited\n"));
3063 #endif /* __WXGTK || __WXMAC__*/
3068 /* handle eventual interrupt, and restore original sigint handler */
3070 wxt_sigint_restore();
3072 FPRINTF((stderr,"wxWidgets terminal properly cleaned-up\n"));
3075 /* -------------------------------------
3076 * GUI Mutex helper functions for porting
3077 * ----------------------------------------*/
3079 void wxt_MutexGuiEnter()
3081 FPRINTF2((stderr,"locking gui mutex\n"));
3082 #if defined(__WXGTK__)||defined(__WXMAC__)
3084 #elif defined(__WXMSW__)
3086 # error "No implementation"
3090 void wxt_MutexGuiLeave()
3092 FPRINTF2((stderr,"unlocking gui mutex\n"));
3093 #if defined(__WXGTK__)||defined(__WXMAC__)
3095 #elif defined(__WXMSW__)
3097 # error "No implementation"
3101 /* ---------------------------------------------------
3102 * SIGINT handling : as the terminal is multithreaded, it needs several mutexes.
3103 * To avoid inconsistencies and deadlock when the user hits ctrl-c,
3104 * each critical set of instructions (implying mutexes for example) should be written :
3105 * wxt_sigint_init();
3106 * < critical instructions >
3107 * wxt_sigint_check();
3108 * wxt_sigint_restore();
3109 * Or, if the critical instructions are in a loop, wxt_sigint_check() should be
3110 * called regularly in the loop.
3111 * ---------------------------------------------------*/
3114 /* our custom SIGINT handler, that just sets a flag */
3115 void wxt_sigint_handler(int WXUNUSED(sig))
3117 FPRINTF((stderr,"custom interrupt handler called\n"));
3118 signal(SIGINT, wxt_sigint_handler);
3119 /* routines must check regularly for wxt_status,
3120 * and abort cleanly on STATUS_INTERRUPT_ON_NEXT_CHECK */
3121 wxt_status = STATUS_INTERRUPT_ON_NEXT_CHECK;
3122 if (wxt_current_plot)
3123 wxt_current_plot->interrupt = TRUE;
3126 /* To be called when the function has finished cleaning after facing STATUS_INTERRUPT_ON_NEXT_CHECK */
3127 /* Provided for flexibility, but use wxt_sigint_check instead directly */
3128 void wxt_sigint_return()
3130 FPRINTF((stderr,"calling original interrupt handler\n"));
3131 wxt_status = STATUS_INTERRUPT;
3132 wxt_sigint_counter = 0;
3133 /* call the original sigint handler */
3134 /* this will not return !! */
3135 (*original_siginthandler)(SIGINT);
3138 /* A critical function should call this from a safe zone (no locked mutex, objects destroyed).
3139 * If the interrupt is asked, this fonction will not return (longjmp) */
3140 void wxt_sigint_check()
3142 FPRINTF2((stderr,"checking interrupt status\n"));
3143 if (wxt_status == STATUS_INTERRUPT_ON_NEXT_CHECK)
3144 wxt_sigint_return();
3147 /* initialize our custom SIGINT handler */
3148 /* this uses a usage counter, so that it can be encapsulated without problem */
3149 void wxt_sigint_init()
3151 /* put our custom sigint handler, store the original one */
3152 if (wxt_sigint_counter == 0)
3153 original_siginthandler = signal(SIGINT, wxt_sigint_handler);
3154 ++wxt_sigint_counter;
3155 FPRINTF2((stderr,"initialize custom interrupt handler %d\n",wxt_sigint_counter));
3158 /* restore the original SIGINT handler */
3159 void wxt_sigint_restore()
3161 if (wxt_sigint_counter==1)
3162 signal(SIGINT, original_siginthandler);
3163 --wxt_sigint_counter;
3164 FPRINTF2((stderr,"restore custom interrupt handler %d\n",wxt_sigint_counter));
3165 if (wxt_sigint_counter<0)
3166 fprintf(stderr,"sigint counter < 0 : error !\n");