
/*
 *@@sourcefile xfldr.c:
 *      This file contains SOM code for the following XWorkplace classes:
 *
 *      --  XFolder class (WPFolder replacement)
 *
 *      XFolder is probably the most complex class of this
 *      package. The main functionalities of XFolder are
 *      hooked into the WPS thru the following method
 *      overrides:
 *
 *      -- XFolder::wpModifyPopupMenu adds all the XFolder menu items
 *         to folder context menus. This calls code in
 *         src/filesys/fdrmenus.c which is shared with XFldDisk,
 *         because both classes largely do the same thing.
 *
 *      -- XFolder::wpOpen calls fdrManipulateNewView, which
 *         subclasses a newly opened folder view frame window
 *         with fnwpSubclWPFolderWindow -- one of the most
 *         complex parts of XWorkplace.
 *         This window procedure intercepts lots of messages
 *         which are needed for the more advanced features.
 *         See src\filesys\fdrsubclass.c for an introduction.
 *
 *         The subclassed folder frame window procedure also
 *         handles WM_COMMAND messages directly to start the
 *         enhanced XWorkplace file operations, such as moving
 *         files to the XWorkplace trash can.
 *
 *      -- Extended folder sorting is now documented in
 *         src\filesys\fdrsort.c (V0.9.12).
 *
 *      -- Lots of wpAdd* settings pages overrides to replace
 *         XFolder settings pages.
 *
 *      Installation of XFolder is now optional (V0.9.0).
 *      However, if any of XFldDisk, XFldStartup, or XFldShutdown are
 *      installed, XFolder must also be installed.
 *
 *      Starting with V0.9.0, the files in classes\ contain only
 *      the SOM interface, i.e. the methods themselves.
 *      The implementation for this class is mostly in filesys\folder.c,
 *      filesys\fdrhotky.c, and filesys\filesys.c.
 *
 *@@somclass XFolder xf_
 *@@somclass M_XFolder xfM_
 *
 *@@changed V0.9.0 [umoeller]: override of wpclsQueryTitle removed
 */

/*
 *      Copyright (C) 1997-2014 Ulrich M”ller.
 *
 *      This file is part of the XWorkplace source package.
 *      XWorkplace is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published
 *      by the Free Software Foundation, in version 2 as it comes in the
 *      "COPYING" file of the XWorkplace main distribution.
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 */

/*
 *  This file was generated by the SOM Compiler and Emitter Framework.
 *  Generated using:
 *      SOM Emitter emitctm: 2.41
 */

#ifndef SOM_Module_xfldr_Source
#define SOM_Module_xfldr_Source
#endif
#define XFolder_Class_Source
#define M_XFolder_Class_Source

#pragma strings(readonly)

/*
 *  Suggested #include order:
 *  1)  os2.h
 *  2)  C library headers
 *  3)  setup.h (code generation and debugging options)
 *  4)  headers in helpers\
 *  5)  at least one SOM implementation header (*.ih)
 *  6)  dlgids.h, headers in shared\ (as needed)
 *  7)  headers in implementation dirs (e.g. filesys\, as needed)
 *  8)  #pragma hdrstop and then more SOM headers which crash with precompiled headers
 */

#define INCL_DOSEXCEPTIONS
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSERRORS

#define INCL_WINWINDOWMGR
#define INCL_WINFRAMEMGR
#define INCL_WININPUT
#define INCL_WINRECTANGLES
#define INCL_WINSYS             // needed for presparams
#define INCL_WINPOINTERS
#define INCL_WINMENUS
#define INCL_WINTIMER
#define INCL_WINDIALOGS
#define INCL_WINBUTTONS
#define INCL_WINENTRYFIELDS
#define INCL_WINLISTBOXES
#define INCL_WINSTDCNR
#define INCL_WINSHELLDATA       // Prf* functions
#define INCL_WINHOOKS
#include <os2.h>

// C library headers
#include <stdio.h>              // needed for except.h
#include <setjmp.h>             // needed for except.h

// generic headers
#include "setup.h"                      // code generation and debugging options

// headers in /helpers
#include "helpers\comctl.h"             // common controls (window procs)
#include "helpers\eah.h"                // extended attributes helper routines
#include "helpers\except.h"             // exception handling
#include "helpers\linklist.h"           // linked list helper routines
#include "helpers\prfh.h"               // INI file helper routines
#include "helpers\standards.h"          // some standard macros
#include "helpers\stringh.h"            // string helper routines
#include "helpers\tree.h"               // red-black binary trees
#include "helpers\xstring.h"            // extended string helpers

// SOM headers which don't crash with prec. header files
// #include "xfobj.ih"                     // XFldObject
#include "xfldr.ih"

// XWorkplace implementation headers
#include "dlgids.h"                     // all the IDs that are shared with NLS
#include "shared\classtest.h"           // some cheap funcs for WPS class checks
#include "shared\common.h"              // the majestic XWorkplace include file
#include "shared\helppanels.h"          // all XWorkplace help panel IDs
#include "shared\kernel.h"              // XWorkplace Kernel
#include "shared\notebook.h"            // generic XWorkplace notebook handling
#include "shared\wpsh.h"                // some pseudo-SOM functions (WPS helper routines)

#include "filesys\filesys.h"            // various file-system object implementation code
#include "filesys\folder.h"             // XFolder implementation
#include "filesys\fdrcommand.h"         // folder menu command reactions
#include "filesys\fdrhotky.h"           // folder hotkey handling
#include "filesys\fdrmenus.h"           // shared folder menu logic
#include "filesys\fdrsplit.h"           // folder split views
#include "filesys\fdrsubclass.h"        // folder subclassing engine
#include "filesys\icons.h"              // icons handling
#include "filesys\object.h"             // XFldObject implementation
#include "filesys\refresh.h"            // folder auto-refresh
#include "filesys\statbars.h"           // status bar translation logic
#include "filesys\xthreads.h"           // extra XWorkplace threads

// other SOM headers
#pragma hdrstop                         // VAC++ keeps crashing otherwise

/* ******************************************************************
 *
 *   Global variables
 *
 ********************************************************************/

extern WPFolder             *G_pConfigFolder = NULL;
                        // used in xfobj.c too

#ifndef __NOFOLDERCONTENTS__
    XWPObjList              *G_llFavoriteFolders = NULL;
#endif
#ifndef __NOQUICKOPEN__
    XWPObjList              *G_llQuickOpenFolders = NULL;
#endif

ULONG                       G_ulViewForModifyMenu;
                            // workaround for wpModifyMenu bug
                            // V1.0.1 (2002-12-08) [umoeller]

/* ******************************************************************
 *
 *   here come the XFolder instance methods
 *
 ********************************************************************/

/*
 *@@ xwpQueryFldrSort:
 *      this returns the folder's sort settings into the specified
 *      USHORT variables.
 *
 *      Either can be set to SET_DEFAULT if no instance data has been
 *      defined; you will then need to query global settings.
 *
 *      See XFolder::xwpSortViewOnce for the values of pusDefaultSort.
 *
 *@@changed V0.9.12 (2001-05-18) [umoeller]: changed prototype
 *@@changed V0.9.12 (2001-05-18) [umoeller]: now supporting details view columns
 */

SOM_Scope BOOL  SOMLINK xf_xwpQueryFldrSort(XFolder *somSelf,
                                            PLONG plDefaultSort,
                                            PLONG plFoldersFirst,
                                            PLONG plAlwaysSort)
{
    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpQueryFldrSort");

    if (plDefaultSort)
        *plDefaultSort = _lDefSortCrit;

    if (plFoldersFirst)
        *plFoldersFirst = _lFoldersFirst;

    if (plAlwaysSort)
        *plAlwaysSort = _lAlwaysSort;

    return TRUE;
}

/*
 *@@ xwpSetFldrSort:
 *      this is the new XFolder method for setting the sort data
 *      for a certain folder.
 *
 *      usDefaultSort can be one of the following:
 *
 *      --  -1:     sort by type (as with standard WPS).
 *
 *      --  -2:     sort by object title (as with standard WPS).
 *
 *      --  -3:     sort by object class (new with XWP).
 *
 *      --  -4:     sort by extension (new with XWP).
 *
 *      --  >= 0: the details column index to sort by.
 *
 *      --  SET_DEFAULT (255): use the global default sort
 *          criterion for this folder.
 *
 *      usfAlwaysSort can be 0 or 1 or SET_DEFAULT also.
 *
 *      This method updates all open folder views with the new
 *      sort settings.
 *
 *      This method returns TRUE if any visible change occurred as
 *      a result to the new settings.
 *
 *@@changed V0.9.2 (2000-03-08) [umoeller]: added folder locking
 *@@changed V0.9.12 (2001-05-18) [umoeller]: changed prototype
 *@@changed V0.9.12 (2001-05-18) [umoeller]: now supporting details view columns
 */

SOM_Scope BOOL  SOMLINK xf_xwpSetFldrSort(XFolder *somSelf,
                                          long lDefaultSort,
                                          long lFoldersFirst,
                                          long lAlwaysSort)
{
    XFolderData *somThis = XFolderGetData(somSelf);

    BOOL fLocked = FALSE,
         fUpdate = FALSE;

    WPObject *pobjLock = NULL;

    PMPF_SORT(("[%s]{%s}",_wpQueryTitle(somSelf),
                            _somGetClassName(somSelf)));
    PMPF_SORT(("  Old: Default %d, Always %d", _lDefSortCrit, _lAlwaysSort));

    TRY_LOUD(excpt1)
    {
        if (pobjLock = cmnLockObject(somSelf))
        {
            XFolderMethodDebug("XFolder","xf_xwpSetFldrSort");

            if (    (lDefaultSort != _lDefSortCrit)
                 && (    ((lDefaultSort >= -4) && (lDefaultSort < 0))
                      || (lDefaultSort == SET_DEFAULT)
                      || (_wpIsSortAttribAvailable(somSelf,
                                                   lDefaultSort))
                    )
               )
            {
                _lDefSortCrit = lDefaultSort;
                fUpdate = TRUE;
            }

            if (lFoldersFirst != _lFoldersFirst)
            {
                _lFoldersFirst = lFoldersFirst;
                fUpdate = TRUE;
            }

            if (lAlwaysSort != _lAlwaysSort)
            {
                _lAlwaysSort = lAlwaysSort;
                fUpdate = TRUE;
            }

            PMPF_SORT(("  New: Default %d, Always %d", _lDefSortCrit, _lAlwaysSort));

        } // end if (fFolderLocked)
    }
    CATCH(excpt1) {} END_CATCH();

    if (pobjLock)
        _wpReleaseObjectMutexSem(pobjLock);

    if (fUpdate)
    {
        // update open views of this folder
#ifndef __ALWAYSEXTSORT__
        if (cmnQuerySetting(sfExtendedSorting))
#endif
        {
            fdrForEachOpenInstanceView(somSelf,
                                       fdrUpdateFolderSorts,
                                       TRUE);   // force
            // update folder "Sort" notebook page, if open
            ntbUpdateVisiblePage(somSelf, SP_FLDRSORT_FLDR);
        }

        // save instance data
        _wpSaveDeferred(somSelf);
    }

    return fUpdate;
}

/*
 *@@ xwpSortViewOnce:
 *      sorts the content of given folder.
 *      As opposed to XFolder::xwpSetFldrSort, this does not
 *      change the folder sort settings, but only sorts the view
 *      once.
 *
 *      This is used by the context menu entries in the "Sort"
 *      menu and the respective folder hotkeys.
 *
 *      lSort must be one of the sort criteria as specified
 *      with XFolder::xwpSetFldrSort.
 *
 *@@changed V0.9.2 (2000-03-08) [umoeller]: added folder locking
 *@@changed V0.9.12 (2001-05-18) [umoeller]: now supporting details view columns
 */

SOM_Scope BOOL  SOMLINK xf_xwpSortViewOnce(XFolder *somSelf,
                                           HWND hwndFrame,
                                           long lSort)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpSortViewOnce");

    return fdrSortViewOnce(somSelf, hwndFrame, lSort);
}

/*
 *@@ xwpQueryIconPos:
 *      this new instance method retrieves the icon position of an
 *      object in a currently populated folder; you need to initialize
 *      the pICONPOS structure first, whose size you need to pass in
 *      ulICONPOSSize; the ICONPOS data will be copied to pipReturn.
 *      The method returns FALSE if something went wrong.
 *
 *@@changed V0.9.2 (2000-03-09) [umoeller]: fixed excessive handle queries
 */

SOM_Scope BOOL  SOMLINK xf_xwpGetIconPos(XFolder *somSelf,
                                         WPObject *pObject,
                                         PBYTE pICONPOS,
                                         USHORT usICONPOSSize,
                                         PICONPOS pipReturn)
{
    USHORT   usStartPos;
    PICONPOS pip;

    CHAR     szKey[100],
             szPath[CCHMAXPATH];

    PSZ      pszClass = _somGetClassName(pObject);

    ULONG    fl = objQueryFlags(pObject);       // V0.9.19 (2002-04-24) [umoeller]

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpGetIconPos");

    usStartPos = 21; // with OS/2 2.1 and above, Henk Kelder says

    _PmpfF(("flags for %s are %lX", _wpQueryTitle(pObject), fl));

    // first step: the icon position of each object within a given
    // .ICONPOS EA starts with a string identifying the object; so
    // first, we need to compose this string depending on the type
    // of the passed object
    if (fl & OBJFL_WPABSTRACT)
    {
        // abstract object:
        HOBJECT  hObject = _wpQueryHandle(pObject);
        _PmpfF(("object %s is abstract", _wpQueryTitle(pObject)));
        sprintf(szKey, "%s:A%lX", pszClass, LOUSHORT(hObject));
    }
    else if (fl & OBJFL_WPFILESYSTEM)
    {
        // file system object
        _PmpfF(("object %s is file-system", _wpQueryTitle(pObject)));
        if (_wpQueryFilename(pObject, szPath, FALSE))
        {
            sprintf(szKey,
                    "%s:%c%s",
                    pszClass,
                    (fl & OBJFL_WPFOLDER) ? 'D' : 'F',
                    szPath);
        }
        else
            return FALSE;
    }

    // now we have the key to search for within the .ICONPOS EA

    if ((pICONPOS) && (pipReturn))
    {
        /* now we go through the .ICONPOS data that was given to us
           and check each item in there if it matches the key we
           composed above */
        for (pip = (PICONPOS)(pICONPOS + usStartPos);
             (PBYTE)pip < pICONPOS + usICONPOSSize;
            )
        {
            if (!stricmp(pip->szIdentity, szKey))
            {
                *pipReturn = *pip;
                return TRUE;
            }
            pip = (PICONPOS)( (PBYTE)pip + sizeof(POINTL) + strlen(pip->szIdentity) + 1 );
        }
    }

    return FALSE;
}

/*
 *@@ xwpBeginEnumContent:
 *      this begins ordered content enumeration on a folder.
 *      Call this method before any call to XFolder::xwpEnumNext.
 *
 *      The "enum content" methods are similar to wpQueryContent,
 *      but take into account the order of objects in a folder.
 *      This is done by evaluating the .ICONPOS extended
 *      attributes of a folder.
 *
 *      This function returns an enumeration handle if the folder
 *      contains any objects at all. Pass this handle to any
 *      subsequent calls of XFolder::xwpEnumNext, and keep calling
 *      XFolder::xwpEnumNext until NULL is returned.
 *
 *      Then call XFolder::xwpEndEnumContent when you're
 *      done to free allocated resources.
 *
 *      If the folder is empty, NULLHANDLE is returned.
 *
 *      The "enum content" methods replace the following
 *      methods, which were present before V0.9.0:
 *               xfInvalidateOrderedContent,
 *               xfUpdateOrderedContent,
 *               xfQueryOrderedContent.
 *      The new methods do not keep memory allocated, so
 *      this new approach was taken.
 *
 *@@added V0.9.0 [umoeller]
 *@@changed V0.9.2 (2000-03-04) [umoeller]: added folder locking
 *@@changed V0.9.3 (2000-04-28) [umoeller]: now pre-resolving wpQueryContent for speed
 */

SOM_Scope ULONG  SOMLINK xf_xwpBeginEnumContent(XFolder *somSelf)
{
    PENUMCONTENT pec;

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpBeginEnumContent");

    if (pec = malloc(sizeof(ENUMCONTENT)))
    {
        BOOL                 fItemsFound = FALSE;
        WPObject             *pObj;
        BOOL                 fFolderLocked = FALSE;

        memset(pec, 0, sizeof(ENUMCONTENT));

        fdrCheckIfPopulated(somSelf,
                            FALSE);        // full populate

        // build new list for ORDEREDLISTITEMs:
        pec->pllOrderedContent = lstCreate(TRUE);       // auto-free list items

        TRY_LOUD(excpt1)
        {
            if (fFolderLocked = !_wpRequestFolderMutexSem(somSelf, 5000))
            {
                // get the folder's content as the WPS delivers it.
                // This is unsorted. Apparently, the WPS returns items
                // in the following order:
                // a)   first: file-system objects in the order returned
                //      by the file system (i.e. alphabetically on HPFS)
                // b)   then all abstract objects in the order they were
                //      placed in this folder.

                // V0.9.20 (2002-07-31) [umoeller]: now using get_pobjNext SOM attribute
                for (pObj = _wpQueryContent(somSelf, NULL, (ULONG)QC_FIRST);
                     pObj;
                     pObj = *__get_pobjNext(pObj))
                {
                    // create new list item
                    PORDEREDLISTITEM poliNew = malloc(sizeof(ORDEREDLISTITEM));
                    ULONG fl = objQueryFlags(pObj);
                    fItemsFound = TRUE;

                    // store object
                    poliNew->pObj = pObj;

                    // Each ICONPOS struct's identity string has the following format:
                    // <class>:<t><identity>
                    // with: <class> being the class of the object
                    //       <t> == A for abstracts, D for folders, F for files
                    //       <identity> for abstract objects: the handle
                    //                  for file-system objects: the filename

                    // now create the identity string for the search object
                    if (fl & OBJFL_WPABSTRACT)
                    {
                        // for abstract objects, this is the low word
                        // of the object handle
                        HOBJECT hobjSearch = _wpQueryHandle(pObj);

                        sprintf(poliNew->szIdentity, ":A%lX", (hobjSearch & 0xFFFF));
                    }
                    else if (fl & OBJFL_WPFILESYSTEM)
                    {
                        // for file-system objects, this is the object's real name
                        ULONG   ulSize = sizeof(poliNew->szIdentity) - 2;

                        poliNew->szIdentity[0] = ':';

                        if (fl & OBJFL_WPFOLDER)
                            poliNew->szIdentity[1] = 'D';
                        else
                            poliNew->szIdentity[1] = 'F';

                        poliNew->szIdentity[2] = '\0';

                        // append real name
                        _wpQueryRealName(pObj,
                                         poliNew->szIdentity + 2,
                                         &ulSize,
                                         FALSE);    // file name only
                    }
                    else
                        cmnLog(__FILE__, __LINE__, __FUNCTION__,
                               "sorting config folder %s: cannot determine type for %s",
                               _wpQueryTitle(somSelf),
                               _wpQueryTitle(pObj));

                    lstAppendItem(pec->pllOrderedContent,
                                  poliNew);
                }
            } // end if fFolderLocked
        }
        CATCH(excpt1) {} END_CATCH();

        if (fFolderLocked)
            _wpReleaseFolderMutexSem(somSelf);

        if (!fItemsFound)
        {
            // folder was empty:
            // cleanup
            lstFree(&pec->pllOrderedContent);
            free(pec);
            pec = NULL;
        }
        else
        {
            PEABINDING           peab;
            SORTBYICONPOS        sip;

            // read .ICONPOS extended attributes of this folder
            _wpQueryFilename(somSelf, sip.szRealName, TRUE);
            if (peab = eaPathReadOneByName(sip.szRealName, ".ICONPOS"))
            {

                //  typedef struct
                //  {
                //    BYTE bFlags;
                //    BYTE bNameLength;
                //    USHORT usValueLength;
                //    PSZ pszName;
                //    PSZ pszValue;
                //  } EABINDING, *PEABINDING;

                PBYTE pICONPOS;
                if (pICONPOS = malloc(peab->usValueLength + 100))
                {
                    ULONG ulICONPOSSize = peab->usValueLength - 5;
                    memcpy(pICONPOS,
                           peab->pszValue + 4,
                           peab->usValueLength - 3);

                    // finally, we have the ICONPOS data in _pICONPOS;
                    // now we pass the ICONPOS data to the sort function
                    // defined above

                    sip.pICONPOS = pICONPOS;
                    sip.usICONPOSSize = ulICONPOSSize;

                    lstQuickSort(pec->pllOrderedContent,
                                 fdrSortByICONPOS,
                                 &sip);     // addtl. param passed to sort func

                    free(pICONPOS);
                }

                eaFreeBinding(peab);
            }
        }
    }

    return (ULONG)pec;
}

