1 /* 2 * Program Manager 3 * 4 * Copyright 1996 Ulrich Schmid 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 /* 22 * PROJECT: ReactOS Program Manager 23 * COPYRIGHT: GPL - See COPYING in the top level directory 24 * FILE: base/shell/progman/group.c 25 * PURPOSE: Program group files helper functions 26 * PROGRAMMERS: Ulrich Schmid 27 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 28 */ 29 30 #include "progman.h" 31 32 /*********************************************************************** 33 * 34 * UX Theming helpers, dropped from msconfig_new/comctl32ex/uxthemesupp.c 35 * 36 */ 37 38 static HMODULE hUxTheme = NULL; 39 40 typedef HRESULT (WINAPI* ETDTProc)(HWND, DWORD); 41 static ETDTProc fnEnableThemeDialogTexture = NULL; 42 43 typedef HRESULT (WINAPI* SWTProc)(HWND, LPCWSTR, LPCWSTR); 44 static SWTProc fnSetWindowTheme = NULL; 45 46 47 static BOOL 48 InitUxTheme(VOID) 49 { 50 if (hUxTheme) return TRUE; 51 52 hUxTheme = LoadLibraryW(L"uxtheme.dll"); 53 if (hUxTheme == NULL) return FALSE; 54 55 fnEnableThemeDialogTexture = 56 (ETDTProc)GetProcAddress(hUxTheme, "EnableThemeDialogTexture"); 57 fnSetWindowTheme = 58 (SWTProc)GetProcAddress(hUxTheme, "SetWindowTheme"); 59 60 return TRUE; 61 } 62 63 #if 0 64 static VOID 65 CleanupUxTheme(VOID) 66 { 67 FreeLibrary(hUxTheme); 68 hUxTheme = NULL; 69 } 70 #endif 71 72 73 //////////////////////////////////////////////////////////////////////////////// 74 // Taken from WinSpy++ 1.7 75 // http://www.catch22.net/software/winspy 76 // Copyright (c) 2002 by J Brown 77 // 78 79 HRESULT 80 WINAPI 81 EnableThemeDialogTexture(_In_ HWND hwnd, 82 _In_ DWORD dwFlags) 83 { 84 if (!InitUxTheme()) 85 return HRESULT_FROM_WIN32(GetLastError()); 86 87 if (!fnEnableThemeDialogTexture) 88 return HRESULT_FROM_WIN32(GetLastError()); 89 90 return fnEnableThemeDialogTexture(hwnd, dwFlags); 91 } 92 93 HRESULT 94 WINAPI 95 SetWindowTheme(_In_ HWND hwnd, 96 _In_ LPCWSTR pszSubAppName, 97 _In_ LPCWSTR pszSubIdList) 98 { 99 if (!InitUxTheme()) 100 return HRESULT_FROM_WIN32(GetLastError()); 101 102 if (!fnSetWindowTheme) 103 return HRESULT_FROM_WIN32(GetLastError()); 104 105 return fnSetWindowTheme(hwnd, pszSubAppName, pszSubIdList); 106 } 107 108 109 /*********************************************************************** 110 * 111 * GROUP_GroupWndProc 112 */ 113 114 static 115 LRESULT 116 CALLBACK 117 GROUP_GroupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 118 { 119 PROGGROUP* group; 120 INT iItem; 121 LVITEMW lvItem; 122 POINT pt; 123 124 group = (PROGGROUP*)GetWindowLongPtrW(hWnd, 0); 125 126 switch (uMsg) 127 { 128 case WM_NCCREATE: 129 { 130 LPCREATESTRUCTW pcs = (LPCREATESTRUCTW)lParam; 131 LPMDICREATESTRUCTW pMDIcs = (LPMDICREATESTRUCTW)pcs->lpCreateParams; 132 group = (PROGGROUP*)pMDIcs->lParam; 133 SetWindowLongPtrW(hWnd, 0, (LONG_PTR)group); 134 135 if (group->bIsCommonGroup) 136 { 137 DefMDIChildProcW(hWnd, WM_SETICON, ICON_BIG, 138 (LPARAM)CopyImage(Globals.hCommonGroupIcon, 139 IMAGE_ICON, 140 GetSystemMetrics(SM_CXICON), 141 GetSystemMetrics(SM_CYICON), 142 LR_COPYFROMRESOURCE)); 143 DefMDIChildProcW(hWnd, WM_SETICON, ICON_SMALL, 144 (LPARAM)CopyImage(Globals.hCommonGroupIcon, 145 IMAGE_ICON, 146 GetSystemMetrics(SM_CXSMICON), 147 GetSystemMetrics(SM_CYSMICON), 148 LR_COPYFROMRESOURCE)); 149 } 150 else 151 { 152 DefMDIChildProcW(hWnd, WM_SETICON, ICON_BIG, 153 (LPARAM)CopyImage(Globals.hPersonalGroupIcon, 154 IMAGE_ICON, 155 GetSystemMetrics(SM_CXICON), 156 GetSystemMetrics(SM_CYICON), 157 LR_COPYFROMRESOURCE)); 158 DefMDIChildProcW(hWnd, WM_SETICON, ICON_SMALL, 159 (LPARAM)CopyImage(Globals.hPersonalGroupIcon, 160 IMAGE_ICON, 161 GetSystemMetrics(SM_CXSMICON), 162 GetSystemMetrics(SM_CYSMICON), 163 LR_COPYFROMRESOURCE)); 164 } 165 break; 166 } 167 168 case WM_NCDESTROY: 169 SetWindowLongPtrW(hWnd, 0, 0); 170 break; 171 172 case WM_CREATE: 173 { 174 DWORD dwStyle; 175 RECT rect; 176 GetClientRect(hWnd, &rect); 177 group->hListView = CreateWindowW(WC_LISTVIEW, 178 NULL, 179 WS_CHILD | WS_VISIBLE | WS_OVERLAPPED, 180 0, 0, 181 rect.right - rect.left, 182 rect.bottom - rect.top, 183 hWnd, 184 NULL, 185 Globals.hInstance, 186 NULL); 187 dwStyle = (GetWindowLongPtrW(group->hListView, GWL_STYLE) | LVS_SHOWSELALWAYS) & ~LVS_AUTOARRANGE; 188 SetWindowLongPtrW(group->hListView, GWL_STYLE, dwStyle); 189 dwStyle = SendMessageA(group->hListView, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0) | LVS_EX_BORDERSELECT; 190 SendMessageA(group->hListView, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_SNAPTOGRID, dwStyle); 191 InitUxTheme(); 192 SetWindowTheme(group->hListView, L"Explorer", NULL); 193 group->hListLarge = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR24 | ILC_MASK, 1, 1); 194 SendMessageA(group->hListView, LVM_SETIMAGELIST, 0, (LPARAM)group->hListLarge); 195 SendMessageA(group->hListView, LVM_SETICONSPACING, 0, MAKELPARAM(80, 64)); 196 break; 197 } 198 199 case WM_DESTROY: 200 { 201 SendMessageA(group->hListView, LVM_SETIMAGELIST, 0, 0); 202 ImageList_Destroy(group->hListLarge); 203 DestroyWindow(group->hListView); 204 break; 205 } 206 207 case WM_SIZE: 208 { 209 RECT rect; 210 rect.left = 0; 211 rect.top = 0; 212 rect.right = LOWORD(lParam); 213 rect.bottom = HIWORD(lParam); 214 AdjustWindowRectEx(&rect, GetWindowLongPtrW(group->hListView, GWL_STYLE), FALSE, GetWindowLongPtrW(group->hListView, GWL_EXSTYLE)); 215 MoveWindow(group->hListView, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); 216 break; 217 } 218 219 case WM_CLOSE: 220 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); 221 break; 222 223 case WM_SYSCOMMAND: 224 if (wParam == SC_CLOSE) wParam = SC_MINIMIZE; 225 break; 226 227 case WM_CHILDACTIVATE: 228 case WM_NCLBUTTONDOWN: 229 Globals.hActiveGroup = (PROGGROUP*)GetWindowLongPtrW(hWnd, 0); 230 Globals.hActiveGroup->hActiveProgram = NULL; 231 break; 232 233 case WM_NOTIFY: 234 switch (((LPNMHDR)lParam)->code) 235 { 236 case NM_CLICK: 237 { 238 iItem = ((LPNMITEMACTIVATE)lParam)->iItem; 239 if (iItem == -1) 240 { 241 group->hActiveProgram = NULL; 242 break; 243 } 244 245 lvItem.mask = LVIF_PARAM; 246 lvItem.iItem = iItem; 247 SendMessageW(group->hListView, LVM_GETITEMW, 0, (LPARAM)&lvItem); 248 group->hActiveProgram = (PROGRAM*)lvItem.lParam; 249 break; 250 } 251 252 case NM_DBLCLK: 253 { 254 iItem = ((LPNMITEMACTIVATE)lParam)->iItem; 255 if (iItem == -1) 256 break; 257 258 lvItem.mask = LVIF_PARAM; 259 lvItem.iItem = iItem; 260 SendMessageW(group->hListView, LVM_GETITEMW, 0, (LPARAM)&lvItem); 261 /* ... or use group->hActiveProgram */ 262 PROGRAM_ExecuteProgram((PROGRAM*)lvItem.lParam); 263 break; 264 } 265 266 case LVN_BEGINDRAG: 267 { 268 POINT ptMin; 269 270 BOOL bFirst = TRUE; 271 for (iItem = SendMessageA(group->hListView, LVM_GETNEXTITEM, -1, LVNI_SELECTED); 272 iItem != -1; 273 iItem = SendMessageA(group->hListView, LVM_GETNEXTITEM, iItem, LVNI_SELECTED)) 274 { 275 if (bFirst) 276 { 277 group->hDragImageList = (HIMAGELIST)SendMessageA(group->hListView, 278 LVM_CREATEDRAGIMAGE, 279 iItem, 280 (LPARAM)&pt); 281 ptMin = pt; 282 bFirst = FALSE; 283 } 284 else 285 { 286 HIMAGELIST hOneImageList, hTempImageList; 287 288 hOneImageList = (HIMAGELIST)SendMessageA(group->hListView, 289 LVM_CREATEDRAGIMAGE, 290 iItem, 291 (LPARAM)&pt); 292 hTempImageList = ImageList_Merge(group->hDragImageList, 293 0, 294 hOneImageList, 295 0, 296 pt.x - ptMin.x, 297 pt.y - ptMin.y); 298 ImageList_Destroy(group->hDragImageList); 299 ImageList_Destroy(hOneImageList); 300 group->hDragImageList = hTempImageList; 301 ptMin.x = min(ptMin.x, pt.x); 302 ptMin.y = min(ptMin.y, pt.y); 303 } 304 } 305 // pt = ((LPNMLISTVIEW)lParam)->ptAction; 306 pt.x = ((LPNMLISTVIEW)lParam)->ptAction.x; 307 pt.y = ((LPNMLISTVIEW)lParam)->ptAction.y; 308 group->ptStart = pt; 309 pt.x -= ptMin.x; 310 pt.y -= ptMin.y; 311 ImageList_BeginDrag(group->hDragImageList, 0, pt.x, pt.y); 312 MapWindowPoints(group->hListView, Globals.hMDIWnd, &pt, 1); 313 ImageList_DragEnter(Globals.hMDIWnd, pt.x, pt.y); 314 group->bDragging = TRUE; 315 group->hOldCursor = GetCursor(); 316 SetCapture(group->hWnd); 317 318 break; 319 } 320 } 321 break; 322 323 case WM_MOUSEMOVE: 324 if (group->bDragging) 325 { 326 pt.x = GET_X_LPARAM(lParam); 327 pt.y = GET_Y_LPARAM(lParam); 328 MapWindowPoints(group->hWnd, Globals.hMDIWnd, &pt, 1); 329 ImageList_DragMove(pt.x, pt.y); 330 } 331 break; 332 333 case WM_LBUTTONUP: 334 if (group->bDragging) 335 { 336 // LVHITTESTINFO lvhti; 337 POINT ptHit; 338 339 group->bDragging = FALSE; 340 ImageList_DragLeave(Globals.hMDIWnd); 341 ImageList_EndDrag(); 342 ImageList_Destroy(group->hDragImageList); 343 ReleaseCapture(); 344 SetCursor(group->hOldCursor); 345 ptHit.x = GET_X_LPARAM(lParam); 346 ptHit.y = GET_Y_LPARAM(lParam); 347 MapWindowPoints(group->hWnd, group->hListView, &ptHit, 1); 348 for (iItem = SendMessageA(group->hListView, LVM_GETNEXTITEM, -1, LVNI_SELECTED); 349 iItem != -1; 350 iItem = SendMessageA(group->hListView, LVM_GETNEXTITEM, iItem, LVNI_SELECTED)) 351 { 352 SendMessageA(group->hListView, LVM_GETITEMPOSITION, iItem, (LPARAM)&pt); 353 pt.x += ptHit.x - group->ptStart.x; 354 pt.y += ptHit.y - group->ptStart.y; 355 SendMessageA(group->hListView, LVM_SETITEMPOSITION, iItem, MAKELPARAM(pt.x, pt.y)); 356 } 357 } 358 break; 359 } 360 361 return DefMDIChildProcW(hWnd, uMsg, wParam, lParam); 362 } 363 364 /*********************************************************************** 365 * 366 * GROUP_RegisterGroupWinClass 367 */ 368 369 ATOM GROUP_RegisterGroupWinClass(VOID) 370 { 371 WNDCLASSW wndClass; 372 373 wndClass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; 374 wndClass.lpfnWndProc = GROUP_GroupWndProc; 375 wndClass.cbClsExtra = 0; 376 wndClass.cbWndExtra = sizeof(LONG_PTR); 377 wndClass.hInstance = Globals.hInstance; 378 wndClass.hIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_GROUP_ICON)); 379 wndClass.hCursor = LoadCursorW(NULL, IDC_ARROW); 380 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 381 wndClass.lpszMenuName = NULL; 382 wndClass.lpszClassName = STRING_GROUP_WIN_CLASS_NAME; 383 384 return RegisterClassW(&wndClass); 385 } 386 387 /*********************************************************************** 388 * 389 * GROUP_NewGroup 390 */ 391 392 VOID GROUP_NewGroup(GROUPFORMAT format, BOOL bIsCommonGroup) 393 { 394 HANDLE hFile; 395 WCHAR szGrpFile[MAX_PATHNAME_LEN] = L""; 396 WCHAR szTitle[MAX_PATHNAME_LEN] = L""; 397 398 // ZeroMemory(szTitle, sizeof(szTitle)); 399 // ZeroMemory(szGrpFile, sizeof(szGrpFile)); 400 401 if (!DIALOG_GroupAttributes(format, szTitle, szGrpFile, MAX_PATHNAME_LEN)) 402 return; 403 404 /* 405 * Just check whether the group file does exist. If it does, close the handle, because GRPFILE_ReadGroupFile will 406 * reopen the file for loading. If it doesn't exist, we create a new one. 407 */ 408 hFile = CreateFileW(szGrpFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 409 if (hFile == INVALID_HANDLE_VALUE) 410 { 411 /* File doesn't exist */ 412 PROGGROUP* hGroup = GROUP_AddGroup(format, bIsCommonGroup, szTitle, szGrpFile, 413 DEF_GROUP_WIN_XPOS, DEF_GROUP_WIN_YPOS, 414 DEF_GROUP_WIN_XPOS + DEF_GROUP_WIN_WIDTH, DEF_GROUP_WIN_YPOS + DEF_GROUP_WIN_HEIGHT, 415 0, 0, SW_SHOWNORMAL, 0, 0, FALSE, FALSE); 416 if (hGroup) 417 GRPFILE_WriteGroupFile(hGroup); 418 } 419 else 420 { 421 /* File exist */ 422 CloseHandle(hFile); 423 GRPFILE_ReadGroupFile(szGrpFile, bIsCommonGroup); 424 } 425 426 /* FIXME Update progman.ini */ 427 } 428 429 /*********************************************************************** 430 * 431 * GROUP_AddGroup 432 */ 433 434 PROGGROUP* 435 GROUP_AddGroup(GROUPFORMAT format, BOOL bIsCommonGroup, LPCWSTR lpszName, LPCWSTR lpszGrpFile, 436 INT left, INT top, INT right, INT bottom, INT xMin, INT yMin, INT nCmdShow, 437 WORD cxIcon, WORD cyIcon, BOOL bOverwriteFileOk, 438 /* FIXME shouldn't be necessary */ 439 BOOL bSuppressShowWindow) 440 { 441 PROGGROUP* hGroup; 442 PROGGROUP* hPrior; 443 PROGGROUP** p; 444 LPWSTR hName; 445 LPWSTR hGrpFile; 446 LPCWSTR GroupFileName; 447 INT skip; 448 INT width; 449 INT height; 450 INT seqnum; 451 MDICREATESTRUCTW mcs; 452 WINDOWPLACEMENT WndPl; 453 454 WndPl.length = sizeof(WndPl); 455 456 // FIXME: Use system default position in case we don't place the window at a given (x,y) coordinate. 457 458 if (bIsCommonGroup) 459 { 460 if (swscanf(lpszGrpFile, 461 L"%d %d %d %d %d %d %d %n", 462 &WndPl.rcNormalPosition.left, 463 &WndPl.rcNormalPosition.top, 464 &WndPl.rcNormalPosition.right, 465 &WndPl.rcNormalPosition.bottom, 466 &WndPl.ptMinPosition.x, 467 &WndPl.ptMinPosition.y, 468 &WndPl.showCmd, 469 &skip) == 7) 470 { 471 WndPl.flags = WPF_SETMINPOSITION; 472 width = WndPl.rcNormalPosition.right - WndPl.rcNormalPosition.left; 473 height = WndPl.rcNormalPosition.bottom - WndPl.rcNormalPosition.top; 474 GroupFileName = &lpszGrpFile[skip]; 475 } 476 else 477 { 478 #if 0 // FIXME! 479 WndPl.rcNormalPosition.top = CW_USEDEFAULT; 480 WndPl.rcNormalPosition.left = CW_USEDEFAULT; 481 WndPl.rcNormalPosition.right = 0; 482 WndPl.rcNormalPosition.bottom = 0; 483 width = CW_USEDEFAULT; 484 height = CW_USEDEFAULT; 485 WndPl.showCmd = SW_SHOWNORMAL; 486 GroupFileName = lpszGrpFile; 487 #else 488 WndPl.flags = WPF_SETMINPOSITION; 489 WndPl.ptMinPosition.x = xMin; 490 WndPl.ptMinPosition.y = yMin; 491 WndPl.rcNormalPosition.left = left; 492 WndPl.rcNormalPosition.top = top; 493 WndPl.rcNormalPosition.right = right; 494 WndPl.rcNormalPosition.bottom = bottom; 495 width = right - left; 496 height = bottom - top; 497 WndPl.showCmd = nCmdShow; 498 GroupFileName = lpszGrpFile; 499 #endif 500 } 501 } 502 else 503 { 504 WndPl.flags = WPF_SETMINPOSITION; 505 WndPl.ptMinPosition.x = xMin; 506 WndPl.ptMinPosition.y = yMin; 507 WndPl.rcNormalPosition.left = left; 508 WndPl.rcNormalPosition.top = top; 509 WndPl.rcNormalPosition.right = right; 510 WndPl.rcNormalPosition.bottom = bottom; 511 width = right - left; 512 height = bottom - top; 513 WndPl.showCmd = nCmdShow; 514 GroupFileName = lpszGrpFile; 515 } 516 517 hGroup = Alloc(HEAP_ZERO_MEMORY, sizeof(*hGroup)); 518 hName = Alloc(HEAP_ZERO_MEMORY, (wcslen(lpszName) + 1) * sizeof(WCHAR)); 519 hGrpFile = Alloc(HEAP_ZERO_MEMORY, (wcslen(GroupFileName) + 1) * sizeof(WCHAR)); 520 if (!hGroup || !hName || !hGrpFile) 521 { 522 MAIN_MessageBoxIDS(IDS_OUT_OF_MEMORY, IDS_ERROR, MB_OK); 523 if (hGroup) Free(hGroup); 524 if (hName) Free(hName); 525 if (hGrpFile) Free(hGrpFile); 526 return NULL; 527 } 528 memcpy(hName , lpszName , (wcslen(lpszName) + 1) * sizeof(WCHAR)); 529 memcpy(hGrpFile, GroupFileName, (wcslen(GroupFileName) + 1) * sizeof(WCHAR)); 530 531 Globals.hActiveGroup = hGroup; 532 533 seqnum = 1; 534 hPrior = NULL; 535 for (p = &Globals.hGroups; *p; p = &hPrior->hNext) 536 { 537 hPrior = *p; 538 if (hPrior->seqnum >= seqnum) 539 seqnum = hPrior->seqnum + 1; 540 } 541 *p = hGroup; 542 543 hGroup->hPrior = hPrior; 544 hGroup->hNext = NULL; 545 hGroup->format = format; 546 hGroup->bIsCommonGroup = bIsCommonGroup; 547 hGroup->hName = hName; 548 hGroup->hGrpFile = hGrpFile; 549 hGroup->bOverwriteFileOk = bOverwriteFileOk; 550 hGroup->seqnum = seqnum; 551 hGroup->nCmdShow = nCmdShow; 552 #if 0 553 hGroup->x = x; 554 hGroup->y = y; 555 hGroup->width = width; 556 hGroup->height = height; 557 #endif 558 hGroup->iconx = cxIcon; 559 hGroup->icony = cyIcon; 560 hGroup->hPrograms = NULL; 561 hGroup->hActiveProgram = NULL; 562 hGroup->TagsSize = 0; 563 hGroup->Tags = NULL; 564 565 mcs.szClass = STRING_GROUP_WIN_CLASS_NAME; 566 mcs.szTitle = lpszName; 567 mcs.hOwner = NULL; 568 mcs.x = WndPl.rcNormalPosition.left; 569 mcs.y = WndPl.rcNormalPosition.top; 570 mcs.cx = width; 571 mcs.cy = height; 572 mcs.style = 0; 573 mcs.lParam = (LPARAM)hGroup; 574 575 hGroup->hWnd = (HWND)SendMessageW(Globals.hMDIWnd, WM_MDICREATE, 0, (LPARAM)&mcs); 576 577 SetWindowPlacement(hGroup->hWnd, &WndPl); 578 579 #if 1 580 if (!bSuppressShowWindow) /* FIXME shouldn't be necessary */ 581 #endif 582 UpdateWindow(hGroup->hWnd); 583 584 return hGroup; 585 } 586 587 588 589 590 591 /*********************************************************************** 592 * 593 * GROUP_ModifyGroup 594 */ 595 596 VOID GROUP_ModifyGroup(PROGGROUP* hGroup) 597 { 598 WCHAR Dest[MAX_PATHNAME_LEN]; // szName 599 WCHAR szGrpFile[MAX_PATHNAME_LEN]; // szFile 600 601 wcsncpy(Dest, hGroup->hName, ARRAYSIZE(Dest)); 602 wcsncpy(szGrpFile, hGroup->hGrpFile, ARRAYSIZE(szGrpFile)); 603 604 if (!DIALOG_GroupAttributes(hGroup->format, Dest, szGrpFile, MAX_PATHNAME_LEN)) 605 return; 606 607 if (wcscmp(szGrpFile, hGroup->hGrpFile)) 608 hGroup->bOverwriteFileOk = FALSE; 609 610 MAIN_ReplaceString(&hGroup->hName, Dest); 611 MAIN_ReplaceString(&hGroup->hGrpFile, szGrpFile); 612 613 GRPFILE_WriteGroupFile(hGroup); 614 615 /* FIXME Delete old GrpFile if GrpFile changed */ 616 617 /* FIXME Update progman.ini */ 618 619 SetWindowTextW(hGroup->hWnd, Dest); 620 } 621 622 /*********************************************************************** 623 * 624 * GROUP_DeleteGroup 625 */ 626 627 VOID GROUP_DeleteGroup(PROGGROUP* hGroup) 628 { 629 if (Globals.hActiveGroup == hGroup) 630 Globals.hActiveGroup = NULL; 631 632 if (hGroup->hPrior) 633 hGroup->hPrior->hNext = hGroup->hNext; 634 else 635 Globals.hGroups = hGroup->hNext; 636 637 if (hGroup->hNext) 638 hGroup->hNext->hPrior = hGroup->hPrior; 639 640 while (hGroup->hPrograms) 641 PROGRAM_DeleteProgram(hGroup->hPrograms, FALSE); 642 643 /* FIXME Update progman.ini */ 644 645 SendMessageW(Globals.hMDIWnd, WM_MDIDESTROY, (WPARAM)hGroup->hWnd, 0); 646 647 if (hGroup->Tags) 648 Free(hGroup->Tags); 649 Free(hGroup->hName); 650 Free(hGroup->hGrpFile); 651 Free(hGroup); 652 } 653 654 /*********************************************************************** 655 * 656 * GROUP_ShowGroupWindow 657 */ 658 659 /* FIXME shouldn't be necessary */ 660 VOID GROUP_ShowGroupWindow(PROGGROUP* hGroup) 661 { 662 ShowWindow(hGroup->hWnd, hGroup->nCmdShow); 663 UpdateWindow(hGroup->hWnd); 664 } 665 666 /*********************************************************************** 667 * 668 * GROUP_ActiveGroup 669 */ 670 671 PROGGROUP* GROUP_ActiveGroup(VOID) 672 { 673 return Globals.hActiveGroup; 674 } 675