Add support for explorer to load the desk.cpl when right clicking on background.
[reactos.git] / reactos / subsys / system / explorer / desktop / desktop.cpp
index 5c44dc8..41b08b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003 Martin Fuchs
+ * Copyright 2003, 2004, 2005 Martin Fuchs
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  //
 
 
-#include "../utility/utility.h"
-#include "../utility/shellclasses.h"
-#include "../utility/shellbrowserimpl.h"
-#include "../utility/window.h"
+#include "precomp.h"
 
-#include "desktop.h"
-#include "../taskbar/desktopbar.h"
-
-#include "../externals.h"
 #include "../explorer_intres.h"
 
+#include "../taskbar/desktopbar.h"
+#include "../taskbar/taskbar.h"        // for PM_GET_LAST_ACTIVE
+
 
 static BOOL (WINAPI*SetShellWindow)(HWND);
 static BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);
 
 
-BOOL IsAnyDesktopRunning()
+#ifdef _USE_HDESK
+
+Desktop::Desktop(HDESK hdesktop/*, HWINSTA hwinsta*/)
+ :     _hdesktop(hdesktop)
+//     _hwinsta(hwinsta)
 {
-       HINSTANCE shell32 = GetModuleHandle(_T("user32"));
+}
 
-       SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(shell32, "SetShellWindow");
-       SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(shell32, "SetShellWindowEx");
+Desktop::~Desktop()
+{
+       if (_hdesktop)
+               CloseDesktop(_hdesktop);
 
-       return GetShellWindow() != 0;
+//     if (_hwinsta)
+//             CloseWindowStation(_hwinsta);
+
+       if (_pThread.get()) {
+               _pThread->Stop();
+               _pThread.release();
+       }
 }
 
+#endif
+
 
-static void draw_desktop_background(HWND hwnd, HDC hdc)
+Desktops::Desktops()
+ :     _current_desktop(0)
 {
-       ClientRect rect(hwnd);
+}
 
