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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

517: void PopMessageLoopThread_Win32(PetscDraw popdraw)
518: {
519:   PetscDraw_Win32 *pop = (PetscDraw_Win32 *)popdraw->data;
520:   MSG              msg;
521:   HWND             hWnd           = NULL;
522:   const char       PopClassName[] = "PETSc Window Pop Class";
523:   RECT             r;
524:   int              width, height;
525:   WNDCLASSEX       myclass;
526:   LPVOID           lpMsgBuf;

528:   PetscFunctionBegin;
529:   /* initialize window class parameters */
530:   myclass.cbSize        = sizeof(WNDCLASSEX);
531:   myclass.style         = CS_OWNDC;
532:   myclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
533:   myclass.cbClsExtra    = 0;
534:   myclass.cbWndExtra    = 0;
535:   myclass.hInstance     = NULL;
536:   myclass.hIcon         = NULL;
537:   myclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
538:   myclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
539:   myclass.lpszMenuName  = NULL;
540:   myclass.lpszClassName = PopClassName;
541:   myclass.hIconSm       = NULL;

543:   RegisterClassEx(&myclass);

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

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

550:   hWnd   = CreateWindowEx(0, PopClassName, NULL, WS_POPUPWINDOW | WS_CAPTION, 0, 0, width, height, NULL, NULL, hInst, NULL);
551:   pop->x = 0;
552:   pop->y = 0;
553:   pop->w = width;
554:   pop->h = height;

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

568:   while (GetMessage(&msg, pop->hWnd, 0, 0)) {
569:     TranslateMessage(&msg);
570:     DispatchMessage(&msg);
571:   }
572:   PetscFunctionReturnVoid();
573: }

575: static PetscErrorCode PetscDrawDestroy_Win32(PetscDraw draw)
576: {
577:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;

579:   PetscFunctionBegin;
580:   SendMessage(windraw->hWnd, WM_DESTROY, 0, 0);
581:   PetscFree(draw->data);
582:   PetscFunctionReturn(PETSC_SUCCESS);
583: }

585: void MessageLoopThread_Win32(PetscDraw draw)
586: {
587:   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
588:   MSG              msg;
589:   HWND             hWnd        = NULL;
590:   const char       classname[] = "PETSc Window Class";
591:   WNDCLASSEX       wclass;
592:   LPVOID           lpMsgBuf;

594:   /* initialize window class parameters */
595:   wclass.cbSize        = sizeof(WNDCLASSEX);
596:   wclass.style         = CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW;
597:   wclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
598:   wclass.cbClsExtra    = 0;
599:   wclass.cbWndExtra    = 0;
600:   wclass.hInstance     = NULL;
601:   wclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
602:   wclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
603:   wclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
604:   wclass.lpszMenuName  = NULL;
605:   wclass.lpszClassName = classname;
606:   wclass.hIconSm       = NULL;

608:   RegisterClassEx(&wclass);

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

612:   if (!hWnd) {
613:     lpMsgBuf = (LPVOID) "Window Not Successfully Created";
614:     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
615:     LocalFree(lpMsgBuf);
616:     exit(0);
617:   }
618:   windraw->hWnd = hWnd;
619:   /* display and update new window */
620:   ShowWindow(hWnd, SW_SHOWNORMAL);
621:   UpdateWindow(hWnd);
622:   SetEvent(windraw->hReadyEvent);

624:   while (GetMessage(&msg, hWnd, 0, 0)) {
625:     TranslateMessage(&msg);
626:     DispatchMessage(&msg);
627:   }
628:   return;
629: }

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

633: static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw draw, PetscDraw *popup)
634: {
635:   PetscDraw_Win32 *win = (PetscDraw_Win32 *)draw->data;
636:   PetscBool        flg = PETSC_TRUE;

638:   PetscFunctionBegin;
639:   PetscCall(PetscOptionsGetBool(((PetscObject)draw)->options, ((PetscObject)draw)->prefix, "-draw_popup", &flg, NULL));
640:   if (flg) {
641:     PetscCall(PetscDrawCreate(PetscObjectComm((PetscObject)draw), NULL, NULL, win->x, win->y + win->h + 36, 220, 220, popup));
642:     PetscCall(PetscDrawSetType(*popup, PETSC_DRAW_WIN32));
643:     draw->popup = *popup;
644:   } else {
645:     *popup = NULL;
646:   }
647:   PetscFunctionReturn(PETSC_SUCCESS);
648: }
649: PETSC_EXTERN PetscErrorCode PetscDrawCreate_Win32(PetscDraw draw)
650: {
651:   PetscDraw_Win32 *windraw;
652:   HANDLE           hThread = NULL;
653:   WindowNode       newnode;

655:   PetscFunctionBegin;
656:   PetscCall(PetscNew(&windraw));
657:   draw->data = windraw;

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

663:   windraw->hReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
664:   /* makes call to MessageLoopThread to creat window and attach a thread */
665:   CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoopThread_Win32, draw, 0, (LPDWORD)hThread);
666:   CloseHandle(hThread);
667:   WaitForSingleObject(windraw->hReadyEvent, INFINITE);
668:   CloseHandle(windraw->hReadyEvent);
669:   WaitForSingleObject(g_hWindowListMutex, INFINITE);

671:   PetscCall(PetscNew(&newnode));
672:   newnode->MouseListHead = NULL;
673:   newnode->MouseListTail = NULL;
674:   newnode->wnext         = WindowListHead;
675:   newnode->wprev         = NULL;
676:   newnode->hWnd          = windraw->hWnd;
677:   if (WindowListHead) WindowListHead->wprev = newnode;
678:   WindowListHead = newnode;
679:   windraw->hdc   = GetDC(windraw->hWnd);

