Actual source code: win32draw.c


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

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

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

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

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

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

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

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

 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:   return 0;
 64: }

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

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

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

140: static PetscErrorCode PetscDrawPause_Win32(PetscDraw draw)
141: {
142:   PetscSleep(draw->pause);
143:   return 0;
144: }

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

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

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

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

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

189:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
190:   else hdc = windraw->node->Buffer;

192:   FillRect(hdc, &rect, hbrush);
193:   /* Forces a WM_PAINT message and erases background */
194:   InvalidateRect(windraw->hWnd, NULL, TRUE);
195:   UpdateWindow(windraw->hWnd);
196:   return 0;
197: }

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

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

215:   SelectPen(hdc, hpen);
216:   MoveToEx(hdc, x1, yone, NULL);
217:   LineTo(hdc, x2, y2);
218:   /* Forces a WM_PAINT message and erases background */
219:   InvalidateRect(windraw->hWnd, NULL, TRUE);
220:   UpdateWindow(windraw->hWnd);
221:   return 0;
222: }

224: static PetscErrorCode PetscDrawLineSetWidth_Win32(PetscDraw draw, PetscReal width)
225: {
226:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
227:   int              averagesize, finalwidth;
228:   RECT             rect;

230:   GetClientRect(windraw->hWnd, &rect);
231:   averagesize = ((rect.right - rect.left) + (rect.bottom - rect.top)) / 2;
232:   finalwidth  = (int)PetscFloorReal(averagesize * width);
233:   if (finalwidth < 1) finalwidth = 1; /* minimum size PetscDrawLine can except */

235:   windraw->linewidth = finalwidth;
236:   return 0;
237: }

239: static PetscErrorCode PetscDrawLineGetWidth_Win32(PetscDraw draw, PetscReal *width)
240: {
241:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

243:   *width = (PetscReal)windraw->linewidth;
244:   return 0;
245: }

247: static PetscErrorCode PetscDrawPoint_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color)
248: {
249:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
250:   HBRUSH           hbrush;
251:   HRGN             hrgn;
252:   int              radius;
253:   int              x1, yone;
254:   HDC              hdc;

256:   TranslateColor_Win32(draw, color);
257:   x1     = XTRANS(draw, windraw, x);
258:   yone   = YTRANS(draw, windraw, y);
259:   hbrush = CreateSolidBrush(windraw->currentcolor);
260:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
261:   else hdc = windraw->node->Buffer;

263:   /* desired size is one logical pixel so just turn it on */
264:   if (windraw->pointdiameter == 1) SetPixelV(hdc, x1, yone, windraw->currentcolor);
265:   else {
266:     /* draw point around position determined */
267:     radius = windraw->pointdiameter / 2; /* integer division */
268:     hrgn   = CreateEllipticRgn(x1 - radius, yone - radius, x1 + radius, yone + radius);
269:     FillRgn(hdc, hrgn, hbrush);
270:   }
271:   /* Forces a WM_PAINT and erases background */
272:   InvalidateRect(windraw->hWnd, NULL, TRUE);
273:   UpdateWindow(windraw->hWnd);
274:   return 0;
275: }

277: static PetscErrorCode PetscDrawPointSetSize_Win32(PetscDraw draw, PetscReal width)
278: {
279:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
280:   int              averagesize, diameter;
281:   RECT             rect;

283:   GetClientRect(windraw->hWnd, &rect);
284:   averagesize = ((rect.right - rect.left) + (rect.bottom - rect.top)) / 2;
285:   diameter    = (int)PetscFloorReal(averagesize * width);
286:   if (diameter < 1) diameter = 1;
287:   windraw->pointdiameter = diameter;
288:   return 0;
289: }

