2 * Copyright 2000, International Business Machines Corporation and others.
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
11 #include <afs/param.h>
18 #include "svr_window.h"
23 #include "propcache.h"
27 * DEFINITIONS ________________________________________________________________
31 #define cREALLOC_DISPLAYQUEUE 128
33 #define cUPDATE_THREADS_MAX 4
37 * VARIABLES __________________________________________________________________
41 static size_t cDisplayQueueActive = 0;
42 static size_t cDisplayQueue = 0;
43 static size_t cUpdateThreadsActive = 0;
44 static DISPLAYREQUEST *aDisplayQueue = NULL;
45 static CRITICAL_SECTION *pcsDisplayQueue = NULL;
47 static DISPLAYREQUEST drActiveSERVERS;
48 static DISPLAYREQUEST drActiveSERVICES;
49 static DISPLAYREQUEST drActiveAGGREGATES;
50 static DISPLAYREQUEST drActiveFILESETS;
51 static DISPLAYREQUEST drActiveSERVERWINDOW;
56 LPIDENT lpiSelectOnDone;
57 } *aWindowActOnDone = NULL;
58 static size_t cWindowActOnDone = 0;
59 static CRITICAL_SECTION *pcsWindowActOnDone = NULL;
63 * PROTOTYPES _________________________________________________________________
67 DWORD WINAPI DisplayQueue_ThreadProc (PVOID lp);
69 BOOL DisplayQueueFilter (size_t idqVictim, size_t idqKiller);
73 * ROUTINES ___________________________________________________________________
77 BOOL CALLBACK GetItemText (HWND hList, LPFLN_GETITEMTEXT_PARAMS pfln, DWORD dwCookie)
79 LPVIEWINFO lpvi = (LPVIEWINFO)dwCookie;
80 LPIDENT lpi = (LPIDENT)(pfln->item.lParam);
83 if (pfln->item.icol < (int)lpvi->nColsShown)
85 size_t iCol = lpvi->aColumns[ pfln->item.icol ];
87 BOOL fShowServerName = !Server_GetServerForChild (GetParent(hList));
91 DISPLAYTARGET dt = dtSERVERS;
92 if (lpvi == &gr.viewSet)
94 else if (lpvi == &gr.viewSvc)
96 else if ((lpvi == &gr.viewAgg) || (lpvi == &gr.viewAggMove) || (lpvi == &gr.viewAggCreate) || (lpvi == &gr.viewAggRestore))
98 else if (lpvi == &gr.viewRep)
104 if (lpi->fIsServer())
105 psz = Server_GetColumnText (lpi, (SERVERCOLUMN)iCol);
109 if (lpi->fIsService())
110 psz = Services_GetColumnText (lpi, (SERVICECOLUMN)iCol, fShowServerName);
114 if (lpi->fIsAggregate())
115 psz = Aggregates_GetColumnText (lpi, (AGGREGATECOLUMN)iCol, fShowServerName);
119 if (lpi->fIsFileset())
120 psz = Filesets_GetColumnText (lpi, (FILESETCOLUMN)iCol, fShowServerName);
121 else if (lpi->fIsAggregate() && (pfln->item.icol == setcolNAME))
122 psz = Aggregates_GetColumnText (lpi, aggcolNAME, FALSE);
123 else if (lpi->fIsServer() && (pfln->item.icol == setcolNAME))
124 psz = Server_GetColumnText (lpi, svrcolNAME);
128 if (lpi->fIsFileset())
129 psz = Replicas_GetColumnText (lpi, (REPLICACOLUMN)iCol);
135 lstrcpy (pfln->item.pszText, (psz) ? psz : TEXT(""));
140 void Display_AddActOnDone (HWND hWnd, WORD wAct, LPIDENT lpiSelectOnDone)
142 if (pcsWindowActOnDone == NULL)
144 pcsWindowActOnDone = New (CRITICAL_SECTION);
145 InitializeCriticalSection (pcsWindowActOnDone);
147 EnterCriticalSection (pcsWindowActOnDone);
149 for (size_t ii = 0; ii < cWindowActOnDone; ++ii)
151 if (aWindowActOnDone[ ii ].hWnd == hWnd)
154 if (ii == cWindowActOnDone)
156 for (ii = 0; ii < cWindowActOnDone; ++ii)
158 if (aWindowActOnDone[ ii ].hWnd == 0)
162 if (ii == cWindowActOnDone)
164 (void)REALLOC( aWindowActOnDone, cWindowActOnDone, 1+ii, 1 );
166 if (ii < cWindowActOnDone)
168 aWindowActOnDone[ ii ].hWnd = hWnd;
169 aWindowActOnDone[ ii ].actOnDone |= wAct;
170 if (!aWindowActOnDone[ ii ].lpiSelectOnDone)
171 aWindowActOnDone[ ii ].lpiSelectOnDone = lpiSelectOnDone;
174 LeaveCriticalSection (pcsWindowActOnDone);
178 WORD Display_FreeActOnDone (HWND hWnd, LPIDENT *plpiSelectOnDone)
182 if (pcsWindowActOnDone == NULL)
184 pcsWindowActOnDone = New (CRITICAL_SECTION);
185 InitializeCriticalSection (pcsWindowActOnDone);
187 EnterCriticalSection (pcsWindowActOnDone);
189 for (size_t ii = 0; ii < cWindowActOnDone; ++ii)
191 if (aWindowActOnDone[ ii ].hWnd == hWnd)
193 wAct = aWindowActOnDone[ ii ].actOnDone;
194 if (!(*plpiSelectOnDone))
195 *plpiSelectOnDone = aWindowActOnDone[ ii ].lpiSelectOnDone;
197 aWindowActOnDone[ ii ].actOnDone = 0;
198 aWindowActOnDone[ ii ].hWnd = 0;
199 aWindowActOnDone[ ii ].lpiSelectOnDone = 0;
204 LeaveCriticalSection (pcsWindowActOnDone);
209 void UpdateDisplay (LPDISPLAYREQUEST pdr, BOOL fWait)
211 BOOL fRunBeforeReturning = FALSE;
213 if (!ASSERT( pdr && pdr->hChild ))
215 if (pdr->lpiNotify && pdr->lpiNotify->fIsCell())
216 pdr->lpiNotify = NULL;
218 if (pcsDisplayQueue == NULL)
220 pcsDisplayQueue = New (CRITICAL_SECTION);
221 InitializeCriticalSection (pcsDisplayQueue);
222 memset (&drActiveSERVERS, 0x00, sizeof(DISPLAYREQUEST));
223 memset (&drActiveSERVICES, 0x00, sizeof(DISPLAYREQUEST));
224 memset (&drActiveAGGREGATES, 0x00, sizeof(DISPLAYREQUEST));
225 memset (&drActiveFILESETS, 0x00, sizeof(DISPLAYREQUEST));
226 memset (&drActiveSERVERWINDOW, 0x00, sizeof(DISPLAYREQUEST));
229 EnterCriticalSection (pcsDisplayQueue);
231 for (size_t idq = 0; idq < cDisplayQueue; ++idq)
233 if (!aDisplayQueue[idq].hChild)
236 if (idq == cDisplayQueue)
238 (void)REALLOC (aDisplayQueue, cDisplayQueue, 1+idq, cREALLOC_DISPLAYQUEUE);
240 if (idq < cDisplayQueue)
242 memcpy (&aDisplayQueue[idq], pdr, sizeof(DISPLAYREQUEST));
244 // Filter the display queue--for instance, if there's a request
245 // to update all filesets, we don't need to file a request to
246 // update an individual fileset. Likewise, if we're about to
247 // file a request to update all filesets, nix all existing update-
248 // this-fileset and update-filesets-on-this-server requests.
250 for (size_t idqKiller = 0; idqKiller < cDisplayQueue; ++idqKiller)
252 if (DisplayQueueFilter (idq, idqKiller))
254 aDisplayQueue[idq].hChild = 0;
259 // Hmmmm...even if there is no request in the queue which lets us
260 // kill this request, there may be a request actively being serviced
261 // *right now* which does so. Test for that case too.
263 if (aDisplayQueue[idq].hChild)
265 if (DisplayQueueFilter (idq, (size_t)-1))
266 aDisplayQueue[idq].hChild = 0;
269 // Did the new request make it through all those tests? If so,
270 // see if we can remove any other entries because of this one.
271 // Then initiate a thread to actually do the work if there isn't one.
273 if (aDisplayQueue[idq].hChild)
275 for (size_t idqVictim = 0; idqVictim < cDisplayQueue; ++idqVictim)
277 if (DisplayQueueFilter (idqVictim, idq))
279 InterlockedDecrementByWindow (aDisplayQueue[idqVictim].hChild);
280 aDisplayQueue[idqVictim].hChild = 0;
281 --cDisplayQueueActive;
285 if (aDisplayQueue[idq].hChild)
287 InterlockedIncrementByWindow (aDisplayQueue[ idq ].hChild);
291 aDisplayQueue[idq].hChild = NULL; // we'll handle this one.
292 fRunBeforeReturning = TRUE; // (remember to do so)
294 else if ((++cDisplayQueueActive) >= 1)
296 if (cUpdateThreadsActive < cUPDATE_THREADS_MAX)
298 ++cUpdateThreadsActive;
299 StartThread (DisplayQueue_ThreadProc, 0);
306 LeaveCriticalSection (pcsDisplayQueue);
308 if (fRunBeforeReturning)
310 DisplayQueue_ThreadProc (pdr);
315 DWORD WINAPI DisplayQueue_ThreadProc (PVOID lp)
317 LPDISPLAYREQUEST pdr = (LPDISPLAYREQUEST)lp;
318 LPDISPLAYREQUEST pdrActive = NULL;
325 EnterCriticalSection (pcsDisplayQueue);
328 memcpy (&dr, pdr, sizeof(DISPLAYREQUEST));
332 for (size_t idq = 0; idq < cDisplayQueue; ++idq)
334 if (aDisplayQueue[idq].hChild)
336 memcpy (&dr, &aDisplayQueue[idq], sizeof(DISPLAYREQUEST));
337 memset (&aDisplayQueue[idq], 0x00, sizeof(DISPLAYREQUEST));
338 --cDisplayQueueActive;
342 if (idq == cDisplayQueue)
344 if (!pdr) // Are we losing a background thread?
345 --cUpdateThreadsActive;
346 LeaveCriticalSection (pcsDisplayQueue);
353 case dtSERVERS: pdrActive = &drActiveSERVERS; break;
354 case dtSERVICES: pdrActive = &drActiveSERVICES; break;
355 case dtAGGREGATES: pdrActive = &drActiveAGGREGATES; break;
356 case dtFILESETS: pdrActive = &drActiveFILESETS; break;
357 case dtSERVERWINDOW: pdrActive = &drActiveSERVERWINDOW; break;
360 memcpy (pdrActive, &dr, sizeof(DISPLAYREQUEST));
362 LeaveCriticalSection (pcsDisplayQueue);
369 Display_Cell_Internal (&dr);
373 Display_Servers_Internal (&dr);
377 Display_Services_Internal (&dr);
381 Display_Aggregates_Internal (&dr);
385 Display_Filesets_Internal (&dr);
389 Display_Replicas_Internal (&dr);
393 Display_ServerWindow_Internal (&dr);
397 EnterCriticalSection (pcsDisplayQueue);
398 LONG dw = InterlockedDecrementByWindow (dr.hChild);
400 memset (pdrActive, 0x00, sizeof(DISPLAYREQUEST));
401 LeaveCriticalSection (pcsDisplayQueue);
405 WORD actOnDone = dr.actOnDone;
406 LPIDENT lpiSelectOnDone = dr.lpiToSelect;
409 actOnDone |= Display_FreeActOnDone (dr.hList, &lpiSelectOnDone);
412 if ((actOnDone & ACT_ENDCHANGE) && dr.hList)
415 FL_EndChange (dr.hList, (LPARAM)lpiSelectOnDone);
416 else // must be a combobox
417 CB_EndChange (dr.hList, (LPARAM)lpiSelectOnDone);
420 if ((actOnDone & ACT_UNCOVER) && dr.hList)
421 AfsAppLib_Uncover (dr.hList);
423 if (actOnDone & ACT_SELPREVIEW)
425 LPIDENT lpiOld = Server_GetServer (SERVERWINDOW_PREVIEWPANE);
426 LPIDENT lpiNew = (LPIDENT)FL_GetSelectedData (GetDlgItem (g.hMain, IDC_SERVERS));
427 if (lpiOld != lpiNew)
428 Server_SelectServer (SERVERWINDOW_PREVIEWPANE, lpiNew, TRUE);
433 Display_AddActOnDone (dr.hList, dr.actOnDone, dr.lpiToSelect);
438 } while (!lp); // if given one task to do, stop; otherwise, loop forever
446 BOOL DisplayQueueFilter (size_t idqVictim, size_t idqKiller)
448 if (idqVictim == idqKiller)
451 LPDISPLAYREQUEST pdrKiller = (idqKiller == (size_t)-1) ? NULL : &aDisplayQueue[ idqKiller ];
452 LPDISPLAYREQUEST pdrVictim = &aDisplayQueue[ idqVictim ];
454 // if there's currently an operation in progress for this window,
455 // we may have just been asked to filter out a new request based on
456 // what's being done now. {idqKiller==-1} signifies this case.
458 if (pdrKiller == NULL) // was idqKiller==-1 etc?
460 switch (pdrVictim->dt)
463 pdrKiller = &drActiveSERVERS;
467 pdrKiller = &drActiveSERVICES;
471 pdrKiller = &drActiveAGGREGATES;
475 pdrKiller = &drActiveFILESETS;
479 pdrKiller = &drActiveSERVERWINDOW;
487 if ( (pdrVictim->dt == pdrKiller->dt) &&
488 (pdrVictim->hChild == pdrKiller->hChild) )
490 // only some windows are subject to this filtering.
492 switch (pdrVictim->dt)
496 return FALSE; // don't bother filtering these.
499 return TRUE; // update svr window twice? why?
502 // if the new request talks about displaying information for a different
503 // server, the user must have selected or deselected a server in the
504 // list. we'll keep the new request.
506 if (pdrKiller->lpiServer != pdrVictim->lpiServer)
509 // if pdrKiller is told to update everything, then all other requests
512 if (!pdrKiller->lpiNotify || pdrKiller->lpiNotify->fIsCell())
515 // if pdrVictim is told to update everything, then we'll always bow to it.
517 if (!pdrVictim->lpiNotify || pdrVictim->lpiNotify->fIsCell())
520 // kill any duplicate request to update a particular object.
522 if (pdrVictim->lpiNotify == pdrKiller->lpiNotify)
525 // kill any request to update a service or aggregate or fileset,
526 // if updating the entire associated server.
528 if ( (pdrKiller->lpiNotify->fIsServer()) &&
529 (pdrVictim->lpiNotify->GetServer() == pdrKiller->lpiNotify) )
532 // kill any request to update a fileset, if updating the entire
533 // associated aggregate.
535 if ( (pdrKiller->lpiNotify->fIsAggregate()) &&
536 (pdrVictim->lpiNotify->fIsFileset()) &&
537 (pdrVictim->lpiNotify->GetAggregate() == pdrKiller->lpiNotify) )
541 // hmmm...guess we need this request after all.
547 void UpdateDisplay_Cell (BOOL fWait)
550 memset (&dr, 0x00, sizeof(dr));
552 dr.hChild = GetDlgItem (g.hMain, IDC_CELL);
553 UpdateDisplay (&dr, fWait);
556 void UpdateDisplay_Servers (BOOL fWait, LPIDENT lpiNotify, ULONG status)
559 memset (&dr, 0x00, sizeof(dr));
561 dr.hChild = GetDlgItem (g.hMain, IDC_SERVERS);
562 dr.lpiNotify = lpiNotify;
565 UpdateDisplay (&dr, fWait);
568 void UpdateDisplay_Services (BOOL fWait, HWND hChild, LPIDENT lpiNotify, ULONG status)
571 memset (&dr, 0x00, sizeof(dr));
574 dr.lpiNotify = lpiNotify;
577 UpdateDisplay (&dr, fWait);
580 void UpdateDisplay_Aggregates (BOOL fWait, HWND hListOrCombo, LPIDENT lpiNotify, ULONG status, LPIDENT lpiServer, LPIDENT lpiToSelect, LPVIEWINFO lpvi)
583 memset (&dr, 0x00, sizeof(dr));
584 dr.dt = dtAGGREGATES;
585 dr.hList = hListOrCombo;
586 dr.hChild = GetParent (hListOrCombo);
587 dr.lpiNotify = lpiNotify;
589 dr.lpiServer = (lpiServer == NULL) ? Server_GetServerForChild (dr.hChild) : lpiServer;
590 dr.lpiToSelect = lpiToSelect;
592 UpdateDisplay (&dr, fWait);
595 void UpdateDisplay_Filesets (BOOL fWait, HWND hListOrCombo, LPIDENT lpiNotify, ULONG status, LPIDENT lpiServer, LPIDENT lpiAggregate, LPIDENT lpiToSelect)
598 memset (&dr, 0x00, sizeof(dr));
600 dr.hList = hListOrCombo;
601 dr.hChild = GetParent (hListOrCombo);
602 dr.lpiNotify = lpiNotify;
604 dr.lpiServer = (lpiServer == NULL) ? Server_GetServerForChild (dr.hChild) : lpiServer;
605 dr.lpiAggregate = lpiAggregate;
606 dr.lpiToSelect = lpiToSelect;
607 UpdateDisplay (&dr, fWait);
610 void UpdateDisplay_Replicas (BOOL fWait, HWND hList, LPIDENT lpiRW, LPIDENT lpiRO)
613 memset (&dr, 0x00, sizeof(dr));
615 dr.hChild = GetParent (hList);
617 dr.lpiNotify = lpiRW;
618 dr.lpiToSelect = lpiRO;
620 UpdateDisplay (&dr, fWait);
624 void UpdateDisplay_ServerWindow (BOOL fWait, LPIDENT lpiServer)
626 // First, if there is a dedicated server window out there, update it.
629 if ((hServer = PropCache_Search (pcSERVER, lpiServer)) != NULL)
632 memset (&dr, 0x00, sizeof(dr));
633 dr.dt = dtSERVERWINDOW;
635 dr.lpiServer = lpiServer;
637 UpdateDisplay (&dr, fWait);
640 // Second, if the preview pane is visible and showing this server,
645 LPIDENT lpiPreview = Server_GetServer (g.hMain);
646 if ((lpiPreview == NULL) || (lpiPreview == lpiServer))
649 memset (&dr, 0x00, sizeof(dr));
650 dr.dt = dtSERVERWINDOW;
652 dr.lpiServer = lpiPreview;
654 UpdateDisplay (&dr, fWait);
660 void UpdateDisplay_SetIconView (BOOL fWait, HWND hDialog, LPICONVIEW piv, ICONVIEW ivNew)
664 if (piv == &gr.ivSvr)
666 UpdateDisplay_Servers (fWait, NULL, 0);
670 LPIDENT lpi = Server_GetServer (hDialog);
671 UpdateDisplay_ServerWindow (fWait, lpi);
676 ICONVIEW Display_GetServerIconView (void)
680 if (gr.fPreview && !gr.fVert)
681 lvs = gr.diHorz.viewSvr.lvsView;
683 lvs = gr.diVert.viewSvr.lvsView;
686 if (lvs != FLS_VIEW_LIST)
693 BOOL HandleColumnNotify (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp, LPVIEWINFO pvi)
695 if (msg == WM_NOTIFY)
697 HWND hList = GetDlgItem (hDlg, ((LPNMHDR)lp)->idFrom);
698 if (fIsFastList (hList))
700 switch (((LPNMHDR)lp)->code)
702 case FLN_COLUMNRESIZE:
703 FL_StoreView (hList, pvi);
706 case FLN_COLUMNCLICK:
707 LPFLN_COLUMNCLICK_PARAMS pp = (LPFLN_COLUMNCLICK_PARAMS)lp;
711 FastList_GetSortStyle (hList, &iCol, &fRev);
713 if (iCol == pp->icol)
714 FastList_SetSortStyle (hList, iCol, !fRev);
716 FastList_SetSortStyle (hList, pp->icol, FALSE);
718 FL_StoreView (hList, pvi);