Commit 7d8711e1 authored by Mike Hearn's avatar Mike Hearn Committed by Alexandre Julliard

- More heapification.

- Split drive code into core, UI and autodetect. - Implement drive autodetection. - Slight redesign of drive tab. - Code cleanup.
parent 14de4815
......@@ -26,23 +26,23 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
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 @@ END
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 @@ END
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 @@ BEGIN
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
/* 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
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
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
......
......@@ -10,6 +10,8 @@ C_SRCS = \
appdefaults.c \
audio.c \
drive.c \
drivedetect.c \
driveui.c \
libraries.c \
main.c \
properties.c \
......
......@@ -105,7 +105,7 @@ init_comboboxes (HWND dialog)
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 @@ static void init_appsheet(HWND dialog)
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 int get_listview_selection(HWND listview)
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 @@ static void on_selection_change(HWND dialog, HWND listview)
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 @@ static void on_add_app_click(HWND dialog)
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 @@ AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
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 @@ AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
break;
}
case BN_CLICKED:
switch(LOWORD(wParam)) {
switch(LOWORD(wParam))
{
case IDC_APP_ADDAPP:
on_add_app_click(hDlg);
break;
......
/*
* 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
struct drive drives[26]; /* one for each drive letter */
static inline int letter_to_index(char letter)
{
char letter;
char *unixpath;
char *label;
char *serial;
uint type;
return (toupper(letter) - 'A');
}
BOOL in_use;
} drive_entry_t;
/* 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;
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 */
WINE_TRACE("\n");
int getDrive(char letter)
{
return (toupper(letter) - 'A');
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 addDrive(char letter, char *targetpath, char *label, char *serial, uint type)
BOOL add_drive(char letter, char *targetpath, char *label, char *serial, uint type)
{
int driveIndex = getDrive(letter);
int driveIndex = letter_to_index(letter);
if(drives[driveIndex].in_use)
return FALSE;
......@@ -79,48 +95,32 @@ BOOL addDrive(char letter, char *targetpath, char *label, char *serial, uint typ
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);
pDrive->in_use = FALSE;
}
HeapFree(GetProcessHeap(), 0, d->unixpath);
HeapFree(GetProcessHeap(), 0, d->label);
HeapFree(GetProcessHeap(), 0, d->serial);
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);
d->in_use = FALSE;
}
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);
}
#if 0
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);
}
/* currently unused, but if users have this burning desire to be able to rename drives,
we can put it back in.
*/
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 @@ BOOL copyDrive(drive_entry_t *pSrc, drive_entry_t *pDst)
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 @@ BOOL moveDrive(drive_entry_t *pSrc, drive_entry_t *pDst)
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, &current_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;
switch (uMsg) {
case WM_CLOSE:
EndDialog(hDlg, wParam);
return TRUE;
case WM_INITDIALOG: {
enable_labelserial_box(hDlg, BOX_MODE_NORMAL);
advancedDriveEditDialog(hDlg, advanced);
editDriveEntry = (drive_entry_t*)lParam;
refreshDriveEditDialog(hDlg);
}
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;
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;
char *devices, *dev;
int len;
int drivecount = 0, i;
int retval;
static const int arraysize = 512;
WINE_TRACE("\n");
/* FIXME: broken symlinks in $WINEPREFIX/dosdevices will not be
returned by this API, so we need to handle that */
/* setup the drives array */
pDev = pDevices = malloc(512);
ret = GetLogicalDriveStrings(512, pDevices);
dev = devices = HeapAlloc(GetProcessHeap(), 0, arraysize);
len = GetLogicalDriveStrings(arraysize, devices);
/* make all devices unused */
for(i = 0; i < 26; i++)
for (i = 0; i < 26; i++)
{
drives[i].letter = 'A' + i;
drives[i].in_use = FALSE;
}
i = 0;
while(ret)
/* work backwards through the result of GetLogicalDriveStrings */
while (len)
{
CHAR volumeNameBuffer[512];
DWORD serialNumber;
CHAR serialNumberString[256];
DWORD maxComponentLength;
DWORD fileSystemFlags;
CHAR fileSystemName[128];
char volname[512]; /* volume name */
DWORD serial;
char serialstr[256];
char rootpath[256];
char simplepath[3];
int pathlen;
char targetpath[256];
char *c;
*pDevices = toupper(*pDevices);
*devices = toupper(*devices);
WINE_TRACE("pDevices == '%s'\n", pDevices);
WINE_TRACE("devices == '%s'\n", devices);
volumeNameBuffer[0] = 0;
volname[0] = 0;
retval = GetVolumeInformation(pDevices,
volumeNameBuffer,
sizeof(volumeNameBuffer),
&serialNumber,
&maxComponentLength,
&fileSystemFlags,
fileSystemName,
sizeof(fileSystemName));
retval = GetVolumeInformation(devices,
volname,
sizeof(volname),
&serial,
NULL,
NULL,
NULL,
0);
if(!retval)
{
WINE_TRACE("GetVolumeInformation() for '%s' failed, setting serialNumber to 0\n", pDevices);
WINE_ERR("GetVolumeInformation() for '%s' failed, setting serial to 0\n", devices);
PRINTERROR();
serialNumber = 0;
serial = 0;
}
WINE_TRACE("serialNumber: '0x%lX'\n", serialNumber);
WINE_TRACE("serial: '0x%lX'\n", serial);
/* build rootpath for GetDriveType() */
strncpy(rootpath, pDevices, sizeof(rootpath));
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)))
if ((rootpath[pathlen - 1] != '\\') && (pathlen < sizeof(rootpath)))
{
rootpath[pathlen] = '\\';
rootpath[pathlen + 1] = 0;
}
strncpy(simplepath, pDevices, 2); /* QueryDosDevice() requires no trailing backslash */
strncpy(simplepath, devices, 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));
/* targetpath may have forward slashes rather than backslashes, so correct */
c = targetpath;
do if (*c == '\\') *c = '/'; while (*c++);
ret-=strlen(pDevices);
pDevices+=strlen(pDevices);
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((*pDevices == 0) && (ret))
while ((*devices == 0) && (len))
{
ret--;
pDevices++;
len--;
devices++;
}
i++;
drivecount++;
}
WINE_TRACE("found %d drives\n", i);
WINE_TRACE("found %d drives\n", drivecount);
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];
......@@ -866,11 +332,13 @@ void applyDriveChanges(void)
{
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 @@ void applyDriveChanges(void)
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;
}
......@@ -906,7 +376,8 @@ void applyDriveChanges(void)
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);
......@@ -918,7 +389,8 @@ void applyDriveChanges(void)
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);
......@@ -945,7 +417,8 @@ void applyDriveChanges(void)
if(retval != ERROR_SUCCESS)
{
WINE_TRACE(" Unable to open '%s'\n", "Software\\Wine\\Drives");
} else
}
else
{
retval = RegSetValueEx(
hKey,
......@@ -958,7 +431,8 @@ void applyDriveChanges(void)
{
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,7 +452,7 @@ void applyDriveChanges(void)
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,
......@@ -992,7 +466,8 @@ void applyDriveChanges(void)
NULL,
NULL);
CloseHandle(hFile);
} else
}
else
{
WINE_TRACE(" CreateFile() error with file '%s'\n", filename);
}
......@@ -1001,78 +476,7 @@ void applyDriveChanges(void)
/* if this drive is in use we should free it up */
if(drives[i].in_use)
{
freeDrive(&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;
delete_drive(&drives[i]); /* free up the string memory */
}
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;
}
/*
* 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;
}
/*
* 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;
}
......@@ -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
......
......@@ -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 @@ void set_window_title(HWND dialog)
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 @@ void set_window_title(HWND dialog)
/**
* 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 @@ void set_window_title(HWND dialog)
* 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 @@ end:
}
/**
* 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 @@ end:
*
* 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 @@ char *get(char *path, char *name, char *def)
}
/* 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 @@ static void process_setting(struct setting *s)
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 @@ void apply(void)
/* ================================== 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 @@ char *keypath(char *section)
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 @@ void PRINTERROR(void)
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);
}
......
......@@ -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 @@ extern char *currentApp; /* NULL means editing global settings */
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 @@ void apply(void);
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 @@ static inline char *strdupA(char *s)
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
......@@ -145,8 +145,8 @@ static void set_from_desktop_edits(HWND dialog) {
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 @@ void on_enable_desktop_clicked(HWND dialog) {
}
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment