Files
fs2open.github.com/code/osapi/outwnd.cpp
T
The_E 9284264885 Patch to add MSVC2015 support. Also fixes a few warnings its compiler threw.
git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@11292 387891d4-d844-0410-90c0-e4c51a9137d3
2015-03-29 11:05:02 +10:00

1352 lines
30 KiB
C++

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#ifndef NDEBUG
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
// to disable otherwise well-lodged compiler warning
#pragma warning(disable: 4201) // nameless struct/union
#include <winioctl.h>
#include <conio.h>
#include "osapi/osapi.h"
#include "osapi/outwnd.h"
#include "osapi/monopub.h"
#include "graphics/2d.h"
#include "freespace2/freespaceresource.h"
#include "globalincs/systemvars.h"
#include "cfile/cfilesystem.h"
#include "globalincs/globals.h"
#include "parse/parselo.h"
extern int Cmdline_debug_window;
#define SCROLL_BUFFER_SIZE 512
#define MAX_LINE_WIDTH 128
#define TASKBAR_HEIGHT 30
#define ID_COPY 32000
#define ID_FIND 32010
#define ID_FILTER 32100
#define TIMER1 1
#define UP_FAST 65537
#define DOWN_FAST 65538
HANDLE hOutputThread=NULL;
DWORD OutputThreadID;
HWND hOutputWnd;
char szOutputClass[] = "OutputWindow";
char spaces[MAX_LINE_WIDTH + 1];
ubyte outwnd_filter_loaded = 0;
char find_text[85];
struct outwnd_filter_struct {
char name[NAME_LENGTH];
bool enabled;
};
SCP_vector<outwnd_filter_struct> OutwndFilter;
int mprintf_last_line = -1;
char outtext[SCROLL_BUFFER_SIZE][MAX_LINE_WIDTH];
int old_scroll_pos = -32768;
int nTextHeight=0, nTextWidth=0, nCharRows=0;
bool outwnd_inited = false;
bool outwnd_disabled = true;
int max_scroll_pos = SCROLL_BUFFER_SIZE - 1;
static int marked = 0;
int marked_top, marked_bottom, marked_left, marked_right;
int old_marked = 0, old_marked_top, old_marked_bottom, old_marked_left, old_marked_right;
int marking_started_x, marking_started_y, client_top_yoffset, cur_line_index, marking_active = 0;
int scroll_wait = 1;
BOOL OutputActive = FALSE;
LPARAM last_mousemove;
int Outwnd_changed = 0;
int find_line = -1, find_pos;
// monochrome screen info
#define NMONO
HANDLE mono_driver=NULL; // handle to the monochrome driver
void outwnd_print(const char *id = NULL, const char *temp = NULL);
BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam);
void find_text_in_outwindow(int n, int p);
void outwnd_copy_marked_selection(HWND hwnd);
void outwnd_update_marking(LPARAM l_parm, HWND hwnd);
void outwnd_paint(HWND hwnd);
ubyte Outwnd_no_filter_file = 0; // 0 = .cfg file found, 1 = not found and warning not printed yet, 2 = not found and warning printed
// used for file logging
int Log_debug_output_to_file = 1;
FILE *Log_fp = NULL;
char *FreeSpace_logfilename = NULL;
SCP_string safe_string;
#ifndef _MSC_VER
inline void _outp(unsigned short port, unsigned char value)
{
asm(
"mov %0,%%al;"
"mov %1,%%dx;"
"out %%al,%%dx;"
: : "g" (value), "g" (port) : "al", "dx");
}
inline unsigned char _inp(unsigned short port)
{
unsigned char value;
asm(
"mov %1,%%dx;"
"in %%dx,%%al;"
"mov %%al,%0"
: "=g"(value) : "g" (port) : "al", "dx");
return value;
}
#endif
inline void text_hilight(HDC &hdc)
{
SetBkColor(hdc, RGB(0, 0, 0));
SetTextColor(hdc, RGB(255, 255, 255));
}
inline void text_normal(HDC &hdc)
{
SetBkColor(hdc, RGB(255, 255, 255));
SetTextColor(hdc, RGB(0, 0, 0));
}
inline void fix_marking_coords(int &x, int &y, LPARAM l_parm)
{
x = (signed short) LOWORD(l_parm) / nTextWidth;
y = ((signed short) HIWORD(l_parm) - client_top_yoffset) / nTextHeight + cur_line_index;
if (y < 0)
y = x = 0;
if (y > SCROLL_BUFFER_SIZE)
{
y = SCROLL_BUFFER_SIZE;
x = 0;
}
if (x < 0)
x = -1;
if (x > MAX_LINE_WIDTH)
{
y++;
x = 0; // marks to end of line
}
}
// InvalidateRect(hOutputWnd,NULL,0);
void load_filter_info(void)
{
FILE *fp = NULL;
char pathname[MAX_PATH_LEN];
char inbuf[NAME_LENGTH+4];
outwnd_filter_struct new_filter;
int z;
outwnd_filter_loaded = 1;
memset( pathname, 0, sizeof(pathname) );
snprintf( pathname, MAX_PATH_LEN, "%s\\%s\\%s", detect_home(), Pathtypes[CF_TYPE_DATA].path, NOX("debug_filter.cfg") );
fp = fopen(pathname, "rt");
if (!fp) {
Outwnd_no_filter_file = 1;
strcpy_s( new_filter.name, "error" );
new_filter.enabled = true;
OutwndFilter.push_back( new_filter );
strcpy_s( new_filter.name, "general" );
new_filter.enabled = true;
OutwndFilter.push_back( new_filter );
strcpy_s( new_filter.name, "warning" );
new_filter.enabled = true;
OutwndFilter.push_back( new_filter );
return;
}
Outwnd_no_filter_file = 0;
while ( fgets(inbuf, NAME_LENGTH+3, fp) ) {
if (*inbuf == '+')
new_filter.enabled = true;
else if (*inbuf == '-')
new_filter.enabled = false;
else
continue; // skip everything else
z = strlen(inbuf) - 1;
if (inbuf[z] == '\n')
inbuf[z] = 0;
Assert( strlen(inbuf+1) < NAME_LENGTH );
strcpy_s(new_filter.name, inbuf + 1);
if ( !stricmp(new_filter.name, "error") ) {
new_filter.enabled = true;
} else if ( !stricmp(new_filter.name, "general") ) {
new_filter.enabled = true;
} else if ( !stricmp(new_filter.name, "warning") ) {
new_filter.enabled = true;
}
OutwndFilter.push_back( new_filter );
}
if ( ferror(fp) && !feof(fp) )
nprintf(("Error", "Error reading \"%s\"\n", pathname));
fclose(fp);
}
void save_filter_info(void)
{
FILE *fp = NULL;
char pathname[MAX_PATH_LEN];
if ( !outwnd_filter_loaded )
return;
if (Outwnd_no_filter_file)
return; // No file, don't save
memset( pathname, 0, sizeof(pathname) );
snprintf( pathname, MAX_PATH_LEN, "%s\\%s\\%s", detect_home(), Pathtypes[CF_TYPE_DATA].path, NOX("debug_filter.cfg") );
fp = fopen(pathname, "wt");
if (fp) {
for (uint i = 0; i < OutwndFilter.size(); i++)
fprintf(fp, "%c%s\n", OutwndFilter[i].enabled ? '+' : '-', OutwndFilter[i].name);
fclose(fp);
}
}
void outwnd_printf2(const char *format, ...)
{
SCP_string temp;
va_list args;
if (format == NULL)
return;
va_start(args, format);
vsprintf(temp, format, args);
va_end(args);
outwnd_print("General", temp.c_str());
}
#ifndef NMONO
char mono_ram[80*25*2];
int mono_x, mono_y;
int mono_found = 0;
void mono_flush()
{
if ( !mono_found ) return;
memcpy( (void *)0xb0000, mono_ram, 80*25*2 );
}
void mono_init()
{
int i;
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&ver);
if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
mono_found = 0;
return;
}
_outp( 0x3b4, 0x0f );
_outp( 0x3b4+1, 0x55 );
if ( _inp( 0x3b4+1 ) == 0x55 ) {
mono_found = 1;
_outp( 0x3b4+1, 0 );
} else {
mono_found = 0;
return;
}
for (i=0; i<80*25; i++ ) {
mono_ram[i*2+0] = ' ';
mono_ram[i*2+1] = 0x07;
}
mono_flush();
mono_x = mono_y = 0;
}
void mono_print( char * text, int len )
{
int i, j;
if ( !mono_found )
return;
for (i=0; i<len; i++ ) {
int scroll_it = 0;
switch( text[i] ) {
case '\n':
scroll_it = 1;
break;
default:
mono_ram[mono_y*160+mono_x*2] = text[i];
if ( mono_x < 79 ) {
mono_x++;
} else {
scroll_it = 1;
}
break;
}
if ( scroll_it ) {
if ( mono_y < 24 ) {
mono_y++;
mono_x = 0;
} else {
memmove( mono_ram, mono_ram+160, 80*24*2 );
for (j=0; j<80; j++ ) {
mono_ram[24*160+j*2] = ' ';
}
mono_y = 24;
mono_x = 0;
}
}
}
mono_flush();
}
#endif // NMONO
void outwnd_printf(const char *id, const char *format, ...)
{
SCP_string temp;
va_list args;
if ( (id == NULL) || (format == NULL) )
return;
va_start(args, format);
vsprintf(temp, format, args);
va_end(args);
outwnd_print(id, temp.c_str());
}
void outwnd_print(const char *id, const char *tmp)
{
const char *sptr;
char *dptr;
int nrows, ccol;
uint i;
if ( (id == NULL) || (tmp == NULL) )
return;
if ( !outwnd_inited )
return;
if (Outwnd_no_filter_file == 1) {
Outwnd_no_filter_file = 2;
outwnd_print( "general", "==========================================================================\n" );
outwnd_print( "general", "DEBUG SPEW: No debug_filter.cfg found, so only general, error, and warning\n" );
outwnd_print( "general", "categories can be shown and no debug_filter.cfg info will be saved.\n" );
outwnd_print( "general", "==========================================================================\n" );
}
uint outwnd_size = OutwndFilter.size();
for (i = 0; i < OutwndFilter.size(); i++) {
if ( !stricmp(id, OutwndFilter[i].name) )
break;
}
// id found that isn't in the filter list yet
if ( i == outwnd_size ) {
// Only create new filters if there was a filter file
if (Outwnd_no_filter_file)
return;
Assert( strlen(id)+1 < NAME_LENGTH );
outwnd_filter_struct new_filter;
strcpy_s(new_filter.name, id);
new_filter.enabled = true;
OutwndFilter.push_back( new_filter );
save_filter_info();
}
if ( !OutwndFilter[i].enabled )
return;
if (Log_debug_output_to_file) {
if (Log_fp != NULL) {
fputs(tmp, Log_fp);
fflush(Log_fp);
}
}
if ( !Cmdline_debug_window )
return;
// everything after this point relates to printing in the debug window
if (mprintf_last_line == -1 ) {
for (i=0; i<SCROLL_BUFFER_SIZE;i++) {
outtext[i][0] = 0;
}
mprintf_last_line = 0;
}
// printf out to the monochrome screen first
if ( mono_driver != ((HANDLE)-1) ) {
DWORD cbReturned;
DeviceIoControl (mono_driver, (DWORD)IOCTL_MONO_PRINT, const_cast<char*>(tmp), strlen(tmp), NULL, 0, &cbReturned, 0 );
#ifndef NMONO
} else {
mono_print(tmp, strlen(tmp) );
#endif
}
sptr = tmp;
ccol = strlen(outtext[mprintf_last_line] );
dptr = &outtext[mprintf_last_line][ccol];
nrows = 0;
while(*sptr) {
if ( (*sptr == '\n') || (ccol >= MAX_LINE_WIDTH-1 ) ) {
nrows++;
mprintf_last_line++;
if (mprintf_last_line >= SCROLL_BUFFER_SIZE )
mprintf_last_line = 0;
ccol = 0;
if ( *sptr != '\n' ) {
outtext[mprintf_last_line][ccol] = *sptr;
ccol++;
}
outtext[mprintf_last_line][ccol] = '\0';
dptr = &outtext[mprintf_last_line][ccol];
} else {
*dptr++ = *sptr;
*dptr = '\0';
ccol++;
}
sptr++;
}
if (outwnd_disabled)
return;
if ( !OutputActive ) {
int oldpos = GetScrollPos( hOutputWnd, SB_VERT );
if ( oldpos != max_scroll_pos ) {
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
si.nPos = max_scroll_pos;
SetScrollInfo(hOutputWnd, SB_VERT, &si, 1 );
InvalidateRect(hOutputWnd,NULL,0);
UpdateWindow(hOutputWnd);
} else {
if ( nrows ) {
RECT client;
ScrollWindow(hOutputWnd,0,-nTextHeight*nrows,NULL,NULL);
GetClientRect(hOutputWnd, &client);
client.top = client.bottom - nTextHeight*(nrows+1);
InvalidateRect(hOutputWnd,&client,0);
UpdateWindow(hOutputWnd);
} else {
Outwnd_changed++;
}
}
}
}
LRESULT CALLBACK outwnd_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
{
switch(msg) {
case WM_ACTIVATEAPP:
// The application z-ordering has change
// foreground application wParm will be
OutputActive = (BOOL)wParam;
break;
case WM_CREATE: {
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_RANGE | SIF_POS;
si.nMin = 0;
si.nMax = max_scroll_pos;
si.nPos = max_scroll_pos;
SetScrollInfo(hwnd, SB_VERT, &si, 1 );
}
break;
case WM_TIMER:
if (scroll_wait)
PostMessage(hwnd, WM_MOUSEMOVE, 0, last_mousemove);
if ( Outwnd_changed ) {
RECT client;
GetClientRect(hOutputWnd, &client);
client.top = client.bottom - nTextHeight;
InvalidateRect(hOutputWnd,&client,0);
}
scroll_wait = 0;
break;
case WM_COMMAND: {
int z;
z = LOWORD(wParam);
if (z >= ID_FILTER && z < ID_FILTER + (int)OutwndFilter.size())
{
z -= ID_FILTER;
OutwndFilter[z].enabled = !OutwndFilter[z].enabled;
if ( !stricmp( OutwndFilter[z].name, "error" ) ) {
OutwndFilter[z].enabled = 1;
} else if ( !stricmp( OutwndFilter[z].name, "general" ) ) {
OutwndFilter[z].enabled = 1;
} else if ( !stricmp( OutwndFilter[z].name, "warning" ) ) {
OutwndFilter[z].enabled = 1;
}
save_filter_info();
break;
}
switch (z)
{
case ID_COPY:
outwnd_copy_marked_selection(hwnd);
break;
/*
case ID_FIND:
if (DialogBox(GetModuleHandle(NULL), "FIND_DIALOG", hOutputWnd,
(int (__stdcall *)(void)) find_dlg_handler) == IDOK)
{
find_text_in_outwindow(mprintf_last_line, 0);
}
break;
*/
}
break;
}
case WM_RBUTTONDOWN: {
HMENU h_menu = CreatePopupMenu();
HMENU h_sub_menu = CreatePopupMenu();
POINT pt;
for (uint i = 0; i < OutwndFilter.size(); i++) {
UINT flags = MFT_STRING; //MF_GRAYED;
if ( !stricmp( OutwndFilter[i].name, "error" ) ) {
flags |= MF_GRAYED;
} else if ( !stricmp( OutwndFilter[i].name, "general" ) ) {
flags |= MF_GRAYED;
} else if ( !stricmp( OutwndFilter[i].name, "warning" ) ) {
flags |= MF_GRAYED;
}
if (OutwndFilter[i].enabled)
AppendMenu(h_sub_menu, flags | MF_CHECKED, ID_FILTER + i, OutwndFilter[i].name);
else
AppendMenu(h_sub_menu, flags, ID_FILTER + i, OutwndFilter[i].name);
}
AppendMenu(h_menu, MFT_STRING, ID_COPY, "&Copy\tEnter");
AppendMenu(h_menu, MFT_STRING, ID_FIND, "&Find Text");
AppendMenu(h_menu, MF_POPUP, (unsigned int) h_sub_menu, "Filter &Messages");
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
ClientToScreen(hwnd, &pt);
TrackPopupMenu(h_menu, 0, pt.x, pt.y, 0, hwnd, NULL);
DestroyMenu(h_menu);
break;
}
case WM_LBUTTONDOWN:
fix_marking_coords(marking_started_x, marking_started_y, lParam);
SetCapture(hwnd); // monopolize mouse
marking_active = 1;
outwnd_update_marking(lParam, hwnd);
break;
case WM_MOUSEMOVE:
last_mousemove = lParam;
if (marking_active){
outwnd_update_marking(lParam, hwnd);
}
break;
case WM_LBUTTONUP:
if (marking_active)
{
ReleaseCapture();
marking_active = 0;
outwnd_update_marking(lParam, hwnd);
}
break;
case WM_VSCROLL: {
SCROLLINFO si;
int vpos = GetScrollPos( hwnd, SB_VERT );
int old_vpos=vpos;
switch (LOWORD(wParam)) {
case SB_LINEDOWN:
vpos++;
break;
case SB_LINEUP:
vpos--;
break;
case SB_THUMBPOSITION:
vpos = HIWORD(wParam);
break;
case SB_THUMBTRACK:
vpos = HIWORD(wParam);
break;
case SB_PAGEDOWN:
vpos += nCharRows;
break;
case SB_PAGEUP:
vpos -= nCharRows;
break;
}
if ( vpos < 0 ) vpos = 0;
else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
si.nPos = vpos;
SetScrollInfo(hwnd, SB_VERT, &si, 1 );
ScrollWindow(hwnd,0,(old_vpos-vpos)*nTextHeight,NULL,NULL);
UpdateWindow(hOutputWnd);
//InvalidateRect(hOutputWnd,NULL,0);
}
break;
case WM_KEYDOWN: {
SCROLLINFO si;
int vpos = GetScrollPos( hwnd, SB_VERT );
int old_vpos=vpos;
int nVirtKey = (int) wParam; // virtual-key code
switch(nVirtKey) {
case VK_DOWN:
case VK_RIGHT:
vpos++;
break;
case VK_UP:
case VK_LEFT:
vpos--;
break;
case VK_NEXT:
vpos += nCharRows;
break;
case VK_PRIOR:
vpos -= nCharRows;
break;
case VK_END:
vpos = 0;
break;
case VK_HOME:
vpos = max_scroll_pos;
break;
case VK_RETURN:
outwnd_copy_marked_selection(hwnd);
break;
case UP_FAST: // special value we define
vpos -= 5;
break;
case DOWN_FAST: // special value we define
vpos += 5;
break;
}
if ( vpos < 0 ) vpos = 0;
else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
si.nPos = vpos;
SetScrollInfo(hwnd, SB_VERT, &si, 1 );
ScrollWindow(hwnd, 0, (old_vpos-vpos)*nTextHeight, NULL, NULL);
UpdateWindow(hOutputWnd);
//InvalidateRect(hOutputWnd,NULL,0);
}
break;
case WM_SIZE:
InvalidateRect(hOutputWnd,NULL,0);
break;
case WM_PAINT:
outwnd_paint(hwnd);
break;
case WM_DESTROY:
outwnd_disabled = true;
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
return 0;
}
void outwnd_copy_marked_selection(HWND hwnd)
{
HGLOBAL h_text;
int i, size = 1;
char *ptr;
if (marked_top == marked_bottom)
{
size += marked_right - marked_left;
} else {
i = marked_top;
size += strlen(outtext[i++]) - marked_left + 2;
while (i < marked_bottom)
size += strlen(outtext[i++]) + 2;
size += marked_right;
}
h_text = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
ptr = (char *) GlobalLock(h_text);
if (marked_top == marked_bottom)
{
i = marked_right - marked_left;
memcpy(ptr, outtext[marked_top] + marked_left, i);
ptr[i] = 0;
} else {
i = marked_top;
strcpy(ptr, outtext[i] + marked_left);
strcat(ptr, "\r\n");
i++;
while (i < marked_bottom)
{
strcat(ptr, outtext[i++]);
strcat(ptr, "\r\n");
}
ptr[strlen(ptr) + marked_right] = 0;
strncat(ptr, outtext[i], marked_right);
}
GlobalUnlock(h_text);
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_TEXT, h_text);
CloseClipboard();
marked = 0;
InvalidateRect(hwnd, NULL, 0);
}
void outwnd_paint(HWND hwnd)
{
int i, n, x, y, len;
int old_nrows, scroll_pos;
HDC hdc;
PAINTSTRUCT ps;
RECT client;
TEXTMETRIC tm;
HFONT newfont, oldfont;
HBRUSH newbrush, oldbrush;
Outwnd_changed = 0;
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hOutputWnd, &client);
newfont = (HFONT)GetStockObject(ANSI_FIXED_FONT);
oldfont = (HFONT)SelectObject(hdc,newfont);
GetTextMetrics(hdc, &tm);
nTextHeight = tm.tmHeight + tm.tmExternalLeading;
nTextWidth = tm.tmAveCharWidth;
old_nrows = nCharRows;
nCharRows = ((client.bottom-client.top)/nTextHeight)+1;
newbrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
oldbrush = (HBRUSH)SelectObject(hdc,newbrush);
y = client.bottom - nTextHeight * nCharRows; // starting y position at top
client_top_yoffset = y - nTextHeight;
scroll_pos = (max_scroll_pos - GetScrollPos( hOutputWnd, SB_VERT ));
cur_line_index = x = mprintf_last_line - scroll_pos - nCharRows;
if (x >= marked_top && x < marked_bottom) // starting in marked area
text_hilight(hdc);
else
text_normal(hdc);
if (scroll_pos != old_scroll_pos) {
if (!scroll_pos) {
char tmp[1024];
sprintf( tmp, "Debug Spew");
SetWindowText( hOutputWnd, tmp );
} else {
char tmp[1024];
sprintf( tmp, "Debug Spew [Scrolled back %d lines]", scroll_pos );
SetWindowText( hOutputWnd, tmp );
}
old_scroll_pos = scroll_pos;
}
i = nCharRows;
while (i--)
{
n = mprintf_last_line - scroll_pos - i;
if (n < 0)
n += SCROLL_BUFFER_SIZE;
if (n >= 0 && n < SCROLL_BUFFER_SIZE)
{
len = strlen(outtext[n]);
if (marked)
{
if (n == marked_top && n == marked_bottom) // special 1 line case
{
if (marked_left)
TextOut(hdc, 0, y, outtext[n], marked_left);
text_hilight(hdc);
x = marked_left * nTextWidth;
TextOut(hdc, x, y, outtext[n] + marked_left, marked_right -
marked_left);
text_normal(hdc);
x = marked_right * nTextWidth;
if (marked_right < len)
TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right);
x = len * nTextWidth;
TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
} else if (n == marked_top) { // start marked on this line
if (marked_left)
TextOut(hdc, 0, y, outtext[n], marked_left);
text_hilight(hdc);
x = marked_left * nTextWidth;
TextOut(hdc, x, y, outtext[n] + marked_left, len - marked_left);
x = len * nTextWidth;
if (marked_left < MAX_LINE_WIDTH)
TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - marked_left);
} else if (n == marked_bottom) { // end marked on this line
if (marked_right)
TextOut(hdc, 0, y, outtext[n], marked_right);
text_normal(hdc);
x = marked_right * nTextWidth;
if (marked_right < len)
TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right);
x = len * nTextWidth;
TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
} else { // whole line marked
TextOut(hdc, 0, y, outtext[n], len);
x = len * nTextWidth;
TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
}
} else {
TextOut(hdc, 0, y, outtext[n], len);
x = len * nTextWidth;
TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len);
}
} else
TextOut(hdc, 0, y, spaces, MAX_LINE_WIDTH);
y += nTextHeight;
}
text_normal(hdc);
SelectObject(hdc, oldfont);
SelectObject(hdc, oldbrush);
DeleteObject(newbrush);
if ( old_nrows != nCharRows ) {
SCROLLINFO si;
max_scroll_pos = SCROLL_BUFFER_SIZE-nCharRows - 1;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_RANGE;
si.nMin = 0;
si.nMax = max_scroll_pos;
SetScrollInfo(hwnd, SB_VERT, &si, 1 );
}
EndPaint(hwnd, &ps);
}
void outwnd_update_marking(LPARAM l_parm, HWND hwnd)
{
int x, y;
RECT rect;
if (!scroll_wait) {
y = (signed short) HIWORD(l_parm);
GetClientRect(hwnd, &rect);
if (y < -150) {
SendMessage(hwnd, WM_KEYDOWN, UP_FAST, 0);
scroll_wait = 1;
} else if (y < 0) {
SendMessage(hwnd, WM_KEYDOWN, VK_UP, 0);
scroll_wait = 1;
}
if (y >= rect.bottom + 150) {
SendMessage(hwnd, WM_KEYDOWN, DOWN_FAST, 0);
scroll_wait = 1;
} else if (y >= rect.bottom) {
SendMessage(hwnd, WM_KEYDOWN, VK_DOWN, 0);
scroll_wait = 1;
}
}
fix_marking_coords(x, y, l_parm);
marked = 1;
marked_top = marked_bottom = marking_started_y;
marked_left = marking_started_x;
marked_right = marking_started_x + 1;
if (y < marked_top)
{
marked_top = y;
marked_left = x;
} else if (y > marked_bottom) {
marked_bottom = y;
marked_right = x + 1;
} else { // must be single line case
if (x < marked_left)
marked_left = x;
if (x >= marked_right)
marked_right = x + 1;
if (marked_left >= (signed int) strlen(outtext[y]))
{
marked = 0; // this isn't going to even show up
return;
}
}
if (marked_left >= (signed int) strlen(outtext[marked_top]))
{
marked_top++;
marked_left = 0;
}
if (marked_right > (signed int) strlen(outtext[marked_bottom]))
marked_right = strlen(outtext[marked_bottom]);
if (marked && (marked_top > marked_bottom || (marked_top == marked_bottom &&
marked_left >= marked_right)))
{
char msg[1024];
sprintf(msg, "Marking limits invalid!\n"
"(%d,%d) to (%d,%d)", marked_left, marked_top, marked_right, marked_bottom);
MessageBox(hwnd, msg, "Error", MB_OK | MB_ICONERROR);
marked = 0;
}
if (marked != old_marked || marked_top != old_marked_top || marked_bottom !=
old_marked_bottom || marked_left != old_marked_left || marked_right !=
old_marked_right)
{
old_marked = marked;
old_marked_left = marked_left;
old_marked_right = marked_right;
old_marked_top = marked_top;
old_marked_bottom = marked_bottom;
InvalidateRect(hwnd, NULL, 0);
}
}
BOOL outwnd_create(int display_under_freespace_window)
{
WNDCLASSEX wclass;
HINSTANCE hInst = GetModuleHandle(NULL);
RECT rect;
DWORD style;
wclass.hInstance = hInst;
wclass.lpszClassName = szOutputClass;
wclass.lpfnWndProc = (WNDPROC) outwnd_handler;
wclass.style = CS_BYTEALIGNCLIENT | CS_OWNDC; //CS_DBLCLKS | CS_PARENTDC| CS_VREDRAW | CS_HREDRAW |;
wclass.cbSize = sizeof(WNDCLASSEX);
wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wclass.lpszMenuName = NULL; //"FreeSpaceMenu";
wclass.cbClsExtra = 0;
wclass.cbWndExtra = 0;
wclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //(HBRUSH)NULL;
if (!RegisterClassEx(&wclass))
return FALSE;
if (display_under_freespace_window) {
style = WS_OVERLAPPEDWINDOW;
RECT client_rect;
client_rect.left = client_rect.top = 0;
client_rect.right = 640;
client_rect.bottom = 480;
AdjustWindowRect(&client_rect,WS_CAPTION | WS_SYSMENU,FALSE);
int _x = (GetSystemMetrics( SM_CXSCREEN )-(client_rect.right - client_rect.left))/2;
int _y = 0;
if ( _x < 0 ) _x = 0;
rect.left = _x;
rect.top = _y;
rect.right = _x + client_rect.right - client_rect.left - 1;
rect.bottom = _y + client_rect.bottom - client_rect.top - 1;
if(!Is_standalone){
rect.top = rect.bottom;
rect.bottom = GetSystemMetrics(SM_CYSCREEN) - TASKBAR_HEIGHT - rect.top;
rect.right -= rect.left;
} else {
rect.left += 350;
rect.right = 550;
rect.bottom = 400;
}
} else {
style = WS_OVERLAPPEDWINDOW | WS_MINIMIZE;
rect.top = rect.bottom = rect.left = rect.right = CW_USEDEFAULT;
}
// Create Game Window
hOutputWnd = CreateWindow(szOutputClass, "Debug Spew", style, rect.left,
rect.top, rect.right, rect.bottom, NULL, NULL, hInst, NULL);
// Show it, but don't activate it. If you activate it, it cause problems
// with fullscreen startups in main window.
SetWindowPos( hOutputWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW );
outwnd_disabled = false;
SetTimer(hOutputWnd, TIMER1, 50, NULL);
for (int i=0; i<MAX_LINE_WIDTH; i++)
spaces[i] = ' ';
spaces[MAX_LINE_WIDTH] = 0;
return TRUE;
}
DWORD outwnd_thread(int display_under_freespace_window)
{
MSG msg;
if (!outwnd_create(display_under_freespace_window))
return 0;
while (1) {
if (WaitMessage()) {
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if (outwnd_disabled) break;
}
return 0;
}
void close_mono()
{
// DeviceIoControl (mono_driver, (DWORD) IOCTL_MONO_CLEAR_SCREEN, NULL, 0, NULL, 0, &cbReturned, 0);
if (hOutputThread) {
CloseHandle(hOutputThread);
hOutputThread = NULL;
}
if (mono_driver) {
CloseHandle(mono_driver);
mono_driver = NULL;
}
}
void outwnd_init_debug_window(int display_under_freespace_window)
{
static bool debug_window_inited = false;
if ( !Cmdline_debug_window || !outwnd_inited || debug_window_inited )
return;
hOutputThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)outwnd_thread, (LPVOID)display_under_freespace_window, 0, &OutputThreadID);
//SetThreadPriority(hOutputThread, THREAD_PRIORITY_TIME_CRITICAL);
#ifndef NMONO
// set up the monochrome drivers
if ( (mono_driver = CreateFile("\\\\.\\MONO", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == ((HANDLE)-1)) {
outwnd_printf2("Cannot get handle to monochrome driver.\n");
mono_init();
}
atexit(close_mono);
#endif
debug_window_inited = true;
}
void outwnd_init(int display_under_freespace_window)
{
if (outwnd_inited)
return;
/*
if (Cmdline_debug_window) {
hOutputThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)outwnd_thread, (LPVOID)display_under_freespace_window, 0, &OutputThreadID);
//SetThreadPriority(hOutputThread, THREAD_PRIORITY_TIME_CRITICAL);
#ifndef NMONO
// set up the monochrome drivers
if ( (mono_driver = CreateFile("\\\\.\\MONO", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == ((HANDLE)-1)) {
outwnd_printf2("Cannot get handle to monochrome driver.\n");
mono_init();
}
atexit(close_mono);
#endif
}
*/
if (Log_fp == NULL) {
char pathname[MAX_PATH_LEN];
/* Set where the log file is going to go */
// Zacam: Set various conditions based on what type of log to generate.
if (Fred_running) {
FreeSpace_logfilename = "fred2_open.log";
} else if (Is_standalone) {
FreeSpace_logfilename = "fs2_standalone.log";
} else {
FreeSpace_logfilename = "fs2_open.log";
}
memset( pathname, 0, sizeof(pathname) );
snprintf(pathname, MAX_PATH_LEN-1, "%s\\%s\\%s", detect_home(), Pathtypes[CF_TYPE_DATA].path, FreeSpace_logfilename);
Log_fp = fopen(pathname, "wb");
if (Log_fp == NULL) {
outwnd_printf("Error", "Error opening %s\n", pathname);
} else {
time_t timedate = time(NULL);
char datestr[50];
memset( datestr, 0, sizeof(datestr) );
strftime( datestr, sizeof(datestr)-1, "%a %b %d %H:%M:%S %Y", localtime(&timedate) );
outwnd_printf("General", "Opened log '%s', %s ...\n", pathname, datestr);
}
}
outwnd_inited = true;
}
BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
GetDlgItemText(hwnd, IDC_TEXT, find_text, 82); // get the text to find
EndDialog(hwnd, IDOK);
return 1;
case IDCANCEL:
EndDialog(hwnd, 0);
return 1;
}
break;
case WM_INITDIALOG:
SendDlgItemMessage(hwnd, IDC_TEXT, EM_LIMITTEXT, 80, 0); // limit text to 80 chars
if (GetDlgCtrlID((HWND) wParam) != IDC_TEXT) {
SetFocus(GetDlgItem(hwnd, IDC_TEXT));
return FALSE;
}
return TRUE;
}
return 0;
}
void find_text_in_outwindow(int n, int p)
{
char *ptr, *str;
str = outtext[n] + p;
while (1)
{
ptr = strstr(str, find_text);
if (ptr)
{
int scroll_pos, pos;
find_pos = ptr - str;
find_line = n;
marked = 1;
marked_top = marked_bottom = find_line;
marked_left = find_pos;
marked_right = find_pos + strlen(find_text);
scroll_pos = (max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT));
pos = mprintf_last_line - scroll_pos;
if (pos < 0)
pos += SCROLL_BUFFER_SIZE;
pos -= n;
if (pos < 0)
pos += SCROLL_BUFFER_SIZE;
Assert(pos >= 0);
if (pos >= nCharRows - 1) // outside of window viewport, so scroll
{
SCROLLINFO si;
pos = mprintf_last_line - n - nCharRows / 2;
if (pos < 0)
pos += SCROLL_BUFFER_SIZE;
if (pos > max_scroll_pos)
pos = max_scroll_pos;
scroll_pos = max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT);
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
si.nPos = max_scroll_pos - pos;
SetScrollInfo(hOutputWnd, SB_VERT, &si, 1);
ScrollWindow(hOutputWnd, 0, (scroll_pos - pos) * nTextHeight, NULL, NULL);
}
InvalidateRect(hOutputWnd, NULL, 0);
UpdateWindow(hOutputWnd);
return;
}
n--;
if (n < 0)
n += SCROLL_BUFFER_SIZE;
if (n == mprintf_last_line)
{
MessageBox(hOutputWnd, "Search text not found", "Find Error", MB_OK | MB_ICONERROR);
find_line = -1;
return;
}
str = outtext[n];
}
}
void outwnd_close()
{
if ( Log_fp != NULL ) {
time_t timedate = time(NULL);
char datestr[50];
memset( datestr, 0, sizeof(datestr) );
strftime( datestr, sizeof(datestr)-1, "%a %b %d %H:%M:%S %Y", localtime(&timedate) );
outwnd_printf("General", "... Log closed, %s\n", datestr);
fclose(Log_fp);
Log_fp = NULL;
}
outwnd_inited = false;
}
void safe_point_print(const char *format, ...)
{
SCP_string temp;
va_list args;
va_start(args, format);
vsprintf(temp, format, args);
va_end(args);
safe_string = temp;
}
void safe_point(const char *file, int line, const char *format, ...)
{
safe_point_print("last safepoint: %s, %d; [%s]", file, line, format);
}
#endif //NDEBUG