[CRT] Remove useless #undef abort from process.h
[reactos.git] / dll / cpl / input / settings_page.c
index 0404b63..7f5057c 100644 (file)
@@ -2,7 +2,8 @@
  * PROJECT:         input.dll
  * FILE:            dll/cpl/input/settings_page.c
  * PURPOSE:         input.dll
  * PROJECT:         input.dll
  * FILE:            dll/cpl/input/settings_page.c
  * PURPOSE:         input.dll
- * PROGRAMMER:      Dmitry Chapyshev (dmitry@reactos.org)
+ * PROGRAMMERS:     Dmitry Chapyshev (dmitry@reactos.org)
+ *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
  */
 
 #include "input.h"
  */
 
 #include "input.h"
 #include "locale_list.h"
 #include "input_list.h"
 
 #include "locale_list.h"
 #include "input_list.h"
 
+static INT s_nAliveLeafCount = 0;
+static INT s_nRootCount = 0;
+static INT s_iKeyboardImage = -1;
+static INT s_iDotImage = -1;
 
 static HICON
 
 static HICON
-CreateLayoutIcon(LPWSTR szLayout, BOOL bIsDefault)
+CreateLayoutIcon(LANGID LangID)
 {
 {
-    INT width = GetSystemMetrics(SM_CXSMICON) * 2;
-    INT height = GetSystemMetrics(SM_CYSMICON);
-    HDC hdc;
-    HDC hdcsrc;
-    HBITMAP hBitmap;
-    HICON hIcon = NULL;
-
-    hdcsrc = GetDC(NULL);
-    hdc = CreateCompatibleDC(hdcsrc);
-    hBitmap = CreateCompatibleBitmap(hdcsrc, width, height);
+    WCHAR szBuf[4];
+    HDC hdcScreen, hdc;
+    HBITMAP hbmColor, hbmMono, hBmpOld;
+    HFONT hFont, hFontOld;
+    LOGFONTW lf;
+    RECT rect;
+    ICONINFO IconInfo;
+    HICON hIcon;
+    INT cxIcon = GetSystemMetrics(SM_CXSMICON);
+    INT cyIcon = GetSystemMetrics(SM_CYSMICON);
+
+    /* Getting "EN", "FR", etc. from English, French, ... */
+    if (GetLocaleInfoW(LangID,
+                       LOCALE_SABBREVLANGNAME | LOCALE_NOUSEROVERRIDE,
+                       szBuf,
+                       ARRAYSIZE(szBuf)) == 0)
+    {
+        szBuf[0] = szBuf[1] = L'?';
+    }
+    szBuf[2] = UNICODE_NULL; /* Truncate the identifier to two characters: "ENG" --> "EN" etc. */
 
 
-    ReleaseDC(NULL, hdcsrc);
+    /* Create hdc, hbmColor and hbmMono */
+    hdcScreen = GetDC(NULL);
+    hdc = CreateCompatibleDC(hdcScreen);
+    hbmColor = CreateCompatibleBitmap(hdcScreen, cxIcon, cyIcon);
+    ReleaseDC(NULL, hdcScreen);
+    hbmMono = CreateBitmap(cxIcon, cyIcon, 1, 1, NULL);
 
 
-    if (hdc && hBitmap)
+    /* Checking NULL */
+    if (!hdc || !hbmColor || !hbmMono)
     {
     {
-        HBITMAP hBmpNew;
-
-        hBmpNew = CreateBitmap(width, height, 1, 1, NULL);
-        if (hBmpNew)
-        {
-            LOGFONTW lf;
+        if (hbmMono)
+            DeleteObject(hbmMono);
+        if (hbmColor)
+            DeleteObject(hbmColor);
+        if (hdc)
+            DeleteDC(hdc);
+        return NULL;
+    }
 
 
-            if (SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0))
-            {
-                ICONINFO IconInfo;
-                HFONT hFont;
+    /* Create a font */
+    hFont = NULL;
+    if (SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0))
+    {
+        /* Override the current size with something manageable */
+        lf.lfHeight = -11;
+        lf.lfWidth = 0;
+        hFont = CreateFontIndirectW(&lf);
+    }
+    if (!hFont)
+        hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+
+    SetRect(&rect, 0, 0, cxIcon, cyIcon);
+
+    /* Draw hbmColor */
+    hBmpOld = SelectObject(hdc, hbmColor);
+    SetDCBrushColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
+    FillRect(hdc, &rect, (HBRUSH)GetStockObject(DC_BRUSH));
+    hFontOld = SelectObject(hdc, hFont);
+    SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+    SetBkMode(hdc, TRANSPARENT);
+    DrawTextW(hdc, szBuf, 2, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
+    SelectObject(hdc, hFontOld);
+
+    /* Fill hbmMono with black */
+    SelectObject(hdc, hbmMono);
+    PatBlt(hdc, 0, 0, cxIcon, cyIcon, BLACKNESS);
+    SelectObject(hdc, hBmpOld);
+
+    /* Create an icon from hbmColor and hbmMono */
+    IconInfo.fIcon = TRUE;
+    IconInfo.xHotspot = IconInfo.yHotspot = 0;
+    IconInfo.hbmColor = hbmColor;
+    IconInfo.hbmMask = hbmMono;
+    hIcon = CreateIconIndirect(&IconInfo);
+
+    /* Clean up */
+    DeleteObject(hFont);
+    DeleteObject(hbmMono);
+    DeleteObject(hbmColor);
+    DeleteDC(hdc);
 
 
-                hFont = CreateFontIndirectW(&lf);
+    return hIcon;
+}
 
 
-                if (hFont != NULL)
-                {
-                    HBITMAP hBmpOld;
+static VOID InitDefaultLangComboBox(HWND hwndCombo)
+{
+    WCHAR szText[256];
+    INPUT_LIST_NODE *pNode;
+    INT iIndex, nCount, iDefault = (INT)SendMessageW(hwndCombo, CB_GETCURSEL, 0, 0);
 
 
-                    hBmpOld = SelectObject(hdc, hBitmap);
+    SendMessageW(hwndCombo, CB_RESETCONTENT, 0, 0);
 
 
-                    if (hBmpOld != NULL)
-                    {
-                        RECT rect;
+    for (pNode = InputList_GetFirst(); pNode != NULL; pNode = pNode->pNext)
+    {
+        if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+            continue;
 
 
-                        SetRect(&rect, 0, 0, width / 2, height);
+        StringCchPrintfW(szText, _countof(szText), L"%s - %s",
+                         pNode->pLocale->pszName, pNode->pLayout->pszName);
+        iIndex = (INT)SendMessageW(hwndCombo, CB_ADDSTRING, 0, (LPARAM)szText);
+        SendMessageW(hwndCombo, CB_SETITEMDATA, iIndex, (LPARAM)pNode);
 
 
-                        if (bIsDefault != FALSE)
-                        {
-                            SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
-                            SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
+        if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
+            iDefault = iIndex;
+    }
 
 
-                            ExtTextOutW(hdc, rect.left, rect.top, ETO_OPAQUE, &rect, L"", 0, NULL);
+    nCount = (INT)SendMessageW(hwndCombo, CB_GETCOUNT, 0, 0);
+    if (iDefault >= nCount)
+        SendMessageW(hwndCombo, CB_SETCURSEL, nCount - 1, 0);
+    else
+        SendMessageW(hwndCombo, CB_SETCURSEL, iDefault, 0);
+}
 
 
-                            SelectObject(hdc, hFont);
-                            DrawTextW(hdc, L"\x2022", 1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
-                        }
-                        else
-                        {
-                            FillRect(hdc, &rect, GetSysColorBrush(COLOR_WINDOW));
-                        }
+static VOID
+SetControlsState(HWND hwndDlg)
+{
+    HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+    HWND hwndCombo = GetDlgItem(hwndDlg, IDC_DEFAULT_LANGUAGE);
+    BOOL bIsLeaf, bCanRemove, bCanProp;
+    HTREEITEM hSelected = TreeView_GetSelection(hwndList);
+    TV_ITEM item = { TVIF_PARAM | TVIF_HANDLE };
+    item.hItem = hSelected;
 
 
-                        SetRect(&rect, width / 2, 0, width, height);
+    bIsLeaf = (hSelected && TreeView_GetItem(hwndList, &item) && HIWORD(item.lParam));
 
 
-                        SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
-                        SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+    bCanRemove = (bIsLeaf && (s_nAliveLeafCount > 1)) || (s_nRootCount > 1);
+    bCanProp = bIsLeaf;
 
 
-                        ExtTextOutW(hdc, rect.left, rect.top, ETO_OPAQUE, &rect, L"", 0, NULL);
+    EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE_BUTTON), bCanRemove);
+    EnableWindow(GetDlgItem(hwndDlg, IDC_PROP_BUTTON), bCanProp);
 
 
-                        SelectObject(hdc, hFont);
-                        DrawTextW(hdc, szLayout, 2, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
+    InitDefaultLangComboBox(hwndCombo);
+}
 
 
-                        SelectObject(hdc, hBmpNew);
+static BOOL CALLBACK
+EnumResNameProc(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam)
+{
+    HICON* phIconSm = (HICON*)lParam;
+    if (*phIconSm)
+        return FALSE;
+
+    *phIconSm = (HICON)LoadImageW(hModule, lpszName, IMAGE_ICON,
+                                  GetSystemMetrics(SM_CXSMICON),
+                                  GetSystemMetrics(SM_CYSMICON),
+                                  0);
+    return TRUE;
+}
 
 
-                        PatBlt(hdc, 0, 0, width, height, BLACKNESS);
+static HICON LoadIMEIcon(LPCTSTR pszImeFile)
+{
+    WCHAR szSysDir[MAX_PATH], szPath[MAX_PATH];
+    HINSTANCE hImeInst;
+    HICON hIconSm = NULL;
 
 
-                        SelectObject(hdc, hBmpOld);
+    GetSystemDirectoryW(szSysDir, _countof(szSysDir));
+    StringCchPrintfW(szPath, _countof(szPath), L"%s\\%s", szSysDir, pszImeFile);
 
 
-                        IconInfo.hbmColor = hBitmap;
-                        IconInfo.hbmMask = hBmpNew;
-                        IconInfo.fIcon = TRUE;
+    hImeInst = LoadLibraryExW(szPath, NULL, DONT_RESOLVE_DLL_REFERENCES);
+    if (hImeInst == NULL)
+        return NULL;
 
 
-                        hIcon = CreateIconIndirect(&IconInfo);
+    EnumResourceNamesW(hImeInst, RT_GROUP_ICON, EnumResNameProc, (LPARAM)&hIconSm);
+    FreeLibrary(hImeInst);
 
 
-                        DeleteObject(hBmpOld);
-                    }
+    return hIconSm;
+}
 
 
-                    DeleteObject(hFont);
-                }
-            }
+static HTREEITEM FindLanguageInList(HWND hwndList, LPCTSTR pszLangName)
+{
+    TV_ITEM item;
+    TCHAR szText[128];
+    HTREEITEM hItem;
 
 
-            DeleteObject(hBmpNew);
-        }
+    hItem = TreeView_GetRoot(hwndList);
+    while (hItem)
+    {
+        szText[0] = 0;
+        item.mask       = TVIF_TEXT | TVIF_HANDLE;
+        item.pszText    = szText;
+        item.cchTextMax = _countof(szText);
+        item.hItem      = hItem;
+        TreeView_GetItem(hwndList, &item);
+        if (_wcsicmp(szText, pszLangName) == 0)
+            return hItem;
+
+        hItem = TreeView_GetNextSibling(hwndList, hItem);
     }
 
     }
 
-    DeleteDC(hdc);
-    DeleteObject(hBitmap);
-
-    return hIcon;
-}
-
-
-static VOID
-SetControlsState(HWND hwndDlg, BOOL bIsEnabled)
-{
-    EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE_BUTTON), bIsEnabled);
-    EnableWindow(GetDlgItem(hwndDlg, IDC_PROP_BUTTON), bIsEnabled);
-    EnableWindow(GetDlgItem(hwndDlg, IDC_SET_DEFAULT), bIsEnabled);
+    return NULL;
 }
 
 }
 
