[winecfg 5] Implement transactions support, remove some crack x11drv prefs, complete desktop sizing code

Mike Hearn mike at theoretic.com
Fri Sep 5 12:24:53 CDT 2003


Hi,

This patch will add some warnings, and yeah, the commenting out of lots
of code is ugly, but don't worry, it's all temporary until I've finished
bringing the code across from the old global config struct. At that
point it'll all be deleted in favour of the transaction system.

The transactions system is very simple, at the moment the default is
instant apply, despite the presence of OK and Cancel buttons. That's a
bit misleading, but the PropertySheet() API doesn't seem to have any way
to express the need for "Close" and maybe "Revert" buttons. The UI
standard on free software desktops for instant apply dialogs is to have
just a Close dialog, with a Revert button in cases where the user might
not be able to undo the changes themselves. For the main window, just a
Close button is enough. Would it be OK to implement a Wine extension
here Alexandre?

ChangeLog:
- Remove "PerfectGraphics", "Use XSHM extension", and "Use a private
colour map", people who know what these actually are can probably use
regedit (we'll need default reg entries, don't let me forget!)
- Implement a simple transaction system for instant apply
- Complete the desktop size code, this now reads and writes to the
registry correctly.
- Remove const modifier from version accessor functions
- Change registry root to Wine/WineCfg for testing purposes

thanks -mike

Only in programs/winecfg: config.log
Only in programs/winecfg: drive.c.old
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/En.rc programs/winecfg/En.rc
--- ../head/programs/winecfg/En.rc	2003-09-04 18:36:00.000000000 +0100
+++ programs/winecfg/En.rc	2003-09-05 17:48:35.000000000 +0100
@@ -62,28 +62,24 @@
 STYLE WS_CHILD | WS_DISABLED
 FONT 8, "MS Sans Serif"
 BEGIN
-    EDITTEXT        IDC_SYSCOLORS,100,41,40,12,ES_AUTOHSCROLL | ES_NUMBER
-    CONTROL         "Use a private color map",IDC_PRIVATEMAP,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,15,62,91,10
-    CONTROL         "Favor correctness over speed",IDC_PERFECTGRAPH,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,15,76,117,10
     CONTROL         "Use XFree DGA extension",IDC_XDGA,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,141,62,97,10
-    CONTROL         "Use XFree Shm extension",IDC_XSHM,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,141,76,96,10
-    CONTROL         "Enable Wine desktop",IDC_MANAGED,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,17,143,84,10
-    EDITTEXT        IDC_DESKTOP_WIDTH,64,159,40,14,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
-    EDITTEXT        IDC_DESKTOP_HEIGHT,117,159,40,14,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
-    GROUPBOX        "Render Settings",IDC_STATIC,8,4,244,90
+                    BS_AUTOCHECKBOX | WS_TABSTOP,145,44,97,10
+    CONTROL         "Enable Wine desktop",IDC_ENABLE_DESKTOP,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,17,110,84,10
+    EDITTEXT        IDC_DESKTOP_WIDTH,64,125,40,14,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
+    EDITTEXT        IDC_DESKTOP_HEIGHT,117,125,40,14,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
+    GROUPBOX        "Render Settings",IDC_STATIC,8,4,244,60
     LTEXT           "The driver color and render settings are used to optimise the way in which colors and applications are displayed.",
                     IDC_STATIC,15,17,228,22
+		    
     LTEXT           "Allocated system colors:",IDC_STATIC,15,43,76,8
-    GROUPBOX        "Wine Desktop",IDC_STATIC,8,99,244,83
+    EDITTEXT        IDC_SYSCOLORS,90,41,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    
+    GROUPBOX        "Wine Desktop",IDC_STATIC,8,65,244,83
     LTEXT           "Wine can be setup to emulate a windows desktop, or can be run in ""Managed"" mode (default) where the default X11 windows manager/environment is resposible for placing the windows.",
