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