/*
 *@@ xwpEnumNext:
 *      this keeps returning the ordered contents of a
 *      folder or NULL if no more objects are found.
 *
 *      Keep calling this function if XFolder::xwpBeginEnumContent
 *      returned a valid enumeration handle, until this
 *      function returns NULL.
 *
 *      Then call XFolder::xwpEndEnumContent when you're
 *      done to free allocated resources.
 *
 *@@added V0.9.0 [umoeller]
 */

SOM_Scope WPObject*  SOMLINK xf_xwpEnumNext(XFolder *somSelf,
                                            ULONG henum)
{
    WPObject *pObject = NULL;
    PENUMCONTENT pec = (PENUMCONTENT)henum;

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpEnumNext");

    if (pec)
    {
        if (pec->pnodeLastQueried == NULL)
            // first call: get first list node
            pec->pnodeLastQueried = lstQueryFirstNode(pec->pllOrderedContent);
        else
            // subsequent calls: get next list node
            pec->pnodeLastQueried = pec->pnodeLastQueried->pNext;

        if (pec->pnodeLastQueried)
        {
            // another item found:
            PORDEREDLISTITEM poli;
            if (poli = (PORDEREDLISTITEM)pec->pnodeLastQueried->pItemData)
                pObject = poli->pObj;
        }
    }

    return pObject;
}

/*
 *@@ xwpEndEnumContent:
 *      this frees resources allocated when enumerating
 *      folder contents.
 *
 *      See XFolder::xwpBeginEnumContent for how to use
 *      this.
 *
 *@@added V0.9.0 [umoeller]
 */

SOM_Scope BOOL  SOMLINK xf_xwpEndEnumContent(XFolder *somSelf,
                                             ULONG henum)
{
    PENUMCONTENT pec = (PENUMCONTENT)henum;
    BOOL brc = FALSE;
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpEndEnumContent");

    if (pec)
    {
        lstFree(&pec->pllOrderedContent);    // this will auto-free the list items
        free(pec);
        brc = TRUE;
    }

    return brc;
}

/*
 *@@ xwpStartFolderContents:
 *      this new XFolder method starts the contents of the folder with a
 *      specified delay for each object.
 *
 *      This displays a progress status window if the respective global
 *      setting is enabled.
 *
 *      If (ulTiming == 0), this operates in "wait" mode, i.e. the next
 *      object is only started after the previous one has been closed.
 *
 *      Otherwise ulTiming must specify a delay in milliseconds, being
 *      the time to wait after each object has been started.
 *
 *      This replaces the terrible "process ordered content" methods with
 *      three threads bombing each other with messages that nobody was
 *      able to follow. That code was still from the XFolder days and
 *      about due for retirement.
 *
 *      As opposed to the old implementation, this method DOES NOT RETURN
 *      until all objects have been processed or the user cancelled the
 *      operation. This does process the caller's message queue though...
 *      and therefore requires the caller to have one.
 *
 *      Returns either NO_ERROR or ERROR_INTERRUPT if the user pressed
 *      the "cancel" button.
 *
 *@@added V0.9.12 (2001-04-29) [umoeller]
 *@@changed V1.0.1 (2003-01-29) [umoeller]: this always returned 0, fixed
 */

SOM_Scope ULONG  SOMLINK xf_xwpStartFolderContents(XFolder *somSelf,
                                                   ULONG ulTiming)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpStartFolderContents");

    return fdrStartFolderContents(somSelf, ulTiming);
}

/*
 *@@ xwpMakeFavoriteFolder:
 *      if fInsert is TRUE, this folder will be made a "favorite folder",
 *      i.e. added to all context menus; if FALSE, it will be removed.
 *
 *@@changed V0.9.0 [umoeller]: updated for new linklist.c functions
 *@@changed V0.9.1: made folder list code generic in folder.c
 *@@changed V0.9.7 (2001-01-18) [umoeller]: added list notify on deletion, which fixed crashes
 */

SOM_Scope ULONG  SOMLINK xf_xwpMakeFavoriteFolder(XFolder *somSelf,
                                                  BOOL fInsert)
{
    // XFolderData     *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpMakeFavoriteFolder");

#ifndef __NOFOLDERCONTENTS__
    #if 1
        if (G_llFavoriteFolders)
            if (fInsert)
                return _Append(G_llFavoriteFolders,
                               somSelf);
            else
                return _Remove(G_llFavoriteFolders,
                               somSelf);
    #else
        return objAddToList(somSelf,
                            &G_llFavoriteFolders,
                            fInsert,
                            INIKEY_FAVORITEFOLDERS,
                            OBJLIST_FAVORITEFOLDER);
    #endif
#endif

    return FALSE;
}

/*
 *@@ xwpIsFavoriteFolder:
 *      returns TRUE if somSelf is on the list of "favorite" folders.
 *
 *@@changed V0.9.0 [umoeller]: updated for new linklist.c functions
 *@@changed V0.9.1: made folder list code generic in folder.c
 */

SOM_Scope BOOL  SOMLINK xf_xwpIsFavoriteFolder(XFolder *somSelf)
{
    // XFolderData     *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpIsFavoriteFolder");

#ifndef __NOFOLDERCONTENTS__
    #if 1
        if (G_llFavoriteFolders)
            return _IsIn(G_llFavoriteFolders,
                         somSelf);
    #else
        return objIsOnList(somSelf,
                           &G_llFavoriteFolders);
    #endif
#endif

    return FALSE;
}

/*
 *@@ xwpSetQuickOpen:
 *      if fQuickOpen == TRUE, somSelf will automatically be
 *      populated at Desktop startup.
 *
 *@@changed V0.9.0 [umoeller]: updated for new linklist.c functions
 *@@changed V0.9.1: made folder list code generic in folder.c
 *@@changed V0.9.7 (2001-01-18) [umoeller]: added list notify on deletion, which fixed crashes
 */

SOM_Scope ULONG  SOMLINK xf_xwpSetQuickOpen(XFolder *somSelf,
                                            BOOL fQuickOpen)
{
    // XFolderData     *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpSetQuickOpen");

#ifndef __NOQUICKOPEN__
    #if 1
        if (G_llQuickOpenFolders)
            if (fQuickOpen)
                return _Append(G_llQuickOpenFolders,
                               somSelf);
            else
                return _Remove(G_llQuickOpenFolders,
                               somSelf);
    #else
        return objAddToList(somSelf,
                            &G_llQuickOpenFolders,
                            fQuickOpen,
                            INIKEY_QUICKOPENFOLDERS,
                            OBJLIST_QUICKOPENFOLDER);
    #endif
#endif

    return FALSE;
}

/*
 *@@ xwpQueryQuickOpen:
 *      returns TRUE if somSelf has the QuickOpen feature ON.
 *
 *@@changed V0.9.0 [umoeller]: updated for new linklist.c functions
 *@@changed V0.9.1: made folder list code generic in folder.c
 */

SOM_Scope BOOL  SOMLINK xf_xwpQueryQuickOpen(XFolder *somSelf)
{
    // XFolderData     *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpSetQuickOpen");

#ifndef __NOQUICKOPEN__
    #if 1
        if (G_llQuickOpenFolders)
            return _IsIn(G_llQuickOpenFolders,
                         somSelf);
    #else
        return objIsOnList(somSelf,
                           &G_llQuickOpenFolders);
    #endif
#endif

    return FALSE;
}

/*
 *@@ xwpSetDefaultDocument:
 *      this sets the default document for this folder.
 *      If a default document is set for a folder, a
 *      double-click on the folder will not open the
 *      folder, but the default document instead.
 *
 *      Returns FALSE on errors, e.g. if pDefDoc is
 *      not a WPFileSystem or does not reside in the
 *      current folder (somSelf).
 *
 *      If pDefDoc is NULL, the default document is
 *      unset to restore normal folder behavior.
 *
 *@@added V0.9.4 (2000-06-09) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xf_xwpSetDefaultDocument(XFolder *somSelf,
                                                 WPFileSystem* pDefDoc)
{
    WPObject *pobjLock = NULL;
    BOOL brc = FALSE;
    XFolderMethodDebug("XFolder","xf_xwpSetDefaultDocument");

    TRY_LOUD(excpt1)
    {
        if (pobjLock = cmnLockObject(somSelf))
        {
            XFolderData *somThis = XFolderGetData(somSelf);

            if (!pDefDoc)
            {
                // NULL:
                _pDefaultDocument = NULL;
                brc = TRUE;
            }
            else
            {
                if (    (_somIsA(pDefDoc, _WPFileSystem))       // must be a WPFileSystem
                     && (_wpQueryFolder(pDefDoc) == somSelf)    // must be in this folder
                   )
                {
                    _pDefaultDocument = pDefDoc;
                    brc = TRUE;
                }
            }

            _wpSaveDeferred(somSelf);
        }
    }
    CATCH(excpt1) {} END_CATCH();

    if (pobjLock)
        _wpReleaseObjectMutexSem(pobjLock);

    return brc;
}

/*
 *@@ xwpQueryDefaultDocument:
 *      returns the default document which has been set
 *      previously with XFolder::xwpSetDefaultDocument
 *      or NULL if there's none.
 *
 *@@added V0.9.4 (2000-06-09) [umoeller]
 */

SOM_Scope WPFileSystem*  SOMLINK xf_xwpQueryDefaultDocument(XFolder *somSelf)
{
    WPFileSystem *rc = NULL;

    XFolderMethodDebug("XFolder","xf_xwpQueryDefaultDocument");

    if (!cmnIsADesktop(somSelf))
    {
        WPObject *pobjLock = NULL;
        TRY_LOUD(excpt1)
        {
            if (pobjLock = cmnLockObject(somSelf))
            {
                XFolderData *somThis = XFolderGetData(somSelf);

                if (_pWszDefaultDocDeferred)
                    // we have a default document, but this hasn't been
                    // resolved yet:
                    rc = NULL;
                else
                    rc = _pDefaultDocument;
            }
        }
        CATCH(excpt1) {} END_CATCH();

        if (pobjLock)
            _wpReleaseObjectMutexSem(pobjLock);
    }

    return rc;
}

/*
 *@@ xwpQueryMenuBarVisibility:
 *      returns TRUE or FALSE if Warp 4's folder bar is
 *      currently visible for this folder. On Warp 3, this
 *      always returns FALSE.
 *
 *      Warp 4 does have a method for querying this, but we want
 *      XWorkplace to run on Warp 3 also, so I have rewritten this.
 *
 *@@added V0.9.0 [umoeller]
 *@@changed V0.9.9 (2001-03-27) [umoeller]: global default was assumed wrong, fixed
 */

SOM_Scope BOOL  SOMLINK xf_xwpQueryMenuBarVisibility(XFolder *somSelf)
{
    XFolderMethodDebug("XFolder","xf_xwpQueryMenuBarVisibility");

    if (G_fIsWarp4)
    {
        XFolderData *somThis = XFolderGetData(somSelf);
        // to find out whether the menu bar has been enabled,
        // check the FDRLONGARRAY (xfldr.idl) to which we have
        // obtained a pointer using the ugly kludge in
        // XFolder::wpRestoreData
        // rewritten V1.0.0 (2002-08-24) [umoeller]
        PIBMFOLDERDATA pData;
        if (pData = (PIBMFOLDERDATA)_pvWPFolderData)
        {
            switch (pData->LongArray.ulMenuBarVisibility)
            {
                case MENUBAR_ON:        // 1
                    return TRUE;

                case MENUBAR_DEFAULT:   // 2
                    return mnuQueryDefaultMenuBarVisibility();
            }
        }
    }

    return FALSE;
}

/*
 *@@ xwpQueryStatusBarVisibility:
 *      this new instance method returns the status bar visibility of
 *      a folder:
 *
 *      -- STATUSBAR_ON:        status bars visible
 *      -- STATUSBAR_OFF:       status bars invisible
 *      -- STATUSBAR_DEFAULT:   use global setting for this folder
 *
 *@@changed V0.9.0 [umoeller]: function prototype changed
 */

SOM_Scope ULONG  SOMLINK xf_xwpQueryStatusBarVisibility(XFolder *somSelf)
{
    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpQueryStatusBarVisibility");

    return _bStatusBarInstance;
}

/*
 *@@ xwpSetStatusBarVisibility:
 *      this new instance method sets the status bar visibility of
 *      a folder.
 *
 *      ulVisibility may be:
 *
 *      -- STATUSBAR_ON:        show status bars
 *      -- STATUSBAR_OFF:       hide status bars
 *      -- STATUSBAR_DEFAULT:   use global setting for this folder
 *
 *      If fUpdate is TRUE, XFolder will have the Worker thread search
 *      for open folder views and update their frame controls accordingly.
 *      Otherwise the status bar setting will only be changed internally
 *      for the next time the folder is opened. Might lead to errors.
 *      Returns TRUE if successful.
 *
 *@@changed V0.9.11 (2001-04-22) [umoeller]: wpSaveDeferred was missing
 */

SOM_Scope BOOL  SOMLINK xf_xwpSetStatusBarVisibility(XFolder *somSelf,
                                                     ULONG ulVisibility,
                                                     BOOL fUpdate)
{
    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpSetStatusBarVisibility");

    if (_bStatusBarInstance != ulVisibility)
    {
        PMPF_STATUSBARS(("%d", ulVisibility));

        _bStatusBarInstance = ulVisibility;

        _wpSaveDeferred(somSelf);       // was missing V0.9.11 (2001-04-22) [umoeller]

        if (fUpdate)
        {
            PMPF_STATUSBARS(("posting WOM_UPDATEALLSTATUSBARS"));

            // update open folder views in Worker thread;
            // this will call fncbUpdateStatusBars for each
            // open folder window
            xthrPostWorkerMsg(WOM_UPDATEALLSTATUSBARS,
                              (MPARAM)1,      // show/hide flag
                              0);
            // update "XFolder" notebook page, if open
            ntbUpdateVisiblePage(somSelf, SP_XFOLDER_FLDR);
        }
    }

    return TRUE;
}

/*
 *@@ xwpUpdateStatusBar:
 *      this method gets called when the status bar needs updating.
 *
 *      To be more precise, it is fdr_fnwpStatusBar which calls this
 *      method after it has received STBM_UPDATESTATUSBAR and the
 *      update timer has elapsed.
 *
 *      This method has been introduced for two reasons:
 *
 *      a)   You can call it yourself if you need to have the
 *           status bar updated; use
 *
 +              WinQueryWindow(hwndFrame, ID_STATUSBAR)
 *
 *           to get hwndStatusBar for this method. If that call
 *           returns NULLHANDLE, there is no status bar for the
 *           folder view.
 *
 *      b)   You can override this method if you wish to have a
 *           different status bar display. This method gets called
 *           using SOM name-lookup resolution, so you can even
 *           override this method if you don't want to derive your
 *           folder class from XFolder. Simply define a method with
 *           the same prototype in your WPFolder subclass, and your
 *           method will get called instead of this default one.
 *
 *           The XWPTrashCan class (xtrash.c) is an example of a
 *           WPFolder (not XFolder!) subclass which overrides this
 *           method (see XWPTrashCan::xwpUpdateStatusBar).
 *
 *           See the SOM Programming Guide for details about name-lookup
 *           method resolution.
 *
 *      It is the responsibility of this method to completely compose
 *      the status bar text (according to the container contents) and
 *      set the status bar to that text. You can use a simple
 *      WinSetWindowText(hwndStatusBar, ...) for that.
 *
 *      This method calls stbComposeText (statbars.c) per default,
 *      which translates all status bar mnemonics except for the
 *      $x flags (tabulators), which are evaluated
 *
 *      If any $x flags are found (see the XWorkplace User Guide for
 *      WPObject status bar codes), these will be parsed during WM_PAINT
 *      of fdr_fnwpStatusBar only. So you can use those tags when
 *      setting the status bar's text to position status bar substrings.
 *      All other tags are not evaluated though.
 *
 *      hwndStatusbar has the HWND of the status bar window (a child
 *      of the folder frame). The QWL_USER window word of that
 *      window points to a STATUSBARDATA structure (statbars.h)
 *      containing more information.
 *
 *      hwndCnr is the container HWND of the folder view to which
 *      the status bar has been added. Use that for getting selected
 *      objects.
 *
 *@@added V0.9.0 [umoeller]
 */

SOM_Scope BOOL  SOMLINK xf_xwpUpdateStatusBar(XFolder *somSelf,
                                              HWND hwndStatusBar,
                                              HWND hwndCnr)
{
    PSZ psz;
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpUpdateStatusBar");

    if (psz = stbComposeText(somSelf,
                             hwndCnr))
    {
        WinSetWindowText(hwndStatusBar, psz);
        free(psz);
    }

    return (psz != 0);
}

/*
 *@@ xwpQueryXFolderStyle:
 *
 *@@added V1.0.1 (2002-11-30) [umoeller]
 */

SOM_Scope ULONG  SOMLINK xf_xwpQueryXFolderStyle(XFolder *somSelf)
{
    ULONG   ulrc = 0;
    BOOL    fFlagsLocked = FALSE;
    XFolderMethodDebug("XFolder","xf_xwpQueryXFolderStyle");

    // we need the lock here because xwpModifyFlags
    // reads and writes holding the lock too
    TRY_LOUD(excpt1)
    {
        XFolderData *somThis = XFolderGetData(somSelf);

        if (fFlagsLocked = objLockFlags())
        {
            ulrc = _flXFolderStyle;
        }
    }
    CATCH(excpt1) {} END_CATCH();

    if (fFlagsLocked)
        objUnlockFlags();

    return ulrc;
}