-                    IDC_STATIC,15,112,228,28
-    LTEXT           "Desktop size:",IDC_DESKTOP_SIZE,17,161,44,8,WS_DISABLED
-    LTEXT           "X",IDC_DESKTOP_BY,108,161,8,8,WS_DISABLED
+                    IDC_STATIC,15,77,228,28
+    LTEXT           "Desktop size:",IDC_DESKTOP_SIZE,17,125,44,8,WS_DISABLED
+    LTEXT           "X",IDC_DESKTOP_BY,108,125,8,8,WS_DISABLED
 END
 
 IDD_DLLCFG DIALOG DISCARDABLE  0, 0, 260, 250
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/main.c programs/winecfg/main.c
--- ../head/programs/winecfg/main.c	2003-09-01 17:35:22.000000000 +0100
+++ programs/winecfg/main.c	2003-09-05 18:14:50.000000000 +0100
@@ -62,6 +62,9 @@
 {
     int i;
     const VERSION_DESC *pVer = NULL;
+    char *curWinVer = getConfigValue("Version", "Windows", "win98");
+    char *curDOSVer = getConfigValue("Version", "DOS", "6.22");
+    char *curWineLook = getConfigValue("Tweak.Layout", "WineLook", "win95");
 
     if ((pVer = getWinVersions ()))
     {
@@ -69,7 +72,7 @@
 	{
 	    SendDlgItemMessage (hDlg, IDC_WINVER, CB_ADDSTRING,
 				0, (LPARAM) pVer->szDescription);
-	    if (!strcmp (pVer->szVersion, config.szWinVer))
+	    if (!strcmp (pVer->szVersion, curWinVer))
 		SendDlgItemMessage (hDlg, IDC_WINVER, CB_SETCURSEL,
 				    (WPARAM) i, 0);
 	}
@@ -80,7 +83,7 @@
 	{
 	    SendDlgItemMessage (hDlg, IDC_DOSVER, CB_ADDSTRING,
 				0, (LPARAM) pVer->szDescription);
-	    if (!strcmp (pVer->szVersion, config.szDOSVer))
+	    if (!strcmp (pVer->szVersion, curDOSVer))
 		SendDlgItemMessage (hDlg, IDC_DOSVER, CB_SETCURSEL,
 				    (WPARAM) i, 0);
 	}
@@ -91,11 +94,15 @@
 	{
 	    SendDlgItemMessage (hDlg, IDC_WINELOOK, CB_ADDSTRING,
 				0, (LPARAM) pVer->szDescription);
-	    if (!strcmp (pVer->szVersion, config.szWinLook))
+	    if (!strcmp (pVer->szVersion, curWineLook))
 		SendDlgItemMessage (hDlg, IDC_WINELOOK, CB_SETCURSEL,
 				    (WPARAM) i, 0);
 	}
     }
+
+    free(curWinVer);
+    free(curDOSVer);
+    free(curWineLook);
 }
 
 INT_PTR CALLBACK
@@ -112,12 +119,12 @@
 		case IDC_WINVER: if (HIWORD(wParam) == CBN_SELCHANGE) {
 		    /* user changed the wine version combobox */
 		    int selection = SendDlgItemMessage( hDlg, IDC_WINVER, CB_GETCURSEL, 0, 0);
-		    const VERSION_DESC *desc = getWinVersions();
+		    VERSION_DESC *desc = getWinVersions();
 
 		    while (selection > 0) {
 			desc++; selection--;
 		    }
-		    strcpy(config.szWinVer, desc->szVersion);
+		    addTransaction("Version", "Windows", ACTION_SET, desc->szVersion);
 		}
 	        break;
 	    }
@@ -264,12 +271,12 @@
     /* Until winecfg is fully functional, warn users that it is incomplete and doesn't do anything */
     WINE_FIXME("The winecfg tool is not yet complete, and does not actually alter your configuration.\n");
     WINE_FIXME("If you want to alter the way Wine works, look in the ~/.wine/config file for more information.\n");
-    
-    /*
-     * Load the configuration from registry
-     */
-    loadConfig (&config);
 
+    if (initialize() != 0) {
+	WINE_ERR("initialization failed, aborting\n");
+	ExitProcess(1);
+    }
+    
     /*
      * The next 3 lines should be all that is needed
      * for the Wine Configuration property sheet
@@ -277,7 +284,6 @@
     InitCommonControls ();
     if (doPropertySheet (hInstance, NULL) > 0) {
 	WINE_TRACE("OK\n");
-	saveConfig(&config);
     } else
 	WINE_TRACE("Cancel\n");
     
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/Makefile.in programs/winecfg/Makefile.in
--- ../head/programs/winecfg/Makefile.in	2003-09-01 17:35:18.000000000 +0100
+++ programs/winecfg/Makefile.in	2003-09-05 18:13:08.000000000 +0100
@@ -11,7 +11,7 @@
 	main.c \
 	properties.c \
 	winecfg.c \
-	x11drvdlg.c
+	x11drvdlg.c 
 
 RC_SRCS = winecfg.rc
 
Only in programs/winecfg: programs
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/properties.c programs/winecfg/properties.c
--- ../head/programs/winecfg/properties.c	2003-09-01 17:35:23.000000000 +0100
+++ programs/winecfg/properties.c	2003-09-05 17:26:55.000000000 +0100
@@ -80,7 +80,7 @@
 
 /*****************************************************************************
  */
-const VERSION_DESC* getWinVersions(void)
+VERSION_DESC* getWinVersions(void)
 {
     return sWinVersions;
 }