-       PaintDesktop(hdc);
+Desktops::~Desktops()
+{
+        // show all hidden windows
+       for(iterator it_dsk=begin(); it_dsk!=end(); ++it_dsk)
+               for(WindowSet::iterator it=it_dsk->_windows.begin(); it!=it_dsk->_windows.end(); ++it)
+                       ShowWindowAsync(*it, SW_SHOW);
+}
+
+void Desktops::init()
+{
+       resize(DESKTOP_COUNT);
+
+#ifdef _USE_HDESK
+       DesktopPtr& desktop = (*this)[0];
+
+       desktop = DesktopPtr(new Desktop(OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP)));
+#endif
+}
+
+#ifdef _USE_HDESK
+
+void Desktops::SwitchToDesktop(int idx)
+{
+       if (_current_desktop == idx)
+               return;
+
+       DesktopPtr& desktop = (*this)[idx];
+
+       DesktopThread* pThread = NULL;
+
+       if (desktop.get()) {
+               if (desktop->_hdesktop)
+                       if (!SwitchDesktop(desktop->_hdesktop))
+                               return;
+       } else {
+               FmtString desktop_name(TEXT("Desktop %d"), idx);
+
+               SECURITY_ATTRIBUTES saAttr = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
 /*
-       HBRUSH bkgndBrush = CreateSolidBrush(RGB(0,32,160));    // dark blue
-       FillRect(hdc, &rect, bkgndBrush);
-       DeleteBrush(bkgndBrush);
+               HWINSTA hwinsta = CreateWindowStation(TEXT("ExplorerWinStation"), 0, GENERIC_ALL, &saAttr);
+
+               if (!SetProcessWindowStation(hwinsta))
+                       return;
 */
+               HDESK hdesktop = CreateDesktop(desktop_name, NULL, NULL, 0, GENERIC_ALL, &saAttr);
+               if (!hdesktop)
+                       return;
+
+               desktop = DesktopPtr(new Desktop(hdesktop/*, hwinsta*/));
+
+               pThread = new DesktopThread(*desktop);
+       }
+
+       _current_desktop = idx;
+
+       if (pThread) {
+               desktop->_pThread = DesktopThreadPtr(pThread);
+               pThread->Start();
+       }
+}
+
+int DesktopThread::Run()
+{
+       if (!SetThreadDesktop(_desktop._hdesktop))
+               return -1;
+
+       HDESK hDesk_old = OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP);
+
+       if (!SwitchDesktop(_desktop._hdesktop))
+               return -1;
+
+       if (!_desktop._hwndDesktop)
+               _desktop._hwndDesktop = DesktopWindow::Create();
+
+       int ret = Window::MessageLoop();
+
+       SwitchDesktop(hDesk_old);
+
+       return ret;
+}
+
+#else // _USE_HDESK
+
+static BOOL CALLBACK SwitchDesktopEnumFct(HWND hwnd, LPARAM lparam)
+{
+       WindowSet& windows = *(WindowSet*)lparam;
+
+       if (IsWindowVisible(hwnd))
+               if (hwnd!=g_Globals._hwndDesktopBar && hwnd!=g_Globals._hwndDesktop)
+                       windows.insert(hwnd);
+
+       return TRUE;
+}
+
+void Desktops::SwitchToDesktop(int idx)
+{
+       if (_current_desktop == idx)
+               return;
 
-       rect.left = rect.right - 280;
-       rect.top = rect.bottom - 56 - DESKTOPBARBAR_HEIGHT;
-       rect.right = rect.left + 250;
-       rect.bottom = rect.top + 40;
+       Desktop& old_desktop = (*this)[_current_desktop];
+       WindowSet& windows = old_desktop._windows;
+       Desktop& desktop = (*this)[idx];
 
-#include "../buildno.h"
-       static const LPCTSTR BkgndText = _T("ReactOS ")_T(KERNEL_VERSION_STR)_T(" Explorer\nby Martin Fuchs");
+       windows.clear();
 
-       BkMode bkMode(hdc, TRANSPARENT);
+        // collect window handles of all other desktops
+       WindowSet other_wnds;
+       for(const_iterator it1=begin(); it1!=end(); ++it1)
+               for(WindowSet::const_iterator it2=it1->_windows.begin(); it2!=it1->_windows.end(); ++it2)
+                       other_wnds.insert(*it2);
 
-       TextColor textColor(hdc, RGB(128,128,192));
-       DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
+        // save currently visible application windows
+       EnumWindows(SwitchDesktopEnumFct, (LPARAM)&windows);
 
-       SetTextColor(hdc, RGB(255,255,255));
-       --rect.right;
-       ++rect.top;
-       DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
+       old_desktop._hwndForeground = (HWND)SendMessage(g_Globals._hwndDesktopBar, PM_GET_LAST_ACTIVE, 0, 0);
+
+        // hide all windows of the previous desktop
+       for(WindowSet::iterator it=windows.begin(); it!=windows.end(); ++it)
+               ShowWindowAsync(*it, SW_HIDE);
+
+        // show all windows of the new desktop
+       for(WindowSet::iterator it=desktop._windows.begin(); it!=desktop._windows.end(); ++it)
+               ShowWindowAsync(*it, SW_SHOW);
+
+       if (desktop._hwndForeground)
+               SetForegroundWindow(desktop._hwndForeground);
+
+        // remove the window handles of the other desktops from what we found on the previous desktop
+       for(WindowSet::const_iterator it=other_wnds.begin(); it!=other_wnds.end(); ++it)
+               windows.erase(*it);
+
+        // We don't need to store the window handles of what's now visible the now current desktop.
+       desktop._windows.clear();
+
+       _current_desktop = idx;
 }
 