291: static PetscErrorCode PetscDrawString_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color, const char *text)
292: {
293:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
294:   RECT             r;
295:   HFONT            hfont;
296:   LOGFONT          logfont;
297:   int              x1, yone;
298:   HDC              hdc;

300:   x1       = XTRANS(draw, windraw, x);
301:   yone     = YTRANS(draw, windraw, y);
302:   r.bottom = yone;
303:   r.left   = x1;
304:   r.right  = x1 + 1;
305:   r.top    = yone + 1;

307:   logfont.lfHeight         = windraw->stringheight;
308:   logfont.lfWidth          = windraw->stringwidth;
309:   logfont.lfEscapement     = 0;
310:   logfont.lfOrientation    = 0;
311:   logfont.lfCharSet        = 0;
312:   logfont.lfClipPrecision  = 0;
313:   logfont.lfItalic         = 0;
314:   logfont.lfOutPrecision   = 0;
315:   logfont.lfPitchAndFamily = DEFAULT_PITCH;
316:   logfont.lfQuality        = DEFAULT_QUALITY;
317:   logfont.lfStrikeOut      = 0;
318:   logfont.lfUnderline      = 0;
319:   logfont.lfWeight         = FW_NORMAL;

321:   hfont = CreateFontIndirect(&logfont);
322:   TranslateColor_Win32(draw, color);
323:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
324:   else hdc = windraw->node->Buffer;

326:   SelectFont(hdc, hfont);
327:   SetTextColor(hdc, windraw->currentcolor);
328:   DrawText(hdc, text, lstrlen(text), &r, DT_NOCLIP);
329:   DeleteObject(hfont);
330:   /* Forces a WM_PAINT message and erases background */
331:   InvalidateRect(windraw->hWnd, NULL, TRUE);
332:   UpdateWindow(windraw->hWnd);
333:   return 0;
334: }

336: static PetscErrorCode PetscDrawStringVertical_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color, const char *text)
337: {
338:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
339:   RECT             r;
340:   HFONT            hfont;
341:   LOGFONT          logfont;
342:   int              x1, yone;
343:   HDC              hdc;

345:   x1       = XTRANS(draw, windraw, x);
346:   yone     = YTRANS(draw, windraw, y);
347:   r.left   = x1;
348:   r.bottom = yone + 30;
349:   r.right  = x1 + 1;
350:   r.top    = yone - 30;

352:   logfont.lfEscapement     = 2700; /* Causes verticle text drawing */
353:   logfont.lfHeight         = windraw->stringheight;
354:   logfont.lfWidth          = windraw->stringwidth;
355:   logfont.lfOrientation    = 0;
356:   logfont.lfCharSet        = DEFAULT_CHARSET;
357:   logfont.lfClipPrecision  = 0;
358:   logfont.lfItalic         = 0;
359:   logfont.lfOutPrecision   = 0;
360:   logfont.lfPitchAndFamily = DEFAULT_PITCH;
361:   logfont.lfQuality        = DEFAULT_QUALITY;
362:   logfont.lfStrikeOut      = 0;
363:   logfont.lfUnderline      = 0;
364:   logfont.lfWeight         = FW_NORMAL;

366:   hfont = CreateFontIndirect(&logfont);
367:   TranslateColor_Win32(draw, color);
368:   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
369:   else hdc = windraw->node->Buffer;

371:   SelectFont(hdc, hfont);
372:   SetTextColor(hdc, windraw->currentcolor);
373:   DrawText(hdc, text, lstrlen(text), &r, DT_NOCLIP | DT_SINGLELINE);
374:   DeleteObject(hfont);
375:   /* Forces a WM_PAINT message and erases background */
376:   InvalidateRect(windraw->hWnd, NULL, TRUE);
377:   UpdateWindow(windraw->hWnd);
378:   return 0;
379: }

