home *** CD-ROM | disk | FTP | other *** search
Wrap
/* windows.c -- System-independant window handling Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk> This file is part of Jade. Jade is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Jade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jade; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "jade.h" #include "jade_protos.h" #include <stdarg.h> #include <stdlib.h> #include <string.h> _PR void settitle(u_char *); _PR void settitlefmt(u_char *, ...); _PR void notitle(VW *); _PR void stdtitle(VW *); _PR void resettitle(VW *); _PR void windows_init(void); _PR void windows_kill(void); _PR void window_sweep(void); _PR void window_prin(VALUE, VALUE); VALUE sym_make_window_hook, sym_destroy_window_hook; /* This can contain `dead' windows, ie vw_Window==NULL, they have been close'd but must hang around until we're sure all refs are dead. */ _PR VW *ViewChain; /* CurrVW is the active window */ _PR VW *CurrVW; _PR int NumWindows; _PR bool LogMsgs; VW *ViewChain; VW *CurrVW; int NumWindows; bool LogMsgs; _PR VALUE cmd_make_window(VALUE xv, VALUE yv, VALUE wv, VALUE hv); DEFUN("make-window", cmd_make_window, subr_make_window, (VALUE xv, VALUE yv, VALUE wv, VALUE hv), V_Subr4, DOC_make_window) /* ::doc:make_window:: (make-window [X] [Y] [WIDTH] [HEIGHT]) Return a new window, it will be displaying the same buffer as the currently active window. ::end:: */ { VW *vw; TX *tx = CurrVW ? CurrVW->vw_Tx : NULL; if(NUMBERP(xv)) DefDims[0] = VNUM(xv); if(NUMBERP(yv)) DefDims[1] = VNUM(yv); if(NUMBERP(wv)) DefDims[2] = VNUM(wv); if(NUMBERP(hv)) DefDims[3] = VNUM(hv); vw = mycalloc(sizeof(VW)); if(vw) { vw->vw_Type = V_Window; vw->vw_Next = ViewChain; ViewChain = vw; copywinprefs(vw, CurrVW); if(setfont(vw)) { vw->vw_Window = newwindow(CurrVW, vw, TRUE); if(vw->vw_Window) { NumWindows++; os_newvw(vw); vw->vw_BlockStatus = -1; vw->vw_LocalVariables = sym_nil; updatedimensions(vw); if(tx) { vw->vw_Tx = tx; vw->vw_CursorPos = tx->tx_SavedCPos; vw->vw_StartLine = tx->tx_SavedWPos.pos_Line; vw->vw_StartCol = tx->tx_SavedWPos.pos_Col; stdtitle(vw); cmd_eval_hook2(sym_make_window_hook, vw); } #ifndef NOSCRLBAR updatescroller(vw); #endif vw->vw_Flags |= VWFF_FORCE_REFRESH; return(vw); } unsetfont(vw); } myfree(vw); } return(NULL); } _PR VALUE cmd_destroy_window(VALUE win); DEFUN("destroy-window", cmd_destroy_window, subr_destroy_window, (VALUE win), V_Subr1, DOC_destroy_window) /* ::doc:destroy_window:: (destroy-window [WINDOW]) Close WINDOW (or the current window), if this was the last one all files in memory are flushed and jade will exit. ::end:: */ { VW *vw = WINDOWP(win) ? VWIN(win) : CurrVW; cmd_eval_hook2(sym_destroy_window_hook, vw); notitle(vw); /* This function is to take care of OS-independant stuff: releasing GCs etc... */ os_killvw(vw); killwindow(vw); unsetfont(vw); NumWindows--; /* This flags that this window is dead. */ vw->vw_Window = WINDOW_NIL; vw->vw_Tx = NULL; if(CurrVW == vw) { while((vw = vw->vw_Next)) { if(vw->vw_Window) { CurrVW = vw; return(vw); } } vw = ViewChain; while(vw && (vw != CurrVW)) { if(vw->vw_Window) { CurrVW = vw; return(vw); } vw = vw->vw_Next; } /* No living windows left :-( we'll die soon :-( */ CurrVW = NULL; ThrowValue = cmd_cons(sym_quit, newnumber(0)); /* experimental. */ return(NULL); } return(CurrVW); } _PR VALUE cmd_sleep_window(VALUE vw); DEFUN("sleep-window", cmd_sleep_window, subr_sleep_window, (VALUE vw), V_Subr1, DOC_sleep_window) /* ::doc:sleep_window:: (sleep-window [WINDOW]) Iconifies the current window. ::end:: */ { if(!WINDOWP(vw)) vw = CurrVW; if((!VWIN(vw)->vw_Sleeping) && sleepwin(VWIN(vw))) return(vw); return(sym_nil); } _PR VALUE cmd_unsleep_window(VALUE vw); DEFUN("unsleep-window", cmd_unsleep_window, subr_unsleep_window, (VALUE vw), V_Subr1, DOC_unsleep_window) /* ::doc:unsleep_window:: (unsleep-window [WINDOW]) Uniconifies the current window. ::end:: */ { if(!WINDOWP(vw)) vw = CurrVW; if((VWIN(vw)->vw_Sleeping) && unsleep(VWIN(vw))) return(vw); return(sym_nil); } _PR VALUE cmd_next_window(VALUE vw, VALUE activ); DEFUN("next-window", cmd_next_window, subr_next_window, (VALUE vw, VALUE activ), V_Subr2, DOC_next_window) /* ::doc:next_window:: (next-window [WINDOW] [ACTIVATE]) Cycles through the open windows forwards. ::end:: */ { if(!WINDOWP(vw)) vw = CurrVW->vw_Next; while(vw != CurrVW) { if(!vw) vw = ViewChain; if(VWIN(vw)->vw_Window) { if(!NILP(activ)) { CurrVW = VWIN(vw); activatewin(VWIN(vw)); } return(vw); } vw = VWIN(vw)->vw_Next; } return(CurrVW); } void settitle(u_char *title) { VW *vw = CurrVW; if(LogMsgs) fprintf(stderr, "%s\n", title); if(!vw->vw_Sleeping) { mystrfree(vw->vw_LastTitle); vw->vw_LastTitle = mystrdup(title); vw->vw_NonStdTitle = TRUE; vw->vw_Flags |= VWFF_REFRESH_STATUS; } } /* * Is my usage of va_* correct?? */ void settitlefmt(u_char *fmt, ...) { VW *vw = CurrVW; va_list args; if(!vw->vw_Sleeping) { u_char fmtbuff[256]; va_start(args, fmt); vsprintf(fmtbuff, fmt, args); va_end(args); if(LogMsgs) fprintf(stderr, "%s\n", fmtbuff); mystrfree(vw->vw_LastTitle); vw->vw_LastTitle = mystrdup(fmtbuff); vw->vw_NonStdTitle = TRUE; vw->vw_Flags |= VWFF_REFRESH_STATUS; } } void notitle(VW *vw) { if(!vw->vw_Sleeping && vw->vw_LastTitle) { mystrfree(vw->vw_LastTitle); vw->vw_LastTitle = NULL; vw->vw_NonStdTitle = FALSE; vw->vw_Flags |= VWFF_REFRESH_STATUS; } } void stdtitle(VW *vw) { if((!vw->vw_NonStdTitle) && (!vw->vw_Sleeping)) { TX *tx = vw->vw_Tx; u_char *blk; u_char fmtbuff[100]; if(vw->vw_BlockStatus >= 0) { if(!vw->vw_BlockStatus) blk = "B"; else blk = "b"; } else blk = ""; mystrfree(vw->vw_LastTitle); sprintf(fmtbuff, "%s%s [%s] (%ld,%ld) %ld line(s) [%s%ld]", VSTR(tx->tx_BufferName), ((tx->tx_Changes != tx->tx_ProperSaveChanges) && (!(tx->tx_Flags & TXFF_SPECIAL))) ? "+" : (tx->tx_Flags & TXFF_RDONLY ? "-" : ""), (tx->tx_ModeName ? (char *)VSTR(tx->tx_ModeName) : "generic"), vw->vw_CursorPos.pos_Col + 1, vw->vw_CursorPos.pos_Line + 1, tx->tx_NumLines, blk, tx->tx_SaveTabs); vw->vw_LastTitle = mystrdup(fmtbuff); vw->vw_Flags |= VWFF_REFRESH_STATUS; } } void resettitle(VW *vw) { vw->vw_NonStdTitle = FALSE; } _PR VALUE cmd_title(VALUE string); DEFUN("title", cmd_title, subr_title, (VALUE string), V_Subr1, DOC_title) /* ::doc:title:: (title STRING) Temporarily sets the status display to STRING, this won't happen until the window is next refreshed. ::end:: */ { DECLARE1(string, STRINGP); settitle(VSTR(string)); return(string); } _PR VALUE cmd_title_now(VALUE string); DEFUN("title-now", cmd_title_now, subr_title_now, (VALUE string), V_Subr1, DOC_title_now) /* ::doc:title_now:: (title STRING) Immediately sets the status display to STRING. ::end:: */ { DECLARE1(string, STRINGP); settitle(VSTR(string)); setvwtitle(CurrVW); CurrVW->vw_Flags &= ~VWFF_REFRESH_STATUS; #ifdef HAVE_X11 XFlush(XDisplay); #endif return(string); } _PR VALUE cmd_font_name(VALUE vw); DEFUN("font-name", cmd_font_name, subr_font_name, (VALUE vw), V_Subr1, DOC_font_name) /* ::doc:font_name:: (font-name [WINDOW]) Returns the name of the font being used in this window. ::end:: */ { if(!WINDOWP(vw)) vw = CurrVW; return(VWIN(vw)->vw_FontName); } _PR VALUE var_max_scroll(VALUE val); DEFUN("max-scroll", var_max_scroll, subr_max_scroll, (VALUE val), V_Var, DOC_max_scroll) /* ::doc:max_scroll:: Maximum scroll distance (number of lines). If a set of lines has to be scrolled further than this the whole window is redrawn. ::end:: */ { VW *vw = CurrVW; if(val) { if(NUMBERP(val)) vw->vw_MaxScroll = VNUM(val); return(NULL); } return(newnumber(vw->vw_MaxScroll)); } _PR VALUE var_y_scroll_step_ratio(VALUE val); DEFUN("y-scroll-step-ratio", var_y_scroll_step_ratio, subr_y_scroll_step_ratio, (VALUE val), V_Var, DOC_y_scroll_step_ratio) /* ::doc:y_scroll_step_ratio:: Controls the actual number of lines scrolled when the cursor moves out of view. The number of lines to move the display origin is calcualted with the formula: LINES_TO_SCROLL = TOTAL_LINES_IN_WINDOW / y-scroll-step-ratio If the value is 0 then the window will be scrolled by one line. ::end:: */ { VW *vw = CurrVW; if(val) { if(NUMBERP(val)) { vw->vw_YStepRatio = VNUM(val); updatedimensions(vw); } return(NULL); } return(newnumber(vw->vw_YStepRatio)); } _PR VALUE var_x_scroll_step_ratio(VALUE val); DEFUN("x-scroll-step-ratio", var_x_scroll_step_ratio, subr_x_scroll_step_ratio, (VALUE val), V_Var, DOC_x_scroll_step_ratio) /* ::doc:x_scroll_step_ratio:: Controls the actual number of columns scrolled when the cursor moves out of view. The number of lines to move the display origin is calcualted with the formula: COLUMNS_TO_SCROLL = TOTAL_COLUMNS_IN_WINDOW / x-scroll-step-ratio If the value is 0 then the window will be scrolled by one column. ::end:: */ { VW *vw = CurrVW; if(val) { if(NUMBERP(val)) { vw->vw_XStepRatio = VNUM(val); updatedimensions(vw); } return(NULL); } return(newnumber(vw->vw_XStepRatio)); } _PR VALUE cmd_rect_blocks_p(VALUE vw); DEFUN("rect-blocks-p", cmd_rect_blocks_p, subr_rect_blocks_p, (VALUE vw), V_Subr1, DOC_rect_blocks_p) /* ::doc:rect_blocks_p:: (rect-blocks-p [WINDOW]) Returns t if blocks marked in WINDOW (or the current one) are treated as rectangles. ::end:: */ { if(!WINDOWP(vw)) vw = CurrVW; if(VWIN(vw)->vw_Flags & VWFF_RECTBLOCKS) return(sym_t); return(sym_nil); } _PR VALUE cmd_set_rect_blocks(VALUE vw, VALUE stat); DEFUN("set-rect-blocks", cmd_set_rect_blocks, subr_set_rect_blocks, (VALUE vw, VALUE stat), V_Subr2, DOC_set_rect_blocks) /* ::doc:set_rect_blocks:: (set-rect-blocks WINDOW STATUS) Controls whether or not blocks are taken as contiguous regions of text or as rectangles in WINDOW. When STATUS is t rectangles are used. ::end:: */ { int oflags; if(!WINDOWP(vw)) vw = CurrVW; oflags = VWIN(vw)->vw_Flags; if(NILP(stat)) VWIN(vw)->vw_Flags &= ~VWFF_RECTBLOCKS; else VWIN(vw)->vw_Flags |= VWFF_RECTBLOCKS; if((VWIN(vw)->vw_BlockStatus == 0) && (VWIN(vw)->vw_Flags != oflags)) setblockrefresh(VWIN(vw)); return(stat); } _PR VALUE cmd_window_asleep_p(void); DEFUN("window-asleep-p", cmd_window_asleep_p, subr_window_asleep_p, (void), V_Subr0, DOC_window_asleep_p) /* ::doc:window_asleep_p:: (window-asleep-p) Returns t if window is currently iconified. ::end:: */ { if(CurrVW->vw_Sleeping) return(sym_t); return(sym_nil); } _PR VALUE cmd_window_count(void); DEFUN("window-count", cmd_window_count, subr_window_count, (void), V_Subr0, DOC_window_count) /* ::doc:window_count:: (window-count) Number of opened windows. ::end:: */ { return(newnumber(NumWindows)); } _PR VALUE cmd_position_window(VALUE left, VALUE top, VALUE width, VALUE height); DEFUN("position-window", cmd_position_window, subr_position_window, (VALUE left, VALUE top, VALUE width, VALUE height), V_Subr4, DOC_position_window) /* ::doc:position_window:: (position-window LEFT TOP WIDTH HEIGHT) Sets the position and dimensions of the current window. These are all *pixel* measurememnts. ::end:: */ { VW *vw = CurrVW; DECLARE1(left, NUMBERP); DECLARE2(top, NUMBERP); DECLARE3(width, NUMBERP); DECLARE4(height, NUMBERP); setvwpos(vw, VNUM(left), VNUM(top), VNUM(width), VNUM(height)); return(sym_t); } _PR VALUE cmd_current_window(void); DEFUN("current-window", cmd_current_window, subr_current_window, (void), V_Subr0, DOC_current_window) /* ::doc:current_window:: (current-window) Returns the currently active window. Note that this is the editor's notion of `current' -- it doesn't necessarily mean that this is the window to which your window system will send input events to. ::end:: */ { return(CurrVW); } _PR VALUE cmd_with_window(VALUE args); DEFUN("with-window", cmd_with_window, subr_with_window, (VALUE args), V_SF, DOC_with_window) /* ::doc:with_window:: (with-window WINDOW FORMS...) <SPECIAL-FORM> Set the editor's current window to WINDOW and evaluate FORMS, then reinstall the original window as the current one. ::end:: */ { if(CONSP(args)) { GCVAL gcv_args; VALUE res; PUSHGC(gcv_args, args); if((res = cmd_eval(VCAR(args))) && WINDOWP(res)) { VALUE oldvw = CurrVW; GCVAL gcv_oldvw; CurrVW = VWIN(res); PUSHGC(gcv_oldvw, oldvw); res = cmd_progn(VCDR(args)); POPGC; CurrVW = VWIN(oldvw); } POPGC; return(res); } return(NULL); } _PR VALUE cmd_set_current_window(VALUE vw, VALUE activ); DEFUN("set-current-window", cmd_set_current_window, subr_set_current_window, (VALUE vw, VALUE activ), V_Subr2, DOC_set_current_window) /* ::doc:set_current_window:: (set-current-window WINDOW [ACTIVATE-P]) Sets the window which jade reguards as current. If ACTIVATE-P is non-nil the window will be activated with respect to the window-system (under X11 this means warping the pointer to the top left corner of the window as well). ::end:: */ { DECLARE1(vw, WINDOWP); CurrVW = VWIN(vw); if(!NILP(activ)) activatewin(VWIN(vw)); return(CurrVW); } _PR VALUE cmd_window_id(VALUE vw); DEFUN("window-id", cmd_window_id, subr_window_id, (VALUE vw), V_Subr1, DOC_window_id) /* ::doc:window_id:: (window-id [WINDOW]) Returns the identifier of the physical window that the Lisp window WINDOW points to. This is window-system dependant, under X11 it will be some integer, under Intuition a pointer (integer) to the window structure. ::end:: */ { if(!WINDOWP(vw)) vw = CurrVW; return(newnumber((long)VWIN(vw)->vw_Window)); } _PR VALUE cmd_font_x_size(VALUE vw); DEFUN("font-x-size", cmd_font_x_size, subr_font_x_size, (VALUE vw), V_Subr1, DOC_font_x_size) /* ::doc:font_x_size:: (font-x-size [WINDOW]) Returns the width of the window's font (in pixels). ::end:: */ { if(!WINDOWP(vw)) vw = CurrVW; return(newnumber((long)VWIN(vw)->vw_FontX)); } _PR VALUE cmd_font_y_size(VALUE vw); DEFUN("font-y-size", cmd_font_y_size, subr_font_y_size, (VALUE vw), V_Subr1, DOC_font_x_size) /* ::doc:font_y_size:: (font-y-size [WINDOW]) Returns the height of the window's font (in pixels). ::end:: */ { if(!WINDOWP(vw)) vw = CurrVW; return(newnumber((long)VWIN(vw)->vw_FontY)); } void windows_init(void) { ADD_SUBR(subr_make_window); ADD_SUBR(subr_destroy_window); ADD_SUBR(subr_sleep_window); ADD_SUBR(subr_unsleep_window); ADD_SUBR(subr_next_window); ADD_SUBR(subr_title); ADD_SUBR(subr_title_now); ADD_SUBR(subr_font_name); ADD_SUBR(subr_max_scroll); ADD_SUBR(subr_y_scroll_step_ratio); ADD_SUBR(subr_x_scroll_step_ratio); ADD_SUBR(subr_rect_blocks_p); ADD_SUBR(subr_set_rect_blocks); ADD_SUBR(subr_window_asleep_p); ADD_SUBR(subr_window_count); ADD_SUBR(subr_position_window); ADD_SUBR(subr_current_window); ADD_SUBR(subr_set_current_window); ADD_SUBR(subr_with_window); ADD_SUBR(subr_window_id); ADD_SUBR(subr_font_x_size); ADD_SUBR(subr_font_y_size); INTERN(sym_make_window_hook, "make-window-hook"); INTERN(sym_destroy_window_hook, "destroy-window-hook"); } void windows_kill(void) { VW *vw, *nxt; while(CurrVW) cmd_destroy_window(CurrVW); vw = ViewChain; while(vw) { nxt = vw->vw_Next; myfree(vw); vw = nxt; } } void window_sweep(void) { VW *vw = ViewChain; ViewChain = NULL; while(vw) { VW *nxt = vw->vw_Next; if(GC_MARKEDP(vw)) { GC_CLR(vw); vw->vw_Next = ViewChain; ViewChain = vw; } else myfree(vw); vw = nxt; } } void window_prin(VALUE strm, VALUE vw) { u_char buf[40]; if(VWIN(vw)->vw_Window) { #ifdef HAVE_X11 sprintf(buf, "#<window %ld ", VWIN(vw)->vw_Window); #else sprintf(buf, "#<window 0x%x ", VWIN(vw)->vw_Window); #endif streamputs(strm, buf, FALSE); streamputs(strm, VSTR(VWIN(vw)->vw_Tx->tx_BufferName), TRUE); streamputc(strm, '>'); } else streamputs(strm, "#<dead-window>", FALSE); }