+#endif // _USE_HDESK
+
+
+static BOOL CALLBACK MinimizeDesktopEnumFct(HWND hwnd, LPARAM lparam)
+{
+       list<MinimizeStruct>& minimized = *(list<MinimizeStruct>*)lparam;
+
+       if (IsWindowVisible(hwnd))
+               if (hwnd!=g_Globals._hwndDesktopBar && hwnd!=g_Globals._hwndDesktop)
+                       if (!IsIconic(hwnd)) {
+                               minimized.push_back(MinimizeStruct(hwnd, GetWindowStyle(hwnd)));
+                               ShowWindowAsync(hwnd, SW_MINIMIZE);
+                       }
+
+       return TRUE;
+}
+
+ /// minimize/restore all windows on the desktop
+void Desktops::ToggleMinimize()
+{
+       list<MinimizeStruct>& minimized = (*this)[_current_desktop]._minimized;
 
-LRESULT        BackgroundWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
+       if (minimized.empty()) {
+               EnumWindows(MinimizeDesktopEnumFct, (LPARAM)&minimized);
+       } else {
+               for(list<MinimizeStruct>::const_iterator it=minimized.begin(); it!=minimized.end(); ++it)
+                       ShowWindowAsync(it->first, it->second&WS_MAXIMIZE? SW_MAXIMIZE: SW_RESTORE);
+
+               minimized.clear();
+       }
+}
+
+
+BOOL IsAnyDesktopRunning()
+{
+       HINSTANCE hUser32 = GetModuleHandle(TEXT("user32"));
+
+       SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(hUser32, "SetShellWindow");
+       SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(hUser32, "SetShellWindowEx");
+
+       return GetShellWindow() != 0;
+}
+
+
+BackgroundWindow::BackgroundWindow(HWND hwnd)
+ :     super(hwnd)
+{
+        // set background brush for the short moment of displaying the
+        // background color while moving foreground windows
+       SetClassLong(hwnd, GCL_HBRBACKGROUND, COLOR_BACKGROUND+1);
+
+       _display_version = RegGetDWORDValue(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), TEXT("PaintDesktopVersion"), 1);
+}
+
+LRESULT BackgroundWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
        switch(nmsg) {
          case WM_ERASEBKGND:
-               PaintDesktop((HDC)wparam);
+               DrawDesktopBkgnd((HDC)wparam);
                return TRUE;
 
          case WM_MBUTTONDBLCLK:
-               explorer_show_frame(_hwnd, SW_SHOWNORMAL);
+               /* Imagelist icons are missing if MainFrame::Create() is called directly from here!
+               explorer_show_frame(SW_SHOWNORMAL); */
+               PostMessage(g_Globals._hwndDesktop, nmsg, wparam, lparam);
                break;
 
+         case PM_DISPLAY_VERSION:
+               if (lparam || wparam) {
+                       DWORD or_mask = wparam;
+                       DWORD reset_mask = LOWORD(lparam);
+                       DWORD xor_mask = HIWORD(lparam);
+                       _display_version = ((_display_version&~reset_mask) | or_mask) ^ xor_mask;
+                       RegSetDWORDValue(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), TEXT("PaintDesktopVersion"), _display_version);
+                       ///@todo Changing the PaintDesktopVersion-Flag needs a restart of the shell -> display a message box
+                       InvalidateRect(_hwnd, NULL, TRUE);
+               }
+               return _display_version;
+
          default:
                return super::WndProc(nmsg, wparam, lparam);
        }
@@ -102,6 +291,17 @@ LRESULT    BackgroundWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
        return 0;
 }
 
+void BackgroundWindow::DrawDesktopBkgnd(HDC hdc)
+{
+       PaintDesktop(hdc);
+
+/* special solid background
+       HBRUSH bkgndBrush = CreateSolidBrush(RGB(0,32,160));    // dark blue
+       FillRect(hdc, &rect, bkgndBrush);
+       DeleteBrush(bkgndBrush);
+*/
+}
+
 
 DesktopWindow::DesktopWindow(HWND hwnd)
  :     super(hwnd)
@@ -118,19 +318,24 @@ DesktopWindow::~DesktopWindow()
 
 HWND DesktopWindow::Create()
 {
-       IconWindowClass wcDesktop(_T("Progman"), IDI_REACTOS, CS_DBLCLKS);
-       wcDesktop.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
+       static IconWindowClass wcDesktop(TEXT("Progman"), IDI_REACTOS, CS_DBLCLKS);
+       /* (disabled because of small ugly temporary artefacts when hiding start menu)
+       wcDesktop.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1); */
 
        int width = GetSystemMetrics(SM_CXSCREEN);
        int height = GetSystemMetrics(SM_CYSCREEN);
 
        HWND hwndDesktop = Window::Create(WINDOW_CREATOR(DesktopWindow),
-                                       WS_EX_TOOLWINDOW, wcDesktop, _T("Program Manager"), WS_POPUP|WS_CLIPCHILDREN|WS_VISIBLE,
+                                       WS_EX_TOOLWINDOW, wcDesktop, TEXT("Program Manager"), WS_POPUP|WS_VISIBLE,      //|WS_CLIPCHILDREN for SDI frames
                                        0, 0, width, height, 0);
 
         // work around to display desktop bar in Wine
        ShowWindow(GET_WINDOW(DesktopWindow, hwndDesktop)->_desktopBar, SW_SHOW);
 
+        // work around for Windows NT, Win 98, ...
+        // Without this the desktop has mysteriously only a size of 800x600 pixels.
+       MoveWindow(hwndDesktop, 0, 0, width, height, TRUE);
+
        return hwndDesktop;
 }
 