@@ -88,7 +88,7 @@
 
 /*****************************************************************************
  */
-const VERSION_DESC* getDOSVersions(void)
+VERSION_DESC* getDOSVersions(void)
 {
     return sDOSVersions;
 }
@@ -96,7 +96,7 @@
 
 /*****************************************************************************
  */
-const VERSION_DESC* getWinelook(void)
+VERSION_DESC* getWinelook(void)
 {
     return sWineLook;
 }
@@ -104,7 +104,7 @@
 
 /*****************************************************************************
  */
-const DLL_DESC* getDLLDefaults(void)
+DLL_DESC* getDLLDefaults(void)
 {
     return sDLLType;
 }
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/properties.h programs/winecfg/properties.h
--- ../head/programs/winecfg/properties.h	2003-09-01 17:35:23.000000000 +0100
+++ programs/winecfg/properties.h	2003-09-05 17:44:13.000000000 +0100
@@ -86,9 +86,9 @@
     int    nSynchronous;
 } X11DRV_DESC;
 
-const VERSION_DESC *getWinVersions(void);
-const VERSION_DESC *getDOSVersions(void);
-const VERSION_DESC *getWinelook(void);
-const DLL_DESC *getDLLDefaults(void);
+VERSION_DESC *getWinVersions(void);
+VERSION_DESC *getDOSVersions(void);
+VERSION_DESC *getWinelook(void);
+DLL_DESC *getDLLDefaults(void);
 
 #endif
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/resource.h programs/winecfg/resource.h
--- ../head/programs/winecfg/resource.h	2003-09-04 18:36:00.000000000 +0100
+++ programs/winecfg/resource.h	2003-09-05 17:52:34.000000000 +0100
@@ -101,3 +101,4 @@
 #define IDC_BOX_LABELSERIAL             1071
 #define IDC_STATIC_SERIAL               1072
 #define IDC_STATIC_LABEL                1073
+#define IDC_ENABLE_DESKTOP              1074
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/winecfg.c programs/winecfg/winecfg.c
--- ../head/programs/winecfg/winecfg.c	2003-09-01 17:35:25.000000000 +0100
+++ programs/winecfg/winecfg.c	2003-09-05 18:05:30.000000000 +0100
@@ -26,6 +26,7 @@
 #include <windows.h>
 #include <winreg.h>
 #include <wine/debug.h>
+#include <assert.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
 
@@ -33,77 +34,42 @@
 
 HKEY configKey = NULL;
 
-/*****************************************************************************
- */
-WINECFG_DESC* allocConfig(void)
-{
-    WINECFG_DESC* pWineCfg =  malloc (sizeof (WINECFG_DESC));
-
-    if (!pWineCfg) goto fail;
-    ZeroMemory(pWineCfg, sizeof(*pWineCfg));
-
-    pWineCfg->pDlls = DPA_Create(100);
-    if (!pWineCfg->pDlls) goto fail;
-    pWineCfg->pApps = DPA_Create(100);
-    if (!pWineCfg->pApps) goto fail;
-    
-    return pWineCfg;
-
-fail:
-    /* FIXME: do something nice */
-    printf("Out of memory");
-    exit(1);
-}
-
-
-/*****************************************************************************
- */
-int freeConfig (WINECFG_DESC* pCfg)
-{
-    int i;
-
-    for (i = 0; i < pCfg->pDlls->nItemCount; i++)
-	free (DPA_GetPtr(pCfg->pDlls, i));
-    DPA_Destroy(pCfg->pDlls);
-    
-    for (i = 0; i < pCfg->pApps->nItemCount; i++)
-	free (DPA_GetPtr(pCfg->pApps, i));
-    DPA_Destroy(pCfg->pApps);
-    
-    free (pCfg);
 
+int initialize() {
+    DWORD res = RegCreateKey(HKEY_LOCAL_MACHINE, WINEHQ_KEY_ROOT, &configKey);
+    if (res != ERROR_SUCCESS) {
+	WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res);
+	return 1;
+    }
     return 0;
 }
 
+
 /*****************************************************************************
  * getConfigValue: Retrieves a configuration value from the registry
  *
- * HKEY  hCurrent : the registry key that the configuration is rooted at
  * char *subKey : the name of the config section
  * char *valueName : the name of the config value
- * char *retVal : pointer to the start of a buffer that has room for >= length chars
- * int   length : length of the buffer pointed to by retVal
  * char *defaultResult : if the key isn't found, return this value instead
  *
- * Returns 0 upon success, non-zero otherwise
+ * Returns a buffer holding the value if successful, NULL if not. Caller is responsible for freeing the result.
  *
  */
