Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

win_syscon.c (13970B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // win_syscon.h
     23 #include "../client/client.h"
     24 #include "win_local.h"
     25 #include "resource.h"
     26 #include <errno.h>
     27 #include <float.h>
     28 #include <fcntl.h>
     29 #include <stdio.h>
     30 #include <direct.h>
     31 #include <io.h>
     32 #include <conio.h>
     33 
     34 #define COPY_ID			1
     35 #define QUIT_ID			2
     36 #define CLEAR_ID		3
     37 
     38 #define ERRORBOX_ID		10
     39 #define ERRORTEXT_ID	11
     40 
     41 #define EDIT_ID			100
     42 #define INPUT_ID		101
     43 
     44 typedef struct
     45 {
     46 	HWND		hWnd;
     47 	HWND		hwndBuffer;
     48 
     49 	HWND		hwndButtonClear;
     50 	HWND		hwndButtonCopy;
     51 	HWND		hwndButtonQuit;
     52 
     53 	HWND		hwndErrorBox;
     54 	HWND		hwndErrorText;
     55 
     56 	HBITMAP		hbmLogo;
     57 	HBITMAP		hbmClearBitmap;
     58 
     59 	HBRUSH		hbrEditBackground;
     60 	HBRUSH		hbrErrorBackground;
     61 
     62 	HFONT		hfBufferFont;
     63 	HFONT		hfButtonFont;
     64 
     65 	HWND		hwndInputLine;
     66 
     67 	char		errorString[80];
     68 
     69 	char		consoleText[512], returnedText[512];
     70 	int			visLevel;
     71 	qboolean	quitOnClose;
     72 	int			windowWidth, windowHeight;
     73 	
     74 	WNDPROC		SysInputLineWndProc;
     75 
     76 } WinConData;
     77 
     78 static WinConData s_wcd;
     79 
     80 static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     81 {
     82 	char *cmdString;
     83 	static qboolean s_timePolarity;
     84 
     85 	switch (uMsg)
     86 	{
     87 	case WM_ACTIVATE:
     88 		if ( LOWORD( wParam ) != WA_INACTIVE )
     89 		{
     90 			SetFocus( s_wcd.hwndInputLine );
     91 		}
     92 
     93 		if ( com_viewlog && ( com_dedicated && !com_dedicated->integer ) )
     94 		{
     95 			// if the viewlog is open, check to see if it's being minimized
     96 			if ( com_viewlog->integer == 1 )
     97 			{
     98 				if ( HIWORD( wParam ) )		// minimized flag
     99 				{
    100 					Cvar_Set( "viewlog", "2" );
    101 				}
    102 			}
    103 			else if ( com_viewlog->integer == 2 )
    104 			{
    105 				if ( !HIWORD( wParam ) )		// minimized flag
    106 				{
    107 					Cvar_Set( "viewlog", "1" );
    108 				}
    109 			}
    110 		}
    111 		break;
    112 
    113 	case WM_CLOSE:
    114 		if ( ( com_dedicated && com_dedicated->integer ) )
    115 		{
    116 			cmdString = CopyString( "quit" );
    117 			Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString );
    118 		}
    119 		else if ( s_wcd.quitOnClose )
    120 		{
    121 			PostQuitMessage( 0 );
    122 		}
    123 		else
    124 		{
    125 			Sys_ShowConsole( 0, qfalse );
    126 			Cvar_Set( "viewlog", "0" );
    127 		}
    128 		return 0;
    129 	case WM_CTLCOLORSTATIC:
    130 		if ( ( HWND ) lParam == s_wcd.hwndBuffer )
    131 		{
    132 			SetBkColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0xB0 ) );
    133 			SetTextColor( ( HDC ) wParam, RGB( 0xff, 0xff, 0x00 ) );
    134 
    135 #if 0	// this draws a background in the edit box, but there are issues with this
    136 			if ( ( hdcScaled = CreateCompatibleDC( ( HDC ) wParam ) ) != 0 )
    137 			{
    138 				if ( SelectObject( ( HDC ) hdcScaled, s_wcd.hbmLogo ) )
    139 				{
    140 					StretchBlt( ( HDC ) wParam, 0, 0, 512, 384, 
    141 							hdcScaled, 0, 0, 512, 384,
    142 							SRCCOPY );
    143 				}
    144 				DeleteDC( hdcScaled );
    145 			}
    146 #endif
    147 			return ( long ) s_wcd.hbrEditBackground;
    148 		}
    149 		else if ( ( HWND ) lParam == s_wcd.hwndErrorBox )
    150 		{
    151 			if ( s_timePolarity & 1 )
    152 			{
    153 				SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
    154 				SetTextColor( ( HDC ) wParam, RGB( 0xff, 0x0, 0x00 ) );
    155 			}
    156 			else
    157 			{
    158 				SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
    159 				SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x0, 0x00 ) );
    160 			}
    161 			return ( long ) s_wcd.hbrErrorBackground;
    162 		}
    163 		break;
    164 
    165 	case WM_COMMAND:
    166 		if ( wParam == COPY_ID )
    167 		{
    168 			SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
    169 			SendMessage( s_wcd.hwndBuffer, WM_COPY, 0, 0 );
    170 		}
    171 		else if ( wParam == QUIT_ID )
    172 		{
    173 			if ( s_wcd.quitOnClose )
    174 			{
    175 				PostQuitMessage( 0 );
    176 			}
    177 			else
    178 			{
    179 				cmdString = CopyString( "quit" );
    180 				Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString );
    181 			}
    182 		}
    183 		else if ( wParam == CLEAR_ID )
    184 		{
    185 			SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
    186 			SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, FALSE, ( LPARAM ) "" );
    187 			UpdateWindow( s_wcd.hwndBuffer );
    188 		}
    189 		break;
    190 	case WM_CREATE:
    191 //		s_wcd.hbmLogo = LoadBitmap( g_wv.hInstance, MAKEINTRESOURCE( IDB_BITMAP1 ) );
    192 //		s_wcd.hbmClearBitmap = LoadBitmap( g_wv.hInstance, MAKEINTRESOURCE( IDB_BITMAP2 ) );
    193 		s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0xB0 ) );
    194 		s_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) );
    195 		SetTimer( hWnd, 1, 1000, NULL );
    196 		break;
    197 	case WM_ERASEBKGND:
    198 #if 0
    199 	HDC hdcScaled;
    200 	HGDIOBJ oldObject;
    201 
    202 #if 1	// a single, large image
    203 		hdcScaled = CreateCompatibleDC( ( HDC ) wParam );
    204 		assert( hdcScaled != 0 );
    205 
    206 		if ( hdcScaled )
    207 		{
    208 			oldObject = SelectObject( ( HDC ) hdcScaled, s_wcd.hbmLogo );
    209 			assert( oldObject != 0 );
    210 			if ( oldObject )
    211 			{
    212 				StretchBlt( ( HDC ) wParam, 0, 0, s_wcd.windowWidth, s_wcd.windowHeight, 
    213 						hdcScaled, 0, 0, 512, 384,
    214 						SRCCOPY );
    215 			}
    216 			DeleteDC( hdcScaled );
    217 			hdcScaled = 0;
    218 		}
    219 #else	// a repeating brush
    220 		{
    221 			HBRUSH hbrClearBrush;
    222 			RECT r;
    223 
    224 			GetWindowRect( hWnd, &r );
    225 
    226 			r.bottom = r.bottom - r.top + 1;
    227 			r.right = r.right - r.left + 1;
    228 			r.top = 0;
    229 			r.left = 0;
    230 
    231 			hbrClearBrush = CreatePatternBrush( s_wcd.hbmClearBitmap );
    232 
    233 			assert( hbrClearBrush != 0 );
    234 
    235 			if ( hbrClearBrush )
    236 			{
    237 				FillRect( ( HDC ) wParam, &r, hbrClearBrush );
    238 				DeleteObject( hbrClearBrush );
    239 			}
    240 		}
    241 #endif
    242 		return 1;
    243 #endif
    244 	    return DefWindowProc( hWnd, uMsg, wParam, lParam );
    245 	case WM_TIMER:
    246 		if ( wParam == 1 )
    247 		{
    248 			s_timePolarity = !s_timePolarity;
    249 			if ( s_wcd.hwndErrorBox )
    250 			{
    251 				InvalidateRect( s_wcd.hwndErrorBox, NULL, FALSE );
    252 			}
    253 		}
    254 		break;
    255     }
    256 
    257     return DefWindowProc( hWnd, uMsg, wParam, lParam );
    258 }
    259 
    260 LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    261 {
    262 	char inputBuffer[1024];
    263 
    264 	switch ( uMsg )
    265 	{
    266 	case WM_KILLFOCUS:
    267 		if ( ( HWND ) wParam == s_wcd.hWnd ||
    268 			 ( HWND ) wParam == s_wcd.hwndErrorBox )
    269 		{
    270 			SetFocus( hWnd );
    271 			return 0;
    272 		}
    273 		break;
    274 
    275 	case WM_CHAR:
    276 		if ( wParam == 13 )
    277 		{
    278 			GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ) );
    279 			strncat( s_wcd.consoleText, inputBuffer, sizeof( s_wcd.consoleText ) - strlen( s_wcd.consoleText ) - 5 );
    280 			strcat( s_wcd.consoleText, "\n" );
    281 			SetWindowText( s_wcd.hwndInputLine, "" );
    282 
    283 			Sys_Print( va( "]%s\n", inputBuffer ) );
    284 
    285 			return 0;
    286 		}
    287 	}
    288 
    289 	return CallWindowProc( s_wcd.SysInputLineWndProc, hWnd, uMsg, wParam, lParam );
    290 }
    291 
    292 /*
    293 ** Sys_CreateConsole
    294 */
    295 void Sys_CreateConsole( void )
    296 {
    297 	HDC hDC;
    298 	WNDCLASS wc;
    299 	RECT rect;
    300 	const char *DEDCLASS = "Q3 WinConsole";
    301 	int nHeight;
    302 	int swidth, sheight;
    303 	int DEDSTYLE = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX;
    304 
    305 	memset( &wc, 0, sizeof( wc ) );
    306 
    307 	wc.style         = 0;
    308 	wc.lpfnWndProc   = (WNDPROC) ConWndProc;
    309 	wc.cbClsExtra    = 0;
    310 	wc.cbWndExtra    = 0;
    311 	wc.hInstance     = g_wv.hInstance;
    312 	wc.hIcon         = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1));
    313 	wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
    314 	wc.hbrBackground = (void *)COLOR_WINDOW;
    315 	wc.lpszMenuName  = 0;
    316 	wc.lpszClassName = DEDCLASS;
    317 
    318 	if ( !RegisterClass (&wc) )
    319 		return;
    320 
    321 	rect.left = 0;
    322 	rect.right = 540;
    323 	rect.top = 0;
    324 	rect.bottom = 450;
    325 	AdjustWindowRect( &rect, DEDSTYLE, FALSE );
    326 
    327 	hDC = GetDC( GetDesktopWindow() );
    328 	swidth = GetDeviceCaps( hDC, HORZRES );
    329 	sheight = GetDeviceCaps( hDC, VERTRES );
    330 	ReleaseDC( GetDesktopWindow(), hDC );
    331 
    332 	s_wcd.windowWidth = rect.right - rect.left + 1;
    333 	s_wcd.windowHeight = rect.bottom - rect.top + 1;
    334 
    335 	s_wcd.hWnd = CreateWindowEx( 0,
    336 							   DEDCLASS,
    337 							   "Quake 3 Console",
    338 							   DEDSTYLE,
    339 							   ( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1,
    340 							   NULL,
    341 							   NULL,
    342 							   g_wv.hInstance,
    343 							   NULL );
    344 
    345 	if ( s_wcd.hWnd == NULL )
    346 	{
    347 		return;
    348 	}
    349 
    350 	//
    351 	// create fonts
    352 	//
    353 	hDC = GetDC( s_wcd.hWnd );
    354 	nHeight = -MulDiv( 8, GetDeviceCaps( hDC, LOGPIXELSY), 72);
    355 
    356 	s_wcd.hfBufferFont = CreateFont( nHeight,
    357 									  0,
    358 									  0,
    359 									  0,
    360 									  FW_LIGHT,
    361 									  0,
    362 									  0,
    363 									  0,
    364 									  DEFAULT_CHARSET,
    365 									  OUT_DEFAULT_PRECIS,
    366 									  CLIP_DEFAULT_PRECIS,
    367 									  DEFAULT_QUALITY,
    368 									  FF_MODERN | FIXED_PITCH,
    369 									  "Courier New" );
    370 
    371 	ReleaseDC( s_wcd.hWnd, hDC );
    372 
    373 	//
    374 	// create the input line
    375 	//
    376 	s_wcd.hwndInputLine = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | 
    377 												ES_LEFT | ES_AUTOHSCROLL,
    378 												6, 400, 528, 20,
    379 												s_wcd.hWnd, 
    380 												( HMENU ) INPUT_ID,	// child window ID
    381 												g_wv.hInstance, NULL );
    382 
    383 	//
    384 	// create the buttons
    385 	//
    386 	s_wcd.hwndButtonCopy = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
    387 												5, 425, 72, 24,
    388 												s_wcd.hWnd, 
    389 												( HMENU ) COPY_ID,	// child window ID
    390 												g_wv.hInstance, NULL );
    391 	SendMessage( s_wcd.hwndButtonCopy, WM_SETTEXT, 0, ( LPARAM ) "copy" );
    392 
    393 	s_wcd.hwndButtonClear = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
    394 												82, 425, 72, 24,
    395 												s_wcd.hWnd, 
    396 												( HMENU ) CLEAR_ID,	// child window ID
    397 												g_wv.hInstance, NULL );
    398 	SendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) "clear" );
    399 
    400 	s_wcd.hwndButtonQuit = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
    401 												462, 425, 72, 24,
    402 												s_wcd.hWnd, 
    403 												( HMENU ) QUIT_ID,	// child window ID
    404 												g_wv.hInstance, NULL );
    405 	SendMessage( s_wcd.hwndButtonQuit, WM_SETTEXT, 0, ( LPARAM ) "quit" );
    406 
    407 
    408 	//
    409 	// create the scrollbuffer
    410 	//
    411 	s_wcd.hwndBuffer = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER | 
    412 												ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
    413 												6, 40, 526, 354,
    414 												s_wcd.hWnd, 
    415 												( HMENU ) EDIT_ID,	// child window ID
    416 												g_wv.hInstance, NULL );
    417 	SendMessage( s_wcd.hwndBuffer, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
    418 
    419 	s_wcd.SysInputLineWndProc = ( WNDPROC ) SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, ( long ) InputLineWndProc );
    420 	SendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
    421 
    422 	ShowWindow( s_wcd.hWnd, SW_SHOWDEFAULT);
    423 	UpdateWindow( s_wcd.hWnd );
    424 	SetForegroundWindow( s_wcd.hWnd );
    425 	SetFocus( s_wcd.hwndInputLine );
    426 
    427 	s_wcd.visLevel = 1;
    428 }
    429 
    430 /*
    431 ** Sys_DestroyConsole
    432 */
    433 void Sys_DestroyConsole( void ) {
    434 	if ( s_wcd.hWnd ) {
    435 		ShowWindow( s_wcd.hWnd, SW_HIDE );
    436 		CloseWindow( s_wcd.hWnd );
    437 		DestroyWindow( s_wcd.hWnd );
    438 		s_wcd.hWnd = 0;
    439 	}
    440 }
    441 
    442 /*
    443 ** Sys_ShowConsole
    444 */
    445 void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
    446 {
    447 	s_wcd.quitOnClose = quitOnClose;
    448 
    449 	if ( visLevel == s_wcd.visLevel )
    450 	{
    451 		return;
    452 	}
    453 
    454 	s_wcd.visLevel = visLevel;
    455 
    456 	if ( !s_wcd.hWnd )
    457 		return;
    458 
    459 	switch ( visLevel )
    460 	{
    461 	case 0:
    462 		ShowWindow( s_wcd.hWnd, SW_HIDE );
    463 		break;
    464 	case 1:
    465 		ShowWindow( s_wcd.hWnd, SW_SHOWNORMAL );
    466 		SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
    467 		break;
    468 	case 2:
    469 		ShowWindow( s_wcd.hWnd, SW_MINIMIZE );
    470 		break;
    471 	default:
    472 		Sys_Error( "Invalid visLevel %d sent to Sys_ShowConsole\n", visLevel );
    473 		break;
    474 	}
    475 }
    476 
    477 /*
    478 ** Sys_ConsoleInput
    479 */
    480 char *Sys_ConsoleInput( void )
    481 {
    482 	if ( s_wcd.consoleText[0] == 0 )
    483 	{
    484 		return NULL;
    485 	}
    486 		
    487 	strcpy( s_wcd.returnedText, s_wcd.consoleText );
    488 	s_wcd.consoleText[0] = 0;
    489 	
    490 	return s_wcd.returnedText;
    491 }
    492 
    493 /*
    494 ** Conbuf_AppendText
    495 */
    496 void Conbuf_AppendText( const char *pMsg )
    497 {
    498 #define CONSOLE_BUFFER_SIZE		16384
    499 
    500 	char buffer[CONSOLE_BUFFER_SIZE*2];
    501 	char *b = buffer;
    502 	const char *msg;
    503 	int bufLen;
    504 	int i = 0;
    505 	static unsigned long s_totalChars;
    506 
    507 	//
    508 	// if the message is REALLY long, use just the last portion of it
    509 	//
    510 	if ( strlen( pMsg ) > CONSOLE_BUFFER_SIZE - 1 )
    511 	{
    512 		msg = pMsg + strlen( pMsg ) - CONSOLE_BUFFER_SIZE + 1;
    513 	}
    514 	else
    515 	{
    516 		msg = pMsg;
    517 	}
    518 
    519 	//
    520 	// copy into an intermediate buffer
    521 	//
    522 	while ( msg[i] && ( ( b - buffer ) < sizeof( buffer ) - 1 ) )
    523 	{
    524 		if ( msg[i] == '\n' && msg[i+1] == '\r' )
    525 		{
    526 			b[0] = '\r';
    527 			b[1] = '\n';
    528 			b += 2;
    529 			i++;
    530 		}
    531 		else if ( msg[i] == '\r' )
    532 		{
    533 			b[0] = '\r';
    534 			b[1] = '\n';
    535 			b += 2;
    536 		}
    537 		else if ( msg[i] == '\n' )
    538 		{
    539 			b[0] = '\r';
    540 			b[1] = '\n';
    541 			b += 2;
    542 		}
    543 		else if ( Q_IsColorString( &msg[i] ) )
    544 		{
    545 			i++;
    546 		}
    547 		else
    548 		{
    549 			*b= msg[i];
    550 			b++;
    551 		}
    552 		i++;
    553 	}
    554 	*b = 0;
    555 	bufLen = b - buffer;
    556 
    557 	s_totalChars += bufLen;
    558 
    559 	//
    560 	// replace selection instead of appending if we're overflowing
    561 	//
    562 	if ( s_totalChars > 0x7fff )
    563 	{
    564 		SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
    565 		s_totalChars = bufLen;
    566 	}
    567 
    568 	//
    569 	// put this text into the windows console
    570 	//
    571 	SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
    572 	SendMessage( s_wcd.hwndBuffer, EM_SCROLLCARET, 0, 0 );
    573 	SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, 0, (LPARAM) buffer );
    574 }
    575 
    576 /*
    577 ** Sys_SetErrorText
    578 */
    579 void Sys_SetErrorText( const char *buf )
    580 {
    581 	Q_strncpyz( s_wcd.errorString, buf, sizeof( s_wcd.errorString ) );
    582 
    583 	if ( !s_wcd.hwndErrorBox )
    584 	{
    585 		s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN,
    586 													6, 5, 526, 30,
    587 													s_wcd.hWnd, 
    588 													( HMENU ) ERRORBOX_ID,	// child window ID
    589 													g_wv.hInstance, NULL );
    590 		SendMessage( s_wcd.hwndErrorBox, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
    591 		SetWindowText( s_wcd.hwndErrorBox, s_wcd.errorString );
    592 
    593 		DestroyWindow( s_wcd.hwndInputLine );
    594 		s_wcd.hwndInputLine = NULL;
    595 	}
    596 }