Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,92 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP Windows cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "wfreerdp-client")
set(MODULE_PREFIX "FREERDP_CLIENT_WINDOWS_CONTROL")
include(WarnUnmaintained)
warn_unmaintained(${MODULE_NAME} "-DWITH_CLIENT_WINDOWS=OFF")
set(${MODULE_PREFIX}_SRCS
wf_gdi.c
wf_gdi.h
wf_event.c
wf_event.h
wf_channels.c
wf_channels.h
wf_graphics.c
wf_graphics.h
wf_cliprdr.c
wf_cliprdr.h
wf_rail.c
wf_rail.h
wf_client.c
wf_client.h
wf_floatbar.c
wf_floatbar.h
wf_defaults.h
wf_defaults.c
resource/wfreerdp.rc
resource/resource.h
)
option(WITH_WINDOWS_CERT_STORE
"Build ${MODULE_NAME} with additional certificate validation against windows certificate store" ON
)
if(WITH_WINDOWS_CERT_STORE)
add_compile_definitions("WITH_WINDOWS_CERT_STORE")
endif()
option(WITH_WIN_CONSOLE "Build ${MODULE_NAME} with console support" OFF)
if(WITH_WIN_CONSOLE)
add_compile_definitions("WITH_WIN_CONSOLE")
set(WIN32_GUI_FLAG "TRUE")
else()
set(WIN32_GUI_FLAG "WIN32")
endif()
option(WITH_PROGRESS_BAR "Build ${MODULE_NAME} with connect progress bar (Windows 7+ or 2008 R2+)" ON)
if(WITH_PROGRESS_BAR)
add_compile_definitions("WITH_PROGRESS_BAR")
endif()
if(CLIENT_INTERFACE_SHARED)
addtargetwithresourcefile(${MODULE_NAME} "SHARED" "${FREERDP_VERSION}" ${MODULE_PREFIX}_SRCS)
else()
addtargetwithresourcefile(${MODULE_NAME} FALSE "${FREERDP_VERSION}" ${MODULE_PREFIX}_SRCS)
endif()
target_include_directories(${MODULE_NAME} INTERFACE $<INSTALL_INTERFACE:include>)
list(APPEND PUB_LIBS freerdp-client)
list(APPEND PUB_LIBS winpr freerdp)
list(APPEND PRIV_LIBS msimg32.lib credui.lib)
if(MINGW)
list(APPEND PRIV_LIBS ntdll.lib) # only required with MINGW
endif()
target_link_libraries(${MODULE_NAME} PUBLIC ${PUB_LIBS})
target_link_libraries(${MODULE_NAME} PRIVATE ${PRIV_LIBS})
if(WITH_CLIENT_INTERFACE)
install(TARGETS ${MODULE_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries
)
endif()
add_subdirectory(cli)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Windows")

View File

@@ -0,0 +1,3 @@
set(FREERDP_CLIENT_NAME "wfreerdp")
set(FREERDP_CLIENT_PLATFORM "Windows")
set(FREERDP_CLIENT_VENDOR "FreeRDP")

View File

@@ -0,0 +1,32 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP Windows cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "wfreerdp")
set(MODULE_PREFIX "FREERDP_CLIENT_WINDOWS")
include_directories(..)
set(${MODULE_PREFIX}_SRCS wfreerdp.c wfreerdp.h ../resource/wfreerdp.rc)
addtargetwithresourcefile(${MODULE_NAME} "${WIN32_GUI_FLAG}" "${FREERDP_VERSION}" ${MODULE_PREFIX}_SRCS)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} wfreerdp-client)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Windows")

View File

@@ -0,0 +1,152 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Client
*
* Copyright 2009-2011 Jay Sorg
* Copyright 2010-2011 Vic Lee
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <winpr/windows.h>
#include <winpr/crt.h>
#include <freerdp/freerdp.h>
#include <freerdp/constants.h>
#include <freerdp/client/file.h>
#include <freerdp/client/cmdline.h>
#include <freerdp/client/channels.h>
#include <freerdp/channels/channels.h>
#include "../resource/resource.h"
#include <wf_client.h>
#include <wf_defaults.h>
#include <shellapi.h>
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int status;
HANDLE thread;
wfContext* wfc;
DWORD dwExitCode;
rdpContext* context;
rdpSettings* settings;
LPWSTR cmd;
char** argv = nullptr;
RDP_CLIENT_ENTRY_POINTS clientEntryPoints = WINPR_C_ARRAY_INIT;
int ret = 1;
int argc = 0;
LPWSTR* args = nullptr;
WINPR_UNUSED(hInstance);
WINPR_UNUSED(hPrevInstance);
WINPR_UNUSED(lpCmdLine);
WINPR_UNUSED(nCmdShow);
RdpClientEntry(&clientEntryPoints);
context = freerdp_client_context_new(&clientEntryPoints);
if (!context)
return -1;
cmd = GetCommandLineW();
if (!cmd)
goto out;
args = CommandLineToArgvW(cmd, &argc);
if (!args || (argc <= 0))
goto out;
argv = calloc((size_t)argc, sizeof(char*));
if (!argv)
goto out;
for (int i = 0; i < argc; i++)
{
int size = WideCharToMultiByte(CP_UTF8, 0, args[i], -1, nullptr, 0, nullptr, nullptr);
if (size <= 0)
goto out;
argv[i] = calloc((size_t)size, sizeof(char));
if (!argv[i])
goto out;
if (WideCharToMultiByte(CP_UTF8, 0, args[i], -1, argv[i], size, nullptr, nullptr) != size)
goto out;
}
freerdp_client_warn_deprecated(argc, argv);
settings = context->settings;
wfc = (wfContext*)context;
if (!settings || !wfc)
goto out;
status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE);
if (status)
{
ret = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
goto out;
}
AddDefaultSettings(settings);
if (freerdp_client_start(context) != 0)
goto out;
thread = freerdp_client_get_thread(context);
if (thread)
{
if (WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0)
{
GetExitCodeThread(thread, &dwExitCode);
ret = (int)dwExitCode;
}
}
if (freerdp_client_stop(context) != 0)
goto out;
out:
freerdp_client_context_free(context);
if (argv)
{
for (int i = 0; i < argc; i++)
free(argv[i]);
free(argv);
}
LocalFree(args);
return ret;
}
#ifdef WITH_WIN_CONSOLE
int main()
{
return WinMain(nullptr, nullptr, nullptr, 0);
}
#endif

View File

@@ -0,0 +1,27 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Client
*
* Copyright 2009-2011 Jay Sorg
* Copyright 2010-2011 Vic Lee
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_FREERDP_H
#define FREERDP_CLIENT_WIN_FREERDP_H
#include "wf_interface.h"
#endif /* FREERDP_CLIENT_WIN_FREERDP_H */

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,12 @@
#define IDI_ICON1 101
#define IDB_MINIMIZE 103
#define IDB_MINIMIZE_ACT 104
#define IDB_LOCK 105
#define IDB_LOCK_ACT 106
#define IDB_UNLOCK 107
#define IDB_UNLOCK_ACT 108
#define IDB_CLOSE 109
#define IDB_CLOSE_ACT 100
#define IDB_RESTORE 111
#define IDB_RESTORE_ACT 112

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,14 @@
#include "resource.h"
IDI_ICON1 ICON "FreeRDP.ico"
IDB_MINIMIZE BITMAP "minimize.bmp"
IDB_MINIMIZE_ACT BITMAP "minimize_active.bmp"
IDB_LOCK BITMAP "lock.bmp"
IDB_LOCK_ACT BITMAP "lock_active.bmp"
IDB_UNLOCK BITMAP "unlock.bmp"
IDB_UNLOCK_ACT BITMAP "unlock_active.bmp"
IDB_CLOSE BITMAP "close.bmp"
IDB_CLOSE_ACT BITMAP "close_active.bmp"
IDB_RESTORE BITMAP "restore.bmp"
IDB_RESTORE_ACT BITMAP "restore_active.bmp"

View File

@@ -0,0 +1,86 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <winpr/assert.h>
#include "wf_channels.h"
#include "wf_rail.h"
#include "wf_cliprdr.h"
#include <freerdp/gdi/gfx.h>
#include <freerdp/gdi/video.h>
#include <freerdp/log.h>
#define TAG CLIENT_TAG("windows")
void wf_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e)
{
wfContext* wfc = (wfContext*)context;
rdpSettings* settings;
WINPR_ASSERT(wfc);
WINPR_ASSERT(e);
settings = wfc->common.context.settings;
WINPR_ASSERT(settings);
if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
{
wf_rail_init(wfc, (RailClientContext*)e->pInterface);
}
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
{
wf_cliprdr_init(wfc, (CliprdrClientContext*)e->pInterface);
}
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
{
wfc->disp = (DispClientContext*)e->pInterface;
}
else
freerdp_client_OnChannelConnectedEventHandler(context, e);
}
void wf_OnChannelDisconnectedEventHandler(void* context, const ChannelDisconnectedEventArgs* e)
{
wfContext* wfc = (wfContext*)context;
rdpSettings* settings;
WINPR_ASSERT(wfc);
WINPR_ASSERT(e);
settings = wfc->common.context.settings;
WINPR_ASSERT(settings);
if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
{
wf_rail_uninit(wfc, (RailClientContext*)e->pInterface);
}
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
{
wf_cliprdr_uninit(wfc, (CliprdrClientContext*)e->pInterface);
}
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
{
wfc->disp = nullptr;
}
else
freerdp_client_OnChannelDisconnectedEventHandler(context, e);
}

View File

@@ -0,0 +1,36 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_CHANNELS_H
#define FREERDP_CLIENT_WIN_CHANNELS_H
#include <freerdp/freerdp.h>
#include <freerdp/client.h>
#include <freerdp/client/channels.h>
#include <freerdp/client/rdpei.h>
#include <freerdp/client/rdpgfx.h>
#include <freerdp/client/encomsp.h>
#include <freerdp/client/cliprdr.h>
#include <freerdp/client/disp.h>
#include "wf_client.h"
void wf_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e);
void wf_OnChannelDisconnectedEventHandler(void* context, const ChannelDisconnectedEventArgs* e);
#endif /* FREERDP_CLIENT_WIN_CHANNELS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,158 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Client
*
* Copyright 2009-2011 Jay Sorg
* Copyright 2010-2011 Vic Lee
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_INTERFACE_H
#define FREERDP_CLIENT_WIN_INTERFACE_H
#include <winpr/windows.h>
#include <winpr/collections.h>
#ifdef WITH_PROGRESS_BAR
#include <shobjidl.h>
#endif
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/gdi/dc.h>
#include <freerdp/gdi/region.h>
#include <freerdp/codec/color.h>
#include <freerdp/client/rail.h>
#include <freerdp/channels/channels.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/client/file.h>
#include "wf_channels.h"
#include "wf_floatbar.h"
#include "wf_event.h"
#include "wf_cliprdr.h"
#ifdef __cplusplus
extern "C"
{
#endif
// System menu constants
#define SYSCOMMAND_ID_SMARTSIZING 1000
#define SYSCOMMAND_ID_REQUEST_CONTROL 1001
typedef struct
{
rdpBitmap _bitmap;
HDC hdc;
HBITMAP bitmap;
HBITMAP org_bitmap;
BYTE* pdata;
} wfBitmap;
typedef struct
{
rdpPointer pointer;
HCURSOR cursor;
} wfPointer;
struct wf_context
{
rdpClientContext common;
int offset_x;
int offset_y;
int fullscreen_toggle;
int fullscreen;
int percentscreen;
WCHAR* window_title;
int client_x;
int client_y;
int client_width;
int client_height;
HANDLE keyboardThread;
HICON icon;
HWND hWndParent;
HINSTANCE hInstance;
WNDCLASSEX wndClass;
LPCTSTR wndClassName;
HCURSOR hDefaultCursor;
UINT systemMenuInsertPosition;
HWND hwnd;
BOOL is_shown;
ITaskbarList3* taskBarList;
POINT diff;
wfBitmap* primary;
wfBitmap* drawing;
HCURSOR cursor;
HBRUSH brush;
HBRUSH org_brush;
RECT update_rect;
RECT scale_update_rect;
DWORD mainThreadId;
DWORD keyboardThreadId;
rdpFile* connectionRdpFile;
BOOL disablewindowtracking;
BOOL updating_scrollbars;
BOOL xScrollVisible;
int xMinScroll;
int xCurrentScroll;
int xMaxScroll;
BOOL yScrollVisible;
int yMinScroll;
int yCurrentScroll;
int yMaxScroll;
void* clipboard;
CliprdrClientContext* cliprdr;
wfFloatBar* floatbar;
RailClientContext* rail;
wHashTable* railWindows;
BOOL isConsole;
DispClientContext* disp;
UINT64 lastSentDate;
BOOL wasMaximized;
};
/**
* Client Interface
*/
FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints);
FREERDP_API int freerdp_client_set_window_size(wfContext* wfc, int width, int height);
FREERDP_API void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, UINT32 client_height);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_CLIENT_WIN_INTERFACE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Clipboard Redirection
*
* Copyright 2012 Jason Champion
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_CLIPRDR_H
#define FREERDP_CLIENT_WIN_CLIPRDR_H
#include "wf_client.h"
BOOL wf_cliprdr_init(wfContext* wfc, CliprdrClientContext* cliprdr);
BOOL wf_cliprdr_uninit(wfContext* wfc, CliprdrClientContext* cliprdr);
#endif /* FREERDP_CLIENT_WIN_CLIPRDR_H */

