Actual source code: win32draw.c

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

548:   RegisterClassEx(&wclass);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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