381: static PetscErrorCode PetscDrawStringSetSize_Win32(PetscDraw draw, PetscReal width, PetscReal height)
382: {
383:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
384:   int              w, h;

386:   w = (int)((windraw->w) * width * (draw->port_xr - draw->port_xl) / (draw->coor_xr - draw->coor_xl));
387:   h = (int)((windraw->h) * height * (draw->port_yr - draw->port_yl) / (draw->coor_yr - draw->coor_yl));
388:   if (h < 1) h = 1;
389:   if (w < 1) w = 1;
390:   windraw->stringheight = h;
391:   windraw->stringwidth  = w;
392:   return 0;
393: }
394: static PetscErrorCode PetscDrawStringGetSize_Win32(PetscDraw draw, PetscReal *width, PetscReal *height)
395: {
396:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
397:   double           scaleX  = (draw->coor_xr - draw->coor_xl) / (draw->w) * (draw->port_xr - draw->port_xl);
398:   double           scaleY  = (draw->coor_yr - draw->coor_yl) / (draw->h) * (draw->port_yr - draw->port_yl);

400:   if (height) *height = (double)windraw->stringheight * scaleY;
401:   if (width) *width = (double)windraw->stringwidth * scaleX;
402:   return 0;
403: }

405: static PetscErrorCode PetscDrawResizeWindow_Win32(PetscDraw draw, int w, int h)
406: {
407:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
408:   RECT             r;

410:   GetWindowRect(windraw->hWnd, &r);
411:   MoveWindow(windraw->hWnd, r.left, r.top, (int)w, (int)h, TRUE);
412:   /* set all variable dealing with window dimensions */
413:   windraw->node->bitheight = windraw->h = draw->h = h;
414:   windraw->node->bitwidth = windraw->w = draw->w = w;
415:   /* set up graphic buffers with the new size of window */
416:   SetBitmapDimensionEx(windraw->node->BufferBit, w, h, NULL);
417:   if (windraw->node->DoubleBuffered) SetBitmapDimensionEx(windraw->node->DoubleBufferBit, w, h, NULL);
418:   windraw->haveresized = PETSC_TRUE;
419:   return 0;
420: }

422: static PetscErrorCode PetscDrawCheckResizedWindow_Win32(PetscDraw draw)
423: {
424:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

427:   return 0;
428: }

430: static PetscErrorCode PetscDrawSetTitle_Win32(PetscDraw draw, const char title[])
431: {
432:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

434:   SetWindowText(windraw->hWnd, title);
435:   return 0;
436: }

438: static PetscErrorCode PetscDrawClear_Win32(PetscDraw draw)
439: {
440:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

442:   /* clear primary buffer */
443:   ExtFloodFill(windraw->node->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);
444:   /* if exists clear secondary buffer */
445:   if (windraw->node->DoubleBuffered) ExtFloodFill(windraw->node->DoubleBuffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);

447:   /* force WM_PAINT message so cleared buffer will show */
448:   InvalidateRect(windraw->hWnd, NULL, TRUE);
449:   UpdateWindow(windraw->hWnd);
450:   return 0;
451: }

453: static PetscErrorCode PetscDrawTriangle_Win32(PetscDraw draw, PetscReal x1, PetscReal yone, PetscReal x2, PetscReal y2, PetscReal x3, PetscReal y3, int c1, int c2, int c3)
454: {
455:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
456:   HBRUSH           hbrush;
457:   HPEN             hpen;
458:   int              p1x, p1y, p2x, p2y, p3x, p3y;
459:   HDC              bit;

461:   AverageColorTriangle_Win32(draw, c1, c2, c3);
462:   hbrush = CreateSolidBrush(windraw->currentcolor);
463:   hpen   = CreatePen(PS_SOLID, 0, windraw->currentcolor);
464:   p1x    = XTRANS(draw, windraw, x1);
465:   p2x    = XTRANS(draw, windraw, x2);
466:   p3x    = XTRANS(draw, windraw, x3);
467:   p1y    = YTRANS(draw, windraw, yone);
468:   p2y    = YTRANS(draw, windraw, y2);
469:   p3y    = YTRANS(draw, windraw, y3);

471:   if (windraw->node->DoubleBuffered) bit = windraw->node->DoubleBuffer;
472:   else bit = windraw->node->Buffer;

474:   BeginPath(bit);
475:   MoveToEx(bit, p1x, p1y, NULL);
476:   LineTo(bit, p2x, p2y);
477:   LineTo(bit, p3x, p3y);
478:   LineTo(bit, p1x, p1y);
479:   EndPath(bit);
480:   SelectPen(bit, hpen);
481:   SelectBrush(bit, hbrush);
482:   StrokeAndFillPath(bit);
483:   /* Forces a WM_PAINT message and erases background */
484:   InvalidateRect(windraw->hWnd, NULL, TRUE);
485:   UpdateWindow(windraw->hWnd);
486:   return 0;
487: }