@@ -140,12 +345,12 @@ LRESULT   DesktopWindow::Init(LPCREATESTRUCT pcs)
        if (super::Init(pcs))
                return 1;
 
-       HRESULT hr = Desktop()->CreateViewObject(_hwnd, IID_IShellView, (void**)&_pShellView);
+       HRESULT hr = GetDesktopFolder()->CreateViewObject(_hwnd, IID_IShellView, (void**)&_pShellView);
 /* also possible:
        SFV_CREATE sfv_create;
 
        sfv_create.cbSize = sizeof(SFV_CREATE);
-       sfv_create.pshf = Desktop();
+       sfv_create.pshf = GetDesktopFolder();
        sfv_create.psvOuter = NULL;
        sfv_create.psfvcb = NULL;
 
@@ -157,15 +362,20 @@ LRESULT   DesktopWindow::Init(LPCREATESTRUCT pcs)
                FOLDERSETTINGS fs;
 
                fs.ViewMode = FVM_ICON;
-               fs.fFlags = FWF_DESKTOP|FWF_NOCLIENTEDGE|FWF_NOSCROLL|FWF_BESTFITWINDOW|FWF_SNAPTOGRID;
+               fs.fFlags = FWF_DESKTOP|FWF_NOCLIENTEDGE|FWF_NOSCROLL|FWF_BESTFITWINDOW|FWF_SNAPTOGRID; //|FWF_AUTOARRANGE;
 
                ClientRect rect(_hwnd);
 
                hr = _pShellView->CreateViewWindow(NULL, &fs, this, &rect, &hWndView);
 
-               //TODO: use IShellBrowser::GetViewStateStream() to restore previous view state -> see SHOpenRegStream()
+               ///@todo use IShellBrowser::GetViewStateStream() to restore previous view state -> see SHOpenRegStream()
 
                if (SUCCEEDED(hr)) {
+                       g_Globals._hwndShellView = hWndView;
+
+                        // subclass shellview window
+                       new DesktopShellView(hWndView, _pShellView);
+
                        _pShellView->UIActivate(SVUIA_ACTIVATE_FOCUS);
 
                /*
@@ -195,10 +405,6 @@ LRESULT    DesktopWindow::Init(LPCREATESTRUCT pcs)
                                hr = pFolderView->SetCurrentViewMode(FVM_DETAILS);
                        }
                */
-
-                       HWND hwndFolderView = ::GetNextWindow(hWndView, GW_CHILD);
-
-                       new BackgroundWindow(hwndFolderView);
                }
        }
 
@@ -209,6 +415,7 @@ LRESULT     DesktopWindow::Init(LPCREATESTRUCT pcs)
 
         // create the explorer bar
        _desktopBar = DesktopBar::Create();
+       g_Globals._hwndDesktopBar = _desktopBar;
 
        return 0;
 }
