winprefs.c revision 05b261ec
1/* 2 * Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 19 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Except as contained in this notice, the name of the XFree86 Project 24 * shall not be used in advertising or otherwise to promote the sale, use 25 * or other dealings in this Software without prior written authorization 26 * from the XFree86 Project. 27 * 28 * Authors: Earle F. Philhower, III 29 */ 30 31#ifdef HAVE_XWIN_CONFIG_H 32#include <xwin-config.h> 33#endif 34#include <stdio.h> 35#include <stdlib.h> 36#ifdef __CYGWIN__ 37#include <sys/resource.h> 38#endif 39#include "win.h" 40 41#include <X11/Xwindows.h> 42#include <shellapi.h> 43 44#include "winprefs.h" 45#include "winmultiwindowclass.h" 46 47/* Where will the custom menu commands start counting from? */ 48#define STARTMENUID WM_USER 49 50/* External global variables */ 51#ifdef XWIN_MULTIWINDOW 52extern DWORD g_dwCurrentThreadID; 53#endif 54 55extern const char *winGetBaseDir(void); 56 57/* From winmultiwindowflex.l, the real parser */ 58extern void parse_file (FILE *fp); 59 60/* From winprefyacc.y, the pref structure loaded by the parser */ 61extern WINPREFS pref; 62 63/* The global X default icon */ 64extern HICON g_hIconX; 65extern HICON g_hSmallIconX; 66 67/* Currently in use command ID, incremented each new menu item created */ 68static int g_cmdid = STARTMENUID; 69 70 71/* Defined in DIX */ 72extern char *display; 73 74/* Local function to handle comma-ified icon names */ 75static HICON 76LoadImageComma (char *fname, int sx, int sy, int flags); 77 78 79/* 80 * Creates or appends a menu from a MENUPARSED structure 81 */ 82static HMENU 83MakeMenu (char *name, 84 HMENU editMenu, 85 int editItem) 86{ 87 int i; 88 int item; 89 MENUPARSED *m; 90 HMENU hmenu, hsub; 91 92 for (i=0; i<pref.menuItems; i++) 93 { 94 if (!strcmp(name, pref.menu[i].menuName)) 95 break; 96 } 97 98 /* Didn't find a match, bummer */ 99 if (i==pref.menuItems) 100 { 101 ErrorF("MakeMenu: Can't find menu %s\n", name); 102 return NULL; 103 } 104 105 m = &(pref.menu[i]); 106 107 if (editMenu) 108 { 109 hmenu = editMenu; 110 item = editItem; 111 } 112 else 113 { 114 hmenu = CreatePopupMenu(); 115 if (!hmenu) 116 { 117 ErrorF("MakeMenu: Unable to CreatePopupMenu() %s\n", name); 118 return NULL; 119 } 120 item = 0; 121 } 122 123 /* Add the menu items */ 124 for (i=0; i<m->menuItems; i++) 125 { 126 /* Only assign IDs one time... */ 127 if ( m->menuItem[i].commandID == 0 ) 128 m->menuItem[i].commandID = g_cmdid++; 129 130 switch (m->menuItem[i].cmd) 131 { 132 case CMD_EXEC: 133 case CMD_ALWAYSONTOP: 134 case CMD_RELOAD: 135 InsertMenu (hmenu, 136 item, 137 MF_BYPOSITION|MF_ENABLED|MF_STRING, 138 m->menuItem[i].commandID, 139 m->menuItem[i].text); 140 break; 141 142 case CMD_SEPARATOR: 143 InsertMenu (hmenu, 144 item, 145 MF_BYPOSITION|MF_SEPARATOR, 146 0, 147 NULL); 148 break; 149 150 case CMD_MENU: 151 /* Recursive! */ 152 hsub = MakeMenu (m->menuItem[i].param, 0, 0); 153 if (hsub) 154 InsertMenu (hmenu, 155 item, 156 MF_BYPOSITION|MF_POPUP|MF_ENABLED|MF_STRING, 157 (UINT_PTR)hsub, 158 m->menuItem[i].text); 159 break; 160 } 161 162 /* If item==-1 (means to add at end of menu) don't increment) */ 163 if (item>=0) 164 item++; 165 } 166 167 return hmenu; 168} 169 170 171#ifdef XWIN_MULTIWINDOW 172/* 173 * Callback routine that is executed once per window class. 174 * Removes or creates custom window settings depending on LPARAM 175 */ 176static wBOOL CALLBACK 177ReloadEnumWindowsProc (HWND hwnd, LPARAM lParam) 178{ 179 HICON hicon; 180 Window wid; 181 182 if (!hwnd) { 183 ErrorF("ReloadEnumWindowsProc: hwnd==NULL!\n"); 184 return FALSE; 185 } 186 187 /* It's our baby, either clean or dirty it */ 188 if (lParam==FALSE) 189 { 190 hicon = (HICON)GetClassLong(hwnd, GCL_HICON); 191 192 /* Unselect any icon in the class structure */ 193 SetClassLong (hwnd, GCL_HICON, (LONG)LoadIcon (NULL, IDI_APPLICATION)); 194 195 /* If it's generated on-the-fly, get rid of it, will regen */ 196 winDestroyIcon (hicon); 197 198 hicon = (HICON)GetClassLong(hwnd, GCL_HICONSM); 199 200 /* Unselect any icon in the class structure */ 201 SetClassLong (hwnd, GCL_HICONSM, 0); 202 203 /* If it's generated on-the-fly, get rid of it, will regen */ 204 winDestroyIcon (hicon); 205 206 /* Remove any menu additions, use bRevert flag */ 207 GetSystemMenu (hwnd, TRUE); 208 209 /* This window is now clean of our taint */ 210 } 211 else 212 { 213 /* Make the icon default, dynamic, or from xwinrc */ 214 SetClassLong (hwnd, GCL_HICON, (LONG)g_hIconX); 215 SetClassLong (hwnd, GCL_HICONSM, (LONG)g_hSmallIconX); 216 wid = (Window)GetProp (hwnd, WIN_WID_PROP); 217 if (wid) 218 winUpdateIcon (wid); 219 /* Update the system menu for this window */ 220 SetupSysMenu ((unsigned long)hwnd); 221 222 /* That was easy... */ 223 } 224 225 return TRUE; 226} 227#endif 228 229 230/* 231 * Removes any custom icons in classes, custom menus, etc. 232 * Frees all members in pref structure. 233 * Reloads the preferences file. 234 * Set custom icons and menus again. 235 */ 236static void 237ReloadPrefs (void) 238{ 239 int i; 240 241#ifdef XWIN_MULTIWINDOW 242 /* First, iterate over all windows replacing their icon with system */ 243 /* default one and deleting any custom system menus */ 244 EnumThreadWindows (g_dwCurrentThreadID, ReloadEnumWindowsProc, FALSE); 245#endif 246 247 /* Now, free/clear all info from our prefs structure */ 248 for (i=0; i<pref.menuItems; i++) 249 free (pref.menu[i].menuItem); 250 free (pref.menu); 251 pref.menu = NULL; 252 pref.menuItems = 0; 253 254 pref.rootMenuName[0] = 0; 255 256 free (pref.sysMenu); 257 pref.sysMenuItems = 0; 258 259 pref.defaultSysMenuName[0] = 0; 260 pref.defaultSysMenuPos = 0; 261 262 pref.iconDirectory[0] = 0; 263 pref.defaultIconName[0] = 0; 264 pref.trayIconName[0] = 0; 265 266 for (i=0; i<pref.iconItems; i++) 267 if (pref.icon[i].hicon) 268 DestroyIcon ((HICON)pref.icon[i].hicon); 269 free (pref.icon); 270 pref.icon = NULL; 271 pref.iconItems = 0; 272 273 /* Free global default X icon */ 274 if (g_hIconX) 275 DestroyIcon (g_hIconX); 276 if (g_hSmallIconX) 277 DestroyIcon (g_hSmallIconX); 278 279 /* Reset the custom command IDs */ 280 g_cmdid = STARTMENUID; 281 282 /* Load the updated resource file */ 283 LoadPreferences(); 284 285 g_hIconX = NULL; 286 g_hSmallIconX = NULL; 287 288#ifdef XWIN_MULTIWINDOW 289 winInitGlobalIcons(); 290#endif 291 292#ifdef XWIN_MULTIWINDOW 293 /* Rebuild the icons and menus */ 294 EnumThreadWindows (g_dwCurrentThreadID, ReloadEnumWindowsProc, TRUE); 295#endif 296 297 /* Whew, done */ 298} 299 300/* 301 * Check/uncheck the ALWAYSONTOP items in this menu 302 */ 303void 304HandleCustomWM_INITMENU(unsigned long hwndIn, 305 unsigned long hmenuIn) 306{ 307 HWND hwnd; 308 HMENU hmenu; 309 DWORD dwExStyle; 310 int i, j; 311 312 hwnd = (HWND)hwndIn; 313 hmenu = (HMENU)hmenuIn; 314 if (!hwnd || !hmenu) 315 return; 316 317 if (GetWindowLong (hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) 318 dwExStyle = MF_BYCOMMAND | MF_CHECKED; 319 else 320 dwExStyle = MF_BYCOMMAND | MF_UNCHECKED; 321 322 for (i=0; i<pref.menuItems; i++) 323 for (j=0; j<pref.menu[i].menuItems; j++) 324 if (pref.menu[i].menuItem[j].cmd==CMD_ALWAYSONTOP) 325 CheckMenuItem (hmenu, pref.menu[i].menuItem[j].commandID, dwExStyle ); 326 327} 328 329/* 330 * Searches for the custom WM_COMMAND command ID and performs action. 331 * Return TRUE if command is proccessed, FALSE otherwise. 332 */ 333Bool 334HandleCustomWM_COMMAND (unsigned long hwndIn, 335 int command) 336{ 337 HWND hwnd; 338 int i, j; 339 MENUPARSED *m; 340 DWORD dwExStyle; 341 342 hwnd = (HWND)hwndIn; 343 344 if (!command) 345 return FALSE; 346 347 for (i=0; i<pref.menuItems; i++) 348 { 349 m = &(pref.menu[i]); 350 for (j=0; j<m->menuItems; j++) 351 { 352 if (command==m->menuItem[j].commandID) 353 { 354 /* Match! */ 355 switch(m->menuItem[j].cmd) 356 { 357#ifdef __CYGWIN__ 358 case CMD_EXEC: 359 if (fork()==0) 360 { 361 struct rlimit rl; 362 unsigned long i; 363 364 /* Close any open descriptors except for STD* */ 365 getrlimit (RLIMIT_NOFILE, &rl); 366 for (i = STDERR_FILENO+1; i < rl.rlim_cur; i++) 367 close(i); 368 369 /* Disassociate any TTYs */ 370 setsid(); 371 372 execl ("/bin/sh", 373 "/bin/sh", 374 "-c", 375 m->menuItem[j].param, 376 NULL); 377 exit (0); 378 } 379 else 380 return TRUE; 381 break; 382#else 383 case CMD_EXEC: 384 { 385 /* Start process without console window */ 386 STARTUPINFO start; 387 PROCESS_INFORMATION child; 388 389 memset (&start, 0, sizeof (start)); 390 start.cb = sizeof (start); 391 start.dwFlags = STARTF_USESHOWWINDOW; 392 start.wShowWindow = SW_HIDE; 393 394 memset (&child, 0, sizeof (child)); 395 396 if (CreateProcess (NULL, m->menuItem[j].param, NULL, NULL, FALSE, 0, 397 NULL, NULL, &start, &child)) 398 { 399 CloseHandle (child.hThread); 400 CloseHandle (child.hProcess); 401 } 402 else 403 MessageBox(NULL, m->menuItem[j].param, "Mingrc Exec Command Error!", MB_OK | MB_ICONEXCLAMATION); 404 } 405 return TRUE; 406#endif 407 case CMD_ALWAYSONTOP: 408 if (!hwnd) 409 return FALSE; 410 411 /* Get extended window style */ 412 dwExStyle = GetWindowLong (hwnd, GWL_EXSTYLE); 413 414 /* Handle topmost windows */ 415 if (dwExStyle & WS_EX_TOPMOST) 416 SetWindowPos (hwnd, 417 HWND_NOTOPMOST, 418 0, 0, 419 0, 0, 420 SWP_NOSIZE | SWP_NOMOVE); 421 else 422 SetWindowPos (hwnd, 423 HWND_TOPMOST, 424 0, 0, 425 0, 0, 426 SWP_NOSIZE | SWP_NOMOVE); 427#if XWIN_MULTIWINDOW 428 /* Reflect the changed Z order */ 429 winReorderWindowsMultiWindow (); 430#endif 431 return TRUE; 432 433 case CMD_RELOAD: 434 ReloadPrefs(); 435 return TRUE; 436 437 default: 438 return FALSE; 439 } 440 } /* match */ 441 } /* for j */ 442 } /* for i */ 443 444 return FALSE; 445} 446 447 448#ifdef XWIN_MULTIWINDOW 449/* 450 * Add the default or a custom menu depending on the class match 451 */ 452void 453SetupSysMenu (unsigned long hwndIn) 454{ 455 HWND hwnd; 456 HMENU sys; 457 int i; 458 WindowPtr pWin; 459 char *res_name, *res_class; 460 461 hwnd = (HWND)hwndIn; 462 if (!hwnd) 463 return; 464 465 pWin = GetProp (hwnd, WIN_WINDOW_PROP); 466 467 sys = GetSystemMenu (hwnd, FALSE); 468 if (!sys) 469 return; 470 471 if (pWin) 472 { 473 /* First see if there's a class match... */ 474 if (winMultiWindowGetClassHint (pWin, &res_name, &res_class)) 475 { 476 for (i=0; i<pref.sysMenuItems; i++) 477 { 478 if (!strcmp(pref.sysMenu[i].match, res_name) || 479 !strcmp(pref.sysMenu[i].match, res_class) ) 480 { 481 free(res_name); 482 free(res_class); 483 484 MakeMenu (pref.sysMenu[i].menuName, sys, 485 pref.sysMenu[i].menuPos==AT_START?0:-1); 486 return; 487 } 488 } 489 490 /* No match, just free alloc'd strings */ 491 free(res_name); 492 free(res_class); 493 } /* Found wm_class */ 494 } /* if pwin */ 495 496 /* Fallback to system default */ 497 if (pref.defaultSysMenuName[0]) 498 { 499 if (pref.defaultSysMenuPos==AT_START) 500 MakeMenu (pref.defaultSysMenuName, sys, 0); 501 else 502 MakeMenu (pref.defaultSysMenuName, sys, -1); 503 } 504} 505#endif 506 507 508/* 509 * Possibly add a menu to the toolbar icon 510 */ 511void 512SetupRootMenu (unsigned long hmenuRoot) 513{ 514 HMENU root; 515 516 root = (HMENU)hmenuRoot; 517 if (!root) 518 return; 519 520 if (pref.rootMenuName[0]) 521 { 522 MakeMenu(pref.rootMenuName, root, 0); 523 } 524} 525 526 527/* 528 * Check for and return an overridden default ICON specified in the prefs 529 */ 530unsigned long 531winOverrideDefaultIcon(int size) 532{ 533 HICON hicon; 534 535 if (pref.defaultIconName[0]) 536 { 537 hicon = LoadImageComma (pref.defaultIconName, size, size, 0); 538 if (hicon==NULL) 539 ErrorF ("winOverrideDefaultIcon: LoadImageComma(%s) failed\n", 540 pref.defaultIconName); 541 542 return (unsigned long)hicon; 543 } 544 545 return 0; 546} 547 548 549/* 550 * Return the HICON to use in the taskbar notification area 551 */ 552unsigned long 553winTaskbarIcon(void) 554{ 555 HICON hicon; 556 557 hicon = 0; 558 /* First try and load an overridden, if success then return it */ 559 if (pref.trayIconName[0]) 560 { 561 hicon = LoadImageComma (pref.trayIconName, 562 GetSystemMetrics (SM_CXSMICON), 563 GetSystemMetrics (SM_CYSMICON), 564 0 ); 565 } 566 567 /* Otherwise return the default */ 568 if (!hicon) 569 hicon = (HICON) LoadImage (g_hInstance, 570 MAKEINTRESOURCE(IDI_XWIN), 571 IMAGE_ICON, 572 GetSystemMetrics (SM_CXSMICON), 573 GetSystemMetrics (SM_CYSMICON), 574 0); 575 576 return (unsigned long)hicon; 577} 578 579 580/* 581 * Parse a filename to extract an icon: 582 * If fname is exactly ",nnn" then extract icon from our resource 583 * else if it is "file,nnn" then extract icon nnn from that file 584 * else try to load it as an .ico file and if that fails return NULL 585 */ 586static HICON 587LoadImageComma (char *fname, int sx, int sy, int flags) 588{ 589 HICON hicon; 590 int index; 591 char file[PATH_MAX+NAME_MAX+2]; 592 593 /* Some input error checking */ 594 if (!fname || !fname[0]) 595 return NULL; 596 597 index = 0; 598 hicon = NULL; 599 600 if (fname[0]==',') 601 { 602 /* It's the XWIN.EXE resource they want */ 603 index = atoi (fname+1); 604 hicon = LoadImage (g_hInstance, 605 MAKEINTRESOURCE(index), 606 IMAGE_ICON, 607 sx, 608 sy, 609 flags); 610 } 611 else 612 { 613 file[0] = 0; 614 /* Prepend path if not given a "X:\" filename */ 615 if ( !(fname[0] && fname[1]==':' && fname[2]=='\\') ) 616 { 617 strcpy (file, pref.iconDirectory); 618 if (pref.iconDirectory[0]) 619 if (fname[strlen(fname)-1]!='\\') 620 strcat (file, "\\"); 621 } 622 strcat (file, fname); 623 624 if (strrchr (file, ',')) 625 { 626 /* Specified as <fname>,<index> */ 627 628 *(strrchr (file, ',')) = 0; /* End string at comma */ 629 index = atoi (strrchr (fname, ',') + 1); 630 hicon = ExtractIcon (g_hInstance, file, index); 631 } 632 else 633 { 634 /* Just an .ico file... */ 635 636 hicon = (HICON)LoadImage (NULL, 637 file, 638 IMAGE_ICON, 639 sx, 640 sy, 641 LR_LOADFROMFILE|flags); 642 } 643 } 644 return hicon; 645} 646 647/* 648 * Check for a match of the window class to one specified in the 649 * ICONS{} section in the prefs file, and load the icon from a file 650 */ 651unsigned long 652winOverrideIcon (unsigned long longWin) 653{ 654 WindowPtr pWin = (WindowPtr) longWin; 655 char *res_name, *res_class; 656 int i; 657 HICON hicon; 658 char *wmName; 659 660 if (pWin==NULL) 661 return 0; 662 663 /* If we can't find the class, we can't override from default! */ 664 if (!winMultiWindowGetClassHint (pWin, &res_name, &res_class)) 665 return 0; 666 667 winMultiWindowGetWMName (pWin, &wmName); 668 669 for (i=0; i<pref.iconItems; i++) { 670 if (!strcmp(pref.icon[i].match, res_name) || 671 !strcmp(pref.icon[i].match, res_class) || 672 (wmName && strstr(wmName, pref.icon[i].match))) 673 { 674 free (res_name); 675 free (res_class); 676 if (wmName) 677 free (wmName); 678 679 if (pref.icon[i].hicon) 680 return pref.icon[i].hicon; 681 682 hicon = LoadImageComma (pref.icon[i].iconFile, 0, 0, LR_DEFAULTSIZE); 683 if (hicon==NULL) 684 ErrorF ("winOverrideIcon: LoadImageComma(%s) failed\n", 685 pref.icon[i].iconFile); 686 687 pref.icon[i].hicon = (unsigned long)hicon; 688 return (unsigned long)hicon; 689 } 690 } 691 692 /* Didn't find the icon, fail gracefully */ 693 free (res_name); 694 free (res_class); 695 if (wmName) 696 free (wmName); 697 698 return 0; 699} 700 701 702/* 703 * Should we free this icon or leave it in memory (is it part of our 704 * ICONS{} overrides)? 705 */ 706int 707winIconIsOverride(unsigned hiconIn) 708{ 709 HICON hicon; 710 int i; 711 712 hicon = (HICON)hiconIn; 713 714 if (!hicon) 715 return 0; 716 717 for (i=0; i<pref.iconItems; i++) 718 if ((HICON)pref.icon[i].hicon == hicon) 719 return 1; 720 721 return 0; 722} 723 724 725 726/* 727 * Try and open ~/.XWinrc and /usr/X11R6/lib/X11/system.XWinrc 728 * Load it into prefs structure for use by other functions 729 */ 730void 731LoadPreferences () 732{ 733 char *home; 734 char fname[PATH_MAX+NAME_MAX+2]; 735 FILE *prefFile; 736 char szDisplay[512]; 737 char *szEnvDisplay; 738 int i, j; 739 char param[PARAM_MAX+1]; 740 char *srcParam, *dstParam; 741 742 /* First, clear all preference settings */ 743 memset (&pref, 0, sizeof(pref)); 744 prefFile = NULL; 745 746 /* Now try and find a ~/.xwinrc file */ 747 home = getenv ("HOME"); 748 if (home) 749 { 750 strcpy (fname, home); 751 if (fname[strlen(fname)-1]!='/') 752 strcat (fname, "/"); 753 strcat (fname, ".XWinrc"); 754 755 prefFile = fopen (fname, "r"); 756 if (prefFile) 757 ErrorF ("winPrefsLoadPreferences: %s\n", fname); 758 } 759 760 /* No home file found, check system default */ 761 if (!prefFile) 762 { 763 char buffer[MAX_PATH]; 764#ifdef RELOCATE_PROJECTROOT 765 snprintf(buffer, sizeof(buffer), "%s\\system.XWinrc", winGetBaseDir()); 766#else 767 strncpy(buffer, PROJECTROOT"/lib/X11/system.XWinrc", sizeof(buffer)); 768#endif 769 buffer[sizeof(buffer)-1] = 0; 770 prefFile = fopen (buffer, "r"); 771 if (prefFile) 772 ErrorF ("winPrefsLoadPreferences: %s\n", buffer); 773 } 774 775 /* If we could open it, then read the settings and close it */ 776 if (prefFile) 777 { 778 parse_file (prefFile); 779 fclose (prefFile); 780 } 781 782 /* Setup a DISPLAY environment variable, need to allocate on heap */ 783 /* because putenv doesn't copy the argument... */ 784 snprintf (szDisplay, 512, "DISPLAY=127.0.0.1:%s.0", display); 785 szEnvDisplay = (char *)(malloc (strlen(szDisplay)+1)); 786 if (szEnvDisplay) 787 { 788 strcpy (szEnvDisplay, szDisplay); 789 putenv (szEnvDisplay); 790 } 791 792 /* Replace any "%display%" in menu commands with display string */ 793 snprintf (szDisplay, 512, "127.0.0.1:%s.0", display); 794 for (i=0; i<pref.menuItems; i++) 795 { 796 for (j=0; j<pref.menu[i].menuItems; j++) 797 { 798 if (pref.menu[i].menuItem[j].cmd==CMD_EXEC) 799 { 800 srcParam = pref.menu[i].menuItem[j].param; 801 dstParam = param; 802 while (*srcParam) { 803 if (!strncmp(srcParam, "%display%", 9)) 804 { 805 memcpy (dstParam, szDisplay, strlen(szDisplay)); 806 dstParam += strlen(szDisplay); 807 srcParam += 9; 808 } 809 else 810 { 811 *dstParam = *srcParam; 812 dstParam++; 813 srcParam++; 814 } 815 } 816 *dstParam = 0; 817 strcpy (pref.menu[i].menuItem[j].param, param); 818 } /* cmd==cmd_exec */ 819 } /* for all menuitems */ 820 } /* for all menus */ 821 822} 823