Various cosmetic changes.
[wine] / dlls / comctl32 / ipaddress.c
1 /*
2  * IP Address control
3  *
4  * Copyright 1999 Chris Morgan<cmorgan@wpi.edu> and
5  *                James Abbatiello<abbeyj@wpi.edu>
6  * Copyright 1998, 1999 Eric Kohl
7  * Copyright 1998 Alex Priem <alexp@sci.kun.nl>
8  *
9  * NOTES
10  *
11  * TODO:
12  *    -Edit control doesn't support the ES_CENTER style which prevents
13  *     this ipaddress control from having centered text look like the
14  *     windows ipaddress control
15  *    -Check all notifications/behavior.
16  *    -Optimization: 
17  *        -include lpipsi in IPADDRESS_INFO.
18  *        -CurrentFocus: field that has focus at moment of processing.
19  *        -connect Rect32 rcClient.
20  *        -check ipaddress.cpp for missing features.
21  *    -refresh: draw '.' instead of setpixel.
22  */
23
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "winbase.h"
30 #include "commctrl.h"
31 #include "debugtools.h"
32
33 DEFAULT_DEBUG_CHANNEL(ipaddress);
34
35 typedef struct
36 {
37         BYTE LowerLimit[4];
38         BYTE UpperLimit[4];
39
40         RECT    rcClient;
41         INT     uFocus;
42 } IPADDRESS_INFO;
43
44 typedef struct
45 {
46     WNDPROC wpOrigProc[4];
47     HWND    hwndIP[4];
48     IPADDRESS_INFO *infoPtr;
49     HWND    hwnd;
50     UINT    uRefCount;
51 } IP_SUBCLASS_INFO, *LPIP_SUBCLASS_INFO;
52
53 #define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongA (hwnd, 0))
54
55 static BOOL 
56 IPADDRESS_SendNotify (HWND hwnd, UINT command);
57 static BOOL 
58 IPADDRESS_SendIPAddressNotify (HWND hwnd, UINT field, BYTE newValue);
59
60 /* property name of tooltip window handle */
61 #define IP_SUBCLASS_PROP "CCIP32SubclassInfo"
62
63
64 static LRESULT CALLBACK
65 IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
66
67
68 static VOID
69 IPADDRESS_Refresh (HWND hwnd, HDC hdc)
70 {
71   RECT rcClient;
72   HBRUSH hbr;
73   COLORREF clr=GetSysColor (COLOR_3DDKSHADOW);
74   int i,x,fieldsize;
75
76   GetClientRect (hwnd, &rcClient);
77   hbr = CreateSolidBrush (RGB(255,255,255));
78   DrawEdge (hdc, &rcClient, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
79   FillRect (hdc, &rcClient, hbr);
80   DeleteObject (hbr);
81
82   x=rcClient.left;
83   fieldsize=(rcClient.right-rcClient.left) / 4;
84
85   for (i=0; i<3; i++) {         /* Should draw text "." here */
86     x+=fieldsize;
87     SetPixel (hdc, x,   13, clr);
88     SetPixel (hdc, x,   14, clr);
89     SetPixel (hdc, x+1, 13, clr);
90     SetPixel (hdc, x+1, 14, clr);
91   }
92 }
93
94
95 static LRESULT
96 IPADDRESS_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
97 {
98   IPADDRESS_INFO *infoPtr;
99   RECT rcClient, edit;
100   int i,fieldsize;
101   LPIP_SUBCLASS_INFO lpipsi;
102         
103
104   infoPtr = (IPADDRESS_INFO *)COMCTL32_Alloc (sizeof(IPADDRESS_INFO));
105   SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
106
107   GetClientRect (hwnd, &rcClient);
108
109   fieldsize=(rcClient.right-rcClient.left) /4;
110
111   edit.top   =rcClient.top+2;
112   edit.bottom=rcClient.bottom-2;
113
114   lpipsi=(LPIP_SUBCLASS_INFO) GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
115   if (lpipsi == NULL)  {
116     lpipsi = (LPIP_SUBCLASS_INFO) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO));
117     lpipsi->hwnd = hwnd;
118     lpipsi->uRefCount++;
119     SetPropA ((HWND)hwnd, IP_SUBCLASS_PROP, (HANDLE)lpipsi);
120 /*              infoPtr->lpipsi= lpipsi; */
121   } else 
122     WARN("IP-create called twice\n");
123         
124   for (i=0; i<=3; i++)
125   {
126     infoPtr->LowerLimit[i]=0;
127     infoPtr->UpperLimit[i]=255;
128     edit.left=rcClient.left+i*fieldsize+6;
129     edit.right=rcClient.left+(i+1)*fieldsize-2;
130     lpipsi->hwndIP[i]= CreateWindowA ("edit", NULL, 
131         WS_CHILD | WS_VISIBLE | ES_CENTER,
132         edit.left, edit.top, edit.right-edit.left, edit.bottom-edit.top,
133         hwnd, (HMENU) 1, GetWindowLongA (hwnd, GWL_HINSTANCE), NULL);
134     lpipsi->wpOrigProc[i]= (WNDPROC)
135         SetWindowLongA (lpipsi->hwndIP[i],GWL_WNDPROC, (LONG)
136         IPADDRESS_SubclassProc);
137     SetPropA ((HWND)lpipsi->hwndIP[i], IP_SUBCLASS_PROP, (HANDLE)lpipsi);
138   }
139
140   lpipsi->infoPtr= infoPtr;
141
142   return 0;
143 }
144
145
146 static LRESULT
147 IPADDRESS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
148 {
149   int i;
150   IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
151   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
152             GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
153
154   for (i=0; i<=3; i++) {
155     SetWindowLongA ((HWND)lpipsi->hwndIP[i], GWL_WNDPROC,
156                   (LONG)lpipsi->wpOrigProc[i]);
157   }
158
159   COMCTL32_Free (infoPtr);
160   SetWindowLongA (hwnd, 0, 0);
161   return 0;
162 }
163
164
165 static LRESULT
166 IPADDRESS_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
167 {
168   HDC hdc;
169
170   TRACE("\n");
171   hdc = GetDC (hwnd);
172   IPADDRESS_Refresh (hwnd, hdc);
173   ReleaseDC (hwnd, hdc);
174
175   IPADDRESS_SendIPAddressNotify (hwnd, 0, 0);  /* FIXME: should use -1 */
176   IPADDRESS_SendNotify (hwnd, EN_KILLFOCUS);       
177   InvalidateRect (hwnd, NULL, TRUE);
178
179   return 0;
180 }
181
182
183 static LRESULT
184 IPADDRESS_Paint (HWND hwnd, WPARAM wParam)
185 {
186   HDC hdc;
187   PAINTSTRUCT ps;
188
189   hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
190   IPADDRESS_Refresh (hwnd, hdc);
191   if(!wParam)
192     EndPaint (hwnd, &ps);
193   return 0;
194 }
195
196
197 static LRESULT
198 IPADDRESS_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
199 {
200   HDC hdc;
201
202   TRACE("\n");
203
204   hdc = GetDC (hwnd);
205   IPADDRESS_Refresh (hwnd, hdc);
206   ReleaseDC (hwnd, hdc);
207
208   return 0;
209 }
210
211
212 static LRESULT
213 IPADDRESS_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
214 {
215   /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
216   TRACE("\n");
217   return 0;
218 }
219
220
221 static BOOL
222 IPADDRESS_SendNotify (HWND hwnd, UINT command)
223 {
224   TRACE("%x\n",command);
225   return (BOOL)SendMessageA (GetParent (hwnd), WM_COMMAND,
226               MAKEWPARAM (GetWindowLongA (hwnd, GWL_ID),command), (LPARAM)hwnd);
227 }
228
229
230 static BOOL
231 IPADDRESS_SendIPAddressNotify (HWND hwnd, UINT field, BYTE newValue)
232 {
233   NMIPADDRESS nmip;
234
235   TRACE("%x %x\n",field,newValue);
236   nmip.hdr.hwndFrom = hwnd;
237   nmip.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
238   nmip.hdr.code     = IPN_FIELDCHANGED;
239
240   nmip.iField=field;
241   nmip.iValue=newValue;
242
243   return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
244                              (WPARAM)nmip.hdr.idFrom, (LPARAM)&nmip);
245 }
246
247
248 static LRESULT
249 IPADDRESS_ClearAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
250 {
251   int i;
252   HDC hdc;
253   char buf[1];
254   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
255             GetPropA ((HWND)hwnd,IP_SUBCLASS_PROP);
256
257   TRACE("\n");
258
259   buf[0]=0;
260   for (i=0; i<=3; i++) 
261     SetWindowTextA (lpipsi->hwndIP[i],buf);
262         
263   hdc = GetDC (hwnd);
264   IPADDRESS_Refresh (hwnd, hdc);
265   ReleaseDC (hwnd, hdc);
266         
267   return 0;
268 }
269
270
271 static LRESULT
272 IPADDRESS_IsBlank (HWND hwnd, WPARAM wParam, LPARAM lParam)
273 {
274   int i;
275   char buf[20];
276   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
277             GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
278
279   TRACE("\n");
280
281   for (i=0; i<=3; i++) {
282     GetWindowTextA (lpipsi->hwndIP[i],buf,5);
283     if (buf[0])
284       return 0;
285   }
286
287   return 1;
288 }
289
290
291 static LRESULT
292 IPADDRESS_GetAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
293 {
294   char field[20];
295   int i,valid,fieldvalue;
296   DWORD ip_addr;
297   IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
298   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
299             GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
300
301   TRACE("\n");
302
303   valid=0;
304   ip_addr=0;
305   for (i=0; i<=3; i++) {
306     GetWindowTextA (lpipsi->hwndIP[i],field,4);
307     ip_addr*=256;
308     if (field[0]) {
309       field[3]=0;
310       fieldvalue=atoi(field);
311       if (fieldvalue<infoPtr->LowerLimit[i]) 
312         fieldvalue=infoPtr->LowerLimit[i];
313       if (fieldvalue>infoPtr->UpperLimit[i]) 
314         fieldvalue=infoPtr->UpperLimit[i];
315       ip_addr+=fieldvalue;
316       valid++;
317     }
318   }
319
320   *(LPDWORD) lParam=ip_addr;
321
322   return valid;
323 }
324
325
326 static LRESULT
327 IPADDRESS_SetRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
328 {
329   IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
330   INT index;
331         
332   TRACE("\n");
333
334   index=(INT) wParam;
335   if ((index<0) || (index>3)) return 0;
336
337   infoPtr->LowerLimit[index]=lParam & 0xff;
338   infoPtr->UpperLimit[index]=(lParam >>8)  & 0xff;
339   return 1;
340 }
341
342
343 static LRESULT
344 IPADDRESS_SetAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
345 {
346   IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
347   HDC hdc;
348   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
349             GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
350   int i,value;
351   DWORD ip_address;
352   char buf[20];
353
354   TRACE("\n");
355   ip_address=(DWORD) lParam;
356
357   for (i=3; i>=0; i--) {
358     value=ip_address & 0xff;
359     if ((value>=infoPtr->LowerLimit[i]) && (value<=infoPtr->UpperLimit[i])) 
360     {
361       sprintf (buf,"%d",value);
362       SetWindowTextA (lpipsi->hwndIP[i],buf);
363       IPADDRESS_SendNotify (hwnd, EN_CHANGE);
364     }
365     ip_address= ip_address >> 8;
366   }
367
368   hdc = GetDC (hwnd);           /* & send notifications */
369   IPADDRESS_Refresh (hwnd, hdc);
370   ReleaseDC (hwnd, hdc);
371
372   return TRUE;
373 }
374
375
376 static LRESULT
377 IPADDRESS_SetFocusToField (HWND hwnd, WPARAM wParam, LPARAM lParam)
378 {
379   /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
380   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetPropA ((HWND)hwnd,
381                                                    IP_SUBCLASS_PROP);
382   INT index;
383
384   index=(INT) wParam;
385   TRACE(" %d\n", index);
386   if ((index<0) || (index>3)) return 0;
387         
388   SetFocus (lpipsi->hwndIP[index]);
389         
390   return 1;
391 }
392
393
394 static LRESULT
395 IPADDRESS_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
396 {
397   TRACE("\n");
398
399   SetFocus (hwnd);
400   IPADDRESS_SendNotify (hwnd, EN_SETFOCUS);
401   IPADDRESS_SetFocusToField (hwnd, 0, 0);
402
403   return TRUE;
404 }
405
406
407 static INT
408 IPADDRESS_CheckField (LPIP_SUBCLASS_INFO lpipsi, int currentfield)
409 {
410   int newField,fieldvalue;
411   char field[20];
412   IPADDRESS_INFO *infoPtr=lpipsi->infoPtr;
413
414   if(currentfield >= 0 && currentfield < 4)
415   {
416     TRACE("\n");
417     GetWindowTextA (lpipsi->hwndIP[currentfield],field,4);
418     if (field[0])
419     {
420       field[3]=0;       
421       newField=-1;
422       fieldvalue=atoi(field);
423     
424       if (fieldvalue < infoPtr->LowerLimit[currentfield]) 
425         newField=infoPtr->LowerLimit[currentfield];
426     
427       if (fieldvalue > infoPtr->UpperLimit[currentfield])
428         newField=infoPtr->UpperLimit[currentfield];
429     
430       if (newField >= 0)
431       {
432         sprintf (field,"%d",newField);
433         SetWindowTextA (lpipsi->hwndIP[currentfield], field);
434         return TRUE;
435       }
436     }
437   }
438   return FALSE;
439 }
440
441
442 static INT
443 IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi, int currentfield)
444 {
445   if(currentfield >= -1 && currentfield < 4)
446   {
447     IPADDRESS_CheckField(lpipsi, currentfield); /* check the fields value */  
448
449     if(currentfield < 3)
450     { 
451       SetFocus (lpipsi->hwndIP[currentfield+1]);
452       return TRUE; 
453     }
454   }
455   return FALSE;
456 }
457
458
459 /* period: move and select the text in the next field to the right if */
460 /*         the current field is not empty(l!=0), we are not in the */
461 /*         left most position, and nothing is selected(startsel==endsel) */
462
463 /* spacebar: same behavior as period */
464
465 /* alpha characters: completely ignored */
466
467 /* digits: accepted when field text length < 2 ignored otherwise. */
468 /*         when 3 numbers have been entered into the field the value */
469 /*         of the field is checked, if the field value exceeds the */
470 /*         maximum value and is changed the field remains the current */
471 /*         field, otherwise focus moves to the field to the right */
472
473 /* tab: change focus from the current ipaddress control to the next */
474 /*      control in the tab order */
475
476 /* right arrow: move to the field on the right to the left most */
477 /*              position in that field if no text is selected, */
478 /*              we are in the right most position in the field, */
479 /*              we are not in the right most field */
480
481 /* left arrow: move to the field on the left to the right most */
482 /*             position in that field if no text is selected, */
483 /*             we are in the left most position in the current field */
484 /*             and we are not in the left most field */
485
486 /* backspace: delete the character to the left of the cursor position, */
487 /*            if none are present move to the field on the left if */
488 /*            we are not in the left most field and delete the right */
489 /*            most digit in that field while keeping the cursor */
490 /*            on the right side of the field */
491
492
493 LRESULT CALLBACK
494 IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
495 {
496   IPADDRESS_INFO *infoPtr;
497   LPIP_SUBCLASS_INFO lpipsi = (LPIP_SUBCLASS_INFO) GetPropA
498         ((HWND)hwnd,IP_SUBCLASS_PROP); 
499   CHAR c = (CHAR)wParam;
500   INT i, l, index, startsel, endsel;
501
502   infoPtr = lpipsi->infoPtr;
503   index=0;             /* FIXME */
504   for (i=0; i<=3; i++) 
505     if (lpipsi->hwndIP[i]==hwnd) index=i;
506
507   switch (uMsg) {
508   case WM_CHAR: 
509     if(isdigit(c)) /* process all digits */
510     {
511       int return_val;
512       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); 
513       l = GetWindowTextLengthA (lpipsi->hwndIP[index]);
514       if(l==2 && startsel==endsel) /* field is full after this key is processed */
515       { 
516         /* process the digit press before we check the field */
517         return_val = CallWindowProcA (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam);
518           
519         /* if the field value was changed stay at the current field */
520         if(!IPADDRESS_CheckField(lpipsi, index))
521           IPADDRESS_GotoNextField (lpipsi,index);
522
523         return return_val;
524       }
525       
526       if(l > 2) /* field is full, stop key messages */
527       {
528         lParam = 0;
529         wParam = 0;
530       }
531       break;
532     }   
533     
534     if(c == '.') /* VK_PERIOD */
535     { 
536       l = GetWindowTextLengthA(lpipsi->hwndIP[index]);
537       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel);
538       if(l != 0 && startsel==endsel && startsel != 0)
539       {
540         IPADDRESS_GotoNextField(lpipsi, index); 
541         SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0, (LPARAM)3);
542       }
543     }
544         
545     /* stop all other characters */
546     wParam = 0;
547     lParam = 0;
548     break;
549
550   case WM_KEYDOWN:
551     if(c == VK_SPACE)
552     { 
553       l = GetWindowTextLengthA(lpipsi->hwndIP[index]);
554       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel);
555       if(l != 0 && startsel==endsel && startsel != 0)
556       {
557         IPADDRESS_GotoNextField(lpipsi, index); 
558         SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0, (LPARAM)3);
559       }
560     }
561
562     if(c == VK_RIGHT)
563     {
564       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel);
565       l = GetWindowTextLengthA (lpipsi->hwndIP[index]);
566     
567       if(startsel==endsel && startsel==l)
568       {
569         IPADDRESS_GotoNextField(lpipsi, index);
570         SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0,(LPARAM)0);
571       }
572     }
573
574     if(c == VK_LEFT)
575     { 
576       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel);
577       if(startsel==0 && startsel==endsel && index > 0)
578       {        
579         IPADDRESS_GotoNextField(lpipsi, index - 2);
580         l = GetWindowTextLengthA(lpipsi->hwndIP[index-1]);
581         SendMessageA(lpipsi->hwndIP[index-1], EM_SETSEL, (WPARAM)l,(LPARAM)l);
582       }     
583     }
584    
585     if(c == VK_BACK) /* VK_BACKSPACE */
586     {
587       CHAR buf[4];
588
589       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); 
590       l = GetWindowTextLengthA (lpipsi->hwndIP[index]);
591       if(startsel==endsel && startsel==0 && index > 0)
592       {
593         l = GetWindowTextLengthA(lpipsi->hwndIP[index-1]);
594         if(l!=0)
595         {
596           GetWindowTextA (lpipsi->hwndIP[index-1],buf,4);
597           buf[l-1] = '\0'; 
598           SetWindowTextA(lpipsi->hwndIP[index-1], buf);
599           SendMessageA(lpipsi->hwndIP[index-1], EM_SETSEL, (WPARAM)l,(LPARAM)l);
600         } 
601         IPADDRESS_GotoNextField(lpipsi, index - 2);
602       }
603     }
604     break;
605
606   default:
607     break;
608   }
609   return CallWindowProcA (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam);
610 }
611
612
613 static LRESULT WINAPI
614 IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
615 {
616   TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam);
617   if (!IPADDRESS_GetInfoPtr (hwnd) && (uMsg != WM_CREATE))
618       return DefWindowProcA (hwnd, uMsg, wParam, lParam);
619   switch (uMsg)
620   {
621     case IPM_CLEARADDRESS:
622       return IPADDRESS_ClearAddress (hwnd, wParam, lParam);
623
624     case IPM_SETADDRESS:
625       return IPADDRESS_SetAddress (hwnd, wParam, lParam);
626
627     case IPM_GETADDRESS:
628       return IPADDRESS_GetAddress (hwnd, wParam, lParam);
629
630     case IPM_SETRANGE:
631       return IPADDRESS_SetRange (hwnd, wParam, lParam);
632
633     case IPM_SETFOCUS:
634       return IPADDRESS_SetFocusToField (hwnd, wParam, lParam);
635
636     case IPM_ISBLANK:
637       return IPADDRESS_IsBlank (hwnd, wParam, lParam);
638
639     case WM_CREATE:
640       return IPADDRESS_Create (hwnd, wParam, lParam);
641
642     case WM_DESTROY:
643       return IPADDRESS_Destroy (hwnd, wParam, lParam);
644
645     case WM_GETDLGCODE:
646       return DLGC_WANTARROWS | DLGC_WANTCHARS;
647
648     case WM_KILLFOCUS:
649       return IPADDRESS_KillFocus (hwnd, wParam, lParam);
650
651     case WM_LBUTTONDOWN:
652       return IPADDRESS_LButtonDown (hwnd, wParam, lParam);
653
654     case WM_PAINT:
655       return IPADDRESS_Paint (hwnd, wParam);
656
657     case WM_SETFOCUS:
658       return IPADDRESS_SetFocus (hwnd, wParam, lParam);
659
660     case WM_SIZE:
661       return IPADDRESS_Size (hwnd, wParam, lParam);
662
663     default:
664       if (uMsg >= WM_USER)
665         ERR("unknown msg %04x wp=%08x lp=%08lx\n",
666                      uMsg, wParam, lParam);
667       return DefWindowProcA (hwnd, uMsg, wParam, lParam);
668     }
669     return 0;
670 }
671
672
673 void IPADDRESS_Register (void)
674 {
675   WNDCLASSA wndClass;
676
677   ZeroMemory (&wndClass, sizeof(WNDCLASSA));
678   wndClass.style         = CS_GLOBALCLASS;
679   wndClass.lpfnWndProc   = (WNDPROC)IPADDRESS_WindowProc;
680   wndClass.cbClsExtra    = 0;
681   wndClass.cbWndExtra    = sizeof(IPADDRESS_INFO *);
682   wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
683   wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
684   wndClass.lpszClassName = WC_IPADDRESSA;
685  
686   RegisterClassA (&wndClass);
687 }
688
689
690 VOID IPADDRESS_Unregister (void)
691 {
692   UnregisterClassA (WC_IPADDRESSA, (HINSTANCE)NULL);
693 }