/* 
   Copyright 2001-2003 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222

**********************************************************************

THREDWND.C holds the code for the thread display window

**********************************************************************
*/
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <richedit.h>
#include <stdio.h>

#include "header.h"
#include "operands.h"
#include "opcodes.h"
#include <ctype.h>
#include "cvinfo.h"

extern HINSTANCE hInstance ;
extern HWND hwndClient,hwndStatus,hwndFrame ;
extern PROCESS DebugProcess ;
extern enum DebugState uState;
extern CONTEXT StoppedRegs ;

HWND hwndThread ;

static char szThreadClassName[] = "xccThreadClass" ;
static char szThreadBlankClassName[] = "xccThreadClass2" ;
static HWND hwndCtrl, hwndBlank ;

static LOGFONT fontdata = {
	16,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
	CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_DONTCARE,
	"Courier New"
} ;
static HFONT ThreadFont ;
static int ThreadAddress, ThreadLines ;
static int curpos ;

int GetEIP(HANDLE hThread)
{
         CONTEXT ThreadRegs ;
         ThreadRegs.ContextFlags = CONTEXT_FULL ;
         
         GetThreadContext(hThread, &ThreadRegs) ;
         return ThreadRegs.Eip ;
}
void ThreadDoPaint(HWND hwnd)
{
	int i ;
   THREAD *list = DebugProcess.threads ;
   int Address = ThreadAddress ;
		char buf[256],*p ;
		PAINTSTRUCT ps ;
		CONTEXT context ;
		HDC dc ;
		HFONT oldFont ;
		RECT rect ;
		int lines ;
		GetClientRect(hwnd,&rect) ;
      lines = (rect.bottom -rect.top)/ 16 ;
		dc = BeginPaint(hwnd, &ps) ;
      SelectObject(dc,ThreadFont) ;
      while (list && Address) {
         list = list->next ;
         Address -= 1 ;
      }
      for (i=0; i < lines && list; i++)  {
         char name[200] ;
         int eip = GetEIP(list->hThread) ;
         if (!FindFunctionName(name,eip))
            name[0] = 0 ;         
         sprintf(buf,"%08x %08X: %s",list->idThread, eip, name) ;

         if (i == curpos) {
           int oldtext = GetTextColor(dc) ;
           int oldbk = GetBkColor(dc) ;
           SetTextColor(dc,oldbk) ;
           SetBkColor(dc,oldtext) ;
           TextOut(dc,0,i*16+rect.top,buf,strlen(buf)) ;
           SetTextColor(dc,oldtext) ;
           SetBkColor(dc,oldbk) ;
         } else
            TextOut(dc,0,i*16+rect.top,buf,strlen(buf)) ;
         list = list->next ;
		}
		
		SelectObject(dc,oldFont) ;

		EndPaint(hwnd, &ps) ;
}
LRESULT  CALLBACK _export ThreadBlankProc( HWND hwnd, UINT iMessage, WPARAM wParam,
																		LPARAM lParam)
{
	int i,lines ;
	RECT r ;
   char module[256] ;
   THREAD *sl ;
   switch(iMessage) {
		case WM_PAINT:
         ThreadDoPaint(hwnd) ;
			return 0 ;
		case WM_SETFOCUS:
			SendMessage(hwndFrame,WM_REDRAWTOOLBAR,0,0) ;
			break ;
		case WM_KILLFOCUS:
         break ;          
      case WM_LBUTTONDOWN:
         lines = HIWORD(lParam) ;
         if (lines/16 + ThreadAddress < ThreadLines) {
            curpos = lines/16 ;
            InvalidateRect(hwnd,0,TRUE) ;
         }
         break ;
      case WM_LBUTTONDBLCLK:
         PostMessage(hwnd,WM_KEYDOWN,VK_RETURN,0) ;
         break ;
      case WM_KEYDOWN:
         switch (wParam) {
            case VK_RETURN:
               sl = DebugProcess.threads ;
               lines = ThreadAddress + curpos ;
               while (sl && lines) {
                  sl = sl->next ;
                  lines-- ;
               }
               if (sl) {
                  int eip = GetEIP(sl->hThread) ;
                  if (GetBreakpointLine(eip,module,&lines)) {
                      char *p ;
                      char nmodule[256] ;
                      static DWINFO x ;
                      FindModuleName(nmodule, module) ;
                      strcpy(x.dwName, nmodule) ;
                      p = strrchr(nmodule, '\\') ;
                      if (p)
                         strcpy(x.dwTitle,p+1) ;
                      else
                         strcpy(x.dwTitle,nmodule) ;
                      x.dwLineNo = lines ;
                      CreateDrawWindow(&x) ;
                  }
               }
               break ;
            case VK_UP:
               if (curpos)
                  curpos-- ;
               else if (ThreadAddress)
                  ThreadAddress-- ;
               InvalidateRect(hwnd,0,0) ;
               break ;
            case VK_DOWN:
               GetClientRect(hwnd,&r) ;
               lines = r.bottom/16 ;
               if (curpos < ThreadLines-1) {
                  if (curpos < lines-1)
                     curpos++ ;
                  else if (ThreadAddress < ThreadLines-1)
                     ThreadAddress++ ;
                  InvalidateRect(hwnd,0,TRUE) ;
               }
               break ;
         }
         break ;
		case WM_VSCROLL:
			GetClientRect(hwnd,&r) ;
			lines = r.bottom/16 ;
			switch(LOWORD(wParam)) {
				case SB_BOTTOM:
               ThreadAddress = ThreadLines -(lines * 1) ;
					break ;
				case SB_TOP:
               ThreadAddress = 0 ;
					break ;
				case SB_ENDSCROLL:
					return 0 ;
				case SB_LINEDOWN:
               ThreadAddress += 1 ;
					break ;
				case SB_LINEUP:
               ThreadAddress -= 1 ;
					break ;
				case SB_PAGEDOWN:
               ThreadAddress += 1 * ( lines-1) ;
					break ;
				case SB_PAGEUP:
               ThreadAddress -= 1 * (lines-1) ;
					break ;
				case SB_THUMBPOSITION:
               ThreadAddress += (HIWORD(wParam) - 32000) * 1 ;
					break ;
				case SB_THUMBTRACK :
					return 0 ;
//					return DefMDIChildProc(hwnd,iMessage,wParam,lParam) ;
			}
         if (ThreadAddress < 0)
            ThreadAddress = 0 ;
         if (ThreadAddress >= ThreadLines)
            ThreadAddress = ThreadLines-1 ;
			InvalidateRect(hwnd,0,0) ;
//			SetScrollPos(hwnd,SB_VERT, 32000,TRUE) ;
			return 0 ;
   }
   return DefWindowProc(hwnd, iMessage ,wParam , lParam) ;
}
LRESULT  CALLBACK _export ThreadProc( HWND hwnd, UINT iMessage, WPARAM wParam,
																		LPARAM lParam)
{
	int i,lines ;
	HDC dc ;
	TEXTMETRIC metric ;
	DEBUG_EVENT *xc ;
	HFONT oldFont ;
	LOGBRUSH brushstr ;
	RECT r ;
   char module[256] ;
   THREAD *sl ;
	switch(iMessage) {
      case WM_SETFOCUS:
         SetFocus(hwndBlank) ;
         break ;
		case WM_SYSCOMMAND :
			if (wParam == SC_CLOSE)
				SendMessage(hwnd,WM_CLOSE,0,0) ;
			break ;
		case WM_COMMAND:
			break ;
		case WM_CREATE:
         hwndThread = hwnd ;
         GetClientRect(hwnd,&r) ;
         hwndCtrl = CreateControlWindow(DID_THREADWND,hwnd,&r,(int)((LPMDICREATESTRUCT)(*(int *)lParam))->lParam) ;
         ThreadFont = CreateFontIndirect(&fontdata) ;
         SendMessage(hwndCtrl,LCF_ADJUSTRECT,0,(LPARAM)&r) ;
         hwndBlank = CreateWindow(szThreadBlankClassName,0,
            WS_CHILD + WS_VSCROLL + WS_CLIPSIBLINGS + WS_BORDER + WS_VISIBLE,
            r.left,r.top,r.right-r.left,r.bottom-r.top,
            hwndCtrl,0,hInstance, 0) ;
            
         break ;
		case WM_CLOSE:
         dmgrHideWindow(DID_THREADWND,TRUE );
			return 0 ;
		case WM_DESTROY:
         dmgrRemoveClient((CCW_params *)GetWindowLong(hwndCtrl,0)) ;
         DestroyWindow(hwndBlank) ;
         hwndThread = 0 ;
         DeleteObject(ThreadFont) ;
			break ;
		case WM_INITMENUPOPUP:
			return 0 ;
		case WM_SIZE:       
         r.left = r.top = 0 ;
         r.right = LOWORD(lParam) ;
         r.bottom = HIWORD(lParam) ;
         MoveWindow(hwndCtrl,0,0,r.right, r.bottom, TRUE) ;
         SendMessage(hwndCtrl, LCF_ADJUSTRECT, 0 , (LPARAM)&r ) ;
         MoveWindow(hwndBlank,r.left,r.top,r.right-r.left,r.bottom-r.top,TRUE );
			break ;
		default: 
			break ;
	}
	return DefMDIChildProc(hwnd,iMessage,wParam,lParam) ;
}
void RegisterThreadWindow(void)
{
		WNDCLASS wc ;
      memset(&wc,0,sizeof(wc)) ;
      wc.style = CS_HREDRAW + CS_VREDRAW + CS_DBLCLKS;
      wc.lpfnWndProc = &ThreadProc ;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = 0;
		wc.hInstance = hInstance ;
		wc.hIcon = LoadIcon(0,IDI_APPLICATION) ;
		wc.hCursor = LoadCursor(0,IDC_ARROW) ;
		wc.hbrBackground = GetStockObject(WHITE_BRUSH) ;
		wc.lpszMenuName = 0 ;
      wc.lpszClassName = szThreadClassName ;
		RegisterClass(&wc) ;
      wc.lpfnWndProc = &ThreadBlankProc ;
      wc.lpszClassName = szThreadBlankClassName ;
		RegisterClass(&wc) ;
}
HWND CreateThreadWindow(void)
{
   CCW_params p ;
	MDICREATESTRUCT mc ;
	HWND rv ;
	RECT r ;
   if (hwndThread) {
      SendMessage(hwndThread,WM_SETFOCUS,0,0) ;
      return hwndThread ;
	}
	GetClientRect(hwndClient,&r) ;
   mc.szClass = szThreadClassName ;
   mc.szTitle = "Thread Window" ;
	mc.hOwner = hInstance ;
	mc.x =  CW_USEDEFAULT;
	mc.y =  CW_USEDEFAULT;
   mc.cx = 30*8;
	mc.cy = 19*8;
   mc.style = WS_CLIPCHILDREN | WS_CHILD | WS_CLIPSIBLINGS | WS_DLGFRAME,
   mc.lParam = (LPARAM) 0 ;
   rv = (HWND) SendMessage(hwndClient,WM_MDICREATE,0,(LPARAM)&mc) ;
	return rv ;
}