-
 static VOID
 AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
 {
 static VOID
 AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
 {
-    INT ItemIndex = -1;
-    INT ImageIndex = -1;
-    LV_ITEM item;
-    HIMAGELIST hImageList;
-
-    hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
-
-    if (hImageList != NULL)
+    TV_ITEM item;
+    TV_INSERTSTRUCT insert;
+    HIMAGELIST hImageList = TreeView_GetImageList(hwndList, TVSIL_NORMAL);
+    WCHAR szKeyboard[64];
+    HTREEITEM hItem;
+    BOOL bBold = !!(pInputNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT);
+
+    hItem = FindLanguageInList(hwndList, pInputNode->pLocale->pszName);
+    if (hItem == NULL)
     {
     {
-        HICON hLayoutIcon;
-
-        hLayoutIcon = CreateLayoutIcon(pInputNode->pszIndicator,
-                                       (pInputNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT));
+        // Language icon
+        INT LangImageIndex = -1;
+        HICON hLangIcon = CreateLayoutIcon(LOWORD(pInputNode->pLocale->dwId));
+        if (hLangIcon)
+        {
+            LangImageIndex = ImageList_AddIcon(hImageList, hLangIcon);
+            DestroyIcon(hLangIcon);
+        }
 
 
-        if (hLayoutIcon != NULL)
+        // Language
+        ZeroMemory(&item, sizeof(item));
+        item.mask           = TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE;
+        item.pszText        = pInputNode->pLocale->pszName;
+        item.iImage         = LangImageIndex;
+        item.iSelectedImage = LangImageIndex;
+        item.lParam         = LOWORD(pInputNode->pLocale->dwId); // HIWORD(item.lParam) == 0
+        if (bBold)
         {
         {
-            ImageIndex = ImageList_AddIcon(hImageList, hLayoutIcon);
-            DestroyIcon(hLayoutIcon);
+            item.state = item.stateMask = TVIS_BOLD;
         }
         }
+        insert.hParent      = TVI_ROOT;
+        insert.hInsertAfter = TVI_LAST;
+        insert.item         = item;
+        hItem = TreeView_InsertItem(hwndList, &insert);
+
+        // The type of input method (currently keyboard only)
+        LoadStringW(hApplet, IDS_KEYBOARD, szKeyboard, _countof(szKeyboard));
+        ZeroMemory(&item, sizeof(item));
+        item.mask           = TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE;
+        item.pszText        = szKeyboard;
+        item.iImage         = s_iKeyboardImage;
+        item.iSelectedImage = s_iKeyboardImage;
+        item.lParam         = 0;  // HIWORD(item.lParam) == 0
+        insert.hParent      = hItem;
+        insert.hInsertAfter = TVI_LAST;
+        insert.item         = item;
+        hItem = TreeView_InsertItem(hwndList, &insert);
     }
     }
+    else
+    {
+        // Language
+        ZeroMemory(&item, sizeof(item));
+        item.mask           = TVIF_STATE | TVIF_HANDLE;
+        item.hItem          = hItem;
+        item.stateMask      = TVIS_BOLD;
+        if (TreeView_GetItem(hwndList, &item) && bBold && !(item.state & TVIS_BOLD))
+        {
+            // Make the item bold
+            item.mask = TVIF_STATE | TVIF_HANDLE;
+            item.hItem = hItem;
+            item.state = item.stateMask = TVIS_BOLD;
+            TreeView_SetItem(hwndList, &item);
+        }
 
 
-    ZeroMemory(&item, sizeof(item));
-
-    item.mask    = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
-    item.pszText = pInputNode->pLocale->pszName;
-    item.iItem   = ListView_GetItemCount(hwndList) + 1;
-    item.lParam  = (LPARAM)pInputNode;
-    item.iImage  = ImageIndex;
+        // The type of input method (currently keyboard only)
+        hItem = TreeView_GetChild(hwndList, hItem);
+    }
 
 
-    ItemIndex = ListView_InsertItem(hwndList, &item);
+    // Input method
+    if (hItem)
+    {
+        INT ImeImageIndex = s_iDotImage;
+        if (IS_IME_HKL(pInputNode->hkl) && pInputNode->pLayout->pszImeFile) // IME?
+        {
+            HICON hImeIcon = LoadIMEIcon(pInputNode->pLayout->pszImeFile);
+            if (hImeIcon)
+            {
+                ImeImageIndex = ImageList_AddIcon(hImageList, hImeIcon);
+                DestroyIcon(hImeIcon);
+            }
+        }
 
 
-    ListView_SetItemText(hwndList, ItemIndex, 1, pInputNode->pLayout->pszName);
+        ZeroMemory(&item, sizeof(item));
+        item.mask           = TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE;
+        item.pszText        = pInputNode->pLayout->pszName;
+        item.iImage         = ImeImageIndex;
+        item.iSelectedImage = ImeImageIndex;
+        item.lParam         = (LPARAM)pInputNode; // HIWORD(item.lParam) != 0
+        if (bBold)
+        {
+            item.state = item.stateMask = TVIS_BOLD; // Make the item bold
+        }
+        insert.hParent      = hItem;
+        insert.hInsertAfter = TVI_LAST;
+        insert.item         = item;
+        hItem = TreeView_InsertItem(hwndList, &insert);
+    }
 }
 
 }
 