View File

@@ -0,0 +1,164 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2022 Stefan Koell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <windows.h>
#include <wincred.h>
#include <stdio.h>
#include <malloc.h>
#include <freerdp/settings.h>
#include "wf_defaults.h"
static PCWSTR ValidateString(const BYTE* pb, ULONG cb)
{
if (!pb || !cb)
return 0;
if (cb % sizeof(WCHAR) != 0)
return 0;
return (PCWSTR)pb;
}
static void AddDefaultSettings_I(rdpSettings* settings, size_t idHostname, size_t idUsername,
size_t idDomain, size_t idPassword)
{
static const PSTR TERMSRV = "TERMSRV/%s";
PSTR TargetName = nullptr;
PSTR UserName = nullptr;
PWSTR TargetNameW = nullptr;
PWSTR ServerHostNameW = nullptr;
PWSTR ParsedUserNameW = nullptr;
PWSTR ParsedDomainW = nullptr;
PWSTR PasswordNullTerminatedW = nullptr;
PCREDENTIALW Credential = WINPR_C_ARRAY_INIT;
PCSTR ServerHostname = freerdp_settings_get_string(settings, idHostname);
if (!ServerHostname)
return;
BOOL bExistUserName = freerdp_settings_get_string(settings, idUsername) != 0;
BOOL bExistPassword = freerdp_settings_get_string(settings, idPassword) != 0;
if (bExistUserName && bExistPassword)
return;
int len = _snprintf(TargetName, 0, TERMSRV, ServerHostname);
if (len < 0)
goto fail;
len++;
TargetName = (PSTR)malloc(len);
if (!TargetName)
goto fail;
_snprintf(TargetName, len, TERMSRV, ServerHostname);
TargetName[len - 1] = 0;
TargetNameW = ConvertUtf8ToWCharAlloc(TargetName, nullptr);
if (!TargetNameW)
goto fail;
if (!CredReadW(TargetNameW, CRED_TYPE_GENERIC, 0, &Credential))
goto fail;
if (!bExistPassword)
{
const WCHAR* PasswordW =
ValidateString(Credential->CredentialBlob, Credential->CredentialBlobSize);
PasswordNullTerminatedW = (PWSTR)calloc(Credential->CredentialBlobSize + 1, sizeof(WCHAR));
if (!PasswordNullTerminatedW)
goto fail;
memcpy(PasswordNullTerminatedW, PasswordW, Credential->CredentialBlobSize * sizeof(WCHAR));
if (PasswordNullTerminatedW)
{
if (!freerdp_settings_set_string_from_utf16(settings, idPassword,
PasswordNullTerminatedW))
{
goto fail;
}
}
}
if (!bExistUserName)
{
const WCHAR* UserNameW = Credential->UserName;
if (UserNameW)
{
ParsedUserNameW = calloc(CREDUI_MAX_USERNAME_LENGTH + 1, sizeof(WCHAR));
if (!ParsedUserNameW)
goto fail;
ParsedDomainW = calloc(CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1, sizeof(WCHAR));
if (!ParsedDomainW)
goto fail;
DWORD ParseResult =
CredUIParseUserNameW(UserNameW, ParsedUserNameW, CREDUI_MAX_USERNAME_LENGTH + 1,
ParsedDomainW, CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1);
if (ParseResult == NO_ERROR)
{
if (!freerdp_settings_set_string_from_utf16(settings, idUsername, ParsedUserNameW))
goto fail;
if (*ParsedDomainW != 0)
{
if (!freerdp_settings_set_string_from_utf16(settings, idDomain, ParsedDomainW))
goto fail;
}
}
else if (ParseResult == ERROR_INVALID_ACCOUNT_NAME)
{
if (!freerdp_settings_set_string_from_utf16(settings, idUsername, UserNameW))
goto fail;
}
}
}
fail:
if (Credential)
{
CredFree(Credential);
}
free(TargetName);
free(UserName);
free(TargetNameW);
free(ServerHostNameW);
free(ParsedUserNameW);
free(ParsedDomainW);
free(PasswordNullTerminatedW);
return;
}
void WINAPI AddDefaultSettings(rdpSettings* settings)
{
AddDefaultSettings_I(settings, FreeRDP_ServerHostname, FreeRDP_Username, FreeRDP_Domain,
FreeRDP_Password);
AddDefaultSettings_I(settings, FreeRDP_GatewayHostname, FreeRDP_GatewayUsername,
FreeRDP_GatewayDomain, FreeRDP_GatewayPassword);
}

View File

@@ -0,0 +1,28 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2022 Stefan Koell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_DEFAULTS_H
#define FREERDP_CLIENT_WIN_DEFAULTS_H
#include <winpr/wtypes.h>
#include <freerdp/api.h>
#include <freerdp/settings.h>
FREERDP_API void WINAPI AddDefaultSettings(_Inout_ rdpSettings* settings);
#endif /* FREERDP_CLIENT_WIN_DEFAULTS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Event Handling
*
* Copyright 2009-2011 Jay Sorg
* Copyright 2010-2011 Vic Lee
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_EVENT_H
#define FREERDP_CLIENT_WIN_EVENT_H
#include "wf_client.h"
#include <freerdp/log.h>
LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
void wf_event_focus_in(wfContext* wfc);
BOOL wf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags);
#define KBD_TAG CLIENT_TAG("windows")
#ifdef WITH_DEBUG_KBD
#define DEBUG_KBD(...) WLog_DBG(KBD_TAG, __VA_ARGS__)
#else
#define DEBUG_KBD(...) \
do \
{ \
} while (0)
#endif
#endif /* FREERDP_CLIENT_WIN_EVENT_H */

View File

