Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / afssvrmgr / display.cpp
blobfa4ba2b0342d00374f8ead25935ae439e51adb35
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
10 #include <winsock2.h>
11 #include <ws2tcpip.h>
13 extern "C" {
14 #include <afs/param.h>
15 #include <afs/stds.h>
18 #include "svrmgr.h"
19 #include "display.h"
20 #include "dispguts.h"
21 #include "svr_window.h"
22 #include "svr_col.h"
23 #include "svc_col.h"
24 #include "agg_col.h"
25 #include "set_col.h"
26 #include "propcache.h"
30 * DEFINITIONS ________________________________________________________________
34 #define cREALLOC_DISPLAYQUEUE 128
36 #define cUPDATE_THREADS_MAX 4
40 * VARIABLES __________________________________________________________________
44 static size_t cDisplayQueueActive = 0;
45 static size_t cDisplayQueue = 0;
46 static size_t cUpdateThreadsActive = 0;
47 static DISPLAYREQUEST *aDisplayQueue = NULL;
48 static CRITICAL_SECTION *pcsDisplayQueue = NULL;
50 static DISPLAYREQUEST drActiveSERVERS;
51 static DISPLAYREQUEST drActiveSERVICES;
52 static DISPLAYREQUEST drActiveAGGREGATES;
53 static DISPLAYREQUEST drActiveFILESETS;
54 static DISPLAYREQUEST drActiveSERVERWINDOW;
56 static struct {
57 HWND hWnd;
58 WORD actOnDone;
59 LPIDENT lpiSelectOnDone;
60 } *aWindowActOnDone = NULL;
61 static size_t cWindowActOnDone = 0;
62 static CRITICAL_SECTION *pcsWindowActOnDone = NULL;
66 * PROTOTYPES _________________________________________________________________
70 DWORD WINAPI DisplayQueue_ThreadProc (PVOID lp);
72 BOOL DisplayQueueFilter (size_t idqVictim, size_t idqKiller);
76 * ROUTINES ___________________________________________________________________
80 BOOL CALLBACK GetItemText (HWND hList, LPFLN_GETITEMTEXT_PARAMS pfln, UINT_PTR dwCookie)
82 LPVIEWINFO lpvi = (LPVIEWINFO)dwCookie;
83 LPIDENT lpi = (LPIDENT)(pfln->item.lParam);
84 LPTSTR psz = NULL;
86 if (pfln->item.icol < (int)lpvi->nColsShown)
88 size_t iCol = lpvi->aColumns[ pfln->item.icol ];
90 BOOL fShowServerName = !Server_GetServerForChild (GetParent(hList));
92 if (lpi != NULL)
94 DISPLAYTARGET dt = dtSERVERS;
95 if (lpvi == &gr.viewSet)
96 dt = dtFILESETS;
97 else if (lpvi == &gr.viewSvc)
98 dt = dtSERVICES;
99 else if ((lpvi == &gr.viewAgg) || (lpvi == &gr.viewAggMove) || (lpvi == &gr.viewAggCreate) || (lpvi == &gr.viewAggRestore))
100 dt = dtAGGREGATES;
101 else if (lpvi == &gr.viewRep)
102 dt = dtREPLICAS;
104 switch (dt)
106 case dtSERVERS:
107 if (lpi->fIsServer())
108 psz = Server_GetColumnText (lpi, (SERVERCOLUMN)iCol);
109 break;
111 case dtSERVICES:
112 if (lpi->fIsService())
113 psz = Services_GetColumnText (lpi, (SERVICECOLUMN)iCol, fShowServerName);
114 break;
116 case dtAGGREGATES:
117 if (lpi->fIsAggregate())
118 psz = Aggregates_GetColumnText (lpi, (AGGREGATECOLUMN)iCol, fShowServerName);
119 break;
121 case dtFILESETS:
122 if (lpi->fIsFileset())
123 psz = Filesets_GetColumnText (lpi, (FILESETCOLUMN)iCol, fShowServerName);
124 else if (lpi->fIsAggregate() && (pfln->item.icol == setcolNAME))
125 psz = Aggregates_GetColumnText (lpi, aggcolNAME, FALSE);
126 else if (lpi->fIsServer() && (pfln->item.icol == setcolNAME))
127 psz = Server_GetColumnText (lpi, svrcolNAME);
128 break;
130 case dtREPLICAS:
131 if (lpi->fIsFileset())
132 psz = Replicas_GetColumnText (lpi, (REPLICACOLUMN)iCol);
133 break;
138 lstrcpy (pfln->item.pszText, (psz) ? psz : TEXT(""));
139 return TRUE;
143 void Display_AddActOnDone (HWND hWnd, WORD wAct, LPIDENT lpiSelectOnDone)
145 if (pcsWindowActOnDone == NULL)
147 pcsWindowActOnDone = New (CRITICAL_SECTION);
148 InitializeCriticalSection (pcsWindowActOnDone);
150 EnterCriticalSection (pcsWindowActOnDone);
152 size_t ii;
153 for (ii = 0; ii < cWindowActOnDone; ++ii)
155 if (aWindowActOnDone[ ii ].hWnd == hWnd)
156 break;
158 if (ii == cWindowActOnDone)
160 for (ii = 0; ii < cWindowActOnDone; ++ii)
162 if (aWindowActOnDone[ ii ].hWnd == 0)
163 break;
166 if (ii == cWindowActOnDone)
168 (void)REALLOC( aWindowActOnDone, cWindowActOnDone, 1+ii, 1 );
170 if (ii < cWindowActOnDone)
172 aWindowActOnDone[ ii ].hWnd = hWnd;
173 aWindowActOnDone[ ii ].actOnDone |= wAct;
174 if (!aWindowActOnDone[ ii ].lpiSelectOnDone)
175 aWindowActOnDone[ ii ].lpiSelectOnDone = lpiSelectOnDone;
178 LeaveCriticalSection (pcsWindowActOnDone);
182 WORD Display_FreeActOnDone (HWND hWnd, LPIDENT *plpiSelectOnDone)
184 WORD wAct = 0;
186 if (pcsWindowActOnDone == NULL)
188 pcsWindowActOnDone = New (CRITICAL_SECTION);
189 InitializeCriticalSection (pcsWindowActOnDone);
191 EnterCriticalSection (pcsWindowActOnDone);
193 for (size_t ii = 0; ii < cWindowActOnDone; ++ii)
195 if (aWindowActOnDone[ ii ].hWnd == hWnd)
197 wAct = aWindowActOnDone[ ii ].actOnDone;
198 if (!(*plpiSelectOnDone))
199 *plpiSelectOnDone = aWindowActOnDone[ ii ].lpiSelectOnDone;
201 aWindowActOnDone[ ii ].actOnDone = 0;
202 aWindowActOnDone[ ii ].hWnd = 0;
203 aWindowActOnDone[ ii ].lpiSelectOnDone = 0;
204 break;
208 LeaveCriticalSection (pcsWindowActOnDone);
209 return wAct;
213 void UpdateDisplay (LPDISPLAYREQUEST pdr, BOOL fWait)
215 BOOL fRunBeforeReturning = FALSE;
217 if (!ASSERT( pdr && pdr->hChild ))
218 return;
219 if (pdr->lpiNotify && pdr->lpiNotify->fIsCell())
220 pdr->lpiNotify = NULL;
222 if (pcsDisplayQueue == NULL)
224 pcsDisplayQueue = New (CRITICAL_SECTION);
225 InitializeCriticalSection (pcsDisplayQueue);
226 memset (&drActiveSERVERS, 0x00, sizeof(DISPLAYREQUEST));
227 memset (&drActiveSERVICES, 0x00, sizeof(DISPLAYREQUEST));
228 memset (&drActiveAGGREGATES, 0x00, sizeof(DISPLAYREQUEST));
229 memset (&drActiveFILESETS, 0x00, sizeof(DISPLAYREQUEST));
230 memset (&drActiveSERVERWINDOW, 0x00, sizeof(DISPLAYREQUEST));
233 EnterCriticalSection (pcsDisplayQueue);
235 size_t idq;
236 for (idq = 0; idq < cDisplayQueue; ++idq)
238 if (!aDisplayQueue[idq].hChild)
239 break;
241 if (idq == cDisplayQueue)
243 (void)REALLOC (aDisplayQueue, cDisplayQueue, 1+idq, cREALLOC_DISPLAYQUEUE);
245 if (idq < cDisplayQueue)
247 memcpy (&aDisplayQueue[idq], pdr, sizeof(DISPLAYREQUEST));
249 // Filter the display queue--for instance, if there's a request
250 // to update all filesets, we don't need to file a request to
251 // update an individual fileset. Likewise, if we're about to
252 // file a request to update all filesets, nix all existing update-
253 // this-fileset and update-filesets-on-this-server requests.
255 for (size_t idqKiller = 0; idqKiller < cDisplayQueue; ++idqKiller)
257 if (DisplayQueueFilter (idq, idqKiller))
259 aDisplayQueue[idq].hChild = 0;
260 break;
264 // Hmmmm...even if there is no request in the queue which lets us
265 // kill this request, there may be a request actively being serviced
266 // *right now* which does so. Test for that case too.
268 if (aDisplayQueue[idq].hChild)
270 if (DisplayQueueFilter (idq, (size_t)-1))
271 aDisplayQueue[idq].hChild = 0;
274 // Did the new request make it through all those tests? If so,
275 // see if we can remove any other entries because of this one.
276 // Then initiate a thread to actually do the work if there isn't one.
278 if (aDisplayQueue[idq].hChild)
280 for (size_t idqVictim = 0; idqVictim < cDisplayQueue; ++idqVictim)
282 if (DisplayQueueFilter (idqVictim, idq))
284 InterlockedDecrementByWindow (aDisplayQueue[idqVictim].hChild);
285 aDisplayQueue[idqVictim].hChild = 0;
286 --cDisplayQueueActive;
290 if (aDisplayQueue[idq].hChild)
292 InterlockedIncrementByWindow (aDisplayQueue[ idq ].hChild);
294 if (fWait)
296 aDisplayQueue[idq].hChild = NULL; // we'll handle this one.
297 fRunBeforeReturning = TRUE; // (remember to do so)
299 else if ((++cDisplayQueueActive) >= 1)
301 if (cUpdateThreadsActive < cUPDATE_THREADS_MAX)
303 ++cUpdateThreadsActive;
304 StartThread (DisplayQueue_ThreadProc, 0);
311 LeaveCriticalSection (pcsDisplayQueue);
313 if (fRunBeforeReturning)
315 DisplayQueue_ThreadProc (pdr);
320 DWORD WINAPI DisplayQueue_ThreadProc (PVOID lp)
322 LPDISPLAYREQUEST pdr = (LPDISPLAYREQUEST)lp;
323 LPDISPLAYREQUEST pdrActive = NULL;
325 Main_StartWorking();
327 do {
328 DISPLAYREQUEST dr;
330 EnterCriticalSection (pcsDisplayQueue);
331 if (pdr)
333 memcpy (&dr, pdr, sizeof(DISPLAYREQUEST));
335 else
337 size_t idq;
338 for (idq = 0; idq < cDisplayQueue; ++idq)
340 if (aDisplayQueue[idq].hChild)
342 memcpy (&dr, &aDisplayQueue[idq], sizeof(DISPLAYREQUEST));
343 memset (&aDisplayQueue[idq], 0x00, sizeof(DISPLAYREQUEST));
344 --cDisplayQueueActive;
345 break;
348 if (idq == cDisplayQueue)
350 if (!pdr) // Are we losing a background thread?
351 --cUpdateThreadsActive;
352 LeaveCriticalSection (pcsDisplayQueue);
353 break;
357 switch (dr.dt)
359 case dtSERVERS: pdrActive = &drActiveSERVERS; break;
360 case dtSERVICES: pdrActive = &drActiveSERVICES; break;
361 case dtAGGREGATES: pdrActive = &drActiveAGGREGATES; break;
362 case dtFILESETS: pdrActive = &drActiveFILESETS; break;
363 case dtSERVERWINDOW: pdrActive = &drActiveSERVERWINDOW; break;
365 if (pdrActive)
366 memcpy (pdrActive, &dr, sizeof(DISPLAYREQUEST));
368 LeaveCriticalSection (pcsDisplayQueue);
370 AfsClass_Enter();
372 switch (dr.dt)
374 case dtCELL:
375 Display_Cell_Internal (&dr);
376 break;
378 case dtSERVERS:
379 Display_Servers_Internal (&dr);
380 break;
382 case dtSERVICES:
383 Display_Services_Internal (&dr);
384 break;
386 case dtAGGREGATES:
387 Display_Aggregates_Internal (&dr);
388 break;
390 case dtFILESETS:
391 Display_Filesets_Internal (&dr);
392 break;
394 case dtREPLICAS:
395 Display_Replicas_Internal (&dr);
396 break;
398 case dtSERVERWINDOW:
399 Display_ServerWindow_Internal (&dr);
400 break;
403 EnterCriticalSection (pcsDisplayQueue);
404 LONG dw = InterlockedDecrementByWindow (dr.hChild);
405 if (pdrActive)
406 memset (pdrActive, 0x00, sizeof(DISPLAYREQUEST));
407 LeaveCriticalSection (pcsDisplayQueue);
409 if (dw == 0)
411 WORD actOnDone = dr.actOnDone;
412 LPIDENT lpiSelectOnDone = dr.lpiToSelect;
413 if (dr.hList)
415 actOnDone |= Display_FreeActOnDone (dr.hList, &lpiSelectOnDone);
418 if ((actOnDone & ACT_ENDCHANGE) && dr.hList)
420 if (dr.fList)
421 FL_EndChange (dr.hList, (LPARAM)lpiSelectOnDone);
422 else // must be a combobox
423 CB_EndChange (dr.hList, (LPARAM)lpiSelectOnDone);
426 if ((actOnDone & ACT_UNCOVER) && dr.hList)
427 AfsAppLib_Uncover (dr.hList);
429 if (actOnDone & ACT_SELPREVIEW)
431 LPIDENT lpiOld = Server_GetServer (SERVERWINDOW_PREVIEWPANE);
432 LPIDENT lpiNew = (LPIDENT)FL_GetSelectedData (GetDlgItem (g.hMain, IDC_SERVERS));
433 if (lpiOld != lpiNew)
434 Server_SelectServer (SERVERWINDOW_PREVIEWPANE, lpiNew, TRUE);
437 else if (dr.hList)
439 Display_AddActOnDone (dr.hList, dr.actOnDone, dr.lpiToSelect);
442 AfsClass_Leave();
444 } while (!lp); // if given one task to do, stop; otherwise, loop forever
446 Main_StopWorking();
448 return 0;
452 BOOL DisplayQueueFilter (size_t idqVictim, size_t idqKiller)
454 if (idqVictim == idqKiller)
455 return FALSE;
457 LPDISPLAYREQUEST pdrKiller = (idqKiller == (size_t)-1) ? NULL : &aDisplayQueue[ idqKiller ];
458 LPDISPLAYREQUEST pdrVictim = &aDisplayQueue[ idqVictim ];
460 // if there's currently an operation in progress for this window,
461 // we may have just been asked to filter out a new request based on
462 // what's being done now. {idqKiller==-1} signifies this case.
464 if (pdrKiller == NULL) // was idqKiller==-1 etc?
466 switch (pdrVictim->dt)
468 case dtSERVERS:
469 pdrKiller = &drActiveSERVERS;
470 break;
472 case dtSERVICES:
473 pdrKiller = &drActiveSERVICES;
474 break;
476 case dtAGGREGATES:
477 pdrKiller = &drActiveAGGREGATES;
478 break;
480 case dtFILESETS:
481 pdrKiller = &drActiveFILESETS;
482 break;
484 case dtSERVERWINDOW:
485 pdrKiller = &drActiveSERVERWINDOW;
486 break;
489 if (!pdrKiller)
490 return FALSE;
493 if ( (pdrVictim->dt == pdrKiller->dt) &&
494 (pdrVictim->hChild == pdrKiller->hChild) )
496 // only some windows are subject to this filtering.
498 switch (pdrVictim->dt)
500 case dtCELL:
501 case dtREPLICAS:
502 return FALSE; // don't bother filtering these.
504 case dtSERVERWINDOW:
505 return TRUE; // update svr window twice? why?
508 // if the new request talks about displaying information for a different
509 // server, the user must have selected or deselected a server in the
510 // list. we'll keep the new request.
512 if (pdrKiller->lpiServer != pdrVictim->lpiServer)
513 return FALSE;
515 // if pdrKiller is told to update everything, then all other requests
516 // are unnecessary.
518 if (!pdrKiller->lpiNotify || pdrKiller->lpiNotify->fIsCell())
519 return TRUE;
521 // if pdrVictim is told to update everything, then we'll always bow to it.
523 if (!pdrVictim->lpiNotify || pdrVictim->lpiNotify->fIsCell())
524 return FALSE;
526 // kill any duplicate request to update a particular object.
528 if (pdrVictim->lpiNotify == pdrKiller->lpiNotify)
529 return TRUE;
531 // kill any request to update a service or aggregate or fileset,
532 // if updating the entire associated server.
534 if ( (pdrKiller->lpiNotify->fIsServer()) &&
535 (pdrVictim->lpiNotify->GetServer() == pdrKiller->lpiNotify) )
536 return TRUE;
538 // kill any request to update a fileset, if updating the entire
539 // associated aggregate.
541 if ( (pdrKiller->lpiNotify->fIsAggregate()) &&
542 (pdrVictim->lpiNotify->fIsFileset()) &&
543 (pdrVictim->lpiNotify->GetAggregate() == pdrKiller->lpiNotify) )
544 return TRUE;
547 // hmmm...guess we need this request after all.
549 return FALSE;
553 void UpdateDisplay_Cell (BOOL fWait)
555 DISPLAYREQUEST dr;
556 memset (&dr, 0x00, sizeof(dr));
557 dr.dt = dtCELL;
558 dr.hChild = GetDlgItem (g.hMain, IDC_CELL);
559 UpdateDisplay (&dr, fWait);
562 void UpdateDisplay_Servers (BOOL fWait, LPIDENT lpiNotify, ULONG status)
564 DISPLAYREQUEST dr;
565 memset (&dr, 0x00, sizeof(dr));
566 dr.dt = dtSERVERS;
567 dr.hChild = GetDlgItem (g.hMain, IDC_SERVERS);
568 dr.lpiNotify = lpiNotify;
569 dr.status = status;
570 dr.fList = TRUE;
571 UpdateDisplay (&dr, fWait);
574 void UpdateDisplay_Services (BOOL fWait, HWND hChild, LPIDENT lpiNotify, ULONG status)
576 DISPLAYREQUEST dr;
577 memset (&dr, 0x00, sizeof(dr));
578 dr.dt = dtSERVICES;
579 dr.hChild = hChild;
580 dr.lpiNotify = lpiNotify;
581 dr.status = status;
582 dr.fList = TRUE;
583 UpdateDisplay (&dr, fWait);
586 void UpdateDisplay_Aggregates (BOOL fWait, HWND hListOrCombo, LPIDENT lpiNotify, ULONG status, LPIDENT lpiServer, LPIDENT lpiToSelect, LPVIEWINFO lpvi)
588 DISPLAYREQUEST dr;
589 memset (&dr, 0x00, sizeof(dr));
590 dr.dt = dtAGGREGATES;
591 dr.hList = hListOrCombo;
592 dr.hChild = GetParent (hListOrCombo);
593 dr.lpiNotify = lpiNotify;
594 dr.status = status;
595 dr.lpiServer = (lpiServer == NULL) ? Server_GetServerForChild (dr.hChild) : lpiServer;
596 dr.lpiToSelect = lpiToSelect;
597 dr.lpvi = lpvi;
598 UpdateDisplay (&dr, fWait);
601 void UpdateDisplay_Filesets (BOOL fWait, HWND hListOrCombo, LPIDENT lpiNotify, ULONG status, LPIDENT lpiServer, LPIDENT lpiAggregate, LPIDENT lpiToSelect)
603 DISPLAYREQUEST dr;
604 memset (&dr, 0x00, sizeof(dr));
605 dr.dt = dtFILESETS;
606 dr.hList = hListOrCombo;
607 dr.hChild = GetParent (hListOrCombo);
608 dr.lpiNotify = lpiNotify;
609 dr.status = status;
610 dr.lpiServer = (lpiServer == NULL) ? Server_GetServerForChild (dr.hChild) : lpiServer;
611 dr.lpiAggregate = lpiAggregate;
612 dr.lpiToSelect = lpiToSelect;
613 UpdateDisplay (&dr, fWait);
616 void UpdateDisplay_Replicas (BOOL fWait, HWND hList, LPIDENT lpiRW, LPIDENT lpiRO)
618 DISPLAYREQUEST dr;
619 memset (&dr, 0x00, sizeof(dr));
620 dr.dt = dtREPLICAS;
621 dr.hChild = GetParent (hList);
622 dr.hList = hList;
623 dr.lpiNotify = lpiRW;
624 dr.lpiToSelect = lpiRO;
625 dr.fList = TRUE;
626 UpdateDisplay (&dr, fWait);
630 void UpdateDisplay_ServerWindow (BOOL fWait, LPIDENT lpiServer)
632 // First, if there is a dedicated server window out there, update it.
634 HWND hServer;
635 if ((hServer = PropCache_Search (pcSERVER, lpiServer)) != NULL)
637 DISPLAYREQUEST dr;
638 memset (&dr, 0x00, sizeof(dr));
639 dr.dt = dtSERVERWINDOW;
640 dr.hChild = hServer;
641 dr.lpiServer = lpiServer;
643 UpdateDisplay (&dr, fWait);
646 // Second, if the preview pane is visible and showing this server,
647 // update it too.
649 if (gr.fPreview)
651 LPIDENT lpiPreview = Server_GetServer (g.hMain);
652 if ((lpiPreview == NULL) || (lpiPreview == lpiServer))
654 DISPLAYREQUEST dr;
655 memset (&dr, 0x00, sizeof(dr));
656 dr.dt = dtSERVERWINDOW;
657 dr.hChild = g.hMain;
658 dr.lpiServer = lpiPreview;
660 UpdateDisplay (&dr, fWait);
666 void UpdateDisplay_SetIconView (BOOL fWait, HWND hDialog, LPICONVIEW piv, ICONVIEW ivNew)
668 *piv = ivNew;
670 if (piv == &gr.ivSvr)
672 UpdateDisplay_Servers (fWait, NULL, 0);
674 else
676 LPIDENT lpi = Server_GetServer (hDialog);
677 UpdateDisplay_ServerWindow (fWait, lpi);
682 ICONVIEW Display_GetServerIconView (void)
684 LONG lvs;
686 if (gr.fPreview && !gr.fVert)
687 lvs = gr.diHorz.viewSvr.lvsView;
688 else
689 lvs = gr.diVert.viewSvr.lvsView;
692 if (lvs != FLS_VIEW_LIST)
693 return ivONEICON;
695 return gr.ivSvr;
699 BOOL HandleColumnNotify (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp, LPVIEWINFO pvi)
701 if (msg == WM_NOTIFY)
703 HWND hList = GetDlgItem (hDlg, (int)((LPNMHDR)lp)->idFrom);
704 if (fIsFastList (hList))
706 switch (((LPNMHDR)lp)->code)
708 case FLN_COLUMNRESIZE:
709 FL_StoreView (hList, pvi);
710 return TRUE;
712 case FLN_COLUMNCLICK:
713 LPFLN_COLUMNCLICK_PARAMS pp = (LPFLN_COLUMNCLICK_PARAMS)lp;
715 int iCol;
716 BOOL fRev;
717 FastList_GetSortStyle (hList, &iCol, &fRev);
719 if (iCol == pp->icol)
720 FastList_SetSortStyle (hList, iCol, !fRev);
721 else
722 FastList_SetSortStyle (hList, pp->icol, FALSE);
724 FL_StoreView (hList, pvi);
725 return TRUE;
730 return FALSE;