489: void PopMessageLoopThread_Win32(PetscDraw popdraw)
490: {
491:   PetscDraw_Win32 *pop = (PetscDraw_Win32 *)popdraw->data;
492:   MSG              msg;
493:   HWND             hWnd           = NULL;
494:   const char       PopClassName[] = "PETSc Window Pop Class";
495:   RECT             r;
496:   int              width, height;
497:   WNDCLASSEX       myclass;
498:   LPVOID           lpMsgBuf;

500:   /* initialize window class parameters */
501:   myclass.cbSize        = sizeof(WNDCLASSEX);
502:   myclass.style         = CS_OWNDC;
503:   myclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
504:   myclass.cbClsExtra    = 0;
505:   myclass.cbWndExtra    = 0;
506:   myclass.hInstance     = NULL;
507:   myclass.hIcon         = NULL;
508:   myclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
509:   myclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
510:   myclass.lpszMenuName  = NULL;
511:   myclass.lpszClassName = PopClassName;
512:   myclass.hIconSm       = NULL;

514:   RegisterClassEx(&myclass);

516:   SetRect(&r, 0, 0, 450, 450);

518:   width  = (r.right - r.left) / 3;
519:   height = (r.bottom - r.top) / 3;

521:   hWnd   = CreateWindowEx(0, PopClassName, NULL, WS_POPUPWINDOW | WS_CAPTION, 0, 0, width, height, NULL, NULL, hInst, NULL);
522:   pop->x = 0;
523:   pop->y = 0;
524:   pop->w = width;
525:   pop->h = height;

527:   if (!hWnd) {
528:     lpMsgBuf = (LPVOID) "Window Not Successfully Created";
529:     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
530:     LocalFree(lpMsgBuf);
531:     exit(0);
532:   }
533:   pop->hWnd = hWnd;
534:   /* display and update new popup window */
535:   ShowWindow(pop->hWnd, SW_SHOWNORMAL);
536:   UpdateWindow(pop->hWnd);
537:   SetEvent(pop->hReadyEvent);

539:   while (GetMessage(&msg, pop->hWnd, 0, 0)) {
540:     TranslateMessage(&msg);
541:     DispatchMessage(&msg);
542:   }
543:   return;
544: }

546: static PetscErrorCode PetscDrawDestroy_Win32(PetscDraw draw)
547: {
548:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

550:   SendMessage(windraw->hWnd, WM_DESTROY, 0, 0);
551:   PetscFree(draw->data);
552:   return 0;
553: }

555: void MessageLoopThread_Win32(PetscDraw draw)
556: {
557:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
558:   MSG              msg;
559:   HWND             hWnd        = NULL;
560:   const char       classname[] = "PETSc Window Class";
561:   WNDCLASSEX       wclass;
562:   LPVOID           lpMsgBuf;

564:   /* initialize window class parameters */
565:   wclass.cbSize        = sizeof(WNDCLASSEX);
566:   wclass.style         = CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW;
567:   wclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
568:   wclass.cbClsExtra    = 0;
569:   wclass.cbWndExtra    = 0;
570:   wclass.hInstance     = NULL;
571:   wclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
572:   wclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
573:   wclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
574:   wclass.lpszMenuName  = NULL;
575:   wclass.lpszClassName = classname;
576:   wclass.hIconSm       = NULL;

578:   RegisterClassEx(&wclass);

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

582:   if (!hWnd) {
583:     lpMsgBuf = (LPVOID) "Window Not Successfully Created";
584:     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
585:     LocalFree(lpMsgBuf);
586:     exit(0);
587:   }
588:   windraw->hWnd = hWnd;
589:   /* display and update new window */
590:   ShowWindow(hWnd, SW_SHOWNORMAL);
591:   UpdateWindow(hWnd);
592:   SetEvent(windraw->hReadyEvent);

594:   while (GetMessage(&msg, hWnd, 0, 0)) {
595:     TranslateMessage(&msg);
596:     DispatchMessage(&msg);
597:   }
598:   return;
599: }

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