@@ -0,0 +1,733 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Float Bar
*
* Copyright 2013 Zhang Zhaolong <zhangzl2013@126.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/crt.h>
#include <winpr/windows.h>
#include "wf_client.h"
#include "wf_floatbar.h"
#include "resource/resource.h"
#include "wf_gdi.h"
#ifdef _MSC_VER
#pragma comment(lib, "Msimg32.lib")
#endif
#define TAG CLIENT_TAG("windows.floatbar")
/* TIMERs */
#define TIMER_HIDE 1
#define TIMER_ANIMAT_SHOW 2
#define TIMER_ANIMAT_HIDE 3
/* Button Type */
#define BUTTON_LOCKPIN 0
#define BUTTON_MINIMIZE 1
#define BUTTON_RESTORE 2
#define BUTTON_CLOSE 3
#define BTN_MAX 4
/* bmp size */
#define BACKGROUND_W 576
#define BACKGROUND_H 27
#define BUTTON_OFFSET 5
#define BUTTON_Y 2
#define BUTTON_WIDTH 23
#define BUTTON_HEIGHT 21
#define BUTTON_SPACING 1
#define LOCK_X (BACKGROUND_H + BUTTON_OFFSET)
#define CLOSE_X ((BACKGROUND_W - (BACKGROUND_H + BUTTON_OFFSET)) - BUTTON_WIDTH)
#define RESTORE_X (CLOSE_X - (BUTTON_WIDTH + BUTTON_SPACING))
#define MINIMIZE_X (RESTORE_X - (BUTTON_WIDTH + BUTTON_SPACING))
#define TEXT_X (BACKGROUND_H + ((BUTTON_WIDTH + BUTTON_SPACING) * 3) + 5)
typedef struct
{
wfFloatBar* floatbar;
int type;
int x, y, h, w;
int active;
HBITMAP bmp;
HBITMAP bmp_act;
/* Lock Specified */
HBITMAP locked_bmp;
HBITMAP locked_bmp_act;
HBITMAP unlocked_bmp;
HBITMAP unlocked_bmp_act;
} Button;
struct s_FloatBar
{
HINSTANCE root_window;
DWORD flags;
HWND parent;
HWND hwnd;
RECT rect;
LONG width;
LONG height;
LONG offset;
wfContext* wfc;
Button* buttons[BTN_MAX];
BOOL shown;
BOOL locked;
HDC hdcmem;
RECT textRect;
UINT_PTR animating;
};
static BOOL floatbar_kill_timers(wfFloatBar* floatbar)
{
UINT_PTR timers[] = { TIMER_HIDE, TIMER_ANIMAT_HIDE, TIMER_ANIMAT_SHOW };
if (!floatbar)
return FALSE;
for (size_t x = 0; x < ARRAYSIZE(timers); x++)
KillTimer(floatbar->hwnd, timers[x]);
floatbar->animating = 0;
return TRUE;
}
static BOOL floatbar_animation(wfFloatBar* const floatbar, const BOOL show)
{
UINT_PTR timer = show ? TIMER_ANIMAT_SHOW : TIMER_ANIMAT_HIDE;
if (!floatbar)
return FALSE;
if (floatbar->shown == show)
return TRUE;
if (floatbar->animating == timer)
return TRUE;
floatbar->animating = timer;
if (SetTimer(floatbar->hwnd, timer, USER_TIMER_MINIMUM, nullptr) == 0)
{
DWORD err = GetLastError();
WLog_ERR(TAG, "SetTimer failed with %08" PRIx32, err);
return FALSE;
}
return TRUE;
}
static BOOL floatbar_trigger_hide(wfFloatBar* floatbar)
{
if (!floatbar_kill_timers(floatbar))
return FALSE;
if (!floatbar->locked && floatbar->shown)
{
if (SetTimer(floatbar->hwnd, TIMER_HIDE, 3000, nullptr) == 0)
{
DWORD err = GetLastError();
WLog_ERR(TAG, "SetTimer failed with %08" PRIx32, err);
return FALSE;
}
}
return TRUE;
}
static BOOL floatbar_hide(wfFloatBar* floatbar)
{
if (!floatbar_kill_timers(floatbar))
return FALSE;
floatbar->offset = floatbar->height - 2;
if (!MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset, floatbar->width,
floatbar->height, TRUE))
{
DWORD err = GetLastError();
WLog_ERR(TAG, "MoveWindow failed with %08" PRIx32, err);
return FALSE;
}
floatbar->shown = FALSE;
if (!floatbar_trigger_hide(floatbar))
return FALSE;
return TRUE;
}
static BOOL floatbar_show(wfFloatBar* floatbar)
{
if (!floatbar_kill_timers(floatbar))
return FALSE;
floatbar->offset = 0;
if (!MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset, floatbar->width,
floatbar->height, TRUE))
{
DWORD err = GetLastError();
WLog_ERR(TAG, "MoveWindow failed with %08" PRIx32, err);
return FALSE;
}
floatbar->shown = TRUE;
if (!floatbar_trigger_hide(floatbar))
return FALSE;
return TRUE;
}
static BOOL button_set_locked(Button* button, BOOL locked)
{
if (locked)
{
button->bmp = button->locked_bmp;
button->bmp_act = button->locked_bmp_act;
}
else
{
button->bmp = button->unlocked_bmp;
button->bmp_act = button->unlocked_bmp_act;
}
InvalidateRect(button->floatbar->hwnd, nullptr, FALSE);
UpdateWindow(button->floatbar->hwnd);
return TRUE;
}
static BOOL update_locked_state(wfFloatBar* floatbar)
{
Button* button;
if (!floatbar)
return FALSE;
button = floatbar->buttons[3];
if (!button_set_locked(button, floatbar->locked))
return FALSE;
return TRUE;
}
static int button_hit(Button* const button)
{
wfFloatBar* const floatbar = button->floatbar;
switch (button->type)
{
case BUTTON_LOCKPIN:
floatbar->locked = !floatbar->locked;
update_locked_state(floatbar);
break;
case BUTTON_MINIMIZE:
ShowWindow(floatbar->parent, SW_MINIMIZE);
break;
case BUTTON_RESTORE:
wf_toggle_fullscreen(floatbar->wfc);
break;
case BUTTON_CLOSE:
SendMessage(floatbar->parent, WM_DESTROY, 0, 0);
break;
default:
return 0;
}
return 0;
}
static int button_paint(const Button* const button, const HDC hdc)
{
if (button != nullptr)
{
wfFloatBar* floatbar = button->floatbar;
BLENDFUNCTION bf;
SelectObject(floatbar->hdcmem, button->active ? button->bmp_act : button->bmp);
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
AlphaBlend(hdc, button->x, button->y, button->w, button->h, floatbar->hdcmem, 0, 0,
button->w, button->h, bf);
}
return 0;
}
static Button* floatbar_create_button(wfFloatBar* const floatbar, const int type, const int resid,
const int resid_act, const int x, const int y, const int h,
const int w)
{
Button* button = (Button*)calloc(1, sizeof(Button));
if (!button)
return nullptr;
button->floatbar = floatbar;
button->type = type;
button->x = x;
button->y = y;
button->w = w;
button->h = h;
button->active = FALSE;
button->bmp = (HBITMAP)LoadImage(floatbar->root_window, MAKEINTRESOURCE(resid), IMAGE_BITMAP, 0,
0, LR_DEFAULTCOLOR);
button->bmp_act = (HBITMAP)LoadImage(floatbar->root_window, MAKEINTRESOURCE(resid_act),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
return button;
}
static Button* floatbar_create_lock_button(wfFloatBar* const floatbar, const int unlock_resid,
const int unlock_resid_act, const int lock_resid,
const int lock_resid_act, const int x, const int y,
const int h, const int w)
{
Button* button = floatbar_create_button(floatbar, BUTTON_LOCKPIN, unlock_resid,
unlock_resid_act, x, y, h, w);
if (!button)
return nullptr;
button->unlocked_bmp = button->bmp;
button->unlocked_bmp_act = button->bmp_act;
button->locked_bmp = (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(lock_resid),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
button->locked_bmp_act =
(HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(lock_resid_act), IMAGE_BITMAP,
0, 0, LR_DEFAULTCOLOR);
return button;
}
static Button* floatbar_get_button(const wfFloatBar* const floatbar, const int x, const int y)
{
if ((y > BUTTON_Y) && (y < BUTTON_Y + BUTTON_HEIGHT))
{
for (int i = 0; i < BTN_MAX; i++)
{
if ((floatbar->buttons[i] != nullptr) && (x > floatbar->buttons[i]->x) &&
(x < floatbar->buttons[i]->x + floatbar->buttons[i]->w))
{
return floatbar->buttons[i];
}
}
}
return nullptr;
}
static BOOL floatbar_paint(wfFloatBar* const floatbar, const HDC hdc)
{
HPEN hpen;
HGDIOBJECT orig;
/* paint background */
GRADIENT_RECT gradientRect = { 0, 1 };
COLORREF rgbTop = RGB(117, 154, 198);
COLORREF rgbBottom = RGB(6, 55, 120);
const int top = 0;
int left = 0;
int bottom = BACKGROUND_H - 1;
int right = BACKGROUND_W - 1;
const int angleOffset = BACKGROUND_H - 1;
TRIVERTEX triVertext[2] = { { left, top, GetRValue(rgbTop) << 8, GetGValue(rgbTop) << 8,
GetBValue(rgbTop) << 8, 0x0000 },
{ right, bottom, GetRValue(rgbBottom) << 8,
GetGValue(rgbBottom) << 8, GetBValue(rgbBottom) << 8, 0x0000 } };
if (!floatbar)
return FALSE;
GradientFill(hdc, triVertext, 2, &gradientRect, 1, GRADIENT_FILL_RECT_V);
/* paint shadow */
hpen = CreatePen(PS_SOLID, 1, RGB(71, 71, 71));
orig = SelectObject(hdc, hpen);
MoveToEx(hdc, left, top, nullptr);
LineTo(hdc, left + angleOffset, bottom);
LineTo(hdc, right - angleOffset, bottom);
LineTo(hdc, right + 1, top - 1);
DeleteObject(hpen);
hpen = CreatePen(PS_SOLID, 1, RGB(107, 141, 184));
SelectObject(hdc, hpen);
left += 1;
bottom -= 1;
right -= 1;
MoveToEx(hdc, left, top, nullptr);
LineTo(hdc, left + (angleOffset - 1), bottom);
LineTo(hdc, right - (angleOffset - 1), bottom);
LineTo(hdc, right + 1, top - 1);
DeleteObject(hpen);
SelectObject(hdc, orig);
const size_t wlen = wcslen(floatbar->wfc->window_title);
DrawText(hdc, floatbar->wfc->window_title, WINPR_ASSERTING_INT_CAST(int, wlen),
&floatbar->textRect,
DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE);
/* paint buttons */
for (int i = 0; i < BTN_MAX; i++)
button_paint(floatbar->buttons[i], hdc);
return TRUE;
}
static LRESULT CALLBACK floatbar_proc(const HWND hWnd, const UINT Msg, const WPARAM wParam,
const LPARAM lParam)
{
static int dragging = FALSE;
static int lbtn_dwn = FALSE;
static int btn_dwn_x = 0;
static wfFloatBar* floatbar;
static TRACKMOUSEEVENT tme;
PAINTSTRUCT ps;
Button* button;
HDC hdc;
int pos_x;
int pos_y;
NONCLIENTMETRICS ncm;
int xScreen = GetSystemMetrics(SM_CXSCREEN);
switch (Msg)
{
case WM_CREATE:
floatbar = ((wfFloatBar*)((CREATESTRUCT*)lParam)->lpCreateParams);
floatbar->hwnd = hWnd;
GetWindowRect(floatbar->hwnd, &floatbar->rect);
floatbar->width = floatbar->rect.right - floatbar->rect.left;
floatbar->height = floatbar->rect.bottom - floatbar->rect.top;
hdc = GetDC(hWnd);
floatbar->hdcmem = CreateCompatibleDC(hdc);
ReleaseDC(hWnd, hdc);
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
tme.dwHoverTime = HOVER_DEFAULT;
// Use caption font, white, draw transparent
GetClientRect(hWnd, &floatbar->textRect);
InflateRect(&floatbar->textRect, -TEXT_X, 0);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(255, 255, 255));
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
SelectObject(hdc, CreateFontIndirect(&ncm.lfCaptionFont));
floatbar_trigger_hide(floatbar);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
floatbar_paint(floatbar, hdc);
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
pos_x = lParam & 0xffff;
pos_y = (lParam >> 16) & 0xffff;
button = floatbar_get_button(floatbar, pos_x, pos_y);
if (!button)
{
SetCapture(hWnd);
dragging = TRUE;
btn_dwn_x = lParam & 0xffff;
}
else
lbtn_dwn = TRUE;
break;
case WM_LBUTTONUP:
pos_x = lParam & 0xffff;
pos_y = (lParam >> 16) & 0xffff;
ReleaseCapture();
dragging = FALSE;
if (lbtn_dwn)
{
button = floatbar_get_button(floatbar, pos_x, pos_y);
if (button)
button_hit(button);
lbtn_dwn = FALSE;
}
break;
case WM_MOUSEMOVE:
pos_x = lParam & 0xffff;
pos_y = (lParam >> 16) & 0xffff;
if (!floatbar->locked)
floatbar_animation(floatbar, TRUE);
if (dragging)
{
floatbar->rect.left = floatbar->rect.left + (lParam & 0xffff) - btn_dwn_x;
if (floatbar->rect.left < 0)
floatbar->rect.left = 0;
else if (floatbar->rect.left > xScreen - floatbar->width)
floatbar->rect.left = xScreen - floatbar->width;
MoveWindow(hWnd, floatbar->rect.left, 0, floatbar->width, floatbar->height, TRUE);
}
else
{
for (int i = 0; i < BTN_MAX; i++)
{
if (floatbar->buttons[i] != nullptr)
{
floatbar->buttons[i]->active = FALSE;
}
}
button = floatbar_get_button(floatbar, pos_x, pos_y);
if (button)
button->active = TRUE;
InvalidateRect(hWnd, nullptr, FALSE);
UpdateWindow(hWnd);
}
TrackMouseEvent(&tme);
break;
case WM_CAPTURECHANGED:
dragging = FALSE;
break;
case WM_MOUSELEAVE:
{
for (int i = 0; i < BTN_MAX; i++)
{
if (floatbar->buttons[i] != nullptr)
{
floatbar->buttons[i]->active = FALSE;
}
}
InvalidateRect(hWnd, nullptr, FALSE);
UpdateWindow(hWnd);
floatbar_trigger_hide(floatbar);
break;
}
case WM_TIMER:
switch (wParam)
{
case TIMER_HIDE:
floatbar_animation(floatbar, FALSE);
break;
case TIMER_ANIMAT_SHOW:
{
floatbar->offset--;
MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset,
floatbar->width, floatbar->height, TRUE);
if (floatbar->offset <= 0)
floatbar_show(floatbar);
break;
}
case TIMER_ANIMAT_HIDE:
{
floatbar->offset++;
MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset,
floatbar->width, floatbar->height, TRUE);
if (floatbar->offset >= floatbar->height - 2)
floatbar_hide(floatbar);
break;
}
default:
break;
}
break;
case WM_DESTROY:
DeleteDC(floatbar->hdcmem);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}
static BOOL floatbar_window_create(wfFloatBar* floatbar)
{
WNDCLASSEX wnd_cls;
HWND barWnd;
HRGN hRgn;
POINT pt[4];
RECT rect;
LONG x;
if (!floatbar)
return FALSE;
if (!GetWindowRect(floatbar->parent, &rect))
return FALSE;
x = (rect.right - rect.left - BACKGROUND_W) / 2;
wnd_cls.cbSize = sizeof(WNDCLASSEX);
wnd_cls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wnd_cls.lpfnWndProc = floatbar_proc;
wnd_cls.cbClsExtra = 0;
wnd_cls.cbWndExtra = 0;
wnd_cls.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wnd_cls.hCursor = LoadCursor(floatbar->root_window, IDC_ARROW);
wnd_cls.hbrBackground = nullptr;
wnd_cls.lpszMenuName = nullptr;
wnd_cls.lpszClassName = L"floatbar";
wnd_cls.hInstance = floatbar->root_window;
wnd_cls.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
RegisterClassEx(&wnd_cls);
barWnd =
CreateWindowEx(WS_EX_TOPMOST, L"floatbar", L"floatbar", WS_CHILD, x, 0, BACKGROUND_W,
BACKGROUND_H, floatbar->parent, nullptr, floatbar->root_window, floatbar);
if (barWnd == nullptr)
return FALSE;
pt[0].x = 0;
pt[0].y = 0;
pt[1].x = BACKGROUND_W;
pt[1].y = 0;
pt[2].x = BACKGROUND_W - BACKGROUND_H;
pt[2].y = BACKGROUND_H;
pt[3].x = BACKGROUND_H;
pt[3].y = BACKGROUND_H;
hRgn = CreatePolygonRgn(pt, 4, ALTERNATE);
SetWindowRgn(barWnd, hRgn, TRUE);
return TRUE;
}
void wf_floatbar_free(wfFloatBar* floatbar)
{
if (!floatbar)
return;
free(floatbar);
}
wfFloatBar* wf_floatbar_new(wfContext* wfc, HINSTANCE window, DWORD flags)
{
wfFloatBar* floatbar;
/* Floatbar not enabled */
if ((flags & 0x0001) == 0)
return nullptr;
if (!wfc)
return nullptr;
// TODO: Disable for remote app
floatbar = (wfFloatBar*)calloc(1, sizeof(wfFloatBar));
if (!floatbar)
return nullptr;
floatbar->root_window = window;
floatbar->flags = flags;
floatbar->wfc = wfc;
floatbar->locked = (flags & 0x0002) != 0;
floatbar->shown = (flags & 0x0006) != 0; /* If it is loked or shown show it */
floatbar->hwnd = nullptr;
floatbar->parent = wfc->hwnd;
floatbar->hdcmem = nullptr;
if (wfc->fullscreen_toggle)
{
floatbar->buttons[0] =
floatbar_create_button(floatbar, BUTTON_MINIMIZE, IDB_MINIMIZE, IDB_MINIMIZE_ACT,
MINIMIZE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
floatbar->buttons[1] =
floatbar_create_button(floatbar, BUTTON_RESTORE, IDB_RESTORE, IDB_RESTORE_ACT,
RESTORE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
}
else
{
floatbar->buttons[0] = nullptr;
floatbar->buttons[1] = nullptr;
}
floatbar->buttons[2] = floatbar_create_button(floatbar, BUTTON_CLOSE, IDB_CLOSE, IDB_CLOSE_ACT,
CLOSE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
floatbar->buttons[3] =
floatbar_create_lock_button(floatbar, IDB_UNLOCK, IDB_UNLOCK_ACT, IDB_LOCK, IDB_LOCK_ACT,
LOCK_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
if (!floatbar_window_create(floatbar))
goto fail;
if (!update_locked_state(floatbar))
goto fail;
if (!wf_floatbar_toggle_fullscreen(
floatbar, freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_Fullscreen)))
goto fail;
return floatbar;
fail:
wf_floatbar_free(floatbar);
return nullptr;
}
BOOL wf_floatbar_toggle_fullscreen(wfFloatBar* floatbar, BOOL fullscreen)
{
BOOL show_fs, show_wn;
if (!floatbar)
return FALSE;
show_fs = (floatbar->flags & 0x0010) != 0;
show_wn = (floatbar->flags & 0x0020) != 0;
if ((show_fs && fullscreen) || (show_wn && !fullscreen))
{
ShowWindow(floatbar->hwnd, SW_SHOWNORMAL);
Sleep(10);
if (floatbar->shown)
floatbar_show(floatbar);
else
floatbar_hide(floatbar);
}
else
{
ShowWindow(floatbar->hwnd, SW_HIDE);
}
return TRUE;
}

View File

@@ -0,0 +1,33 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Float Bar
*
* Copyright 2013 Zhang Zhaolong <zhangzl2013@126.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_FLOATBAR_H
#define FREERDP_CLIENT_WIN_FLOATBAR_H
#include <winpr/crt.h>
typedef struct s_FloatBar wfFloatBar;
typedef struct wf_context wfContext;
wfFloatBar* wf_floatbar_new(wfContext* wfc, HINSTANCE window, DWORD flags);
void wf_floatbar_free(wfFloatBar* floatbar);
BOOL wf_floatbar_toggle_fullscreen(wfFloatBar* floatbar, BOOL fullscreen);
#endif /* FREERDP_CLIENT_WIN_FLOATBAR_H */

View File

@@ -0,0 +1,864 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows GDI
*
* Copyright 2009-2011 Jay Sorg
* Copyright 2010-2011 Vic Lee
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <freerdp/log.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/constants.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/gdi/gdi.h>
#include "wf_client.h"
#include "wf_graphics.h"
#include "wf_gdi.h"
#define TAG CLIENT_TAG("windows.gdi")
static const BYTE wf_rop2_table[] = {
R2_BLACK, /* 0 */
R2_NOTMERGEPEN, /* DPon */
R2_MASKNOTPEN, /* DPna */
R2_NOTCOPYPEN, /* Pn */
R2_MASKPENNOT, /* PDna */
R2_NOT, /* Dn */
R2_XORPEN, /* DPx */
R2_NOTMASKPEN, /* DPan */
R2_MASKPEN, /* DPa */
R2_NOTXORPEN, /* DPxn */
R2_NOP, /* D */
R2_MERGENOTPEN, /* DPno */
R2_COPYPEN, /* P */
R2_MERGEPENNOT, /* PDno */
R2_MERGEPEN, /* PDo */
R2_WHITE, /* 1 */
};
static BOOL wf_decode_color(wfContext* wfc, const UINT32 srcColor, COLORREF* color, UINT32* format)
{
rdpGdi* gdi;
rdpSettings* settings;
UINT32 SrcFormat, DstFormat;
if (!wfc)
return FALSE;
gdi = wfc->common.context.gdi;
settings = wfc->common.context.settings;
if (!gdi || !settings)
return FALSE;
SrcFormat = gdi_get_pixel_format(freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
if (format)
*format = SrcFormat;
switch (FreeRDPGetBitsPerPixel(gdi->dstFormat))
{
case 32:
DstFormat = PIXEL_FORMAT_ABGR32;
break;
case 24:
DstFormat = PIXEL_FORMAT_BGR24;
break;
case 16:
DstFormat = PIXEL_FORMAT_RGB16;
break;
default:
return FALSE;
}
*color = FreeRDPConvertColor(srcColor, SrcFormat, DstFormat, &gdi->palette);
return TRUE;
}
static BOOL wf_set_rop2(HDC hdc, int rop2)
{
if ((rop2 < 0x01) || (rop2 > 0x10))
{
WLog_ERR(TAG, "Unsupported ROP2: %d", rop2);
return FALSE;
}
SetROP2(hdc, wf_rop2_table[rop2 - 1]);
return TRUE;
}
static wfBitmap* wf_glyph_new(wfContext* wfc, GLYPH_DATA* glyph)
{
wfBitmap* glyph_bmp;
glyph_bmp = wf_image_new(wfc, glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, glyph->aj);
if (!glyph_bmp)
WLog_ERR(TAG, "wf_image_new failed for glyph");
return glyph_bmp;
}
static void wf_glyph_free(wfBitmap* glyph)
{
wf_image_free(glyph);
}
static BYTE* wf_glyph_convert(wfContext* wfc, int width, int height, const BYTE* data)
{
const int src_bytes_per_row = (width + 7) / 8;
const int dst_bytes_per_row = src_bytes_per_row + (src_bytes_per_row % 2);
BYTE* cdata = (BYTE*)malloc(dst_bytes_per_row * height);
if (!cdata)
{
WLog_ERR(TAG, "malloc failed for cdata buffer");
return nullptr;
}
const BYTE* src = data;
for (int indexy = 0; indexy < height; indexy++)
{
BYTE* dst = &cdata[1ull * indexy * dst_bytes_per_row];
for (int indexx = 0; indexx < dst_bytes_per_row; indexx++)
{
if (indexx < src_bytes_per_row)
*dst++ = *src++;
else
*dst++ = 0;
}
}
return cdata;
}
static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, UINT32 bpp)
{
HBRUSH br;
LOGBRUSH lbr;
BYTE* cdata;
BYTE ipattern[8];
HBITMAP pattern = nullptr;
lbr.lbStyle = brush->style;
if (lbr.lbStyle == BS_DIBPATTERN || lbr.lbStyle == BS_DIBPATTERN8X8 ||
lbr.lbStyle == BS_DIBPATTERNPT)
lbr.lbColor = DIB_RGB_COLORS;
else
lbr.lbColor = color;
if (lbr.lbStyle == BS_PATTERN || lbr.lbStyle == BS_PATTERN8X8)
{
if (brush->bpp > 1)
{
UINT32 format = gdi_get_pixel_format(bpp);
pattern = wf_create_dib(wfc, 8, 8, format, brush->data, nullptr);
lbr.lbHatch = (ULONG_PTR)pattern;
}
else
{
for (UINT32 i = 0; i != 8; i++)
ipattern[7 - i] = brush->data[i];
cdata = wf_glyph_convert(wfc, 8, 8, ipattern);
pattern = CreateBitmap(8, 8, 1, 1, cdata);
lbr.lbHatch = (ULONG_PTR)pattern;
free(cdata);
}
}
else if (lbr.lbStyle == BS_HATCHED)
{
lbr.lbHatch = brush->hatch;
}
else
{
lbr.lbHatch = 0;
}
br = CreateBrushIndirect(&lbr);
SetBrushOrgEx(wfc->drawing->hdc, brush->x, brush->y, nullptr);
if (pattern != nullptr)
DeleteObject(pattern);
return br;
}
BOOL wf_scale_rect(wfContext* wfc, RECT* source)
{
UINT32 ww, wh, dw, dh;
rdpSettings* settings;
if (!wfc || !source || !wfc->common.context.settings)
return FALSE;
settings = wfc->common.context.settings;
if (!settings)
return FALSE;
dw = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
dh = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
if (!wfc->client_width)
wfc->client_width = dw;
if (!wfc->client_height)
wfc->client_height = dh;
ww = wfc->client_width;
wh = wfc->client_height;
if (!ww)
ww = dw;
if (!wh)
wh = dh;
if (freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_SmartSizing) &&
(ww != dw || wh != dh))
{
source->bottom = source->bottom * wh / dh + 20;
source->top = source->top * wh / dh - 20;
source->left = source->left * ww / dw - 20;
source->right = source->right * ww / dw + 20;
}
source->bottom -= wfc->yCurrentScroll;
source->top -= wfc->yCurrentScroll;
source->left -= wfc->xCurrentScroll;
source->right -= wfc->xCurrentScroll;
return TRUE;
}
void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height)
{
RECT rect;
rdpGdi* gdi = wfc->common.context.gdi;
wfc->update_rect.left = x + wfc->offset_x;
wfc->update_rect.top = y + wfc->offset_y;
wfc->update_rect.right = wfc->update_rect.left + width;
wfc->update_rect.bottom = wfc->update_rect.top + height;
wf_scale_rect(wfc, &(wfc->update_rect));
InvalidateRect(wfc->hwnd, &(wfc->update_rect), FALSE);
rect.left = x;
rect.right = width;
rect.top = y;
rect.bottom = height;
wf_scale_rect(wfc, &rect);
gdi_InvalidateRegion(gdi->primary->hdc, rect.left, rect.top, rect.right, rect.bottom);
}
void wf_update_offset(wfContext* wfc)
{
rdpSettings* settings;
settings = wfc->common.context.settings;
if (wfc->fullscreen)
{
if (freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_UseMultimon))
{
int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
wfc->offset_x = (w - freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)) / 2;
if (wfc->offset_x < x)
wfc->offset_x = x;
wfc->offset_y = (h - freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)) / 2;
if (wfc->offset_y < y)
wfc->offset_y = y;
}
else
{
wfc->offset_x = (GetSystemMetrics(SM_CXSCREEN) -
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)) /
2;
if (wfc->offset_x < 0)
wfc->offset_x = 0;
wfc->offset_y = (GetSystemMetrics(SM_CYSCREEN) -
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)) /
2;
if (wfc->offset_y < 0)
wfc->offset_y = 0;
}
}
else
{
wfc->offset_x = 0;
wfc->offset_y = 0;
}
}
void wf_resize_window(wfContext* wfc)
{
rdpSettings* settings;
settings = wfc->common.context.settings;
if (wfc->fullscreen)
{
if (freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_UseMultimon))
{
int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_POPUP);
SetWindowPos(wfc->hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED);
}
else
{
SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_POPUP);
SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED);
}
}
else if (!freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_Decorations))
{
SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_CHILD);
if (freerdp_settings_get_bool(settings, FreeRDP_EmbeddedWindow))
{
if (!wfc->client_height)
wfc->client_height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
if (!wfc->client_width)
wfc->client_width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
wf_update_canvas_diff(wfc);
/* Now resize to get full canvas size and room for caption and borders */
SetWindowPos(wfc->hwnd, HWND_TOP, wfc->client_x, wfc->client_y,
wfc->client_width + wfc->diff.x, wfc->client_height + wfc->diff.y,
0 /*SWP_FRAMECHANGED*/);
}
else
{
/* Now resize to get full canvas size and room for caption and borders */
SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0,
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
SWP_FRAMECHANGED);
wf_update_canvas_diff(wfc);
SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1,
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) + wfc->diff.x,
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) + wfc->diff.y,
SWP_NOMOVE | SWP_FRAMECHANGED);
}
}
else
{
SetWindowLongPtr(wfc->hwnd, GWL_STYLE,
WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX |
WS_MAXIMIZEBOX);
if (!wfc->client_height)
wfc->client_height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
if (!wfc->client_width)
wfc->client_width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
if (!wfc->client_x)
wfc->client_x = 10;
if (!wfc->client_y)
wfc->client_y = 10;
wf_update_canvas_diff(wfc);
/* Now resize to get full canvas size and room for caption and borders */
int width, height;
if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) &&
freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth) &&
freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight))
{
width = freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth);
height = freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight);
}
else
{
width = wfc->client_width + wfc->diff.x;
height = wfc->client_height + wfc->diff.y;
}
int xpos, ypos;
if ((freerdp_settings_get_uint32(settings, FreeRDP_DesktopPosX) != UINT32_MAX) &&
(freerdp_settings_get_uint32(settings, FreeRDP_DesktopPosY) != UINT32_MAX))
{
xpos = freerdp_settings_get_uint32(settings, FreeRDP_DesktopPosX);
ypos = freerdp_settings_get_uint32(settings, FreeRDP_DesktopPosY);
}
else
{
xpos = wfc->client_x;
ypos = wfc->client_y;
}
SetWindowPos(wfc->hwnd, HWND_TOP, xpos, ypos, width, height, 0 /*SWP_FRAMECHANGED*/);
// wf_size_scrollbars(wfc, wfc->client_width, wfc->client_height);
}
wf_update_offset(wfc);
}
void wf_toggle_fullscreen(wfContext* wfc)
{
ShowWindow(wfc->hwnd, SW_HIDE);
wfc->fullscreen = !wfc->fullscreen;
if (wfc->fullscreen)
{
wfc->disablewindowtracking = TRUE;
}
wf_floatbar_toggle_fullscreen(wfc->floatbar, wfc->fullscreen);
SetParent(wfc->hwnd, wfc->fullscreen ? nullptr : wfc->hWndParent);
wf_resize_window(wfc);
ShowWindow(wfc->hwnd, SW_SHOW);
SetForegroundWindow(wfc->hwnd);
if (!wfc->fullscreen)
{
// Re-enable window tracking AFTER resizing it back, otherwise it can lean to repositioning
// errors.
wfc->disablewindowtracking = FALSE;
}
}
static BOOL wf_gdi_palette_update(rdpContext* context, const PALETTE_UPDATE* palette)
{
return TRUE;
}
void wf_set_null_clip_rgn(wfContext* wfc)
{
SelectClipRgn(wfc->drawing->hdc, nullptr);
}
void wf_set_clip_rgn(wfContext* wfc, int x, int y, int width, int height)
{
HRGN clip;
clip = CreateRectRgn(x, y, x + width, y + height);
SelectClipRgn(wfc->drawing->hdc, clip);
DeleteObject(clip);
}
static BOOL wf_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds)
{
HRGN hrgn;
wfContext* wfc = (wfContext*)context;
if (!context || !bounds)
return FALSE;
if (bounds != nullptr)
{
hrgn = CreateRectRgn(bounds->left, bounds->top, bounds->right + 1, bounds->bottom + 1);
SelectClipRgn(wfc->drawing->hdc, hrgn);
DeleteObject(hrgn);
}
else
SelectClipRgn(wfc->drawing->hdc, nullptr);
return TRUE;
}
static BOOL wf_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
{
wfContext* wfc = (wfContext*)context;
if (!context || !dstblt)
return FALSE;
if (!BitBlt(wfc->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
dstblt->nHeight, nullptr, 0, 0, gdi_rop3_code(dstblt->bRop)))
return FALSE;
wf_invalidate_region(wfc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
return TRUE;
}
static BOOL wf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
{
HBRUSH brush;
HBRUSH org_brush;
int org_bkmode;
COLORREF fgcolor;
COLORREF bgcolor;
COLORREF org_bkcolor;
COLORREF org_textcolor;
BOOL rc;
wfContext* wfc = (wfContext*)context;
if (!context || !patblt)
return FALSE;
if (!wf_decode_color(wfc, patblt->foreColor, &fgcolor, nullptr))
return FALSE;
if (!wf_decode_color(wfc, patblt->backColor, &bgcolor, nullptr))
return FALSE;
brush = wf_create_brush(wfc, &patblt->brush, fgcolor,
freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth));
org_bkmode = SetBkMode(wfc->drawing->hdc, OPAQUE);
org_bkcolor = SetBkColor(wfc->drawing->hdc, bgcolor);
org_textcolor = SetTextColor(wfc->drawing->hdc, fgcolor);
org_brush = (HBRUSH)SelectObject(wfc->drawing->hdc, brush);
rc = PatBlt(wfc->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
patblt->nHeight, gdi_rop3_code(patblt->bRop));
SelectObject(wfc->drawing->hdc, org_brush);
DeleteObject(brush);
SetBkMode(wfc->drawing->hdc, org_bkmode);
SetBkColor(wfc->drawing->hdc, org_bkcolor);
SetTextColor(wfc->drawing->hdc, org_textcolor);
if (wfc->drawing == wfc->primary)
wf_invalidate_region(wfc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
patblt->nHeight);
return rc;
}
static BOOL wf_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
{
wfContext* wfc = (wfContext*)context;
if (!context || !scrblt || !wfc->drawing)
return FALSE;
if (!BitBlt(wfc->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
scrblt->nHeight, wfc->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
gdi_rop3_code(scrblt->bRop)))
return FALSE;
wf_invalidate_region(wfc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight);
return TRUE;
}
static BOOL wf_gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
{
RECT rect;
HBRUSH brush;
COLORREF brush_color;
wfContext* wfc = (wfContext*)context;
if (!context || !opaque_rect)
return FALSE;
if (!wf_decode_color(wfc, opaque_rect->color, &brush_color, nullptr))
return FALSE;
rect.left = opaque_rect->nLeftRect;
rect.top = opaque_rect->nTopRect;
rect.right = opaque_rect->nLeftRect + opaque_rect->nWidth;
rect.bottom = opaque_rect->nTopRect + opaque_rect->nHeight;
brush = CreateSolidBrush(brush_color);
FillRect(wfc->drawing->hdc, &rect, brush);
DeleteObject(brush);
if (wfc->drawing == wfc->primary)
wf_invalidate_region(wfc, rect.left, rect.top, rect.right - rect.left + 1,
rect.bottom - rect.top + 1);
return TRUE;
}
static BOOL wf_gdi_multi_opaque_rect(rdpContext* context,
const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
{
RECT rect;
HBRUSH brush;
COLORREF brush_color;
wfContext* wfc = (wfContext*)context;
if (!context || !multi_opaque_rect)
return FALSE;
if (!wf_decode_color(wfc, multi_opaque_rect->color, &brush_color, nullptr))
return FALSE;
for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
{
const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
rect.left = rectangle->left;
rect.top = rectangle->top;
rect.right = rectangle->left + rectangle->width;
rect.bottom = rectangle->top + rectangle->height;
brush = CreateSolidBrush(brush_color);
FillRect(wfc->drawing->hdc, &rect, brush);
if (wfc->drawing == wfc->primary)
wf_invalidate_region(wfc, rect.left, rect.top, rect.right - rect.left + 1,
rect.bottom - rect.top + 1);
DeleteObject(brush);
}
return TRUE;
}
static BOOL wf_gdi_line_to(rdpContext* context, const LINE_TO_ORDER* line_to)
{
HPEN pen;
HPEN org_pen;
int x, y, w, h;
COLORREF pen_color;
wfContext* wfc = (wfContext*)context;
if (!context || !line_to)
return FALSE;
if (!wf_decode_color(wfc, line_to->penColor, &pen_color, nullptr))
return FALSE;
pen = CreatePen(line_to->penStyle, line_to->penWidth, pen_color);
wf_set_rop2(wfc->drawing->hdc, line_to->bRop2);
org_pen = (HPEN)SelectObject(wfc->drawing->hdc, pen);
MoveToEx(wfc->drawing->hdc, line_to->nXStart, line_to->nYStart, nullptr);
LineTo(wfc->drawing->hdc, line_to->nXEnd, line_to->nYEnd);
x = (line_to->nXStart < line_to->nXEnd) ? line_to->nXStart : line_to->nXEnd;
y = (line_to->nYStart < line_to->nYEnd) ? line_to->nYStart : line_to->nYEnd;
w = (line_to->nXStart < line_to->nXEnd) ? (line_to->nXEnd - line_to->nXStart)
: (line_to->nXStart - line_to->nXEnd);
h = (line_to->nYStart < line_to->nYEnd) ? (line_to->nYEnd - line_to->nYStart)
: (line_to->nYStart - line_to->nYEnd);
if (wfc->drawing == wfc->primary)
wf_invalidate_region(wfc, x, y, w, h);
SelectObject(wfc->drawing->hdc, org_pen);
DeleteObject(pen);
return TRUE;
}
static BOOL wf_gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline)
{
BOOL rc = FALSE;
int org_rop2;
HPEN hpen;
HPEN org_hpen;
COLORREF pen_color;
wfContext* wfc = (wfContext*)context;
if (!context || !polyline)
return FALSE;
if (!wf_decode_color(wfc, polyline->penColor, &pen_color, nullptr))
return FALSE;
hpen = CreatePen(0, 1, pen_color);
org_rop2 = wf_set_rop2(wfc->drawing->hdc, polyline->bRop2);
org_hpen = (HPEN)SelectObject(wfc->drawing->hdc, hpen);
if (polyline->numDeltaEntries > 0)
{
POINT* pts;
POINT temp;
int numPoints;
numPoints = polyline->numDeltaEntries + 1;
pts = (POINT*)malloc(sizeof(POINT) * numPoints);
if (!pts)
{
WLog_ERR(TAG, "malloc failed for polyline points");
goto fail;
}
pts[0].x = temp.x = polyline->xStart;
pts[0].y = temp.y = polyline->yStart;
for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
{
temp.x += polyline->points[i].x;
temp.y += polyline->points[i].y;
pts[i + 1].x = temp.x;
pts[i + 1].y = temp.y;
}
if (wfc->drawing == wfc->primary)
wf_invalidate_region(wfc, wfc->client_x, wfc->client_y, wfc->client_width,
wfc->client_height);
Polyline(wfc->drawing->hdc, pts, numPoints);
free(pts);
}
rc = TRUE;
fail:
SelectObject(wfc->drawing->hdc, org_hpen);
wf_set_rop2(wfc->drawing->hdc, org_rop2);
DeleteObject(hpen);
return rc;
}
static BOOL wf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
{
wfBitmap* bitmap;
wfContext* wfc = (wfContext*)context;
if (!context || !memblt)
return FALSE;
bitmap = (wfBitmap*)memblt->bitmap;
if (!bitmap || !wfc->drawing || !wfc->drawing->hdc)
return FALSE;
if (!BitBlt(wfc->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
gdi_rop3_code(memblt->bRop)))
return FALSE;
if (wfc->drawing == wfc->primary)
wf_invalidate_region(wfc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
memblt->nHeight);
return TRUE;
}
static BOOL wf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
{
BOOL rc = FALSE;
HDC hdc;
wfBitmap* bitmap;
wfContext* wfc = (wfContext*)context;
COLORREF fgcolor, bgcolor, orgColor;
HBRUSH orgBrush = nullptr, brush = nullptr;
if (!context || !mem3blt)
return FALSE;
bitmap = (wfBitmap*)mem3blt->bitmap;
if (!bitmap || !wfc->drawing || !wfc->drawing->hdc)
return FALSE;
hdc = wfc->drawing->hdc;
if (!wf_decode_color(wfc, mem3blt->foreColor, &fgcolor, nullptr))
return FALSE;
if (!wf_decode_color(wfc, mem3blt->backColor, &bgcolor, nullptr))
return FALSE;
orgColor = SetTextColor(hdc, fgcolor);
switch (mem3blt->brush.style)
{
case GDI_BS_SOLID:
brush = CreateSolidBrush(fgcolor);
break;
case GDI_BS_HATCHED:
case GDI_BS_PATTERN:
{
HBITMAP bmp = CreateBitmap(8, 8, 1, mem3blt->brush.bpp, mem3blt->brush.data);
brush = CreatePatternBrush(bmp);
}
break;
default:
goto fail;
}
orgBrush = SelectObject(hdc, brush);
if (!BitBlt(hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight,
bitmap->hdc, mem3blt->nXSrc, mem3blt->nYSrc, gdi_rop3_code(mem3blt->bRop)))
goto fail;
if (wfc->drawing == wfc->primary)
wf_invalidate_region(wfc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth,
mem3blt->nHeight);
rc = TRUE;
fail:
if (brush)
SelectObject(hdc, orgBrush);
SetTextColor(hdc, orgColor);
return rc;
}
static BOOL wf_gdi_surface_frame_marker(rdpContext* context,
const SURFACE_FRAME_MARKER* surface_frame_marker)
{
rdpSettings* settings;
if (!context || !surface_frame_marker || !context->instance)
return FALSE;
settings = context->settings;
if (!settings)
return FALSE;
if (surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END &&
freerdp_settings_get_uint32(settings, FreeRDP_FrameAcknowledge) > 0)
{
IFCALL(context->update->SurfaceFrameAcknowledge, context, surface_frame_marker->frameId);
}
return TRUE;
}
void wf_gdi_register_update_callbacks(rdpUpdate* update)
{
rdpPrimaryUpdate* primary = update->primary;
update->Palette = wf_gdi_palette_update;
update->SetBounds = wf_gdi_set_bounds;
primary->DstBlt = wf_gdi_dstblt;
primary->PatBlt = wf_gdi_patblt;
primary->ScrBlt = wf_gdi_scrblt;
primary->OpaqueRect = wf_gdi_opaque_rect;
primary->MultiOpaqueRect = wf_gdi_multi_opaque_rect;
primary->LineTo = wf_gdi_line_to;
primary->Polyline = wf_gdi_polyline;
primary->MemBlt = wf_gdi_memblt;
primary->Mem3Blt = wf_gdi_mem3blt;
update->SurfaceFrameMarker = wf_gdi_surface_frame_marker;
}
void wf_update_canvas_diff(wfContext* wfc)
{
RECT rc_client, rc_wnd;
int dx, dy;
GetClientRect(wfc->hwnd, &rc_client);
GetWindowRect(wfc->hwnd, &rc_wnd);
dx = (rc_wnd.right - rc_wnd.left) - rc_client.right;
dy = (rc_wnd.bottom - rc_wnd.top) - rc_client.bottom;
if (!wfc->disablewindowtracking)
{
wfc->diff.x = dx;
wfc->diff.y = dy;
}
}

