[Spice-devel] [PATCH] Controlling Windows display settings (e.g., wallpaper, UI effects and font smoothing)

Yonit Halperin yhalperi at redhat.com
Tue Aug 10 22:46:32 PDT 2010


The configuration is received from Spice client.
The main usage of this option is for disabling display features in order to accelerate Spice performance over limited network connections.
---
 common/vdcommon.h           |    2 +
 vdagent/desktop_layout.h    |    1 +
 vdagent/display_setting.cpp |  525 +++++++++++++++++++++++++++++++++++++++++++
 vdagent/display_setting.h   |   64 ++++++
 vdagent/vdagent.cpp         |  123 ++++++++++
 vdagent/vdagent.vcproj      |    8 +
 vdservice/vdservice.cpp     |   29 ++-
 7 files changed, 748 insertions(+), 4 deletions(-)
 create mode 100644 vdagent/display_setting.cpp
 create mode 100644 vdagent/display_setting.h

diff --git a/common/vdcommon.h b/common/vdcommon.h
index 9095404..9a68649 100644
--- a/common/vdcommon.h
+++ b/common/vdcommon.h
@@ -33,12 +33,14 @@ typedef CRITICAL_SECTION mutex_t;
 #define VD_SERVICE_PIPE_NAME   TEXT("\\\\.\\pipe\\vdservicepipe")
 #define VD_MESSAGE_HEADER_SIZE (sizeof(VDPipeMessage) + sizeof(VDAgentMessage))
 #define VD_PIPE_BUF_SIZE       (1024 * 1024)
