[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, ®_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