/*
 *@@ xwpSetXFolderStyle:
 *
 *@@added V1.0.1 (2002-11-30) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xf_xwpModifyXFolderStyle(XFolder *somSelf,
                                                 ULONG flFlags,
                                                 ULONG flMask,
                                                 BOOL fUpdate)
{
    BOOL    brc = FALSE,
            fFlagsLocked = FALSE;

    XFolderMethodDebug("XFolder","xf_xwpSetXFolderStyle");

    TRY_LOUD(excpt1)
    {
        XFolderData *somThis = XFolderGetData(somSelf);

        if (fFlagsLocked = objLockFlags())
        {
            _flXFolderStyle = (
                                  // copy all unaffected
                                  (_flXFolderStyle & ~flFlags)
                                  // OR with masked new ones
                                | (flFlags & flMask)
                              );

            brc = _wpSaveDeferred(somSelf);
        }
    }
    CATCH(excpt1) {} END_CATCH();

    if (fFlagsLocked)
        objUnlockFlags();

    return brc;
}

/*
 *@@ xwpBuildToolBar:
 *      this new XFolder instance method is called when a
 *      new folder view is opened and XWorkplace needs the
 *      tool bar layout for the new view.
 *
 *      This method must build the tool bar for the given
 *      view of somSelf by calling XFolder::xwpAddToolbarButton
 *      for each tool bar button that should be added.
 *
 *      hToolBar is a private handle of the toolbar and
 *      should be passed to that method.
 *
 *@@added V1.0.1 (2002-11-30) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xf_xwpBuildToolBar(XFolder *somSelf,
                                           ULONG hToolBar,
                                           ULONG ulView)
{
    HPOINTER    hptr;
    ULONG       flStyle = _xwpQueryXFolderStyle(somSelf),
                fl2;

    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpBuildToolBar");

    cmnGetStandardIcon(STDICON_TB_REFRESH, &hptr, NULL, NULL);
    _xwpAddToolbarButton(somSelf,
                         hToolBar,
                         (PSZ)cmnGetString(ID_XSSI_REFRESHNOW),
                         TBBS_COMMAND,
                         WPMENUID_REFRESH,
                         hptr);

    cmnGetStandardIcon(STDICON_TB_FIND, &hptr, NULL, NULL);
    _xwpAddToolbarButton(somSelf,
                         hToolBar,
                         (PSZ)cmnGetString(ID_XSDI_MENU_FIND),
                         TBBS_COMMAND,
                         WPMENUID_FIND,
                         hptr);

    cmnGetStandardIcon(STDICON_TB_HELP, &hptr, NULL, NULL);
    _xwpAddToolbarButton(somSelf,
                         hToolBar,
                         (PSZ)cmnGetString(DID_HELP),
                         TBBS_COMMAND,
                         WPMENUID_EXTENDEDHELP,
                         hptr);

    _xwpAddToolbarButton(somSelf,
                         hToolBar,
                         NULL,          // separator
                         0,
                         0,
                         0);

    cmnGetStandardIcon(STDICON_TB_MULTIPLECOLUMNS, &hptr, NULL, NULL);
    _xwpAddToolbarButton(somSelf,
                         hToolBar,
                         (PSZ)cmnGetString(ID_XSDI_MENU_ICONVIEW),
                         TBBS_COMMAND | TBBS_RADIO
                            | ((!(flStyle & XFFL_SPLIT_DETAILS))
                                ? TBBS_CHECKINITIAL
                                : 0),
                         WPMENUID_CHANGETOICON,
                         hptr);

    cmnGetStandardIcon(STDICON_TB_DETAILS, &hptr, NULL, NULL);
    _xwpAddToolbarButton(somSelf,
                         hToolBar,
                         (PSZ)cmnGetString(ID_XSDI_MENU_DETAILSVIEW),
                         TBBS_COMMAND | TBBS_RADIO
                            | ((flStyle & XFFL_SPLIT_DETAILS)
                                ? TBBS_CHECKINITIAL
                                : 0),
                         WPMENUID_CHANGETODETAILS,
                         hptr);

    cmnGetStandardIcon(STDICON_TB_SMALLICONS, &hptr, NULL, NULL);
    fl2 = TBBS_COMMAND | TBBS_CHECK;
    if (flStyle & XFFL_SPLIT_DETAILS)
        fl2 |= WS_DISABLED | TBBS_CHECKINITIAL;
    else if (!(flStyle & XFFL_SPLIT_NOMINI))
        fl2 |= TBBS_CHECKINITIAL;
    _xwpAddToolbarButton(somSelf,
                         hToolBar,
                         (PSZ)cmnGetString(ID_XFSI_SMALLICONS),
                         fl2,
                         *G_pulVarMenuOfs + ID_XFMI_OFS_SMALLICONS,
                         hptr);

    return TRUE;
}

/*
 *@@ xwpAddToolbarButton:
 *      adds a new tool bar button to the internal list
 *      when a tool bar is built for a new folder view.
 *
 *      This can _only_ be called form xwpBuildToolBar.
 *
 *      As a special case, if pcszTitle is NULL, this adds
 *      a vertical separator. All other parameters are ignored.
 *
 *@@added V1.0.1 (2002-11-30) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xf_xwpAddToolbarButton(XFolder *somSelf,
                                               ULONG hToolBar,
                                               PSZ pcszTitle,
                                               ULONG flStyle,
                                               USHORT usID,
                                               HPOINTER hptrIcon)
{
    PLINKLIST       pll;
    PTOOLBARCONTROL ptc;
    XSTRING         str;
    CHAR            sz[50];
    ULONG           cb;
    PCSZ            pcszClass;
    BOOL            brc = FALSE;
    PSZ             pszBuf;

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpAddToolbarButton");

    xstrInit(&str, 0);

    if (!pcszTitle)
    {
        // null title means separator
        pcszClass = WC_CCTL_SEPARATOR;
        pszBuf = NULL;
        ptc = (PTOOLBARCONTROL)malloc(sizeof(TOOLBARCONTROL));
    }
    else
    {
        cb = sprintf(sz, "#%d#", hptrIcon);
        xstrcpy(&str, sz, cb);
        xstrcat(&str, pcszTitle, 0);
        pcszClass = WC_CCTL_TBBUTTON;
        if (ptc = (PTOOLBARCONTROL)malloc(sizeof(TOOLBARCONTROL) + str.ulLength + 1))
        {
            // string buffer after TOOLBARCONTROL struct
            pszBuf = (PSZ)(ptc + 1);
            memcpy(pszBuf, str.psz, str.ulLength + 1);
        }
    }

    if (    (pll = (PLINKLIST)hToolBar)
         && (ptc)
       )
    {
        ptc->pcszClass = pcszClass;
        ptc->pcszTitle = pszBuf;
        ptc->flStyle = flStyle
                    | cmnQuerySetting(sflToolBarStyle)
                    | TBBS_DROPMNEMONIC
                    | TBBS_AUTORESIZE
                    | WS_VISIBLE
                    ;
        ptc->id = usID;
        ptc->cx = (pcszTitle) ? 50 : 10;
        ptc->cy = 10;
        lstAppendItem(pll, ptc);
        brc = TRUE;
    }

    xstrClear(&str);

    return brc;
}

/*
 *@@ xwpProcessViewCommand:
 *      this new XFolder instance method gets called when
 *      XFolder's subclassed window procedure
 *      (fnwpSubclWPFolderWindow) intercepts a WM_COMMAND
 *      message. This gets called before the WPS gets a
 *      chance to process that command, which will probably
 *      result in a call to wpMenuItemSelected for each of
 *      the affected objects in the container.
 *
 *      The purpose of this new message is to allow any folder
 *      (e.g. a subclass of WPFolder) to intercept object
 *      operations _before_ wpMenuItemSelected. While
 *      wpMenuItemSelected is OK for doing things which only
 *      affect a single object, it is not quite suitable
 *      for collecting all selected objects and processing
 *      them all at once. This is where overriding this method
 *      helps.
 *
 *      If this returns TRUE, it is assumed that the command
 *      was processed, and it is swallowed (i.e. not passed
 *      on to the standard WPS processing). If you're not
 *      interested in a command, you must return FALSE,
 *      or you'll break all other menu items.
 *
 *      Parameters:
 *
 *      -- usCommand has the command message (e.g. WPMENUID_DELETE).
 *
 *      -- hwndCnr has the folder's container window where the
 *         command originated from.
 *
 *      -- pFirstObject has the first of the selected objects.
 *
 *      -- ulSelectionFlags has information on the context why
 *         pFirstObject was considered selected. This is one
 *         of SEL_WHITESPACE, SEL_SINGLESEL, SEL_MULTISEL,
 *         SEL_SINGLEOTHER, SEL_NONEATALL (see wpshQuerySourceObject
 *         for details). You can use wpshQueryNextSourceObject to
 *         get the others, if this is indicated here.
 *
 *@@added V0.9.7 (2001-01-13) [umoeller]
 *@@changed V1.0.0 (2002-08-26) [umoeller]: method renamed from processObjectCommand
 */

SOM_Scope BOOL  SOMLINK xf_xwpProcessViewCommand(XFolder *somSelf,
                                                 USHORT usCommand,
                                                 HWND hwndCnr,
                                                 WPObject* pFirstObject,
                                                 ULONG ulSelectionFlags)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpProcessViewCommand");

    return fcmdProcessViewCommand(somSelf,
                                  usCommand,
                                  hwndCnr,
                                  pFirstObject,
                                  ulSelectionFlags);
}

/*
 *@@ xwpAddXFolderPages:
 *      this adds the new first "View" page into a folder settings notebook.
 *      This used to be the "XFolder" page with versions before 0.9.16.
 *
 *@@changed V0.9.16 (2001-09-29): now using dialog formatter
 */

SOM_Scope ULONG  SOMLINK xf_xwpAddXFolderPages(XFolder *somSelf,
                                               HWND hwndDlg)
{
    INSERTNOTEBOOKPAGE inbp;

    XFolderMethodDebug("XFolder","xf_xwpAddXFolderPages");

    memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
    inbp.somSelf = somSelf;
    inbp.hwndNotebook = hwndDlg;
    inbp.hmod = cmnQueryNLSModuleHandle(FALSE);
    inbp.ulDlgID = ID_XFD_EMPTYDLG; // ID_XSD_SETTINGS_FLDR1; V0.9.16 (2001-09-29) [umoeller]
    inbp.ulPageID = SP_XFOLDER_FLDR;
    inbp.usPageStyleFlags = BKA_MAJOR | BKA_MINOR;
    inbp.fEnumerate = TRUE;
    inbp.pcszName = cmnGetString(ID_XSSI_VIEWPAGE);    // V0.9.16 (2001-10-23) [umoeller]
    inbp.pcszMinorName = cmnGetString(ID_XSSI_GENERALVIEWPAGE);  // V0.9.16 (2001-10-23) [umoeller]
    inbp.ulDefaultHelpPanel  = ID_XSH_SETTINGS_FLDR1;
    inbp.pfncbInitPage    = fdrXFolderInitPage;
    inbp.pfncbItemChanged = fdrXFolderItemChanged;

    return ntbInsertPage(&inbp);
}

/*
 *@@ xwpQuerySetup2:
 *      this XFldObject method is overridden to support
 *      setup strings for folders.
 *
 *      See XFldObject::xwpQuerySetup2 for details.
 *
 *@@added V0.9.1 (2000-01-17) [umoeller]
 *@@changed V0.9.16 (2001-10-11) [umoeller]: adjusted to new implementation
 *@@changed V1.0.1 (2002-12-08) [umoeller]: now calling parent methods directly
 */

SOM_Scope BOOL  SOMLINK xf_xwpQuerySetup2(XFolder *somSelf, PVOID pstrSetup)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpQuerySetup2");

    // call XFolder implementation
    if (fdrQuerySetup(somSelf, pstrSetup))
        return parent_xwpQuerySetup2(somSelf,
                                     pstrSetup);

    return FALSE;
}

/*
 *@@ xwpSetDisableCnrAdd:
 *      sets the "disable automatic cnr add" flag for this folder.
 *
 *      Normally, this flag is FALSE (resulting in the standard
 *      WPS behavior for wpAddToContent). However, you may choose
 *      to call this method with (fDisable == TRUE), which will
 *      NOT automatically insert objects into the container when
 *      the folder is populated.
 *
 *      After that, the behavior of XFolder::wpAddToContent is
 *      modified with a number of ugly hacks to prevent object
 *      insertion.
 *
 *      NOTE: You must call this method during the processing
 *      of the folder's wpInitData, or otherwise the folder
 *      contents might become garbled.
 *
 *@@added V0.9.7 (2001-01-13) [umoeller]
 */

SOM_Scope void  SOMLINK xf_xwpSetDisableCnrAdd(XFolder *somSelf,
                                               BOOL fDisable)
{
    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_xwpSetDisableCnrAdd");

    _fDisableAutoCnrAdd = fDisable;
}

/*
 *@@ wpInitData:
 *      this WPObject instance method gets called when the
 *      object is being initialized (on wake-up or creation).
 *      We initialize our additional instance data here.
 *      Always call the parent method first.
 *
 *@@changed V0.9.4 (2000-08-02) [umoeller]: added "keep title" instance setting
 */

SOM_Scope void  SOMLINK xf_wpInitData(XFolder *somSelf)
{
    static SOMClass *s_pWPFolder = NULL;

    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpInitData");

    XFolder_parent_WPFolder_wpInitData(somSelf);

    // V1.0.1 (2003-01-25) [umoeller]
    _xwpModifyFlags(somSelf,
                    OBJFL_WPFOLDER,
                    OBJFL_WPFOLDER);

    // get pointer to IBM WPFolder instance data;
    // see WPProgram::wpInitData for more about this hack
    if (!s_pWPFolder)
    {
        // first call:
        SOMClass *pClass = _somGetClass(somSelf);
                        // XWPFolder class object now

        while (pClass = _somGetParent(pClass))
                    // either WPFolder class object or another
                    // WPFolder replacement now
        {
            if (!strcmp(_somGetName(pClass), "WPFolder"))
            {
                // got it:
                s_pWPFolder = pClass;

                PMPF_RESTOREDATA(("somGetInstanceSize %d",
                                _somGetInstanceSize(pClass)));
                PMPF_RESTOREDATA(("somGetInstancePartSize %d",
                                _somGetInstancePartSize(pClass)));
                PMPF_RESTOREDATA(("sizeof(IBMOBJECTDATA) %d",
                                sizeof(IBMOBJECTDATA)));

                break;
            }
        }
    }

    if (s_pWPFolder)
        _pvWPFolderData = somDataResolve(somSelf, _somGetInstanceToken(s_pWPFolder));
    else
        _pvWPFolderData = NULL; // shouldn't happen, but be safe

    // _PmpfF(("WPFolder data = 0x%lX, XFoldder data 0x%lX", _pvWPFolderData, somThis));

    // V1.0.1 (2002-11-30) [umoeller]
    _flXFolderStyle = XFFL_DEFAULTSTYLE;

    // set all the instance variables to safe defaults
    _bSnapToGridInstance = 2;
    _bFullPathInstance = 2;
    _bKeepTitleInstance = 2;
    _bFolderHotkeysInstance = 2;
    _bStatusBarInstance = STATUSBAR_DEFAULT;

    _lDefSortCrit = SET_DEFAULT;
    _lFoldersFirst = SET_DEFAULT;
    _lAlwaysSort = SET_DEFAULT;

    /*   all removed V1.0.0 (2002-08-24) [umoeller]
    _pFolderSortInfo = NULL;
    _pFolderLongArray = NULL;
    _pszFolderStrArray = NULL;
    _cbFolderStrArray = 0;
    _cbFolderLongArray = 0;

    _pFolderBackground = NULL;
    _cbFolderBackground = 0;

    _pulFolderShowAllInTreeView = NULL;

    _pWszFolderBkgndImageFile = NULL;
    */

    _pfnResolvedUpdateStatusBar = NULL;

    _pDefaultDocument = NULL; // V0.9.4 (2000-06-09) [umoeller]
    _pWszDefaultDocDeferred = NULL; // V0.9.4 (2000-06-09) [umoeller]

    _cObjects = 0;

    _fDisableAutoCnrAdd = FALSE;

    _cNotificationsPending = 0;

    treeInit((TREE**)&_FileSystemsTreeRoot,
             &_cFileSystems);
    treeInit((TREE**)&_AbstractsTreeRoot,
             &_cAbstracts);

    _pMonitor = NULL;
}

/*
 *@@ wpSetup:
 *      this WPObject instance method is called to allow an
 *      object to set itself up according to setup strings.
 *      As opposed to wpSetupOnce, this gets called any time
 *      a setup string is invoked.
 *
 *      XFolder will examine its setup strings here.
 *
 *@@changed V0.9.1 (2000-01-03) [umoeller]: now processing our own strings first
 *@@changed V0.9.6 (2000-10-16) [umoeller]: added QUICKOPEN=IMMEDIATE
 */

SOM_Scope BOOL  SOMLINK xf_wpSetup(XFolder *somSelf, PSZ pszSetupString)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpSetup");

    if (    (XFolder_parent_WPFolder_wpSetup(somSelf, pszSetupString))
         && (fdrSetup(somSelf, pszSetupString))
       )
        return TRUE;

    return FALSE;
}

/*
 *@@ wpObjectReady:
 *      this WPObject notification method gets called by the
 *      WPS when object instantiation is complete, for any reason.
 *      ulCode and refObject signify why and where from the
 *      object was created.
 *      The parent method must be called first.
 *
 *      See XFldObject::wpObjectReady for remarks about using
 *      this method as a copy constructor.
 *
 *      We will have this object's pointer stored
 *      in a global list (maintained by the Worker thread)
 *      so that XShutdown knows which objects are currently
 *      awake.
 *
 *      Note: XFldObject::wpObjectReady already does this
 *      for all objects, but on my Warp 4 (FP 10), that
 *      method does _not_ get called for WPFolder instances,
 *      so we override this method for XFolder also.
 *
 *@@added V0.9.0 [umoeller]
 *@@changed V0.9.4 (2000-06-09) [umoeller]: added default document
 *@@changed V0.9.19 (2002-04-02) [umoeller]: fixed missing XFldObject initialization, which caused the missing refresh on rename
 */

SOM_Scope void  SOMLINK xf_wpObjectReady(XFolder *somSelf,
                                         ULONG ulCode,
                                         WPObject* refObject)
{
    WPObject *pobjLock = NULL;
    // XFolderMethodDebug("XFolder","xf_wpObjectReady");

    PMPF_SOMMETHODS(("XFolder::wpObjectReady for %s (class %s), ulCode: %s",
                     _wpQueryTitle(somSelf),
                     _somGetName(_somGetClass(somSelf)),
                     (ulCode == OR_AWAKE) ? "OR_AWAKE"
                     : (ulCode == OR_FROMTEMPLATE) ? "OR_FROMTEMPLATE"
                     : (ulCode == OR_FROMCOPY) ? "OR_FROMCOPY"
                     : (ulCode == OR_NEW) ? "OR_NEW"
                     : (ulCode == OR_SHADOW) ? "OR_SHADOW"
                     : (ulCode == OR_REFERENCE) ? "OR_REFERENCE"
                     : "unknown code"
                   ));

    // call the WPFolder parent method... HOWEVER, apparently WPFolder
    // doesn't call its parent, that's why the init flags were never
    // set; so call objReady explicitly afterwards
    XFolder_parent_WPFolder_wpObjectReady(somSelf, ulCode, refObject);

    /* xthrPostWorkerMsg(WOM_ADDAWAKEOBJECT,
                      (MPARAM)somSelf,
                      MPNULL); */ // handled by objReady now V0.9.19 (2002-04-02) [umoeller]

    objReady(somSelf, ulCode, refObject);

    TRY_LOUD(excpt1)
    {
        if (ctsIsRootFolder(somSelf))
        {
            // a root folder has been made awake:
            fdrRegisterAwakeRootFolder(somSelf);
            // strange, we never get this for WPSharedDir objs
        }

        if (pobjLock = cmnLockObject(somSelf))
        {
            XFolderData *somThis = XFolderGetData(somSelf);

            // were we copied?
            if (ulCode & OR_REFERENCE)
            {
                // XFolderData *somThat = XFolderGetData(refObject);
                // yes: fix the instance data which SOM has done
                // a flat binary copy on... V0.9.7 (2000-12-13) [umoeller]
                _pfnResolvedUpdateStatusBar = NULL;

                _pDefaultDocument = NULL;
            }


            // in all cases, resolve deferred default document
            if (_pWszDefaultDocDeferred)
            {
                // this has been set by wpRestoreState
                _pDefaultDocument = wpshContainsFile(somSelf, _pWszDefaultDocDeferred);
                    // can return NULL if not found
                wpshStore(somSelf, &_pWszDefaultDocDeferred, NULL, NULL);
            }
        }
    }
    CATCH(excpt1) {} END_CATCH();

    if (pobjLock)
        _wpReleaseObjectMutexSem(pobjLock);
}

