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