1 /* The routines in this file provide display support under
2 the Microsoft Windows environment on an IBM-PC or compatible
3 computer.
4
5 Must be compiled with Borland C++ 2.0 or MSC 6.0 or later versions
6
7 It should not be compiled if the WINDOW_MSWIN symbol is not set */
8
9 /* The functions in this module are mostly concerned with the mapping
10 between character cells and client coordinates. */
11
12 #include "estruct.h"
13 #include "elang.h"
14 #include <stdio.h>
15 #include <time.h>
16 #include "eproto.h"
17 #include "edef.h"
18
19 #include "mswin.h"
20
21 #if COLOR
22 /* palette table. It is initialized for the default colors, but can be
23 changed by the spal function */
24 static COLORREF EmacsPalette [16] = {
25 0x00000000, /* black */
26 0x00000080, /* red */
27 0x00008000, /* green */
28 0x00008080, /* yellow */
29 0x00800000, /* blue */
30 0x00800080, /* magenta */
31 0x00808000, /* cyan */
32 0x00C0C0C0, /* grey (light) */
33 0x00808080, /* gray (dark) */
34 0x000000FF, /* light red */
35 0x0000FF00, /* light green */
36 0x0000FFFF, /* light yellow*/
37 0x00FF0000, /* light blue */
38 0x00FF00FF, /* light magenta*/
39 0x00FFFF00, /* light cyan */
40 0x00FFFFFF /* white */
41 };
42 #endif
43
44 static HWND hCaretWnd = 0; /* window where the caret belongs */
45 static int CaretVisible = 0; /* the caret should be visible if not 0 */
46 static int CaretCol, CaretRow; /* caret position */
47 /* Text Metrics values (from the CellMetrics structure) are used as follows:
48
49 -------------------------------- Client area upper boundary
50 | ^
51 | OffsetY
52 | v
53 | ^
54 | HalfLeadingY
55 | v
56 | ---------- ----------
57 |<---->| | | ^
58 OffsetX | cell | cell | | . . .
59 | | 0,0 | 1,0 | SizeY
60 | | | | |
61 | | | | v
62 | ---------- ----------
63 | ^
64 | <- SizeX-> LeadingY = 2 * HalfLeadingY
65 | v
66 | ---------- ----------
67 | | | |
68 | | cell | cell |
69 | | 0,1 | 1,1 |
70 | | | |
71 |
72 | ...
73 |
74 Client area left boundary
75 */
76
77 /* BuildCellMetrics: fills a CellMetrics structure from a font description */
78 /* ================ */
79
BuildCellMetrics(CellMetrics * cm,HFONT hFont)80 void FAR PASCAL BuildCellMetrics (CellMetrics *cm, HFONT hFont)
81 {
82 HDC hDC;
83 TEXTMETRIC Metrics;
84 HANDLE hPrevFont;
85
86 hDC = GetDC (hFrameWnd);
87 hPrevFont = SelectFont (hDC, hFont);
88 GetTextMetrics (hDC, &Metrics);
89 SelectObject (hDC, hPrevFont);
90 ReleaseDC (hFrameWnd, hDC);
91 cm->SizeX = Metrics.tmAveCharWidth;
92 if (cm->SizeX == 0) cm->SizeX = 1; /* ATM gives 0 sometimes !!! */
93 cm->SizeY = Metrics.tmHeight;
94 if (cm->SizeY == 0) cm->SizeY = 1;
95 cm->HalfLeadingY = Metrics.tmExternalLeading / 2;
96 cm->OffsetX = cm->SizeX / 4;
97 if ((cm->OffsetY = (cm->SizeY / 8) - cm->HalfLeadingY) < 0) {
98 cm->OffsetY = 0;
99 /* for a reasonable upper boundary separation, we want
100 (SizeY / 8) <= OffsetY + HalfLeadingY */
101 }
102 cm->LeadingY = 2 * cm->HalfLeadingY;
103 cm->MLHeight = cm->SizeY + cm->LeadingY + (2 * cm->OffsetY) +
104 GetSystemMetrics(SM_CYBORDER);
105 } /* BuildCellMetrics */
106
107 /* InvalidateCells: marks character cells for repaint */
108 /* =============== */
109
InvalidateCells(HWND hWnd,int leftcol,int toprow,int rightcol,int bottomrow)110 void FAR PASCAL InvalidateCells (HWND hWnd, int leftcol, int toprow,
111 int rightcol, int bottomrow)
112 {
113 RECT Rect; /* used for Cell and Client coordinates */
114 RECT ClientRect; /* MDI window client area */
115 POINT MaxBottomRight; /* Cell coordinates of bottom right of MDI
116 window */
117
118 GetClientRect (hWnd, &ClientRect);
119 ClientToCell (hWnd, *(POINT *)&ClientRect.right, &MaxBottomRight);
120
121 Rect.left = leftcol;
122 Rect.top = toprow;
123 CellToClient (hWnd, *(POINT *)&Rect.left, (POINT *)&Rect.left);
124 if (leftcol == 0) Rect.left = 0;
125 else Rect.left -= EmacsCM.SizeX / 2; /* see Rect.right below... */
126 if (toprow == 0) Rect.top = 0;
127
128 Rect.right = rightcol + 1;
129 Rect.bottom = bottomrow + 1;
130 CellToClient (hWnd, *(POINT *)&Rect.right, (POINT *)&Rect.right);
131 if (rightcol + 1 >= MaxBottomRight.x) Rect.right = ClientRect.right;
132 else Rect.right += EmacsCM.SizeX / 2;
133 /* this adjustment is done to avoid left-over pixels caused by
134 characters which display an overhang outside their cells
135 (for instance: w & W in Courier New). The corresponding
136 adjustment is done on Rect.left a few lines above */
137 if (bottomrow + 1 >= MaxBottomRight.y) Rect.bottom = ClientRect.bottom;
138
139 InvalidateRect (hWnd, &Rect, FALSE);
140 /* the background does not need erasing since Paint will
141 completely fill the invalid rectangle */
142 } /* InvalidateCells */
143
144 /* MinimumClientSize: computes the minimum client area size */
145 /* ================= */
146
MinimumClientSize(HWND hWnd,int NCols,int NRows,int * Width,int * Height)147 void FAR PASCAL MinimumClientSize (HWND hWnd, int NCols, int NRows,
148 int *Width, int *Height)
149
150 /* The values pointed by Height and Width are set to the smallest value
151 that allows displaying NRows rows and NCols columns. A NULL pointer
152 disables the computing of the associated value */
153 {
154 if (Height) *Height = (2 * EmacsCM.OffsetY) +
155 (NRows * (EmacsCM.SizeY + EmacsCM.LeadingY));
156 if (Width) *Width = (2 * EmacsCM.OffsetX) + (NCols * EmacsCM.SizeX);
157 } /* MinimumClientSize */
158
159 /* DisplayableRows: returns the number of rows displayable in the client area */
160 /* =============== */
161
DisplayableRows(HWND hWnd,int Height,CellMetrics * cm)162 int FAR PASCAL DisplayableRows (HWND hWnd, int Height, CellMetrics *cm)
163
164 /* Heigh is the hypothetic heigh of the client area. If this parameter
165 is 0, the real client area is measured. If it is negative, the
166 maximal client area (maximized child in a maximized frame) is used.
167 */
168 {
169 RECT Rect;
170 int x;
171
172 if (Height == 0) GetClientRect (hWnd, &Rect);
173 else {
174 if (Height > 0) {
175 Rect.bottom = Height;
176 }
177 else {
178 Rect.bottom = GetSystemMetrics (SM_CYFULLSCREEN) -
179 (GetSystemMetrics (SM_CYMENU) + cm->MLHeight);
180 }
181 }
182 x = (Rect.bottom - (2 * cm->OffsetY)) / (cm->SizeY + cm->LeadingY);
183 if (x < 0) return 0;
184 return x;
185 } /* DisplayableRows */
186
187 /* DisplayableColumns: returns the number of columns displayable in the client area */
188 /* ================== */
189
DisplayableColumns(HWND hWnd,int Width,CellMetrics * cm)190 int FAR PASCAL DisplayableColumns (HWND hWnd, int Width, CellMetrics *cm)
191
192 /* Width is the hypothetic width of the client area. If this parameter
193 is 0, the real client area is measured. If it is negative, the
194 maximal client area (maximized child in a maximized frame) is used.
195 */
196 {
197 RECT Rect;
198 int x;
199
200 if (Width== 0) GetClientRect (hWnd, &Rect);
201 else {
202 if (Width > 0) {
203 Rect.right = Width;
204 }
205 else {
206 Rect.right = GetSystemMetrics (SM_CXFULLSCREEN);
207 }
208 }
209 x = (Rect.right - (2 * cm->OffsetX)) / cm->SizeX;
210 if (x < 0) return 0;
211 return x;
212 } /* DisplayableColumns */
213
214 /* UpdateEmacsCaretPos: position the caret according to CaretCol/CaretRow */
215 /* =================== */
216
UpdateEmacsCaretPos(void)217 static void PASCAL UpdateEmacsCaretPos (void)
218 {
219 POINT pt;
220
221 pt.x = CaretCol;
222 pt.y = CaretRow;
223 CellToClient (hCaretWnd, pt, &pt);
224
225 if (caret_shape == 0 && hCaretWnd != hFrameWnd) {
226 pt.y += EmacsCM.SizeY - (EmacsCM.SizeY / 4);
227 }
228
229 SetCaretPos (pt.x, pt.y + EmacsCM.HalfLeadingY);
230 } /* UpdateEmacsCaretPos */
231
232 /* EmacsCaret: Creates or destroys the caret */
233 /* ========== */
234
EmacsCaret(BOOL Show)235 void FAR PASCAL EmacsCaret (BOOL Show)
236
237 /* the Show parameter is TRUE if the caret should be created and FALSE
238 if it should be destroyed */
239 {
240 short xsize, ysize;
241
242 if (Show) {
243 if (hCaretWnd == 0) return;
244 if (hFrameWnd == GetActiveWindow ()) {
245 if (!IsWindow (hCaretWnd)) {
246 /* this may happen in some transient cases when closing
247 down a screen */
248 hCaretWnd = 0;
249 return;
250 }
251
252 if (hCaretWnd == hFrameWnd) {
253 xsize = GetSystemMetrics (SM_CXBORDER);
254 ysize = EmacsCM.SizeY;
255 }
256 else {
257 xsize = (caret_shape == 1)? EmacsCM.SizeX/4: EmacsCM.SizeX;
258 ysize = (caret_shape == 0)? EmacsCM.SizeY/4: EmacsCM.SizeY;
259 }
260
261 CreateCaret (hCaretWnd, NULL, xsize, ysize);
262 UpdateEmacsCaretPos();
263 if (CaretVisible && !IsIconic (hCaretWnd))
264 ShowCaret (hCaretWnd);
265 }
266 }
267 else /* destroy the caret */
268 DestroyCaret ();
269
270 } /* EmacsCaret */
271
272 /* MoveEmacsCaret: updates the caret position */
273 /* ============== */
274
MoveEmacsCaret(HWND hWnd,int col,int row)275 void FAR PASCAL MoveEmacsCaret (HWND hWnd, int col, int row)
276 {
277 CaretCol = col;
278 CaretRow = row;
279 if (hWnd != hCaretWnd) {
280 hCaretWnd = hWnd;
281 EmacsCaret (TRUE);
282 }
283 else {
284 hCaretWnd = hWnd;
285 UpdateEmacsCaretPos ();
286 }
287 } /* MoveEmacsCaret */
288
289 /* ShowEmacsCaret: shows or hides the caret used by emacs */
290 /* ============== */
291
ShowEmacsCaret(BOOL Show)292 void FAR PASCAL ShowEmacsCaret (BOOL Show)
293
294 /* this function is used to make the caret visible only when waiting for
295 user input */
296 {
297 if (Show) {
298 if (!CaretVisible) {
299 if (!IsIconic (hCaretWnd)) ShowCaret (hCaretWnd);
300 }
301 ++CaretVisible;
302 }
303 else {
304 --CaretVisible;
305 if (!CaretVisible) {
306 HideCaret (NULL);
307 }
308 }
309 } /* ShowEmacsCaret */
310
311 /* InMessageLine: non-zero if caret currently in the message line */
312 /* ============= */
313
InMessageLine(void)314 BOOL FAR PASCAL InMessageLine (void)
315 {
316 return (hCaretWnd == hFrameWnd);
317 } /* InMessageLine */
318
319 /* CellToClient: converts character cell coordinates into client coordinates */
320 /* ============ */
321
CellToClient(HWND hWnd,POINT Cell,LPPOINT Client)322 void FAR PASCAL CellToClient (HWND hWnd, POINT Cell, LPPOINT Client)
323
324 /* The resulting Client coordinates indicate the upper left pixel one
325 HalfLeadingY above the character cell */
326 {
327 Client->x = (Cell.x * EmacsCM.SizeX) + EmacsCM.OffsetX;
328 if (hWnd == hFrameWnd ) {
329 RECT Rect;
330
331 GetClientRect (hWnd, &Rect);
332 Client->y = (Rect.bottom - EmacsCM.MLHeight) + EmacsCM.OffsetY +
333 GetSystemMetrics (SM_CYBORDER);
334 }
335 else Client->y = (Cell.y * (EmacsCM.SizeY + EmacsCM.LeadingY)) +
336 EmacsCM.OffsetY;
337 } /* CellToClient */
338
339 /* ClientToCell: converts client coordinates into character cell coordinates */
340 /* ============ */
341
ClientToCell(HWND hWnd,POINT Client,LPPOINT Cell)342 void FAR PASCAL ClientToCell (HWND hWnd, POINT Client, LPPOINT Cell)
343
344 /* The area associated with a Cell is the character cell itself, plus
345 the HalfLeadingY-high areas above and under the cell */
346 {
347 int MaxCol, MaxRow;
348
349 if (hWnd == hFrameWnd) { /* message line case */
350 MaxCol = MLSIZE - 1;
351 MaxRow = 0;
352 }
353 else { /* screen case */
354 register SCREEN *sp;
355
356 sp = (SCREEN*)GetWindowLong (hWnd, GWL_SCRPTR);
357 MaxCol = sp->s_ncol - 1;
358 MaxRow = sp->s_nrow - 1;
359 }
360 if ((Cell->x = (Client.x - EmacsCM.OffsetX) /
361 EmacsCM.SizeX) < 0) Cell->x = 0;
362 else Cell->x = min (Cell->x, MaxCol);
363 if ((Cell->y = (Client.y - EmacsCM.OffsetY) /
364 (EmacsCM.SizeY + EmacsCM.LeadingY)) < 0) Cell->y = 0;
365 else Cell->y = min (Cell->y, MaxRow);
366 } /* ClientToCell */
367
368 /* GetMinMaxInfo: processes the WM_GETMINMAXINFO message for a screen */
369 /* ============= */
370
GetMinMaxInfo(HWND hWnd,LPPOINT rgpt)371 void FAR PASCAL GetMinMaxInfo (HWND hWnd, LPPOINT rgpt)
372 {
373 if (InternalRequest) return; /* none of our business */
374
375 if (notquiescent) {
376 /* forbid all size changes */
377 RECT Rect;
378
379 GetWindowRect (hWnd, &Rect);
380 rgpt[1].x = Rect.right - Rect.left;
381 rgpt[1].y = Rect.bottom - Rect.top;
382 rgpt[2] = *(POINT*)&Rect.left;
383 rgpt[3] = rgpt[1];
384 rgpt[4] = rgpt[1];
385 }
386 else { /* compute minimum tracking size */
387 int X, Y;
388
389 /* minimum displayed text width = 3 */
390 /* minimum displayed text height = 10 */
391 MinimumClientSize (hWnd, term.t_margin, 2, &X, &Y);
392 rgpt[3].x = X + (2 * GetSystemMetrics (SM_CXFRAME)) +
393 GetSystemMetrics (SM_CXVSCROLL);
394 rgpt[3].y = Y + GetSystemMetrics (SM_CYCAPTION) +
395 (2 * GetSystemMetrics (SM_CYFRAME)) +
396 GetSystemMetrics (SM_CYHSCROLL);
397 }
398 } /* GetMinMaxInfo */
399
400 /* ScrReSize: processes the WM_SIZE message */
401 /* ========= */
402
ScrReSize(HWND hWnd,UINT wParam,WORD cx,WORD cy)403 BOOL FAR PASCAL ScrReSize (HWND hWnd, UINT wParam, WORD cx, WORD cy)
404
405 /* returns TRUE only if real resizing performed */
406 {
407 BOOL ChgWidth, ChgHeight;
408
409 if ((wParam != SIZENORMAL) && (wParam != SIZEFULLSCREEN)) {
410 return FALSE;
411 }
412 ChgWidth = (cx != GetWindowWord (hWnd, GWW_SCRCX));
413 ChgHeight = (cy != GetWindowWord (hWnd, GWW_SCRCY));
414 if (!ChgWidth && !ChgHeight) return FALSE;
415
416 SetWindowWord (hWnd, GWW_SCRCX, cx);
417 SetWindowWord (hWnd, GWW_SCRCY, cy);
418 if (!InternalRequest) {
419 SCREEN *TopScreen;
420
421 InternalRequest = TRUE;
422 TopScreen = first_screen;
423 select_screen ((SCREEN *)GetWindowLong (hWnd, GWL_SCRPTR), FALSE);
424 if (ChgWidth) {
425 newwidth (TRUE, DisplayableColumns (hWnd, cx, &EmacsCM));
426 }
427 if (ChgHeight) {
428 newsize (TRUE, DisplayableRows (hWnd, cy, &EmacsCM));
429 }
430 select_screen (TopScreen, FALSE);
431 update (FALSE);
432 InternalRequest = FALSE;
433 }
434 return TRUE;
435 } /* ScrReSize */
436
437 /* ScrPaint: processes WM_PAINT messages for emacs screens */
438 /* ======== */
439
ScrPaint(HWND hWnd)440 void FAR PASCAL ScrPaint (HWND hWnd)
441 {
442 SCREEN *sp;
443 PAINTSTRUCT ps;
444 HANDLE hPrevFont;
445 RECT Rect;
446 int Row, BottomRow;
447 int Col;
448 int Length;
449
450 /* note that if the WM_PAINT is not passed through the message loop
451 (as would hapen with use of UpdateWindow), it is possible to
452 attempt repainting while defferupdate is TRUE which means update
453 has been deffered */
454
455 BeginPaint (hWnd, &ps);
456 sp = (SCREEN*)GetWindowLong (hWnd, GWL_SCRPTR);
457
458 /*-calculate the row/col loop control variables and normalize the
459 coordinates of the first line's rectangle into Rect */
460 CopyRect (&Rect, &ps.rcPaint);
461 ClientToCell (hWnd, *(POINT *)&Rect.left, (POINT *)&Rect.left);
462 Col = Rect.left;
463 Row = Rect.top;
464 --Rect.right; /* in rectangle conventions, */
465 --Rect.bottom; /* the lower/right border is excluded */
466 ClientToCell (hWnd, *(POINT *)&Rect.right, (POINT *)&Rect.right);
467 ++Rect.right;
468 Length = Rect.right - Col;
469 BottomRow = Rect.bottom;
470 Rect.bottom = Rect.top + 1;
471 CellToClient (hWnd, *(POINT *)&Rect.left, (POINT *)&Rect.left);
472 CellToClient (hWnd, *(POINT *)&Rect.right, (POINT *)&Rect.right);
473 /* Rect now contains a bounding rectangle for the 1st row. This will
474 be used to paint the row's background and will be moved down one
475 row's height at each iteration of the painting loop */
476
477 /*-loop from top to bottom, writing one line at a time */
478 hPrevFont = SelectFont (ps.hdc, hEmacsFont);
479 do {
480 VIDEO *vp;
481
482 vp = sp->s_physical[Row];
483 if (!(vp->v_flag & VFNEW)) { /* valid contents */
484 COLORREF FColor, BColor;
485 POINT RevPt;
486 int i;
487 RECT BoundingRect; /* clipping rectangle */
488 int Boundary[4]; /* horizontal paint boundaries:
489 [0] to [1] is painted in normal video,
490 [1] to [2] is painted in reverse video,
491 [2] to [3] is painted in normal video */
492
493 CopyRect (&BoundingRect, &ps.rcPaint);
494 if (Row > 0) BoundingRect.top = Rect.top;
495 if (Row < BottomRow) BoundingRect.bottom = Rect.bottom;
496
497 Boundary[0] = BoundingRect.left;
498 Boundary[3] = BoundingRect.right;
499 if (vp->v_right) { /* there is a reverse video area */
500 if (vp->v_left <= 0) {
501 /* special case: flush to the border */
502 Boundary[1] = 0;
503 }
504 else {
505 RevPt.y = 0;
506 RevPt.x = vp->v_left;
507 CellToClient (hWnd, RevPt, &RevPt);
508 Boundary[1] = max(BoundingRect.left,RevPt.x);
509 }
510 RevPt.y = 0;
511 RevPt.x = vp->v_right;
512 CellToClient (hWnd, RevPt, &RevPt);
513 Boundary[2] = min(BoundingRect.right,RevPt.x);
514 }
515 else { /* only normal video */
516 Boundary[1] = Boundary [0];
517 Boundary[2] = Boundary [0];
518 }
519
520 /*-Paint the row in up to three parts, between the computed
521 boundaries (reverse video is applied between [1] and [2] */
522 for (i = 0; i < 3; i++) if (Boundary[i] < Boundary [i+1]) {
523 BoundingRect.left = Boundary[i];
524 BoundingRect.right = Boundary[i+1];
525 #if COLOR
526 if (ColorDisplay) {
527 FColor = EmacsPalette[i == 1 ?
528 vp->v_bcolor : vp->v_fcolor];
529 BColor = EmacsPalette[i == 1 ?
530 vp->v_fcolor : vp->v_bcolor];
531 }
532 else { /* monochrome display */
533 #else
534 {
535 #endif
536 if (i == 1) { /* "reverse" video */
537 FColor = GetSysColor (COLOR_HIGHLIGHTTEXT);
538 BColor = GetSysColor (COLOR_HIGHLIGHT);
539 }
540 else {
541 FColor = GetSysColor (COLOR_WINDOWTEXT);
542 BColor = GetSysColor (COLOR_WINDOW);
543 }
544 }
545 SetBkColor (ps.hdc, BColor);
546 SetTextColor (ps.hdc, FColor);
547 ExtTextOut (ps.hdc,
548 Rect.left, Rect.top + EmacsCM.HalfLeadingY,
549 ETO_OPAQUE | ETO_CLIPPED, &BoundingRect,
550 &vp->v_text[Col],
551 Length, NULL);
552 }
553 }
554 Rect.top = Rect.bottom;
555 Rect.bottom += EmacsCM.SizeY + EmacsCM.LeadingY;
556 } while (++Row <= BottomRow);
557
558 SelectObject (ps.hdc, hPrevFont);
559 EndScrPaint:
560 EndPaint (hWnd, &ps);
561 } /* ScrPaint */
562
563 /* MLPaint: processes WM_PAINT messages for the Message Line */
564 /* ======= */
565
566 void FAR PASCAL MLPaint (void)
567 {
568 PAINTSTRUCT ps;
569 HANDLE hPrev, hPen;
570 RECT Rect;
571 POINT Client;
572
573 BeginPaint (hFrameWnd, &ps);
574
575 /*-draw the text portion targetted for repaint */
576 hPrev = SelectFont (ps.hdc, hEmacsFont);
577 ClientToCell (hFrameWnd, *(POINT*)&ps.rcPaint.left, (POINT*)&Rect.left);
578 ClientToCell (hFrameWnd, *(POINT*)&ps.rcPaint.right, (POINT*)&Rect.right);
579 CellToClient (hFrameWnd, *(POINT*)&Rect.left, &Client);
580 ExtTextOut (ps.hdc,
581 Client.x, Client.y + EmacsCM.HalfLeadingY,
582 ETO_OPAQUE, &ps.rcPaint,
583 &MLBuf[Rect.left],
584 Rect.right - Rect.left + 1, NULL);
585 SelectObject (ps.hdc, hPrev);
586
587 /*-draw the separation line at top of message line */
588 hPen = CreatePen (PS_SOLID, GetSystemMetrics (SM_CYBORDER), RGB(0,0,0));
589 hPrev = SelectObject (ps.hdc, hPen);
590 GetClientRect (hFrameWnd, &Rect);
591 Rect.top = Rect.bottom - EmacsCM.MLHeight;
592 #if WINDOW_MSWIN32
593 MoveToEx (ps.hdc, 0, Rect.top, NULL);
594 #else
595 MoveTo (ps.hdc, 0, Rect.top);
596 #endif
597 LineTo (ps.hdc, Rect.right, Rect.top);
598 SelectObject (ps.hdc, hPrev);
599 DeleteObject (hPen);
600
601 EndPaint (hFrameWnd, &ps);
602 } /* MLPaint */
603
604 /* spal: set palette from $palette string */
605 /* ==== */
606
607 PASCAL spal (char *pstr)
608 {
609 #if COLOR
610 int pal; /* current palette position */
611
612 for (pal = 0; pal < 16; pal++) {
613 DWORD clr; /* current color value */
614 int i;
615 unsigned char n;
616
617 if (*pstr== 0) break;
618 clr = 0;
619 for (i = 0; i < 3; i++) if (*pstr) {
620 n = *pstr++ - '0';
621 if (n >= 8) n = 255;
622 else n *= 32;
623 clr |= (DWORD)n << (i * 8);
624 }
625 EmacsPalette[pal] = clr;
626 }
627 #endif
628 return 0;
629 } /* spal */
630