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