kernel32/tests: Don't hardcode C drive for CreateDirectory tests.
[wine] / dlls / shell32 / control.c
index 58516bb..fc012a9 100644 (file)
@@ -34,6 +34,7 @@
 #include "wine/debug.h"
 #include "cpl.h"
 #include "wine/unicode.h"
+#include "commctrl.h"
 
 #define NO_SHLWAPI_REG
 #include "shlwapi.h"
@@ -118,6 +119,22 @@ CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel)
           LoadStringW(applet->hModule, info.idInfo,
                       applet->info[i].szInfo, sizeof(applet->info[i].szInfo) / sizeof(WCHAR));
 
+       /* some broken control panels seem to return incorrect values in CPL_INQUIRE,
+          but proper data in CPL_NEWINQUIRE. if we get an empty string or a null
+          icon, see what we can get from CPL_NEWINQUIRE */
+
+       if ((applet->info[i].szName == 0) || (lstrlenW(applet->info[i].szName) == 0))
+           info.idName = CPL_DYNAMIC_RES;
+
+       /* zero-length szInfo may not be a buggy applet, but it doesn't hurt for us
+          to check anyway */
+
+       if ((applet->info[i].szInfo == 0) || (lstrlenW(applet->info[i].szInfo) == 0))
+           info.idInfo = CPL_DYNAMIC_RES;
+
+       if (applet->info[i].hIcon == NULL)
+           info.idIcon = CPL_DYNAMIC_RES;
+
        if ((info.idIcon == CPL_DYNAMIC_RES) || (info.idName == CPL_DYNAMIC_RES) ||
            (info.idInfo == CPL_DYNAMIC_RES)) {
           applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&newinfo);
@@ -164,18 +181,100 @@ CPlApplet*       Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel)
     return NULL;
 }
 
+#define IDC_LISTVIEW        1000
+#define IDC_STATUSBAR       1001
+
+#define NUM_COLUMNS            2
+#define LISTVIEW_DEFSTYLE   (WS_CHILD | WS_VISIBLE | WS_TABSTOP |\
+                             LVS_SORTASCENDING | LVS_AUTOARRANGE | LVS_SINGLESEL)
+
+static BOOL Control_CreateListView (CPanel *panel)
+{
+    RECT ws, sb;
+    WCHAR empty_string[] = {0};
+    WCHAR buf[MAX_STRING_LEN];
+    LVCOLUMNW lvc;
+
+    /* Create list view */
+    GetClientRect(panel->hWndStatusBar, &sb);
+    GetClientRect(panel->hWnd, &ws);
+
+    panel->hWndListView = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW,
+                          empty_string, LISTVIEW_DEFSTYLE | LVS_ICON,
+                          0, 0, ws.right - ws.left, ws.bottom - ws.top -
+                          (sb.bottom - sb.top), panel->hWnd,
+                          (HMENU) IDC_LISTVIEW, panel->hInst, NULL);
+
+    if (!panel->hWndListView)
+        return FALSE;
+
+    /* Create image lists for list view */
+    panel->hImageListSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
+        GetSystemMetrics(SM_CYSMICON), ILC_MASK, 1, 1);
+    panel->hImageListLarge = ImageList_Create(GetSystemMetrics(SM_CXICON),
+        GetSystemMetrics(SM_CYICON), ILC_MASK, 1, 1);
+
+    (void) ListView_SetImageList(panel->hWndListView, panel->hImageListSmall, LVSIL_SMALL);
+    (void) ListView_SetImageList(panel->hWndListView, panel->hImageListLarge, LVSIL_NORMAL);
+
+    /* Create columns for list view */
+    lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
+    lvc.pszText = buf;
+    lvc.fmt = LVCFMT_LEFT;
+
+    /* Name column */
+    lvc.iSubItem = 0;
+    lvc.cx = (ws.right - ws.left) / 3;
+    LoadStringW(shell32_hInstance, IDS_CPANEL_NAME, buf, sizeof(buf) / sizeof(buf[0]));
+
+    if (ListView_InsertColumnW(panel->hWndListView, 0, &lvc) == -1)
+        return FALSE;
+
+    /* Description column */
+    lvc.iSubItem = 1;
+    lvc.cx = ((ws.right - ws.left) / 3) * 2;
+    LoadStringW(shell32_hInstance, IDS_CPANEL_DESCRIPTION, buf, sizeof(buf) /
+        sizeof(buf[0]));
+
+    if (ListView_InsertColumnW(panel->hWndListView, 1, &lvc) == -1)
+        return FALSE;
+
+    return(TRUE);
+}
+
 static void     Control_WndProc_Create(HWND hWnd, const CREATESTRUCTW* cs)
 {
    CPanel*     panel = (CPanel*)cs->lpCreateParams;
    HMENU hMenu, hSubMenu;
    CPlApplet*  applet;
    MENUITEMINFOW mii;
-   int menucount, i;
+   unsigned int i;
+   int menucount, index;
    CPlItem *item;
+   LVITEMW lvItem;
+   INITCOMMONCONTROLSEX icex;
+   INT sb_parts;
+   int itemidx;
 
    SetWindowLongPtrW(hWnd, 0, (LONG_PTR)panel);
    panel->hWnd = hWnd;
 
+   /* Initialise common control DLL */
+   icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+   icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_BAR_CLASSES;
+   InitCommonControlsEx(&icex);
+
+   /* create the status bar */
+   if (!(panel->hWndStatusBar = CreateStatusWindowW(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, NULL, hWnd, IDC_STATUSBAR)))
+       return;
+
+   sb_parts = -1;
+   SendMessageW(panel->hWndStatusBar, SB_SETPARTS, 1, (LPARAM) &sb_parts);
+
+   /* create the list view */
+   if (!Control_CreateListView(panel))
+       return;
+
    hMenu = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_CPANEL));
 
    /* insert menu items for applets */