+static VOID ExpandTreeItem(HWND hwndTree, HTREEITEM hItem)
+{
+    TreeView_Expand(hwndTree, hItem, TVE_EXPAND);
+    hItem = TreeView_GetChild(hwndTree, hItem);
+    while (hItem)
+    {
+        ExpandTreeItem(hwndTree, hItem);
+        hItem = TreeView_GetNextSibling(hwndTree, hItem);
+    }
+}
 
 static VOID
 UpdateInputListView(HWND hwndList)
 {
 
 static VOID
 UpdateInputListView(HWND hwndList)
 {
-    INPUT_LIST_NODE *pCurrentInputNode;
-    HIMAGELIST hImageList;
+    INPUT_LIST_NODE *pNode;
+    HIMAGELIST hImageList = TreeView_GetImageList(hwndList, TVSIL_NORMAL);
+    HTREEITEM hItem;
+    HICON hKeyboardIcon, hDotIcon;
+
+    ImageList_RemoveAll(hImageList);
+    TreeView_DeleteAllItems(hwndList);
+
+    // Add keyboard icon
+    s_iKeyboardImage = -1;
+    hKeyboardIcon = (HICON)LoadImageW(hApplet, MAKEINTRESOURCEW(IDI_KEYBOARD), IMAGE_ICON,
+                                      GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+                                      0);
+    if (hKeyboardIcon)
+    {
+        s_iKeyboardImage = ImageList_AddIcon(hImageList, hKeyboardIcon);
+        DestroyIcon(hKeyboardIcon);
+    }
 
 
-    hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
-    if (hImageList != NULL)
+    // Add dot icon
+    s_iDotImage = -1;
+    hDotIcon = (HICON)LoadImageW(hApplet, MAKEINTRESOURCEW(IDI_DOT), IMAGE_ICON,
+                                 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+                                 0);
+    if (hDotIcon)
     {
     {
-        ImageList_RemoveAll(hImageList);
+        s_iDotImage = ImageList_AddIcon(hImageList, hDotIcon);
+        DestroyIcon(hDotIcon);
     }
 
     }
 
-    ListView_DeleteAllItems(hwndList);
+    InputList_Sort();
 
 
-    for (pCurrentInputNode = InputList_GetFirst();
-         pCurrentInputNode != NULL;
-         pCurrentInputNode = pCurrentInputNode->pNext)
+    s_nAliveLeafCount = InputList_GetAliveCount();
+
+    // Add items to the list
+    for (pNode = InputList_GetFirst(); pNode; pNode = pNode->pNext)
     {
     {
-        if (!(pCurrentInputNode->wFlags & INPUT_LIST_NODE_FLAG_DELETED))
-        {
-            AddToInputListView(hwndList, pCurrentInputNode);
-        }
+        if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+            continue;
+
+        AddToInputListView(hwndList, pNode);
+    }
+
+    // Expand all (with counting s_nRootCount)
+    s_nRootCount = 0;
+    hItem = TreeView_GetRoot(hwndList);
+    while (hItem)
+    {
+        ++s_nRootCount;
+        ExpandTreeItem(hwndList, hItem);
+        hItem = TreeView_GetNextSibling(hwndList, hItem);
     }
     }
-}
 
 
+    // Redraw
+    InvalidateRect(hwndList, NULL, TRUE);
+}
 
 static VOID
 OnInitSettingsPage(HWND hwndDlg)
 {
 
 static VOID
 OnInitSettingsPage(HWND hwndDlg)
 {
-    HWND hwndInputList;
+    HWND hwndInputList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+    HIMAGELIST hLayoutImageList, hOldImageList;
 
     LayoutList_Create();
     LocaleList_Create();
     InputList_Create();
 
 
     LayoutList_Create();
     LocaleList_Create();
     InputList_Create();
 
-    hwndInputList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+    EnableWindow(GetDlgItem(hwndDlg, IDC_LANGUAGE_BAR), FALSE);
 
 
-    if (hwndInputList != NULL)
+    hLayoutImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
+                                        GetSystemMetrics(SM_CYSMICON),
+                                        ILC_COLOR8 | ILC_MASK, 0, 0);
+    if (hLayoutImageList != NULL)
     {
     {
-        WCHAR szBuffer[MAX_STR_LEN];
-        HIMAGELIST hLayoutImageList;
-        LV_COLUMN column;
-
-        ListView_SetExtendedListViewStyle(hwndInputList, LVS_EX_FULLROWSELECT);
-
-        ZeroMemory(&column, sizeof(column));
-
-        column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
-
-        LoadStringW(hApplet, IDS_LANGUAGE, szBuffer, ARRAYSIZE(szBuffer));
-        column.fmt      = LVCFMT_LEFT;
-        column.iSubItem = 0;
-        column.pszText  = szBuffer;
-        column.cx       = 175;
-        ListView_InsertColumn(hwndInputList, 0, &column);
-
-        LoadStringW(hApplet, IDS_LAYOUT, szBuffer, ARRAYSIZE(szBuffer));
-        column.fmt      = LVCFMT_RIGHT;
-        column.cx       = 155;
-        column.iSubItem = 1;
-        column.pszText  = szBuffer;
-        ListView_InsertColumn(hwndInputList, 1, &column);
-
-        hLayoutImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON) * 2,
-                                            GetSystemMetrics(SM_CYSMICON),
-                                            ILC_COLOR8 | ILC_MASK, 0, 0);
-        if (hLayoutImageList != NULL)
-        {
-            ListView_SetImageList(hwndInputList, hLayoutImageList, LVSIL_SMALL);
-        }
-
-        UpdateInputListView(hwndInputList);
+        hOldImageList = TreeView_SetImageList(hwndInputList, hLayoutImageList, TVSIL_NORMAL);
+        ImageList_Destroy(hOldImageList);
     }
 
     }
 
