home *** CD-ROM | disk | FTP | other *** search
- #ifdef X11 /** WHOLE FILE **/
-
- /*
- This is a quickie port of a MsWindows version of MicroEMACS to
- X11 (Un*x flavor). The original code ran under DOS to a bios interface
- with direct hardware access to the keyboard and system clock. This
- version and the following X files have been (mostly) hooked in underneath
- the original code, which thankfully had most of the terminal io (screen
- access) and keyboard input at a level distinct from the core editor. Not
- every function is relegated to the absolute best .c file location (for
- example, some system calls are implemented inside xwin.c vs unix.c for making
- shell commands). In addition, much bashing was done to make
- this Emacs look more like GNU-Emacs (make/next-error functions), automatic
- timed backups, timestamp checking, and a large assortment of functions
- implemented to extend the editor and move it away from MicroEMACS to
- GNU-emacs feel. Hopefully a reasonable result given the amount of time
- spent.
-
- The goal was not to make emacs really window-aware. Instead, the window
- specific code was to act like a terminal. That is why the startup code (X11)
- executes first; to create a window, etc such that when EmaxMain is called,
- the 'terminal' (ie window) exists. The input handling is done by creating
- an internal queue at the 'terminal' level and emacs just reads chars from
- the 'keyboard' buffer. Special window-specific things happen without core
- code being aware (ie focus events, etc). Events which require a core code
- response, like window resize, generate emacs recognizable keycodes (or
- entire command strings) which the editor can get. Resize in specific
- generates redraw-display and the core code already did a terminal size
- query for that command.
-
- Mouse events are funny; window specific code handles them as far as
- determining double click, etc. But window level code only goes as far
- as converting mouse events to emacs commands for left, right, up/down,
- etc. In other words, emacs is now mouse-aware, but in an abstract way.
- A wayward user can use the keyboard to send mouse actions, though not
- easily. Only window level code can parse a mouse click/motion to rows
- and columns that emacs needs. This is based on font, window size, etc.
-
- Note that there are typedefs and defines which look like MS Windows
- things; I ported the Dos version to Windows 3.1 first and moved as much
- as I could straight to X11-land. Blame that for the code organization!
-
- X source files:
-
- jam.h version defines, includes, etc
- xwin.c (this file) main, event loop, window creation, etc
- xio.c (aka ttyio.c) character output, scrolling, etc
- xkey.c map keypress event to some EMACS virtual key
- or extended commands
- unix.c not X11 at all, but some un*x flavored things
- */
-
- #define XWIN_C /* for extern of globals */
-
- #include "jam.h"
- #include "def.h"
- #include "keyname.h"
- #include "stdio.h"
- #include "ttydef.h"
- #include "chrdef.h"
- #include "time.h"
-
- #include "keysym.h"
- #ifdef HP
- # include "HPkeysym.h"
- #endif
-
- #ifdef INTERACTIVE
- # include "bsdtypes.h"
- # define pid_t int /* major ughlyness due to include bug */
- #endif
-
- #include <sys/time.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <unistd.h>
-
- #if defined(SOL) || defined (HP)
- # include <sys/resource.h>
- struct rlimit rlim;
- #endif
-
- /* Globals for all of emacs
- */
- Display *gDpy = 0;
- Window gWindow = 0;
- XFontStruct *gFont = 0;
- XCharStruct *gXchar = 0;
- GC gText = NULL;
- GC gTouchedText = NULL;
- GC gMode = NULL;
- GC gXor = NULL;
- int g_nLineHeight, g_nCharWidth, g_nLineAscent;
- BOOL g_hasFocus = FALSE;
- BOOL edInited = FALSE;
- int g_caret = 0;
- int g_caret_x, g_caret_y;
-
- /* Local variables
- */
- static XEvent s_event;
- static Cursor s_hand = 0, s_pointer = 0, s_wait = 0, s_size = 0, s_arrow;
- static char s_timestr[35] = {0};
- static BOOL s_btndown = FALSE;
- static BOOL s_fatal = FALSE;
- static int s_sTicks = 0; /* inc-save interval */
- static char *blank = " ";
- static char *fontname = def_fontname;
- static char *display = 0;
- static int s_scrollTicks = 0; /* autoscroll */
- static pid_t child = (pid_t) -1;
- static BOOL logready = FALSE;
- static unsigned long s_textcolor, s_touchedtextcolor, s_windowcolor;
- static char *tcolor = NULL, *ccolor = NULL, *wcolor = NULL;
- static Colormap s_cmap;
- static int s_screen;
-
- /* Local functions
- */
- static void rn_(SetTheTitle, (void));
- static void rn_(GetTheTime, (void));
- static void rn_(InitX, (int ac, char **av, int *nac, char ** nav));
- static int rn_(DoGCs, (void));
- static void rn_(DoTimer, (void));
- static void rn_(use, (void));
- static void *rn_(childdone, (void));
- static void rn_(getjoblog, (void));
- static int rn_(newcolor, (int which));
- static void rn_(ReverseCaret, (GC gc));
-
- /* Which mouse button - Note LEFT is button 1 and RIGHT is button 2!!!!
- * because this code migrated from Windows where 2 button mouses are the
- * norm (yes, it is icky).
- */
- #define LEFT 0x1
- #define RIGHT 0x2
-
- BOOL WindowFatalState()
- {
- return(s_fatal);
- }
-
- static int errorhandler(dpy, event)
- Display *dpy;
- XErrorEvent *event;
- {
- #define ErrorLen 128
- char msg[ErrorLen];
-
- XGetErrorText(dpy, event->error_code, msg, ErrorLen);
- printf("Xlib error: request %d minor %d \n\t%s\n",
- event->request_code, event->minor_code, msg);
- ttbeep();
- }
- static int ioerrorhandler(dpy)
- Display *dpy;
- {
- if (anycb(ABORT))
- printf("Fatal XIO error, flushing changes!\n");
- ealtmsg = TRUE;
- s_fatal = TRUE;
- IncrementalSave();
- exit (-1); /* we're dead anyway */
- }
-
- /* X support functions
- */
- int NewFont(f, n)
- int f, n;
- {
- XFontStruct *font;
- char newname[NFILEN*2];
- int s;
-
- s = eread("New font name:", newname, NFILEN*2, EFNEW);
- if (s != TRUE)
- return (s);
-
- if (!(font = XLoadQueryFont(gDpy,newname)))
- {
- ewprintf("Can't load requested font %s.", newname);
- s = ABORT;
- }
- else
- {
- XFreeFont(gDpy, gFont); /* release old font */
- gFont = font; /* replace the font */
- #if 1 /* easier this way */
- DoGCs(); /* reset the GC values */
- #else
- gXchar = &gFont->max_bounds; /* recompute all info */
- gXchar = &gFont->max_bounds;
- g_nLineHeight = gFont->ascent + gFont->descent + FudgeHeight;
- if (g_nLineHeight % 2)
- g_nLineHeight++; /* force even # pixels */
- g_nCharWidth = gXchar->width;
- XSetFont(gDpy, gMode, gFont->fid); /* update gc's */
- XSetFont(gDpy, gText, gFont->fid);
- XSetFont(gDpy, gTouchedText, gFont->fid);
- XSetFont(gDpy, gXor, gFont->fid); /* overkill,cursor gc only */
- #endif
- myrefresh(0, 1);
- WindowSync();
- }
- }
- int NewTextColor(f, n)
- int f, n;
- {
- return(newcolor(CTEXT));
- }
- int NewTouchedTextColor(f, n)
- int f, n;
- {
- return(newcolor(CHIGH));
- }
- int NewWindowColor(f, n)
- int f, n;
- {
- int s = newcolor(CMODE);
-
- if (s)
- XSetWindowBackground(gDpy, gWindow, s_windowcolor);
-
- return(s);
- }
- /* work function for color changing
- */
- static int newcolor(type)
- int type;
- {
- char color[NFILEN*2];
- int s;
- XColor colorcell, rgb;
- char *msg;
-
- if (type == CTEXT)
- msg = "New text color: ";
- else if (type == CHIGH)
- msg = "New touched text color: ";
- else if (type == CMODE)
- msg = "New window color: ";
-
- s = eread(msg, color, NFILEN*2, EFNEW);
- if (s != TRUE)
- return (s);
-
- if (!XAllocNamedColor(gDpy, s_cmap, color, &colorcell, &rgb))
- ewprintf("Unable to allocate color");
- else
- {
- if (type == CTEXT)
- s_textcolor = colorcell.pixel;
- else if (type == CHIGH)
- s_touchedtextcolor = colorcell.pixel;
- else if (type == CMODE)
- s_windowcolor = colorcell.pixel;
- else
- {
- ewprintf("Internal error changing colors");
- return(FALSE);
- }
- DoGCs();
- myrefresh(0, 1);
- WindowSync();
- }
- return(s);
- }
-
- /* Main entry point, ta da!
- */
- static char *whoami;
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- #define MAXARGS 500
- int myargc = 0;
- char *myargv[MAXARGS];
- XColor colorcell, rgb;
-
- /* Open the device based on user input; create
- * drawing context and open a default font
- */
- whoami = argv[0]; /* progname */
-
- if (argc > MAXARGS)
- {
- printf("Number of input args too large! Truncating to %d\n", MAXARGS);
- argc = MAXARGS;
- }
- InitX(argc, argv, &myargc, myargv);
-
- /* Init colors, drawing GC's
- */
- if (tcolor && XAllocNamedColor(gDpy, s_cmap, tcolor, &colorcell, &rgb))
- s_textcolor = colorcell.pixel;
- else
- s_textcolor = BlackPixel(gDpy, s_screen);
- if (ccolor && XAllocNamedColor(gDpy, s_cmap, ccolor, &colorcell, &rgb))
- s_touchedtextcolor = colorcell.pixel;
- else
- s_touchedtextcolor = BlackPixel(gDpy, s_screen);
- if (wcolor && XAllocNamedColor(gDpy, s_cmap, wcolor, &colorcell, &rgb))
- s_windowcolor = colorcell.pixel;
- else
- s_windowcolor = WhitePixel(gDpy, s_screen);
- DoGCs();
-
- /* Cursors (mouse pointers...)
- */
- s_hand = XCreateFontCursor(gDpy, XC_xterm);
- s_pointer = XCreateFontCursor(gDpy, XC_top_left_arrow);
- s_wait = XCreateFontCursor(gDpy, XC_watch);
- s_size = XCreateFontCursor(gDpy, XC_double_arrow);
- s_arrow = XCreateFontCursor(gDpy, XC_question_arrow);
-
- /* Initially size window based on font
- */
- InitSizeWindow(ncol = START_COLS, nrow = START_LINES);
-
- /* Init internal input buffer(s)
- */
- InitInput();
-
- /* Set signals to be ignored
- */
- signal(SIGQUIT, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
-
- /* Capture errors.
- */
- XSetIOErrorHandler(ioerrorhandler); /* fatal */
- XSetErrorHandler(errorhandler); /* non fatal */
-
- /* Default title, make window visible, set cursor...
- */
- WindowNormalCursor();
- XStoreName(gDpy, gWindow, g_APPNAME);
- XMapWindow(gDpy, gWindow);
- XSync(gDpy, TRUE); /* sync, throw away all previous events */
-
- /*
- * Call 'main' body of editor. Note it trys to open the
- * terminal, etc but those functions are now noops..
- */
- edInited = TRUE; /* any message after this is ok to process */
- EmaxMain(myargc, myargv);
- return(0);
- }
-
- /* Create/modify gcs for CTEXT, CHIGH and CMODE colors and cursor;
- * This will sometimes unnecessarily reset some values but it's easier
- * to capture all the code in one place.
- */
- static int DoGCs()
- {
- XGCValues _gcv, *gcv;
- XVisualInfo vinfo;
-
- /* This will only abort the editor if called the
- * first time; after that, there should be a font
- */
- if (!gFont)
- if (!(gFont = XLoadQueryFont(gDpy, fontname)))
- {
- printf("Can't load font %s, trying 'fixed'\n", fontname);
- if (!(gFont = XLoadQueryFont(gDpy, "fixed")))
- {
- printf("Can't load fixed font\n");
- use();
- exit(-1);
- }
- }
- gcv = &_gcv;
- gXchar = &gFont->max_bounds;
- g_nCharWidth = gXchar->width;
- g_nLineHeight = gFont->ascent + gFont->descent + FudgeHeight;
-
- /* GC for text
- */
- gcv->foreground = s_textcolor;
- gcv->background = s_windowcolor;
- gcv->function = GXcopy;
- gcv->font = gFont->fid;
- if (!gText)
- gText = XCreateGC(gDpy, gWindow,
- GCForeground|GCBackground|GCFunction|GCFont, gcv);
- else
- XChangeGC(gDpy, gText, GCForeground|GCBackground|GCFunction|GCFont, gcv);
-
- /* GC for window background
- */
- gcv->foreground = s_windowcolor;
- gcv->background = s_textcolor;
- gcv->function = GXcopy;
- gcv->font = gFont->fid;
- if (!gMode)
- gMode = XCreateGC(gDpy, gWindow,
- GCForeground|GCBackground|GCFunction|GCFont, gcv);
- else
- XChangeGC(gDpy, gMode, GCForeground|GCBackground|GCFunction|GCFont, gcv);
-
- /* GC for touched text
- */
- gcv->foreground = s_touchedtextcolor;
- gcv->background = s_windowcolor;
- gcv->function = GXcopy;
- gcv->font = gFont->fid;
- if (!gTouchedText)
- gTouchedText = XCreateGC(gDpy, gWindow,
- GCForeground|GCBackground|GCFunction|GCFont, gcv);
- else
- XChangeGC(gDpy, gTouchedText, GCForeground|GCBackground|GCFunction|GCFont,
- gcv);
-
- /* GC for XOR
- */
- gcv->foreground = s_textcolor;
- gcv->background = s_windowcolor;
-
- /* This is not a good test; but invert works pretty
- * well on the color and monochrome servers I tried, and xor works
- * much better on the grayscale SPARCstation...
- */
- # ifdef SOL
- if (!XMatchVisualInfo(gDpy, s_screen, 8, StaticGray, &vinfo) &&
- !XMatchVisualInfo(gDpy, s_screen, 8, GrayScale, &vinfo))
- # else
- if (1)
- # endif
- gcv->function = GXinvert;
- else
- gcv->function = GXxor;
- gcv->plane_mask = XAllPlanes();
- gcv->font = gFont->fid;
- if (!gXor)
- gXor = XCreateGC(gDpy, gWindow,
- GCForeground|GCBackground|GCFunction|GCPlaneMask|GCFont,
- gcv);
- else
- XChangeGC(gDpy, gXor,
- GCForeground|GCBackground|GCFunction|GCPlaneMask|GCFont, gcv);
- }
- /* (Re)Set clipping into all GC's.
- */
- void NewClipping (x, y, w, h)
- int x, y, w, h;
- {
- static XRectangle clip; /* probably doesn't need to be static */
-
- /* Some servers seem to croak on negatives..
- */
- clip.x = (x < 0 ? 0 : x);
- clip.y = (y < 0 ? 0 : y);
- clip.width = (w <= 0 ? WinWidth() : w);
- clip.height = (h <= 0 ? WinHeight() : h);
-
- XSetClipRectangles(gDpy, gText, 0, 0, &clip, 1, Unsorted);
- XSetClipRectangles(gDpy, gTouchedText, 0, 0, &clip, 1, Unsorted);
- XSetClipRectangles(gDpy, gXor, 0, 0, &clip, 1, Unsorted);
- XSetClipRectangles(gDpy, gMode, 0, 0, &clip, 1, Unsorted);
- }
-
- /* Open the display, parse arguments as needed
- * and prepare them for core code.
- */
- static void InitX(argc, argv, newargc, newargv)
- int argc, *newargc;
- char *argv[], *newargv[];
- {
- unsigned long x_mask;
- int height,width,border;
- int offset;
- XWMHints hints;
- int i, j;
-
- display = (char *)getenv("DISPLAY");
-
- /* Cheapo argument parsing... look for font override and/or
- * display override. All else packages for core editor to eat.
- */
- for (j = i = 0; i < argc; i++)
- {
- if ((strcmp(argv[i], "-font") == 0) && (i + 1 < argc))
- {
- i++;
- fontname = argv[i];
- }
- else if ((strcmp(argv[i], "-display") == 0) && (i + 1 < argc))
- {
- i++;
- display = argv[i];
- }
- else if ((strcmp(argv[i], "-fg") == 0) && (i + 1 < argc))
- {
- i++;
- tcolor = argv[i];
- }
- else if ((strcmp(argv[i], "-fg2") == 0) && (i + 1 < argc))
- {
- i++;
- ccolor = argv[i];
- }
- else if ((strcmp(argv[i], "-bg") == 0) && (i + 1 < argc))
- {
- i++;
- wcolor = argv[i];
- }
- else
- newargv[j++] = argv[i];
- }
-
- *newargc = j; /* number of args */
-
- if ((gDpy = XOpenDisplay(display)) == NULL)
- {
- printf("Can not open display [%s]", display);
- use();
- exit(-1);
- }
-
- /* The one and only window.
- */
- x_mask = EnterWindowMask | LeaveWindowMask | ButtonPressMask | ExposureMask |
- ButtonReleaseMask | KeyPressMask | KeyReleaseMask | FocusChangeMask |
- Button1MotionMask | StructureNotifyMask | SubstructureNotifyMask;
-
- /* Create the window - setting white/black
- * (this is a dummy temp size which will be reset after the
- * font is loaded).
- */
- width = 10;
- height = 10;
- border = 1;
- s_screen = DefaultScreen(gDpy);
- s_cmap = DefaultColormap(gDpy, s_screen);
- gWindow = XCreateSimpleWindow(gDpy, RootWindow(gDpy, s_screen),
- 10, 50, width, height, border,
- BlackPixel(gDpy, s_screen),
- WhitePixel(gDpy, s_screen));
-
- /* Let the windows get some events
- */
- XSelectInput(gDpy, gWindow, x_mask);
-
- /* Window manager stuff. More complete window manager
- * hints would be nice.
- */
- hints.flags = InputHint;
- hints.input = 1;
- XSetWMHints(gDpy, gWindow, &hints);
- }
-
- /* Set window title as needed.
- */
- static void SetTheTitle()
- {
- char buffer[200], dir[100];
- #ifndef HOSTNAMELEN /* doesn't seem to be in a standard .h file! */
- # define HOSTNAMELEN 256
- #endif
- static char hostname[HOSTNAMELEN+1] = {0};
- static char lastTitle[512] = {0};
-
- if (!hostname[0])
- gethostname(hostname, HOSTNAMELEN);
- strcpy(buffer, g_APPNAME);
- strcat(buffer, " ");
- strcat(buffer, shortversion());
- if (wdir)
- strcpy(dir, wdir);
- adjustnamecase(dir);
- if (hostname[0])
- {
- strcat(buffer, "@");
- strcat(buffer, hostname);
- }
- strcat(buffer, " (");
- strcat(buffer, dir);
- strcat(buffer, ") ");
- strcat(buffer, s_timestr);
- if (strcmp(buffer, lastTitle) != 0)
- {
- XStoreName(gDpy, gWindow, buffer);
- strcpy(lastTitle, buffer); /* save last time */
- WindowSync();
- }
- }
-
- /* Update the time string, used for window title
- */
- static void GetTheTime()
- {
- long currtime;
- struct tm *timestruct;
-
- time(&currtime);
- timestruct = localtime(&currtime);
- sprintf(s_timestr, " %02d:%02d\0", timestruct->tm_hour, timestruct->tm_min);
- }
-
- /* Event during screen update? (ie redraw/refresh)
- */
- BOOL WindowLookaheadEvent()
- {
- return(FALSE); /* no event considered as interrupting */
- }
-
- /* Dump a string to a message box; if fatal,
- * leave ungracefully...
- */
- void WindowMessage(s, fatal)
- char *s;
- BOOL fatal;
- {
- printf("%s\n", s); /* well, the terminal is ok for X */
- if (fatal)
- {
- s_fatal = TRUE;
- ealtmsg = TRUE;
- IncrementalSave();
- exit(-1);
- }
- }
-
- /* Simple-minded stub to exec something
- */
- winspawn(s, windows)
- char *s;
- BOOL windows; /* misnamed - means peer job not monitored to completion */
- {
- char buffer[NFILEN + L_tmpnam + 1];
- pid_t parent = getpid();
- pid_t oldchild = child;
-
- #ifndef NJBOS
- if (!windows)
- if (child != (pid_t)-1)
- {
- ewprintf("Can't run mulitple shell commands at this time!");
- return(FALSE);
- }
- #endif
-
- if (s && *s)
- {
- #ifndef JOBS
- /* Make a log file for this parent process to
- * use for all shell jobs
- */
- if (spawnfilename[0] == '\0')
- #endif
- {
- strcpy(spawnfilename, mktempTemplate);
- mktemp(spawnfilename);
- }
-
- if (!windows)
- {
- sprintf(buffer, "echo '%s shell..' > %s", g_APPNAME, spawnfilename);
- system(buffer);
- }
-
- strcpy(buffer, s);
- if (!windows)
- {
- strcat(buffer, " 2>> "); /* concatenate... */
- strcat(buffer, spawnfilename);
- }
- else
- strcat(buffer, "&");
- ewprintf("Running 'sh %s'", buffer);
-
- /* Fork a child to run the system call.
- * Child just exits when done, parent
- * watches for the signal.
- */
- if (!windows)
- signal(SIGUSR1, childdone); /* wait for child-is-done signal */
- if ((child = fork()) != (pid_t)-1)
- {
- if (child == 0)
- {
- if (system(buffer) == 127)
- printf("'PID %d system call error!\n", getpid());
-
- if (!windows)
- {
- #ifndef SOL /* This is weird.... */
- kill(parent, SIGUSR1);
- #else
- sigsend(P_PID, parent, SIGUSR1); /* tell parent */
- #endif
- }
- _exit(0);
- }
- }
- #ifndef NJOBS
- if (windows)
- child = oldchild; /* restore state of any current job */
- #endif
- }
-
- return(TRUE);
- }
- /* Captures signal to indicate
- * child shell process is complete
- */
- static void *childdone()
- {
- logready = TRUE;
- }
- static void getjoblog()
- {
- int r;
-
- logready = FALSE;
- r = eyesno("Shell command completed, read log");
- if (r == TRUE)
- {
- BUFFER *bp;
- #ifndef NJOBS
- bp = bfind(spawnfilename, FALSE);
-
- /* Nuke any old logs from different dirs
- */
- if (bp)
- {
- bp->b_flag &= ~BFCHG;
- if (strcmp(bp->b_fname, spawnfilename) != 0)
- nukebuffer(bp);
- }
- #endif
-
- #if 1
- ExtendedFunction(function_name(poptofilequiet));
- AddString(spawnfilename);
- AddKchar(CCHR('J'));
- #else
- AddString(spawnfilename);
- AddKchar(CCHR('J'));
- poptofilequiet(0, 1); /* go get it */
- ExtendedFunction(function_name(donothing));
-
- /* Mark the file to be deleted when buffer is
- * nuked
- */
- if (bp = bfind(spawnfilename, FALSE))
- bp->b_flag |= BFDELETE;
- #endif
- }
-
- child = (pid_t)-1; /* child is done */
- }
-
- /* Find row col from pos
- */
- void GetRowCol(prow, pcol, x, y)
- int *prow;
- int *pcol;
- int x;
- int y;
- {
- register int row, col;
-
- col = (x + 1)/g_nCharWidth;
- row = (y + 1)/g_nLineHeight;
- if (col < 0)
- col = 0;
- else if (col > ncol)
- col = ncol;
- if (row < 0)
- row = 0;
- else if (row > nrow)
- row = nrow;
-
- *pcol = col;
- *prow = row;
- }
-
- /* Draw cursor; s_cur_* set on draw, used on un-draw.
- * Needed because ttmove moves g_caret_* w/o turning
- * off caret.
- */
- static int s_cur_x = -1, s_cur_y = -1;;
- static char s_cur_char;
- void DoShowCaret()
- {
- MakeCaretVis(TRUE);
- s_cur_x = g_caret_x;
- s_cur_y = g_caret_y;
- #if 1
- if (curwp->w_doto >= llength(curwp->w_dotp))
- s_cur_char = ' ';
- else
- {
- s_cur_char = lgetc(curwp->w_dotp, curwp->w_doto);
- if ((s_cur_char < XK_space) || (s_cur_char > XK_asciitilde))
- {
- if (s_cur_char == '\t')
- s_cur_char = ' ';
- else if (ISCTRL(s_cur_char) && !eprompting)
- s_cur_char = '^';
- else
- s_cur_char = ' ';
- }
- else if (eprompting && !isearching)
- s_cur_char = ' ';
- }
- #endif
- ReverseCaret(gMode);
- }
- /* Erase cursor
- */
- void DoHideCaret()
- {
- GC gctemp = (showtouchedlines && curwp->w_dotp->l_flag & LFCHANGE) ?
- gTouchedText : gText;
- MakeCaretVis(FALSE);
- ReverseCaret(gctemp);
- }
- /* Do draw for cursor shape
- */
- static void ReverseCaret(gc)
- GC gc;
- {
- if ((s_cur_x == -1) || (s_cur_y == -1))
- return;
- #if 1
- XDrawImageString(gDpy, gWindow, gc, s_cur_x, yCharPos(s_cur_y),
- &s_cur_char, 1);
- #else
- XFillRectangle(gDpy, gWindow, gXor, s_cur_x, s_cur_y,
- (unsigned int)g_nCharWidth,
- (unsigned int)(g_nLineHeight - FudgeHeight));
- #endif
- WindowFlush();
- }
- /* Manage pointer-cursor switching for some operations
- */
- void WindowDragCursor()
- {
- XDefineCursor(gDpy, gWindow, s_hand);
- WindowFlush();
- }
- void WindowArrowCursor()
- {
- XDefineCursor(gDpy, gWindow, s_arrow);
- WindowFlush();
- }
- void WindowSizeCursor()
- {
- XDefineCursor(gDpy, gWindow, s_size);
- WindowFlush();
- }
- void WindowSleepCursor()
- {
- if (s_fatal)
- return;
- XDefineCursor(gDpy, gWindow, s_wait);
- WindowFlush();
- }
- void WindowNormalCursor()
- {
- if (s_fatal)
- return;
- XDefineCursor(gDpy, gWindow, s_pointer);
- WindowFlush();
- }
-
- /* Main event loop/processing; called from core editor to
- * get 'keyboard' event. Returns only when a queued event
- * results from some X event. (Note the use of 'noop()' to
- * effect a return).
- */
- #define OneClick 250 /* get from resource file ! */
- #define IsLeft (b->button == LEFT)
- #define IsRight (b->button == RIGHT)
- #define IsDoubleClick (!IsLeftShift && (b->time - lastdown < OneClick))
- #define IsLeftShift (IsLeft && GetShiftState(&s_event))
-
- void WindowGetEvent(ptr)
- KCHAR *ptr;
- {
- static BOOL hackflag = FALSE;
- BOOL result;
- static Time lastdown = 0;
- char buff[40];
- int downcol, downrow;
- XButtonEvent *b = (XButtonEvent *)&s_event;
- XMotionEvent *m = (XMotionEvent *)&s_event;
- XExposeEvent *e = (XExposeEvent *)&s_event;
- BOOL wasvis = IsCaretVis();
-
- /* Cursor on during wait.
- */
- if (IsCaretCreated() && (s_btndown == 0))
- SetCaretVis((wasvis = TRUE));
-
- /* See if something there, else wait.
- */
- for (result = FALSE; !result; )
- if (!(result = WindowReturnKCHAR(ptr)))
- {
- int selreturn = 0;
- struct timeval tv;
-
- tv.tv_sec = 0;
- tv.tv_usec = TIME_INC;
-
- /* Use select call to block waiting for new events
- * IFF no events already queued. XNextEvent will flush
- * output, but because select is used to simulate a timer as
- * well as process-block for i/o, an explicit flush is needed.
- * So, select will block until the connection has i/o or the
- * timeout value (set above) expires.
- */
- WindowFlush();
- if (XEventsQueued(gDpy, QueuedAlready))
- selreturn = 1;
- else
- {
- fd_set fds;
-
- /* hack for no refresh when needed
- */
- if (hackflag)
- {
- NoClipping();
- ExtendedFunction(function_name(myrefresh));
- hackflag = FALSE;
- goto out; /* ughly */
- }
-
- FD_ZERO(&fds);
- FD_SET(ConnectionNumber(gDpy), &fds);
- #if defined(SOL) || defined(HP)
- if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
- {
- selreturn = select(rlim.rlim_cur, &fds, 0, 0, &tv);
- }
- else
- {
- ewprintf("getrlimit failed!");
- ttbeep();
- continue;
- }
- #else
- selreturn = select(getdtablesize(), &fds, 0, 0, &tv);
- #endif
- }
-
- /* 'selreturn' indicates state; events waiting (ie previous
- * events or new), the timer 'ticked' or an error occurred.
- */
- if (selreturn < 0)
- {
- ttbeep();
- continue; /* what else to do? try again */
- }
-
- /* NULL means timer expired w/o traffic on socket
- */
- else if (selreturn == 0)
- DoTimer();
-
- /* Process and return if result of this event
- * yields a KCHAR. To get here means XNextEvent
- * will not block because something is in the queue.
- */
- else
- {
- XNextEvent(gDpy, &s_event);
- switch(s_event.type)
- {
- case FocusIn:
- SetCaretCreated(TRUE);
- SetCaretVis(TRUE);
- g_hasFocus = TRUE;
- break;
-
- case FocusOut:
- #if 0
- SetCaretVis(FALSE);
- SetCaretCreated(FALSE);
- #endif
- g_hasFocus = FALSE;
- break;
-
- case ConfigureNotify:
- {
- int save_ncol = ncol;
- int save_nrow = nrow;
-
- WindowSync();
- WindowGetSize(&nrow, &ncol);
- if ((nrow == save_nrow) && (ncol == save_ncol))
- break;
-
- /* BUG PRONE - this is basically doing
- * a hack to get a resize but not draw
- * a zillion times; most every resize gets
- * a corresponding refresh. Note the
- * hack flag...
- */
- NewClipping(0, 0, 1, 1);
- hackflag = TRUE;
- ExtendedFunction(function_name(myrefresh));
- break;
- }
-
- case Expose:
- case GraphicsExpose:
- {
- int row = ttrow; /* save cursor */
- int col = ttcol;
-
- /* clip to damaged area, repair window..
- * and restore clipping
- */
- NewClipping(e->x, e->y, e->width, e->height);
- if (wasvis)
- SetCaretVis(FALSE);
- sgarbf = TRUE;
- update();
- if (wasvis)
- SetCaretVis(TRUE);
- NoClipping();
- hackflag = FALSE;
- if (isearching)
- noop(); /* jumpSearch(); hacky research to refresh */
- else if (eprompting)
- erepair(); /* fix prompt+msg */
- else
- ExtendedFunction(function_name(donothing));
- ttmove(row, col); /* restore cursor */
- break;
- }
-
- case MotionNotify:
- GetRowCol(&downrow, &downcol, m->x, m->y);
- if ((s_btndown & LEFT) && !(s_btndown & RIGHT))
- {
- ExtendedFunction(function_name(mousecmd));
- AddString(MoveStr);
- sprintf(buff, posFormat, downrow, downcol);
- AddString(buff);
- }
- break;
-
- case ButtonRelease:
- GetRowCol(&downrow, &downcol, b->x, b->y);
- if (IsLeft && (s_btndown & LEFT))
- {
- s_btndown &= ~LEFT;
- ExtendedFunction(function_name(mousecmd));
- AddString(LeftUp);
- sprintf(buff, posFormat, downrow, downcol);
- AddString(buff);
- }
- else if (IsRight && (s_btndown & RIGHT))
- {
- s_btndown &= ~RIGHT;
- noop();
- }
- break;
-
- case ButtonPress:
- GetRowCol(&downrow, &downcol, b->x, b->y);
-
- switch(b->button)
- {
- case RIGHT:
- s_btndown |= RIGHT;
- ExtendedFunction(function_name(mousecmd));
- if (s_btndown & LEFT)
- {
- AddString(MouseAbort);
- AddKchar(' ');
- }
- else
- {
- AddString(RightDwn);
- sprintf(buff, posFormat, downrow, downcol);
- AddString(buff);
- }
- break;
-
- case LEFT:
- s_btndown |= LEFT;
- ExtendedFunction(function_name(mousecmd));
- if (s_btndown & RIGHT)
- {
- AddString(MouseAbort);
- AddKchar(' ');
- }
- else
- {
- /* doubleclick left is special
- */
- if (IsDoubleClick)
- {
- AddString(DoubleClick);
- AddKchar(' ');
- lastdown = b->time;
- break; /* no other params! */
- }
- else if (IsLeftShift)
- AddString(LeftDwnShift);
- else /* normal left */
- AddString(LeftDwn);
- sprintf(buff, posFormat, downrow, downcol);
- AddString(buff);
- lastdown = b->time;
- }
- break;
-
- default:
- ewprintf("Unsupported button");
- ttbeep();
- break;
- }
- break;
-
- case KeyRelease:
- case KeyPress:
- /* Keyboard input events cause some delay to autosave
- */
- if (s_event.type == KeyPress)
- {
- s_sTicks -= SAVE_DELAY;
- if (s_sTicks < 0)
- s_sTicks = 0;
- }
-
- /* prevent garbled commands interrupting mouse
- */
- if (!s_btndown)
- WindowMapKey((XKeyEvent *)&s_event, s_event.type == KeyPress);
- break;
-
- default:
- break;
- } /* switch */
- } /* XNextEvent */
- } /* for () */
-
-
- /* cursor off during process
- */
- out: /* I hate goto's.... */
- if (wasvis)
- SetCaretVis(FALSE);
- }
-
- /* Process a 'timer' message; really result of timeout
- * on select call as opposed to actual event.
- */
- static void DoTimer()
- {
- static int tTicks = 0; /* Title update interval */
- static BOOL incallback = FALSE; /* Prevent recursion in WM_TIMER
- triggered routine calls */
-
- if (edInited)
- {
- /* Log ready? Try to be polite about interrupting the
- * user. (Ughly code here!)
- */
- if (!isearching && !eprompting && !s_btndown)
- {
- /* What time is it?
- */
- if (!incallback)
- {
- incallback = TRUE;
- AnyPendingAlarms();
- incallback = FALSE;
- }
- /* spawned job ran
- */
- if (logready)
- {
- SetCaretVis(FALSE);
- getjoblog();
- noop();
- }
- }
-
- /* counter for incremental save (keyboard input delays this)
- */
- s_sTicks++;
- if ((s_sTicks > INCS_PER_SAVE) && !incallback && !eprompting)
- {
- /* Any messages printed by routines called
- * from a timer must not use standard
- * output method (ie async)
- */
- ealtmsg = TRUE;
- incallback = TRUE;
- IncrementalSave();
- incallback = FALSE;
- s_sTicks = 0;
- ealtmsg = FALSE;
- }
-
- /* Counter for titlebar update
- */
- tTicks++;
- if (tTicks > INCS_PER_UPDATE)
- {
- GetTheTime(); /* get current clock time */
- SetTheTitle(); /* fix window title */
- tTicks = 0;
- }
-
- /* auto scroll mode line
- */
- if ((s_btndown & LEFT) && GetCtrlState(&s_event))
- {
- s_scrollTicks++;
- if (s_scrollTicks >= DELAY_TO_SCROLL)
- {
- char buff[8];
-
- ExtendedFunction(function_name(mousecmd));
- AddString(MouseTimer);
- sprintf(buff, " %d ", GetShiftState(&s_event));
- AddString(buff);
- s_scrollTicks = DELAY_TO_SCROLL; /* prevent overflow */
- }
- }
- else
- s_scrollTicks = 0; /* force reset */
-
- /* Mail status changed?
- */
- anynewmail();
- }
- }
- void WindowSync()
- {
- XSync(gDpy, FALSE);
- }
- void WindowFlush()
- {
- ttcharflush();
- XFlush(gDpy);
- }
-
- static void use()
- {
- printf("\nusage: %s [-font font] [-display dpy] [-fg] [-fg2] [-bg] [files]\n",
- whoami);
- }
-
- /* sleep hack - not so long..
- */
- unsigned sleep(x)
- unsigned int x;
- {
- /* x is number of seconds; this is a major hack to
- * wait for a timeout; note NO real fd's used. This works
- * because no i/o can normally occur to cause a wakeup,
- * and the timeout value can be tuned so sleeping isn't such a
- * lengthy process (ie x=1 is about 3/4 of a sec).
- */
- int selreturn = 0;
- struct timeval tv;
- fd_set fds;
-
- tv.tv_sec = 0;
- tv.tv_usec = x * TIME_INC;
-
- FD_ZERO(&fds);
- #if defined(SOL) || defined(HP)
-
- if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
- selreturn = select(rlim.rlim_cur, &fds, 0, 0, &tv);
- else
- {
- ewprintf("getrlimit failed!");
- ttbeep();
- }
- #else
- selreturn = select(getdtablesize(), &fds, 0, 0, &tv);
- #endif
- }
- #endif /** JAM **/
-