681:   windraw->stringheight  = 10;
682:   windraw->stringwidth   = 6;
683:   windraw->linewidth     = 1; /* default pixel sizes of graphics until user changes them */
684:   windraw->pointdiameter = 1;
685:   windraw->node          = newnode;

687:   windraw->x = draw->x;
688:   windraw->y = draw->y;
689:   windraw->w = newnode->bitwidth = draw->w;
690:   windraw->h = newnode->bitheight = draw->h;

692:   /* Create and initialize primary graphics buffer */
693:   newnode->Buffer    = CreateCompatibleDC(windraw->hdc);
694:   newnode->BufferBit = CreateCompatibleBitmap(windraw->hdc, windraw->w, windraw->h);
695:   newnode->store     = SelectObject(newnode->Buffer, newnode->BufferBit);
696:   ExtFloodFill(newnode->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);

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

701:   ReleaseDC(windraw->hWnd, windraw->hdc);
702:   ReleaseMutex(g_hWindowListMutex);
703:   PetscFunctionReturn(PETSC_SUCCESS);
704: }

706: /* FUNCTION: PetscWndProc(HWND, unsigned, WORD, LONG)
707:    PURPOSE:  Processes messages for the main window.
708:    WM_COMMAND  - process the application menu
709:    WM_PAINT    - Paint the main window
710:    WM_DESTROY  - post a quit message and return */

712: LRESULT CALLBACK PetscWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
713: {
714:   int wmId;

716:   switch (message) {
717:     HANDLE_MSG(hWnd, WM_PAINT, OnPaint_Win32);
718:     HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy_Win32);
719:   case WM_COMMAND:
720:     wmId = LOWORD(wParam);
721:     /* Parse the menu selections:*/
722:     switch (wmId) {
723:     case IDM_EXIT:
724:       DestroyWindow(hWnd);
725:       break;
726:     default:
727:       return DefWindowProc(hWnd, message, wParam, lParam);
728:     }
729:     break;
730:   case WM_LBUTTONUP:
731:     MouseRecord_Win32(hWnd, PETSC_BUTTON_LEFT);
732:     break;
733:   case WM_RBUTTONUP:
734:     MouseRecord_Win32(hWnd, PETSC_BUTTON_RIGHT);
735:     break;
736:   case WM_MBUTTONUP:
737:     MouseRecord_Win32(hWnd, PETSC_BUTTON_CENTER);
738:     break;
739:   default:
740:     return DefWindowProc(hWnd, message, wParam, lParam);
741:   }
742:   return 0;
743: }

745: static void OnPaint_Win32(HWND hWnd)
746: {
747:   PAINTSTRUCT ps;
748:   HDC         hdc;
749:   WindowNode  current = NULL;

751:   InvalidateRect(hWnd, NULL, TRUE);
752:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
753:   current = WindowListHead;
754:   hdc     = BeginPaint(hWnd, &ps);

756:   while (current) {
757:     if (current->hWnd == hWnd) {
758:       /* flushes primary buffer to window */
759:       BitBlt(hdc, 0, 0, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES), current->Buffer, 0, 0, SRCCOPY);

761:       /* StretchBlt(hdc,0,0,w,h,
762:         current->Buffer,0,0,current->bitwidth,current->bitheight,SRCCOPY); */
763:       break;
764:     }
765:     current = current->wnext;
766:   }
767:   EndPaint(hWnd, &ps);
768:   ReleaseMutex(g_hWindowListMutex);
769:   return;
770: }

772: static PetscErrorCode MouseRecord_Win32(HWND hWnd, PetscDrawButton button)
773: {
774:   /* Called by all three mouse button actions
775:     Records needed mouse data in windows data structure */
776:   WindowNode current = NULL;
777:   MouseNode  newnode;
778:   POINT      mousepos;

780:   PetscFunctionBegin;
781:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
782:   current = WindowListHead;
783:   if (current->IsGetMouseOn == TRUE) {
784:     SetEvent(current->event);
785:     while (current) {
786:       if (current->hWnd == hWnd) {
787:         PetscCall(PetscNew(&newnode));
788:         newnode->Button = button;
789:         GetCursorPos(&mousepos);
790:         newnode->user.x = mousepos.x;
791:         newnode->user.y = mousepos.y;
792:         ScreenToClient(hWnd, &mousepos);
793:         newnode->phys.x = mousepos.x;
794:         newnode->phys.y = mousepos.y;
795:         if (!current->MouseListTail) {
796:           current->MouseListHead = newnode;
797:           current->MouseListTail = newnode;
798:         } else {
799:           current->MouseListTail->mnext = newnode;
800:           current->MouseListTail        = newnode;
801:         }
802:         newnode->mnext = NULL;

804:         break;
805:       }
806:       current = current->wnext;
807:     }
808:   }
809:   ReleaseMutex(g_hWindowListMutex);
810:   PetscFunctionReturn(PETSC_SUCCESS);
811: }

813: static void OnDestroy_Win32(HWND hWnd)
814: {
815:   /* searches linked list of window data and frees corresponding memory */
816:   WindowNode current;

818:   PetscFunctionBegin;
819:   WaitForSingleObject(g_hWindowListMutex, INFINITE);
820:   current = WindowListHead;

822:   SetEvent(current->event);
823:   while (current) {
824:     if (current->hWnd == hWnd) {
825:       if (current->wprev) current->wprev->wnext = current->wnext;
826:       else WindowListHead = current->wnext;
827:       if (current->MouseListHead) deletemouselist_Win32(current);
828:       else PetscFree(current);
829:       break;
830:     }
831:     current = current->wnext;
832:   }
833:   ReleaseMutex(g_hWindowListMutex);
834:   PostQuitMessage(0);
835:   PetscFunctionReturnVoid();
836: }