Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!batcomputer!munnari.oz.au!manuel!anucsd!pdact!dbell From: dbell@pdact.pd.necisa.oz.au (David I. Bell) Newsgroups: comp.os.minix Subject: MINI-X graphics package (part 4/9) Message-ID: <995@pdact.pd.necisa.oz.au> Date: 22 Apr 91 00:52:40 GMT Organization: NEC Information Systems Australia, Canberra Lines: 2130 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'mini-x/kernel/ega.x' <<'END_OF_FILE' X/* Copyright (c) 1991 David I. Bell X * Permission is granted to use, distribute, or modify this source, X * provided that this copyright notice remains intact. X * X * The algorithms for some of these routines are taken from the book: X * Programmer's Guide to PC and PS/2 Video Systems by Richard Wilton. X * X * Routines to draw pixels and lines for EGA/VGA resolutions. X * The drawing mode in the data/rotate register is not changed in this X * module, and must be changed as necessary by the callers. X */ X X#include "protect.h" X X X#define PIXCOLS 640 /* number of pixels across */ X#define PIXROWS 350 /* number of pixels down */ X#define PIXBYTES 80 /* number of bytes across */ X#define CHARROWS 14 /* number of pixels in char heights */ X#define CHARCOLS 8 /* number of pixels in char widths */ X#define BITMAPSIZE 2 /* number of bytes in GR_BITMAP */ X X#define BUFFERADDR 0xa000 /* EGA buffer segment address */ X#define MEMADDR 0xa0000 /* physical memory address of buffer */ X#define PORTADDR 0x03ce /* graphics controller port address */ X#define BITMASKREG 0x08 /* bit mask register */ X#define INITBITMASK 0xff08 /* set full bit mask output value */ X#define WRITEMODE2 0x0205 /* select write mode 2 output value */ X#define INITWRITEMODE 0x0005 /* restore default write mode 0 */ X#define PIXSHIFT 3 /* convert pixels to byte offset */ X X X .globl _ega_getcharbits /* read bitmap for a character */ X .globl _ega_drawline /* draw a line */ X .globl _ega_drawpoint /* set an individual pixel */ X .globl _ega_drawtext /* draw text string */ X .globl _ega_readpoint /* read an individual pixel */ X X .bss X .extern _rom_char_addr /* ROM char bitmap physical address */ X .text X X X/* X * Routine to return the bitmap for a character from the ROM. X * Called from C: X * ega_getcharbits(char, retbitmap, retwidth, retheight); X * GR_CHAR char; X * GR_BITMAP *retbitmap; X * GR_SIZE *retwidth; X * GR_SIZE *retheight; X * The retbitmap is a pointer to an array of GR_BITMAP values (shorts), X * of length CHARROWS. Retwidth and retheight are the returned X * width and height of the character. X */ X X#define char 8 /* character to get bitmap of */ X#define retaddr 12 /* returned address of bitmap */ X#define retwidth 16 /* returned width of character */ X#define retheight 20 /* returned height of character */ X X X_ega_getcharbits: X push ebp /* setup stack frame and preserve registers */ X mov ebp, esp X push es X X xor eax, eax /* get character code */ X movb al, char(ebp) X mov ecx, #CHARROWS /* get number of bytes of data for chars */ X mul ecx /* make offset into ROM bitmap table */ X add eax, _rom_char_addr /* physical addr of bitmap for char */ X mov bx, #FLAT_DS_SELECTOR /* flat address space selector */ X mov es, bx X mov ebx, retaddr(ebp) /* address for returned bits */ X xor edx, edx /* clear low order part of bitmap values */ X Xgetcharloop: X seg es /* get next byte of bitmap */ X movb dh, (eax) X mov (ebx), dx /* store in caller's buffer */ X inc eax /* advance ROM address */ X add ebx, #BITMAPSIZE /* and buffer address */ X loop getcharloop /* loop until did all rows of char */ X X mov ax, #CHARCOLS /* return width of character */ X mov ebx, retwidth(ebp) X mov (ebx), ax X mov ax, #CHARROWS /* return height of character */ X mov ebx, retheight(ebp) X mov (ebx), ax X X pop es /* restore registers and return */ X pop ebp X ret X X X/* X * Routine to draw an arbitrary line. X * Called from C: X * _ega_drawline(x1, y1, x2, y2, color); X */ X X/* argument offsets, starting with 8 bytes (eip + ebp) */ X#define x1 8 /* first X coordinate */ X#define y1 12 /* first Y coordinate */ X#define x2 16 /* second X coordinate */ X#define y2 20 /* second Y coordinate */ X#define color 24 /* pixel value */ X X/* local variable offsets from ebp */ X#define rowincr -4 /* byte increment between rows */ X#define incr1 -8 /* first increment */ X#define incr2 -12 /* second increment */ X#define routine -16 /* routine to jump to */ X X X_ega_drawline: X push ebp /* setup stack frame and preserve registers */ X mov ebp, esp X X /* X * Make sure that the line is totally within the screen area. X * If not, we are allowed to completely ignore the line. X */ X mov eax, x1(ebp) /* EAX := x1 */ X cmp eax, #PIXCOLS /* if ((x1<0) || (x1>=PIXCOLS)) return */ X jae badline X mov eax, x2(ebp) /* EAX := x2 */ X cmp eax, #PIXCOLS /* if ((x2<0) || (x2>=PIXCOLS)) return */ X jae badline X mov eax, y1(ebp) /* EAX := y1 */ X cmp eax, #PIXROWS /* if ((y1<0) || (y1>=PIXROWS)) return */ X jae badline X mov eax, y2(ebp) /* EAX := y2 */ X cmp eax, #PIXROWS /* if ((y2<0) || (y2>=PIXROWS)) return */ X jae badline X j lineok X Xbadline: X pop ebp X ret X X /* X * Here when we know the line is totally drawable. X */ Xlineok: X sub esp, #16 X push esi X push edi X push es X X /* configure the graphics controller */ X X mov dx, #PORTADDR /* DX := Graphics Controller port address */ X movb ah, color(ebp) /* pixel value */ X xorb al, al /* Set/Reset register number (0) */ X out dx, ax X X mov ax, #0x0f01 /* AH := bit plane mask for Enable Set/Reset */ X out dx, ax /* AL := Enable Set/Reset register number */ X X /* check for vertical line */ X X mov esi, #PIXBYTES /* increment for video buffer */ X mov ecx, x2(ebp) X sub ecx, x1(ebp) /* CX := x2 - x1 */ X jnz L117 /* jump if vertical line */ X jmp VertLine XL117: X /* force x1 < x2 */ X X jns L01 /* jump if x2 > x1 */ X X neg ecx /* CX := x1 - x2 */ X X mov ebx, x2(ebp) /* exchange x1 and x2 */ X xchg ebx, x1(ebp) X mov x2(ebp), ebx X X mov ebx, y2(ebp) /* exchange y1 and y2 */ X xchg ebx, y1(ebp) X mov y2(ebp), ebx X X /* calculate dy = ABS(y2 - y1) */ X XL01: mov ebx, y2(ebp) X sub ebx, y1(ebp) /* BX := y2 - y1 */ X jnz L115 /* jump if horizontal line */ X jmp HorizLine XL115: X jns L03 /* jump if slope is positive */ X X neg ebx /* BX := y1 - y2 */ X neg esi /* negate increment for buffer interleave */ X X /* select appropriate routine for slope of line */ X XL03: mov rowincr(ebp), esi /* save vertical increment */ X mov routine(ebp), #LowSlope X cmp ebx, ecx X jle L04 /* jump if dy <= dx (slope <= 1) */ X mov routine(ebp), #HighSlope X xchg ebx, ecx /* exchange dy and dx */ X X /* calculate initial decision variable and increments */ X XL04: shl ebx, #1 /* BX := 2 * dy */ X mov incr1(ebp), ebx /* incr1 := 2 * dy */ X sub ebx, ecx X mov esi, ebx /* SI := d = 2 * dy - dx */ X sub ebx, ecx X mov incr2(ebp), ebx /* incr2 := 2 * (dy - dx) */ X X /* calculate first pixel address */ X X push ecx /* preserve register */ X mov eax, y1(ebp) /* AX := y */ X mov ebx, x1(ebp) /* BX := x */ X call PixelAddr /* AH := bit mask */ X /* ES:BX -> buffer */ X /* CL := bits to shift left */ X X mov edi, ebx /* es:di -> buffer */ X shlb ah, cl /* AH := bit mask in proper position */ X movb bl, ah /* AH,BL := bit mask */ X movb al, #BITMASKREG /* AL := Bit Mask Register number */ X X pop ecx /* restore register */ X inc ecx /* CX := number of pixels to draw */ X X jmp #routine(ebp) /* jump to appropriate routine for slope */ X X X/* X * Routine for vertical lines X */ XVertLine: X mov eax, y1(ebp) /* AX := y1 */ X mov ebx, y2(ebp) /* BX := y2 */ X mov ecx, ebx X sub ecx, eax /* CX := dy */ X jge L31 /* jump if dy >= 0 */ X X neg ecx /* force dy >= 0 */ X mov eax, ebx /* AX := y2 */ X XL31: inc ecx /* CX := number of pixels to draw */ X mov ebx, x1(ebp) /* BX := x */ X push ecx /* save register */ X call PixelAddr /* AH := bit mask */ X /* ES:BX -> video buffer */ X /* CL := number bits to shift left */ X X/* set up Graphics controller */ X X shlb ah, cl /* AH := bit mask in proper position */ X movb al, #BITMASKREG /* AL := Bit Mask register number */ X out dx, ax X X pop ecx /* restore register */ X X/* draw the line */ X X push ds X push es X pop ds XL111: orb (ebx), al /* set pixel */ X add ebx, esi /* increment to next line */ X loop L111 X pop ds X jmp Lexit X X X/* X * Routine for horizontal lines (slope = 0) X */ XHorizLine: X push ds /* preserve DS */ X X mov eax, y1(ebp) X mov ebx, x1(ebp) X call PixelAddr /* AH := bit mask */ X /* ES:BX -> video buffer */ X /* CL := number bits to shift left */ X mov edi, ebx /* ES:DI -> buffer */ X movb dh, ah /* DH := unshifted bit mask for left byte */ X X notb dh X shlb dh, cl /* DH := reverse bit mask for first byte */ X notb dh /* DH := bit mask for first byte */ X X mov ecx, x2(ebp) X andb cl, #0x07 X xorb cl, #0x07 /* CL := number of bits to shift left */ X movb dl, #0xff /* DL := unshifted bit mask for right byte */ X shlb dl, cl /* DL := bit mask for last byte */ X X /* determine byte offset of first and last pixel in the line */ X X mov eax, x2(ebp) /* AX := x2 */ X mov ebx, x1(ebp) /* BX := x1 */ X X movb cl, #PIXSHIFT /* bits to convert pixels to bytes */ X X shr eax, cl /* AX := byte offset of X2 */ X shr ebx, cl /* BX := byte offset of X1 */ X mov ecx, eax X sub ecx, ebx /* CX := (number of bytes in line) - 1 */ X X /* get Graphics Controller port address into DX */ X X mov ebx, edx /* BH := bit mask for first byte */ X /* BL := bit mask for last byte */ X mov dx, #PORTADDR /* DX := Graphics Controller port */ X movb al, #BITMASKREG /* AL := Bit mask Register number */ X X /* make video buffer addressable through DS:SI */ X X push es X pop ds X mov esi, edi /* DS:SI -> video buffer */ X X /* set pixels in leftmost byte of the line */ X X orb bh, bh X js L43 /* jump if byte-aligned (x1 is leftmost) */ X X or ecx, ecx X jnz L42 /* jump if more than one byte in the line */ X X andb bl, bh /* BL := bit mask for the line */ X jmp L44 X XL42: movb ah, bh /* AH := bit mask for first byte */ X out dx, ax /* update graphics controller */ X X movsb /* update bit planes */ X dec ecx X X /* use a fast 8086 machine instruction to draw the remainder of the line */ X XL43: movb ah, #0xff /* AH := bit mask */ X out dx, ax /* update Bit Mask register */ X rep X movsb /* update all pixels in the line */ X X /* set pixels in the rightmost byte of the line */ X XL44: movb ah, bl /* AH := bit mask for last byte */ X out dx, ax /* update Graphics Controller */ X movsb /* update bit planes */ X X pop ds /* restore ds */ X jmp Lexit X X X/* X * Routine for dy >= dx (slope <= 1) X * ES:DI -> video buffer X * AL = Bit Mask Register number X * BL = bit mask for first pixel X * CX = number of pixels to draw X * DX = Graphics Controller port address X * SI = decision variable X */ XLowSlope: X XL10: movb ah, bl /* AH := bit mask for next pixel */ X XL11: orb ah, bl /* mask current bit position */ X rorb bl, #1 /* rotate pixel value */ X jc L14 /* jump if bit mask rotated to leftmost position */ X X /* bit mask not shifted out */ X X or esi, esi /* test sign of d */ X jns L12 /* jump if d >= 0 */ X X add esi, incr1(ebp) /* d := d + incr1 */ X loop L11 X X out dx, ax /* update Bit Mask register */ X seg es X orb (edi), al /* set remaining pixel(s) */ X jmp Lexit X XL12: add esi, incr2(ebp) /* d := d + incr2 */ X out dx, ax /* update Bit Mask register */ X X seg es X orb (edi), al /* update bit planes */ X X add edi, rowincr(ebp) /* increment y */ X loop L10 X jmp Lexit X X /* bit mask shifted out */ X XL14: out dx, ax /* update Bit Mask register */ X X seg es X orb (edi), al /* update bit planes */ X inc edi /* increment x */ X X or esi, esi /* test sign of d */ X jns L15 /* jump if non-negative */ X X add esi, incr1(ebp) /* d := d + incr1 */ X loop L10 X jmp Lexit X XL15: add esi, incr2(ebp) /* d := d + incr2 */ X add edi, rowincr(ebp) /* vertical increment */ X loop L10 X jmp Lexit X X X/* X * Routine for dy > dx (slope > 1) X * ES:DI -> video buffer X * AH = bit mask for first pixel X * AL = Bit Mask register number X * CX = number pixels to draw X * DX = Graphics Controller port address X * SI = decision variable X */ XHighSlope: X mov ebx, rowincr(ebp) /* BX := y increment */ X XL21: out dx, ax /* update Bit Mask register */ XL21a: seg es X orb (edi), al /* update bit planes */ X X add edi, ebx /* increment y */ X XL22: or esi, esi /* test sign of d */ X jns L23 /* jump if d >= 0 */ X X add esi, incr1(ebp) /* d := d + incr1 */ X loop L21a X jmp Lexit X XL23: add esi, incr2(ebp) /* d := d + incr2 */ X rorb ah, #1 /* rotate bit mask */ X adc edi, #0 /* increment DI if when mask rotated to */ X /* leftmost pixel position */ X loop L21 X/* jmp Lexit */ X X X /* restore default Graphics Controller state and return to caller */ X XLexit: xor ax, ax /* AH := 0, AL := 0 */ X out dx, ax /* restore Set/Reset register */ X X inc ax /* AH := 0, AL := 1 */ X out dx, ax /* restore Enable Set/Reset register */ X X mov ax, #INITBITMASK /* AH := 0xff, AL := 0 */ X out dx, ax /* restore Bit Mask register */ X X pop es X pop edi X pop esi X mov esp, ebp /* restore registers and return */ X pop ebp X ret X X#undef color X X X/* X * Routine to set an individual pixel value. X * Called from C like: X * _ega_drawpoint(x, y, color); X */ X X/* argument offsets, starting with 8 bytes (eip + ebp) */ X#define x 8 /* X coordinate */ X#define y 12 /* Y coordinate */ X#define color 16 /* pixel value */ X X X_ega_drawpoint: X push ebp X mov ebp, esp X push ds /* save registers and set up stack frame */ X X mov ecx, x(ebp) /* ECX := x */ X cmp ecx, #PIXCOLS /* if ((x<0) || (x>=PIXCOLS)) return */ X jae done X X mov eax, y(ebp) /* EAX := y */ X cmp eax, #PIXROWS /* if ((y<0) || (y>=PIXROWS)) return */ X jae done X X mov edx, #PIXBYTES /* AX := (y * PIXBYTES) */ X mul edx X X mov ebx, ecx /* BX := (x / 8) */ X shr ebx, #3 X X add ebx, eax /* BX := (y * PIXBYTES) + (x / 8) */ X add ebx,#MEMADDR /* add in memory physical address */ X X andb cl, #0x07 /* CL := (x % 8) */ X xorb cl, #0x07 /* CL := 7 - (x % 8) */ X movb ch, #0x01 /* CH := 1 << (7 - (x % 8)) (mask) */ X shlb ch, cl X X mov ax, #FLAT_DS_SELECTOR /* DS := EGA buffer segment address */ X mov ds, ax X X mov dx, #PORTADDR /* graphics controller port address */ X mov ax, #WRITEMODE2 /* select write mode 2 */ X out dx, ax /* (load value 2 into mode register 5) */ X movb al, #BITMASKREG /* set the bit mask register */ X movb ah, ch /* (load bit mask into register 8) */ X out dx, ax X movb al, (ebx) /* dummy read to latch bit planes */ X mov ax, color(ebp) /* pixel value */ X movb (ebx), al /* write pixel back to bit planes */ X X mov ax, #INITWRITEMODE /* restore default write mode 0 */ X out dx, ax /* (load value 0 into mode register 5) */ X mov ax, #INITBITMASK /* restore default bit mask */ X out dx, ax /* (load value ff into register 8) */ X Xdone: pop ds /* restore registers and return */ X pop ebp X ret X X X/* X * Routine to draw a text string using the ROM character bitmap. X * If the background color is (long) -1 then it is not drawn. X * Called from C like: X * ega_drawtext(x, y, cp, len, fg, bg); X */ X#undef x X#undef y X#define x 8 /* X coordinate */ X#define y 12 /* Y coordinate */ X#define cp 16 /* character pointer */ X#define len 20 /* length of string */ X#define fg 24 /* foreground color */ X#define bg 28 /* background color */ X X_ega_drawtext: X push ebp X mov ebp, esp X push ds /* save registers we use */ X push es X push edi X push esi X X mov eax, y(ebp) /* EAX := y */ X cmp eax, #PIXROWS /* if ((y<0) || (y>=PIXROWS)) return */ X jae donetext X add eax, #CHARROWS-1 /* convert y to top of chars */ X jl donetext /* if not enough room, return */ X X mov ebx, x(ebp) /* EBX := x */ X cmp ebx, #PIXCOLS /* if ((x<0) || (x>=PIXCOLS)) return */ X jae donetext X X mov ecx, len(ebp) /* see if length is non-positive */ X or ecx, ecx X jle donetext X X cmp ecx, #PIXCOLS /* or very large */ X jae donetext X X shl ecx, #3 /* convert char length to pixel column count */ X add ecx, ebx /* determine first column to not touch */ X cmp ecx, #PIXCOLS /* see if will write off end */ X jg donetext X Xcharloop: X mov ebx, cp(ebp) /* get address of next character */ X xor eax, eax X movb al, (ebx) /* get next character */ X inc ebx /* increment character pointer */ X mov cp(ebp), ebx /* save away */ X mov edx,#CHARROWS /* bytes between character bitmaps */ X mul edx /* convert char code to offset in ROM table */ X add eax, _rom_char_addr /* make physical address of char bits */ X mov esi, eax /* save in source register */ X X mov eax, x(ebp) X mov edx, #PIXBYTES /* AX := (y * PIXBYTES) */ X mul edx X X movb cl, bl /* save low order column bits */ X shr ebx, #3 /* BX := (x / 8) */ X X add ebx, eax /* BX := (y * PIXBYTES) + (x / 8) */ X add ebx,#MEMADDR /* add in memory physical address */ X X andb cl, #0x07 /* CL := (x % 8) */ X xorb cl, #0x07 /* CL := 7 - (x % 8) */ X X mov dx, #FLAT_DS_SELECTOR /* ES := EGA buffer segment address */ X mov ds, dx X X movb ch, #0x01 /* CH := 1 << (7 - (col % 8)) (mask) */ X shlb ch, cl /* CH := bit mask in proper position */ X Xdonetext: X pop esi X pop edi X pop es X pop ds X ret X X X/* X * Routine to read the value of an individual pixel. X * Called from C like: X * color = readpoint(x, y); X */ X X#undef x X#undef y X#define x 8 /* X coordinate */ X#define y 12 /* Y coordinate */ X X X_ega_readpoint: X push ebp X mov ebp, esp X X /* X * Make sure that the line is totally within the screen area. X * If not, then return a pixel value of 0. X */ X mov eax, y(ebp) /* EAX := y */ X mov ebx, x(ebp) /* EBX := x */ X cmp eax, #PIXROWS /* if ((y<0) || (y>=PIXROWS)) return */ X jae retzero X cmp ebx, #PIXCOLS /* if ((x<0) || (x>=PIXCOLS)) return */ X jae retzero X X push si X push ds X X mov edx, #PIXBYTES /* AX := (y * PIXBYTES) */ X mul edx X X movb cl, bl /* save low order column bits */ X shr ebx, #3 /* BX := (x / 8) */ X X add ebx, eax /* BX := (y * PIXBYTES) + (x / 8) */ X add ebx,#MEMADDR /* add in memory physical address */ X X andb cl, #0x07 /* CL := (x % 8) */ X xorb cl, #0x07 /* CL := 7 - (x % 8) */ X X mov dx, #FLAT_DS_SELECTOR /* ES := EGA buffer segment address */ X mov ds, dx X X movb ch, #0x01 /* CH := 1 << (7 - (col % 8)) (mask) */ X shlb ch, cl /* CH := bit mask in proper position */ X X mov esi, ebx /* ES:SI -> region buffer byte */ X xorb bl, bl /* BL is used to accumulate the pixel value */ X X mov dx, #PORTADDR /* DX := Graphics Controller port */ X mov ax, #0x0304 /* AH := initial bit plane number */ X /* AL := Read Map Select register number */ X XL112: out dx, ax /* select bit plane */ X movb bh, (esi) /* BH := byte from current bit plane */ X andb bh, ch /* mask one bit */ X negb bh /* bit 7 of BH := 1 if masked bit = 1 */ X /* bit 7 of BH := 0 if masked bit = 0 */ X rol bx, #1 /* bit 0 of BL := next bit from pixel value */ X decb ah /* AH := next bit plane number */ X jge L112 X X xor eax, eax /* AL := pixel value */ X movb al, bl X X pop ds X pop si X pop ebp X ret X Xretzero: X pop ebp X xor eax, eax X ret X X X/* X * Local routine to convert row and column numbers to pixel addresses and masks. X * Input: EAX = row X * EBX = column X * Output: X * AH := bit mask X * ES:EBX -> video buffer X * CL := number bits to shift left X */ XPixelAddr: X push edx X X mov edx, #PIXBYTES /* AX := (row * PIXBYTES) */ X mul edx X X movb cl, bl /* save low order column bits */ X shr ebx, #3 /* BX := (col / 8) */ X X add ebx, eax /* BX := (row * PIXBYTES) + (col / 8) */ X add ebx,#MEMADDR /* add in memory physical address */ X X andb cl, #0x07 /* CL := (col % 8) */ X xorb cl, #0x07 /* CL := 7 - (col % 8) */ X movb ah, #0x01 /* AH := 1 << (7 - (col % 8)) (mask) */ X X mov dx, #FLAT_DS_SELECTOR /* ES := EGA buffer segment address */ X mov es, dx X X pop edx X X ret END_OF_FILE if test 18881 -ne `wc -c <'mini-x/kernel/ega.x'`; then echo shar: \"'mini-x/kernel/ega.x'\" unpacked with wrong size! fi # end of 'mini-x/kernel/ega.x' fi if test -f 'mini-x/server/client.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mini-x/server/client.c'\" else echo shar: Extracting \"'mini-x/server/client.c'\" \(16055 characters\) sed "s/^X//" >'mini-x/server/client.c' <<'END_OF_FILE' X/* X * Copyright (c) 1991 David I. Bell X * Permission is granted to use, distribute, or modify this source, X * provided that this copyright notice remains intact. X * X * Client routines to do graphics with windows and graphics contexts. X * NOTE: These are stub routines at the moment because the server X * routines are loaded with the client into one process. The problem X * with this is that you can run only one client program on the screen. X * Eventually, the server will run in its own process, and these routines X * then must ship their arguments across some network interface to that X * process. At that point, the server can then serve multiple clients X * simultaneously. X */ X#include X#include "graph_serv.h" X X X/* X * The following is used to allocate ids which the server will X * recognize as our windows and such. Since we and the server X * keep in step in the allocation, it is not necessary to wait X * for the server to return resource ids. X */ Xstatic GR_ID allocid; X X X/* X * The following is the user defined function for handling errors. X * If this is not set, then the default action is to close the connection X * to the server, describe the error, and then exit. This error function X * will only be called when the client asks for events. X */ Xstatic GR_ERROR_FUNC GrErrorFunc; X X X X/* X * Open a connection to the graphics server. X * Returns zero if successful, -1 on failure. X */ Xint XGrOpen() X{ X GrErrorFunc = 0; X allocid = GsOpen(); X if (allocid == 0) X return -1; X return 0; X} X X X/* X * Close the graphics device, first flushing any waiting messages. X */ Xvoid XGrClose() X{ X GsClose(); X} X X X/* X * Set an error handling routine, which will be called on any errors from X * the server (when events are asked for by the client). If zero is given, X * then a default routine will be used. Returns the previous error handler. X */ XGR_ERROR_FUNC XGrSetErrorHandler(func) X GR_ERROR_FUNC func; /* function to handle error */ X{ X GR_ERROR_FUNC oldfunc; /* previous function */ X X oldfunc = GrErrorFunc; X GrErrorFunc = func; X return oldfunc; X} X X X/* X * Return useful information about the screen. X */ Xvoid XGrGetScreenInfo(sip) X GR_SCREEN_INFO *sip; /* address of screen info */ X{ X GsGetScreenInfo(sip); X} X X X/* X * Return useful information about the specified font. X */ Xvoid XGrGetFontInfo(font, fip) X GR_FONT font; /* font number */ X GR_FONT_INFO *fip; /* address of font info */ X{ X GsGetFontInfo(font, fip); X} X X X/* X * Return information about the specified graphics context. X */ Xvoid XGrGetGCInfo(gc, gcip) X GR_GC_ID gc; /* graphics context */ X GR_GC_INFO *gcip; /* address of graphics context info */ X{ X GsGetGCInfo(gc, gcip); X} X X X/* X * Return the size of a text string for the font in a graphics context. X * This is the width of the string, the height of the string, X * and the height above the bottom of the font of the baseline for the font. X */ Xvoid XGrGetGCTextSize(gc, cp, len, retwidth, retheight, retbase) X GR_GC_ID gc; /* graphics context containing font */ X GR_CHAR *cp; /* address of text string */ X GR_SIZE len; /* length of text string */ X GR_SIZE *retwidth; /* returned width of string */ X GR_SIZE *retheight; /* returned height of string */ X GR_SIZE *retbase; /* returned height of baseline */ X{ X GsGetGCTextSize(gc, cp, len, retwidth, retheight, retbase); X} X X X/* X * Return the next event from the event queue. X * This waits for a new one if one is not ready. X * If it is an error event, then a user-specified routine is X * called if it was defined, otherwise we clean up and exit. X */ Xvoid XGrGetNextEvent(ep) X GR_EVENT *ep; /* address where event is returned */ X{ X GsFlush(); X while (1) { X GsGetNextEvent(ep); X if (ep->type != GR_EVENT_TYPE_ERROR) X return; X X if (GrErrorFunc) { X (*GrErrorFunc)(ep->error.code, ep->error.name, X ep->error.id); X continue; X } X X GsClose(); X fprintf(stderr, "Graphics error %d, function %s, resource id %ld\n", X ep->error.code, ep->error.name, ep->error.id); X exit(1); X } X} X X X/* X * Return the next event from the event queue if one is ready. X * If one is not ready, then the type GR_EVENT_TYPE_NONE is returned. X * If it is an error event, then a user-specified routine is called X * if it was defined, otherwise we clean up and exit. X */ Xvoid XGrCheckNextEvent(ep) X GR_EVENT *ep; /* address where event is returned */ X{ X GrPeekEvent(ep); X if (ep->type != GR_EVENT_TYPE_NONE) X GrGetNextEvent(ep); X} X X X/* X * Return the next event from the event queue if available. X * If there is no event, then a null event type is returned. X */ Xvoid XGrPeekEvent(ep) X GR_EVENT *ep; /* address where event is returned */ X{ X GsFlush(); X GsPeekEvent(ep); X} X X X/* X * Select events for a window for this client. X * The events are a bitmask for the events desired. X */ Xvoid XGrSelectEvents(wid, eventmask) X GR_WINDOW_ID wid; /* window id */ X GR_EVENT_MASK eventmask; /* mask of events wanted */ X{ X GsSelectEvents(wid, eventmask); X} X X X/* X * Allocate a new window which is a child of the specified window. X * The window inherits the cursor of the parent window. X */ XGR_WINDOW_ID XGrNewWindow(parent, x, y, width, height, bordersize, background, bordercolor) X GR_WINDOW_ID parent; /* parent id */ X GR_COORD x; /* x position relative to parent */ X GR_COORD y; /* y position relative to parent */ X GR_SIZE width; /* width */ X GR_SIZE height; /* height */ X GR_SIZE bordersize; /* size of border */ X GR_COLOR background; /* background color */ X GR_COLOR bordercolor; /* border color */ X{ X GsNewWindow(parent, x, y, width, height, bordersize, X background, bordercolor); X X return ++allocid; X} X X X/* X * Allocate a new input-only window which is a child of the specified window. X * The window inherits the cursor of the parent window. X */ XGR_WINDOW_ID XGrNewInputWindow(parent, x, y, width, height) X GR_WINDOW_ID parent; /* parent id */ X GR_COORD x; /* x position relative to parent */ X GR_COORD y; /* y position relative to parent */ X GR_SIZE width; /* width */ X GR_SIZE height; /* height */ X{ X GsNewInputWindow(parent, x, y, width, height); X X return ++allocid; X} X X X/* X * Destroy an existing window. X */ Xvoid XGrDestroyWindow(wid) X GR_WINDOW_ID wid; /* window to destroy */ X{ X GsDestroyWindow(wid); X} X X X/* X * Return information about a window id. X */ Xvoid XGrGetWindowInfo(wid, infoptr) X GR_WINDOW_ID wid; /* window to find out about */ X GR_WINDOW_INFO *infoptr; /* pointer to returned data */ X{ X GsGetWindowInfo(wid, infoptr); X} X X X/* X * Allocate a new GC with default parameters. X */ XGR_GC_ID XGrNewGC() X{ X GsNewGC(); X X return ++allocid; X} X X X/* X * Allocate a new GC which is a copy of another one. X */ XGR_GC_ID XGrCopyGC(gc) X GR_GC_ID gc; /* graphics context to copy */ X{ X GsCopyGC(gc); X X return ++allocid; X} X X X/* X * Destroy an existing graphics context. X */ Xvoid XGrDestroyGC(gc) X GR_GC_ID gc; /* graphics context to destroy */ X{ X GsDestroyGC(gc); X} X X X/* X * Map the window to make it (and possibly its children) visible on the screen. X * This paints the border and background of the window, and creates an X * exposure event to tell the client to draw into it. X */ Xvoid XGrMapWindow(wid) X GR_WINDOW_ID wid; /* window to be mapped */ X{ X GsMapWindow(wid); X} X X X/* X * Unmap the window to make it and its children invisible on the screen. X */ Xvoid XGrUnmapWindow(wid) X GR_WINDOW_ID wid; /* window to be unmapped */ X{ X GsUnmapWindow(wid); X} X X X/* X * Raise the window to the highest level among its siblings. X */ Xvoid XGrRaiseWindow(wid) X GR_WINDOW_ID wid; /* window to be raised */ X{ X GsRaiseWindow(wid); X} X X X/* X * Lower the window to the lowest level among its siblings. X */ Xvoid XGrLowerWindow(wid) X GR_WINDOW_ID wid; /* window to be lowered */ X{ X GsLowerWindow(wid); X} X X X/* X * Move the window to the specified position relative to its parent. X */ Xvoid XGrMoveWindow(wid, x, y) X GR_WINDOW_ID wid; /* window to be lowered */ X GR_COORD x; /* new relative x position */ X GR_COORD y; /* new relative y position */ X{ X GsMoveWindow(wid, x, y); X} X X X/* X * Resize the window to be the specified size. X */ Xvoid XGrResizeWindow(wid, width, height) X GR_WINDOW_ID wid; /* window to be lowered */ X GR_SIZE width; /* new width of window */ X GR_SIZE height; /* new height of window */ X{ X GsResizeWindow(wid, width, height); X} X X X/* X * Clear the specified window by setting it to its background color. X * If the exposeflag is nonzero, then this also creates an exposure X * event for the window. X */ Xvoid XGrClearWindow(wid, exposeflag) X GR_WINDOW_ID wid; /* window id */ X GR_BOOL exposeflag; /* nonzero to cause an exposure */ X{ X GsClearWindow(wid, exposeflag); X} X X X/* X * Set the focus to a particular window. X * This makes keyboard events only visible to that window or children of it, X * depending on the pointer location. X */ Xvoid XGrSetFocus(wid) X GR_WINDOW_ID wid; /* window id */ X{ X GsSetFocus(wid); X} X X X/* X * Set the border of a window to the specified color. X */ Xvoid XGrSetBorderColor(wid, color) X GR_WINDOW_ID wid; /* window id */ X GR_COLOR color; /* color for border */ X{ X GsSetBorderColor(wid, color); X} X X X/* X * Specify a cursor for a window. X * This cursor will only be used within that window, and by default X * for its new children. If the cursor is currently within this X * window, it will be changed to the new one immediately. X */ Xvoid XGrSetCursor(wid, width, height, hotx, hoty, foreground, background, X fgbitmap, bgbitmap) X X GR_WINDOW_ID wid; /* window id to set cursor for */ X GR_SIZE width; /* width of cursor */ X GR_SIZE height; /* height of cursor */ X GR_COORD hotx; /* relative x position of hot spot */ X GR_COORD hoty; /* relative y position of hot spot */ X GR_COLOR foreground; /* foreground color of cursor */ X GR_COLOR background; /* background color of cursor */ X GR_BITMAP *fgbitmap; /* foreground bitmap */ X GR_BITMAP *bgbitmap; /* background bitmap */ X{ X GsSetCursor(wid, width, height, hotx, hoty, foreground, background, X fgbitmap, bgbitmap); X} X X X/* X * Move the cursor to the specified absolute screen coordinates. X * The coordinates are that of the defined hot spot of the cursor. X * The cursor's appearance is changed to that defined for the window X * in which the cursor is moved to. X */ Xvoid XGrMoveCursor(x, y) X GR_COORD x; /* new x position of cursor */ X GR_COORD y; /* new y position of cursor */ X{ X GsMoveCursor(x, y); X} X X X/* X * Flush the message buffer of any messages it may contain. X */ Xvoid XGrFlush() X{ X GsFlush(); X} X X X/* X * Set the foreground color in a graphics context. X */ Xvoid XGrSetGCForeground(gc, foreground) X GR_GC_ID gc; /* graphics context id */ X GR_COLOR foreground; /* foreground color */ X{ X GsSetGCForeground(gc, foreground); X} X X X/* X * Set the background color in a graphics context. X */ Xvoid XGrSetGCBackground(gc, background) X GR_GC_ID gc; /* graphics context id */ X GR_COLOR background; /* background color */ X{ X GsSetGCBackground(gc, background); X} X X X/* X * Set the drawing mode in a graphics context. X */ Xvoid XGrSetGCMode(gc, mode) X GR_GC_ID gc; /* graphics context id */ X GR_MODE mode; /* drawing mode */ X{ X GsSetGCMode(gc, mode); X} X X X/* X * Set whether or not the background color is drawn in bitmaps and text. X */ Xvoid XGrSetGCUseBackground(gc, flag) X GR_GC_ID gc; /* graphics context id */ X GR_BOOL flag; /* TRUE if background is drawn */ X{ X GsSetGCUseBackground(gc, flag); X} X X X/* X * Set the font used for text drawing in a graphics context. X * The font is a number identifying one of several fonts. X * Font number 0 is always available, and is the default font. X */ Xvoid XGrSetGCFont(gc, font) X GR_GC_ID gc; /* graphics context id */ X GR_FONT font; /* text font */ X{ X GsSetGCFont(gc, font); X} X X X/* X * Draw a line in the specified drawable using the specified graphics context. X */ Xvoid XGrLine(id, gc, x1, y1, x2, y2) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x1; X GR_COORD y1; X GR_COORD x2; X GR_COORD y2; X{ X GsLine(id, gc, x1, y1, x2, y2); X} X X X/* X * Draw the boundary of a rectangle in the specified drawable using the X * specified graphics context. X */ Xvoid XGrRect(id, gc, x, y, width, height) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X{ X GsRect(id, gc, x, y, width, height); X} X X X/* X * Fill a rectangle in the specified drawable using the specified X * graphics context. X */ Xvoid XGrFillRect(id, gc, x, y, width, height) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X{ X GsFillRect(id, gc, x, y, width, height); X} X X X/* X * Draw the boundary of an ellipse in the specified drawable with X * the specified graphics context. X */ Xvoid XGrEllipse(id, gc, x, y, rx, ry) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE rx; X GR_SIZE ry; X{ X GsEllipse(id, gc, x, y, rx, ry); X} X X X/* X * Fill an ellipse in the specified drawable using the specified X * graphics context. X */ Xvoid XGrFillEllipse(id, gc, x, y, rx, ry) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE rx; X GR_SIZE ry; X{ X GsFillEllipse(id, gc, x, y, rx, ry); X} X X X/* X * Draw a rectangular area in the specified drawable using the specified X * graphics, as determined by the specified bit map. This differs from X * rectangle drawing in that the rectangle is drawn using the foreground X * color and possibly the background color as determined by the bit map. X * Each row of bits is aligned to the next bitmap word boundary (so there X * is padding at the end of the row). The background bit values are X * only written if the usebackground flag is set in the GC. X */ Xvoid XGrBitmap(id, gc, x, y, width, height, bitmaptable) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X GR_BITMAP *bitmaptable; X{ X GsBitmap(id, gc, x, y, width, height, bitmaptable); X} X X X/* X * Draw a rectangular area in the specified drawable using the specified X * graphics context. This differs from rectangle drawing in that the X * color values for each pixel in the rectangle are specified. The color X * values are restricted to 8 bit values. The color table is indexed X * row by row. Values whose color matches the background color are only X * written if the usebackground flag is set in the GC. X */ Xvoid XGrArea8(id, gc, x, y, width, height, colortable) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X GR_COLOR8 *colortable; X{ X GsArea8(id, gc, x, y, width, height, colortable); X} X X X/* X * Read the color values from the specified rectangular area of the X * specified drawable into a supplied buffer. If the drawable is a X * window which is obscured by other windows, then the returned values X * will include the values from the covering windows. Regions outside X * of the screen boundaries, or unmapped windows will return black. X */ Xvoid XGrReadArea8(id, x, y, width, height, colortable) X GR_DRAW_ID id; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X GR_COLOR8 *colortable; X{ X GsReadArea8(id, x, y, width, height, colortable); X} X X X/* X * Draw a point in the specified drawable using the specified X * graphics context. X */ Xvoid XGrPoint(id, gc, x, y) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X{ X GsPoint(id, gc, x, y); X} X X X/* X * Draw a polygon in the specified drawable using the specified X * graphics context. The polygon is only complete if the first X * point is repeated at the end. X */ Xvoid XGrPoly(id, gc, count, pointtable) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COUNT count; X GR_POINT *pointtable; X{ X GsPoly(id, gc, count, pointtable); X} X X X/* X * Draw a filled polygon in the specified drawable using the specified X * graphics context. The last point may be a duplicate of the first X * point, but this is not required. X */ Xvoid XGrFillPoly(id, gc, count, pointtable) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COUNT count; X GR_POINT *pointtable; X{ X GsFillPoly(id, gc, count, pointtable); X} X X X/* X * Draw a text string in the specified drawable using the specified X * graphics context. The background of the characters are only drawn X * if the usebackground flag in the GC is set. X */ Xvoid XGrText(id, gc, x, y, str, count) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_CHAR *str; X GR_COUNT count; X{ X GsText(id, gc, x, y, str, count); X} X X/* END CODE */ END_OF_FILE if test 16055 -ne `wc -c <'mini-x/server/client.c'`; then echo shar: \"'mini-x/server/client.c'\" unpacked with wrong size! fi # end of 'mini-x/server/client.c' fi if test -f 'mini-x/server/serv_event.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mini-x/server/serv_event.c'\" else echo shar: Extracting \"'mini-x/server/serv_event.c'\" \(16971 characters\) sed "s/^X//" >'mini-x/server/serv_event.c' <<'END_OF_FILE' X/* X * Copyright (c) 1991 David I. Bell X * Permission is granted to use, distribute, or modify this source, X * provided that this copyright notice remains intact. X * X * Graphics server event routines for windows. X */ X#include X#include "graph_serv.h" X X Xextern char *malloc(); X X X/* X * Generate an error from a graphics function. X * This creates a special event which describes the error. X * Only one error event at a time can be saved for delivery to a client. X * This is ok since there are usually lots of redundant errors generated X * before the client can notice, errors occurs after the fact, and clients X * can't do much about them except complain and die. The error is saved X * specially so that memory problems cannot occur. X */ Xvoid XGsError(code, id) X GR_ERROR code; /* error code */ X GR_ID id; /* id value to describe */ X{ X GR_EVENT_ERROR *ep; /* event to describe error */ X X /* X * If there is already an outstanding error, then forget this one. X */ X if (curclient->errorevent.type == GR_EVENT_TYPE_ERROR) X return; X X /* X * Save the error in a special location. X */ X ep = &curclient->errorevent; X ep->type = GR_EVENT_TYPE_ERROR; X strncpy(ep->name, curfunc, sizeof(GR_FUNC_NAME)); X ep->name[sizeof(GR_FUNC_NAME)-1] = '\0'; X ep->code = code; X ep->id = id; X} X X X/* X * Allocate an event to be passed back to the specified client. X * The event is already chained onto the event queue, and only X * needs filling out. Returns NULL with an error generated if X * the event cannot be allocated. X */ XGR_EVENT * XGsAllocEvent(client) X GR_CLIENT *client; /* client to send event to */ X{ X GR_EVENT_LIST *elp; /* current element list */ X GR_CLIENT *oldcurclient; /* old current client */ X X /* X * Get a new event structure from the free list, or else X * allocate it using malloc. X */ X elp = eventfree; X if (elp) X eventfree = elp->next; X else { X elp = (GR_EVENT_LIST *) malloc(sizeof(GR_EVENT_LIST)); X if (elp == NULL) { X oldcurclient = curclient; X curclient = client; X GsError(GR_ERROR_MALLOC_FAILED, 0); X curclient = oldcurclient; X return NULL; X } X } X X /* X * Add the event to the end of the event list. X */ X if (client->eventhead) X client->eventtail->next = elp; X else X client->eventhead = elp; X client->eventtail = elp; X elp->next = NULL; X elp->event.type = GR_EVENT_TYPE_NONE; X X return &elp->event; X} X X X/* X * Check for a new event to arrive from the hardware devices. X * The event is either a keystroke or a mouse event, and is placed at X * the end of the client's event queue. This collects all available X * status before returning. NOTICE: If waiting is required then this X * routine is a busy loop since there is no poll MINIX call. X */ Xvoid XGsCheckEvent(waitflag) X GR_BOOL waitflag; /* TRUE if should wait for event */ X{ X GR_COORD rootx; /* latest mouse x position */ X GR_COORD rooty; /* latest mouse y position */ X GR_BUTTON newbuttons; /* latest buttons */ X GR_CHAR ch; /* latest character */ X GR_MODIFIER modifiers; /* latest modifiers */ X int mousestatus; /* latest mouse status */ X int keystatus; /* latest keyboard status */ X X GsFlush(); X if (GdCheckError(GR_FALSE)) { X GsError(GR_ERROR_SCREEN_ERROR, 0); X return; X } X X do { X /* X * First read the latest mouse and keyboard status. X */ X mousestatus = GsReadMouse(&rootx, &rooty, &newbuttons); X keystatus = GsReadKeyboard(&ch, &modifiers); X if (mousestatus < 0) { X GsError(GR_ERROR_MOUSE_ERROR, 0); X return; X } X if (keystatus < 0) { X GsError(GR_ERROR_KEYBOARD_ERROR, 0); X return; X } X X /* X * Then deliver mouse or keyboard events as appropriate. X * We must handle mouse status first in order to get the X * cursor location updated quickly. X */ X if (mousestatus) { X waitflag = GR_FALSE; X GsHandleMouseStatus(rootx, rooty, newbuttons, X modifiers); X } X X if (keystatus) { X waitflag = GR_FALSE; X GsDeliverKeyboardEvent(GR_EVENT_TYPE_KEY_DOWN, ch, X newbuttons, modifiers); X } X X } while (waitflag || mousestatus || keystatus); X} X X X/* X * Handle all mouse events. These are mouse enter, mouse exit, mouse X * motion, mouse position, button down, and button up. This also moves X * the cursor to the new mouse position and changes it shape if needed. X */ Xvoid XGsHandleMouseStatus(newx, newy, newbuttons, modifiers) X GR_COORD newx; /* new x position of mouse */ X GR_COORD newy; /* new y position of mouse */ X GR_BUTTON newbuttons; /* new button states */ X GR_BUTTON modifiers; /* modifiers (SHIFT, CTRL, etc) */ X{ X GR_BUTTON changebuttons; /* buttons that have changed */ X X /* X * First, if the mouse has moved, then position the cursor to the X * new location, which will send mouse enter, mouse exit, focus in, X * and focus out events if needed. Check here for mouse motion and X * mouse position events. Flush the device queue to make sure the X * new cursor location is quickly seen by the user. X */ X if ((newx != cursorx) || (newy != cursory)) { X GsMoveCursor(newx, newy); X GsFlush(); X GsDeliverMotionEvent(GR_EVENT_TYPE_MOUSE_MOTION, X newbuttons, modifiers); X GsDeliverMotionEvent(GR_EVENT_TYPE_MOUSE_POSITION, X newbuttons, modifiers); X } X X /* X * Next, generate a button up event if any buttons have been released. X */ X changebuttons = (curbuttons & ~newbuttons); X if (changebuttons) { X GsDeliverButtonEvent(GR_EVENT_TYPE_BUTTON_UP, X newbuttons, changebuttons, modifiers); X } X X /* X * Finally, generate a button down event if any buttons have been X * pressed. X */ X changebuttons = (~curbuttons & newbuttons); X if (changebuttons) { X GsDeliverButtonEvent(GR_EVENT_TYPE_BUTTON_DOWN, X newbuttons, changebuttons, modifiers); X } X X curbuttons = newbuttons; X} X X X/* X * Deliver a mouse button event to the clients which have selected for it. X * Each client can only be delivered one instance of the event. The window X * the event is delivered for is either the smallest one containing the X * mouse coordinates, or else one of its direct ancestors. The lowest X * window in that tree which has enabled for the event gets it. This scan X * is done independently for each client. If a window with the correct X * noprop mask is reached, or if no window selects for the event, then the X * event is discarded for that client. Special case: for the first client X * that is enabled for both button down and button up events in a window, X * then the pointer is implicitly grabbed by that window when a button is X * pressed down in that window. The grabbing remains until all buttons are X * released. While the pointer is grabbed, no other clients or windows can X * receive button down or up events. X */ Xvoid XGsDeliverButtonEvent(type, buttons, changebuttons, modifiers) X GR_EVENT_TYPE type; /* type of event */ X GR_BUTTON buttons; /* current button information */ X GR_BUTTON changebuttons; /* buttons which have changed */ X GR_MODIFIER modifiers; /* modifiers (SHIFT, CTRL, etc) */ X{ X GR_EVENT_BUTTON *ep; /* mouse button event */ X GR_WINDOW *wp; /* current window */ X GR_EVENT_CLIENT *ecp; /* current event client */ X GR_CLIENT *client; /* current client */ X GR_WINDOW_ID subwid; /* subwindow id event is for */ X GR_EVENT_MASK eventmask; /* event mask */ X GR_EVENT_MASK tempmask; /* to get around compiler bug */ X X eventmask = GR_EVENTMASK(type); X if (eventmask == 0) X return; X X eventnumber++; X X /* X * If the pointer is implicitly grabbed, then the only window X * which can receive button events is that window. Otherwise X * the window the pointer is in gets the events. Determine the X * subwindow by seeing if it is a child of the grabbed button. X */ X wp = mousewp; X subwid = wp->id; X X if (grabbuttonwp) { X while ((wp != rootwp) && (wp != grabbuttonwp)) X wp = wp->parent; X if (wp != grabbuttonwp) X subwid = grabbuttonwp->id; X wp = grabbuttonwp; X } X X for (;;) { X for (ecp = wp->eventclients; ecp; ecp = ecp->next) { X if ((ecp->eventmask & eventmask) == 0) X continue; X X client = ecp->client; X if (client->eventnumber == eventnumber) X continue; X X client->eventnumber = eventnumber; X X /* X * If this is a button down, the buttons are not X * yet grabbed, and this client is enabled for both X * button down and button up events, then implicitly X * grab the window for him. X */ X if ((type == GR_EVENT_TYPE_BUTTON_DOWN) X && (grabbuttonwp == NULL)) X { X tempmask = GR_EVENT_MASK_BUTTON_UP; X if (ecp->eventmask & tempmask) X grabbuttonwp = wp; X } X X ep = (GR_EVENT_BUTTON *) GsAllocEvent(client); X if (ep == NULL) X continue; X X ep->type = type; X ep->wid = wp->id; X ep->subwid = subwid; X ep->rootx = cursorx; X ep->rooty = cursory; X ep->x = cursorx - wp->x; X ep->y = cursory - wp->y; X ep->buttons = buttons; X ep->changebuttons = changebuttons; X ep->modifiers = modifiers; X } X X /* X * Events do not propagate if the window was grabbed. X * Also release the grab if the buttons are now all released, X * which can cause various events. X */ X if (grabbuttonwp) { X if (buttons == 0) { X grabbuttonwp = NULL; X GsMoveCursor(cursorx, cursory); X GsFlush(); X } X return; X } X X if ((wp == rootwp) || (wp->nopropmask & eventmask)) X return; X X wp = wp->parent; X } X} X X X/* X * Deliver a mouse motion event to the clients which have selected for it. X * Each client can only be delivered one instance of the event. The window X * the event is delivered for is either the smallest one containing the X * mouse coordinates, or else one of its direct ancestors. The lowest X * window in that tree which has enabled for the event gets it. This scan X * is done independently for each client. If a window with the correct X * noprop mask is reached, or if no window selects for the event, then the X * event is discarded for that client. Special case: If the event type is X * GR_EVENT_TYPE_MOUSE_POSITION, then only the last such event is queued for X * any single client to reduce events. If the mouse is implicitly grabbed, X * then only the grabbing window receives the events, and continues to do X * so even if the mouse is currently outside of the grabbing window. X */ Xvoid XGsDeliverMotionEvent(type, buttons, modifiers) X GR_EVENT_TYPE type; /* type of event */ X GR_BUTTON buttons; /* current button information */ X GR_MODIFIER modifiers; /* modifiers (SHIFT, CTRL, etc) */ X{ X GR_EVENT_MOUSE *ep; /* mouse motion event */ X GR_WINDOW *wp; /* current window */ X GR_EVENT_CLIENT *ecp; /* current event client */ X GR_CLIENT *client; /* current client */ X GR_WINDOW_ID subwid; /* subwindow id event is for */ X GR_EVENT_MASK eventmask; /* event mask */ X X eventmask = GR_EVENTMASK(type); X if (eventmask == 0) X return; X X eventnumber++; X X wp = mousewp; X subwid = wp->id; X X if (grabbuttonwp) { X while ((wp != rootwp) && (wp != grabbuttonwp)) X wp = wp->parent; X if (wp != grabbuttonwp) X subwid = grabbuttonwp->id; X wp = grabbuttonwp; X } X X for (;;) { X for (ecp = wp->eventclients; ecp; ecp = ecp->next) { X if ((ecp->eventmask & eventmask) == 0) X continue; X X client = ecp->client; X if (client->eventnumber == eventnumber) X continue; X X client->eventnumber = eventnumber; X X /* X * If the event is for just the latest position, X * then search the event queue for an existing X * event of this type (if any), and free it. X */ X if (type == GR_EVENT_TYPE_MOUSE_POSITION) X GsFreePositionEvent(client, wp->id, subwid); X X ep = (GR_EVENT_MOUSE *) GsAllocEvent(client); X if (ep == NULL) X continue; X X ep->type = type; X ep->wid = wp->id; X ep->subwid = subwid; X ep->rootx = cursorx; X ep->rooty = cursory; X ep->x = cursorx - wp->x; X ep->y = cursory - wp->y; X ep->buttons = buttons; X ep->modifiers = modifiers; X } X X if ((wp == rootwp) || grabbuttonwp || X (wp->nopropmask & eventmask)) X return; X X wp = wp->parent; X } X} X X X/* X * Deliver a keyboard event to one of the clients which have selected for it. X * Only the first client found gets the event (no duplicates are sent). The X * window the event is delivered to is either the smallest one containing X * the mouse coordinates, or else one of its direct ancestors (if such a X * window is a descendant of the focus window), or else just the focus window. X * The lowest window in that tree which has enabled for the event gets it. X * If a window with the correct noprop mask is reached, or if no window selects X * for the event, then the event is discarded. X */ Xvoid XGsDeliverKeyboardEvent(type, ch, buttons, modifiers) X GR_EVENT_TYPE type; /* type of event */ X GR_CHAR ch; /* character */ X GR_BUTTON buttons; /* button information */ X GR_MODIFIER modifiers; /* modifiers (SHIFT, CTRL, etc) */ X{ X GR_EVENT_KEYSTROKE *ep; /* keystroke event */ X GR_WINDOW *wp; /* current window */ X GR_WINDOW *tempwp; /* temporary window pointer */ X GR_EVENT_CLIENT *ecp; /* current event client */ X GR_WINDOW_ID subwid; /* subwindow id event is for */ X GR_EVENT_MASK eventmask; /* event mask */ X X eventmask = GR_EVENTMASK(type); X if (eventmask == 0) X return; X X wp = mousewp; X subwid = wp->id; X X /* X * See if the actual window the pointer is in is a descendant of X * the focus window. If not, then ignore it, and force the input X * into the focus window itself. X */ X tempwp = wp; X while ((tempwp != focuswp) && (tempwp != rootwp)) X tempwp = tempwp->parent; X X if (tempwp != focuswp) { X wp = focuswp; X subwid = wp->id; X } X X /* X * Now walk upwards looking for the first window which will accept X * the keyboard event. However, do not go beyond the focus window, X * and only give the event to one client. X */ X for (;;) { X for (ecp = wp->eventclients; ecp; ecp = ecp->next) { X if ((ecp->eventmask & eventmask) == 0) X continue; X X ep = (GR_EVENT_KEYSTROKE *) GsAllocEvent(ecp->client); X if (ep == NULL) X return; X X ep->type = type; X ep->wid = wp->id; X ep->subwid = subwid; X ep->rootx = cursorx; X ep->rooty = cursory; X ep->x = cursorx - wp->x; X ep->y = cursory - wp->y; X ep->buttons = buttons; X ep->modifiers = modifiers; X ep->ch = ch; X return; /* only one client gets it */ X } X X if ((wp == rootwp) || (wp == focuswp) || X (wp->nopropmask & eventmask)) X return; X X wp = wp->parent; X } X} X X X/* X * Try to deliver a exposure event to the clients which have selected for it. X * This does not send exposure events for unmapped or input-only windows. X * Exposure events do not propagate upwards. X */ Xvoid XGsDeliverExposureEvent(wp, x, y, width, height) X GR_WINDOW *wp; /* window being exposed */ X GR_COORD x; /* x position of cursor */ X GR_COORD y; /* y position of cursor */ X GR_SIZE width; /* width of exposure */ X GR_SIZE height; /* height of exposure */ X{ X GR_EVENT_EXPOSURE *ep; /* exposure event */ X GR_EVENT_CLIENT *ecp; /* current event client */ X X if (wp->unmapcount || !wp->output) X return; X X for (ecp = wp->eventclients; ecp; ecp = ecp->next) { X if ((ecp->eventmask & GR_EVENT_MASK_EXPOSURE) == 0) X continue; X X ep = (GR_EVENT_EXPOSURE *) GsAllocEvent(ecp->client); X if (ep == NULL) X continue; X X ep->type = GR_EVENT_TYPE_EXPOSURE; X ep->wid = wp->id; X ep->x = x; X ep->y = y; X ep->width = width; X ep->height = height; X } X} X X X/* X * Try to deliver a general event such as focus in, focus out, mouse enter, X * or mouse exit to the clients which have selected for it. These events X * only have the window id as data, and do not propagate upwards. X */ Xvoid XGsDeliverGeneralEvent(wp, type) X GR_WINDOW *wp; /* window to give event to */ X GR_EVENT_TYPE type; /* event type */ X{ X GR_EVENT_GENERAL *gp; /* general event */ X GR_EVENT_CLIENT *ecp; /* current event client */ X GR_EVENT_MASK eventmask; /* event mask */ X X eventmask = GR_EVENTMASK(type); X if (eventmask == 0) X return; X X for (ecp = wp->eventclients; ecp; ecp = ecp->next) { X if ((ecp->eventmask & eventmask) == 0) X continue; X X gp = (GR_EVENT_GENERAL *) GsAllocEvent(ecp->client); X if (gp == NULL) X continue; X X gp->type = type; X gp->wid = wp->id; X } X} X X X/* X * Search for a matching mouse position event in the specified client's X * event queue, and remove it. This is used to prevent multiple position X * events from being delivered, thus providing a more efficient rubber- X * banding effect than if the mouse motion events were all sent. X */ Xvoid XGsFreePositionEvent(client, wid, subwid) X GR_CLIENT *client; /* client to search */ X GR_WINDOW_ID wid; /* window id to search for */ X GR_WINDOW_ID subwid; /* subwindow id to search for */ X{ X GR_EVENT_LIST *elp; /* current element list */ X GR_EVENT_LIST *prevelp; /* previous element list */ X X prevelp = NULL; X for (elp = client->eventhead; elp; prevelp = elp, elp = elp->next) { X if (elp->event.type != GR_EVENT_TYPE_MOUSE_POSITION) X continue; X if (elp->event.mouse.wid != wid) X continue; X if (elp->event.mouse.subwid != subwid) X continue; X X /* X * Found one, remove it and put it back on the free list. X */ X if (prevelp) X prevelp->next = elp->next; X else X client->eventhead = elp->next; X if (client->eventtail == elp) X client->eventtail = prevelp; X X elp->next = eventfree; X eventfree = elp; X return; X } X} X X/* END CODE */ END_OF_FILE if test 16971 -ne `wc -c <'mini-x/server/serv_event.c'`; then echo shar: \"'mini-x/server/serv_event.c'\" unpacked with wrong size! fi # end of 'mini-x/server/serv_event.c' fi echo shar: End of archive 4 \(of 9\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 9 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0