+#define VD_AGENT_REGISTRY_KEY "SOFTWARE\\Red Hat\\Spice\\vdagent\\"
 
 enum {
     VD_AGENT_COMMAND,
     VD_AGENT_RESET,
     VD_AGENT_RESET_ACK,
     VD_AGENT_QUIT,
+    VD_AGENT_SESSION_LOGON,
 };
 
 typedef __declspec (align(1)) struct VDPipeMessage {
diff --git a/vdagent/desktop_layout.h b/vdagent/desktop_layout.h
index 22bbc8f..f6cf372 100644
--- a/vdagent/desktop_layout.h
+++ b/vdagent/desktop_layout.h
@@ -42,6 +42,7 @@ public:
     void set_pos(LONG x, LONG y) { _pos_x = x; _pos_y = y;}
     void move_pos(LONG x, LONG y) { _pos_x += x; _pos_y += y;}
     void set_res(DWORD width, DWORD height, DWORD depth);
+    void set_depth(DWORD depth) { _depth = depth;}
     void set_attached(bool attached) { _attached = attached;}
 
 private:
diff --git a/vdagent/display_setting.cpp b/vdagent/display_setting.cpp
new file mode 100644
index 0000000..246b78f
--- /dev/null
+++ b/vdagent/display_setting.cpp
@@ -0,0 +1,525 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <windows.h>
+#include <stdio.h>
+#include <Sddl.h>
+#include <string.h>
+#include <tlhelp32.h>
+#include "display_setting.h"
+#include "vdlog.h"
+
+enum DisplaySettingFlags {
+    DISPLAY_SETTING_FLAGS_DISABLE_WALLPAPER = (1 << 0),
+    DISPLAY_SETTING_FLAGS_DISABLE_FONT_SMOOTH = (1 << 1),
+    DISPLAY_SETTING_FLAGS_DISABLE_ANIMATION = (1 << 2),
+};
+
+#define DISPLAY_SETTING_MASK_REG_VALUE "DisplaySettingMask"
+#define USER_DESKTOP_REGISTRY_KEY "Control Panel\\Desktop"
+
+void DisplaySetting::set(DisplaySettingOptions& opts)
+{
+    HKEY hkey;
+    DWORD dispos;
+    LSTATUS status;
+    BYTE reg_mask = 0;
+
+    vd_printf("setting display options");
+
+    if (opts._disable_wallpaper) {
+        reg_mask |= DISPLAY_SETTING_FLAGS_DISABLE_WALLPAPER;
+    }
+
+    if (opts._disable_font_smoothing) {
+        reg_mask |= DISPLAY_SETTING_FLAGS_DISABLE_FONT_SMOOTH;
+    }
+
+    if (opts._disable_animation) {
+        reg_mask |= DISPLAY_SETTING_FLAGS_DISABLE_ANIMATION;
+    }
+
+    status = RegCreateKeyExA(HKEY_LOCAL_MACHINE, _reg_key.c_str(), 0, NULL,
+                             REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dispos);
+    if (status != ERROR_SUCCESS) {
+        vd_printf("create/open registry key: fail %d", GetLastError());
+    } else {
+        status = RegSetValueExA(hkey, DISPLAY_SETTING_MASK_REG_VALUE, 0,
+                                REG_BINARY, &reg_mask, sizeof(reg_mask));
+        if (status != ERROR_SUCCESS) {
+            vd_printf("setting registry key DisplaySettingMask: fail %d", GetLastError());
+        }
+        RegCloseKey(hkey);
+    }
+
+    load(opts);
+}
+
+void DisplaySetting::load()
+{
+    LSTATUS status;
+    HKEY hkey;
+    DWORD value_type;
+    DWORD value_size;
+    BYTE setting_mask;
+    DisplaySettingOptions display_opts;
+
+    vd_printf("loading display setting");
+
+    status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, _reg_key.c_str(), 0, KEY_READ, &hkey);
+    if (status != ERROR_SUCCESS) {
+        vd_printf("open registry key: fail %d", status);
+        return;
+    }
+
+    value_size = sizeof(setting_mask);
+    status = RegQueryValueExA(hkey, DISPLAY_SETTING_MASK_REG_VALUE, NULL,
+                              &value_type, &setting_mask, &value_size);
+
+    if (status != ERROR_SUCCESS) {
+        vd_printf("get registry mask value: fail %d", GetLastError());
+        RegCloseKey(hkey);
+        return;
+    }
+
+    RegCloseKey(hkey);
+
+    if (value_type != REG_BINARY) {
+        vd_printf("get registry mask value: bad value type %d", value_type);
+        return;
+    }
+
+    if (setting_mask & DISPLAY_SETTING_FLAGS_DISABLE_WALLPAPER) {
+        display_opts._disable_wallpaper = true;
+    }
+
+    if (setting_mask & DISPLAY_SETTING_FLAGS_DISABLE_FONT_SMOOTH) {
+        display_opts._disable_font_smoothing = true;
+    }
+
+    if (setting_mask & DISPLAY_SETTING_FLAGS_DISABLE_ANIMATION) {
+        display_opts._disable_animation = true;
+    }
+
+    load(display_opts);
+}
+
+// returns 0 if failes
+DWORD DisplaySetting::get_user_process_id()
+{
+    PROCESSENTRY32 proc_entry;
+    DWORD explorer_pid = 0;
+    HANDLE token = NULL;
+    DWORD agent_session_id;
+
+    if (!ProcessIdToSessionId(GetCurrentProcessId(), &agent_session_id)) {
+        vd_printf("ProcessIdToSessionId for current process failed %u", GetLastError());
+        return 0;
+    }
+
+    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (snap == INVALID_HANDLE_VALUE) {
+        vd_printf("CreateToolhelp32Snapshot() failed %u", GetLastError());
+        return 0;
+    }
+    ZeroMemory(&proc_entry, sizeof(proc_entry));
+    proc_entry.dwSize = sizeof(PROCESSENTRY32);
+    if (!Process32First(snap, &proc_entry)) {
+        vd_printf("Process32First() failed %u", GetLastError());
+        CloseHandle(snap);
+        return 0;
+    }
+    do {
+        if (_tcsicmp(proc_entry.szExeFile, TEXT("explorer.exe")) == 0) {
+            DWORD explorer_session_id;
+            if (!ProcessIdToSessionId(proc_entry.th32ProcessID, &explorer_session_id)) {
+                vd_printf("ProcessIdToSessionId for explorer failed %u", GetLastError());
+                break;
+            }
+            
+            if (explorer_session_id == agent_session_id) {
+                explorer_pid = proc_entry.th32ProcessID;
+                break;
+            }
+        }
+    } while (Process32Next(snap, &proc_entry));
+
+    CloseHandle(snap);
+    if (explorer_pid == 0) {
+        vd_printf("explorer.exe not found");
+        return 0;
+    }
+    return explorer_pid;
+}
+
+bool DisplaySetting::load(DisplaySettingOptions& opts)
+{
+    bool need_reload = false;
+    bool ret = true;
+
+    if (opts._disable_wallpaper) {
+        ret &= disable_wallpaper();
+    } else {
+        need_reload = true;
+    }
+
+    if (opts._disable_font_smoothing) {
+        ret &= disable_font_smoothing();
+    } else {
+        need_reload = true;
+    }
+
+    if (opts._disable_animation) {
+        ret &= disable_animation();
+    } else {
+        need_reload = true;
+    }
+
+    if (need_reload) {
+        ret &= reload_from_registry(opts);
+    }
+
+    return ret;
+}
+
+bool DisplaySetting::reload_from_registry(DisplaySettingOptions& opts)
+{
+    DWORD user_pid;
+    HANDLE hprocess, htoken;
+    bool ret = true;
+
+    user_pid = get_user_process_id();
+
+    if (!user_pid) {
+        vd_printf("get_user_process_id failed");
+        return false;
+    } else {
+        vd_printf("explorer pid %d", user_pid);
+    }
+
+    hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, user_pid);
+
+    if (!OpenProcessToken(hprocess, TOKEN_ALL_ACCESS, &htoken)) {
+        vd_printf("OpenProcessToken: failed %d", GetLastError());
+        CloseHandle(hprocess);
+        return false;
+    }
+
+    HKEY hkey_cur_user = NULL;
+    HKEY hkey_desktop = NULL;
+    LONG status;
+    try {
+        ImpersonateLoggedOnUser(htoken);
+
+        status = RegOpenCurrentUser(KEY_READ, &hkey_cur_user);
+        if (status != ERROR_SUCCESS) {
+            vd_printf("RegOpenCurrentUser: failed %d", GetLastError());
+            throw;
+        }
+
+        status = RegOpenKeyExA(hkey_cur_user, USER_DESKTOP_REGISTRY_KEY, 0,
+                               KEY_READ, &hkey_desktop);
+        if (status != ERROR_SUCCESS) {
+            vd_printf("RegOpenKeyExA: failed %d", GetLastError());
+            throw;
+        }
+
+        if (!opts._disable_wallpaper) {
+            ret &= reload_wallpaper(hkey_desktop);
+        }
+
+        if (!opts._disable_font_smoothing) {
+            ret &= reload_font_smoothing(hkey_desktop);
+        }
+
+        if (!opts._disable_animation) {
+            ret &= reload_animation(hkey_desktop);
+        }
+
+        RegCloseKey(hkey_desktop);
+        RegCloseKey(hkey_cur_user);
+        RevertToSelf();
+        CloseHandle(htoken);
+        CloseHandle(hprocess);
+    } catch(...) {
+        if (hkey_desktop) {
+            RegCloseKey(hkey_desktop);
+        }
+
+        if (hkey_cur_user) {
+            RegCloseKey(hkey_cur_user);
+        }
+
+        RevertToSelf();
+        CloseHandle(htoken);
+        CloseHandle(hprocess);
+        return false;
+    }
+    return ret;
+}
+
+bool DisplaySetting::disable_wallpaper()
+{
+    if (SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, "", 0)) {
+        vd_printf("disable wallpaper: success");
+        return true;
+    } else {
+        vd_printf("disable wallpaper: fail %d", GetLastError());
+        return false;
+    }
+}
+
+bool DisplaySetting::reload_wallpaper(HKEY desktop_reg_key)
+{
+    TCHAR wallpaper_path[MAX_PATH + 1];
+    DWORD value_size = sizeof(wallpaper_path);
+    DWORD value_type;
+    LONG status;
+    TCHAR cur_wallpaper[MAX_PATH + 1];
+
+    vd_printf("");
+    status = RegQueryValueEx(desktop_reg_key, TEXT("Wallpaper"), NULL,
+                             &value_type, (LPBYTE)wallpaper_path, &value_size);
+    if (status != ERROR_SUCCESS) {
+        vd_printf("RegQueryValueEx(Wallpaper) : fail %ld", status);
+        return false;
+    }
+
+    if (value_type != REG_SZ) {
+        vd_printf("bad wallpaper value type %d (expected REG_SZ)", value_type);
+        return false;
+    }
+
+    if (wallpaper_path[value_size - 1] != '\0') {
+        wallpaper_path[value_size] = '\0';
+    }
+
+    if (SystemParametersInfo(SPI_GETDESKWALLPAPER, sizeof(cur_wallpaper), cur_wallpaper, 0)) {
+        if (_tcscmp(cur_wallpaper, TEXT("")) != 0) {
+            vd_printf("wallpaper wasn't disabled");
+            return true;
+        }
+    } else {
+        vd_printf("SPI_GETDESKWALLPAPER failed");
+    }
+
+    if (SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, wallpaper_path, 0)) {
+        vd_printf("reload wallpaper: success");
+        return true;
+    } else {
+        vd_printf("reload wallpaper: failed %d", GetLastError());
+        return false;
+    }
+}
+
+bool DisplaySetting::disable_font_smoothing()
+{
+    if (SystemParametersInfoA(SPI_SETFONTSMOOTHING, FALSE, NULL, 0)) {
+        vd_printf("disable font smoothing: success");
+        return true;
+    } else {
+        vd_printf("disable font smoothing: fail %d", GetLastError());
+        return false;
+    }
+}
+
+bool DisplaySetting::reload_font_smoothing(HKEY desktop_reg_key)
+{
+    CHAR smooth_value[4];
+    DWORD value_size = sizeof(smooth_value);
+    DWORD value_type;
+    LONG status;
+    BOOL cur_font_smooth;
+
+    vd_printf("");
+    status = RegQueryValueExA(desktop_reg_key, "FontSmoothing", NULL,
+                              &value_type, (LPBYTE)smooth_value, &value_size);
+    if (status != ERROR_SUCCESS) {
+        vd_printf("RegQueryValueEx(FontSmoothing) : fail %ld", status);
+        return false;
+    }
+
+    if (value_type != REG_SZ) {
+        vd_printf("bad font smoothing value type %d (expected REG_SZ)", value_type);
+        return false;
+    }
+
+    if (smooth_value[value_size - 1] != '\0') {
+        smooth_value[value_size] = '\0';
+    }
+
+    if (strcmp(smooth_value, "0") == 0) {
+        vd_printf("font smoothing is disabled in registry. do nothing");
+        return true;
+    } else if (strcmp(smooth_value, "2") != 0) {
+        vd_printf("unexpectd font smoothing value %s", smooth_value);
+        return false;
+    }
+
+    if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &cur_font_smooth, 0)) {
+        if (cur_font_smooth)  {
+            vd_printf("font smoothing value didn't change");
+            return true;
+        }
+    } else {
+        vd_printf("SPI_GETFONTSMOOTHING failed");
+    }
+
+    if (SystemParametersInfo(SPI_SETFONTSMOOTHING, TRUE, NULL, 0)) {
+        vd_printf("reload font smoothing: success");
+        return true;
+    } else {
+        vd_printf("reload font smoothing: failed %d", GetLastError());
+        return false;
+    }
+}
+
+bool DisplaySetting::disable_animation()
+{
+    ANIMATIONINFO win_animation;
+    bool ret = true;
+
+    ret &= set_bool_system_parameter_info(SPI_SETUIEFFECTS, FALSE);
+
+    win_animation.cbSize = sizeof(ANIMATIONINFO);
+    win_animation.iMinAnimate = 0;
+
+    if (SystemParametersInfoA(SPI_SETANIMATION, sizeof(ANIMATIONINFO), 
+                              &win_animation, 0)) {
+        vd_printf("disable window animation: success");
+    } else {
+        vd_printf("disable window animation: fail %d", GetLastError());
+        ret = false;
+    }
+
+    return ret;
+}
+
+bool DisplaySetting::reload_win_animation(HKEY desktop_reg_key)
+{
+    HKEY win_metrics_hkey;
+    CHAR win_anim_value[4];
+    DWORD value_size = sizeof(win_anim_value);
+    DWORD value_type;
+    LONG status;
+    ANIMATIONINFO active_win_animation;
+
+    vd_printf("");
+
+    status = RegOpenKeyExA(desktop_reg_key, "WindowMetrics", 0,
+                           KEY_READ, &win_metrics_hkey);
+    if (status != ERROR_SUCCESS) {
+        vd_printf("RegOpenKeyExA(WindowMetrics) : fail %ld", status);
+        return false;
+    }
+
+    status = RegQueryValueExA(win_metrics_hkey, "MinAnimate", NULL,
+                              &value_type, (LPBYTE)win_anim_value, &value_size);
+    if (status != ERROR_SUCCESS) {
+        vd_printf("RegQueryValueEx(MinAnimate) : fail %ld", status);
+        RegCloseKey(win_metrics_hkey);
+        return false;
+    }
+
+    RegCloseKey(win_metrics_hkey);
+
+    if (value_type != REG_SZ) {
+        vd_printf("bad MinAnimate value type %d (expected REG_SZ)", value_type);
+        return false;
+    }
+
+    if (win_anim_value[value_size - 1] != '\0') {
+        win_anim_value[value_size] = '\0';
+    }
+
+    if (!strcmp(win_anim_value, "0")) {
+        vd_printf("window animation is disabled in registry. do nothing");
+        return true;
+    }  else if (strcmp(win_anim_value, "1") != 0) {
+        vd_printf("unexpectd window animation value %s", win_anim_value);
+        return false;
+    }
+    active_win_animation.cbSize = sizeof(ANIMATIONINFO);
+    active_win_animation.iMinAnimate = 1;
+
+    if (SystemParametersInfoA(SPI_SETANIMATION, sizeof(ANIMATIONINFO), 
+                              &active_win_animation, 0)) {
+        vd_printf("reload window animation: success");
+        return false;
+    } else {
+        vd_printf("reload window animation: fail %d", GetLastError());
+        return false;
+    }
+}
+
+bool DisplaySetting::set_bool_system_parameter_info(int action, BOOL param)
+{
+    if (!SystemParametersInfo(action, 0, (PVOID)param, 0)) {
+        vd_printf("SystemParametersInfo %d: failed %d", action, GetLastError());
+        return false;
+    }
+    return true;
+}
+
+bool DisplaySetting::reload_ui_effects(HKEY desktop_reg_key)
+{
+    DWORD ui_mask[2]; // one DWORD in xp, two DWORD in Windows 7
+    DWORD value_size = sizeof(ui_mask);
+    DWORD value_type;
+    LONG status;
+    bool ret = true;
+    vd_printf("");
+    status = RegQueryValueExA(desktop_reg_key, "UserPreferencesMask", NULL,
+                              &value_type, (LPBYTE)&ui_mask, &value_size);
+    if (status != ERROR_SUCCESS) {
+        vd_printf("RegQueryValueEx(UserPreferencesMask) : fail %ld", status);
+        return false;
+    }
+    
+    if (value_type != REG_BINARY) {
+        vd_printf("bad UserPreferencesMask value type %d (expected REG_BINARY)", value_type);
+        return false;
+    }
+    
+    vd_printf("UserPreferencesMask = %x %x", ui_mask[0], ui_mask[1]);
+
+    ret &= set_bool_system_parameter_info(SPI_SETUIEFFECTS, ui_mask[0] & 0x80000000);
+    ret &= set_bool_system_parameter_info(SPI_SETACTIVEWINDOWTRACKING, ui_mask[0] & 0x01);
+    ret &= set_bool_system_parameter_info(SPI_SETMENUANIMATION, ui_mask[0] & 0x02);
+    ret &= set_bool_system_parameter_info(SPI_SETCOMBOBOXANIMATION, ui_mask[0] & 0x04);
+    ret &= set_bool_system_parameter_info(SPI_SETLISTBOXSMOOTHSCROLLING, ui_mask[0] & 0x08);
+    ret &= set_bool_system_parameter_info(SPI_SETGRADIENTCAPTIONS, ui_mask[0] & 0x10);
+    ret &= set_bool_system_parameter_info(SPI_SETKEYBOARDCUES, ui_mask[0] & 0x20);
+    ret &= set_bool_system_parameter_info(SPI_SETACTIVEWNDTRKZORDER, ui_mask[0] & 0x40);
+    ret &= set_bool_system_parameter_info(SPI_SETHOTTRACKING, ui_mask[0] & 0x80);
+
+    ret &= set_bool_system_parameter_info(SPI_SETMENUFADE, ui_mask[0] & 0x200);
+    ret &= set_bool_system_parameter_info(SPI_SETSELECTIONFADE, ui_mask[0] & 0x400);
+    ret &= set_bool_system_parameter_info(SPI_SETTOOLTIPANIMATION, ui_mask[0] & 0x800);
+    ret &= set_bool_system_parameter_info(SPI_SETTOOLTIPFADE, ui_mask[0] & 0x1000);
+    ret &= set_bool_system_parameter_info(SPI_SETCURSORSHADOW, ui_mask[0] & 0x2000);
+
+    return true;
+}
+
+bool DisplaySetting::reload_animation(HKEY desktop_reg_key)
+{
+    bool ret = true;
+    vd_printf("");
+    ret &= reload_win_animation(desktop_reg_key);
+    ret &= reload_ui_effects(desktop_reg_key);
+    return ret;
+}
diff --git a/vdagent/display_setting.h b/vdagent/display_setting.h
new file mode 100644
index 0000000..923132f
--- /dev/null
+++ b/vdagent/display_setting.h
@@ -0,0 +1,64 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_DISPLAY_SETTING
+#define _H_DISPLAY_SETTING
+
+#include <string>
+
+class DisplaySettingOptions {
+public:
+    DisplaySettingOptions() 
+        : _disable_wallpaper (false)
+        , _disable_font_smoothing (false)
+        , _disable_animation (false) {}
+
+public:
+    bool _disable_wallpaper;
+    bool _disable_font_smoothing;
+    bool _disable_animation;
+};
+
+class DisplaySetting {
+public:
+    DisplaySetting(char* registry_key) : _reg_key (registry_key) {}
+    void set(DisplaySettingOptions& opts);
+    void load();
+
+private:
+    bool disable_wallpaper();
+    bool disable_font_smoothing();
+    bool disable_animation();
+
+    bool load(DisplaySettingOptions& opts);
+    bool reload_from_registry(DisplaySettingOptions& opts);
+    bool reload_wallpaper(HKEY desktop_reg_key);
+    bool reload_font_smoothing(HKEY desktop_reg_key);
+    bool reload_animation(HKEY desktop_reg_key);
+
+    bool reload_win_animation(HKEY desktop_reg_key);
+    bool reload_ui_effects(HKEY desktop_reg_key);
+
+    bool set_bool_system_parameter_info(int action, BOOL param);
+    DWORD get_user_process_id();
+
+private:
+    std::string _reg_key;
+
+};
+
+#endif
diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index d6518a1..a3dd5cc 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -17,6 +17,7 @@
 
 #include "vdcommon.h"
 #include "desktop_layout.h"
