Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / wxterminal / wxt_gui.cpp
1 /*
2  * $Id: wxt_gui.cpp,v 1.30.2.9 2008/07/29 22:19:05 sfeam Exp $
3  */
4
5 /* GNUPLOT - wxt_gui.cpp */
6
7 /*[
8  * Copyright 2005,2006   Timothee Lecomte
9  *
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.
15  *
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,
20  * provided you
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
28  *    software.
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.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35  *
36  *
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.
49 ]*/
50
51 /* -----------------------------------------------------
52  * The following code uses the wxWidgets library, which is
53  * distributed under its own licence (derivated from the LGPL).
54  *
55  * You can read it at the following address :
56  * http://www.wxwidgets.org/licence.htm
57  * -----------------------------------------------------*/
58
59 /* ------------------------------------------------------
60  * This file implements in C++ the functions which are called by wxt.trm :
61  *
62  * It depends on the generic cairo functions,
63  * declared in gp_cairo.h for all the drawing work.
64  *
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.
70  *
71  * ------------------------------------------------------*/
72
73 /* PORTING NOTES
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 :
76  *
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.
80  * Examples :
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 !]
84  *
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.
92  */
93
94
95 /* define DEBUG here to have debugging messages in stderr */
96 #include "wxt_gui.h"
97
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"
102 /* cursors */
103 #include "bitmaps/xpm/cross.xpm"
104 #include "bitmaps/xpm/right.xpm"
105 #include "bitmaps/xpm/rotate.xpm"
106 #include "bitmaps/xpm/size.xpm"
107 /* Toolbar icons
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"
118
119 /* ---------------------------------------------------------------------------
120  * event tables and other macros for wxWidgets
121  * --------------------------------------------------------------------------*/
122
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.
126  */
127
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 )
133 #ifdef USE_MOUSE
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 )
139 #endif /*USE_MOUSE*/
140         EVT_TOOL( Toolbar_Config, wxtFrame::OnConfig )
141         EVT_TOOL( Toolbar_Help, wxtFrame::OnHelp )
142 END_EVENT_TABLE()
143
144 BEGIN_EVENT_TABLE( wxtPanel, wxPanel )
145         EVT_PAINT( wxtPanel::OnPaint )
146         EVT_ERASE_BACKGROUND( wxtPanel::OnEraseBackground )
147         EVT_SIZE( wxtPanel::OnSize )
148 #ifdef USE_MOUSE
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 )
157 #endif /*USE_MOUSE*/
158 END_EVENT_TABLE()
159
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 )
165 END_EVENT_TABLE()
166
167
168 #if defined(__WXGTK__)||defined(__WXMAC__)
169 /* ----------------------------------------------------------------------------
170  *   gui thread
171  * ----------------------------------------------------------------------------*/
172
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()
176 {
177         FPRINTF((stderr,"gui_thread_entry\n"));
178
179         /* don't answer to SIGINT in this thread - avoids LONGJMP problems */
180         sigset_t set;
181         sigemptyset(&set);
182         sigaddset(&set, SIGINT);
183         pthread_sigmask(SIG_BLOCK, &set, NULL);
184
185         /* gui loop */
186         wxTheApp->OnRun();
187
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. */
191         wxt_MutexGuiLeave();
192
193         FPRINTF((stderr,"gui_thread_entry finishing\n"));
194         return NULL;
195 }
196 #elif defined (__WXMSW__)
197 /* nothing to do here */
198 #else
199 # error "Not implemented."
200 #endif
201
202
203
204 /* ----------------------------------------------------------------------------
205  *  `Main program' equivalent: the program execution "starts" here
206  * ----------------------------------------------------------------------------*/
207
208 /* Create a new application object */
209 IMPLEMENT_APP_NO_MAIN(wxtApp)
210
211 bool wxtApp::OnInit()
212 {
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.*/
216
217         /* initialize frames icons */
218         icon.AddIcon(wxIcon(icon16x16_xpm));
219         icon.AddIcon(wxIcon(icon32x32_xpm));
220         icon.AddIcon(wxIcon(icon64x64_xpm));
221
222         /* we load the image handlers, needed to copy the plot to clipboard, and to load icons */
223         ::wxInitAllImageHandlers();
224
225 #ifdef __WXMSW__
226         /* allow the toolbar to display properly png icons with an alpha channel */
227         wxSystemOptions::SetOption(wxT("msw.remap"), 0);
228 #endif /* __WXMSW__ */
229
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);
239
240         /* load cursors */
241         LoadCursor(wxt_cursor_cross, cross);
242         LoadCursor(wxt_cursor_right, right);
243         LoadCursor(wxt_cursor_rotate, rotate);
244         LoadCursor(wxt_cursor_size, size);
245
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
249          * to Get() */
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();
257
258         return true; /* means that process must continue */
259 }
260
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)
263 {
264         wxMemoryInputStream pngstream(embedded_png, length);
265         toolBarBitmaps[icon_number] = new wxBitmap(wxImage(pngstream, wxBITMAP_TYPE_PNG));
266 }
267
268 /* load a cursor */
269 void wxtApp::LoadCursor(wxCursor &cursor, const char* xpm_bits[])
270 {
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);
280 }
281
282 /* cleanup on exit
283  * In a pure wxWidgets app, the returned int is the exit status of the app.
284  * Here it is not used. */
285 int wxtApp::OnExit()
286 {
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
290          * we want here!) */
291         delete wxConfigBase::Set((wxConfigBase *) NULL);
292         return 0;
293 }
294
295 /* will gently terminate the gui thread */
296 void wxtApp::OnExitLoop( wxCommandEvent& WXUNUSED(event) )
297 {
298         FPRINTF((stderr,"wxtApp::OnExitLoop\n"));
299         wxTheApp->ExitMainLoop();
300 }
301
302 /* ---------------------------------------------------------------------------
303  * Frame : the main windows (one for each plot)
304  * ----------------------------------------------------------------------------*/
305
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)
310 {
311         FPRINTF((stderr,"wxtFrame constructor\n"));
312
313         /* used to check for panel initialization */
314         panel = NULL;
315
316         /* initialize the state of the configuration dialog */
317         config_displayed = false;
318
319         /* set up the window icon, in several resolutions */
320         SetIcons(icon);
321
322         /* set up the status bar, and fill it with an empty
323          * string. It will be immediately overriden by gnuplot. */
324         CreateStatusBar();
325         SetStatusText( wxT("") );
326
327         /* set up the toolbar */
328         wxToolBar * toolbar = CreateToolBar();
329         /* With wxMSW, default toolbar size is only 16x15. */
330         toolbar->SetToolBitmapSize(wxSize(16,16));
331
332         toolbar->AddTool(Toolbar_CopyToClipboard, wxT("Copy"),
333                                 *(toolBarBitmaps[0]), wxT("Copy the plot to clipboard"));
334 #ifdef USE_MOUSE
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"));
346 #endif /*USE_MOUSE*/
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"));
352         toolbar->Realize();
353
354         FPRINTF((stderr,"wxtFrame constructor 2\n"));
355
356         /* build the panel, which will contain the visible device context */
357         panel = new wxtPanel( this, this->GetId(), this->GetClientSize() );
358
359         /* setting minimum height and width for the window */
360         SetSizeHints(100, 100);
361
362         FPRINTF((stderr,"wxtFrame constructor 3\n"));
363 }
364
365
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 ) )
369 {
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);
373         wxMemoryDC cp_dc;
374         wxClientDC dc(panel);
375
376         cp_dc.SelectObject(cp_bitmap);
377         cp_dc.Blit(0,0,width,height,&dc,0,0);
378         cp_dc.SelectObject(wxNullBitmap);
379
380         wxTheClipboard->UsePrimarySelection(false);
381         /* SetData clears the clipboard */
382         if ( wxTheClipboard->Open() ) {
383                 wxTheClipboard->SetData(new wxBitmapDataObject(cp_bitmap));
384                 wxTheClipboard->Close();
385         }
386         wxTheClipboard->Flush();
387 }
388
389 #ifdef USE_MOUSE
390 /* toolbar event : Replot */
391 void wxtFrame::OnReplot( wxCommandEvent& WXUNUSED( event ) )
392 {
393         if ( this->GetId()==wxt_window_number )
394                 wxt_exec_event(GE_keypress, 0, 0, 'e' , 0, this->GetId());
395 }
396
397 /* toolbar event : Toggle Grid */
398 void wxtFrame::OnToggleGrid( wxCommandEvent& WXUNUSED( event ) )
399 {
400         if ( this->GetId()==wxt_window_number )
401                 wxt_exec_event(GE_keypress, 0, 0, 'g', 0, this->GetId());
402 }
403
404 /* toolbar event : Previous Zoom in history */
405 void wxtFrame::OnZoomPrevious( wxCommandEvent& WXUNUSED( event ) )
406 {
407         if ( this->GetId()==wxt_window_number )
408                 wxt_exec_event(GE_keypress, 0, 0, 'p', 0, this->GetId());
409 }
410
411 /* toolbar event : Next Zoom in history */
412 void wxtFrame::OnZoomNext( wxCommandEvent& WXUNUSED( event ) )
413 {
414         if ( this->GetId()==wxt_window_number )
415                 wxt_exec_event(GE_keypress, 0, 0, 'n', 0, this->GetId());
416 }
417
418 /* toolbar event : Autoscale */
419 void wxtFrame::OnAutoscale( wxCommandEvent& WXUNUSED( event ) )
420 {
421         if ( this->GetId()==wxt_window_number )
422                 wxt_exec_event(GE_keypress, 0, 0, 'a', 0, this->GetId());
423 }
424 #endif /*USE_MOUSE*/
425
426 /* toolbar event : Config */
427 void wxtFrame::OnConfig( wxCommandEvent& WXUNUSED( event ) )
428 {
429         /* if we have already opened a dialog, just raise it */
430         if (config_displayed) {
431                 config_dialog->Raise();
432                 return;
433         }
434
435         /* otherwise, open a dialog */
436         config_displayed = true;
437         config_dialog = new wxtConfigDialog(this);
438         config_dialog->Show(true);
439 }
440
441
442 /* toolbar event : Help */
443 void wxtFrame::OnHelp( wxCommandEvent& WXUNUSED( event ) )
444 {
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 );
456 }
457
458 /* called on Close() (menu or window manager) */
459 void wxtFrame::OnClose( wxCloseEvent& event )
460 {
461         FPRINTF((stderr,"OnClose\n"));
462         if ( event.CanVeto() ) {
463                 /* Default behaviour when Quit is clicked, or the window cross X */
464                 event.Veto();
465                 this->Hide();
466         }
467         else /* Should not happen, but just in case */
468                 this->Destroy();
469 }
470
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 )
475 {
476         FPRINTF((stderr,"frame OnSize\n"));
477
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.*/
480         if (panel)
481                 panel->SetSize( this->GetClientSize() );
482 }
483
484 /* ---------------------------------------------------------------------------
485  * Panel : the space used for the plot, between the toolbar and the statusbar
486  * ----------------------------------------------------------------------------*/
487
488 /* panel constructor
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 )
492 {
493         FPRINTF((stderr,"panel constructor\n"));
494
495         /* initialisations */
496         gp_cairo_initialize_plot(&plot);
497         GetSize(&(plot.device_xmax),&(plot.device_ymax));
498
499         settings_queued = false;
500
501 #ifdef USE_MOUSE
502         mouse_x = 0;
503         mouse_y = 0;
504         wxt_zoombox = false;
505         zoom_x1 = 0;
506         zoom_y1 = 0;
507         zoom_string1 = wxT("");
508         zoom_string2 = wxT("");
509
510         wxt_ruler = false;
511         wxt_ruler_x = 0;
512         wxt_ruler_y = 0;
513
514         modifier_mask = 0;
515 #endif /*USE_MOUSE*/
516
517 #if defined(GTK_SURFACE)
518         gdkpixmap = NULL;
519 #elif defined(__WXMSW__)
520         hdc = NULL;
521         hbm = NULL;
522 #else /* IMAGE_SURFACE */
523         cairo_bitmap = NULL;
524         data32 = NULL;
525 #endif /* SURFACE */
526
527         FPRINTF((stderr,"panel constructor4\n"));
528
529         /* create the device context to be drawn */
530         wxt_cairo_create_context();
531
532         FPRINTF((stderr,"panel constructor5\n"));
533
534 #ifdef IMAGE_SURFACE
535         wxt_cairo_create_bitmap();
536 #endif
537         FPRINTF((stderr,"panel constructor6\n"));
538 }
539
540
541 /* destructor */
542 wxtPanel::~wxtPanel()
543 {
544         FPRINTF((stderr,"panel destructor\n"));
545         wxt_cairo_free_context();
546
547         /* clear the command list, free the allocated memory */
548         ClearCommandlist();
549 }
550
551 /* temporary store new settings values to be applied for the next plot */
552 void wxtPanel::wxt_settings_queue(TBOOLEAN antialiasing,
553                                         TBOOLEAN oversampling,
554                                         int hinting_setting)
555 {
556         mutex_queued.Lock();
557         settings_queued = true;
558         antialiasing_queued = antialiasing;
559         oversampling_queued = oversampling;
560         hinting_queued = hinting_setting;
561         mutex_queued.Unlock();
562 }
563
564 /* apply queued settings */
565 void wxtPanel::wxt_settings_apply()
566 {
567         mutex_queued.Lock();
568         if (settings_queued) {
569                 plot.antialiasing = antialiasing_queued;
570                 plot.oversampling = oversampling_queued;
571                 plot.hinting = hinting_queued;
572                 settings_queued = false;
573         }
574         mutex_queued.Unlock();
575 }
576
577 /* clear the command list, free the allocated memory */
578 void wxtPanel::ClearCommandlist()
579 {
580         command_list_mutex.Lock();
581
582         command_list_t::iterator iter; /*declare the iterator*/
583
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;
592 #ifdef WITH_IMAGE
593                 if (iter->command == command_image)
594                         delete[] iter->image;
595 #endif /* WITH_IMAGE */
596         }
597
598         command_list.clear();
599         command_list_mutex.Unlock();
600 }
601
602
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) )
606 {
607         /* Constructor of the device context */
608         wxPaintDC dc(this);
609         DrawToDC(dc, GetUpdateRegion());
610 }
611
612 /* same as OnPaint, but can be directly called by a user function */
613 void wxtPanel::Draw()
614 {
615         wxClientDC dc(this);
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);
619 }
620
621 /* copy the plot to the panel, draw zoombow and ruler needed */
622 void wxtPanel::DrawToDC(wxDC &dc, wxRegion &region)
623 {
624         wxPen tmp_pen;
625
626         /* TODO extend the region mechanism to surfaces other than GTK_SURFACE */
627 #ifdef GTK_SURFACE
628         wxRegionIterator upd(region);
629         int vX,vY,vW,vH; /* Dimensions of client area in pixels */
630
631         while (upd) {
632                 vX = upd.GetX();
633                 vY = upd.GetY();
634                 vW = upd.GetW();
635                 vH = upd.GetH();
636         
637                 FPRINTF((stderr,"OnPaint %d,%d,%d,%d\n",vX,vY,vW,vH));
638                 /* Repaint this rectangle */
639                 if (gdkpixmap)
640                         gdk_draw_drawable(dc.GetWindow(),
641                                 dc.m_penGC,
642                                 gdkpixmap,
643                                 vX,vY,
644                                 vX,vY,
645                                 vW,vH);
646                 ++upd;
647         }
648 #elif defined(__WXMSW__)
649         BitBlt((HDC) dc.GetHDC(), 0, 0, plot.device_xmax, plot.device_ymax, hdc, 0, 0, SRCCOPY);
650 #else
651         dc.DrawBitmap(*cairo_bitmap, 0, 0, false);
652 #endif
653
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),
659                                 0,
660                                 plot.device_xmax - (int) (plot.xmax/plot.oversampling_scale*plot.xscale),
661                                 plot.device_ymax);
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 ) );
665                 dc.DrawRectangle(0,
666                                 (int) (plot.ymax/plot.oversampling_scale*plot.yscale),
667                                 plot.device_xmax,
668                                 (int) (plot.device_ymax - plot.ymax/plot.oversampling_scale*plot.yscale));
669         }
670
671 #ifdef USE_MOUSE
672         if (wxt_zoombox) {
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 );
686
687                 dc.SetFont( wxFont( (int) plot.fontsize, wxFONTFAMILY_DEFAULT,
688                         wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false,
689                         wxString(plot.fontname, wxConvLocal) ) );
690
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')),
694                         zoom_x1, zoom_y1);
695
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')),
699                         mouse_x, mouse_y);
700
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 */
703                 wxt_zoombox = false;
704         }
705
706         if (wxt_ruler) {
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 );
713         }
714
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 );
722         }
723 #endif /*USE_MOUSE*/
724
725 }
726
727 /* avoid flickering under win32 */
728 void wxtPanel::OnEraseBackground( wxEraseEvent &WXUNUSED(event) )
729 {
730 }
731
732 /* when the window is resized */
733 void wxtPanel::OnSize( wxSizeEvent& event )
734 {
735         /* don't do anything if term variables are not initialized */
736         if (plot.xmax == 0 || plot.ymax == 0)
737                 return;
738
739         /* update window size, and scaling variables */
740         GetSize(&(plot.device_xmax),&(plot.device_ymax));
741
742         double new_xscale, new_yscale;
743         
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);
746
747         /* We will keep the aspect ratio constant */
748         if (new_yscale < new_xscale) {
749                 plot.xscale = new_yscale;
750                 plot.yscale = new_yscale;
751         } else {
752                 plot.xscale = new_xscale;
753                 plot.yscale = new_xscale;
754         }
755         FPRINTF((stderr,"panel OnSize %d %d %lf %lf\n",
756                 plot.device_xmax, plot.device_ymax, plot.xscale,plot.yscale));
757
758         /* create a new cairo context of the good size */
759         wxt_cairo_create_context();
760         /* redraw the plot with the new scaling */
761         wxt_cairo_refresh();
762 }
763
764 #ifdef USE_MOUSE
765 /* when the mouse is moved over the panel */
766 void wxtPanel::OnMotion( wxMouseEvent& event )
767 {
768         /* Get and store mouse position for _put_tmp_text() and key events (ruler) */
769         mouse_x = event.GetX();
770         mouse_y = event.GetY();
771
772         UpdateModifiers(event);
773
774         /* update the ruler_lineto thing */
775         if (wxt_ruler && wxt_ruler_lineto)
776                 Draw();
777
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());
784 }
785
786 /* mouse "click" event */
787 void wxtPanel::OnLeftDown( wxMouseEvent& event )
788 {
789         int x,y;
790         x = (int) gnuplot_x( &plot, event.GetX() );
791         y = (int) gnuplot_y( &plot, event.GetY() );
792
793         UpdateModifiers(event);
794
795         if ( this->GetId()==wxt_window_number )
796                 wxt_exec_event(GE_buttonpress, x, y, 1, 0, this->GetId());
797 }
798
799 /* mouse "click" event */
800 void wxtPanel::OnLeftUp( wxMouseEvent& event )
801 {
802         int x,y;
803         x = (int) gnuplot_x( &plot, event.GetX() );
804         y = (int) gnuplot_y( &plot, event.GetY() );
805
806         UpdateModifiers(event);
807
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();
812         }
813 }
814
815 /* mouse "click" event */
816 void wxtPanel::OnMiddleDown( wxMouseEvent& event )
817 {
818         int x,y;
819         x = (int) gnuplot_x( &plot, event.GetX() );
820         y = (int) gnuplot_y( &plot, event.GetY() );
821
822         UpdateModifiers(event);
823
824         if ( this->GetId()==wxt_window_number )
825                 wxt_exec_event(GE_buttonpress, x, y, 2, 0, this->GetId());
826 }
827
828 /* mouse "click" event */
829 void wxtPanel::OnMiddleUp( wxMouseEvent& event )
830 {
831         int x,y;
832         x = (int) gnuplot_x( &plot, event.GetX() );
833         y = (int) gnuplot_y( &plot, event.GetY() );
834
835         UpdateModifiers(event);
836
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();
842         }
843 }
844
845 /* mouse "click" event */
846 void wxtPanel::OnRightDown( wxMouseEvent& event )
847 {
848         int x,y;
849         x = (int) gnuplot_x( &plot, event.GetX() );
850         y = (int) gnuplot_y( &plot, event.GetY() );
851
852         UpdateModifiers(event);
853
854         if ( this->GetId()==wxt_window_number )
855                 wxt_exec_event(GE_buttonpress, x, y, 3, 0, this->GetId());
856 }
857
858 /* mouse "click" event */
859 void wxtPanel::OnRightUp( wxMouseEvent& event )
860 {
861         int x,y;
862         x = (int) gnuplot_x( &plot, event.GetX() );
863         y = (int) gnuplot_y( &plot, event.GetY() );
864
865         UpdateModifiers(event);
866
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();
871         }
872 }
873
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 )
879 {
880         int current_modifier_mask = 0;
881
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);
886
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());
891         }
892 }
893
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 )
897 {
898         int keycode = event.GetKeyCode();
899         int gp_keycode;
900
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;
905
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);
910
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());
915         }
916
917 #define WXK_GPKEYCODE(wxkey,kcode) case wxkey : gp_keycode=kcode; break;
918
919         if (keycode<256) {
920                 switch (keycode) {
921                 case WXK_SPACE :
922                         if ((wxt_ctrl==yes && event.ControlDown())
923                                 || wxt_ctrl!=yes) {
924                                 RaiseConsoleWindow();
925                                 return;
926                         } else {
927                                 gp_keycode = ' ';
928                                 break;
929                         }
930                 case 'q' :
931                 /* ctrl+q does not send 113 but 17 */
932                 /* WARNING : may be the same for other combinations */
933                 case 17 :
934                         if ((wxt_ctrl==yes && event.ControlDown())
935                                 || wxt_ctrl!=yes) {
936                                 /* closes terminal window */
937                                 this->GetParent()->Close(false);
938                                 return;
939                         } else {
940                                 gp_keycode = 'q';
941                                 break;
942                         }
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 */
949                 }
950         } else {
951                 switch( keycode ) {
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);
970                 
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);
981                 
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 */
1013                 }
1014         }
1015
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());
1021         }
1022
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
1035          */
1036 }
1037 #endif /*USE_MOUSE*/
1038
1039 /* ====license information====
1040  * The following code originates from other gnuplot files,
1041  * and is not subject to the alternative license statement.
1042  */
1043
1044
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()
1050 {
1051 #ifdef USE_GTK
1052         char *window_env;
1053         unsigned long windowid = 0;
1054         /* retrieve XID of gnuplot window */
1055         window_env = getenv("WINDOWID");
1056         if (window_env)
1057                 sscanf(window_env, "%lu", &windowid);
1058         
1059         char *ptr = getenv("KONSOLE_DCOP_SESSION"); /* Try KDE's Konsole first. */
1060         if (ptr) {
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
1064                 * 2. if
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).
1072                 *
1073                 * Implementation and tests on KDE 3.1.4: Petr Mikulik.
1074                 */
1075                 char *konsole_name = NULL;
1076                 char *cmd = NULL;
1077                 /* use 'while' to easily break out (aka catch exception) */
1078                 while (1) {
1079                         char *konsole_tab;
1080                         unsigned long w;
1081                         FILE *p;
1082                         ptr = strchr(ptr, '(');
1083                         /* the string for tab nb 4 looks like 'DCOPRef(konsole-2866, session-4)' */
1084                         if (!ptr) break;
1085                         konsole_name = strdup(ptr+1);
1086                         konsole_tab = strchr(konsole_name, ',');
1087                         if (!konsole_tab) break;
1088                         *konsole_tab++ = 0;
1089                         ptr = strchr(konsole_tab, ')');
1090                         if (ptr) *ptr = 0;
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");
1095                         if (p) {
1096                                 fscanf(p, "%lu", &w);
1097                                 pclose(p);
1098                         }
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 */
1102                         } else {
1103                                 windowid = w;
1104                                 /* $WINDOWID has not been known (KDE 3.1), thus set it up */
1105                         }
1106                         sprintf(cmd, "dcop %s konsole activateSession %s", konsole_name, konsole_tab);
1107                         system(cmd);
1108                 }
1109                 if (konsole_name) free(konsole_name);
1110                 if (cmd) free(cmd);
1111         }
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 */
1115         
1116         if (windowid) {
1117                 gdk_window_raise(gdk_window_foreign_new(windowid));
1118                 gdk_window_focus(gdk_window_foreign_new(windowid), GDK_CURRENT_TIME);
1119         }
1120 #endif /* USE_GTK */
1121
1122 #ifdef _Windows
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 */
1128
1129 #ifdef OS2
1130         /* we assume that the console window is managed by PM, not by a X server */
1131         HSWITCH hSwitch = 0;
1132         SWCNTRL swGnu;
1133         HWND hw;
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);
1140 #endif /* OS2 */
1141 }
1142
1143 /* ====license information====
1144  * End of the non-relicensable portion.
1145  */
1146
1147
1148 /* ------------------------------------------------------
1149  * Configuration dialog
1150  * ------------------------------------------------------*/
1151
1152 /* configuration dialog : handler for a close event */
1153 void wxtConfigDialog::OnClose( wxCloseEvent& WXUNUSED( event ) )
1154 {
1155         wxtFrame *parent = (wxtFrame *) GetParent();
1156         parent->config_displayed = false;
1157         this->Destroy();
1158 }
1159
1160 /* configuration dialog : handler for a button event */
1161 void wxtConfigDialog::OnButton( wxCommandEvent& event )
1162 {
1163         TBOOLEAN antialiasing;
1164         TBOOLEAN oversampling;
1165
1166         wxConfigBase *pConfig = wxConfigBase::Get();
1167         Validate();
1168         TransferDataFromWindow();
1169
1170         wxtFrame *parent = (wxtFrame *) GetParent();
1171
1172         switch (event.GetId()) {
1173         case Config_OK :
1174                 Close(true);
1175                 /* continue */
1176         case Config_APPLY :
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;
1181
1182                 switch (rendering_setting) {
1183                 case 0 :
1184                         antialiasing = FALSE;
1185                         oversampling = FALSE;
1186                         break;
1187                 case 1 :
1188                         antialiasing = TRUE;
1189                         oversampling = FALSE;
1190                         break;
1191                 case 2 :
1192                 default :
1193                         antialiasing = TRUE;
1194                         oversampling = TRUE;
1195                         break;
1196                 }
1197
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);
1202
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"));
1213                 break;
1214         case Config_CANCEL :
1215         default :
1216                 Close(true);
1217                 break;
1218         }
1219 }
1220
1221 /* Configuration dialog constructor */
1222 wxtConfigDialog::wxtConfigDialog(wxWindow* parent)
1223         : wxDialog(parent, -1, wxT("Terminal configuration"), wxDefaultPosition, wxDefaultSize,
1224                    wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1225 {
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) );*/
1234
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);
1241
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));
1251
1252         wxString choices[3];
1253         choices[0] = wxT("No antialiasing");
1254         choices[1] = wxT("Antialiasing");
1255         choices[2] = wxT("Antialiasing and oversampling");
1256
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 );
1261
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));
1266
1267         text_hinting = new wxStaticText(this, wxID_ANY,
1268                 wxT("Hinting (100=full,0=none) :"));
1269
1270         slider = new wxSlider(this, wxID_ANY, 0, 0, 100,
1271                 wxDefaultPosition, wxDefaultSize,
1272                 wxSL_HORIZONTAL|wxSL_LABELS,
1273                 wxGenericValidator(&hinting_setting));
1274
1275         if (rendering_setting != 2) {
1276                 slider->Enable(false);
1277                 text_hinting->Enable(false);
1278         }
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));
1283
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));
1291
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));
1299
1300         /* use the sizer for layout */
1301         SetSizer( vsizer );
1302         /* set size hints to honour minimum size */
1303         vsizer->SetSizeHints( this );
1304 }
1305
1306 /* enable or disable the hinting slider depending on the selection of the oversampling method */
1307 void wxtConfigDialog::OnRendering( wxCommandEvent& event )
1308 {
1309         if (event.GetInt() != 2) {
1310                 slider->Enable(false);
1311                 text_hinting->Enable(false);
1312         } else {
1313                 slider->Enable(true);
1314                 text_hinting->Enable(true);
1315         }
1316 }
1317
1318 /* ------------------------------------------------------
1319  * functions that are called by gnuplot
1320  * ------------------------------------------------------*/
1321
1322 /* "Called once, when the device is first selected."
1323  * Is the 'main' function of the terminal. */
1324 void wxt_init()
1325 {
1326         FPRINTF((stderr,"Init\n"));
1327
1328         if ( wxt_abort_init ) {
1329                 fprintf(stderr,"Previous attempt to initialize wxWidgets has failed. Not retrying.\n");
1330                 return;
1331         }
1332
1333         wxt_sigint_init();
1334
1335         if ( wxt_status == STATUS_UNINITIALIZED ) {
1336                 FPRINTF((stderr,"First Init\n"));
1337
1338 #ifdef __WXMSW__
1339                 /* the following is done in wxEntry() with wxMSW only */
1340                 wxSetInstance(GetModuleHandle(NULL));
1341                 wxApp::m_nCmdShow = SW_SHOW;
1342 #endif
1343
1344                 if (!wxInitialize()) {
1345                         fprintf(stderr,"Failed to initialize wxWidgets.\n");
1346                         wxt_abort_init = true;
1347                         return;
1348                 }
1349
1350                 /* app initialization */
1351                 wxTheApp->CallOnInit();
1352
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();
1359                 thread->Create();
1360                 thread->Run();
1361 #elif defined (__WXMSW__)
1362 /* nothing to do */
1363 #else
1364 # error "Not implemented."
1365 #endif /*__WXMSW__*/
1366
1367
1368 #ifdef USE_MOUSE
1369                 /* initialize the gnuplot<->terminal event system state */
1370                 wxt_change_thread_state(RUNNING);
1371 #endif /*USE_MOUSE*/
1372
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*/
1379
1380                 /* register call for "persist" effect and cleanup */
1381                 GP_ATEXIT(wxt_atexit);
1382         }
1383
1384         wxt_sigint_check();
1385
1386         /* try to find the requested window in the list of existing ones */
1387         wxt_current_window = wxt_findwindowbyid(wxt_window_number);
1388
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"));
1392
1393                 wxt_MutexGuiEnter();
1394                 wxt_window_t window;
1395                 window.id = wxt_window_number;
1396                 /* create a new plot window and show it */
1397                 wxString title;
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);
1403                 else
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());
1420         }
1421
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);
1426
1427         wxt_sigint_check();
1428
1429         bool raise_setting;
1430        bool persist_setting;
1431         bool ctrl_setting;
1432         int rendering_setting;
1433         int hinting_setting;
1434
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();
1438
1439         if (!pConfig->Read(wxT("raise"), &raise_setting)) {
1440                 pConfig->Write(wxT("raise"), true);
1441                 raise_setting = true;
1442         }
1443         if (wxt_raise==UNSET)
1444                 wxt_raise = raise_setting?yes:no;
1445
1446         if (!pConfig->Read(wxT("persist"), &persist_setting))
1447                 pConfig->Write(wxT("persist"), false);
1448
1449         if (!pConfig->Read(wxT("ctrl"), &ctrl_setting)) {
1450                 pConfig->Write(wxT("ctrl"), false);
1451                 ctrl_setting = false;
1452         }
1453         if (wxt_ctrl==UNSET)
1454                 wxt_ctrl = ctrl_setting?yes:no;
1455
1456         if (!pConfig->Read(wxT("rendering"), &rendering_setting)) {
1457                 pConfig->Write(wxT("rendering"), 2);
1458                 rendering_setting = 2;
1459         }
1460         switch (rendering_setting) {
1461         case 0 :
1462                 wxt_current_plot->antialiasing = FALSE;
1463                 wxt_current_plot->oversampling = FALSE;
1464                 break;
1465         case 1 :
1466                 wxt_current_plot->antialiasing = TRUE;
1467                 wxt_current_plot->oversampling = FALSE;
1468                 break;
1469         case 2 :
1470         default :
1471                 wxt_current_plot->antialiasing = TRUE;
1472                 wxt_current_plot->oversampling = TRUE;
1473                 break;
1474         }
1475
1476         if (!pConfig->Read(wxT("hinting"), &hinting_setting)) {
1477                 pConfig->Write(wxT("hinting"), 100);
1478                 hinting_setting = 100;
1479         }
1480         wxt_current_plot->hinting = hinting_setting;
1481
1482         /* accept the following commands from gnuplot */
1483         wxt_status = STATUS_OK;
1484         wxt_current_plot->interrupt = FALSE;
1485
1486         wxt_sigint_check();
1487         wxt_sigint_restore();
1488
1489         FPRINTF((stderr,"Init finished \n"));
1490 }
1491
1492
1493 /* "Called just before a plot is going to be displayed."
1494  * Should clear the terminal. */
1495 void wxt_graphics()
1496 {
1497         if (wxt_status != STATUS_OK)
1498                 return;
1499
1500 #ifdef DEBUG
1501         /* performance watch - to be removed */
1502         sw.Start();
1503 #endif
1504
1505         /* The sequence of gnuplot commands is critical as it involves mutexes.
1506          * We replace the original interrupt handler with a custom one. */
1507         wxt_sigint_init();
1508
1509         /* update the window scale factor first, cairo needs it */
1510         wxt_current_plot->xscale = 1.0;
1511         wxt_current_plot->yscale = 1.0;
1512
1513         /* apply the queued rendering settings */
1514         wxt_current_panel->wxt_settings_apply();
1515
1516         FPRINTF((stderr,"Graphics1\n"));
1517
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);
1522
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;
1531
1532         wxt_MutexGuiLeave();
1533
1534         /* set font details (hchar, vchar, h_tic, v_tic) according to settings */
1535         wxt_set_font("");
1536
1537         /* clear the command list, and free the allocated memory */
1538         wxt_current_panel->ClearCommandlist();
1539
1540         wxt_sigint_check();
1541         wxt_sigint_restore();
1542
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));
1545 }
1546
1547 void wxt_text()
1548 {
1549         if (wxt_status != STATUS_OK) {
1550 #ifdef USE_MOUSE
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. */
1554                 event_plotdone();
1555 #endif
1556                 return;
1557         }
1558
1559         wxt_sigint_init();
1560
1561         FPRINTF((stderr,"Text0 %d\n", sw.Time())); /*performance watch*/
1562
1563         /* translates the command list to a bitmap */
1564         wxt_MutexGuiEnter();
1565         wxt_current_panel->wxt_cairo_refresh();
1566         wxt_MutexGuiLeave();
1567
1568         wxt_sigint_check();
1569
1570         /* raise the window, conditionnaly to the user choice */
1571         wxt_MutexGuiEnter();
1572         wxt_raise_window(wxt_current_window,false);
1573         wxt_MutexGuiLeave();
1574
1575         FPRINTF((stderr,"Text2 %d\n", sw.Time())); /*performance watch*/
1576
1577 #ifdef USE_MOUSE
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*/
1581
1582         wxt_sigint_check();
1583         wxt_sigint_restore();
1584
1585         FPRINTF((stderr,"Text finished %d\n", sw.Time())); /*performance watch*/
1586 }
1587
1588 void wxt_reset()
1589 {
1590         /* sent when gnuplot exits and when the terminal or the output change.*/
1591         FPRINTF((stderr,"wxt_reset\n"));
1592
1593         if (wxt_status == STATUS_UNINITIALIZED)
1594                 return;
1595
1596 #ifdef USE_MOUSE
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. */
1603
1604                 /* clear the event list */
1605                 wxt_clear_event_list();
1606         }
1607
1608         /* stop sending mouse events */
1609         FPRINTF((stderr,"change thread state\n"));
1610         wxt_change_thread_state(RUNNING);
1611 #endif /*USE_MOUSE*/
1612
1613         FPRINTF((stderr,"wxt_reset ends\n"));
1614 }
1615
1616 void wxt_move(unsigned int x, unsigned int y)
1617 {
1618         if (wxt_status != STATUS_OK)
1619                 return;
1620
1621         gp_command temp_command;
1622
1623         temp_command.command = command_move;
1624         temp_command.x1 = x;
1625         temp_command.y1 = term->ymax - y;
1626
1627         wxt_command_push(temp_command);
1628 }
1629
1630 void wxt_vector(unsigned int x, unsigned int y)
1631 {
1632         if (wxt_status != STATUS_OK)
1633                 return;
1634
1635         gp_command temp_command;
1636
1637         temp_command.command = command_vector;
1638         temp_command.x1 = x;
1639         temp_command.y1 = term->ymax - y;
1640
1641         wxt_command_push(temp_command);
1642 }
1643
1644 void wxt_put_text(unsigned int x, unsigned int y, const char * string)
1645 {
1646         if (wxt_status != STATUS_OK)
1647                 return;
1648
1649         gp_command temp_command;
1650
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;
1657         else
1658                 temp_command.command = command_put_text;
1659
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);
1665
1666         wxt_command_push(temp_command);
1667 }
1668
1669 void wxt_linetype(int lt)
1670 {
1671         if (wxt_status != STATUS_OK)
1672                 return;
1673
1674         gp_command temp_command;
1675         gp_command temp_command2;
1676
1677         temp_command.command = command_color;
1678         temp_command.color = gp_cairo_linetype2color( lt );
1679
1680         temp_command2.command = command_linestyle;
1681         if (lt == -1)
1682                 temp_command2.integer_value = GP_CAIRO_DASH;
1683         else
1684                 temp_command2.integer_value = GP_CAIRO_SOLID;
1685
1686         wxt_command_push(temp_command);
1687         wxt_command_push(temp_command2);
1688 }
1689
1690
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)
1694 {
1695         if (wxt_status != STATUS_OK)
1696                 return 1;
1697
1698         char fontname[MAX_ID_LEN + 1] = "";
1699         gp_command temp_command;
1700         int fontsize = 0;
1701
1702         temp_command.command = command_set_font;
1703
1704         if (!font || !(*font)) {
1705                 strncpy(fontname, "", sizeof(fontname));
1706                 fontsize = 0;
1707         } else {
1708                 int sep;
1709
1710                 sep = strcspn(font,",");
1711                 if (sep > 0) {
1712                         strncpy(fontname, font, sep);
1713                         fontname[sep] = '\0';
1714                 }
1715                 if (font[sep] == ',')
1716                         sscanf(&(font[sep+1]), "%d", &fontsize);
1717         }
1718
1719         wxt_sigint_init();
1720         wxt_MutexGuiEnter();
1721
1722         if ( strlen(fontname) == 0 ) {
1723                 if ( strlen(wxt_set_fontname) == 0 )
1724                         strncpy(fontname, "Sans", sizeof(fontname));
1725                 else
1726                         strncpy(fontname, wxt_set_fontname, sizeof(fontname));
1727         }
1728
1729         if ( fontsize == 0 ) {
1730                 if ( wxt_set_fontsize == 0 )
1731                         fontsize = 10;
1732                 else
1733                         fontsize = wxt_set_fontsize;
1734         }
1735
1736
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();
1742         wxt_sigint_check();
1743         wxt_sigint_restore();
1744
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;
1749
1750         wxt_command_push(temp_command);
1751         /* the returned int is not used anywhere */
1752         return 1;
1753 }
1754         
1755
1756 int wxt_justify_text(enum JUSTIFY mode)
1757 {
1758         if (wxt_status != STATUS_OK)
1759                 return 1;
1760
1761         gp_command temp_command;
1762
1763         temp_command.command = command_justify;
1764         temp_command.mode = mode;
1765
1766         wxt_command_push(temp_command);
1767         return 1; /* we can justify */
1768 }
1769
1770 void wxt_point(unsigned int x, unsigned int y, int pointstyle)
1771 {
1772         if (wxt_status != STATUS_OK)
1773                 return;
1774
1775         gp_command temp_command;
1776
1777         temp_command.command = command_point;
1778         temp_command.x1 = x;
1779         temp_command.y1 = term->ymax - y;
1780         temp_command.integer_value = pointstyle;
1781
1782         wxt_command_push(temp_command);
1783 }
1784
1785 void wxt_pointsize(double ptsize)
1786 {
1787         if (wxt_status != STATUS_OK)
1788                 return;
1789
1790         /* same behaviour as x11 terminal */
1791         if (ptsize<0) ptsize = 1;
1792
1793         gp_command temp_command;
1794         temp_command.command = command_pointsize;
1795         temp_command.double_value = ptsize;
1796
1797         wxt_command_push(temp_command);
1798 }
1799
1800 void wxt_linewidth(double lw)
1801 {
1802         if (wxt_status != STATUS_OK)
1803                 return;
1804
1805         gp_command temp_command;
1806
1807         temp_command.command = command_linewidth;
1808         temp_command.double_value = lw;
1809
1810         wxt_command_push(temp_command);
1811 }
1812
1813 int wxt_text_angle(int angle)
1814 {
1815         if (wxt_status != STATUS_OK)
1816                 return 1;
1817
1818         gp_command temp_command;
1819
1820         temp_command.command = command_text_angle;
1821         /* a double is needed to compute cos, sin, etc. */
1822         temp_command.double_value = (double) angle;
1823
1824         wxt_command_push(temp_command);
1825         return 1; /* 1 means we can rotate */
1826 }
1827
1828 void wxt_fillbox(int style, unsigned int x, unsigned int y, unsigned int width, unsigned int height)
1829 {
1830         if (wxt_status != STATUS_OK)
1831                 return;
1832
1833         gp_command temp_command;
1834
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;
1841
1842         wxt_command_push(temp_command);
1843 }
1844
1845 int wxt_make_palette(t_sm_palette * palette)
1846 {
1847         /* we can do continuous colors */
1848         return 0;
1849 }
1850
1851 void wxt_set_color(t_colorspec *colorspec)
1852 {
1853         if (wxt_status != STATUS_OK)
1854                 return;
1855
1856         rgb_color rgb1;
1857         gp_command temp_command;
1858
1859         if (colorspec->type == TC_LT) {
1860                 wxt_linetype(colorspec->lt);
1861                 return;
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;
1868         } else return;
1869
1870         temp_command.command = command_color;
1871         temp_command.color = rgb1;
1872
1873         wxt_command_push(temp_command);
1874 }
1875
1876
1877 /* here we send the polygon command */
1878 void wxt_filled_polygon(int n, gpiPoint *corners)
1879 {
1880         if (wxt_status != STATUS_OK)
1881                 return;
1882
1883         gp_command temp_command;
1884
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;
1893                 ++corners_copy;
1894         }
1895
1896         wxt_command_push(temp_command);
1897 }
1898
1899 #ifdef WITH_IMAGE
1900 void wxt_image(unsigned M, unsigned N, coordval * image, gpiPoint * corner, t_imagecolor color_mode)
1901 {
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
1928         image. */
1929
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 ??? */
1933
1934         if (wxt_status != STATUS_OK)
1935                 return;
1936
1937         int imax;
1938         gp_command temp_command;
1939
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;   
1952
1953         if (color_mode == IC_RGB)
1954                 imax = 3*M*N;
1955         else
1956                 imax = M*N;
1957
1958         temp_command.image = new coordval[imax];
1959         memcpy(temp_command.image, image, imax*sizeof(coordval));
1960
1961         wxt_command_push(temp_command);
1962 }
1963 #endif /*WITH_IMAGE*/
1964
1965 #ifdef USE_MOUSE
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[])
1971 {
1972         if (wxt_status == STATUS_UNINITIALIZED)
1973                 return;
1974
1975         wxt_sigint_init();
1976         wxt_MutexGuiEnter();
1977
1978         switch ( n ) {
1979         case 0:
1980                 wxt_current_window->frame->SetStatusText( wxString(str, wxConvLocal) );
1981                 break;
1982         case 1:
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);
1986                 break;
1987         case 2:
1988                 if ( strlen(str)==0 )
1989                         wxt_current_panel->wxt_zoombox = false;
1990                 else {
1991                         wxt_current_panel->wxt_zoombox = true;
1992                         wxt_current_panel->zoom_string2 =  wxString(str, wxConvLocal);
1993                 }
1994                 wxt_current_panel->Draw();
1995                 break;
1996         default :
1997                 break;
1998         }
1999
2000         wxt_MutexGuiLeave();
2001         wxt_sigint_check();
2002         wxt_sigint_restore();
2003 }
2004
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,
2009  * -1=start zooming,
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)
2015 {
2016         if (wxt_status == STATUS_UNINITIALIZED)
2017                 return;
2018
2019         wxt_sigint_init();
2020         wxt_MutexGuiEnter();
2021
2022         switch ( c ) {
2023         case -4:
2024                 wxt_current_panel->wxt_ruler_lineto = false;
2025                 wxt_current_panel->Draw();
2026                 break;
2027         case -3:
2028                 wxt_current_panel->wxt_ruler_lineto = true;
2029                 wxt_current_panel->Draw();
2030                 break;
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) );
2035                 break;
2036         case -1: /* start zooming */
2037                 wxt_current_panel->SetCursor(wxt_cursor_right);
2038                 break;
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();
2043                 break;
2044         case 1: /* rotation */
2045                 wxt_current_panel->SetCursor(wxt_cursor_rotate);
2046                 break;
2047         case 2: /* scaling */
2048                 wxt_current_panel->SetCursor(wxt_cursor_size);
2049                 break;
2050         case 3: /* zooming */
2051                 wxt_current_panel->SetCursor(wxt_cursor_right);
2052                 break;
2053         default:
2054                 wxt_current_panel->SetCursor(wxt_cursor_cross);
2055                 break;
2056         }
2057
2058         wxt_MutexGuiLeave();
2059         wxt_sigint_check();
2060         wxt_sigint_restore();
2061 }
2062
2063
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)
2067 {
2068         if (wxt_status == STATUS_UNINITIALIZED)
2069                 return;
2070
2071         wxt_sigint_init();
2072         wxt_MutexGuiEnter();
2073
2074         if (x<0) {
2075                 wxt_current_panel->wxt_ruler = false;
2076                 wxt_current_panel->Draw();
2077         } else {
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();
2082         }
2083
2084         wxt_MutexGuiLeave();
2085         wxt_sigint_check();
2086         wxt_sigint_restore();
2087 }
2088
2089 /* Write a string to the clipboard */
2090 void wxt_set_clipboard(const char s[])
2091 {
2092         if (wxt_status == STATUS_UNINITIALIZED)
2093                 return;
2094
2095         wxt_sigint_init();
2096         wxt_MutexGuiEnter();
2097
2098         if (wxTheClipboard->Open()) {
2099                 wxTheClipboard->SetData( new wxTextDataObject(wxString(s, wxConvLocal)) );
2100                 wxTheClipboard->Flush();
2101                 wxTheClipboard->Close();
2102         }
2103
2104         wxt_MutexGuiLeave();
2105         wxt_sigint_check();
2106         wxt_sigint_restore();
2107 }
2108 #endif /*USE_MOUSE*/
2109
2110
2111 /* ===================================================================
2112  * Command list processing
2113  * =================================================================*/
2114
2115 /* push a command in the current commands list */
2116 void wxt_command_push(gp_command command)
2117 {
2118         wxt_sigint_init();
2119         wxt_current_panel->command_list_mutex.Lock();
2120         wxt_current_command_list->push_back(command);
2121         wxt_current_panel->command_list_mutex.Unlock();
2122         wxt_sigint_check();
2123         wxt_sigint_restore();
2124 }
2125
2126 /* refresh the plot by (re)processing the plot commands list */
2127 void wxtPanel::wxt_cairo_refresh()
2128 {
2129         /* Clear background. */
2130         gp_cairo_clear(&plot);
2131
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 */
2140                         Draw();
2141                         return;
2142                 }
2143                 wxt_cairo_exec_command( *wxt_iter );
2144         }
2145
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);
2150
2151 /* the following is a test for a bug in cairo when drawing to a gdkpixmap */
2152 #if 0
2153         cairo_set_source_rgb(plot.cr,1,1,1);
2154         cairo_paint(plot.cr);
2155
2156         cairo_matrix_t matrix;
2157         cairo_matrix_init(&matrix,
2158                         plot.xscale,
2159                         0,
2160                         0,
2161                         plot.yscale,
2162                         0,
2163                         0);
2164         cairo_set_matrix(plot.cr, &matrix);
2165
2166         cairo_t *context;
2167         cairo_surface_t *surface;
2168         surface = cairo_surface_create_similar(cairo_get_target(plot.cr),
2169                                              CAIRO_CONTENT_COLOR_ALPHA,
2170                                              plot.device_xmax,
2171                                              plot.device_ymax);
2172         context = cairo_create(surface);
2173         cairo_set_operator(context,CAIRO_OPERATOR_SATURATE);
2174
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);
2181
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);
2188
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);
2195
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);
2202
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);
2209
2210         cairo_pattern_t *pattern = cairo_pattern_create_for_surface( surface );
2211         cairo_destroy( context );
2212
2213         cairo_surface_destroy( surface );
2214         cairo_set_source( plot.cr, pattern );
2215         cairo_pattern_destroy( pattern );
2216         cairo_paint(plot.cr);
2217
2218         cairo_matrix_init(&matrix,
2219                         plot.xscale/plot.oversampling_scale,
2220                         0,
2221                         0,
2222                         plot.yscale/plot.oversampling_scale,
2223                         0,
2224                         0);
2225         cairo_set_matrix(plot.cr, &matrix);
2226 #endif
2227
2228 #ifdef IMAGE_SURFACE
2229         wxt_cairo_create_bitmap();
2230 #endif /* !have_gtkcairo */
2231
2232         /* draw the pixmap to the screen */
2233         Draw();
2234         FPRINTF((stderr,"commands done, number of commands %d\n", command_list.size()));
2235 }
2236
2237
2238 void wxtPanel::wxt_cairo_exec_command(gp_command command)
2239 {
2240         switch ( command.command ) {
2241         case command_color :
2242                 gp_cairo_set_color(&plot,command.color);
2243                 return;
2244         case command_filled_polygon :
2245                 gp_cairo_draw_polygon(&plot, command.integer_value, command.corners);
2246                 return;
2247         case command_move :
2248                 gp_cairo_move(&plot, command.x1, command.y1);
2249                 return;
2250         case command_vector :
2251                 gp_cairo_vector(&plot, command.x1, command.y1);
2252                 return;
2253         case command_linestyle :
2254                 gp_cairo_set_linestyle(&plot, command.integer_value);
2255                 return;
2256         case command_linetype :
2257                 gp_cairo_set_linetype(&plot, command.integer_value);
2258                 return;
2259         case command_pointsize :
2260                 gp_cairo_set_pointsize(&plot, command.double_value);
2261                 return;
2262         case command_point :
2263                 gp_cairo_draw_point(&plot, command.x1, command.y1, command.integer_value);
2264                 return;
2265         case command_justify :
2266                 gp_cairo_set_justify(&plot,command.mode);
2267                 return;
2268         case command_put_text :
2269                 gp_cairo_draw_text(&plot, command.x1, command.y1, command.string);
2270                 return;
2271         case command_enhanced_put_text :
2272                 gp_cairo_draw_enhanced_text(&plot, command.x1, command.y1, command.string);
2273                 return;
2274         case command_set_font :
2275                 gp_cairo_set_font(&plot, command.string, command.integer_value);
2276                 return;
2277         case command_linewidth :
2278                 gp_cairo_set_linewidth(&plot, command.double_value);;
2279                 return;
2280         case command_text_angle :
2281                 gp_cairo_set_textangle(&plot, command.double_value);
2282                 return;
2283         case command_fillbox :
2284                 gp_cairo_draw_fillbox(&plot, command.x1, command.y1,
2285                                         command.x2, command.y2,
2286                                         command.integer_value);
2287                 return;
2288 #ifdef WITH_IMAGE
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);
2297                 return;
2298 #endif /*WITH_IMAGE*/
2299         }
2300 }
2301
2302
2303 /* given a plot number (id), return the associated plot structure */
2304 wxt_window_t* wxt_findwindowbyid(wxWindowID id)
2305 {
2306         size_t i;
2307         for(i=0;i<wxt_window_list.size();++i) {
2308                 if (wxt_window_list[i].id == id)
2309                         return &(wxt_window_list[i]);
2310         }
2311         return NULL;
2312 }
2313
2314 /*----------------------------------------------------------------------------
2315  *   raise-lower functions
2316  *----------------------------------------------------------------------------*/
2317
2318 void wxt_raise_window(wxt_window_t* window, bool force)
2319 {
2320         FPRINTF((stderr,"raise window\n"));
2321
2322         window->frame->Show(true);
2323
2324         if (wxt_raise != no||force) {
2325 #ifdef USE_GTK
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);
2332 #else
2333                 window->frame->Raise();
2334 #endif /*USE_GTK */
2335         }
2336 }
2337
2338
2339 void wxt_lower_window(wxt_window_t* window)
2340 {
2341 #ifdef USE_GTK
2342         window->frame->panel->Refresh(false);
2343         gdk_window_lower(window->frame->GetHandle()->window);
2344 #else
2345         window->frame->Lower();
2346 #endif /* USE_GTK */
2347 }
2348
2349
2350 /* raise the plot with given number */
2351 void wxt_raise_terminal_window(int number)
2352 {
2353         wxt_window_t *window;
2354
2355         if (wxt_status != STATUS_OK)
2356                 return;
2357
2358         wxt_sigint_init();
2359
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);
2365         }
2366         wxt_MutexGuiLeave();
2367
2368         wxt_sigint_check();
2369         wxt_sigint_restore();
2370 }
2371
2372 /* raise the plot the whole group */
2373 void wxt_raise_terminal_group()
2374 {
2375         /* declare the iterator */
2376         std::vector<wxt_window_t>::iterator wxt_iter;
2377
2378         if (wxt_status != STATUS_OK)
2379                 return;
2380
2381         wxt_sigint_init();
2382
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);
2389         }
2390         wxt_MutexGuiLeave();
2391
2392         wxt_sigint_check();
2393         wxt_sigint_restore();
2394 }
2395
2396 /* lower the plot with given number */
2397 void wxt_lower_terminal_window(int number)
2398 {
2399         wxt_window_t *window;
2400
2401         if (wxt_status != STATUS_OK)
2402                 return;
2403
2404         wxt_sigint_init();
2405
2406         wxt_MutexGuiEnter();
2407         if ((window = wxt_findwindowbyid(number))) {
2408                 FPRINTF((stderr,"wxt : lower window %d\n",number));
2409                 wxt_lower_window(window);
2410         }
2411         wxt_MutexGuiLeave();
2412
2413         wxt_sigint_check();
2414         wxt_sigint_restore();
2415 }
2416
2417 /* lower the plot the whole group */
2418 void wxt_lower_terminal_group()
2419 {
2420         /* declare the iterator */
2421         std::vector<wxt_window_t>::iterator wxt_iter;
2422
2423         if (wxt_status != STATUS_OK)
2424                 return;
2425
2426         wxt_sigint_init();
2427
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));
2432         }
2433         wxt_MutexGuiLeave();
2434
2435         wxt_sigint_check();
2436         wxt_sigint_restore();
2437 }
2438
2439 /* close the specified window */
2440 void wxt_close_terminal_window(int number)
2441 {
2442         wxt_window_t *window;
2443
2444         if (wxt_status != STATUS_OK)
2445                 return;
2446
2447         wxt_sigint_init();
2448
2449         wxt_MutexGuiEnter();
2450         if ((window = wxt_findwindowbyid(number))) {
2451                 FPRINTF((stderr,"wxt : close window %d\n",number));
2452                 window->frame->Close(false);
2453         }
2454         wxt_MutexGuiLeave();
2455
2456         wxt_sigint_check();
2457         wxt_sigint_restore();
2458 }
2459
2460 /* update the window title */
2461 void wxt_update_title(int number)
2462 {
2463         wxt_window_t *window;
2464         wxString title;
2465
2466         if (wxt_status != STATUS_OK)
2467                 return;
2468
2469         wxt_sigint_init();
2470
2471         wxt_MutexGuiEnter();
2472
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);
2480                 } else
2481                         title.Printf(wxT("Gnuplot (window id : %d)"), window->id);
2482
2483                 window->frame->SetTitle(title);
2484         }
2485
2486         wxt_MutexGuiLeave();
2487
2488         wxt_sigint_check();
2489         wxt_sigint_restore();
2490 }
2491
2492 /* --------------------------------------------------------
2493  * Cairo stuff
2494  * --------------------------------------------------------*/
2495
2496 void wxtPanel::wxt_cairo_create_context()
2497 {
2498         cairo_surface_t *fake_surface;
2499
2500         if ( plot.cr )
2501                 cairo_destroy(plot.cr);
2502
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;
2512         } else {
2513                 plot.success = TRUE;
2514         }
2515
2516         /* set the transformation matrix of the context, and other details */
2517         gp_cairo_initialize_context(&plot);
2518 }
2519
2520 void wxtPanel::wxt_cairo_free_context()
2521 {
2522         if (plot.cr)
2523                 cairo_destroy(plot.cr);
2524
2525         if (plot.success)
2526                 wxt_cairo_free_platform_context();
2527 }
2528
2529
2530 #ifdef GTK_SURFACE
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()
2534 {
2535         cairo_surface_t *surface;
2536         wxClientDC dc(this);
2537
2538         FPRINTF((stderr,"wxt_cairo_create_context\n"));
2539
2540         /* free gdkpixmap */
2541         wxt_cairo_free_platform_context();
2542         
2543         /* GetWindow is a wxGTK specific wxDC method that returns
2544          * the GdkWindow on which painting should be done */
2545
2546         if ( !GDK_IS_DRAWABLE(dc.GetWindow()) )
2547                 return 1;
2548
2549
2550         gdkpixmap = gdk_pixmap_new(dc.GetWindow(), plot.device_xmax, plot.device_ymax, -1);
2551
2552         if ( !GDK_IS_DRAWABLE(gdkpixmap) )
2553                 return 1;
2554
2555         plot.cr = gdk_cairo_create(gdkpixmap);
2556         return 0;
2557 }
2558
2559 void wxtPanel::wxt_cairo_free_platform_context()
2560 {
2561         if (gdkpixmap)
2562                 g_object_unref(gdkpixmap);
2563 }
2564
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()
2569 {
2570         cairo_surface_t *surface;
2571         wxClientDC dc(this);
2572
2573         FPRINTF((stderr,"wxt_cairo_create_context\n"));
2574
2575         /* free hdc and hbm */
2576         wxt_cairo_free_platform_context();
2577
2578         /* GetHDC is a wxMSW specific wxDC method that returns
2579          * the HDC on which painting should be done */
2580
2581         /* Create a compatible DC. */
2582         hdc = CreateCompatibleDC( (HDC) dc.GetHDC() );
2583
2584         if (!hdc)
2585                 return 1;
2586
2587         /* Create a bitmap big enough for our client rectangle. */
2588         hbm = CreateCompatibleBitmap((HDC) dc.GetHDC(), plot.device_xmax, plot.device_ymax);
2589
2590         if ( !hbm )
2591                 return 1;
2592
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 );
2598         return 0;
2599 }
2600
2601 void wxtPanel::wxt_cairo_free_platform_context()
2602 {
2603         if (hdc)
2604                 DeleteDC(hdc);
2605         if (hbm)
2606                 DeleteObject(hbm);
2607 }
2608
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()
2613 {
2614         int width, height;
2615         cairo_surface_t *surface;
2616
2617         FPRINTF((stderr,"wxt_cairo_create_context\n"));
2618
2619         if (data32)
2620                 delete[] data32;
2621
2622         width = plot.device_xmax;
2623         height = plot.device_ymax;
2624
2625         if (width<1||height<1)
2626                 return 1;
2627
2628         data32 = new unsigned int[width*height];
2629
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 );
2634         return 0;
2635 }
2636
2637
2638 /* create a wxBitmap (to be painted to the screen) from the buffered cairo surface. */
2639 void wxtPanel::wxt_cairo_create_bitmap()
2640 {
2641         int width, height;
2642         unsigned char *data24;
2643         wxImage *image;
2644
2645         if (!data32)
2646                 return;
2647
2648         width = plot.device_xmax;
2649         height = plot.device_ymax;
2650
2651         data24 = new unsigned char[3*width*height];
2652
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);
2660         }
2661
2662         /* create a wxImage from data24 */
2663         image = new wxImage(width, height, data24, true);
2664
2665         if (cairo_bitmap)
2666                 delete cairo_bitmap;
2667
2668         /* create a wxBitmap from the wxImage. */
2669         cairo_bitmap = new wxBitmap( *image );
2670
2671         /* free memory */
2672         delete image;
2673         delete[] data24;
2674 }
2675
2676
2677 void wxtPanel::wxt_cairo_free_platform_context()
2678 {
2679         if (data32)
2680                 delete[] data32;
2681         if (cairo_bitmap)
2682                 delete cairo_bitmap;
2683 }
2684 #endif /* IMAGE_SURFACE */
2685
2686 /* --------------------------------------------------------
2687  * events handling
2688  * --------------------------------------------------------*/
2689
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 */
2693
2694 #ifdef WXTDEBUGINPUT
2695 # define FPRINTF2(a) FPRINTF(a)
2696 #else
2697 # define FPRINTF2(a)
2698 #endif
2699
2700 #ifdef USE_MOUSE
2701 /* protected check for the state of the event list */
2702 bool wxt_check_eventlist_empty()
2703 {
2704         bool result;
2705         mutexProtectingEventList.Lock();
2706         result = EventList.empty();
2707         mutexProtectingEventList.Unlock();
2708         return result;
2709 }
2710
2711 /* protected check for the state of the main thread (running or waiting for input) */
2712 wxt_thread_state_t wxt_check_thread_state()
2713 {
2714         wxt_thread_state_t result;
2715         mutexProtectingThreadState.Lock();
2716         result = wxt_thread_state;
2717         mutexProtectingThreadState.Unlock();
2718         return result;
2719 }
2720
2721 /* multithread safe method to change thread state */
2722 void wxt_change_thread_state(wxt_thread_state_t state)
2723 {
2724         wxt_sigint_init();
2725         mutexProtectingThreadState.Lock();
2726         wxt_thread_state = state;
2727         mutexProtectingThreadState.Unlock();
2728         wxt_sigint_check();
2729         wxt_sigint_restore();
2730 }
2731
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)
2736 {
2737         struct gp_event_t event;
2738
2739         event.type = type;
2740         event.mx = mx;
2741         event.my = my;
2742         event.par1 = par1;
2743         event.par2 = par2;
2744         event.winid = id;
2745
2746 #ifdef _Windows
2747         FPRINTF2((stderr,"Processing event\n"));
2748         do_event( &event );
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;
2758         }
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;
2763         }
2764 #else
2765         /* add the event to the event list */
2766         if (wxt_check_thread_state() == WAITING_FOR_STDIN)
2767         {
2768                 FPRINTF2((stderr,"Gui thread adds an event to the list\n"));
2769                 mutexProtectingEventList.Lock();
2770                 EventList.push_back(event);
2771                 mutexProtectingEventList.Unlock();
2772         }
2773 #endif /* ! _Windows */
2774 }
2775
2776
2777 /* clear the event list, caring for the mutex */
2778 void wxt_clear_event_list()
2779 {
2780         mutexProtectingEventList.Lock();
2781         EventList.clear();
2782         mutexProtectingEventList.Unlock();
2783 }
2784
2785
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()
2790 {
2791         struct gp_event_t wxt_event;
2792         int button;
2793
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)
2811                                 return 1;
2812                 }
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;
2817                                 return 1;
2818                         }
2819                 }
2820         }
2821         return 0;
2822         
2823 }
2824
2825 #ifdef __WXMSW__
2826 /* Implements waitforinput used in wxt.trm
2827  * the terminal events are directly processed when they are received */
2828 int wxt_waitforinput()
2829 {
2830         return getch();
2831 }
2832
2833 #elif defined(__WXGTK__)||defined(__WXMAC__)
2834
2835 /* Implements waitforinput used in wxt.trm
2836  * Returns the next input charachter, meanwhile treats terminal events */
2837 int wxt_waitforinput()
2838 {
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)
2847                 return getc(stdin);
2848
2849         int ierr;
2850         int fd = fileno(stdin);
2851         struct timeval timeout;
2852         fd_set fds;
2853
2854         wxt_change_thread_state(WAITING_FOR_STDIN);
2855
2856         do {
2857                 if (wxt_process_events()) {
2858                         wxt_change_thread_state(RUNNING);
2859                         return '\0';
2860                 }
2861
2862                 timeout.tv_sec = 0;
2863                 timeout.tv_usec = 10000;
2864                 FD_ZERO(&fds);
2865                 FD_SET(0/*fd*/,&fds);
2866
2867                 ierr = select(1, &fds, NULL, NULL, &timeout);
2868
2869                 /* check for error on select and return immediately if any */
2870                 if (ierr<0) {
2871                         wxt_change_thread_state(RUNNING);
2872                         return '\0';
2873                 }
2874         } while (!FD_ISSET(fd,&fds));
2875
2876         /* if we are paused_for_mouse, we should continue to wait for a mouse click */
2877         if (paused_for_mouse)
2878                 while (true) {
2879                         if (wxt_process_events()) {
2880                                 wxt_change_thread_state(RUNNING);
2881                                 return '\0';
2882                         }
2883                         /* wait 10 microseconds */
2884                         wxMicroSleep(10);
2885                 }
2886
2887         wxt_change_thread_state(RUNNING);
2888         return getchar();
2889 }
2890 #else  /* !__WXMSW__ && !__WXGTK__ && !__WXMAC__*/
2891 #error "Not implemented"
2892 #endif
2893
2894 #endif /*USE_MOUSE*/
2895
2896 /* --------------------------------------------------------
2897  * 'persist' option handling
2898  * --------------------------------------------------------*/
2899
2900 /* returns true if at least one plot window is opened.
2901  * Used to handle 'persist' */
2902 bool wxt_window_opened()
2903 {
2904         std::vector<wxt_window_t>::iterator wxt_iter; /*declare the iterator*/
2905
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();
2910                         return true;
2911                 }
2912         }
2913         wxt_MutexGuiLeave();
2914         return false;
2915 }
2916
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. */
2921 void wxt_atexit()
2922 {
2923         int i;
2924         int persist_setting;
2925 #ifdef _Windows
2926         MSG msg;
2927 #endif /*_Windows*/
2928
2929         if (wxt_status == STATUS_UNINITIALIZED)
2930                 return;
2931
2932         /* first look for command_line setting */
2933         if (wxt_persist==UNSET && persist_cl)
2934                 wxt_persist = TRUE;
2935
2936         wxConfigBase *pConfig = wxConfigBase::Get();
2937
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;
2942         }
2943
2944         /* and let's go ! */
2945         if (wxt_persist==UNSET|| wxt_persist==no) {
2946                 wxt_cleanup();
2947                 return;
2948         }
2949
2950         /* if the user hits ctrl-c and quits again, really quit */
2951         wxt_persist = no;
2952
2953         FPRINTF((stderr,"wxWidgets terminal handles 'persist' setting\n"));
2954
2955 #ifdef _Windows
2956         if (!interactive) {
2957                 interactive = TRUE;
2958                 /* be sure to show the text window */
2959                 ShowWindow(textwin.hWndParent, textwin.nCmdShow);
2960                 while (!com_line());
2961         }
2962
2963         /* cleanup and quit */
2964         wxt_cleanup();
2965 #else /*_Windows*/
2966
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 );
2978
2979         /* wait for the gui thread to exit */
2980         thread->Wait();
2981         delete thread;
2982
2983         /* fork */
2984         pid_t pid = fork();
2985
2986         /* the parent just exits, the child keeps going */
2987         if (!pid) {
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();
2991                 thread->Create();
2992                 thread->Run();
2993
2994 # endif /* HAVE_WORKING_FORK */
2995
2996 # ifdef USE_MOUSE
2997                 wxt_change_thread_state(WAITING_FOR_STDIN);
2998 # endif /*USE_MOUSE*/
2999
3000                 /* protect the following from interrupt */
3001                 wxt_sigint_init();
3002
3003                 while (wxt_window_opened()) {
3004 # ifdef USE_MOUSE
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 */
3011                         wxMicroSleep(10);
3012                         wxt_sigint_check();
3013                 }
3014
3015                 wxt_sigint_restore();
3016
3017 # ifdef USE_MOUSE
3018                 wxt_change_thread_state(RUNNING);
3019 # endif /*USE_MOUSE*/
3020
3021                 /* cleanup and quit */
3022                 wxt_cleanup();
3023
3024 # ifdef HAVE_WORKING_FORK
3025         }
3026 # endif /* HAVE_WORKING_FORK */
3027 #endif /* !_Windows */
3028 }
3029
3030
3031 /* destroy everything related to wxWidgets */
3032 void wxt_cleanup()
3033 {
3034         std::vector<wxt_window_t>::iterator wxt_iter; /*declare the iterator*/
3035
3036         if (wxt_status == STATUS_UNINITIALIZED)
3037                 return;
3038
3039         FPRINTF((stderr,"cleanup before exit\n"));
3040
3041         /* prevent wxt_reset (for example) from doing anything bad after that */
3042         wxt_status = STATUS_UNINITIALIZED;
3043
3044         /* protect the following from interrupt */
3045         wxt_sigint_init();
3046
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();
3052
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(),
3057                         thread->IsAlive(),
3058                         thread->IsRunning() ));
3059
3060         thread->Wait();
3061         delete thread;
3062         FPRINTF((stderr,"gui thread exited\n"));
3063 #endif /* __WXGTK || __WXMAC__*/
3064
3065         wxTheApp->OnExit();
3066         wxUninitialize();
3067
3068         /* handle eventual interrupt, and restore original sigint handler */
3069         wxt_sigint_check();
3070         wxt_sigint_restore();
3071
3072         FPRINTF((stderr,"wxWidgets terminal properly cleaned-up\n"));
3073 }
3074
3075 /* -------------------------------------
3076  * GUI Mutex helper functions for porting
3077  * ----------------------------------------*/
3078
3079 void wxt_MutexGuiEnter()
3080 {
3081         FPRINTF2((stderr,"locking gui mutex\n"));
3082 #if defined(__WXGTK__)||defined(__WXMAC__)
3083         wxMutexGuiEnter();
3084 #elif defined(__WXMSW__)
3085 #else
3086 # error "No implementation"
3087 #endif
3088 }
3089
3090 void wxt_MutexGuiLeave()
3091 {
3092         FPRINTF2((stderr,"unlocking gui mutex\n"));
3093 #if defined(__WXGTK__)||defined(__WXMAC__)
3094         wxMutexGuiLeave();
3095 #elif defined(__WXMSW__)
3096 #else
3097 # error "No implementation"
3098 #endif
3099 }
3100
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  * ---------------------------------------------------*/
3112
3113
3114 /* our custom SIGINT handler, that just sets a flag */
3115 void wxt_sigint_handler(int WXUNUSED(sig))
3116 {
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;
3124 }
3125
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()
3129 {
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);
3136 }
3137
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()
3141 {
3142         FPRINTF2((stderr,"checking interrupt status\n"));
3143         if (wxt_status == STATUS_INTERRUPT_ON_NEXT_CHECK)
3144                 wxt_sigint_return();
3145 }
3146
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()
3150 {
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));
3156 }
3157
3158 /* restore the original SIGINT handler */
3159 void wxt_sigint_restore()
3160 {
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");
3167 }