-int getConfigValue (HKEY hCurrent, char *subkey, char *valueName, char *retVal, int length, char *defaultResult)
+char *getConfigValue (char *subkey, char *valueName, char *defaultResult)
 {
-    CHAR *buffer;
+    char *buffer = NULL;
     DWORD dataLength;
     HKEY hSubKey = NULL;
-    DWORD res = 1; /* assume failure */
+    DWORD res;
 
     WINE_TRACE("subkey=%s, valueName=%s, defaultResult=%s\n", subkey, valueName, defaultResult);
-    
-    if( (res=RegOpenKeyEx( hCurrent, subkey, 0, KEY_ALL_ACCESS, &hSubKey ))
-            !=ERROR_SUCCESS )
-    {
+
+    res = RegOpenKeyEx( configKey, subkey, 0, KEY_ALL_ACCESS, &hSubKey );
+    if(res != ERROR_SUCCESS)  {
         if( res==ERROR_FILE_NOT_FOUND )
         {
             WINE_TRACE("Section key not present - using default\n");
-            strncpy(retVal, defaultResult, length);
+            return strdup(defaultResult);
         }
         else
         {
@@ -113,20 +79,16 @@
     }
     
     res = RegQueryValueExA( hSubKey, valueName, NULL, NULL, NULL, &dataLength);
-    if( res == ERROR_FILE_NOT_FOUND )
-    {
+    if( res == ERROR_FILE_NOT_FOUND ) {
         WINE_TRACE("Value not present - using default\n");
-        strncpy(retVal, defaultResult, length);
-        goto end;
-    }
-
-    if( res!=ERROR_SUCCESS )
-    {
+        buffer = strdup(defaultResult);
+	goto end;
+    } else if( res!=ERROR_SUCCESS )  {
         WINE_ERR("Couldn't query value's length (res=%ld)\n", res );
         goto end;
     }
 
-    buffer=malloc( dataLength );
+    buffer = malloc(dataLength);
     if( buffer==NULL )
     {
         WINE_ERR("Couldn't allocate %lu bytes for the value\n", dataLength );
@@ -134,15 +96,12 @@
     }
     
     RegQueryValueEx(hSubKey, valueName, NULL, NULL, (LPBYTE)buffer, &dataLength);
-    strncpy(retVal, buffer, length);
-    free(buffer);
-    res = 0;
     
 end:
     if( hSubKey!=NULL )
         RegCloseKey( hSubKey );
 
-    return res;
+    return buffer;
     
 }
 
@@ -157,13 +116,17 @@
  * Returns 0 on success, non-zero otherwise
  *
  */
-int setConfigValue (HKEY hCurrent, char *subkey, char *valueName, const char *value) {
+int setConfigValue (char *subkey, char *valueName, const char *value) {
     DWORD res = 1;
     HKEY key = NULL;
 
     WINE_TRACE("subkey=%s, valueName=%s, value=%s\n", subkey, valueName, value);
+
+    assert( subkey != NULL );
+    assert( valueName != NULL );
+    assert( value != NULL );
     
-    res = RegCreateKey(hCurrent, subkey, &key);
+    res = RegCreateKey(configKey, subkey, &key);
     if (res != ERROR_SUCCESS) goto end;
 
     res = RegSetValueEx(key, valueName, 0, REG_SZ, value, strlen(value) + 1);
@@ -176,6 +139,45 @@
     return res;
 }
 
+/* returns 0 on success, an HRESULT from the registry funtions otherwise */
+HRESULT doesConfigValueExist(char *subkey, char *valueName) {
+    HRESULT hr;
+    HKEY key;
+
+    WINE_TRACE("subkey=%s, valueName=%s - ", subkey, valueName);
+    
+    hr = RegOpenKeyEx(configKey, subkey, 0, KEY_READ, &key);
+    if (hr != S_OK) {
+	WINE_TRACE("no: subkey does not exist\n");
+	return hr;
+    }
+
+    hr = RegQueryValueEx(key, valueName, NULL, NULL, NULL, NULL);
+    if (hr != S_OK) {
+	WINE_TRACE("no: key does not exist\n");
+	return hr;
+    }
+
+    RegCloseKey(key);
+    WINE_TRACE("yes\n");
+    return S_OK;
+}
+
+/* removes the requested value from the registry, however, does not remove the section if empty. Returns S_OK (0) on success. */
+HRESULT removeConfigValue(char *subkey, char *valueName) {
+    HRESULT hr;
+    HKEY key;
+    WINE_TRACE("subkey=%s, valueName=%s\n", subkey, valueName);
+    
+    hr = RegOpenKeyEx(configKey, subkey, 0, KEY_READ, &key);
+    if (hr != S_OK) return hr;
+
+    hr = RegDeleteValue(key, valueName);
+    if (hr != ERROR_SUCCESS) return hr;
+
+    return S_OK;
+}
+
 
 /*****************************************************************************
  * Name       : loadConfig
@@ -183,9 +185,6 @@
  * Parameters : pCfg
  * Returns    : 0 on success, -1 otherwise
  *
- * FIXME: We are supposed to load these values from the registry.
- *        This is not active yet, so just setup some (hopefully) 
- *        sane defaults
  */
 int loadConfig (WINECFG_DESC* pCfg)
 {
@@ -196,63 +195,29 @@
 
     WINE_TRACE("\n");
 
-    res = RegCreateKey(HKEY_LOCAL_MACHINE, WINE_KEY_ROOT, &configKey);
-    if (res != ERROR_SUCCESS)
-    {
-        WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res);
-        return -1;
-    }
-
-    /* Windows and DOS versions */
-    getConfigValue(configKey, "Version", "Windows", pCfg->szWinVer, MAX_VERSION_LENGTH, "win95");
-    getConfigValue(configKey, "Version", "DOS", pCfg->szDOSVer, MAX_VERSION_LENGTH, "6.22");
-    getConfigValue(configKey, "Tweak.Layout", "WineLook", pCfg->szWinLook, MAX_VERSION_LENGTH, "win95");
+    return_if_fail( initialize() == 0 , 1 );
 
     /* System Paths */
-    getConfigValue(configKey, "Wine", "Windows", pCfg->szWinDir, MAX_PATH, "c:\\Windows");
+/*  getConfigValue(configKey, "Wine", "Windows", pCfg->szWinDir, MAX_PATH, "c:\\Windows");
     getConfigValue(configKey, "Wine", "System", pCfg->szWinSysDir, MAX_PATH, "c:\\Windows\\System");
     getConfigValue(configKey, "Wine", "Temp", pCfg->szWinTmpDir, MAX_PATH, "c:\\Windows\\Temp");
     getConfigValue(configKey, "Wine", "Profile", pCfg->szWinProfDir, MAX_PATH, "c:\\Windows\\Profiles\\Administrator");
     getConfigValue(configKey, "Wine", "Path", pCfg->szWinPath, MAX_PATH, "c:\\Windows;c:\\Windows\\System");
-
+*/
     /* Graphics driver */
-    getConfigValue(configKey, "Wine", "GraphicsDriver", pCfg->szGraphDriver, MAX_NAME_LENGTH, "x11drv");
-    
+/*  getConfigValue(configKey, "Wine", "GraphicsDriver", pCfg->szGraphDriver, MAX_NAME_LENGTH, "x11drv");
+ */    
     /*
      * DLL defaults for all applications is built using
      * the default DLL structure
      */
-    for (pDllDefaults = getDLLDefaults (); *pDllDefaults->szName; pDllDefaults++)
+/*    for (pDllDefaults = getDLLDefaults (); *pDllDefaults->szName; pDllDefaults++)
     {
         DLL_DESC *pDll = malloc(sizeof(DLL_DESC));
 	memcpy (pDll, pDllDefaults, sizeof(DLL_DESC));
         DPA_InsertPtr(pCfg->pDlls, INT_MAX, pDll);
     }
-
-    /*
-     * Application defaults on a per application
-     * level (if not set, this defaults to what 
-     * is already there)
-     */
-    
-    /* FIXME: Finish these off. Do we actually need GUI for all of them? */
-
-    /*
-     * X11Drv defaults
-     */
-    getConfigValue(configKey, "x11drv", "Display", pCfg->sX11Drv.szX11Display, sizeof(pCfg->sX11Drv.szX11Display), ":0.0");
-    
-    getConfigValue(configKey, "x11drv", "AllocSystemColors", buffer, sizeof(buffer), "100");
-    pCfg->sX11Drv.nSysColors = atoi(buffer);
-    
-    getConfigValue(configKey, "x11drv", "PrivateColorMap", buffer, sizeof(buffer), "N");
-    pCfg->sX11Drv.nPrivateMap = IS_OPTION_TRUE(buffer[0]);
-    
-    getConfigValue(configKey, "x11drv", "PerfectGraphics", buffer, sizeof(buffer), "N");
-    pCfg->sX11Drv.nPerfect = IS_OPTION_TRUE(buffer[0]);
-    
-    getConfigValue(configKey, "x11drv", "Desktop", buffer, sizeof(buffer), "640x480");
-    sscanf(buffer, "%dx%d", &pCfg->sX11Drv.nDesktopSizeX, &pCfg->sX11Drv.nDesktopSizeY);
+*/
 
     pCfg->sX11Drv.nTextCP = 0;
     pCfg->sX11Drv.nXVideoPort = 43;
@@ -271,7 +236,7 @@
     /*
      * Drive mappings
      */
-    pCfg->pDrives = DPA_Create(26);
+/*  pCfg->pDrives = DPA_Create(26);
     for (i = 0;
 	 RegEnumKeyExA(configKey, i, subKeyName, &sizeOfSubKeyName, NULL, NULL, NULL, NULL ) != ERROR_NO_MORE_ITEMS;
          ++i, sizeOfSubKeyName=50) {
@@ -359,35 +324,78 @@
 	}
     }
     WINE_TRACE("loaded %d drives\n", pCfg->driveCount);
-
-    RegCloseKey( configKey );
+ */
     return 0;
 }
 
-/*****************************************************************************
- * saveConfig : Stores the configuration structure
- *
- * Returns    : 0 on success, -1 otherwise
- *
- * FIXME: This is where we are to write the changes to the registry.
- *        This is not setup yet, so do nothing and say ok.
- */
-int saveConfig (const WINECFG_DESC* pCfg)
-{
-    HKEY key;
-    DWORD res;
 
-    WINE_TRACE("\n");
+
+/* ========================================================================= */
+/* Transaction management code */
+
+struct transaction *tqhead, *tqtail;
+int instantApply = 1;
+
+void destroyTransaction(struct transaction *trans) {
+    assert( trans != NULL );
     
-    res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINE_KEY_ROOT, 0, KEY_ALL_ACCESS, &key);
-    if (res != ERROR_SUCCESS) {
-	WINE_ERR("Failed to open Wine config registry branch, res=%ld\n", res);
-	return -1;
-    }
+    WINE_TRACE("destroying %p\n", trans);
+    
+    free(trans->section);
+    free(trans->key);
+    if (trans->newValue) free(trans->newValue);
+    
+    if (trans->next) trans->next->prev = trans->prev;
+    if (trans->prev) trans->prev->next = trans->next;
+    if (trans == tqhead) tqhead = NULL;
+    if (trans == tqtail) tqtail = NULL;
+    
+    free(trans);
+}
 
-    /* Windows and DOS versions */
-    setConfigValue(key, "Version", "Windows", pCfg->szWinVer);
+void addTransaction(char *section, char *key, enum transaction_action action, char *newValue) {
+    struct transaction *trans = malloc(sizeof(struct transaction));
     
-    WINE_FIXME("We don't write out the entire configuration yet\n");
-    return 0;
+    assert( section != NULL );
+    assert( key != NULL );
+    if (action == ACTION_SET) assert( newValue != NULL );
+
+    trans->section = section;
+    trans->key = key;
+    trans->newValue = newValue;
+    trans->action = action;
+    trans->next = NULL;
+    trans->prev = NULL;
+    
+    if (tqtail == NULL) {
+	tqtail = trans;
+	tqhead = tqtail;
+    } else {
+	tqhead->next = trans;
+	trans->prev = tqhead;
+	tqhead = trans;
+    }
+
+    if (instantApply) processTransaction(trans);
+}
+
+void processTransaction(struct transaction *trans) {
+    if (trans->action == ACTION_SET) {
+	WINE_TRACE("Setting %s\\%s to '%s'\n", trans->section, trans->key, trans->newValue);
+	setConfigValue(trans->section, trans->key, trans->newValue);
+    } else if (trans->action == ACTION_REMOVE) {
+	WINE_TRACE("Removing %s\\%s", trans->section, trans->key);
+	removeConfigValue(trans->section, trans->key);
+    }
+    /* TODO: implement notifications here */
 }
+
+void processTransQueue() {
+    WINE_TRACE("\n");
+    while (tqhead != NULL) {
+	processTransaction(tqhead);
+	tqhead = tqhead->next;
+	destroyTransaction(tqhead->prev);
+    }
+}
+
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/winecfg.h programs/winecfg/winecfg.h
--- ../head/programs/winecfg/winecfg.h	2003-09-01 17:35:25.000000000 +0100
+++ programs/winecfg/winecfg.h	2003-09-05 18:03:17.000000000 +0100
@@ -30,6 +30,60 @@
 #define IS_OPTION_FALSE(ch) \
     ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
 
+#define return_if_fail(try, ret) \
+    if (!(try)) { \
+	WINE_ERR("assertion (##try) failed, returning\n"); \
+	return ret; \
+    }
+
+/* Transaction management */
+enum transaction_action {
+    ACTION_SET,
+    ACTION_REMOVE
+};
+
+struct transaction {
+    char *section;
+    char *key;
+    char *newValue;
+    enum transaction_action action;
+    struct transaction *next, *prev;
+};
+extern struct transaction *tqhead, *tqtail;
+
+extern int instantApply; /* non-zero means apply all changes instantly */
+
+
+/* Commits a transaction to the registry */
+void processTransaction(struct transaction *trans);
+
+/* Processes every pending transaction in the queue, removing them as it works from head to tail */
+void processTransQueue();
+
+/* Adds a transaction to the head of the queue. If we're using instant apply, this calls processTransaction
+ * action can be either:
+ *   ACTION_SET -> this transaction will change a registry key, newValue is the replacement value
+ *   ACTION_REMOVE -> this transaction will remove a registry key. In this case, newValue is ignored.
+ */
+void addTransaction(char *section, char *key, enum transaction_action action, char *newValue);
+
+/* frees the transaction structure, all fields, and removes it from the queue if in it */
+void destroyTransaction(struct transaction *trans);
+
+/* Initializes the transaction system */
+int initialize();
+
+
+
+
+
+
+
+
+
+
+
+
 typedef struct structWineCfg
 {
     char   szWinVer[MAX_VERSION_LENGTH];
@@ -61,11 +115,13 @@
 int loadConfig(WINECFG_DESC *pCfg);
 int saveConfig(const WINECFG_DESC *pCfg);
 
-int setConfigValue (HKEY hCurrent, char *subkey, char *valueName, const char *value);
-int getConfigValue (HKEY hCurrent, char *subkey, char *valueName, char *retVal, int length, char *defaultResult);
-
+int setConfigValue (char *subkey, char *valueName, const char *value);
+char *getConfigValue (char *subkey, char *valueName, char *defaultResult);
+HRESULT doesConfigValueExist (char *subkey, char *valueName);
+HRESULT removeConfigValue (char *subkey, char *valueName);
 
 /* X11DRV */
+
 void initX11DrvDlg (HWND hDlg);
 void saveX11DrvDlgSettings (HWND hDlg);
 INT_PTR CALLBACK X11DrvDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
@@ -77,6 +133,6 @@
 INT_PTR CALLBACK DriveDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 INT_PTR CALLBACK DriveEditDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
-#define WINE_KEY_ROOT "Software\\Wine\\Wine\\Config"
+#define WINEHQ_KEY_ROOT "Software\\Wine\\WineCfg\\Config"
 
 #endif
diff -ur --exclude-from=diff-exclusions ../head/programs/winecfg/x11drvdlg.c programs/winecfg/x11drvdlg.c
--- ../head/programs/winecfg/x11drvdlg.c	2003-08-30 01:40:46.000000000 +0100
+++ programs/winecfg/x11drvdlg.c	2003-09-05 17:18:38.000000000 +0100
@@ -30,67 +30,139 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
 
+#define RES_MAXLEN 5 /* the maximum number of characters in a screen dimension. 5 digits should be plenty, what kind of crazy person runs their screen >10,000 pixels across? */
+
+int updatingUI;
+
+void updateGUIForDesktopMode(HWND hDlg) {
+    WINE_TRACE("\n");
+
+    updatingUI = TRUE;
+    
+    /* do we have desktop mode enabled? */
+    if (doesConfigValueExist("x11drv", "Desktop") == S_OK) {
+	CheckDlgButton(hDlg, IDC_ENABLE_DESKTOP, BST_CHECKED);
+	/* enable the controls */
+	EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP_WIDTH), 1);
+	EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP_HEIGHT), 1);
+	EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP_SIZE), 1);
+	EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP_BY), 1);
+	SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_WIDTH), "640");
+	SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_HEIGHT), "480");	
+    }
+    else {
+	CheckDlgButton(hDlg, IDC_ENABLE_DESKTOP, BST_UNCHECKED);
+	/* disable the controls */
+	EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP_WIDTH), 0);
+	EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP_HEIGHT), 0);
+	EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP_SIZE), 0);
+	EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP_BY), 0);
+
+	SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_WIDTH), "");
+	SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_HEIGHT), "");
+    }
+
+    updatingUI = FALSE;
+}
+
 /* pokes the win32 api to setup the dialog from the config struct */
 void initX11DrvDlg (HWND hDlg)
 {
-    char szBuf[20];
+    char *buf;
+    int x, y;
+    char *i;
+
+    updatingUI = TRUE;
+    
+    updateGUIForDesktopMode(hDlg);
+    
+    /* desktop size */
+    buf = getConfigValue("x11drv", "Desktop", "640x480");
+    i = strchr(buf, 'x');
+    *i = '\0';
+    i++;
+    SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_WIDTH), buf);
+    SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_HEIGHT), i);
+    free(buf);
+
+    SendDlgItemMessage(hDlg, IDC_DESKTOP_WIDTH, EM_LIMITTEXT, RES_MAXLEN, 0);
+    SendDlgItemMessage(hDlg, IDC_DESKTOP_HEIGHT, EM_LIMITTEXT, RES_MAXLEN, 0);    
+    
+    updatingUI = FALSE;
+}
 