+#include "display_setting.h"
 #include <lmcons.h>
 
 #define CLIPBOARD_ENABLED
@@ -38,6 +39,7 @@ private:
     bool handle_mouse_event(VDAgentMouseState* state);
     bool handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port);
     bool handle_clipboard(VDAgentClipboard* clipboard, uint32_t size);
+    bool handle_display_config(VDAgentDisplayConfig* display_config, uint32_t port);
     bool handle_control(VDPipeMessage* msg);
     bool on_clipboard_change();
     DWORD get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state,
@@ -52,6 +54,8 @@ private:
     bool write_clipboard();
     bool connect_pipe();
     bool send_input();
+    void set_display_depth(uint32_t depth);
+    void load_display_setting();
 
 private:
     static VDAgent* _singleton;
@@ -73,8 +77,14 @@ private:
     bool _pending_write;
     bool _running;
     DesktopLayout* _desktop_layout;
+    DisplaySetting _display_setting;
     VDPipeState _pipe_state;
     mutex_t _write_mutex;
+
+    bool _logon_desktop;
+    bool _display_setting_initialized;
+    bool _logon_occured;
+
     VDLog* _log;
 };
 
@@ -105,6 +115,9 @@ VDAgent::VDAgent()
     , _pending_write (false)
     , _running (false)
     , _desktop_layout (NULL)