View File

@@ -0,0 +1,37 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows GDI
*
* Copyright 2009-2011 Jay Sorg
* Copyright 2010-2011 Vic Lee
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_GDI_H
#define FREERDP_CLIENT_WIN_GDI_H
#include "wf_client.h"
void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height);
void wf_update_offset(wfContext* wfc);
void wf_resize_window(wfContext* wfc);
void wf_toggle_fullscreen(wfContext* wfc);
BOOL wf_scale_rect(wfContext* wfc, RECT* source);
void wf_gdi_register_update_callbacks(rdpUpdate* update);
void wf_update_canvas_diff(wfContext* wfc);
#endif /* FREERDP_CLIENT_WIN_GDI_H */

View File

@@ -0,0 +1,379 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Graphical Objects
*
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <winpr/crt.h>
#include <freerdp/codecs.h>
#include <freerdp/log.h>
#include "wf_gdi.h"
#include "wf_graphics.h"
#define TAG CLIENT_TAG("windows")
HBITMAP wf_create_dib(wfContext* wfc, UINT32 width, UINT32 height, UINT32 srcFormat,
const BYTE* data, BYTE** pdata)
{
HDC hdc;
int negHeight;
HBITMAP bitmap;
BITMAPINFO bmi;
BYTE* cdata = nullptr;
UINT32 dstFormat = srcFormat;
/**
* See: http://msdn.microsoft.com/en-us/library/dd183376
* if biHeight is positive, the bitmap is bottom-up
* if biHeight is negative, the bitmap is top-down
* Since we get top-down bitmaps, let's keep it that way
*/
negHeight = (height < 0) ? height : height * (-1);
hdc = GetDC(nullptr);
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = negHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = FreeRDPGetBitsPerPixel(dstFormat);
bmi.bmiHeader.biCompression = BI_RGB;
bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&cdata, nullptr, 0);
if (data)
freerdp_image_copy(cdata, dstFormat, 0, 0, 0, width, height, data, srcFormat, 0, 0, 0,
&wfc->common.context.gdi->palette, FREERDP_FLIP_NONE);
if (pdata)
*pdata = cdata;
ReleaseDC(nullptr, hdc);
GdiFlush();
return bitmap;
}
wfBitmap* wf_image_new(wfContext* wfc, UINT32 width, UINT32 height, UINT32 format, const BYTE* data)
{
wfBitmap* image = (wfBitmap*)malloc(sizeof(wfBitmap));
if (!image)
{
WLog_ERR(TAG, "malloc failed for wfBitmap");
return nullptr;
}
HDC hdc = GetDC(nullptr);
image->hdc = CreateCompatibleDC(hdc);
image->bitmap = wf_create_dib(wfc, width, height, format, data, &(image->pdata));
image->org_bitmap = (HBITMAP)SelectObject(image->hdc, image->bitmap);
ReleaseDC(nullptr, hdc);
return image;
}
void wf_image_free(wfBitmap* image)
{
if (image != 0)
{
SelectObject(image->hdc, image->org_bitmap);
DeleteObject(image->bitmap);
DeleteDC(image->hdc);
free(image);
}
}
/* Bitmap Class */
static BOOL wf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
{
HDC hdc;
wfContext* wfc = (wfContext*)context;
wfBitmap* wf_bitmap = (wfBitmap*)bitmap;
if (!context || !bitmap)
return FALSE;
wf_bitmap = (wfBitmap*)bitmap;
hdc = GetDC(nullptr);
wf_bitmap->hdc = CreateCompatibleDC(hdc);
if (!bitmap->data)
wf_bitmap->bitmap = CreateCompatibleBitmap(hdc, bitmap->width, bitmap->height);
else
wf_bitmap->bitmap = wf_create_dib(wfc, bitmap->width, bitmap->height, bitmap->format,
bitmap->data, nullptr);
wf_bitmap->org_bitmap = (HBITMAP)SelectObject(wf_bitmap->hdc, wf_bitmap->bitmap);
ReleaseDC(nullptr, hdc);
return TRUE;
}
static void wf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
{
wfBitmap* wf_bitmap = (wfBitmap*)bitmap;
if (wf_bitmap != 0)
{
SelectObject(wf_bitmap->hdc, wf_bitmap->org_bitmap);
DeleteObject(wf_bitmap->bitmap);
DeleteDC(wf_bitmap->hdc);
winpr_aligned_free(wf_bitmap->_bitmap.data);
wf_bitmap->_bitmap.data = nullptr;
}
}
static BOOL wf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
{
BOOL rc;
UINT32 width, height;
wfContext* wfc = (wfContext*)context;
wfBitmap* wf_bitmap = (wfBitmap*)bitmap;
if (!context || !bitmap)
return FALSE;
width = bitmap->right - bitmap->left + 1;
height = bitmap->bottom - bitmap->top + 1;
rc = BitBlt(wfc->primary->hdc, bitmap->left, bitmap->top, width, height, wf_bitmap->hdc, 0, 0,
SRCCOPY);
wf_invalidate_region(wfc, bitmap->left, bitmap->top, width, height);
return rc;
}
static BOOL wf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
{
wfContext* wfc = (wfContext*)context;
wfBitmap* bmp = (wfBitmap*)bitmap;
rdpGdi* gdi = context->gdi;
if (!gdi || !wfc)
return FALSE;
if (primary)
wfc->drawing = wfc->primary;
else if (!bmp)
return FALSE;
else
wfc->drawing = bmp;
return TRUE;
}
/* Pointer Class */
static BOOL flip_bitmap(const BYTE* src, BYTE* dst, UINT32 scanline, UINT32 nHeight)
{
BYTE* bottomLine = dst + scanline * (nHeight - 1);
for (UINT32 x = 0; x < nHeight; x++)
{
memcpy(bottomLine, src, scanline);
src += scanline;
bottomLine -= scanline;
}
return TRUE;
}
static BOOL wf_Pointer_New(rdpContext* context, rdpPointer* pointer)
{
HCURSOR hCur;
ICONINFO info;
rdpGdi* gdi;
BOOL rc = FALSE;
if (!context || !pointer)
return FALSE;
gdi = context->gdi;
if (!gdi)
return FALSE;
info.fIcon = FALSE;
info.xHotspot = pointer->xPos;
info.yHotspot = pointer->yPos;
if (pointer->xorBpp == 1)
{
BYTE* pdata = nullptr;
if ((pointer->lengthAndMask > 0) || (pointer->lengthXorMask > 0))
{
pdata =
(BYTE*)winpr_aligned_malloc(pointer->lengthAndMask + pointer->lengthXorMask, 16);
if (!pdata)
goto fail;
}
CopyMemory(pdata, pointer->andMaskData, pointer->lengthAndMask);
CopyMemory(pdata + pointer->lengthAndMask, pointer->xorMaskData, pointer->lengthXorMask);
info.hbmMask = CreateBitmap(pointer->width, pointer->height * 2, 1, 1, pdata);
winpr_aligned_free(pdata);
info.hbmColor = nullptr;
}
else
{
UINT32 srcFormat;
BYTE* pdata = nullptr;
if (pointer->lengthAndMask > 0)
{
pdata = (BYTE*)winpr_aligned_malloc(pointer->lengthAndMask, 16);
if (!pdata)
goto fail;
flip_bitmap(pointer->andMaskData, pdata, (pointer->width + 7) / 8, pointer->height);
}
info.hbmMask = CreateBitmap(pointer->width, pointer->height, 1, 1, pdata);
winpr_aligned_free(pdata);
/* currently color xorBpp is only 24 per [T128] section 8.14.3 */
srcFormat = gdi_get_pixel_format(pointer->xorBpp);
if (!srcFormat)
goto fail;
info.hbmColor = wf_create_dib((wfContext*)context, pointer->width, pointer->height,
gdi->dstFormat, nullptr, &pdata);
if (!info.hbmColor)
goto fail;
if (!freerdp_image_copy_from_pointer_data(
pdata, gdi->dstFormat, 0, 0, 0, pointer->width, pointer->height,
pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData,
pointer->lengthAndMask, pointer->xorBpp, &gdi->palette))
{
goto fail;
}
}
hCur = CreateIconIndirect(&info);
((wfPointer*)pointer)->cursor = hCur;
rc = TRUE;
fail:
if (info.hbmMask)
DeleteObject(info.hbmMask);
if (info.hbmColor)
DeleteObject(info.hbmColor);
return rc;
}
static void wf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
{
HCURSOR hCur;
if (!context || !pointer)
return;
hCur = ((wfPointer*)pointer)->cursor;
if (hCur != 0)
DestroyIcon(hCur);
}
static BOOL wf_Pointer_Set(rdpContext* context, rdpPointer* pointer)
{
HCURSOR hCur;
wfContext* wfc = (wfContext*)context;
if (!context || !pointer)
return FALSE;
hCur = ((wfPointer*)pointer)->cursor;
if (hCur != nullptr)
{
SetCursor(hCur);
wfc->cursor = hCur;
}
return TRUE;
}
static BOOL wf_Pointer_SetNull(rdpContext* context)
{
if (!context)
return FALSE;
return TRUE;
}
static BOOL wf_Pointer_SetDefault(rdpContext* context)
{
if (!context)
return FALSE;
return TRUE;
}
static BOOL wf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
{
if (!context)
return FALSE;
return TRUE;
}
BOOL wf_register_pointer(rdpGraphics* graphics)
{
wfContext* wfc;
rdpPointer pointer = WINPR_C_ARRAY_INIT;
if (!graphics)
return FALSE;
wfc = (wfContext*)graphics->context;
pointer.size = sizeof(wfPointer);
pointer.New = wf_Pointer_New;
pointer.Free = wf_Pointer_Free;
pointer.Set = wf_Pointer_Set;
pointer.SetNull = wf_Pointer_SetNull;
pointer.SetDefault = wf_Pointer_SetDefault;
pointer.SetPosition = wf_Pointer_SetPosition;
graphics_register_pointer(graphics, &pointer);
return TRUE;
}
/* Graphics Module */
BOOL wf_register_graphics(rdpGraphics* graphics)
{
wfContext* wfc;
rdpGlyph glyph;
rdpBitmap bitmap;
if (!graphics)
return FALSE;
wfc = (wfContext*)graphics->context;
bitmap = *graphics->Bitmap_Prototype;
bitmap.size = sizeof(wfBitmap);
bitmap.New = wf_Bitmap_New;
bitmap.Free = wf_Bitmap_Free;
bitmap.Paint = wf_Bitmap_Paint;
bitmap.SetSurface = wf_Bitmap_SetSurface;
graphics_register_bitmap(graphics, &bitmap);
glyph = *graphics->Glyph_Prototype;
graphics_register_glyph(graphics, &glyph);
return TRUE;
}