603: static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw draw, PetscDraw *popup)
604: {
605:   PetscDraw_Win32 *win = (PetscDraw_Win32 *)draw->data;
606:   PetscBool        flg = PETSC_TRUE;

608:   PetscOptionsGetBool(((PetscObject)draw)->options, ((PetscObject)draw)->prefix, "-draw_popup", &flg, NULL);
609:   if (flg) {
610:     PetscDrawCreate(PetscObjectComm((PetscObject)draw), NULL, NULL, win->x, win->y + win->h + 36, 220, 220, popup);
611:     PetscDrawSetType(*popup, PETSC_DRAW_WIN32);
612:     draw->popup = *popup;
613:   } else {
614:     *popup = NULL;
615:   }
616:   return 0;
617: }
618: PETSC_EXTERN PetscErrorCode PetscDrawCreate_Win32(PetscDraw draw)
619: {
620:   PetscDraw_Win32 *windraw;
621:   HANDLE           hThread = NULL;
622:   WindowNode       newnode;

624:   PetscNew(&windraw);
625:   draw->data = windraw;

627:   /* the following is temporary fix for initializing a global datastructure */
628:   if (!g_hWindowListMutex) g_hWindowListMutex = CreateMutex(NULL, FALSE, NULL);
629:   PetscMemcpy(draw->ops, &DvOps, sizeof(DvOps));

631:   windraw->hReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
632:   /* makes call to MessageLoopThread to creat window and attach a thread */
633:   CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoopThread_Win32, draw, 0, (LPDWORD)hThread);
634:   CloseHandle(hThread);
635:   WaitForSingleObject(windraw->hReadyEvent, INFINITE);
636:   CloseHandle(windraw->hReadyEvent);
637:   WaitForSingleObject(g_hWindowListMutex, INFINITE);

639:   PetscNew(&newnode);
640:   newnode->MouseListHead = NULL;
641:   newnode->MouseListTail = NULL;
642:   newnode->wnext         = WindowListHead;
643:   newnode->wprev         = NULL;
644:   newnode->hWnd          = windraw->hWnd;
645:   if (WindowListHead) WindowListHead->wprev = newnode;
646:   WindowListHead = newnode;
647:   windraw->hdc   = GetDC(windraw->hWnd);

649:   windraw->stringheight  = 10;
650:   windraw->stringwidth   = 6;
651:   windraw->linewidth     = 1; /* default pixel sizes of graphics until user changes them */
652:   windraw->pointdiameter = 1;
653:   windraw->node          = newnode;

655:   windraw->x = draw->x;
656:   windraw->y = draw->y;
657:   windraw->w = newnode->bitwidth = draw->w;
658:   windraw->h = newnode->bitheight = draw->h;

660:   /* Create and initialize primary graphics buffer */
661:   newnode->Buffer    = CreateCompatibleDC(windraw->hdc);
662:   newnode->BufferBit = CreateCompatibleBitmap(windraw->hdc, windraw->w, windraw->h);
663:   newnode->store     = SelectObject(newnode->Buffer, newnode->BufferBit);
664:   ExtFloodFill(newnode->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);

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

669:   ReleaseDC(windraw->hWnd, windraw->hdc);
670:   ReleaseMutex(g_hWindowListMutex);
671:   return 0;
672: }

674: /* FUNCTION: PetscWndProc(HWND, unsigned, WORD, LONG)
675:    PURPOSE:  Processes messages for the main window.
676:    WM_COMMAND  - process the application menu
677:    WM_PAINT    - Paint the main window
678:    WM_DESTROY  - post a quit message and return */