-    /* system colors */
-    sprintf (szBuf, "%d", config.sX11Drv.nSysColors);
-    SendDlgItemMessage (hDlg, IDC_SYSCOLORS, WM_SETTEXT, 0, (LPARAM) szBuf);
-
-    /* private color map */
-    if (config.sX11Drv.nPrivateMap)
-	SendDlgItemMessage( hDlg, IDC_PRIVATEMAP, BM_SETCHECK, BST_CHECKED, 0);
-
-    /* perfect graphics */
-    if (config.sX11Drv.nPerfect)
-	SendDlgItemMessage( hDlg, IDC_PERFECTGRAPH, BM_SETCHECK, BST_CHECKED, 0);
 
-    /* desktop size */
-    sprintf (szBuf, "%d", config.sX11Drv.nDesktopSizeX);
-    SendDlgItemMessage (hDlg, IDC_DESKTOP_WIDTH, WM_SETTEXT, 0, (LPARAM) szBuf);
-    sprintf (szBuf, "%d", config.sX11Drv.nDesktopSizeY);
-    SendDlgItemMessage (hDlg, IDC_DESKTOP_HEIGHT, WM_SETTEXT, 0, (LPARAM) szBuf);
 
-    if (config.sX11Drv.nDGA) SendDlgItemMessage( hDlg, IDC_XDGA, BM_SETCHECK, BST_CHECKED, 0);
-    if (config.sX11Drv.nXShm) SendDlgItemMessage( hDlg, IDC_XSHM, BM_SETCHECK, BST_CHECKED, 0);
+void setFromDesktopSizeEdits(HWND hDlg) {
+    char *width = malloc(RES_MAXLEN+1);
+    char *height = malloc(RES_MAXLEN+1);
+    char *newStr = malloc((RES_MAXLEN*2) + 2);
+
+    if (updatingUI) return;
+    
+    WINE_TRACE("\n");
+    
+    GetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_WIDTH), width, RES_MAXLEN+1);
+    GetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_HEIGHT), height, RES_MAXLEN+1);
+
+    if (strcmp(width, "") == 0) strcpy(width, "640");
+    if (strcmp(height, "") == 0) strcpy(height, "480");
+    
+    sprintf(newStr, "%sx%s", width, height);
+    addTransaction("x11drv", "Desktop", ACTION_SET, newStr);
+
+    free(width);
+    free(height);
+    free(newStr);
 }
 