/*
 *@@ wpUnInitData:
 *      this WPObject instance method is called when the object
 *      is destroyed as a SOM object, either because it's being
 *      made dormant (via wpMakeDormant) or being deleted for
 *      good (via wpFree). All allocated in-memory resources
 *      should be freed here, but to destroy the physical
 *      representation of the object, override wpDestroyObject
 *      instead.
 *
 *      The parent method must always be called last.
 *
 *@@changed V0.9.9 (2001-02-01) [umoeller]: added notify cleanup, semaphores
 *@@changed V0.9.12 (2001-05-22) [umoeller]: fixed refresh synchronization
 *@@changed V0.9.16 (2001-11-25) [umoeller]: fixed crash on config folder delete
 */

SOM_Scope void  SOMLINK xf_wpUnInitData(XFolder *somSelf)
{
    PUSEITEM pui;

    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpUnInitData");

    if (somSelf == G_pConfigFolder)
        // unset this or we'll crash on the next menu build
        // V0.9.16 (2001-11-25) [umoeller]
        G_pConfigFolder = NULL;

    wpshStore(somSelf, &_pWszDefaultDocDeferred, NULL, NULL);

    // lock out the folder auto-refresh
    if (fdrGetNotifySem(SEM_INDEFINITE_WAIT))
    {
        // now check if we have any pending file-system
        // notifications from folder auto-refresh
        if (_cNotificationsPending)     // V0.9.12 (2001-05-22) [umoeller]
        {
            refrClearFolderNotifications(somSelf);
            _cNotificationsPending = 0;
        }

        fdrReleaseNotifySem();
    }

    // request the object mutex; we can LEAVE it requested since
    // XFldObject::wpUnInitData will request it anyway, and
    // WPObject::wpUnInitData will delete the mutex
    _wpRequestObjectMutexSem(somSelf, SEM_INDEFINITE_WAIT);

    // check if this folder is currently showing on the right
    // side of the folder split view; if so, then we MUST
    // notify the split view because it has internal pointers
    // to somSelf that must be removed
    // V1.0.0 (2002-08-28) [umoeller]
    for (pui = _wpFindUseItem(somSelf, USAGE_OPENVIEW, NULL);
         pui;
         pui = _wpFindUseItem(somSelf, USAGE_OPENVIEW, pui))
    {
        PVIEWITEM pvi = (PVIEWITEM)(pui + 1);

        if (pvi->view == *G_pulVarMenuOfs + ID_XFMI_OFS_SPLIT_SUBFILES)
        {
            // the view item "handle" is the view handle
            // of the split view's hwndFilesFrame
            WinSendMsg(pvi->handle,
                       FM_DELETINGFDR,
                       NULL,
                       NULL);
        }
    }

    XFolder_parent_WPFolder_wpUnInitData(somSelf);
        // fixed this (V0.9.0)
}

/*
 *@@ wpFree:
 *      this WPObject method destroys the persistent form of the object
 *      and then frees the memory that represented that object.
 *      See object.c for a detailed description of an object's lifecycle.
 *
 *      For WPFolders, this is called when a folder is actually to be
 *      deleted. We will call the parent method and then also remove
 *      those darn PMWorkplace:FolderPos entries which the WPS never
 *      deletes.
 *
 *      If the folder is somewhere in the config folder hierarchy,
 *      we also invalidate the config folder caches in fdrmenus.c.
 *
 *@@changed V0.9.0 [umoeller]: adjusted to new config folder handling
 *@@changed V0.9.12 (2001-05-12) [umoeller]: removed wpQueryHandle for now
 */

SOM_Scope BOOL  SOMLINK xf_wpFree(XFolder *somSelf)
{
    BOOL        brc;
    // HOBJECT     hObj = NULLHANDLE;
    // XFolder *pCfg = _xwpclsQueryConfigFolder(_XFolder);

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpFree");

    /* if (cmnQuerySetting(sCleanupINIs))
    {
        // "clean up INI files": get object handle for
        // folderpos deletion later. This doesn't hurt
        // because every folder has a handle once it has
        // been opened
        hObj = _wpQueryHandle(somSelf);
    } */

    // @@ todo replace this!! we don't want to create
    // a handle for every folder

    // according to WPS docs, the parent method should be called
    // AFTER additional processing; probably somSelf becomes invalid
    // after this
    brc = XFolder_parent_WPFolder_wpFree(somSelf);

    /* if (brc)
        // successfully deleted:
        if (hObj)
            // have FOLDERPOS entries
            // deleted by Worker thread; we only pass the
            // object HANDLE and not somSelf because somSelf
            // is no longer valid after having called the parent
            xthrPostWorkerMsg(WOM_DELETEFOLDERPOS,
                              (MPARAM)hObj, NULL);
       */

    return brc;
}

/*
 *@@ wpDestroyObject:
 *      this undocumented WPObject method gets called during
 *      wpFree processing to destroy the physical storage of
 *      an object (for file-system objects, the file or folder,
 *      for abstracts, the INI data).
 *
 *      Starting with V0.9.20, we are now able to override this
 *      undocumented WPS method too, so the previous overhead
 *      with xwpDestroyStorage has been removed.
 *
 *      This implementation actually deletes the folder using
 *      DosDeleteDir.
 *
 *      As opposed to the WPS, we are smart enough NOT to
 *      display a message box here if the folder no longer
 *      exists in the first place. In that case, we return
 *      TRUE, since the folder was obviously already deleted.
 *
 *@@added V0.9.20 (2002-07-25) [umoeller]
 *@@changed V1.0.0 (2002-09-09) [umoeller]: added wpSetError on errors
 */

SOM_Scope BOOL  SOMLINK xf_wpDestroyObject(XFolder *somSelf)
{
    BOOL    brc = FALSE;
    CHAR    szFilename[CCHMAXPATH];

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpDestroyObject");

    if (_wpQueryFilename(somSelf, szFilename, TRUE))
    {
        APIRET arc = DosDeleteDir(szFilename);

        // _PmpfF(("DosDelete returned %d", arc));

        switch (arc)
        {
            case NO_ERROR:
                // if the fs object doesn't exist any more,
                // simply return TRUE also
            case ERROR_FILE_NOT_FOUND:
            case ERROR_PATH_NOT_FOUND:
                brc = TRUE;
            break;

            default:
                // anything else is truly an error, so set an error
                // code on the object so fops_bottom.c can figure
                // out what went wrong; wpFree has called
                // wpSetError(NO_ERROR) previously
                // V1.0.0 (2002-09-09) [umoeller]
                _wpSetError(somSelf, arc);
        }
    }

    return brc;

    // return XFolder_parent_WPFolder_wpDestroyObject(somSelf);
}

/*
 *@@ wpSaveState:
 *      this WPObject instance method saves an object's state
 *      persistently so that it can later be re-initialized
 *      with wpRestoreState. This gets called during wpClose,
 *      wpSaveImmediate or wpSaveDeferred processing.
 *      All persistent instance variables should be stored here.
 *
 *@@changed V0.9.4 (2000-06-09) [umoeller]: added default document
 *@@changed V0.9.4 (2000-08-02) [umoeller]: added "keep title" instance setting
 *@@changed V0.9.7 (2000-12-18) [umoeller]: fixed folder sorts
 *@@changed V0.9.12 (2001-05-18) [umoeller]: reworked for new folder sorting
 *@@changed V1.0.1 (2002-11-30) [umoeller]: added tool bar
 */

SOM_Scope BOOL  SOMLINK xf_wpSaveState(XFolder *somSelf)
{
    BOOL brc = FALSE;
    XFolderData *somThis = XFolderGetData(somSelf);
    // XFolderMethodDebug("XFolder","xf_wpSaveState");

    PMPF_RESTOREDATA(("[%s]", _wpQueryTitle(somSelf)));

    // we will now save all our instance data; in order
    // not to blow up the EA size too much, we will only
    // save data which is different from the "transparent"
    // (i.e. Global) setting

    if (_bSnapToGridInstance != 2)
        _wpSaveLong(somSelf, (PSZ)G_pcszXFolder, 1, (ULONG)_bSnapToGridInstance);
    if (_bFullPathInstance != 2)
        _wpSaveLong(somSelf, (PSZ)G_pcszXFolder, 2, (ULONG)_bFullPathInstance);
    if (_bFolderHotkeysInstance != 2)
        _wpSaveLong(somSelf, (PSZ)G_pcszXFolder, 3, (ULONG)_bFolderHotkeysInstance);
    if (_bStatusBarInstance != STATUSBAR_DEFAULT)
        _wpSaveLong(somSelf, (PSZ)G_pcszXFolder, 4, (ULONG)_bStatusBarInstance);

    // ID 5 used to be inflated SB frame, must not be used again

    // ID 6 used to be "always sort", this has been raised to 9
    // ID 7 used to be "default sort", this has been raised to 10
    // V0.9.7 (2000-12-18) [umoeller]

    if (_pDefaultDocument)  // V0.9.4 (2000-06-09) [umoeller]
    {
        CHAR szDefaultDoc[CCHMAXPATH];
        _wpQueryFilename(_pDefaultDocument, szDefaultDoc, FALSE);   // not qualified
        _wpSaveString(somSelf, (PSZ)G_pcszXFolder, 8, szDefaultDoc);
    }

    // sort keys changed again V0.9.12 (2001-05-18) [umoeller]
    // note: we must always save these, even if they have the default value
    _wpSaveLong(somSelf, (PSZ)G_pcszXFolder, 11, (ULONG)_lDefSortCrit);
    _wpSaveLong(somSelf, (PSZ)G_pcszXFolder, 12, (ULONG)_lFoldersFirst);
    _wpSaveLong(somSelf, (PSZ)G_pcszXFolder, 13, (ULONG)_lAlwaysSort);

    // V1.0.1 (2002-11-30) [umoeller]
    if (_flXFolderStyle != XFFL_DEFAULTSTYLE)
        _wpSaveLong(somSelf, (PSZ)G_pcszXFolder, 14, (ULONG)_flXFolderStyle);

    brc = XFolder_parent_WPFolder_wpSaveState(somSelf);

    PMPF_RESTOREDATA(("%s: End of wpSaveState", _wpQueryTitle(somSelf)));

    return brc;
}

/*
 *@@ wpRestoreState:
 *      this WPObject instance method gets called during object
 *      initialization (after wpInitData) to restore the data
 *      which was stored with wpSaveState.
 *
 *      We restore XFolder isntance data such as the sort
 *      settings.
 *
 *      In addition, we speed up icon loading for folders. While
 *      the WPS at least tries to speed up icon loading for
 *      data files in this method (see XFldDataFile::wpRestoreState),
 *      it doesn't do so for folders even though the data is
 *      very much present in the FILEFINDBUF3 passed in ulReserved.
 *      So what we do for folders is parse the icon buffer here;
 *      if we find any data, we set the icon here.
 *
 *      In addition, we override XWPFileSystem::wpQueryIcon to
 *      avoid going to the file system again which can
 *      significantly speed up folder icons on CD-ROM drives,
 *      for example.
 *
 *@@changed V0.9.4 (2000-06-09) [umoeller]: added default document
 *@@changed V0.9.4 (2000-08-02) [umoeller]: added "keep title" instance setting
 *@@changed V0.9.12 (2001-05-18) [umoeller]: reworked for new folder sorting
 *@@changed V0.9.16 (2002-01-04) [umoeller]: added icon handling
 *@@changed V1.0.1 (2002-11-30) [umoeller]: added tool bar
 */

SOM_Scope BOOL  SOMLINK xf_wpRestoreState(XFolder *somSelf,
                                          ULONG ulReserved)
{
    ULONG   ul;
    BOOL    brc;
    CHAR    szDefaultDoc[CCHMAXPATH];
    ULONG   cbDefaultDoc = sizeof(szDefaultDoc);

    XFolderData *somThis = XFolderGetData(somSelf);
    // XFolderMethodDebug("XFolder","xf_wpRestoreState");

    PMPF_RESTOREDATA(("[%s]", _wpQueryTitle(somSelf) ));

#ifndef __NOTURBOFOLDERS__
    // new icon handling code follows
    // V0.9.16 (2002-01-04) [umoeller]
    if (cmnQuerySetting(sfTurboFolders))
    {
        PMAKEAWAKEFS pFSData = (PMAKEAWAKEFS)ulReserved;
        PMINIRECORDCORE prec = _wpQueryCoreRecord(somSelf);
        APIRET arc;
        HPOINTER hptrNew;

        if (    (!prec->hptrIcon)
             && (pFSData)
             && (pFSData->pFea2List)
             && (!(arc = icoBuildPtrFromFEA2List(pFSData->pFea2List,
                                                 &hptrNew,
                                                 NULL,
                                                 NULL)))
           )
        {
            _wpSetIcon(somSelf, hptrNew);
            _wpModifyStyle(somSelf,
                           OBJSTYLE_NOTDEFAULTICON,
                           OBJSTYLE_NOTDEFAULTICON);
        }
    }
#endif

    // we will now restore all the different XFolder settings
    // into the instance data; note that if _wpRestoreLong
    // returns FALSE (i.e. setting not found), we always use
    // the "transparent" value which makes this folder use
    // the corresponding Global Setting

    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXFolder, 1, &ul))
        _bSnapToGridInstance = (BYTE)ul;
    else
        _bSnapToGridInstance = 2;

    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXFolder, 2, &ul))
        _bFullPathInstance = (BYTE)ul;
    else
        _bFullPathInstance = 2;

    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXFolder, 3, &ul))
        _bFolderHotkeysInstance = (BYTE)ul;
    else
        _bFolderHotkeysInstance = 2;

    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXFolder, 4, &ul))
        _bStatusBarInstance = (BYTE)ul;
    /* else         not needed, this is the default from wpInitData
        _bStatusBarInstance = STATUSBAR_DEFAULT; */

    // ID 5 used to be inflated SB frame, must not be used again

    // ID 6 used to be "always sort", this has been raised to 9
    // ID 7 used to be "default sort", this has been raised to 10
    // V0.9.7 (2000-12-18) [umoeller]

    if (_wpRestoreString(somSelf, (PSZ)G_pcszXFolder, 8, szDefaultDoc, &cbDefaultDoc))
        // store file name in instance data; wpObjectReady will then
        // find the file, which doesn't work when the folder isn't
        // fully initialized
        wpshStore(somSelf, &_pWszDefaultDocDeferred, szDefaultDoc, NULL);

    // sort keys changed again V0.9.12 (2001-05-18) [umoeller]

    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXFolder, 11, &ul))
        _lDefSortCrit = ul;

    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXFolder, 12, &ul))
        _lFoldersFirst = ul;

    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXFolder, 13, &ul))
        _lAlwaysSort = ul;
    else
        // setting not found:
        if (cmnIsADesktop(somSelf))
            // otherwise we might automatically sort the desktop...
            // not really what we want!
            _lAlwaysSort = FALSE;

    PMPF_SORT(("[%s] _bAlwaysSortInstance is %d",
                _wpQueryTitle(somSelf), _lAlwaysSort));

    // V1.0.1 (2002-11-30) [umoeller]
    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXFolder, 14, &ul))
        _flXFolderStyle = (BYTE)ul;

    // in this case, we MUST call the parent LAST because
    // wpRestoreData checks for whether an XFolder sort setting
    // has been restored!!
    brc = XFolder_parent_WPFolder_wpRestoreState(somSelf, ulReserved);

    PMPF_RESTOREDATA(("  End of XFolder::wpRestoreState"));

    return brc;
}

/*
 *@@ wpRestoreData:
 *      this WPObject instance method restores a chunk
 *      of binary instance data which was previously
 *      saved by WPObject::wpSaveData.
 *
 *      This may only be used while WPObject::wpRestoreState
 *      is being processed.
 *
 *      This method normally isn't designed to be overridden.
 *      However, since this gets called by WPFolder::wpRestoreState,
 *      we override this method to be able to intercept pointers
 *      to the WPFolder instance data and compare them to what
 *      we've calculated in the IBMFOLDERDATA for debugging.
 *
 *@@changed V0.9.7 (2000-12-18) [umoeller]: fixed always sort bug
 *@@changed V1.0.0 (2002-08-24) [umoeller]: removed all code, except for debugging
 */

