merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / subsys / system / explorer / desktop / desktop.cpp
index f72af94..21ecd83 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/dragdropimpl.h"
-#include "../utility/window.h"
+#include "precomp.h"
 
-#include "../globals.h"
-#include "../externals.h"
 #include "../explorer_intres.h"
 
-#include "desktop.h"
 #include "../taskbar/desktopbar.h"
-#include "../shell/mainframe.h"        // for MainFrame::OpenShellFolders()
+#include "../taskbar/taskbar.h"        // for PM_GET_LAST_ACTIVE
 
 
 static BOOL (WINAPI*SetShellWindow)(HWND);
@@ -158,18 +151,13 @@ int DesktopThread::Run()
 
 #else // _USE_HDESK
 
-static BOOL CALLBACK DesktopEnumFct(HWND hwnd, LPARAM lparam)
+static BOOL CALLBACK SwitchDesktopEnumFct(HWND hwnd, LPARAM lparam)
 {
        WindowSet& windows = *(WindowSet*)lparam;
 
-       if (IsWindowVisible(hwnd)) {
-               DWORD pid;
-
-               GetWindowThreadProcessId(hwnd, &pid);
-
-               if (pid != GetCurrentProcessId())
+       if (hwnd!=g_Globals._hwndDesktopBar && hwnd!=g_Globals._hwndDesktop)
+               if (IsWindowVisible(hwnd))
                        windows.insert(hwnd);
-       }
 
        return TRUE;
 }
@@ -179,16 +167,24 @@ void Desktops::SwitchToDesktop(int idx)
        if (_current_desktop == idx)
                return;
 
-       Desktop& desktop = (*this)[idx];
-
-        // save currently visible application windows
        Desktop& old_desktop = (*this)[_current_desktop];
        WindowSet& windows = old_desktop._windows;
+       Desktop& desktop = (*this)[idx];
 
        windows.clear();
-       EnumWindows(DesktopEnumFct, (LPARAM)&windows);
 
-        // hide all windows we found
+        // 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);
 
@@ -196,6 +192,14 @@ void Desktops::SwitchToDesktop(int idx)
        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;
@@ -204,59 +208,87 @@ void Desktops::SwitchToDesktop(int idx)
 #endif // _USE_HDESK
 
 
-BOOL IsAnyDesktopRunning()
+static BOOL CALLBACK MinimizeDesktopEnumFct(HWND hwnd, LPARAM lparam)
 {
-       HINSTANCE hUser32 = GetModuleHandle(TEXT("user32"));
+       list<MinimizeStruct>& minimized = *(list<MinimizeStruct>*)lparam;
 
-       SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(hUser32, "SetShellWindow");
-       SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(hUser32, "SetShellWindowEx");
+       if (hwnd!=g_Globals._hwndDesktopBar && hwnd!=g_Globals._hwndDesktop)
+               if (IsWindowVisible(hwnd) && !IsIconic(hwnd)) {
+                       RECT rect;
 
-       return GetShellWindow() != 0;
-}
+                       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;
+}
 
-static void draw_desktop_background(HWND hwnd, HDC hdc)
+ /// minimize/restore all windows on the desktop
+void Desktops::ToggleMinimize()
 {
-       ClientRect rect(hwnd);
+       list<MinimizeStruct>& minimized = (*this)[_current_desktop]._minimized;
 
-       PaintDesktop(hdc);
-/*
-       HBRUSH bkgndBrush = CreateSolidBrush(RGB(0,32,160));    // dark blue
-       FillRect(hdc, &rect, bkgndBrush);
-       DeleteBrush(bkgndBrush);
-*/
+       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);
 
-       rect.left = rect.right - 280;
-       rect.top = rect.bottom - 56 - DESKTOPBARBAR_HEIGHT;
-       rect.right = rect.left + 250;
-       rect.bottom = rect.top + 40;
+               minimized.clear();
+       }
+}
 
-#include "../buildno.h"
-       static const LPCTSTR BkgndText = TEXT("ReactOS ")TEXT(KERNEL_VERSION_STR)TEXT(" Explorer\nby Martin Fuchs");
 
-       BkMode bkMode(hdc, TRANSPARENT);
+BOOL IsAnyDesktopRunning()
+{
+       HINSTANCE hUser32 = GetModuleHandle(TEXT("user32"));
 
-       TextColor textColor(hdc, RGB(128,128,192));
-       DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
+       SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(hUser32, "SetShellWindow");
+       SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(hUser32, "SetShellWindowEx");
 
-       SetTextColor(hdc, RGB(255,255,255));
-       --rect.right;
-       ++rect.top;
-       DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
+       return GetShellWindow() != 0;
 }
 
 
-LRESULT        BackgroundWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
+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(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);
        }
@@ -264,6 +296,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)
@@ -281,13 +324,14 @@ DesktopWindow::~DesktopWindow()
 HWND DesktopWindow::Create()
 {
        static IconWindowClass wcDesktop(TEXT("Progman"), IDI_REACTOS, CS_DBLCLKS);
-       wcDesktop.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
+       /* (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,
+                                       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
@@ -385,10 +429,6 @@ 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:
@@ -401,7 +441,7 @@ LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
          case WM_DESTROY:
 
                ///@todo use IShellBrowser::GetViewStateStream() and _pShellView->SaveViewState() to store view state
-               
+
                if (SetShellWindow)
                        SetShellWindow(0);
                break;
@@ -427,8 +467,10 @@ LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 
 HRESULT DesktopWindow::OnDefaultCommand(LPIDA pida)
 {
-       if (MainFrame::OpenShellFolders(pida, 0))
+#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;
 }
@@ -487,7 +529,7 @@ bool DesktopShellView::InitDragDrop()
        return true;
 }
 
-LRESULT        DesktopShellView::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
+LRESULT DesktopShellView::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
        switch(nmsg) {
          case WM_CONTEXTMENU:
@@ -503,6 +545,9 @@ LRESULT     DesktopShellView::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
          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);
        }
@@ -550,7 +595,7 @@ bool DesktopShellView::DoContextMenu(int x, int y)
        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);
+       hr = ShellFolderContextMenu(ShellFolder(parent_pidl), _hwnd, pida->cidl, apidl, x, y, _cm_ifs);
 
        selection->Release();
 
@@ -566,6 +611,8 @@ HRESULT DesktopShellView::DoDesktopContextMenu(int x, int y)
        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) {
@@ -577,6 +624,8 @@ HRESULT DesktopShellView::DoDesktopContextMenu(int x, int y)
 
                                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) {