2
* Windowing code for Win32 API (aka Windows NT)
3
* Jonathan Shekter Aug 94
4
* Updates for COW version, Aug 1995
6
* Lots of stuff, Aug 1996
8
#include "copyright2.h"
12
#define NO_BOOLEAN //So defs.h doesn't screw us over
23
#include "teams.bitmap"
24
#include "mapcursor.bitmap"
25
#include "localcursor.bitmap"
30
#pragma warn -par //Turon off "parameter never used..." warning
62
#define RaceDefaultOffset (C_ROM - RED)
65
#define WIN_EDGE 1 //Width or window border edge
74
#define MoveTo(dc, x, y) MoveToEx(dc, x, y, NULL);
76
// Custom window messages, used for communicating between threads
77
#define WM_TERMINATE_WAIT WM_USER
78
#define WM_CROSS_THREAD_DESTROY (WM_USER+1)
81
#define MAX_SCROLLWINDOW_LINES 100
83
#define MAX_SCROLLWINDOW_LINES 300
85
//The max # lines a scrollwindow will have
87
#define EVENT_Q_SIZE 15
88
//The number of events our custom queue will hold
101
struct stringList *next;
104
typedef struct tagWindow
110
short UsingCreatedCursor;
113
struct Icon *TileIcon;
115
struct menuItem *items;
116
struct stringList *strings;
121
W_Callback HandleKeydown;
122
W_Callback HandleKeyup;
123
W_Callback HandleButton;
124
W_Callback HandleExpose;
128
static Window myroot;
131
register Window *win;\
134
win = (Window *)window
136
#define FNHEADER_VOID\
137
register Window *win;\
140
win = (Window *)window
142
/******************************* Function prototypes *********************/
143
void W_Cleanup(void );
145
LRESULT PASCAL NetrekWndProc(HWND,UINT,WPARAM,LPARAM);
146
unsigned char *X11toCursor(unsigned char *bits, int width, int height);
147
void RedrawMenu(Window *win, HDC hdc);
148
void RedrawScrolling(Window *win, HDC hdc);
149
void ChangeMenuItem(Window *win, int n, char *str, int len, W_Color color);
150
void AddToScrolling(Window *win, W_Color color, char *str, int len);
151
void DrawBorder(Window *win, HDC hdc);
152
unsigned char *X11toDIB(unsigned char *bits, int width, int height);
153
unsigned char *X11toDIBAndMirror(unsigned char *bits, int width, int height,
154
int outwidth, int outheight);
155
int checkGeometry(char *name, int *x, int *y, int *width, int *height);
156
void checkParent(char *name, W_Window *parent);
157
int checkMapped(char *name);
160
inline void ResetSysColors(void);
161
inline void SetTrekSysColors(void);
163
/******************************* Globals ****************************/
164
extern HINSTANCE MyInstance;
165
char ClassName[] = "NetrekWindow";
166
char FontFileName[] = "\\ntfonts2.fon";
167
extern int DefaultsLoaded;
170
#ifdef SUPPORT_WIN32S
171
extern W_Window console;
175
W_Font W_BigFont, W_RegularFont;
176
W_Font W_HighlightFont, W_UnderlineFont;
177
W_Color W_White=WHITE, W_Black=BLACK, W_Red=RED, W_Green=GREEN;
178
W_Color W_Yellow=YELLOW, W_Cyan=CYAN, W_Grey=GREY;
180
W_Color W_Ind = C_IND, W_Fed = C_FED, W_Rom = C_ROM, W_Kli = C_KLI, W_Ori = C_ORI;
183
int W_Textwidth=6, W_Textheight=10;
186
const int SysColorNames[] = { COLOR_BTNFACE, COLOR_BTNTEXT, COLOR_3DFACE,
187
COLOR_3DDKSHADOW, COLOR_3DHILIGHT };
188
DWORD TrekSysColors[] = { 0, 0xffffff, 0, 0xc0c0c0, 0x808080 };
189
DWORD SysColors[sizeof(TrekSysColors)];
191
HDC GlobalMemDC, GlobalMemDC2;
192
HBITMAP GlobalOldMemDCBitmap, GlobalOldMemDC2Bitmap;
193
HCURSOR TrekCursor, WarnCursor;
202
colortable[COLORS] = {
203
{ RGB(0xff, 0xff, 0xff), 0, 0, 0}, //White
204
{ RGB(0x00, 0x00, 0x00), 0, 0, 0}, //Black
205
{ RGB(0xff, 0x5f, 0x5f), 0, 0, 0}, //Red
206
{ RGB(0x5f, 0xff, 0x5f), 0, 0, 0}, //Green
207
{ RGB(0xff, 0xff, 0x5f), 0, 0, 0}, //Yellow
208
{ RGB(0x5f, 0xff, 0xff), 0, 0, 0}, //Cyan
209
{ RGB(0xa0, 0xa0, 0xa0), 0, 0, 0} //Light grey
212
{ RGB(0xff, 0x5f, 0x5f), 0, 0, 0}, //Rom
213
{ RGB(0x5f, 0xff, 0x5f), 0, 0, 0}, //Kli
214
{ RGB(0xff, 0xff, 0x5f), 0, 0, 0}, //Fed
215
{ RGB(0x5f, 0xff, 0xff), 0, 0, 0}, //Ori
216
{ RGB(0xa0, 0xa0, 0xa0), 0, 0, 0} //Ind
219
// Used when we're in fixed-16 color mode - color values altered so that the color
220
// mapper picks the proper color. These are "intense" versions of the standard colors
221
altcolortable[COLORS] = {
222
{ RGB(0xff, 0xff, 0xff), 0, 0, 0}, //White
223
{ RGB(0x00, 0x00, 0x00), 0, 0, 0}, //Black
224
{ RGB(0xff, 0x00, 0x00), 0, 0, 0}, //Red
225
{ RGB(0x00, 0xff, 0x00), 0, 0, 0}, //Green
226
{ RGB(0xff, 0xff, 0x00), 0, 0, 0}, //Yellow
227
{ RGB(0x00, 0xff, 0xff), 0, 0, 0}, //Cyan
228
{ RGB(0xa0, 0xa0, 0xa0), 0, 0, 0} //Light grey
231
{ RGB(0xff, 0x00, 0x00), 0, 0, 0}, //Rom
232
{ RGB(0x00, 0xff, 0x00), 0, 0, 0}, //Kli
233
{ RGB(0xff, 0xff, 0x00), 0, 0, 0}, //Fed
234
{ RGB(0x00, 0xff, 0xff), 0, 0, 0}, //Ori
235
{ RGB(0xa0, 0xa0, 0xa0), 0, 0, 0} //Ind
239
char *colornames[COLORS] = {
257
HPALETTE NetrekPalette = 0;
259
//A structure that the W_Icon type (really a bitmap, not an icon) points to
262
HWND hwnd; //The window this is going into
263
HBITMAP bm; //The Windows bitmap it has been stored in
264
int x,y; //The source position in this bitmap
265
int width, height; //guess...
266
RECT *ClipRectAddr; //Address of the window clip region
269
#ifndef SCALE_BITMAPS
270
#define BIGBITMAP_WIDTH 240
271
#define BIGBITMAP_HEIGHT 240
273
static int BIGBITMAP_WIDTH = 240;
274
static int BIGBITMAP_HEIGHT = 240;
280
struct BitmapList *next; //Put these in a LL for later de-allocation
283
struct BitmapList *CurrentBitmap = NULL;
287
//Table that we will build use for virtual key code conversion. We can't
288
//just let Windows do it as we want to proces strange things like
289
// ^@ or ^# which the standard windows TranslateMessage() / ToAscii()
290
//will not do. So, we process VK codes instead, which means we have
291
//to manually map the SHIFT key. We create this mapping by asking for
292
// the VK + shift state for each ascii char during init.
294
//Mapping tables for VK codes to ASCII. We can't just let windows do
295
//it as we want strange combinations like ^@, so we build these maps
298
char VKShiftMap[256];
301
void W_Initialize(char *display)
309
static int InitDone = 0;
318
printf("Initializing windowing system\n");
322
wc.style = CS_NOCLOSE | CS_HREDRAW | CS_VREDRAW; //Don't allow them to close windows
323
wc.lpfnWndProc = NetrekWndProc;
325
wc.cbWndExtra = sizeof(Window *); //Store Window * in extra space
326
wc.hInstance = MyInstance;
327
wc.hIcon = LoadIcon(MyInstance, "main");
328
wc.hCursor = NULL; //We're handling our own cursors
329
wc.hbrBackground = NULL;
330
wc.lpszMenuName = NULL;
331
wc.lpszClassName = ClassName;
335
//Load our cursors - the ones we use from a resource file, anyway
336
TrekCursor = LoadCursor(MyInstance, "trek");
337
WarnCursor = LoadCursor(MyInstance, "warn");
339
//Create the fonts that we need. The fonts are actually in our resource file
340
strcpy(FileName, GetExeDir());
341
strcat(FileName, FontFileName);
342
AddFontResource(FileName);
344
memset(&lf, 0, sizeof(LOGFONT));
345
strcpy(lf.lfFaceName, "Netrek");
348
lf.lfHeight = intDefault("fontsize",10);
349
lf.lfWeight = FW_REGULAR;
350
W_RegularFont = (W_Font) CreateFontIndirect(&lf);
352
lf.lfWeight = FW_BOLD;
353
strcpy(lf.lfFaceName, "Netrek");
354
W_HighlightFont = (W_Font) CreateFontIndirect(&lf);
356
lf.lfWeight = FW_REGULAR;
357
lf.lfUnderline = TRUE;
358
strcpy(lf.lfFaceName, "Netrek");
359
W_UnderlineFont = (W_Font) CreateFontIndirect(&lf);
361
//Use arial for the BigFont
362
lf.lfUnderline = FALSE;
363
lf.lfWeight = FW_MEDIUM;
364
strcpy(lf.lfFaceName,"Arial");
365
lf.lfHeight = 52; // 52
367
W_BigFont = (W_Font) CreateFontIndirect(&lf);
369
//Set up or memory DCs. We need to get the default bitmap and store it,
370
//for later use. The only way we can do this is to select another bitmap
371
//into it... So we'll create a junk one, then delete it.
372
GlobalMemDC = CreateCompatibleDC(NULL);
373
GlobalMemDC2 = CreateCompatibleDC(NULL);
374
junk = CreateBitmap(1,1,1,1,NULL);
375
GlobalOldMemDCBitmap = (HBITMAP) SelectObject(GlobalMemDC, junk);
376
SelectObject(GlobalMemDC, GlobalOldMemDCBitmap);
377
GlobalOldMemDC2Bitmap = (HBITMAP) SelectObject(GlobalMemDC2, junk);
378
SelectObject(GlobalMemDC2, GlobalOldMemDC2Bitmap);
382
//Find out just how big the font is
385
SelectObject(GlobalMemDC,W_HighlightFont); // Should be the biggest
386
if (GetTextMetrics(GlobalMemDC,&ftm))
388
W_Textwidth = ftm.tmAveCharWidth;
389
W_Textheight = ftm.tmHeight;
393
//Create Virtual Key mapping table
394
memset(VKMap, 0, sizeof(VKMap));
395
memset(VKShiftMap, 0, sizeof(VKShiftMap));
396
for (i=0; i<128; i++)
398
SHORT res = VkKeyScan((TCHAR) i);
400
/* Converted SHR's to TESTs, faster on x86 -SAC */
401
if (!(res & 0xff00)) //!highbyte == no shift,ctrl,alt
403
else if (res & 0x100) //Bit 1 of high byte = shift key
404
VKShiftMap[res & 0xff] = i;
406
VKMap[VK_ESCAPE] = 27; // 27 is mapped as Ctrl-[ by Windows
407
VKMap[VK_TAB] = 'i'+96; // Make it look like '^i' so macroKey: TAB will work
408
VKShiftMap[VK_SPACE] =' '; // Map shift+space -> space
409
VKShiftMap[VK_RETURN] ='\r'; // Map shift+return -> return
410
VKShiftMap[VK_ESCAPE] =27; // Map shift+escape-> escape
412
MainThreadID = GetCurrentThreadId(); // Save main thread ID so we can tell
413
// which thread we're in later
415
// Get the current system colors
416
for (i=0; i<sizeof(SysColorNames); i++)
418
SysColors[i] = GetSysColor(SysColorNames[i]);
425
//Does all the resource de-allocation needed
426
//The rest of the silly code doesn't play nice and call DestroyIcon(), etc,
427
//so we have to track resource usage ourself.
431
struct BitmapList *tmp, *p = CurrentBitmap;
434
// Reset the system colors to something recognizable
437
//Get rid of the color pens, etc.
438
for (i=0; i<COLORS; i++)
440
DeleteObject(colortable[i].brush);
441
DeleteObject(colortable[i].pen);
442
DeleteObject(colortable[i].dashedpen);
445
//Delete our two loaded (and shared, and hence not deleted when the window is
447
DestroyCursor(TrekCursor);
448
DestroyCursor(WarnCursor);
451
DeleteObject((HFONT)W_RegularFont);
452
DeleteObject((HFONT)W_HighlightFont);
453
DeleteObject((HFONT)W_UnderlineFont);
454
DeleteObject((HFONT)W_BigFont);
456
strcpy(FileName, GetExeDir());
457
strcat(FileName, FontFileName);
458
RemoveFontResource(FileName);
460
//Select the original bitmaps back and delete our memory DCs
461
SelectObject(GlobalMemDC, GlobalOldMemDCBitmap);
462
DeleteDC(GlobalMemDC);
463
SelectObject(GlobalMemDC2, GlobalOldMemDC2Bitmap);
464
DeleteDC(GlobalMemDC2);
466
//Destory our custom palette
468
DeleteObject(NetrekPalette);
470
//Remove the bitmap structures we've created, by traversing the linked list
482
* Figure out what kind of display we have, for color mapping
483
* There are basically three possible situations:
484
* 1) A fixed 16 color display (use alternate colors so they map well)
485
* 2) A paletted 8-bit display (create a custom palette and use it)
486
* 3) A 16 (15?) or 24 bit true-color display (no problem...)
487
* We also let the use force a selection on the above.
490
#define hexdig(a) ( ((a)>='a' && (a)<='f') ? ((a)-'a'+10) : \
491
( ((a)>='A' && (a)<='F') ? ((a)-'A'+10) : ((a)-'0') ) )
492
#define hexbyte(a) ( hexdig(*(a))*16 + hexdig(*((a)+1)) )
503
dtype=intDefault("forceDisplay", 0);
506
if (booleanDefault("forceMono", 0))
510
//Look at display hardware and make a choice
511
hdc = GetDC(HWND_DESKTOP);
513
i=GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
515
printf("Bits per pixel detected: %d\n", i);
518
if ( (i<=4) || ((i<15) && !(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)) )
520
else if ( (i<15) && (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) )
525
ReleaseDC(HWND_DESKTOP, hdc);
529
if (dtype == 1) // need extra bright clrs on 4 plane display
530
memcpy(colortable, altcolortable, sizeof(colortable));
532
//Modify colors from netrekrc file directives
533
for (i=0; i<COLORS; i++)
536
sprintf(buf, "color.%s", colornames[i]); //Check netrekrc file
537
def = getdefault(buf);
539
if (!def && i>=COLORS-RaceDefaultOffset) // For race colors we use default color
540
{ // color for that race if not set, i.e.
541
sprintf(buf, "color.%s", colornames[i-RaceDefaultOffset]);
542
def = getdefault(buf); // if "color.rom" is not set, "color.red"
546
if (def[0] == '#') //Explicit RGB color
548
colortable[i].rgb = RGB(hexbyte(def+1), hexbyte(def+3), hexbyte(def+5));
552
for (j=0; j<XCLRS; j++) //Else assume color name
553
if (!stricmp(def, xclrs[j].name))
556
colortable[i].rgb = RGB(xclrs[j].r, xclrs[j].g, xclrs[j].b);
558
fprintf(stderr, "Color '%s' unknown\n", def);
566
printf("16 color display detected.\n");
571
//Paletted display. Create a custom palette, and set the RGB indices
572
//in the colortable to palette indices instead of explicit colors
574
char space[sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * (COLORS)];
575
LOGPALETTE *pal = (LOGPALETTE *) space;
577
pal->palVersion = 0x300; //Windows version >=3.0 palette
578
pal->palNumEntries = COLORS;
579
for (i=0; i<COLORS; i++)
581
pal->palPalEntry[i].peRed = GetRValue(colortable[i].rgb);
582
pal->palPalEntry[i].peGreen = GetGValue(colortable[i].rgb);
583
pal->palPalEntry[i].peBlue = GetBValue(colortable[i].rgb);
584
pal->palPalEntry[i].peFlags = 0;
585
colortable[i].rgb = PALETTEINDEX(i);
587
NetrekPalette = CreatePalette(pal);
590
printf("Paletted color display detected.\n");
595
//else, everything's okey dokey, we have a true-color display
598
//Create the various pens and brushes for each color
599
for (i=0; i<COLORS; i++)
601
DWORD dashbits[] = { 1, 2 };
602
colortable[i].brush = CreateSolidBrush(colortable[i].rgb);
603
colortable[i].pen = CreatePen(PS_SOLID | PS_INSIDEFRAME, 1, colortable[i].rgb);
604
colortable[i].dashedpen = CreatePen(PS_DOT, 1, colortable[i].rgb);
609
W_Window W_RenameWindow(W_Window window, char *str)
612
SetWindowText(win->hwnd, str);
617
//Internal function - used as the base for all window creation
618
Window *newWindow(char *name, int x, int y, int width, int height,
619
W_Window parent, int border, W_Color color, int type)
621
Window *window,*parentwin=0;
623
char title_buff[100];
625
DWORD SpecialStyle = 0;
627
if ( !(window = (Window *)malloc(sizeof(Window)) ) )
629
printf("Not enough memory to create a new window.");
632
memset(window, 0, sizeof(Window));
634
//Stuff ripped from x11window.c - provides nicer titles when the window
635
// is a wait window or the main window.
636
if (strcmp (name, "netrek") == 0)
643
sprintf (title_buff, "Netrek @ %s", serverName);
645
SpecialStyle = WS_OVERLAPPEDWINDOW; //Make main window sizeable
646
//SpecialStyle |=WS_BORDER;
648
else if (strcmp (name, "wait") == 0)
654
width += GetSystemMetrics( SM_CXFRAME);
655
//Make the wait window show up in the task list
656
SpecialStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
659
else if (strncmp (name, "Meta", 4) == 0)
662
height += GetSystemMetrics( SM_CYFRAME ) + border;
663
//Make the Metaserver window show up in the task list
664
SpecialStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
667
#ifdef SUPPORT_WIN32S
668
else if (strcmp (name, "Console") == 0)
670
SpecialStyle = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
677
//Mask border - 15 pixels max - and make sure it's at least 1, and that it's not black
678
if (border > 15) border = 15;
679
if (!border) border=1;
680
if (color == BLACK) color = WHITE;
682
//Set the various attributes to default states
684
window->border = border;
685
window->BorderColor=color;
686
window->cursor = LoadCursor(NULL, IDC_ARROW);
688
//Check the parent - parent to root (==desktop) if null
693
parentwin = (baseWin ? (Window *)baseWin : &myroot);
694
SpecialStyle |= baseWin ? WS_POPUP | WS_CAPTION : WS_POPUP;
698
parentwin = (Window *)parent;
699
SpecialStyle |= WS_CHILD;
703
//Actually create the window
704
//Hacked to allow negative create locations -SAC
705
window->hwnd = CreateWindow( ClassName,
707
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | SpecialStyle,
708
x + parentwin->border,
709
y + parentwin->border,
712
( (SpecialStyle & WS_CAPTION) ? GetSystemMetrics( SM_CYCAPTION ) : 0),
716
(void *)window); //Pass Window struct * as user param
720
printf("CreateWindow() for %s failed...",name);
724
//Select the custom palette if we're in a paletted mode
725
hdc = GetDC(window->hwnd);
728
SelectPalette(hdc, NetrekPalette, FALSE);
731
ReleaseDC(window->hwnd, hdc);
734
AnyWindow = window->hwnd;
739
W_Window W_MakeWindow(char *name, int x, int y, int width, int height,
740
W_Window parent, int border, W_Color color)
744
//Get the default position, etc.
745
checkGeometry(name, &x, &y, &width, &height);
747
//Get the default parent..
748
checkParent(name, &parent);
750
if ( !(newwin = newWindow(name, x, y, width, height, parent, border, color, WIN_GRAPH)))
753
//Map (show) the window if the user spec'd it
754
if (checkMapped(name))
755
W_MapWindow((W_Window)newwin);
757
return (W_Window) newwin;
761
//Make a window that contains fixed-spaced text, where columns must be
762
//aligned, etc. The x and y passed are in character cells, not pixels.
763
W_Window W_MakeTextWindow(char *name, int x, int y, int width, int height,
764
W_Window parent, int border)
768
//Get the default position, etc.
769
checkGeometry(name, &x, &y, &width, &height);
771
//Get the default parent..
772
checkParent(name, &parent);
774
if (!(newwin = newWindow( name, x, y,
775
width * W_Textwidth + WIN_EDGE * 2,
776
MENU_PAD * 2 + height * W_Textheight,
777
parent, border, W_Black, WIN_TEXT)) )
780
//Store the original textheight, width
781
newwin->TextHeight = height;
782
newwin->TextWidth = width;
784
//Map (show) the window if the user spec'd it
785
if (checkMapped(name))
786
W_MapWindow((W_Window)newwin);
788
return (W_Window) newwin;
791
// Make a WIN_SCROLL type window.
792
// We use a scrollbar so we can look through the text, something the X version
793
// didn't have. Nyah, nyah.
794
W_Window W_MakeScrollingWindow(char *name, int x, int y, int width, int height,
795
W_Window parent, int border)
802
//Get the default position, etc.
803
checkGeometry(name, &x, &y, &width, &height);
805
//Get the default parent..
806
checkParent(name, &parent);
808
if (! (newwin = newWindow( name, x, y,
809
width * W_Textwidth + WIN_EDGE * 2 + GetSystemMetrics(SM_CXVSCROLL),
810
height * W_Textheight + MENU_PAD * 2,
811
parent, border, W_White, WIN_SCROLL)) )
814
//Store the original textheight, width
815
newwin->TextHeight = height;
816
newwin->TextWidth = width;
818
//Give it a scroll bar, and set the range (to zero, initially)
819
SetWindowLong(newwin->hwnd, GWL_STYLE, GetWindowLong(newwin->hwnd, GWL_STYLE) | WS_VSCROLL );
820
SetScrollRange(newwin->hwnd, SB_VERT, 0, 0, FALSE);
822
//Map (show) the window if the user spec'd it
823
if (checkMapped(name))
824
W_MapWindow((W_Window)newwin);
826
return (W_Window) newwin;
830
//Make a menu window. This is similar to a text window in that it has a 1x1 mappiing
831
//between coordinates and character cells. Note that the height parameter
832
//specified here indicates the number of items
833
W_Window W_MakeMenu(char *name, int x, int y,int width,int height,W_Window parent,int border)
835
struct menuItem *items;
841
//Get the default position, etc.
842
checkGeometry(name, &x, &y, &width, &height);
844
//Get the default parent..
845
checkParent(name, &parent);
847
if (! (newwin = newWindow( name, x, y,
848
width * W_Textwidth + WIN_EDGE * 2,
849
height * (W_Textheight + MENU_PAD * 2) + (height - 1) * MENU_BAR,
850
parent, border, W_Black, WIN_MENU)) )
853
if ( !(items=(struct menuItem *) malloc(height*sizeof(struct menuItem))) )
854
fprintf(stderr,"Could not allocate storage for menu window");
856
for (i=0; i<height; i++)
858
items[i].string=NULL;
859
items[i].color=W_White;
861
newwin->items = items;
862
newwin->NumItems = height;
863
newwin->TextHeight = height;
865
//Map (show) the window if the user spec'd it
866
if (checkMapped(name))
867
W_MapWindow((W_Window)newwin);
869
return (W_Window) newwin;
872
void W_ChangeBorder(W_Window window, W_Color color)
877
win->BorderColor = color;
879
hdc = GetDC(win->hwnd); //Turn off boder clipping
882
SelectPalette(hdc, NetrekPalette, FALSE);
885
DrawBorder(win, hdc);
886
ReleaseDC(win->hwnd, hdc);
890
//Displays the window.
891
void W_MapWindow(W_Window window)
895
ShowWindow(win->hwnd, SW_SHOWNORMAL);
896
BringWindowToTop(win->hwnd);
897
if (window==baseWin &&
898
!booleanDefault("netrek.w32caption",1))
899
PostMessage(win->hwnd, WM_SYSKEYDOWN, VK_RETURN, 0);
903
void W_UnmapWindow(W_Window window)
907
ShowWindow(win->hwnd, SW_HIDE);
910
//Returns TRUE if the window is visible, and also not minimized
911
int W_IsMapped(W_Window window)
915
return (IsWindowVisible(win->hwnd) && !IsIconic(win->hwnd));
918
void W_FillArea(W_Window window, int x, int y, int width, int height, int color)
924
border = win->border;
926
//do a rectangle intersection with the clipping rect, inlined for speed
927
x+=border; y+=border;
928
r.left = max(x, border);
929
r.right= min(x+width, win->ClipRect.right);
930
if (r.right < r.left)
931
return; //Horizantal extents do not overlap
932
r.top = max(y, border);
933
r.bottom = min(y+height, win->ClipRect.bottom);
934
if (r.bottom < r.top)
935
return; //Vertical extents do not overlap
937
hdc = GetDC(win->hwnd);
940
SelectPalette(hdc, NetrekPalette, FALSE);
943
FillRect(hdc, &r, colortable[color].brush);
944
ReleaseDC(win->hwnd, hdc);
947
void W_ClearArea(W_Window window, int x, int y, int width, int height)
953
border = win->border;
955
if (win->type == WIN_TEXT)
957
x = x * W_Textwidth + WIN_EDGE;
958
y = y * W_Textheight + MENU_PAD;
959
width *= W_Textwidth;
960
height *= W_Textheight;
963
//do a rectangle intersection with the clipping rect, inlined for speed
964
x+=border; y+=border;
965
r.left = max(x, border);
966
r.right= min(x+width, win->ClipRect.right);
967
if (r.right < r.left)
968
return; //Horizantal extents do not overlap
969
r.top = max(y, border);
970
r.bottom = min(y+height, win->ClipRect.bottom);
971
if (r.bottom < r.top)
972
return; //Vertical extents do not overlap
974
hdc = GetDC(win->hwnd);
977
SelectPalette(hdc, NetrekPalette, FALSE);
980
// FillRect doesn't do the edges (right and bottom) -SAC
981
r.right++; r.bottom++;
982
FillRect(hdc, &r, colortable[W_Black].brush);
983
ReleaseDC(win->hwnd, hdc);
986
//We don't need to cache...
987
void W_CacheClearArea(W_Window window, int x, int y, int width, int height)
989
W_ClearArea(window, x, y, width, height);
992
void W_FlushClearAreaCache(W_Window window)
994
//Hmmm.... Do I really prefer lima beans, or coconuts... I wonder...
998
// Clear multiple areas
999
void W_ClearAreas(W_Window window, int *xs, int *ys, int *widths, int *heights, int num)
1003
register int border,x,y,width,height;
1005
border = win->border;
1007
hdc = GetDC(win->hwnd);
1010
SelectPalette(hdc, NetrekPalette, FALSE);
1011
RealizePalette(hdc);
1020
width = widths[num];
1021
height = heights[num];
1023
if (win->type == WIN_TEXT)
1025
x = x * W_Textwidth + WIN_EDGE;
1026
y = y * W_Textheight + MENU_PAD;
1027
width *= W_Textwidth;
1028
height *= W_Textheight;
1031
//do a rectangle intersection with the clipping rect, inlined for speed
1032
x+=border; y+=border;
1033
r.left = max(x, border);
1034
r.right= min(x+width, win->ClipRect.right);
1035
if (r.right < r.left)
1036
continue; //Horizantal extents do not overlap
1037
r.top = max(y, border);
1038
r.bottom = min(y+height, win->ClipRect.bottom);
1039
if (r.bottom < r.top)
1040
continue; //Vertical extents do not overlap
1042
FillRect(hdc, &r, colortable[W_Black].brush);
1045
ReleaseDC(win->hwnd, hdc);
1050
void W_ClearWindow(W_Window window)
1055
hdc = GetDC(win->hwnd);
1058
SelectPalette(hdc, NetrekPalette, FALSE);
1059
RealizePalette(hdc);
1063
FillRect(hdc, &win->ClipRect, colortable[BLACK].brush);
1066
struct Icon *icon = win->TileIcon;
1070
GetClientRect(win->hwnd, &r);
1072
//Bitmap should be white on window bk color
1073
SetTextColor(hdc, colortable[BLACK].rgb);
1074
SetBkColor(hdc, colortable[WHITE].rgb);
1077
SelectObject(GlobalMemDC, icon->bm);
1079
//Paste the bitmap into the window
1080
for (i=0; i<r.bottom; i+=icon->height)
1081
for (j=0; j<r.right; j+=icon->width)
1083
icon->width, icon->height, GlobalMemDC, 0, 0, SRCCOPY );
1084
DrawBorder(win, hdc);
1087
ReleaseDC(win->hwnd, hdc);
1091
//These globals used for communication between the following three fns
1092
//We implement a custom queue of only those message we are interested in.
1093
//The event (message) processing would really be quite simple, except
1094
//for the fact that many messages in Windows are _sent_, rather than
1095
//retrieved via GetMessage(), so the window proc must be able to post
1096
//events to the queue on its own without calling W_NextEvent().
1097
W_Event EventQueue[EVENT_Q_SIZE];
1098
int EventHead=0, EventTail=0;
1100
//Are there events (messages) in our queue?
1101
//Here is the main message loop of our program. We first a)check
1102
//to see if there is an event in the queue, and then if there isn't b) do
1103
//the PeekMessage() thing, then c) check the queue again
1104
int W_EventsPending()
1108
if ( (GetAsyncKeyState(VK_SHIFT) & ~0x1) && (GetAsyncKeyState(27) & ~0x1))
1109
exit(-1); //Safety device - Shft+ESC = clean termination
1112
if (EventHead != EventTail) //Event already in queue
1115
//Essentially, while there is a message in the application queue
1116
//and we haven't got and "event", continue processing messages
1117
while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
1119
//TranslateMessage(&msg); //Yes, translate keyboard messages,
1120
DispatchMessage(&msg); //dispatch the message to the window proc
1121
if (EventHead != EventTail)
1125
return (0); //Nothing waiting
1128
// Wait for an event to become available; it returns zero if it recieves a
1129
// WM_TERMAINTE_WAIT (defined as WM_USER) message,
1130
// which we use to reset the game (it's issued by another thread)
1131
int W_WaitForEvent()
1135
while (EventHead == EventTail) // Get an event
1138
GetMessage(&msg, NULL, 0, 0);
1139
if (msg.message == WM_TERMINATE_WAIT) // Quit message recieved
1142
//TranslateMessage(&msg); //translate keyboard messages,
1143
DispatchMessage(&msg); //dispatch the message to the window proc
1148
// Force W_WaitForEvent to terminate. Notice we send the message to
1149
// any window, the point is that it will be processed in the main thread.
1150
void W_TerminateWait()
1152
PostMessage(AnyWindow, WM_TERMINATE_WAIT, 0, 0);
1155
//Get the next event (message). Simply copies the event *, and advances the pointer
1156
void W_NextEvent(W_Event *event)
1158
if (EventHead == EventTail) //Make sure there actually is a message!
1161
EventHead = (EventHead + 1) % EVENT_Q_SIZE; //Advance queue pointer
1162
memcpy(event, &EventQueue[EventHead], sizeof(W_Event));
1165
//Return any already queued events
1166
int W_SpNextEvent(W_Event *event)
1168
if (W_EventsQueued())
1177
//The main window proc for all of the game's windows. Strange design, this netrek code...
1178
//But I guess this is really just a dispatcher function - the events are actually
1179
//"processed" in the rest of the code. Also, all these #ifdef's clutter it needlessly...
1181
//Two very useful defines. These capture an event, after it is determined to be
1182
//valid. Doing this AFTER the event (message) is determined valid increases
1183
//the code size, and makes for the macros, but it also greatly speeds up
1184
//processing of the zillion other messages that go through the loop.
1186
#define GET_STRUCT_PTR\
1187
win=(Window *)GetWindowLong(hwnd, 0)
1189
#define STORE_EVENT\
1190
i = (EventTail + 1) % EVENT_Q_SIZE;\
1191
if (i != EventHead)\
1193
if (InSendMessage())\
1194
GetCursorPos(&pos);\
1197
*((DWORD *)&spos) = GetMessagePos();\
1198
pos.x = spos.x; pos.y = spos.y;\
1200
ScreenToClient(hwnd, &pos);\
1201
EventQueue[EventTail].x = pos.x - win->border;\
1202
EventQueue[EventTail].y = pos.y - win->border;\
1203
EventQueue[EventTail].Window=(W_Window) win;\
1204
if ( win->type == WIN_MENU )\
1206
if (EventQueue[EventTail].y % (W_Textheight + MENU_PAD * 2 + MENU_BAR) >=\
1207
W_Textheight + MENU_PAD * 2)\
1209
EventQueue[EventTail].y /= (W_Textheight + MENU_PAD * 2 + MENU_BAR) ;\
1212
//A similar version of the above that gets the mouse pos from LPARAM -
1213
//used in processing mouse messages
1214
#define STORE_EVENT_MOUSE\
1215
i = (EventTail + 1) % EVENT_Q_SIZE;\
1216
if (i != EventHead)\
1218
if (InSendMessage())\
1219
GetCursorPos(&pos);\
1222
*((DWORD *)&spos) = GetMessagePos();\
1223
pos.x = spos.x; pos.y = spos.y;\
1225
ScreenToClient(hwnd, &pos);\
1226
EventQueue[EventTail].x = pos.x - win->border;\
1227
EventQueue[EventTail].y = pos.y - win->border;\
1228
EventQueue[EventTail].Window=(W_Window) win;\
1229
if ( win->type == WIN_MENU )\
1231
if (EventQueue[EventTail].y % (W_Textheight + MENU_PAD * 2 + MENU_BAR) >=\
1232
W_Textheight + MENU_PAD * 2)\
1234
EventQueue[EventTail].y /= (W_Textheight + MENU_PAD * 2 + MENU_BAR) ;\
1237
LRESULT CALLBACK NetrekWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1239
register Window *win;
1247
#if defined(MOTION_MOUSE) || defined(XTRA_MESSAGE_UI)
1248
static POINTS prev_pos;
1249
static HWND LastPressHwnd;
1255
//Store our structure pointer - passed from newWindow() as final CreateWindow() param
1256
SetWindowLong(hwnd, 0, (LONG)(Window *)((CREATESTRUCT *)lParam)->lpCreateParams );
1260
//Create/adjust our clipping rect, which is used to prevent drawing into
1264
win->ClipRect.left = win->ClipRect.top = win->border;
1265
win->ClipRect.right = LOWORD(lParam) - win->border;
1266
win->ClipRect.bottom = HIWORD(lParam) - win->border;
1272
hdc = BeginPaint(hwnd, &ps); //Do the beginpaint/endpaint thing
1273
//so that the invalid rectangle is updated
1276
SelectPalette(hdc, NetrekPalette, FALSE);
1277
RealizePalette(hdc);
1280
i = TRUE; //Store this event
1281
if (win->type == WIN_MENU)
1283
RedrawMenu(win, hdc);
1284
i = FALSE; //Don't store this event
1286
else if (win->type == WIN_SCROLL)
1288
RedrawScrolling(win, hdc);
1289
i = FALSE; //Don't store this event
1292
DrawBorder(win, hdc);
1294
EndPaint(hwnd, &ps); //Update the invalid region, etc.
1298
i = (EventTail + 1) % EVENT_Q_SIZE;
1301
EventQueue[EventTail].type=W_EV_EXPOSE;
1302
EventQueue[EventTail].Window = (W_Window) GetWindowLong(hwnd, 0);
1303
EventQueue[EventTail].x = ps.rcPaint.left ;//- win->border;
1304
EventQueue[EventTail].y = ps.rcPaint.top ;//- win->border;
1305
/* EventQueue[EventTail].width = ps.rcPaint.right - ps.rcPaint.left;
1306
EventQueue[EventTail].height = ps.rcPaint.bottom - ps.rcPaint.top;*/
1310
case WM_LBUTTONDOWN:
1311
BringWindowToTop(hwnd);
1315
LastPressHwnd = hwnd;
1317
#ifdef SHIFTED_MOUSE
1318
if ((wParam & MK_SHIFT) && (wParam & MK_CONTROL))
1319
EventQueue[EventTail].key = W_LBUTTON4;
1320
else if (wParam & MK_SHIFT)
1321
EventQueue[EventTail].key = W_LBUTTON2;
1322
else if (wParam & MK_CONTROL)
1323
EventQueue[EventTail].key = W_LBUTTON3;
1325
EventQueue[EventTail].key = W_LBUTTON;
1327
EventQueue[EventTail].key = W_LBUTTON;
1328
#endif /* SHIFTED_MOUSE */
1331
prev_pos = MAKEPOINTS(lParam);
1333
EventQueue[EventTail].type=W_EV_BUTTON;
1337
case WM_MBUTTONDOWN:
1338
BringWindowToTop(hwnd);
1342
LastPressHwnd = hwnd;
1344
#ifdef SHIFTED_MOUSE
1345
if ((wParam & MK_SHIFT) && (wParam & MK_CONTROL))
1346
EventQueue[EventTail].key = W_MBUTTON4;
1347
else if (wParam & MK_SHIFT)
1348
EventQueue[EventTail].key = W_MBUTTON2;
1349
else if (wParam & MK_CONTROL)
1350
EventQueue[EventTail].key = W_MBUTTON3;
1352
EventQueue[EventTail].key = W_MBUTTON;
1354
EventQueue[EventTail].key = W_MBUTTON;
1355
#endif /* SHIFTED_MOUSE */
1358
prev_pos = MAKEPOINTS(lParam);
1360
EventQueue[EventTail].type=W_EV_BUTTON;
1363
case WM_RBUTTONDOWN:
1364
BringWindowToTop(hwnd);
1368
LastPressHwnd = hwnd;
1370
#ifdef SHIFTED_MOUSE
1371
if ((wParam & MK_SHIFT) && (wParam & MK_CONTROL))
1372
EventQueue[EventTail].key = W_RBUTTON4;
1373
else if (wParam & MK_SHIFT)
1374
EventQueue[EventTail].key = W_RBUTTON2;
1375
else if (wParam & MK_CONTROL)
1376
EventQueue[EventTail].key = W_RBUTTON3;
1378
EventQueue[EventTail].key = W_RBUTTON;
1380
EventQueue[EventTail].key = W_RBUTTON;
1381
#endif /* SHIFTED_MOUSE */
1384
prev_pos = MAKEPOINTS(lParam);
1386
EventQueue[EventTail].type=W_EV_BUTTON;
1389
// Watch for stuff like ALT-ENTER
1391
if (wParam == VK_RETURN)
1397
cx = GetSystemMetrics(SM_CXEDGE);
1399
cx = GetSystemMetrics(SM_CXBORDER);
1400
cy = GetSystemMetrics(SM_CYEDGE);
1402
GetSystemMetrics(SM_CYBORDER);
1404
wl = GetWindowLong(((Window *)baseWin)->hwnd, GWL_STYLE);
1405
GetWindowRect(((Window *)baseWin)->hwnd, &r);
1406
if (wl & WS_CAPTION)
1409
r.left += GetSystemMetrics(SM_CXBORDER);
1410
r.top += GetSystemMetrics(SM_CYBORDER);
1413
r.left -= GetSystemMetrics(SM_CXBORDER);
1414
r.top -= GetSystemMetrics(SM_CYBORDER);
1416
SetWindowLong(((Window *)baseWin)->hwnd, GWL_STYLE, wl);
1417
// Update the window since the height has changed
1418
MoveWindow(((Window *)baseWin)->hwnd, r.left, r.top,
1419
r.right-r.left, r.bottom-r.top, TRUE);
1424
//Keyboard event - also catch the mousebuttons, #ifdef
1426
//Manually map key to ASCII based on shift state
1427
j = ( (GetKeyState(VK_SHIFT) & ~0x1 ) ? VKShiftMap : VKMap)[wParam];
1429
if (!j) //No event if we can't map the key to ASCII
1432
//If we're not supposed to ignore caps lock, xlate keys on Caps Lock
1433
if (GetKeyState(VK_CAPITAL) & 0x1)
1435
printf("Got a capslock!\n");
1437
j = ( islower((char)j) ? toupper((char)j) : tolower((char)j) );
1439
//Modified version of STORE_EVENT... we flip window pointers
1440
//in middle of processing after we get the mouse pos. This
1441
//lets us emulate X-style keyboard focus
1443
i = (EventTail + 1) % EVENT_Q_SIZE;
1446
if (InSendMessage())
1450
*((DWORD *)&spos) = GetMessagePos();
1451
pos.x = spos.x; pos.y = spos.y;
1454
//Change the source window in the middle of all this to the one
1457
hwnd = WindowFromPoint( pos);
1458
if (GetWindowLong(hwnd, GWL_WNDPROC) != (LONG) NetrekWndProc)
1459
return 0; //Mouse is not in one of our windows
1461
if (!hwnd || hwnd == ((Window *)baseWin))
1462
hwnd = ((Window *)w)->hwnd;
1464
LastPressHwnd = hwnd;
1466
ScreenToClient(hwnd, &pos);
1470
EventQueue[EventTail].x = pos.x - win->border;
1471
EventQueue[EventTail].y = pos.y - win->border;
1472
EventQueue[EventTail].Window=(W_Window) win;
1473
if ( win->type == WIN_MENU )
1475
if (EventQueue[EventTail].y % (W_Textheight + MENU_PAD * 2 + MENU_BAR) >=
1476
W_Textheight + MENU_PAD * 2)
1478
EventQueue[EventTail].y /= (W_Textheight + MENU_PAD * 2 + MENU_BAR) ;
1481
EventQueue[EventTail].type=W_EV_KEY;
1484
if (use_control_key && (GetKeyState(VK_CONTROL) & ~0x1) )
1485
EventQueue[EventTail].key = (char) j + 96;
1487
EventQueue[EventTail].key=(char) j;
1489
EventQueue[EventTail].key=(char)j;
1495
SetCursor(win->cursor);
1497
#if defined(MOTION_MOUSE) || defined(XTRA_MESSAGE_UI)
1498
if ((win->type != WIN_GRAPH) || (hwnd != LastPressHwnd))
1499
return(0); // only allow in graphics windows and must be the window last clicked in
1500
// (the latter avoids a bug where Windows sends a mousemove message
1501
// to a window exposed when the one on top is hidden/destroyed)
1503
//Check to see if we are entering a message and should be looking
1504
//to place the message on hold
1505
if (messageon && messHoldThresh)
1509
/* a^2 + b^2 = c^2 - messHoldThresh is c^2.
1510
* Keep a running total of (a^2 + b^2) */
1513
x = prev_pos.x - LOWORD(lParam);
1514
messMouseDelta += x*x;
1515
x = prev_pos.y - HIWORD(lParam);
1516
messMouseDelta += x*x;
1519
prev_pos = MAKEPOINTS(lParam);
1521
if ((messMouseDelta>=messHoldThresh) ||
1522
(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)))
1527
if (! (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) )
1528
return(0); //We don't want to know about it if no mouse buttons are down
1530
//Check to see if the mouse has moved >= user_motion_thresh
1531
thresh = abs (prev_pos.x - LOWORD(lParam)) + abs (prev_pos.y - HIWORD(lParam));
1532
if (thresh < user_motion_thresh)
1535
prev_pos = MAKEPOINTS(lParam);
1537
//Okay, we have an event - store and process further
1539
EventQueue[EventTail].type = W_EV_BUTTON;
1541
#ifdef SHIFTED_MOUSE
1542
//Turn shift+button into a differnt code, and that sort of thing...
1545
if (wParam & MK_CONTROL && wParam & MK_SHIFT)
1547
if (wParam & MK_LBUTTON)
1548
EventQueue[EventTail].key = W_LBUTTON4;
1549
else if (wParam & MK_MBUTTON)
1550
EventQueue[EventTail].key = W_MBUTTON4;
1551
else if (wParam & MK_RBUTTON)
1552
EventQueue[EventTail].key = W_RBUTTON4;
1557
if (wParam & MK_SHIFT)
1559
if (wParam & MK_LBUTTON)
1560
EventQueue[EventTail].key = W_LBUTTON2;
1561
else if (wParam & MK_MBUTTON)
1562
EventQueue[EventTail].key = W_MBUTTON2;
1563
else if (wParam & MK_RBUTTON)
1564
EventQueue[EventTail].key = W_RBUTTON2;
1569
if (wParam & MK_CONTROL)
1571
if (wParam & MK_LBUTTON)
1572
EventQueue[EventTail].key = W_LBUTTON3;
1573
else if (wParam & MK_MBUTTON)
1574
EventQueue[EventTail].key = W_MBUTTON3;
1575
else if (wParam & MK_RBUTTON)
1576
EventQueue[EventTail].key = W_RBUTTON3;
1581
#endif /* SHIFTED_MOUSE */
1583
//Whew! If, after checking for all that, there are no shift keys,
1584
//no controls keys, process this normally
1585
if (wParam & MK_LBUTTON)
1586
EventQueue[EventTail].key = W_LBUTTON;
1587
else if (wParam & MK_MBUTTON)
1588
EventQueue[EventTail].key = W_MBUTTON;
1589
else if (wParam & MK_RBUTTON)
1590
EventQueue[EventTail].key = W_RBUTTON;
1593
#endif /* MOTION_MOUSE */
1598
//And now, for your amusement and edification, some of the more exotic
1599
//mesages handled here for things like our scroll windows,
1600
//background bitmap tiling, and dragging windows by their borders
1602
//Scroll bar moved message - from a scrolling window
1605
i = GetScrollPos(hwnd, SB_VERT);
1606
switch (LOWORD(wParam))
1615
i += win->TextHeight;
1618
i -= win->TextHeight;
1621
case SB_THUMBPOSITION:
1627
SetScrollPos(hwnd, SB_VERT, i, TRUE); //Move scroll
1628
InvalidateRect(hwnd, &win->ClipRect, TRUE); //Redraw text in window
1632
//Trap WM_ERASEBKGRND, to handle windows with tiled backgrounds
1636
GetClientRect(hwnd, &r);
1639
SelectPalette((HDC)wParam, NetrekPalette, FALSE);
1640
RealizePalette((HDC)wParam);
1645
FillRect((HDC)wParam, &r, colortable[BLACK].brush);
1649
//As far as I can tell, the bitmap should be white on window bk color...
1650
SetTextColor((HDC)wParam, colortable[BLACK].rgb);
1651
SetBkColor((HDC)wParam, colortable[WHITE].rgb);
1654
icon = win->TileIcon;
1655
SelectObject(GlobalMemDC, icon->bm);
1657
//Paste the bitmap into the window
1658
for (i=0; i<r.bottom; i+=icon->height)
1659
for (j=0; j<r.right; j+=icon->width)
1660
BitBlt( (HDC)wParam, j, i,
1661
icon->width, icon->height, GlobalMemDC, 0, 0, SRCCOPY );
1666
//Return "in caption" whenever the mouse is on the border, or in client otherwise
1668
i = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
1672
pos.x = LOWORD(lParam); pos.y = HIWORD(lParam);
1673
ScreenToClient(hwnd, &pos);
1674
return ( ( (pos.x < win->border) || (pos.x >= win->ClipRect.right) ||
1675
(pos.y < win->border) || (pos.y >= win->ClipRect.bottom) ) ?
1679
else if (i == HTBORDER)
1684
//This message sent from another thread to indicate a window should be destroyed,
1685
// which only the main thread can do
1686
case WM_CROSS_THREAD_DESTROY:
1687
DestroyWindow((HWND)wParam);
1690
//Delete all of our data, etc, when the window is killed
1691
//DON'T PRINTF() HERE!!! Unless of course you feel like crashing...
1695
if (win->UsingCreatedCursor)
1696
DeleteObject( win->cursor );
1698
//If it is a menu or scroll window, free the menu item data
1699
if ( win->type == WIN_MENU )
1701
for (i=0; i<win->NumItems; i++)
1702
if (win->items[i].string)
1703
free((void *)win->items[i].string);
1704
free((void *)win->items);
1706
else if ( win->type == WIN_SCROLL)
1708
struct stringList *p = win->strings;
1709
struct stringList *tmp;
1713
free((void *)p->string);
1719
//Free the Window structure
1725
if (hwnd==((Window *)baseWin)->hwnd)
1733
//if (baseWin && (((void *)wParam)==((Window *)baseWin)->hwnd))
1734
if (hwnd==((Window *)baseWin)->hwnd)
1743
return DefWindowProc(hwnd, msg, wParam, lParam);
1746
//Slightly diffent from W_EventsPending -- does not get any new events, merely
1747
//reads from out queue.
1748
int W_EventsQueued()
1750
return (EventHead != EventTail);
1754
//Draw a line.. yay, what a challenge
1755
//Well, considering XDrawLine goes from pt to pt, and
1756
//LineTo doesn't draw the last point, a bigger one -SAC 07 Aug 1996
1757
//Changed to SACLineTo 25 Aug 96
1758
void W_MakeLine(W_Window window, int x0, int y0, int x1, int y1, W_Color color)
1762
register int border;
1766
hdc = GetDC(win->hwnd);
1769
SelectPalette(hdc, NetrekPalette, FALSE);
1770
RealizePalette(hdc);
1772
SelectObject(hdc, colortable[color].pen);
1773
MoveTo(hdc, x0+border, y0+border);
1774
LineTo(hdc, x1+border, y1+border);
1775
/* Get that last point in there ... -SAC */
1776
SetPixel(hdc, x1+border, y1+border, colortable[color].rgb);
1777
ReleaseDC(win->hwnd, hdc);
1781
//We don't need to cache...
1782
void W_CacheLine(W_Window window, int x0, int y0, int x1, int y1, W_Color color)
1784
W_MakeLine(window, x0, y0, x1, y1, color);
1787
void W_FlushLineCaches(W_Window window)
1791
// Make *many* lines :)
1792
void W_MakeLines(W_Window window, int *x0, int *y0, int *x1, int *y1, int num, W_Color color)
1795
register int border;
1799
hdc = GetDC(win->hwnd);
1802
SelectPalette(hdc, NetrekPalette, FALSE);
1803
RealizePalette(hdc);
1805
SelectObject(hdc, colortable[color].pen);
1810
MoveTo(hdc, x0[num]+border, y0[num]+border);
1811
LineTo(hdc, x1[num]+border, y1[num]+border);
1812
SetPixel(hdc, x1[num]+border, y1[num]+border, colortable[color].rgb);
1815
ReleaseDC(win->hwnd, hdc);
1821
//Draw a dashed line, inidicating a tractor/pressor beam
1822
//Do it manually though, as Win32 sucks at creating arbitrary pens
1823
//Apologies if this isn't perfect, it's been a while since I had to
1824
//write an integer linedraw routine.
1825
//Whoops! Can't swap the points - 26 Aug 96
1827
void W_MakeTractLine (W_Window window, int x0, int y0, int x1, int y1, W_Color color)
1832
unsigned __int32 d1,d2,d3;
1833
int dp /* Dash pointer */, dc /* Dash counter */;
1834
register int Md /* Major direction */, md; /* minor direction */
1835
/* 3 blank, 1 solid... etc. -SAC */
1836
int dashdesc[] = { 10, 1 };
1840
dashdesc[0] = intDefault("tpdotdist",dashdesc[0]);
1849
hdc = GetDC(win->hwnd);
1852
SelectPalette(hdc, NetrekPalette, FALSE);
1853
RealizePalette(hdc);
1865
/* Major axis is x */
1867
if (d3) d1 = (((__int64) d3)<<32)/d2;
1870
Md = x0 < x1 ? 1 : -1;
1871
md = y0 < y1 ? 1 : -1;
1875
while ((Md==1 ? x0 <= x1 : x0 >= x1))
1877
if (dp & 1) // An odd number
1878
SetPixel(hdc, x0, y0, colortable[color].rgb);
1893
if (!d1 || (d3 > d2))
1900
/* Major axis is y */
1902
if (d2) d1 = (((__int64) d2)<<32)/d3;
1906
Md = y0 < y1 ? 1 : -1;
1907
md = x0 < x1 ? 1 : -1;
1911
while ((Md==1 ? y0 <= y1 : y0 >= y1))
1913
if (dp & 1) // An odd number
1914
SetPixel(hdc, x0, y0, colortable[color].rgb);
1929
if (!d1 || (d3 > d2))
1937
ReleaseDC(win->hwnd, hdc);
1941
//Draw a dashed line, inidicating a tractor/pressor beam
1942
void Old_W_MakeTractLine (W_Window window, int x0, int y0, int x1, int y1, W_Color color)
1946
register int border;
1950
hdc = GetDC(win->hwnd);
1953
SelectPalette(hdc, NetrekPalette, FALSE);
1954
RealizePalette(hdc);
1956
SetBkMode(hdc, TRANSPARENT);
1957
SelectObject(hdc, colortable[color].dashedpen);
1958
MoveTo(hdc, x0+border, y0+border);
1959
LineTo(hdc, x1+border, y1+border);
1960
ReleaseDC(win->hwnd, hdc);
1964
//The same as MakeLine, for now... at least, for the X code it was.
1965
void W_MakePhaserLine (W_Window window, int x0, int y0, int x1, int y1, W_Color color)
1969
register int border;
1973
hdc = GetDC(win->hwnd);
1976
SelectPalette(hdc, NetrekPalette, FALSE);
1977
RealizePalette(hdc);
1979
SelectObject(hdc, colortable[color].pen);
1980
MoveTo(hdc, x0+border, y0+border);
1981
LineTo(hdc, x1+border, y1+border);
1982
SetPixel(hdc, x1+border, y1+border, colortable[color].rgb);
1983
ReleaseDC(win->hwnd, hdc);
1987
//Draw a triangle. Yay.
1988
void W_WriteTriangle (W_Window window, int x, int y, int s, int t, W_Color color)
2002
points[1].x = x + s;
2003
points[1].y = y - s;
2004
points[2].x = x - s;
2005
points[2].y = y - s;
2011
points[1].x = x + s;
2012
points[1].y = y + s;
2013
points[2].x = x - s;
2014
points[2].y = y + s;
2018
hdc = GetDC(win->hwnd);
2021
SelectPalette(hdc, NetrekPalette, FALSE);
2022
RealizePalette(hdc);
2024
SelectObject(hdc, colortable[color].pen);
2025
SelectObject(hdc, GetStockObject(NULL_BRUSH));
2027
Polygon(hdc, points, 3);
2029
ReleaseDC(win->hwnd, hdc);
2033
//Put some text in a window. This is a straight ExtTextOut call if it's a
2034
//graphics window, a ExtTextOut call with mapped coordinates if it's a
2035
//text window, an addition to a listbox if it's a scrolling window
2036
//(in which case the position is ignored: it always goes at the end
2037
//of the list) and a call to set a menu item if it's a menu window.
2038
void W_WriteText(W_Window window, int x,int y,W_Color color,char *str,int len, W_Font font)
2043
register int border;
2045
border = win->border;
2050
x = x * W_Textwidth + WIN_EDGE;
2051
y = y * W_Textheight+MENU_PAD;
2055
hdc = GetDC(win->hwnd);
2058
SelectPalette(hdc, NetrekPalette, FALSE);
2059
RealizePalette(hdc);
2062
SelectObject(hdc, (HFONT)font);
2063
SetTextColor(hdc, colortable[color].rgb);
2064
SetBkColor(hdc, colortable[BLACK].rgb);
2066
GetTextExtentPoint(hdc, str, len, &ext);
2068
//do a rectangle intersection with the clipping rect, inlined for speed
2069
x+=border; y+=border;
2070
r.left = max(x, border);
2071
r.right= min(x+ext.cx, win->ClipRect.right);
2072
if (r.right < r.left)
2073
return; //Horizantal extents do not overlap
2074
r.top = max(y, border);
2075
r.bottom = min(y+ext.cy, win->ClipRect.bottom);
2076
if (r.bottom < r.top)
2077
return; //Vertical extents do not overlap
2079
ExtTextOut( hdc, x, y, ETO_CLIPPED|ETO_OPAQUE, &r, str, len, NULL);
2081
ReleaseDC(win->hwnd, hdc);
2086
AddToScrolling(win, color, str, len);
2091
ChangeMenuItem(win, y, str, len, color);
2095
printf("Unknown window type in W_WriteText");
2100
void W_MaskText(W_Window window, int x,int y,W_Color color,char *str,int len, W_Font font)
2108
x = x * W_Textwidth + WIN_EDGE;
2109
y = y * W_Textheight+MENU_PAD;
2113
hdc = GetDC(win->hwnd);
2116
SelectPalette(hdc, NetrekPalette, FALSE);
2117
RealizePalette(hdc);
2119
SelectObject(hdc, (HFONT)font);
2120
SetTextColor(hdc, colortable[color].rgb);
2121
SetBkMode(hdc, TRANSPARENT);
2123
ExtTextOut( hdc, x+win->border, y+win->border, ETO_CLIPPED, &(win->ClipRect), str, len, NULL);
2125
ReleaseDC(win->hwnd, hdc);
2130
AddToScrolling(win, color, str, len);
2135
ChangeMenuItem(win, y, str, len, color);
2139
printf("Unknown window type in W_WriteText");
2144
// Succesively dump each BitmapList
2145
void W_ShowBitmaps()
2147
static struct BitmapList *pBM=0;
2148
static W_Window tmp = 0;
2152
printf("pBM: %p\nbmlCount: %d",pBM,bmlCount);
2156
pBM = CurrentBitmap;
2158
tmp = W_MakeWindow("Bitmap",10,10,BIGBITMAP_WIDTH+5,BIGBITMAP_HEIGHT+5,
2169
printf("tmp: %p\n",tmp);
2170
if (!SelectObject(GlobalMemDC, pBM->bm))
2172
if (!(hdc = GetDC( ((Window *)tmp)->hwnd)))
2174
BitBlt(hdc,0,0,BIGBITMAP_WIDTH, BIGBITMAP_HEIGHT, GlobalMemDC, 0, 0, SRCCOPY);
2175
SelectObject(GlobalMemDC, GlobalOldMemDCBitmap);
2176
ReleaseDC(((Window *)tmp)->hwnd, hdc);
2181
// We've reached the end, kill the window.
2183
W_DestroyWindow(tmp);
2190
//Creates a bitmap object out of X11 bitmap data...
2191
//What we actually do is allocate a number of 240x240 bitmaps, and copy
2192
//each image to a new section of the bitmap. Part of the W_Icon structure
2193
//that we return has an x,y index into this bitmap. In this fashion,
2194
//we avoid allocating every bitmap handle in the system for the 1,000 or so
2195
//bitmaps that we need.
2196
//Fixed to actually work as intended - 19 Aug 96 SAC
2197
W_Icon W_StoreBitmap(int width,int height,char *bits,W_Window window)
2199
static int CurX=0, CurY=-1, MaxY=0;
2200
struct Icon *bitmap=0;
2201
struct BitmapList *NewBitmap=0;
2202
unsigned char *bits2=0;
2203
HBITMAP temp=0,temp2=0;
2209
CurY = BIGBITMAP_HEIGHT+1; // Force the first bitmap to be created
2211
//Allocate memory for the bitmap structure and convert the
2212
//X11 bitmap into a useful form
2213
if (!(bitmap = (struct Icon *) malloc(sizeof(struct Icon))) ||
2214
!(bits2 = X11toDIB(bits, width, height)) )
2217
newwidth = ((width + 0xf) & ~0xf);
2218
//Create a temporary Windows bitmap object
2219
if (! (temp = CreateBitmap(newwidth, height, 1, 1, bits2)) )
2224
//Save the width, height, window...
2225
bitmap->hwnd = win->hwnd;
2226
bitmap->width = width;
2227
bitmap->height = height;
2228
bitmap->ClipRectAddr = &win->ClipRect;
2230
//Is the bitmap large enough to justify it's own HBitmap, or
2231
//should we make it part of a "Big Bitmap"?
2232
if ( (width>(BIGBITMAP_WIDTH/2)) && (height>(BIGBITMAP_HEIGHT/2)) ) //if it's big....
2234
if ( !(NewBitmap = (struct BitmapList *) malloc(sizeof(struct BitmapList))) )
2237
//Copy the bitmap to new location so we can mirror it
2238
if ( !(temp2 = CreateBitmap(width, height, 1, 1, NULL)) )
2245
SelectObject(GlobalMemDC, temp);
2246
SelectObject(GlobalMemDC2, temp2);
2247
StretchBlt(GlobalMemDC2, 0, 0, width, height, GlobalMemDC, newwidth-1, 0, -width, height, SRCCOPY);
2249
NewBitmap->bm = temp2;
2256
NewBitmap->next = CurrentBitmap->next; //Insert the entry in the linked list
2257
CurrentBitmap->next = NewBitmap; //as the item after CurrentBitmap
2261
printf("Got impossible internal error in W_StoreBitmap(). Please report to author.\n");
2268
//Figure out where to store the image in the current big bitmap
2269
width = (width + 0x7) & ~0x7; //Round up to nearest eight bits
2270
//height = (height + 0x7) & ~0x7;
2271
if ( (CurX + width) > BIGBITMAP_WIDTH || (CurY + height) > BIGBITMAP_HEIGHT )
2273
CurX = 0; //Advance to next line
2276
if ( (CurY + height) > BIGBITMAP_HEIGHT)
2280
WORD mask[] = { 0xaaaa, 0x5555 };
2283
if ( !(NewBitmap = (struct BitmapList *) malloc(sizeof(struct BitmapList))) ||
2284
!(NewBitmap->bm = CreateBitmap(BIGBITMAP_WIDTH, BIGBITMAP_HEIGHT, 1,1, NULL)) )
2289
NewBitmap->next = CurrentBitmap; //Advance to next bitmap
2290
CurrentBitmap = NewBitmap; //Store in LL
2297
bmrect.right = BIGBITMAP_WIDTH-1;
2298
bmrect.bottom = BIGBITMAP_HEIGHT-1;
2300
hb = CreateBitmap(2,2,1,1,(const void *) mask );
2301
SpeckleBr = CreatePatternBrush(hb);
2303
SelectObject(GlobalMemDC2, CurrentBitmap->bm);
2304
FillRect(GlobalMemDC2, &bmrect, SpeckleBr);
2305
DeleteObject(SpeckleBr);
2306
SelectObject(GlobalMemDC2, GlobalOldMemDC2Bitmap);
2311
//Copy the bits to their new location, mirroring as we go
2312
if (!SelectObject(GlobalMemDC, temp))
2313
printf("SelectObject(DC, temp) bombed");
2314
if (!SelectObject(GlobalMemDC2, CurrentBitmap->bm))
2315
printf("SelectObject(DC2,CurrentBitmap->tm) bombed");
2320
while (!StretchBlt(GlobalMemDC2, CurX, CurY, width, height, GlobalMemDC, newwidth-1, 0, -width, height, SRCCOPY) &&
2326
printf(" CurX=%3d CurY=%3d width=%3d height=%3d newwidth-1=%3d -width=%3d re=%3d %d\n",
2327
CurX, CurY, width, height, newwidth-1, -width, re, x);
2329
printf("++ CurX=%3d CurY=%3d width=%3d height=%3d newwidth-1=%3d -width=%3d\n",
2330
CurX, CurY, width, height, newwidth-1, -width);
2333
StretchBlt(GlobalMemDC2, CurX, CurY, width, height, GlobalMemDC, newwidth-1, 0, -width, height, SRCCOPY);
2336
MaxY = max(MaxY, height); //The current row (of bitmaps) max height
2338
//Store the position in the big bitmap, and increment the current X pointer
2339
bitmap->bm = CurrentBitmap->bm;
2345
SelectObject(GlobalMemDC, GlobalOldMemDCBitmap); //So we don't crunch on the next line...
2347
SelectObject(GlobalMemDC2, GlobalOldMemDC2Bitmap); //Bitmaps can only be selected into one
2348
//DC at a time, so deselect it from here.
2349
return (W_Icon) bitmap;
2352
printf("Memory allocation or CreateBitmap() failure in StoreBitmap\n");
2353
if (bits2) free(bits2);
2354
if (bitmap) free(bitmap);
2355
if (NewBitmap) free(NewBitmap);
2356
if (temp) DeleteObject(temp);
2357
if (temp2) DeleteObject(temp2);
2361
//Put an image on the screen (yay!). Because of all the #$%#$ work that
2362
//has gone into storing the bitmaps (see above), this is thankfully
2363
//a low-overhead call - almost directly translates into the GDI BitBlt
2364
void W_WriteBitmap(int x, int y, W_Icon icon, W_Color color)
2366
register struct Icon *bitmap = (struct Icon *)icon;
2367
register int border,width,height;
2368
register int srcx,srcy;
2371
//Fast (I hope) rectangle intersection, don't overwrite our borders
2374
border=bitmap->ClipRectAddr->top;
2375
x+=border; y+=border;
2378
width = bitmap->width - (border-x);
2382
else if ( (width = bitmap->ClipRectAddr->right-x) > bitmap->width)
2383
width = bitmap->width;
2386
height = bitmap->height - (border-y);
2390
else if ( (height = bitmap->ClipRectAddr->bottom-y) > bitmap->height)
2391
height = bitmap->height;
2393
hdc = GetDC( bitmap->hwnd );
2396
SelectPalette(hdc, NetrekPalette, FALSE);
2397
RealizePalette(hdc);
2399
SelectObject(GlobalMemDC, bitmap->bm );
2401
//Set the color of the bitmap
2402
//(oddly enough, 1-bit = bk color, 0-bit = text (fg) color)
2403
SetBkColor(hdc, colortable[color].rgb);
2404
SetTextColor(hdc, colortable[BLACK].rgb);
2406
BitBlt(hdc, x, y, //Copy the bitmap
2412
SRCPAINT); // <-- using OR mode
2414
ReleaseDC( bitmap->hwnd, hdc);
2417
void W_TileWindow(W_Window window, W_Icon icon)
2422
win->TileIcon = (struct Icon *)icon;
2424
InvalidateRect(win->hwnd, NULL, TRUE);
2425
UpdateWindow(win->hwnd);
2428
void W_UnTileWindow(W_Window window)
2437
InvalidateRect(win->hwnd, NULL, TRUE);
2438
UpdateWindow(win->hwnd);
2442
int W_WindowWidth(W_Window window)
2446
return (win->ClipRect.right - win->border);
2449
int W_WindowHeight(W_Window window)
2453
return (win->ClipRect.bottom - win->border);
2456
//We fake window events as a socket, by using this magic number
2457
//and a fudge in our implementation of select()...
2460
return(0x0CABBABE); //Magic number, can be anything but must match winmain.c's select()
2465
MessageBeep(MB_ICONEXCLAMATION);
2468
void W_SetIconWindow(W_Window main, W_Window icon)
2471
* MS-Windows requires an icon, i.e. a pixmap, not a window, as the iconized image.
2472
* So, ignore this. We use our own special blend of 11 herbs and spices, stored
2473
* in the resource file, and coated in crispy batter, as the icon for all of our windows.
2477
//Easy enough... except for the fact that only the thread which created the window
2478
// can destroy it. So if we are not the main thread we post a message
2479
void W_DestroyWindow(W_Window window)
2483
printf("Destroying %X\n", win->hwnd);
2485
if (GetCurrentThreadId() == MainThreadID)
2486
DestroyWindow(win->hwnd);
2488
PostMessage(AnyWindow, WM_CROSS_THREAD_DESTROY, (WPARAM)win->hwnd, 0);
2491
//Redraw a menu window.
2492
void RedrawMenu(Window *win, HDC hdc)
2497
SelectObject(hdc, (HFONT)W_RegularFont);
2499
r.left = win->border;
2500
r.right = win->ClipRect.right;
2502
for (count = 1; count < win->NumItems; count++)
2504
r.top = count * (W_Textheight + MENU_PAD * 2) + (count - 1) * MENU_BAR + win->border;
2505
r.bottom = r.top + MENU_BAR;
2506
FillRect(hdc, &r, colortable[W_White].brush);
2509
SetBkMode(hdc, TRANSPARENT);
2511
for (count = 0; count < win->NumItems; count++)
2512
if ((win->items[count]).string)
2514
SetTextColor(hdc, colortable[(win->items[count]).color].rgb);
2515
TextOut( hdc, WIN_EDGE + win->border,
2516
count * (W_Textheight + MENU_PAD * 2 + MENU_BAR) + MENU_PAD + win->border,
2517
win->items[count].string, win->items[count].len);
2521
//Change a specific menu item, and redraw.
2522
void ChangeMenuItem(Window *win, int n, char *str, int len, W_Color color)
2524
register struct menuItem *p = &(win->items[n]);
2528
if (n >= win->NumItems)
2534
p->string = (char *) malloc(len + 1);
2535
strcpy(p->string, str);
2539
hdc = GetDC(win->hwnd);
2542
SelectPalette(hdc, NetrekPalette, FALSE);
2543
RealizePalette(hdc);
2546
r.left = win->ClipRect.left;
2547
r.right = win->ClipRect.right;
2548
r.top = n * (W_Textheight + MENU_PAD * 2 + MENU_BAR) + MENU_PAD + win->border;
2549
r.bottom = r.top + W_Textheight;
2550
FillRect(hdc, &r, colortable[W_Black].brush);
2552
SetBkMode(hdc, TRANSPARENT);
2553
SelectObject(hdc, (HFONT)W_RegularFont);
2557
SetTextColor(hdc, colortable[p->color].rgb);
2558
TextOut( hdc, WIN_EDGE + win->border,
2559
n * (W_Textheight + MENU_PAD * 2 + MENU_BAR) + MENU_PAD + win->border,
2563
DrawBorder(win, hdc);
2564
ReleaseDC(win->hwnd, hdc);
2568
void AddToScrolling(Window *win, W_Color color, char *str, int len)
2570
struct stringList *p = win->strings;
2571
struct stringList *end, *p2;
2572
int NumStrings = win->NumItems;
2574
//Find the end of the linked-list of strings...
2575
if (p) // ...if the list has been created
2587
if (NumStrings < MAX_SCROLLWINDOW_LINES) //Create a new stringList item
2589
p2 = (struct stringList *) malloc(sizeof(struct stringList));
2592
fprintf(stderr,"Not enough memory to allocate a new listbox string.\n");
2597
win->strings = p2; //Store the new start of list
2599
p = p2; //Point p to the new string
2601
win->NumItems = ++NumStrings; //Inc the string number
2603
else //Re-use the first string, place it at the end of the list
2607
win->strings = p->next; //Store the new start of list
2610
if (str[len-1] == '\n') //Remove trailing newlines
2613
p->string = (char *) malloc(win->TextWidth+ 1);
2616
printf("Not enough memory to allocate a new listbox string.");
2621
strncpy(p->string, str, win->TextWidth);
2623
/* we pad out the string with spaces so we don't have to clear
2625
if (len < win->TextWidth-1)
2626
memset(p->string + len, ' ', win->TextWidth-len-1);
2627
p->string[win->TextWidth-1] = 0;
2629
if (end) end->next = p;
2632
//Mark as out of date...
2633
win->AddedStrings++;
2636
//Redraw a scrolling window
2637
void RedrawScrolling(Window *win, HDC hdc)
2639
struct stringList *p = win->strings;
2640
int NumStrings = win->NumItems;
2644
if (!win->AddedStrings && !win->NumItems)
2647
if (win->AddedStrings) //If strings were added since last paint,
2648
{ //Turn off clipping == FULL redraw
2649
i = win->NumItems - win->TextHeight;
2651
if ((i - win->AddedStrings) > GetScrollPos(win->hwnd, SB_VERT))
2653
// The player is looking back in the list. Don't move things on him!
2654
HiddenLines = GetScrollPos(win->hwnd,SB_VERT);
2655
win->AddedStrings = 0;
2656
SetScrollRange(win->hwnd, SB_VERT, 0, i, TRUE);
2658
// We are at then end away, scroll away
2659
SelectClipRgn(hdc, NULL);
2660
win->AddedStrings = 0;
2661
SetScrollRange(win->hwnd, SB_VERT, 0, i, FALSE);
2662
//update the scrollbar range
2663
SetScrollPos(win->hwnd, SB_VERT, i, TRUE);
2664
//update the scrollbar pos and redraw the scroll bar
2668
HiddenLines = GetScrollPos(win->hwnd,SB_VERT);
2671
//Advance to the first visible line
2672
NumStrings -= HiddenLines;
2673
while (HiddenLines--)
2677
SelectObject(hdc, (HFONT)W_RegularFont);
2678
SetBkMode(hdc, OPAQUE);
2679
SetBkColor(hdc, colortable[W_Black].rgb);
2681
//Draw each line of text
2682
if (NumStrings > win->TextHeight)
2683
NumStrings = win->TextHeight;
2684
for (i = win->TextHeight-NumStrings; i<win->TextHeight && p; i++)
2686
SetTextColor(hdc, colortable[p->color].rgb);
2687
TextOut( hdc, WIN_EDGE, MENU_PAD + i * W_Textheight, p->string, strlen(p->string));
2693
void W_FlushScrollingWindow(W_Window window)
2696
struct stringList *p;
2701
if (!win->AddedStrings)
2704
y = win->NumItems - win->TextHeight;
2707
// Just update scrollbar if we are looking back
2708
if ((y - win->AddedStrings) > GetScrollPos(win->hwnd, SB_VERT))
2710
SetScrollRange(win->hwnd, SB_VERT, 0, y, TRUE);
2711
win->AddedStrings = 0;
2714
//Do full redraw if faster
2715
if (win->AddedStrings > (win->TextHeight/2))
2717
InvalidateRect(win->hwnd, NULL, FALSE);
2718
UpdateWindow(win->hwnd); //Generates paint msg, which calls RedrawScrolling
2723
hdc = GetDC(win->hwnd);
2726
SelectPalette(hdc, NetrekPalette, FALSE);
2727
RealizePalette(hdc);
2729
SelectObject(hdc, (HFONT)W_RegularFont);
2730
SetBkColor(hdc, colortable[W_Black].rgb);
2731
SetBkMode(hdc, OPAQUE);
2733
//update the scrollbar range and position
2734
SetScrollRange(win->hwnd, SB_VERT, 0, y, FALSE);
2735
SetScrollPos(win->hwnd, SB_VERT, y, TRUE);
2737
//Scroll up however many lines. Use ScrollDC se we don't invalidate the window
2738
y = win->TextHeight - win->AddedStrings;
2740
if (y < 0) //Pathalogical case (but it does happen):
2741
{ //First Flush() call has more lines added than will fit
2742
win->AddedStrings += y; //in one window height
2746
ScrollDC(hdc, 0, -win->AddedStrings * W_Textheight, &win->ClipRect, &win->ClipRect, NULL, NULL);
2748
//Advance to the first visible line
2750
HiddenLines = max(0, win->NumItems - win->AddedStrings);
2751
for (; HiddenLines; HiddenLines--)
2754
//Draw each line of text
2755
y = y * W_Textheight + MENU_PAD;
2756
while (win->AddedStrings)
2758
SetTextColor(hdc, colortable[p->color].rgb);
2759
TextOut( hdc, WIN_EDGE, y, p->string, win->TextWidth);
2762
win->AddedStrings--;
2765
DrawBorder(win, hdc);
2766
ReleaseDC(win->hwnd, hdc);
2769
void W_DefineMapcursor(W_Window window)
2771
W_DefineCursor(window,
2780
void W_DefineLocalcursor(W_Window window)
2782
W_DefineCursor(window,
2791
#define MakeTeamCursor(upper, team) \
2792
void W_Define##upper##Cursor(W_Window window) \
2794
W_DefineCursor(window, \
2795
team##_cruiser_width, \
2796
team##_cruiser_height, \
2797
team##_cruiser_bits, \
2799
team##_cruiser_width/2, \
2800
team##_cruiser_height/2); \
2803
MakeTeamCursor(Fed, fed)
2804
MakeTeamCursor(Kli, kli)
2805
MakeTeamCursor(Rom, rom)
2806
MakeTeamCursor(Ori, ori)
2809
//Sets the cursor to a Star-Trek badge
2810
void W_DefineTrekCursor(W_Window window)
2814
if (win->UsingCreatedCursor)
2816
DestroyCursor( win->cursor );
2817
win->UsingCreatedCursor = FALSE;
2820
win->cursor = TrekCursor;
2823
//Sets the cursor to an exclamation mark
2824
void W_DefineWarningCursor(W_Window window)
2828
if (win->UsingCreatedCursor)
2830
DestroyCursor( win->cursor );
2831
win->UsingCreatedCursor = FALSE;
2834
win->cursor = WarnCursor;
2838
//Sets the cursor to the ol' boring arrow...
2839
void W_DefineArrowCursor(W_Window window)
2843
if (win->UsingCreatedCursor)
2845
DestroyCursor( win->cursor );
2846
win->UsingCreatedCursor = FALSE;
2849
win->cursor = LoadCursor(NULL, IDC_ARROW);
2852
//Sets the cursor to a an I-beam, indicating text insertion
2853
void W_DefineTextCursor(W_Window window)
2857
if (win->UsingCreatedCursor)
2859
DestroyCursor( win->cursor );
2860
win->UsingCreatedCursor = FALSE;
2863
win->cursor = LoadCursor(NULL, IDC_IBEAM);
2867
//Sets the cursor for a window, from an arbitrary set of bits
2868
void W_DefineCursor(W_Window window,int width,int height,
2869
char *bits,char *mask,int xhot,int yhot)
2874
unsigned char *bits2, *mask2;
2877
//NB: we throw away the passed bitmap and create our own,
2878
//since the X bitmap passed is blank, since it uses the masks
2880
bits2 = X11toCursor(bits, width, height);
2881
mask2 = (unsigned char *) malloc(32 * 32/8);
2883
if (!bits2 || !mask2)
2885
fprintf(stderr, "Memory allocation failed while setting a cursor");
2889
//Create the mask as the inverse of the bitmap
2890
for (i=0; i<32*32/8; i++)
2891
mask2[i] = ~bits2[i];
2893
//Check to see if we are using a created (i.e., must be deleted) cursor already,
2894
//and also set this flag for future reference
2895
if (win->UsingCreatedCursor)
2896
DestroyCursor( win->cursor );
2898
win->UsingCreatedCursor = TRUE;
2901
CreateCursor(MyInstance, xhot, yhot, 32, 32, (void *)mask2, (void *)bits2);
2908
/***************************************************************************/
2909
/* Looks up any default geometry specified in the defaults file and */
2910
/* returns the values found there. Geometry should be of the form */
2911
/* 502x885+1+1, 502x885, or +1+1. This allows width or width and height */
2912
/* or width height and x, or width height x and y, or x or x and y. Note */
2913
/* that height or y can not be specified unless width and x are also */
2916
/* The result returned indicates which values were set. */
2918
/* result & 0x1 ----> width set G_SET_WIDTH */
2919
/* result & 0x2 ----> height set G_SET_HEIGHT */
2920
/* result & 0x4 ----> x set G_SET_X */
2921
/* result & 0x8 ----> y set G_SET_Y */
2922
/***************************************************************************/
2923
/* Hacked to handle negative geometries 21 Aug 96 -SAC */
2924
#define G_SET_WIDTH 0x1
2925
#define G_SET_HEIGHT 0x2
2928
int checkGeometry(char *name, int *x, int *y, int *width, int *height)
2935
sprintf(buf, "%s.geometry", name);
2936
geom_default = getdefault(buf);
2938
return 0; /* nothing set */
2940
if (*s != '+' && *s != '-') /* width and height at least */
2942
while (*s != 'x' && *s != 0)
2944
*width = atoi(geom_default);
2945
result |= G_SET_WIDTH;
2950
while (*s != '+' && *s != '-' && *s != 0)
2952
*height = atoi(geom_default);
2953
result |= G_SET_HEIGHT;
2959
while (*s != '+' && *s != '-' && *s != 0)
2961
*x = atoi(geom_default);
2962
if (*(geom_default-1)=='-')
2969
*y = atoi(geom_default);
2970
if (*(geom_default-1)=='-')
2976
void checkParent (char *name, W_Window *parent)
2983
sprintf (buf, "%s.parent", name);
2984
adefault = getdefault (buf);
2985
if (adefault == NULL)
2988
/* parent must be name of other window or "root" */
2989
if (strcmpi (adefault, "root") == 0)
2991
//*parent = (W_Window) &myroot;
2995
else if (strcmpi(adefault,"netrek") == 0)
2997
//we changed the title of the netrek window,
2998
//so FindWindow won't work. Do it manually
3003
/* find the window with the name specified */
3004
if (found = FindWindow(ClassName, adefault))
3005
*parent = (W_Window) GetWindowLong(found, 0); //Return struct ptr
3011
//Should this window be initially mapped?
3012
int checkMapped(char *name)
3017
sprintf(buf, "%s.mapped", name);
3018
return(booleanDefault(buf, 0));
3021
checkMappedPref(char *name, int preferred)
3026
sprintf(buf, "%s.mapped", name);
3027
return (booleanDefault(buf, preferred));
3030
//Move the mouse cursor to the new window, or back to old pos if window==NULL
3031
void W_WarpPointer(W_Window window)
3033
static POINT warped_from;
3034
static int W_in_message = 0;
3040
SetCursorPos(warped_from.x, warped_from.y);
3047
GetWindowRect(((Window *)window)->hwnd, &r);
3048
GetCursorPos(&warped_from);
3049
SetCursorPos((r.left + r.right)/2, (r.top + r.bottom)/2);
3055
//An un-documented function that seems to be needed anyway
3056
//Checks if the mouse is in the given window - and if so, where?
3057
int findMouseInWin(int *x, int *y, W_Window window)
3065
hwnd = ChildWindowFromPoint(((Window *)baseWin)->hwnd, p);
3066
if (!hwnd || (W_Window)GetWindowLong(hwnd, 0) != window)
3073
ScreenToClient(hwnd, &p);
3080
void DrawBorder(Window *win, HDC hdc)
3083
register int size = win->border;
3085
GetClientRect(win->hwnd, &r);
3086
SelectObject(hdc, colortable[ win->BorderColor ].pen);
3087
SelectObject(hdc, GetStockObject(NULL_BRUSH));
3089
for ( ; size; size--) //Draw a series of shrinking rectangles
3091
Rectangle(hdc, r.left, r.top, r.right, r.bottom);
3101
//Converts a NxM X11 cursor bitmap, where N<=32 && M<=32 into a 32 x 32 Windows cursor bitmap
3102
//To expand the size, it simply places the NxM in the upper left corner
3104
unsigned char *X11toCursor(unsigned char *bits, int width, int height)
3106
if (width > 32 || height > 32)
3108
fprintf(stderr,"Attempt to define cursor > 32x32. Cursor will be garbled!");
3109
width = min(32, width);
3110
height = min(32, height);
3112
return X11toDIBAndMirror(bits, width, height, 32, 32);
3116
//Convert X11-style packed monochrome bitmap information to a Windows monochrome DIB
3117
//Picks the smallest size that will fit the original X-bitmap (X-bitmaps are byte-padded
3118
//while Windows bitmaps are word-padded). Does not mirror the bitmap -- we use StretchBlt
3119
//with negative width when we copy into the initial memory DC during StoreBitmap (faster method)
3120
unsigned char *X11toDIB(unsigned char *bits, int width, int height)
3122
int outbytewidth = ((width + 0xF) & ~0xF)/8; //width of a line in bytes
3123
int inbytewidth = (width + 0x7) /8;
3126
register unsigned char *data;
3127
unsigned char *base =
3128
(unsigned char *)malloc(outbytewidth * height); //malloc decode space
3132
memset(base, 0, outbytewidth * height); //Clear the array
3134
for (i=0; i<height; i++)
3136
data = base + ((i+1) * outbytewidth);
3137
for (j=0; j<inbytewidth; j++)
3145
//Converts X-style monochrome bitmap to GDI usable format
3146
//and mirrors the image (As X11 bmps are right-to-left). Used for
3148
unsigned char *X11toDIBAndMirror(unsigned char *bits, int width, int height,
3149
int outwidth, int outheight)
3151
register unsigned char rot,rot2; //Need lotsa register vars
3152
register unsigned char *data; //for this to run fast
3155
int bytewidth = outwidth /8; //width of a line in bytes
3156
unsigned char *base =
3157
(unsigned char *)malloc(bytewidth * outheight); //malloc decode space
3161
memset(base, 0, bytewidth * outheight); //Clear the array
3163
//Perform the actual conversion. X11 bitmaps are stored in
3164
//reverse bit-order (i.e. 0xC0 when the image is actually 0x03)
3165
for (i=0; i<height; i++) //For each line in height...
3167
data = base + (i*bytewidth); //Get start of line in dest
3168
rot=0x01; //Mask = 00000001b
3169
rot2=0x80; //Mask = 10000000b
3170
for (j=0; j<width; j++) //For each pixel in width...
3172
if (*bits & rot) //If bit is set in source,
3173
*data |= rot2; // or dest with the other mask.
3175
rot<<=1; //Shift masks in opposite directions
3177
if (!rot2) //If we have done 8 shifts,
3179
rot=0x01; // reset masks,
3181
bits++; // inc source and dest ptrs.
3185
if (rot != 0x1) //If we didn't process the whole byte,
3186
bits++; //inc source ptr
3195
/* Supposed to flush input caches... whatever */
3198
#define MAKE_WINDOW_GETTER(name, part) \
3199
W_Callback name(W_Window w) \
3201
return ( w ? ((Window *)w)->part : NULL );\
3204
#define MAKE_WINDOW_SETTER(name, part) \
3205
W_Callback name(W_Window w, W_Callback c) \
3208
((Window *)w)->part = c;\
3212
MAKE_WINDOW_GETTER(W_GetWindowKeyDownHandler, HandleKeydown);
3213
MAKE_WINDOW_SETTER(W_SetWindowKeyDownHandler, HandleKeydown);
3215
MAKE_WINDOW_GETTER(W_GetWindowKeyUpHandler, HandleKeyup);
3216
MAKE_WINDOW_SETTER(W_SetWindowKeyUpHandler, HandleKeyup);
3218
MAKE_WINDOW_GETTER(W_GetWindowButtonHandler, HandleButton);
3219
MAKE_WINDOW_SETTER(W_SetWindowButtonHandler, HandleButton);
3221
MAKE_WINDOW_GETTER(W_GetWindowExposeHandler, HandleExpose);
3222
MAKE_WINDOW_SETTER(W_SetWindowExposeHandler, HandleExpose);
3225
void W_ResizeWindow(W_Window window, int neww, int newh) /* TSH 2/93 */
3229
SetWindowPos(((Window *)window)->hwnd, NULL, 0, 0, neww, newh, SWP_NOMOVE);
3232
void W_ResizeTextWindow(W_Window window, int neww, int newh) /* TSH 2/93 */
3238
win->TextHeight = newh;
3239
win->TextWidth = neww;
3240
W_ResizeWindow(window, neww*W_Textwidth + WIN_EDGE*2,
3241
newh*W_Textheight + WIN_EDGE*2 );
3244
void W_ResizeMenu(W_Window window, int neww, int newh) /* TSH 2/93 */
3248
win->NumItems = newh;
3249
win->TextHeight = newh;
3250
win->TextWidth = neww;
3252
W_ResizeWindow(window, neww*W_Textwidth+WIN_EDGE*2,
3253
newh*(W_Textheight+MENU_PAD*2)+(newh-1)*MENU_BAR);
3256
//Is this a mono display?
3259
HDC hdc = GetDC(HWND_DESKTOP);
3260
register int result =
3261
( (GetDeviceCaps(hdc, PLANES) == 1) && (GetDeviceCaps(hdc, COLORRES) == 1) );
3262
ReleaseDC(HWND_DESKTOP, hdc);
3267
#ifdef SHORT_PACKETS
3268
/* Apparently this solves some problem on X, but here it just forces a redraw...*/
3269
/* Hrm - This was using redrawScrolling(win), updated to (win, hdc) -SAC 24 Jul 96 */
3270
/* Was void W_SetSensitive(Window *window, int b) -SAC */
3271
void W_SetSensitive(Window *window, int b)
3278
b; /* Makes compiler happy -SAC */
3279
if (win->type == WIN_SCROLL)
3283
RedrawScrolling(win,hdc);
3291
// We use OR mode for drawing bitmaps anyway, so this is the same call
3292
void W_OverlayBitmap(int x, int y, W_Icon icon, W_Color color)
3294
register struct Icon *bitmap = (struct Icon *)icon;
3295
register int border,width,height;
3296
register int srcx,srcy;
3299
//Fast (I hope) rectangle intersection, don't overwrite our borders
3302
border=bitmap->ClipRectAddr->top;
3303
x+=border; y+=border;
3306
width = bitmap->width - (border-x);
3310
else if ( (width = bitmap->ClipRectAddr->right-x) > bitmap->width)
3311
width = bitmap->width;
3314
height = bitmap->height - (border-y);
3318
else if ( (height = bitmap->ClipRectAddr->bottom-y) > bitmap->height)
3319
height = bitmap->height;
3321
hdc = GetDC( bitmap->hwnd );
3324
SelectPalette(hdc, NetrekPalette, FALSE);
3325
RealizePalette(hdc);
3327
SelectObject(GlobalMemDC, bitmap->bm );
3329
//Set the color of the bitmap
3330
//(oddly enough, 1-bit = bk color, 0-bit = text (fg) color)
3331
SetBkColor(hdc, colortable[color].rgb);
3332
SetTextColor(hdc, colortable[BLACK].rgb);
3334
BitBlt(hdc, x, y, //Copy the bitmap
3340
SRCPAINT); // <-- using OR mode
3342
ReleaseDC( bitmap->hwnd, hdc);
3346
void W_EraseTTSText(W_Window window, int max_width, int y, int width)
3348
register int x = (max_width - width) / 2;
3354
W_ClearArea(window, x, y, width, W_Textheight);
3357
void W_WriteTTSText(W_Window window, int max_width, int y, int width, char *str, int len)
3359
register int x = (max_width - width) / 2;
3368
hdc = GetDC(win->hwnd);
3371
SelectPalette(hdc, NetrekPalette, FALSE);
3372
RealizePalette(hdc);
3375
SetTextColor(hdc, colortable[GREY].rgb);
3376
SetBkMode(hdc, TRANSPARENT);
3377
TextOut(hdc, x, y, str, len);
3378
ReleaseDC(win->hwnd, hdc);
3382
int W_TTSTextWidth(char *s, int len)
3384
return len*W_Textwidth;
3389
void W_SetWindowName(W_Window window, char *name)
3393
SetWindowText(win->hwnd, name);
3397
//////////////////////////////////////////////////////////////////////////////////
3398
// Reset the system colors. inlines >> macros! -SAC
3400
inline void ResetSysColors(void)
3402
if (booleanDefault("mungscrollbarcolors",0))
3403
SetSysColors(sizeof(SysColorNames),SysColorNames,SysColors);
3407
inline void SetTrekSysColors(void)
3409
if (booleanDefault("mungscrollbarcolors",0))
3410
SetSysColors(sizeof(SysColorNames),SysColorNames,TrekSysColors);