+    , _display_setting (VD_AGENT_REGISTRY_KEY)
+    , _logon_desktop (false)
+    , _display_setting_initialized (false)
     , _log (NULL)
 {
     TCHAR log_path[MAX_PATH];
@@ -233,6 +246,25 @@ void VDAgent::input_desktop_message_loop()
     } else {
         vd_printf("GetUserObjectInformation failed %u", GetLastError());
     }
+
+    // loading the display settings for the current session's logged on user only
+    // after 1) we receive logon event, and 2) the desktop switched from Winlogon
+    if (_tcscmp(desktop_name, TEXT("Winlogon")) == 0) {
+        _logon_desktop = true;
+    } else {
+        // first load after connection
+        if (!_display_setting_initialized) {
+            vd_printf("First display setting");
+            _display_setting.load();
+            _display_setting_initialized = true;
+        } else if (_logon_occured && _logon_desktop) {
+            vd_printf("LOGON display setting");
+            _display_setting.load();
+        }
+        _logon_occured = false;
+        _logon_desktop = false;
+    }
+
     _hwnd = CreateWindow(VD_AGENT_WINCLASS_NAME, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
     if (!_hwnd) {
         vd_printf("CreateWindow() failed: %u", GetLastError());
@@ -466,6 +498,80 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
     return ret;
 }
 
+void VDAgent::set_display_depth(uint32_t depth)
+{
+    size_t display_count;
+
+    display_count = _desktop_layout->get_display_count();
+
+    // setting depth for all the monitors, including unattached ones
+    for (uint32_t i = 0; i < display_count; i++) {
+        DisplayMode* mode = _desktop_layout->get_display(i);
+        ASSERT(mode);
+        mode->set_depth(depth);
+    }
+
+    if (display_count) {
+        _desktop_layout->set_displays();
+    }
+}
+
+
+void VDAgent::load_display_setting()
+{
+    _display_setting.load();
+}
+
+bool VDAgent::handle_display_config(VDAgentDisplayConfig* display_config, uint32_t port)
+{
+    DisplaySettingOptions disp_setting_opts;
+    VDPipeMessage* reply_pipe_msg;
+    VDAgentMessage* reply_msg;
+    VDAgentReply* reply;
+    DWORD msg_size;
+
+    if (display_config->flags & VD_AGENT_DISPLAY_CONFIG_FLAG_DISABLE_WALLPAPER) {
+        disp_setting_opts._disable_wallpaper = TRUE;
+    }
+
+    if (display_config->flags & VD_AGENT_DISPLAY_CONFIG_FLAG_DISABLE_FONT_SMOOTH) {
+       disp_setting_opts._disable_font_smoothing = TRUE;
+    }
+
+    if (display_config->flags & VD_AGENT_DISPLAY_CONFIG_FLAG_DISABLE_ANIMATION) {
+        disp_setting_opts._disable_animation = TRUE;
+    }
+
+    _display_setting.set(disp_setting_opts);
+
+    if (display_config->flags & VD_AGENT_DISPLAY_CONFIG_FLAG_SET_COLOR_DEPTH) {
+        set_display_depth(display_config->depth);
+    }
+
+    msg_size = VD_MESSAGE_HEADER_SIZE + sizeof(VDAgentReply);
+    reply_pipe_msg = (VDPipeMessage*)write_lock(msg_size);
+    if (!reply_pipe_msg) {
+        return false;
+    }
+
+    reply_pipe_msg->type = VD_AGENT_COMMAND;
+    reply_pipe_msg->opaque = port;
+    reply_pipe_msg->size = sizeof(VDAgentMessage) + sizeof(VDAgentReply);
+    reply_msg = (VDAgentMessage*)reply_pipe_msg->data;
+    reply_msg->protocol = VD_AGENT_PROTOCOL;
+    reply_msg->type = VD_AGENT_REPLY;
+    reply_msg->opaque = 0;
+    reply_msg->size = sizeof(VDAgentReply);
+    reply = (VDAgentReply*)reply_msg->data;
+    reply->type = VD_AGENT_DISPLAY_CONFIG;
+    reply->error = VD_AGENT_SUCCESS;
+    write_unlock(msg_size);
+    if (!_pending_write) {
+        write_completion(0, 0, &_pipe_state.write.overlap);
+    }
+    return true;
+}
+
 bool VDAgent::handle_control(VDPipeMessage* msg)
 {
     switch (msg->type) {
@@ -483,6 +589,17 @@ bool VDAgent::handle_control(VDPipeMessage* msg)
         }
         break;
     }
+    case VD_AGENT_SESSION_LOGON:
+        vd_printf("session logon");
+        // loading the display settings for the current session's logged on user only
+        // after 1) we receive logon event, and 2) the desktop switched from Winlogon
+        if (!_logon_desktop) {
+            vd_printf("LOGON display setting");
+            _display_setting.load();
+        } else {
+            _logon_occured = true;
+        }
+        break;
     case VD_AGENT_QUIT:
         vd_printf("Agent quit");
         _running = false;
@@ -619,6 +736,12 @@ void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port)
         }
         break;
 #endif // CLIPBOARD_ENABLED
