Something went wrong. Try again.
Reactos
Something went wrong. Try again.
21 kB · 897 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898/* * 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 * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
// // Explorer clone // // desktop.cpp // // Martin Fuchs, 09.08.2003 //
#include <precomp.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);
#ifdef _USE_HDESK
Desktop::Desktop(HDESK hdesktop/*, HWINSTA hwinsta*/) : _hdesktop(hdesktop)// _hwinsta(hwinsta){}
Desktop::~Desktop(){ if (_hdesktop) CloseDesktop(_hdesktop);
// if (_hwinsta)// CloseWindowStation(_hwinsta);
if (_pThread.get()) { _pThread->Stop(); _pThread.release(); }}
#endif
Desktops::Desktops() : _current_desktop(0){}
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};/* 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 (hwnd!=g_Globals._hwndDesktopBar && hwnd!=g_Globals._hwndDesktop) if (IsWindowVisible(hwnd)) windows.insert(hwnd);
return TRUE;}
void Desktops::SwitchToDesktop(int idx){ if (_current_desktop == idx) return;
Desktop& old_desktop = (*this)[_current_desktop]; WindowSet& windows = old_desktop._windows; Desktop& desktop = (*this)[idx];
windows.clear();
// 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);
// save currently visible application windows EnumWindows(SwitchDesktopEnumFct, (LPARAM)&windows);
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 (hwnd!=g_Globals._hwndDesktopBar && hwnd!=g_Globals._hwndDesktop) if (IsWindowVisible(hwnd) && !IsIconic(hwnd)) { RECT rect;
if (GetWindowRect(hwnd,&rect)) if (rect.right>0 && rect.bottom>0 && rect.right>rect.left && rect.bottom>rect.top) { minimized.push_back(MinimizeStruct(hwnd, GetWindowStyle(hwnd))); ShowWindowAsync(hwnd, SW_MINIMIZE); } }
return TRUE;}
/// minimize/restore all windows on the desktopvoid Desktops::ToggleMinimize(){ list<MinimizeStruct>& minimized = (*this)[_current_desktop]._minimized;
if (minimized.empty()) { EnumWindows(MinimizeDesktopEnumFct, (LPARAM)&minimized); } else { const list<MinimizeStruct>& cminimized = minimized; for(list<MinimizeStruct>::const_reverse_iterator it=cminimized.rbegin(); it!=cminimized.rend(); ++it) { ShowWindowAsync(it->first, it->second&WS_MAXIMIZE? SW_MAXIMIZE: SW_RESTORE); Sleep(20); }
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 SetClassLongPtr(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: DrawDesktopBkgnd((HDC)wparam); return TRUE;
case WM_MBUTTONDBLCLK: /* 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); }
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){ _pShellView = NULL;}
DesktopWindow::~DesktopWindow(){ if (_pShellView) _pShellView->Release();}
HWND DesktopWindow::Create(){ 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, 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;}
LRESULT DesktopWindow::Init(LPCREATESTRUCT pcs){ if (super::Init(pcs)) return 1;
HRESULT hr = GetDesktopFolder()->CreateViewObject(_hwnd, IID_IShellView, (void**)&_pShellView);/* also possible: SFV_CREATE sfv_create;
sfv_create.cbSize = sizeof(SFV_CREATE); sfv_create.pshf = GetDesktopFolder(); sfv_create.psvOuter = NULL; sfv_create.psfvcb = NULL;
HRESULT hr = SHCreateShellFolderView(&sfv_create, &_pShellView);*/ HWND hWndView = 0;
if (SUCCEEDED(hr)) { FOLDERSETTINGS fs;
fs.ViewMode = FVM_ICON; 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()
if (SUCCEEDED(hr)) { g_Globals._hwndShellView = hWndView;
// subclass shellview window new DesktopShellView(hWndView, _pShellView);
_pShellView->UIActivate(SVUIA_ACTIVATE_FOCUS);
/* IShellView2* pShellView2;
hr = _pShellView->QueryInterface(IID_IShellView2, (void**)&pShellView2);
SV2CVW2_PARAMS params; params.cbSize = sizeof(SV2CVW2_PARAMS); params.psvPrev = _pShellView; params.pfs = &fs; params.psbOwner = this; params.prcView = ▭ params.pvid = params.pvid;//@@
hr = pShellView2->CreateViewWindow2(¶ms); params.pvid; */
/* IFolderView* pFolderView;
hr = _pShellView->QueryInterface(IID_IFolderView, (void**)&pFolderView);
if (SUCCEEDED(hr)) { hr = pFolderView->GetAutoArrange(); hr = pFolderView->SetCurrentViewMode(FVM_DETAILS); } */ } }
if (hWndView && SetShellWindowEx) SetShellWindowEx(_hwnd, hWndView); else if (SetShellWindow) SetShellWindow(_hwnd);
// create the explorer bar _desktopBar = DesktopBar::Create(); g_Globals._hwndDesktopBar = _desktopBar;
return 0;}
LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam){ switch(nmsg) { case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_MBUTTONDBLCLK: explorer_show_frame(SW_SHOWNORMAL); break;
case WM_DISPLAYCHANGE: MoveWindow(_hwnd, 0, 0, LOWORD(lparam), HIWORD(lparam), TRUE); MoveWindow(g_Globals._hwndShellView, 0, 0, LOWORD(lparam), HIWORD(lparam), TRUE); MoveWindow(_desktopBar, 0, HIWORD(lparam) - DESKTOPBARBAR_HEIGHT, LOWORD(lparam), DESKTOPBARBAR_HEIGHT, TRUE); break;
case WM_GETISHELLBROWSER: return (LRESULT)static_cast<IShellBrowser*>(this);
case WM_DESTROY:
///@todo use IShellBrowser::GetViewStateStream() and _pShellView->SaveViewState() to store view state
if (SetShellWindow) SetShellWindow(0); break;
case WM_CLOSE: ShowExitWindowsDialog(_hwnd); break;
case WM_SYSCOMMAND: if (wparam == SC_TASKLIST) { if (_desktopBar) SendMessage(_desktopBar, nmsg, wparam, lparam); } goto def;
case WM_SYSCOLORCHANGE: // redraw background window - it's done by system //InvalidateRect(g_Globals._hwndShellView, NULL, TRUE);
// forward message to common controls SendMessage(g_Globals._hwndShellView, WM_SYSCOLORCHANGE, 0, 0); SendMessage(_desktopBar, WM_SYSCOLORCHANGE, 0, 0); break;
case WM_SETTINGCHANGE: SendMessage(g_Globals._hwndShellView, nmsg, wparam, lparam); break;
case PM_TRANSLATE_MSG: { /* TranslateAccelerator is called for all explorer windows that are open so we have to decide if this is the correct recipient */ LPMSG lpmsg = (LPMSG)lparam; HWND hwnd = lpmsg->hwnd;
while(hwnd) { if(hwnd == _hwnd) break;
hwnd = GetParent(hwnd); }
if (hwnd) return _pShellView->TranslateAccelerator(lpmsg) == S_OK; return false; }
default: def: return super::WndProc(nmsg, wparam, lparam); }
return 0;}
HRESULT DesktopWindow::OnDefaultCommand(LPIDA pida){#ifndef ROSSHELL // in shell-only-mode fall through and let shell32 handle the command if (MainFrameBase::OpenShellFolders(pida, 0)) return S_OK;#endif
return E_NOTIMPL;}
DesktopShellView::DesktopShellView(HWND hwnd, IShellView* pShellView) : super(hwnd), _pShellView(pShellView){ _hwndListView = GetNextWindow(hwnd, GW_CHILD);
// 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 = 0; // default icon arrangement
InitDragDrop();}
DesktopShellView::~DesktopShellView(){ if (FAILED(RevokeDragDrop(_hwnd))) assert(0);}
bool DesktopShellView::InitDragDrop(){ CONTEXT("DesktopShellView::InitDragDrop()");
DesktopDropTarget * pDropTarget = new DesktopDropTarget(_hwnd);
if (!pDropTarget) return false;
pDropTarget->AddRef();
if (FAILED(RegisterDragDrop(_hwnd, pDropTarget))) { pDropTarget->Release(); return false; }
FORMATETC ftetc;
ftetc.dwAspect = DVASPECT_CONTENT; ftetc.lindex = -1; ftetc.tymed = TYMED_HGLOBAL; ftetc.cfFormat = CF_HDROP;
pDropTarget->AddSuportedFormat(ftetc); pDropTarget->Release();
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))) 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){ 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();
if (SUCCEEDED(hr)) refresh(); else 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, 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-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); } } else _cm_ifs.reset(); DestroyMenu(hmenu); }
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);
/* disable default allignment */ SetWindowStyle(_hwndListView, GetWindowStyle(_hwndListView)&~LVS_ALIGNMASK);//|LVS_ALIGNTOP|LVS_AUTOARRANGE);
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 xoffset = (cx-32)/2; int yoffset = 4/*(cy-32)/2*/;
int start_x = start_pos.x * (work_area.right - cx) + xoffset; int start_y = start_pos.y * (work_area.bottom - cy) + yoffset;
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; int xhv = start_x; int yhv = start_y;
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 - cx + 2*xoffset; else { y += dy1;
if (y + cy - 2 * yoffset > work_area.bottom) { y = start_y; start_x += dx2; x = start_x; } }
continue; } else if (_icon_algo == ARRANGE_BORDER_HV) { if (++cnt & 1) x = work_area.right - x - cx + 2*xoffset; else if (cnt & 2) { yhv += cy; y = yhv; x = start_x;
if (y + cy - 2 * yoffset > work_area.bottom) { start_x += cx; xhv = start_x; x = xhv; start_y += cy; yhv = start_y; y = yhv; } } else { xhv += cx; x = xhv; y = start_y;
if (x + cx - 2 * xoffset > work_area.right) { start_x += cx; xhv = start_x; x = xhv; start_y += cy; yhv = start_y; y = yhv; } }
continue; } else if (_icon_algo == ARRANGE_ROUNDABOUT) {
///@todo
}
x += dx1; y += dy1;
if (x<0 || x+cx-2*xoffset>work_area.right) { x = start_x; y += dy2; } else if (y<0 || y+cy-2*yoffset>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); }}
void DesktopShellView::refresh(){ ///@todo}