View File

@@ -0,0 +1,34 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Graphical Objects
*
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_GRAPHICS_H
#define FREERDP_CLIENT_WIN_GRAPHICS_H
#include "wf_client.h"
HBITMAP wf_create_dib(wfContext* wfc, UINT32 width, UINT32 height, UINT32 format, const BYTE* data,
BYTE** pdata);
wfBitmap* wf_image_new(wfContext* wfc, UINT32 width, UINT32 height, UINT32 format,
const BYTE* data);
void wf_image_free(wfBitmap* image);
BOOL wf_register_pointer(rdpGraphics* graphics);
BOOL wf_register_graphics(rdpGraphics* graphics);
#endif /* FREERDP_CLIENT_WIN_GRAPHICS_H */

View File

@@ -0,0 +1,994 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2013-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <winpr/crt.h>
#include <freerdp/log.h>
#include <freerdp/client/rail.h>
#include <winpr/tchar.h>
#include <winpr/print.h>
#include "wf_rail.h"
#define TAG CLIENT_TAG("windows")
#define GET_X_LPARAM(lParam) ((UINT16)(lParam & 0xFFFF))
#define GET_Y_LPARAM(lParam) ((UINT16)((lParam >> 16) & 0xFFFF))
struct wf_rail_window
{
wfContext* wfc;
HWND hWnd;
DWORD dwStyle;
DWORD dwExStyle;
int x;
int y;
int width;
int height;
char* title;
};
/* RemoteApp Core Protocol Extension */
typedef struct
{
UINT32 style;
const char* name;
BOOL multi;
} WINDOW_STYLE;
static const WINDOW_STYLE WINDOW_STYLES[] = { { WS_BORDER, "WS_BORDER", FALSE },
{ WS_CAPTION, "WS_CAPTION", FALSE },
{ WS_CHILD, "WS_CHILD", FALSE },
{ WS_CLIPCHILDREN, "WS_CLIPCHILDREN", FALSE },
{ WS_CLIPSIBLINGS, "WS_CLIPSIBLINGS", FALSE },
{ WS_DISABLED, "WS_DISABLED", FALSE },
{ WS_DLGFRAME, "WS_DLGFRAME", FALSE },
{ WS_GROUP, "WS_GROUP", FALSE },
{ WS_HSCROLL, "WS_HSCROLL", FALSE },
{ WS_ICONIC, "WS_ICONIC", FALSE },
{ WS_MAXIMIZE, "WS_MAXIMIZE", FALSE },
{ WS_MAXIMIZEBOX, "WS_MAXIMIZEBOX", FALSE },
{ WS_MINIMIZE, "WS_MINIMIZE", FALSE },
{ WS_MINIMIZEBOX, "WS_MINIMIZEBOX", FALSE },
{ WS_OVERLAPPED, "WS_OVERLAPPED", FALSE },
{ WS_OVERLAPPEDWINDOW, "WS_OVERLAPPEDWINDOW", TRUE },
{ WS_POPUP, "WS_POPUP", FALSE },
{ WS_POPUPWINDOW, "WS_POPUPWINDOW", TRUE },
{ WS_SIZEBOX, "WS_SIZEBOX", FALSE },
{ WS_SYSMENU, "WS_SYSMENU", FALSE },
{ WS_TABSTOP, "WS_TABSTOP", FALSE },
{ WS_THICKFRAME, "WS_THICKFRAME", FALSE },
{ WS_VISIBLE, "WS_VISIBLE", FALSE } };
static const WINDOW_STYLE EXTENDED_WINDOW_STYLES[] = {
{ WS_EX_ACCEPTFILES, "WS_EX_ACCEPTFILES", FALSE },
{ WS_EX_APPWINDOW, "WS_EX_APPWINDOW", FALSE },
{ WS_EX_CLIENTEDGE, "WS_EX_CLIENTEDGE", FALSE },
{ WS_EX_COMPOSITED, "WS_EX_COMPOSITED", FALSE },
{ WS_EX_CONTEXTHELP, "WS_EX_CONTEXTHELP", FALSE },
{ WS_EX_CONTROLPARENT, "WS_EX_CONTROLPARENT", FALSE },
{ WS_EX_DLGMODALFRAME, "WS_EX_DLGMODALFRAME", FALSE },
{ WS_EX_LAYERED, "WS_EX_LAYERED", FALSE },
{ WS_EX_LAYOUTRTL, "WS_EX_LAYOUTRTL", FALSE },
{ WS_EX_LEFT, "WS_EX_LEFT", FALSE },
{ WS_EX_LEFTSCROLLBAR, "WS_EX_LEFTSCROLLBAR", FALSE },
{ WS_EX_LTRREADING, "WS_EX_LTRREADING", FALSE },
{ WS_EX_MDICHILD, "WS_EX_MDICHILD", FALSE },
{ WS_EX_NOACTIVATE, "WS_EX_NOACTIVATE", FALSE },
{ WS_EX_NOINHERITLAYOUT, "WS_EX_NOINHERITLAYOUT", FALSE },
{ WS_EX_NOPARENTNOTIFY, "WS_EX_NOPARENTNOTIFY", FALSE },
{ WS_EX_OVERLAPPEDWINDOW, "WS_EX_OVERLAPPEDWINDOW", TRUE },
{ WS_EX_PALETTEWINDOW, "WS_EX_PALETTEWINDOW", TRUE },
{ WS_EX_RIGHT, "WS_EX_RIGHT", FALSE },
{ WS_EX_RIGHTSCROLLBAR, "WS_EX_RIGHTSCROLLBAR", FALSE },
{ WS_EX_RTLREADING, "WS_EX_RTLREADING", FALSE },
{ WS_EX_STATICEDGE, "WS_EX_STATICEDGE", FALSE },
{ WS_EX_TOOLWINDOW, "WS_EX_TOOLWINDOW", FALSE },
{ WS_EX_TOPMOST, "WS_EX_TOPMOST", FALSE },
{ WS_EX_TRANSPARENT, "WS_EX_TRANSPARENT", FALSE },
{ WS_EX_WINDOWEDGE, "WS_EX_WINDOWEDGE", FALSE }
};
static void PrintWindowStyles(UINT32 style)
{
WLog_INFO(TAG, "\tWindow Styles:\t{");
for (size_t i = 0; i < ARRAYSIZE(WINDOW_STYLES); i++)
{
if (style & WINDOW_STYLES[i].style)
{
if (WINDOW_STYLES[i].multi)
{
if ((style & WINDOW_STYLES[i].style) != WINDOW_STYLES[i].style)
continue;
}
WLog_INFO(TAG, "\t\t%s", WINDOW_STYLES[i].name);
}
}
}
static void PrintExtendedWindowStyles(UINT32 style)
{
WLog_INFO(TAG, "\tExtended Window Styles:\t{");
for (size_t i = 0; i < ARRAYSIZE(EXTENDED_WINDOW_STYLES); i++)
{
if (style & EXTENDED_WINDOW_STYLES[i].style)
{
if (EXTENDED_WINDOW_STYLES[i].multi)
{
if ((style & EXTENDED_WINDOW_STYLES[i].style) != EXTENDED_WINDOW_STYLES[i].style)
continue;
}
WLog_INFO(TAG, "\t\t%s", EXTENDED_WINDOW_STYLES[i].name);
}
}
}
static void PrintRailWindowState(const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_STATE_ORDER* windowState)
{
if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW)
WLog_INFO(TAG, "WindowCreate: WindowId: 0x%08X", orderInfo->windowId);
else
WLog_INFO(TAG, "WindowUpdate: WindowId: 0x%08X", orderInfo->windowId);
WLog_INFO(TAG, "{");
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OWNER)
{
WLog_INFO(TAG, "\tOwnerWindowId: 0x%08X", windowState->ownerWindowId);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE)
{
WLog_INFO(TAG, "\tStyle: 0x%08X ExtendedStyle: 0x%08X", windowState->style,
windowState->extendedStyle);
PrintWindowStyles(windowState->style);
PrintExtendedWindowStyles(windowState->extendedStyle);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_SHOW)
{
WLog_INFO(TAG, "\tShowState: %u", windowState->showState);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE)
{
const WCHAR* str = (const WCHAR*)windowState->titleInfo.string;
char* title =
ConvertWCharNToUtf8Alloc(str, windowState->titleInfo.length / sizeof(WCHAR), nullptr);
WLog_INFO(TAG, "\tTitleInfo: %s (length = %hu)", title, windowState->titleInfo.length);
free(title);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
{
WLog_INFO(TAG, "\tClientOffsetX: %d ClientOffsetY: %d", windowState->clientOffsetX,
windowState->clientOffsetY);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
{
WLog_INFO(TAG, "\tClientAreaWidth: %u ClientAreaHeight: %u", windowState->clientAreaWidth,
windowState->clientAreaHeight);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT)
{
WLog_INFO(TAG, "\tRPContent: %u", windowState->RPContent);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT)
{
WLog_INFO(TAG, "\tRootParentHandle: 0x%08X", windowState->rootParentHandle);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
{
WLog_INFO(TAG, "\tWindowOffsetX: %d WindowOffsetY: %d", windowState->windowOffsetX,
windowState->windowOffsetY);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
{
WLog_INFO(TAG, "\tWindowClientDeltaX: %d WindowClientDeltaY: %d",
windowState->windowClientDeltaX, windowState->windowClientDeltaY);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
{
WLog_INFO(TAG, "\tWindowWidth: %u WindowHeight: %u", windowState->windowWidth,
windowState->windowHeight);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
{
RECTANGLE_16* rect;
WLog_INFO(TAG, "\tnumWindowRects: %u", windowState->numWindowRects);
for (UINT32 index = 0; index < windowState->numWindowRects; index++)
{
rect = &windowState->windowRects[index];
WLog_INFO(TAG, "\twindowRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", index,
rect->left, rect->top, rect->right, rect->bottom);
}
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
{
WLog_INFO(TAG, "\tvisibileOffsetX: %d visibleOffsetY: %d", windowState->visibleOffsetX,
windowState->visibleOffsetY);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
{
RECTANGLE_16* rect;
WLog_INFO(TAG, "\tnumVisibilityRects: %u", windowState->numVisibilityRects);
for (UINT32 index = 0; index < windowState->numVisibilityRects; index++)
{
rect = &windowState->visibilityRects[index];
WLog_INFO(TAG, "\tvisibilityRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", index,
rect->left, rect->top, rect->right, rect->bottom);
}
}
WLog_INFO(TAG, "}");
}
static void PrintRailIconInfo(const WINDOW_ORDER_INFO* orderInfo, const ICON_INFO* iconInfo)
{
WLog_INFO(TAG, "ICON_INFO");
WLog_INFO(TAG, "{");
WLog_INFO(TAG, "\tbigIcon: %s",
(orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ICON_BIG) ? "true" : "false");
WLog_INFO(TAG, "\tcacheEntry; 0x%08X", iconInfo->cacheEntry);
WLog_INFO(TAG, "\tcacheId: 0x%08X", iconInfo->cacheId);
WLog_INFO(TAG, "\tbpp: %u", iconInfo->bpp);
WLog_INFO(TAG, "\twidth: %u", iconInfo->width);
WLog_INFO(TAG, "\theight: %u", iconInfo->height);
WLog_INFO(TAG, "\tcbColorTable: %u", iconInfo->cbColorTable);
WLog_INFO(TAG, "\tcbBitsMask: %u", iconInfo->cbBitsMask);
WLog_INFO(TAG, "\tcbBitsColor: %u", iconInfo->cbBitsColor);
WLog_INFO(TAG, "\tcolorTable: %p", (void*)iconInfo->colorTable);
WLog_INFO(TAG, "\tbitsMask: %p", (void*)iconInfo->bitsMask);
WLog_INFO(TAG, "\tbitsColor: %p", (void*)iconInfo->bitsColor);
WLog_INFO(TAG, "}");
}
LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
int x, y;
int width;
int height;
UINT32 xPos;
UINT32 yPos;
PAINTSTRUCT ps;
UINT32 inputFlags;
wfContext* wfc = nullptr;
rdpInput* input = nullptr;
rdpContext* context = nullptr;
wfRailWindow* railWindow;
railWindow = (wfRailWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (railWindow)
wfc = railWindow->wfc;
if (wfc)
context = (rdpContext*)wfc;
if (context)
input = context->input;
switch (msg)
{
case WM_PAINT:
{
if (!wfc)
return 0;
hDC = BeginPaint(hWnd, &ps);
x = ps.rcPaint.left;
y = ps.rcPaint.top;
width = ps.rcPaint.right - ps.rcPaint.left + 1;
height = ps.rcPaint.bottom - ps.rcPaint.top + 1;
BitBlt(hDC, x, y, width, height, wfc->primary->hdc, railWindow->x + x,
railWindow->y + y, SRCCOPY);
EndPaint(hWnd, &ps);
}
break;
case WM_LBUTTONDOWN:
{
if (!railWindow || !input)
return 0;
xPos = GET_X_LPARAM(lParam) + railWindow->x;
yPos = GET_Y_LPARAM(lParam) + railWindow->y;
inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1;
if (input)
input->MouseEvent(input, inputFlags, xPos, yPos);
}
break;
case WM_LBUTTONUP:
{
if (!railWindow || !input)
return 0;
xPos = GET_X_LPARAM(lParam) + railWindow->x;
yPos = GET_Y_LPARAM(lParam) + railWindow->y;
inputFlags = PTR_FLAGS_BUTTON1;
if (input)
input->MouseEvent(input, inputFlags, xPos, yPos);
}
break;
case WM_RBUTTONDOWN:
{
if (!railWindow || !input)
return 0;
xPos = GET_X_LPARAM(lParam) + railWindow->x;
yPos = GET_Y_LPARAM(lParam) + railWindow->y;
inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2;
if (input)
input->MouseEvent(input, inputFlags, xPos, yPos);
}
break;
case WM_RBUTTONUP:
{
if (!railWindow || !input)
return 0;
xPos = GET_X_LPARAM(lParam) + railWindow->x;
yPos = GET_Y_LPARAM(lParam) + railWindow->y;
inputFlags = PTR_FLAGS_BUTTON2;
if (input)
input->MouseEvent(input, inputFlags, xPos, yPos);
}
break;
case WM_MOUSEMOVE:
{
if (!railWindow || !input)
return 0;
xPos = GET_X_LPARAM(lParam) + railWindow->x;
yPos = GET_Y_LPARAM(lParam) + railWindow->y;
inputFlags = PTR_FLAGS_MOVE;
if (input)
input->MouseEvent(input, inputFlags, xPos, yPos);
}
break;
case WM_MOUSEWHEEL:
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
#define RAIL_DISABLED_WINDOW_STYLES \
(WS_BORDER | WS_THICKFRAME | WS_DLGFRAME | WS_CAPTION | WS_OVERLAPPED | WS_VSCROLL | \
WS_HSCROLL | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
#define RAIL_DISABLED_EXTENDED_WINDOW_STYLES \
(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE)
static BOOL wf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_STATE_ORDER* windowState)
{
wfRailWindow* railWindow = nullptr;
wfContext* wfc = (wfContext*)context;
RailClientContext* rail = wfc->rail;
UINT32 fieldFlags = orderInfo->fieldFlags;
PrintRailWindowState(orderInfo, windowState);
if (fieldFlags & WINDOW_ORDER_STATE_NEW)
{
BOOL rc;
HANDLE hInstance;
WCHAR* titleW = nullptr;
WNDCLASSEX wndClassEx = WINPR_C_ARRAY_INIT;
railWindow = (wfRailWindow*)calloc(1, sizeof(wfRailWindow));
if (!railWindow)
return FALSE;
railWindow->wfc = wfc;
railWindow->dwStyle = windowState->style;
railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES;
railWindow->dwExStyle = windowState->extendedStyle;
railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES;
railWindow->x = windowState->windowOffsetX;
railWindow->y = windowState->windowOffsetY;
railWindow->width = windowState->windowWidth;
railWindow->height = windowState->windowHeight;
if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
{
const WCHAR* str = (const WCHAR*)windowState->titleInfo.string;
char* title = nullptr;
if (windowState->titleInfo.length == 0)
{
if (!(title = _strdup("")))
{
WLog_ERR(TAG, "failed to duplicate empty window title string");
/* error handled below */
}
}
else if (!(title = ConvertWCharNToUtf8Alloc(
str, windowState->titleInfo.length / sizeof(WCHAR), nullptr)))
{
WLog_ERR(TAG, "failed to convert window title");
/* error handled below */
}
railWindow->title = title;
}
else
{
if (!(railWindow->title = _strdup("RdpRailWindow")))
WLog_ERR(TAG, "failed to duplicate default window title string");
}
if (!railWindow->title)
{
free(railWindow);
return FALSE;
}
titleW = ConvertUtf8ToWCharAlloc(railWindow->title, nullptr);
hInstance = GetModuleHandle(nullptr);
wndClassEx.cbSize = sizeof(WNDCLASSEX);
wndClassEx.style = 0;
wndClassEx.lpfnWndProc = wf_RailWndProc;
wndClassEx.cbClsExtra = 0;
wndClassEx.cbWndExtra = 0;
wndClassEx.hIcon = nullptr;
wndClassEx.hCursor = nullptr;
wndClassEx.hbrBackground = nullptr;
wndClassEx.lpszMenuName = nullptr;
wndClassEx.lpszClassName = _T("RdpRailWindow");
wndClassEx.hInstance = hInstance;
wndClassEx.hIconSm = nullptr;
RegisterClassEx(&wndClassEx);
railWindow->hWnd = CreateWindowExW(railWindow->dwExStyle, /* dwExStyle */
_T("RdpRailWindow"), /* lpClassName */
titleW, /* lpWindowName */
railWindow->dwStyle, /* dwStyle */
railWindow->x, /* x */
railWindow->y, /* y */
railWindow->width, /* nWidth */
railWindow->height, /* nHeight */
nullptr, /* hWndParent */
nullptr, /* hMenu */
hInstance, /* hInstance */
nullptr /* lpParam */
);
if (!railWindow->hWnd)
{
free(titleW);
free(railWindow->title);
free(railWindow);
WLog_ERR(TAG, "CreateWindowExW failed with error %" PRIu32 "", GetLastError());
return FALSE;
}
SetWindowLongPtr(railWindow->hWnd, GWLP_USERDATA, (LONG_PTR)railWindow);
rc = HashTable_Insert(wfc->railWindows, (void*)(UINT_PTR)orderInfo->windowId,
(void*)railWindow);
free(titleW);
UpdateWindow(railWindow->hWnd);
return rc;
}
else
{
railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
(void*)(UINT_PTR)orderInfo->windowId);
}
if (!railWindow)
return TRUE;
if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE))
{
if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
{
railWindow->x = windowState->windowOffsetX;
railWindow->y = windowState->windowOffsetY;
}
if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
{
railWindow->width = windowState->windowWidth;
railWindow->height = windowState->windowHeight;
}
SetWindowPos(railWindow->hWnd, nullptr, railWindow->x, railWindow->y, railWindow->width,
railWindow->height, 0);
}
if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
{
}
if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
{
railWindow->dwStyle = windowState->style;
railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES;
railWindow->dwExStyle = windowState->extendedStyle;
railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES;
SetWindowLongPtr(railWindow->hWnd, GWL_STYLE, (LONG)railWindow->dwStyle);
SetWindowLongPtr(railWindow->hWnd, GWL_EXSTYLE, (LONG)railWindow->dwExStyle);
}
if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
{
ShowWindow(railWindow->hWnd, windowState->showState);
}
if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
{
const WCHAR* str = (const WCHAR*)windowState->titleInfo.string;
char* title = nullptr;
if (windowState->titleInfo.length == 0)
{
if (!(title = _strdup("")))
{
WLog_ERR(TAG, "failed to duplicate empty window title string");
return FALSE;
}
}
else if (!(title = ConvertWCharNToUtf8Alloc(
str, windowState->titleInfo.length / sizeof(WCHAR), nullptr)))
{
WLog_ERR(TAG, "failed to convert window title");
return FALSE;
}
free(railWindow->title);
railWindow->title = title;
SetWindowTextW(railWindow->hWnd, str);
}
if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
{
}
if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
{
}
if (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
{
}
if (fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT)
{
}
if (fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT)
{
}
if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
{
HRGN hWndRect;
HRGN hWndRects;
RECTANGLE_16* rect;
if (windowState->numWindowRects > 0)
{
rect = &(windowState->windowRects[0]);
hWndRects = CreateRectRgn(rect->left, rect->top, rect->right, rect->bottom);
for (UINT32 index = 1; index < windowState->numWindowRects; index++)
{
rect = &(windowState->windowRects[index]);
hWndRect = CreateRectRgn(rect->left, rect->top, rect->right, rect->bottom);
CombineRgn(hWndRects, hWndRects, hWndRect, RGN_OR);
DeleteObject(hWndRect);
}
SetWindowRgn(railWindow->hWnd, hWndRects, TRUE);
DeleteObject(hWndRects);
}
}
if (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
{
}
if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
{
}
UpdateWindow(railWindow->hWnd);
return TRUE;
}
static BOOL wf_rail_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
{
wfRailWindow* railWindow = nullptr;
wfContext* wfc = (wfContext*)context;
RailClientContext* rail = wfc->rail;
WLog_DBG(TAG, "RailWindowDelete");
railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
(void*)(UINT_PTR)orderInfo->windowId);
if (!railWindow)
return TRUE;
HashTable_Remove(wfc->railWindows, (void*)(UINT_PTR)orderInfo->windowId);
DestroyWindow(railWindow->hWnd);
free(railWindow);
return TRUE;
}
static BOOL wf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_ICON_ORDER* windowIcon)
{
HDC hDC;
int bpp;
int width;
int height;
HICON hIcon;
BOOL bigIcon;
ICONINFO iconInfo = WINPR_C_ARRAY_INIT;
BITMAPINFO bitmapInfo = WINPR_C_ARRAY_INIT;
wfRailWindow* railWindow;
BITMAPINFOHEADER* bitmapInfoHeader;
wfContext* wfc = (wfContext*)context;
RailClientContext* rail = wfc->rail;
WLog_DBG(TAG, "RailWindowIcon");
PrintRailIconInfo(orderInfo, windowIcon->iconInfo);
railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
(void*)(UINT_PTR)orderInfo->windowId);
if (!railWindow)
return TRUE;
bigIcon = (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ICON_BIG) ? TRUE : FALSE;
hDC = GetDC(railWindow->hWnd);
iconInfo.fIcon = TRUE;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
bitmapInfoHeader = &(bitmapInfo.bmiHeader);
bpp = windowIcon->iconInfo->bpp;
width = windowIcon->iconInfo->width;
height = windowIcon->iconInfo->height;
bitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
bitmapInfoHeader->biWidth = width;
bitmapInfoHeader->biHeight = height;
bitmapInfoHeader->biPlanes = 1;
bitmapInfoHeader->biBitCount = bpp;
bitmapInfoHeader->biCompression = 0;
bitmapInfoHeader->biSizeImage = height * width * ((bpp + 7) / 8);
bitmapInfoHeader->biXPelsPerMeter = width;
bitmapInfoHeader->biYPelsPerMeter = height;
bitmapInfoHeader->biClrUsed = 0;
bitmapInfoHeader->biClrImportant = 0;
iconInfo.hbmMask = CreateDIBitmap(hDC, bitmapInfoHeader, CBM_INIT,
windowIcon->iconInfo->bitsMask, &bitmapInfo, DIB_RGB_COLORS);
iconInfo.hbmColor =
CreateDIBitmap(hDC, bitmapInfoHeader, CBM_INIT, windowIcon->iconInfo->bitsColor,
&bitmapInfo, DIB_RGB_COLORS);
hIcon = CreateIconIndirect(&iconInfo);
if (hIcon)
{
WPARAM wParam;
LPARAM lParam;
wParam = (WPARAM)bigIcon ? ICON_BIG : ICON_SMALL;
lParam = (LPARAM)hIcon;
SendMessage(railWindow->hWnd, WM_SETICON, wParam, lParam);
}
ReleaseDC(nullptr, hDC);
if (windowIcon->iconInfo->cacheEntry != 0xFFFF)
{
/* icon should be cached */
}
return TRUE;
}
static BOOL wf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_CACHED_ICON_ORDER* windowCachedIcon)
{
WLog_DBG(TAG, "RailWindowCachedIcon");
return TRUE;
}
static void wf_rail_notify_icon_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const NOTIFY_ICON_STATE_ORDER* notifyIconState)
{
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION)
{
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP)
{
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP)
{
}
if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE)
{
}
if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
{
const ICON_INFO* iconInfo = &(notifyIconState->icon);
PrintRailIconInfo(orderInfo, iconInfo);
}
if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
{
}
}
static BOOL wf_rail_notify_icon_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const NOTIFY_ICON_STATE_ORDER* notifyIconState)
{
wfContext* wfc = (wfContext*)context;
RailClientContext* rail = wfc->rail;
WLog_DBG(TAG, "RailNotifyIconCreate");
wf_rail_notify_icon_common(context, orderInfo, notifyIconState);
return TRUE;
}
static BOOL wf_rail_notify_icon_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const NOTIFY_ICON_STATE_ORDER* notifyIconState)
{
wfContext* wfc = (wfContext*)context;
RailClientContext* rail = wfc->rail;
WLog_DBG(TAG, "RailNotifyIconUpdate");
wf_rail_notify_icon_common(context, orderInfo, notifyIconState);
return TRUE;
}
static BOOL wf_rail_notify_icon_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
{
wfContext* wfc = (wfContext*)context;
RailClientContext* rail = wfc->rail;
WLog_DBG(TAG, "RailNotifyIconDelete");
return TRUE;
}
static BOOL wf_rail_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const MONITORED_DESKTOP_ORDER* monitoredDesktop)
{
wfContext* wfc = (wfContext*)context;
RailClientContext* rail = wfc->rail;
WLog_DBG(TAG, "RailMonitorDesktop");
return TRUE;
}
static BOOL wf_rail_non_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
{
wfContext* wfc = (wfContext*)context;
RailClientContext* rail = wfc->rail;
WLog_DBG(TAG, "RailNonMonitorDesktop");
return TRUE;
}
void wf_rail_register_update_callbacks(rdpUpdate* update)
{
rdpWindowUpdate* window = update->window;
window->WindowCreate = wf_rail_window_common;
window->WindowUpdate = wf_rail_window_common;
window->WindowDelete = wf_rail_window_delete;
window->WindowIcon = wf_rail_window_icon;
window->WindowCachedIcon = wf_rail_window_cached_icon;
window->NotifyIconCreate = wf_rail_notify_icon_create;
window->NotifyIconUpdate = wf_rail_notify_icon_update;
window->NotifyIconDelete = wf_rail_notify_icon_delete;
window->MonitoredDesktop = wf_rail_monitored_desktop;
window->NonMonitoredDesktop = wf_rail_non_monitored_desktop;
}
/* RemoteApp Virtual Channel Extension */
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT wf_rail_server_execute_result(RailClientContext* context,
const RAIL_EXEC_RESULT_ORDER* execResult)
{
WLog_DBG(TAG, "RailServerExecuteResult: 0x%08X", execResult->rawResult);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT wf_rail_server_system_param(RailClientContext* context,
const RAIL_SYSPARAM_ORDER* sysparam)
{
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT wf_rail_server_handshake(RailClientContext* context,
const RAIL_HANDSHAKE_ORDER* handshake)
{
return client_rail_server_start_cmd(context);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT wf_rail_server_handshake_ex(RailClientContext* context,
const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
{
return client_rail_server_start_cmd(context);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT wf_rail_server_local_move_size(RailClientContext* context,
const RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
{
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT wf_rail_server_min_max_info(RailClientContext* context,
const RAIL_MINMAXINFO_ORDER* minMaxInfo)
{
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT wf_rail_server_language_bar_info(RailClientContext* context,
const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
{
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT wf_rail_server_get_appid_response(RailClientContext* context,
const RAIL_GET_APPID_RESP_ORDER* getAppIdResp)
{
return CHANNEL_RC_OK;
}
void wf_rail_invalidate_region(wfContext* wfc, REGION16* invalidRegion)
{
RECT updateRect;
RECTANGLE_16 windowRect;
ULONG_PTR* pKeys = nullptr;
wfRailWindow* railWindow;
const RECTANGLE_16* extents;
REGION16 windowInvalidRegion;
region16_init(&windowInvalidRegion);
size_t count = HashTable_GetKeys(wfc->railWindows, &pKeys);
for (size_t index = 0; index < count; index++)
{
railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows, (void*)pKeys[index]);
if (railWindow)
{
windowRect.left = railWindow->x;
windowRect.top = railWindow->y;
windowRect.right = railWindow->x + railWindow->width;
windowRect.bottom = railWindow->y + railWindow->height;
region16_clear(&windowInvalidRegion);
region16_intersect_rect(&windowInvalidRegion, invalidRegion, &windowRect);
if (!region16_is_empty(&windowInvalidRegion))
{
extents = region16_extents(&windowInvalidRegion);
updateRect.left = extents->left - railWindow->x;
updateRect.top = extents->top - railWindow->y;
updateRect.right = extents->right - railWindow->x;
updateRect.bottom = extents->bottom - railWindow->y;
InvalidateRect(railWindow->hWnd, &updateRect, FALSE);
}
}
}
region16_uninit(&windowInvalidRegion);
}
BOOL wf_rail_init(wfContext* wfc, RailClientContext* rail)
{
rdpContext* context = (rdpContext*)wfc;
wfc->rail = rail;
rail->custom = (void*)wfc;
rail->ServerExecuteResult = wf_rail_server_execute_result;
rail->ServerSystemParam = wf_rail_server_system_param;
rail->ServerHandshake = wf_rail_server_handshake;
rail->ServerHandshakeEx = wf_rail_server_handshake_ex;
rail->ServerLocalMoveSize = wf_rail_server_local_move_size;
rail->ServerMinMaxInfo = wf_rail_server_min_max_info;
rail->ServerLanguageBarInfo = wf_rail_server_language_bar_info;
rail->ServerGetAppIdResponse = wf_rail_server_get_appid_response;
wf_rail_register_update_callbacks(context->update);
wfc->railWindows = HashTable_New(TRUE);
return (wfc->railWindows != nullptr);
}
void wf_rail_uninit(wfContext* wfc, RailClientContext* rail)
{
wfc->rail = nullptr;
rail->custom = nullptr;
HashTable_Free(wfc->railWindows);
}

View File

@@ -0,0 +1,33 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2013-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WIN_RAIL_H
#define FREERDP_CLIENT_WIN_RAIL_H
typedef struct wf_rail_window wfRailWindow;
#include "wf_client.h"
#include <freerdp/client/rail.h>
BOOL wf_rail_init(wfContext* wfc, RailClientContext* rail);
void wf_rail_uninit(wfContext* wfc, RailClientContext* rail);
void wf_rail_invalidate_region(wfContext* wfc, REGION16* invalidRegion);
#endif /* FREERDP_CLIENT_WIN_RAIL_H */