[Spice-commits] common/vdcommon.h vdagent/desktop_layout.h vdagent/display_setting.cpp vdagent/display_setting.h vdagent/vdagent.cpp vdagent/vdagent.vcproj vdservice/vdservice.cpp

Yonit Halperin yhalperi at kemper.freedesktop.org
Tue Aug 24 00:49:10 PDT 2010


 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(-)

New commits:
commit 5833dc9760eaa9d9ae9ed46aeae5481f4052b5d5
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 8 13:06:57 2010 +0300

    Controlling Windows display settings (e.g., wallpaper, UI effects and font smoothing)
    
    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.

diff --git a/common/vdcommon.h b/common/vdcommon.h
index f097de4..1097720 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 dc8accb..a43ee49 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 b7510f2..b1f47c0 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 f7f6bef..108728b 100644
--- a/vdagent/vdagent.vcproj
+++ b/vdagent/vdagent.vcproj
@@ -498,6 +498,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\display_setting.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\vdagent.cpp"
 				>
 			</File>
@@ -516,6 +520,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\display_setting.h"
+				>
+			</File>
+			<File
 				RelativePath=".\resource.h"
 				>
 			</File>
diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index 157734b..6fec0c1 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;


More information about the Spice-commits mailing list