SOM_Scope BOOL  SOMLINK xf_wpRestoreData(XFolder *somSelf,
                                         PSZ pszClass, ULONG ulKey,
                                         PBYTE pValue, PULONG pcbValue)
{
    BOOL        brc;

#ifdef __DEBUG__
    ULONG       cbOrigValue = 0;
    // XFolderMethodDebug("XFolder","xf_wpRestoreData");

    // get the size of the buffer which was given to us
    if (pValue)
        // pValue given:
        cbOrigValue = *pcbValue;
    // else: caller is requesting the size of the data
#endif

    // always call parent, even for the sort data, or
    // the WPFolder original gets confused
    brc = XFolder_parent_WPFolder_wpRestoreData(somSelf,
                                                pszClass, ulKey,
                                                pValue, pcbValue);

#ifdef __DEBUG__
    // after we have restored the setting by calling the
    // default WPFolder method, we check for a few flags
    // which we might be interested in; we can then store
    // the pointer to WPS-internal data in XFolder instance
    // data
    if (!strcmp(pszClass, G_pcszWPFolder))
    {
        XFolderData *somThis = XFolderGetData(somSelf);

        switch (ulKey)
        {
            case IDKEY_FDRBACKGROUND:       // size: 2 bytes
                if (pValue)
                {
                    // _cbFolderBackground = *pcbValue;
                    // _pFolderBackground = (PVOID)pValue;
                    PIBMFOLDERDATA pData = (PIBMFOLDERDATA)_pvWPFolderData;
                    PMPF_RESTOREDATA(("0x%lX <-- pValue of IDKEY_FDRBACKGROUND (%d bytes)",
                                pValue,
                                *pcbValue));
                    PMPF_RESTOREDATA(("0x%lX <-- we calculated (%d bytes)",
                                &pData->Background.BkgndStore,
                                sizeof(IBMFDRBKGNDSTORE)));
                }
            break;

            case IDKEY_FDRSORTINFO:
                // then the pointer given to this method (pValue) must
                // be the pointer to the WPFolder-internal FDRSORTINFO
                // structure (undocumented, I've declared it in
                // xfldr.idl); we store this pointer in the instance
                // data so that we can manipulate it later
                if (pValue)
                {
                    PIBMFOLDERDATA pData = (PIBMFOLDERDATA)_pvWPFolderData;
                    PMPF_RESTOREDATA(("0x%lX <-- pValue of IDKEY_FDRSORTINFO (%d bytes)",
                                pValue,
                                *pcbValue));
                    PMPF_RESTOREDATA(("0x%lX <-- we calculated (%d bytes)",
                                &pData->SortInfo,
                                sizeof(IBMSORTINFO)));
                }

            break;

            /* case IDKEY_FDRCNRBACKGROUND:
                _Pmpf(("%s::wpRestoreString: IDKEY_FDRCNRBACKGROUND -> %d",
                       _wpQueryTitle(somSelf),
                       brc));
                if (pValue)
                {
                    XFolderData *somThis = XFolderGetData(somSelf);
                    _cbFdrCnrBackground = *pcbValue;
                    _pszFdrCnrBackground = pValue;     // buffer
                }
            break; */

            case IDKEY_FDRLONGARRAY:        // size: 84 bytes
                // store the size of the data returned in
                // folder instance data, in case it is not
                // 84 bytes (as it is with Warp 4 fixpak 8)
                // _cbFolderLongArray = *pcbValue;
                if (pValue)
                {
                    PIBMFOLDERDATA pData = (PIBMFOLDERDATA)_pvWPFolderData;
                    PMPF_RESTOREDATA(("0x%lX <-- pValue of IDKEY_FDRLONGARRAY (%d bytes)",
                                pValue,
                                *pcbValue));
                    PMPF_RESTOREDATA(("0x%lX <-- we calculated (%d bytes)",
                                &pData->LongArray,
                                sizeof(FDRLONGARRAY)));
                    // _pFolderLongArray = (PFDRLONGARRAY)pValue;
                }
            break;

/*
            case IDKEY_FDRSTRARRAY:         // size: 400 bytes
                // store the size of the data returned in
                // folder instance data, in case it is not
                // 400 bytes (as it is with Warp 4 fixpak 8)
                if (pValue)
                {
                    // _pFolderLongArray = (PFDRLONGARRAY)pValue;
                    _cbFolderStrArray = *pcbValue;
                    _pszFolderStrArray = (PSZ)pValue;
                }
            break;
*/

            /* case IDKEY_CNRBACKGROUND:
            {
                XFolderData *somThis = XFolderGetData(somSelf);
                if (pValue)
                {
                    _cbCnrBackground = *pcbValue;
                    _pvCnrBackground = pValue;
                }
            }
            break;  */

            /*
             * the following others were queried for G:\root\test
             * under Warp 4 fixpak 8:
             */

            /*
                IDKEY_xxx (WPObject 11) size 32 -> 32           WPOBJECT_DATA
                IDKEY_xxx (WPObject 12) size 400 -> 400         WPOBJECT_STRINGS
                IDKEY_xxx (WPObject 4) size 8 -> 8              ?!?
                IDKEY_xxx (WPFolder 2924) size 542 -> 542       IDKEY_CNRBACKGROUND
                IDKEY_xxx (WPFolder 2920) size 542 -> 542       IDKEY_FDRINCCLASS
                IDKEY_xxx (WPFolder 2925) size 542 -> 542       IDKEY_FDRINCCRITERIA
                IDKEY_xxx (WPFolder 2938) size 8 -> 8           IDKEY_FDRGRIDINFO

            and these under Warp 3, no fixpaks:
                IDKEY_xxx (WPObject 11) size 28 -> 28           (+) four bytes less
                IDKEY_xxx (WPObject 12) size 400 -> 400         (+)
                IDKEY_xxx (WPObject 4) size 8 -> 8              (+)
                IDKEY_xxx (WPFolder 2924) size 542 -> 542       (+)
                IDKEY_xxx (WPFolder 2920) size 542 -> 542       (+)
                IDKEY_xxx (WPFolder 2925) size 542 -> 542       (+)
                i.e. the same, except the grid info

            but if we had a folder background set (Warp 4):
                IDKEY_xxx (WPObject 11) size 32 -> 32
                IDKEY_xxx (WPObject 12) size 400 -> 400
                IDKEY_xxx (WPObject 4) size 8 -> 8
                IDKEY_xxx (WPFolder 2924) size 542 -> 542       IDKEY_CNRBACKGROUND
                IDKEY_xxx (WPFolder 2920) size 542 -> 542       IDKEY_FDRINCCLASS
                IDKEY_xxx (WPFolder 2925) size 542 -> 107       IDKEY_FDRINCCRITERIA
                IDKEY_xxx (WPFolder 2920) size 260 -> 260       IDKEY_FDRINCCLASS
                IDKEY_xxx (WPFolder 2925) size 260 -> 107       IDKEY_FDRINCCRITERIA
                IDKEY_xxx (WPFolder 2925) size 107 -> 107       IDKEY_FDRINCCRITERIA
                IDKEY_xxx (WPFolder 2938) size 8 -> 8
            and on Warp 3:
                IDKEY_xxx (WPObject 11) size 28 -> 28
                IDKEY_xxx (WPObject 12) size 400 -> 400
                IDKEY_xxx (WPObject 4) size 8 -> 8
                                                            no  IDKEY_CNRBACKGROUND
                IDKEY_xxx (WPFolder 2920) size 259 -> 259       IDKEY_FDRINCCLASS
                IDKEY_xxx (WPFolder 2925) size 259 -> 178       IDKEY_FDRINCCRITERIA
                IDKEY_xxx (WPFolder 2920) size 260 -> 260       IDKEY_FDRINCCLASS
                IDKEY_xxx (WPFolder 2925) size 260 -> 178       IDKEY_FDRINCCRITERIA
                IDKEY_xxx (WPFolder 2925) size 178 -> 178       IDKEY_FDRINCCRITERIA

            */

            /* this is what we got from the "Programme" folder (Warp 4):

                 Long IDKEY_xxx (WPFileSystem 4) --> 0x0
                 Data IDKEY_xxx (WPObject 11) size 32 -> 32         WPOBJECT_DATA
                 Data IDKEY_xxx (WPObject 12) size 400 -> 400       WPOBJECT_STRINGS
                 Data IDKEY_xxx (WPObject 4) size 8 -> 8            ?!?
                 Data IDKEY_xxx (WPFolder 2924) size 542 -> 542     IDKEY_CNRBACKGROUND
                 Strg IDKEY_xxx (WPFolder 2921) --> NULL            IDKEY_FDRINCNAME
                 Data IDKEY_xxx (WPFolder 2920) size 0 -> 542       IDKEY_FDRINCCLASS
                 Data IDKEY_xxx (WPFolder 2925) size 0 -> 107       IDKEY_FDRINCCRITERIA
                 Data IDKEY_xxx (WPFolder 2920) size 0 -> 260       * IDKEY_FDRINCCLASS
                 Data IDKEY_xxx (WPFolder 2925) size 0 -> 107       * IDKEY_FDRINCCRITERIA
                 Data IDKEY_xxx (WPFolder 2925) size 107 -> 107     * IDKEY_FDRINCCRITERIA
                 Strg IDKEY_xxx (WPFolder 2921) -->                 * IDKEY_FDRINCNAME
                 Data IDKEY_xxx (WPFolder 2938) size 8 -> 8         IDKEY_FDRGRIDINFO
                 Long IDKEY_xxx (WPFolder 2939) --> 0x0             IDKEY_FDRTREEVIEWCONTENTS

                 Long IDKEY_xxx (WPFileSystem 4) --> 0x0
                 Data IDKEY_xxx (WPObject 11) size 32 -> 32
                 Data IDKEY_xxx (WPObject 12) size 400 -> 400
                 Data IDKEY_xxx (WPObject 4) size 8 -> 8
                 Strg IDKEY_xxx (WPFolder 2934) --> F:\OS2\BITMAP\PLASTER.BMP
                                                                    IDKEY_FDRCNRBACKGROUND
                 Strg IDKEY_xxx (WPFolder 2921) --> NULL
                 Data IDKEY_xxx (WPFolder 2920) size 0 -> 259
                 Data IDKEY_xxx (WPFolder 2925) size 0 -> 107
                 Data IDKEY_xxx (WPFolder 2920) size 0 -> 260
                 Data IDKEY_xxx (WPFolder 2925) size 0 -> 107
                 Data IDKEY_xxx (WPFolder 2925) size 107 -> 107
                 Strg IDKEY_xxx (WPFolder 2921) --> F:\OS2\BITMAP\PLASTER.BMP
                                                                    IDKEY_FDRCNRBACKGROUND
                 Data IDKEY_xxx (WPFolder 2938) size 8 -> 8
                 Long IDKEY_xxx (WPFolder 2939) --> 0x0             IDKEY_FDRTREEVIEWCONTENTS

            */

            /*
             *  the following are apperently never queried
             *  (Warp 4 FP 8 German):
             */

            /*
                case IDKEY_FDRSORTATTRIBS:
                case IDKEY_FDRSORTCLASS:
                case IDKEY_FDRINVISCOLUMNS:
                case IDKEY_FDRCONTENTATTR:
                case IDKEY_FDRSNEAKYCOUNT:
                case IDKEY_FDRCNRBACKGROUND:
                case IDKEY_FDRBKGNDIMAGEFILE:
            */


        }   // end switch
    }

    if ((pValue) && (brc))
        PMPF_RESTOREDATA(("Data %s (%s %d) size_in %d -> out %d",
                cmnIdentifyRestoreID(pszClass, ulKey),
                pszClass, ulKey,
                cbOrigValue,    // size in or 0 if size queried
                *pcbValue));    // size out

#endif

    return brc;
}

/*
 *@@ wpQueryDefaultView:
 *      this WPObject method returns the default view of an object,
 *      that is, which view is opened if the program file is
 *      double-clicked upon. This is also used to mark
 *      the default view in the "Open" context submenu.
 *
 *      We change the folder's default view to "open default document"
 *      if this has been enabled in "Workplace Shell" and a
 *      default document exists.
 *
 *@@added V0.9.4 (2000-06-09) [umoeller]
 *@@changed V0.9.12 (2001-04-30) [umoeller]: added global default view support
 */

SOM_Scope ULONG  SOMLINK xf_wpQueryDefaultView(XFolder *somSelf)
{
    ULONG   ulDefaultView = 0;
    BOOL    fIsDesktop = cmnIsADesktop(somSelf);

    XFolderMethodDebug("XFolder","xf_wpQueryDefaultView");

    if (    (objIsObjectInitialized(somSelf))    // wpPopulate hangs otherwise
         && (!fIsDesktop)
       )
    {
#ifndef __NOFDRDEFAULTDOCS__
        if (    (cmnQuerySetting(sfFdrDefaultDoc))
             && (cmnQuerySetting(sfFdrDefaultDocView))
           )
        {
            // XFolderData *somThis = XFolderGetData(somSelf);
            WPFileSystem *pDefaultDoc;
            if (pDefaultDoc = _xwpQueryDefaultDocument(somSelf))
                // we have a default document for this folder:
                // change default view to menu item ID of "open default document"
                // (same as in mnuModifyDataFilePopupMenu)
                ulDefaultView = *G_pulVarMenuOfs + ID_XFMI_OFS_FDRDEFAULTDOC;
        }
#endif

        // _Pmpf((__FUNCTION__ "1: default view is %u", ulDefaultView));

        if (!ulDefaultView)
        {
            // not queried above (no default document):
            // if global default views are enabled (user doesn't want
            // inherit from parent), check that value

            // _PmpfF(("global is %u", cmnQuerySetting(sulDefaultFolderView)));

            if (cmnQuerySetting(sulDefaultFolderView))        // 0 means default -> inherit
            {
                // global default views enabled:

                // OK, this is complicated. WPFolder::wpQueryDefaultView goes
                // through a lot of code apparently to check if
                // a)  a default view was explicitly set for this folder; if
                //     so, it is returned.
                // b)  if not, wpQueryDefaultView is invoked on the parent folder...
                //     so this recurses into the parent folders until some folder
                //     view was found.
                //     (No comment on that other than that the WPS implementation
                //     isn't exactly speedy.)

                // So what we do here is check if a default view was explicitly
                // set: if so, we return it, otherwise we return the default
                // setting from the "Workplace Shell" object simply. Problem is
                // that it isn't trivial to find out whether a default view
                // was explicitly set for the folder... so we've added an
                // XFldObject method for that as well which gives us the value
                // directly from the instance data.
                ulDefaultView = _xwpQueryRealDefaultView(somSelf);

                // _PmpfF(("_xwpQueryRealDefaultView returned %d", ulDefaultView));

                // 3) check...
                switch (ulDefaultView)
                {
                    case OPEN_DEFAULT:  // returned by XFldObject if no explicit
                                        // default view was set
                    case 103:           // special code returned for "inherit from parent";
                                        // this is what WPFolder checks for, apparently

                        // call our class method override... we could
                        // simply use
                        //      ulDefaultView = cmnQuerySetting(sulDefaultFolderView)
                        // here, but I'm not sure if some WPFolder subclass
                        // overrides M_WPFolder::wpclsQueryDefaultView, so
                        // we should use the class method.
                        // The XFolder implementation simply returns
                        // cmnQuerySetting(sulDefaultFolderView,) but a WPFolder
                        // subclass may change that.
                        ulDefaultView = _wpclsQueryDefaultView(_somGetClass(somSelf));
                    break;

                    // else: use explicit view set by user
                }
            }
        }
    }

    if (!ulDefaultView)
        // still not set: this happens if global default views are disabled
        // --> inherit from parent (standard WPS behavior)
        ulDefaultView = XFolder_parent_WPFolder_wpQueryDefaultView(somSelf);

    // _PmpfF(("returning %d", ulDefaultView));

    return ulDefaultView;
}

/*
 *@@ wpQueryDefaultHelp:
 *      this WPObject instance method specifies the default
 *      help panel for an object. This should hand out a help
 *      panel describing what this object can do in general
 *      and return TRUE.
 *
 *      See XFldObject::wpQueryDefaultHelp for general remarks
 *      for how the method works.
 *
 *      XFolder will return something different for the
 *      Config folder and its subfolders; otherwise we call
 *      the parent for folder default help.
 *
 *@@changed V0.9.20 (2002-07-12) [umoeller]: added template help
 */

SOM_Scope BOOL  SOMLINK xf_wpQueryDefaultHelp(XFolder *somSelf,
                                              PULONG pHelpPanelId,
                                              PSZ HelpLibrary)
{
    XFolder *pCfg = _xwpclsQueryConfigFolder(_XFolder);

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpQueryDefaultHelp");

    if (    (pCfg)
         && (wpshResidesBelow(somSelf, pCfg))
       )
    {
        // somSelf is in the config folder hierarchy:
        // display help for config folders
        strhncpy0(HelpLibrary, cmnQueryHelpLibrary(), CCHMAXPATH);
        *pHelpPanelId = ID_XMH_CONFIGFOLDER;
        return TRUE;
    }
    else
        if (_wpQueryStyle(somSelf) & OBJSTYLE_TEMPLATE)
        {
            // different help for folder templates
            // V0.9.20 (2002-07-12) [umoeller]
            strhncpy0(HelpLibrary, cmnQueryHelpLibrary(), CCHMAXPATH);
            *pHelpPanelId = ID_XSH_FOLDER_TEMPLATE;
            return TRUE;
        }

    // not cfg folder: call parent, which might call our
    // new V0.9.19 class method to replace the default
    // folder help
    return XFolder_parent_WPFolder_wpQueryDefaultHelp(somSelf,
                                                      pHelpPanelId,
                                                      HelpLibrary);
}

/*
 *@@ wpDisplayMenu:
 *      this WPObject instance method creates and displays
 *      an object's popup menu, which is returned.
 *
 *      From my testing (after overriding menu methods),
 *      I found out that wpDisplayMenu calls the following
 *      methods in this order:
 *
 *      --  wpFilterMenu (Warp-4-specific);
 *
 *      --  wpFilterPopupMenu;
 *
 *      --  wpModifyPopupMenu;
 *
 *      --  wpModifyMenu (Warp-4-specific).
 *
 *      Normally, we wouldn't need to override this method...
 *      if there was a way to find out what menu type is
 *      currently being built. Since there isn't, we store
 *      the ulMenuType in the instance data so we can check
 *      in our menu manipulation code.
 *
 *@@added V0.9.12 (2001-05-22) [umoeller]
 */

SOM_Scope HWND  SOMLINK xf_wpDisplayMenu(XFolder *somSelf,
                                         HWND hwndOwner,
                                         HWND hwndClient,
                                         POINTL* ptlPopupPt,
                                         ULONG ulMenuType,
                                         ULONG ulReserved)
{
    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpDisplayMenu");

    _ulLastDisplayedMenuType = ulMenuType;
        // V0.9.12 (2001-05-29) [umoeller]

    return XFolder_parent_WPFolder_wpDisplayMenu(somSelf,
                                                 hwndOwner,
                                                 hwndClient,
                                                 ptlPopupPt,
                                                 ulMenuType,
                                                 ulReserved);
}