680: LRESULT CALLBACK PetscWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
681: {
682:   int wmId;

684:   switch (message) {
685:     HANDLE_MSG(hWnd, WM_PAINT, OnPaint_Win32);
686:     HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy_Win32);
687:   case WM_COMMAND:
688:     wmId = LOWORD(wParam);
689:     /* Parse the menu selections:*/
690:     switch (wmId) {
691:     case IDM_EXIT:
692:       DestroyWindow(hWnd);
693:       break;
694:     default:
695:       return DefWindowProc(hWnd, message, wParam, lParam);
696:     }
697:     break;
698:   case WM_LBUTTONUP:
699:     MouseRecord_Win32(hWnd, PETSC_BUTTON_LEFT);
700:     break;
701:   case WM_RBUTTONUP:
702:     MouseRecord_Win32(hWnd, PETSC_BUTTON_RIGHT);
703:     break;
704:   case WM_MBUTTONUP:
705:     MouseRecord_Win32(hWnd, PETSC_BUTTON_CENTER);
706:     break;
707:   default:
708:     return DefWindowProc(hWnd, message, wParam, lParam);
709:   }
710:   return 0;
711: }

713: static void OnPaint_Win32(HWND hWnd)
714: {
715:   PAINTSTRUCT ps;
716:   HDC         hdc;
717:   WindowNode  current = NULL;

719:   InvalidateRect(hWnd, NULL, TRUE);
720:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
721:   current = WindowListHead;
722:   hdc     = BeginPaint(hWnd, &ps);

724:   while (current) {
725:     if (current->hWnd == hWnd) {
726:       /* flushes primary buffer to window */
727:       BitBlt(hdc, 0, 0, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES), current->Buffer, 0, 0, SRCCOPY);

729:       /* StretchBlt(hdc,0,0,w,h,
730:         current->Buffer,0,0,current->bitwidth,current->bitheight,SRCCOPY); */
731:       break;
732:     }
733:     current = current->wnext;
734:   }
735:   EndPaint(hWnd, &ps);
736:   ReleaseMutex(g_hWindowListMutex);
737:   return;
738: }

740: static PetscErrorCode MouseRecord_Win32(HWND hWnd, PetscDrawButton button)
741: {
742:   /* Called by all three mouse button actions
743:     Records needed mouse data in windows data structure */
744:   WindowNode current = NULL;
745:   MouseNode  newnode;
746:   POINT      mousepos;

748:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
749:   current = WindowListHead;
750:   if (current->IsGetMouseOn == TRUE) {
751:     SetEvent(current->event);
752:     while (current) {
753:       if (current->hWnd == hWnd) {
754:         PetscNew(&newnode);
755:         newnode->Button = button;
756:         GetCursorPos(&mousepos);
757:         newnode->user.x = mousepos.x;
758:         newnode->user.y = mousepos.y;
759:         ScreenToClient(hWnd, &mousepos);
760:         newnode->phys.x = mousepos.x;
761:         newnode->phys.y = mousepos.y;
762:         if (!current->MouseListTail) {
763:           current->MouseListHead = newnode;
764:           current->MouseListTail = newnode;
765:         } else {
766:           current->MouseListTail->mnext = newnode;
767:           current->MouseListTail        = newnode;
768:         }
769:         newnode->mnext = NULL;

771:         break;
772:       }
773:       current = current->wnext;
774:     }
775:   }
776:   ReleaseMutex(g_hWindowListMutex);
777:   return 0;
778: }

780: static void OnDestroy_Win32(HWND hWnd)
781: {
782:   /* searches linked list of window data and frees corresponding memory */
783:   WindowNode current;

785:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
786:   current = WindowListHead;

788:   SetEvent(current->event);
789:   while (current) {
790:     if (current->hWnd == hWnd) {
791:       if (current->wprev) current->wprev->wnext = current->wnext;
792:       else WindowListHead = current->wnext;
793:       if (current->MouseListHead) deletemouselist_Win32(current);
794:       else PetscFree(current);
795:       break;
796:     }
797:     current = current->wnext;
798:   }
799:   ReleaseMutex(g_hWindowListMutex);
800:   PostQuitMessage(0);
801:   return;
802: }