re-show all hidden windows at explorer termination
[reactos.git] / reactos / subsys / system / explorer / desktop / desktop.cpp
1 /*
2 * Copyright 2003 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // desktop.cpp
24 //
25 // Martin Fuchs, 09.08.2003
26 //
27
28
29 #include "../utility/utility.h"
30 #include "../utility/shellclasses.h"
31 #include "../utility/shellbrowserimpl.h"
32 #include "../utility/dragdropimpl.h"
33 #include "../utility/window.h"
34
35 #include "../globals.h"
36 #include "../externals.h"
37 #include "../explorer_intres.h"
38
39 #include "desktop.h"
40 #include "../taskbar/desktopbar.h"
41 #include "../shell/mainframe.h" // for MainFrame::Create()
42
43
44 static BOOL (WINAPI*SetShellWindow)(HWND);
45 static BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);
46
47
48 #ifdef _USE_HDESK
49
50 Desktop::Desktop(HDESK hdesktop/*, HWINSTA hwinsta*/)
51 : _hdesktop(hdesktop)
52 // _hwinsta(hwinsta)
53 {
54 }
55
56 Desktop::~Desktop()
57 {
58 if (_hdesktop)
59 CloseDesktop(_hdesktop);
60
61 // if (_hwinsta)
62 // CloseWindowStation(_hwinsta);
63
64 if (_pThread.get()) {
65 _pThread->Stop();
66 _pThread.release();
67 }
68 }
69
70 #endif
71
72
73 Desktops::Desktops()
74 : _current_desktop(0)
75 {
76 }
77
78 Desktops::~Desktops()
79 {
80 // show all hidden windows
81 for(iterator it_dsk=begin(); it_dsk!=end(); ++it_dsk)
82 for(WindowSet::iterator it=it_dsk->_windows.begin(); it!=it_dsk->_windows.end(); ++it)
83 ShowWindowAsync(*it, SW_SHOW);
84 }
85
86 void Desktops::init()
87 {
88 resize(DESKTOP_COUNT);
89
90 #ifdef _USE_HDESK
91 DesktopPtr& desktop = (*this)[0];
92
93 desktop = DesktopPtr(new Desktop(OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP)));
94 #endif
95 }
96
97 #ifdef _USE_HDESK
98
99 void Desktops::SwitchToDesktop(int idx)
100 {
101 if (_current_desktop == idx)
102 return;
103
104 DesktopPtr& desktop = (*this)[idx];
105
106 DesktopThread* pThread = NULL;
107
108 if (desktop.get()) {
109 if (desktop->_hdesktop)
110 if (!SwitchDesktop(desktop->_hdesktop))
111 return;
112 } else {
113 FmtString desktop_name(TEXT("Desktop %d"), idx);
114
115 SECURITY_ATTRIBUTES saAttr = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
116 /*
117 HWINSTA hwinsta = CreateWindowStation(TEXT("ExplorerWinStation"), 0, GENERIC_ALL, &saAttr);
118
119 if (!SetProcessWindowStation(hwinsta))
120 return;
121 */
122 HDESK hdesktop = CreateDesktop(desktop_name, NULL, NULL, 0, GENERIC_ALL, &saAttr);
123 if (!hdesktop)
124 return;
125
126 desktop = DesktopPtr(new Desktop(hdesktop/*, hwinsta*/));
127
128 pThread = new DesktopThread(*desktop);
129 }
130
131 _current_desktop = idx;
132
133 if (pThread) {
134 desktop->_pThread = DesktopThreadPtr(pThread);
135 pThread->Start();
136 }
137 }
138
139 int DesktopThread::Run()
140 {
141 if (!SetThreadDesktop(_desktop._hdesktop))
142 return -1;
143
144 HDESK hDesk_old = OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP);
145
146 if (!SwitchDesktop(_desktop._hdesktop))
147 return -1;
148
149 if (!_desktop._hwndDesktop)
150 _desktop._hwndDesktop = DesktopWindow::Create();
151
152 int ret = Window::MessageLoop();
153
154 SwitchDesktop(hDesk_old);
155
156 return ret;
157 }
158
159 #else // _USE_HDESK
160
161 static BOOL CALLBACK DesktopEnumFct(HWND hwnd, LPARAM lparam)
162 {
163 WindowSet& windows = *(WindowSet*)lparam;
164
165 if (IsWindowVisible(hwnd)) {
166 DWORD pid;
167
168 GetWindowThreadProcessId(hwnd, &pid);
169
170 if (pid != GetCurrentProcessId())
171 windows.insert(hwnd);
172 }
173
174 return TRUE;
175 }
176
177 void Desktops::SwitchToDesktop(int idx)
178 {
179 if (_current_desktop == idx)
180 return;
181
182 Desktop& desktop = (*this)[idx];
183
184 // save currently visible application windows
185 Desktop& old_desktop = (*this)[_current_desktop];
186 WindowSet& windows = old_desktop._windows;
187
188 windows.clear();
189 EnumWindows(DesktopEnumFct, (LPARAM)&windows);
190
191 // hide all windows we found
192 for(WindowSet::iterator it=windows.begin(); it!=windows.end(); ++it)
193 ShowWindowAsync(*it, SW_HIDE);
194
195 // show all windows of the new desktop
196 for(WindowSet::iterator it=desktop._windows.begin(); it!=desktop._windows.end(); ++it)
197 ShowWindowAsync(*it, SW_SHOW);
198
199 desktop._windows.clear();
200
201 _current_desktop = idx;
202 }
203
204 #endif // _USE_HDESK
205
206
207 BOOL IsAnyDesktopRunning()
208 {
209 HINSTANCE hUser32 = GetModuleHandle(TEXT("user32"));
210
211 SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(hUser32, "SetShellWindow");
212 SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(hUser32, "SetShellWindowEx");
213
214 return GetShellWindow() != 0;
215 }
216
217
218 static void draw_desktop_background(HWND hwnd, HDC hdc)
219 {
220 ClientRect rect(hwnd);
221
222 PaintDesktop(hdc);
223 /*
224 HBRUSH bkgndBrush = CreateSolidBrush(RGB(0,32,160)); // dark blue
225 FillRect(hdc, &rect, bkgndBrush);
226 DeleteBrush(bkgndBrush);
227 */
228
229 rect.left = rect.right - 280;
230 rect.top = rect.bottom - 56 - DESKTOPBARBAR_HEIGHT;
231 rect.right = rect.left + 250;
232 rect.bottom = rect.top + 40;
233
234 #include "../buildno.h"
235 static const LPCTSTR BkgndText = TEXT("ReactOS ")TEXT(KERNEL_VERSION_STR)TEXT(" Explorer\nby Martin Fuchs");
236
237 BkMode bkMode(hdc, TRANSPARENT);
238
239 TextColor textColor(hdc, RGB(128,128,192));
240 DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
241
242 SetTextColor(hdc, RGB(255,255,255));
243 --rect.right;
244 ++rect.top;
245 DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
246 }
247
248
249 LRESULT BackgroundWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
250 {
251 switch(nmsg) {
252 case WM_ERASEBKGND:
253 PaintDesktop((HDC)wparam);
254 return TRUE;
255
256 case WM_MBUTTONDBLCLK:
257 explorer_show_frame(SW_SHOWNORMAL);
258 break;
259
260 default:
261 return super::WndProc(nmsg, wparam, lparam);
262 }
263
264 return 0;
265 }
266
267
268 DesktopWindow::DesktopWindow(HWND hwnd)
269 : super(hwnd)
270 {
271 _pShellView = NULL;
272 }
273
274 DesktopWindow::~DesktopWindow()
275 {
276 if (_pShellView)
277 _pShellView->Release();
278 }
279
280
281 HWND DesktopWindow::Create()
282 {
283 static IconWindowClass wcDesktop(TEXT("Progman"), IDI_REACTOS, CS_DBLCLKS);
284 wcDesktop.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
285
286 int width = GetSystemMetrics(SM_CXSCREEN);
287 int height = GetSystemMetrics(SM_CYSCREEN);
288
289 HWND hwndDesktop = Window::Create(WINDOW_CREATOR(DesktopWindow),
290 WS_EX_TOOLWINDOW, wcDesktop, TEXT("Program Manager"), WS_POPUP|WS_VISIBLE|WS_CLIPCHILDREN,
291 0, 0, width, height, 0);
292
293 // work around to display desktop bar in Wine
294 ShowWindow(GET_WINDOW(DesktopWindow, hwndDesktop)->_desktopBar, SW_SHOW);
295
296 // work around for Windows NT, Win 98, ...
297 // Without this the desktop has mysteriously only a size of 800x600 pixels.
298 MoveWindow(hwndDesktop, 0, 0, width, height, TRUE);
299
300 return hwndDesktop;
301 }
302
303
304 LRESULT DesktopWindow::Init(LPCREATESTRUCT pcs)
305 {
306 if (super::Init(pcs))
307 return 1;
308
309 HRESULT hr = GetDesktopFolder()->CreateViewObject(_hwnd, IID_IShellView, (void**)&_pShellView);
310 /* also possible:
311 SFV_CREATE sfv_create;
312
313 sfv_create.cbSize = sizeof(SFV_CREATE);
314 sfv_create.pshf = GetDesktopFolder();
315 sfv_create.psvOuter = NULL;
316 sfv_create.psfvcb = NULL;
317
318 HRESULT hr = SHCreateShellFolderView(&sfv_create, &_pShellView);
319 */
320 HWND hWndView = 0;
321
322 if (SUCCEEDED(hr)) {
323 FOLDERSETTINGS fs;
324
325 fs.ViewMode = FVM_ICON;
326 fs.fFlags = FWF_DESKTOP|FWF_NOCLIENTEDGE|FWF_NOSCROLL|FWF_BESTFITWINDOW|FWF_SNAPTOGRID; //|FWF_AUTOARRANGE;
327
328 ClientRect rect(_hwnd);
329
330 hr = _pShellView->CreateViewWindow(NULL, &fs, this, &rect, &hWndView);
331
332 ///@todo use IShellBrowser::GetViewStateStream() to restore previous view state -> see SHOpenRegStream()
333
334 if (SUCCEEDED(hr)) {
335 g_Globals._hwndShellView = hWndView;
336
337 // subclass shellview window
338 new DesktopShellView(hWndView, _pShellView);
339
340 _pShellView->UIActivate(SVUIA_ACTIVATE_FOCUS);
341
342 /*
343 IShellView2* pShellView2;
344
345 hr = _pShellView->QueryInterface(IID_IShellView2, (void**)&pShellView2);
346
347 SV2CVW2_PARAMS params;
348 params.cbSize = sizeof(SV2CVW2_PARAMS);
349 params.psvPrev = _pShellView;
350 params.pfs = &fs;
351 params.psbOwner = this;
352 params.prcView = ▭
353 params.pvid = params.pvid;//@@
354
355 hr = pShellView2->CreateViewWindow2(&params);
356 params.pvid;
357 */
358
359 /*
360 IFolderView* pFolderView;
361
362 hr = _pShellView->QueryInterface(IID_IFolderView, (void**)&pFolderView);
363
364 if (SUCCEEDED(hr)) {
365 hr = pFolderView->GetAutoArrange();
366 hr = pFolderView->SetCurrentViewMode(FVM_DETAILS);
367 }
368 */
369 }
370 }
371
372 if (hWndView && SetShellWindowEx)
373 SetShellWindowEx(_hwnd, hWndView);
374 else if (SetShellWindow)
375 SetShellWindow(_hwnd);
376
377 // create the explorer bar
378 _desktopBar = DesktopBar::Create();
379 g_Globals._hwndDesktopBar = _desktopBar;
380
381 return 0;
382 }
383
384
385 LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
386 {
387 switch(nmsg) {
388 case WM_PAINT:
389 draw_desktop_background(_hwnd, PaintCanvas(_hwnd));
390 break;
391
392 case WM_LBUTTONDBLCLK:
393 case WM_RBUTTONDBLCLK:
394 case WM_MBUTTONDBLCLK:
395 explorer_show_frame(SW_SHOWNORMAL);
396 break;
397
398 case WM_GETISHELLBROWSER:
399 return (LRESULT)static_cast<IShellBrowser*>(this);
400
401 case WM_DESTROY:
402
403 ///@todo use IShellBrowser::GetViewStateStream() and _pShellView->SaveViewState() to store view state
404
405 if (SetShellWindow)
406 SetShellWindow(0);
407 break;
408
409 case WM_CLOSE:
410 ShowExitWindowsDialog(_hwnd);
411 break;
412
413 case WM_SYSCOMMAND:
414 if (wparam == SC_TASKLIST) {
415 if (_desktopBar)
416 SendMessage(_desktopBar, nmsg, wparam, lparam);
417 }
418 goto def;
419
420 default: def:
421 return super::WndProc(nmsg, wparam, lparam);
422 }
423
424 return 0;
425 }
426
427
428 HRESULT DesktopWindow::OnDefaultCommand(LPIDA pida)
429 {
430 if (MainFrame::OpenShellFolders(pida, 0))
431 return S_OK;
432
433 return E_NOTIMPL;
434 }
435
436
437 DesktopShellView::DesktopShellView(HWND hwnd, IShellView* pShellView)
438 : super(hwnd),
439 _pShellView(pShellView)
440 {
441 _hwndListView = ::GetNextWindow(hwnd, GW_CHILD);
442
443 SetWindowStyle(_hwndListView, GetWindowStyle(_hwndListView)&~LVS_ALIGNMASK);//|LVS_ALIGNTOP|LVS_AUTOARRANGE);
444
445 // work around for Windows NT, Win 98, ...
446 // Without this the desktop has mysteriously only a size of 800x600 pixels.
447 ClientRect rect(hwnd);
448 MoveWindow(_hwndListView, 0, 0, rect.right, rect.bottom, TRUE);
449
450 // subclass background window
451 new BackgroundWindow(_hwndListView);
452
453 _icon_algo = 1; // default icon arrangement
454
455 PositionIcons();
456 InitDragDrop();
457 }
458
459 bool DesktopShellView::InitDragDrop()
460 {
461 CONTEXT("DesktopShellView::InitDragDrop()");
462
463 _pDropTarget = new DesktopDropTarget(_hwnd);
464
465 if (!_pDropTarget)
466 return false;
467
468 _pDropTarget->AddRef();
469
470 if (FAILED(RegisterDragDrop(_hwnd, _pDropTarget))) {
471 _pDropTarget->Release();
472 _pDropTarget = NULL;
473 return false;
474 }
475 else
476 _pDropTarget->Release();
477
478 FORMATETC ftetc;
479
480 ftetc.dwAspect = DVASPECT_CONTENT;
481 ftetc.lindex = -1;
482 ftetc.tymed = TYMED_HGLOBAL;
483 ftetc.cfFormat = CF_HDROP;
484
485 _pDropTarget->AddSuportedFormat(ftetc);
486
487 return true;
488 }
489
490 LRESULT DesktopShellView::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
491 {
492 switch(nmsg) {
493 case WM_CONTEXTMENU:
494 if (!DoContextMenu(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)))
495 DoDesktopContextMenu(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
496 break;
497
498 case PM_SET_ICON_ALGORITHM:
499 _icon_algo = wparam;
500 PositionIcons();
501 break;
502
503 case PM_GET_ICON_ALGORITHM:
504 return _icon_algo;
505
506 default:
507 return super::WndProc(nmsg, wparam, lparam);
508 }
509
510 return 0;
511 }
512
513 int DesktopShellView::Command(int id, int code)
514 {
515 return super::Command(id, code);
516 }
517
518 int DesktopShellView::Notify(int id, NMHDR* pnmh)
519 {
520 return super::Notify(id, pnmh);
521 }
522
523 bool DesktopShellView::DoContextMenu(int x, int y)
524 {
525 IDataObject* selection;
526
527 HRESULT hr = _pShellView->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (void**)&selection);
528 if (FAILED(hr))
529 return false;
530
531 PIDList pidList;
532
533 hr = pidList.GetData(selection);
534 if (FAILED(hr)) {
535 selection->Release();
536 //CHECKERROR(hr);
537 return false;
538 }
539
540 LPIDA pida = pidList;
541 if (!pida->cidl) {
542 selection->Release();
543 return false;
544 }
545
546 LPCITEMIDLIST parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
547
548 LPCITEMIDLIST* apidl = (LPCITEMIDLIST*) alloca(pida->cidl*sizeof(LPCITEMIDLIST));
549
550 for(int i=pida->cidl; i>0; --i)
551 apidl[i-1] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i]);
552
553 hr = ShellFolderContextMenu(ShellFolder(parent_pidl), _hwnd, pida->cidl, apidl, x, y);
554
555 selection->Release();
556
557 CHECKERROR(hr);
558
559 return true;
560 }
561
562 HRESULT DesktopShellView::DoDesktopContextMenu(int x, int y)
563 {
564 IContextMenu* pcm;
565
566 HRESULT hr = DesktopFolder()->GetUIObjectOf(_hwnd, 0, NULL, IID_IContextMenu, NULL, (LPVOID*)&pcm);
567
568 if (SUCCEEDED(hr)) {
569 HMENU hmenu = CreatePopupMenu();
570
571 if (hmenu) {
572 hr = pcm->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST-1, CMF_NORMAL|CMF_EXPLORE);
573
574 if (SUCCEEDED(hr)) {
575 AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
576 AppendMenu(hmenu, 0, FCIDM_SHVIEWLAST-1, ResString(IDS_ABOUT_EXPLORER));
577
578 UINT idCmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON, x, y, 0, _hwnd, NULL);
579
580 if (idCmd == FCIDM_SHVIEWLAST-1) {
581 explorer_about(_hwnd);
582 } else if (idCmd) {
583 CMINVOKECOMMANDINFO cmi;
584
585 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
586 cmi.fMask = 0;
587 cmi.hwnd = _hwnd;
588 cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST);
589 cmi.lpParameters = NULL;
590 cmi.lpDirectory = NULL;
591 cmi.nShow = SW_SHOWNORMAL;
592 cmi.dwHotKey = 0;
593 cmi.hIcon = 0;
594
595 hr = pcm->InvokeCommand(&cmi);
596 }
597 }
598 }
599
600 pcm->Release();
601 }
602
603 return hr;
604 }
605
606
607 #define ARRANGE_BORDER_DOWN 8
608 #define ARRANGE_BORDER_HV 9
609 #define ARRANGE_ROUNDABOUT 10
610
611 static const POINTS s_align_start[] = {
612 {0, 0}, // left/top
613 {0, 0},
614 {1, 0}, // right/top
615 {1, 0},
616 {0, 1}, // left/bottom
617 {0, 1},
618 {1, 1}, // right/bottom
619 {1, 1},
620
621 {0, 0}, // left/top
622 {0, 0},
623 {0, 0}
624 };
625
626 static const POINTS s_align_dir1[] = {
627 { 0, +1}, // down
628 {+1, 0}, // right
629 {-1, 0}, // left
630 { 0, +1}, // down
631 { 0, -1}, // up
632 {+1, 0}, // right
633 {-1, 0}, // left
634 { 0, -1}, // up
635
636 { 0, +1}, // down
637 {+1, 0}, // right
638 {+1, 0} // right
639 };
640
641 static const POINTS s_align_dir2[] = {
642 {+1, 0}, // right
643 { 0, +1}, // down
644 { 0, +1}, // down
645 {-1, 0}, // left
646 {+1, 0}, // right
647 { 0, -1}, // up
648 { 0, -1}, // up
649 {-1, 0}, // left
650
651 {+1, 0}, // right
652 { 0, +1}, // down
653 { 0, +1} // down
654 };
655
656 typedef pair<int,int> IconPos;
657 typedef map<IconPos, int> IconMap;
658
659 void DesktopShellView::PositionIcons(int dir)
660 {
661 DWORD spacing = ListView_GetItemSpacing(_hwndListView, FALSE);
662
663 RECT work_area;
664 SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0);
665
666 const POINTS& dir1 = s_align_dir1[_icon_algo];
667 const POINTS& dir2 = s_align_dir2[_icon_algo];
668 const POINTS& start_pos = s_align_start[_icon_algo];
669
670 int dir_x1 = dir1.x;
671 int dir_y1 = dir1.y;
672 int dir_x2 = dir2.x;
673 int dir_y2 = dir2.y;
674
675 int cx = LOWORD(spacing);
676 int cy = HIWORD(spacing);
677
678 int dx1 = dir_x1 * cx;
679 int dy1 = dir_y1 * cy;
680 int dx2 = dir_x2 * cx;
681 int dy2 = dir_y2 * cy;
682
683 int start_x = (start_pos.x * work_area.right)/cx*cx + (cx-32)/2;
684 int start_y = (start_pos.y * work_area.bottom)/cy*cy + 4/*(cy-32)/2*/;
685
686 if (start_x >= work_area.right)
687 start_x -= cx;
688
689 if (start_y >= work_area.bottom)
690 start_y -= cy;
691
692 int x = start_x;
693 int y = start_y;
694
695 int all = ListView_GetItemCount(_hwndListView);
696 int i1, i2;
697
698 if (dir > 0) {
699 i1 = 0;
700 i2 = all;
701 } else {
702 i1 = all-1;
703 i2 = -1;
704 }
705
706 IconMap pos_idx;
707 int cnt = 0;
708
709 for(int idx=i1; idx!=i2; idx+=dir) {
710 pos_idx[IconPos(y, x)] = idx;
711
712 if (_icon_algo == ARRANGE_BORDER_DOWN) {
713 if (++cnt & 1)
714 x = work_area.right - x;
715 else {
716 y += dy1;
717
718 if (y >= work_area.bottom) {
719 y = start_y;
720 x += dx2;
721 }
722 }
723
724 continue;
725 }
726 else if (_icon_algo == ARRANGE_BORDER_HV) {
727 if (++cnt & 1)
728 x = work_area.right - x;
729 else if (cnt & 2) {
730 y += dy1;
731
732 if (y >= work_area.bottom) {
733 y = start_y;
734 x += dx2;
735 }
736 } else {
737 x += dx1;
738
739 if (x >= work_area.right) {
740 x = start_x;
741 y += dy2;
742 }
743 }
744
745 continue;
746 }
747 else if (_icon_algo == ARRANGE_ROUNDABOUT) {
748
749 ///@todo
750
751 }
752
753 x += dx1;
754 y += dy1;
755
756 if (x<0 || x>=work_area.right) {
757 x = start_x;
758 y += dy2;
759 } else if (y<0 || y>=work_area.bottom) {
760 y = start_y;
761 x += dx2;
762 }
763 }
764
765 // use a little trick to get the icons where we want them to be...
766
767 for(IconMap::const_iterator it=pos_idx.end(); --it!=pos_idx.begin(); ) {
768 const IconPos& pos = it->first;
769
770 ListView_SetItemPosition32(_hwndListView, it->second, pos.second, pos.first);
771 }
772
773 for(IconMap::const_iterator it=pos_idx.begin(); it!=pos_idx.end(); ++it) {
774 const IconPos& pos = it->first;
775
776 ListView_SetItemPosition32(_hwndListView, it->second, pos.second, pos.first);
777 }
778 }