xref: /petsc/src/sys/classes/draw/impls/win32/win32draw.c (revision d0e6bf2ad94dcc89b258ce16c7987200a4714786)
1 #include <petscsys.h>
2 #include <petsc/private/drawimpl.h>
3 #include <../src/sys/classes/draw/impls/win32/win32draw.h>
4 
5 #define IDC_FOUR       109
6 #define IDI_FOUR       107
7 #define IDM_EXIT       105
8 #define IDR_POPUP      103
9 #define MAX_LOADSTRING 100
10 
11 #if !defined(SelectPen)
12   #define SelectPen(hdc, hpen) ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))
13 #endif
14 #if !defined(SelectFont)
15   #define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
16 #endif
17 #if !defined(SelectBrush)
18   #define SelectBrush(hdc, hbrush) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbrush)))
19 #endif
20 #if !defined(GetStockBrush)
21   #define GetStockBrush(i) ((HBRUSH)GetStockObject(i))
22 #endif
23 
24 #define XTRANS(draw, win, x) (int)(((win)->w) * ((draw)->port_xl + (((x - (draw)->coor_xl) * ((draw)->port_xr - (draw)->port_xl)) / ((draw)->coor_xr - (draw)->coor_xl))))
25 #define YTRANS(draw, win, y) (int)(((win)->h) * (1.0 - (draw)->port_yl - (((y - (draw)->coor_yl) * ((draw)->port_yr - (draw)->port_yl)) / ((draw)->coor_yr - (draw)->coor_yl))))
26 
27 HINSTANCE  hInst;
28 HANDLE     g_hWindowListMutex = NULL;
29 WindowNode WindowListHead     = NULL;
30 
31 /* Hard coded color hue until hue.c works with this */
32 unsigned char RedMap[]   = {255, 0, 255, 0, 0, 0, 255, 127, 34, 255, 238, 165, 255, 255, 190, 255, 255, 238, 0, 255, 105, 154, 135, 0, 0, 244, 152, 176, 220, 216, 50, 255};
33 unsigned char GreenMap[] = {255, 0, 0, 255, 255, 0, 0, 255, 139, 165, 130, 42, 182, 127, 190, 255, 215, 162, 197, 246, 105, 205, 206, 100, 0, 164, 245, 224, 17, 191, 205, 240};
34 unsigned char BlueMap[]  = {255, 0, 0, 0, 255, 255, 225, 212, 34, 0, 238, 42, 193, 80, 190, 0, 0, 173, 205, 143, 105, 50, 235, 0, 128, 96, 255, 230, 120, 216, 50, 245};
35 
36 /* Forward declarations of functions included in this code module: */
37 LRESULT CALLBACK      PetscWndProc(HWND, UINT, WPARAM, LPARAM);
38 static PetscErrorCode TranslateColor_Win32(PetscDraw, int);
39 static PetscErrorCode AverageColorRectangle_Win32(PetscDraw, int, int, int, int);
40 static PetscErrorCode AverageColorTriangle_Win32(PetscDraw, int, int, int);
41 static PetscErrorCode deletemouselist_Win32(WindowNode);
42 static void           OnPaint_Win32(HWND);
43 static void           OnDestroy_Win32(HWND);
44 static PetscErrorCode MouseRecord_Win32(HWND, PetscDrawButton);
45 static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw, PetscDraw *);
46 
PetscDrawSetDoubleBuffer_Win32(PetscDraw draw)47 static PetscErrorCode PetscDrawSetDoubleBuffer_Win32(PetscDraw draw)
48 {
49   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
50   HDC              hdc     = GetDC(windraw->hWnd);
51 
52   PetscFunctionBegin;
53   windraw->node->DoubleBuffer    = CreateCompatibleDC(hdc);
54   windraw->node->DoubleBufferBit = CreateCompatibleBitmap(hdc, windraw->w, windraw->h);
55   windraw->node->dbstore         = SelectObject(windraw->node->DoubleBuffer, windraw->node->DoubleBufferBit);
56   /* Fill background of second buffer */
57   ExtFloodFill(windraw->node->DoubleBuffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);
58   /* Copy current buffer into second buffer and set window data as double buffered */
59   BitBlt(windraw->node->DoubleBuffer, 0, 0, windraw->w, windraw->h, windraw->node->Buffer, 0, 0, SRCCOPY);
60 
61   windraw->node->DoubleBuffered = PETSC_TRUE;
62   ReleaseDC(windraw->hWnd, hdc);
63   PetscFunctionReturn(PETSC_SUCCESS);
64 }
65 
PetscDrawFlush_Win32(PetscDraw draw)66 static PetscErrorCode PetscDrawFlush_Win32(PetscDraw draw)
67 {
68   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
69   HDC              hdc     = GetDC(windraw->hWnd);
70 
71   PetscFunctionBegin;
72   /* flush double buffer into primary buffer */
73   BitBlt(windraw->node->Buffer, 0, 0, windraw->w, windraw->h, windraw->node->DoubleBuffer, 0, 0, SRCCOPY);
74   /* flush double buffer into window */
75   BitBlt(hdc, 0, 0, windraw->w, windraw->h, windraw->node->DoubleBuffer, 0, 0, SRCCOPY);
76   ReleaseDC(windraw->hWnd, hdc);
77   PetscFunctionReturn(PETSC_SUCCESS);
78 }
79 
deletemouselist_Win32(WindowNode deletelist)80 static PetscErrorCode deletemouselist_Win32(WindowNode deletelist)
81 {
82   /* Called upon window close. Frees memory of linked list of stored mouse commands */
83   MouseNode node;
84 
85   while (deletelist->MouseListHead) {
86     node = deletelist->MouseListHead;
87     if (deletelist->MouseListHead->mnext) deletelist->MouseListHead = deletelist->MouseListHead->mnext;
88     PetscFree(node);
89   }
90   deletelist->MouseListHead = deletelist->MouseListTail = NULL;
91   if (deletelist->wprev) deletelist->wprev->wnext = deletelist->wnext;
92   if (deletelist->wnext) deletelist->wnext->wprev = deletelist->wprev;
93   PetscFree(deletelist);
94   return PETSC_SUCCESS;
95 }
96 
PetscDrawGetMouseButton_Win32(PetscDraw draw,PetscDrawButton * button,PetscReal * x_user,PetscReal * y_user,PetscReal * x_phys,PetscReal * y_phys)97 static PetscErrorCode PetscDrawGetMouseButton_Win32(PetscDraw draw, PetscDrawButton *button, PetscReal *x_user, PetscReal *y_user, PetscReal *x_phys, PetscReal *y_phys)
98 {
99   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
100   WindowNode       current;
101   MouseNode        node = 0;
102 
103   PetscFunctionBegin;
104   /* Make sure no other code is using the linked list at this moment */
105   WaitForSingleObject(g_hWindowListMutex, INFINITE);
106   /* Look for the node that matches the window you are using */
107   current = WindowListHead;
108   while (current) {
109     if (current->hWnd == windraw->hWnd) {
110       current->IsGetMouseOn = TRUE;
111       break;
112     } else current = current->wnext;
113   }
114   /* If no actions have occurred, wait for one */
115   node = current->MouseListHead;
116   if (!node) {
117     ReleaseMutex(g_hWindowListMutex);
118     WaitForSingleObject(current->event, INFINITE);
119     WaitForSingleObject(g_hWindowListMutex, INFINITE);
120   }
121   /* once we have the information, assign the pointers to it */
122   *button = current->MouseListHead->Button;
123   *x_user = current->MouseListHead->user.x;
124   *y_user = current->MouseListHead->user.y;
125   /* optional arguments */
126   if (x_phys) *x_phys = current->MouseListHead->phys.x;
127   if (y_phys) *y_phys = current->MouseListHead->phys.y;
128   /* remove set of information from sub linked-list, delete the node */
129   current->MouseListHead = current->MouseListHead->mnext;
130   if (!current->MouseListHead) {
131     ResetEvent(current->event);
132     current->MouseListTail = NULL;
133   }
134   if (node) PetscFree(node);
135 
136   /* Release mutex so that  other code can use
137      the linked list now that we are done with it */
138   ReleaseMutex(g_hWindowListMutex);
139   PetscFunctionReturn(PETSC_SUCCESS);
140 }
141 
PetscDrawPause_Win32(PetscDraw draw)142 static PetscErrorCode PetscDrawPause_Win32(PetscDraw draw)
143 {
144   PetscFunctionBegin;
145   PetscSleep(draw->pause);
146   PetscFunctionReturn(PETSC_SUCCESS);
147 }
148 
TranslateColor_Win32(PetscDraw draw,int color)149 static PetscErrorCode TranslateColor_Win32(PetscDraw draw, int color)
150 {
151   /* Maps single color value into the RGB colors in our tables */
152   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
153   windraw->currentcolor    = RGB(RedMap[color], GreenMap[color], BlueMap[color]);
154   return PETSC_SUCCESS;
155 }
156 
AverageColorRectangle_Win32(PetscDraw draw,int c1,int c2,int c3,int c4)157 static PetscErrorCode AverageColorRectangle_Win32(PetscDraw draw, int c1, int c2, int c3, int c4)
158 {
159   /* Averages colors given at points of rectangle and sets color from color table
160     will be changed once the color gradient problem is worked out */
161   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
162   windraw->currentcolor    = RGB((RedMap[c1] + RedMap[c2] + RedMap[c3] + RedMap[c4]) / 4, (GreenMap[c1] + GreenMap[c2] + GreenMap[c3] + GreenMap[c4]) / 4, (BlueMap[c1] + BlueMap[c2] + BlueMap[c3] + BlueMap[c4]) / 4);
163   return PETSC_SUCCESS;
164 }
165 
AverageColorTriangle_Win32(PetscDraw draw,int c1,int c2,int c3)166 static PetscErrorCode AverageColorTriangle_Win32(PetscDraw draw, int c1, int c2, int c3)
167 {
168   /* Averages colors given at points of rectangle and sets color from color table
169     will be changed once the color gradient problem is worked out */
170   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
171   windraw->currentcolor    = RGB((RedMap[c1] + RedMap[c2] + RedMap[c3]) / 3, (GreenMap[c1] + GreenMap[c2] + GreenMap[c3]) / 3, (BlueMap[c1] + BlueMap[c2] + BlueMap[c3]) / 3);
172   return PETSC_SUCCESS;
173 }
174 
PetscDrawRectangle_Win32(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int c1,int c2,int c3,int c4)175 static PetscErrorCode PetscDrawRectangle_Win32(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int c1, int c2, int c3, int c4)
176 {
177   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
178   HBRUSH           hbrush;
179   RECT             rect;
180   int              x1, yone, x2, y2;
181   HDC              hdc;
182 
183   PetscFunctionBegin;
184   x1   = XTRANS(draw, windraw, xl);
185   x2   = XTRANS(draw, windraw, xr);
186   yone = YTRANS(draw, windraw, yl);
187   y2   = YTRANS(draw, windraw, yr);
188   SetRect(&rect, x1, y2, x2, yone);
189   if (c1 == c2 && c2 == c3 && c3 == c4) TranslateColor_Win32(draw, c1);
190   else AverageColorRectangle_Win32(draw, c1, c2, c3, c4);
191   hbrush = CreateSolidBrush(windraw->currentcolor);
192 
193   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
194   else hdc = windraw->node->Buffer;
195 
196   FillRect(hdc, &rect, hbrush);
197   /* Forces a WM_PAINT message and erases background */
198   InvalidateRect(windraw->hWnd, NULL, TRUE);
199   UpdateWindow(windraw->hWnd);
200   PetscFunctionReturn(PETSC_SUCCESS);
201 }
202 
PetscDrawLine_Win32(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int color)203 static PetscErrorCode PetscDrawLine_Win32(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int color)
204 {
205   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
206   HPEN             hpen;
207   int              x1, yone, x2, y2;
208   HDC              hdc;
209 
210   PetscFunctionBegin;
211   TranslateColor_Win32(draw, color);
212   x1   = XTRANS(draw, windraw, xl);
213   x2   = XTRANS(draw, windraw, xr);
214   yone = YTRANS(draw, windraw, yl);
215   y2   = YTRANS(draw, windraw, yr);
216   hpen = CreatePen(PS_SOLID, windraw->linewidth, windraw->currentcolor);
217   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
218   else hdc = windraw->node->Buffer;
219 
220   SelectPen(hdc, hpen);
221   MoveToEx(hdc, x1, yone, NULL);
222   LineTo(hdc, x2, y2);
223   /* Forces a WM_PAINT message and erases background */
224   InvalidateRect(windraw->hWnd, NULL, TRUE);
225   UpdateWindow(windraw->hWnd);
226   PetscFunctionReturn(PETSC_SUCCESS);
227 }
228 
PetscDrawLineSetWidth_Win32(PetscDraw draw,PetscReal width)229 static PetscErrorCode PetscDrawLineSetWidth_Win32(PetscDraw draw, PetscReal width)
230 {
231   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
232   int              averagesize, finalwidth;
233   RECT             rect;
234 
235   PetscFunctionBegin;
236   GetClientRect(windraw->hWnd, &rect);
237   averagesize = ((rect.right - rect.left) + (rect.bottom - rect.top)) / 2;
238   finalwidth  = (int)PetscFloorReal(averagesize * width);
239   if (finalwidth < 1) finalwidth = 1; /* minimum size PetscDrawLine can except */
240 
241   windraw->linewidth = finalwidth;
242   PetscFunctionReturn(PETSC_SUCCESS);
243 }
244 
PetscDrawLineGetWidth_Win32(PetscDraw draw,PetscReal * width)245 static PetscErrorCode PetscDrawLineGetWidth_Win32(PetscDraw draw, PetscReal *width)
246 {
247   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
248 
249   PetscFunctionBegin;
250   *width = (PetscReal)windraw->linewidth;
251   PetscFunctionReturn(PETSC_SUCCESS);
252 }
253 
PetscDrawPoint_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color)254 static PetscErrorCode PetscDrawPoint_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color)
255 {
256   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
257   HBRUSH           hbrush;
258   HRGN             hrgn;
259   int              radius;
260   int              x1, yone;
261   HDC              hdc;
262 
263   PetscFunctionBegin;
264   TranslateColor_Win32(draw, color);
265   x1     = XTRANS(draw, windraw, x);
266   yone   = YTRANS(draw, windraw, y);
267   hbrush = CreateSolidBrush(windraw->currentcolor);
268   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
269   else hdc = windraw->node->Buffer;
270 
271   /* desired size is one logical pixel so just turn it on */
272   if (windraw->pointdiameter == 1) SetPixelV(hdc, x1, yone, windraw->currentcolor);
273   else {
274     /* draw point around position determined */
275     radius = windraw->pointdiameter / 2; /* integer division */
276     hrgn   = CreateEllipticRgn(x1 - radius, yone - radius, x1 + radius, yone + radius);
277     FillRgn(hdc, hrgn, hbrush);
278   }
279   /* Forces a WM_PAINT and erases background */
280   InvalidateRect(windraw->hWnd, NULL, TRUE);
281   UpdateWindow(windraw->hWnd);
282   PetscFunctionReturn(PETSC_SUCCESS);
283 }
284 
PetscDrawPointSetSize_Win32(PetscDraw draw,PetscReal width)285 static PetscErrorCode PetscDrawPointSetSize_Win32(PetscDraw draw, PetscReal width)
286 {
287   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
288   int              averagesize, diameter;
289   RECT             rect;
290 
291   PetscFunctionBegin;
292   GetClientRect(windraw->hWnd, &rect);
293   averagesize = ((rect.right - rect.left) + (rect.bottom - rect.top)) / 2;
294   diameter    = (int)PetscFloorReal(averagesize * width);
295   if (diameter < 1) diameter = 1;
296   windraw->pointdiameter = diameter;
297   PetscFunctionReturn(PETSC_SUCCESS);
298 }
299 
PetscDrawString_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color,const char * text)300 static PetscErrorCode PetscDrawString_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color, const char *text)
301 {
302   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
303   RECT             r;
304   HFONT            hfont;
305   LOGFONT          logfont;
306   int              x1, yone;
307   HDC              hdc;
308 
309   PetscFunctionBegin;
310   x1       = XTRANS(draw, windraw, x);
311   yone     = YTRANS(draw, windraw, y);
312   r.bottom = yone;
313   r.left   = x1;
314   r.right  = x1 + 1;
315   r.top    = yone + 1;
316 
317   logfont.lfHeight         = windraw->stringheight;
318   logfont.lfWidth          = windraw->stringwidth;
319   logfont.lfEscapement     = 0;
320   logfont.lfOrientation    = 0;
321   logfont.lfCharSet        = 0;
322   logfont.lfClipPrecision  = 0;
323   logfont.lfItalic         = 0;
324   logfont.lfOutPrecision   = 0;
325   logfont.lfPitchAndFamily = DEFAULT_PITCH;
326   logfont.lfQuality        = DEFAULT_QUALITY;
327   logfont.lfStrikeOut      = 0;
328   logfont.lfUnderline      = 0;
329   logfont.lfWeight         = FW_NORMAL;
330 
331   hfont = CreateFontIndirect(&logfont);
332   TranslateColor_Win32(draw, color);
333   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
334   else hdc = windraw->node->Buffer;
335 
336   SelectFont(hdc, hfont);
337   SetTextColor(hdc, windraw->currentcolor);
338   DrawText(hdc, text, lstrlen(text), &r, DT_NOCLIP);
339   DeleteObject(hfont);
340   /* Forces a WM_PAINT message and erases background */
341   InvalidateRect(windraw->hWnd, NULL, TRUE);
342   UpdateWindow(windraw->hWnd);
343   PetscFunctionReturn(PETSC_SUCCESS);
344 }
345 
PetscDrawStringVertical_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color,const char * text)346 static PetscErrorCode PetscDrawStringVertical_Win32(PetscDraw draw, PetscReal x, PetscReal y, int color, const char *text)
347 {
348   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
349   RECT             r;
350   HFONT            hfont;
351   LOGFONT          logfont;
352   int              x1, yone;
353   HDC              hdc;
354 
355   PetscFunctionBegin;
356   x1       = XTRANS(draw, windraw, x);
357   yone     = YTRANS(draw, windraw, y);
358   r.left   = x1;
359   r.bottom = yone + 30;
360   r.right  = x1 + 1;
361   r.top    = yone - 30;
362 
363   logfont.lfEscapement     = 2700; /* Causes vertical text drawing */
364   logfont.lfHeight         = windraw->stringheight;
365   logfont.lfWidth          = windraw->stringwidth;
366   logfont.lfOrientation    = 0;
367   logfont.lfCharSet        = DEFAULT_CHARSET;
368   logfont.lfClipPrecision  = 0;
369   logfont.lfItalic         = 0;
370   logfont.lfOutPrecision   = 0;
371   logfont.lfPitchAndFamily = DEFAULT_PITCH;
372   logfont.lfQuality        = DEFAULT_QUALITY;
373   logfont.lfStrikeOut      = 0;
374   logfont.lfUnderline      = 0;
375   logfont.lfWeight         = FW_NORMAL;
376 
377   hfont = CreateFontIndirect(&logfont);
378   TranslateColor_Win32(draw, color);
379   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
380   else hdc = windraw->node->Buffer;
381 
382   SelectFont(hdc, hfont);
383   SetTextColor(hdc, windraw->currentcolor);
384   DrawText(hdc, text, lstrlen(text), &r, DT_NOCLIP | DT_SINGLELINE);
385   DeleteObject(hfont);
386   /* Forces a WM_PAINT message and erases background */
387   InvalidateRect(windraw->hWnd, NULL, TRUE);
388   UpdateWindow(windraw->hWnd);
389   PetscFunctionReturn(PETSC_SUCCESS);
390 }
391 
PetscDrawStringSetSize_Win32(PetscDraw draw,PetscReal width,PetscReal height)392 static PetscErrorCode PetscDrawStringSetSize_Win32(PetscDraw draw, PetscReal width, PetscReal height)
393 {
394   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
395   int              w, h;
396 
397   PetscFunctionBegin;
398   w = (int)(windraw->w * width * (draw->port_xr - draw->port_xl) / (draw->coor_xr - draw->coor_xl));
399   h = (int)(windraw->h * height * (draw->port_yr - draw->port_yl) / (draw->coor_yr - draw->coor_yl));
400   if (h < 1) h = 1;
401   if (w < 1) w = 1;
402   windraw->stringheight = h;
403   windraw->stringwidth  = w;
404   PetscFunctionReturn(PETSC_SUCCESS);
405 }
PetscDrawStringGetSize_Win32(PetscDraw draw,PetscReal * width,PetscReal * height)406 static PetscErrorCode PetscDrawStringGetSize_Win32(PetscDraw draw, PetscReal *width, PetscReal *height)
407 {
408   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
409   double           scaleX  = (draw->coor_xr - draw->coor_xl) / (draw->w) * (draw->port_xr - draw->port_xl);
410   double           scaleY  = (draw->coor_yr - draw->coor_yl) / (draw->h) * (draw->port_yr - draw->port_yl);
411 
412   PetscFunctionBegin;
413   if (height) *height = (double)windraw->stringheight * scaleY;
414   if (width) *width = (double)windraw->stringwidth * scaleX;
415   PetscFunctionReturn(PETSC_SUCCESS);
416 }
417 
PetscDrawResizeWindow_Win32(PetscDraw draw,int w,int h)418 static PetscErrorCode PetscDrawResizeWindow_Win32(PetscDraw draw, int w, int h)
419 {
420   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
421   RECT             r;
422 
423   PetscFunctionBegin;
424   GetWindowRect(windraw->hWnd, &r);
425   MoveWindow(windraw->hWnd, r.left, r.top, (int)w, (int)h, TRUE);
426   /* set all variable dealing with window dimensions */
427   windraw->node->bitheight = windraw->h = draw->h = h;
428   windraw->node->bitwidth = windraw->w = draw->w = w;
429   /* set up graphic buffers with the new size of window */
430   SetBitmapDimensionEx(windraw->node->BufferBit, w, h, NULL);
431   if (windraw->node->DoubleBuffered) SetBitmapDimensionEx(windraw->node->DoubleBufferBit, w, h, NULL);
432   windraw->haveresized = PETSC_TRUE;
433   PetscFunctionReturn(PETSC_SUCCESS);
434 }
435 
PetscDrawCheckResizedWindow_Win32(PetscDraw draw)436 static PetscErrorCode PetscDrawCheckResizedWindow_Win32(PetscDraw draw)
437 {
438   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
439 
440   PetscFunctionBegin;
441   PetscCheck(windraw->haveresized != 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for resizing windows on Microsoft Windows");
442   PetscFunctionReturn(PETSC_SUCCESS);
443 }
444 
PetscDrawSetTitle_Win32(PetscDraw draw,const char title[])445 static PetscErrorCode PetscDrawSetTitle_Win32(PetscDraw draw, const char title[])
446 {
447   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
448 
449   PetscFunctionBegin;
450   SetWindowText(windraw->hWnd, title);
451   PetscFunctionReturn(PETSC_SUCCESS);
452 }
453 
PetscDrawClear_Win32(PetscDraw draw)454 static PetscErrorCode PetscDrawClear_Win32(PetscDraw draw)
455 {
456   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
457 
458   PetscFunctionBegin;
459   /* clear primary buffer */
460   ExtFloodFill(windraw->node->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);
461   /* if exists clear secondary buffer */
462   if (windraw->node->DoubleBuffered) ExtFloodFill(windraw->node->DoubleBuffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);
463 
464   /* force WM_PAINT message so cleared buffer will show */
465   InvalidateRect(windraw->hWnd, NULL, TRUE);
466   UpdateWindow(windraw->hWnd);
467   PetscFunctionReturn(PETSC_SUCCESS);
468 }
469 
PetscDrawTriangle_Win32(PetscDraw draw,PetscReal x1,PetscReal yone,PetscReal x2,PetscReal y2,PetscReal x3,PetscReal y3,int c1,int c2,int c3)470 static PetscErrorCode PetscDrawTriangle_Win32(PetscDraw draw, PetscReal x1, PetscReal yone, PetscReal x2, PetscReal y2, PetscReal x3, PetscReal y3, int c1, int c2, int c3)
471 {
472   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
473   HBRUSH           hbrush;
474   HPEN             hpen;
475   int              p1x, p1y, p2x, p2y, p3x, p3y;
476   HDC              bit;
477 
478   PetscFunctionBegin;
479   AverageColorTriangle_Win32(draw, c1, c2, c3);
480   hbrush = CreateSolidBrush(windraw->currentcolor);
481   hpen   = CreatePen(PS_SOLID, 0, windraw->currentcolor);
482   p1x    = XTRANS(draw, windraw, x1);
483   p2x    = XTRANS(draw, windraw, x2);
484   p3x    = XTRANS(draw, windraw, x3);
485   p1y    = YTRANS(draw, windraw, yone);
486   p2y    = YTRANS(draw, windraw, y2);
487   p3y    = YTRANS(draw, windraw, y3);
488 
489   if (windraw->node->DoubleBuffered) bit = windraw->node->DoubleBuffer;
490   else bit = windraw->node->Buffer;
491 
492   BeginPath(bit);
493   MoveToEx(bit, p1x, p1y, NULL);
494   LineTo(bit, p2x, p2y);
495   LineTo(bit, p3x, p3y);
496   LineTo(bit, p1x, p1y);
497   EndPath(bit);
498   SelectPen(bit, hpen);
499   SelectBrush(bit, hbrush);
500   StrokeAndFillPath(bit);
501   /* Forces a WM_PAINT message and erases background */
502   InvalidateRect(windraw->hWnd, NULL, TRUE);
503   UpdateWindow(windraw->hWnd);
504   PetscFunctionReturn(PETSC_SUCCESS);
505 }
506 
PetscDrawSetVisible_Win32(PetscDraw draw,PetscBool visible)507 static PetscErrorCode PetscDrawSetVisible_Win32(PetscDraw draw, PetscBool visible)
508 {
509   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
510 
511   PetscFunctionBegin;
512   ShowWindow(windraw->hWnd, visible ? SW_SHOWNA : SW_HIDE);
513   PetscFunctionReturn(PETSC_SUCCESS);
514 }
515 
PetscDrawDestroy_Win32(PetscDraw draw)516 static PetscErrorCode PetscDrawDestroy_Win32(PetscDraw draw)
517 {
518   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
519 
520   PetscFunctionBegin;
521   SendMessage(windraw->hWnd, WM_DESTROY, 0, 0);
522   PetscFree(draw->data);
523   PetscFunctionReturn(PETSC_SUCCESS);
524 }
525 
MessageLoopThread_Win32(PetscDraw draw)526 static void MessageLoopThread_Win32(PetscDraw draw)
527 {
528   PetscDraw_Win32 *windraw = (PetscDraw_Win32 *)draw->data;
529   MSG              msg;
530   HWND             hWnd        = NULL;
531   const char       classname[] = "PETSc Window Class";
532   WNDCLASSEX       wclass;
533   LPVOID           lpMsgBuf;
534 
535   /* initialize window class parameters */
536   wclass.cbSize        = sizeof(WNDCLASSEX);
537   wclass.style         = CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW;
538   wclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
539   wclass.cbClsExtra    = 0;
540   wclass.cbWndExtra    = 0;
541   wclass.hInstance     = NULL;
542   wclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
543   wclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
544   wclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
545   wclass.lpszMenuName  = NULL;
546   wclass.lpszClassName = classname;
547   wclass.hIconSm       = NULL;
548 
549   RegisterClassEx(&wclass);
550 
551   hWnd = CreateWindowEx(0, classname, NULL, WS_OVERLAPPEDWINDOW, draw->x, draw->y, draw->w, draw->h, NULL, NULL, hInst, NULL);
552 
553   if (!hWnd) {
554     lpMsgBuf = (LPVOID) "Window Not Successfully Created";
555     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
556     LocalFree(lpMsgBuf);
557     exit(0);
558   }
559   windraw->hWnd = hWnd;
560   /* display and update new window */
561   ShowWindow(hWnd, SW_SHOWNORMAL);
562   UpdateWindow(hWnd);
563   SetEvent(windraw->hReadyEvent);
564 
565   while (GetMessage(&msg, hWnd, 0, 0)) {
566     TranslateMessage(&msg);
567     DispatchMessage(&msg);
568   }
569   return;
570 }
571 
572 static struct _PetscDrawOps DvOps = {PetscDrawSetDoubleBuffer_Win32, PetscDrawFlush_Win32, PetscDrawLine_Win32, PetscDrawLineSetWidth_Win32, PetscDrawLineGetWidth_Win32, PetscDrawPoint_Win32, PetscDrawPointSetSize_Win32, PetscDrawString_Win32, PetscDrawStringVertical_Win32, PetscDrawStringSetSize_Win32, PetscDrawStringGetSize_Win32, 0, PetscDrawClear_Win32, PetscDrawRectangle_Win32, PetscDrawTriangle_Win32, 0, PetscDrawGetMouseButton_Win32, PetscDrawPause_Win32, 0, 0, PetscDrawGetPopup_Win32, PetscDrawSetTitle_Win32, PetscDrawCheckResizedWindow_Win32, PetscDrawResizeWindow_Win32, PetscDrawDestroy_Win32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PetscDrawSetVisible_Win32};
573 
PetscDrawGetPopup_Win32(PetscDraw draw,PetscDraw * popup)574 static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw draw, PetscDraw *popup)
575 {
576   PetscDraw_Win32 *win = (PetscDraw_Win32 *)draw->data;
577   PetscBool        flg = PETSC_TRUE;
578 
579   PetscFunctionBegin;
580   PetscCall(PetscOptionsGetBool(((PetscObject)draw)->options, ((PetscObject)draw)->prefix, "-draw_popup", &flg, NULL));
581   if (flg) {
582     PetscCall(PetscDrawCreate(PetscObjectComm((PetscObject)draw), NULL, NULL, win->x, win->y + win->h + 36, 220, 220, popup));
583     PetscCall(PetscDrawSetType(*popup, PETSC_DRAW_WIN32));
584     draw->popup = *popup;
585   } else {
586     *popup = NULL;
587   }
588   PetscFunctionReturn(PETSC_SUCCESS);
589 }
PetscDrawCreate_Win32(PetscDraw draw)590 PETSC_EXTERN PetscErrorCode PetscDrawCreate_Win32(PetscDraw draw)
591 {
592   PetscDraw_Win32 *windraw;
593   HANDLE           hThread = NULL;
594   WindowNode       newnode;
595 
596   PetscFunctionBegin;
597   PetscCall(PetscNew(&windraw));
598   draw->data = windraw;
599 
600   /* the following is temporary fix for initializing a global datastructure */
601   if (!g_hWindowListMutex) g_hWindowListMutex = CreateMutex(NULL, FALSE, NULL);
602   draw->ops[0] = DvOps;
603 
604   windraw->hReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
605   /* makes call to MessageLoopThread to creat window and attach a thread */
606   CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoopThread_Win32, draw, 0, (LPDWORD)hThread);
607   CloseHandle(hThread);
608   WaitForSingleObject(windraw->hReadyEvent, INFINITE);
609   CloseHandle(windraw->hReadyEvent);
610   WaitForSingleObject(g_hWindowListMutex, INFINITE);
611 
612   PetscCall(PetscNew(&newnode));
613   newnode->MouseListHead = NULL;
614   newnode->MouseListTail = NULL;
615   newnode->wnext         = WindowListHead;
616   newnode->wprev         = NULL;
617   newnode->hWnd          = windraw->hWnd;
618   if (WindowListHead) WindowListHead->wprev = newnode;
619   WindowListHead = newnode;
620   windraw->hdc   = GetDC(windraw->hWnd);
621 
622   windraw->stringheight  = 10;
623   windraw->stringwidth   = 6;
624   windraw->linewidth     = 1; /* default pixel sizes of graphics until user changes them */
625   windraw->pointdiameter = 1;
626   windraw->node          = newnode;
627 
628   windraw->x = draw->x;
629   windraw->y = draw->y;
630   windraw->w = newnode->bitwidth = draw->w;
631   windraw->h = newnode->bitheight = draw->h;
632 
633   /* Create and initialize primary graphics buffer */
634   newnode->Buffer    = CreateCompatibleDC(windraw->hdc);
635   newnode->BufferBit = CreateCompatibleBitmap(windraw->hdc, windraw->w, windraw->h);
636   newnode->store     = SelectObject(newnode->Buffer, newnode->BufferBit);
637   ExtFloodFill(newnode->Buffer, 0, 0, COLOR_WINDOW, FLOODFILLBORDER);
638 
639   newnode->event          = CreateEvent(NULL, TRUE, FALSE, NULL);
640   newnode->DoubleBuffered = PETSC_FALSE;
641 
642   ReleaseDC(windraw->hWnd, windraw->hdc);
643   ReleaseMutex(g_hWindowListMutex);
644   PetscFunctionReturn(PETSC_SUCCESS);
645 }
646 
647 /* FUNCTION: PetscWndProc(HWND, unsigned, WORD, LONG)
648    PURPOSE:  Processes messages for the main window.
649    WM_COMMAND  - process the application menu
650    WM_PAINT    - Paint the main window
651    WM_DESTROY  - post a quit message and return */
652 
PetscWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)653 LRESULT CALLBACK PetscWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
654 {
655   int wmId;
656 
657   switch (message) {
658     HANDLE_MSG(hWnd, WM_PAINT, OnPaint_Win32);
659     HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy_Win32);
660   case WM_COMMAND:
661     wmId = LOWORD(wParam);
662     /* Parse the menu selections:*/
663     switch (wmId) {
664     case IDM_EXIT:
665       DestroyWindow(hWnd);
666       break;
667     default:
668       return DefWindowProc(hWnd, message, wParam, lParam);
669     }
670     break;
671   case WM_LBUTTONUP:
672     MouseRecord_Win32(hWnd, PETSC_BUTTON_LEFT);
673     break;
674   case WM_RBUTTONUP:
675     MouseRecord_Win32(hWnd, PETSC_BUTTON_RIGHT);
676     break;
677   case WM_MBUTTONUP:
678     MouseRecord_Win32(hWnd, PETSC_BUTTON_CENTER);
679     break;
680   default:
681     return DefWindowProc(hWnd, message, wParam, lParam);
682   }
683   return 0;
684 }
685 
OnPaint_Win32(HWND hWnd)686 static void OnPaint_Win32(HWND hWnd)
687 {
688   PAINTSTRUCT ps;
689   HDC         hdc;
690   WindowNode  current = NULL;
691 
692   InvalidateRect(hWnd, NULL, TRUE);
693   WaitForSingleObject(g_hWindowListMutex, INFINITE);
694   current = WindowListHead;
695   hdc     = BeginPaint(hWnd, &ps);
696 
697   while (current) {
698     if (current->hWnd == hWnd) {
699       /* flushes primary buffer to window */
700       BitBlt(hdc, 0, 0, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES), current->Buffer, 0, 0, SRCCOPY);
701 
702       /* StretchBlt(hdc,0,0,w,h,
703         current->Buffer,0,0,current->bitwidth,current->bitheight,SRCCOPY); */
704       break;
705     }
706     current = current->wnext;
707   }
708   EndPaint(hWnd, &ps);
709   ReleaseMutex(g_hWindowListMutex);
710   return;
711 }
712 
MouseRecord_Win32(HWND hWnd,PetscDrawButton button)713 static PetscErrorCode MouseRecord_Win32(HWND hWnd, PetscDrawButton button)
714 {
715   /* Called by all three mouse button actions
716     Records needed mouse data in windows data structure */
717   WindowNode current = NULL;
718   MouseNode  newnode;
719   POINT      mousepos;
720 
721   PetscFunctionBegin;
722   WaitForSingleObject(g_hWindowListMutex, INFINITE);
723   current = WindowListHead;
724   if (current->IsGetMouseOn == TRUE) {
725     SetEvent(current->event);
726     while (current) {
727       if (current->hWnd == hWnd) {
728         PetscCall(PetscNew(&newnode));
729         newnode->Button = button;
730         GetCursorPos(&mousepos);
731         newnode->user.x = mousepos.x;
732         newnode->user.y = mousepos.y;
733         ScreenToClient(hWnd, &mousepos);
734         newnode->phys.x = mousepos.x;
735         newnode->phys.y = mousepos.y;
736         if (!current->MouseListTail) {
737           current->MouseListHead = newnode;
738           current->MouseListTail = newnode;
739         } else {
740           current->MouseListTail->mnext = newnode;
741           current->MouseListTail        = newnode;
742         }
743         newnode->mnext = NULL;
744 
745         break;
746       }
747       current = current->wnext;
748     }
749   }
750   ReleaseMutex(g_hWindowListMutex);
751   PetscFunctionReturn(PETSC_SUCCESS);
752 }
753 
OnDestroy_Win32(HWND hWnd)754 static void OnDestroy_Win32(HWND hWnd)
755 {
756   /* searches linked list of window data and frees corresponding memory */
757   WindowNode current;
758 
759   PetscFunctionBegin;
760   WaitForSingleObject(g_hWindowListMutex, INFINITE);
761   current = WindowListHead;
762 
763   SetEvent(current->event);
764   while (current) {
765     if (current->hWnd == hWnd) {
766       if (current->wprev) current->wprev->wnext = current->wnext;
767       else WindowListHead = current->wnext;
768       if (current->MouseListHead) deletemouselist_Win32(current);
769       else PetscFree(current);
770       break;
771     }
772     current = current->wnext;
773   }
774   ReleaseMutex(g_hWindowListMutex);
775   PostQuitMessage(0);
776   PetscFunctionReturnVoid();
777 }
778