2 * $Logfile: /Freespace2/code/OsApi/OutWnd.cpp $
7 * Routines for debugging output
10 * Revision 1.1 2002/05/03 03:28:10 root
14 * 6 6/03/99 6:37p Dave
15 * More TNT fun. Made perspective bitmaps more flexible.
17 * 5 6/02/99 6:18p Dave
18 * Fixed TNT lockup problems! Wheeeee!
20 * 4 12/14/98 12:13p Dave
21 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
24 * 3 10/08/98 2:38p Dave
25 * Cleanup up OsAPI code significantly. Removed old functions, centralized
28 * 2 10/07/98 10:53a Dave
31 * 1 10/07/98 10:50a Dave
33 * 49 5/15/98 3:36p John
34 * Fixed bug with new graphics window code and standalone server. Made
35 * hwndApp not be a global anymore.
37 * 48 5/14/98 5:42p John
38 * Revamped the whole window position/mouse code for the graphics windows.
40 * 47 5/14/98 11:24a Allender
41 * throw mprints to outtext regardless of gr mode
43 * 46 4/30/98 4:53p John
44 * Restructured and cleaned up cfile code. Added capability to read off
45 * of CD-ROM drive and out of multiple pack files.
47 * 45 4/16/98 6:31p Dave
48 * Doubled MAX_FILTERS to 48
50 * 44 3/31/98 5:18p John
51 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
52 * bunch of debug stuff out of player file. Made model code be able to
53 * unload models and malloc out only however many models are needed.
56 * 43 3/11/98 12:06p John
57 * Made it so output window never gets focus upon startup
59 * 42 2/16/98 9:47a John
60 * Made so only error, general, and warning are shown if no
61 * debug_filter.cfg and .cfg file isn't saved if so.
63 * 41 2/05/98 9:21p John
64 * Some new Direct3D code. Added code to monitor a ton of stuff in the
67 * 40 1/15/98 9:14p John
68 * Made it so general, error and warning can't be turned off.
70 * 39 9/13/97 10:44a Lawrance
71 * allow logging of nprintf output to file
73 * 38 8/23/97 11:32a Dave
74 * Made debug window size correctly in standalone mode.
76 * 37 8/22/97 3:42p Hoffoss
77 * Lowered the filter limit to 24, and added support for filter recycling,
78 * instead of the rather nasty Assert if we should happen to exceed this
81 * 36 8/05/97 4:29p Dave
82 * Futzed with window sizes/placements for standalone mode.
84 * 35 8/04/97 3:15p Dave
85 * Added an include for systemvars.h
87 * 34 5/20/97 1:13p Allender
88 * fixes to make outwnd work better under Win95
90 * 33 5/14/97 11:08a John
91 * fixed bug under 95 that occasionally hung program.
93 * 32 5/07/97 3:01p Lawrance
94 * check for NT in mono_init
96 * 31 5/07/97 3:06p John
97 * disabled new mono direct stuff under NT.
99 * 30 5/07/97 2:59p John
100 * Made so mono driver works under '95.
102 * 29 4/22/97 10:56a John
103 * fixed some resource leaks.
115 // to disable otherwise well-lodged compiler warning
116 #pragma warning(disable: 4201)
118 #include <winioctl.h>
126 #include "freespaceresource.h"
127 #include "systemvars.h"
129 #define MAX_FILTERS 48
130 #define SCROLL_BUFFER_SIZE 512
131 #define MAX_LINE_WIDTH 128
132 #define TASKBAR_HEIGHT 30
134 #define ID_COPY 32000
135 #define ID_FIND 32010
136 #define ID_FILTER 32100
138 #define UP_FAST 65537
139 #define DOWN_FAST 65538
141 HANDLE hOutputThread=NULL;
142 DWORD OutputThreadID;
145 char szOutputClass[] = "OutputWindow";
146 char spaces[MAX_LINE_WIDTH + 1];
147 int outwnd_filter_count = 0;
148 int outwnd_filter_loaded = 0;
151 struct outwnd_filter_struct {
152 char name[FILTER_NAME_LENGTH];
154 } *outwnd_filter[MAX_FILTERS], real_outwnd_filter[MAX_FILTERS];
156 int mprintf_last_line = -1;
157 char outtext[SCROLL_BUFFER_SIZE][MAX_LINE_WIDTH];
158 int old_scroll_pos = -32768;
159 int nTextHeight=0, nTextWidth=0, nCharRows=0;
160 int outwnd_inited = FALSE;
161 int outwnd_disabled = TRUE;
162 int max_scroll_pos = SCROLL_BUFFER_SIZE - 1;
163 static int marked = 0;
164 int marked_top, marked_bottom, marked_left, marked_right;
165 int old_marked = 0, old_marked_top, old_marked_bottom, old_marked_left, old_marked_right;
166 int marking_started_x, marking_started_y, client_top_yoffset, cur_line_index, marking_active = 0;
168 BOOL OutputActive = FALSE;
169 LPARAM last_mousemove;
170 int Outwnd_changed = 0;
171 int find_line = -1, find_pos;
173 // monochrome screen info
174 HANDLE mono_driver=NULL; // handle to the monochrome driver
176 void outwnd_print(char *id, char *tmp);
177 BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam);
178 void find_text_in_outwindow(int n, int p);
179 void outwnd_copy_marked_selection(HWND hwnd);
180 void outwnd_update_marking(LPARAM l_parm, HWND hwnd);
181 void outwnd_paint(HWND hwnd);
183 int Outwnd_no_filter_file = 0; // 0 = .cfg file found, 1 = not found and warning not printed yet, 2 = not found and warning printed
185 // used for file logging
187 int Log_debug_output_to_file = 0;
189 char *Freespace_logfilename = "fs.log";
192 inline void text_hilight(HDC &hdc)
194 SetBkColor(hdc, RGB(0, 0, 0));
195 SetTextColor(hdc, RGB(255, 255, 255));
198 inline void text_normal(HDC &hdc)
200 SetBkColor(hdc, RGB(255, 255, 255));
201 SetTextColor(hdc, RGB(0, 0, 0));
204 inline void fix_marking_coords(int &x, int &y, LPARAM l_parm)
206 x = (signed short) LOWORD(l_parm) / nTextWidth;
207 y = ((signed short) HIWORD(l_parm) - client_top_yoffset) / nTextHeight + cur_line_index;
212 if (y > SCROLL_BUFFER_SIZE)
214 y = SCROLL_BUFFER_SIZE;
221 if (x > MAX_LINE_WIDTH)
224 x = 0; // marks to end of line
229 // InvalidateRect(hOutputWnd,NULL,0);
231 void load_filter_info(void)
234 char pathname[256], inbuf[FILTER_NAME_LENGTH+4];
237 outwnd_filter_loaded = 1;
238 outwnd_filter_count = 0;
239 strcpy(pathname, "Debug_filter.cfg" );
240 fp = fopen(pathname, "rt");
242 Outwnd_no_filter_file = 1;
244 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
245 strcpy( outwnd_filter[outwnd_filter_count]->name, "error" );
246 outwnd_filter[outwnd_filter_count]->state = 1;
247 outwnd_filter_count++;
249 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
250 strcpy( outwnd_filter[outwnd_filter_count]->name, "general" );
251 outwnd_filter[outwnd_filter_count]->state = 1;
252 outwnd_filter_count++;
254 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
255 strcpy( outwnd_filter[outwnd_filter_count]->name, "warning" );
256 outwnd_filter[outwnd_filter_count]->state = 1;
257 outwnd_filter_count++;
262 Outwnd_no_filter_file = 0;
264 while (fgets(inbuf, FILTER_NAME_LENGTH+3, fp))
266 if (outwnd_filter_count == MAX_FILTERS)
269 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
271 outwnd_filter[outwnd_filter_count]->state = 1;
272 else if (*inbuf == '-')
273 outwnd_filter[outwnd_filter_count]->state = 0;
274 else continue; // skip everything else
276 z = strlen(inbuf) - 1;
277 if (inbuf[z] == '\n')
280 Assert(strlen(inbuf+1) < FILTER_NAME_LENGTH);
281 strcpy(outwnd_filter[outwnd_filter_count]->name, inbuf + 1);
283 if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "error" ) ) {
284 outwnd_filter[outwnd_filter_count]->state = 1;
285 } else if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "general" ) ) {
286 outwnd_filter[outwnd_filter_count]->state = 1;
287 } else if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "warning" ) ) {
288 outwnd_filter[outwnd_filter_count]->state = 1;
291 outwnd_filter_count++;
294 if (ferror(fp) && !feof(fp))
295 nprintf(("Error", "Error reading \"%s\"\n", pathname));
300 void save_filter_info(void)
306 if (!outwnd_filter_loaded)
309 if ( Outwnd_no_filter_file ) {
310 return; // No file, don't save
313 strcpy(pathname, "Debug_filter.cfg" );
314 fp = fopen(pathname, "wt");
317 for (i=0; i<outwnd_filter_count; i++)
318 fprintf(fp, "%c%s\n", outwnd_filter[i]->state ? '+' : '-', outwnd_filter[i]->name);
324 void outwnd_printf2(char *format, ...)
326 char tmp[MAX_LINE_WIDTH*4];
329 va_start(args, format);
330 vsprintf(tmp, format, args);
332 outwnd_print("General", tmp);
336 char mono_ram[80*25*2];
342 if ( !mono_found ) return;
343 memcpy( (void *)0xb0000, mono_ram, 80*25*2 );
352 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
354 if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
359 _outp( 0x3b4, 0x0f );
360 _outp( 0x3b4+1, 0x55 );
362 if ( _inp( 0x3b4+1 ) == 0x55 ) {
371 for (i=0; i<80*25; i++ ) {
372 mono_ram[i*2+0] = ' ';
373 mono_ram[i*2+1] = 0x07;
380 void mono_print( char * text, int len )
384 if ( !mono_found ) return;
386 for (i=0; i<len; i++ ) {
394 mono_ram[mono_y*160+mono_x*2] = text[i];
408 memmove( mono_ram, mono_ram+160, 80*24*2 );
409 for (j=0; j<80; j++ ) {
410 mono_ram[24*160+j*2] = ' ';
420 void outwnd_printf(char *id, char *format, ...)
422 char tmp[MAX_LINE_WIDTH*4];
425 va_start(args, format);
426 vsprintf(tmp, format, args);
428 outwnd_print(id, tmp);
431 void outwnd_print(char *id, char *tmp)
436 outwnd_filter_struct *temp;
438 if(gr_screen.mode == GR_DIRECT3D){
445 if ( Outwnd_no_filter_file == 1 ) {
446 Outwnd_no_filter_file = 2;
448 outwnd_print( "general", "==========================================================================\n" );
449 outwnd_print( "general", "DEBUG SPEW: No debug_filter.cfg found, so only general, error, and warning\n" );
450 outwnd_print( "general", "categories can be shown and no debug_filter.cfg info will be saved.\n" );
451 outwnd_print( "general", "==========================================================================\n" );
457 for (i=0; i<outwnd_filter_count; i++)
458 if (!stricmp(id, outwnd_filter[i]->name))
462 if (i == outwnd_filter_count) // new id found that's not yet in filter list
464 // Only create new filters if there was a filter file
465 if ( Outwnd_no_filter_file ) {
469 if (outwnd_filter_count >= MAX_FILTERS) {
470 Assert(outwnd_filter_count == MAX_FILTERS); // how did it get over the max? Very bad..
471 outwnd_printf("General", "Outwnd filter limit reached. Recycling \"%s\" to add \"%s\"",
472 outwnd_filter[MAX_FILTERS - 1]->name, id);
474 i--; // overwrite the last element (oldest used filter in the list)
477 Assert(strlen(id) < FILTER_NAME_LENGTH);
478 outwnd_filter[i] = &real_outwnd_filter[i]; // note: this assumes the list doesn't have gaps (from deleting an element for example)
479 strcpy(outwnd_filter[i]->name, id);
480 outwnd_filter[i]->state = 1;
481 outwnd_filter_count = i + 1;
485 // sort the filters from most recently used to oldest, so oldest ones will get recycled first
486 temp = outwnd_filter[i];
488 outwnd_filter[i + 1] = outwnd_filter[i];
491 outwnd_filter[i] = temp;
493 if (!outwnd_filter[i]->state)
496 if (mprintf_last_line == -1 ) {
497 for (i=0; i<SCROLL_BUFFER_SIZE;i++) {
501 mprintf_last_line = 0;
504 // printf out to the monochrome screen first
505 if ( mono_driver != ((HANDLE)-1) ) {
508 DeviceIoControl (mono_driver, (DWORD)IOCTL_MONO_PRINT, tmp, strlen(tmp), NULL, 0, &cbReturned, 0 );
510 mono_print(tmp, strlen(tmp) );
514 ccol = strlen(outtext[mprintf_last_line] );
515 dptr = &outtext[mprintf_last_line][ccol];
520 if ( Log_debug_output_to_file ) {
521 if ( Log_fp != NULL ) {
530 if ( (*sptr == '\n') || (ccol >= MAX_LINE_WIDTH-1 ) ) {
533 if (mprintf_last_line >= SCROLL_BUFFER_SIZE )
534 mprintf_last_line = 0;
536 if ( *sptr != '\n' ) {
537 outtext[mprintf_last_line][ccol] = *sptr;
540 outtext[mprintf_last_line][ccol] = '\0';
541 dptr = &outtext[mprintf_last_line][ccol];
550 if(gr_screen.mode == GR_DIRECT3D){
553 // if ( D3D_enabled ) {
554 // return; // Direct3D seems to hang sometimes printing to window
557 if ( outwnd_disabled ){
561 if ( !OutputActive ) {
562 int oldpos = GetScrollPos( hOutputWnd, SB_VERT );
563 if ( oldpos != max_scroll_pos ) {
565 si.cbSize = sizeof(SCROLLINFO);
567 si.nPos = max_scroll_pos;
568 SetScrollInfo(hOutputWnd, SB_VERT, &si, 1 );
569 InvalidateRect(hOutputWnd,NULL,0);
570 UpdateWindow(hOutputWnd);
574 ScrollWindow(hOutputWnd,0,-nTextHeight*nrows,NULL,NULL);
575 GetClientRect(hOutputWnd, &client);
576 client.top = client.bottom - nTextHeight*(nrows+1);
577 InvalidateRect(hOutputWnd,&client,0);
579 UpdateWindow(hOutputWnd);
587 LRESULT CALLBACK outwnd_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
592 // The application z-ordering has change
593 // foreground application wParm will be
594 OutputActive = (BOOL)wParam;
599 si.cbSize = sizeof(SCROLLINFO);
600 si.fMask = SIF_RANGE | SIF_POS;
602 si.nMax = max_scroll_pos;
603 si.nPos = max_scroll_pos;
604 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
610 PostMessage(hwnd, WM_MOUSEMOVE, 0, last_mousemove);
612 if ( Outwnd_changed ) {
614 GetClientRect(hOutputWnd, &client);
615 client.top = client.bottom - nTextHeight;
616 InvalidateRect(hOutputWnd,&client,0);
626 if (z >= ID_FILTER && z < ID_FILTER + outwnd_filter_count)
629 outwnd_filter[z]->state = !outwnd_filter[z]->state;
631 if ( !stricmp( outwnd_filter[z]->name, "error" ) ) {
632 outwnd_filter[z]->state = 1;
633 } else if ( !stricmp( outwnd_filter[z]->name, "general" ) ) {
634 outwnd_filter[z]->state = 1;
635 } else if ( !stricmp( outwnd_filter[z]->name, "warning" ) ) {
636 outwnd_filter[z]->state = 1;
645 outwnd_copy_marked_selection(hwnd);
650 if (DialogBox(GetModuleHandle(NULL), "FIND_DIALOG", hOutputWnd,
651 (int (__stdcall *)(void)) find_dlg_handler) == IDOK)
653 find_text_in_outwindow(mprintf_last_line, 0);
662 case WM_RBUTTONDOWN: {
663 HMENU h_menu = CreatePopupMenu();
664 HMENU h_sub_menu = CreatePopupMenu();
668 for (i=0; i<outwnd_filter_count; i++)
670 UINT flags = MFT_STRING; //MF_GRAYED;
672 if ( !stricmp( outwnd_filter[i]->name, "error" ) ) {
674 } else if ( !stricmp( outwnd_filter[i]->name, "general" ) ) {
676 } else if ( !stricmp( outwnd_filter[i]->name, "warning" ) ) {
680 if (outwnd_filter[i]->state)
681 AppendMenu(h_sub_menu, flags | MF_CHECKED, ID_FILTER + i, outwnd_filter[i]->name);
683 AppendMenu(h_sub_menu, flags, ID_FILTER + i, outwnd_filter[i]->name);
686 AppendMenu(h_menu, MFT_STRING, ID_COPY, "&Copy\tEnter");
687 AppendMenu(h_menu, MFT_STRING, ID_FIND, "&Find Text");
688 AppendMenu(h_menu, MF_POPUP, (unsigned int) h_sub_menu, "Filter &Messages");
689 pt.x = LOWORD(lParam);
690 pt.y = HIWORD(lParam);
691 ClientToScreen(hwnd, &pt);
693 TrackPopupMenu(h_menu, 0, pt.x, pt.y, 0, hwnd, NULL);
699 fix_marking_coords(marking_started_x, marking_started_y, lParam);
700 SetCapture(hwnd); // monopolize mouse
702 outwnd_update_marking(lParam, hwnd);
706 last_mousemove = lParam;
708 outwnd_update_marking(lParam, hwnd);
717 outwnd_update_marking(lParam, hwnd);
723 int vpos = GetScrollPos( hwnd, SB_VERT );
725 switch (LOWORD(wParam)) {
732 case SB_THUMBPOSITION:
733 vpos = HIWORD(wParam);
736 vpos = HIWORD(wParam);
745 if ( vpos < 0 ) vpos = 0;
746 else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos;
747 si.cbSize = sizeof(SCROLLINFO);
750 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
751 ScrollWindow(hwnd,0,(old_vpos-vpos)*nTextHeight,NULL,NULL);
752 UpdateWindow(hOutputWnd);
753 //InvalidateRect(hOutputWnd,NULL,0);
759 int vpos = GetScrollPos( hwnd, SB_VERT );
761 int nVirtKey = (int) wParam; // virtual-key code
781 vpos = max_scroll_pos;
784 outwnd_copy_marked_selection(hwnd);
786 case UP_FAST: // special value we define
789 case DOWN_FAST: // special value we define
794 if ( vpos < 0 ) vpos = 0;
795 else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos;
796 si.cbSize = sizeof(SCROLLINFO);
799 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
800 ScrollWindow(hwnd, 0, (old_vpos-vpos)*nTextHeight, NULL, NULL);
801 UpdateWindow(hOutputWnd);
802 //InvalidateRect(hOutputWnd,NULL,0);
807 InvalidateRect(hOutputWnd,NULL,0);
820 return DefWindowProc(hwnd, msg, wParam, lParam);
827 void outwnd_copy_marked_selection(HWND hwnd)
833 if (marked_top == marked_bottom)
835 size += marked_right - marked_left;
839 size += strlen(outtext[i++]) - marked_left + 2;
841 while (i < marked_bottom)
842 size += strlen(outtext[i++]) + 2;
844 size += marked_right;
847 h_text = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
848 ptr = (char *) GlobalLock(h_text);
850 if (marked_top == marked_bottom)
852 i = marked_right - marked_left;
853 memcpy(ptr, outtext[marked_top] + marked_left, i);
858 strcpy(ptr, outtext[i] + marked_left);
862 while (i < marked_bottom)
864 strcat(ptr, outtext[i++]);
868 ptr[strlen(ptr) + marked_right] = 0;
869 strncat(ptr, outtext[i], marked_right);
872 GlobalUnlock(h_text);
875 SetClipboardData(CF_TEXT, h_text);
879 InvalidateRect(hwnd, NULL, 0);
882 void outwnd_paint(HWND hwnd)
885 int old_nrows, scroll_pos;
890 HFONT newfont, oldfont;
891 HBRUSH newbrush, oldbrush;
895 hdc = BeginPaint(hwnd, &ps);
896 GetClientRect(hOutputWnd, &client);
897 newfont = (HFONT)GetStockObject(ANSI_FIXED_FONT);
898 oldfont = (HFONT)SelectObject(hdc,newfont);
900 GetTextMetrics(hdc, &tm);
901 nTextHeight = tm.tmHeight + tm.tmExternalLeading;
902 nTextWidth = tm.tmAveCharWidth;
903 old_nrows = nCharRows;
904 nCharRows = ((client.bottom-client.top)/nTextHeight)+1;
906 newbrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
907 oldbrush = (HBRUSH)SelectObject(hdc,newbrush);
909 y = client.bottom - nTextHeight * nCharRows; // starting y position at top
910 client_top_yoffset = y - nTextHeight;
911 scroll_pos = (max_scroll_pos - GetScrollPos( hOutputWnd, SB_VERT ));
912 cur_line_index = x = mprintf_last_line - scroll_pos - nCharRows;
913 if (x >= marked_top && x < marked_bottom) // starting in marked area
917 if (scroll_pos != old_scroll_pos) {
920 sprintf( tmp, "Debug Spew");
921 SetWindowText( hOutputWnd, tmp );
925 sprintf( tmp, "Debug Spew [Scrolled back %d lines]", scroll_pos );
926 SetWindowText( hOutputWnd, tmp );
929 old_scroll_pos = scroll_pos;
935 n = mprintf_last_line - scroll_pos - i;
937 n += SCROLL_BUFFER_SIZE;
939 if (n >= 0 && n < SCROLL_BUFFER_SIZE)
941 len = strlen(outtext[n]);
944 if (n == marked_top && n == marked_bottom) // special 1 line case
947 TextOut(hdc, 0, y, outtext[n], marked_left);
950 x = marked_left * nTextWidth;
951 TextOut(hdc, x, y, outtext[n] + marked_left, marked_right -
955 x = marked_right * nTextWidth;
956 if (marked_right < len)
957 TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right);
959 x = len * nTextWidth;
960 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
962 } else if (n == marked_top) { // start marked on this line
964 TextOut(hdc, 0, y, outtext[n], marked_left);
967 x = marked_left * nTextWidth;
969 TextOut(hdc, x, y, outtext[n] + marked_left, len - marked_left);
971 x = len * nTextWidth;
972 if (marked_left < MAX_LINE_WIDTH)
973 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - marked_left);
975 } else if (n == marked_bottom) { // end marked on this line
977 TextOut(hdc, 0, y, outtext[n], marked_right);
980 x = marked_right * nTextWidth;
981 if (marked_right < len)
982 TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right);
984 x = len * nTextWidth;
985 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
987 } else { // whole line marked
988 TextOut(hdc, 0, y, outtext[n], len);
989 x = len * nTextWidth;
990 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
994 TextOut(hdc, 0, y, outtext[n], len);
995 x = len * nTextWidth;
996 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
999 TextOut(hdc, 0, y, spaces, MAX_LINE_WIDTH);
1005 SelectObject(hdc, oldfont);
1006 SelectObject(hdc, oldbrush);
1007 DeleteObject(newbrush);
1009 if ( old_nrows != nCharRows ) {
1011 max_scroll_pos = SCROLL_BUFFER_SIZE-nCharRows - 1;
1012 si.cbSize = sizeof(SCROLLINFO);
1013 si.fMask = SIF_RANGE;
1015 si.nMax = max_scroll_pos;
1016 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
1019 EndPaint(hwnd, &ps);
1023 void outwnd_update_marking(LPARAM l_parm, HWND hwnd)
1029 y = (signed short) HIWORD(l_parm);
1030 GetClientRect(hwnd, &rect);
1033 SendMessage(hwnd, WM_KEYDOWN, UP_FAST, 0);
1037 SendMessage(hwnd, WM_KEYDOWN, VK_UP, 0);
1041 if (y >= rect.bottom + 150) {
1042 SendMessage(hwnd, WM_KEYDOWN, DOWN_FAST, 0);
1045 } else if (y >= rect.bottom) {
1046 SendMessage(hwnd, WM_KEYDOWN, VK_DOWN, 0);
1051 fix_marking_coords(x, y, l_parm);
1053 marked_top = marked_bottom = marking_started_y;
1054 marked_left = marking_started_x;
1055 marked_right = marking_started_x + 1;
1062 } else if (y > marked_bottom) {
1064 marked_right = x + 1;
1066 } else { // must be single line case
1067 if (x < marked_left)
1069 if (x >= marked_right)
1070 marked_right = x + 1;
1072 if (marked_left >= (signed int) strlen(outtext[y]))
1074 marked = 0; // this isn't going to even show up
1079 if (marked_left >= (signed int) strlen(outtext[marked_top]))
1085 if (marked_right > (signed int) strlen(outtext[marked_bottom]))
1086 marked_right = strlen(outtext[marked_bottom]);
1088 if (marked && (marked_top > marked_bottom || (marked_top == marked_bottom &&
1089 marked_left >= marked_right)))
1093 sprintf(msg, "Marking limits invalid!\n"
1094 "(%d,%d) to (%d,%d)", marked_left, marked_top, marked_right, marked_bottom);
1096 MessageBox(hwnd, msg, "Error", MB_OK | MB_ICONERROR);
1100 if (marked != old_marked || marked_top != old_marked_top || marked_bottom !=
1101 old_marked_bottom || marked_left != old_marked_left || marked_right !=
1104 old_marked = marked;
1105 old_marked_left = marked_left;
1106 old_marked_right = marked_right;
1107 old_marked_top = marked_top;
1108 old_marked_bottom = marked_bottom;
1109 InvalidateRect(hwnd, NULL, 0);
1113 BOOL outwnd_create(int display_under_freespace_window)
1117 HINSTANCE hInst = GetModuleHandle(NULL);
1121 wclass.hInstance = hInst;
1122 wclass.lpszClassName = szOutputClass;
1123 wclass.lpfnWndProc = (WNDPROC) outwnd_handler;
1124 wclass.style = CS_BYTEALIGNCLIENT | CS_OWNDC; //CS_DBLCLKS | CS_PARENTDC| CS_VREDRAW | CS_HREDRAW |;
1125 wclass.cbSize = sizeof(WNDCLASSEX);
1126 wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1127 wclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
1128 wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
1129 wclass.lpszMenuName = NULL; //"FreeSpaceMenu";
1130 wclass.cbClsExtra = 0;
1131 wclass.cbWndExtra = 0;
1132 wclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //(HBRUSH)NULL;
1134 if (!RegisterClassEx(&wclass))
1137 if (display_under_freespace_window) {
1138 style = WS_OVERLAPPEDWINDOW;;
1141 client_rect.left = client_rect.top = 0;
1142 client_rect.right = 640;
1143 client_rect.bottom = 480;
1144 AdjustWindowRect(&client_rect,WS_CAPTION | WS_SYSMENU,FALSE);
1146 int x = (GetSystemMetrics( SM_CXSCREEN )-(client_rect.right - client_rect.left))/2;
1152 rect.right = x + client_rect.right - client_rect.left - 1;
1153 rect.bottom = y + client_rect.bottom - client_rect.top - 1;
1156 rect.top = rect.bottom;
1157 rect.bottom = GetSystemMetrics(SM_CYSCREEN) - TASKBAR_HEIGHT - rect.top;
1158 rect.right -= rect.left;
1165 style = WS_OVERLAPPEDWINDOW | WS_MINIMIZE;;
1166 rect.top = rect.bottom = rect.left = rect.right = CW_USEDEFAULT;
1169 // Create Game Window
1170 hOutputWnd = CreateWindow(szOutputClass, "Debug Spew", style, rect.left,
1171 rect.top, rect.right, rect.bottom, NULL, NULL, hInst, NULL);
1173 // Show it, but don't activate it. If you activate it, it cause problems
1174 // with fullscreen startups in main window.
1175 SetWindowPos( hOutputWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW );
1177 outwnd_disabled = FALSE;
1178 SetTimer(hOutputWnd, TIMER1, 50, NULL);
1179 for (x=0; x<MAX_LINE_WIDTH; x++)
1182 spaces[MAX_LINE_WIDTH] = 0;
1186 DWORD outwnd_thread(int display_under_freespace_window)
1190 if (!outwnd_create(display_under_freespace_window))
1194 if (WaitMessage()) {
1195 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
1196 TranslateMessage(&msg);
1197 DispatchMessage(&msg);
1201 if (outwnd_disabled) break;
1208 // DeviceIoControl (mono_driver, (DWORD) IOCTL_MONO_CLEAR_SCREEN, NULL, 0, NULL, 0, &cbReturned, 0);
1209 if (hOutputThread) {
1210 CloseHandle(hOutputThread);
1211 hOutputThread = NULL;
1214 CloseHandle(mono_driver);
1219 void outwnd_init(int display_under_freespace_window)
1222 if (!outwnd_inited) {
1223 outwnd_inited = TRUE;
1224 hOutputThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)outwnd_thread, (LPVOID)display_under_freespace_window, 0, &OutputThreadID);
1225 //SetThreadPriority(hOutputThread, THREAD_PRIORITY_TIME_CRITICAL);
1227 // set up the monochrome drivers
1228 if ( (mono_driver = CreateFile("\\\\.\\MONO", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == ((HANDLE)-1)) {
1229 outwnd_printf2("Cannot get handle to monochrome driver.\n");
1238 if ( Log_fp == NULL ) {
1239 Log_fp = fopen(Freespace_logfilename, "wb");
1244 BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
1249 switch (LOWORD(wParam)) {
1251 GetDlgItemText(hwnd, IDC_TEXT, find_text, 82); // get the text to find
1252 EndDialog(hwnd, IDOK);
1262 SendDlgItemMessage(hwnd, IDC_TEXT, EM_LIMITTEXT, 80, 0); // limit text to 80 chars
1263 if (GetDlgCtrlID((HWND) wParam) != IDC_TEXT) {
1264 SetFocus(GetDlgItem(hwnd, IDC_TEXT));
1274 void find_text_in_outwindow(int n, int p)
1278 str = outtext[n] + p;
1281 ptr = strstr(str, find_text);
1284 int scroll_pos, pos;
1286 find_pos = ptr - str;
1289 marked_top = marked_bottom = find_line;
1290 marked_left = find_pos;
1291 marked_right = find_pos + strlen(find_text);
1293 scroll_pos = (max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT));
1294 pos = mprintf_last_line - scroll_pos;
1296 pos += SCROLL_BUFFER_SIZE;
1300 pos += SCROLL_BUFFER_SIZE;
1303 if (pos >= nCharRows - 1) // outside of window viewport, so scroll
1307 pos = mprintf_last_line - n - nCharRows / 2;
1309 pos += SCROLL_BUFFER_SIZE;
1311 if (pos > max_scroll_pos)
1312 pos = max_scroll_pos;
1314 scroll_pos = max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT);
1315 si.cbSize = sizeof(SCROLLINFO);
1317 si.nPos = max_scroll_pos - pos;
1318 SetScrollInfo(hOutputWnd, SB_VERT, &si, 1);
1319 ScrollWindow(hOutputWnd, 0, (scroll_pos - pos) * nTextHeight, NULL, NULL);
1322 InvalidateRect(hOutputWnd, NULL, 0);
1323 UpdateWindow(hOutputWnd);
1329 n += SCROLL_BUFFER_SIZE;
1331 if (n == mprintf_last_line)
1333 MessageBox(hOutputWnd, "Search text not found", "Find Error", MB_OK | MB_ICONERROR);
1345 if ( Log_fp != NULL ) {