+    case VD_AGENT_DISPLAY_CONFIG:
+        if (!a->handle_display_config((VDAgentDisplayConfig*)msg->data, port)) {
+            vd_printf("handle_display_config failed");
+            a->_running = false;
+        }        
+        break;
     default:
         vd_printf("Unsupported message type %u size %u", msg->type, msg->size);
     }
diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj
index a7df8e0..0453c12 100644
--- a/vdagent/vdagent.vcproj
+++ b/vdagent/vdagent.vcproj
@@ -341,6 +341,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\display_setting.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\vdagent.cpp"
 				>
 			</File>
@@ -359,6 +363,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\display_setting.h"
+				>
+			</File>
+			<File
 				RelativePath=".\resource.h"
 				>
 			</File>
diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index 7d13e56..d80d499 100644
--- a/vdservice/vdservice.cpp
+++ b/vdservice/vdservice.cpp
@@ -46,6 +46,7 @@ enum {
     VD_EVENT_CONTROL,
     VD_EVENT_READ,
     VD_EVENT_WRITE,
+    VD_EVENT_LOGON,
     VD_EVENT_AGENT, // Must be before last
     VD_EVENTS_COUNT // Must be last
 };
@@ -73,6 +74,7 @@ private:
     bool handle_agent_control(VDPipeMessage* msg);
     bool restart_agent(bool normal_restart);
     bool launch_agent();