@@ -201,11 +300,29 @@ static void        Control_WndProc_Create(HWND hWnd, const CREATESTRUCTW* cs)
          mii.dwTypeData = applet->info[i].szName;
          mii.cch = sizeof(applet->info[i].szName) / sizeof(applet->info[i].szName[0]);
          mii.wID = IDM_CPANEL_APPLET_BASE + menucount;
-         mii.dwItemData = (DWORD) item;
+         mii.dwItemData = (ULONG_PTR)item;
 
          if (InsertMenuItemW(hSubMenu, menucount, TRUE, &mii)) {
-             DrawMenuBar(hWnd);
-             menucount++;
+            /* add the list view item */
+            index = ImageList_AddIcon(panel->hImageListLarge, applet->info[i].hIcon);
+            ImageList_AddIcon(panel->hImageListSmall, applet->info[i].hIcon);
+
+            lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
+            lvItem.iItem = menucount;
+            lvItem.iSubItem = 0;
+            lvItem.pszText = applet->info[i].szName;
+            lvItem.iImage = index;
+            lvItem.lParam = (LPARAM) item;
+
+            itemidx = ListView_InsertItemW(panel->hWndListView, &lvItem);
+
+            /* add the description */
+            ListView_SetItemTextW(panel->hWndListView, itemidx, 1,
+                applet->info[i].szInfo);
+
+            /* update menu bar, increment count */
+            DrawMenuBar(hWnd);
+            menucount++;
          }
       }
    }
@@ -224,7 +341,7 @@ static void Control_FreeCPlItems(HWND hWnd, CPanel *panel)
 {
     HMENU hMenu, hSubMenu;
     MENUITEMINFOW mii;
-    int i;
+    unsigned int i;
 
     /* get the File menu */
     hMenu = GetMenu(hWnd);
@@ -250,6 +367,65 @@ static void Control_FreeCPlItems(HWND hWnd, CPanel *panel)
     }
 }
 
