Terminal I/O requirements: Every time a user joins a YTalk connection, he is given a window in which his output will appear. This terminal I/O is modularized in such a way that YTalk should be able to drive any windowing system or terminal, as long as someone programs a set of primitive functions. When init_term() [in term.c] is called from main(), it will select the appropriate window system, initialize pointers to the appropriate primitives, and call the init function for that window system. After this initialization, YTalk will transparently communicate with the window system by using these primitives. It is therefore important that each primitive should be implemented exactly the same for each windowing system. The purpose of this document is to define the expected behavior of each of the terminal I/O functions. A valid YTalk 3.0 terminal interface provides an input interface. Each time the user sends keyboard input, the input should be given to YTalk by calling this function in comm.c: void my_input(user, buf, len) [in comm.c] yuser *user; ychar *buf; int len; The "user" parameter should be set to the user pointer whose window the given input was taken from (ie: I had my mouse cursor in the window assigned to user X and typed some info). The my_input routine will send the given info to the given user as an aside, ie: no other users get sent this info. If a terminal interface cannot distinguish input from various windows, or if you do not wish to bother with this, then just send "me" as the user. Any input given the "me" user will get sent to all connected users. Note that it is much more optimal to call this function once with a batch of input characters rather than calling this function once for each character. A valid YTalk 3.0 terminal interface provides these output functions: void init_???() This is called when the terminal interface has been selected for use. It should initialize any static variables and start any necessary connections. It should not open or create any user windows. Input processing (ie: calls to my_input() in comm.c) should begin after this initialization function is called. ---------------------- void end_???() This is called before YTalk exits. All open windows should be shut down, any memory should be freed, and any connections should be terminated. Consider your terminal interface worthy if it can survive this test indefinitely: for(;;) { init_???(); end_???(); } ---------------------- int open_???(user, title) yuser *user; char *title; Zero should be returned on success; any other value will be interpreted as an error. This function should open a new window with the given title and assigned to the given user. All future calls which affect this window will be passed the same user pointer. Since the yuser structure is not passed between clients, you may add any variables you wish to the structure as long as you comment them as part of your terminal interface. The terminal interface should never modify any of the other fields in the yuser structure, especially the window height and width fields. These should only be set by calling the resize_win() [term.c] function. The cursor position should be preset to 0,0. The window size is assumed to be 80 columns by 24 rows. If this is not the case, you are required to call the function resize_win() [term.c] with the appropriate height and width values. I suggest you always call resize_win() from within open_???(). void resize_win(user, height, width) [in term.c] yuser *user; int height, width; ---------------------- void close_???(user) yuser *user; This will close the window assigned to the given user and free any attached memory. Again, imagine the test: for(;;) { open_???(user, "test"); close_???(user); } ---------------------- void addch_???(user, char) yuser *user; ychar char; This will add the given character to the window, following the terminal I/O rules listed below. ---------------------- void move_???(user, y, x) yuser *user; int y, x; This will move the cursor (the next output location) to the given Y,X coordinates, following the terminal I/O rules listed below. ---------------------- void clreol_???(user) yuser *user; This will clear all characters from (and including) the current cursor position to the end of the line. The cursor position does not change. ---------------------- void clreos_???(user) yuser *user; This will clear all characters from (and including) the current cursor position to the end of the screen. The cursor position does not change. ---------------------- void scroll_???(user) yuser *user; This will scroll the window up one line, losing the line at the top of the window and creating a BLANK line at the bottom of the window. The cursor's X and Y positions do not change. This function can be implemented using the other primitives, so it is therefore optional. I strongly recommend that it be included, as it will no doubt be faster than the version implemented through the primitives. If it is not available, then _scroll_term should be set to NULL in term.c. ---------------------- void rev_scroll_???(user) yuser *user; This will revserse-scroll the window up one line, losing the line at the bottom of the window and creating a BLANK line at the top of the window. The cursor's X and Y positions do not change. This function can be implemented using the other primitives, so it is therefore optional. I strongly recommend that it be included, as it will no doubt be faster than the version implemented through the primitives. If it is not available, then _rev_scroll_term should be set to NULL in term.c. ---------------------- void flush_???(user) yuser *user; If your window driver optimizes I/O by queuing updates and sending batches of changes at a time, this function should flush any pending output. If your window driver does not require flushes, then this function should do nothing. ---------------------- Terminal I/O Rules: [ For simplicity, I'll use "maxrows" to mean the maximum number of ] [ rows and "maxcols" to mean the maximum number of columns in a window. ] When a window is initially opened, the cursor position should start at the upper left-hand corner. This position is Y=0,X=0, or (0,0). The Y position is always given first and corresponds to the row number, starting at zero and ending at (maxrows-1). The X position is always given second and corresponds to the column number, starting at zero and ending at (maxcols-1). Every window is required to have at least two rows, and each row should have at least 20 columns. Every time a character is added to the window, it should be placed at the cursor's current Y,X position, clearing and overwriting any character which may already be there. Then, the cursor's X position should be incremented by one. If the X position is now greater than or equal to maxcols, then the X position should be set back to (maxcols-1). THERE IS NO DEFINITION FOR WRAPPING. The cursor's Y position is never incremented as a result of X being too large. Instead, X is maintained at (maxcols-1) until move_???() is called to move the cursor. Since there is no definition for wrapping, it follows that there is no definition for automatic scrolling. A window should only scroll when scroll_???() is called explicitly. Note that some terminals will scroll automatically when a character is placed in the lower right-hand corner. If this is the case with your system, I suggest you tell YTalk that your terminal is actually one row shorter. You could tell YTalk it is one column skinnier, but this effect can be visually displeasing. The terminal interface will only be asked to display printable characters. These are the characters in the decimal range from 32 [space] to 126 [tilde] inclusive. Therefore, the addch_???() procedure need not consider how to display control characters or high-bit characters, because these will never be sent. Similarly, the move_???() procedure will never be called with Y or X values outside the range of the current window. -- EOF --