+    void send_logon();
     bool kill_agent();
 
 private:
@@ -81,6 +83,7 @@ private:
     SERVICE_STATUS_HANDLE _status_handle;
     PROCESS_INFORMATION _agent_proc_info;
     HANDLE _control_event;
+    HANDLE _logon_event;
     HANDLE _events[VD_EVENTS_COUNT];
     TCHAR _agent_path[MAX_PATH];
     VDIPort* _vdi_port;
@@ -161,6 +164,7 @@ VDService::VDService()
     _control_event = CreateEvent(NULL, FALSE, FALSE, NULL);
     _pipe_state.write.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
     _pipe_state.read.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    _logon_event = CreateEvent(NULL, FALSE, FALSE, NULL);
     _agent_path[0] = wchar_t('\0');
     MUTEX_INIT(_agent_mutex);
     _singleton = this;
@@ -168,6 +172,7 @@ VDService::VDService()
 
 VDService::~VDService()
 {
+    CloseHandle(_logon_event);
     CloseHandle(_pipe_state.read.overlap.hEvent);
     CloseHandle(_pipe_state.write.overlap.hEvent);
     CloseHandle(_control_event);
@@ -294,10 +299,14 @@ DWORD WINAPI VDService::control_handler(DWORD control, DWORD event_type, LPVOID
         DWORD session_id = ((WTSSESSION_NOTIFICATION*)event_data)->dwSessionId;
         vd_printf("Session %u %s", session_id, session_events[event_type]);
         SetServiceStatus(s->_status_handle, &s->_status);
-        if (s->_system_version != SYS_VER_UNSUPPORTED && event_type == WTS_CONSOLE_CONNECT) {
-            s->_session_id = session_id;
-            if (!s->restart_agent(true)) {
-                s->stop();
+        if (s->_system_version != SYS_VER_UNSUPPORTED) {
+            if (event_type == WTS_CONSOLE_CONNECT) {
+                s->_session_id = session_id;
+                if (!s->restart_agent(true)) {
+                    s->stop();
+               }
+            } else if (event_type == WTS_SESSION_LOGON) {
+                s->send_logon();
             }
         }
         break;
@@ -426,6 +435,7 @@ bool VDService::execute()
     _events[VD_EVENT_CONTROL] = _control_event;
     _events[VD_EVENT_READ] = _vdi_port->get_read_event();
     _events[VD_EVENT_WRITE] = _vdi_port->get_write_event();
+    _events[VD_EVENT_LOGON] = _logon_event;
     _events[VD_EVENT_AGENT] = _agent_proc_info.hProcess;
     _chunk_size = _chunk_port = 0;
     read_pipe();
@@ -484,6 +494,10 @@ bool VDService::execute()
             case WAIT_OBJECT_0 + VD_EVENT_WRITE:
                 _vdi_port->write_completion();
                 break;
+            case WAIT_OBJECT_0 + VD_EVENT_LOGON:
+                vd_printf("logon event");
+                write_agent_control(VD_AGENT_SESSION_LOGON, 0);
+                break;
             case WAIT_OBJECT_0 + VD_EVENT_AGENT:
                 vd_printf("Agent killed");
                 if (_system_version == SYS_VER_WIN_XP) {
@@ -874,6 +888,13 @@ void VDService::stop()
     }
 }
 
+void VDService::send_logon()
+{
+    if (_logon_event && !SetEvent(_logon_event)) {
+        vd_printf("SetEvent() failed: %u", GetLastError());
+    }
+}
+
 void VDService::pipe_write_completion()
 {
     VDPipeState* ps = &this->_pipe_state;
-- 
1.7.1.1



More information about the Spice-devel mailing list