diff --git a/CMakeLists.txt b/CMakeLists.txt
index e8268be12..718f9ff70 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -776,8 +776,8 @@ if(WITH_CHANNELS)
add_subdirectory(channels)
endif()
-if(WITH_CLIENT)
- add_subdirectory(client)
+if(WITH_CLIENT_COMMON OR WITH_CLIENT)
+add_subdirectory(client)
endif()
if(WITH_SERVER)
diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c
index 96d0dc79d..b082c830e 100644
--- a/channels/cliprdr/server/cliprdr_main.c
+++ b/channels/cliprdr/server/cliprdr_main.c
@@ -1004,9 +1004,9 @@ static UINT cliprdr_server_receive_filecontents_response(CliprdrServerContext* c
response.cbRequested = header->dataLen - 4;
response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */
- IFCALLRET(context->ServerFileContentsResponse, error, context, &response);
+ IFCALLRET(context->ClientFileContentsResponse, error, context, &response);
if (error)
- WLog_ERR(TAG, "ServerFileContentsResponse failed with error %lu!", error);
+ WLog_ERR(TAG, "ClientFileContentsResponse failed with error %lu!", error);
return error;
}
diff --git a/client/Android/FreeRDPCore/res/values-zh/strings.xml b/client/Android/FreeRDPCore/res/values-zh/strings.xml
new file mode 100644
index 000000000..b4514265c
--- /dev/null
+++ b/client/Android/FreeRDPCore/res/values-zh/strings.xml
@@ -0,0 +1,199 @@
+
+
+
+ 是
+ 否
+ 取消
+ 继续
+ 登录
+ 断开
+
+ 退出
+ 关于
+ 帮助
+ 新建连接
+ 设置
+
+ 操作
+ 连接
+ 编辑
+ 删除
+
+ 键盘
+ 功能键
+ 触控鼠标
+ 主目录
+ 断开连接
+
+ 手动连接
+ 活动会话数
+
+ 搜索
+
+ 登录
+ 没有服务
+ 连接中 …
+ 正在断开连接 …
+ 连接丢失
+ 密码错误
+ 用户名错误
+ 新建连接
+
+ 主机信息
+ 标签*
+ 远程主机ip或域名
+ 端口
+ 登录信息
+ 登录信息
+ 用户名
+ 密码
+ 域
+ 设置
+ 显示
+ 显示设置
+ 颜色深度
+
+ - High Color (16 Bit)
+ - True Color (24 Bit)
+ - Highest Quality (32 Bit)
+
+
+ - 16
+ - 24
+ - 32
+
+ 分辨率
+ 自动
+ 全屏
+ 自定义
+
+ - 自动
+ - 全屏
+ - 自定义
+ - 640x480
+ - 720x480
+ - 800x600
+ - 1024x768
+ - 1280x1024
+ - 1440x900
+ - 1920x1080
+ - 1920x1200
+
+
+ - 自动
+ - 全屏
+ - 自定义
+ - 640x480
+ - 720x480
+ - 800x600
+ - 1024x768
+ - 1280x1024
+ - 1440x900
+ - 1920x1080
+ - 1920x1200
+
+ 宽度
+ 高度
+ 连接性能
+ 性能设置
+ RemoteFX
+ 桌面背景
+ 字体平滑
+ 桌面拼合
+ 拖动是显示窗口内容
+ 菜单动画效果
+ 视觉样式
+ 高级
+ 高级设置
+ 3G设置
+ 使用3G网络时的显示设置
+ 使用3G网络时的连接性能
+ 路由
+ 使用路由
+ 路由设置
+ SDCard 重定向
+ 音频重定向
+
+ - 不要播放
+ - 在远程主机播放
+ - 在此设备上播放
+
+
+ - 0
+ - 1
+ - 2
+
+ 麦克风重定向
+ 连接协议
+
+ - 自动
+ - RDP
+ - TLS
+ - NLA
+
+
+ - 0
+ - 1
+ - 2
+ - 3
+
+ 远程程序
+ 工作目录
+ Async channel
+ Async transport
+ Async input
+ Async update
+ 控制台模式
+
+ *******
+ 未设置
+ 用户界面
+ 隐藏状态栏
+ 隐藏缩放控件
+ 交换鼠标左右键
+ 翻转滚动
+ 触摸指针自动滚屏
+ 退出时确认是否退出
+ 省电设计
+ 关闭空闲连接
+ 安全
+ 接受所有证书
+ 清除证书缓存
+ %1$d 秒后
+ Disabled
+
+ 连接设置
+ 设置
+ aFreeRDP - FreeRDP for Android
+ RDP Connections
+ 帮助
+ 关于
+
+ 不保存即退出?
+ 点击 “继续” 继续编辑,点击 "取消" 放弃当前更改
+ 建立连接失败!
+
+ 由于主机不支持您的设置所以显示设置已经修改为适应主机的设置!
+ 清除证书缓存成功!
+ 清楚证书缓存失败!
+
+ 证书验证
+ 未能验证远程主机证书的安全性,是否连接?
+ 请输入您的证书
+ 创建快捷方式
+ 快捷方式名称:
+ 连接中 …
+ 正在登录 …
+ 关于aFreeRDP
+ 是否保存连接设置?
+ 连接设置还没保存! 是否保存?
+ 保存?
+ 是否保存更改?
+ 不再提示
+ 退出?
+ 是否退出?
+ 清除证书缓存?
+ 是否清除所有的证书缓存?
+ Debug Level
+ Debug Settings
+
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index b8b769922..37a811db2 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -19,7 +19,7 @@
add_subdirectory(common)
-if(FREERDP_VENDOR)
+if(FREERDP_VENDOR AND WITH_CLIENT)
if(WIN32)
add_subdirectory(Windows)
else()
@@ -58,28 +58,28 @@ if(FREERDP_VENDOR)
endif()
# Pick up other clients
+if(WITH_CLIENT)
+ set(FILENAME "ModuleOptions.cmake")
+ file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}")
-set(FILENAME "ModuleOptions.cmake")
-file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}")
-
-foreach(FILEPATH ${FILEPATHS})
- if(${FILEPATH} MATCHES "^([^/]*)/+${FILENAME}")
- string(REGEX REPLACE "^([^/]*)/+${FILENAME}" "\\1" FREERDP_CLIENT ${FILEPATH})
- set(FREERDP_CLIENT_ENABLED 0)
- include(${FILEPATH})
- if(FREERDP_CLIENT_ENABLED)
- if(NOT (${FREERDP_CLIENT_VENDOR} MATCHES "FreeRDP"))
- list(APPEND FREERDP_EXTRA_CLIENTS ${FREERDP_CLIENT})
- if(${FREERDP_CLIENT_VENDOR} MATCHES "${VENDOR}")
- set(CLIENT_VENDOR_PATH "client/${FREERDP_CLIENT}" PARENT_SCOPE)
+ foreach(FILEPATH ${FILEPATHS})
+ if(${FILEPATH} MATCHES "^([^/]*)/+${FILENAME}")
+ string(REGEX REPLACE "^([^/]*)/+${FILENAME}" "\\1" FREERDP_CLIENT ${FILEPATH})
+ set(FREERDP_CLIENT_ENABLED 0)
+ include(${FILEPATH})
+ if(FREERDP_CLIENT_ENABLED)
+ if(NOT (${FREERDP_CLIENT_VENDOR} MATCHES "FreeRDP"))
+ list(APPEND FREERDP_EXTRA_CLIENTS ${FREERDP_CLIENT})
+ if(${FREERDP_CLIENT_VENDOR} MATCHES "${VENDOR}")
+ set(CLIENT_VENDOR_PATH "client/${FREERDP_CLIENT}" PARENT_SCOPE)
+ endif()
endif()
endif()
endif()
- endif()
-endforeach()
-
-foreach(FREERDP_CLIENT ${FREERDP_EXTRA_CLIENTS})
- add_subdirectory(${FREERDP_CLIENT})
-endforeach()
+ endforeach()
+ foreach(FREERDP_CLIENT ${FREERDP_EXTRA_CLIENTS})
+ add_subdirectory(${FREERDP_CLIENT})
+ endforeach()
+endif()
diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c
index b45f18c35..3f056210e 100644
--- a/client/X11/xf_client.c
+++ b/client/X11/xf_client.c
@@ -342,7 +342,7 @@ BOOL xf_sw_end_paint(rdpContext* context)
xf_lock_x11(xfc, FALSE);
- xf_rail_paint(xfc, x, y, x + w - 1, y + h - 1);
+ xf_rail_paint(xfc, x, y, x + w, y + h);
xf_unlock_x11(xfc, FALSE);
}
@@ -455,7 +455,7 @@ BOOL xf_hw_end_paint(rdpContext* context)
xf_lock_x11(xfc, FALSE);
- xf_rail_paint(xfc, x, y, x + w - 1, y + h - 1);
+ xf_rail_paint(xfc, x, y, x + w, y + h);
xf_unlock_x11(xfc, FALSE);
}
@@ -1852,7 +1852,11 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
xfc->_NET_WORKAREA = XInternAtom(xfc->display, "_NET_WORKAREA", False);
xfc->_NET_WM_STATE = XInternAtom(xfc->display, "_NET_WM_STATE", False);
xfc->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfc->display, "_NET_WM_STATE_FULLSCREEN", False);
+ xfc->_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ xfc->_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
xfc->_NET_WM_FULLSCREEN_MONITORS = XInternAtom(xfc->display, "_NET_WM_FULLSCREEN_MONITORS", False);
+ xfc->_NET_WM_NAME = XInternAtom(xfc->display, "_NET_WM_NAME", False);
+ xfc->_NET_WM_PID = XInternAtom(xfc->display, "_NET_WM_PID", False);
xfc->_NET_WM_WINDOW_TYPE = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE", False);
xfc->_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
xfc->_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
@@ -1863,6 +1867,8 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
xfc->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfc->display, "_NET_WM_STATE_SKIP_PAGER", False);
xfc->_NET_WM_MOVERESIZE = XInternAtom(xfc->display, "_NET_WM_MOVERESIZE", False);
xfc->_NET_MOVERESIZE_WINDOW = XInternAtom(xfc->display, "_NET_MOVERESIZE_WINDOW", False);
+
+ xfc->UTF8_STRING = XInternAtom(xfc->display, "UTF8_STRING", FALSE);
xfc->WM_PROTOCOLS = XInternAtom(xfc->display, "WM_PROTOCOLS", False);
xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False);
xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False);
diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c
index 1d6d9c06d..243e920d2 100644
--- a/client/X11/xf_keyboard.c
+++ b/client/X11/xf_keyboard.c
@@ -466,7 +466,7 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym)
return TRUE;
}
- if(xfc->fullscreen_toggle)
+ if(!xfc->remote_app && xfc->fullscreen_toggle)
{
if (keysym == XK_Return)
{
diff --git a/client/X11/xf_monitor.c b/client/X11/xf_monitor.c
index 920323ade..346bcd9c4 100644
--- a/client/X11/xf_monitor.c
+++ b/client/X11/xf_monitor.c
@@ -120,7 +120,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
int i;
int nmonitors = 0;
int primaryMonitorFound = FALSE;
- int vX, vY, vWidth, vHeight;
VIRTUAL_SCREEN* vscreen;
rdpSettings* settings = xfc->settings;
@@ -270,10 +269,10 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
if (settings->MonitorCount)
{
/* Initialize bounding rectangle for all monitors */
- vWidth = settings->MonitorDefArray[0].width;
- vHeight = settings->MonitorDefArray[0].height;
- vX = settings->MonitorDefArray[0].x;
- vY = settings->MonitorDefArray[0].y;
+ int vX = settings->MonitorDefArray[0].x;
+ int vY = settings->MonitorDefArray[0].y;
+ int vR = vX + settings->MonitorDefArray[0].width;
+ int vB = vY + settings->MonitorDefArray[0].height;
xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom =
xfc->fullscreenMonitors.left = xfc->fullscreenMonitors.right = settings->MonitorDefArray[0].orig_screen;
@@ -285,36 +284,36 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
/* does the same as gdk_rectangle_union */
int destX = MIN(vX, settings->MonitorDefArray[i].x);
int destY = MIN(vY, settings->MonitorDefArray[i].y);
- int destWidth = MAX(vX + vWidth, settings->MonitorDefArray[i].x + settings->MonitorDefArray[i].width) - destX;
- int destHeight = MAX(vY + vHeight, settings->MonitorDefArray[i].y + settings->MonitorDefArray[i].height) - destY;
+ int destR = MAX(vR, settings->MonitorDefArray[i].x + settings->MonitorDefArray[i].width);
+ int destB = MAX(vB, settings->MonitorDefArray[i].y + settings->MonitorDefArray[i].height);
if (vX != destX)
xfc->fullscreenMonitors.left = settings->MonitorDefArray[i].orig_screen;
if (vY != destY)
xfc->fullscreenMonitors.top = settings->MonitorDefArray[i].orig_screen;
- if (vWidth != destWidth)
+ if (vR != destR)
xfc->fullscreenMonitors.right = settings->MonitorDefArray[i].orig_screen;
- if (vHeight != destHeight)
+ if (vB != destB)
xfc->fullscreenMonitors.bottom = settings->MonitorDefArray[i].orig_screen;
vX = destX;
vY = destY;
- vWidth = destWidth;
- vHeight = destHeight;
+ vR = destR;
+ vB = destB;
}
settings->DesktopPosX = vX;
settings->DesktopPosY = vY;
vscreen->area.left = 0;
- vscreen->area.right = vWidth - 1;
+ vscreen->area.right = vR - vX - 1;
vscreen->area.top = 0;
- vscreen->area.bottom = vHeight - 1;
+ vscreen->area.bottom = vB - vY - 1;
if (settings->Workarea)
{
vscreen->area.top = xfc->workArea.y;
- vscreen->area.bottom = (vHeight - (vHeight - (xfc->workArea.height + xfc->workArea.y))) - 1;
+ vscreen->area.bottom = xfc->workArea.height + xfc->workArea.y - 1;
}
/* If there are multiple monitors and we have not selected a primary */
diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c
index a4617a228..22a941c53 100644
--- a/client/X11/xf_rail.c
+++ b/client/X11/xf_rail.c
@@ -119,25 +119,17 @@ void xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow)
return;
/* If current window position disagrees with RDP window position, send update to RDP server */
- if (appWindow->x != (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX) ||
- appWindow->y != (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY) ||
+ if (appWindow->x != appWindow->windowOffsetX ||
+ appWindow->y != appWindow->windowOffsetY ||
appWindow->width != appWindow->windowWidth ||
appWindow->height != appWindow->windowHeight)
{
- /*
- * windowOffset corresponds to the window location on the rail server
- * but our local window is based uses a local offset since the windowOffset
- * can be negative and but X does not support negative values. Not using an
- * offset can result in blank areas for a maximized window
- */
windowMove.windowId = appWindow->windowId;
/*
* Calculate new size/position for the rail window(new values for windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server
- * New position is based on: Current local rail window offset +
- * Local offset correction(current correction value to translate the local window offset to the server rail window offset)
*/
- windowMove.left = appWindow->x + appWindow->localWindowOffsetCorrX;
- windowMove.top = appWindow->y + appWindow->localWindowOffsetCorrY;
+ windowMove.left = appWindow->x;
+ windowMove.top = appWindow->y;
windowMove.right = windowMove.left + appWindow->width;
windowMove.bottom = windowMove.top + appWindow->height;
@@ -163,12 +155,10 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
/*
* Calculate new size/position for the rail window(new values for windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server
- * New position is based on: Current local rail window offset +
- * Local offset correction(current correction value to translate the local window offset to the server rail window offset)
*
*/
- windowMove.left = appWindow->x + appWindow->localWindowOffsetCorrX;
- windowMove.top = appWindow->y + appWindow->localWindowOffsetCorrY;
+ windowMove.left = appWindow->x;
+ windowMove.top = appWindow->y;
windowMove.right = windowMove.left + appWindow->width; /* In the update to RDP the position is one past the window */
windowMove.bottom = windowMove.top + appWindow->height;
@@ -180,8 +170,6 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
XQueryPointer(xfc->display, appWindow->handle,
&root_window, &child_window, &x, &y, &child_x, &child_y, &mask);
- input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y);
-
/* only send the mouse coordinates if not a keyboard move or size */
if ((appWindow->local_move.direction != _NET_WM_MOVERESIZE_MOVE_KEYBOARD) &&
(appWindow->local_move.direction != _NET_WM_MOVERESIZE_SIZE_KEYBOARD))
@@ -194,8 +182,8 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
* we can start to receive GDI orders for the new window dimensions before we
* receive the RAIL ORDER for the new window size. This avoids that race condition.
*/
- appWindow->windowOffsetX = windowMove.left;
- appWindow->windowOffsetY = windowMove.top;
+ appWindow->windowOffsetX = appWindow->x;
+ appWindow->windowOffsetY = appWindow->y;
appWindow->windowWidth = appWindow->width;
appWindow->windowHeight = appWindow->height;
appWindow->local_move.state = LMS_TERMINATING;
@@ -277,6 +265,7 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
xfAppWindow* appWindow = NULL;
xfContext* xfc = (xfContext*) context;
UINT32 fieldFlags = orderInfo->fieldFlags;
+ BOOL position_or_size_updated = FALSE;
if (fieldFlags & WINDOW_ORDER_STATE_NEW)
{
@@ -296,9 +285,7 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
appWindow->width = appWindow->windowWidth = windowState->windowWidth;
appWindow->height = appWindow->windowHeight = windowState->windowHeight;
- appWindow->localWindowOffsetCorrX = 0;
- appWindow->localWindowOffsetCorrY = 0;
-
+ /* Ensure window always gets a window title */
if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
{
char* title = NULL;
@@ -321,8 +308,6 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
HashTable_Add(xfc->railWindows, (void*) (UINT_PTR) orderInfo->windowId, (void*) appWindow);
xf_AppWindowInit(xfc, appWindow);
-
- return TRUE;
}
else
{
@@ -333,37 +318,31 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
if (!appWindow)
return FALSE;
+ /* Keep track of any position/size update so that we can force a refresh of the window */
+ if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
+ (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) ||
+ (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) ||
+ (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) ||
+ (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) ||
+ (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) ||
+ (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY))
+ {
+ position_or_size_updated = TRUE;
+ }
+
+
/* Update Parameters */
- if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
- (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE))
+ if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
{
- if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
- {
- appWindow->windowOffsetX = windowState->windowOffsetX;
- appWindow->windowOffsetY = windowState->windowOffsetY;
+ appWindow->windowOffsetX = windowState->windowOffsetX;
+ appWindow->windowOffsetY = windowState->windowOffsetY;
+ }
- /*
- * The rail server can give negative window coordinates when updating windowOffsetX and windowOffsetY,
- * but we can only send unsigned integers to the rail server. Therefore, we maintain a local offset.
- */
-
- if (appWindow->windowOffsetX < 0)
- appWindow->localWindowOffsetCorrX = 0 - appWindow->windowOffsetX;
- else
- appWindow->localWindowOffsetCorrX = 0;
-
- if (appWindow->windowOffsetY < 0)
- appWindow->localWindowOffsetCorrY = 0 - appWindow->windowOffsetY;
- else
- appWindow->localWindowOffsetCorrY = 0;
- }
-
- if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
- {
- appWindow->windowWidth = windowState->windowWidth;
- appWindow->windowHeight = windowState->windowHeight;
- }
+ if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
+ {
+ appWindow->windowWidth = windowState->windowWidth;
+ appWindow->windowHeight = windowState->windowHeight;
}
if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
@@ -479,41 +458,43 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
xf_SetWindowText(xfc, appWindow, appWindow->title);
}
- if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
- (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE))
+ if (position_or_size_updated)
{
+ UINT32 visibilityRectsOffsetX = (appWindow->visibleOffsetX - (appWindow->clientOffsetX - appWindow->windowClientDeltaX));
+ UINT32 visibilityRectsOffsetY = (appWindow->visibleOffsetY - (appWindow->clientOffsetY - appWindow->windowClientDeltaY));
+
/*
* The rail server like to set the window to a small size when it is minimized even though it is hidden
* in some cases this can cause the window not to restore back to its original size. Therefore we don't
* update our local window when that rail window state is minimized
*/
- if (appWindow->rail_state == WINDOW_SHOW_MINIMIZED)
- return TRUE;
+ if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)
+ {
- /* Do nothing if window is already in the correct position */
- if (appWindow->x == (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX) &&
- appWindow->y == (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY) &&
+ /* Redraw window area if already in the correct position */
+ if (appWindow->x == appWindow->windowOffsetX &&
+ appWindow->y == appWindow->windowOffsetY &&
appWindow->width == appWindow->windowWidth &&
appWindow->height == appWindow->windowHeight)
- {
- xf_UpdateWindowArea(xfc, appWindow, 0, 0, appWindow->windowWidth, appWindow->windowHeight);
- }
- else
- {
- xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX, appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY,
- appWindow->windowWidth, appWindow->windowHeight);
+ {
+ xf_UpdateWindowArea(xfc, appWindow, 0, 0, appWindow->windowWidth, appWindow->windowHeight);
+ }
+ else
+ {
+ xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, appWindow->windowOffsetY,
+ appWindow->windowWidth, appWindow->windowHeight);
+ }
+
+ xf_SetWindowVisibilityRects(xfc, appWindow, visibilityRectsOffsetX, visibilityRectsOffsetY, appWindow->visibilityRects, appWindow->numVisibilityRects);
}
}
- if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
+ /* We should only be using the visibility rects for shaping the window */
+ /*if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
{
xf_SetWindowRects(xfc, appWindow, appWindow->windowRects, appWindow->numWindowRects);
- }
+ }*/
- if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
- {
- xf_SetWindowVisibilityRects(xfc, appWindow, appWindow->visibilityRects, appWindow->numVisibilityRects);
- }
return TRUE;
}
diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c
index b7a4663e2..28f8bc8f1 100644
--- a/client/X11/xf_window.c
+++ b/client/X11/xf_window.c
@@ -185,30 +185,37 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen)
*/
startX = startX + xfc->instance->settings->MonitorLocalShiftX;
startY = startY + xfc->instance->settings->MonitorLocalShiftY;
+
+ /* Set monitor bounds */
+ if (settings->MonitorCount > 1)
+ {
+ xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_FULLSCREEN_MONITORS, 5,
+ xfc->fullscreenMonitors.top,
+ xfc->fullscreenMonitors.bottom,
+ xfc->fullscreenMonitors.left,
+ xfc->fullscreenMonitors.right,
+ 1);
+ }
}
xf_ResizeDesktopWindow(xfc, window, width, height);
+ if (fullscreen)
+ {
+ /* enter full screen: move the window before adding NET_WM_STATE_FULLSCREEN */
+ XMoveWindow(xfc->display, window->handle, startX, startY);
+ }
+
/* Set the fullscreen state */
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
xfc->_NET_WM_STATE_FULLSCREEN, 0, 0);
- /* Only send monitor bounds if they are valid */
- if ((xfc->fullscreenMonitors.top >= 0) &&
- (xfc->fullscreenMonitors.bottom >= 0) &&
- (xfc->fullscreenMonitors.left >= 0) &&
- (xfc->fullscreenMonitors.right >= 0))
+ if (!fullscreen)
{
- xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_FULLSCREEN_MONITORS, 5,
- xfc->fullscreenMonitors.top,
- xfc->fullscreenMonitors.bottom,
- xfc->fullscreenMonitors.left,
- xfc->fullscreenMonitors.right,
- 1);
+ /* leave full screen: move the window after removing NET_WM_STATE_FULLSCREEN */
+ XMoveWindow(xfc->display, window->handle, startX, startY);
}
-
- XMoveWindow(xfc->display, window->handle, startX, startY);
}
/* http://tronche.com/gui/x/xlib/window-information/XGetWindowProperty.html */
@@ -327,7 +334,7 @@ static void xf_SetWindowPID(xfContext* xfc, Window window, pid_t pid)
if (!pid)
pid = getpid();
- am_wm_pid = XInternAtom(xfc->display, "_NET_WM_PID", False);
+ am_wm_pid = xfc->_NET_WM_PID;
XChangeProperty(xfc->display, window, am_wm_pid, XA_CARDINAL,
32, PropModeReplace, (BYTE*) &pid, 1);
@@ -567,9 +574,11 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UIN
}
else
{
- XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_WINDOW_TYPE,
- XA_ATOM, 32, PropModeReplace, (BYTE*) &window_type, 1);
+ window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL;
}
+
+ XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_WINDOW_TYPE,
+ XA_ATOM, 32, PropModeReplace, (BYTE*) &window_type, 1);
}
void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, char* name)
@@ -577,8 +586,8 @@ void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, char* name)
const size_t i = strlen(name);
XStoreName(xfc->display, appWindow->handle, name);
- Atom wm_Name = XInternAtom(xfc->display, "_NET_WM_NAME", FALSE);
- Atom utf8Str = XInternAtom(xfc->display, "UTF8_STRING", FALSE);
+ Atom wm_Name = xfc->_NET_WM_NAME;
+ Atom utf8Str = xfc->UTF8_STRING;
XChangeProperty(xfc->display, appWindow->handle, wm_Name, utf8Str, 8,
PropModeReplace, (unsigned char *)name, i);
@@ -821,9 +830,10 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state)
case WINDOW_SHOW_MAXIMIZED:
/* Set the window as maximized */
- xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, 1,
- XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False),
- XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False), 0);
+ xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4,
+ _NET_WM_STATE_ADD,
+ xfc->_NET_WM_STATE_MAXIMIZED_VERT,
+ xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0);
/*
* This is a workaround for the case where the window is maximized locally before the rail server is told to maximize
* the window, this appears to be a race condition where the local window with incomplete data and once the window is
@@ -838,9 +848,10 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state)
case WINDOW_SHOW:
/* Ensure the window is not maximized */
- xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, 0,
- XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False),
- XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False), 0);
+ xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4,
+ _NET_WM_STATE_REMOVE,
+ xfc->_NET_WM_STATE_MAXIMIZED_VERT,
+ xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0);
/*
* Ignore configure requests until both the Maximized properties have been processed
* to prevent condition where WM overrides size of request due to one or both of these properties
@@ -923,7 +934,7 @@ void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rec
}
-void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects)
+void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects)
{
int i;
XRectangle* xrects;
@@ -942,7 +953,7 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANG
xrects[i].height = rects[i].bottom - rects[i].top;
}
- XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0);
+ XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, rectsOffsetX, rectsOffsetY, xrects, nrects, ShapeSet, 0);
free(xrects);
#endif
@@ -951,20 +962,14 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANG
void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height)
{
int ax, ay;
- UINT32 translatedWindowOffsetX;
- UINT32 translatedWindowOffsetY;
- /* Translate the server rail window offset to a local offset */
- translatedWindowOffsetX = (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX);
- translatedWindowOffsetY = (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY);
+ ax = x + appWindow->windowOffsetX;
+ ay = y + appWindow->windowOffsetY;
- ax = x + translatedWindowOffsetX;
- ay = y + translatedWindowOffsetY;
-
- if (ax + width > translatedWindowOffsetX + appWindow->width)
- width = (translatedWindowOffsetX + appWindow->width - 1) - ax;
- if (ay + height > translatedWindowOffsetY + appWindow->height)
- height = (translatedWindowOffsetY + appWindow->height - 1) - ay;
+ if (ax + width > appWindow->windowOffsetX + appWindow->width)
+ width = (appWindow->windowOffsetX + appWindow->width - 1) - ax;
+ if (ay + height > appWindow->windowOffsetY + appWindow->height)
+ height = (appWindow->windowOffsetY + appWindow->height - 1) - ay;
xf_lock_x11(xfc, TRUE);
diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h
index 9120fd1df..0a41c798a 100644
--- a/client/X11/xf_window.h
+++ b/client/X11/xf_window.h
@@ -102,22 +102,22 @@ struct xf_app_window
UINT32 dwExStyle;
UINT32 showState;
- UINT32 clientOffsetX;
- UINT32 clientOffsetY;
+ INT32 clientOffsetX;
+ INT32 clientOffsetY;
UINT32 clientAreaWidth;
UINT32 clientAreaHeight;
- UINT32 windowOffsetX;
- UINT32 windowOffsetY;
- UINT32 windowClientDeltaX;
- UINT32 windowClientDeltaY;
+ INT32 windowOffsetX;
+ INT32 windowOffsetY;
+ INT32 windowClientDeltaX;
+ INT32 windowClientDeltaY;
UINT32 windowWidth;
UINT32 windowHeight;
UINT32 numWindowRects;
RECTANGLE_16* windowRects;
- UINT32 visibleOffsetX;
- UINT32 visibleOffsetY;
+ INT32 visibleOffsetX;
+ INT32 visibleOffsetY;
UINT32 numVisibilityRects;
RECTANGLE_16* visibilityRects;
@@ -160,7 +160,7 @@ void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int wid
void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state);
//void xf_SetWindowIcon(xfContext* xfc, xfAppWindow* appWindow, rdpIcon* icon);
void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects);
-void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects);
+void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects);
void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style);
void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height);
void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow);
diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h
index 5e1bdfab1..a885536c7 100644
--- a/client/X11/xfreerdp.h
+++ b/client/X11/xfreerdp.h
@@ -185,6 +185,8 @@ struct xf_context
xfClipboard* clipboard;
CliprdrClientContext* cliprdr;
+ Atom UTF8_STRING;
+
Atom _NET_WM_ICON;
Atom _MOTIF_WM_HINTS;
Atom _NET_CURRENT_DESKTOP;
@@ -192,11 +194,16 @@ struct xf_context
Atom _NET_WM_STATE;
Atom _NET_WM_STATE_FULLSCREEN;
+ Atom _NET_WM_STATE_MAXIMIZED_HORZ;
+ Atom _NET_WM_STATE_MAXIMIZED_VERT;
Atom _NET_WM_STATE_SKIP_TASKBAR;
Atom _NET_WM_STATE_SKIP_PAGER;
Atom _NET_WM_FULLSCREEN_MONITORS;
+ Atom _NET_WM_NAME;
+ Atom _NET_WM_PID;
+
Atom _NET_WM_WINDOW_TYPE;
Atom _NET_WM_WINDOW_TYPE_NORMAL;
Atom _NET_WM_WINDOW_TYPE_DIALOG;
diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake
index 244fdcf6e..9d501c164 100644
--- a/cmake/ConfigOptions.cmake
+++ b/cmake/ConfigOptions.cmake
@@ -60,16 +60,17 @@ CMAKE_DEPENDENT_OPTION(TESTS_WTSAPI_EXTRA "Build extra WTSAPI tests (interactive
option(WITH_SAMPLE "Build sample code" OFF)
-option(WITH_CLIENT "Build client binaries" ON)
+option(WITH_CLIENT_COMMON "Build client common library" ON)
+cmake_dependent_option(WITH_CLIENT "Build client binaries" ON WITH_CLIENT_COMMON ON)
+
option(WITH_SERVER "Build server binaries" OFF)
option(STATIC_CHANNELS "Build channels statically" ON)
option(WITH_CHANNELS "Build virtual channel plugins" ON)
-if(WITH_CLIENT AND WITH_CHANNELS)
- option(WITH_CLIENT_CHANNELS "Build virtual channel plugins" ON)
-endif()
+cmake_dependent_option(WITH_CLIENT_CHANNELS "Build virtual channel plugins" ON
+ "WITH_CLIENT_COMMON;WITH_CHANNELS" ON)
if(WITH_SERVER AND WITH_CHANNELS)
option(WITH_SERVER_CHANNELS "Build virtual channel plugins" ON)
diff --git a/include/freerdp/window.h b/include/freerdp/window.h
index c52c35c72..4a5b2b84f 100644
--- a/include/freerdp/window.h
+++ b/include/freerdp/window.h
@@ -174,22 +174,22 @@ struct _WINDOW_STATE_ORDER
UINT32 extendedStyle;
UINT32 showState;
RAIL_UNICODE_STRING titleInfo;
- UINT32 clientOffsetX;
- UINT32 clientOffsetY;
+ INT32 clientOffsetX;
+ INT32 clientOffsetY;
UINT32 clientAreaWidth;
UINT32 clientAreaHeight;
UINT32 RPContent;
UINT32 rootParentHandle;
- UINT32 windowOffsetX;
- UINT32 windowOffsetY;
- UINT32 windowClientDeltaX;
- UINT32 windowClientDeltaY;
+ INT32 windowOffsetX;
+ INT32 windowOffsetY;
+ INT32 windowClientDeltaX;
+ INT32 windowClientDeltaY;
UINT32 windowWidth;
UINT32 windowHeight;
UINT32 numWindowRects;
RECTANGLE_16* windowRects;
- UINT32 visibleOffsetX;
- UINT32 visibleOffsetY;
+ INT32 visibleOffsetX;
+ INT32 visibleOffsetY;
UINT32 numVisibilityRects;
RECTANGLE_16* visibilityRects;
};
diff --git a/libfreerdp/cache/glyph.c b/libfreerdp/cache/glyph.c
index 037c5a5d9..0157d40bc 100644
--- a/libfreerdp/cache/glyph.c
+++ b/libfreerdp/cache/glyph.c
@@ -260,6 +260,12 @@ BOOL update_gdi_fast_index(rdpContext* context, FAST_INDEX_ORDER* fastIndex)
if (opRight == 0)
opRight = fastIndex->bkRight;
+ /* Server can send a massive number (32766) which appears to be
+ * undocumented special behavior for "Erase all the way right".
+ * X11 has nondeterministic results asking for a draw that wide. */
+ if (opRight > context->instance->settings->DesktopWidth)
+ opRight = context->instance->settings->DesktopWidth;
+
if (x == -32768)
x = fastIndex->bkLeft;
@@ -313,6 +319,10 @@ BOOL update_gdi_fast_glyph(rdpContext* context, FAST_GLYPH_ORDER* fastGlyph)
if (opRight == 0)
opRight = fastGlyph->bkRight;
+ /* See update_gdi_fast_index opRight comment. */
+ if (opRight > context->instance->settings->DesktopWidth)
+ opRight = context->instance->settings->DesktopWidth;
+
if (x == -32768)
x = fastGlyph->bkLeft;
diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c
index 7e4235cb8..08c5c4284 100644
--- a/libfreerdp/codec/color.c
+++ b/libfreerdp/codec/color.c
@@ -3444,8 +3444,8 @@ int freerdp_image32_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDs
pSrcPixel++;
}
- pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcStep];
- pDstPixel = (BYTE*) &((BYTE*) pDstPixel)[nDstStep];
+ pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcPad];
+ pDstPixel = (BYTE*) &((BYTE*) pDstPixel)[nDstPad];
}
return 1;
diff --git a/winpr/include/winpr/wlog.h b/winpr/include/winpr/wlog.h
index 7ac9dd002..f7c0efd17 100644
--- a/winpr/include/winpr/wlog.h
+++ b/winpr/include/winpr/wlog.h
@@ -32,6 +32,7 @@ extern "C" {
#include
#include
+#include
typedef struct _wLog wLog;
typedef struct _wLogMessage wLogMessage;
@@ -115,6 +116,7 @@ struct _wLogLayout
#define WLOG_APPENDER_CALLBACK 3
#define WLOG_APPENDER_SYSLOG 4
#define WLOG_APPENDER_JOURNALD 5
+#define WLOG_APPENDER_UDP 6
#define WLOG_PACKET_INBOUND 1
#define WLOG_PACKET_OUTBOUND 2
@@ -213,6 +215,16 @@ struct _wLogJournaldAppender
};
typedef struct _wLogJournaldAppender wLogJournaldAppender;
+struct _wLogUdpAppender
+{
+ WLOG_APPENDER_COMMON();
+ char *host;
+ struct sockaddr targetAddr;
+ int targetAddrLen;
+ SOCKET sock;
+};
+typedef struct _wLogUdpAppender wLogUdpAppender;
+
/**
* Filter
diff --git a/winpr/libwinpr/path/path.c b/winpr/libwinpr/path/path.c
index de7b2aaeb..2f853aad0 100644
--- a/winpr/libwinpr/path/path.c
+++ b/winpr/libwinpr/path/path.c
@@ -596,13 +596,13 @@ HRESULT PathCchRemoveExtensionW(PWSTR pszPath, size_t cchPath)
BOOL PathCchIsRootA(PCSTR pszPath)
{
WLog_ERR(TAG, "%s: not implemented", __FUNCTION__);
- return E_NOTIMPL;
+ return FALSE;
}
BOOL PathCchIsRootW(PCWSTR pszPath)
{
WLog_ERR(TAG, "%s: not implemented", __FUNCTION__);
- return E_NOTIMPL;
+ return FALSE;
}
/**
diff --git a/winpr/libwinpr/thread/argv.c b/winpr/libwinpr/thread/argv.c
index 2bd7dc4fb..ad96da236 100644
--- a/winpr/libwinpr/thread/argv.c
+++ b/winpr/libwinpr/thread/argv.c
@@ -101,7 +101,6 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs)
LPSTR* pArgs;
int maxNumArgs;
int maxBufferSize;
- int currentIndex;
int cmdLineLength;
BOOL* lpEscapedChars;
LPSTR lpEscapedCmdLine;
@@ -167,36 +166,29 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs)
p += length;
for (i = 0; i < (n / 2); i++)
- {
- *pOutput = '\\';
- pOutput++;
- }
+ *pOutput++ = '\\';
p += n + 1;
if ((n % 2) != 0)
lpEscapedChars[pOutput - lpEscapedCmdLine] = TRUE;
- *pOutput = '"';
- pOutput++;
+ *pOutput++ = '"';
pLastEnd = p;
}
- *pOutput = '\0';
- pOutput++;
+ *pOutput++ = '\0';
lpCmdLine = (LPCSTR) lpEscapedCmdLine;
cmdLineLength = strlen(lpCmdLine);
}
maxNumArgs = 2;
- currentIndex = 0;
p = (char*) lpCmdLine;
- while (currentIndex < cmdLineLength - 1)
+ while (p < lpCmdLine + cmdLineLength)
{
- index = strcspn(p, " \t");
- currentIndex += (index + 1);
- p = (char*) &lpCmdLine[currentIndex];
+ p += strcspn(p, " \t");
+ p += strspn(p, " \t");
maxNumArgs++;
}
@@ -209,32 +201,24 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs)
pArgs = (LPSTR*) buffer;
pOutput = (char*) &buffer[maxNumArgs * (sizeof(char*))];
numArgs = 0;
- currentIndex = 0;
p = (char*) lpCmdLine;
- while (currentIndex < cmdLineLength)
+ while (p < lpCmdLine + cmdLineLength)
{
- pBeg = pEnd = p;
+ pBeg = p;
while (1)
{
- index = strcspn(p, " \t\"\0");
-
- if ((p[index] == '"') && (lpEscapedChars[&p[index] - lpCmdLine]))
- {
- p = &p[index + 1];
- continue;
- }
-
- break;
+ p += strcspn(p, " \t\"\0");
+ if ((*p != '"') || !lpEscapedChars[p - lpCmdLine])
+ break;
+ p++;
}
- if (p[index] != '"')
+ if (*p != '"')
{
/* no whitespace escaped with double quotes */
- p = &p[index + 1];
- pEnd = p - 1;
- length = (pEnd - pBeg);
+ length = p - pBeg;
CopyMemory(pOutput, pBeg, length);
pOutput[length] = '\0';
pArgs[numArgs++] = pOutput;
@@ -242,62 +226,35 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs)
}
else
{
- p = &p[index + 1];
+ p++;
while (1)
{
- index = strcspn(p, "\"\0");
-
- if ((p[index] == '"') && (lpEscapedChars[&p[index] - lpCmdLine]))
- {
- p = &p[index + 1];
- continue;
- }
-
- break;
+ p += strcspn(p, "\"\0");
+ if ((*p != '"') || !lpEscapedChars[p - lpCmdLine])
+ break;
+ p++;
}
- if (p[index] != '"')
- {
+ if (*p != '"')
WLog_ERR(TAG, "parsing error: uneven number of unescaped double quotes!");
- }
- if (p[index] == '\0')
- {
- p = &p[index + 1];
- pEnd = p - 1;
- }
- else
- {
- p = &p[index + 1];
- index = strcspn(p, " \t\0");
- p = &p[index + 1];
- pEnd = p - 1;
- }
+ if (*p && *(++p))
+ p += strcspn(p, " \t\0");
- length = 0;
pArgs[numArgs++] = pOutput;
- while (pBeg < pEnd)
+ while (pBeg < p)
{
if (*pBeg != '"')
- {
- *pOutput = *pBeg;
- pOutput++;
- length++;
- }
-
+ *pOutput++ = *pBeg;
pBeg++;
}
- *pOutput = '\0';
- pOutput++;
+ *pOutput++ = '\0';
}
- while ((*p == ' ') || (*p == '\t'))
- p++;
-
- currentIndex = (p - lpCmdLine);
+ p += strspn(p, " \t");
}
free(lpEscapedCmdLine);
diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt
index a84d180f8..2a8411966 100644
--- a/winpr/libwinpr/utils/CMakeLists.txt
+++ b/winpr/libwinpr/utils/CMakeLists.txt
@@ -94,6 +94,8 @@ set(${MODULE_PREFIX}_WLOG_SRCS
wlog/CallbackAppender.h
wlog/ConsoleAppender.c
wlog/ConsoleAppender.h
+ wlog/UdpAppender.c
+ wlog/UdpAppender.h
${SYSLOG_SRCS}
${JOURNALD_SRCS}
)
diff --git a/winpr/libwinpr/utils/wlog/Appender.c b/winpr/libwinpr/utils/wlog/Appender.c
index 8008f6df3..a9c4d566f 100644
--- a/winpr/libwinpr/utils/wlog/Appender.c
+++ b/winpr/libwinpr/utils/wlog/Appender.c
@@ -58,6 +58,9 @@ wLogAppender* WLog_Appender_New(wLog* log, DWORD logAppenderType)
appender = (wLogAppender*) WLog_JournaldAppender_New(log);
break;
#endif
+ case WLOG_APPENDER_UDP:
+ appender = (wLogAppender*) WLog_UdpAppender_New(log);
+ break;
default:
fprintf(stderr, "%s: unknown handler type %d\n", __FUNCTION__, logAppenderType);
appender = NULL;
@@ -118,6 +121,9 @@ void WLog_Appender_Free(wLog* log, wLogAppender* appender)
WLog_JournaldAppender_Free(log, (wLogJournaldAppender *) appender);
break;
#endif
+ case WLOG_APPENDER_UDP:
+ WLog_UdpAppender_Free(log, (wLogUdpAppender *) appender);
+ break;
default:
fprintf(stderr, "%s: don't know how to free appender type %d\n", __FUNCTION__, appender->Type);
break;
diff --git a/winpr/libwinpr/utils/wlog/Appender.h b/winpr/libwinpr/utils/wlog/Appender.h
index ccb57085a..6b9b8ee21 100644
--- a/winpr/libwinpr/utils/wlog/Appender.h
+++ b/winpr/libwinpr/utils/wlog/Appender.h
@@ -26,6 +26,7 @@
#include "wlog/BinaryAppender.h"
#include "wlog/ConsoleAppender.h"
#include "wlog/CallbackAppender.h"
+#include "wlog/UdpAppender.h"
#ifdef HAVE_SYSLOG_H
#include "wlog/SyslogAppender.h"
diff --git a/winpr/libwinpr/utils/wlog/UdpAppender.c b/winpr/libwinpr/utils/wlog/UdpAppender.c
new file mode 100644
index 000000000..bc161d37b
--- /dev/null
+++ b/winpr/libwinpr/utils/wlog/UdpAppender.c
@@ -0,0 +1,209 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * WinPR Logger
+ *
+ * Copyright © 2015 Thincast Technologies GmbH
+ * Copyright © 2015 David FORT
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include
+#include
+#include
+
+#include
+
+#include "wlog/Message.h"
+#include "wlog/UdpAppender.h"
+
+#ifndef _WIN32
+#include
+#include
+#include
+#endif
+
+static BOOL WLog_UdpAppender_Open(wLog* log, wLogUdpAppender* appender)
+{
+ char addressString[256];
+ struct addrinfo hints;
+ struct addrinfo* result;
+ int status, addrLen;
+ char *colonPos;
+
+
+ if (!appender)
+ return FALSE;
+
+ if (appender->targetAddrLen) /* already opened */
+ return TRUE;
+
+ colonPos = strchr(appender->host, ':');
+ if (!colonPos)
+ return FALSE;
+ addrLen = colonPos - appender->host;
+ memcpy(addressString, appender->host, addrLen);
+ addressString[addrLen] = '\0';
+
+ ZeroMemory(&hints, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ status = getaddrinfo(addressString, colonPos+1, &hints, &result);
+ if (status != 0)
+ return FALSE;
+
+ if (result->ai_addrlen > sizeof(appender->targetAddr))
+ {
+ freeaddrinfo(result);
+ return FALSE;
+ }
+
+ memcpy(&appender->targetAddr, result->ai_addr, result->ai_addrlen);
+ appender->targetAddrLen = result->ai_addrlen;
+
+
+ return TRUE;
+}
+
+BOOL Wlog_UdpAppender_SetTarget(wLogUdpAppender* appender, const char *host)
+{
+
+ appender->targetAddrLen = 0;
+ if (appender->host)
+ free(appender->host);
+
+ appender->host = _strdup(host);
+ return (appender->host != NULL) && WLog_UdpAppender_Open(NULL, appender);
+}
+
+static BOOL WLog_UdpAppender_Close(wLog* log, wLogUdpAppender* appender)
+{
+ if (!log || !appender)
+ return FALSE;
+
+ return TRUE;
+}
+
+static BOOL WLog_UdpAppender_WriteMessage(wLog* log, wLogUdpAppender* appender, wLogMessage* message)
+{
+ char prefix[WLOG_MAX_PREFIX_SIZE];
+
+ if (!log || !appender || !message)
+ return FALSE;
+
+ message->PrefixString = prefix;
+ WLog_Layout_GetMessagePrefix(log, appender->Layout, message);
+
+ _sendto(appender->sock, message->PrefixString, strlen(message->PrefixString),
+ 0, &appender->targetAddr, appender->targetAddrLen);
+
+ _sendto(appender->sock, message->TextString, strlen(message->TextString),
+ 0, &appender->targetAddr, appender->targetAddrLen);
+
+ _sendto(appender->sock, "\n", 1, 0, &appender->targetAddr, appender->targetAddrLen);
+
+ return TRUE;
+}
+
+static BOOL WLog_UdpAppender_WriteDataMessage(wLog* log, wLogUdpAppender* appender, wLogMessage* message)
+{
+ if (!log || !appender || !message)
+ return FALSE;
+
+ return TRUE;
+}
+
+static BOOL WLog_UdpAppender_WriteImageMessage(wLog* log, wLogUdpAppender* appender, wLogMessage* message)
+{
+ if (!log || !appender || !message)
+ return FALSE;
+
+
+ return TRUE;
+}
+
+wLogUdpAppender* WLog_UdpAppender_New(wLog* log)
+{
+ wLogUdpAppender* appender;
+ DWORD nSize;
+ LPCSTR name;
+
+ appender = (wLogUdpAppender*) calloc(1, sizeof(wLogUdpAppender));
+ if (!appender)
+ return NULL;
+
+ appender->Type = WLOG_APPENDER_UDP;
+
+ appender->Open = (WLOG_APPENDER_OPEN_FN) WLog_UdpAppender_Open;
+ appender->Close = (WLOG_APPENDER_OPEN_FN) WLog_UdpAppender_Close;
+ appender->WriteMessage =
+ (WLOG_APPENDER_WRITE_MESSAGE_FN) WLog_UdpAppender_WriteMessage;
+ appender->WriteDataMessage =
+ (WLOG_APPENDER_WRITE_DATA_MESSAGE_FN) WLog_UdpAppender_WriteDataMessage;
+ appender->WriteImageMessage =
+ (WLOG_APPENDER_WRITE_IMAGE_MESSAGE_FN) WLog_UdpAppender_WriteImageMessage;
+
+ appender->sock = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (appender->sock == INVALID_SOCKET)
+ goto error_sock;
+
+ name = "WLOG_UDP_TARGET";
+ nSize = GetEnvironmentVariableA(name, NULL, 0);
+ if (nSize)
+ {
+ appender->host = (LPSTR) malloc(nSize);
+ if (!appender->host)
+ goto error_host_alloc;
+
+ GetEnvironmentVariableA(name, appender->host, nSize);
+
+ if (!WLog_UdpAppender_Open(log, appender))
+ goto error_open;
+ }
+ else
+ {
+ appender->host = _strdup("127.0.0.1:20000");
+ if (!appender->host)
+ goto error_host_alloc;
+ }
+
+ return appender;
+
+error_open:
+ free(appender->host);
+error_host_alloc:
+ closesocket(appender->sock);
+error_sock:
+ free(appender);
+ return NULL;
+}
+
+void WLog_UdpAppender_Free(wLog* log, wLogUdpAppender* appender)
+{
+ if (appender)
+ {
+ if (appender->sock != INVALID_SOCKET)
+ {
+ closesocket(appender->sock);
+ appender->sock = INVALID_SOCKET;
+ }
+ free(appender->host);
+ free(appender);
+ }
+}
diff --git a/winpr/libwinpr/utils/wlog/UdpAppender.h b/winpr/libwinpr/utils/wlog/UdpAppender.h
new file mode 100644
index 000000000..cd25345f4
--- /dev/null
+++ b/winpr/libwinpr/utils/wlog/UdpAppender.h
@@ -0,0 +1,35 @@
+/**
+ * Copyright © 2015 Thincast Technologies GmbH
+ * Copyright © 2015 David FORT
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef WINPR_LIBWINPR_UTILS_WLOG_UDPAPPENDER_H_
+#define WINPR_LIBWINPR_UTILS_WLOG_UDPAPPENDER_H_
+
+#include
+
+#include "wlog/wlog.h"
+
+WINPR_API wLogUdpAppender* WLog_UdpAppender_New(wLog* log);
+WINPR_API void WLog_UdpAppender_Free(wLog* log, wLogUdpAppender* appender);
+WINPR_API BOOL Wlog_UdpAppender_SetTarget(wLogUdpAppender* appender, const char *host);
+
+#endif /* WINPR_LIBWINPR_UTILS_WLOG_UDPAPPENDER_H_ */
diff --git a/winpr/libwinpr/utils/wlog/wlog.c b/winpr/libwinpr/utils/wlog/wlog.c
index 7dc6208e8..123fe6384 100644
--- a/winpr/libwinpr/utils/wlog/wlog.c
+++ b/winpr/libwinpr/utils/wlog/wlog.c
@@ -706,6 +706,8 @@ wLog* WLog_GetRoot()
else if (_stricmp(env, "JOURNALD") == 0)
logAppenderType = WLOG_APPENDER_JOURNALD;
#endif
+ else if (_stricmp(env, "UDP") == 0)
+ logAppenderType = WLOG_APPENDER_UDP;
free(env);
}