Actual source code: win32draw.c

      1: #include <petscsys.h>
      2: #include <petsc/private/drawimpl.h>
      3: #include <../src/sys/classes/draw/impls/win32/win32draw.h>

      5: #define IDC_FOUR       109
      6: #define IDI_FOUR       107
      7: #define IDM_EXIT       105
      8: #define IDR_POPUP      103
      9: #define MAX_LOADSTRING 100

     11: #if !defined(SelectPen)
     12:   #define SelectPen(hdc, hpen) ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))
     13: #endif
     14: #if !defined(SelectFont)
     15:   #define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
     16: #endif
     17: #if !defined(SelectBrush)
     18:   #define SelectBrush(hdc, hbrush) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbrush)))
     19: #endif
     20: #if !defined(GetStockBrush)
     21:   #define GetStockBrush(i) ((HBRUSH)GetStockObject(i))
     22: #endif

     24: #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))))
     25: #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))))

     27: HINSTANCE  hInst;
     28: HANDLE     g_hWindowListMutex = NULL;
     29: WindowNode WindowListHead     = NULL;

     31: /* Hard coded color hue until hue.c works with this */
     32: 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};
     33: 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};
     34: 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};

     36: /* Forward declarations of functions included in this code module: */
     37: LRESULT CALLBACK      PetscWndProc(HWND, UINT, WPARAM, LPARAM);
     38: static PetscErrorCode TranslateColor_Win32(PetscDraw, int);
     39: static PetscErrorCode AverageColorRectangle_Win32(PetscDraw, int, int, int, int);
     40: static PetscErrorCode AverageColorTriangle_Win32(PetscDraw, int, int, int);
     41: static PetscErrorCode deletemouselist_Win32(WindowNode);
     42: static void           OnPaint_Win32(HWND);
     43: static void           OnDestroy_Win32(HWND);
     44: static PetscErrorCode MouseRecord_Win32(HWND, PetscDrawButton);
     45: static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw, PetscDraw *);

     47: static PetscErrorCode PetscDrawSetDoubleBuffer_Win32(PetscDraw draw)
     48: {
     49:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
     50:   HDC              hdc     = GetDC(windraw->hWnd);

     52:   PetscFunctionBegin;
     53:   windraw->node->DoubleBuffer    = CreateCompatibleDC(hdc);
     54:   windraw->node->DoubleBufferBit = CreateCompatibleBitmap(hdc, windraw->w, windraw->h);
     55:   windraw->node->dbstore         = SelectObject(windraw->node->DoubleBuffer, windraw->node->DoubleBufferBit);
     56:   /* Fill background of second buffer */
     57:   ExtFloodFill(windraw->node->DoubleBuffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);
     58:   /* Copy current buffer into second buffer and set window data as double buffered */
     59:   BitBlt(windraw->node->DoubleBuffer, 0, 0, windraw->w, windraw->h, windraw->node->Buffer, 0, 0, SRCCOPY);

     61:   windraw->node->DoubleBuffered = PETSC_TRUE;
     62:   ReleaseDC(windraw->hWnd, hdc);
     63:   PetscFunctionReturn(PETSC_SUCCESS);
     64: }

     66: static PetscErrorCode PetscDrawFlush_Win32(PetscDraw draw)
     67: {
     68:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
     69:   HDC              hdc     = GetDC(windraw->hWnd);

     71:   PetscFunctionBegin;
     72:   /* flush double buffer into primary buffer */
     73:   BitBlt(windraw->node->Buffer, 0, 0, windraw->w, windraw->h, windraw->node->DoubleBuffer, 0, 0, SRCCOPY);
     74:   /* flush double buffer into window */
     75:   BitBlt(hdc, 0, 0, windraw->w, windraw->h, windraw->node->DoubleBuffer, 0, 0, SRCCOPY);
     76:   ReleaseDC(windraw->hWnd, hdc);
     77:   PetscFunctionReturn(PETSC_SUCCESS);
     78: }

     80: static PetscErrorCode deletemouselist_Win32(WindowNode deletelist)
     81: {
     82:   /* Called upon window close. Frees memory of linked list of stored mouse commands */
     83:   MouseNode node;

     85:   while (deletelist->MouseListHead) {
     86:     node = deletelist->MouseListHead;
     87:     if (deletelist->MouseListHead->mnext) deletelist->MouseListHead = deletelist->MouseListHead->mnext;
     88:     PetscFree(node);
     89:   }
     90:   deletelist->MouseListHead = deletelist->MouseListTail = NULL;
     91:   if (deletelist->wprev) deletelist->wprev->wnext = deletelist->wnext;
     92:   if (deletelist->wnext) deletelist->wnext->wprev = deletelist->wprev;
     93:   PetscFree(deletelist);
     94:   return PETSC_SUCCESS;
     95: }

     97: static PetscErrorCode PetscDrawGetMouseButton_Win32(PetscDraw draw, PetscDrawButton *button, PetscReal *x_user, PetscReal *y_user, PetscReal *x_phys, PetscReal *y_phys)
     98: {
     99:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    100:   WindowNode       current;
    101:   MouseNode        node = 0;

    103:   PetscFunctionBegin;
    104:   /* Make sure no other code is using the linked list at this moment */
    105:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
    106:   /* Look for the node that matches the window you are using */
    107:   current = WindowListHead;
    108:   while (current) {
    109:     if (current->hWnd == windraw->hWnd) {
    110:       current->IsGetMouseOn = TRUE;
    111:       break;
    112:     } else current = current->wnext;
    113:   }
    114:   /* If no actions have occurred, wait for one */
    115:   node = current->MouseListHead;
    116:   if (!node) {
    117:     ReleaseMutex(g_hWindowListMutex);
    118:     WaitForSingleObject(current->event, INFINITE);
    119:     WaitForSingleObject(g_hWindowListMutex, INFINITE);
    120:   }
    121:   /* once we have the information, assign the pointers to it */
    122:   *button = current->MouseListHead->Button;
    123:   *x_user = current->MouseListHead->user.x;
    124:   *y_user = current->MouseListHead->user.y;
    125:   /* optional arguments */
    126:   if (x_phys) *x_phys = current->MouseListHead->phys.x;
    127:   if (y_phys) *y_phys = current->MouseListHead->phys.y;
    128:   /* remove set of information from sub linked-list, delete the node */
    129:   current->MouseListHead = current->MouseListHead->mnext;
    130:   if (!current->MouseListHead) {
    131:     ResetEvent(current->event);
    132:     current->MouseListTail = NULL;
    133:   }
    134:   if (node) PetscFree(node);

    136:   /* Release mutex so that  other code can use
    137:      the linked list now that we are done with it */
    138:   ReleaseMutex(g_hWindowListMutex);
    139:   PetscFunctionReturn(PETSC_SUCCESS);
    140: }

    142: static PetscErrorCode PetscDrawPause_Win32(PetscDraw draw)
    143: {
    144:   PetscFunctionBegin;
    145:   PetscSleep(draw->pause);
    146:   PetscFunctionReturn(PETSC_SUCCESS);
    147: }

    149: static PetscErrorCode TranslateColor_Win32(PetscDraw draw, int color)
    150: {
    151:   /* Maps single color value into the RGB colors in our tables */
    152:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    153:   windraw->currentcolor    = RGB(RedMap[color], GreenMap[color], BlueMap[color]);
    154:   return PETSC_SUCCESS;
    155: }

    157: static PetscErrorCode AverageColorRectangle_Win32(PetscDraw draw, int c1, int c2, int c3, int c4)
    158: {
    159:   /* Averages colors given at points of rectangle and sets color from color table
    160:     will be changed once the color gradient problem is worked out */
    161:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    162:   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);
    163:   return PETSC_SUCCESS;
    164: }

    166: static PetscErrorCode AverageColorTriangle_Win32(PetscDraw draw, int c1, int c2, int c3)
    167: {
    168:   /* Averages colors given at points of rectangle and sets color from color table
    169:     will be changed once the color gradient problem is worked out */
    170:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    171:   windraw->currentcolor    = RGB((RedMap[c1] + RedMap[c2] + RedMap[c3]) / 3, (GreenMap[c1] + GreenMap[c2] + GreenMap[c3]) / 3, (BlueMap[c1] + BlueMap[c2] + BlueMap[c3]) / 3);
    172:   return PETSC_SUCCESS;
    173: }

    175: static PetscErrorCode PetscDrawRectangle_Win32(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int c1, int c2, int c3, int c4)
    176: {
    177:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    178:   HBRUSH           hbrush;
    179:   RECT             rect;
    180:   int              x1, yone, x2, y2;
    181:   HDC              hdc;

    183:   PetscFunctionBegin;
    184:   x1   = XTRANS(draw, windraw, xl);
    185:   x2   = XTRANS(draw, windraw, xr);
    186:   yone = YTRANS(draw, windraw, yl);
    187:   y2   = YTRANS(draw, windraw, yr);
    188:   SetRect(&rect, x1, y2, x2, yone);
    189:   if (c1 == c2 && c2 == c3 && c3 == c4) TranslateColor_Win32(draw, c1);
    190:   else AverageColorRectangle_Win32(draw, c1, c2, c3, c4);
    191:   hbrush = CreateSolidBrush(windraw->currentcolor);

    193:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
    194:   else hdc = windraw->node->Buffer;

    196:   FillRect(hdc, &rect, hbrush);
    197:   /* Forces a WM_PAINT message and erases background */
    198:   InvalidateRect(windraw->hWnd, NULL, TRUE);
    199:   UpdateWindow(windraw->hWnd);
    200:   PetscFunctionReturn(PETSC_SUCCESS);
    201: }

    203: static PetscErrorCode PetscDrawLine_Win32(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int color)
    204: {
    205:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    206:   HPEN             hpen;
    207:   int              x1, yone, x2, y2;
    208:   HDC              hdc;

    210:   PetscFunctionBegin;
    211:   TranslateColor_Win32(draw, color);
    212:   x1   = XTRANS(draw, windraw, xl);
    213:   x2   = XTRANS(draw, windraw, xr);
    214:   yone = YTRANS(draw, windraw, yl);
    215:   y2   = YTRANS(draw, windraw, yr);
    216:   hpen = CreatePen(PS_SOLID, windraw->linewidth, windraw->currentcolor);
    217:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
    218:   else hdc = windraw->node->Buffer;

    220:   SelectPen(hdc, hpen);
    221:   MoveToEx(hdc, x1, yone, NULL);
    222:   LineTo(hdc, x2, y2);
    223:   /* Forces a WM_PAINT message and erases background */
    224:   InvalidateRect(windraw->hWnd, NULL, TRUE);
    225:   UpdateWindow(windraw->hWnd);
    226:   PetscFunctionReturn(PETSC_SUCCESS);
    227: }

    229: static PetscErrorCode PetscDrawLineSetWidth_Win32(PetscDraw draw, PetscReal width)
    230: {
    231:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    232:   int              averagesize, finalwidth;
    233:   RECT             rect;

    235:   PetscFunctionBegin;
    236:   GetClientRect(windraw->hWnd, &rect);
    237:   averagesize = ((rect.right - rect.left) + (rect.bottom - rect.top)) / 2;
    238:   finalwidth  = (int)PetscFloorReal(averagesize * width);
    239:   if (finalwidth < 1) finalwidth = 1; /* minimum size PetscDrawLine can except */

    241:   windraw->linewidth = finalwidth;
    242:   PetscFunctionReturn(PETSC_SUCCESS);
    243: }

    245: static PetscErrorCode PetscDrawLineGetWidth_Win32(PetscDraw draw, PetscReal *width)
    246: {
    247:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

    249:   PetscFunctionBegin;
    250:   *width = (PetscReal)windraw->linewidth;
    251:   PetscFunctionReturn(PETSC_SUCCESS);
    252: }

    254: static PetscErrorCode PetscDrawPoint_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color)
    255: {
    256:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    257:   HBRUSH           hbrush;
    258:   HRGN             hrgn;
    259:   int              radius;
    260:   int              x1, yone;
    261:   HDC              hdc;

    263:   PetscFunctionBegin;
    264:   TranslateColor_Win32(draw, color);
    265:   x1     = XTRANS(draw, windraw, x);
    266:   yone   = YTRANS(draw, windraw, y);
    267:   hbrush = CreateSolidBrush(windraw->currentcolor);
    268:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
    269:   else hdc = windraw->node->Buffer;

    271:   /* desired size is one logical pixel so just turn it on */
    272:   if (windraw->pointdiameter == 1) SetPixelV(hdc, x1, yone, windraw->currentcolor);
    273:   else {
    274:     /* draw point around position determined */
    275:     radius = windraw->pointdiameter / 2; /* integer division */
    276:     hrgn   = CreateEllipticRgn(x1 - radius, yone - radius, x1 + radius, yone + radius);
    277:     FillRgn(hdc, hrgn, hbrush);
    278:   }
    279:   /* Forces a WM_PAINT and erases background */
    280:   InvalidateRect(windraw->hWnd, NULL, TRUE);
    281:   UpdateWindow(windraw->hWnd);
    282:   PetscFunctionReturn(PETSC_SUCCESS);
    283: }

    285: static PetscErrorCode PetscDrawPointSetSize_Win32(PetscDraw draw, PetscReal width)
    286: {
    287:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    288:   int              averagesize, diameter;
    289:   RECT             rect;

    291:   PetscFunctionBegin;
    292:   GetClientRect(windraw->hWnd, &rect);
    293:   averagesize = ((rect.right - rect.left) + (rect.bottom - rect.top)) / 2;
    294:   diameter    = (int)PetscFloorReal(averagesize * width);
    295:   if (diameter < 1) diameter = 1;
    296:   windraw->pointdiameter = diameter;
    297:   PetscFunctionReturn(PETSC_SUCCESS);
    298: }

    300: static PetscErrorCode PetscDrawString_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color, const char *text)
    301: {
    302:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    303:   RECT             r;
    304:   HFONT            hfont;
    305:   LOGFONT          logfont;
    306:   int              x1, yone;
    307:   HDC              hdc;

    309:   PetscFunctionBegin;
    310:   x1       = XTRANS(draw, windraw, x);
    311:   yone     = YTRANS(draw, windraw, y);
    312:   r.bottom = yone;
    313:   r.left   = x1;
    314:   r.right  = x1 + 1;
    315:   r.top    = yone + 1;

    317:   logfont.lfHeight         = windraw->stringheight;
    318:   logfont.lfWidth          = windraw->stringwidth;
    319:   logfont.lfEscapement     = 0;
    320:   logfont.lfOrientation    = 0;
    321:   logfont.lfCharSet        = 0;
    322:   logfont.lfClipPrecision  = 0;
    323:   logfont.lfItalic         = 0;
    324:   logfont.lfOutPrecision   = 0;
    325:   logfont.lfPitchAndFamily = DEFAULT_PITCH;
    326:   logfont.lfQuality        = DEFAULT_QUALITY;
    327:   logfont.lfStrikeOut      = 0;
    328:   logfont.lfUnderline      = 0;
    329:   logfont.lfWeight         = FW_NORMAL;

    331:   hfont = CreateFontIndirect(&logfont);
    332:   TranslateColor_Win32(draw, color);
    333:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
    334:   else hdc = windraw->node->Buffer;

    336:   SelectFont(hdc, hfont);
    337:   SetTextColor(hdc, windraw->currentcolor);
    338:   DrawText(hdc, text, lstrlen(text), &r, DT_NOCLIP);
    339:   DeleteObject(hfont);
    340:   /* Forces a WM_PAINT message and erases background */
    341:   InvalidateRect(windraw->hWnd, NULL, TRUE);
    342:   UpdateWindow(windraw->hWnd);
    343:   PetscFunctionReturn(PETSC_SUCCESS);
    344: }

    346: static PetscErrorCode PetscDrawStringVertical_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color, const char *text)
    347: {
    348:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    349:   RECT             r;
    350:   HFONT            hfont;
    351:   LOGFONT          logfont;
    352:   int              x1, yone;
    353:   HDC              hdc;

    355:   PetscFunctionBegin;
    356:   x1       = XTRANS(draw, windraw, x);
    357:   yone     = YTRANS(draw, windraw, y);
    358:   r.left   = x1;
    359:   r.bottom = yone + 30;
    360:   r.right  = x1 + 1;
    361:   r.top    = yone - 30;

    363:   logfont.lfEscapement     = 2700; /* Causes vertical text drawing */
    364:   logfont.lfHeight         = windraw->stringheight;
    365:   logfont.lfWidth          = windraw->stringwidth;
    366:   logfont.lfOrientation    = 0;
    367:   logfont.lfCharSet        = DEFAULT_CHARSET;
    368:   logfont.lfClipPrecision  = 0;
    369:   logfont.lfItalic         = 0;
    370:   logfont.lfOutPrecision   = 0;
    371:   logfont.lfPitchAndFamily = DEFAULT_PITCH;
    372:   logfont.lfQuality        = DEFAULT_QUALITY;
    373:   logfont.lfStrikeOut      = 0;
    374:   logfont.lfUnderline      = 0;
    375:   logfont.lfWeight         = FW_NORMAL;

    377:   hfont = CreateFontIndirect(&logfont);
    378:   TranslateColor_Win32(draw, color);
    379:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
    380:   else hdc = windraw->node->Buffer;

    382:   SelectFont(hdc, hfont);
    383:   SetTextColor(hdc, windraw->currentcolor);
    384:   DrawText(hdc, text, lstrlen(text), &r, DT_NOCLIP | DT_SINGLELINE);
    385:   DeleteObject(hfont);
    386:   /* Forces a WM_PAINT message and erases background */
    387:   InvalidateRect(windraw->hWnd, NULL, TRUE);
    388:   UpdateWindow(windraw->hWnd);
    389:   PetscFunctionReturn(PETSC_SUCCESS);
    390: }

    392: static PetscErrorCode PetscDrawStringSetSize_Win32(PetscDraw draw, PetscReal width, PetscReal height)
    393: {
    394:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    395:   int              w, h;

    397:   PetscFunctionBegin;
    398:   w = (int)(windraw->w * width * (draw->port_xr - draw->port_xl) / (draw->coor_xr - draw->coor_xl));
    399:   h = (int)(windraw->h * height * (draw->port_yr - draw->port_yl) / (draw->coor_yr - draw->coor_yl));
    400:   if (h < 1) h = 1;
    401:   if (w < 1) w = 1;
    402:   windraw->stringheight = h;
    403:   windraw->stringwidth  = w;
    404:   PetscFunctionReturn(PETSC_SUCCESS);
    405: }
    406: static PetscErrorCode PetscDrawStringGetSize_Win32(PetscDraw draw, PetscReal *width, PetscReal *height)
    407: {
    408:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    409:   double           scaleX  = (draw->coor_xr - draw->coor_xl) / (draw->w) * (draw->port_xr - draw->port_xl);
    410:   double           scaleY  = (draw->coor_yr - draw->coor_yl) / (draw->h) * (draw->port_yr - draw->port_yl);

    412:   PetscFunctionBegin;
    413:   if (height) *height = (double)windraw->stringheight * scaleY;
    414:   if (width) *width = (double)windraw->stringwidth * scaleX;
    415:   PetscFunctionReturn(PETSC_SUCCESS);
    416: }

    418: static PetscErrorCode PetscDrawResizeWindow_Win32(PetscDraw draw, int w, int h)
    419: {
    420:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    421:   RECT             r;

    423:   PetscFunctionBegin;
    424:   GetWindowRect(windraw->hWnd, &r);
    425:   MoveWindow(windraw->hWnd, r.left, r.top, (int)w, (int)h, TRUE);
    426:   /* set all variable dealing with window dimensions */
    427:   windraw->node->bitheight = windraw->h = draw->h = h;
    428:   windraw->node->bitwidth = windraw->w = draw->w = w;
    429:   /* set up graphic buffers with the new size of window */
    430:   SetBitmapDimensionEx(windraw->node->BufferBit, w, h, NULL);
    431:   if (windraw->node->DoubleBuffered) SetBitmapDimensionEx(windraw->node->DoubleBufferBit, w, h, NULL);
    432:   windraw->haveresized = PETSC_TRUE;
    433:   PetscFunctionReturn(PETSC_SUCCESS);
    434: }

    436: static PetscErrorCode PetscDrawCheckResizedWindow_Win32(PetscDraw draw)
    437: {
    438:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

    440:   PetscFunctionBegin;
    441:   PetscCheck(windraw->haveresized != 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for resizing windows on Microsoft Windows");
    442:   PetscFunctionReturn(PETSC_SUCCESS);
    443: }

    445: static PetscErrorCode PetscDrawSetTitle_Win32(PetscDraw draw, const char title[])
    446: {
    447:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

    449:   PetscFunctionBegin;
    450:   SetWindowText(windraw->hWnd, title);
    451:   PetscFunctionReturn(PETSC_SUCCESS);
    452: }

    454: static PetscErrorCode PetscDrawClear_Win32(PetscDraw draw)
    455: {
    456:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

    458:   PetscFunctionBegin;
    459:   /* clear primary buffer */
    460:   ExtFloodFill(windraw->node->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);
    461:   /* if exists clear secondary buffer */
    462:   if (windraw->node->DoubleBuffered) ExtFloodFill(windraw->node->DoubleBuffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);

    464:   /* force WM_PAINT message so cleared buffer will show */
    465:   InvalidateRect(windraw->hWnd, NULL, TRUE);
    466:   UpdateWindow(windraw->hWnd);
    467:   PetscFunctionReturn(PETSC_SUCCESS);
    468: }

    470: static PetscErrorCode PetscDrawTriangle_Win32(PetscDraw draw, PetscReal x1, PetscReal yone, PetscReal x2, PetscReal y2, PetscReal x3, PetscReal y3, int c1, int c2, int c3)
    471: {
    472:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    473:   HBRUSH           hbrush;
    474:   HPEN             hpen;
    475:   int              p1x, p1y, p2x, p2y, p3x, p3y;
    476:   HDC              bit;

    478:   PetscFunctionBegin;
    479:   AverageColorTriangle_Win32(draw, c1, c2, c3);
    480:   hbrush = CreateSolidBrush(windraw->currentcolor);
    481:   hpen   = CreatePen(PS_SOLID, 0, windraw->currentcolor);
    482:   p1x    = XTRANS(draw, windraw, x1);
    483:   p2x    = XTRANS(draw, windraw, x2);
    484:   p3x    = XTRANS(draw, windraw, x3);
    485:   p1y    = YTRANS(draw, windraw, yone);
    486:   p2y    = YTRANS(draw, windraw, y2);
    487:   p3y    = YTRANS(draw, windraw, y3);

    489:   if (windraw->node->DoubleBuffered) bit = windraw->node->DoubleBuffer;
    490:   else bit = windraw->node->Buffer;

    492:   BeginPath(bit);
    493:   MoveToEx(bit, p1x, p1y, NULL);
    494:   LineTo(bit, p2x, p2y);
    495:   LineTo(bit, p3x, p3y);
    496:   LineTo(bit, p1x, p1y);
    497:   EndPath(bit);
    498:   SelectPen(bit, hpen);
    499:   SelectBrush(bit, hbrush);
    500:   StrokeAndFillPath(bit);
    501:   /* Forces a WM_PAINT message and erases background */
    502:   InvalidateRect(windraw->hWnd, NULL, TRUE);
    503:   UpdateWindow(windraw->hWnd);
    504:   PetscFunctionReturn(PETSC_SUCCESS);
    505: }

    507: static PetscErrorCode PetscDrawSetVisible_Win32(PetscDraw draw, PetscBool visible)
    508: {
    509:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

    511:   PetscFunctionBegin;
    512:   ShowWindow(windraw->hWnd, visible ? SW_SHOWNA : SW_HIDE);
    513:   PetscFunctionReturn(PETSC_SUCCESS);
    514: }

    516: static PetscErrorCode PetscDrawDestroy_Win32(PetscDraw draw)
    517: {
    518:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

    520:   PetscFunctionBegin;
    521:   SendMessage(windraw->hWnd, WM_DESTROY, 0, 0);
    522:   PetscFree(draw->data);
    523:   PetscFunctionReturn(PETSC_SUCCESS);
    524: }

    526: static void MessageLoopThread_Win32(PetscDraw draw)
    527: {
    528:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
    529:   MSG              msg;
    530:   HWND             hWnd        = NULL;
    531:   const char       classname[] = "PETSc Window Class";
    532:   WNDCLASSEX       wclass;
    533:   LPVOID           lpMsgBuf;

    535:   /* initialize window class parameters */
    536:   wclass.cbSize        = sizeof(WNDCLASSEX);
    537:   wclass.style         = CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW;
    538:   wclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
    539:   wclass.cbClsExtra    = 0;
    540:   wclass.cbWndExtra    = 0;
    541:   wclass.hInstance     = NULL;
    542:   wclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    543:   wclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
    544:   wclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
    545:   wclass.lpszMenuName  = NULL;
    546:   wclass.lpszClassName = classname;
    547:   wclass.hIconSm       = NULL;

    549:   RegisterClassEx(&wclass);

    551:   hWnd = CreateWindowEx(0, classname, NULL, WS_OVERLAPPEDWINDOW, draw->x, draw->y, draw->w, draw->h, NULL, NULL, hInst, NULL);

    553:   if (!hWnd) {
    554:     lpMsgBuf = (LPVOID) "Window Not Successfully Created";
    555:     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
    556:     LocalFree(lpMsgBuf);
    557:     exit(0);
    558:   }
    559:   windraw->hWnd = hWnd;
    560:   /* display and update new window */
    561:   ShowWindow(hWnd, SW_SHOWNORMAL);
    562:   UpdateWindow(hWnd);
    563:   SetEvent(windraw->hReadyEvent);

    565:   while (GetMessage(&msg, hWnd, 0, 0)) {
    566:     TranslateMessage(&msg);
    567:     DispatchMessage(&msg);
    568:   }
    569:   return;
    570: }

    572: 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};

    574: static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw draw, PetscDraw *popup)
    575: {
    576:   PetscDraw_Win32 *win = (PetscDraw_Win32 *)draw->data;
    577:   PetscBool        flg = PETSC_TRUE;

    579:   PetscFunctionBegin;
    580:   PetscCall(PetscOptionsGetBool(((PetscObject)draw)->options, ((PetscObject)draw)->prefix, "-draw_popup", &flg, NULL));
    581:   if (flg) {
    582:     PetscCall(PetscDrawCreate(PetscObjectComm((PetscObject)draw), NULL, NULL, win->x, win->y + win->h + 36, 220, 220, popup));
    583:     PetscCall(PetscDrawSetType(*popup, PETSC_DRAW_WIN32));
    584:     draw->popup = *popup;
    585:   } else {
    586:     *popup = NULL;
    587:   }
    588:   PetscFunctionReturn(PETSC_SUCCESS);
    589: }
    590: PETSC_EXTERN PetscErrorCode PetscDrawCreate_Win32(PetscDraw draw)
    591: {
    592:   PetscDraw_Win32 *windraw;
    593:   HANDLE           hThread = NULL;
    594:   WindowNode       newnode;

    596:   PetscFunctionBegin;
    597:   PetscCall(PetscNew(&windraw));
    598:   draw->data = windraw;

    600:   /* the following is temporary fix for initializing a global datastructure */
    601:   if (!g_hWindowListMutex) g_hWindowListMutex = CreateMutex(NULL, FALSE, NULL);
    602:   draw->ops[0] = DvOps;

    604:   windraw->hReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    605:   /* makes call to MessageLoopThread to creat window and attach a thread */
    606:   CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoopThread_Win32, draw, 0, (LPDWORD)hThread);
    607:   CloseHandle(hThread);
    608:   WaitForSingleObject(windraw->hReadyEvent, INFINITE);
    609:   CloseHandle(windraw->hReadyEvent);
    610:   WaitForSingleObject(g_hWindowListMutex, INFINITE);

    612:   PetscCall(PetscNew(&newnode));
    613:   newnode->MouseListHead = NULL;
    614:   newnode->MouseListTail = NULL;
    615:   newnode->wnext         = WindowListHead;
    616:   newnode->wprev         = NULL;
    617:   newnode->hWnd          = windraw->hWnd;
    618:   if (WindowListHead) WindowListHead->wprev = newnode;
    619:   WindowListHead = newnode;
    620:   windraw->hdc   = GetDC(windraw->hWnd);

    622:   windraw->stringheight  = 10;
    623:   windraw->stringwidth   = 6;
    624:   windraw->linewidth     = 1; /* default pixel sizes of graphics until user changes them */
    625:   windraw->pointdiameter = 1;
    626:   windraw->node          = newnode;

    628:   windraw->x = draw->x;
    629:   windraw->y = draw->y;
    630:   windraw->w = newnode->bitwidth = draw->w;
    631:   windraw->h = newnode->bitheight = draw->h;

    633:   /* Create and initialize primary graphics buffer */
    634:   newnode->Buffer    = CreateCompatibleDC(windraw->hdc);
    635:   newnode->BufferBit = CreateCompatibleBitmap(windraw->hdc, windraw->w, windraw->h);
    636:   newnode->store     = SelectObject(newnode->Buffer, newnode->BufferBit);
    637:   ExtFloodFill(newnode->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);

    639:   newnode->event          = CreateEvent(NULL, TRUE, FALSE, NULL);
    640:   newnode->DoubleBuffered = PETSC_FALSE;

    642:   ReleaseDC(windraw->hWnd, windraw->hdc);
    643:   ReleaseMutex(g_hWindowListMutex);
    644:   PetscFunctionReturn(PETSC_SUCCESS);
    645: }

    647: /* FUNCTION: PetscWndProc(HWND, unsigned, WORD, LONG)
    648:    PURPOSE:  Processes messages for the main window.
    649:    WM_COMMAND  - process the application menu
    650:    WM_PAINT    - Paint the main window
    651:    WM_DESTROY  - post a quit message and return */

    653: LRESULT CALLBACK PetscWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    654: {
    655:   int wmId;

    657:   switch (message) {
    658:     HANDLE_MSG(hWnd, WM_PAINT, OnPaint_Win32);
    659:     HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy_Win32);
    660:   case WM_COMMAND:
    661:     wmId = LOWORD(wParam);
    662:     /* Parse the menu selections:*/
    663:     switch (wmId) {
    664:     case IDM_EXIT:
    665:       DestroyWindow(hWnd);
    666:       break;
    667:     default:
    668:       return DefWindowProc(hWnd, message, wParam, lParam);
    669:     }
    670:     break;
    671:   case WM_LBUTTONUP:
    672:     MouseRecord_Win32(hWnd, PETSC_BUTTON_LEFT);
    673:     break;
    674:   case WM_RBUTTONUP:
    675:     MouseRecord_Win32(hWnd, PETSC_BUTTON_RIGHT);
    676:     break;
    677:   case WM_MBUTTONUP:
    678:     MouseRecord_Win32(hWnd, PETSC_BUTTON_CENTER);
    679:     break;
    680:   default:
    681:     return DefWindowProc(hWnd, message, wParam, lParam);
    682:   }
    683:   return 0;
    684: }

    686: static void OnPaint_Win32(HWND hWnd)
    687: {
    688:   PAINTSTRUCT ps;
    689:   HDC         hdc;
    690:   WindowNode  current = NULL;

    692:   InvalidateRect(hWnd, NULL, TRUE);
    693:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
    694:   current = WindowListHead;
    695:   hdc     = BeginPaint(hWnd, &ps);

    697:   while (current) {
    698:     if (current->hWnd == hWnd) {
    699:       /* flushes primary buffer to window */
    700:       BitBlt(hdc, 0, 0, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES), current->Buffer, 0, 0, SRCCOPY);

    702:       /* StretchBlt(hdc,0,0,w,h,
    703:         current->Buffer,0,0,current->bitwidth,current->bitheight,SRCCOPY); */
    704:       break;
    705:     }
    706:     current = current->wnext;
    707:   }
    708:   EndPaint(hWnd, &ps);
    709:   ReleaseMutex(g_hWindowListMutex);
    710:   return;
    711: }

    713: static PetscErrorCode MouseRecord_Win32(HWND hWnd, PetscDrawButton button)
    714: {
    715:   /* Called by all three mouse button actions
    716:     Records needed mouse data in windows data structure */
    717:   WindowNode current = NULL;
    718:   MouseNode  newnode;
    719:   POINT      mousepos;

    721:   PetscFunctionBegin;
    722:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
    723:   current = WindowListHead;
    724:   if (current->IsGetMouseOn == TRUE) {
    725:     SetEvent(current->event);
    726:     while (current) {
    727:       if (current->hWnd == hWnd) {
    728:         PetscCall(PetscNew(&newnode));
    729:         newnode->Button = button;
    730:         GetCursorPos(&mousepos);
    731:         newnode->user.x = mousepos.x;
    732:         newnode->user.y = mousepos.y;
    733:         ScreenToClient(hWnd, &mousepos);
    734:         newnode->phys.x = mousepos.x;
    735:         newnode->phys.y = mousepos.y;
    736:         if (!current->MouseListTail) {
    737:           current->MouseListHead = newnode;
    738:           current->MouseListTail = newnode;
    739:         } else {
    740:           current->MouseListTail->mnext = newnode;
    741:           current->MouseListTail        = newnode;
    742:         }
    743:         newnode->mnext = NULL;

    745:         break;
    746:       }
    747:       current = current->wnext;
    748:     }
    749:   }
    750:   ReleaseMutex(g_hWindowListMutex);
    751:   PetscFunctionReturn(PETSC_SUCCESS);
    752: }

    754: static void OnDestroy_Win32(HWND hWnd)
    755: {
    756:   /* searches linked list of window data and frees corresponding memory */
    757:   WindowNode current;

    759:   PetscFunctionBegin;
    760:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
    761:   current = WindowListHead;

    763:   SetEvent(current->event);
    764:   while (current) {
    765:     if (current->hWnd == hWnd) {
    766:       if (current->wprev) current->wprev->wnext = current->wnext;
    767:       else WindowListHead = current->wnext;
    768:       if (current->MouseListHead) deletemouselist_Win32(current);
    769:       else PetscFree(current);
    770:       break;
    771:     }
    772:     current = current->wnext;
    773:   }
    774:   ReleaseMutex(g_hWindowListMutex);
    775:   PostQuitMessage(0);
    776:   PetscFunctionReturnVoid();
    777: }