/*
 *@@ wpFilterMenu:
 *      this WPObject instance method was new with Warp 4
 *      allows the object to filter out standard menu items
 *      in a more fine-grained way than wpModifyPopupMenu.
 *      For one, this gives the object the menu type that
 *      is being built, and secondly this allows for
 *      filtering more items than the 32 bits of the filter
 *      flag in wpFilterPopupMenu have room for.
 *
 *      Once again however, the description of this method
 *      in WPSREF is unusable. As input, this method
 *      receives an array of ULONGs in pFlags. wpobject.h
 *      in the 4.5 Toolkit lists the CTXT_* flags together
 *      with the ULONG array item index where each flag
 *      applies. pFlags->Flags[0] is equivalent to the flags
 *      byte of the old wpFilterPopupMenu method.
 *
 *      Note also that the WPS appears to ignore the return
 *      value of this function.
 *
 *      With V1.0.1, we override this instead of
 *      wpFilterPopupMenu for folders too. Note that the
 *      WPS correctly passes the split view IDs with ulView
 *      since apparently it runs thru the VIEWITEMs to
 *      figure it out.
 *
 *@@added V1.0.1 (2002-12-08) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xf_wpFilterMenu(XFolder *somSelf,
                                        FILTERFLAGS* pFlags,
                                        HWND hwndCnr,
                                        BOOL fMultiSelect,
                                        ULONG ulMenuType,
                                        ULONG ulView,
                                        ULONG ulReserved)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpFilterMenu");

    PMPF_MENUS(("entering, ulView is 0x%lX (%s)",
                    ulView,
                    cmnIdentifyView(ulView)));
    PMPF_MENUS(("flags[0]: %08X, flags[1]: %08X, flags[2]: %08X",
                pFlags->Flags[0], pFlags->Flags[1], pFlags->Flags[2]));

    XFolder_parent_WPFolder_wpFilterMenu(somSelf,
                                         pFlags,
                                         hwndCnr,
                                         fMultiSelect,
                                         ulMenuType,
                                         ulView,
                                         ulReserved);

    PMPF_MENUS(("parent flags[0]: %08X, flags[1]: %08X, flags[2]: %08X",
                pFlags->Flags[0], pFlags->Flags[1], pFlags->Flags[2]));
    PMPF_MENUS(("  CTXT_CRANOTHER %d", pFlags->Flags[0] & CTXT_CRANOTHER));

    // if object has been deleted already (ie. is in trashcan),
    // remove delete
    if (_xwpQueryDeletion(somSelf, NULL, NULL))
        pFlags->Flags[0] &= ~CTXT_DELETE; // V0.9.5 (2000-09-20) [pr]

    pFlags->Flags[0] &= ~(cmnQuerySetting(mnuQueryMenuWPSSetting(somSelf)));

    if (    (ulView == *G_pulVarMenuOfs + ID_XFMI_OFS_SPLITVIEW)
         || (ulView == *G_pulVarMenuOfs + ID_XFMI_OFS_SPLIT_SUBFILES)
       )
    {
        // the WPS hasn't identified these view types and kicked
        // the "switch to ..." items out of the view menu: let's
        // add them back in
        if (_xwpQueryXFolderStyle(somSelf) & XFFL_SPLIT_DETAILS)
            // split view is in details mode:
            pFlags->Flags[0] |= CTXT_CHANGETOICON;
        else
            // split view is in icon mode:
            pFlags->Flags[0] |= CTXT_CHANGETODETAILS;
    }

    // store ulView in global variable because wpModifyMenu
    // is highly buggy
    G_ulViewForModifyMenu = ulView;

    return TRUE;
}

/*
 *@@ wpModifyMenu:
 *      this WPObject instance method was new with Warp 4 and
 *      allows the object to manipulate its menu in a more
 *      fine-grained way than wpModifyPopupMenu.
 *
 *      With V1.0.0, while adding support for the split view
 *      to the menu methods, I finally got tired of all the
 *      send-msg hacks to get Warp 4 menu items to work and
 *      decided to finally break Warp 3 support for XWorkplace.
 *      It's been fun while it lasted, but enough is enough.
 *      We are now overriding this method directly through
 *      the IDL files.
 *
 *      ulMenuType will be one of the following:
 *
 *      --  MENU_OBJECTPOPUP: Pop-up menu for the object icon.
 *          This can come in for any object.
 *
 *      --  MENU_OPENVIEWPOPUP: Pop-up menu for an open view.
 *          I think this can reasonably only come in for folders,
 *          although it seems to be handled by the WPObject method.
 *
 *      --  MENU_FOLDERPULLDOWN: Pull-down menu for a folder.
 *          This comes in for folders only.
 *
 *      --  MENU_EDITPULLDOWN: Pull-down menu for the Edit menu option.
 *          This comes in TWICE, first on the selected object in
 *          the view's container (if any) with ulView == CLOSED_ICON,
 *          and then a second time on the view's folder with ulView
 *          set to the folder's current view.
 *
 *      --  MENU_VIEWPULLDOWN: Pull-down menu for the View menu option.
 *          This comes in for folders only.
 *
 *      --  MENU_SELECTEDPULLDOWN: Pull-down menu for the Selected menu option.
 *          This comes in for non-folder objects also to let the object
 *          decide what options it wants to present in the folder's
 *          "Selected" pulldown.
 *
 *      --  MENU_HELPPULLDOWN: Pull-down menu for the Help menu option.
 *          This comes in for folders only.
 *
 *      --  MENU_TITLEBARPULLDOWN: this is listed in the toolkit headers,
 *          but not described in WPSREF. I think this is what comes in
 *          if the system menu is being built for an open object view.
 *
 *      Be warned, the ulView parameter appears to be always 0, which
 *      is not terribly helpful (as opposed to wpFilterMenu, where this
 *      works).
 *
 *@@added V1.0.0 (2002-08-31) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xf_wpModifyMenu(XFolder *somSelf,
                                        HWND hwndMenu,
                                        HWND hwndCnr,
                                        ULONG iPosition,
                                        ULONG ulMenuType,
                                        ULONG ulView,
                                        ULONG ulReserved)
{
    BOOL brc;

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpModifyMenu");

    PMPF_MENUS(("[%s] hwndMenu 0x%lX hwndCnr 0x%lX",
                _wpQueryTitle(somSelf),
                hwndMenu,
                hwndCnr));
    PMPF_MENUS(("   type = 0x%lX (%s), view = 0x%lX (%s)",
                ulMenuType,
                (ulMenuType == MENU_OBJECTPOPUP) ? "MENU_OBJECTPOPUP"
                : (ulMenuType == MENU_OPENVIEWPOPUP) ? "MENU_OPENVIEWPOPUP"
                : (ulMenuType == MENU_TITLEBARPULLDOWN) ? "MENU_TITLEBARPULLDOWN"
                : (ulMenuType == MENU_TITLEBARPULLDOWNINT) ? "MENU_TITLEBARPULLDOWNINT"
                : (ulMenuType == MENU_FOLDERPULLDOWN) ? "MENU_FOLDERPULLDOWN"
                : (ulMenuType == MENU_VIEWPULLDOWN) ? "MENU_VIEWPULLDOWN"
                : (ulMenuType == MENU_HELPPULLDOWN) ? "MENU_HELPPULLDOWN"
                : (ulMenuType == MENU_EDITPULLDOWN) ? "MENU_EDITPULLDOWN"
                : (ulMenuType == MENU_SELECTEDPULLDOWN) ? "MENU_SELECTEDPULLDOWN"
                : (ulMenuType == MENU_FOLDERMENUBAR) ? "MENU_FOLDERMENUBAR"
                : (ulMenuType == MENU_USER) ? "MENU_USER"
                : "unknown",
                ulView,
                cmnIdentifyView(ulView)
                ));

    if (brc = XFolder_parent_WPFolder_wpModifyMenu(somSelf,
                                                   hwndMenu,
                                                   hwndCnr,
                                                   iPosition,
                                                   ulMenuType,
                                                   ulView,
                                                   ulReserved))
    {
        brc = mnuModifyFolderMenu(somSelf,
                                  hwndMenu,
                                  hwndCnr,
                                  ulMenuType,
                                  G_ulViewForModifyMenu);       // stored in wpFilterMenu
    }

    PMPF_MENUS(("returning %d", brc));

    return brc;
}

/*
 *@@ wpMenuItemSelected:
 *      this WPObject method processes menu selections.
 *      This must be overridden to support new menu
 *      items which have been added in wpModifyPopupMenu.
 *
 *      See XFldObject::wpMenuItemSelected for additional
 *      remarks.
 *
 *      We pass the input to mnuMenuItemSelected in fdrmenus.c
 *      because disk menu items are mostly shared with XFldDisk.
 */

SOM_Scope BOOL  SOMLINK xf_wpMenuItemSelected(XFolder *somSelf,
                                                 HWND hwndFrame,
                                                 ULONG ulMenuId)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpMenuItemSelected");

    // call the menu item checker common to XFolder and XFldDisk
    // (fdrmenus.c); this returns TRUE if one of the manipulated
    // menu items was selected
    if (fcmdMenuItemSelected(somSelf, hwndFrame, ulMenuId))
        return TRUE;

    // none of our menu items: pass on to parent
    return XFolder_parent_WPFolder_wpMenuItemSelected(somSelf, hwndFrame, ulMenuId);
}

/*
 *@@ wpMenuItemHelpSelected:
 *      display help for a context menu item.
 */

SOM_Scope BOOL  SOMLINK xf_wpMenuItemHelpSelected(XFolder *somSelf,
                                                     ULONG MenuId)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpMenuItemHelpSelected");

    // call the common help processor in fdrmenus.c;
    // if this returns TRUE, help was requested for one
    // of the new menu items
    if (fcmdMenuItemHelpSelected(somSelf, MenuId))
        return TRUE;

    // else: none of our menu items, call default
    return XFolder_parent_WPFolder_wpMenuItemHelpSelected(somSelf,
                                                          MenuId);
}

/*
 *@@ wpOpen:
 *      this WPObject instance method gets called when
 *      a new view needs to be opened. Normally, this
 *      gets called after wpViewObject has scanned the
 *      object's USEITEMs and has determined that a new
 *      view is needed.
 *
 *      This _normally_ runs on thread 1 of the WPS, but
 *      this is not always the case. If this gets called
 *      in response to a menu selection from the "Open"
 *      submenu or a double-click in the folder, this runs
 *      on the thread of the folder (which _normally_ is
 *      thread 1). However, if this results from WinOpenObject
 *      or an OPEN setup string, this will not be on thread 1.
 *
 *      This is one of the main hooks where the XFolder
 *      features are inserted into the WPS.
 *      We call the parent method first (which will create
 *      the folder window) and then subclass the
 *      resulting frame window with the new
 *      fnwpSubclWPFolderWindow window procedure.
 *
 *@@changed V0.9.2 (2000-03-04) [umoeller]: fixed work-area hangs
 *@@changed V0.9.4 (2000-06-09) [umoeller]: added default documents
 *@@changed V0.9.18 (2002-03-20) [umoeller]: added pre-populate support
 *@@changed V0.9.19 (2002-04-02) [umoeller]: moved pre-populate to XFldDesktop::wpOpen
 *@@changed V1.0.0 (2002-08-24) [umoeller]: added split view
 *@@changed V1.0.10 (2014-05-11) [pr]: add split view fallback
 */

SOM_Scope HWND  SOMLINK xf_wpOpen(XFolder *somSelf,
                                  HWND hwndCnr,
                                  ULONG ulView,
                                  ULONG param)
{
    HWND        hwndNewFrame; // return HWND
    BOOL        fOpenDefaultDoc = FALSE;

    XFolderMethodDebug("XFolder","xf_wpOpen");

#ifndef __NOFDRDEFAULTDOCS__
    // default document support
    if (ulView == OPEN_DEFAULT)
    {
        if (    (cmnQuerySetting(sfFdrDefaultDoc))
             && (cmnQuerySetting(sfFdrDefaultDocView))
             && (!cmnIsADesktop(somSelf))
           )
        {
            fOpenDefaultDoc = TRUE;
        }
    }
    else if (ulView == *G_pulVarMenuOfs + ID_XFMI_OFS_FDRDEFAULTDOC)
        fOpenDefaultDoc = TRUE;

    if (fOpenDefaultDoc)
    {
        WPFileSystem *pDefaultDoc;
        if (pDefaultDoc = _xwpQueryDefaultDocument(somSelf))
            _wpViewObject(pDefaultDoc, NULLHANDLE, OPEN_DEFAULT, 0);
    }
    else
#endif
    {
        // added split view
        // V1.0.0 (2002-08-21) [umoeller]
        if (    (cmnQuerySetting(sfFdrSplitViews))
             && (ulView == *G_pulVarMenuOfs + ID_XFMI_OFS_SPLITVIEW)
           )
        {
            hwndNewFrame = fdrCreateSplitView(somSelf,
                                              somSelf,
                                              ulView);
        }
        else
        {
            // not default document, not split view:
            TRY_LOUD(excpt1)
            {
                // request object mutex;
                // parent_wpOpen starts the Populate thread, and we
                // don't want that one to start until we are done
                // with our folder manipulations
                /* fFolderLocked = !_wpRequestObjectMutexSem(somSelf, 5000);
                if (fFolderLocked) */
                // V0.9.2 (2000-03-04) [umoeller]: no, don't do this, this
                // prevents work areas from re-opening

                if (ulView == *G_pulVarMenuOfs + ID_XFMI_OFS_SPLITVIEW)  // V1.0.10
                    ulView = OPEN_CONTENTS;

                // have parent do the window creation
                hwndNewFrame = XFolder_parent_WPFolder_wpOpen(somSelf,
                                                              hwndCnr,
                                                              ulView,
                                                              param);

                if (   (ulView == OPEN_CONTENTS)
                    || (ulView == OPEN_TREE)
                    || (ulView == OPEN_DETAILS)
                   )
                {
                    fdrManipulateNewView(somSelf,
                                         hwndNewFrame,
                                         ulView);
                }
            }
            CATCH(excpt1) { } END_CATCH();

            /* if (fFolderLocked)
                _wpReleaseObjectMutexSem(somSelf); */
                        // this will unblock the Populate thread
        }
    }

    return hwndNewFrame;
}

/*
 *@@ wpPopulate:
 *      this instance method populates a folder.
 *
 *      In most cases, this method gets called on a separate
 *      thread which is started right before a folder view
 *      is opened. However, this can really get called on
 *      any thread, and XWorkplace calls this too synchronously
 *      sometimes to make sure the folder contents are up-to-date.
 *
 *      Now, starting with V0.9.16, we have the "turbo folders"
 *      feature which, among other things, allows us to do a faster
 *      populate. So if this is enabled, we call fdrPopulate instead
 *      of the parent method. See remarks there.
 *
 *      Note that the WPS appears to ignore the pszPath
 *      parameter that is passed in.
 */

SOM_Scope BOOL  SOMLINK xf_wpPopulate(XFolder *somSelf,
                                      ULONG ulReserved,
                                      PSZ pszPath,
                                      BOOL fFoldersOnly)
{
    BOOL    brc = FALSE;
    CHAR    szFolderFullPath[CCHMAXPATH];

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpPopulate");

#ifndef __NOTURBOFOLDERS__
    if (    // turbo folders enabled?
            (cmnQuerySetting(sfTurboFolders))
            // but don't dare turbo populate on desktop yet
         && (!cmnIsADesktop(somSelf))
            // and we cannot handle UNC at this point
         && (_wpQueryFilename(somSelf, szFolderFullPath, TRUE))
         && (szFolderFullPath[1] == ':')
       )
    {
        BOOL fExit = FALSE;                 // cannot exit right now
        brc = fdrPopulate(somSelf,
                          szFolderFullPath,
                          ulReserved,
                          fFoldersOnly,
                          &fExit);
    }
    else
#endif
        brc = XFolder_parent_WPFolder_wpPopulate(somSelf,
                                                 ulReserved,
                                                 pszPath,
                                                 fFoldersOnly);

    return brc;
}

/*
 *@@ wpRefresh:
 *      this WPFileSystem method compares the internal
 *      object data with the data on disk and refreshes
 *      the object, if necessary.
 *
 *      See XWPFileSystem::wpRefresh for details.
 *
 *      The WPFolder override apparently recurses into
 *      subfolders as well.
 *
 *      Note that this method normally does _not_
 *      get called on thread 1, but some other
 *      thread, so this better be thread-safe.
 */

SOM_Scope BOOL  SOMLINK xf_wpRefresh(XFolder *somSelf,
                                     ULONG ulView,
                                     PVOID pReserved)
{
    BOOL        rc;

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpRefresh");

    rc = XFolder_parent_WPFolder_wpRefresh(somSelf, ulView, pReserved);

    fdrForEachOpenInstanceView(somSelf,
                               stb_UpdateCallback,
                               2);           // update

    xthrPostWorkerMsg(WOM_REFRESHFOLDERVIEWS,
                      (MPARAM)somSelf,
                      (MPARAM)FDRUPDATE_TITLE);

    return rc;
}

/*
 *@@ wpInsertSettingsPage:
 *      this WPObject helper method actually inserts a
 *      settings page into an object's settings notebook.
 *      This normally gets called by all the wpAdd*
 *      methods to register a page with a settings notebook.
 *
 *      We override this for XFolder to allow for hacking
 *      the "Icon view" page, which is normally BKA_MAJOR
 *      but must now be BKA_MINOR for our new top "View"
 *      page.
 *
 *@@added V0.9.16 (2001-10-23) [umoeller]
 */

SOM_Scope ULONG  SOMLINK xf_wpInsertSettingsPage(XFolder *somSelf,
                                                 HWND hwndNotebook,
                                                 PPAGEINFO ppageinfo)
{
    USHORT  fsOld;
    ULONG   ul;
    BOOL    fInAddFolderView1Page;

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpInsertSettingsPage");

    if (fInAddFolderView1Page = (_xwpQueryFlags(somSelf) & OBJFL_FOLDERVIEW1PAGING))
    {
        // we are in the context of XFolder::wpAddFolderView1Page:
        // hack BKA_MAJOR to be BKA_MINOR instead
        fsOld = ppageinfo->usPageStyleFlags;
        ppageinfo->usPageStyleFlags = BKA_MINOR;
    }

    ul = XFolder_parent_WPFolder_wpInsertSettingsPage(somSelf,
                                                      hwndNotebook,
                                                      ppageinfo);

    // restore the old setting to be on the safe side
    if (fInAddFolderView1Page)
    {
        ppageinfo->usPageStyleFlags = fsOld;
        _xwpModifyFlags(somSelf,
                        OBJFL_FOLDERVIEW1PAGING,
                        0);
    }

    return ul;
}

/*
 *@@ wpAddObjectGeneralPage2:
 *      this WPObject instance method adds the "Animation icon"
 *      page to an object's settings notebook.
 *      For folders, we'll insert the object's "Internals" page
 *      here (now called "Object" page).
 *
 *      For folders, this is not done by XFldObject::wpAddObjectGeneralPage
 *      because otherwise the "Object" page would be between
 *      the two icon pages.
 *
 *@@added V0.9.2 (2000-02-27) [umoeller]
 *@@changed V0.9.16 (2001-10-15) [umoeller]: now replacing animation icon page too
 *@@changed V0.9.19 (2002-06-15) [umoeller]: now using XFldObject::xwpAddReplacementIconPage
 */

SOM_Scope ULONG  SOMLINK xf_wpAddObjectGeneralPage2(XFolder *somSelf,
                                                    HWND hwndNotebook)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpAddObjectGeneralPage2");

#ifndef __ALWAYSREPLACEICONPAGE__
    if (cmnQuerySetting(sfReplaceIconPage))
#endif
    {
        // call the new method V0.9.19 (2002-06-15) [umoeller]
        return _xwpAddReplacementIconPage(somSelf,
                                          hwndNotebook,
                                          SP_OBJECT_ICONPAGE2,
                                          ID_XSH_OBJICONPAGE2);

        /* INSERTNOTEBOOKPAGE inbp;
        memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
        inbp.somSelf = somSelf;
        inbp.hwndNotebook = hwndNotebook;
        inbp.hmod = cmnQueryNLSModuleHandle(FALSE);
        inbp.ulDlgID = ID_XFD_EMPTYDLG;
        inbp.ulPageID = SP_OBJECT_ICONPAGE2;      // page 2!
        inbp.usPageStyleFlags = BKA_MINOR;
        inbp.fEnumerate = TRUE;
        // inbp.pcszName = cmnGetString(ID_XSSI_ICONPAGE);
                    // no title, this should be "page 2/2"
        inbp.ulDefaultHelpPanel  = ID_XSH_OBJICONPAGE2;
        inbp.pfncbInitPage    = icoIcon1InitPage;
        inbp.pfncbItemChanged = icoIcon1ItemChanged;

        return ntbInsertPage(&inbp); */
    }

#ifndef __ALWAYSREPLACEICONPAGE__
    return XFolder_parent_WPFolder_wpAddObjectGeneralPage2(somSelf,
                                                           hwndNotebook);
#endif
}

/*
 *@@ wpAddFile1Page:
 *      this normally adds the first "File" page to
 *      the file's settings notebook; if allowed,
 *      we will replace this with our own version,
 *      which combines the three "File" pages into
 *      one single page.
 *
 *      We cannot override this in XWPFileSystem because
 *      WPFolder overrides this too.
 *
 *@@added V0.9.0
 */

SOM_Scope ULONG  SOMLINK xf_wpAddFile1Page(XFolder *somSelf,
                                           HWND hwndNotebook)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpAddFile1Page");

#ifndef __ALWAYSREPLACEFILEPAGE__
    if (cmnQuerySetting(sfReplaceFilePage))
    {
#endif
        return fsysInsertFilePages(somSelf,
                                   hwndNotebook);
#ifndef __ALWAYSREPLACEFILEPAGE__
    }
    else
        return XFolder_parent_WPFolder_wpAddFile1Page(somSelf, hwndNotebook);
#endif
}

/*
 *@@ wpAddFile2Page:
 *      this normally adds the second "File" page to
 *      the file's settings notebook; since we
 *      combine the three "File" pages into one,
 *      we'll remove this page, if allowed.
 *
 *      We cannot override this in XWPFileSystem because
 *      WPFolder overrides this too.
 *
 *@@added V0.9.0
 */

