#include #include #include <../src/sys/classes/draw/impls/win32/win32draw.h> #define IDC_FOUR 109 #define IDI_FOUR 107 #define IDM_EXIT 105 #define IDR_POPUP 103 #define MAX_LOADSTRING 100 #if !defined(SelectPen) #define SelectPen(hdc, hpen) ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen))) #endif #if !defined(SelectFont) #define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont))) #endif #if !defined(SelectBrush) #define SelectBrush(hdc, hbrush) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbrush))) #endif #if !defined(GetStockBrush) #define GetStockBrush(i) ((HBRUSH)GetStockObject(i)) #endif #define XTRANS(draw, win, x) (int)(((win)->w) * ((draw)->port_xl + (((x - (draw)->coor_xl) * ((draw)->port_xr - (draw)->port_xl)) / ((draw)->coor_xr - (draw)->coor_xl)))) #define YTRANS(draw, win, y) (int)(((win)->h) * (1.0 - (draw)->port_yl - (((y - (draw)->coor_yl) * ((draw)->port_yr - (draw)->port_yl)) / ((draw)->coor_yr - (draw)->coor_yl)))) HINSTANCE hInst; HANDLE g_hWindowListMutex = NULL; WindowNode WindowListHead = NULL; /* Hard coded color hue until hue.c works with this */ unsigned char RedMap[] = {255, 0, 255, 0, 0, 0, 255, 127, 34, 255, 238, 165, 255, 255, 190, 255, 255, 238, 0, 255, 105, 154, 135, 0, 0, 244, 152, 176, 220, 216, 50, 255}; unsigned char GreenMap[] = {255, 0, 0, 255, 255, 0, 0, 255, 139, 165, 130, 42, 182, 127, 190, 255, 215, 162, 197, 246, 105, 205, 206, 100, 0, 164, 245, 224, 17, 191, 205, 240}; unsigned char BlueMap[] = {255, 0, 0, 0, 255, 255, 225, 212, 34, 0, 238, 42, 193, 80, 190, 0, 0, 173, 205, 143, 105, 50, 235, 0, 128, 96, 255, 230, 120, 216, 50, 245}; /* Forward declarations of functions included in this code module: */ LRESULT CALLBACK PetscWndProc(HWND, UINT, WPARAM, LPARAM); static PetscErrorCode TranslateColor_Win32(PetscDraw, int); static PetscErrorCode AverageColorRectangle_Win32(PetscDraw, int, int, int, int); static PetscErrorCode AverageColorTriangle_Win32(PetscDraw, int, int, int); static PetscErrorCode deletemouselist_Win32(WindowNode); static void OnPaint_Win32(HWND); static void OnDestroy_Win32(HWND); static PetscErrorCode MouseRecord_Win32(HWND, PetscDrawButton); static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw, PetscDraw *); static PetscErrorCode PetscDrawSetDoubleBuffer_Win32(PetscDraw draw) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; HDC hdc = GetDC(windraw->hWnd); PetscFunctionBegin; windraw->node->DoubleBuffer = CreateCompatibleDC(hdc); windraw->node->DoubleBufferBit = CreateCompatibleBitmap(hdc, windraw->w, windraw->h); windraw->node->dbstore = SelectObject(windraw->node->DoubleBuffer, windraw->node->DoubleBufferBit); /* Fill background of second buffer */ ExtFloodFill(windraw->node->DoubleBuffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER); /* Copy current buffer into second buffer and set window data as double buffered */ BitBlt(windraw->node->DoubleBuffer, 0, 0, windraw->w, windraw->h, windraw->node->Buffer, 0, 0, SRCCOPY); windraw->node->DoubleBuffered = PETSC_TRUE; ReleaseDC(windraw->hWnd, hdc); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawFlush_Win32(PetscDraw draw) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; HDC hdc = GetDC(windraw->hWnd); PetscFunctionBegin; /* flush double buffer into primary buffer */ BitBlt(windraw->node->Buffer, 0, 0, windraw->w, windraw->h, windraw->node->DoubleBuffer, 0, 0, SRCCOPY); /* flush double buffer into window */ BitBlt(hdc, 0, 0, windraw->w, windraw->h, windraw->node->DoubleBuffer, 0, 0, SRCCOPY); ReleaseDC(windraw->hWnd, hdc); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode deletemouselist_Win32(WindowNode deletelist) { /* Called upon window close. Frees memory of linked list of stored mouse commands */ MouseNode node; while (deletelist->MouseListHead) { node = deletelist->MouseListHead; if (deletelist->MouseListHead->mnext) deletelist->MouseListHead = deletelist->MouseListHead->mnext; PetscFree(node); } deletelist->MouseListHead = deletelist->MouseListTail = NULL; if (deletelist->wprev) deletelist->wprev->wnext = deletelist->wnext; if (deletelist->wnext) deletelist->wnext->wprev = deletelist->wprev; PetscFree(deletelist); return PETSC_SUCCESS; } static PetscErrorCode PetscDrawGetMouseButton_Win32(PetscDraw draw, PetscDrawButton *button, PetscReal *x_user, PetscReal *y_user, PetscReal *x_phys, PetscReal *y_phys) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; WindowNode current; MouseNode node = 0; PetscFunctionBegin; /* Make sure no other code is using the linked list at this moment */ WaitForSingleObject(g_hWindowListMutex, INFINITE); /* Look for the node that matches the window you are using */ current = WindowListHead; while (current) { if (current->hWnd == windraw->hWnd) { current->IsGetMouseOn = TRUE; break; } else current = current->wnext; } /* If no actions have occurred, wait for one */ node = current->MouseListHead; if (!node) { ReleaseMutex(g_hWindowListMutex); WaitForSingleObject(current->event, INFINITE); WaitForSingleObject(g_hWindowListMutex, INFINITE); } /* once we have the information, assign the pointers to it */ *button = current->MouseListHead->Button; *x_user = current->MouseListHead->user.x; *y_user = current->MouseListHead->user.y; /* optional arguments */ if (x_phys) *x_phys = current->MouseListHead->phys.x; if (y_phys) *y_phys = current->MouseListHead->phys.y; /* remove set of information from sub linked-list, delete the node */ current->MouseListHead = current->MouseListHead->mnext; if (!current->MouseListHead) { ResetEvent(current->event); current->MouseListTail = NULL; } if (node) PetscFree(node); /* Release mutex so that other code can use the linked list now that we are done with it */ ReleaseMutex(g_hWindowListMutex); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawPause_Win32(PetscDraw draw) { PetscFunctionBegin; PetscSleep(draw->pause); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode TranslateColor_Win32(PetscDraw draw, int color) { /* Maps single color value into the RGB colors in our tables */ PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; windraw->currentcolor = RGB(RedMap[color], GreenMap[color], BlueMap[color]); return PETSC_SUCCESS; } static PetscErrorCode AverageColorRectangle_Win32(PetscDraw draw, int c1, int c2, int c3, int c4) { /* Averages colors given at points of rectangle and sets color from color table will be changed once the color gradient problem is worked out */ PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; windraw->currentcolor = RGB((RedMap[c1] + RedMap[c2] + RedMap[c3] + RedMap[c4]) / 4, (GreenMap[c1] + GreenMap[c2] + GreenMap[c3] + GreenMap[c4]) / 4, (BlueMap[c1] + BlueMap[c2] + BlueMap[c3] + BlueMap[c4]) / 4); return PETSC_SUCCESS; } static PetscErrorCode AverageColorTriangle_Win32(PetscDraw draw, int c1, int c2, int c3) { /* Averages colors given at points of rectangle and sets color from color table will be changed once the color gradient problem is worked out */ PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; windraw->currentcolor = RGB((RedMap[c1] + RedMap[c2] + RedMap[c3]) / 3, (GreenMap[c1] + GreenMap[c2] + GreenMap[c3]) / 3, (BlueMap[c1] + BlueMap[c2] + BlueMap[c3]) / 3); return PETSC_SUCCESS; } static PetscErrorCode PetscDrawRectangle_Win32(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int c1, int c2, int c3, int c4) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; HBRUSH hbrush; RECT rect; int x1, yone, x2, y2; HDC hdc; PetscFunctionBegin; x1 = XTRANS(draw, windraw, xl); x2 = XTRANS(draw, windraw, xr); yone = YTRANS(draw, windraw, yl); y2 = YTRANS(draw, windraw, yr); SetRect(&rect, x1, y2, x2, yone); if (c1 == c2 && c2 == c3 && c3 == c4) TranslateColor_Win32(draw, c1); else AverageColorRectangle_Win32(draw, c1, c2, c3, c4); hbrush = CreateSolidBrush(windraw->currentcolor); if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer; else hdc = windraw->node->Buffer; FillRect(hdc, &rect, hbrush); /* Forces a WM_PAINT message and erases background */ InvalidateRect(windraw->hWnd, NULL, TRUE); UpdateWindow(windraw->hWnd); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawLine_Win32(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int color) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; HPEN hpen; int x1, yone, x2, y2; HDC hdc; PetscFunctionBegin; TranslateColor_Win32(draw, color); x1 = XTRANS(draw, windraw, xl); x2 = XTRANS(draw, windraw, xr); yone = YTRANS(draw, windraw, yl); y2 = YTRANS(draw, windraw, yr); hpen = CreatePen(PS_SOLID, windraw->linewidth, windraw->currentcolor); if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer; else hdc = windraw->node->Buffer; SelectPen(hdc, hpen); MoveToEx(hdc, x1, yone, NULL); LineTo(hdc, x2, y2); /* Forces a WM_PAINT message and erases background */ InvalidateRect(windraw->hWnd, NULL, TRUE); UpdateWindow(windraw->hWnd); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawLineSetWidth_Win32(PetscDraw draw, PetscReal width) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; int averagesize, finalwidth; RECT rect; PetscFunctionBegin; GetClientRect(windraw->hWnd, &rect); averagesize = ((rect.right - rect.left) + (rect.bottom - rect.top)) / 2; finalwidth = (int)PetscFloorReal(averagesize * width); if (finalwidth < 1) finalwidth = 1; /* minimum size PetscDrawLine can except */ windraw->linewidth = finalwidth; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawLineGetWidth_Win32(PetscDraw draw, PetscReal *width) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; PetscFunctionBegin; *width = (PetscReal)windraw->linewidth; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawPoint_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; HBRUSH hbrush; HRGN hrgn; int radius; int x1, yone; HDC hdc; PetscFunctionBegin; TranslateColor_Win32(draw, color); x1 = XTRANS(draw, windraw, x); yone = YTRANS(draw, windraw, y); hbrush = CreateSolidBrush(windraw->currentcolor); if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer; else hdc = windraw->node->Buffer; /* desired size is one logical pixel so just turn it on */ if (windraw->pointdiameter == 1) SetPixelV(hdc, x1, yone, windraw->currentcolor); else { /* draw point around position determined */ radius = windraw->pointdiameter / 2; /* integer division */ hrgn = CreateEllipticRgn(x1 - radius, yone - radius, x1 + radius, yone + radius); FillRgn(hdc, hrgn, hbrush); } /* Forces a WM_PAINT and erases background */ InvalidateRect(windraw->hWnd, NULL, TRUE); UpdateWindow(windraw->hWnd); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawPointSetSize_Win32(PetscDraw draw, PetscReal width) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; int averagesize, diameter; RECT rect; PetscFunctionBegin; GetClientRect(windraw->hWnd, &rect); averagesize = ((rect.right - rect.left) + (rect.bottom - rect.top)) / 2; diameter = (int)PetscFloorReal(averagesize * width); if (diameter < 1) diameter = 1; windraw->pointdiameter = diameter; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawString_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color, const char *text) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; RECT r; HFONT hfont; LOGFONT logfont; int x1, yone; HDC hdc; PetscFunctionBegin; x1 = XTRANS(draw, windraw, x); yone = YTRANS(draw, windraw, y); r.bottom = yone; r.left = x1; r.right = x1 + 1; r.top = yone + 1; logfont.lfHeight = windraw->stringheight; logfont.lfWidth = windraw->stringwidth; logfont.lfEscapement = 0; logfont.lfOrientation = 0; logfont.lfCharSet = 0; logfont.lfClipPrecision = 0; logfont.lfItalic = 0; logfont.lfOutPrecision = 0; logfont.lfPitchAndFamily = DEFAULT_PITCH; logfont.lfQuality = DEFAULT_QUALITY; logfont.lfStrikeOut = 0; logfont.lfUnderline = 0; logfont.lfWeight = FW_NORMAL; hfont = CreateFontIndirect(&logfont); TranslateColor_Win32(draw, color); if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer; else hdc = windraw->node->Buffer; SelectFont(hdc, hfont); SetTextColor(hdc, windraw->currentcolor); DrawText(hdc, text, lstrlen(text), &r, DT_NOCLIP); DeleteObject(hfont); /* Forces a WM_PAINT message and erases background */ InvalidateRect(windraw->hWnd, NULL, TRUE); UpdateWindow(windraw->hWnd); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawStringVertical_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color, const char *text) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; RECT r; HFONT hfont; LOGFONT logfont; int x1, yone; HDC hdc; PetscFunctionBegin; x1 = XTRANS(draw, windraw, x); yone = YTRANS(draw, windraw, y); r.left = x1; r.bottom = yone + 30; r.right = x1 + 1; r.top = yone - 30; logfont.lfEscapement = 2700; /* Causes vertical text drawing */ logfont.lfHeight = windraw->stringheight; logfont.lfWidth = windraw->stringwidth; logfont.lfOrientation = 0; logfont.lfCharSet = DEFAULT_CHARSET; logfont.lfClipPrecision = 0; logfont.lfItalic = 0; logfont.lfOutPrecision = 0; logfont.lfPitchAndFamily = DEFAULT_PITCH; logfont.lfQuality = DEFAULT_QUALITY; logfont.lfStrikeOut = 0; logfont.lfUnderline = 0; logfont.lfWeight = FW_NORMAL; hfont = CreateFontIndirect(&logfont); TranslateColor_Win32(draw, color); if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer; else hdc = windraw->node->Buffer; SelectFont(hdc, hfont); SetTextColor(hdc, windraw->currentcolor); DrawText(hdc, text, lstrlen(text), &r, DT_NOCLIP | DT_SINGLELINE); DeleteObject(hfont); /* Forces a WM_PAINT message and erases background */ InvalidateRect(windraw->hWnd, NULL, TRUE); UpdateWindow(windraw->hWnd); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawStringSetSize_Win32(PetscDraw draw, PetscReal width, PetscReal height) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; int w, h; PetscFunctionBegin; w = (int)(windraw->w * width * (draw->port_xr - draw->port_xl) / (draw->coor_xr - draw->coor_xl)); h = (int)(windraw->h * height * (draw->port_yr - draw->port_yl) / (draw->coor_yr - draw->coor_yl)); if (h < 1) h = 1; if (w < 1) w = 1; windraw->stringheight = h; windraw->stringwidth = w; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawStringGetSize_Win32(PetscDraw draw, PetscReal *width, PetscReal *height) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; double scaleX = (draw->coor_xr - draw->coor_xl) / (draw->w) * (draw->port_xr - draw->port_xl); double scaleY = (draw->coor_yr - draw->coor_yl) / (draw->h) * (draw->port_yr - draw->port_yl); PetscFunctionBegin; if (height) *height = (double)windraw->stringheight * scaleY; if (width) *width = (double)windraw->stringwidth * scaleX; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawResizeWindow_Win32(PetscDraw draw, int w, int h) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; RECT r; PetscFunctionBegin; GetWindowRect(windraw->hWnd, &r); MoveWindow(windraw->hWnd, r.left, r.top, (int)w, (int)h, TRUE); /* set all variable dealing with window dimensions */ windraw->node->bitheight = windraw->h = draw->h = h; windraw->node->bitwidth = windraw->w = draw->w = w; /* set up graphic buffers with the new size of window */ SetBitmapDimensionEx(windraw->node->BufferBit, w, h, NULL); if (windraw->node->DoubleBuffered) SetBitmapDimensionEx(windraw->node->DoubleBufferBit, w, h, NULL); windraw->haveresized = PETSC_TRUE; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawCheckResizedWindow_Win32(PetscDraw draw) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; PetscFunctionBegin; PetscCheck(windraw->haveresized != 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for resizing windows on Microsoft Windows"); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawSetTitle_Win32(PetscDraw draw, const char title[]) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; PetscFunctionBegin; SetWindowText(windraw->hWnd, title); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawClear_Win32(PetscDraw draw) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; PetscFunctionBegin; /* clear primary buffer */ ExtFloodFill(windraw->node->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER); /* if exists clear secondary buffer */ if (windraw->node->DoubleBuffered) ExtFloodFill(windraw->node->DoubleBuffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER); /* force WM_PAINT message so cleared buffer will show */ InvalidateRect(windraw->hWnd, NULL, TRUE); UpdateWindow(windraw->hWnd); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawTriangle_Win32(PetscDraw draw, PetscReal x1, PetscReal yone, PetscReal x2, PetscReal y2, PetscReal x3, PetscReal y3, int c1, int c2, int c3) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; HBRUSH hbrush; HPEN hpen; int p1x, p1y, p2x, p2y, p3x, p3y; HDC bit; PetscFunctionBegin; AverageColorTriangle_Win32(draw, c1, c2, c3); hbrush = CreateSolidBrush(windraw->currentcolor); hpen = CreatePen(PS_SOLID, 0, windraw->currentcolor); p1x = XTRANS(draw, windraw, x1); p2x = XTRANS(draw, windraw, x2); p3x = XTRANS(draw, windraw, x3); p1y = YTRANS(draw, windraw, yone); p2y = YTRANS(draw, windraw, y2); p3y = YTRANS(draw, windraw, y3); if (windraw->node->DoubleBuffered) bit = windraw->node->DoubleBuffer; else bit = windraw->node->Buffer; BeginPath(bit); MoveToEx(bit, p1x, p1y, NULL); LineTo(bit, p2x, p2y); LineTo(bit, p3x, p3y); LineTo(bit, p1x, p1y); EndPath(bit); SelectPen(bit, hpen); SelectBrush(bit, hbrush); StrokeAndFillPath(bit); /* Forces a WM_PAINT message and erases background */ InvalidateRect(windraw->hWnd, NULL, TRUE); UpdateWindow(windraw->hWnd); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawSetVisible_Win32(PetscDraw draw, PetscBool visible) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; PetscFunctionBegin; ShowWindow(windraw->hWnd, visible ? SW_SHOWNA : SW_HIDE); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PetscDrawDestroy_Win32(PetscDraw draw) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; PetscFunctionBegin; SendMessage(windraw->hWnd, WM_DESTROY, 0, 0); PetscFree(draw->data); PetscFunctionReturn(PETSC_SUCCESS); } static void MessageLoopThread_Win32(PetscDraw draw) { PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data; MSG msg; HWND hWnd = NULL; const char classname[] = "PETSc Window Class"; WNDCLASSEX wclass; LPVOID lpMsgBuf; /* initialize window class parameters */ wclass.cbSize = sizeof(WNDCLASSEX); wclass.style = CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW; wclass.lpfnWndProc = (WNDPROC)PetscWndProc; wclass.cbClsExtra = 0; wclass.cbWndExtra = 0; wclass.hInstance = NULL; wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wclass.hCursor = LoadCursor(NULL, IDC_ARROW); wclass.hbrBackground = GetStockBrush(WHITE_BRUSH); wclass.lpszMenuName = NULL; wclass.lpszClassName = classname; wclass.hIconSm = NULL; RegisterClassEx(&wclass); hWnd = CreateWindowEx(0, classname, NULL, WS_OVERLAPPEDWINDOW, draw->x, draw->y, draw->w, draw->h, NULL, NULL, hInst, NULL); if (!hWnd) { lpMsgBuf = (LPVOID) "Window Not Successfully Created"; MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION); LocalFree(lpMsgBuf); exit(0); } windraw->hWnd = hWnd; /* display and update new window */ ShowWindow(hWnd, SW_SHOWNORMAL); UpdateWindow(hWnd); SetEvent(windraw->hReadyEvent); while (GetMessage(&msg, hWnd, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return; } static struct _PetscDrawOps DvOps = {PetscDrawSetDoubleBuffer_Win32, PetscDrawFlush_Win32, PetscDrawLine_Win32, PetscDrawLineSetWidth_Win32, PetscDrawLineGetWidth_Win32, PetscDrawPoint_Win32, PetscDrawPointSetSize_Win32, PetscDrawString_Win32, PetscDrawStringVertical_Win32, PetscDrawStringSetSize_Win32, PetscDrawStringGetSize_Win32, 0, PetscDrawClear_Win32, PetscDrawRectangle_Win32, PetscDrawTriangle_Win32, 0, PetscDrawGetMouseButton_Win32, PetscDrawPause_Win32, 0, 0, PetscDrawGetPopup_Win32, PetscDrawSetTitle_Win32, PetscDrawCheckResizedWindow_Win32, PetscDrawResizeWindow_Win32, PetscDrawDestroy_Win32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PetscDrawSetVisible_Win32}; static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw draw, PetscDraw *popup) { PetscDraw_Win32 *win = (PetscDraw_Win32 *)draw->data; PetscBool flg = PETSC_TRUE; PetscFunctionBegin; PetscCall(PetscOptionsGetBool(((PetscObject)draw)->options, ((PetscObject)draw)->prefix, "-draw_popup", &flg, NULL)); if (flg) { PetscCall(PetscDrawCreate(PetscObjectComm((PetscObject)draw), NULL, NULL, win->x, win->y + win->h + 36, 220, 220, popup)); PetscCall(PetscDrawSetType(*popup, PETSC_DRAW_WIN32)); draw->popup = *popup; } else { *popup = NULL; } PetscFunctionReturn(PETSC_SUCCESS); } PETSC_EXTERN PetscErrorCode PetscDrawCreate_Win32(PetscDraw draw) { PetscDraw_Win32 *windraw; HANDLE hThread = NULL; WindowNode newnode; PetscFunctionBegin; PetscCall(PetscNew(&windraw)); draw->data = windraw; /* the following is temporary fix for initializing a global datastructure */ if (!g_hWindowListMutex) g_hWindowListMutex = CreateMutex(NULL, FALSE, NULL); draw->ops[0] = DvOps; windraw->hReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* makes call to MessageLoopThread to creat window and attach a thread */ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoopThread_Win32, draw, 0, (LPDWORD)hThread); CloseHandle(hThread); WaitForSingleObject(windraw->hReadyEvent, INFINITE); CloseHandle(windraw->hReadyEvent); WaitForSingleObject(g_hWindowListMutex, INFINITE); PetscCall(PetscNew(&newnode)); newnode->MouseListHead = NULL; newnode->MouseListTail = NULL; newnode->wnext = WindowListHead; newnode->wprev = NULL; newnode->hWnd = windraw->hWnd; if (WindowListHead) WindowListHead->wprev = newnode; WindowListHead = newnode; windraw->hdc = GetDC(windraw->hWnd); windraw->stringheight = 10; windraw->stringwidth = 6; windraw->linewidth = 1; /* default pixel sizes of graphics until user changes them */ windraw->pointdiameter = 1; windraw->node = newnode; windraw->x = draw->x; windraw->y = draw->y; windraw->w = newnode->bitwidth = draw->w; windraw->h = newnode->bitheight = draw->h; /* Create and initialize primary graphics buffer */ newnode->Buffer = CreateCompatibleDC(windraw->hdc); newnode->BufferBit = CreateCompatibleBitmap(windraw->hdc, windraw->w, windraw->h); newnode->store = SelectObject(newnode->Buffer, newnode->BufferBit); ExtFloodFill(newnode->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER); newnode->event = CreateEvent(NULL, TRUE, FALSE, NULL); newnode->DoubleBuffered = PETSC_FALSE; ReleaseDC(windraw->hWnd, windraw->hdc); ReleaseMutex(g_hWindowListMutex); PetscFunctionReturn(PETSC_SUCCESS); } /* FUNCTION: PetscWndProc(HWND, unsigned, WORD, LONG) PURPOSE: Processes messages for the main window. WM_COMMAND - process the application menu WM_PAINT - Paint the main window WM_DESTROY - post a quit message and return */ LRESULT CALLBACK PetscWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId; switch (message) { HANDLE_MSG(hWnd, WM_PAINT, OnPaint_Win32); HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy_Win32); case WM_COMMAND: wmId = LOWORD(wParam); /* Parse the menu selections:*/ switch (wmId) { case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_LBUTTONUP: MouseRecord_Win32(hWnd, PETSC_BUTTON_LEFT); break; case WM_RBUTTONUP: MouseRecord_Win32(hWnd, PETSC_BUTTON_RIGHT); break; case WM_MBUTTONUP: MouseRecord_Win32(hWnd, PETSC_BUTTON_CENTER); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } static void OnPaint_Win32(HWND hWnd) { PAINTSTRUCT ps; HDC hdc; WindowNode current = NULL; InvalidateRect(hWnd, NULL, TRUE); WaitForSingleObject(g_hWindowListMutex, INFINITE); current = WindowListHead; hdc = BeginPaint(hWnd, &ps); while (current) { if (current->hWnd == hWnd) { /* flushes primary buffer to window */ BitBlt(hdc, 0, 0, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES), current->Buffer, 0, 0, SRCCOPY); /* StretchBlt(hdc,0,0,w,h, current->Buffer,0,0,current->bitwidth,current->bitheight,SRCCOPY); */ break; } current = current->wnext; } EndPaint(hWnd, &ps); ReleaseMutex(g_hWindowListMutex); return; } static PetscErrorCode MouseRecord_Win32(HWND hWnd, PetscDrawButton button) { /* Called by all three mouse button actions Records needed mouse data in windows data structure */ WindowNode current = NULL; MouseNode newnode; POINT mousepos; PetscFunctionBegin; WaitForSingleObject(g_hWindowListMutex, INFINITE); current = WindowListHead; if (current->IsGetMouseOn == TRUE) { SetEvent(current->event); while (current) { if (current->hWnd == hWnd) { PetscCall(PetscNew(&newnode)); newnode->Button = button; GetCursorPos(&mousepos); newnode->user.x = mousepos.x; newnode->user.y = mousepos.y; ScreenToClient(hWnd, &mousepos); newnode->phys.x = mousepos.x; newnode->phys.y = mousepos.y; if (!current->MouseListTail) { current->MouseListHead = newnode; current->MouseListTail = newnode; } else { current->MouseListTail->mnext = newnode; current->MouseListTail = newnode; } newnode->mnext = NULL; break; } current = current->wnext; } } ReleaseMutex(g_hWindowListMutex); PetscFunctionReturn(PETSC_SUCCESS); } static void OnDestroy_Win32(HWND hWnd) { /* searches linked list of window data and frees corresponding memory */ WindowNode current; PetscFunctionBegin; WaitForSingleObject(g_hWindowListMutex, INFINITE); current = WindowListHead; SetEvent(current->event); while (current) { if (current->hWnd == hWnd) { if (current->wprev) current->wprev->wnext = current->wnext; else WindowListHead = current->wnext; if (current->MouseListHead) deletemouselist_Win32(current); else PetscFree(current); break; } current = current->wnext; } ReleaseMutex(g_hWindowListMutex); PostQuitMessage(0); PetscFunctionReturnVoid(); }