NIM - Fix taskbar button visibility on Vista
[krb5.git] / src / windows / identity / ui / newcredwnd.c
1 /*
2  * Copyright (c) 2005 Massachusetts Institute of Technology
3  * Copyright (c) 2007 Secure Endpoints Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use, copy,
9  * modify, merge, publish, distribute, sublicense, and/or sell copies
10  * of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 /* $Id$ */
27
28 /* Include the OEMRESOURCE constants for locating standard icon
29    resources. */
30 #define OEMRESOURCE
31
32 #include<khmapp.h>
33 #include<assert.h>
34
35 ATOM khui_newcredwnd_cls;
36
37 /* forward dcl */
38 static void
39 nc_position_credtext(khui_nc_wnd_data * d);
40
41 /* Common dialog procedure used by the main credential panel
42    (IDD_NC_NEWCRED) and the button bar (IDC_NC_BBAR). */
43
44 static void
45 nc_layout_main_panel(khui_nc_wnd_data * d);
46
47 static void
48 nc_layout_new_cred_window(khui_nc_wnd_data * d);
49
50 static INT_PTR CALLBACK 
51 nc_common_dlg_proc(HWND hwnd,
52                    UINT uMsg,
53                    WPARAM wParam,
54                    LPARAM lParam)
55 {
56     switch(uMsg) {
57     case WM_INITDIALOG:
58         {
59             khui_nc_wnd_data * d;
60
61             d = (khui_nc_wnd_data *) lParam;
62
63 #pragma warning(push)
64 #pragma warning(disable: 4244)
65             SetWindowLongPtr(hwnd, DWLP_USER, lParam);
66 #pragma warning(pop)
67
68             if (d->nc->subtype == KMSG_CRED_PASSWORD) {
69                 ShowWindow(GetDlgItem(hwnd, IDC_NC_ADVANCED),
70                            SW_HIDE);
71             }
72         }
73         return TRUE;
74
75     case WM_COMMAND:
76         {
77             int ctrl_id;
78
79             ctrl_id = LOWORD(wParam);
80             if (ctrl_id < KHUI_CW_ID_MIN ||
81                 ctrl_id > KHUI_CW_ID_MAX) {
82                 /* pump it to the parent */
83                 PostMessage(GetParent(hwnd), WM_COMMAND, wParam, lParam);
84                 return TRUE;
85             } /* else we allow the message to fall through and get
86                  passed into the identity provider's message
87                  handler. */
88         }
89         break;
90
91     case KHUI_WM_NC_NOTIFY:
92         {
93             khui_nc_wnd_data * d;
94             d = (khui_nc_wnd_data *)(LONG_PTR) 
95                 GetWindowLongPtr(hwnd, DWLP_USER);
96
97             /* message sent by parent to notify us of something */
98             switch(HIWORD(wParam)) {
99             case WMNC_DIALOG_EXPAND:
100                 /* fallthrough */
101             case WMNC_UPDATE_LAYOUT:
102                 if(hwnd == d->dlg_main) {
103
104                     nc_layout_main_panel(d);
105
106                     return TRUE;
107                 }
108                 break;          /* nop */
109             }
110         }
111         return TRUE;
112     }
113
114     /* check if we have a wnd_data, and if so pass the message on to
115        the identity provider callback. */
116     {
117         khui_nc_wnd_data * d;
118
119         d = (khui_nc_wnd_data *) (LONG_PTR)
120             GetWindowLongPtr(hwnd, DWLP_USER);
121
122         /* TODO: filter out and forward only the messages that
123            originated or pertain to the identity selection
124            controls. */
125         if (d && d->nc && d->nc->ident_cb) {
126             return d->nc->ident_cb(d->nc, WMNC_IDENT_WMSG, hwnd, uMsg, 
127                                    wParam, lParam);
128         }
129     }
130
131     return FALSE;
132 }
133
134 static void
135 nc_notify_clear(khui_nc_wnd_data * d) {
136
137     if (d->notif_type == NC_NOTIFY_NONE)
138         /* there are no notifications anyway. */
139         return;
140
141     if (d->hwnd_notif_label)
142         DestroyWindow(d->hwnd_notif_label);
143
144     if (d->hwnd_notif_aux)
145         DestroyWindow(d->hwnd_notif_aux);
146
147     d->hwnd_notif_label = NULL;
148     d->hwnd_notif_aux = NULL;
149
150     SetRectEmpty(&d->r_notif);
151
152     d->notif_type = NC_NOTIFY_NONE;
153
154     /* Note that we must call nc_layout_main_panel() after calling
155        this to adjust the layout of the main panel.  However we aren't
156        calling it here since we might want to add another set of
157        notifications or make other changes to the main panel content
158        before calling nc_layout_main_panel(). */
159 }
160
161 static void
162 nc_notify_marquee(khui_nc_wnd_data * d, const wchar_t * label) {
163
164 #if (_WIN32_IE >= 0x0600)
165     HDC hdc;
166     size_t length;
167     SIZE label_size;
168 #endif
169
170     RECT r_label;
171     RECT r_mq;
172     RECT r_row;
173     HFONT hfont;
174     HWND hwnd;
175     HDWP hdefer;
176
177     /* Clear the notification area.  We only support one notification
178        at a time. */
179     nc_notify_clear(d);
180
181 #ifdef DEBUG
182     assert(d->dlg_main);
183 #endif
184
185 #if (_WIN32_IE >= 0x0600)
186
187     /* We can only show the marquee control if the comctl32 DLL is
188        version 6.0 or later.  Otherwise we only show the label. */
189
190     if (FAILED(StringCchLength(label, KHUI_MAXCCH_SHORT_DESC, &length))) {
191 #ifdef DEBUG
192         assert(FALSE);
193 #endif
194         length = KHUI_MAXCCH_SHORT_DESC;
195     }
196
197     /* See how big the notification control needs to be. */
198
199     hdc = GetDC(d->dlg_main);
200 #ifdef DEBUG
201     assert(hdc != NULL);
202 #endif
203
204     GetTextExtentPoint32(hdc, label, (int) length, &label_size);
205
206     ReleaseDC(d->dlg_main, hdc);
207
208     CopyRect(&r_row, &d->r_row);
209
210     if (label_size.cx > d->r_e_label.right - d->r_e_label.left) {
211         /* using an entire row */
212         CopyRect(&r_label, &d->r_row);
213         CopyRect(&r_mq, &d->r_n_input);
214         OffsetRect(&r_mq, 0, r_row.bottom - r_row.top);
215         r_row.bottom += r_row.bottom - r_row.top;
216     } else if (label_size.cx > d->r_n_label.right - d->r_n_label.left) {
217         /* using large labels */
218         CopyRect(&r_label, &d->r_e_label);
219         CopyRect(&r_mq, &d->r_e_input);
220     } else {
221         /* normal labels */
222         CopyRect(&r_label, &d->r_n_label);
223         CopyRect(&r_mq, &d->r_n_input);
224     }
225
226     InflateRect(&r_mq, 0, - ((r_mq.bottom - r_mq.top) / 4));
227
228 #else  /* _WIN32_IE < 0x0600 */
229
230     /* We are just showing the label */
231     CopyRect(&r_row, &d->r_row);
232     CopyRect(&r_label, &r_row);
233     SetRectEmpty(&r_mq);
234
235 #endif /* _WIN32_IE >= 0x0600 */
236
237     {
238         long y;
239
240         if (IsRectEmpty(&d->r_custprompt)) {
241             y = d->r_idspec.bottom;
242         } else {
243             y = d->r_custprompt.bottom;
244         }
245
246         OffsetRect(&r_row, d->r_area.left, y);
247         OffsetRect(&r_label, r_row.left, r_row.top);
248         OffsetRect(&r_mq, r_row.left, r_row.top);
249     }
250
251     hfont = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0);
252
253     hdefer = BeginDeferWindowPos(2);
254
255     /* the label */
256     hwnd = CreateWindowEx(0,
257                           L"STATIC",
258                           label,
259                           WS_CHILD | SS_ENDELLIPSIS,
260                           r_label.left, r_label.top,
261                           r_label.right - r_label.left,
262                           r_label.bottom - r_label.top,
263                           d->dlg_main,
264                           NULL, NULL, NULL);
265 #ifdef DEBUG
266     assert(hwnd != NULL);
267 #endif
268     SendMessage(hwnd, WM_SETFONT, (WPARAM) hfont, (LPARAM) TRUE);
269
270     DeferWindowPos(hdefer, hwnd, NULL,
271                    0, 0, 0, 0,
272                    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
273                    SWP_NOSIZE | SWP_SHOWWINDOW);
274
275     d->hwnd_notif_label = hwnd;
276
277     /* and the marquee */
278
279 #if (_WIN32_IE >= 0x0600)
280
281     /* unfortunately, the marquee is only available on comctl32
282        version 6.0 or later.  On previous versions, we only display
283        the message label. */
284
285     hwnd = CreateWindowEx(0,
286                           PROGRESS_CLASS,
287                           L"",
288                           WS_CHILD | PBS_MARQUEE,
289                           r_mq.left, r_mq.top,
290                           r_mq.right - r_mq.left,
291                           r_mq.bottom - r_mq.top,
292                           d->dlg_main,
293                           NULL, NULL, NULL);
294 #ifdef DEBUG
295     assert(hwnd != NULL);
296 #endif
297
298     SendMessage(hwnd, PBM_SETMARQUEE, TRUE, 100);
299
300     DeferWindowPos(hdefer, hwnd, NULL,
301                    0, 0, 0, 0,
302                    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
303                    SWP_NOSIZE | SWP_SHOWWINDOW);
304
305     d->hwnd_notif_aux = hwnd;
306
307 #endif /* _WIN32_IE >= 0x0600 */
308
309     EndDeferWindowPos(hdefer);
310
311     CopyRect(&d->r_notif, &r_row);
312
313     d->notif_type = NC_NOTIFY_MARQUEE;
314
315     /* Note that we must call nc_layout_main_panel() after calling
316        this to adjust the layout of the main panel.  However we aren't
317        calling it here since we might want to add another set of
318        notifications or make other changes to the main panel content
319        before calling nc_layout_main_panel(). */
320 }
321
322 static void
323 nc_notify_message(khui_nc_wnd_data * d,
324                   kherr_severity severity,
325                   const wchar_t * message) {
326
327     SIZE icon_size;
328     LPCTSTR icon_res;
329     HICON h_icon;
330     HWND hwnd;
331     HFONT hfont;
332     HDWP hdefer;
333
334     RECT r_row;
335     RECT r_label;
336     RECT r_icon;
337
338     nc_notify_clear(d);
339
340     icon_size.cx = GetSystemMetrics(SM_CXSMICON);
341     icon_size.cy = GetSystemMetrics(SM_CYSMICON);
342
343     switch(severity) {
344     case KHERR_INFO:
345         icon_res = MAKEINTRESOURCE(OIC_INFORMATION);
346         break;
347
348     case KHERR_WARNING:
349         icon_res = MAKEINTRESOURCE(OIC_WARNING);
350         break;
351
352     case KHERR_ERROR:
353         icon_res = MAKEINTRESOURCE(OIC_ERROR);
354         break;
355
356     default:
357         icon_res = NULL;
358     }
359
360     if (icon_res != NULL) {
361         h_icon = (HICON) LoadImage(NULL,
362                                    icon_res,
363                                    IMAGE_ICON,
364                                    icon_size.cx,
365                                    icon_size.cy,
366                                    LR_DEFAULTCOLOR | LR_SHARED);
367     } else {
368         h_icon = NULL;
369     }
370
371     CopyRect(&r_row, &d->r_row);
372
373 #define CENTERVALUE(w,v) ((w)/2 - (v)/2)
374
375     SetRect(&r_icon,
376             0, CENTERVALUE(r_row.bottom - r_row.top, icon_size.cy),
377             icon_size.cx,
378             CENTERVALUE(r_row.bottom - r_row.top, icon_size.cy) + icon_size.cy);
379
380 #undef CENTERVALUE
381
382     CopyRect(&r_label, &r_row);
383     OffsetRect(&r_label, -r_label.left, -r_label.top);
384     r_label.left += (icon_size.cx * 3) / 2;
385
386     {
387         long y;
388
389         if (IsRectEmpty(&d->r_custprompt)) {
390             y = d->r_idspec.bottom;
391         } else {
392             y = d->r_custprompt.bottom;
393         }
394
395         OffsetRect(&r_row, d->r_area.left, y);
396         OffsetRect(&r_label, r_row.left, r_row.top);
397         OffsetRect(&r_icon, r_row.left, r_row.top);
398     }
399
400     hfont = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0);
401
402     hdefer = BeginDeferWindowPos(2);
403
404     hwnd = CreateWindowEx(0,
405                           L"STATIC",
406                           message,
407                           WS_CHILD | SS_ENDELLIPSIS | SS_CENTER,
408                           r_label.left, r_label.top,
409                           r_label.right - r_label.left,
410                           r_label.bottom - r_label.top,
411                           d->dlg_main,
412                           NULL, NULL, NULL);
413 #ifdef DEBUG
414     assert(hwnd != NULL);
415 #endif
416     SendMessage(hwnd, WM_SETFONT, (WPARAM) hfont, (LPARAM) TRUE);
417
418     DeferWindowPos(hdefer, hwnd, NULL,
419                    0, 0, 0, 0,
420                    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
421                    SWP_NOSIZE | SWP_SHOWWINDOW);
422
423     d->hwnd_notif_label = hwnd;
424
425     hwnd = CreateWindowEx(0,
426                           L"STATIC",
427                           NULL,
428                           WS_CHILD | SS_ICON |
429 #if (_WIN32_IE >= 0x0600)
430                           SS_REALSIZECONTROL
431 #else
432                           0
433 #endif
434                           ,
435                           r_icon.left, r_icon.top,
436                           r_icon.right - r_icon.left,
437                           r_icon.bottom - r_icon.top,
438                           d->dlg_main,
439                           NULL, NULL, NULL);
440 #ifdef DEBUG
441     assert(hwnd != NULL);
442 #endif
443
444     if (h_icon && hwnd)
445         SendMessage(hwnd, STM_SETICON, (WPARAM) h_icon, 0);
446
447     DeferWindowPos(hdefer, hwnd, NULL,
448                    0, 0, 0, 0,
449                    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
450                    SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOZORDER);
451
452     d->hwnd_notif_aux = hwnd;
453
454     EndDeferWindowPos(hdefer);
455
456     CopyRect(&d->r_notif, &r_row);
457
458     d->notif_type = NC_NOTIFY_MESSAGE;
459
460     /* Note that we must call nc_layout_main_panel() after calling
461        this to adjust the layout of the main panel.  However we aren't
462        calling it here since we might want to add another set of
463        notifications or make other changes to the main panel content
464        before calling nc_layout_main_panel(). */
465 }
466
467 static void
468 nc_layout_main_panel(khui_nc_wnd_data * d)
469 {
470     RECT r_main;
471     HWND hw_ct;
472     HWND hw_ct_label;
473     HDWP hdwp;
474     RECT r_used;                /* extent used by identity specifiers,
475                                    custom prompts and notificaiton
476                                    controls. */
477
478     RECT r_wmain;              /* extents of the main window in screen
479                                   coordinates. */
480
481     r_main.left = 0;
482     r_main.top = 0;
483     r_main.bottom = NCDLG_HEIGHT;
484     r_main.right = NCDLG_WIDTH;
485
486     MapDialogRect(d->dlg_main, &r_main);
487
488     CopyRect(&r_used, &d->r_idspec);
489
490     GetWindowRect(d->dlg_main, &r_wmain);
491
492     hdwp = BeginDeferWindowPos(7);
493
494     /* check if the notification area and the custom prompt area are
495        overlapping. */
496
497     if (d->notif_type != NC_NOTIFY_NONE) {
498         long delta_y = 0;
499         RECT r;
500
501         CopyRect(&r, &d->r_custprompt);
502
503         if (IsRectEmpty(&d->r_custprompt)) {
504             /* if there are no custom prompts, then the notification
505                area should be immediately below the identitify
506                specifers. */
507
508             delta_y = d->r_idspec.bottom - d->r_notif.top;
509         } else {
510             /* otherwise, the notification area should be immediately
511                below the custom prompt area */
512
513             delta_y = d->r_custprompt.bottom - d->r_notif.top;
514         }
515
516         if (delta_y != 0) {
517             RECT r_lbl;
518             RECT r_aux;
519
520             if (d->hwnd_notif_label) {
521                 GetWindowRect(d->hwnd_notif_label, &r_lbl);
522                 OffsetRect(&r_lbl, -r_wmain.left, delta_y - r_wmain.top);
523
524                 DeferWindowPos(hdwp, d->hwnd_notif_label, NULL,
525                                r_lbl.left, r_lbl.top, 0, 0,
526                                SWP_NOACTIVATE | SWP_NOOWNERZORDER |
527                                SWP_NOZORDER | SWP_NOSIZE);
528             }
529
530             if (d->hwnd_notif_aux) {
531                 GetWindowRect(d->hwnd_notif_aux, &r_aux);
532                 OffsetRect(&r_aux, -r_wmain.left, delta_y - r_wmain.top);
533
534                 DeferWindowPos(hdwp, d->hwnd_notif_aux, NULL,
535                                r_aux.left, r_aux.top, 0, 0,
536                                SWP_NOACTIVATE | SWP_NOOWNERZORDER |
537                                SWP_NOZORDER | SWP_NOSIZE);
538             }
539
540             OffsetRect(&d->r_notif, 0, delta_y);
541         }
542     }
543
544     if (!IsRectEmpty(&d->r_custprompt)) {
545         r_used.bottom = max(d->r_custprompt.bottom,
546                             r_used.bottom);
547     }
548
549     if (!IsRectEmpty(&d->r_notif)) {
550         r_used.bottom = max(d->r_notif.bottom,
551                             r_used.bottom);
552     }
553
554     if (d->nc->mode == KHUI_NC_MODE_MINI) {
555         RECT r_ok;
556         RECT r_cancel;
557         RECT r_advanced;
558         HWND hw;
559
560         hw = GetDlgItem(d->dlg_main, IDOK);
561 #ifdef DEBUG
562         assert(hw != NULL);
563 #endif
564         GetWindowRect(hw, &r_ok);
565         OffsetRect(&r_ok, -r_wmain.left, -r_ok.top + r_used.bottom);
566
567         DeferWindowPos(hdwp, hw, NULL,
568                        r_ok.left, r_ok.top, 0, 0,
569                        SWP_NOACTIVATE | SWP_NOOWNERZORDER |
570                        SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
571
572         hw = GetDlgItem(d->dlg_main, IDCANCEL);
573 #ifdef DEBUG
574         assert(hw != NULL);
575 #endif
576         GetWindowRect(hw, &r_cancel);
577         OffsetRect(&r_cancel, -r_wmain.left, -r_cancel.top + r_used.bottom);
578
579         DeferWindowPos(hdwp, hw, NULL,
580                        r_cancel.left, r_cancel.top, 0, 0,
581                        SWP_NOACTIVATE | SWP_NOOWNERZORDER |
582                        SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
583
584         hw = GetDlgItem(d->dlg_main, IDC_NC_ADVANCED);
585 #ifdef DEBUG
586         assert(hw != NULL);
587 #endif
588         GetWindowRect(hw, &r_advanced);
589         OffsetRect(&r_advanced, -r_wmain.left, -r_advanced.top + r_used.bottom);
590
591         DeferWindowPos(hdwp, hw, NULL,
592                        r_advanced.left, r_advanced.top, 0, 0,
593                        SWP_NOACTIVATE | SWP_NOOWNERZORDER |
594                        SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
595
596         /* and now update the extents of the main panel */
597         r_main.bottom = r_used.bottom + (r_ok.bottom - r_ok.top) + d->r_area.top;
598
599         CopyRect(&d->r_main, &r_main);
600
601     } else {
602
603         HWND hw;
604
605         hw = GetDlgItem(d->dlg_main, IDOK);
606 #ifdef DEBUG
607         assert(hw != NULL);
608 #endif
609         if (IsWindowVisible(hw))
610             DeferWindowPos(hdwp, hw, NULL,
611                            0, 0, 0, 0,
612                            SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE |
613                            SWP_NOOWNERZORDER | SWP_NOZORDER);
614
615         hw = GetDlgItem(d->dlg_main, IDCANCEL);
616 #ifdef DEBUG
617         assert(hw != NULL);
618 #endif
619         if (IsWindowVisible(hw))
620             DeferWindowPos(hdwp, hw, NULL,
621                            0, 0, 0, 0,
622                            SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE |
623                            SWP_NOOWNERZORDER | SWP_NOZORDER);
624
625         hw = GetDlgItem(d->dlg_main, IDC_NC_ADVANCED);
626 #ifdef DEBUG
627         assert(hw != NULL);
628 #endif
629         if (IsWindowVisible(hw))
630             DeferWindowPos(hdwp, hw, NULL,
631                            0, 0, 0, 0,
632                            SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE |
633                            SWP_NOOWNERZORDER | SWP_NOZORDER);
634
635         d->r_credtext.top = r_used.bottom;
636
637         CopyRect(&d->r_main, &r_main);
638     }
639
640     /* now update the layout of the credentials text window */
641
642     hw_ct = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT);
643     hw_ct_label = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT_LABEL);
644 #ifdef DEBUG
645     assert(hw_ct != NULL);
646     assert(hw_ct_label != NULL);
647 #endif
648
649     if (d->nc->mode == KHUI_NC_MODE_MINI ||
650         d->r_credtext.bottom < d->r_credtext.top + d->r_row.bottom * 2) {
651
652         /* either we aren't supposed to show the credentials text
653            window, or we don't have enough room. */
654         if (IsWindowVisible(hw_ct) || IsWindowVisible(hw_ct_label)) {
655
656             DeferWindowPos(hdwp, hw_ct, NULL,
657                            0, 0, 0, 0,
658                            SWP_HIDEWINDOW | SWP_NOOWNERZORDER |
659                            SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
660
661             DeferWindowPos(hdwp, hw_ct_label, NULL,
662                            0, 0, 0, 0,
663                            SWP_HIDEWINDOW | SWP_NOOWNERZORDER |
664                            SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
665
666         }
667
668     } else {
669
670         DeferWindowPos(hdwp,
671                        hw_ct, NULL,
672                        d->r_credtext.left + d->r_n_input.left, /* x */
673                        d->r_credtext.top, /* y */
674                        d->r_n_input.right - d->r_n_input.left, /* width */
675                        d->r_credtext.bottom - d->r_credtext.top, /* height */
676                        SWP_NOACTIVATE | SWP_NOOWNERZORDER | 
677                        SWP_NOZORDER | SWP_SHOWWINDOW);
678
679         DeferWindowPos(hdwp,
680                        hw_ct_label, NULL,
681                        d->r_credtext.left + d->r_n_label.left, /* x */
682                        d->r_credtext.top, /* y */
683                        d->r_n_label.right - d->r_n_label.left, /* width */
684                        d->r_n_label.bottom - d->r_n_label.top, /* height */
685                        SWP_NOACTIVATE | SWP_NOOWNERZORDER |
686                        SWP_NOZORDER | SWP_SHOWWINDOW);
687     }
688
689     EndDeferWindowPos(hdwp);
690
691     /* NOTE: although we updated d->r_main, if the new credentials
692        window is in mini mode, we must call
693        nc_layout_new_cred_window() to adjust the size of the new
694        credentials window to fit the main panel.  We don't do it here
695        because we need to keep these two operations separate. */
696 }
697
698 /* Credential type panel comparison function.  Tabs are sorted based
699    on the following criteria:
700
701    1) By ordinal - Panels with ordinal -1 will be ranked after panels
702       whose ordinal is not -1.
703
704    2) By name - Case insensitive comparison of the name.  If the panel
705       does not have a name (i.e. the ->name member is NULL, it will be
706       ranked after panels which have a name.
707  */
708 static int __cdecl
709 nc_tab_sort_func(const void * v1, const void * v2)
710 {
711     /* v1 and v2 and of type : khui_new_creds_by_type ** */
712     khui_new_creds_by_type *t1, *t2;
713
714     t1 = *((khui_new_creds_by_type **) v1);
715     t2 = *((khui_new_creds_by_type **) v2);
716
717     if(t1->ordinal !=  -1) {
718         if(t2->ordinal != -1) {
719             if(t1->ordinal == t2->ordinal) {
720                 if (t1->name && t2->name)
721                     return _wcsicmp(t1->name, t2->name);
722                 else if (t1->name)
723                     return -1;
724                 else if (t2->name)
725                     return 1;
726                 else
727                     return 0;
728             } else {
729                 /* safe to convert to an int here */
730                 return (int) (t1->ordinal - t2->ordinal);
731             }
732         } else
733             return -1;
734     } else {
735         if(t2->ordinal != -1)
736             return 1;
737         else if (t1->name && t2->name)
738             return wcscmp(t1->name, t2->name);
739         else if (t1->name)
740             return -1;
741         else if (t2->name)
742             return 1;
743         else
744             return 0;
745     }
746 }
747
748 static void 
749 nc_notify_types(khui_new_creds * c, UINT uMsg,
750                 WPARAM wParam, LPARAM lParam, BOOL sync)
751 {
752     khm_size i;
753
754     for(i=0; i<c->n_types; i++) {
755
756         if (c->types[i]->hwnd_panel == NULL)
757             continue;
758
759         if (sync)
760             SendMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam);
761         else
762             PostMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam);
763     }
764 }
765
766 static void
767 nc_clear_password_fields(khui_nc_wnd_data * d)
768 {
769     khm_size i;
770     khm_boolean need_sync = FALSE;
771
772     khui_cw_lock_nc(d->nc);
773
774     for (i=0; i < d->nc->n_prompts; i++) {
775         if ((d->nc->prompts[i]->flags & KHUI_NCPROMPT_FLAG_HIDDEN) &&
776             d->nc->prompts[i]->hwnd_edit) {
777             SetWindowText(d->nc->prompts[i]->hwnd_edit,
778                           L"");
779             need_sync = TRUE;
780         }
781     }
782
783     khui_cw_unlock_nc(d->nc);
784
785     if (need_sync) {
786         khui_cw_sync_prompt_values(d->nc);
787     }
788 }
789
790 /* used by nc_enable_controls */
791
792 struct nc_enum_wnd_data {
793     khui_nc_wnd_data * d;
794     khm_boolean enable;
795 };
796
797 static
798 BOOL CALLBACK
799 nc_enum_wnd_proc(HWND hwnd,
800                  LPARAM lParam)
801 {
802     struct nc_enum_wnd_data * wd;
803
804     wd = (struct nc_enum_wnd_data *) lParam;
805
806     EnableWindow(hwnd, wd->enable);
807
808     return TRUE;
809 }
810
811 static void
812 nc_enable_controls(khui_nc_wnd_data * d, khm_boolean enable)
813 {
814     struct nc_enum_wnd_data wd;
815
816     ZeroMemory(&wd, sizeof(wd));
817
818     wd.d = d;
819     wd.enable = enable;
820
821     EnumChildWindows(d->dlg_main, nc_enum_wnd_proc, (LPARAM) &wd);
822 }
823
824 #define NC_MAXCCH_CREDTEXT 16384
825 #define NC_MAXCB_CREDTEXT (NC_MAXCCH_CREDTEXT * sizeof(wchar_t))
826
827 static void 
828 nc_update_credtext(khui_nc_wnd_data * d) 
829 {
830     wchar_t * ctbuf = NULL;
831     wchar_t * buf;
832     BOOL okEnable = FALSE;
833     BOOL validId = FALSE;
834     HWND hw = NULL;
835     size_t cch = 0;
836
837     ctbuf = PMALLOC(NC_MAXCB_CREDTEXT);
838
839     assert(ctbuf != NULL);
840
841     LoadString(khm_hInstance, IDS_NC_CREDTEXT_TABS, ctbuf, NC_MAXCCH_CREDTEXT);
842     StringCchLength(ctbuf, NC_MAXCCH_CREDTEXT, &cch);
843     buf = ctbuf + cch;
844     nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, 
845                     MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), (LPARAM) d->nc, TRUE);
846
847     /* hopefully all the types have updated their credential texts */
848
849     /* if the dialog is in the mini mode, we have to display
850        exceptions using a notification. */
851     if (d->nc->mode == KHUI_NC_MODE_MINI) {
852         BOOL need_layout = FALSE;
853         if (d->nc->n_identities == 0) {
854
855             /* There are no identities selected. We don't show any
856                notifications here. */
857             if (d->notif_type != NC_NOTIFY_NONE) {
858                 nc_notify_clear(d);
859                 need_layout = TRUE;
860             }
861
862         } else {
863
864             wchar_t id_name[KCDB_IDENT_MAXCCH_NAME];
865             wchar_t format[256];
866             wchar_t msg[ARRAYLENGTH(format) + ARRAYLENGTH(id_name)];
867             khm_size cbbuf;
868             khm_int32 flags;
869
870             kcdb_identity_get_flags(d->nc->identities[0], &flags);
871
872             cbbuf = sizeof(id_name);
873             kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf);
874
875             if (flags & KCDB_IDENT_FLAG_INVALID) {
876
877                 /* identity is invalid */
878                 LoadString(khm_hInstance, IDS_NCN_IDENT_INVALID,
879                            format, ARRAYLENGTH(format));
880                 StringCbPrintf(msg, sizeof(msg), format, id_name);
881
882                 nc_notify_message(d, KHERR_ERROR, msg);
883
884                 need_layout = TRUE;
885
886             } else if ((flags & KCDB_IDENT_FLAG_VALID) ||
887                        d->nc->subtype == KMSG_CRED_PASSWORD) {
888                 /* special case: If we are going to change the
889                    password, we don't expect the identity provider to
890                    validate the identity in real time.  As such, we
891                    assume that the identity is valid. */
892  
893                /* identity is valid */
894                 if (d->notif_type != NC_NOTIFY_NONE) {
895                     nc_notify_clear(d);
896                     need_layout = TRUE;
897                 }
898
899             } else if (flags & KCDB_IDENT_FLAG_UNKNOWN) {
900
901                 /* unknown state */
902                 LoadString(khm_hInstance, IDS_NCN_IDENT_UNKNOWN,
903                            format, ARRAYLENGTH(format));
904                 StringCbPrintf(msg, sizeof(msg), format, id_name);
905
906                 nc_notify_message(d, KHERR_WARNING, msg);
907
908                 need_layout = TRUE;
909
910             } else {
911
912                 /* still checking */
913                 LoadString(khm_hInstance, IDS_NCN_IDENT_CHECKING,
914                            format, ARRAYLENGTH(format));
915                 StringCbPrintf(msg, sizeof(msg), format, id_name);
916
917                 nc_notify_marquee(d, msg);
918
919                 need_layout = TRUE;
920
921             }
922         }
923
924         if (need_layout) {
925             nc_layout_main_panel(d);
926             nc_layout_new_cred_window(d);
927         }
928     }
929
930     if(d->nc->n_identities == 1) {
931         wchar_t main_fmt[256];
932         wchar_t id_fmt[256];
933         wchar_t id_name[KCDB_IDENT_MAXCCH_NAME];
934         wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256];
935         khm_size cbbuf;
936         khm_int32 flags;
937
938         LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_ONE, 
939                    main_fmt, (int) ARRAYLENGTH(main_fmt));
940
941         cbbuf = sizeof(id_name);
942         kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf);
943
944         kcdb_identity_get_flags(d->nc->identities[0], &flags);
945
946         if (flags & KCDB_IDENT_FLAG_INVALID) {
947             LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, 
948                        id_fmt, (int) ARRAYLENGTH(id_fmt));
949         } else if(flags & KCDB_IDENT_FLAG_VALID) {
950             LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, 
951                        id_fmt, (int) ARRAYLENGTH(id_fmt));
952         } else if(flags & KCDB_IDENT_FLAG_UNKNOWN) {
953             LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED,
954                        id_fmt, (int) ARRAYLENGTH(id_fmt));
955         } else if(d->nc->subtype == KMSG_CRED_NEW_CREDS) {
956             LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_CHECKING, 
957                        id_fmt, (int) ARRAYLENGTH(id_fmt));
958         } else {
959             LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, 
960                        id_fmt, (int) ARRAYLENGTH(id_fmt));
961         }
962
963         StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name);
964
965         StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), 
966                        main_fmt, id_string);
967
968         if (flags & KCDB_IDENT_FLAG_VALID) {
969             if (flags & KCDB_IDENT_FLAG_DEFAULT)
970                 LoadString(khm_hInstance, IDS_NC_ID_DEF,
971                            id_string, ARRAYLENGTH(id_string));
972             else if (d->nc->set_default)
973                 LoadString(khm_hInstance, IDS_NC_ID_WDEF,
974                            id_string, ARRAYLENGTH(id_string));
975             else
976                 LoadString(khm_hInstance, IDS_NC_ID_NDEF,
977                            id_string, ARRAYLENGTH(id_string));
978
979             StringCbCat(buf, NC_MAXCB_CREDTEXT - cch * sizeof(wchar_t),
980                         id_string);
981         }
982
983     } else if(d->nc->n_identities > 1) {
984         wchar_t *ids_string;
985         khm_size cb_ids_string;
986
987         wchar_t id_name[KCDB_IDENT_MAXCCH_NAME];
988         wchar_t id_fmt[256];
989         wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256];
990
991         wchar_t main_fmt[256];
992         khm_size cbbuf;
993
994         LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_MANY, 
995                    main_fmt, (int) ARRAYLENGTH(main_fmt));
996
997         /* we are going to concatenate all the identity names into
998            a comma separated string */
999
1000         /* d->nc->n_identities is at least 2 */
1001         ids_string = PMALLOC((KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * 
1002                             (d->nc->n_identities - 1));
1003         cb_ids_string = 
1004             (KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * 
1005             (d->nc->n_identities - 1);
1006
1007         assert(ids_string != NULL);
1008
1009         ids_string[0] = 0;
1010
1011         {
1012             khm_size i;
1013             khm_int32 flags;
1014
1015             for(i=1; i<d->nc->n_identities; i++) {
1016                 if(i>1) {
1017                     StringCbCat(ids_string, cb_ids_string, L",");
1018                 }
1019
1020                 flags = 0;
1021
1022                 cbbuf = sizeof(id_name);
1023                 kcdb_identity_get_name(d->nc->identities[i], id_name, &cbbuf);
1024                 kcdb_identity_get_flags(d->nc->identities[i], &flags);
1025                 if(flags & KCDB_IDENT_FLAG_INVALID) {
1026                     LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, 
1027                                id_fmt, (int) ARRAYLENGTH(id_fmt));
1028                 } else if(flags & KCDB_IDENT_FLAG_VALID) {
1029                     LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, 
1030                                id_fmt, (int) ARRAYLENGTH(id_fmt));
1031                 } else {
1032                     LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, 
1033                                id_fmt, (int) ARRAYLENGTH(id_fmt));
1034                 }
1035
1036                 StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name);
1037                 StringCbCat(ids_string, cb_ids_string, id_string);
1038             }
1039
1040             cbbuf = sizeof(id_name);
1041             kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf);
1042             kcdb_identity_get_flags(d->nc->identities[0], &flags);
1043             if(flags & KCDB_IDENT_FLAG_INVALID) {
1044                 LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, 
1045                            id_fmt, (int) ARRAYLENGTH(id_fmt));
1046             } else if(flags & KCDB_IDENT_FLAG_VALID) {
1047                 LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, 
1048                            id_fmt, (int) ARRAYLENGTH(id_fmt));
1049             } else {
1050                 LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, 
1051                            id_fmt, (int) ARRAYLENGTH(id_fmt));
1052             }
1053             StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name);
1054
1055             StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), 
1056                            main_fmt, id_string, ids_string);
1057
1058             PFREE(ids_string);
1059         }
1060     } else {
1061         LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_NONE, 
1062                    buf, (int)(NC_MAXCCH_CREDTEXT - cch));
1063     }
1064
1065     /* now, append the credtext string from each of the cred types */
1066     {
1067         khm_size i;
1068         size_t cb;
1069         wchar_t * buf;
1070
1071         cb = NC_MAXCB_CREDTEXT;
1072         buf = ctbuf;
1073
1074         for(i=0; i<d->nc->n_types; i++) {
1075             if(d->nc->types[i]->credtext != NULL) {
1076                 StringCbCatEx(buf, cb, 
1077                               d->nc->types[i]->credtext,
1078                               &buf, &cb,
1079                               0);
1080             }
1081         }
1082     }
1083
1084     SetDlgItemText(d->dlg_main, IDC_NC_CREDTEXT, ctbuf);
1085
1086     PFREE(ctbuf);
1087
1088     /* so depending on whether the primary identity was found to be
1089        invalid, we need to disable the Ok button and set the title to
1090        reflect this */
1091
1092     if(d->nc->n_identities > 0) {
1093         khm_int32 flags = 0;
1094
1095         if(KHM_SUCCEEDED(kcdb_identity_get_flags(d->nc->identities[0], 
1096                                                &flags)) &&
1097            (flags & KCDB_IDENT_FLAG_VALID)) {
1098             validId = TRUE;
1099         }
1100     }
1101
1102     if (d->nc->window_title == NULL) {
1103         if(validId) {
1104             wchar_t wpostfix[256];
1105             wchar_t wtitle[KCDB_IDENT_MAXCCH_NAME + 256];
1106             khm_size cbsize;
1107
1108             cbsize = sizeof(wtitle);
1109             kcdb_identity_get_name(d->nc->identities[0], wtitle, &cbsize);
1110
1111             if (d->nc->subtype == KMSG_CRED_PASSWORD)
1112                 LoadString(khm_hInstance, IDS_WTPOST_PASSWORD,
1113                            wpostfix, (int) ARRAYLENGTH(wpostfix));
1114             else
1115                 LoadString(khm_hInstance, IDS_WTPOST_NEW_CREDS, 
1116                            wpostfix, (int) ARRAYLENGTH(wpostfix));
1117
1118             StringCbCat(wtitle, sizeof(wtitle), wpostfix);
1119
1120             SetWindowText(d->nc->hwnd, wtitle);
1121         } else {
1122             wchar_t wtitle[256];
1123
1124             if (d->nc->subtype == KMSG_CRED_PASSWORD)
1125                 LoadString(khm_hInstance, IDS_WT_PASSWORD,
1126                            wtitle, (int) ARRAYLENGTH(wtitle));
1127             else
1128                 LoadString(khm_hInstance, IDS_WT_NEW_CREDS, 
1129                            wtitle, (int) ARRAYLENGTH(wtitle));
1130
1131             SetWindowText(d->nc->hwnd, wtitle);
1132         }
1133     }
1134
1135     if (!(d->nc->response & KHUI_NC_RESPONSE_PROCESSING)) {
1136         if(validId ||
1137            d->nc->subtype == KMSG_CRED_PASSWORD) {
1138             /* TODO: check if all the required fields have valid values
1139                before enabling the Ok button */
1140             okEnable = TRUE;
1141         }
1142
1143         hw = GetDlgItem(d->dlg_main, IDOK);
1144         EnableWindow(hw, okEnable);
1145         hw = GetDlgItem(d->dlg_bb, IDOK);
1146         EnableWindow(hw, okEnable);
1147     }
1148 }
1149
1150 static void
1151 nc_layout_new_cred_window(khui_nc_wnd_data * ncd) {
1152     khui_new_creds * c;
1153     RECT r_main;
1154     RECT r_ncdialog;
1155     HDWP hdefer;
1156
1157     c = ncd->nc;
1158
1159     r_main.left = 0;
1160     r_main.top = 0;
1161     r_main.right = NCDLG_WIDTH;
1162     r_main.bottom = NCDLG_HEIGHT;
1163
1164     MapDialogRect(ncd->dlg_main, &r_main);
1165
1166     hdefer = BeginDeferWindowPos(5);
1167
1168     if (c->mode == KHUI_NC_MODE_MINI) {
1169
1170         if (IsWindowVisible(ncd->tab_wnd)) {
1171             DeferWindowPos(hdefer,
1172                            ncd->tab_wnd, NULL,
1173                            0, 0, 0, 0,
1174                            SWP_HIDEWINDOW |
1175                            SWP_NOMOVE | SWP_NOOWNERZORDER |
1176                            SWP_NOSIZE | SWP_NOZORDER);
1177         }
1178
1179         if (IsWindowVisible(ncd->dlg_bb)) {
1180             DeferWindowPos(hdefer,
1181                            ncd->dlg_bb, NULL,
1182                            0, 0, 0, 0,
1183                            SWP_HIDEWINDOW |
1184                            SWP_NOMOVE | SWP_NOOWNERZORDER |
1185                            SWP_NOSIZE | SWP_NOZORDER);
1186         }
1187
1188         DeferWindowPos(hdefer, ncd->dlg_main, NULL,
1189                        r_main.left, r_main.top,
1190                        r_main.right - r_main.left,
1191                        r_main.bottom - r_main.top,
1192                        SWP_NOACTIVATE | SWP_NOOWNERZORDER |
1193                        SWP_NOZORDER | SWP_SHOWWINDOW);
1194
1195         /* note that the ncd->r_main.bottom may not be the same as
1196            r_main.bottom because ncd->r_main.bottom is set dynamically
1197            depending on custom controls. ncd->r_main is valid only
1198            once nc_layout_main_panel() is called.*/
1199         CopyRect(&ncd->r_required, &ncd->r_main);
1200
1201     } else {
1202         RECT r_tabctrl;
1203         RECT r_displayarea;
1204         RECT r_bbar;
1205         khm_size i;
1206
1207         /* calculate the size of the tab control so that it fits
1208            snugly around the expanded main panel. */
1209         CopyRect(&r_tabctrl, &r_main);
1210         TabCtrl_AdjustRect(ncd->tab_wnd, TRUE, &r_tabctrl);
1211
1212         if (r_tabctrl.left < 0 ||
1213             r_tabctrl.top < 0) {
1214
1215             OffsetRect(&r_tabctrl,
1216                        (r_tabctrl.left < 0)? -r_tabctrl.left : 0,
1217                        (r_tabctrl.top < 0)? -r_tabctrl.top : 0);
1218
1219         }
1220
1221 #ifdef DEBUG
1222         assert(r_tabctrl.left == 0);
1223         assert(r_tabctrl.top == 0);
1224 #endif
1225
1226         OffsetRect(&r_tabctrl, 0, ncd->r_area.top);
1227
1228         /* and now calculate the rectangle where the main panel should
1229            be inside the tab control. */
1230         CopyRect(&r_displayarea, &r_tabctrl);
1231         TabCtrl_AdjustRect(ncd->tab_wnd, FALSE, &r_displayarea);
1232
1233         DeferWindowPos(hdefer,
1234                        ncd->tab_wnd, HWND_BOTTOM,
1235                        r_tabctrl.left, r_tabctrl.top,
1236                        r_tabctrl.right - r_tabctrl.left,
1237                        r_tabctrl.bottom - r_tabctrl.top,
1238                        SWP_NOACTIVATE | SWP_NOOWNERZORDER |
1239                        SWP_SHOWWINDOW);
1240
1241         /* we have to place the button bar just to the right of the
1242            tab panel. */
1243         r_bbar.left = 0;
1244         r_bbar.top = 0;
1245         r_bbar.right = NCDLG_BBAR_WIDTH;
1246         r_bbar.bottom = NCDLG_BBAR_HEIGHT;
1247
1248         MapDialogRect(ncd->dlg_main, &r_bbar);
1249
1250         OffsetRect(&r_bbar, r_tabctrl.right, 0);
1251
1252         DeferWindowPos(hdefer,
1253                        ncd->dlg_bb, NULL,
1254                        r_bbar.left, r_bbar.top,
1255                        r_bbar.right - r_bbar.left,
1256                        r_bbar.bottom - r_bbar.top,
1257                        SWP_NOACTIVATE | SWP_NOOWNERZORDER |
1258                        SWP_NOZORDER | SWP_SHOWWINDOW);
1259
1260         /* move the main panel inside the tab control... */
1261         DeferWindowPos(hdefer,
1262                        ncd->dlg_main, NULL,
1263                        r_displayarea.left, r_displayarea.top,
1264                        r_displayarea.right - r_displayarea.left,
1265                        r_displayarea.bottom - r_displayarea.top,
1266                        SWP_NOACTIVATE | SWP_NOOWNERZORDER |
1267                        SWP_NOZORDER |
1268                        (ncd->current_panel == 0 ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
1269
1270         /* and also move all the credential type panels (if they have
1271            been created) inside the tab control too. */
1272         khui_cw_lock_nc(c);
1273
1274         for (i=0; i < c->n_types; i++) {
1275             if (c->types[i]->hwnd_panel != NULL) {
1276                 DeferWindowPos(hdefer,
1277                                c->types[i]->hwnd_panel, NULL,
1278                                r_displayarea.left, r_displayarea.top,
1279                                r_displayarea.right - r_displayarea.left,
1280                                r_displayarea.bottom - r_displayarea.top,
1281                                SWP_NOACTIVATE | SWP_NOOWNERZORDER |
1282                                SWP_NOZORDER |
1283                                (ncd->current_panel == c->types[i]->ordinal ?
1284                                 SWP_SHOWWINDOW : SWP_HIDEWINDOW));
1285             }
1286         }
1287
1288         khui_cw_unlock_nc(c);
1289
1290         /* then update the required size of the new credentials
1291            dialog. */
1292         ncd->r_required.left = 0;
1293         ncd->r_required.top = 0;
1294         ncd->r_required.right = r_bbar.right;
1295         ncd->r_required.bottom = max(r_tabctrl.bottom, r_bbar.bottom) + ncd->r_area.top;
1296     }
1297
1298     /* commit all the window moves, resizes and hides/shows we did*/
1299     EndDeferWindowPos(hdefer);
1300
1301     /* now we have to see if the client area of the new credentials
1302        window is the right size. */
1303
1304     GetClientRect(c->hwnd, &r_ncdialog);
1305
1306     if (
1307
1308         ((r_ncdialog.right - r_ncdialog.left !=
1309           ncd->r_required.right - ncd->r_required.left)
1310
1311          ||
1312
1313          (r_ncdialog.bottom - r_ncdialog.top !=
1314           ncd->r_required.bottom - ncd->r_required.top))
1315
1316         &&
1317
1318         /* we don't bother if the new creds window is already in the
1319            process of changing the size. */
1320         !ncd->size_changing) {
1321
1322         /* if not, notify the window that the size needs adjusting. */
1323         if (IsWindowVisible(c->hwnd))
1324             PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY,
1325                         MAKEWPARAM(0, WMNC_UPDATE_LAYOUT), 0);
1326         else
1327             SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY,
1328                         MAKEWPARAM(0, WMNC_UPDATE_LAYOUT), 0);
1329     }
1330 }
1331
1332 #define CW_PARAM DWLP_USER
1333
1334 static LRESULT 
1335 nc_handle_wm_create(HWND hwnd,
1336                     UINT uMsg,
1337                     WPARAM wParam,
1338                     LPARAM lParam)
1339 {
1340     LPCREATESTRUCT lpc;
1341     khui_new_creds * c;
1342     khui_nc_wnd_data * ncd;
1343     int x, y;
1344     int width, height;
1345     RECT r;
1346     HFONT hf_main;
1347
1348     lpc = (LPCREATESTRUCT) lParam;
1349
1350     ncd = PMALLOC(sizeof(*ncd));
1351     ZeroMemory(ncd, sizeof(*ncd));
1352
1353     c = (khui_new_creds *) lpc->lpCreateParams;
1354     ncd->nc = c;
1355     c->hwnd = hwnd;
1356
1357 #ifdef DEBUG
1358     assert(c->subtype == KMSG_CRED_NEW_CREDS ||
1359            c->subtype == KMSG_CRED_PASSWORD);
1360 #endif
1361
1362 #pragma warning(push)
1363 #pragma warning(disable: 4244)
1364     SetWindowLongPtr(hwnd, CW_PARAM, (LONG_PTR) ncd);
1365 #pragma warning(pop)
1366
1367     /* first, create the tab control that will house the main dialog
1368        panel as well as the plug-in specific panels */
1369     ncd->tab_wnd = CreateWindowEx(0, /* extended style */
1370                                   WC_TABCONTROL,
1371                                   L"TabControloxxrz", /* window name */
1372                                   TCS_HOTTRACK | TCS_RAGGEDRIGHT |
1373                                   TCS_SINGLELINE | TCS_TABS |
1374                                   WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS,
1375                                   0, 0, 100, 100, /* x,y,width height.
1376                                                      We'll be changing
1377                                                      these later
1378                                                      anyway. */
1379                                   hwnd,
1380                                   (HMENU) IDC_NC_TABS,
1381                                   NULL,
1382                                   0);
1383
1384 #ifdef DEBUG
1385     assert(ncd->tab_wnd != NULL);
1386 #endif
1387
1388     /* try to create the main dialog panel */
1389
1390     ncd->dlg_main = CreateDialogParam(khm_hInstance,
1391                                       MAKEINTRESOURCE(IDD_NC_NEWCRED),
1392                                       hwnd,
1393                                       nc_common_dlg_proc,
1394                                       (LPARAM) ncd);
1395 #ifdef DEBUG
1396     assert(ncd->dlg_main != NULL);
1397 #endif
1398
1399     hf_main = (HFONT) SendMessage(ncd->dlg_main, WM_GETFONT, 0, 0);
1400     if (hf_main)
1401         SendMessage(ncd->tab_wnd, WM_SETFONT, (WPARAM) hf_main, FALSE);
1402
1403     {
1404         RECT r_main;
1405         RECT r_area;
1406         RECT r_row;
1407         HWND hw;
1408             
1409         /* During the operation of the new credentials window, we will
1410            need to dynamically change the layout of the controls as a
1411            result of custom prompting from credentials providers and
1412            identity selectors from identity providers.  In order to
1413            guide the dynamic layout, we pick out a few metrics from
1414            the dialog template for the main panel. The metrics come
1415            from hidden STATIC controls in the dialog template. */
1416
1417         GetWindowRect(ncd->dlg_main, &r_main);
1418
1419         /* IDC_NC_TPL_PANEL spans the full extent of the dialog that
1420            we can populate with custom controls. */
1421         hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_PANEL);
1422 #ifdef DEBUG
1423         assert(hw);
1424 #endif
1425         GetWindowRect(hw, &r_area);
1426         OffsetRect(&r_area,-r_main.left, -r_main.top);
1427         CopyRect(&ncd->r_area, &r_area);
1428
1429         /* IDC_NC_TPL_ROW spans the extent of a row of normal sized
1430            custom controls.  A row of custom controls typicall consist
1431            of a text label and an input control. */
1432         hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW);
1433 #ifdef DEBUG
1434         assert(hw);
1435 #endif
1436         GetWindowRect(hw, &r);
1437         CopyRect(&r_row, &r);
1438         OffsetRect(&r,-r.left, -r.top);
1439         CopyRect(&ncd->r_row, &r);
1440
1441         /* IDC_NC_TPL_LABEL spans the extent that a normal sized
1442            label.  The control overlaps IDC_NC_TPL_ROW so we can get
1443            coordinates relative to the row extents. */
1444         hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL);
1445 #ifdef DEBUG
1446         assert(hw);
1447 #endif
1448         GetWindowRect(hw, &r);
1449         OffsetRect(&r,-r_row.left, -r_row.top);
1450         CopyRect(&ncd->r_n_label, &r);
1451
1452         /* IDC_NC_TPL_INPUT spans the extent of a normal sized input
1453            control in a custom control row.  The control overlaps
1454            IDC_NC_TPL_ROW so we can get relative coordinates. */
1455         hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT);
1456 #ifdef DEBUG
1457         assert(hw);
1458 #endif
1459         GetWindowRect(hw, &r);
1460         OffsetRect(&r, -r_row.left, -r_row.top);
1461         CopyRect(&ncd->r_n_input, &r);
1462
1463         /* IDC_NC_TPL_ROW_LG spans the extent of a row of large sized
1464            controls. */
1465         hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW_LG);
1466 #ifdef DEBUG
1467         assert(hw);
1468 #endif
1469         GetWindowRect(hw, &r_row);
1470
1471         /* IDC_NC_TPL_LABEL_LG is a large sized label.  The control
1472            overlaps IDC_NC_TPL_ROW_LG. */
1473         hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL_LG);
1474 #ifdef DEBUG
1475         assert(hw);
1476 #endif
1477         GetWindowRect(hw, &r);
1478         OffsetRect(&r, -r_row.left, -r_row.top);
1479         CopyRect(&ncd->r_e_label, &r);
1480
1481         /* IDC_NC_TPL_INPUT_LG is a large sized input control.
1482            Overlaps IDC_NC_TPL_ROW_LG. */
1483         hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT_LG);
1484 #ifdef DEBUG
1485         assert(hw);
1486 #endif
1487         GetWindowRect(hw, &r);
1488         OffsetRect(&r, -r_row.left, -r_row.top);
1489         CopyRect(&ncd->r_e_input, &r);
1490
1491         CopyRect(&ncd->r_credtext, &ncd->r_area);
1492         CopyRect(&ncd->r_idspec, &ncd->r_area);
1493
1494         ncd->r_idspec.bottom = ncd->r_idspec.top;
1495
1496         /* And finally the credential text window.  The only metric we
1497            take from here is the Y coordinate of the bottom of the
1498            control since the actual size and position of the
1499            credentials window will change depending on the custom
1500            controls being displayed. */
1501         hw = GetDlgItem(ncd->dlg_main, IDC_NC_CREDTEXT);
1502 #ifdef DEBUG
1503         assert(hw);
1504 #endif
1505         GetWindowRect(hw, &r);
1506         OffsetRect(&r, -r_main.left, -r_main.top);
1507         ncd->r_credtext.bottom = r.bottom;
1508     }
1509
1510     /* if the mode is 'mini'*/
1511     r.left = 0;
1512     r.top = 0;
1513
1514     if(c->mode == KHUI_NC_MODE_MINI) {
1515         r.right = NCDLG_WIDTH;
1516         r.bottom = NCDLG_HEIGHT;
1517     } else {
1518         r.right = NCDLG_WIDTH + NCDLG_BBAR_WIDTH;
1519         r.bottom = NCDLG_BBAR_HEIGHT;
1520     }
1521
1522     MapDialogRect(ncd->dlg_main, &r);
1523
1524     /* position the new credentials dialog */
1525     width = r.right - r.left;
1526     height = r.bottom - r.top;
1527
1528     /* adjust width and height to accomodate NC area */
1529     {
1530         RECT wr,cr;
1531
1532         GetWindowRect(hwnd, &wr);
1533         GetClientRect(hwnd, &cr);
1534
1535         /* the non-client and client areas have already been calculated
1536            at this point.  We just use the difference to adjust the width
1537            and height */
1538         width += (wr.right - wr.left) - (cr.right - cr.left);
1539         height += (wr.bottom - wr.top) - (cr.bottom - cr.top);
1540     }
1541
1542     /* if the parent window is visible, we center the new credentials
1543        dialog over the parent.  Otherwise, we center it on the primary
1544        display. */
1545
1546     if (IsWindowVisible(lpc->hwndParent)) {
1547         GetWindowRect(lpc->hwndParent, &r);
1548     } else {
1549         if(!SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID) &r, 0)) {
1550             /* failover to the window coordinates */
1551             GetWindowRect(lpc->hwndParent, &r);
1552         }
1553     }
1554     x = (r.right + r.left)/2 - width / 2;
1555     y = (r.top + r.bottom)/2 - height / 2;
1556
1557     MoveWindow(hwnd, x, y, width, height, FALSE);
1558
1559     ncd->dlg_bb = CreateDialogParam(khm_hInstance,
1560                                     MAKEINTRESOURCE(IDD_NC_BBAR),
1561                                     hwnd,
1562                                     nc_common_dlg_proc,
1563                                     (LPARAM) ncd);
1564
1565 #ifdef DEBUG
1566     assert(ncd->dlg_bb);
1567 #endif
1568
1569     /* Call the identity provider callback to set the identity
1570        selector controls.  These controls need to be there before we
1571        layout the main panel. */
1572     c->ident_cb(c, WMNC_IDENT_INIT, NULL, 0, 0, (LPARAM) ncd->dlg_main);
1573
1574     if (c->mode == KHUI_NC_MODE_EXPANDED) {
1575         SendMessage(ncd->dlg_main, KHUI_WM_NC_NOTIFY,
1576                     MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0);
1577     } else {
1578         /* we don't call nc_layout_main_panel() if the dialog is
1579            expanded because posting WMNC_DIALOG_EXPAND to the main
1580            panel results in it getting called anyway. */
1581         nc_layout_main_panel(ncd);
1582     }
1583
1584     nc_layout_new_cred_window(ncd);
1585
1586     /* add this to the dialog chain */
1587     khm_add_dialog(hwnd);
1588
1589     return TRUE;
1590 }
1591
1592 /* add a control row supplied by an identity provider */
1593 static void
1594 nc_add_control_row(khui_nc_wnd_data * d, 
1595                    HWND label,
1596                    HWND input,
1597                    khui_control_size size)
1598 {
1599     RECT r_row;
1600     RECT r_label;
1601     RECT r_input;
1602     HFONT hf;
1603     HDWP hdefer;
1604
1605     hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0);
1606     SendMessage(label, WM_SETFONT, (WPARAM) hf, FALSE);
1607     SendMessage(input, WM_SETFONT, (WPARAM) hf, FALSE);
1608
1609     CopyRect(&r_row, &d->r_row);
1610     OffsetRect(&r_row, d->r_idspec.left, d->r_idspec.bottom);
1611
1612     if (size == KHUI_CTRLSIZE_SMALL) {
1613         CopyRect(&r_label, &d->r_n_label);
1614         CopyRect(&r_input, &d->r_n_input);
1615         OffsetRect(&r_label, r_row.left, r_row.top);
1616         OffsetRect(&r_input, r_row.left, r_row.top);
1617     } else if (size == KHUI_CTRLSIZE_HALF) {
1618         CopyRect(&r_label, &d->r_e_label);
1619         CopyRect(&r_input, &d->r_e_input);
1620         OffsetRect(&r_label, r_row.left, r_row.top);
1621         OffsetRect(&r_input, r_row.left, r_row.top);
1622     } else if (size == KHUI_CTRLSIZE_FULL) {
1623         CopyRect(&r_label, &d->r_n_label);
1624         r_label.right = d->r_row.right;
1625         CopyRect(&r_input, &d->r_n_input);
1626         OffsetRect(&r_input, r_row.left, r_row.top);
1627         OffsetRect(&r_input, 0, r_input.bottom);
1628         r_row.bottom += r_input.bottom;
1629         OffsetRect(&r_label, r_row.left, r_row.top);
1630     } else {
1631         SetRectEmpty(&r_label);
1632         SetRectEmpty(&r_input);
1633 #ifdef DEBUG
1634         assert(FALSE);
1635 #endif
1636         return;
1637     }
1638
1639     hdefer = BeginDeferWindowPos(2);
1640
1641     if (label)
1642         DeferWindowPos(hdefer, label,
1643                        ((d->hwnd_last_idspec != NULL)?
1644                         d->hwnd_last_idspec:
1645                         HWND_TOP),
1646                        r_label.left, r_label.top,
1647                        r_label.right - r_label.left,
1648                        r_label.bottom - r_label.top,
1649                        SWP_NOACTIVATE | SWP_NOOWNERZORDER);
1650
1651     if (input)
1652         DeferWindowPos(hdefer, input,
1653                        (label ? label : ((d->hwnd_last_idspec != NULL)?
1654                                          d->hwnd_last_idspec:
1655                                          HWND_TOP)),
1656                        r_input.left, r_input.top,
1657                        r_input.right - r_input.left,
1658                        r_input.bottom - r_input.top,
1659                        SWP_NOACTIVATE | SWP_NOOWNERZORDER);
1660
1661     EndDeferWindowPos(hdefer);
1662
1663     d->hwnd_last_idspec = (input ? input : label);
1664
1665     d->r_idspec.bottom = r_row.bottom;
1666
1667     /* we don't update the layout of the main panel yet, since these
1668        control additions happen before the main panel is displayed.  A
1669        call to nc_layout_main_panel() will be made before the main
1670        panel is shown anyway. */
1671
1672 }
1673
1674
1675 static LRESULT 
1676 nc_handle_wm_destroy(HWND hwnd,
1677                      UINT uMsg,
1678                      WPARAM wParam,
1679                      LPARAM lParam)
1680 {
1681     khui_nc_wnd_data * d;
1682
1683     /* remove self from dialog chain */
1684     khm_del_dialog(hwnd);
1685
1686     d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);
1687
1688     d->nc->ident_cb(d->nc, WMNC_IDENT_EXIT, NULL, 0, 0, 0);
1689
1690     if (d->hwnd_notif_label)
1691         DestroyWindow(d->hwnd_notif_label);
1692     if (d->hwnd_notif_aux)
1693         DestroyWindow(d->hwnd_notif_aux);
1694
1695     if(d->dlg_bb)
1696         DestroyWindow(d->dlg_bb);
1697     if(d->dlg_main)
1698         DestroyWindow(d->dlg_main);
1699
1700     d->dlg_bb = NULL;
1701     d->dlg_main = NULL;
1702
1703     PFREE(d);
1704
1705     return TRUE;
1706 }
1707
1708 static LRESULT 
1709 nc_handle_wm_command(HWND hwnd,
1710                      UINT uMsg,
1711                      WPARAM wParam,
1712                      LPARAM lParam)
1713 {
1714     khui_nc_wnd_data * d;
1715
1716     d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);
1717
1718     switch(HIWORD(wParam)) {
1719     case BN_CLICKED:
1720         switch(LOWORD(wParam)) {
1721
1722         case IDOK:
1723             d->nc->result = KHUI_NC_RESULT_PROCESS;
1724
1725             /* fallthrough */
1726
1727         case IDCANCEL:
1728             /* the default value for d->nc->result is set to
1729                KHUI_NC_RESULT_CANCEL */
1730             d->nc->response = KHUI_NC_RESPONSE_PROCESSING;
1731
1732             nc_enable_controls(d, FALSE);
1733
1734             nc_notify_types(d->nc, 
1735                             KHUI_WM_NC_NOTIFY, 
1736                             MAKEWPARAM(0,WMNC_DIALOG_PREPROCESS), 
1737                             (LPARAM) d->nc,
1738                             TRUE);
1739
1740             khui_cw_sync_prompt_values(d->nc);
1741
1742             khm_cred_dispatch_process_message(d->nc);
1743
1744             /* we won't know whether to abort or not until we get
1745                feedback from the plugins, even if the command was
1746                to cancel */
1747             {
1748                 HWND hw;
1749
1750                 hw = GetDlgItem(d->dlg_main, IDOK);
1751                 EnableWindow(hw, FALSE);
1752                 hw = GetDlgItem(d->dlg_main, IDCANCEL);
1753                 EnableWindow(hw, FALSE);
1754                 hw = GetDlgItem(d->dlg_main, IDC_NC_ADVANCED);
1755                 EnableWindow(hw, FALSE);
1756                 hw = GetDlgItem(d->dlg_bb, IDOK);
1757                 EnableWindow(hw, FALSE);
1758                 hw = GetDlgItem(d->dlg_bb, IDCANCEL);
1759                 EnableWindow(hw, FALSE);
1760             }
1761             return FALSE;
1762
1763         case IDC_NC_HELP:
1764             khm_html_help(hwnd, NULL, HH_HELP_CONTEXT, IDH_ACTION_NEW_ID);
1765             return FALSE;
1766
1767         case IDC_NC_BASIC:
1768         case IDC_NC_ADVANCED: 
1769             /* the Options button in the main window was clicked.  we
1770                respond by expanding the dialog. */
1771             PostMessage(hwnd, KHUI_WM_NC_NOTIFY, 
1772                         MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0);
1773             return FALSE;
1774
1775         case IDC_NC_CREDTEXT: /* credtext link activated */
1776             {
1777                 khui_htwnd_link * l;
1778                 wchar_t sid[KHUI_MAXCCH_HTLINK_FIELD];
1779                 wchar_t sparam[KHUI_MAXCCH_HTLINK_FIELD];
1780                 wchar_t * colon;
1781
1782                 l = (khui_htwnd_link *) lParam;
1783
1784                 /* do we have a valid link? */
1785                 if(l->id == NULL || l->id_len >= ARRAYLENGTH(sid))
1786                     return TRUE; /* nope */
1787
1788                 StringCchCopyN(sid, ARRAYLENGTH(sid), l->id, l->id_len);
1789                 sid[l->id_len] = L'\0'; /* just make sure */
1790
1791                 if(l->param != NULL && 
1792                    l->param_len < ARRAYLENGTH(sparam) &&
1793                    l->param_len > 0) {
1794
1795                     StringCchCopyN(sparam, ARRAYLENGTH(sparam),
1796                                    l->param, l->param_len);
1797                     sparam[l->param_len] = L'\0';
1798
1799                 } else {
1800                     sparam[0] = L'\0';
1801                 }
1802
1803                 /* If the ID is of the form '<credtype>:<link_tag>'
1804                    and <credtype> is a valid name of a credentials
1805                    type that is participating in the credentials
1806                    acquisition process, then we forward the message to
1807                    the panel that is providing the UI for that cred
1808                    type.  We also switch to that panel first, unless
1809                    the link is of the form '<credtype>:!<link_tag>'. */
1810
1811                 colon = wcschr(sid, L':');
1812                 if (colon != NULL) {
1813                     khm_int32 credtype;
1814                     khui_new_creds_by_type * t;
1815
1816                     *colon = L'\0';
1817                     if (KHM_SUCCEEDED(kcdb_credtype_get_id(sid, &credtype)) &&
1818                         KHM_SUCCEEDED(khui_cw_find_type(d->nc, credtype, &t))){
1819                         *colon = L':';
1820
1821                         if (t->ordinal != d->current_panel &&
1822                             *(colon + 1) != L'!')
1823                             PostMessage(hwnd,
1824                                         KHUI_WM_NC_NOTIFY,
1825                                         MAKEWPARAM(t->ordinal,
1826                                                    WMNC_DIALOG_SWITCH_PANEL),
1827                                         0);
1828
1829                         return SendMessage(t->hwnd_panel,
1830                                            KHUI_WM_NC_NOTIFY,
1831                                            MAKEWPARAM(0, WMNC_CREDTEXT_LINK),
1832                                            lParam);
1833                     } else {
1834                         *colon = L':';
1835                     }
1836                 }
1837
1838                 /* if it was for us, then we need to process the message */
1839                 if(!_wcsicmp(sid, CTLINKID_SWITCH_PANEL)) {
1840                     khm_int32 credtype;
1841                     khui_new_creds_by_type * t;
1842
1843                     if (KHM_SUCCEEDED(kcdb_credtype_get_id(sparam, 
1844                                                            &credtype)) &&
1845                         KHM_SUCCEEDED(khui_cw_find_type(d->nc,
1846                                                         credtype, &t))) {
1847                         if (t->ordinal != d->current_panel)
1848                             PostMessage(hwnd,
1849                                         KHUI_WM_NC_NOTIFY,
1850                                         MAKEWPARAM(t->ordinal,
1851                                                    WMNC_DIALOG_SWITCH_PANEL),
1852                                         0);
1853                     }
1854                 } else if (!_wcsicmp(sid, L"NotDef")) {
1855                     d->nc->set_default = FALSE;
1856                     nc_update_credtext(d);
1857                 } else if (!_wcsicmp(sid, L"MakeDef")) {
1858                     d->nc->set_default = TRUE;
1859                     nc_update_credtext(d);
1860                 }
1861             }
1862             return FALSE;
1863
1864 #if 0
1865         case NC_BN_SET_DEF_ID:
1866             {
1867                 d->nc->set_default =
1868                     (IsDlgButtonChecked(d->dlg_main, NC_BN_SET_DEF_ID)
1869                      == BST_CHECKED);
1870             }
1871             return FALSE;
1872 #endif
1873         }
1874         break;
1875     }
1876
1877     return TRUE;
1878 }
1879
1880 static LRESULT nc_handle_wm_moving(HWND hwnd,
1881                                    UINT uMsg,
1882                                    WPARAM wParam,
1883                                    LPARAM lParam)
1884 {
1885     khui_nc_wnd_data * d;
1886
1887     d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);
1888
1889     nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, 
1890                     MAKEWPARAM(0, WMNC_DIALOG_MOVE), (LPARAM) d->nc, TRUE);
1891
1892     return FALSE;
1893 }
1894
1895 static LRESULT nc_handle_wm_nc_notify(HWND hwnd,
1896                                UINT uMsg,
1897                                WPARAM wParam,
1898                                LPARAM lParam)
1899 {
1900     khui_nc_wnd_data * d;
1901     int id;
1902
1903     d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);
1904
1905     switch(HIWORD(wParam)) {
1906
1907     case WMNC_DIALOG_SWITCH_PANEL:
1908         id = LOWORD(wParam);
1909         if(id >= 0 && id <= (int) d->nc->n_types) {
1910             /* one of the tab buttons were pressed */
1911             if(d->current_panel == id) {
1912                 return TRUE; /* nothing to do */
1913             }
1914
1915             d->current_panel = id;
1916
1917             TabCtrl_SetCurSel(d->tab_wnd, id);
1918         }
1919
1920         if(d->nc->mode == KHUI_NC_MODE_EXPANDED) {
1921             nc_layout_new_cred_window(d);
1922             return TRUE;
1923         }
1924         /*else*/
1925         /* fallthrough */
1926
1927     case WMNC_DIALOG_EXPAND:
1928         /* we are switching from basic to advanced or vice versa */
1929
1930         if (d->nc->mode == KHUI_NC_MODE_EXPANDED) {
1931             d->nc->mode = KHUI_NC_MODE_MINI;
1932         } else {
1933             d->nc->mode = KHUI_NC_MODE_EXPANDED;
1934         }
1935
1936         /* if we are switching to the advanced mode, we clear any
1937            notifications because we now have a credential text area
1938            for that. */
1939         if (d->nc->mode == KHUI_NC_MODE_EXPANDED)
1940             nc_notify_clear(d);
1941
1942         nc_layout_main_panel(d);
1943
1944         nc_layout_new_cred_window(d);
1945
1946         break;
1947
1948     case WMNC_DIALOG_SETUP:
1949
1950         if(d->nc->n_types > 0) {
1951             khm_size i;
1952             for(i=0; i < d->nc->n_types;i++) {
1953
1954                 if (d->nc->types[i]->dlg_proc == NULL) {
1955                     d->nc->types[i]->hwnd_panel = NULL;
1956                 } else {
1957                     /* Create the dialog panel */
1958                     d->nc->types[i]->hwnd_panel = 
1959                         CreateDialogParam(d->nc->types[i]->h_module,
1960                                           d->nc->types[i]->dlg_template,
1961                                           d->nc->hwnd,
1962                                           d->nc->types[i]->dlg_proc,
1963                                           (LPARAM) d->nc);
1964
1965 #ifdef DEBUG
1966                     assert(d->nc->types[i]->hwnd_panel);
1967 #endif
1968                 }
1969             }
1970         }
1971
1972         break;
1973
1974     case WMNC_DIALOG_ACTIVATE:
1975         {
1976             wchar_t wname[KCDB_MAXCCH_NAME];
1977             TCITEM tabitem;
1978             khm_int32 t;
1979
1980             /* About to activate the window. We should add all the
1981                panels to the tab control.  */
1982
1983 #ifdef DEBUG
1984             assert(d->tab_wnd != NULL);
1985 #endif
1986
1987             ZeroMemory(&tabitem, sizeof(tabitem));
1988
1989             tabitem.mask = TCIF_PARAM | TCIF_TEXT;
1990
1991             LoadString(khm_hInstance, IDS_NC_IDENTITY, 
1992                        wname, ARRAYLENGTH(wname));
1993
1994             tabitem.pszText = wname;
1995             tabitem.lParam = 0; /* ordinal */
1996
1997             TabCtrl_InsertItem(d->tab_wnd, 0, &tabitem);
1998
1999             khui_cw_lock_nc(d->nc);
2000
2001             if(d->nc->n_types > 0) {
2002                 khm_size i;
2003
2004                 /* We should sort the tabs first.  See
2005                    nc_tab_sort_func() for sort criteria. */
2006                 qsort(d->nc->types, 
2007                       d->nc->n_types, 
2008                       sizeof(*(d->nc->types)), 
2009                       nc_tab_sort_func);
2010
2011                 for(i=0; i < d->nc->n_types;i++) {
2012
2013                     d->nc->types[i]->ordinal = i + 1;
2014
2015                     if(d->nc->types[i]->name)
2016                         tabitem.pszText = d->nc->types[i]->name;
2017                     else {
2018                         khm_size cbsize;
2019
2020                         cbsize = sizeof(wname);
2021
2022                         if(KHM_FAILED
2023                            (kcdb_credtype_describe
2024                             (d->nc->types[i]->type, 
2025                              wname, 
2026                              &cbsize, 
2027                              KCDB_TS_SHORT))) {
2028
2029 #ifdef DEBUG
2030                             assert(FALSE);
2031 #endif
2032                             wname[0] = L'\0';
2033
2034                         }
2035
2036                         tabitem.pszText = wname;
2037
2038                     }
2039
2040                     tabitem.lParam = d->nc->types[i]->ordinal;
2041
2042                     TabCtrl_InsertItem(d->tab_wnd, d->nc->types[i]->ordinal,
2043                                        &tabitem);
2044                 }
2045             }
2046
2047             khui_cw_unlock_nc(d->nc);
2048
2049             nc_update_credtext(d);
2050
2051             TabCtrl_SetCurSel(d->tab_wnd, 0); /* the first selected
2052                                                  tab is the main
2053                                                  panel. */
2054
2055             /* bring the window to the top, if necessary */
2056             if (KHM_SUCCEEDED(khc_read_int32(NULL,
2057                                              L"CredWindow\\Windows\\NewCred\\ForceToTop",
2058                                              &t)) &&
2059
2060                 t != 0) {
2061                 /* it used to be that the above condition also called
2062                    !khm_is_dialog_active() to find out whether there
2063                    was a dialog active.  If there was, we wouldn't try
2064                    to bring the new cred window to the foreground. But
2065                    that was not the behavior we want. */
2066
2067                 /* if the main window is not visible, then the SetWindowPos()
2068                    call is sufficient to bring the new creds window to the
2069                    top.  However, if the main window is visible but not
2070                    active, the main window needs to be activated before a
2071                    child window can be activated. */
2072                 khm_activate_main_window();
2073
2074                 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
2075                              (SWP_NOMOVE | SWP_NOSIZE));
2076             }
2077
2078             ShowWindow(hwnd, SW_SHOWNOACTIVATE);
2079
2080             /* we don't enable animations until a specific timeout
2081                elapses after showing the window.  We don't need to
2082                animate any size changes if the user has barely had a
2083                chance to notice the original size. This prevents the
2084                new cred window from appearing in an animated state. */
2085             SetTimer(hwnd, NC_TIMER_ENABLEANIMATE, ENABLEANIMATE_TIMEOUT, NULL);
2086
2087             SetFocus(hwnd);
2088
2089             if (d->nc->n_identities == 0)
2090                 break;
2091             /* else */
2092             /*   fallthrough */
2093         }
2094
2095     case WMNC_IDENTITY_CHANGE:
2096         {
2097             BOOL okEnable = FALSE;
2098
2099             nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY,
2100                             MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), (LPARAM) d->nc,
2101                             TRUE);
2102
2103             if (d->nc->subtype == KMSG_CRED_NEW_CREDS &&
2104                 d->nc->n_identities > 0 &&
2105                 d->nc->identities[0]) {
2106                 khm_int32 f = 0;
2107
2108                 kcdb_identity_get_flags(d->nc->identities[0], &f);
2109
2110                 if (!(f & KCDB_IDENT_FLAG_DEFAULT)) {
2111                     d->nc->set_default = FALSE;
2112                 }
2113             }
2114
2115             nc_update_credtext(d);
2116
2117         }
2118         break;
2119
2120     case WMNC_TYPE_STATE:
2121         /* fallthrough */
2122     case WMNC_UPDATE_CREDTEXT:
2123         nc_update_credtext(d);
2124         break;
2125
2126     case WMNC_CLEAR_PROMPTS:
2127         {
2128             khm_size i;
2129
2130             khui_cw_lock_nc(d->nc);
2131
2132             if(d->hwnd_banner != NULL) {
2133                 DestroyWindow(d->hwnd_banner);
2134                 d->hwnd_banner = NULL;
2135             }
2136
2137             if(d->hwnd_name != NULL) {
2138                 DestroyWindow(d->hwnd_name);
2139                 d->hwnd_name = NULL;
2140             }
2141
2142             for(i=0;i<d->nc->n_prompts;i++) {
2143                 if(!(d->nc->prompts[i]->flags & 
2144                      KHUI_NCPROMPT_FLAG_STOCK)) {
2145                     if(d->nc->prompts[i]->hwnd_static != NULL)
2146                         DestroyWindow(d->nc->prompts[i]->hwnd_static);
2147
2148                     if(d->nc->prompts[i]->hwnd_edit != NULL)
2149                         DestroyWindow(d->nc->prompts[i]->hwnd_edit);
2150                 }
2151
2152                 d->nc->prompts[i]->hwnd_static = NULL;
2153                 d->nc->prompts[i]->hwnd_edit = NULL;
2154             }
2155
2156             khui_cw_unlock_nc(d->nc);
2157
2158             SetRectEmpty(&d->r_custprompt);
2159
2160             nc_layout_main_panel(d);
2161
2162             nc_layout_new_cred_window(d);
2163         }
2164         break;
2165
2166     case WMNC_SET_PROMPTS:
2167         {
2168             khm_size i;
2169             int  y;
2170             HWND hw, hw_prev;
2171             HFONT hf, hfold;
2172             HDC hdc;
2173             BOOL use_large_lables = FALSE;
2174
2175             /* we assume that WMNC_CLEAR_PROMPTS has already been
2176                received */
2177
2178 #ifdef DEBUG
2179             assert(IsRectEmpty(&d->r_custprompt));
2180 #endif
2181
2182             khui_cw_lock_nc(d->nc);
2183
2184 #if 0
2185             /* special case, we have one prompt and it is a password
2186                prompt.  very common */
2187             if(d->nc->n_prompts == 1 && 
2188                d->nc->prompts[0]->type == KHUI_NCPROMPT_TYPE_PASSWORD) {
2189
2190                 hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD);
2191                 EnableWindow(hw, TRUE);
2192
2193                 d->nc->prompts[0]->flags |= KHUI_NCPROMPT_FLAG_STOCK;
2194                 d->nc->prompts[0]->hwnd_edit = hw;
2195                 d->nc->prompts[0]->hwnd_static = NULL; /* don't care */
2196
2197                 khui_cw_unlock_nc(d->nc);
2198                 break;
2199             }
2200 #endif
2201             /* for everything else */
2202
2203             y = d->r_idspec.bottom;
2204
2205             d->r_custprompt.left = d->r_area.left;
2206             d->r_custprompt.right = d->r_area.right;
2207             d->r_custprompt.top = y;
2208
2209             hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0);
2210
2211             if (d->nc->pname != NULL) {
2212                 hw =
2213                     CreateWindowEx
2214                     (0,
2215                      L"STATIC",
2216                      d->nc->pname,
2217                      SS_SUNKEN | WS_CHILD,
2218                      d->r_area.left, y,
2219                      d->r_row.right, 
2220                      d->r_n_label.bottom - d->r_n_label.top,
2221                      d->dlg_main,
2222                      NULL,
2223                      khm_hInstance,
2224                      NULL);
2225
2226 #ifdef DEBUG
2227                 assert(hw);
2228 #endif
2229                 d->hwnd_name = hw;
2230                 SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM) TRUE);
2231                 ShowWindow(hw, SW_SHOW);
2232
2233                 y += d->r_n_label.bottom - d->r_n_label.top;
2234             }
2235
2236             if (d->nc->banner != NULL) {
2237                 hw = 
2238                     CreateWindowEx
2239                     (0,
2240                      L"STATIC",
2241                      d->nc->banner,
2242                      WS_CHILD,
2243                      d->r_area.left, y,
2244                      d->r_row.right, d->r_row.bottom,
2245                      d->dlg_main,
2246                      NULL,
2247                      khm_hInstance,
2248                      NULL);
2249 #ifdef DEBUG
2250                 assert(hw);
2251 #endif
2252                 d->hwnd_banner = hw;
2253                 SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM)TRUE);
2254                 ShowWindow(hw, SW_SHOW);
2255                 y += d->r_row.bottom;
2256             }
2257
2258             hw_prev = d->hwnd_last_idspec;
2259
2260             hdc = GetWindowDC(d->dlg_main);
2261             hfold = SelectObject(hdc,hf);
2262
2263             /* first do a trial run and see if we should use the
2264                larger text labels or not.  This is so that all the
2265                labels and input controls align properly. */
2266             for (i=0; i < d->nc->n_prompts; i++) {
2267                 if (d->nc->prompts[i]->prompt != NULL) {
2268                     SIZE s;
2269
2270                     GetTextExtentPoint32(hdc, 
2271                                          d->nc->prompts[i]->prompt, 
2272                                          (int) wcslen(d->nc->prompts[i]->prompt),
2273                                          &s);
2274
2275                     if(s.cx >= d->r_n_label.right - d->r_n_label.left) {
2276                         use_large_lables = TRUE;
2277                         break;
2278                     }
2279                 }
2280             }
2281
2282             for(i=0; i<d->nc->n_prompts; i++) {
2283                 RECT pr, er;
2284                 SIZE s;
2285                 int dy;
2286
2287                 if(d->nc->prompts[i]->prompt != NULL) {
2288                     GetTextExtentPoint32(hdc, 
2289                                          d->nc->prompts[i]->prompt, 
2290                                          (int) wcslen(d->nc->prompts[i]->prompt),
2291                                          &s);
2292                     if(s.cx < d->r_n_label.right - d->r_n_label.left &&
2293                        !use_large_lables) {
2294                         CopyRect(&pr, &d->r_n_label);
2295                         CopyRect(&er, &d->r_n_input);
2296                         dy = d->r_row.bottom;
2297                     } else if(s.cx <
2298                               d->r_e_label.right - d->r_e_label.left) {
2299                         CopyRect(&pr, &d->r_e_label);
2300                         CopyRect(&er, &d->r_e_input);
2301                         dy = d->r_row.bottom;
2302                     } else {
2303                         /* oops. the prompt doesn't fit in our
2304                            controls.  we need to use up two lines */
2305                         pr.left = 0;
2306                         pr.right = d->r_row.right;
2307                         pr.top = 0;
2308                         pr.bottom = d->r_n_label.bottom - 
2309                             d->r_n_label.top;
2310                         CopyRect(&er, &d->r_n_input);
2311                         OffsetRect(&er, 0, pr.bottom);
2312                         dy = er.bottom + (d->r_row.bottom - 
2313                                           d->r_n_input.bottom);
2314                     }
2315                 } else {
2316                     SetRectEmpty(&pr);
2317                     CopyRect(&er, &d->r_n_input);
2318                     dy = d->r_row.bottom;
2319                 }
2320
2321                 if(IsRectEmpty(&pr)) {
2322                     d->nc->prompts[i]->hwnd_static = NULL;
2323                 } else {
2324                     OffsetRect(&pr, d->r_area.left, y);
2325
2326                     hw = CreateWindowEx
2327                         (0,
2328                          L"STATIC",
2329                          d->nc->prompts[i]->prompt,
2330                          WS_CHILD,
2331                          pr.left, pr.top,
2332                          pr.right - pr.left, pr.bottom - pr.top,
2333                          d->dlg_main,
2334                          NULL,
2335                          khm_hInstance,
2336                          NULL);
2337 #ifdef DEBUG
2338                     assert(hw);
2339 #endif
2340
2341                     SendMessage(hw, WM_SETFONT, 
2342                                 (WPARAM) hf, (LPARAM) TRUE);
2343
2344                     SetWindowPos(hw, hw_prev,
2345                                  0, 0, 0, 0,
2346                                  SWP_NOACTIVATE | SWP_NOMOVE |
2347                                  SWP_NOOWNERZORDER | SWP_NOSIZE |
2348                                  SWP_SHOWWINDOW);
2349
2350                     d->nc->prompts[i]->hwnd_static = hw;
2351                     hw_prev = hw;
2352                 }
2353
2354                 OffsetRect(&er, d->r_area.left, y);
2355
2356                 hw = CreateWindowEx
2357                     (0,
2358                      L"EDIT",
2359                      (d->nc->prompts[i]->def ? 
2360                       d->nc->prompts[i]->def : L""),
2361                      WS_CHILD | WS_TABSTOP |
2362                      WS_BORDER |
2363                      ((d->nc->prompts[i]->flags & 
2364                        KHUI_NCPROMPT_FLAG_HIDDEN)? ES_PASSWORD:0),
2365                      er.left, er.top,
2366                      er.right - er.left, er.bottom - er.top,
2367                      d->dlg_main,
2368                      NULL,
2369                      khm_hInstance,
2370                      NULL);
2371
2372 #ifdef DEBUG
2373                 assert(hw);
2374 #endif
2375
2376                 SendMessage(hw, WM_SETFONT, 
2377                             (WPARAM) hf, (LPARAM) TRUE);
2378
2379                 SetWindowPos(hw, hw_prev,
2380                              0, 0, 0, 0, 
2381                              SWP_NOACTIVATE | SWP_NOMOVE | 
2382                              SWP_NOOWNERZORDER | SWP_NOSIZE | 
2383                              SWP_SHOWWINDOW);
2384
2385                 SendMessage(hw, EM_SETLIMITTEXT,
2386                             KHUI_MAXCCH_PROMPT_VALUE -1,
2387                             0);
2388
2389                 d->nc->prompts[i]->hwnd_edit = hw;
2390
2391                 hw_prev = hw;
2392
2393                 y += dy;
2394             }
2395
2396             if (d->nc->n_prompts > 0 &&
2397                 d->nc->prompts[0]->hwnd_edit) {
2398
2399                 PostMessage(d->dlg_main, WM_NEXTDLGCTL,
2400                             (WPARAM) d->nc->prompts[0]->hwnd_edit,
2401                             MAKELPARAM(TRUE, 0));
2402
2403             }
2404
2405             SelectObject(hdc, hfold);
2406             ReleaseDC(d->dlg_main, hdc);
2407
2408             khui_cw_unlock_nc(d->nc);
2409
2410             d->r_custprompt.bottom = y;
2411
2412             if (d->r_custprompt.bottom == d->r_custprompt.top)
2413                 SetRectEmpty(&d->r_custprompt);
2414
2415             nc_layout_main_panel(d);
2416
2417             nc_layout_new_cred_window(d);
2418         }
2419         break;
2420
2421     case WMNC_DIALOG_PROCESS_COMPLETE:
2422         {
2423             khui_new_creds * nc;
2424
2425             nc = d->nc;
2426
2427             nc->response &= ~KHUI_NC_RESPONSE_PROCESSING;
2428
2429             if(nc->response & KHUI_NC_RESPONSE_NOEXIT) {
2430                 HWND hw;
2431
2432                 nc_enable_controls(d, TRUE);
2433
2434                 /* reset state */
2435                 nc->result = KHUI_NC_RESULT_CANCEL;
2436
2437                 hw = GetDlgItem(d->dlg_main, IDOK);
2438                 EnableWindow(hw, TRUE);
2439                 hw = GetDlgItem(d->dlg_main, IDCANCEL);
2440                 EnableWindow(hw, TRUE);
2441                 hw = GetDlgItem(d->dlg_main, IDC_NC_ADVANCED);
2442                 EnableWindow(hw, TRUE);
2443                 hw = GetDlgItem(d->dlg_bb, IDOK);
2444                 EnableWindow(hw, TRUE);
2445                 hw = GetDlgItem(d->dlg_bb, IDCANCEL);
2446                 EnableWindow(hw, TRUE);
2447
2448                 nc_clear_password_fields(d);
2449
2450                 return TRUE;
2451             }
2452
2453             DestroyWindow(hwnd);
2454
2455             kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc);
2456         }
2457         break;
2458
2459         /* MUST be called with SendMessage */
2460     case WMNC_ADD_CONTROL_ROW:
2461         {
2462             khui_control_row * row;
2463
2464             row = (khui_control_row *) lParam;
2465
2466 #ifdef DEBUG
2467             assert(row->label);
2468             assert(row->input);
2469 #endif
2470
2471             nc_add_control_row(d, row->label, row->input, row->size);
2472         }
2473         break;
2474
2475     case WMNC_UPDATE_LAYOUT:
2476         {
2477
2478             RECT r_client;
2479             khm_int32 animate;
2480             khm_int32 steps;
2481             khm_int32 timeout;
2482
2483             /* We are already adjusting the size of the window.  The
2484                next time the timer fires, it will notice if the target
2485                size has changed. */
2486             if (d->size_changing)
2487                 return TRUE;
2488
2489             GetClientRect(hwnd, &r_client);
2490
2491             if ((r_client.right - r_client.left ==
2492                  d->r_required.right - d->r_required.left) &&
2493                 (r_client.bottom - r_client.top ==
2494                  d->r_required.bottom - d->r_required.top)) {
2495
2496                 /* the window is already at the right size */
2497                 return TRUE;
2498
2499             }
2500
2501             if (!IsWindowVisible(hwnd)) {
2502                 /* The window is not visible yet.  There's no need to
2503                    animate anything. */
2504
2505                 animate = FALSE;
2506
2507             } else if (KHM_FAILED(khc_read_int32(NULL,
2508                                                  L"CredWindow\\Windows\\NewCred\\AnimateSizeChanges",
2509                                                  &animate))) {
2510 #ifdef DEBUG
2511                 assert(FALSE);
2512 #endif
2513                 animate = TRUE;
2514             }
2515
2516             /* if we aren't animating the window resize, then we just
2517                do it in one call. */
2518             if (!animate || !d->animation_enabled) {
2519                 RECT r_window;
2520
2521                 CopyRect(&r_window, &d->r_required);
2522                 AdjustWindowRectEx(&r_window, NC_WINDOW_STYLES, FALSE,
2523                                    NC_WINDOW_EX_STYLES);
2524
2525                 SetWindowPos(hwnd, NULL, 0, 0,
2526                              r_window.right - r_window.left,
2527                              r_window.bottom - r_window.top,
2528                              SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
2529                              SWP_NOZORDER);
2530
2531                 return TRUE;
2532             }
2533
2534             if (KHM_FAILED(khc_read_int32(NULL,
2535                                           L"CredWindow\\Windows\\NewCred\\AnimationSteps",
2536                                           &steps))) {
2537 #ifdef DEBUG
2538                 assert(FALSE);
2539 #endif
2540                 steps = NC_SZ_STEPS_DEF;
2541             } else {
2542
2543                 if (steps < NC_SZ_STEPS_MIN)
2544                     steps = NC_SZ_STEPS_MIN;
2545                 else if (steps > NC_SZ_STEPS_MAX)
2546                     steps = NC_SZ_STEPS_MAX;
2547
2548             }
2549
2550             if (KHM_FAILED(khc_read_int32(NULL,
2551                                           L"CredWindow\\Windows\\NewCred\\AnimationStepTimeout",
2552                                           &timeout))) {
2553 #ifdef DEBUG
2554                 assert(FALSE);
2555 #endif
2556                 timeout = NC_SZ_TIMEOUT_DEF;
2557             } else {
2558
2559                 if (timeout < NC_SZ_TIMEOUT_MIN)
2560                     timeout = NC_SZ_TIMEOUT_MIN;
2561                 else if (timeout > NC_SZ_TIMEOUT_MAX)
2562                     timeout = NC_SZ_TIMEOUT_MAX;
2563
2564             }
2565
2566             CopyRect(&d->sz_ch_source, &r_client);
2567             OffsetRect(&d->sz_ch_source, -d->sz_ch_source.left, -d->sz_ch_source.top);
2568             CopyRect(&d->sz_ch_target, &d->r_required);
2569             OffsetRect(&d->sz_ch_target, -d->sz_ch_target.left, -d->sz_ch_target.top);
2570             d->sz_ch_increment = 0;
2571             d->sz_ch_max = steps;
2572             d->sz_ch_timeout = timeout;
2573             d->size_changing = TRUE;
2574
2575             SetTimer(hwnd, NC_TIMER_SIZER, timeout, NULL);
2576         }
2577         break;
2578     } /* switch(HIWORD(wParam)) */
2579
2580     return TRUE;
2581 }
2582
2583 static LRESULT nc_handle_wm_timer(HWND hwnd,
2584                                   UINT uMsg,
2585                                   WPARAM wParam,
2586                                   LPARAM lParam) {
2587     khui_nc_wnd_data * d;
2588
2589     d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);
2590
2591     if (wParam == NC_TIMER_SIZER) {
2592
2593         RECT r_now;
2594
2595         /* are we done with this sizing operation? */
2596         if (!d->size_changing ||
2597             d->sz_ch_increment >= d->sz_ch_max) {
2598
2599             d->size_changing = FALSE;
2600             KillTimer(hwnd, NC_TIMER_SIZER);
2601             return 0;
2602         }
2603
2604         /* have the requirements changed while we were processing the
2605            sizing operation? */
2606         if ((d->r_required.right - d->r_required.left !=
2607              d->sz_ch_target.right)
2608
2609             ||
2610
2611             (d->r_required.bottom - d->r_required.top !=
2612              d->sz_ch_target.bottom)) {
2613
2614             /* the target size has changed.  we need to restart the
2615                sizing operation. */
2616
2617             RECT r_client;
2618
2619             GetClientRect(hwnd, &r_client);
2620
2621             CopyRect(&d->sz_ch_source, &r_client);
2622             OffsetRect(&d->sz_ch_source, -d->sz_ch_source.left, -d->sz_ch_source.top);
2623             CopyRect(&d->sz_ch_target, &d->r_required);
2624             OffsetRect(&d->sz_ch_target, -d->sz_ch_target.left, -d->sz_ch_target.top);
2625             d->sz_ch_increment = 0;
2626
2627             /* leave the other fields alone */
2628
2629 #ifdef DEBUG
2630             assert(d->sz_ch_max >= NC_SZ_STEPS_MIN);
2631             assert(d->sz_ch_max <= NC_SZ_STEPS_MAX);
2632             assert(d->sz_ch_timeout >= NC_SZ_TIMEOUT_MIN);
2633             assert(d->sz_ch_timeout <= NC_SZ_TIMEOUT_MAX);
2634             assert(d->size_changing);
2635 #endif
2636         }
2637
2638         /* we are going to do the next increment */
2639         d->sz_ch_increment ++;
2640
2641         /* now, figure out the size of the client area for this
2642            step */
2643
2644         r_now.left = 0;
2645         r_now.top = 0;
2646
2647 #define PROPORTION(v1, v2, i, s) (((v1) * ((s) - (i)) + (v2) * (i)) / (s))
2648
2649         r_now.right = PROPORTION(d->sz_ch_source.right, d->sz_ch_target.right,
2650                                  d->sz_ch_increment, d->sz_ch_max);
2651
2652         r_now.bottom = PROPORTION(d->sz_ch_source.bottom, d->sz_ch_target.bottom,
2653                                   d->sz_ch_increment, d->sz_ch_max);
2654
2655 #undef  PROPORTION
2656
2657 #ifdef DEBUG
2658         {
2659             long dx = (r_now.right - d->sz_ch_target.right) *
2660                 (d->sz_ch_source.right - d->sz_ch_target.right);
2661
2662             long dy = (r_now.bottom - d->sz_ch_target.bottom) *
2663                 (d->sz_ch_source.bottom - d->sz_ch_target.bottom);
2664
2665             if (dx < 0 || dy < 0) {
2666                 KillTimer(hwnd, NC_TIMER_SIZER);
2667                 assert(dx >= 0);
2668                 assert(dy >= 0);
2669                 SetTimer(hwnd, NC_TIMER_SIZER, d->sz_ch_timeout, NULL);
2670             }
2671         }
2672 #endif
2673
2674         AdjustWindowRectEx(&r_now, NC_WINDOW_STYLES, FALSE,
2675                            NC_WINDOW_EX_STYLES);
2676
2677         SetWindowPos(hwnd, NULL,
2678                      0, 0,
2679                      r_now.right - r_now.left,
2680                      r_now.bottom - r_now.top,
2681                      SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
2682                      SWP_NOZORDER);
2683
2684         /* and now we wait for the next timer message */
2685
2686         return 0;
2687     } else if (wParam == NC_TIMER_ENABLEANIMATE) {
2688
2689         d->animation_enabled = TRUE;
2690         KillTimer(hwnd, NC_TIMER_ENABLEANIMATE);
2691     }
2692
2693     return 0;
2694 }
2695
2696 static LRESULT nc_handle_wm_notify(HWND hwnd,
2697                                    UINT uMsg,
2698                                    WPARAM wParam,
2699                                    LPARAM lParam) {
2700
2701     LPNMHDR nmhdr;
2702     khui_nc_wnd_data * d;
2703
2704     d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);
2705     nmhdr = (LPNMHDR) lParam;
2706
2707     if (nmhdr->code == TCN_SELCHANGE) {
2708         /* the current tab has changed. */
2709         int idx;
2710         TCITEM tcitem;
2711
2712         idx = TabCtrl_GetCurSel(d->tab_wnd);
2713         ZeroMemory(&tcitem, sizeof(tcitem));
2714
2715         tcitem.mask = TCIF_PARAM;
2716         TabCtrl_GetItem(d->tab_wnd, idx, &tcitem);
2717
2718         d->current_panel = (int) tcitem.lParam;
2719
2720         nc_layout_new_cred_window(d);
2721
2722         return TRUE;
2723     }
2724
2725     return FALSE;
2726 }
2727
2728 static LRESULT nc_handle_wm_help(HWND hwnd,
2729                                  UINT uMsg,
2730                                  WPARAM wParam,
2731                                  LPARAM lParam) {
2732     static DWORD ctxids[] = {
2733         NC_TS_CTRL_ID_MIN, IDH_NC_TABMAIN,
2734         NC_TS_CTRL_ID_MIN + 1, IDH_NC_TABBUTTON,
2735         NC_TS_CTRL_ID_MIN + 2, IDH_NC_TABBUTTON,
2736         NC_TS_CTRL_ID_MIN + 3, IDH_NC_TABBUTTON,
2737         NC_TS_CTRL_ID_MIN + 4, IDH_NC_TABBUTTON,
2738         NC_TS_CTRL_ID_MIN + 5, IDH_NC_TABBUTTON,
2739         NC_TS_CTRL_ID_MIN + 6, IDH_NC_TABBUTTON,
2740         NC_TS_CTRL_ID_MIN + 7, IDH_NC_TABBUTTON,
2741         IDOK, IDH_NC_OK,
2742         IDCANCEL, IDH_NC_CANCEL,
2743         IDC_NC_HELP, IDH_NC_HELP,
2744         IDC_NC_ADVANCED, IDH_NC_ADVANCED,
2745         IDC_NC_CREDTEXT, IDH_NC_CREDWND,
2746         0
2747     };
2748
2749     HELPINFO * hlp;
2750     HWND hw = NULL;
2751     HWND hw_ctrl;
2752     khui_nc_wnd_data * d;
2753
2754     d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);
2755
2756     hlp = (HELPINFO *) lParam;
2757
2758     if (d->nc->subtype != KMSG_CRED_NEW_CREDS &&
2759         d->nc->subtype != KMSG_CRED_PASSWORD)
2760         return TRUE;
2761
2762     if (hlp->iContextType != HELPINFO_WINDOW)
2763         return TRUE;
2764
2765     if (hlp->hItemHandle != NULL &&
2766         hlp->hItemHandle != hwnd) {
2767         DWORD id;
2768         int i;
2769
2770         hw_ctrl =hlp->hItemHandle;
2771
2772         id = GetWindowLong(hw_ctrl, GWL_ID);
2773         for (i=0; ctxids[i] != 0; i += 2)
2774             if (ctxids[i] == id)
2775                 break;
2776
2777         if (ctxids[i] != 0)
2778             hw = khm_html_help(hw_ctrl,
2779                                ((d->nc->subtype == KMSG_CRED_NEW_CREDS)?
2780                                 L"::popups_newcreds.txt":
2781                                 L"::popups_password.txt"),
2782                                HH_TP_HELP_WM_HELP,
2783                                (DWORD_PTR) ctxids);
2784     }
2785
2786     if (hw == NULL) {
2787         khm_html_help(hwnd, NULL, HH_HELP_CONTEXT,
2788                       ((d->nc->subtype == KMSG_CRED_NEW_CREDS)?
2789                        IDH_ACTION_NEW_ID: IDH_ACTION_PASSWD_ID));
2790     }
2791
2792     return TRUE;
2793 }
2794
2795 static LRESULT CALLBACK nc_window_proc(HWND hwnd,
2796                                        UINT uMsg,
2797                                        WPARAM wParam,
2798                                        LPARAM lParam)
2799 {
2800     switch(uMsg) {
2801     case WM_CREATE:
2802         return nc_handle_wm_create(hwnd, uMsg, wParam, lParam);
2803
2804     case WM_DESTROY:
2805         return nc_handle_wm_destroy(hwnd, uMsg, wParam, lParam);
2806
2807     case WM_COMMAND:
2808         return nc_handle_wm_command(hwnd, uMsg, wParam, lParam);
2809
2810     case WM_NOTIFY:
2811         return nc_handle_wm_notify(hwnd, uMsg, wParam, lParam);
2812
2813     case WM_MOVE:
2814     case WM_MOVING:
2815         return nc_handle_wm_moving(hwnd, uMsg, wParam, lParam);
2816
2817     case WM_TIMER:
2818         return nc_handle_wm_timer(hwnd, uMsg, wParam, lParam);
2819
2820     case WM_HELP:
2821         return nc_handle_wm_help(hwnd, uMsg, wParam, lParam);
2822
2823     case KHUI_WM_NC_NOTIFY:
2824         return nc_handle_wm_nc_notify(hwnd, uMsg, wParam, lParam);
2825     }
2826
2827     /* Note that this is technically a dialog box */
2828     return DefDlgProc(hwnd, uMsg, wParam, lParam);
2829 }
2830
2831 void khm_register_newcredwnd_class(void)
2832 {
2833     WNDCLASSEX wcx;
2834
2835     wcx.cbSize = sizeof(wcx);
2836     wcx.style = CS_DBLCLKS | CS_OWNDC;
2837     wcx.lpfnWndProc = nc_window_proc;
2838     wcx.cbClsExtra = 0;
2839     wcx.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR);
2840     wcx.hInstance = khm_hInstance;
2841     wcx.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP));
2842     wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
2843     wcx.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
2844     wcx.lpszMenuName = NULL;
2845     wcx.lpszClassName = KHUI_NEWCREDWND_CLASS;
2846     wcx.hIconSm = NULL;
2847
2848     khui_newcredwnd_cls = RegisterClassEx(&wcx);
2849 }
2850
2851 void khm_unregister_newcredwnd_class(void)
2852 {
2853     UnregisterClass((LPWSTR) khui_newcredwnd_cls, khm_hInstance);
2854 }
2855
2856 HWND khm_create_newcredwnd(HWND parent, khui_new_creds * c)
2857 {
2858     wchar_t wtitle[256];
2859     HWND hwnd;
2860
2861     if (c->window_title == NULL) {
2862         if (c->subtype == KMSG_CRED_PASSWORD)
2863             LoadString(khm_hInstance, 
2864                        IDS_WT_PASSWORD,
2865                        wtitle,
2866                        ARRAYLENGTH(wtitle));
2867         else
2868             LoadString(khm_hInstance, 
2869                        IDS_WT_NEW_CREDS,
2870                        wtitle,
2871                        ARRAYLENGTH(wtitle));
2872     }
2873
2874     hwnd = CreateWindowEx(NC_WINDOW_EX_STYLES,
2875                           MAKEINTATOM(khui_newcredwnd_cls),
2876                           ((c->window_title)?c->window_title: wtitle),
2877                           NC_WINDOW_STYLES,
2878                           0,0,400,400,    /* bogus values.  the window
2879                                              is going to resize and
2880                                              reposition itself
2881                                              anyway */
2882                           parent,
2883                           NULL,
2884                           khm_hInstance,
2885                           (LPVOID) c);
2886
2887 #ifdef DEBUG
2888     assert(hwnd != NULL);
2889 #endif
2890
2891     /* note that the window is not visible yet.  That's because, at
2892        this point we don't know what the panels are */
2893
2894     return hwnd;
2895 }
2896
2897 void khm_prep_newcredwnd(HWND hwnd)
2898 {
2899     SendMessage(hwnd, KHUI_WM_NC_NOTIFY, 
2900                 MAKEWPARAM(0, WMNC_DIALOG_SETUP), 0);
2901 }
2902
2903 void khm_show_newcredwnd(HWND hwnd)
2904 {
2905     /* add all the panels in and prep UI */
2906     PostMessage(hwnd, KHUI_WM_NC_NOTIFY, 
2907                 MAKEWPARAM(0, WMNC_DIALOG_ACTIVATE), 0);
2908 }