-void
-saveX11DrvDlgSettings (HWND hDlg)
-{
+void onEnableDesktopClicked(HWND hDlg) {
+    WINE_TRACE("\n");
+    if (IsDlgButtonChecked(hDlg, IDC_ENABLE_DESKTOP) == BST_CHECKED) {
+	/* it was just unchecked, so read the values of the edit boxes, set the config value */
+	setFromDesktopSizeEdits(hDlg);
+    } else {
+	/* it was just checked, so remove the config values */
+	addTransaction("x11drv", "Desktop", ACTION_REMOVE, NULL);
+    }
+    updateGUIForDesktopMode(hDlg);
 }
-
+    
 INT_PTR CALLBACK
 X11DrvDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     switch (uMsg) {
 	case WM_INITDIALOG:
 	    break;
-
+	    
 	case WM_COMMAND:
 	    switch(HIWORD(wParam)) {
 		case EN_CHANGE: {
 		    SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0);
+		    if ( (LOWORD(wParam) == IDC_DESKTOP_WIDTH) || (LOWORD(wParam) == IDC_DESKTOP_HEIGHT) ) setFromDesktopSizeEdits(hDlg);
 		    break;
 		}
-
+		case BN_CLICKED: {
+		    WINE_TRACE("%ld\n", LOWORD(wParam));
+		    switch(LOWORD(wParam)) {
+			case IDC_ENABLE_DESKTOP: onEnableDesktopClicked(hDlg); break;
+		    };
+		    break;
+		}
+		    
 		default:
 		    break;
 	    }
 	    break;
-
+	
+	
 	case WM_NOTIFY:
 	    switch (((LPNMHDR)lParam)->code) {
 		case PSN_KILLACTIVE: {
-		    /* validate user info.  Lets just assume everything is okay for now */
 		    SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
 		    break;
 		}
 		case PSN_APPLY: {
-		    /* should probably check everything is really all rosy :) */
-		    saveX11DrvDlgSettings (hDlg);
 		    SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
 		    break;
 		}
@@ -100,7 +172,7 @@
 		}
 	    }
 	    break;
-
+         
 	default:
 	    break;
     }





More information about the wine-patches mailing list