@@ -217,14 +424,10 @@ LRESULT   DesktopWindow::Init(LPCREATESTRUCT pcs)
 LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
        switch(nmsg) {
-         case WM_PAINT:
-               draw_desktop_background(_hwnd, PaintCanvas(_hwnd));
-               break;
-
          case WM_LBUTTONDBLCLK:
          case WM_RBUTTONDBLCLK:
          case WM_MBUTTONDBLCLK:
-               explorer_show_frame(_hwnd, SW_SHOWNORMAL);
+               explorer_show_frame(SW_SHOWNORMAL);
                break;
 
          case WM_GETISHELLBROWSER:
@@ -232,14 +435,15 @@ LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 
          case WM_DESTROY:
 
-               //TODO: use IShellBrowser::GetViewStateStream() and _pShellView->SaveViewState() to store view state
+               ///@todo use IShellBrowser::GetViewStateStream() and _pShellView->SaveViewState() to store view state
                
                if (SetShellWindow)
                        SetShellWindow(0);
                break;
 
          case WM_CLOSE:
-               break;  // Over-ride close. We need to close desktop some other way.
+               ShowExitWindowsDialog(_hwnd);
+               break;
 
          case WM_SYSCOMMAND:
                if (wparam == SC_TASKLIST) {
@@ -254,3 +458,382 @@ LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 
        return 0;
 }
+
+
+HRESULT DesktopWindow::OnDefaultCommand(LPIDA pida)
+{
+       if (MainFrameBase::OpenShellFolders(pida, 0))
+               return S_OK;
+
+       return E_NOTIMPL;
+}
+
+
+DesktopShellView::DesktopShellView(HWND hwnd, IShellView* pShellView)
+ :     super(hwnd),
+       _pShellView(pShellView)
+{
+       _hwndListView = ::GetNextWindow(hwnd, GW_CHILD);
+
+       SetWindowStyle(_hwndListView, GetWindowStyle(_hwndListView)&~LVS_ALIGNMASK);//|LVS_ALIGNTOP|LVS_AUTOARRANGE);
+
+        // work around for Windows NT, Win 98, ...
+        // Without this the desktop has mysteriously only a size of 800x600 pixels.
+       ClientRect rect(hwnd);
+       MoveWindow(_hwndListView, 0, 0, rect.right, rect.bottom, TRUE);
+
+        // subclass background window
+       new BackgroundWindow(_hwndListView);
+
+       _icon_algo = 1; // default icon arrangement
+
+       PositionIcons();
+       InitDragDrop();
+}
+
+bool DesktopShellView::InitDragDrop()
+{
+       CONTEXT("DesktopShellView::InitDragDrop()");
+
+       _pDropTarget = new DesktopDropTarget(_hwnd);
+
+       if (!_pDropTarget)
+               return false;
+
+       _pDropTarget->AddRef();
+
+       if (FAILED(RegisterDragDrop(_hwnd, _pDropTarget))) {
+               _pDropTarget->Release();
+               _pDropTarget = NULL;
+               return false;
+       }
+       else
+               _pDropTarget->Release();
+
+       FORMATETC ftetc;
+
+       ftetc.dwAspect = DVASPECT_CONTENT;
+       ftetc.lindex = -1;
+       ftetc.tymed = TYMED_HGLOBAL;
+       ftetc.cfFormat = CF_HDROP;
+
+       _pDropTarget->AddSuportedFormat(ftetc);
+
+       return true;
+}
+
+LRESULT DesktopShellView::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
+{
+       switch(nmsg) {
+         case WM_CONTEXTMENU:
+               if (!DoContextMenu(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam), _cm_ifs))
+                       DoDesktopContextMenu(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
+               break;
+
+         case PM_SET_ICON_ALGORITHM:
+               _icon_algo = wparam;
+               PositionIcons();
+               break;
+
+         case PM_GET_ICON_ALGORITHM:
+               return _icon_algo;
+
+         case PM_DISPLAY_VERSION:
+               return SendMessage(_hwndListView, nmsg, wparam, lparam);
+
+         default:
+               return super::WndProc(nmsg, wparam, lparam);
+       }
+
+       return 0;
+}
+
+int DesktopShellView::Command(int id, int code)
+{
+       return super::Command(id, code);
+}
+
+int DesktopShellView::Notify(int id, NMHDR* pnmh)
+{
+       return super::Notify(id, pnmh);
+}
+
+bool DesktopShellView::DoContextMenu(int x, int y, CtxMenuInterfaces& cm_ifs)
+{
+       IDataObject* selection;
+
+       HRESULT hr = _pShellView->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (void**)&selection);
+       if (FAILED(hr))
+               return false;
+
+       PIDList pidList;
+
+       hr = pidList.GetData(selection);
+       if (FAILED(hr)) {
+               selection->Release();
+               //CHECKERROR(hr);
+               return false;
+       }
+
+       LPIDA pida = pidList;
+       if (!pida->cidl) {
+               selection->Release();
+               return false;
+       }
+
+       LPCITEMIDLIST parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
+
+       LPCITEMIDLIST* apidl = (LPCITEMIDLIST*) alloca(pida->cidl*sizeof(LPCITEMIDLIST));
+
+       for(int i=pida->cidl; i>0; --i)
+               apidl[i-1] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i]);
+
+       hr = ShellFolderContextMenu(ShellFolder(parent_pidl), _hwnd, pida->cidl, apidl, x, y, cm_ifs);
+
+       selection->Release();
+
+       CHECKERROR(hr);
+
+       return true;
+}
+
+HRESULT DesktopShellView::DoDesktopContextMenu(int x, int y)
+{
+       IContextMenu* pcm;
+
+       HRESULT hr = DesktopFolder()->GetUIObjectOf(_hwnd, 0, NULL, IID_IContextMenu, NULL, (LPVOID*)&pcm);
+
+       if (SUCCEEDED(hr)) {
+               pcm = _cm_ifs.query_interfaces(pcm);
+
+               HMENU hmenu = CreatePopupMenu();
+
+               if (hmenu) {
+                       hr = pcm->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST-1, CMF_NORMAL|CMF_EXPLORE);
+
+                       if (SUCCEEDED(hr)) {
+                               AppendMenu(hmenu, 0, FCIDM_SHVIEWLAST-3, ResString(IDS_PROPERTIES_EXPLORER));
+                               AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+                               AppendMenu(hmenu, 0, FCIDM_SHVIEWLAST-1, ResString(IDS_ABOUT_EXPLORER));
+
+                               UINT idCmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON, x, y, 0, _hwnd, NULL);
+
+                               _cm_ifs.reset();
+
+                               if (idCmd == FCIDM_SHVIEWLAST-3) {
+                                       ShellExecute (_hwnd, _T("open"), _T("c:\\reactos\\system32\\rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0"), NULL, NULL, SW_SHOWNORMAL);
+
+
+                                       //explorer_about(_hwnd);
+                                       //system("c:\\reactos\\system32\\cmd.exe");
+                                       
+                                       //ShellExecute (_hwnd, _T("open"), _T("%SystemRoot%\\system32\\cmd.exe"), NULL, NULL, SW_SHOWNORMAL);
+                                       
+                                         //ShellExecute(NULL,"open","c:\\windows\\system32\\cmd.exe",NULL,NULL,SW_SHOWNORMAL);
+                                       //WCHAR* pFile="%SystemRoot%\system32\cmd.exe";
+                                       //int rcode;
+                                        //TCHAR pFile[256];
+                                        //strcopy("%SystemRoot%\\system32\\cmd.exe",pFile);
+                                        //ShellExecute(NULL, NULL, pFile, NULL, "C:\\", SW_SHOW);
+                                       //HINSTANCE rcode=ShellExecute(NULL, "open", pFile, NULL, "C:\\", SW_SHOW);
+                                       //ShellExecute(hwnd, __TEXT("open"), __TEXT("%SystemRoot%\system32\cmd.exe"), __TEXT("c:\"), SH_SHOW); 
+                               }
+                               if (idCmd == FCIDM_SHVIEWLAST-1) {
+                                       explorer_about(_hwnd);
+                               } else if (idCmd) {
+                                 CMINVOKECOMMANDINFO cmi;
+
+                                 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
+                                 cmi.fMask = 0;
+                                 cmi.hwnd = _hwnd;
+                                 cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST);
+                                 cmi.lpParameters = NULL;
+                                 cmi.lpDirectory = NULL;
+                                 cmi.nShow = SW_SHOWNORMAL;
+                                 cmi.dwHotKey = 0;
+                                 cmi.hIcon = 0;
+
+                                 hr = pcm->InvokeCommand(&cmi);
+                               }
+                       }
+               }
+
+               pcm->Release();
+       }
+
+       return hr;
+}
+
+
+#define        ARRANGE_BORDER_DOWN      8
+#define        ARRANGE_BORDER_HV        9
+#define        ARRANGE_ROUNDABOUT      10
+
+static const POINTS s_align_start[] = {
+       {0, 0}, // left/top
+       {0, 0},
+       {1, 0}, // right/top
+       {1, 0},
+       {0, 1}, // left/bottom
+       {0, 1},
+       {1, 1}, // right/bottom
+       {1, 1},
+
+       {0, 0}, // left/top
+       {0, 0},
+       {0, 0}
+};
+
+static const POINTS s_align_dir1[] = {
+       { 0, +1},       // down
+       {+1,  0},       // right
+       {-1,  0},       // left
+       { 0, +1},       // down
+       { 0, -1},       // up
+       {+1,  0},       // right
+       {-1,  0},       // left
+       { 0, -1},       // up
+
+       { 0, +1},       // down
+       {+1,  0},       // right
+       {+1,  0}        // right
+};
+
+static const POINTS s_align_dir2[] = {
+       {+1,  0},       // right
+       { 0, +1},       // down
+       { 0, +1},       // down
+       {-1,  0},       // left
+       {+1,  0},       // right
+       { 0, -1},       // up
+       { 0, -1},       // up
+       {-1,  0},       // left
+
+       {+1,  0},       // right
+       { 0, +1},       // down
+       { 0, +1}        // down
+};
+
+typedef pair<int,int> IconPos;
+typedef map<IconPos, int> IconMap;
+
+void DesktopShellView::PositionIcons(int dir)
+{
+       DWORD spacing = ListView_GetItemSpacing(_hwndListView, FALSE);
+
+       RECT work_area;
+       SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0);
+
+       const POINTS& dir1 = s_align_dir1[_icon_algo];
+       const POINTS& dir2 = s_align_dir2[_icon_algo];
+       const POINTS& start_pos = s_align_start[_icon_algo];
+
+       int dir_x1 = dir1.x;
+       int dir_y1 = dir1.y;
+       int dir_x2 = dir2.x;
+       int dir_y2 = dir2.y;
+
+       int cx = LOWORD(spacing);
+       int cy = HIWORD(spacing);
+
+       int dx1 = dir_x1 * cx;
+       int dy1 = dir_y1 * cy;
+       int dx2 = dir_x2 * cx;
+       int dy2 = dir_y2 * cy;
+
+       int start_x = (start_pos.x * work_area.right)/cx*cx + (cx-32)/2;
+       int start_y = (start_pos.y * work_area.bottom)/cy*cy + 4/*(cy-32)/2*/;
+
+       if (start_x >= work_area.right)
+               start_x -= cx;
+
+       if (start_y >= work_area.bottom)
+               start_y -= cy;
+
+       int x = start_x;
+       int y = start_y;
+
+       int all = ListView_GetItemCount(_hwndListView);
+       int i1, i2;
+
+       if (dir > 0) {
+               i1 = 0;
+               i2 = all;
+       } else {
+               i1 = all-1;
+               i2 = -1;
+       }
+
+       IconMap pos_idx;
+       int cnt = 0;
+
+       for(int idx=i1; idx!=i2; idx+=dir) {
+               pos_idx[IconPos(y, x)] = idx;
+
+               if (_icon_algo == ARRANGE_BORDER_DOWN) {
+                       if (++cnt & 1)
+                               x = work_area.right - x;
+                       else {
+                               y += dy1;
+
+                               if (y >= work_area.bottom) {
+                                       y = start_y;
+                                       x += dx2;
+                               }
+                       }
+
+                       continue;
+               }
+               else if (_icon_algo == ARRANGE_BORDER_HV) {
+                       if (++cnt & 1)
+                               x = work_area.right - x;
+                       else if (cnt & 2) {
+                               y += dy1;
+
+                               if (y >= work_area.bottom) {
+                                       y = start_y;
+                                       x += dx2;
+                               }
+                       } else {
+                               x += dx1;
+
+                               if (x >= work_area.right) {
+                                       x = start_x;
+                                       y += dy2;
+                               }
+                       }
+
+                       continue;
+               }
+               else if (_icon_algo == ARRANGE_ROUNDABOUT) {
+
+                       ///@todo
+
+               }
+
+               x += dx1;
+               y += dy1;
+
+               if (x<0 || x>=work_area.right) {
+                       x = start_x;
+                       y += dy2;
+               } else if (y<0 || y>=work_area.bottom) {
+                       y = start_y;
+                       x += dx2;
+               }
+       }
+
+        // use a little trick to get the icons where we want them to be...
+
+       for(IconMap::const_iterator it=pos_idx.end(); --it!=pos_idx.begin(); ) {
+               const IconPos& pos = it->first;
+
+               ListView_SetItemPosition32(_hwndListView, it->second, pos.second, pos.first);
+       }
+
+       for(IconMap::const_iterator it=pos_idx.begin(); it!=pos_idx.end(); ++it) {
+               const IconPos& pos = it->first;
+
+               ListView_SetItemPosition32(_hwndListView, it->second, pos.second, pos.first);
+       }
+}