+static void Control_UpdateListViewStyle(CPanel *panel, UINT style, UINT id)
+{
+    HMENU hMenu, hSubMenu;
+
+    SetWindowLongW(panel->hWndListView, GWL_STYLE, LISTVIEW_DEFSTYLE | style);
+
+    /* update the menu */
+    hMenu = GetMenu(panel->hWnd);
+    hSubMenu = GetSubMenu(hMenu, 1);
+
+    CheckMenuRadioItem(hSubMenu, FCIDM_SHVIEW_BIGICON, FCIDM_SHVIEW_REPORTVIEW,
+        id, MF_BYCOMMAND);
+}
+
+static CPlItem* Control_GetCPlItem_From_MenuID(HWND hWnd, UINT id)
+{
+    HMENU hMenu, hSubMenu;
+    MENUITEMINFOW mii;
+
+    /* retrieve the CPlItem structure from the menu item data */
+    hMenu = GetMenu(hWnd);
+
+    if (!hMenu)
+        return NULL;
+
+    hSubMenu = GetSubMenu(hMenu, 0);
+
+    if (!hSubMenu)
+        return NULL;
+
+    mii.cbSize = sizeof(MENUITEMINFOW);
+    mii.fMask = MIIM_DATA;
+
+    if (!GetMenuItemInfoW(hSubMenu, id, FALSE, &mii))
+        return NULL;
+
+    return (CPlItem *) mii.dwItemData;
+}
+
+static CPlItem* Control_GetCPlItem_From_ListView(CPanel *panel)
+{
+    LVITEMW lvItem;
+    int selitem;
+
+    selitem = SendMessageW(panel->hWndListView, LVM_GETNEXTITEM, -1, LVNI_FOCUSED
+        | LVNI_SELECTED);
+
+    if (selitem != -1)
+    {
+        lvItem.iItem = selitem;
+        lvItem.mask = LVIF_PARAM;
+
+        if (SendMessageW(panel->hWndListView, LVM_GETITEMW, 0, (LPARAM) &lvItem))
+            return (CPlItem *) lvItem.lParam;
+    }
+
+    return NULL;
+}
+
 static LRESULT WINAPI  Control_WndProc(HWND hWnd, UINT wMsg,
                                        WPARAM lParam1, LPARAM lParam2)
 {
@@ -288,9 +464,19 @@ static LRESULT WINAPI      Control_WndProc(HWND hWnd, UINT wMsg,
                  }
 
              case FCIDM_SHVIEW_BIGICON:
+                 Control_UpdateListViewStyle(panel, LVS_ICON, FCIDM_SHVIEW_BIGICON);
+                 return 0;
+
              case FCIDM_SHVIEW_SMALLICON:
+                 Control_UpdateListViewStyle(panel, LVS_SMALLICON, FCIDM_SHVIEW_SMALLICON);
+                 return 0;
+
              case FCIDM_SHVIEW_LISTVIEW:
+                 Control_UpdateListViewStyle(panel, LVS_LIST, FCIDM_SHVIEW_LISTVIEW);
+                 return 0;
+
              case FCIDM_SHVIEW_REPORTVIEW:
+                 Control_UpdateListViewStyle(panel, LVS_REPORT, FCIDM_SHVIEW_REPORTVIEW);
                  return 0;
 
              default:
@@ -298,28 +484,7 @@ static LRESULT WINAPI      Control_WndProc(HWND hWnd, UINT wMsg,
                  if ((LOWORD(lParam1) >= IDM_CPANEL_APPLET_BASE) &&
                      (LOWORD(lParam1) <= IDM_CPANEL_APPLET_BASE + panel->total_subprogs))
                  {
-                     CPlItem *item;
-                     HMENU hMenu, hSubMenu;
-                     MENUITEMINFOW mii;
-
-                     /* retrieve the CPlItem structure from the menu item data */
-                     hMenu = GetMenu(hWnd);
-
-                     if (!hMenu)
-                         break;
-
-                     hSubMenu = GetSubMenu(hMenu, 0);
-
-                     if (!hSubMenu)
-                         break;
-
-                     mii.cbSize = sizeof(MENUITEMINFOW);
-                     mii.fMask = MIIM_DATA;
-
-                     if (!GetMenuItemInfoW(hSubMenu, LOWORD(lParam1), FALSE, &mii))
-                         break;
-
-                     item = (CPlItem *) mii.dwItemData;
+                     CPlItem *item = Control_GetCPlItem_From_MenuID(hWnd, LOWORD(lParam1));
 
                      /* execute the applet if item is valid */
                      if (item)
@@ -333,7 +498,105 @@ static LRESULT WINAPI     Control_WndProc(HWND hWnd, UINT wMsg,
          }
 
          break;
+
+      case WM_NOTIFY:
+      {
+          LPNMHDR nmh = (LPNMHDR) lParam2;
+
+          switch (nmh->idFrom)
+          {
+              case IDC_LISTVIEW:
+                  switch (nmh->code)
+                  {
+                      case NM_RETURN:
+                      case NM_DBLCLK:
+                      {
+                          CPlItem *item = Control_GetCPlItem_From_ListView(panel);
+
+                          /* execute the applet if item is valid */
+                          if (item)
+                              item->applet->proc(item->applet->hWnd, CPL_DBLCLK,
+                                  item->id, item->applet->info[item->id].lData);
+
+                          return 0;
+                      }
+                      case LVN_ITEMCHANGED:
+                      {
+                          CPlItem *item = Control_GetCPlItem_From_ListView(panel);
+
+                          /* update the status bar if item is valid */
+                          if (item)
+                              SetWindowTextW(panel->hWndStatusBar,
+                                  item->applet->info[item->id].szInfo);
+                          else
+                              SetWindowTextW(panel->hWndStatusBar, NULL);
+
+                          return 0;
+                      }
+                  }
+
+                  break;
+          }
+
+          break;
+      }
+
+      case WM_MENUSELECT:
+          /* check if this is an applet */
+          if ((LOWORD(lParam1) >= IDM_CPANEL_APPLET_BASE) &&
+              (LOWORD(lParam1) <= IDM_CPANEL_APPLET_BASE + panel->total_subprogs))
+          {
+              CPlItem *item = Control_GetCPlItem_From_MenuID(hWnd, LOWORD(lParam1));
+
+              /* update the status bar if item is valid */
+              if (item)
+                  SetWindowTextW(panel->hWndStatusBar, item->applet->info[item->id].szInfo);
+          }
+          else if ((HIWORD(lParam1) == 0xFFFF) && (lParam2 == 0))
+          {
+              /* reset status bar description to that of the selected icon */
+              CPlItem *item = Control_GetCPlItem_From_ListView(panel);
+
+              if (item)
+                  SetWindowTextW(panel->hWndStatusBar, item->applet->info[item->id].szInfo);
+              else
+                  SetWindowTextW(panel->hWndStatusBar, NULL);
+
+              return 0;
+          }
+          else
+              SetWindowTextW(panel->hWndStatusBar, NULL);
+
+          return 0;
+
+      case WM_SIZE:
+      {
+          HDWP hdwp;
+          RECT sb;
+
+          hdwp = BeginDeferWindowPos(2);
+
+          if (hdwp == NULL)
+              break;
+
+          GetClientRect(panel->hWndStatusBar, &sb);
+
+          hdwp = DeferWindowPos(hdwp, panel->hWndListView, NULL, 0, 0,
+              LOWORD(lParam2), HIWORD(lParam2) - (sb.bottom - sb.top),
+              SWP_NOZORDER | SWP_NOMOVE);
+
+          if (hdwp == NULL)
+              break;
+
+          hdwp = DeferWindowPos(hdwp, panel->hWndStatusBar, NULL, 0, 0,
+              LOWORD(lParam2), LOWORD(lParam1), SWP_NOZORDER | SWP_NOMOVE);
+
+          if (hdwp != NULL)
+              EndDeferWindowPos(hdwp);
+
+          return 0;
       }
+     }
    }
 
    return DefWindowProcW(hWnd, wMsg, lParam1, lParam2);
@@ -353,7 +616,7 @@ static void    Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst)
     wc.lpfnWndProc = Control_WndProc;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = sizeof(CPlApplet*);
-    wc.hInstance = hInst;
+    wc.hInstance = panel->hInst = hInst;
     wc.hIcon = 0;
     wc.hCursor = LoadCursorW( 0, (LPWSTR)IDC_ARROW );
     wc.hbrBackground = GetStockObject(WHITE_BRUSH);