program Warp;
(*****************************************************************************
                 Desktop objects launcher
             Copyright (c) 1999 by AVM Software

Представление иерархии объектов рабочего стола в форме вложенного меню.
*****************************************************************************)

uses Windows,Registry,SysUtils,Messages,WarpMenu,TaskBar,WarpDesk;

{$R *.RES}
{$R WarpMenu.RES}

const
  WM_TASKBAR = WM_APP + 1;
  ICON_ID = 0;
  Hint : array[0..63] of char = 'Warp Button : Desktop as Menu';

  sClassName = 'sWarpButtonHandlerWindow';
  AboutText = 'Desktop objects launcher V1.0'#13 +
              'Copyright (c) 1999 by AVM Software';
  AboutCaption = 'About';
  AboutIcon = 'MAINICON';
  RegKey = '\Software\AVM Software\Warp';
  ShowIconValName = 'ShowIcons';
  SkipFoldersValName : array[sfTrashCan..sfControls] of string[19] =
      ( 'ExcludeRecycleBin', 'ExcludeNetwork', 'ExcludeControls' );

var
  hWnd  : THandle;
  Msg   : TMsg;
  TaskBarCreated : integer;
  MainIcon,WaitIcon : HIcon;
  AppMutex : THandle;

procedure ShowAboutDialog;
  var
    Version: TOSVersionInfo;
    MsgBoxParamsW: TMsgBoxParamsW;
    MsgBoxParamsA: TMsgBoxParamsA;
  begin
    Version.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
    GetVersionEx(Version);
    if Version.dwPlatformId = VER_PLATFORM_WIN32_NT then begin
      FillChar(MsgBoxParamsW, SizeOf(MsgBoxParamsW), #0);
      with MsgBoxParamsW do begin
        cbSize := SizeOf(MsgBoxParamsW);
        hwndOwner := hWnd;
        hInstance := SysInit.hInstance;
        lpszText  := AboutText;
        lpszCaption := AboutCaption;
        lpszIcon := AboutIcon;
        dwStyle := MB_USERICON;
      end;
      MessageBoxIndirectW(MsgBoxParamsW);
    end else begin
      FillChar(MsgBoxParamsA, SizeOf(MsgBoxParamsA), #0);
      with MsgBoxParamsA do begin
        cbSize := SizeOf(MsgBoxParamsA);
        hwndOwner := hWnd;
        hInstance := SysInit.hInstance;
        lpszText  := AboutText;
        lpszCaption := AboutCaption;
        lpszIcon := AboutIcon;
        dwStyle := MB_USERICON;
      end;
      MessageBoxIndirectA(MsgBoxParamsA);
    end;
  end;

procedure CreateTaskBarIcon;
  begin
    TaskBarAddIcon(hWnd, ICON_ID, MainIcon, WM_TASKBAR, Hint);
  end;

procedure PopupMenu(hWnd : THandle);
  var Menu,Popup,Options,ExcFlds : hMenu; i : integer;
  begin
    Menu := LoadMenu(hInstance, 'MAINMENU');
    Popup := GetSubMenu(Menu, 0);
    Options := GetSubMenu(Popup, 2);
    CheckMenuRadioItem(Options, siNoIcons, siLargeIcons, ShowIcons, MF_BYPOSITION);
    ExcFlds := GetSubMenu(Options, 4);
    for i := sfTrashCan to sfControls do
      if i in SkipFoldSet then CheckMenuItem(ExcFlds, i, MF_CHECKED or MF_BYPOSITION);
    ExecMenu(hWnd, Popup);
    DestroyMenu(Menu);
  end;

procedure InitDesktopMenu;
  begin
    TaskBarModifyIcon(hWnd, ICON_ID, NIF_ICON or NIF_TIP, WaitIcon, 'Init menu objects..');
    InitWarpDesktop(hWnd);
    TaskBarModifyIcon(hWnd, ICON_ID, NIF_ICON or NIF_TIP, MainIcon, Hint);
  end;

procedure RefreshDesktopMenu(Option : integer);
  var Ini : TRegistry;
  begin
    Ini := TRegistry.Create;
    Ini.RootKey := HKEY_CURRENT_USER;
    Ini.OpenKey(RegKey, true);
    Ini.WriteInteger(ShowIconValName, Option);
    RefreshMenu(Option);
    Ini.Free;
  end;

procedure ChangeExcludeList(Skip : integer);
  var Ini : TRegistry; I : integer;
  begin
    if Skip in SkipFoldSet then exclude(SkipFoldSet, Skip)
    else include(SkipFoldSet, Skip);
    Ini := TRegistry.Create;
    Ini.RootKey := HKEY_CURRENT_USER;
    Ini.OpenKey(RegKey, true);
    for i := low(SkipFoldersValName) to high(SkipFoldersValName) do
      Ini.WriteInteger(SkipFoldersValName[i], ord(i in SkipFoldSet));
    InitDesktopMenu;
    Ini.Free;
  end;

procedure LoadMenuOptions;
  var Ini : TRegistry; I : integer;
  begin
    Ini := TRegistry.Create;
    Ini.RootKey := HKEY_CURRENT_USER;
    if Ini.OpenKey(RegKey, false) then
      begin
        if Ini.ValueExists(ShowIconValName) then ShowIcons := Ini.ReadInteger(ShowIconValName);
        for i := low(SkipFoldersValName) to high(SkipFoldersValName) do
          if Ini.ValueExists(SkipFoldersValName[i]) then
            if Ini.ReadInteger(SkipFoldersValName[i]) = 0 then
              exclude(SkipFoldSet, i)
            else include(SkipFoldSet, i);
      end;
    Ini.Free;
  end;

function WindowProc(hWnd : THandle; uMsg,wParam,lParam : integer) : integer;
  stdcall; export;
  begin
    Result := 0;
    if uMsg = TaskBarCreated then CreateTaskbarIcon
    else case uMsg of
      WM_COMMAND:
        case wParam of
          ID_ABOUT      : ShowAboutDialog;
          ID_REFRESH    : InitDesktopMenu;
          ID_NOICONS    : RefreshDesktopMenu(siNoIcons);
          ID_SMALLICONS : RefreshDesktopMenu(siSmallIcons);
          ID_LARGEICONS : RefreshDesktopMenu(siLargeIcons);
          ID_EX_TRASHCAN: ChangeExcludeList(sfTrashCan);
          ID_EX_NETWORK : ChangeExcludeList(sfNetwork);
          ID_EX_CONTROLS: ChangeExcludeList(sfControls);
          ID_CLOSE      : PostMessage(hWnd, WM_DESTROY, 0, 0);
        else HandleDeskMenu(hWnd, wParam, lParam);
        end;
      WM_DISPLAYCHANGE,
      WM_WININICHANGE   : RefreshMenu(ShowIcons);
      WM_TASKBAR :
        case wParam of
          ICON_ID:
            case lParam of
              WM_LBUTTONDOWN: PopupDesktop(hWnd, true);
              WM_RBUTTONDOWN: PopupMenu(hWnd);
            end;
        end;
      WM_HOTKEY :
        case wParam of
          0 : PopupDesktop(hWnd, false);
        end;
      WM_DESTROY :
        begin
          PostQuitMessage(0); exit;
        end;
      WM_DRAWITEM     : DrawDeskMenuItem(PDrawItemStruct(lParam));
      WM_MEASUREITEM  : MeasureDeskMenuItem(PMeasureItemStruct(lParam));
    end;
    Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
  end;

procedure CreateMonitorWindow;
  var WndClass: TWndClass;
  begin
    FillChar(WndClass, SizeOf(WndClass), 0);
    with WndClass do begin
      hInstance      := SysInit.hInstance;
      lpszClassName  := sClassName;
      lpfnWndProc    := @WindowProc;
    end;
    RegisterClass(WndClass);
    hWnd := CreateWindow(sClassName, '', 0, 0, 0, 0, 0, 0, 0, hInstance, nil);
  end;

function OneInstance : boolean;
  var CritSecMutex: THandle;
  begin
    CritSecMutex := CreateMutex( nil, true, pchar(sClassName + '.OneInstance32.CriticalSection') );
    AppMutex := CreateMutex( nil, false, pchar(sClassName + 'OneInstance32.Default') );
    result := WaitForSingleObject( AppMutex, 0 ) <> WAIT_TIMEOUT;
    ReleaseMutex( CritSecMutex );
    CloseHandle( CritSecMutex );
    if not result then CloseHandle(AppMutex);
  end;

begin
  if not OneInstance then exit;
  MainIcon := LoadIcon(hInstance, 'MAINICON');
  WaitIcon := LoadIcon(hInstance, 'WAITICON');
  CreateMonitorWindow;
  RegisterHotKey(hWnd, 0, MOD_ALT or MOD_CONTROL, VK_F12);
  TaskBarCreated := RegisterWindowMessage('TaskbarCreated');
  CreateTaskBarIcon;
  ShowWindow(hWnd, SW_HIDE);
  LoadMenuOptions;
  InitDesktopMenu;
  repeat
    if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin
      if Msg.Message = WM_QUIT then break;
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end else
    if MsgWaitForMultipleObjects(1, NotifyObj, false, INFINITE, QS_ALLINPUT) = WAIT_OBJECT_0 then
      begin
        InitDesktopMenu;
        FindNextChangeNotification(NotifyObj);
      end;
  until false;
  TaskBarDeleteIcon(hWnd, ICON_ID);
  DoneWarpDesktop(hWnd);
  CloseHandle(AppMutex);
  Halt(Msg.wParam);
end.

