Windows: conditionally set tray icon state
[openafs.git] / src / WINNT / afssvrmgr / display.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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  */
9
10 #include <winsock2.h>
11 #include <ws2tcpip.h>
12
13 extern "C" {
14 #include <afs/param.h>
15 #include <afs/stds.h>
16 }
17
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"
27
28
29 /*
30  * DEFINITIONS ________________________________________________________________
31  *
32  */
33
34 #define cREALLOC_DISPLAYQUEUE  128
35
36 #define cUPDATE_THREADS_MAX      4
37
38
39 /*
40  * VARIABLES __________________________________________________________________
41  *
42  */
43
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;
49
50 static DISPLAYREQUEST drActiveSERVERS;
51 static DISPLAYREQUEST drActiveSERVICES;
52 static DISPLAYREQUEST drActiveAGGREGATES;
53 static DISPLAYREQUEST drActiveFILESETS;
54 static DISPLAYREQUEST drActiveSERVERWINDOW;
55
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;
63
64
65 /*
66  * PROTOTYPES _________________________________________________________________
67  *
68  */
69
70 DWORD WINAPI DisplayQueue_ThreadProc (PVOID lp);
71
72 BOOL DisplayQueueFilter (size_t idqVictim, size_t idqKiller);
73
74
75 /*
76  * ROUTINES ___________________________________________________________________
77  *
78  */
79
80 BOOL CALLBACK GetItemText (HWND hList, LPFLN_GETITEMTEXT_PARAMS pfln, UINT_PTR dwCookie)
81
82    LPVIEWINFO lpvi = (LPVIEWINFO)dwCookie;
83    LPIDENT lpi = (LPIDENT)(pfln->item.lParam);
84    LPTSTR psz = NULL;
85
86    if (pfln->item.icol < (int)lpvi->nColsShown)
87       {
88       size_t iCol = lpvi->aColumns[ pfln->item.icol ];
89
90       BOOL fShowServerName = !Server_GetServerForChild (GetParent(hList));
91
92       if (lpi != NULL)
93          {
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;
103
104          switch (dt)
105             {
106             case dtSERVERS:
107                if (lpi->fIsServer())
108                   psz = Server_GetColumnText (lpi, (SERVERCOLUMN)iCol);
109                break;
110
111             case dtSERVICES:
112                if (lpi->fIsService())
113                   psz = Services_GetColumnText (lpi, (SERVICECOLUMN)iCol, fShowServerName);
114                break;
115
116             case dtAGGREGATES:
117                if (lpi->fIsAggregate())
118                   psz = Aggregates_GetColumnText (lpi, (AGGREGATECOLUMN)iCol, fShowServerName);
119                break;
120
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;
129
130             case dtREPLICAS:
131                if (lpi->fIsFileset())
132                   psz = Replicas_GetColumnText (lpi, (REPLICACOLUMN)iCol);
133                break;
134             }
135          }
136       }
137
138    lstrcpy (pfln->item.pszText, (psz) ? psz : TEXT(""));
139    return TRUE;
140 }
141
142
143 void Display_AddActOnDone (HWND hWnd, WORD wAct, LPIDENT lpiSelectOnDone)
144 {
145    if (pcsWindowActOnDone == NULL)
146       {
147       pcsWindowActOnDone = New (CRITICAL_SECTION);
148       InitializeCriticalSection (pcsWindowActOnDone);
149       }
150    EnterCriticalSection (pcsWindowActOnDone);
151
152    size_t ii;
153    for (ii = 0; ii < cWindowActOnDone; ++ii)
154       {
155       if (aWindowActOnDone[ ii ].hWnd == hWnd)
156          break;
157       }
158    if (ii == cWindowActOnDone)
159       {
160       for (ii = 0; ii < cWindowActOnDone; ++ii)
161          {
162          if (aWindowActOnDone[ ii ].hWnd == 0)
163             break;
164          }
165       }
166    if (ii == cWindowActOnDone)
167       {
168       (void)REALLOC( aWindowActOnDone, cWindowActOnDone, 1+ii, 1 );
169       }
170    if (ii < cWindowActOnDone)
171       {
172       aWindowActOnDone[ ii ].hWnd = hWnd;
173       aWindowActOnDone[ ii ].actOnDone |= wAct;
174       if (!aWindowActOnDone[ ii ].lpiSelectOnDone)
175          aWindowActOnDone[ ii ].lpiSelectOnDone = lpiSelectOnDone;
176       }
177
178    LeaveCriticalSection (pcsWindowActOnDone);
179 }
180
181
182 WORD Display_FreeActOnDone (HWND hWnd, LPIDENT *plpiSelectOnDone)
183 {
184    WORD wAct = 0;
185
186    if (pcsWindowActOnDone == NULL)
187       {
188       pcsWindowActOnDone = New (CRITICAL_SECTION);
189       InitializeCriticalSection (pcsWindowActOnDone);
190       }
191    EnterCriticalSection (pcsWindowActOnDone);
192
193    for (size_t ii = 0; ii < cWindowActOnDone; ++ii)
194       {
195       if (aWindowActOnDone[ ii ].hWnd == hWnd)
196          {
197          wAct = aWindowActOnDone[ ii ].actOnDone;
198          if (!(*plpiSelectOnDone))
199             *plpiSelectOnDone = aWindowActOnDone[ ii ].lpiSelectOnDone;
200
201          aWindowActOnDone[ ii ].actOnDone = 0;
202          aWindowActOnDone[ ii ].hWnd = 0;
203          aWindowActOnDone[ ii ].lpiSelectOnDone = 0;
204          break;
205          }
206       }
207
208    LeaveCriticalSection (pcsWindowActOnDone);
209    return wAct;
210 }
211
212
213 void UpdateDisplay (LPDISPLAYREQUEST pdr, BOOL fWait)
214 {
215    BOOL fRunBeforeReturning = FALSE;
216
217    if (!ASSERT( pdr && pdr->hChild ))
218       return;
219    if (pdr->lpiNotify && pdr->lpiNotify->fIsCell())
220       pdr->lpiNotify = NULL;
221
222    if (pcsDisplayQueue == NULL)
223       {
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));
231       }
232
233    EnterCriticalSection (pcsDisplayQueue);
234
235    size_t idq;
236    for (idq = 0; idq < cDisplayQueue; ++idq)
237       {
238       if (!aDisplayQueue[idq].hChild)
239          break;
240       }
241    if (idq == cDisplayQueue)
242       {
243       (void)REALLOC (aDisplayQueue, cDisplayQueue, 1+idq, cREALLOC_DISPLAYQUEUE);
244       }
245    if (idq < cDisplayQueue)
246       {
247       memcpy (&aDisplayQueue[idq], pdr, sizeof(DISPLAYREQUEST));
248
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.
254       //
255       for (size_t idqKiller = 0; idqKiller < cDisplayQueue; ++idqKiller)
256          {
257          if (DisplayQueueFilter (idq, idqKiller))
258             {
259             aDisplayQueue[idq].hChild = 0;
260             break;
261             }
262          }
263
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.
267       //
268       if (aDisplayQueue[idq].hChild)
269          {
270          if (DisplayQueueFilter (idq, (size_t)-1))
271             aDisplayQueue[idq].hChild = 0;
272          }
273
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.
277       //
278       if (aDisplayQueue[idq].hChild)
279          {
280          for (size_t idqVictim = 0; idqVictim < cDisplayQueue; ++idqVictim)
281             {
282             if (DisplayQueueFilter (idqVictim, idq))
283                {
284                InterlockedDecrementByWindow (aDisplayQueue[idqVictim].hChild);
285                aDisplayQueue[idqVictim].hChild = 0;
286                --cDisplayQueueActive;
287                }
288             }
289
290          if (aDisplayQueue[idq].hChild)
291             {
292             InterlockedIncrementByWindow (aDisplayQueue[ idq ].hChild);
293
294             if (fWait)
295                {
296                aDisplayQueue[idq].hChild = NULL; // we'll handle this one.
297                fRunBeforeReturning = TRUE;       // (remember to do so)
298                }
299             else if ((++cDisplayQueueActive) >= 1)
300                {
301                if (cUpdateThreadsActive < cUPDATE_THREADS_MAX)
302                   {
303                   ++cUpdateThreadsActive;
304                   StartThread (DisplayQueue_ThreadProc, 0);
305                   }
306                }
307             }
308          }
309       }
310
311    LeaveCriticalSection (pcsDisplayQueue);
312
313    if (fRunBeforeReturning)
314       {
315       DisplayQueue_ThreadProc (pdr);
316       }
317 }
318
319
320 DWORD WINAPI DisplayQueue_ThreadProc (PVOID lp)
321 {
322    LPDISPLAYREQUEST pdr = (LPDISPLAYREQUEST)lp;
323    LPDISPLAYREQUEST pdrActive = NULL;
324
325    Main_StartWorking();
326
327    do {
328       DISPLAYREQUEST dr;
329
330       EnterCriticalSection (pcsDisplayQueue);
331       if (pdr)
332          {
333          memcpy (&dr, pdr, sizeof(DISPLAYREQUEST));
334          }
335       else
336          {
337          size_t idq;
338          for (idq = 0; idq < cDisplayQueue; ++idq)
339             {
340             if (aDisplayQueue[idq].hChild)
341                {
342                memcpy (&dr, &aDisplayQueue[idq], sizeof(DISPLAYREQUEST));
343                memset (&aDisplayQueue[idq], 0x00, sizeof(DISPLAYREQUEST));
344                --cDisplayQueueActive;
345                break;
346                }
347             }
348          if (idq == cDisplayQueue)
349             {
350             if (!pdr) // Are we losing a background thread?
351                --cUpdateThreadsActive;
352             LeaveCriticalSection (pcsDisplayQueue);
353             break;
354             }
355          }
356
357       switch (dr.dt)
358          {
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;
364          }
365       if (pdrActive)
366          memcpy (pdrActive, &dr, sizeof(DISPLAYREQUEST));
367
368       LeaveCriticalSection (pcsDisplayQueue);
369
370       AfsClass_Enter();
371
372       switch (dr.dt)
373          {
374          case dtCELL:
375             Display_Cell_Internal (&dr);
376             break;
377
378          case dtSERVERS:
379             Display_Servers_Internal (&dr);
380             break;
381
382          case dtSERVICES:
383             Display_Services_Internal (&dr);
384             break;
385
386          case dtAGGREGATES:
387             Display_Aggregates_Internal (&dr);
388             break;
389
390          case dtFILESETS:
391             Display_Filesets_Internal (&dr);
392             break;
393
394          case dtREPLICAS:
395             Display_Replicas_Internal (&dr);
396             break;
397
398          case dtSERVERWINDOW:
399             Display_ServerWindow_Internal (&dr);
400             break;
401          }
402
403       EnterCriticalSection (pcsDisplayQueue);
404       LONG dw = InterlockedDecrementByWindow (dr.hChild);
405       if (pdrActive)
406          memset (pdrActive, 0x00, sizeof(DISPLAYREQUEST));
407       LeaveCriticalSection (pcsDisplayQueue);
408
409       if (dw == 0)
410          {
411          WORD actOnDone = dr.actOnDone;
412          LPIDENT lpiSelectOnDone = dr.lpiToSelect;
413          if (dr.hList)
414             {
415             actOnDone |= Display_FreeActOnDone (dr.hList, &lpiSelectOnDone);
416             }
417
418          if ((actOnDone & ACT_ENDCHANGE) && dr.hList)
419             {
420             if (dr.fList)
421                FL_EndChange (dr.hList, (LPARAM)lpiSelectOnDone);
422             else // must be a combobox
423                CB_EndChange (dr.hList, (LPARAM)lpiSelectOnDone);
424             }
425
426          if ((actOnDone & ACT_UNCOVER) && dr.hList)
427             AfsAppLib_Uncover (dr.hList);
428
429          if (actOnDone & ACT_SELPREVIEW)
430             {
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);
435             }
436          }
437       else if (dr.hList)
438          {
439          Display_AddActOnDone (dr.hList, dr.actOnDone, dr.lpiToSelect);
440          }
441
442       AfsClass_Leave();
443
444       } while (!lp);  // if given one task to do, stop; otherwise, loop forever
445
446    Main_StopWorking();
447
448    return 0;
449 }
450
451
452 BOOL DisplayQueueFilter (size_t idqVictim, size_t idqKiller)
453 {
454    if (idqVictim == idqKiller)
455       return FALSE;
456
457    LPDISPLAYREQUEST pdrKiller = (idqKiller == (size_t)-1) ? NULL : &aDisplayQueue[ idqKiller ];
458    LPDISPLAYREQUEST pdrVictim = &aDisplayQueue[ idqVictim ];
459
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.
463    //
464    if (pdrKiller == NULL) // was idqKiller==-1 etc?
465       {
466       switch (pdrVictim->dt)
467          {
468          case dtSERVERS:
469             pdrKiller = &drActiveSERVERS;
470             break;
471
472          case dtSERVICES:
473             pdrKiller = &drActiveSERVICES;
474             break;
475
476          case dtAGGREGATES:
477             pdrKiller = &drActiveAGGREGATES;
478             break;
479
480          case dtFILESETS:
481             pdrKiller = &drActiveFILESETS;
482             break;
483
484          case dtSERVERWINDOW:
485             pdrKiller = &drActiveSERVERWINDOW;
486             break;
487          }
488
489       if (!pdrKiller)
490          return FALSE;
491       }
492
493    if ( (pdrVictim->dt == pdrKiller->dt) &&
494         (pdrVictim->hChild == pdrKiller->hChild) )
495       {
496       // only some windows are subject to this filtering.
497       //
498       switch (pdrVictim->dt)
499          {
500          case dtCELL:
501          case dtREPLICAS:
502             return FALSE; // don't bother filtering these.
503
504          case dtSERVERWINDOW:
505             return TRUE;  // update svr window twice?  why?
506          }
507
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.
511       //
512       if (pdrKiller->lpiServer != pdrVictim->lpiServer)
513          return FALSE;
514
515       // if pdrKiller is told to update everything, then all other requests
516       // are unnecessary.
517       //
518       if (!pdrKiller->lpiNotify || pdrKiller->lpiNotify->fIsCell())
519          return TRUE;
520
521       // if pdrVictim is told to update everything, then we'll always bow to it.
522       //
523       if (!pdrVictim->lpiNotify || pdrVictim->lpiNotify->fIsCell())
524          return FALSE;
525
526       // kill any duplicate request to update a particular object.
527       //
528       if (pdrVictim->lpiNotify == pdrKiller->lpiNotify)
529          return TRUE;
530
531       // kill any request to update a service or aggregate or fileset,
532       // if updating the entire associated server.
533       //
534       if ( (pdrKiller->lpiNotify->fIsServer()) &&
535            (pdrVictim->lpiNotify->GetServer() == pdrKiller->lpiNotify) )
536          return TRUE;
537
538       // kill any request to update a fileset, if updating the entire
539       // associated aggregate.
540       //
541       if ( (pdrKiller->lpiNotify->fIsAggregate()) &&
542            (pdrVictim->lpiNotify->fIsFileset()) &&
543            (pdrVictim->lpiNotify->GetAggregate() == pdrKiller->lpiNotify) )
544          return TRUE;
545       }
546
547    // hmmm...guess we need this request after all.
548    //
549    return FALSE;
550 }
551
552
553 void UpdateDisplay_Cell (BOOL fWait)
554 {
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);
560 }
561
562 void UpdateDisplay_Servers (BOOL fWait, LPIDENT lpiNotify, ULONG status)
563 {
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);
572 }
573
574 void UpdateDisplay_Services (BOOL fWait, HWND hChild, LPIDENT lpiNotify, ULONG status)
575 {
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);
584 }
585
586 void UpdateDisplay_Aggregates (BOOL fWait, HWND hListOrCombo, LPIDENT lpiNotify, ULONG status, LPIDENT lpiServer, LPIDENT lpiToSelect, LPVIEWINFO lpvi)
587 {
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);
599 }
600
601 void UpdateDisplay_Filesets (BOOL fWait, HWND hListOrCombo, LPIDENT lpiNotify, ULONG status, LPIDENT lpiServer, LPIDENT lpiAggregate, LPIDENT lpiToSelect)
602 {
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);
614 }
615
616 void UpdateDisplay_Replicas (BOOL fWait, HWND hList, LPIDENT lpiRW, LPIDENT lpiRO)
617 {
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);
627 }
628
629
630 void UpdateDisplay_ServerWindow (BOOL fWait, LPIDENT lpiServer)
631 {
632    // First, if there is a dedicated server window out there, update it.
633    //
634    HWND hServer;
635    if ((hServer = PropCache_Search (pcSERVER, lpiServer)) != NULL)
636       {
637       DISPLAYREQUEST dr;
638       memset (&dr, 0x00, sizeof(dr));
639       dr.dt = dtSERVERWINDOW;
640       dr.hChild = hServer;
641       dr.lpiServer = lpiServer;
642
643       UpdateDisplay (&dr, fWait);
644       }
645
646    // Second, if the preview pane is visible and showing this server,
647    // update it too.
648    //
649    if (gr.fPreview)
650       {
651       LPIDENT lpiPreview = Server_GetServer (g.hMain);
652       if ((lpiPreview == NULL) || (lpiPreview == lpiServer))
653          {
654          DISPLAYREQUEST dr;
655          memset (&dr, 0x00, sizeof(dr));
656          dr.dt = dtSERVERWINDOW;
657          dr.hChild = g.hMain;
658          dr.lpiServer = lpiPreview;
659
660          UpdateDisplay (&dr, fWait);
661          }
662       }
663 }
664
665
666 void UpdateDisplay_SetIconView (BOOL fWait, HWND hDialog, LPICONVIEW piv, ICONVIEW ivNew)
667 {
668    *piv = ivNew;
669
670    if (piv == &gr.ivSvr)
671       {
672       UpdateDisplay_Servers (fWait, NULL, 0);
673       }
674    else
675       {
676       LPIDENT lpi = Server_GetServer (hDialog);
677       UpdateDisplay_ServerWindow (fWait, lpi);
678       }
679 }
680
681
682 ICONVIEW Display_GetServerIconView (void)
683 {
684    LONG lvs;
685
686    if (gr.fPreview && !gr.fVert)
687       lvs = gr.diHorz.viewSvr.lvsView;
688    else
689       lvs = gr.diVert.viewSvr.lvsView;
690
691
692    if (lvs != FLS_VIEW_LIST)
693       return ivONEICON;
694
695    return gr.ivSvr;
696 }
697
698
699 BOOL HandleColumnNotify (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp, LPVIEWINFO pvi)
700 {
701    if (msg == WM_NOTIFY)
702       {
703       HWND hList = GetDlgItem (hDlg, (int)((LPNMHDR)lp)->idFrom);
704       if (fIsFastList (hList))
705          {
706          switch (((LPNMHDR)lp)->code)
707             { 
708             case FLN_COLUMNRESIZE:
709                FL_StoreView (hList, pvi);
710                return TRUE;
711
712             case FLN_COLUMNCLICK:
713                LPFLN_COLUMNCLICK_PARAMS pp = (LPFLN_COLUMNCLICK_PARAMS)lp;
714
715                int iCol;
716                BOOL fRev;
717                FastList_GetSortStyle (hList, &iCol, &fRev);
718
719                if (iCol == pp->icol)
720                   FastList_SetSortStyle (hList, iCol, !fRev);
721                else
722                   FastList_SetSortStyle (hList, pp->icol, FALSE);
723
724                FL_StoreView (hList, pvi);
725                return TRUE;
726             }
727          }
728       }
729
730    return FALSE;
731 }
732