SOM_Scope ULONG  SOMLINK xf_wpAddFile2Page(XFolder *somSelf,
                                           HWND hwndNotebook)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpAddFile2Page");

#ifndef __ALWAYSREPLACEFILEPAGE__
    if (cmnQuerySetting(sfReplaceFilePage))
#endif
        return SETTINGS_PAGE_REMOVED;
#ifndef __ALWAYSREPLACEFILEPAGE__
    else
        return XFolder_parent_WPFolder_wpAddFile2Page(somSelf, hwndNotebook);
#endif
}

/*
 *@@ wpAddFile3Page:
 *      this normally adds the second "File" page to
 *      the file's settings notebook; since we
 *      combine the three "File" pages into one,
 *      we'll remove this page, if allowed.
 *
 *      We cannot override this in XWPFileSystem because
 *      WPFolder overrides this too.
 *
 *@@added V0.9.0
 */

SOM_Scope ULONG  SOMLINK xf_wpAddFile3Page(XFolder *somSelf,
                                           HWND hwndNotebook)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpAddFile3Page");

#ifndef __ALWAYSREPLACEFILEPAGE__
    if (cmnQuerySetting(sfReplaceFilePage))
#endif
        return SETTINGS_PAGE_REMOVED;
#ifndef __ALWAYSREPLACEFILEPAGE__
    else
        return XFolder_parent_WPFolder_wpAddFile3Page(somSelf, hwndNotebook);
#endif
}

/*
 *@@ wpAddFolderBackgroundPage:
 *      this normally adds the  "Background" page to
 *      the folder's settings notebook. We now use
 *      this method to add the "XFolder" page right
 *      before that by calling XFolder::xwpAddXFolderPages.
 *
 *      This has been changed with V0.9.0 so that the
 *      "XFolder" page no longer sits at the front of
 *      the settings notebook, but together with the
 *      other folder settings pages.
 *
 *@@added V0.9.0 [umoeller]
 */

SOM_Scope ULONG  SOMLINK xf_wpAddFolderBackgroundPage(XFolder *somSelf,
                                                      HWND hwndNotebook)
{
    BOOL    brc;

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpAddFolderBackgroundPage");

    brc = XFolder_parent_WPFolder_wpAddFolderBackgroundPage(somSelf,
                                                            hwndNotebook);
    /* if (brc)
        _xwpAddXFolderPages(somSelf, hwndNotebook);
       */

    return brc;
}

/*
 *@@ wpAddFolderSortPage:
 *      this normally adds the "Sort" page to the folder
 *      settings notebook; if allowed, we will replace this
 *      by the new XFolder version of it.
 */

SOM_Scope ULONG  SOMLINK xf_wpAddFolderSortPage(XFolder *somSelf,
                                                   HWND hwndNotebook)
{
    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpAddFolderSortPage");

#ifndef __ALWAYSEXTSORT__
    if (cmnQuerySetting(sfExtendedSorting))
#endif
    {
        // extended sorting enabled:
        INSERTNOTEBOOKPAGE inbp;
        memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
        inbp.somSelf = somSelf;
        inbp.hwndNotebook = hwndNotebook;
        inbp.hmod = cmnQueryNLSModuleHandle(FALSE);
        inbp.ulDlgID = ID_XSD_SETTINGS_FLDRSORT;
        inbp.usPageStyleFlags = BKA_MAJOR;
        inbp.pcszName = cmnGetString(ID_XSSI_SORT);  // pszSort
        inbp.ulDefaultHelpPanel  = ID_XSH_SORTPAGE;
                        // changed V0.9.12 (2001-05-20) [umoeller]

        // mark this page as "instance", because both
        // the instance settings notebook and the
        // "Workplace Shell" object use the same
        // callbacks
        inbp.ulPageID = SP_FLDRSORT_FLDR;
        inbp.pfncbInitPage    = fdrSortInitPage;
        inbp.pfncbItemChanged = fdrSortItemChanged;

        return ntbInsertPage(&inbp);
    }

#ifndef __ALWAYSEXTSORT__
    return XFolder_parent_WPFolder_wpAddFolderSortPage(somSelf,
                                                       hwndNotebook);
#endif
}

/*
 *@@ wpAddFolderView1Page:
 *      this WPFolder method adds the "Icon view" page to the
 *      folder settings notebook.
 *
 *      We override this to add the standard "View" page on
 *      top of that (formerly the "XFolder" page).
 *
 *@@added V0.9.16 (2001-10-23) [umoeller]
 */

SOM_Scope ULONG  SOMLINK xf_wpAddFolderView1Page(XFolder *somSelf,
                                                 HWND hwndNotebook)
{
    ULONG       ul;
    BOOL        fIsRootFdr;
    XFolderData *somThis = XFolderGetData(somSelf);

    XFolderMethodDebug("XFolder","xf_wpAddFolderView1Page");

    // evil hack for wpInsertSettingsPage
    if (!(fIsRootFdr = ctsIsRootFolder(somSelf)))
        _xwpModifyFlags(somSelf,
                        OBJFL_FOLDERVIEW1PAGING,
                        OBJFL_FOLDERVIEW1PAGING);

    ul = XFolder_parent_WPFolder_wpAddFolderView1Page(somSelf,
                                                      hwndNotebook);

    if (!fIsRootFdr)
    {
        _xwpModifyFlags(somSelf,
                        OBJFL_FOLDERVIEW1PAGING,
                        0);

        if (ul)
            _xwpAddXFolderPages(somSelf, hwndNotebook);
            // @@todo what if a WPFolder subclass overrides
            // this method to return SETTINGS_PAGE_REMOVED
            // only? We never get called then!
    }

    return ul;
}

/*
 *@@ wpAddToContent:
 *      this WPFolder method is overridden to intercept the
 *      notification of the "Added an object to a folder"
 *      event for subclasses that define their own folder view.
 *
 *      From my testing, the standard WPFolder implementation
 *      appears to call the undocumented WPObject method
 *      wpSetNextObject to maintain the order of objects
 *      in a folder. In addition, this inserts objects into
 *      open container views.
 *
 *      We must replace this method completely to be able
 *      to suppress the automatic adding of objects for
 *      folders. For example, the trash can and the font
 *      folder take a long time to populate, and we don't want
 *      each object to be added separately. Instead, we want
 *      all objects to be added in one flush.
 *
 *      So... if XFolder::xwpSetDisableCnrAdd has been called
 *      with the disable flag set, this method will instead
 *      call fdrAddToContent.
 *
 *@@changed V0.9.6 (2000-10-26) [pr]: update status bars
 *@@changed V0.9.16 (2001-10-25) [umoeller]: moved all the implementation to fdrcontent.c
 */

SOM_Scope BOOL  SOMLINK xf_wpAddToContent(XFolder *somSelf,
                                          WPObject* Object)
{
    XFolderData *somThis = XFolderGetData(somSelf);
    // XFolderMethodDebug("XFolder","xf_wpAddToContent");

    BOOL    brc = TRUE,
            fCallParent = TRUE,
            fFdrWriteLocked = FALSE,
            fFdrObjLocked = FALSE;

    PMPF_CNRCONTENT(("wpAddToContent, folder: %s, object: %s",
             _wpQueryTitle(somSelf),
             _wpQueryTitle(Object)));

    if (
            (_fDisableAutoCnrAdd)
#ifndef __NOTURBOFOLDERS__
         || (cmnQuerySetting(sfTurboFolders))
#endif
       )
    {
        TRY_LOUD(excpt1)
        {
            if (    (fFdrWriteLocked = !fdrRequestFolderWriteMutexSem(somSelf))
                 && (brc = fdrAddToContent(somSelf, Object, &fCallParent))
                    // check if the folder is currently showing on the right
                    // side of a folder split view (yes, we only support this
                    // right now if turbo folders are enabled)
                    // V1.0.0 (2002-08-28) [umoeller]
                 && (fFdrObjLocked = !_wpRequestObjectMutexSem(somSelf, SEM_INDEFINITE_WAIT))
               )
            {
                PUSEITEM pui;
                for (pui = _wpFindUseItem(somSelf, USAGE_OPENVIEW, NULL);
                     pui;
                     pui = _wpFindUseItem(somSelf, USAGE_OPENVIEW, pui))
                {
                    PVIEWITEM   pvi = (PVIEWITEM)(pui + 1);
                    HWND        hwndCnr;
                    if (    (pvi->view == *G_pulVarMenuOfs + ID_XFMI_OFS_SPLIT_SUBFILES)
                         // we set the following flag in the split view while we're
                         // populating
                         && (!(pvi->ulViewState & VIEWSTATE_OPENING))
                         && (hwndCnr = WinWindowFromID(pvi->handle, FID_CLIENT))
                       )
                    {
                        // alright, add it
                        POINTL ptl = {0, 0};
                        _wpCnrInsertObject(Object,
                                           hwndCnr,
                                           &ptl,
                                           NULL,
                                           NULL);
                    }
                }
            }
        }
        CATCH(excpt1)
        {
            brc = FALSE;
        } END_CATCH();
    }

    // release folder's _object_ mutex before calling parent
    // V1.0.0 (2002-08-28) [umoeller]
    if (fFdrObjLocked)
        _wpReleaseObjectMutexSem(somSelf);

    // keep the folder locked while calling the parent!
    // V0.9.16 (2002-01-26) [umoeller]
    if (fCallParent)
        brc = XFolder_parent_WPFolder_wpAddToContent(somSelf, Object);

    if (fFdrWriteLocked)
        fdrReleaseFolderWriteMutexSem(somSelf);

    if (!(_wpQueryFldrFlags(somSelf) & (FOI_POPULATEINPROGRESS | FOI_REFRESHINPROGRESS)))
        fdrForEachOpenInstanceView(somSelf,
                                   stb_PostCallback,
                                   STBM_UPDATESTATUSBAR);

    return brc;
}

/*
 *@@ wpDeleteFromContent:
 *      this method should be overridden to intercept the
 *      notification of the "Removed an object from a folder"
 *      event for subclasses that define their own folder view.
 *      The parent must always be called.
 *
 *@@changed V0.9.6 (2000-10-26) [pr]: update status bars
 */

SOM_Scope BOOL  SOMLINK xf_wpDeleteFromContent(XFolder *somSelf,
                                               WPObject* Object)
{
    BOOL    brc = FALSE,
            fFolderLocked = FALSE;

    // XFolderData *somThis = XFolderGetData(somSelf);
    // XFolderMethodDebug("XFolder","xf_wpDeleteFromContent");

    PMPF_CNRCONTENT(("wpDeleteFromContent, folder: %s, object: %s",
             _wpQueryTitle(somSelf),
             _wpQueryTitle(Object)));

#ifndef __NOTURBOFOLDERS__
    if (cmnQuerySetting(sfTurboFolders))
    {
        TRY_LOUD(excpt1)
        {
            if (fFolderLocked = !fdrRequestFolderWriteMutexSem(somSelf))
                brc = fdrDeleteFromContent(somSelf, Object);
        }
        CATCH(excpt1)
        {
            brc = FALSE;
        } END_CATCH();
    }
#endif

    // keep the folder locked while calling the parent!
    brc = XFolder_parent_WPFolder_wpDeleteFromContent(somSelf, Object);

    if (fFolderLocked)
        fdrReleaseFolderWriteMutexSem(somSelf);

    if (!(_wpQueryFldrFlags(somSelf) & (FOI_POPULATEINPROGRESS | FOI_REFRESHINPROGRESS)))
        fdrForEachOpenInstanceView(somSelf,
                                   stb_PostCallback,
                                   STBM_UPDATESTATUSBAR);

    return brc;
}

/*
 *@@ wpQueryContent:
 *      this WPFolder method can be called to enumerate a
 *      folder's contents.
 *
 *      This can be called in various ways:
 *
 *      --  If ulOption is QC_FIRST, the first object in the
 *          folder is returned. "Object" is ignored.
 *
 *      --  If ulOption is QC_NEXT, the object after "Object"
 *          is returned.
 *
 *      --  If ulOption is QC_LAST, the last object in the
 *          folder is returned.
 *
 *      For folders that have the "no auto-add" flag set (see
 *      XFolder::xwpSetDisableCnrAdd), we must override this
 *      to make this still work.
 *
 *@@added V0.9.7 (2001-01-13) [umoeller]
 */

SOM_Scope WPObject*  SOMLINK xf_wpQueryContent(XFolder *somSelf,
                                               WPObject* Object,
                                               ULONG ulOption)
{
    XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpQueryContent");

    if (_fDisableAutoCnrAdd)
        // do not call the parent!!
        // call our own implementation instead
        return fdrQueryContent(somSelf, Object, ulOption);

    return XFolder_parent_WPFolder_wpQueryContent(somSelf, Object, ulOption);
}

/*
 *@@ wpStoreIconPosData:
 *      this method is documented only for Warp 4
 *      (but exists in Warp 3 also, see WPFOLDER.H);
 *      it is called when an open folder in icon or
 *      details view is closed.
 *
 *      The WPS then apparently saves the .ICONPOS
 *      data to disk; we only override this method to be
 *      notified that we need to to invalidate our
 *      internal lists of the config folder contents.
 *
 *@@changed V0.9.0 [umoeller]: now invaliding lists in fdrmenus.c
 */

SOM_Scope BOOL  SOMLINK xf_wpStoreIconPosData(XFolder *somSelf,
                                              PICONPOS pIconPos,
                                              ULONG cbSize)
{
    XFolder *pCfg = _xwpclsQueryConfigFolder(_XFolder);

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpStoreIconPosData");

    if (wpshResidesBelow(somSelf, pCfg))
    {
        // somSelf is in the config folder hierarchy:
        // invalidate the content lists for the config
        // folders so that they will be rebuilt
        mnuInvalidateConfigCache();
    }

    return XFolder_parent_WPFolder_wpStoreIconPosData(somSelf,
                                                      pIconPos,
                                                      cbSize);
}

/*
 *@@ wpSetFldrSort:
 *      apparently, this method normally gets called by the
 *      WPS every time it tries to sort a folder. That is,
 *      when one of the "Sort" menu items is selected or when
 *      the folder is sorted for another reason, e.g. because
 *      "Always sort" is on and a file in the folder was
 *      renamed.
 *
 *      The WPS ref. says about this method:
 *      "This instance method sets the sort attributes on
 *      the folder window and  saves those values in the
 *      instance data. Note:  This method only rearranges a
 *      folder open in icon view. If (pSortRecord == NULL),
 *      the values are reset to the default sort values."
 *
 *      However, the description of this method in the WPS
 *      ref. is complete garbage. The SORTFASTINFO structure
 *      described there is obviously not used, but some
 *      undocumented data instead. (I guess that's why IBM
 *      uses a PVOID here, so they need not apologize.)
 *      Also, this method rearranges _all_ open folders, not
 *      just icons views.
 *
 *      Anyway, if XFolder extended sorting is enabled,
 *      we can intercept this method call to prevent the
 *      WPS from sorting the container. We will then not
 *      call the default method, but our own one instead.
 *      Since XFolder completely takes over the other sort
 *      functions, this method probably only gets called
 *      when files are renamed any more.
 *
 *@@changed V0.9.4 (2000-06-08) [umoeller]: reversed call order
 */

SOM_Scope BOOL  SOMLINK xf_wpSetFldrSort(XFolder *somSelf,
                                         PVOID pSortRecord,
                                         ULONG ulView,
                                         ULONG ulType)
{
    BOOL    brc;

    XFolderMethodDebug("XFolder","xf_wpSetFldrSort");

    brc = XFolder_parent_WPFolder_wpSetFldrSort(somSelf,
                                                pSortRecord,
                                                ulView,
                                                ulType);
    if (brc)
    {
#ifndef __ALWAYSEXTSORT__
        if (cmnQuerySetting(sfExtendedSorting))
#endif
        {
            HWND hwndFrame, hwndCnr;
            if (    (hwndFrame = wpshQueryFrameFromView(somSelf, ulView))
                 && (hwndCnr = WinWindowFromID(hwndFrame, FID_CLIENT))
               )
            {
                fdrSetFldrCnrSort(somSelf,
                                  hwndCnr,
                                  TRUE);  // enfore cnr sort
                return TRUE;
            }
        }
    }

    return brc;
}

/*
 *@@ wpRedrawFolderBackground:
 *      this undocumented WPFolder method appears to get
 *      called when the background needs to be redrawn
 *      for open folder views. This happens, for example,
 *      when the user changes the settings on a folder's
 *      "Background" settings notebook page.
 *
 *      We intercept this notification to redraw split
 *      views as well.
 *
 *@@added V1.0.0 (2002-09-24) [umoeller]
 */

SOM_Scope void  SOMLINK xf_wpRedrawFolderBackground(XFolder *somSelf)
{
    XFolderData *somThis = XFolderGetData(somSelf);
    BOOL        fLocked = FALSE;
    XFolderMethodDebug("XFolder","xf_wpRedrawFolderBackground");

    XFolder_parent_WPFolder_wpRedrawFolderBackground(somSelf);

    TRY_LOUD(excpt1)
    {
        PMPF_SPLITVIEW(("checking viewitems"));
        if (fLocked = !_wpRequestObjectMutexSem(somSelf, SEM_INDEFINITE_WAIT))
        {
            PUSEITEM pui = NULL;
            while (pui = _wpFindUseItem(somSelf, USAGE_OPENVIEW, pui))
            {
                PVIEWITEM   pvi = (PVIEWITEM)(pui + 1);

                if (         // is this folder currently showing in the right half
                             // of a split view?
                        (    (pvi->view == *G_pulVarMenuOfs + ID_XFMI_OFS_SPLIT_SUBFILES)
                             // is this folder currently showing as the root of
                             // a split view (i.e. in the left half of a split view)?
                          || ((pvi->view == *G_pulVarMenuOfs + ID_XFMI_OFS_SPLITVIEW))
                        )
                     // we set the following flag in the split view while we're
                     // populating
                     && (!(pvi->ulViewState & VIEWSTATE_OPENING))
                   )
                {
                    // yes: update
                    PMPF_SPLITVIEW(("found hwnd 0x%lX", pvi->handle));
                    WinPostMsg(pvi->handle,
                               FM_FDRBACKGROUNDCHANGED,     // V1.0.1 (2002-11-30) [umoeller]
                               (MPARAM)somSelf,
                               0);
                }
            }
        }
    }
    CATCH(excpt1)
    {
    } END_CATCH();

    if (fLocked)
        _wpReleaseObjectMutexSem(somSelf);
}

/*
 *@@ wpSetTitle:
 *      this is called when the folder is renamed.
 *      We then need to update the titles of this
 *      folder AND of possibly open subfolders with
 *      the full path; we pass this task to the Worker
 *      thread, since it may take a while.
 */

SOM_Scope BOOL  SOMLINK xf_wpSetTitle(XFolder *somSelf, PSZ pszNewTitle)
{
    BOOL rc;
    // XFolder *pCfg = _xwpclsQueryConfigFolder(_XFolder);

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpSetTitle");

    /* if (wpshResidesBelow(somSelf, pCfg))
    {
        // somSelf is in the config folder hierarchy:
        // invalidate the content lists for the config
        // folders so that they will be rebuilt
        mnuInvalidateConfigCache();
    } */

    rc = XFolder_parent_WPFolder_wpSetTitle(somSelf, pszNewTitle);

    if (_wpFindUseItem(somSelf, USAGE_OPENVIEW, NULL))
        // any open views: update titles
        xthrPostWorkerMsg(WOM_REFRESHFOLDERVIEWS, (MPARAM)somSelf, (MPARAM)FDRUPDATE_TITLE);

    return rc;
}

