- More heapification. - Split drive code into core, UI and autodetect. - Implement drive autodetection. - Slight redesign of drive tab. - Code cleanup.
diff --git a/programs/winecfg/En.rc b/programs/winecfg/En.rc index c6cdb5a..7f9d55a 100644 --- a/programs/winecfg/En.rc +++ b/programs/winecfg/En.rc
@@ -26,23 +26,23 @@ IDD_ABOUTCFG DIALOGEX 0, 0, 260, 250 STYLE WS_CHILD -FONT 8, "MS Shell Dlg" +FONT 8, "MS Sans Serif" BEGIN LTEXT "Wine Version:",IDC_STATIC,119,17,55,8 LTEXT "CVS",IDC_WINEVER,179,17,56,8 CONTROL IDB_WINE,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE | WS_BORDER,15,17,157,111, WS_EX_TRANSPARENT LTEXT "http://www.winehq.org/",IDC_STATIC,119,31,106,8 - GROUPBOX "Information",IDC_STATIC,8,4,244,106 + GROUPBOX " Information ",IDC_STATIC,8,4,244,106 CTEXT "This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.", IDC_STATIC,119,44,124,59 END IDD_APPCFG DIALOG DISCARDABLE 0, 0, 260, 250 STYLE WS_CHILD | WS_DISABLED -FONT 8, "MS Shell Dlg" +FONT 8, "MS Sans Serif" BEGIN - GROUPBOX "Application Settings",IDC_STATIC, 8,4,244,240 + GROUPBOX " Application Settings ",IDC_STATIC, 8,4,244,240 LTEXT "Wine can mimic different Windows versions for each application.", IDC_STATIC,15,20,227,20 CONTROL "Applications",IDC_APP_LISTVIEW,"SysListView32",WS_BORDER | WS_TABSTOP | LVS_LIST | LVS_SINGLESEL | LVS_SHOWSELALWAYS, @@ -57,7 +57,7 @@ IDD_GRAPHCFG DIALOG DISCARDABLE 0, 0, 260, 250 STYLE WS_CHILD | WS_DISABLED -FONT 8, "MS Shell Dlg" +FONT 8, "MS Sans Serif" BEGIN LTEXT "Screen color depth: ",IDC_STATIC,8,10,70,30 COMBOBOX IDC_SCREEN_DEPTH,80,8,170,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP @@ -81,9 +81,9 @@ IDD_DLLCFG DIALOG DISCARDABLE 0, 0, 260, 250 STYLE WS_CHILD | WS_DISABLED -FONT 8, "MS Shell Dlg" +FONT 8, "MS Sans Serif" BEGIN - GROUPBOX "DLL Overrides",IDC_STATIC,8,4,244,240 + GROUPBOX " DLL Overrides ",IDC_STATIC,8,4,244,240 LTEXT "Dynamic Link Libraries can be specified individually to be either builtin (provided by Wine) or native (taken from Windows or provided by the application)." , IDC_STATIC,15,17,228,32 LISTBOX IDC_DLLS_LIST,15,50,142,187,WS_BORDER | WS_TABSTOP | WS_VSCROLL @@ -98,62 +98,44 @@ PUSHBUTTON "&Remove DLL override",IDC_DLLS_REMOVEDLL,163,224,82,14 END -IDD_SYSTEMCFG DIALOG DISCARDABLE 0, 0, 260, 250 -STYLE WS_CHILD -FONT 8, "MS Shell Dlg" -BEGIN - GROUPBOX "Drives",IDC_STATIC,8,4,244,120 - LISTBOX IDC_LIST_DRIVES,15,23,179,90,WS_VSCROLL - PUSHBUTTON "&Add",IDC_DRIVE_ADD,197,22,50,22 - PUSHBUTTON "&Remove",IDC_DRIVE_REMOVE,197,51,50,22 - PUSHBUTTON "&Edit",IDC_DRIVE_EDIT,197,80,50,22 -END - IDD_DRIVECFG DIALOG DISCARDABLE 0, 0, 260, 250 STYLE WS_CHILD | WS_DISABLED -FONT 8, "MS Shell Dlg" +FONT 8, "MS Sans Serif" BEGIN - GROUPBOX "Drive Mappings",IDC_STATIC,7,107,246,112 - LISTBOX IDC_LIST_DRIVES,14,118,232,76,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Add...",IDC_BUTTON_ADD,14,199,37,14 - PUSHBUTTON "Remove",IDC_BUTTON_REMOVE,55,199,37,14 - PUSHBUTTON "Edit...",IDC_BUTTON_EDIT,97,199,37,14 - PUSHBUTTON "Autodetect...",IDC_BUTTON_AUTODETECT,197,199,49,14 - LTEXT "WARNING: You don't seem to have a C drive defined. Click 'Add Drive' to add one.", IDS_DRIVE_NO_C, 7,223,250,110 -END + GROUPBOX " Drive mappings ",IDC_STATIC,8,4,244,240 + LISTBOX IDC_LIST_DRIVES,15,18,232,76,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Add...",IDC_BUTTON_ADD,15,98,37,14 + PUSHBUTTON "&Remove",IDC_BUTTON_REMOVE,56,98,37,14 + PUSHBUTTON "Auto&detect...",IDC_BUTTON_AUTODETECT,197,98,49,14 -IDD_DRIVE_EDIT DIALOG DISCARDABLE 0, 0, 203, 169 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Drive Configuration" -FONT 8, "MS Shell Dlg" -BEGIN - DEFPUSHBUTTON "&Ok",ID_BUTTON_OK,145,150,50,16 - LTEXT "Letter:",IDC_STATIC,5,23,26,9 - EDITTEXT IDC_EDIT_LABEL,63,108,78,13,ES_AUTOHSCROLL - LTEXT "Label:",IDC_STATIC_LABEL,33,111,29,12 - LTEXT "Serial:",IDC_STATIC_SERIAL,33,127,29,12 - EDITTEXT IDC_EDIT_SERIAL,63,124,78,13,ES_AUTOHSCROLL - LTEXT "Type:",IDC_STATIC_TYPE,5,39,21,10 - EDITTEXT IDC_EDIT_PATH,31,5,117,13,ES_AUTOHSCROLL - LTEXT "Path:",IDC_STATIC,5,8,20,9 - COMBOBOX IDC_COMBO_LETTER,31,20,77,60,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Browse...",IDC_BUTTON_BROWSE_PATH,154,5,40,13 - COMBOBOX IDC_COMBO_TYPE,31,36,77,60,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Show Advanced",IDC_BUTTON_SHOW_HIDE_ADVANCED,134,34,60,16 - CONTROL "Autodetect from Device:",IDC_RADIO_AUTODETECT,"Button", - BS_AUTORADIOBUTTON,21,69,93,10 - EDITTEXT IDC_EDIT_DEVICE,33,79,108,13,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BUTTON_BROWSE_DEVICE,148,79,40,13 - CONTROL "Manually Assign:",IDC_RADIO_ASSIGN,"Button", - BS_AUTORADIOBUTTON,21,98,69,10 - GROUPBOX "Label and serial number",IDC_BOX_LABELSERIAL,6,58,189,85 + /* editing drive details */ + LTEXT "&Path:",IDC_STATIC,15,123,20,9 + EDITTEXT IDC_EDIT_PATH,41,120,160,13,ES_AUTOHSCROLL | WS_TABSTOP + PUSHBUTTON "&Browse...",IDC_BUTTON_BROWSE_PATH,206,120,40,13 + + LTEXT "&Type:",IDC_STATIC_TYPE,15,138,21,10 + COMBOBOX IDC_COMBO_TYPE,41,135,77,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT "Label and serial number",IDC_LABELSERIAL_STATIC,15,155,55,10 + + PUSHBUTTON "&Show Advanced",IDC_BUTTON_SHOW_HIDE_ADVANCED,186,136,60,13 + CONTROL "Autodetect &from Device:",IDC_RADIO_AUTODETECT,"Button", + BS_AUTORADIOBUTTON,15,166,93,10 + EDITTEXT IDC_EDIT_DEVICE,27,176,174,13,ES_AUTOHSCROLL + PUSHBUTTON "Bro&wse...",IDC_BUTTON_BROWSE_DEVICE,206,176,40,13 + CONTROL "&Manually Assign:",IDC_RADIO_ASSIGN,"Button", + BS_AUTORADIOBUTTON,15,195,69,10 + + LTEXT "&Label:",IDC_STATIC_LABEL,33,208,29,12 + EDITTEXT IDC_EDIT_LABEL,63,205,78,13,ES_AUTOHSCROLL | WS_TABSTOP + LTEXT "S&erial:",IDC_STATIC_SERIAL,33,225,29,12 + EDITTEXT IDC_EDIT_SERIAL,63,221,78,13,ES_AUTOHSCROLL | WS_TABSTOP + END IDD_AUDIOCFG DIALOG DISCARDABLE 0, 0, 260, 250 STYLE WS_CHILD | WS_DISABLED -FONT 8, "MS Shell Dlg" +FONT 8, "MS Sans Serif" BEGIN LTEXT "Audio driver: ",IDC_STATIC,10,20,60,8 COMBOBOX IDC_AUDIO_DRIVER,70,18,85,85,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
diff --git a/programs/winecfg/Makefile.in b/programs/winecfg/Makefile.in index b5de0ea..91639a6 100644 --- a/programs/winecfg/Makefile.in +++ b/programs/winecfg/Makefile.in
@@ -10,6 +10,8 @@ appdefaults.c \ audio.c \ drive.c \ + drivedetect.c \ + driveui.c \ libraries.c \ main.c \ properties.c \
diff --git a/programs/winecfg/appdefaults.c b/programs/winecfg/appdefaults.c index 610bdac..4a36665 100644 --- a/programs/winecfg/appdefaults.c +++ b/programs/winecfg/appdefaults.c
@@ -105,7 +105,7 @@ SendDlgItemMessage(dialog, IDC_DOSVER, CB_RESETCONTENT, 0, 0); /* add the default entries (automatic) which correspond to no setting */ - if (currentApp) + if (current_app) { SendDlgItemMessage(dialog, IDC_WINVER, CB_ADDSTRING, 0, (LPARAM) "Use global settings"); SendDlgItemMessage(dialog, IDC_DOSVER, CB_ADDSTRING, 0, (LPARAM) "Use global settings"); @@ -173,7 +173,7 @@ size = sizeof(appname); while (RegEnumKeyEx(key, i, appname, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { - add_listview_item(listview, appname, strdup(appname)); + add_listview_item(listview, appname, strdupA(appname)); i++; size = sizeof(appname); @@ -219,7 +219,7 @@ static void on_selection_change(HWND dialog, HWND listview) { LVITEM item; - char *oldapp = currentApp; + char *oldapp = current_app; WINE_TRACE("()\n"); @@ -230,23 +230,23 @@ ListView_GetItem(listview, &item); - currentApp = (char *) item.lParam; + current_app = (char *) item.lParam; - if (currentApp) + if (current_app) { - WINE_TRACE("currentApp is now %s\n", currentApp); + WINE_TRACE("current_app is now %s\n", current_app); enable(IDC_APP_REMOVEAPP); } else { - WINE_TRACE("currentApp=NULL, editing global settings\n"); + WINE_TRACE("current_app=NULL, editing global settings\n"); /* focus will never be on the button in this callback so it's safe */ disable(IDC_APP_REMOVEAPP); } /* reset the combo boxes if we changed from/to global/app-specific */ - if ((oldapp && !currentApp) || (!oldapp && currentApp)) + if ((oldapp && !current_app) || (!oldapp && current_app)) init_comboboxes(dialog); update_comboboxes(dialog); @@ -276,12 +276,12 @@ HWND listview = GetDlgItem(dialog, IDC_APP_LISTVIEW); int count = ListView_GetItemCount(listview); - if (currentApp) free(currentApp); - currentApp = strdup(filetitle); + if (current_app) HeapFree(GetProcessHeap(), 0, current_app); + current_app = strdupA(filetitle); - WINE_TRACE("adding %s\n", currentApp); + WINE_TRACE("adding %s\n", current_app); - add_listview_item(listview, currentApp, currentApp); + add_listview_item(listview, current_app, current_app); ListView_SetItemState(listview, count, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); @@ -375,9 +375,11 @@ break; case WM_COMMAND: - switch(HIWORD(wParam)) { + switch(HIWORD(wParam)) + { case CBN_SELCHANGE: - switch(LOWORD(wParam)) { + switch(LOWORD(wParam)) + { case IDC_WINVER: on_winver_change(hDlg); break; @@ -386,7 +388,8 @@ break; } case BN_CLICKED: - switch(LOWORD(wParam)) { + switch(LOWORD(wParam)) + { case IDC_APP_ADDAPP: on_add_app_click(hDlg); break;
diff --git a/programs/winecfg/drive.c b/programs/winecfg/drive.c index d59b239..01c8349 100644 --- a/programs/winecfg/drive.c +++ b/programs/winecfg/drive.c
@@ -1,8 +1,8 @@ /* - * Drive management UI code + * Drive management code * * Copyright 2003 Mark Westcott - * Copyright 2003 Mike Hearn + * Copyright 2003-2004 Mike Hearn * Copyright 2004 Chris Morgan * * This library is free software; you can redistribute it and/or @@ -21,10 +21,6 @@ * */ -/* TODO: */ -/* - Support for devices(not sure what this means) */ -/* - Various autodetections */ - #include <assert.h> #include <stdarg.h> #include <stdlib.h> @@ -47,30 +43,50 @@ WINE_DEFAULT_DEBUG_CHANNEL(winecfg); -typedef struct drive_entry_s -{ - char letter; - char *unixpath; - char *label; - char *serial; - uint type; +struct drive drives[26]; /* one for each drive letter */ - BOOL in_use; -} drive_entry_t; - -static BOOL updatingUI = FALSE; -static drive_entry_t* editDriveEntry; -static int lastSel = 0; /* the last drive selected in the property sheet */ -drive_entry_t drives[26]; /* one for each drive letter */ - -int getDrive(char letter) +static inline int letter_to_index(char letter) { return (toupper(letter) - 'A'); } -BOOL addDrive(char letter, char *targetpath, char *label, char *serial, uint type) +/* This function produces a mask for each drive letter that isn't + * currently used. Each bit of the long result represents a letter, + * with A being the least significant bit, and Z being the most + * significant. + * + * To calculate this, we loop over each letter, and see if we can get + * a drive entry for it. If so, we set the appropriate bit. At the + * end, we flip each bit, to give the desired result. + * + * The letter parameter is always marked as being available. This is + * so the edit dialog can display the currently used drive letter + * alongside the available ones. + */ +long drive_available_mask(char letter) { - int driveIndex = getDrive(letter); + long result = 0; + int i; + + WINE_TRACE("\n"); + + + for(i = 0; i < 26; i++) + { + if (!drives[i].in_use) continue; + result |= (1 << (toupper(drives[i].letter) - 'A')); + } + + result = ~result; + if (letter) result |= DRIVE_MASK_BIT(letter); + + WINE_TRACE("finished drive letter loop with %lx\n", result); + return result; +} + +BOOL add_drive(char letter, char *targetpath, char *label, char *serial, uint type) +{ + int driveIndex = letter_to_index(letter); if(drives[driveIndex].in_use) return FALSE; @@ -79,48 +95,32 @@ letter, targetpath, label, serial, type); drives[driveIndex].letter = toupper(letter); - drives[driveIndex].unixpath = strdup(targetpath); - drives[driveIndex].label = strdup(label); - drives[driveIndex].serial = strdup(serial); + drives[driveIndex].unixpath = strdupA(targetpath); + drives[driveIndex].label = strdupA(label); + drives[driveIndex].serial = strdupA(serial); drives[driveIndex].type = type; drives[driveIndex].in_use = TRUE; return TRUE; } -/* frees up the memory associated with a drive and returns the */ -/* pNext of the given drive entry */ -void freeDrive(drive_entry_t *pDrive) +/* deallocates the contents of the drive. does not free the drive itself */ +void delete_drive(struct drive *d) { - free(pDrive->unixpath); - free(pDrive->label); - free(pDrive->serial); + HeapFree(GetProcessHeap(), 0, d->unixpath); + HeapFree(GetProcessHeap(), 0, d->label); + HeapFree(GetProcessHeap(), 0, d->serial); - pDrive->in_use = FALSE; + d->in_use = FALSE; } -void setDriveLabel(drive_entry_t *pDrive, char *label) -{ - WINE_TRACE("pDrive->letter '%c', label = '%s'\n", pDrive->letter, label); - free(pDrive->label); - pDrive->label = strdup(label); -} +#if 0 -void setDriveSerial(drive_entry_t *pDrive, char *serial) -{ - WINE_TRACE("pDrive->letter '%c', serial = '%s'\n", pDrive->letter, serial); - free(pDrive->serial); - pDrive->serial = strdup(serial); -} +/* currently unused, but if users have this burning desire to be able to rename drives, + we can put it back in. + */ -void setDrivePath(drive_entry_t *pDrive, char *path) -{ - WINE_TRACE("pDrive->letter '%c', path = '%s'\n", pDrive->letter, path); - free(pDrive->unixpath); - pDrive->unixpath = strdup(path); -} - -BOOL copyDrive(drive_entry_t *pSrc, drive_entry_t *pDst) +BOOL copyDrive(struct drive *pSrc, struct drive *pDst) { if(pDst->in_use) { @@ -132,16 +132,16 @@ if(!pSrc->label) WINE_TRACE("!pSrc->label\n"); if(!pSrc->serial) WINE_TRACE("!pSrc->serial\n"); - pDst->unixpath = strdup(pSrc->unixpath); - pDst->label = strdup(pSrc->label); - pDst->serial = strdup(pSrc->serial); + pDst->unixpath = strdupA(pSrc->unixpath); + pDst->label = strdupA(pSrc->label); + pDst->serial = strdupA(pSrc->serial); pDst->type = pSrc->type; pDst->in_use = TRUE; return TRUE; } -BOOL moveDrive(drive_entry_t *pSrc, drive_entry_t *pDst) +BOOL moveDrive(struct drive *pSrc, struct drive *pDst) { WINE_TRACE("pSrc->letter == %c, pDst->letter == %c\n", pSrc->letter, pDst->letter); @@ -151,650 +151,116 @@ return FALSE; } - freeDrive(pSrc); + delete_drive(pSrc); return TRUE; } -int refreshDriveDlg (HWND dialog) -{ - int driveCount = 0; - int doesDriveCExist = FALSE; - int i; - - WINE_TRACE("\n"); - - updatingUI = TRUE; - - /* Clear the listbox */ - SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_RESETCONTENT, 0, 0); - - for(i = 0; i < 26; i++) - { - char *title = 0; - int titleLen; - int itemIndex; - - /* skip over any unused drives */ - if(!drives[i].in_use) - continue; - - if(drives[i].letter == 'C') - doesDriveCExist = TRUE; - - titleLen = snprintf(title, 0, "Drive %c:\\ %s", 'A' + i, - drives[i].unixpath); - titleLen++; /* add a byte for the trailing null */ - - title = malloc(titleLen); - - /* the %s in the item label will be replaced by the drive letter, so -1, then - -2 for the second %s which will be expanded to the label, finally + 1 for terminating #0 */ - snprintf(title, titleLen, "Drive %c:\\ %s", 'A' + i, - drives[i].unixpath); - - WINE_TRACE("title is '%s'\n", title); - - /* the first SendMessage call adds the string and returns the index, the second associates that index with it */ - itemIndex = SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_ADDSTRING ,(WPARAM) -1, (LPARAM) title); - SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_SETITEMDATA, itemIndex, (LPARAM) &drives[i]); - - free(title); - driveCount++; - } - - WINE_TRACE("loaded %d drives\n", driveCount); - SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_SETSEL, TRUE, lastSel); - - /* show the warning if there is no Drive C */ - if (!doesDriveCExist) - ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL); - else - ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE); - - /* disable or enable controls depending on whether we are editing global vs app specific config */ - if (currentApp) { - WINE_TRACE("enabling controls\n"); - enable(IDC_LIST_DRIVES); - enable(IDC_BUTTON_ADD); - enable(IDC_BUTTON_REMOVE); - enable(IDC_BUTTON_EDIT); - enable(IDC_BUTTON_AUTODETECT); - } else { - WINE_TRACE("disabling controls\n"); - disable(IDC_LIST_DRIVES); - disable(IDC_BUTTON_ADD); - disable(IDC_BUTTON_REMOVE); - disable(IDC_BUTTON_EDIT); - disable(IDC_BUTTON_AUTODETECT); - } - - - updatingUI = FALSE; - return driveCount; -} - -/******************************************************************************/ -/* The Drive Editing Dialog */ -/******************************************************************************/ -#define DRIVE_MASK_BIT(B) 1<<(toupper(B)-'A') - -typedef struct { - const uint sCode; - const char *sDesc; -} code_desc_pair; - -static code_desc_pair type_pairs[] = { - {DRIVE_FIXED, "Local hard disk"}, - {DRIVE_REMOTE, "Network share" }, - {DRIVE_REMOVABLE, "Floppy disk"}, - {DRIVE_CDROM, "CD-ROM"} -}; -#define DRIVE_TYPE_DEFAULT 1 - - -void fill_drive_droplist(long mask, char currentLetter, HWND hDlg) -{ - int i; - int selection; - int count; - int next_letter; - char sName[4] = "A:"; - - for( i=0, count=0, selection=-1, next_letter=-1; i <= 'Z'-'A'; ++i ) { - if( mask & DRIVE_MASK_BIT('A'+i) ) { - int index; - - sName[0] = 'A' + i; - index = SendDlgItemMessage( hDlg, IDC_COMBO_LETTER, CB_ADDSTRING, 0, (LPARAM) sName ); - - if( toupper(currentLetter) == 'A' + i ) { - selection = count; - } - - if( i >= 2 && next_letter == -1){ /*default drive is first one of C-Z */ - next_letter = count; - } - - count++; - } - } - - if( selection == -1 ) { - selection = next_letter; - } - - SendDlgItemMessage( hDlg, IDC_COMBO_LETTER, CB_SETCURSEL, selection, 0 ); -} - -#define BOX_MODE_CD_ASSIGN 1 -#define BOX_MODE_CD_AUTODETECT 2 -#define BOX_MODE_NONE 3 -#define BOX_MODE_NORMAL 4 -void enable_labelserial_box(HWND dialog, int mode) -{ - WINE_TRACE("mode=%d\n", mode); - switch (mode) { - case BOX_MODE_CD_ASSIGN: -/* enable(IDC_RADIO_AUTODETECT); */ - enable(IDC_RADIO_ASSIGN); - disable(IDC_EDIT_DEVICE); - disable(IDC_BUTTON_BROWSE_DEVICE); - enable(IDC_EDIT_SERIAL); - enable(IDC_EDIT_LABEL); - enable(IDC_STATIC_SERIAL); - enable(IDC_STATIC_LABEL); - break; - - case BOX_MODE_CD_AUTODETECT: -/* enable(IDC_RADIO_AUTODETECT); */ - enable(IDC_RADIO_ASSIGN); - enable(IDC_EDIT_DEVICE); - enable(IDC_BUTTON_BROWSE_DEVICE); - disable(IDC_EDIT_SERIAL); - disable(IDC_EDIT_LABEL); - disable(IDC_STATIC_SERIAL); - disable(IDC_STATIC_LABEL); - break; - - case BOX_MODE_NONE: - disable(IDC_RADIO_AUTODETECT); - disable(IDC_RADIO_ASSIGN); - disable(IDC_EDIT_DEVICE); - disable(IDC_BUTTON_BROWSE_DEVICE); - disable(IDC_EDIT_SERIAL); - disable(IDC_EDIT_LABEL); - disable(IDC_STATIC_SERIAL); - disable(IDC_STATIC_LABEL); - break; - - case BOX_MODE_NORMAL: - disable(IDC_RADIO_AUTODETECT); - enable(IDC_RADIO_ASSIGN); - disable(IDC_EDIT_DEVICE); - disable(IDC_BUTTON_BROWSE_DEVICE); - enable(IDC_EDIT_SERIAL); - enable(IDC_EDIT_LABEL); - enable(IDC_STATIC_SERIAL); - enable(IDC_STATIC_LABEL); - break; - } -} - -/* This function produces a mask for each drive letter that isn't currently used. Each bit of the long result - * represents a letter, with A being the least significant bit, and Z being the most significant. - * - * To calculate this, we loop over each letter, and see if we can get a drive entry for it. If so, we - * set the appropriate bit. At the end, we flip each bit, to give the desired result. - * - * The letter parameter is always marked as being available. This is so the edit dialog can display the - * currently used drive letter alongside the available ones. - */ -long drive_available_mask(char letter) -{ - long result = 0; - int i; - - WINE_TRACE("\n"); - - - for(i = 0; i < 26; i++) - { - if(!drives[i].in_use) continue; - result |= (1 << (toupper(drives[i].letter) - 'A')); - } - - result = ~result; - if (letter) result |= DRIVE_MASK_BIT(letter); - - WINE_TRACE( "finished drive letter loop with %lx\n", result ); - return result; -} - -void advancedDriveEditDialog(HWND hDlg, BOOL showAdvanced) -{ -#define ADVANCED_DELTA 120 - - static RECT okpos; - static BOOL got_initial_ok_position = FALSE; - - static RECT windowpos; /* we only use the height of this rectangle */ - static BOOL got_initial_window_position = FALSE; - - static RECT current_window; - - INT state; - INT offset; - char *text; - - if(!got_initial_ok_position) - { - POINT pt; - GetWindowRect(GetDlgItem(hDlg, ID_BUTTON_OK), &okpos); - pt.x = okpos.left; - pt.y = okpos.top; - ScreenToClient(hDlg, &pt); - okpos.right+= (pt.x - okpos.left); - okpos.bottom+= (pt.y - okpos.top); - okpos.left = pt.x; - okpos.top = pt.y; - got_initial_ok_position = TRUE; - } - - if(!got_initial_window_position) - { - GetWindowRect(hDlg, &windowpos); - got_initial_window_position = TRUE; - } - - if(showAdvanced) - { - state = SW_NORMAL; - offset = 0; - text = "Hide Advanced"; - } else - { - state = SW_HIDE; - offset = ADVANCED_DELTA; - text = "Show Advanced"; - } - - ShowWindow(GetDlgItem(hDlg, IDC_STATIC_TYPE), state); - ShowWindow(GetDlgItem(hDlg, IDC_COMBO_TYPE), state); - ShowWindow(GetDlgItem(hDlg, IDC_BOX_LABELSERIAL), state); - ShowWindow(GetDlgItem(hDlg, IDC_RADIO_AUTODETECT), state); - ShowWindow(GetDlgItem(hDlg, IDC_RADIO_ASSIGN), state); - ShowWindow(GetDlgItem(hDlg, IDC_EDIT_LABEL), state); - ShowWindow(GetDlgItem(hDlg, IDC_EDIT_DEVICE), state); - ShowWindow(GetDlgItem(hDlg, IDC_STATIC_LABEL), state); - ShowWindow(GetDlgItem(hDlg, IDC_BUTTON_BROWSE_DEVICE), state); - SetWindowPos(GetDlgItem(hDlg, ID_BUTTON_OK), - HWND_TOP, - okpos.left, okpos.top - offset, okpos.right - okpos.left, - okpos.bottom - okpos.top, - 0); - - /* resize the parent window */ - GetWindowRect(hDlg, ¤t_window); - SetWindowPos(hDlg, - HWND_TOP, - current_window.left, - current_window.top, - windowpos.right - windowpos.left, - windowpos.bottom - windowpos.top - offset, - 0); - - /* update the button text based on the state */ - SetWindowText(GetDlgItem(hDlg, IDC_BUTTON_SHOW_HIDE_ADVANCED), - text); -} - - -void refreshDriveEditDialog(HWND dialog) { - char *path; - uint type; - char *label; - char *serial; - char *device; - unsigned int i; - int selection = -1; - - updatingUI = TRUE; - - WINE_TRACE("\n"); - - /* Drive letters */ - fill_drive_droplist( drive_available_mask( editDriveEntry->letter ), editDriveEntry->letter, dialog ); - - /* path */ - path = editDriveEntry->unixpath; - if (path) { - WINE_TRACE("set path control text to '%s'\n", path); - SetWindowText(GetDlgItem(dialog, IDC_EDIT_PATH), path); - } else WINE_WARN("no Path field?\n"); - - /* drive type */ - type = editDriveEntry->type; - if (type) { - for(i = 0; i < sizeof(type_pairs)/sizeof(code_desc_pair); i++) { - SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, - (LPARAM) type_pairs[i].sDesc); - if(type_pairs[i].sCode == type){ - selection = i; - } - } - - if( selection == -1 ) selection = DRIVE_TYPE_DEFAULT; - SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0); - } else WINE_WARN("no Type field?\n"); - - - /* removeable media properties */ - label = editDriveEntry->label; - if (label) { - SendDlgItemMessage(dialog, IDC_EDIT_LABEL, WM_SETTEXT, 0,(LPARAM)label); - } else WINE_WARN("no Label field?\n"); - - /* set serial edit text */ - serial = editDriveEntry->serial; - if (serial) { - SendDlgItemMessage(dialog, IDC_EDIT_SERIAL, WM_SETTEXT, 0,(LPARAM)serial); - } else WINE_WARN("no Serial field?\n"); - - /* TODO: get the device here to put into the edit box */ - device = "Not implemented yet"; - if (device) { - SendDlgItemMessage(dialog, IDC_EDIT_DEVICE, WM_SETTEXT, 0,(LPARAM)device); - } else WINE_WARN("no Device field?\n"); - - selection = IDC_RADIO_ASSIGN; - if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE)) { -#if 0 - if (device) { - selection = IDC_RADIO_AUTODETECT; - enable_labelserial_box(dialog, BOX_MODE_CD_AUTODETECT); - } else { #endif - selection = IDC_RADIO_ASSIGN; - enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN); -#if 0 - } -#endif - } else { - enable_labelserial_box(dialog, BOX_MODE_NORMAL); - selection = IDC_RADIO_ASSIGN; - } - CheckRadioButton( dialog, IDC_RADIO_AUTODETECT, IDC_RADIO_ASSIGN, selection ); - - updatingUI = FALSE; - - return; -} - -/* storing the drive propsheet HWND here is a bit ugly, but the simplest solution for now */ -static HWND driveDlgHandle; - -void onEditChanged(HWND hDlg, WORD controlID) { - WINE_TRACE("controlID=%d\n", controlID); - switch (controlID) { - case IDC_EDIT_LABEL: { - char *label = get_control_text(hDlg, controlID); - if(!label) label = strdup(""); - setDriveLabel(editDriveEntry, label); - refreshDriveDlg(driveDlgHandle); - if (label) HeapFree(GetProcessHeap(), 0, label); - break; - } - case IDC_EDIT_PATH: { - char *path = get_control_text(hDlg, controlID); - if (!path) path = strdup("fake_windows"); /* default to assuming fake_windows in the .wine directory */ - WINE_TRACE("got path from control of '%s'\n", path); - setDrivePath(editDriveEntry, path); - if (path) HeapFree(GetProcessHeap(), 0, path); - break; - } - case IDC_EDIT_SERIAL: { - char *serial = get_control_text(hDlg, controlID); - if(!serial) serial = strdup(""); - setDriveSerial(editDriveEntry, serial); - if (serial) HeapFree(GetProcessHeap(), 0, serial); - break; - } - case IDC_EDIT_DEVICE: { - char *device = get_control_text(hDlg,controlID); - /* TODO: handle device if/when it makes sense to do so.... */ - if (device) HeapFree(GetProcessHeap(), 0, device); - refreshDriveDlg(driveDlgHandle); - break; - } - } -} - -/* edit a drive entry */ -INT_PTR CALLBACK DriveEditDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +/* Load currently defined drives into the drives array */ +void load_drives() { - int selection; - static BOOL advanced = FALSE; + char *devices, *dev; + int len; + int drivecount = 0, i; + int retval; + static const int arraysize = 512; - switch (uMsg) { - case WM_CLOSE: - EndDialog(hDlg, wParam); - return TRUE; + WINE_TRACE("\n"); - case WM_INITDIALOG: { - enable_labelserial_box(hDlg, BOX_MODE_NORMAL); - advancedDriveEditDialog(hDlg, advanced); - editDriveEntry = (drive_entry_t*)lParam; - refreshDriveEditDialog(hDlg); - } + /* FIXME: broken symlinks in $WINEPREFIX/dosdevices will not be + returned by this API, so we need to handle that */ - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_COMBO_TYPE: - if (HIWORD(wParam) != CBN_SELCHANGE) break; - selection = SendDlgItemMessage( hDlg, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0); - if( selection == 2 || selection == 3 ) { /* cdrom or floppy */ - if (IsDlgButtonChecked(hDlg, IDC_RADIO_AUTODETECT)) - enable_labelserial_box(hDlg, BOX_MODE_CD_AUTODETECT); - else - enable_labelserial_box(hDlg, BOX_MODE_CD_ASSIGN); - } - else { - enable_labelserial_box( hDlg, BOX_MODE_NORMAL ); - } - editDriveEntry->type = type_pairs[selection].sCode; - break; + /* setup the drives array */ + dev = devices = HeapAlloc(GetProcessHeap(), 0, arraysize); + len = GetLogicalDriveStrings(arraysize, devices); - case IDC_COMBO_LETTER: { - int item = SendDlgItemMessage(hDlg, IDC_COMBO_LETTER, CB_GETCURSEL, 0, 0); - char newLetter[4]; - SendDlgItemMessage(hDlg, IDC_COMBO_LETTER, CB_GETLBTEXT, item, (LPARAM) newLetter); - - if (HIWORD(wParam) != CBN_SELCHANGE) break; - if (newLetter[0] == editDriveEntry->letter) break; - - WINE_TRACE("changing drive letter to %c\n", newLetter[0]); - moveDrive(editDriveEntry, &drives[getDrive(newLetter[0])]); - editDriveEntry = &drives[getDrive(newLetter[0])]; - refreshDriveDlg(driveDlgHandle); - break; - } - - case IDC_BUTTON_BROWSE_PATH: - WRITEME(hDlg); - break; - - case IDC_RADIO_AUTODETECT: { - /* TODO: */ - WINE_FIXME("Implement autodetection\n"); - enable_labelserial_box(hDlg, BOX_MODE_CD_AUTODETECT); - refreshDriveDlg(driveDlgHandle); - break; - } - - case IDC_RADIO_ASSIGN: - { - char *edit, *serial; - edit = get_control_text(hDlg, IDC_EDIT_LABEL); - if(!edit) edit = strdup(""); - setDriveLabel(editDriveEntry, edit); - HeapFree(GetProcessHeap(), 0, edit); - - serial = get_control_text(hDlg, IDC_EDIT_SERIAL); - if(!serial) serial = strdup(""); - setDriveSerial(editDriveEntry, serial); - HeapFree(GetProcessHeap(), 0, serial); - - /* TODO: we don't have a device at this point */ -/* setDriveValue(editWindowLetter, "Device", NULL); */ - enable_labelserial_box(hDlg, BOX_MODE_CD_ASSIGN); - refreshDriveDlg(driveDlgHandle); - break; - } - - case IDC_BUTTON_SHOW_HIDE_ADVANCED: - advanced = (advanced == TRUE) ? FALSE : TRUE; /* toggle state */ - advancedDriveEditDialog(hDlg, advanced); - break; - - case ID_BUTTON_OK: - EndDialog(hDlg, wParam); - return TRUE; - - } - if (HIWORD(wParam) == EN_CHANGE) onEditChanged(hDlg, LOWORD(wParam)); - break; - } - return FALSE; -} - -void onAddDriveClicked(HWND hDlg) { - /* we should allocate a drive letter automatically. We also need - some way to let the user choose the mapping point, for now we - will just force them to enter a path automatically, with / being - the default. In future we should be able to temporarily map / - then invoke the directory chooser dialog. */ - - char newLetter = 'C'; /* we skip A and B, they are historically floppy drives */ - long mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */ - - while (mask & (1 << (newLetter - 'A'))) { - newLetter++; - if (newLetter > 'Z') { - MessageBox(NULL, "You cannot add any more drives.\n\nEach drive must have a letter, from A to Z, so you cannot have more than 26", "", MB_OK | MB_ICONEXCLAMATION); - return; - } - } - WINE_TRACE("allocating drive letter %c\n", newLetter); - - if(newLetter == 'C') { - addDrive(newLetter, "fake_windows", "System Drive", "", DRIVE_FIXED); - } else { - addDrive(newLetter, "/", "", "", DRIVE_FIXED); - } - - refreshDriveDlg(driveDlgHandle); - - DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) &(drives[getDrive(newLetter)])); -} - -void onDriveInitDialog(void) -{ - char *pDevices, *pDev; - int ret; - int i; - int retval; - - WINE_TRACE("\n"); - - /* setup the drives array */ - pDev = pDevices = malloc(512); - ret = GetLogicalDriveStrings(512, pDevices); - - /* make all devices unused */ - for(i = 0; i < 26; i++) - { - drives[i].letter = 'A' + i; - drives[i].in_use = FALSE; - } - - i = 0; - - while(ret) - { - CHAR volumeNameBuffer[512]; - DWORD serialNumber; - CHAR serialNumberString[256]; - DWORD maxComponentLength; - DWORD fileSystemFlags; - CHAR fileSystemName[128]; - char rootpath[256]; - char simplepath[3]; - int pathlen; - char targetpath[256]; - - *pDevices = toupper(*pDevices); - - WINE_TRACE("pDevices == '%s'\n", pDevices); - - volumeNameBuffer[0] = 0; - - retval = GetVolumeInformation(pDevices, - volumeNameBuffer, - sizeof(volumeNameBuffer), - &serialNumber, - &maxComponentLength, - &fileSystemFlags, - fileSystemName, - sizeof(fileSystemName)); - if(!retval) + /* make all devices unused */ + for (i = 0; i < 26; i++) { - WINE_TRACE("GetVolumeInformation() for '%s' failed, setting serialNumber to 0\n", pDevices); - PRINTERROR(); - serialNumber = 0; + drives[i].letter = 'A' + i; + drives[i].in_use = FALSE; } - WINE_TRACE("serialNumber: '0x%lX'\n", serialNumber); - - /* build rootpath for GetDriveType() */ - strncpy(rootpath, pDevices, sizeof(rootpath)); - pathlen = strlen(rootpath); - /* ensure that we have a backslash on the root path */ - if((rootpath[pathlen - 1] != '\\') && - (pathlen < sizeof(rootpath))) - { - rootpath[pathlen] = '\\'; - rootpath[pathlen + 1] = 0; - } - - strncpy(simplepath, pDevices, 2); /* QueryDosDevice() requires no trailing backslash */ - simplepath[2] = 0; - QueryDosDevice(simplepath, targetpath, sizeof(targetpath)); - - snprintf(serialNumberString, sizeof(serialNumberString), "%lX", serialNumber); - WINE_TRACE("serialNumberString: '%s'\n", serialNumberString); - addDrive(*pDevices, targetpath, volumeNameBuffer, serialNumberString, GetDriveType(rootpath)); - - ret-=strlen(pDevices); - pDevices+=strlen(pDevices); - - /* skip over any nulls */ - while((*pDevices == 0) && (ret)) + /* work backwards through the result of GetLogicalDriveStrings */ + while (len) { - ret--; - pDevices++; + char volname[512]; /* volume name */ + DWORD serial; + char serialstr[256]; + char rootpath[256]; + char simplepath[3]; + int pathlen; + char targetpath[256]; + char *c; + + *devices = toupper(*devices); + + WINE_TRACE("devices == '%s'\n", devices); + + volname[0] = 0; + + retval = GetVolumeInformation(devices, + volname, + sizeof(volname), + &serial, + NULL, + NULL, + NULL, + 0); + if(!retval) + { + WINE_ERR("GetVolumeInformation() for '%s' failed, setting serial to 0\n", devices); + PRINTERROR(); + serial = 0; + } + + WINE_TRACE("serial: '0x%lX'\n", serial); + + /* build rootpath for GetDriveType() */ + strncpy(rootpath, devices, sizeof(rootpath)); + pathlen = strlen(rootpath); + + /* ensure that we have a backslash on the root path */ + if ((rootpath[pathlen - 1] != '\\') && (pathlen < sizeof(rootpath))) + { + rootpath[pathlen] = '\\'; + rootpath[pathlen + 1] = 0; + } + + strncpy(simplepath, devices, 2); /* QueryDosDevice() requires no trailing backslash */ + simplepath[2] = 0; + QueryDosDevice(simplepath, targetpath, sizeof(targetpath)); + + /* targetpath may have forward slashes rather than backslashes, so correct */ + c = targetpath; + do if (*c == '\\') *c = '/'; while (*c++); + + snprintf(serialstr, sizeof(serialstr), "%lX", serial); + WINE_TRACE("serialstr: '%s'\n", serialstr); + add_drive(*devices, targetpath, volname, serialstr, GetDriveType(rootpath)); + + len -= strlen(devices); + devices += strlen(devices); + + /* skip over any nulls */ + while ((*devices == 0) && (len)) + { + len--; + devices++; + } + + drivecount++; } - i++; - } + WINE_TRACE("found %d drives\n", drivecount); - WINE_TRACE("found %d drives\n", i); - - free(pDev); + HeapFree(GetProcessHeap(), 0, dev); } - -void applyDriveChanges(void) +/* some of this code appears to be broken by bugs in Wine: the label + * setting code has no effect, for instance */ +void apply_drive_changes() { int i; CHAR devicename[4]; @@ -815,7 +281,7 @@ { defineDevice = FALSE; foundDrive = FALSE; - snprintf(devicename, sizeof(devicename), "%c:", 'A' + i); + snprintf(devicename, sizeof(devicename), "%c:", 'A' + i); /* get a drive */ if(QueryDosDevice(devicename, targetpath, sizeof(targetpath))) @@ -866,11 +332,13 @@ { defineDevice = TRUE; WINE_TRACE(" making changes to drive '%s'\n", devicename); - } else + } + else { WINE_TRACE(" no changes to drive '%s'\n", devicename); } - } else if(foundDrive && !drives[i].in_use) + } + else if(foundDrive && !drives[i].in_use) { /* remove this drive */ if(!DefineDosDevice(DDD_REMOVE_DEFINITION, devicename, drives[i].unixpath)) @@ -878,12 +346,14 @@ WINE_ERR("unable to remove devicename of '%s', targetpath of '%s'\n", devicename, drives[i].unixpath); PRINTERROR(); - } else + } + else { WINE_TRACE("removed devicename of '%s', targetpath of '%s'\n", devicename, drives[i].unixpath); } - } else if(drives[i].in_use) /* foundDrive must be false from the above check */ + } + else if(drives[i].in_use) /* foundDrive must be false from the above check */ { defineDevice = TRUE; } @@ -900,17 +370,18 @@ /* define this drive */ /* DefineDosDevice() requires that NO trailing slash be present */ - snprintf(devicename, sizeof(devicename), "%c:", 'A' + i); + snprintf(devicename, sizeof(devicename), "%c:", 'A' + i); if(!DefineDosDevice(DDD_RAW_TARGET_PATH, devicename, drives[i].unixpath)) { WINE_ERR(" unable to define devicename of '%s', targetpath of '%s'\n", devicename, drives[i].unixpath); PRINTERROR(); - } else + } + else { WINE_TRACE(" added devicename of '%s', targetpath of '%s'\n", devicename, drives[i].unixpath); - + /* SetVolumeLabel() requires a trailing slash */ snprintf(devicename, sizeof(devicename), "%c:\\", 'A' + i); if(!SetVolumeLabel(devicename, drives[i].label)) @@ -918,7 +389,8 @@ WINE_ERR("unable to set volume label for devicename of '%s', label of '%s'\n", devicename, drives[i].label); PRINTERROR(); - } else + } + else { WINE_TRACE(" set volume label for devicename of '%s', label of '%s'\n", devicename, drives[i].label); @@ -934,7 +406,7 @@ typeText = "floppy"; else /* must be DRIVE_CDROM */ typeText = "cdrom"; - + snprintf(driveValue, sizeof(driveValue), "%c:", toupper(drives[i].letter)); @@ -945,7 +417,8 @@ if(retval != ERROR_SUCCESS) { WINE_TRACE(" Unable to open '%s'\n", "Software\\Wine\\Drives"); - } else + } + else { retval = RegSetValueEx( hKey, @@ -958,7 +431,8 @@ { WINE_TRACE(" Unable to set value of '%s' to '%s'\n", driveValue, typeText); - } else + } + else { WINE_TRACE(" Finished setting value of '%s' to '%s'\n", driveValue, typeText); @@ -978,21 +452,22 @@ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if(hFile) + if (hFile != INVALID_HANDLE_VALUE) { WINE_TRACE(" writing serial number of '%s'\n", drives[i].serial); WriteFile(hFile, drives[i].serial, strlen(drives[i].serial), NULL, - NULL); + NULL); WriteFile(hFile, "\n", strlen("\n"), NULL, - NULL); + NULL); CloseHandle(hFile); - } else + } + else { WINE_TRACE(" CreateFile() error with file '%s'\n", filename); } @@ -1001,78 +476,7 @@ /* if this drive is in use we should free it up */ if(drives[i].in_use) { - freeDrive(&drives[i]); /* free up the string memory */ + delete_drive(&drives[i]); /* free up the string memory */ } } } - - -INT_PTR CALLBACK -DriveDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - int nItem; - drive_entry_t *pDrive; - - switch (uMsg) { - case WM_INITDIALOG: - onDriveInitDialog(); - break; - - case WM_SHOWWINDOW: - set_window_title(hDlg); - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_LIST_DRIVES: - /* double click should open the edit window for the chosen drive */ - if (HIWORD(wParam) == LBN_DBLCLK) - SendMessageA(hDlg, WM_COMMAND, IDC_BUTTON_EDIT, 0); - - if (HIWORD(wParam) == LBN_SELCHANGE) lastSel = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0); - break; - - case IDC_BUTTON_ADD: - onAddDriveClicked(hDlg); - break; - - case IDC_BUTTON_REMOVE: - if (HIWORD(wParam) != BN_CLICKED) break; - nItem = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0); - pDrive = (drive_entry_t*)SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETITEMDATA, nItem, 0); - freeDrive(pDrive); - refreshDriveDlg(driveDlgHandle); - break; - - case IDC_BUTTON_EDIT: - if (HIWORD(wParam) != BN_CLICKED) break; - nItem = SendMessage(GetDlgItem(hDlg, IDC_LIST_DRIVES), LB_GETCURSEL, 0, 0); - pDrive = (drive_entry_t*)SendMessage(GetDlgItem(hDlg, IDC_LIST_DRIVES), LB_GETITEMDATA, nItem, 0); - DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) pDrive); - break; - - case IDC_BUTTON_AUTODETECT: - WRITEME(hDlg); - break; - } - break; - - case WM_NOTIFY: switch(((LPNMHDR)lParam)->code) { - case PSN_KILLACTIVE: - WINE_TRACE("PSN_KILLACTIVE\n"); - SetWindowLong(hDlg, DWL_MSGRESULT, FALSE); - break; - case PSN_APPLY: - applyDriveChanges(); - SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR); - break; - case PSN_SETACTIVE: - driveDlgHandle = hDlg; - refreshDriveDlg (driveDlgHandle); - break; - } - break; - } - - return FALSE; -}
diff --git a/programs/winecfg/drivedetect.c b/programs/winecfg/drivedetect.c new file mode 100644 index 0000000..61b66d5 --- /dev/null +++ b/programs/winecfg/drivedetect.c
@@ -0,0 +1,252 @@ +/* + * Drive autodetection code + * + * Copyright 2004 Mike Hearn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <wine/debug.h> +#include <wine/library.h> + +#include "winecfg.h" + +#include <stdio.h> +#include <mntent.h> +#include <stdlib.h> +#include <errno.h> + +#include <sys/stat.h> + +#include <winbase.h> + +WINE_DEFAULT_DEBUG_CHANNEL(winecfg); + +BOOL gui_mode = TRUE; +static long working_mask = 0; + +static char *ignored_fstypes[] = { + "devpts", + "tmpfs", + "proc", + "sysfs", + "swap", + "usbdevfs", + "rpc_pipefs", + NULL +}; + +static BOOL should_ignore_fstype(char *type) +{ + char **s; + + for (s = ignored_fstypes; *s; s++) + if (!strcmp(*s, type)) return TRUE; + + return FALSE; +} + +static BOOL is_drive_defined(char *path) +{ + int i; + + for (i = 0; i < 26; i++) + if (drives[i].in_use && !strcmp(drives[i].unixpath, path)) return TRUE; + + return FALSE; +} + +/* returns Z + 1 if there are no more available letters */ +static char allocate_letter() +{ + char letter; + + for (letter = 'C'; letter <= 'Z'; letter++) + if ((DRIVE_MASK_BIT(letter) & working_mask) != 0) break; + + return letter; +} + +#define FSTAB_OPEN 1 +#define NO_MORE_LETTERS 2 +#define NO_ROOT 3 +#define NO_DRIVE_C 4 + +static void report_error(int code) +{ + char *buffer; + int len; + + switch (code) + { + case FSTAB_OPEN: + if (gui_mode) + { + static const char *s = "Could not open your mountpoint description table.\n\nOpening of /etc/fstab failed: %s"; + len = snprintf(NULL, 0, s, strerror(errno)); + buffer = HeapAlloc(GetProcessHeap(), 0, len + 1); + snprintf(buffer, len, s, strerror(errno)); + MessageBox(NULL, s, "", MB_OK | MB_ICONEXCLAMATION); + HeapFree(GetProcessHeap(), 0, buffer); + } + else + { + fprintf(stderr, "winecfg: could not open fstab: %s", strerror(errno)); + } + break; + + case NO_MORE_LETTERS: + if (gui_mode) MessageBox(NULL, "No more letters are available to auto-detect available drives with.", "", MB_OK | MB_ICONEXCLAMATION); + fprintf(stderr, "winecfg: no more available letters while scanning /etc/fstab"); + break; + + case NO_ROOT: + if (gui_mode) MessageBox(NULL, "Could not ensure that the root directory was mapped.\n\n" + "This can happen if you run out of drive letters. " + "It's important to have the root directory mapped, otherwise Wine" + "will not be able to always find the programs you want to run. " + "Try unmapping a drive letter then trying again.", "", + MB_OK | MB_ICONEXCLAMATION); + else fprintf(stderr, "winecfg: unable to map root drive\n"); + break; + + case NO_DRIVE_C: + if (gui_mode) + MessageBox(NULL, "No virtual drive C mapped\n\nTry running wineprefixcreate", "", MB_OK | MB_ICONEXCLAMATION); + else + fprintf(stderr, "winecfg: no drive_c directory\n"); + } + +} + +static void ensure_root_is_mapped() +{ + int i; + BOOL mapped = FALSE; + + for (i = 0; i < 26; i++) + if (drives[i].in_use && !strcmp(drives[i].unixpath, "/")) mapped = TRUE; + + if (!mapped) + { + /* work backwards from Z, trying to map it */ + char letter; + + for (letter = 'Z'; letter >= 'A'; letter--) + { + if (drives[letter - 'A'].in_use) continue; + add_drive(letter, "/", "System", 0, DRIVE_FIXED); + WINE_TRACE("allocated drive %c as the root drive\n", letter); + } + + if (letter == ('A' - 1)) report_error(NO_ROOT); + } +} + +static void ensure_drive_c_is_mapped() +{ + struct stat buf; + const char *configdir = wine_get_config_dir(); + int len; + char *drive_c_dir; + + if (drives[2].in_use) return; + + len = snprintf(NULL, 0, "%s/../drive_c", configdir); + drive_c_dir = HeapAlloc(GetProcessHeap(), 0, len); + snprintf(drive_c_dir, len, "%s/../drive_c", configdir); + HeapFree(GetProcessHeap(), 0, drive_c_dir); + + if (stat(drive_c_dir, &buf) == 0) + { + add_drive('C', "../drive_c", "Virtual Windows Drive", "0", DRIVE_FIXED); + } + else + { + report_error(NO_DRIVE_C); + } +} + +int autodetect_drives() +{ + struct mntent *ent; + FILE *fstab; + + /* we want to build a list of autodetected drives, then ensure each entry + exists in the users setup. so, we superimpose the autodetected drives + onto whatever is pre-existing. + + for now let's just rummage around inside the fstab. + */ + + load_drives(); + + working_mask = drive_available_mask('\0'); + + fstab = fopen("/etc/fstab", "r"); + if (!fstab) + { + report_error(FSTAB_OPEN); + return FALSE; + } + + while ((ent = getmntent(fstab))) + { + char letter; + char label[256]; + int type; + + WINE_TRACE("ent->mnt_dir=%s\n", ent->mnt_dir); + + if (should_ignore_fstype(ent->mnt_type)) continue; + if (is_drive_defined(ent->mnt_dir)) continue; + + /* allocate a drive for it */ + letter = allocate_letter(); + if (letter == ']') + { + report_error(NO_MORE_LETTERS); + fclose(fstab); + return FALSE; + } + + WINE_TRACE("adding drive %c for %s, type %s\n", letter, ent->mnt_dir, ent->mnt_type); + + strncpy(label, "Drive X", 8); + label[6] = letter; + + if (!strcmp(ent->mnt_type, "nfs")) type = DRIVE_REMOTE; + else if (!strcmp(ent->mnt_type, "nfs4")) type = DRIVE_REMOTE; + else if (!strcmp(ent->mnt_type, "smbfs")) type = DRIVE_REMOTE; + else if (!strcmp(ent->mnt_type, "cifs")) type = DRIVE_REMOTE; + else if (!strcmp(ent->mnt_type, "coda")) type = DRIVE_REMOTE; + else if (!strcmp(ent->mnt_type, "iso9660")) type = DRIVE_CDROM; + else if (!strcmp(ent->mnt_type, "ramfs")) type = DRIVE_RAMDISK; + else type = DRIVE_FIXED; + + add_drive(letter, ent->mnt_dir, label, "0", type); + + working_mask |= DRIVE_MASK_BIT(letter); + } + + fclose(fstab); + + ensure_root_is_mapped(); + + ensure_drive_c_is_mapped(); + + return TRUE; +}
diff --git a/programs/winecfg/driveui.c b/programs/winecfg/driveui.c new file mode 100644 index 0000000..0b99f31 --- /dev/null +++ b/programs/winecfg/driveui.c
@@ -0,0 +1,650 @@ +/* + * Drive management UI code + * + * Copyright 2003 Mark Westcott + * Copyright 2004 Chris Morgan + * Copyright 2003-2004 Mike Hearn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <stdarg.h> +#include <stdio.h> + +#include <windef.h> +#include <winbase.h> +#include <winreg.h> +#include <shellapi.h> +#include <objbase.h> +#include <shlguid.h> +#include <shlwapi.h> +#include <shlobj.h> +#include <winuser.h> + +#include <wine/debug.h> + +#include "winecfg.h" +#include "resource.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winecfg); + +#define BOX_MODE_CD_ASSIGN 1 +#define BOX_MODE_CD_AUTODETECT 2 +#define BOX_MODE_NONE 3 +#define BOX_MODE_NORMAL 4 + +static BOOL advanced = FALSE; +static BOOL updating_ui = FALSE; +static struct drive* current_drive; + +static void get_etched_rect(HWND dialog, RECT *rect); + +static void set_advanced(HWND dialog) +{ + int state; + char *text; + RECT rect; + + /* FIXME: internationalization */ + if (advanced) + { + state = SW_NORMAL; + text = "&Hide Advanced"; + } + else + { + state = SW_HIDE; + text = "&Show Advanced"; + } + + ShowWindow(GetDlgItem(dialog, IDC_RADIO_AUTODETECT), state); + ShowWindow(GetDlgItem(dialog, IDC_RADIO_ASSIGN), state); + ShowWindow(GetDlgItem(dialog, IDC_EDIT_LABEL), state); + ShowWindow(GetDlgItem(dialog, IDC_EDIT_DEVICE), state); + ShowWindow(GetDlgItem(dialog, IDC_STATIC_LABEL), state); + ShowWindow(GetDlgItem(dialog, IDC_BUTTON_BROWSE_DEVICE), state); + ShowWindow(GetDlgItem(dialog, IDC_EDIT_SERIAL), state); + ShowWindow(GetDlgItem(dialog, IDC_STATIC_SERIAL), state); + ShowWindow(GetDlgItem(dialog, IDC_LABELSERIAL_STATIC), state); + + /* update the button text based on the state */ + SetWindowText(GetDlgItem(dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED), text); + + /* redraw for the etched line */ + get_etched_rect(dialog, &rect); + InflateRect(&rect, 5, 5); + InvalidateRect(dialog, &rect, TRUE); +} + +struct drive_typemap { + const uint sCode; + const char *sDesc; +}; + +static struct drive_typemap type_pairs[] = { + { DRIVE_FIXED, "Local hard disk" }, + { DRIVE_REMOTE, "Network share" }, + { DRIVE_REMOVABLE, "Floppy disk" }, + { DRIVE_CDROM, "CD-ROM" } +}; + +#define DRIVE_TYPE_DEFAULT 1 + +void fill_drive_droplist(long mask, char curletter, HWND dialog) +{ + int i; + int selection; + int count; + int next_letter; + char sName[4] = "A:"; + + for (i = 0, count = 0, selection = -1, next_letter = -1; i <= 'Z'-'A'; ++i) + { + if (mask & DRIVE_MASK_BIT('A' + i)) + { + int index; + + sName[0] = 'A' + i; + index = SendDlgItemMessage(dialog, IDC_COMBO_LETTER, CB_ADDSTRING, 0, (LPARAM) sName); + + if (toupper(curletter) == 'A' + i) + { + selection = count; + } + + if (i >= 2 && next_letter == -1) + { + /* default drive is first one of C-Z */ + next_letter = count; + } + + count++; + } + } + + if (selection == -1) + { + selection = next_letter; + } + + SendDlgItemMessage(dialog, IDC_COMBO_LETTER, CB_SETCURSEL, selection, 0); +} + + +void enable_labelserial_box(HWND dialog, int mode) +{ + WINE_TRACE("mode=%d\n", mode); + + switch (mode) + { + case BOX_MODE_CD_ASSIGN: + enable(IDC_RADIO_ASSIGN); + disable(IDC_EDIT_DEVICE); + disable(IDC_BUTTON_BROWSE_DEVICE); + enable(IDC_EDIT_SERIAL); + enable(IDC_EDIT_LABEL); + enable(IDC_STATIC_SERIAL); + enable(IDC_STATIC_LABEL); + break; + + case BOX_MODE_CD_AUTODETECT: + enable(IDC_RADIO_ASSIGN); + enable(IDC_EDIT_DEVICE); + enable(IDC_BUTTON_BROWSE_DEVICE); + disable(IDC_EDIT_SERIAL); + disable(IDC_EDIT_LABEL); + disable(IDC_STATIC_SERIAL); + disable(IDC_STATIC_LABEL); + break; + + case BOX_MODE_NONE: + disable(IDC_RADIO_ASSIGN); + disable(IDC_EDIT_DEVICE); + disable(IDC_BUTTON_BROWSE_DEVICE); + disable(IDC_EDIT_SERIAL); + disable(IDC_EDIT_LABEL); + disable(IDC_STATIC_SERIAL); + disable(IDC_STATIC_LABEL); + break; + + case BOX_MODE_NORMAL: + enable(IDC_RADIO_ASSIGN); + disable(IDC_EDIT_DEVICE); + disable(IDC_BUTTON_BROWSE_DEVICE); + enable(IDC_EDIT_SERIAL); + enable(IDC_EDIT_LABEL); + enable(IDC_STATIC_SERIAL); + enable(IDC_STATIC_LABEL); + break; + } +} + +int fill_drives_list(HWND dialog) +{ + int count = 0; + BOOL drivec_present = FALSE; + int i; + int prevsel = -1; + + WINE_TRACE("\n"); + + updating_ui = TRUE; + + prevsel = SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0); + + /* Clear the listbox */ + SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_RESETCONTENT, 0, 0); + + for(i = 0; i < 26; i++) + { + char *title = 0; + int len; + int index; + + /* skip over any unused drives */ + if (!drives[i].in_use) + continue; + + if (drives[i].letter == 'C') + drivec_present = TRUE; + + len = snprintf(title, 0, "%c: %s", 'A' + i, + drives[i].unixpath); + len++; /* add a byte for the trailing null */ + + title = HeapAlloc(GetProcessHeap(), 0, len); + + /* the %s in the item label will be replaced by the drive letter, so -1, then + -2 for the second %s which will be expanded to the label, finally + 1 for terminating #0 */ + snprintf(title, len, "%c: %s", 'A' + i, + drives[i].unixpath); + + WINE_TRACE("title is '%s'\n", title); + + /* the first SendMessage call adds the string and returns the index, the second associates that index with it */ + index = SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_ADDSTRING ,(WPARAM) -1, (LPARAM) title); + SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_SETITEMDATA, index, (LPARAM) &drives[i]); + + HeapFree(GetProcessHeap(), 0, title); + count++; + } + + WINE_TRACE("loaded %d drives\n", count); + + /* show the warning if there is no Drive C */ + if (!drivec_present) + ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL); + else + ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE); + + SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_SETCURSEL, prevsel == -1 ? 0 : prevsel, 0); + + updating_ui = FALSE; + return count; +} + + +void on_add_click(HWND dialog) +{ + /* we should allocate a drive letter automatically. We also need + some way to let the user choose the mapping point, for now we + will just force them to enter a path automatically, with / being + the default. In future we should be able to temporarily map / + then invoke the directory chooser dialog. */ + + char new = 'C'; /* we skip A and B, they are historically floppy drives */ + long mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */ + int i, c; + + while (mask & (1 << (new - 'A'))) + { + new++; + if (new > 'Z') + { + MessageBox(dialog, "You cannot add any more drives.\n\nEach drive must have a letter, from A to Z, so you cannot have more than 26", "", MB_OK | MB_ICONEXCLAMATION); + return; + } + } + + WINE_TRACE("allocating drive letter %c\n", new); + + if (new == 'C') add_drive(new, "../drive_c", "System Drive", "", DRIVE_FIXED); + else add_drive(new, "/", "", "", DRIVE_FIXED); + + fill_drives_list(dialog); + + /* select the newly created drive */ + mask = ~drive_available_mask(0); + c = 0; + for (i = 0; i < 26; i++) + { + if ('A' + i == new) break; + if ((1 << i) & mask) c++; + } + SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_SETCURSEL, c, 0); + + SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES)); +} + +void on_remove_click(HWND dialog) +{ + int item; + struct drive *drive; + + item = SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0); + if (item == -1) return; /* no selection */ + + drive = (struct drive *) SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_GETITEMDATA, item, 0); + + if (drive->letter == 'C') + { + DWORD result = MessageBox(dialog, "Are you sure you want to delete drive C?\n\nMost Windows applications expect drive C to exist, and will die messily if it doesn't. If you proceed remember to recreate it!", "", MB_YESNO | MB_ICONEXCLAMATION); + if (result == IDNO) return; + } + + delete_drive(drive); + + fill_drives_list(dialog); + + item = item - 1; + if (item < 0) item = 0; + SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_SETCURSEL, item, 0); /* previous item */ + + SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES)); +} + +void update_controls(HWND dialog) { + char *path; + uint type; + char *label; + char *serial; + char *device; + int i, selection = -1; + + updating_ui = TRUE; + + i = SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0); + if (i == -1) + { + /* no selection? let's select something for the user. this will re-enter */ + SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_SETCURSEL, 0, 0); + return; + } + current_drive = (struct drive *) SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_GETITEMDATA, i, 0); + + WINE_TRACE("Updating sheet for drive %c\n", current_drive->letter); + + /* Drive letters */ + fill_drive_droplist(drive_available_mask(current_drive->letter), current_drive->letter, dialog); + + /* path */ + path = current_drive->unixpath; + WINE_TRACE("set path control text to '%s'\n", path); + set_text(dialog, IDC_EDIT_PATH, path); + + /* drive type */ + type = current_drive->type; + if (type) + { + for (i = 0; i < sizeof(type_pairs) / sizeof(struct drive_typemap); i++) + { + SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM) type_pairs[i].sDesc); + + if (type_pairs[i].sCode == type) + { + selection = i; + } + } + + if (selection == -1) selection = DRIVE_TYPE_DEFAULT; + SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0); + } else WINE_WARN("no Type field?\n"); + + + /* removeable media properties */ + label = current_drive->label; + set_text(dialog, IDC_EDIT_LABEL, label); + + /* set serial edit text */ + serial = current_drive->serial; + set_text(dialog, IDC_EDIT_SERIAL, serial); + + /* TODO: get the device here to put into the edit box */ + device = "Not implemented yet"; + set_text(dialog, IDC_EDIT_DEVICE, device); + device = NULL; + + selection = IDC_RADIO_ASSIGN; + if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE)) + { + if (device) + { + selection = IDC_RADIO_AUTODETECT; + enable_labelserial_box(dialog, BOX_MODE_CD_AUTODETECT); + } + else + { + selection = IDC_RADIO_ASSIGN; + enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN); + } + } + else + { + enable_labelserial_box(dialog, BOX_MODE_NORMAL); + selection = IDC_RADIO_ASSIGN; + } + + CheckRadioButton(dialog, IDC_RADIO_AUTODETECT, IDC_RADIO_ASSIGN, selection); + + updating_ui = FALSE; + + return; +} + +void on_edit_changed(HWND dialog, WORD id) +{ + if (updating_ui) return; + + WINE_TRACE("edit id %d changed\n", id); + + /* using fill_drives_list here is pretty lazy, but i'm tired + + fortunately there are only 26 letters in the alphabet, so + we don't have to worry about efficiency too much here :) */ + + switch (id) + { + case IDC_EDIT_LABEL: + { + char *label; + + label = get_text(dialog, id); + if (current_drive->label) HeapFree(GetProcessHeap(), 0, current_drive->label); + current_drive->label = label ? label : strdupA(""); + + WINE_TRACE("set label to %s\n", current_drive->label); + + fill_drives_list(dialog); + break; + } + + case IDC_EDIT_PATH: + { + char *path; + + path = get_text(dialog, id); + if (current_drive->unixpath) HeapFree(GetProcessHeap(), 0, current_drive->unixpath); + current_drive->unixpath = path ? path : strdupA("drive_c"); + + WINE_TRACE("set path to %s\n", current_drive->unixpath); + + fill_drives_list(dialog); + break; + } + + case IDC_EDIT_SERIAL: + { + char *serial; + + serial = get_text(dialog, id); + if (current_drive->serial) HeapFree(GetProcessHeap(), 0, current_drive->serial); + current_drive->serial = serial ? serial : strdupA(""); + + WINE_TRACE("set serial to %s", current_drive->serial); + + break; + } + + case IDC_EDIT_DEVICE: + { + char *device = get_text(dialog, id); + /* TODO: handle device if/when it makes sense to do so.... */ + if (device) HeapFree(GetProcessHeap(), 0, device); + fill_drives_list(dialog); + break; + } + } +} + +static void get_etched_rect(HWND dialog, RECT *rect) +{ + GetClientRect(dialog, rect); + + /* these dimensions from the labelserial static in En.rc */ + rect->top = 258; + rect->bottom = 258; + rect->left += 35; + rect->right -= 25; +} + +/* this just draws a nice line to separate the advanced gui from the n00b gui :) */ +static void paint(HWND dialog) +{ + PAINTSTRUCT ps; + + BeginPaint(dialog, &ps); + + if (advanced) + { + RECT rect; + + get_etched_rect(dialog, &rect); + + DrawEdge(ps.hdc, &rect, EDGE_ETCHED, BF_TOP); + } + + EndPaint(dialog, &ps); +} + +INT_PTR CALLBACK +DriveDlgProc (HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam) +{ + int item; + struct drive *drive; + + switch (msg) + { + case WM_INITDIALOG: + load_drives(); + + if (!drives[2].in_use) + MessageBox(dialog, "You don't have a drive C. This is not so great.\n\nRemember to click 'Add' in the Drives tab to create one!\n", "", MB_OK | MB_ICONEXCLAMATION); + + fill_drives_list(dialog); + update_controls(dialog); + /* put in non-advanced mode by default */ + set_advanced(dialog); + break; + + case WM_SHOWWINDOW: + set_window_title(dialog); + break; + + case WM_PAINT: + paint(dialog); + break; + + case WM_COMMAND: + if (HIWORD(wParam) == EN_CHANGE) + { + on_edit_changed(dialog, LOWORD(wParam)); + break; + } + + switch (LOWORD(wParam)) + { + case IDC_LIST_DRIVES: + if (HIWORD(wParam) == LBN_SELCHANGE) + update_controls(dialog); + + break; + + case IDC_BUTTON_ADD: + if (HIWORD(wParam) != BN_CLICKED) break; + on_add_click(dialog); + break; + + case IDC_BUTTON_REMOVE: + if (HIWORD(wParam) != BN_CLICKED) break; + on_remove_click(dialog); + break; + + case IDC_BUTTON_EDIT: + if (HIWORD(wParam) != BN_CLICKED) break; + item = SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_GETCURSEL, 0, 0); + drive = (struct drive *) SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_GETITEMDATA, item, 0); + /*DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) drive); */ + break; + + case IDC_BUTTON_AUTODETECT: + autodetect_drives(); + fill_drives_list(dialog); + break; + + case IDC_BUTTON_SHOW_HIDE_ADVANCED: + advanced = !advanced; + set_advanced(dialog); + break; + + case IDC_BUTTON_BROWSE_PATH: + MessageBox(dialog, "", "Write me!", MB_OK); + break; + + case IDC_RADIO_ASSIGN: + { + char *str; + + str = get_text(dialog, IDC_EDIT_LABEL); + if (current_drive->label) HeapFree(GetProcessHeap(), 0, current_drive->label); + current_drive->label = str ? str : strdupA(""); + + str = get_text(dialog, IDC_EDIT_SERIAL); + if (current_drive->serial) HeapFree(GetProcessHeap(), 0, current_drive->serial); + current_drive->serial = str ? str : strdupA(""); + + /* TODO: we don't have a device at this point */ + + enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN); + + break; + } + + + case IDC_COMBO_TYPE: + { + int mode = BOX_MODE_NORMAL; + int selection; + + if (HIWORD(wParam) != CBN_SELCHANGE) break; + + selection = SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0); + + if (selection == 2 || selection == 3) /* cdrom or floppy */ + { + if (IsDlgButtonChecked(dialog, IDC_RADIO_AUTODETECT)) + mode = BOX_MODE_CD_AUTODETECT; + else + mode = BOX_MODE_CD_ASSIGN; + } + + enable_labelserial_box(dialog, mode); + + current_drive->type = type_pairs[selection].sCode; + break; + } + + } + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) + { + case PSN_KILLACTIVE: + WINE_TRACE("PSN_KILLACTIVE\n"); + SetWindowLong(dialog, DWL_MSGRESULT, FALSE); + break; + case PSN_APPLY: + apply_drive_changes(); + SetWindowLong(dialog, DWL_MSGRESULT, PSNRET_NOERROR); + break; + case PSN_SETACTIVE: + break; + } + break; + } + + return FALSE; +}
diff --git a/programs/winecfg/resource.h b/programs/winecfg/resource.h index 2a90a88..8111854 100644 --- a/programs/winecfg/resource.h +++ b/programs/winecfg/resource.h
@@ -35,7 +35,6 @@ #define IDD_GRAPHCFG 110 #define IDD_DLLCFG 111 #define IDD_DRIVECFG 112 -#define IDD_SYSTEMCFG 113 #define IDD_DRIVE_EDIT 114 #define IDB_WINE_LOGO 200 #define IDC_TABABOUT 1001 @@ -95,13 +94,15 @@ #define IDC_RADIO_AUTODETECT 1068 #define IDC_RADIO_ASSIGN 1069 #define IDC_BUTTON_BROWSE_DEVICE 1070 -#define IDC_BOX_LABELSERIAL 1071 #define IDC_STATIC_SERIAL 1072 #define IDC_STATIC_LABEL 1073 #define IDC_ENABLE_DESKTOP 1074 #define IDS_DRIVE_NO_C 1075 #define IDC_BUTTON_SHOW_HIDE_ADVANCED 1076 #define IDC_STATIC_TYPE 1077 +#define IDC_LABELSERIAL_STATIC 1078 + +#define IDC_DRIVE_LABEL 1078 /* graphics */ #define IDC_ENABLE_MANAGED 1100
diff --git a/programs/winecfg/winecfg.c b/programs/winecfg/winecfg.c index 0d8f1b4..7e7d45e 100644 --- a/programs/winecfg/winecfg.c +++ b/programs/winecfg/winecfg.c
@@ -19,6 +19,12 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * TODO: + * - Use unicode + * - Icons in listviews/icons + * - Better add app dialog, scan c: for EXE files and add to list in background + * - Use [GNOME] HIG style groupboxes rather than win32 style (looks nicer, imho) + * */ #include <assert.h> @@ -47,11 +53,11 @@ char *newtitle; /* update the window title */ - if (currentApp) + if (current_app) { char *template = "Wine Configuration for %s"; - newtitle = HeapAlloc(GetProcessHeap(), 0, strlen(template) + strlen(currentApp) + 1); - sprintf(newtitle, template, currentApp); + newtitle = HeapAlloc(GetProcessHeap(), 0, strlen(template) + strlen(current_app) + 1); + sprintf(newtitle, template, current_app); } else { @@ -65,7 +71,7 @@ /** - * get_config_key: Retrieves a configuration value from the registry + * getkey: Retrieves a configuration value from the registry * * char *subkey : the name of the config section * char *name : the name of the config value @@ -75,7 +81,7 @@ * not. Caller is responsible for releasing the result. * */ -static char *get_config_key (char *subkey, char *name, char *def) +static char *getkey (char *subkey, char *name, char *def) { LPBYTE buffer = NULL; DWORD len; @@ -123,7 +129,7 @@ } /** - * set_config_key: convenience wrapper to set a key/value pair + * setkey: convenience wrapper to set a key/value pair * * const char *subKey : the name of the config section * const char *valueName : the name of the config value @@ -133,7 +139,7 @@ * * If valueName or value is NULL, an empty section will be created */ -int set_config_key(const char *subkey, const char *name, const char *value) { +int setkey(const char *subkey, const char *name, const char *value) { DWORD res = 1; HKEY key = NULL; @@ -252,7 +258,7 @@ } /* no, so get from the registry */ - val = get_config_key(path, name, def); + val = getkey(path, name, def); WINE_TRACE("returning %s\n", val); @@ -439,7 +445,7 @@ if (s->value) { WINE_TRACE("Setting %s:%s to '%s'\n", s->path, s->name, s->value); - set_config_key(s->path, s->name, s->value); + setkey(s->path, s->name, s->value); } else { @@ -465,7 +471,7 @@ /* ================================== utility functions ============================ */ -char *currentApp = NULL; /* the app we are currently editing, or NULL if editing global */ +char *current_app = NULL; /* the app we are currently editing, or NULL if editing global */ /* returns a registry key path suitable for passing to addTransaction */ char *keypath(char *section) @@ -474,10 +480,10 @@ if (result) HeapFree(GetProcessHeap(), 0, result); - if (currentApp) + if (current_app) { - result = HeapAlloc(GetProcessHeap(), 0, strlen("AppDefaults\\") + strlen(currentApp) + 2 /* \\ */ + strlen(section) + 1 /* terminator */); - sprintf(result, "AppDefaults\\%s\\%s", currentApp, section); + result = HeapAlloc(GetProcessHeap(), 0, strlen("AppDefaults\\") + strlen(current_app) + 2 /* \\ */ + strlen(section) + 1 /* terminator */); + sprintf(result, "AppDefaults\\%s\\%s", current_app, section); } else { @@ -494,6 +500,10 @@ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL); + + /* eliminate trailing newline, is this a Wine bug? */ + *(strrchr(msg, '\n')) = '\0'; + WINE_TRACE("error: '%s'\n", msg); }
diff --git a/programs/winecfg/winecfg.h b/programs/winecfg/winecfg.h index 2a28160..f54f543 100644 --- a/programs/winecfg/winecfg.h +++ b/programs/winecfg/winecfg.h
@@ -38,15 +38,7 @@ #define IS_OPTION_FALSE(ch) \ ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0') -#define return_if_fail(try) \ - if (!(try)) { \ - WINE_ERR("check (" #try ") at %s:%d failed, returning\n", __FILE__, __LINE__ - 1); \ - return; \ - } - -#define WRITEME(owner) MessageBox(owner, "Write me!", "", MB_OK | MB_ICONEXCLAMATION); - -extern char *currentApp; /* NULL means editing global settings */ +extern char *current_app; /* NULL means editing global settings */ /* Use get and set to alter registry settings. The changes made through set won't be committed to the registry until process_all_settings is called, @@ -55,6 +47,7 @@ You are expected to release the result of get. The parameters to set will be copied, so release them too when necessary. */ + void set(char *path, char *name, char *value); char *get(char *path, char *name, char *def); BOOL exists(char *path, char *name); @@ -62,37 +55,52 @@ char **enumerate_values(char *path); /* returns a string of the form "AppDefaults\\appname.exe\\section", or just "section" if - * the user is editing the global settings. - * - * no explicit free is needed of the string returned by this function + the user is editing the global settings. + + no explicit free is needed of the string returned by this function */ char *keypath(char *section); -/* Initializes the transaction system */ int initialize(void); extern HKEY config_key; +/* hack for the property sheet control */ void set_window_title(HWND dialog); -/* Graphics */ - -void initGraphDlg (HWND hDlg); -void saveGraphDlgSettings (HWND hDlg); +/* Window procedures */ INT_PTR CALLBACK GraphDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - -/* Drive management */ -void initDriveDlg (HWND hDlg); -void saveDriveSettings (HWND hDlg); - INT_PTR CALLBACK DriveDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK DriveEditDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - -/* Audio config dialog */ INT_PTR CALLBACK AudioDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -/* some basic utilities to make win32 suck less */ +/* Drive management */ +void load_drives(); +int autodetect_drives(); + +struct drive +{ + char letter; + char *unixpath; + char *label; + char *serial; + DWORD type; /* one of the DRIVE_ constants from winbase.h */ + + BOOL in_use; +}; + +#define DRIVE_MASK_BIT(B) 1 << (toupper(B) - 'A') + +long drive_available_mask(char letter); +BOOL add_drive(char letter, char *targetpath, char *label, char *serial, unsigned int type); +void delete_drive(struct drive *pDrive); +void apply_drive_changes(); +extern struct drive drives[26]; /* one for each drive letter */ + +BOOL gui_mode; + +/* Some basic utilities to make win32 suck less */ #define disable(id) EnableWindow(GetDlgItem(dialog, id), 0); #define enable(id) EnableWindow(GetDlgItem(dialog, id), 1); void PRINTERROR(void); /* WINE_TRACE() the plaintext error message from GetLastError() */ @@ -104,15 +112,20 @@ return strcpy(r, s); } -static inline char *get_control_text(HWND dialog, WORD id) +static inline char *get_text(HWND dialog, WORD id) { HWND item = GetDlgItem(dialog, id); int len = GetWindowTextLength(item) + 1; - char *result = HeapAlloc(GetProcessHeap(), 0, len); - if (GetWindowText(item, result, len) == 0) return NULL; + char *result = len ? HeapAlloc(GetProcessHeap(), 0, len) : NULL; + if (!result || GetWindowText(item, result, len) == 0) return NULL; return result; } -#define WINE_KEY_ROOT "Software\\Wine\\Wine\\Config" +static inline void set_text(HWND dialog, WORD id, char *text) +{ + SetWindowText(GetDlgItem(dialog, id), text); +} + +#define WINE_KEY_ROOT "Software\\Wine\\Testing\\Config" #endif
diff --git a/programs/winecfg/x11drvdlg.c b/programs/winecfg/x11drvdlg.c index 47d7477..0ac863f 100644 --- a/programs/winecfg/x11drvdlg.c +++ b/programs/winecfg/x11drvdlg.c
@@ -145,8 +145,8 @@ WINE_TRACE("\n"); - width = get_control_text(dialog, IDC_DESKTOP_WIDTH); - height = get_control_text(dialog, IDC_DESKTOP_HEIGHT); + width = get_text(dialog, IDC_DESKTOP_WIDTH); + height = get_text(dialog, IDC_DESKTOP_HEIGHT); if (strcmp(width, "") == 0) { @@ -184,7 +184,7 @@ } static void on_screen_depth_changed(HWND dialog) { - char *newvalue = get_control_text(dialog, IDC_SCREEN_DEPTH); + char *newvalue = get_text(dialog, IDC_SCREEN_DEPTH); char *spaceIndex = strchr(newvalue, ' '); WINE_TRACE("newvalue=%s\n", newvalue);