2 * $Logfile: /Freespace2/code/OsApi/OutWnd.cpp $
7 * Routines for debugging output
10 * Revision 1.2 2002/05/07 03:16:48 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:10 root
17 * 6 6/03/99 6:37p Dave
18 * More TNT fun. Made perspective bitmaps more flexible.
20 * 5 6/02/99 6:18p Dave
21 * Fixed TNT lockup problems! Wheeeee!
23 * 4 12/14/98 12:13p Dave
24 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
27 * 3 10/08/98 2:38p Dave
28 * Cleanup up OsAPI code significantly. Removed old functions, centralized
31 * 2 10/07/98 10:53a Dave
34 * 1 10/07/98 10:50a Dave
36 * 49 5/15/98 3:36p John
37 * Fixed bug with new graphics window code and standalone server. Made
38 * hwndApp not be a global anymore.
40 * 48 5/14/98 5:42p John
41 * Revamped the whole window position/mouse code for the graphics windows.
43 * 47 5/14/98 11:24a Allender
44 * throw mprints to outtext regardless of gr mode
46 * 46 4/30/98 4:53p John
47 * Restructured and cleaned up cfile code. Added capability to read off
48 * of CD-ROM drive and out of multiple pack files.
50 * 45 4/16/98 6:31p Dave
51 * Doubled MAX_FILTERS to 48
53 * 44 3/31/98 5:18p John
54 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
55 * bunch of debug stuff out of player file. Made model code be able to
56 * unload models and malloc out only however many models are needed.
59 * 43 3/11/98 12:06p John
60 * Made it so output window never gets focus upon startup
62 * 42 2/16/98 9:47a John
63 * Made so only error, general, and warning are shown if no
64 * debug_filter.cfg and .cfg file isn't saved if so.
66 * 41 2/05/98 9:21p John
67 * Some new Direct3D code. Added code to monitor a ton of stuff in the
70 * 40 1/15/98 9:14p John
71 * Made it so general, error and warning can't be turned off.
73 * 39 9/13/97 10:44a Lawrance
74 * allow logging of nprintf output to file
76 * 38 8/23/97 11:32a Dave
77 * Made debug window size correctly in standalone mode.
79 * 37 8/22/97 3:42p Hoffoss
80 * Lowered the filter limit to 24, and added support for filter recycling,
81 * instead of the rather nasty Assert if we should happen to exceed this
84 * 36 8/05/97 4:29p Dave
85 * Futzed with window sizes/placements for standalone mode.
87 * 35 8/04/97 3:15p Dave
88 * Added an include for systemvars.h
90 * 34 5/20/97 1:13p Allender
91 * fixes to make outwnd work better under Win95
93 * 33 5/14/97 11:08a John
94 * fixed bug under 95 that occasionally hung program.
96 * 32 5/07/97 3:01p Lawrance
97 * check for NT in mono_init
99 * 31 5/07/97 3:06p John
100 * disabled new mono direct stuff under NT.
102 * 30 5/07/97 2:59p John
103 * Made so mono driver works under '95.
105 * 29 4/22/97 10:56a John
106 * fixed some resource leaks.
118 // to disable otherwise well-lodged compiler warning
119 #pragma warning(disable: 4201)
121 #include <winioctl.h>
129 #include "freespaceresource.h"
130 #include "systemvars.h"
132 #define MAX_FILTERS 48
133 #define SCROLL_BUFFER_SIZE 512
134 #define MAX_LINE_WIDTH 128
135 #define TASKBAR_HEIGHT 30
137 #define ID_COPY 32000
138 #define ID_FIND 32010
139 #define ID_FILTER 32100
141 #define UP_FAST 65537
142 #define DOWN_FAST 65538
144 HANDLE hOutputThread=NULL;
145 DWORD OutputThreadID;
148 char szOutputClass[] = "OutputWindow";
149 char spaces[MAX_LINE_WIDTH + 1];
150 int outwnd_filter_count = 0;
151 int outwnd_filter_loaded = 0;
154 struct outwnd_filter_struct {
155 char name[FILTER_NAME_LENGTH];
157 } *outwnd_filter[MAX_FILTERS], real_outwnd_filter[MAX_FILTERS];
159 int mprintf_last_line = -1;
160 char outtext[SCROLL_BUFFER_SIZE][MAX_LINE_WIDTH];
161 int old_scroll_pos = -32768;
162 int nTextHeight=0, nTextWidth=0, nCharRows=0;
163 int outwnd_inited = FALSE;
164 int outwnd_disabled = TRUE;
165 int max_scroll_pos = SCROLL_BUFFER_SIZE - 1;
166 static int marked = 0;
167 int marked_top, marked_bottom, marked_left, marked_right;
168 int old_marked = 0, old_marked_top, old_marked_bottom, old_marked_left, old_marked_right;
169 int marking_started_x, marking_started_y, client_top_yoffset, cur_line_index, marking_active = 0;
171 BOOL OutputActive = FALSE;
172 LPARAM last_mousemove;
173 int Outwnd_changed = 0;
174 int find_line = -1, find_pos;
176 // monochrome screen info
177 HANDLE mono_driver=NULL; // handle to the monochrome driver
179 void outwnd_print(char *id, char *tmp);
180 BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam);
181 void find_text_in_outwindow(int n, int p);
182 void outwnd_copy_marked_selection(HWND hwnd);
183 void outwnd_update_marking(LPARAM l_parm, HWND hwnd);
184 void outwnd_paint(HWND hwnd);
186 int Outwnd_no_filter_file = 0; // 0 = .cfg file found, 1 = not found and warning not printed yet, 2 = not found and warning printed
188 // used for file logging
190 int Log_debug_output_to_file = 0;
192 char *Freespace_logfilename = "fs.log";
195 inline void text_hilight(HDC &hdc)
197 SetBkColor(hdc, RGB(0, 0, 0));
198 SetTextColor(hdc, RGB(255, 255, 255));
201 inline void text_normal(HDC &hdc)
203 SetBkColor(hdc, RGB(255, 255, 255));
204 SetTextColor(hdc, RGB(0, 0, 0));
207 inline void fix_marking_coords(int &x, int &y, LPARAM l_parm)
209 x = (signed short) LOWORD(l_parm) / nTextWidth;
210 y = ((signed short) HIWORD(l_parm) - client_top_yoffset) / nTextHeight + cur_line_index;
215 if (y > SCROLL_BUFFER_SIZE)
217 y = SCROLL_BUFFER_SIZE;
224 if (x > MAX_LINE_WIDTH)
227 x = 0; // marks to end of line
232 // InvalidateRect(hOutputWnd,NULL,0);
234 void load_filter_info(void)
237 char pathname[256], inbuf[FILTER_NAME_LENGTH+4];
240 outwnd_filter_loaded = 1;
241 outwnd_filter_count = 0;
242 strcpy(pathname, "Debug_filter.cfg" );
243 fp = fopen(pathname, "rt");
245 Outwnd_no_filter_file = 1;
247 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
248 strcpy( outwnd_filter[outwnd_filter_count]->name, "error" );
249 outwnd_filter[outwnd_filter_count]->state = 1;
250 outwnd_filter_count++;
252 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
253 strcpy( outwnd_filter[outwnd_filter_count]->name, "general" );
254 outwnd_filter[outwnd_filter_count]->state = 1;
255 outwnd_filter_count++;
257 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
258 strcpy( outwnd_filter[outwnd_filter_count]->name, "warning" );
259 outwnd_filter[outwnd_filter_count]->state = 1;
260 outwnd_filter_count++;
265 Outwnd_no_filter_file = 0;
267 while (fgets(inbuf, FILTER_NAME_LENGTH+3, fp))
269 if (outwnd_filter_count == MAX_FILTERS)
272 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
274 outwnd_filter[outwnd_filter_count]->state = 1;
275 else if (*inbuf == '-')
276 outwnd_filter[outwnd_filter_count]->state = 0;
277 else continue; // skip everything else
279 z = strlen(inbuf) - 1;
280 if (inbuf[z] == '\n')
283 Assert(strlen(inbuf+1) < FILTER_NAME_LENGTH);
284 strcpy(outwnd_filter[outwnd_filter_count]->name, inbuf + 1);
286 if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "error" ) ) {
287 outwnd_filter[outwnd_filter_count]->state = 1;
288 } else if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "general" ) ) {
289 outwnd_filter[outwnd_filter_count]->state = 1;
290 } else if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "warning" ) ) {
291 outwnd_filter[outwnd_filter_count]->state = 1;
294 outwnd_filter_count++;
297 if (ferror(fp) && !feof(fp))
298 nprintf(("Error", "Error reading \"%s\"\n", pathname));
303 void save_filter_info(void)
309 if (!outwnd_filter_loaded)
312 if ( Outwnd_no_filter_file ) {
313 return; // No file, don't save
316 strcpy(pathname, "Debug_filter.cfg" );
317 fp = fopen(pathname, "wt");
320 for (i=0; i<outwnd_filter_count; i++)
321 fprintf(fp, "%c%s\n", outwnd_filter[i]->state ? '+' : '-', outwnd_filter[i]->name);
327 void outwnd_printf2(char *format, ...)
329 char tmp[MAX_LINE_WIDTH*4];
332 va_start(args, format);
333 vsprintf(tmp, format, args);
335 outwnd_print("General", tmp);
339 char mono_ram[80*25*2];
345 if ( !mono_found ) return;
346 memcpy( (void *)0xb0000, mono_ram, 80*25*2 );
355 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
357 if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
362 _outp( 0x3b4, 0x0f );
363 _outp( 0x3b4+1, 0x55 );
365 if ( _inp( 0x3b4+1 ) == 0x55 ) {
374 for (i=0; i<80*25; i++ ) {
375 mono_ram[i*2+0] = ' ';
376 mono_ram[i*2+1] = 0x07;
383 void mono_print( char * text, int len )
387 if ( !mono_found ) return;
389 for (i=0; i<len; i++ ) {
397 mono_ram[mono_y*160+mono_x*2] = text[i];
411 memmove( mono_ram, mono_ram+160, 80*24*2 );
412 for (j=0; j<80; j++ ) {
413 mono_ram[24*160+j*2] = ' ';
423 void outwnd_printf(char *id, char *format, ...)
425 char tmp[MAX_LINE_WIDTH*4];
428 va_start(args, format);
429 vsprintf(tmp, format, args);
431 outwnd_print(id, tmp);
434 void outwnd_print(char *id, char *tmp)
439 outwnd_filter_struct *temp;
441 if(gr_screen.mode == GR_DIRECT3D){
448 if ( Outwnd_no_filter_file == 1 ) {
449 Outwnd_no_filter_file = 2;
451 outwnd_print( "general", "==========================================================================\n" );
452 outwnd_print( "general", "DEBUG SPEW: No debug_filter.cfg found, so only general, error, and warning\n" );
453 outwnd_print( "general", "categories can be shown and no debug_filter.cfg info will be saved.\n" );
454 outwnd_print( "general", "==========================================================================\n" );
460 for (i=0; i<outwnd_filter_count; i++)
461 if (!stricmp(id, outwnd_filter[i]->name))
465 if (i == outwnd_filter_count) // new id found that's not yet in filter list
467 // Only create new filters if there was a filter file
468 if ( Outwnd_no_filter_file ) {
472 if (outwnd_filter_count >= MAX_FILTERS) {
473 Assert(outwnd_filter_count == MAX_FILTERS); // how did it get over the max? Very bad..
474 outwnd_printf("General", "Outwnd filter limit reached. Recycling \"%s\" to add \"%s\"",
475 outwnd_filter[MAX_FILTERS - 1]->name, id);
477 i--; // overwrite the last element (oldest used filter in the list)
480 Assert(strlen(id) < FILTER_NAME_LENGTH);
481 outwnd_filter[i] = &real_outwnd_filter[i]; // note: this assumes the list doesn't have gaps (from deleting an element for example)
482 strcpy(outwnd_filter[i]->name, id);
483 outwnd_filter[i]->state = 1;
484 outwnd_filter_count = i + 1;
488 // sort the filters from most recently used to oldest, so oldest ones will get recycled first
489 temp = outwnd_filter[i];
491 outwnd_filter[i + 1] = outwnd_filter[i];
494 outwnd_filter[i] = temp;
496 if (!outwnd_filter[i]->state)
499 if (mprintf_last_line == -1 ) {
500 for (i=0; i<SCROLL_BUFFER_SIZE;i++) {
504 mprintf_last_line = 0;
507 // printf out to the monochrome screen first
508 if ( mono_driver != ((HANDLE)-1) ) {
511 DeviceIoControl (mono_driver, (DWORD)IOCTL_MONO_PRINT, tmp, strlen(tmp), NULL, 0, &cbReturned, 0 );
513 mono_print(tmp, strlen(tmp) );
517 ccol = strlen(outtext[mprintf_last_line] );
518 dptr = &outtext[mprintf_last_line][ccol];
523 if ( Log_debug_output_to_file ) {
524 if ( Log_fp != NULL ) {
533 if ( (*sptr == '\n') || (ccol >= MAX_LINE_WIDTH-1 ) ) {
536 if (mprintf_last_line >= SCROLL_BUFFER_SIZE )
537 mprintf_last_line = 0;
539 if ( *sptr != '\n' ) {
540 outtext[mprintf_last_line][ccol] = *sptr;
543 outtext[mprintf_last_line][ccol] = '\0';
544 dptr = &outtext[mprintf_last_line][ccol];
553 if(gr_screen.mode == GR_DIRECT3D){
556 // if ( D3D_enabled ) {
557 // return; // Direct3D seems to hang sometimes printing to window
560 if ( outwnd_disabled ){
564 if ( !OutputActive ) {
565 int oldpos = GetScrollPos( hOutputWnd, SB_VERT );
566 if ( oldpos != max_scroll_pos ) {
568 si.cbSize = sizeof(SCROLLINFO);
570 si.nPos = max_scroll_pos;
571 SetScrollInfo(hOutputWnd, SB_VERT, &si, 1 );
572 InvalidateRect(hOutputWnd,NULL,0);
573 UpdateWindow(hOutputWnd);
577 ScrollWindow(hOutputWnd,0,-nTextHeight*nrows,NULL,NULL);
578 GetClientRect(hOutputWnd, &client);
579 client.top = client.bottom - nTextHeight*(nrows+1);
580 InvalidateRect(hOutputWnd,&client,0);
582 UpdateWindow(hOutputWnd);
590 LRESULT CALLBACK outwnd_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
595 // The application z-ordering has change
596 // foreground application wParm will be
597 OutputActive = (BOOL)wParam;
602 si.cbSize = sizeof(SCROLLINFO);
603 si.fMask = SIF_RANGE | SIF_POS;
605 si.nMax = max_scroll_pos;
606 si.nPos = max_scroll_pos;
607 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
613 PostMessage(hwnd, WM_MOUSEMOVE, 0, last_mousemove);
615 if ( Outwnd_changed ) {
617 GetClientRect(hOutputWnd, &client);
618 client.top = client.bottom - nTextHeight;
619 InvalidateRect(hOutputWnd,&client,0);
629 if (z >= ID_FILTER && z < ID_FILTER + outwnd_filter_count)
632 outwnd_filter[z]->state = !outwnd_filter[z]->state;
634 if ( !stricmp( outwnd_filter[z]->name, "error" ) ) {
635 outwnd_filter[z]->state = 1;
636 } else if ( !stricmp( outwnd_filter[z]->name, "general" ) ) {
637 outwnd_filter[z]->state = 1;
638 } else if ( !stricmp( outwnd_filter[z]->name, "warning" ) ) {
639 outwnd_filter[z]->state = 1;
648 outwnd_copy_marked_selection(hwnd);
653 if (DialogBox(GetModuleHandle(NULL), "FIND_DIALOG", hOutputWnd,
654 (int (__stdcall *)(void)) find_dlg_handler) == IDOK)
656 find_text_in_outwindow(mprintf_last_line, 0);
665 case WM_RBUTTONDOWN: {
666 HMENU h_menu = CreatePopupMenu();
667 HMENU h_sub_menu = CreatePopupMenu();
671 for (i=0; i<outwnd_filter_count; i++)
673 UINT flags = MFT_STRING; //MF_GRAYED;
675 if ( !stricmp( outwnd_filter[i]->name, "error" ) ) {
677 } else if ( !stricmp( outwnd_filter[i]->name, "general" ) ) {
679 } else if ( !stricmp( outwnd_filter[i]->name, "warning" ) ) {
683 if (outwnd_filter[i]->state)
684 AppendMenu(h_sub_menu, flags | MF_CHECKED, ID_FILTER + i, outwnd_filter[i]->name);
686 AppendMenu(h_sub_menu, flags, ID_FILTER + i, outwnd_filter[i]->name);
689 AppendMenu(h_menu, MFT_STRING, ID_COPY, "&Copy\tEnter");
690 AppendMenu(h_menu, MFT_STRING, ID_FIND, "&Find Text");
691 AppendMenu(h_menu, MF_POPUP, (unsigned int) h_sub_menu, "Filter &Messages");
692 pt.x = LOWORD(lParam);
693 pt.y = HIWORD(lParam);
694 ClientToScreen(hwnd, &pt);
696 TrackPopupMenu(h_menu, 0, pt.x, pt.y, 0, hwnd, NULL);
702 fix_marking_coords(marking_started_x, marking_started_y, lParam);
703 SetCapture(hwnd); // monopolize mouse
705 outwnd_update_marking(lParam, hwnd);
709 last_mousemove = lParam;
711 outwnd_update_marking(lParam, hwnd);
720 outwnd_update_marking(lParam, hwnd);
726 int vpos = GetScrollPos( hwnd, SB_VERT );
728 switch (LOWORD(wParam)) {
735 case SB_THUMBPOSITION:
736 vpos = HIWORD(wParam);
739 vpos = HIWORD(wParam);
748 if ( vpos < 0 ) vpos = 0;
749 else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos;
750 si.cbSize = sizeof(SCROLLINFO);
753 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
754 ScrollWindow(hwnd,0,(old_vpos-vpos)*nTextHeight,NULL,NULL);
755 UpdateWindow(hOutputWnd);
756 //InvalidateRect(hOutputWnd,NULL,0);
762 int vpos = GetScrollPos( hwnd, SB_VERT );
764 int nVirtKey = (int) wParam; // virtual-key code
784 vpos = max_scroll_pos;
787 outwnd_copy_marked_selection(hwnd);
789 case UP_FAST: // special value we define
792 case DOWN_FAST: // special value we define
797 if ( vpos < 0 ) vpos = 0;
798 else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos;
799 si.cbSize = sizeof(SCROLLINFO);
802 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
803 ScrollWindow(hwnd, 0, (old_vpos-vpos)*nTextHeight, NULL, NULL);
804 UpdateWindow(hOutputWnd);
805 //InvalidateRect(hOutputWnd,NULL,0);
810 InvalidateRect(hOutputWnd,NULL,0);
823 return DefWindowProc(hwnd, msg, wParam, lParam);
830 void outwnd_copy_marked_selection(HWND hwnd)
836 if (marked_top == marked_bottom)
838 size += marked_right - marked_left;
842 size += strlen(outtext[i++]) - marked_left + 2;
844 while (i < marked_bottom)
845 size += strlen(outtext[i++]) + 2;
847 size += marked_right;
850 h_text = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
851 ptr = (char *) GlobalLock(h_text);
853 if (marked_top == marked_bottom)
855 i = marked_right - marked_left;
856 memcpy(ptr, outtext[marked_top] + marked_left, i);
861 strcpy(ptr, outtext[i] + marked_left);
865 while (i < marked_bottom)
867 strcat(ptr, outtext[i++]);
871 ptr[strlen(ptr) + marked_right] = 0;
872 strncat(ptr, outtext[i], marked_right);
875 GlobalUnlock(h_text);
878 SetClipboardData(CF_TEXT, h_text);
882 InvalidateRect(hwnd, NULL, 0);
885 void outwnd_paint(HWND hwnd)
888 int old_nrows, scroll_pos;
893 HFONT newfont, oldfont;
894 HBRUSH newbrush, oldbrush;
898 hdc = BeginPaint(hwnd, &ps);
899 GetClientRect(hOutputWnd, &client);
900 newfont = (HFONT)GetStockObject(ANSI_FIXED_FONT);
901 oldfont = (HFONT)SelectObject(hdc,newfont);
903 GetTextMetrics(hdc, &tm);
904 nTextHeight = tm.tmHeight + tm.tmExternalLeading;
905 nTextWidth = tm.tmAveCharWidth;
906 old_nrows = nCharRows;
907 nCharRows = ((client.bottom-client.top)/nTextHeight)+1;
909 newbrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
910 oldbrush = (HBRUSH)SelectObject(hdc,newbrush);
912 y = client.bottom - nTextHeight * nCharRows; // starting y position at top
913 client_top_yoffset = y - nTextHeight;
914 scroll_pos = (max_scroll_pos - GetScrollPos( hOutputWnd, SB_VERT ));
915 cur_line_index = x = mprintf_last_line - scroll_pos - nCharRows;
916 if (x >= marked_top && x < marked_bottom) // starting in marked area
920 if (scroll_pos != old_scroll_pos) {
923 sprintf( tmp, "Debug Spew");
924 SetWindowText( hOutputWnd, tmp );
928 sprintf( tmp, "Debug Spew [Scrolled back %d lines]", scroll_pos );
929 SetWindowText( hOutputWnd, tmp );
932 old_scroll_pos = scroll_pos;
938 n = mprintf_last_line - scroll_pos - i;
940 n += SCROLL_BUFFER_SIZE;
942 if (n >= 0 && n < SCROLL_BUFFER_SIZE)
944 len = strlen(outtext[n]);
947 if (n == marked_top && n == marked_bottom) // special 1 line case
950 TextOut(hdc, 0, y, outtext[n], marked_left);
953 x = marked_left * nTextWidth;
954 TextOut(hdc, x, y, outtext[n] + marked_left, marked_right -
958 x = marked_right * nTextWidth;
959 if (marked_right < len)
960 TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right);
962 x = len * nTextWidth;
963 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
965 } else if (n == marked_top) { // start marked on this line
967 TextOut(hdc, 0, y, outtext[n], marked_left);
970 x = marked_left * nTextWidth;
972 TextOut(hdc, x, y, outtext[n] + marked_left, len - marked_left);
974 x = len * nTextWidth;
975 if (marked_left < MAX_LINE_WIDTH)
976 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - marked_left);
978 } else if (n == marked_bottom) { // end marked on this line
980 TextOut(hdc, 0, y, outtext[n], marked_right);
983 x = marked_right * nTextWidth;
984 if (marked_right < len)
985 TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right);
987 x = len * nTextWidth;
988 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
990 } else { // whole line marked
991 TextOut(hdc, 0, y, outtext[n], len);
992 x = len * nTextWidth;
993 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
997 TextOut(hdc, 0, y, outtext[n], len);
998 x = len * nTextWidth;
999 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
1002 TextOut(hdc, 0, y, spaces, MAX_LINE_WIDTH);
1008 SelectObject(hdc, oldfont);
1009 SelectObject(hdc, oldbrush);
1010 DeleteObject(newbrush);
1012 if ( old_nrows != nCharRows ) {
1014 max_scroll_pos = SCROLL_BUFFER_SIZE-nCharRows - 1;
1015 si.cbSize = sizeof(SCROLLINFO);
1016 si.fMask = SIF_RANGE;
1018 si.nMax = max_scroll_pos;
1019 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
1022 EndPaint(hwnd, &ps);
1026 void outwnd_update_marking(LPARAM l_parm, HWND hwnd)
1032 y = (signed short) HIWORD(l_parm);
1033 GetClientRect(hwnd, &rect);
1036 SendMessage(hwnd, WM_KEYDOWN, UP_FAST, 0);
1040 SendMessage(hwnd, WM_KEYDOWN, VK_UP, 0);
1044 if (y >= rect.bottom + 150) {
1045 SendMessage(hwnd, WM_KEYDOWN, DOWN_FAST, 0);
1048 } else if (y >= rect.bottom) {
1049 SendMessage(hwnd, WM_KEYDOWN, VK_DOWN, 0);
1054 fix_marking_coords(x, y, l_parm);
1056 marked_top = marked_bottom = marking_started_y;
1057 marked_left = marking_started_x;
1058 marked_right = marking_started_x + 1;
1065 } else if (y > marked_bottom) {
1067 marked_right = x + 1;
1069 } else { // must be single line case
1070 if (x < marked_left)
1072 if (x >= marked_right)
1073 marked_right = x + 1;
1075 if (marked_left >= (signed int) strlen(outtext[y]))
1077 marked = 0; // this isn't going to even show up
1082 if (marked_left >= (signed int) strlen(outtext[marked_top]))
1088 if (marked_right > (signed int) strlen(outtext[marked_bottom]))
1089 marked_right = strlen(outtext[marked_bottom]);
1091 if (marked && (marked_top > marked_bottom || (marked_top == marked_bottom &&
1092 marked_left >= marked_right)))
1096 sprintf(msg, "Marking limits invalid!\n"
1097 "(%d,%d) to (%d,%d)", marked_left, marked_top, marked_right, marked_bottom);
1099 MessageBox(hwnd, msg, "Error", MB_OK | MB_ICONERROR);
1103 if (marked != old_marked || marked_top != old_marked_top || marked_bottom !=
1104 old_marked_bottom || marked_left != old_marked_left || marked_right !=
1107 old_marked = marked;
1108 old_marked_left = marked_left;
1109 old_marked_right = marked_right;
1110 old_marked_top = marked_top;
1111 old_marked_bottom = marked_bottom;
1112 InvalidateRect(hwnd, NULL, 0);
1116 BOOL outwnd_create(int display_under_freespace_window)
1120 HINSTANCE hInst = GetModuleHandle(NULL);
1124 wclass.hInstance = hInst;
1125 wclass.lpszClassName = szOutputClass;
1126 wclass.lpfnWndProc = (WNDPROC) outwnd_handler;
1127 wclass.style = CS_BYTEALIGNCLIENT | CS_OWNDC; //CS_DBLCLKS | CS_PARENTDC| CS_VREDRAW | CS_HREDRAW |;
1128 wclass.cbSize = sizeof(WNDCLASSEX);
1129 wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1130 wclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
1131 wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
1132 wclass.lpszMenuName = NULL; //"FreeSpaceMenu";
1133 wclass.cbClsExtra = 0;
1134 wclass.cbWndExtra = 0;
1135 wclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //(HBRUSH)NULL;
1137 if (!RegisterClassEx(&wclass))
1140 if (display_under_freespace_window) {
1141 style = WS_OVERLAPPEDWINDOW;;
1144 client_rect.left = client_rect.top = 0;
1145 client_rect.right = 640;
1146 client_rect.bottom = 480;
1147 AdjustWindowRect(&client_rect,WS_CAPTION | WS_SYSMENU,FALSE);
1149 int x = (GetSystemMetrics( SM_CXSCREEN )-(client_rect.right - client_rect.left))/2;
1155 rect.right = x + client_rect.right - client_rect.left - 1;
1156 rect.bottom = y + client_rect.bottom - client_rect.top - 1;
1159 rect.top = rect.bottom;
1160 rect.bottom = GetSystemMetrics(SM_CYSCREEN) - TASKBAR_HEIGHT - rect.top;
1161 rect.right -= rect.left;
1168 style = WS_OVERLAPPEDWINDOW | WS_MINIMIZE;;
1169 rect.top = rect.bottom = rect.left = rect.right = CW_USEDEFAULT;
1172 // Create Game Window
1173 hOutputWnd = CreateWindow(szOutputClass, "Debug Spew", style, rect.left,
1174 rect.top, rect.right, rect.bottom, NULL, NULL, hInst, NULL);
1176 // Show it, but don't activate it. If you activate it, it cause problems
1177 // with fullscreen startups in main window.
1178 SetWindowPos( hOutputWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW );
1180 outwnd_disabled = FALSE;
1181 SetTimer(hOutputWnd, TIMER1, 50, NULL);
1182 for (x=0; x<MAX_LINE_WIDTH; x++)
1185 spaces[MAX_LINE_WIDTH] = 0;
1189 DWORD outwnd_thread(int display_under_freespace_window)
1193 if (!outwnd_create(display_under_freespace_window))
1197 if (WaitMessage()) {
1198 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
1199 TranslateMessage(&msg);
1200 DispatchMessage(&msg);
1204 if (outwnd_disabled) break;
1211 // DeviceIoControl (mono_driver, (DWORD) IOCTL_MONO_CLEAR_SCREEN, NULL, 0, NULL, 0, &cbReturned, 0);
1212 if (hOutputThread) {
1213 CloseHandle(hOutputThread);
1214 hOutputThread = NULL;
1217 CloseHandle(mono_driver);
1222 void outwnd_init(int display_under_freespace_window)
1225 if (!outwnd_inited) {
1226 outwnd_inited = TRUE;
1227 hOutputThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)outwnd_thread, (LPVOID)display_under_freespace_window, 0, &OutputThreadID);
1228 //SetThreadPriority(hOutputThread, THREAD_PRIORITY_TIME_CRITICAL);
1230 // set up the monochrome drivers
1231 if ( (mono_driver = CreateFile("\\\\.\\MONO", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == ((HANDLE)-1)) {
1232 outwnd_printf2("Cannot get handle to monochrome driver.\n");
1241 if ( Log_fp == NULL ) {
1242 Log_fp = fopen(Freespace_logfilename, "wb");
1247 BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
1252 switch (LOWORD(wParam)) {
1254 GetDlgItemText(hwnd, IDC_TEXT, find_text, 82); // get the text to find
1255 EndDialog(hwnd, IDOK);
1265 SendDlgItemMessage(hwnd, IDC_TEXT, EM_LIMITTEXT, 80, 0); // limit text to 80 chars
1266 if (GetDlgCtrlID((HWND) wParam) != IDC_TEXT) {
1267 SetFocus(GetDlgItem(hwnd, IDC_TEXT));
1277 void find_text_in_outwindow(int n, int p)
1281 str = outtext[n] + p;
1284 ptr = strstr(str, find_text);
1287 int scroll_pos, pos;
1289 find_pos = ptr - str;
1292 marked_top = marked_bottom = find_line;
1293 marked_left = find_pos;
1294 marked_right = find_pos + strlen(find_text);
1296 scroll_pos = (max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT));
1297 pos = mprintf_last_line - scroll_pos;
1299 pos += SCROLL_BUFFER_SIZE;
1303 pos += SCROLL_BUFFER_SIZE;
1306 if (pos >= nCharRows - 1) // outside of window viewport, so scroll
1310 pos = mprintf_last_line - n - nCharRows / 2;
1312 pos += SCROLL_BUFFER_SIZE;
1314 if (pos > max_scroll_pos)
1315 pos = max_scroll_pos;
1317 scroll_pos = max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT);
1318 si.cbSize = sizeof(SCROLLINFO);
1320 si.nPos = max_scroll_pos - pos;
1321 SetScrollInfo(hOutputWnd, SB_VERT, &si, 1);
1322 ScrollWindow(hOutputWnd, 0, (scroll_pos - pos) * nTextHeight, NULL, NULL);
1325 InvalidateRect(hOutputWnd, NULL, 0);
1326 UpdateWindow(hOutputWnd);
1332 n += SCROLL_BUFFER_SIZE;
1334 if (n == mprintf_last_line)
1336 MessageBox(hOutputWnd, "Search text not found", "Find Error", MB_OK | MB_ICONERROR);
1348 if ( Log_fp != NULL ) {