1 /******************************************************************************
2 *                                                                             *
3 *   T e x t   w i n d o w   t h a t   a l l o w s   s i m p l e   I / O       *
4 *                                                                             *
5 *******************************************************************************
6 * Copyright (C) 2003-17 by Arthur Norman, Codemist. All Rights Reserved.      *
7 *******************************************************************************
8 * This library is free software; you can redistribute it and/or               *
9 * modify it under the terms of the GNU Lesser General Public                  *
10 * License as published by the Free Software Foundation;                       *
11 * version 2.1 of the License.                                                 *
12 *                                                                             *
13 * This library is distributed in the hope that it will be useful,             *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of              *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           *
16 * Lesser General Public License for more details.                             *
17 *                                                                             *
18 * You should have received a copy of the GNU Lesser General Public            *
19 * License along with this library; if not, write to the Free Software         *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.  *
21 *                                                                             *
22 * I would have granted rights similar to those in the FOX addendum to the     *
23 * LGPL, but since this code requires modifications to the body of FOX I am    *
24 * not able to to do that and this is hence only available under LGPL 2.1      *
25 ******************************************************************************/
26 
27 // However as a special exception to LGPL 2.1 I grant permission for my code
28 // to be merged or linked with other code that is subject to LGPL version 3
29 // or GPL version 3. This provision does not represent permission to alter the
30 // license of my code to be that of LGPL 3 or GPL 3 - of itself and when
31 // removed from any LGPL 3 context it remains LGPL 2.1 and the freedom
32 // enshrined by that can not be reduced by adding in the additional
33 // constraints that LGPL 3 views as protections. However clearly the combined
34 // work that then includes my work would be subject to "3". But as per LGPL
35 // 2.1 (and the same would be true if I had used a BSD-style license here)
36 // notices explaining the license terms related to my code should not be
37 // removed. Anybody who changes or extends my code is permitted but not
38 // obliged to apply this exception, and perhaps by doing do they do not lock
39 // out (L)GPL 3 users but guarantee continued support for (L)GPL 2.1 in a way
40 // that the "or later" clause does not (since that permits anybody to
41 // unilaterally select just one version of the library to use, to the
42 // potential detriment of those whose choice differs).
43 
44 
45 #ifndef FXTERMINAL_H
46 #define FXTERMINAL_H
47 
48 #include "FXText.h"
49 
50 #include "FXDCNativePrinter.h"
51 
52 
53 // Include header files that give access to thread primitives.
54 
55 #ifdef WIN32
56 #include <windows.h>
57 #else
58 #include <pthread.h>
59 #endif
60 
61 #ifndef WIN64
62 #include <unistd.h>
63 #endif
64 
65 extern int windowed;
66 
67 namespace FX {
68 
69 // Firstly I will define a Mutex. This is something made pretty directly
70 // available in both Windows and Posix threads. Because of this I will
71 // just map names using some C macros.
72 
73 // Mutex m;
74 // InitMutex(m);
75 // ... LockMutex(m) ... UnlockMutex(m) ...
76 // DestroyMutex(m);
77 
78 // It will often make sense to put calls to DestroyMutex in the destuctor
79 // for a class where its constructor did the InitMutex.
80 
81 
82 #ifdef WIN32
83 typedef CRITICAL_SECTION Mutex;
84 #define InitMutex(m)    InitializeCriticalSection(&m)
85 #define DestroyMutex(m) DeleteCriticalSection(&m)
86 #define LockMutex(m)    EnterCriticalSection(&m)
87 #define UnlockMutex(m)  LeaveCriticalSection(&m)
88 #else
89 typedef pthread_mutex_t Mutex;
90 #define InitMutex(m)    pthread_mutex_init(&m, NULL)
91 #define DestroyMutex(m) pthread_mutex_destroy(&m)
92 #define LockMutex(m)    pthread_mutex_lock(&m)
93 #define UnlockMutex(m)  pthread_mutex_unlock(&m)
94 #endif
95 
96 
97 // signalling from one task to another
98 
99 #ifdef WIN32
100 extern HANDLE pipedes;
101 extern int event_code;
102 #else
103 extern int pipedes[2];
104 #endif
105 #define PIPE_READ_PORT 0
106 #define PIPE_WRITE_PORT 1
107 
108 extern FXMenuBar *main_menu_bar;
109 
110 extern char **modules_list, **switches_list;
111 
112 extern const char *fwin_maths;
113 
114 //
115 // I derive a sub-class from MainWindow just so I can notice when the
116 // window is re-sized and record information in the registry.
117 //
118 
119 class FXAPI FXMainWindow1 : public FXMainWindow
120 {
121     FXDECLARE(FXMainWindow1)
122 public:
123     FXMainWindow1(FXApp *, const FXString &, FXIcon *, FXIcon *, FXuint,
124         FXint,FXint,FXint,FXint,FXint,FXint,FXint,FXint,FXint,FXint);
125     FXMainWindow1();
126     virtual void create();
127     long onConfigure(FXObject *,FXSelector,void *);
128 };
129 
130 
131 extern const char *colour_spec;
132 extern FXApp *application_object;
133 extern FXMainWindow1 *main_window;
134 extern const char *reduceMenus[];
135 #ifdef WIN32
136 extern DWORD __stdcall worker_thread(void *);
137 #else
138 extern void *worker_thread(void *);
139 #endif
140 extern FXTimer *timer;
141 extern char mid_stuff[32], full_title[90];
142 
143 extern FXFont *selectFont(const char *name, int size,
144     int weight, int slant, int encoding, int setwidth, int hints);
145 
146 #ifdef WIN32
147 extern HANDLE thread1;
148 #else
149 extern pthread_t thread1;
150 #endif
151 
152 extern int rootWidth, rootHeight;
153 
154 /// Multiline text widget supporting use as a terminal-window style
155 /// interface to other worker code.
156 
157 class FXAPI FXTerminal : public FXText {
158   FXDECLARE(FXTerminal)
159 
160 public:
161   enum {
162     STYLE_UNDERLINE = 0x0001,   /// Underline text
163     STYLE_STRIKEOUT = 0x0002,   /// Strike out text
164     STYLE_BOLD      = 0x0004,   /// bold text
165     STYLE_PROMPT    = 0x0008,   /// displayed in alternate colour
166     STYLE_INPUT     = 0x0010,   /// displayed in yet another colour
167     STYLE_MATH      = 0x0020,   /// mathematics in TeX internal style
168     STYLE_GREEK     = 0x0040    /// displayed in alternate font (sometime?)
169     };
170 
171   long onTimeout(FXObject*,FXSelector,void*);
172   long onCmdInsertNewline(FXObject*,FXSelector,void*);
173   long onIPC(FXObject*,FXSelector,void*);
174 
175   long requestFlushBuffer();
176   long requestSetPrompt();
177   long requestRequestInput();
178   long requestWorkerExiting();
179   long requestRefreshTitle();
180   long requestShowMath();
181   long requestSetMenus();
182   long requestRefreshSwitches();
183 
184   long onCmdRead(FXObject *c, FXSelector s, void *ptr);
185   long onCmdSave(FXObject *c, FXSelector s, void *ptr);
186   long onCmdSaveSelection(FXObject *c, FXSelector s, void *ptr);
187   long onCmdToFile(FXObject *c, FXSelector s, void *ptr);
188   long onCmdPrint(FXObject *c, FXSelector s, void *ptr);
189   long onCmdPrintSelection(FXObject *c, FXSelector s, void *ptr);
190   long doPrinting(int startp, int endp);
191   long onCmdCutSel(FXObject *c, FXSelector s, void *ptr);
192   long onCmdPasteSel(FXObject *c, FXSelector s, void *ptr);
193   long onCmdPasteMiddle(FXObject *c, FXSelector s, void *ptr);
194   long onCmdCopySel(FXObject *c, FXSelector s, void *ptr);
195   long onCmdCopySelText(FXObject *c, FXSelector s, void *ptr);
196   long onCmdReinput(FXObject *c, FXSelector s, void *ptr);
197   long onCmdClear(FXObject *c, FXSelector s, void *ptr);
198   long onCmdRedraw(FXObject *c, FXSelector s, void *ptr);
199   long onCmdHome(FXObject *c, FXSelector s, void *ptr);
200   long onCmdEnd(FXObject *c, FXSelector s, void *ptr);
201   long onCmdFont(FXObject *c, FXSelector s, void *ptr);
202   long onCmdResetFont(FXObject *c, FXSelector s, void *ptr);
203   long onCmdResetWindow(FXObject *c, FXSelector s, void *ptr);
204   long onCmdBreak(FXObject *c, FXSelector s, void *ptr);
205   long onCmdBacktrace(FXObject *c, FXSelector s, void *ptr);
206   long onCmdBreakLoop(FXObject *c, FXSelector s, void *ptr);
207   long onCmdPause(FXObject *c, FXSelector s, void *ptr);
208   long onCmdResume(FXObject *c, FXSelector s, void *ptr);
209   long onCmdStop(FXObject *c, FXSelector s, void *ptr);
210   long onCmdDiscard(FXObject *c, FXSelector s, void *ptr);
211   long onCmdLoadModule(FXObject *c, FXSelector s, void *ptr);
212   long onCmdFlipSwitch(FXObject *c, FXSelector s, void *ptr);
213   long onCmdSelectBrowser(FXObject *c, FXSelector s, void *ptr);
214   long onCmdReduce(FXObject *c, FXSelector s, void *ptr);
215   long onCmdHelp(FXObject *c, FXSelector s, void *ptr);
216   long onCmdAbout(FXObject *c, FXSelector s, void *ptr);
217 
218   void setEOF();
219   void setEditable(FXbool st = TRUE);
220   void performPaste(FXchar *, FXint);
221   int insertFromPaste();
222   int isStartPrompt(const char *s);
223   int isStyle(const char *s);
224 
225 // The next batch are for the "readline-like" input interface
226   int keyFlags, searchFlags, startMatch, pauseFlags,
227       historyFirst, historyLast, historyNumber, promptEnd;
228   unsigned short int searchStack[256];
229   wchar_t searchString[256];
230   Mutex pauseMutex;
231 #define ANY_KEYS       1
232 #define ESC_PENDING    2
233 #define SEARCH_LENGTH   (searchFlags & 0xff)
234 #define SEARCH_FORWARD  0x100
235 #define SEARCH_BACKWARD 0x200
236 #define PAUSE_PAUSE    1
237 #define PAUSE_STOP     2
238 #define PAUSE_DISCARD  4
239   int getHistoryEvent();
240   int trySearch();
241   int matchString(const wchar_t *p, int n, const wchar_t *t);
242 
243   int editBacktrace();
244   int editRedisplay();
245   int editUppercase();
246   int editCopyRegion();
247   int editExtendedCommand();
248   int editObeyCommand();
249   int editSetMark();
250   int editMoveLineStart();
251   int editPrevChar();
252   int editPrevWord();
253   int editBreak();
254   int editBreakLoop();
255   int editCapitalize();
256   int editDeleteForward();
257   int editDeleteForwardWord();
258   int editMoveLineEnd();
259   int editNextChar();
260   int editNextWord();
261   int editStartAgain();
262   int editDeleteBackward();
263   int editDeleteBackwardWord();
264   int editNewline();
265   int editCutLine();
266   int editLowercase();
267   int editHistoryNext();
268   int editHistoryPrev();
269   int editSearchHistoryNext();
270   int editSearchHistoryPrev();
271   int editUpLine();
272   int editTranspose();
273   int editDeleteLastWord();
274   int editPaste();
275   int editRotateClipboard();
276   int editEscape();
277   int editReinput();
278   int editUndo();
279   int editCopyPreviousWord();
280 
281   int setInputText(const char *text, int n);
282   int setInputText(const wchar_t *text, int n);
283 
284   void findTeXstart() const;
285   int charForShowMath();
286   void insertMathsLines();
287   void recordBoxAddress(int n, union Box *b);
288   union Box *getBoxAddress(int n) const;
289 
290   enum {  // used with signalling
291     FLUSH_BUFFER,
292     SET_PROMPT,
293     REQUEST_INPUT,
294     MINIMIZE_MAIN,
295     RESTORE_MAIN,
296     WORKER_EXITING,
297     REFRESH_TITLE,
298     SHOW_MATH,
299     SET_MENUS,
300     REFRESH_SWITCHES,
301     DUMMY_MESSAGE
302     };
303 
304 
305   enum {
306     ID_IPC=FXText::ID_LAST,
307     ID_TIMEOUT,
308 
309     ID_READ,
310     ID_SAVE,
311     ID_SAVE_SELECTION,
312     ID_TO_FILE,
313     ID_PRINT,
314     ID_PRINT_SELECTION,
315     ID_CUT_SEL_X,     // NB exists in FXText but here I will want to...
316     ID_PASTE_SEL_X,   // adjust the cursor position as I go.
317     ID_COPY_SEL_X,
318     ID_COPY_SEL_TEXT_X,
319     ID_REINPUT,
320 //  ID_SELECT_ALL,    // done by the underlying FXText
321     ID_CLEAR,
322     ID_REDRAW,
323     ID_HOME,
324     ID_END,
325     ID_FONT,
326     ID_RESET_FONT,
327     ID_RESET_WINDOW,
328     ID_BREAK,
329     ID_BACKTRACE,
330     ID_BREAKLOOP,
331     ID_PAUSE,
332     ID_RESUME,
333     ID_STOP,
334     ID_DISCARD,
335     ID_BROWSER,
336     ID_HELP,
337     ID_ABOUT,
338     ID_LOAD_MODULE,
339     ID_FLIP_SWITCH,
340 
341     ID_REDUCE,     // for the new "Calculus", "Algebra" etc menu items...
342     ID_LAST
343     };
344 
345   void calcVisRows(FXint startline,FXint endline);
346 
347   void drawContents(FXDCWindow& dc,FXint x,FXint y,FXint w,FXint h) const;
348 
349   void drawTextRow(FXDCWindow& dc,FXint line,FXint left,FXint right) const;
350 
351   void drawBufferText(FXDCWindow &dc, FXint x, FXint y,
352                       FXint w, FXint h, FXint pos, FXint n,
353                       FXuint style) const;
354 
355   int cmrFontsEmbedded;  // Used in ShowMath case
356 
357   int printBufferText(FXDCNativePrinter &dc, FXint x, FXint y,
358                       char *str, FXint n,
359                       FXuint style);
360 
361   int printTextRow(FXDCNativePrinter &dc, int p, int y, int left, int right);
362 
363   void printContents(FXDCNativePrinter &dc, int startpos, int endpos,
364        int left, int right, int top, int bottom);
365 
366   /// Construct multi-line text widget
367   FXTerminal(const char *argv0,
368              FXComposite *p, FXObject* tgt=NULL, FXSelector sel=0,
369              FXuint opts=0, FXint x=0, FXint y=0, FXint w=0, FXint h=0);
370 
371   virtual void create();
372 
373   /// Change text font
374   void setFont(FXFont* fnt);
375 
376   /// forces everything to 80 columns
377   int forceWidth();
378 
379   /// enable or disable text styles
380   void setStyled(FXbool st=TRUE);
381 
382   /// Change number of visible rows
383   void setVisibleRows(FXint rows);
384 
385   /// Change number of visible columns
386   void setVisibleColumns(FXint cols);
387 
388   /// Append n characters of text at the end of the buffer
389   void appendText(const FXchar *text,FXint n,FXbool notify=FALSE);
390 
391   /// Append n characters of text at the end of the buffer
392   void appendStyledText(const FXchar *text,FXint n,
393                         FXint style=0,FXbool notify=FALSE);
394 
395   void appendStyledText(const FXString &text,
396                         FXint style=0,FXbool notify=FALSE);
397 
398   /// Handle keyboard input
399   long onKeyPress(FXObject *,FXSelector, void *);
400 
401   /// Test if editable
402   FXbool isEditable();
403   int isEditableForBackspace();
404 
405   /// Destructor
406   virtual ~FXTerminal();
407 
408   FXTimer *timer;
409 
410   void setupShowMath();
411   void reportDestroy(int p);
412 
413   int sync_even;
414   Mutex mutex1, mutex2, mutex3, mutex4;
415 
416   FILE *logfile;
417 
418   void type_ahead(int c);
419   void string_ahead(const char *s);
420 
421 // I will have a buffer for transfer of characters from the application
422 // to the user-interface. Use of printf-like things is a bit delicate
423 // because buffer overflow in vsprintf is a danger. I allow a margin
424 // of length (200).
425 // When I (eventually) gain confidence in C99 I will use vsnprintf and
426 // be safer.
427 
428 #define FWIN_BUFFER_SIZE  1000
429 #define SPARE_FOR_VFPRINTF 200
430 
431   char fwin_buffer[FWIN_BUFFER_SIZE];
432 
433 // The following two are used by both worker and interface tasks, and so
434 // over-clever compiler optimisation of them is undesirable.
435 //
436 // fwin_in belongs to the worker thread, while fwin_out is owned by the
437 // user interface. Each will use read-only access to the other (unless the
438 // two are synchronised, in which case full access is permitted). I will
439 // assume that my hardware makes simple reads and writes of these variables
440 // atomic.
441 
442   volatile int fwin_in, fwin_out;
443 
444 #define INPUT_BUFFER_LENGTH 512
445 
446   int inputBufferLen;
447   int inputBufferP;
448   char inputBuffer[INPUT_BUFFER_LENGTH];
449   wchar_t inputWBuffer[INPUT_BUFFER_LENGTH];
450 
451   int recently_flushed;
452 
453   int argc;
454   const char **argv;
455 
456 #ifdef WIN32
457   DWORD worker_thread(void *);
458 #else
459   void *worker_thread(void *);
460 #endif
461 
462   int lineSpacing;
463   FXColor  promptColor;         // prompt string colour
464   FXColor  inputColor;          // input text colour
465   FXTerminal();
466 
467   };
468 
469 extern void setEOF();
470 
471 extern FXTerminal *text;
472 
473 #ifdef WIN32
474 #define DEFAULT_FONT_NAME "Courier New"
475 #else
476 #ifdef __APPLE__
477 // As of April 2016 it seems that Menlo is probably a better
478 // default font to use on a Macintosh than Courier...
479 //#define DEFAULT_FONT_NAME "Menlo"
480 
481 // July 2019: a user does not have Menlo on their machine. So here is some
482 // horrid code to try a range of options in the hope of selecting something!
483 
484 #define DEFAULT_FONT_NAME get_mac_default_font()
485 
486 
get_mac_default_font()487 inline const char *get_mac_default_font()
488 {   static char mac_default_font[40] = "";
489     if (mac_default_font[0] == 0)
490 // This is now a list of the fixed pitch fonts installed on my mid 2014
491 // Macbook. I hope that at least one of these will be available for use
492 // on both older and newer platforms.
493     {   static const char *possible_fonts[] =
494         {   "/System/Library/Fonts/Menlo.ttc",
495             "/System/Library/Fonts/Monaco.dfont",
496             "/Library/Fonts/Courier New.ttf",
497             "/System/Library/Fonts/Courier.dfont",
498             "/Library/Fonts/Andale Mono.ttf"
499         };
500         bool found = false;
501         for (int i=0; i<sizeof(possible_fonts)/sizeof(possible_fonts[0]); i++)
502         {   FILE *f = fopen(possible_fonts[i], "rb");
503             if (f == NULL)
504             {   printlog("%s not found\n", possible_fonts[i]);
505                 continue;
506             }
507             fclose(f);
508             if (found)
509                 printlog("%s found but will not be used\n", possible_fonts[i]);
510             else
511             {
512 // Keep just the bif after the last "/", and then clobber the suffix, so
513 // eg /System/Library/Fonts/Menlo.ttc gets turned into just Menlo.
514                 strcpy(mac_default_font, 1+strrchr(possible_fonts[i], '/'));
515                 *strrchr(mac_default_font, '.') = 0;
516                 printlog("Will try with font %s\n", mac_default_font);
517                 found = true;
518             }
519         }
520         if (!found)
521         {   printlog("Will fall back to Menlo\n");
522             strcpy(mac_default_font, "Menlo");
523         }
524     }
525     printlog("font to use is %s\n", mac_default_font);
526     return mac_default_font;
527 }
528 
529 #else
530 #define DEFAULT_FONT_NAME "courier"
531 #endif
532 #endif
533 
534 } // namespace
535 
536 extern int showmathInitialised;
537 
538 
539 #endif
540 
541 // end of FXTerminal.h
542