/*
 *@@ wpMoveObject:
 *      this is called when the folder is moved to a
 *      different location; we then need to update
 *      the titles of this folder AND of possibly open
 *      subfolders with the full path; we pass this
 *      job to the Worker thread.
 */

SOM_Scope BOOL  SOMLINK xf_wpMoveObject(XFolder *somSelf,
                                        WPFolder* Folder)
{
    BOOL rc;
    XFolder *pCfg = _xwpclsQueryConfigFolder(_XFolder);

    // XFolderData *somThis = XFolderGetData(somSelf);
    XFolderMethodDebug("XFolder","xf_wpMoveObject");

    if (    (pCfg)
         && (wpshResidesBelow(somSelf, pCfg))
       )
        // this was in the config folder hierarchy:
        mnuInvalidateConfigCache();

    // call the parent method first, which will actually move the folder
    rc = XFolder_parent_WPFolder_wpMoveObject(somSelf, Folder);

    xthrPostWorkerMsg(WOM_REFRESHFOLDERVIEWS, (MPARAM)somSelf, (MPARAM)FDRUPDATE_TITLE);

    return rc;
}

/* ******************************************************************
 *
 *   here come the XFolder class methods
 *
 ********************************************************************/

/*
 *@@ xwpclsQueryConfigFolder:
 *      returns the XFolder Configuration Folder or NULL
 *      if it doesn't exist.
 *
 *@@added V0.9.0 [umoeller]
 *@@changed V0.9.2 (2000-02-26) [umoeller]: object is now always checked for integrity
 */

SOM_Scope XFolder*  SOMLINK xfM_xwpclsQueryConfigFolder(M_XFolder *somSelf)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_xwpclsQueryConfigFolder");

    if (G_pConfigFolder == NULL)
        // config folder not queried yet:
        // do it now
        G_pConfigFolder = cmnQueryObjectFromID(XFOLDER_CONFIGID);

    // in any case, check that object
    if (!wpshCheckObject(G_pConfigFolder))
        G_pConfigFolder = NULL;

    return G_pConfigFolder;
}

/*
 *@@ xwpclsQueryFavoriteFolder:
 *      This returns "favorite" folders.
 *
 *      If pFolder == NULL, the first favorite folder is returned,
 *      otherwise the favorite folder which comes after pFolder
 *      in the favorite folder list.
 *
 *      This returns NULL if no more folders are found.
 *
 *@@changed V0.9.7 (2001-01-18) [umoeller]: added list notify on deletion, which fixed crashes
 */

SOM_Scope XFolder*  SOMLINK xfM_xwpclsQueryFavoriteFolder(M_XFolder *somSelf,
                                                          XFolder* pFolder)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);

    M_XFolderMethodDebug("M_XFolder","xfM_xwpclsQueryFavoriteFolder");

#ifndef __NOFOLDERCONTENTS__
    #if 1
        if (G_llFavoriteFolders)
            return _Enum(G_llFavoriteFolders, pFolder);
    #else
        return objEnumList(&G_llFavoriteFolders,
                           pFolder,
                           INIKEY_FAVORITEFOLDERS,
                           OBJLIST_FAVORITEFOLDER);
    #endif
#endif

    return NULL;
}

/*
 *@@ xwpclsQueryQuickOpenFolder:
 *      This returns folders which have the "QuickOpen" flag on.
 *
 *      If pFolder == NULL, the first such folder is returned,
 *      otherwise the folder which comes after pFolder
 *      in the quick-open folder list.
 *
 *      This returns NULL if no more folders are found.
 *
 *@@changed V0.9.7 (2001-01-18) [umoeller]: added list notify on deletion, which fixed crashes
 */

SOM_Scope XFolder*  SOMLINK xfM_xwpclsQueryQuickOpenFolder(M_XFolder *somSelf,
                                                           XFolder* pFolder)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);

    M_XFolderMethodDebug("M_XFolder","xfM_xwpclsQueryQuickOpenFolder");

#ifndef __NOQUICKOPEN__
    #if 1
        if (G_llQuickOpenFolders)
            return _Enum(G_llQuickOpenFolders, pFolder);
    #else
        return objEnumList(&G_llQuickOpenFolders,
                           pFolder,
                           INIKEY_QUICKOPENFOLDERS,
                           OBJLIST_QUICKOPENFOLDER);
    #endif
#endif

    return NULL;
}

/*
 *@@ xwpclsQueryMenuBarVisibility:
 *      this returns the default visibility of menu bars
 *      as specified in the "System" object. Warp 4 has
 *      no method for this, so this has been added.
 *
 *      On Warp 3, this returns FALSE always.
 *
 *@@added V0.9.1 (2000-01-17) [umoeller]
 *@@changed V0.9.16 (2001-10-19) [umoeller]: fixed wrong default on Warp 4
 */

SOM_Scope BOOL  SOMLINK xfM_xwpclsQueryMenuBarVisibility(M_XFolder *somSelf)
{
    BOOL brc = FALSE;
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_xwpclsQueryMenuBarVisibility");

    if (G_fIsWarp4)
    {
        CHAR szValue[10];
        if (PrfQueryProfileString(HINI_USER,
                                  (PSZ)WPINIAPP_WORKPLACE, // "PM_Workplace"
                                  (PSZ)WPINIKEY_MENUBAR, // "FolderMenuBar",
                                  "ON",     // default on Warp 4
                                            // V0.9.16 (2001-10-19) [umoeller]
                                  szValue,
                                  sizeof(szValue)))
        {
            if (!strcmp(szValue, "ON"))
                brc = TRUE;
        }
    }

    return brc;
}

/*
 *@@ xwpclsQueryOpenFolders:
 *      this new XFolder method iterates over all open folders.
 *
 *      This is terribly ineffective, but for now the only
 *      option if split views should be included in your
 *      query too.
 *
 *@@added V1.0.1 (2002-11-30) [umoeller]
 */

SOM_Scope XFolder*  SOMLINK xfM_xwpclsQueryOpenFolders(M_XFolder *somSelf,
                                                       XFolder* pFolder,
                                                       BOOL fLock)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_xwpclsQueryOpenFolders");

    PMPF_STATUSBARS(("calling fdrQueryOpenFolders"));

    return fdrQueryOpenFolders(pFolder, fLock);
}

/*
 *@@ wpclsInitData:
 *      this M_WPObject class method gets called when a class
 *      is loaded by the WPS (probably from within a
 *      somFindClass call) and allows the class to initialize
 *      itself.
 *
 *@@changed V0.9.0 [umoeller]: added class object to KERNELGLOBALS
 */

SOM_Scope void  SOMLINK xfM_wpclsInitData(M_XFolder *somSelf)
{
    M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_wpclsInitData");

    M_XFolder_parent_M_WPFolder_wpclsInitData(somSelf);

    _hptrAni1 = NULLHANDLE;

    if (krnLock(__FILE__, __LINE__, __FUNCTION__))
    {
        if (krnClassInitialized(G_pcszXFolder))
        {
            // first call:

            // initialize other data
#if 1
    #ifndef __NOFOLDERCONTENTS__
                G_llFavoriteFolders = _xwpclsCreateList(_XFldObject,
                                                        (PSZ)INIAPP_XWORKPLACE,
                                                        (PSZ)INIKEY_FAVORITEFOLDERS);
    #endif
    #ifndef __NOQUICKOPEN__
                G_llQuickOpenFolders = _xwpclsCreateList(_XFldObject,
                                                         (PSZ)INIAPP_XWORKPLACE,
                                                         (PSZ)INIKEY_QUICKOPENFOLDERS);
    #endif
#else
    #ifndef __NOFOLDERCONTENTS__
                lstInit(&G_llFavoriteFolders.ll, FALSE);    // no auto-free
                G_llFavoriteFolders.fLoaded = FALSE;
    #endif
    #ifndef __NOQUICKOPEN__
                lstInit(&G_llQuickOpenFolders.ll, FALSE);      // no auto-free
                G_llQuickOpenFolders.fLoaded = FALSE;
    #endif
#endif

            fdrLoadFolderHotkeys();

            // register class for supplementary object
            // windows, which are created for each folder view
            // which is opened
            WinRegisterClass(WinQueryAnchorBlock(HWND_DESKTOP),
                             (PSZ)WNDCLASS_SUPPLOBJECT,    // class name
                             (PFNWP)fdr_fnwpSupplFolderObject,    // Window procedure
                             0,       // class style
                             4);      // extra window words for SUBCLFOLDERVIEW
                                      // pointer (see fdrSubclassFolderView)

            // install local hook (fdrsubclass.c)
            WinSetHook(WinQueryAnchorBlock(HWND_DESKTOP),
                       HMQ_CURRENT,
                       HK_SENDMSG,
                       (PFN)fdr_SendMsgHook,
                       NULLHANDLE);  // module handle, can be 0 for local hook

            // create the standard GEA2LIST for turbo populate
            // V0.9.16 (2001-10-28) [umoeller]
            fsysCreateStandardGEAList();     // filesys.c
        }

        krnUnlock();
    }
}

/*
 *@@ wpclsCreateDefaultTemplates:
 *      this M_WPObject class method is called by the
 *      Templates folder to allow a class to
 *      create its default templates.
 *
 *      The default WPS behavior is to create new templates
 *      if the class default title is different from the
 *      existing templates.
 *
 *      Since we are replacing the class, we will have to
 *      suppress this in order not to crowd the Templates
 *      folder.
 */

SOM_Scope BOOL  SOMLINK xfM_wpclsCreateDefaultTemplates(M_XFolder *somSelf,
                                                        WPObject* Folder)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_wpclsCreateDefaultTemplates");

    // we only override this class method if it is
    // being called for the XFolder class object itself.
    // If this is being called for a subclass, we use
    // the parent method, because we do not want to
    // break the default behavior for subclasses.
    if (somSelf == _XFolder)
        return TRUE;
        // means that the Templates folder should _not_ create templates
        // by itself; we pretend that we've done this

    return M_XFolder_parent_M_WPFolder_wpclsCreateDefaultTemplates(somSelf,
                                                                   Folder);
}

/*
 *@@ wpclsQueryDefaultView:
 *      this M_WPObject class method returns the default view for
 *      objects of a class.
 *      The way this works is that WPObject::wpQueryDefaultView
 *      apparently checks for whether an instance default view
 *      has been set by the user. If not, this class method gets
 *      called.
 *
 *      Now, the WPFolder metaclass overrides this method to
 *      return some undocumented value of 103. Presumably, this
 *      causes the WPFolder::wpQueryDefaultView method override
 *      to go thru the parent folders to find a default view
 *      by inheritance.
 *
 *      To disable this stupid behavior, if the user has set a
 *      fixed default view in "Workplace Shell", we can simply
 *      return that here and WPFolder::wpQueryDefaultView will
 *      return that as well.
 *
 *@@added V0.9.12 (2001-04-30) [umoeller]
 */

SOM_Scope ULONG  SOMLINK xfM_wpclsQueryDefaultView(M_XFolder *somSelf)
{
    ULONG ul;
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_wpclsQueryDefaultView");

    if (ul = cmnQuerySetting(sulDefaultFolderView))
    {
        // something set (0 means standard WPS inheritance behavior):
        // return that
        // _PmpfF(("returning %u", cmnQuerySetting(sulDefaultFolderView)));

        return ul;
    }

    // return the stupid 103 code
    return M_XFolder_parent_M_WPFolder_wpclsQueryDefaultView(somSelf);
}

/*
 *@@ wpclsQueryTitle:
 *      this M_WPObject class method tells the WPS the clear
 *      name of a class, which is shown in the third column
 *      of a Details view and also used as the default title
 *      for new objects of a class.
 *
 *      We override the standard folder class name only if
 *      the user has enabled "fix class titles" in XWPSetup.
 *
 *@@added V0.9.12 (2001-05-22) [umoeller]
 */

SOM_Scope PSZ  SOMLINK xfM_wpclsQueryTitle(M_XFolder *somSelf)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_wpclsQueryTitle");

#ifndef __ALWAYSFIXCLASSTITLES__
    if (!cmnQuerySetting(sfFixClassTitles))
        return M_XFolder_parent_M_WPFolder_wpclsQueryTitle(somSelf);
#endif

    return (PSZ)cmnGetString(ID_XSSI_CLASSTITLE_FOLDER);
}

/*
 *@@ wpclsQueryDefaultHelp:
 *      this M_WPObject class method returns the default help
 *      panel for objects of this class. This gets called
 *      from WPObject::wpQueryDefaultHelp if no instance
 *      help settings (HELPLIBRARY, HELPPANEL) have been
 *      set for an individual object. It is thus recommended
 *      to override this method instead of the instance
 *      method to change the default help panel for a class
 *      in order not to break instance help settings (fixed
 *      with 0.9.20).
 *
 *      We replace the default folder help because,
 *      frankly, it sucks.
 *
 *@@added V0.9.19 (2002-04-17) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xfM_wpclsQueryDefaultHelp(M_XFolder *somSelf,
                                                  PULONG pHelpPanelId,
                                                  PSZ pszHelpLibrary)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_wpclsQueryDefaultHelp");

    strcpy(pszHelpLibrary, cmnQueryHelpLibrary());
    *pHelpPanelId = ID_XSH_FOLDER_MAIN;
    return TRUE;
}

/*
 *@@ wpclsQueryIconData:
 *      this M_WPObject class method must return information
 *      about how to build the default icon for objects
 *      of a class. This gets called from various other
 *      methods whenever a class default icon is needed;
 *      most importantly, M_WPObject::wpclsQueryIcon
 *      calls this to build a class default icon, which
 *      is then cached in the class's instance data.
 *      If a subclass wants to change a class default icon,
 *      it should always override _this_ method instead of
 *      wpclsQueryIcon.
 *
 *      Note that the default WPS implementation does not
 *      allow for specifying the ICON_FILE format here,
 *      which is why we have overridden
 *      M_XFldObject::wpclsQueryIcon too. This allows us
 *      to return icon _files_ for theming too. For details
 *      about the WPS's crappy icon management, refer to
 *      src\filesys\icons.c.
 *
 *      We give folders a new default closed icon, if the
 *      global settings allow this.
 */

SOM_Scope ULONG  SOMLINK xfM_wpclsQueryIconData(M_XFolder *somSelf,
                                                PICONINFO pIconInfo)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_wpclsQueryIconData");

#ifndef __NOICONREPLACEMENTS__
    if (cmnQuerySetting(sfIconReplacements))
    {
        /* hmodIconsDLL = cmnQueryIconsDLL();
        // icon replacements allowed:
        if ((pIconInfo) && (hmodIconsDLL))
        {
            pIconInfo->fFormat = ICON_RESOURCE;
            pIconInfo->hmod = hmodIconsDLL;
            pIconInfo->resid = 100;
        }*/

        // now using cmnGetStandardIcon
        // V0.9.16 (2002-01-13) [umoeller]
        ULONG cb = 0;
        if (!cmnGetStandardIcon(STDICON_FOLDER_CLOSED,
                                NULL,            // no hpointer
                                &cb,
                                pIconInfo))      // fill icon info
            return cb;

        return 0;
    }

#endif
    // icon replacements not allowed: call default
    return M_XFolder_parent_M_WPFolder_wpclsQueryIconData(somSelf,
                                                          pIconInfo);
}

/*
 *@@ wpclsQueryIconDataN:
 *      give folders a new default open icon, if the
 *      global settings allow this.
 *      See the notes for wpclsQueryIconData.
 */

SOM_Scope ULONG  SOMLINK xfM_wpclsQueryIconDataN(M_XFolder *somSelf,
                                                 ICONINFO* pIconInfo,
                                                 ULONG ulIconIndex)
{
    // M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_wpclsQueryIconDataN");

#ifndef __NOICONREPLACEMENTS__
    if (    (cmnQuerySetting(sfIconReplacements))
         && (ulIconIndex == 1)
       )
    {
        /* hmodIconsDLL = cmnQueryIconsDLL();
        // icon replacements allowed:
        if ((pIconInfo) && (hmodIconsDLL))
        {
            pIconInfo->fFormat = ICON_RESOURCE;
            pIconInfo->hmod = hmodIconsDLL;
            pIconInfo->resid = 101;
        }
        ulrc = sizeof(ICONINFO); */

        // now using cmnGetStandardIcon
        // V0.9.16 (2002-01-13) [umoeller]
        ULONG cb = 0;
        if (!cmnGetStandardIcon(STDICON_FOLDER_OPEN,
                                NULL,            // no hpointer
                                &cb,
                                pIconInfo))      // fill icon info
            return cb;

        return 0;
    }

#endif
    // icon replacements not allowed: call default
    return M_XFolder_parent_M_WPFolder_wpclsQueryIconDataN(somSelf,
                                                           pIconInfo,
                                                           ulIconIndex);
}

/*
 *@@ wpclsQueryIconN:
 *      this WPFolder class method should return the class
 *      animation icon with the given index.
 *
 *      We need to override this because the default WPFolder
 *      method does not support the ICON_FILE format returned
 *      by our new M_XFolder::wpclsQueryIconDataN. Since there
 *      is _no_ wpclsSetIconDataN method as with the object
 *      method (see M_XFldObject::wpclsSetIconData), we need
 *      to override this instead. Gee, what a mess.
 *
 *@@added V0.9.16 (2002-01-26) [umoeller]
 */

SOM_Scope HPOINTER  SOMLINK xfM_wpclsQueryIconN(M_XFolder *somSelf,
                                                ULONG ulIconIndex)
{
    HPOINTER hptr = NULLHANDLE;

    M_XFolderData *somThis = M_XFolderGetData(somSelf);
    M_XFolderMethodDebug("M_XFolder","xfM_wpclsQueryIconN");

#ifndef __NOICONREPLACEMENTS__
    if (cmnQuerySetting(sfIconReplacements))
    {
        switch (ulIconIndex)
        {
            case 0:
                // closed folder icon; call WPObject (XFldObject) method
                hptr = _wpclsQueryIcon(somSelf);
            break;

            case 1:
                // avoid loading duplicate icons; do this only
                // once per folder class
                if (!_hptrAni1)
                {
                    PICONINFO pbData = NULL;
                    APIRET arc;
                    if (!(arc = DosAllocMem((PVOID*)&pbData,
                                            0x10000,        // 64 K
                                            OBJ_TILE | PAG_COMMIT | PAG_READ | PAG_WRITE)))
                    {
                        if (_wpclsQueryIconDataN(somSelf,
                                                 pbData,
                                                 ulIconIndex))
                        {
                            switch (pbData->fFormat)
                            {
                                case ICON_FILE:
                                    PMPF_ICONREPLACEMENTS(("        pIconInfo->pszFileName %s", pbData->pszFileName));

                                    icoLoadICOFile(pbData->pszFileName,
                                                   &_hptrAni1,
                                                   NULL,
                                                   NULL);
                                break;

                                case ICON_RESOURCE:
                                    _hptrAni1 = WinLoadPointer(HWND_DESKTOP,
                                                               pbData->hmod,
                                                               pbData->resid);
                                break;

                                case ICON_DATA:
                                    icoBuildPtrHandle(pbData->pIconData,
                                                      &_hptrAni1);
                                break;
                            }
                        }

                        DosFreeMem(pbData);
                    }
                }

                hptr = _hptrAni1;
            break;

        } // end switch (ulIconIndex)
    }

    if (!hptr)
#endif
        hptr = M_XFolder_parent_M_WPFolder_wpclsQueryIconN(somSelf,
                                                           ulIconIndex);

    return hptr;
}