-    SetControlsState(hwndDlg, FALSE);
+    UpdateInputListView(hwndInputList);
+
+    SetControlsState(hwndDlg);
 }
 
 
 static VOID
 OnDestroySettingsPage(HWND hwndDlg)
 {
 }
 
 
 static VOID
 OnDestroySettingsPage(HWND hwndDlg)
 {
-    HIMAGELIST hImageList;
-
     LayoutList_Destroy();
     LocaleList_Destroy();
     InputList_Destroy();
     LayoutList_Destroy();
     LocaleList_Destroy();
     InputList_Destroy();
-
-    hImageList = ListView_GetImageList(GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST),
-                                       LVSIL_SMALL);
-    if (hImageList != NULL)
-    {
-        ImageList_Destroy(hImageList);
-    }
 }
 
 
 }
 
 
@@ -266,6 +433,7 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
                            AddDialogProc) == IDOK)
             {
                 UpdateInputListView(GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST));
                            AddDialogProc) == IDOK)
             {
                 UpdateInputListView(GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST));
+                SetControlsState(hwndDlg);
                 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
             }
         }
                 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
             }
         }
@@ -273,21 +441,35 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
 
         case IDC_REMOVE_BUTTON:
         {
 
         case IDC_REMOVE_BUTTON:
         {
-            HWND hwndList;
-            
-            hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
-
-            if (hwndList != NULL)
+            HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+            if (hwndList)
             {
             {
-                LVITEM item = { 0 };
-
-                item.mask = LVIF_PARAM;
-                item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
+                HTREEITEM hItem = TreeView_GetSelection(hwndList);
+                TV_ITEM item = { TVIF_HANDLE | TVIF_PARAM };
+                item.hItem = hItem;
 
 
-                if (ListView_GetItem(hwndList, &item) != FALSE)
+                if (hItem && TreeView_GetItem(hwndList, &item))
                 {
                 {
-                    InputList_Remove((INPUT_LIST_NODE*) item.lParam);
+                    if (item.lParam == 0) // Branch? (currently branch is keyboard only)
+                    {
+                        // Get root of branch
+                        item.hItem = TreeView_GetParent(hwndList, hItem);
+                        TreeView_GetItem(hwndList, &item);
+                    }
+
+                    if (HIWORD(item.lParam)) // Leaf?
+                    {
+                        if (InputList_Remove((INPUT_LIST_NODE*)item.lParam))
+                            g_bRebootNeeded = TRUE;
+                    }
+                    else // Root?
+                    {
+                        if (InputList_RemoveByLang(LOWORD(item.lParam)))
+                            g_bRebootNeeded = TRUE;
+                    }
+
                     UpdateInputListView(hwndList);
                     UpdateInputListView(hwndList);
+                    SetControlsState(hwndDlg);
                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
                 }
             }
                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
                 }
             }
@@ -296,18 +478,14 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
 
         case IDC_PROP_BUTTON:
         {
 
         case IDC_PROP_BUTTON:
         {
-            HWND hwndList;
-            
-            hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
-
-            if (hwndList != NULL)
+            HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+            if (hwndList)
             {
             {
-                LVITEM item = { 0 };
-
-                item.mask = LVIF_PARAM;
-                item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
+                HTREEITEM hItem = TreeView_GetSelection(hwndList);
+                TV_ITEM item = { TVIF_HANDLE | TVIF_PARAM };
+                item.hItem = hItem;
 
 
-                if (ListView_GetItem(hwndList, &item) != FALSE)
+                if (hItem && TreeView_GetItem(hwndList, &item) && HIWORD(item.lParam))
                 {
                     if (DialogBoxParamW(hApplet,
                                         MAKEINTRESOURCEW(IDD_INPUT_LANG_PROP),
                 {
                     if (DialogBoxParamW(hApplet,
                                         MAKEINTRESOURCEW(IDD_INPUT_LANG_PROP),
@@ -316,6 +494,7 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
                                         item.lParam) == IDOK)
                     {
                         UpdateInputListView(hwndList);
                                         item.lParam) == IDOK)
                     {
                         UpdateInputListView(hwndList);
+                        SetControlsState(hwndDlg);
                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
                     }
                 }
                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
                     }
                 }
@@ -323,29 +502,6 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
         }
         break;
 
         }
         break;
 
-        case IDC_SET_DEFAULT:
-        {
-            HWND hwndList;
-            
-            hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
-
-            if (hwndList != NULL)
-            {
-                LVITEM item = { 0 };
-
-                item.mask = LVIF_PARAM;
-                item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
-
-                if (ListView_GetItem(hwndList, &item) != FALSE)
-                {
-                    InputList_SetDefault((INPUT_LIST_NODE*) item.lParam);
-                    UpdateInputListView(hwndList);
-                    PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
-                }
-            }
-        }
-        break;
-
         case IDC_KEY_SET_BTN:
         {
             DialogBoxW(hApplet,
         case IDC_KEY_SET_BTN:
         {
             DialogBoxW(hApplet,
@@ -354,63 +510,104 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
                        KeySettingsDialogProc);
         }
         break;
                        KeySettingsDialogProc);
         }
         break;
+
+        case IDC_LANGUAGE_BAR:
+        {
+            // FIXME
+            break;
+        }
+
+        case IDC_DEFAULT_LANGUAGE:
+        {
+            if (HIWORD(wParam) == CBN_SELENDOK)
+            {
+                HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+                HWND hwndCombo = GetDlgItem(hwndDlg, IDC_DEFAULT_LANGUAGE);
+                INT iSelected = (INT)SendMessageW(hwndCombo, CB_GETCURSEL, 0, 0);
+                if (iSelected != CB_ERR)
+                {
+                    LPARAM lParam = SendMessageW(hwndCombo, CB_GETITEMDATA, iSelected, 0);
+                    if (lParam)
+                    {
+                        INPUT_LIST_NODE* pNode = (INPUT_LIST_NODE*)lParam;
+                        if (!(pNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT))
+                        {
+                            g_bRebootNeeded = TRUE;
+                            InputList_SetDefault(pNode);
+                            UpdateInputListView(hwndList);
+                            SetControlsState(hwndDlg);
+                            PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
+                        }
+                    }
+                }
+            }
+        }
     }
 }
 
     }
 }
 
