2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/OsApi/OutWnd.cpp $
15 * Routines for debugging output
18 * Revision 1.3 2002/06/09 04:41:25 relnev
19 * added copyright header
21 * Revision 1.2 2002/05/07 03:16:48 theoddone33
22 * The Great Newline Fix
24 * Revision 1.1.1.1 2002/05/03 03:28:10 root
28 * 6 6/03/99 6:37p Dave
29 * More TNT fun. Made perspective bitmaps more flexible.
31 * 5 6/02/99 6:18p Dave
32 * Fixed TNT lockup problems! Wheeeee!
34 * 4 12/14/98 12:13p Dave
35 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
38 * 3 10/08/98 2:38p Dave
39 * Cleanup up OsAPI code significantly. Removed old functions, centralized
42 * 2 10/07/98 10:53a Dave
45 * 1 10/07/98 10:50a Dave
47 * 49 5/15/98 3:36p John
48 * Fixed bug with new graphics window code and standalone server. Made
49 * hwndApp not be a global anymore.
51 * 48 5/14/98 5:42p John
52 * Revamped the whole window position/mouse code for the graphics windows.
54 * 47 5/14/98 11:24a Allender
55 * throw mprints to outtext regardless of gr mode
57 * 46 4/30/98 4:53p John
58 * Restructured and cleaned up cfile code. Added capability to read off
59 * of CD-ROM drive and out of multiple pack files.
61 * 45 4/16/98 6:31p Dave
62 * Doubled MAX_FILTERS to 48
64 * 44 3/31/98 5:18p John
65 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
66 * bunch of debug stuff out of player file. Made model code be able to
67 * unload models and malloc out only however many models are needed.
70 * 43 3/11/98 12:06p John
71 * Made it so output window never gets focus upon startup
73 * 42 2/16/98 9:47a John
74 * Made so only error, general, and warning are shown if no
75 * debug_filter.cfg and .cfg file isn't saved if so.
77 * 41 2/05/98 9:21p John
78 * Some new Direct3D code. Added code to monitor a ton of stuff in the
81 * 40 1/15/98 9:14p John
82 * Made it so general, error and warning can't be turned off.
84 * 39 9/13/97 10:44a Lawrance
85 * allow logging of nprintf output to file
87 * 38 8/23/97 11:32a Dave
88 * Made debug window size correctly in standalone mode.
90 * 37 8/22/97 3:42p Hoffoss
91 * Lowered the filter limit to 24, and added support for filter recycling,
92 * instead of the rather nasty Assert if we should happen to exceed this
95 * 36 8/05/97 4:29p Dave
96 * Futzed with window sizes/placements for standalone mode.
98 * 35 8/04/97 3:15p Dave
99 * Added an include for systemvars.h
101 * 34 5/20/97 1:13p Allender
102 * fixes to make outwnd work better under Win95
104 * 33 5/14/97 11:08a John
105 * fixed bug under 95 that occasionally hung program.
107 * 32 5/07/97 3:01p Lawrance
108 * check for NT in mono_init
110 * 31 5/07/97 3:06p John
111 * disabled new mono direct stuff under NT.
113 * 30 5/07/97 2:59p John
114 * Made so mono driver works under '95.
116 * 29 4/22/97 10:56a John
117 * fixed some resource leaks.
129 // to disable otherwise well-lodged compiler warning
130 #pragma warning(disable: 4201)
132 #include <winioctl.h>
140 #include "freespaceresource.h"
141 #include "systemvars.h"
143 #define MAX_FILTERS 48
144 #define SCROLL_BUFFER_SIZE 512
145 #define MAX_LINE_WIDTH 128
146 #define TASKBAR_HEIGHT 30
148 #define ID_COPY 32000
149 #define ID_FIND 32010
150 #define ID_FILTER 32100
152 #define UP_FAST 65537
153 #define DOWN_FAST 65538
155 HANDLE hOutputThread=NULL;
156 DWORD OutputThreadID;
159 char szOutputClass[] = "OutputWindow";
160 char spaces[MAX_LINE_WIDTH + 1];
161 int outwnd_filter_count = 0;
162 int outwnd_filter_loaded = 0;
165 struct outwnd_filter_struct {
166 char name[FILTER_NAME_LENGTH];
168 } *outwnd_filter[MAX_FILTERS], real_outwnd_filter[MAX_FILTERS];
170 int mprintf_last_line = -1;
171 char outtext[SCROLL_BUFFER_SIZE][MAX_LINE_WIDTH];
172 int old_scroll_pos = -32768;
173 int nTextHeight=0, nTextWidth=0, nCharRows=0;
174 int outwnd_inited = FALSE;
175 int outwnd_disabled = TRUE;
176 int max_scroll_pos = SCROLL_BUFFER_SIZE - 1;
177 static int marked = 0;
178 int marked_top, marked_bottom, marked_left, marked_right;
179 int old_marked = 0, old_marked_top, old_marked_bottom, old_marked_left, old_marked_right;
180 int marking_started_x, marking_started_y, client_top_yoffset, cur_line_index, marking_active = 0;
182 BOOL OutputActive = FALSE;
183 LPARAM last_mousemove;
184 int Outwnd_changed = 0;
185 int find_line = -1, find_pos;
187 // monochrome screen info
188 HANDLE mono_driver=NULL; // handle to the monochrome driver
190 void outwnd_print(char *id, char *tmp);
191 BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam);
192 void find_text_in_outwindow(int n, int p);
193 void outwnd_copy_marked_selection(HWND hwnd);
194 void outwnd_update_marking(LPARAM l_parm, HWND hwnd);
195 void outwnd_paint(HWND hwnd);
197 int Outwnd_no_filter_file = 0; // 0 = .cfg file found, 1 = not found and warning not printed yet, 2 = not found and warning printed
199 // used for file logging
201 int Log_debug_output_to_file = 0;
203 char *Freespace_logfilename = "fs.log";
206 inline void text_hilight(HDC &hdc)
208 SetBkColor(hdc, RGB(0, 0, 0));
209 SetTextColor(hdc, RGB(255, 255, 255));
212 inline void text_normal(HDC &hdc)
214 SetBkColor(hdc, RGB(255, 255, 255));
215 SetTextColor(hdc, RGB(0, 0, 0));
218 inline void fix_marking_coords(int &x, int &y, LPARAM l_parm)
220 x = (signed short) LOWORD(l_parm) / nTextWidth;
221 y = ((signed short) HIWORD(l_parm) - client_top_yoffset) / nTextHeight + cur_line_index;
226 if (y > SCROLL_BUFFER_SIZE)
228 y = SCROLL_BUFFER_SIZE;
235 if (x > MAX_LINE_WIDTH)
238 x = 0; // marks to end of line
243 // InvalidateRect(hOutputWnd,NULL,0);
245 void load_filter_info(void)
248 char pathname[256], inbuf[FILTER_NAME_LENGTH+4];
251 outwnd_filter_loaded = 1;
252 outwnd_filter_count = 0;
253 strcpy(pathname, "Debug_filter.cfg" );
254 fp = fopen(pathname, "rt");
256 Outwnd_no_filter_file = 1;
258 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
259 strcpy( outwnd_filter[outwnd_filter_count]->name, "error" );
260 outwnd_filter[outwnd_filter_count]->state = 1;
261 outwnd_filter_count++;
263 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
264 strcpy( outwnd_filter[outwnd_filter_count]->name, "general" );
265 outwnd_filter[outwnd_filter_count]->state = 1;
266 outwnd_filter_count++;
268 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
269 strcpy( outwnd_filter[outwnd_filter_count]->name, "warning" );
270 outwnd_filter[outwnd_filter_count]->state = 1;
271 outwnd_filter_count++;
276 Outwnd_no_filter_file = 0;
278 while (fgets(inbuf, FILTER_NAME_LENGTH+3, fp))
280 if (outwnd_filter_count == MAX_FILTERS)
283 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
285 outwnd_filter[outwnd_filter_count]->state = 1;
286 else if (*inbuf == '-')
287 outwnd_filter[outwnd_filter_count]->state = 0;
288 else continue; // skip everything else
290 z = strlen(inbuf) - 1;
291 if (inbuf[z] == '\n')
294 Assert(strlen(inbuf+1) < FILTER_NAME_LENGTH);
295 strcpy(outwnd_filter[outwnd_filter_count]->name, inbuf + 1);
297 if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "error" ) ) {
298 outwnd_filter[outwnd_filter_count]->state = 1;
299 } else if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "general" ) ) {
300 outwnd_filter[outwnd_filter_count]->state = 1;
301 } else if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "warning" ) ) {
302 outwnd_filter[outwnd_filter_count]->state = 1;
305 outwnd_filter_count++;
308 if (ferror(fp) && !feof(fp))
309 nprintf(("Error", "Error reading \"%s\"\n", pathname));
314 void save_filter_info(void)
320 if (!outwnd_filter_loaded)
323 if ( Outwnd_no_filter_file ) {
324 return; // No file, don't save
327 strcpy(pathname, "Debug_filter.cfg" );
328 fp = fopen(pathname, "wt");
331 for (i=0; i<outwnd_filter_count; i++)
332 fprintf(fp, "%c%s\n", outwnd_filter[i]->state ? '+' : '-', outwnd_filter[i]->name);
338 void outwnd_printf2(char *format, ...)
340 char tmp[MAX_LINE_WIDTH*4];
343 va_start(args, format);
344 vsprintf(tmp, format, args);
346 outwnd_print("General", tmp);
350 char mono_ram[80*25*2];
356 if ( !mono_found ) return;
357 memcpy( (void *)0xb0000, mono_ram, 80*25*2 );
366 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
368 if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
373 _outp( 0x3b4, 0x0f );
374 _outp( 0x3b4+1, 0x55 );
376 if ( _inp( 0x3b4+1 ) == 0x55 ) {
385 for (i=0; i<80*25; i++ ) {
386 mono_ram[i*2+0] = ' ';
387 mono_ram[i*2+1] = 0x07;
394 void mono_print( char * text, int len )
398 if ( !mono_found ) return;
400 for (i=0; i<len; i++ ) {
408 mono_ram[mono_y*160+mono_x*2] = text[i];
422 memmove( mono_ram, mono_ram+160, 80*24*2 );
423 for (j=0; j<80; j++ ) {
424 mono_ram[24*160+j*2] = ' ';
434 void outwnd_printf(char *id, char *format, ...)
436 char tmp[MAX_LINE_WIDTH*4];
439 va_start(args, format);
440 vsprintf(tmp, format, args);
442 outwnd_print(id, tmp);
445 void outwnd_print(char *id, char *tmp)
450 outwnd_filter_struct *temp;
452 if(gr_screen.mode == GR_DIRECT3D){
459 if ( Outwnd_no_filter_file == 1 ) {
460 Outwnd_no_filter_file = 2;
462 outwnd_print( "general", "==========================================================================\n" );
463 outwnd_print( "general", "DEBUG SPEW: No debug_filter.cfg found, so only general, error, and warning\n" );
464 outwnd_print( "general", "categories can be shown and no debug_filter.cfg info will be saved.\n" );
465 outwnd_print( "general", "==========================================================================\n" );
471 for (i=0; i<outwnd_filter_count; i++)
472 if (!stricmp(id, outwnd_filter[i]->name))
476 if (i == outwnd_filter_count) // new id found that's not yet in filter list
478 // Only create new filters if there was a filter file
479 if ( Outwnd_no_filter_file ) {
483 if (outwnd_filter_count >= MAX_FILTERS) {
484 Assert(outwnd_filter_count == MAX_FILTERS); // how did it get over the max? Very bad..
485 outwnd_printf("General", "Outwnd filter limit reached. Recycling \"%s\" to add \"%s\"",
486 outwnd_filter[MAX_FILTERS - 1]->name, id);
488 i--; // overwrite the last element (oldest used filter in the list)
491 Assert(strlen(id) < FILTER_NAME_LENGTH);
492 outwnd_filter[i] = &real_outwnd_filter[i]; // note: this assumes the list doesn't have gaps (from deleting an element for example)
493 strcpy(outwnd_filter[i]->name, id);
494 outwnd_filter[i]->state = 1;
495 outwnd_filter_count = i + 1;
499 // sort the filters from most recently used to oldest, so oldest ones will get recycled first
500 temp = outwnd_filter[i];
502 outwnd_filter[i + 1] = outwnd_filter[i];
505 outwnd_filter[i] = temp;
507 if (!outwnd_filter[i]->state)
510 if (mprintf_last_line == -1 ) {
511 for (i=0; i<SCROLL_BUFFER_SIZE;i++) {
515 mprintf_last_line = 0;
518 // printf out to the monochrome screen first
519 if ( mono_driver != ((HANDLE)-1) ) {
522 DeviceIoControl (mono_driver, (DWORD)IOCTL_MONO_PRINT, tmp, strlen(tmp), NULL, 0, &cbReturned, 0 );
524 mono_print(tmp, strlen(tmp) );
528 ccol = strlen(outtext[mprintf_last_line] );
529 dptr = &outtext[mprintf_last_line][ccol];
534 if ( Log_debug_output_to_file ) {
535 if ( Log_fp != NULL ) {
544 if ( (*sptr == '\n') || (ccol >= MAX_LINE_WIDTH-1 ) ) {
547 if (mprintf_last_line >= SCROLL_BUFFER_SIZE )
548 mprintf_last_line = 0;
550 if ( *sptr != '\n' ) {
551 outtext[mprintf_last_line][ccol] = *sptr;
554 outtext[mprintf_last_line][ccol] = '\0';
555 dptr = &outtext[mprintf_last_line][ccol];
564 if(gr_screen.mode == GR_DIRECT3D){
567 // if ( D3D_enabled ) {
568 // return; // Direct3D seems to hang sometimes printing to window
571 if ( outwnd_disabled ){
575 if ( !OutputActive ) {
576 int oldpos = GetScrollPos( hOutputWnd, SB_VERT );
577 if ( oldpos != max_scroll_pos ) {
579 si.cbSize = sizeof(SCROLLINFO);
581 si.nPos = max_scroll_pos;
582 SetScrollInfo(hOutputWnd, SB_VERT, &si, 1 );
583 InvalidateRect(hOutputWnd,NULL,0);
584 UpdateWindow(hOutputWnd);
588 ScrollWindow(hOutputWnd,0,-nTextHeight*nrows,NULL,NULL);
589 GetClientRect(hOutputWnd, &client);
590 client.top = client.bottom - nTextHeight*(nrows+1);
591 InvalidateRect(hOutputWnd,&client,0);
593 UpdateWindow(hOutputWnd);
601 LRESULT CALLBACK outwnd_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
606 // The application z-ordering has change
607 // foreground application wParm will be
608 OutputActive = (BOOL)wParam;
613 si.cbSize = sizeof(SCROLLINFO);
614 si.fMask = SIF_RANGE | SIF_POS;
616 si.nMax = max_scroll_pos;
617 si.nPos = max_scroll_pos;
618 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
624 PostMessage(hwnd, WM_MOUSEMOVE, 0, last_mousemove);
626 if ( Outwnd_changed ) {
628 GetClientRect(hOutputWnd, &client);
629 client.top = client.bottom - nTextHeight;
630 InvalidateRect(hOutputWnd,&client,0);
640 if (z >= ID_FILTER && z < ID_FILTER + outwnd_filter_count)
643 outwnd_filter[z]->state = !outwnd_filter[z]->state;
645 if ( !stricmp( outwnd_filter[z]->name, "error" ) ) {
646 outwnd_filter[z]->state = 1;
647 } else if ( !stricmp( outwnd_filter[z]->name, "general" ) ) {
648 outwnd_filter[z]->state = 1;
649 } else if ( !stricmp( outwnd_filter[z]->name, "warning" ) ) {
650 outwnd_filter[z]->state = 1;
659 outwnd_copy_marked_selection(hwnd);
664 if (DialogBox(GetModuleHandle(NULL), "FIND_DIALOG", hOutputWnd,
665 (int (__stdcall *)(void)) find_dlg_handler) == IDOK)
667 find_text_in_outwindow(mprintf_last_line, 0);
676 case WM_RBUTTONDOWN: {
677 HMENU h_menu = CreatePopupMenu();
678 HMENU h_sub_menu = CreatePopupMenu();
682 for (i=0; i<outwnd_filter_count; i++)
684 UINT flags = MFT_STRING; //MF_GRAYED;
686 if ( !stricmp( outwnd_filter[i]->name, "error" ) ) {
688 } else if ( !stricmp( outwnd_filter[i]->name, "general" ) ) {
690 } else if ( !stricmp( outwnd_filter[i]->name, "warning" ) ) {
694 if (outwnd_filter[i]->state)
695 AppendMenu(h_sub_menu, flags | MF_CHECKED, ID_FILTER + i, outwnd_filter[i]->name);
697 AppendMenu(h_sub_menu, flags, ID_FILTER + i, outwnd_filter[i]->name);
700 AppendMenu(h_menu, MFT_STRING, ID_COPY, "&Copy\tEnter");
701 AppendMenu(h_menu, MFT_STRING, ID_FIND, "&Find Text");
702 AppendMenu(h_menu, MF_POPUP, (unsigned int) h_sub_menu, "Filter &Messages");
703 pt.x = LOWORD(lParam);
704 pt.y = HIWORD(lParam);
705 ClientToScreen(hwnd, &pt);
707 TrackPopupMenu(h_menu, 0, pt.x, pt.y, 0, hwnd, NULL);
713 fix_marking_coords(marking_started_x, marking_started_y, lParam);
714 SetCapture(hwnd); // monopolize mouse
716 outwnd_update_marking(lParam, hwnd);
720 last_mousemove = lParam;
722 outwnd_update_marking(lParam, hwnd);
731 outwnd_update_marking(lParam, hwnd);
737 int vpos = GetScrollPos( hwnd, SB_VERT );
739 switch (LOWORD(wParam)) {
746 case SB_THUMBPOSITION:
747 vpos = HIWORD(wParam);
750 vpos = HIWORD(wParam);
759 if ( vpos < 0 ) vpos = 0;
760 else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos;
761 si.cbSize = sizeof(SCROLLINFO);
764 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
765 ScrollWindow(hwnd,0,(old_vpos-vpos)*nTextHeight,NULL,NULL);
766 UpdateWindow(hOutputWnd);
767 //InvalidateRect(hOutputWnd,NULL,0);
773 int vpos = GetScrollPos( hwnd, SB_VERT );
775 int nVirtKey = (int) wParam; // virtual-key code
795 vpos = max_scroll_pos;
798 outwnd_copy_marked_selection(hwnd);
800 case UP_FAST: // special value we define
803 case DOWN_FAST: // special value we define
808 if ( vpos < 0 ) vpos = 0;
809 else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos;
810 si.cbSize = sizeof(SCROLLINFO);
813 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
814 ScrollWindow(hwnd, 0, (old_vpos-vpos)*nTextHeight, NULL, NULL);
815 UpdateWindow(hOutputWnd);
816 //InvalidateRect(hOutputWnd,NULL,0);
821 InvalidateRect(hOutputWnd,NULL,0);
834 return DefWindowProc(hwnd, msg, wParam, lParam);
841 void outwnd_copy_marked_selection(HWND hwnd)
847 if (marked_top == marked_bottom)
849 size += marked_right - marked_left;
853 size += strlen(outtext[i++]) - marked_left + 2;
855 while (i < marked_bottom)
856 size += strlen(outtext[i++]) + 2;
858 size += marked_right;
861 h_text = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
862 ptr = (char *) GlobalLock(h_text);
864 if (marked_top == marked_bottom)
866 i = marked_right - marked_left;
867 memcpy(ptr, outtext[marked_top] + marked_left, i);
872 strcpy(ptr, outtext[i] + marked_left);
876 while (i < marked_bottom)
878 strcat(ptr, outtext[i++]);
882 ptr[strlen(ptr) + marked_right] = 0;
883 strncat(ptr, outtext[i], marked_right);
886 GlobalUnlock(h_text);
889 SetClipboardData(CF_TEXT, h_text);
893 InvalidateRect(hwnd, NULL, 0);
896 void outwnd_paint(HWND hwnd)
899 int old_nrows, scroll_pos;
904 HFONT newfont, oldfont;
905 HBRUSH newbrush, oldbrush;
909 hdc = BeginPaint(hwnd, &ps);
910 GetClientRect(hOutputWnd, &client);
911 newfont = (HFONT)GetStockObject(ANSI_FIXED_FONT);
912 oldfont = (HFONT)SelectObject(hdc,newfont);
914 GetTextMetrics(hdc, &tm);
915 nTextHeight = tm.tmHeight + tm.tmExternalLeading;
916 nTextWidth = tm.tmAveCharWidth;
917 old_nrows = nCharRows;
918 nCharRows = ((client.bottom-client.top)/nTextHeight)+1;
920 newbrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
921 oldbrush = (HBRUSH)SelectObject(hdc,newbrush);
923 y = client.bottom - nTextHeight * nCharRows; // starting y position at top
924 client_top_yoffset = y - nTextHeight;
925 scroll_pos = (max_scroll_pos - GetScrollPos( hOutputWnd, SB_VERT ));
926 cur_line_index = x = mprintf_last_line - scroll_pos - nCharRows;
927 if (x >= marked_top && x < marked_bottom) // starting in marked area
931 if (scroll_pos != old_scroll_pos) {
934 sprintf( tmp, "Debug Spew");
935 SetWindowText( hOutputWnd, tmp );
939 sprintf( tmp, "Debug Spew [Scrolled back %d lines]", scroll_pos );
940 SetWindowText( hOutputWnd, tmp );
943 old_scroll_pos = scroll_pos;
949 n = mprintf_last_line - scroll_pos - i;
951 n += SCROLL_BUFFER_SIZE;
953 if (n >= 0 && n < SCROLL_BUFFER_SIZE)
955 len = strlen(outtext[n]);
958 if (n == marked_top && n == marked_bottom) // special 1 line case
961 TextOut(hdc, 0, y, outtext[n], marked_left);
964 x = marked_left * nTextWidth;
965 TextOut(hdc, x, y, outtext[n] + marked_left, marked_right -
969 x = marked_right * nTextWidth;
970 if (marked_right < len)
971 TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right);
973 x = len * nTextWidth;
974 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
976 } else if (n == marked_top) { // start marked on this line
978 TextOut(hdc, 0, y, outtext[n], marked_left);
981 x = marked_left * nTextWidth;
983 TextOut(hdc, x, y, outtext[n] + marked_left, len - marked_left);
985 x = len * nTextWidth;
986 if (marked_left < MAX_LINE_WIDTH)
987 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - marked_left);
989 } else if (n == marked_bottom) { // end marked on this line
991 TextOut(hdc, 0, y, outtext[n], marked_right);
994 x = marked_right * nTextWidth;
995 if (marked_right < len)
996 TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right);
998 x = len * nTextWidth;
999 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
1001 } else { // whole line marked
1002 TextOut(hdc, 0, y, outtext[n], len);
1003 x = len * nTextWidth;
1004 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
1008 TextOut(hdc, 0, y, outtext[n], len);
1009 x = len * nTextWidth;
1010 TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
1013 TextOut(hdc, 0, y, spaces, MAX_LINE_WIDTH);
1019 SelectObject(hdc, oldfont);
1020 SelectObject(hdc, oldbrush);
1021 DeleteObject(newbrush);
1023 if ( old_nrows != nCharRows ) {
1025 max_scroll_pos = SCROLL_BUFFER_SIZE-nCharRows - 1;
1026 si.cbSize = sizeof(SCROLLINFO);
1027 si.fMask = SIF_RANGE;
1029 si.nMax = max_scroll_pos;
1030 SetScrollInfo(hwnd, SB_VERT, &si, 1 );
1033 EndPaint(hwnd, &ps);
1037 void outwnd_update_marking(LPARAM l_parm, HWND hwnd)
1043 y = (signed short) HIWORD(l_parm);
1044 GetClientRect(hwnd, &rect);
1047 SendMessage(hwnd, WM_KEYDOWN, UP_FAST, 0);
1051 SendMessage(hwnd, WM_KEYDOWN, VK_UP, 0);
1055 if (y >= rect.bottom + 150) {
1056 SendMessage(hwnd, WM_KEYDOWN, DOWN_FAST, 0);
1059 } else if (y >= rect.bottom) {
1060 SendMessage(hwnd, WM_KEYDOWN, VK_DOWN, 0);
1065 fix_marking_coords(x, y, l_parm);
1067 marked_top = marked_bottom = marking_started_y;
1068 marked_left = marking_started_x;
1069 marked_right = marking_started_x + 1;
1076 } else if (y > marked_bottom) {
1078 marked_right = x + 1;
1080 } else { // must be single line case
1081 if (x < marked_left)
1083 if (x >= marked_right)
1084 marked_right = x + 1;
1086 if (marked_left >= (signed int) strlen(outtext[y]))
1088 marked = 0; // this isn't going to even show up
1093 if (marked_left >= (signed int) strlen(outtext[marked_top]))
1099 if (marked_right > (signed int) strlen(outtext[marked_bottom]))
1100 marked_right = strlen(outtext[marked_bottom]);
1102 if (marked && (marked_top > marked_bottom || (marked_top == marked_bottom &&
1103 marked_left >= marked_right)))
1107 sprintf(msg, "Marking limits invalid!\n"
1108 "(%d,%d) to (%d,%d)", marked_left, marked_top, marked_right, marked_bottom);
1110 MessageBox(hwnd, msg, "Error", MB_OK | MB_ICONERROR);
1114 if (marked != old_marked || marked_top != old_marked_top || marked_bottom !=
1115 old_marked_bottom || marked_left != old_marked_left || marked_right !=
1118 old_marked = marked;
1119 old_marked_left = marked_left;
1120 old_marked_right = marked_right;
1121 old_marked_top = marked_top;
1122 old_marked_bottom = marked_bottom;
1123 InvalidateRect(hwnd, NULL, 0);
1127 BOOL outwnd_create(int display_under_freespace_window)
1131 HINSTANCE hInst = GetModuleHandle(NULL);
1135 wclass.hInstance = hInst;
1136 wclass.lpszClassName = szOutputClass;
1137 wclass.lpfnWndProc = (WNDPROC) outwnd_handler;
1138 wclass.style = CS_BYTEALIGNCLIENT | CS_OWNDC; //CS_DBLCLKS | CS_PARENTDC| CS_VREDRAW | CS_HREDRAW |;
1139 wclass.cbSize = sizeof(WNDCLASSEX);
1140 wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1141 wclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
1142 wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
1143 wclass.lpszMenuName = NULL; //"FreeSpaceMenu";
1144 wclass.cbClsExtra = 0;
1145 wclass.cbWndExtra = 0;
1146 wclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //(HBRUSH)NULL;
1148 if (!RegisterClassEx(&wclass))
1151 if (display_under_freespace_window) {
1152 style = WS_OVERLAPPEDWINDOW;;
1155 client_rect.left = client_rect.top = 0;
1156 client_rect.right = 640;
1157 client_rect.bottom = 480;
1158 AdjustWindowRect(&client_rect,WS_CAPTION | WS_SYSMENU,FALSE);
1160 int x = (GetSystemMetrics( SM_CXSCREEN )-(client_rect.right - client_rect.left))/2;
1166 rect.right = x + client_rect.right - client_rect.left - 1;
1167 rect.bottom = y + client_rect.bottom - client_rect.top - 1;
1170 rect.top = rect.bottom;
1171 rect.bottom = GetSystemMetrics(SM_CYSCREEN) - TASKBAR_HEIGHT - rect.top;
1172 rect.right -= rect.left;
1179 style = WS_OVERLAPPEDWINDOW | WS_MINIMIZE;;
1180 rect.top = rect.bottom = rect.left = rect.right = CW_USEDEFAULT;
1183 // Create Game Window
1184 hOutputWnd = CreateWindow(szOutputClass, "Debug Spew", style, rect.left,
1185 rect.top, rect.right, rect.bottom, NULL, NULL, hInst, NULL);
1187 // Show it, but don't activate it. If you activate it, it cause problems
1188 // with fullscreen startups in main window.
1189 SetWindowPos( hOutputWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW );
1191 outwnd_disabled = FALSE;
1192 SetTimer(hOutputWnd, TIMER1, 50, NULL);
1193 for (x=0; x<MAX_LINE_WIDTH; x++)
1196 spaces[MAX_LINE_WIDTH] = 0;
1200 DWORD outwnd_thread(int display_under_freespace_window)
1204 if (!outwnd_create(display_under_freespace_window))
1208 if (WaitMessage()) {
1209 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
1210 TranslateMessage(&msg);
1211 DispatchMessage(&msg);
1215 if (outwnd_disabled) break;
1222 // DeviceIoControl (mono_driver, (DWORD) IOCTL_MONO_CLEAR_SCREEN, NULL, 0, NULL, 0, &cbReturned, 0);
1223 if (hOutputThread) {
1224 CloseHandle(hOutputThread);
1225 hOutputThread = NULL;
1228 CloseHandle(mono_driver);
1233 void outwnd_init(int display_under_freespace_window)
1236 if (!outwnd_inited) {
1237 outwnd_inited = TRUE;
1238 hOutputThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)outwnd_thread, (LPVOID)display_under_freespace_window, 0, &OutputThreadID);
1239 //SetThreadPriority(hOutputThread, THREAD_PRIORITY_TIME_CRITICAL);
1241 // set up the monochrome drivers
1242 if ( (mono_driver = CreateFile("\\\\.\\MONO", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == ((HANDLE)-1)) {
1243 outwnd_printf2("Cannot get handle to monochrome driver.\n");
1252 if ( Log_fp == NULL ) {
1253 Log_fp = fopen(Freespace_logfilename, "wb");
1258 BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
1263 switch (LOWORD(wParam)) {
1265 GetDlgItemText(hwnd, IDC_TEXT, find_text, 82); // get the text to find
1266 EndDialog(hwnd, IDOK);
1276 SendDlgItemMessage(hwnd, IDC_TEXT, EM_LIMITTEXT, 80, 0); // limit text to 80 chars
1277 if (GetDlgCtrlID((HWND) wParam) != IDC_TEXT) {
1278 SetFocus(GetDlgItem(hwnd, IDC_TEXT));
1288 void find_text_in_outwindow(int n, int p)
1292 str = outtext[n] + p;
1295 ptr = strstr(str, find_text);
1298 int scroll_pos, pos;
1300 find_pos = ptr - str;
1303 marked_top = marked_bottom = find_line;
1304 marked_left = find_pos;
1305 marked_right = find_pos + strlen(find_text);
1307 scroll_pos = (max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT));
1308 pos = mprintf_last_line - scroll_pos;
1310 pos += SCROLL_BUFFER_SIZE;
1314 pos += SCROLL_BUFFER_SIZE;
1317 if (pos >= nCharRows - 1) // outside of window viewport, so scroll
1321 pos = mprintf_last_line - n - nCharRows / 2;
1323 pos += SCROLL_BUFFER_SIZE;
1325 if (pos > max_scroll_pos)
1326 pos = max_scroll_pos;
1328 scroll_pos = max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT);
1329 si.cbSize = sizeof(SCROLLINFO);
1331 si.nPos = max_scroll_pos - pos;
1332 SetScrollInfo(hOutputWnd, SB_VERT, &si, 1);
1333 ScrollWindow(hOutputWnd, 0, (scroll_pos - pos) * nTextHeight, NULL, NULL);
1336 InvalidateRect(hOutputWnd, NULL, 0);
1337 UpdateWindow(hOutputWnd);
1343 n += SCROLL_BUFFER_SIZE;
1345 if (n == mprintf_last_line)
1347 MessageBox(hOutputWnd, "Search text not found", "Find Error", MB_OK | MB_ICONERROR);
1359 if ( Log_fp != NULL ) {