1 // "fwin.h"                                           2003-2021, A C Norman
2 //
3 // This defines the public interface supported by the "fwin" window
4 // interface.
5 //
6 //
7 
8 
9 /**************************************************************************
10  * Copyright (C) 2021, Codemist.                         A C Norman       *
11  *                                                                        *
12  * Redistribution and use in source and binary forms, with or without     *
13  * modification, are permitted provided that the following conditions are *
14  * met:                                                                   *
15  *                                                                        *
16  *     * Redistributions of source code must retain the relevant          *
17  *       copyright notice, this list of conditions and the following      *
18  *       disclaimer.                                                      *
19  *     * Redistributions in binary form must reproduce the above          *
20  *       copyright notice, this list of conditions and the following      *
21  *       disclaimer in the documentation and/or other materials provided  *
22  *       with the distribution.                                           *
23  *                                                                        *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS    *
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT      *
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS      *
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE         *
28  * COPYRIGHT OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,   *
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,   *
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS  *
31  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
32  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR  *
33  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF     *
34  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
35  * DAMAGE.                                                                *
36  *************************************************************************/
37 
38 // $Id: fwin.h 5609 2021-01-23 22:02:30Z arthurcnorman $
39 
40 
41 //
42 // The code here is provides a windowed framework in which reasonably
43 // ordinary C code can run.  The functions described here are the
44 // interface.  In GUI mode it is built on and relies upon the Fox Toolkit
45 // and an associated threads package: by virtue of that it is expected
46 // to be reasonably cross-platform portable, and in particular it supports
47 // Linux and Windows (via MinGW32).
48 //
49 // When used anywhere (including within FOX) this code is licensed as above
50 // and not under any more restrictice license.
51 //
52 
53 
54 #ifndef header_fwin_h
55 #define header_fwin_h 1
56 
57 #include <cstdio>
58 #include <cstdarg>
59 #include <cstdlib>
60 #include <csignal>
61 #include <atomic>
62 
63 using std::atomic;
64 
65 //
66 // Logging support, only enabled in debug mode.
67 //
68 // Usage (eg):  FWIN_LOG("I reached %d of %s\n", __LINE__, __FILE__);
69 //
70 
71 #ifdef DEBUG
72 extern void fwin_write_log(const char *s, ...);
73 #define FWIN_LOG(...) fwin_write_log(__VA_ARGS__)
74 #else
75 #define FWIN_LOG(...) ((void)0)
76 #endif
77 
78 
79 //
80 // The C++ code will eventually be entered at fwin_main() in what looks like
81 // a normal way. This is a type for it.
82 //
83 typedef int fwin_entrypoint(int argc, const char *argv[]);
84 
85 //
86 // To start things going you call the following. It sets up the windowed-style
87 // environment and eventually invoked fwin_main as the entrypoint of the
88 // main application.
89 //
90 
91 extern int fwin_startup(int argc, const char *argv[],
92                         fwin_entrypoint *fwin_main);
93 
94 //
95 // fullProgramName is a string like "d:\xxx\yyy\something.exe"  This is
96 // made available so that applications can edit it to generate names of
97 // resource files (eg by just altering the ".exe" bit on the end into some
98 // other suffix. I will try to find a full path for the executable on
99 // Unix too.
100 //
101 extern const char *fullProgramName;
102 
103 //
104 // programName holds just the "something" out of fullProgramName.
105 // Note that I impose an arbitrary limit on the length of the name of the
106 // executable.
107 //
108 extern const char *programName;
109 
110 //
111 // programDir gives the directory from which this application was launched.
112 // If you try to put your executables in a directory with a very long path,
113 // or possibly in a path that has really funny characters in in, you do so
114 // at your own risk!
115 //
116 extern const char *programDir;
117 
118 //
119 // This returns bits that indicates what options fwin is running with:
120 //
121 //    0   A plain command-line system in circumstances where I do not do any
122 //        local editing or special trapping of ^C. I just leave the
123 //        underlying operating system to do all that, to the extent that it
124 //        will. This is used if stdin/stdout are not directly connected to
125 //        a terminal or if the terminal does not seem to support cursor
126 //        addressability.
127 //    1   A command-line version, but where I use raw keyboard access and
128 //        cursor-addressible terminal output to support local editing and
129 //        a simple history mechanism styles after the GNU readline model.
130 //    2   Running in a window with character input via window events and a
131 //        GNU readline-like set of local editing facilities.
132 //
133 
134 #define FWIN_WITH_TERMED  1
135 #define FWIN_IN_WINDOW    2
136 
137 extern int fwin_windowmode();
138 
139 //
140 // To finish off you can either return from fwin_main(), or you can go
141 //        fwin_exit(n);
142 // The system will forcibly close down for you if the EXIT item on
143 // the FILE menu or the CLOSE item on the SYSTEM menu gets selected.  But
144 // direct use of the C function "exit()" is not considered proper.
145 //
146 
147 extern void fwin_exit(int return_code);
148 
149 //
150 // If, when the program is stopping, fwin_pause_at_end has been set to
151 // be non-zero (by default it will be zero) then an alert box is displayed
152 // forcing the user to give positive confirmation before the main window
153 // is closed.  This does not give an opportunity to cancel the exit, just to
154 // read the final state of the screen...   This effect does not occur if
155 // program exit is caused by selecting EXIT from the FILE menu or CLOSE
156 // from the system menu. That is (deliberate in my code) because in those
157 // cases the user has taken explicit interactive action to terminate the
158 // program so an extra prompt seems unnecessary.
159 //
160 extern bool fwin_pause_at_end;
161 
162 
163 //
164 // fwin_minimize() indicates that the window should be shrunk to be just
165 // an icon.
166 // NOTE that if the command-line arguments to an application include
167 // "--", "-f" or "-F" then the application will be started off minimised.
168 // this is ugly and represents ways that options I want for *MY* application
169 // have crept in where things ought to be generic. My reasoning at one
170 // stage was that I wanted the window to eb minimised right from the start
171 // so letting my code begin and then calling fwin_minimize would not be
172 // so good.
173 //
174 extern void fwin_minimize(void);
175 
176 //
177 // fwin_restore() indicates that the window should be restored to
178 // regular size.
179 //
180 extern void fwin_restore(void);
181 
182 //
183 // Rather than using putchar() and printf(), here are the calls
184 // the can be made to get output onto the screen.  NOTE that fwin_puts()
185 // is more like fputs than puts in that it just dumps the characters in its
186 // string to the screen [it does not add an extra newline in the way that
187 // puts does].
188 // These functions support printable ASCII characters.
189 // I have not thought too hard about TAB and FormFeed here... yet.
190 //
191 extern void fwin_putchar(int c);
192 extern void fwin_puts(const char *s);
193 
194 extern void fwin_showmath(const char *s);
195 
196 extern void fwin_printf(const char *fmt, ...);
197 extern void fwin_vfprintf(const char *fmt, std::va_list a);
198 
199 //
200 // fwin_linelength holds the number of normal-sized (ie the basic
201 // fixed-pitch font being used) characters that fit across the screen.
202 // Its value can change at any time if the user re-sizes the window.
203 // When the screen is minimized its value will remain at the pre-minimized
204 // value. An attempt is made to create the initial window to make this
205 // have the value 80. Actually just at preesent fwin insists on keeping
206 // its window at a width of 80 so this value will never change!
207 //
208 extern int fwin_linelength;
209 
210 //
211 // ensure_screen() causes the display to catch up with whatever else has
212 // been going on.
213 //
214 extern void fwin_ensure_screen(void);
215 
216 //
217 // fwin_getchar() behaves rather as one might expect getchar() to - it
218 // grabs a character from the keyboard input buffer.
219 //
220 extern int fwin_getchar(void);
221 
222 //
223 // If FWIN is running in a window and that window is closed then mustQuit is
224 // set so that fwin_getchar() then always return EOF.
225 //
226 extern atomic<bool> mustQuit;
227 
228 //
229 // fwin_set_prompt() tells fwin what string (of up to some limited
230 // number of characters) should be used as a prompt.
231 //
232 
233 #define MAX_PROMPT_LENGTH 80
234 
235 extern void fwin_set_prompt(const char *s);
236 
237 //
238 // Clears screen.
239 //
240 extern void fwin_clear_screen();
241 
242 //
243 // Returns window size (measured in character positions) packed as
244 //    (width << 16) + height
245 //
246 extern int fwin_screen_size();
247 
248 //
249 // The following function can be used to register a callback that is
250 // used to help expand file-names of the form "$xxx/yyy". It is given the
251 // "xxx" part and a character (which will be '$' or '@' - the two cases
252 // give two chances for lookup, one used ahead of checking system environment
253 // variables and the other after. If returns either a string that is the
254 // expansion or nullptr if there is none.
255 // If you do not register anything then no custom lookup is performed.
256 //
257 typedef char *lookup_function(char *s, int ch);
258 
259 extern void fwin_set_lookup(lookup_function *f);
260 
261 //
262 // fwin will call the function passed here before (with an arg of 1)
263 // and after (with an arg of 0) any time it is liable to delay. In
264 // particular when it might be about to block waiting for keyboard
265 // input. The idea is that this can be used to help the caller discount
266 // time spent in such cases.
267 //
268 typedef void delay_callback_t(int);
269 
270 extern void fwin_callback_on_delay(delay_callback_t *f);
271 
272 //
273 // fwin will call the function passed here to try to signal an
274 // exception to the worker thread. The idea is that the user-passed
275 // function can then do whatever it takes to synchronise with the
276 // worker. It can either signal the worker thread (but note that you need
277 // to do a bit of background reading before you try to mix exceptions
278 // and threads), or it can set a simple flag and the worker can poll.
279 //
280 // The intent is that if it passes QUIET_INTERRUPT or NOISY_INTERRUPT the
281 // worker is interrupted without or with it giving messages (eg a
282 // backtrace). If QUERY_INTERRUPT is passed no exception is raised, but
283 // the expectation is that 0 is returned if the previous exception has
284 // now been accepted and processed.
285 //
286 // If fwin detects an interrupt condition while it is waiting for keyboard
287 // input or if it has generated an interrupt just before the start of
288 // such a wait and a QUERY_INTERRUPT call indicates that its interrupt
289 // request is still pending then as well as the activation of the callback
290 // function fwin_getchar returns promptly, discarding any typed-ahead
291 // stuff and returning some character.
292 //
293 // If the callback function tries to raise exceptions etc then great care
294 // may be needed to ensure it can not abort the worker in the middle of
295 // a handshake where it synchronizes with the GUI thread.  Hmm yet more
296 // thought is called for here! And beware - the callback function can be
297 // invoked multiple times or even several times at once.
298 //
299 
300 #define QUERY_INTERRUPT 0
301 #define QUIET_INTERRUPT 1
302 #define NOISY_INTERRUPT 2
303 #define BREAK_LOOP      3
304 #define QUIT_PROGRAM    4
305 
306 //
307 // The following is just for use by REDUCE. It adjusts menu entries
308 // to support loading packages and setting/clearing REDUCE switches.
309 // The callback function will be invoked from time to time to keep the
310 // information up to date
311 //
312 typedef void review_switch_settings_function();
313 
314 extern void fwin_menus(char **modules, char **switches,
315                        review_switch_settings_function *f);
316 
317 //
318 // The next is used when the application has re-set some switches without the
319 // GUI's help, and it updates the menu
320 //
321 extern void fwin_refresh_switches(char **switches, char **packages);
322 
323 
324 //
325 // Short messages can be displayed at the left middle and right of the
326 // main title-ribbon of your window.  These functions set the text to be
327 // displayed there.  If there is not much room then only the middle one
328 // will remain visible.  Each message should be limited to around 30 chars
329 // (and will be best if kept shorter than that).  The default position was
330 // once that the left position displayed the time & date (but it is
331 // now left blank), the middle one the name of the program being run and
332 // the right one is blank. fwin_report_left(nullptr) or fwin_report_mid(nullptr)
333 // re-instate the default display. Use fwin_report_left("") is a yet clearer
334 // way of indicating that blank info to the left is required.
335 //
336 extern void fwin_report_left(const char *msg);
337 extern void fwin_report_mid(const char *msg);
338 extern void fwin_report_right(const char *msg);
339 
340 //
341 // The following four strings may be updated (but PLEASE keep within the
342 // length limit) to make the display in the "ABOUT" box reflect your
343 // particular application. Note that to avoid triggering additional LGPL
344 // requirements (that are akin to the original BSD "advertising clause")
345 // you should never make the strings here appear to be copyright notices,
346 // since if you do you are then obliged to extent them to include full
347 // copyright notices for any LGPL code you use anywhere.
348 //
349 extern char about_box_title[40];       // "About XXX";
350 extern char about_box_description[40]; // "XXX version 1.1";
351 // <icon appears here>
352 extern char about_box_rights_1[40];    // "Author";
353 extern char about_box_rights_2[40];    // "additional author";
354 //
355 // The next 2 lines will contain the text
356 //    "This software uses the FOX Toolkit"
357 //    "(http://www.fox-toolkit.org)"
358 // as requested by the authors of FOX
359 //
360 
361 extern char about_box_rights_3[40];    // "Credit to FOX";
362 extern char about_box_rights_4[40];    // "ditto";
363 
364 //
365 // The HELP drop-down menu in fwin always has some basic items on it, but
366 // the user can add more by calling fwin_setHelpFile() where arg 1 is the
367 // text to appear on the menu and arg 2 identifies the help file that will be
368 // opened if the menu item is selected. Specifying nullptr as the second item
369 // removes the key. The information about help keys is kept in the registry
370 // not in any file that CSL has direct access to, and the new help items may
371 // not be visible until the user exits from CSL and re-starts it.
372 //
373 extern void fwin_set_help_file(const char *key, const char *path);
374 
375 //
376 // The declarations below here are to be treated as private and should
377 // not be touched by users.
378 //
379 extern int plain_worker(int argc, const char *argv[],
380                         fwin_entrypoint *fwin_main);
381 extern delay_callback_t *delay_callback;
382 
383 //
384 // The following three functions (putchar_overwrite, move_cursor_vertically
385 // and move_to_column) are not intended for use by end-users, and they
386 // only apply when fwin is running in windowed mode. They are used internally
387 // to support local editing and history.
388 //
389 
390 //
391 // like fwin_putchar(), but overwrites what exists on the screen rather
392 // than inserting.
393 //
394 extern void fwin_putchar_overwrite(int c);
395 
396 //
397 // Move the cursor up or down n lines. n is positive for movement
398 // down the screen.
399 //
400 extern void fwin_move_cursor_vertically(int n);
401 
402 //
403 // Move the cursor directly to the indicated column. "0" indicates
404 // the first position in the row.
405 //
406 extern void fwin_move_to_column(int column);
407 
408 //
409 // What follows is to do with a history mechanism... and again is not
410 // intended for public export.
411 //
412 
413 #define INPUT_HISTORY_SIZE 100
414 
415 extern wchar_t *input_history[INPUT_HISTORY_SIZE];
416 extern int input_history_next;
417 
418 extern void input_history_init();
419 
420 extern void input_history_end();
421 
422 extern void input_history_add(const wchar_t *s);
423 
424 extern const wchar_t *input_history_get(int n);
425 
426 //
427 // This is for version-specific control
428 //
429 
430 #ifndef INT_VERSION
431 #define INT_VERSION(a,b,c) (((a*1000) + b)*1000 + c)
432 #endif
433 
434 //
435 // By passing argv[0] to the following you can find the fully rooted
436 // name of the application that you are running. This may be useful if
437 // you want to put some resources (eg fonts) in the same directory as the
438 // executable. If the profram was launched by quoting the name of a symbolic
439 // link then that will be followed so that the path delivered is that of the
440 // true file.
441 //
442 extern int find_program_directory(const char *argv0);
443 
444 // Support for file date manipulation
445 
446 typedef struct date_and_type_
447 {   unsigned long int date;
448     unsigned long int type;
449 } date_and_type;
450 
451 // Reinstate date and filetype...
452 
453 extern void set_filedate(const char *name,
454                          unsigned long int datestamp,
455                          unsigned long int ftype);
456 
457 extern void put_fileinfo(date_and_type *p, const char *name);
458 
459 //
460 // Some things that are really intended to be private to the implementation
461 // but at present it seems easiest to mention them in this header rather
462 // than inventing a new header file.
463 //
464 
465 // The integer variable "windowed" is zero if running in console mode, but
466 // has other non-zero values depending on whether the window starts off
467 // normally or minimised.
468 
469 extern int windowed;
470 
471 extern int windowed_worker(int argc, const char *argv[],
472                            fwin_entrypoint *fwin_main);
473 
474 extern bool fwin_use_xft;
475 
476 extern bool directoryp(char *f, const char *o, size_t n);
477 
478 extern bool using_termed;
479 
480 extern int fwin_plain_getchar();
481 
482 extern bool texmacs_mode;
483 
484 #ifdef HAVE_SIGACTION
485 extern void sigint_handler(int signo, siginfo_t *t, void *v);
486 #else // !HAVE_SIGACTION
487 extern void sigint_handler(int signo);
488 #endif // !HAVE_SIGACTION
489 
490 extern int plain_worker(int argc, const char *argv[],
491                         fwin_entrypoint *fwin_main);
492 extern char fwin_prompt_string[MAX_PROMPT_LENGTH];
493 
494 extern int get_current_directory(char *s, size_t n);
495 extern bool file_readable(char *filename, const char *old, size_t n);
496 extern bool file_writeable(char *filename, const char *old, size_t n);
497 extern bool file_executable(char *filename, const char *old,
498                             size_t n);
499 extern int rename_file(char *from_name, const char *from_old,
500                        size_t from_size,
501                        char *to_name, const char *to_old, size_t to_size);
502 extern int get_home_directory(char *b, size_t len);
503 extern int get_users_home_directory(char *b, size_t len);
504 extern int my_system(const char *s);
505 extern int truncate_file(std::FILE *f, long int where);
506 
507 
508 #endif // header_fwin_h
509 
510 // end of "fwin.h"
511