+BOOL EnableProcessPrivileges(LPCWSTR lpPrivilegeName, BOOL bEnable)
+{
+    HANDLE hToken;
+    LUID luid;
+    TOKEN_PRIVILEGES tokenPrivileges;
+    BOOL Ret;
+
+    Ret = OpenProcessToken(GetCurrentProcess(),
+                           TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+                           &hToken);
+    if (!Ret)
+        return Ret;     // failure
+
+    Ret = LookupPrivilegeValueW(NULL, lpPrivilegeName, &luid);
+    if (Ret)
+    {
+        tokenPrivileges.PrivilegeCount = 1;
+        tokenPrivileges.Privileges[0].Luid = luid;
+        tokenPrivileges.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
 
 
-static VOID
+        Ret = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, 0, 0);
+    }
+
+    CloseHandle(hToken);
+    return Ret;
+}
+
+static INT_PTR
 OnNotifySettingsPage(HWND hwndDlg, LPARAM lParam)
 {
 OnNotifySettingsPage(HWND hwndDlg, LPARAM lParam)
 {
-    LPNMHDR header;
-
-    header = (LPNMHDR)lParam;
+    LPNMHDR header = (LPNMHDR)lParam;
 
     switch (header->code)
     {
 
     switch (header->code)
     {
-        case NM_CLICK:
+        case TVN_SELCHANGED:
         {
         {
-            if (header->idFrom == IDC_KEYLAYOUT_LIST)
-            {
-                INT iSelected = ListView_GetNextItem(header->hwndFrom, -1, LVNI_SELECTED);
-
-                if (iSelected != -1)
-                {
-                    LVITEM item = { 0 };
-
-                    SetControlsState(hwndDlg, TRUE);
-
-                    item.mask = LVIF_PARAM;
-                    item.iItem = iSelected;
-
-                    if (ListView_GetItem(header->hwndFrom, &item) != FALSE)
-                    {
-                        INPUT_LIST_NODE *pInput;
-
-                        pInput = (INPUT_LIST_NODE*) item.lParam;
+            SetControlsState(hwndDlg);
+            break;
+        }
 
 
-                        if (pInput != NULL && pInput->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
-                        {
-                            EnableWindow(GetDlgItem(hwndDlg, IDC_SET_DEFAULT), FALSE);
-                        }
-                    }
-                }
-                else
-                {
-                    SetControlsState(hwndDlg, FALSE);
-                }
+        case TVN_ITEMEXPANDING:
+        {
+            // FIXME: Prevent collapse (COMCTL32 is buggy)
+            // https://bugs.winehq.org/show_bug.cgi?id=53727
+            NM_TREEVIEW* pTreeView = (NM_TREEVIEW*)lParam;
+            if ((pTreeView->action & TVE_TOGGLE) == TVE_COLLAPSE)
+            {
+                SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
+                return TRUE;
             }
             }
+            break;
         }
         }
-        break;
 
         case PSN_APPLY:
         {
             /* Write Input Methods list to registry */
 
         case PSN_APPLY:
         {
             /* Write Input Methods list to registry */
-            InputList_Process();
+            g_bRebootNeeded |= InputList_Process();
+            break;
         }
         }
-        break;
     }
     }
-}
 
 
+    return 0;
+}
 
 INT_PTR CALLBACK
 SettingsPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
 
 INT_PTR CALLBACK
 SettingsPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
@@ -419,7 +616,7 @@ SettingsPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
     {
         case WM_INITDIALOG:
             OnInitSettingsPage(hwndDlg);
     {
         case WM_INITDIALOG:
             OnInitSettingsPage(hwndDlg);
-            break;
+            return TRUE;
 
         case WM_DESTROY:
             OnDestroySettingsPage(hwndDlg);
 
         case WM_DESTROY:
             OnDestroySettingsPage(hwndDlg);
@@ -430,8 +627,7 @@ SettingsPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
             break;
 
         case WM_NOTIFY:
             break;
 
         case WM_NOTIFY:
-            OnNotifySettingsPage(hwndDlg, lParam);
-            break;
+            return OnNotifySettingsPage(hwndDlg, lParam);
     }
 
     return FALSE;
     }
 
     return FALSE;