Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
198
third_party/FreeRDP/client/X11/CMakeLists.txt
vendored
Normal file
198
third_party/FreeRDP/client/X11/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP X11 Client
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2013 Corey Clayton <can.of.tuna@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.
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
if(NOT FREERDP_DEFAULT_PROJECT_VERSION)
|
||||
set(FREERDP_DEFAULT_PROJECT_VERSION "1.0.0.0")
|
||||
endif()
|
||||
|
||||
project(xfreerdp-client LANGUAGES C VERSION ${FREERDP_DEFAULT_PROJECT_VERSION})
|
||||
|
||||
message("project ${PROJECT_NAME} is using version ${PROJECT_VERSION}")
|
||||
|
||||
set(MODULE_NAME "xfreerdp")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/)
|
||||
include(ProjectCStandard)
|
||||
include(CommonConfigOptions)
|
||||
|
||||
include(ConfigureFreeRDP)
|
||||
|
||||
find_package(X11 REQUIRED)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../resources)
|
||||
include_directories(SYSTEM ${X11_INCLUDE_DIRS})
|
||||
include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
set(SRCS
|
||||
xf_types.h
|
||||
xf_utils.h
|
||||
xf_utils.c
|
||||
xf_x11_utils.c
|
||||
xf_gfx.c
|
||||
xf_gfx.h
|
||||
xf_rail.c
|
||||
xf_rail.h
|
||||
xf_input.c
|
||||
xf_input.h
|
||||
xf_debug.h
|
||||
xf_event.c
|
||||
xf_event.h
|
||||
xf_floatbar.c
|
||||
xf_floatbar.h
|
||||
xf_input.c
|
||||
xf_input.h
|
||||
xf_channels.c
|
||||
xf_channels.h
|
||||
xf_cliprdr.c
|
||||
xf_cliprdr.h
|
||||
xf_monitor.c
|
||||
xf_monitor.h
|
||||
xf_disp.c
|
||||
xf_disp.h
|
||||
xf_graphics.c
|
||||
xf_graphics.h
|
||||
xf_keyboard.c
|
||||
xf_keyboard.h
|
||||
keyboard_x11.h
|
||||
keyboard_x11.c
|
||||
xkb_layout_ids.h
|
||||
xkb_layout_ids.c
|
||||
xf_video.c
|
||||
xf_video.h
|
||||
xf_window.c
|
||||
xf_window.h
|
||||
xf_client.c
|
||||
xf_client.h
|
||||
)
|
||||
|
||||
if(CHANNEL_TSMF_CLIENT)
|
||||
list(APPEND SRCS xf_tsmf.c xf_tsmf.h)
|
||||
endif()
|
||||
|
||||
if(CLIENT_INTERFACE_SHARED)
|
||||
addtargetwithresourcefile(${PROJECT_NAME} "SHARED" "${PROJECT_VERSION}" SRCS)
|
||||
else()
|
||||
addtargetwithresourcefile(${PROJECT_NAME} "STATIC" "${PROJECT_VERSION}" SRCS)
|
||||
endif()
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE $<INSTALL_INTERFACE:include>)
|
||||
|
||||
set(PRIV_LIBS ${X11_LIBRARIES})
|
||||
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_XShm_FOUND)
|
||||
add_compile_definitions(WITH_XSHM)
|
||||
include_directories(SYSTEM ${X11_XShm_INCLUDE_PATH})
|
||||
list(APPEND PRIV_LIBS ${X11_Xext_LIB})
|
||||
endif()
|
||||
|
||||
option(WITH_XINERAMA "[X11] enable xinerama" ON)
|
||||
if(WITH_XINERAMA)
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_Xinerama_FOUND)
|
||||
add_compile_definitions(WITH_XINERAMA)
|
||||
include_directories(SYSTEM ${X11_Xinerama_INCLUDE_PATH})
|
||||
list(APPEND PRIV_LIBS ${X11_Xinerama_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_XEXT "[X11] enable Xext" ON)
|
||||
if(WITH_XEXT)
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_Xext_FOUND)
|
||||
add_compile_definitions(WITH_XEXT)
|
||||
list(APPEND PRIV_LIBS ${X11_Xext_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_XCURSOR "[X11] enable Xcursor" ON)
|
||||
if(WITH_XCURSOR)
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_Xcursor_FOUND)
|
||||
add_compile_definitions(WITH_XCURSOR)
|
||||
include_directories(SYSTEM ${X11_Xcursor_INCLUDE_PATH})
|
||||
list(APPEND PRIV_LIBS ${X11_Xcursor_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_XV "[X11] enable Xv" ON)
|
||||
if(WITH_XV)
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_Xv_FOUND)
|
||||
add_compile_definitions(WITH_XV)
|
||||
include_directories(SYSTEM ${X11_Xv_INCLUDE_PATH})
|
||||
list(APPEND PRIV_LIBS ${X11_Xv_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_XI "[X11] enable Xi" ON)
|
||||
if(WITH_XI)
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_Xi_FOUND)
|
||||
add_compile_definitions(WITH_XI)
|
||||
include_directories(SYSTEM ${X11_Xi_INCLUDE_PATH})
|
||||
list(APPEND PRIV_LIBS ${X11_Xi_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_XRENDER "[X11] enable XRender" ON)
|
||||
if(WITH_XRENDER)
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_Xrender_FOUND)
|
||||
add_compile_definitions(WITH_XRENDER)
|
||||
include_directories(SYSTEM ${X11_Xrender_INCLUDE_PATH})
|
||||
list(APPEND PRIV_LIBS ${X11_Xrender_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_XRANDR "[X11] enable XRandR" ON)
|
||||
if(WITH_XRANDR)
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_Xrandr_FOUND)
|
||||
add_compile_definitions(WITH_XRANDR)
|
||||
include_directories(SYSTEM ${X11_Xrandr_INCLUDE_PATH})
|
||||
list(APPEND PRIV_LIBS ${X11_Xrandr_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_XFIXES "[X11] enable Xfixes" ON)
|
||||
if(WITH_XFIXES)
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_Xfixes_FOUND)
|
||||
add_compile_definitions(WITH_XFIXES)
|
||||
include_directories(SYSTEM ${X11_Xfixes_INCLUDE_PATH})
|
||||
list(APPEND PRIV_LIBS ${X11_Xfixes_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND PUB_LIBS freerdp-client)
|
||||
|
||||
list(APPEND PRIV_LIBS m)
|
||||
if(NOT APPLE)
|
||||
list(APPEND PRIV_LIBS rt)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${PUB_LIBS})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${PRIV_LIBS})
|
||||
|
||||
if(WITH_CLIENT_INTERFACE)
|
||||
installwithrpath(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
|
||||
endif()
|
||||
add_subdirectory(cli)
|
||||
add_subdirectory(man)
|
||||
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "Client/X11")
|
||||
3
third_party/FreeRDP/client/X11/ModuleOptions.cmake
vendored
Normal file
3
third_party/FreeRDP/client/X11/ModuleOptions.cmake
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
set(FREERDP_CLIENT_NAME "xfreerdp")
|
||||
set(FREERDP_CLIENT_PLATFORM "X11")
|
||||
set(FREERDP_CLIENT_VENDOR "FreeRDP")
|
||||
39
third_party/FreeRDP/client/X11/cli/CMakeLists.txt
vendored
Normal file
39
third_party/FreeRDP/client/X11/cli/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP X11 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(SRCS xfreerdp.c)
|
||||
|
||||
addtargetwithresourcefile(${MODULE_NAME} TRUE "${PROJECT_VERSION}" SRCS)
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "..")
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "Client/X11")
|
||||
|
||||
list(APPEND LIBS xfreerdp-client)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBS})
|
||||
|
||||
installwithrpath(
|
||||
TARGETS
|
||||
${MODULE_NAME}
|
||||
RUNTIME
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_BINDIR}
|
||||
COMPONENT
|
||||
client
|
||||
)
|
||||
install_freerdp_desktop("${MODULE_NAME}")
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/X11")
|
||||
120
third_party/FreeRDP/client/X11/cli/xfreerdp.c
vendored
Normal file
120
third_party/FreeRDP/client/X11/cli/xfreerdp.c
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Client
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012 HP Development Company, LLC
|
||||
*
|
||||
* 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 <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#include <freerdp/streamdump.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
|
||||
#include "../xf_client.h"
|
||||
#include "../xfreerdp.h"
|
||||
|
||||
static void xfreerdp_print_help(void)
|
||||
{
|
||||
printf("Keyboard Shortcuts:\n");
|
||||
printf("\t<Right CTRL>\n");
|
||||
printf("\t\treleases keyboard and mouse grab\n");
|
||||
printf("\t<CTRL>+<ALT>+<Return>\n");
|
||||
printf("\t\ttoggles fullscreen state of the application\n");
|
||||
printf("\t<CTRL>+<ALT>+c\n");
|
||||
printf("\t\ttoggles remote control in a remote assistance session\n");
|
||||
printf("\t<CTRL>+<ALT>+m\n");
|
||||
printf("\t\tminimizes the application\n");
|
||||
printf("\tAction Script\n");
|
||||
printf("\t\tExecutes a predefined script on key press.\n");
|
||||
printf("\t\tShould the script not exist it is ignored.\n");
|
||||
printf("\t\tScripts can be provided at the default location ~/.config/freerdp/action.sh or as "
|
||||
"command line argument /action:script:<path>\n");
|
||||
printf("\t\tThe script will receive the current key combination as argument.\n");
|
||||
printf("\t\tThe output of the script is parsed for 'key-local' which tells that the script "
|
||||
"used the key combination, otherwise the combination is forwarded to the remote.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int rc = 1;
|
||||
int status = 0;
|
||||
HANDLE thread = nullptr;
|
||||
xfContext* xfc = nullptr;
|
||||
DWORD dwExitCode = 0;
|
||||
rdpContext* context = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
RDP_CLIENT_ENTRY_POINTS clientEntryPoints = WINPR_C_ARRAY_INIT;
|
||||
|
||||
clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS);
|
||||
clientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION;
|
||||
|
||||
RdpClientEntry(&clientEntryPoints);
|
||||
|
||||
context = freerdp_client_context_new(&clientEntryPoints);
|
||||
if (!context)
|
||||
return 1;
|
||||
|
||||
settings = context->settings;
|
||||
xfc = (xfContext*)context;
|
||||
|
||||
status = freerdp_client_settings_parse_command_line(context->settings, argc, argv, FALSE);
|
||||
if (status)
|
||||
{
|
||||
rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_ListMonitors))
|
||||
xf_list_monitors(xfc);
|
||||
else
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case COMMAND_LINE_STATUS_PRINT:
|
||||
case COMMAND_LINE_STATUS_PRINT_VERSION:
|
||||
case COMMAND_LINE_STATUS_PRINT_BUILDCONFIG:
|
||||
break;
|
||||
case COMMAND_LINE_STATUS_PRINT_HELP:
|
||||
default:
|
||||
xfreerdp_print_help();
|
||||
break;
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CREATE_REQUEST, FALSE))
|
||||
goto out;
|
||||
|
||||
if (freerdp_client_start(context) != 0)
|
||||
goto out;
|
||||
|
||||
thread = freerdp_client_get_thread(context);
|
||||
|
||||
(void)WaitForSingleObject(thread, INFINITE);
|
||||
GetExitCodeThread(thread, &dwExitCode);
|
||||
rc = xf_exit_code_from_disconnect_reason(dwExitCode);
|
||||
|
||||
freerdp_client_stop(context);
|
||||
|
||||
out:
|
||||
freerdp_client_context_free(context);
|
||||
|
||||
return rc;
|
||||
}
|
||||
147
third_party/FreeRDP/client/X11/keyboard_x11.c
vendored
Normal file
147
third_party/FreeRDP/client/X11/keyboard_x11.c
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Keyboard Mapping
|
||||
*
|
||||
* Copyright 2009-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2023 Bernhard Miklautz <bernhard.miklautz@thincast.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 <string.h>
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "xf_debug.h"
|
||||
#include "keyboard_x11.h"
|
||||
#include "xkb_layout_ids.h"
|
||||
#include "xf_utils.h"
|
||||
|
||||
static BOOL parse_xkb_rule_names(char* xkb_rule, unsigned long num_bytes, char** layout,
|
||||
char** variant)
|
||||
{
|
||||
/* Sample output for "Canadian Multilingual Standard"
|
||||
*
|
||||
* _XKB_RULES_NAMES_BACKUP(STRING) = "xorg", "pc105", "ca", "multi", "magic"
|
||||
*
|
||||
* Format: "rules", "model", "layout", "variant", "options"
|
||||
*
|
||||
* Where "xorg" is the set of rules
|
||||
* "pc105" the keyboard model
|
||||
* "ca" the keyboard layout(s) (can also be something like 'us,uk')
|
||||
* "multi" the keyboard layout variant(s) (in the examples, “,winkeys” - which means first
|
||||
* layout uses some “default” variant and second uses “winkeys” variant)
|
||||
* "magic" - configuration option (in the examples,
|
||||
* “eurosign:e,lv3:ralt_switch,grp:rctrl_toggle”
|
||||
* - three options)
|
||||
*/
|
||||
for (size_t i = 0, index = 0; i < num_bytes; i++, index++)
|
||||
{
|
||||
char* ptr = xkb_rule + i;
|
||||
i += strnlen(ptr, num_bytes - i);
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0: // rules
|
||||
break;
|
||||
case 1: // model
|
||||
break;
|
||||
case 2: // layout
|
||||
{
|
||||
/* If multiple languages are present we just take the first one */
|
||||
char* delimiter = strchr(ptr, ',');
|
||||
if (delimiter)
|
||||
*delimiter = '\0';
|
||||
*layout = ptr;
|
||||
break;
|
||||
}
|
||||
case 3: // variant
|
||||
{
|
||||
/* If multiple variants are present we just take the first one */
|
||||
char* delimiter = strchr(ptr, ',');
|
||||
if (delimiter)
|
||||
*delimiter = '\0';
|
||||
*variant = ptr;
|
||||
}
|
||||
break;
|
||||
case 4: // option
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD kbd_layout_id_from_x_property(wLog* log, Display* display, Window root,
|
||||
char* property_name)
|
||||
{
|
||||
char* layout = nullptr;
|
||||
char* variant = nullptr;
|
||||
char* rule = nullptr;
|
||||
Atom type = None;
|
||||
int item_size = 0;
|
||||
unsigned long items = 0;
|
||||
unsigned long unread_items = 0;
|
||||
DWORD layout_id = 0;
|
||||
|
||||
Atom property = XInternAtom(display, property_name, False);
|
||||
if (property == None)
|
||||
return 0;
|
||||
|
||||
if (LogDynAndXGetWindowProperty(log, display, root, property, 0, 1024, False, XA_STRING, &type,
|
||||
&item_size, &items, &unread_items,
|
||||
(unsigned char**)&rule) != Success)
|
||||
return 0;
|
||||
|
||||
if (type != XA_STRING || item_size != 8 || unread_items != 0)
|
||||
{
|
||||
XFree(rule);
|
||||
return 0;
|
||||
}
|
||||
|
||||
parse_xkb_rule_names(rule, items, &layout, &variant);
|
||||
|
||||
DEBUG_X11("%s layout: %s, variant: %s", property_name, layout, variant);
|
||||
layout_id = xf_find_keyboard_layout_in_xorg_rules(layout, variant);
|
||||
|
||||
XFree(rule);
|
||||
|
||||
return layout_id;
|
||||
}
|
||||
|
||||
int xf_detect_keyboard_layout_from_xkb(wLog* log, DWORD* keyboardLayoutId)
|
||||
{
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
|
||||
if (!display)
|
||||
return 0;
|
||||
|
||||
Window root = DefaultRootWindow(display);
|
||||
if (!root)
|
||||
return 0;
|
||||
|
||||
/* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */
|
||||
DWORD id = kbd_layout_id_from_x_property(log, display, root, "_XKB_RULES_NAMES_BACKUP");
|
||||
|
||||
if (0 == id)
|
||||
id = kbd_layout_id_from_x_property(log, display, root, "_XKB_RULES_NAMES");
|
||||
|
||||
if (0 != id)
|
||||
*keyboardLayoutId = id;
|
||||
|
||||
LogDynAndXCloseDisplay(log, display);
|
||||
return (int)id;
|
||||
}
|
||||
25
third_party/FreeRDP/client/X11/keyboard_x11.h
vendored
Normal file
25
third_party/FreeRDP/client/X11/keyboard_x11.h
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Keyboard Mapping
|
||||
*
|
||||
* Copyright 2009-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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <freerdp/api.h>
|
||||
|
||||
int xf_detect_keyboard_layout_from_xkb(wLog* log, DWORD* keyboardLayoutId);
|
||||
14
third_party/FreeRDP/client/X11/man/CMakeLists.txt
vendored
Normal file
14
third_party/FreeRDP/client/X11/man/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
set(DEPS
|
||||
../../common/man/freerdp-global-options.1
|
||||
xfreerdp-shortcuts.1
|
||||
../../common/man/freerdp-global-envvar.1
|
||||
../../common/man/freerdp-global-config.1
|
||||
xfreerdp-global-config.1
|
||||
xfreerdp-examples.1
|
||||
../../common/man/freerdp-global-links.1
|
||||
)
|
||||
|
||||
include(GetSysconfDir)
|
||||
get_sysconf_dir("" SYSCONF_DIR)
|
||||
set(VAR_NAMES "VENDOR" "PRODUCT" "VENDOR_PRODUCT" "SYSCONF_DIR")
|
||||
generate_and_install_freerdp_man_from_xml(${MODULE_NAME} "1" "${DEPS}" "${VAR_NAMES}")
|
||||
181
third_party/FreeRDP/client/X11/man/xfreerdp-examples.1.in
vendored
Normal file
181
third_party/FreeRDP/client/X11/man/xfreerdp-examples.1.in
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
.RS 4
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
#!/bin/bash
|
||||
|
||||
# we got a key combination
|
||||
if [ "$1" = "key" ];
|
||||
then
|
||||
# we only got one argument \*(Aqkey\*(Aq
|
||||
# list all supported combinations with echo
|
||||
if [ $# \-eq 1 ];
|
||||
then
|
||||
echo "ctrl+alt+f1"
|
||||
echo "ctrl+alt+f2"
|
||||
else
|
||||
# We want the action for a single combination
|
||||
# use \*(Aqkey\-local\*(Aq to not forward to RDP session
|
||||
if [ "$2" = "ctrl+alt+f1" ];
|
||||
then
|
||||
echo "key\-local"
|
||||
fi
|
||||
if [ "$2" = "ctrl+alt+f2" ];
|
||||
then
|
||||
echo "/usr/local/bin/somescript\&.sh"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ "$1" = "xevent" ];
|
||||
then
|
||||
if [ $# \-eq 1 ];
|
||||
then
|
||||
echo "FocusIn"
|
||||
echo "SelectionClear"
|
||||
else
|
||||
if [ "$2" = "SelectionNotify" ];
|
||||
then
|
||||
echo "/usr/local/bin/someprogram"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
Example action script for key events, listing
|
||||
\fIctrl+alt+f1\fR
|
||||
to be handled by local window manager and
|
||||
\fIctrl+alt+f2\fR
|
||||
executing a script
|
||||
.sp
|
||||
The return value of the program determines if the key is handled locally or remotely (0 for local, > 0 for remote, < 0 for errors)
|
||||
.RE
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@ connection\&.rdp /p:Pwd123! /f\fR
|
||||
.RS 4
|
||||
Connect in fullscreen mode using a stored configuration
|
||||
\fIconnection\&.rdp\fR
|
||||
and the password
|
||||
\fIPwd123!\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@ /u:USER /size:50%h /v:rdp\&.contoso\&.com\fR
|
||||
.RS 4
|
||||
Connect to host
|
||||
\fIrdp\&.contoso\&.com\fR
|
||||
with user
|
||||
\fIUSER\fR
|
||||
and a size of
|
||||
\fI50 percent of the height\fR\&. If width (w) is set instead of height (h) like /size:50%w\&. 50 percent of the width is used\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@ /u:CONTOSO\e\eJohnDoe /p:Pwd123! /v:rdp\&.contoso\&.com\fR
|
||||
.RS 4
|
||||
Connect to host
|
||||
\fIrdp\&.contoso\&.com\fR
|
||||
with user
|
||||
\fICONTOSO\e\eJohnDoe\fR
|
||||
and password
|
||||
\fIPwd123!\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@ /u:JohnDoe /p:Pwd123! /w:1366 /h:768 /v:192\&.168\&.1\&.100:4489\fR
|
||||
.RS 4
|
||||
Connect to host
|
||||
\fI192\&.168\&.1\&.100\fR
|
||||
on port
|
||||
\fI4489\fR
|
||||
with user
|
||||
\fIJohnDoe\fR, password
|
||||
\fIPwd123!\fR\&. The screen width is set to
|
||||
\fI1366\fR
|
||||
and the height to
|
||||
\fI768\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@ /u:JohnDoe /p:Pwd123! /vmconnect:C824F53E\-95D2\-46C6\-9A18\-23A5BB403532 /v:192\&.168\&.1\&.100\fR
|
||||
.RS 4
|
||||
Establish a connection to host
|
||||
\fI192\&.168\&.1\&.100\fR
|
||||
with user
|
||||
\fIJohnDoe\fR, password
|
||||
\fIPwd123!\fR
|
||||
and connect to Hyper\-V console (use port 2179, disable negotiation) with VMID
|
||||
\fIC824F53E\-95D2\-46C6\-9A18\-23A5BB403532\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB+clipboard\fR
|
||||
.RS 4
|
||||
Activate clipboard redirection
|
||||
.RE
|
||||
.PP
|
||||
\fB/drive:home,/home/user\fR
|
||||
.RS 4
|
||||
Activate drive redirection of
|
||||
\fI/home/user\fR
|
||||
as home drive
|
||||
.RE
|
||||
.PP
|
||||
\fB/smartcard:<device>\fR
|
||||
.RS 4
|
||||
Activate smartcard redirection for device
|
||||
\fIdevice\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB/printer:<device>,<driver>\fR
|
||||
.RS 4
|
||||
Activate printer redirection for printer
|
||||
\fIdevice\fR
|
||||
using driver
|
||||
\fIdriver\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB/serial:<device>\fR
|
||||
.RS 4
|
||||
Activate serial port redirection for port
|
||||
\fIdevice\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB/parallel:<device>\fR
|
||||
.RS 4
|
||||
Activate parallel port redirection for port
|
||||
\fIdevice\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB/sound:sys:alsa\fR
|
||||
.RS 4
|
||||
Activate audio output redirection using device
|
||||
\fIsys:alsa\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB/microphone:sys:alsa\fR
|
||||
.RS 4
|
||||
Activate audio input redirection using device
|
||||
\fIsys:alsa\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB/multimedia:sys:alsa\fR
|
||||
.RS 4
|
||||
Activate multimedia redirection using device
|
||||
\fIsys:alsa\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB/usb:id,dev:054c:0268\fR
|
||||
.RS 4
|
||||
Activate USB device redirection for the device identified by
|
||||
\fI054c:0268\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB/kbd:remap:29=58,remap:58=29\fR
|
||||
.RS 4
|
||||
Swap left Control (\
|
||||
\fI29\fR\
|
||||
) and Caps Lock (\
|
||||
\fI58\fR\
|
||||
).
|
||||
.RE
|
||||
22
third_party/FreeRDP/client/X11/man/xfreerdp-global-config.1.in
vendored
Normal file
22
third_party/FreeRDP/client/X11/man/xfreerdp-global-config.1.in
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
.SH "GLOBAL CONFIGURATION (X11 client)"
|
||||
.PP
|
||||
The X11 client configuration location is
|
||||
\fI@SYSCONF_DIR@/xfreerdp\&.json\fR
|
||||
.br
|
||||
|
||||
File format is JSON
|
||||
.RE
|
||||
.PP
|
||||
Supported options:
|
||||
.RS 4
|
||||
.PP
|
||||
\fIisActionScriptAllowed\fR
|
||||
.RS 4
|
||||
.PP
|
||||
.RS 4
|
||||
\fIJSON boolean\fR
|
||||
.br
|
||||
|
||||
Allow or block action scripts. Default (if option is not set) is to allow action scripts.
|
||||
.RE
|
||||
.RE
|
||||
44
third_party/FreeRDP/client/X11/man/xfreerdp-shortcuts.1.in
vendored
Normal file
44
third_party/FreeRDP/client/X11/man/xfreerdp-shortcuts.1.in
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
.SH "KEYBOARD SHORTCUTS"
|
||||
.PP
|
||||
<Right CTRL>
|
||||
.RS 4
|
||||
releases keyboard and mouse grab.
|
||||
.br
|
||||
If keyboard is grabbed the local system shortcuts do no longer work and are sent to the remote system.
|
||||
.br
|
||||
If the Mouse is grabbed (optional) local gesture detection does not work and the mouse might not be able to leave the RDP window. Mouse events are not altered.
|
||||
.RE
|
||||
.PP
|
||||
<CTRL>+<ALT>+<Return>
|
||||
.RS 4
|
||||
toggles fullscreen state of the application
|
||||
.RE
|
||||
.PP
|
||||
<CTRL>+<ALT>+<m>
|
||||
.RS 4
|
||||
Minimizes the application
|
||||
.RE
|
||||
.PP
|
||||
<CTRL>+<ALT>+c
|
||||
.RS 4
|
||||
toggles remote control in a remote assistance session
|
||||
.RE
|
||||
.PP
|
||||
<CTRL>+<ALT>+<d>
|
||||
.RS 4
|
||||
Disconnect the session and terminate application
|
||||
.RE
|
||||
.PP
|
||||
Action Script
|
||||
.RS 4
|
||||
executes a predefined script on key press\&.
|
||||
Should the script not exist it is ignored\&.
|
||||
Scripts can be provided at the default location
|
||||
\fI$XDG_CONFIG_HOME/freerdp/action\&.sh\fR
|
||||
or as command line argument
|
||||
\fI/action:script:<path>\fR\&.
|
||||
The script will receive the current key combination as argument\&.
|
||||
The output of the script is parsed for
|
||||
\fIkey\-local\fR
|
||||
which tells that the script used the key combination, otherwise the combination is forwarded to the remote\&.
|
||||
.RE
|
||||
15
third_party/FreeRDP/client/X11/man/xfreerdp.1.in
vendored
Normal file
15
third_party/FreeRDP/client/X11/man/xfreerdp.1.in
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
.TH "@MANPAGE_NAME@" "1" "@MAN_TODAY@" "freerdp" "@MANPAGE_NAME@"
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.SH "NAME"
|
||||
@MANPAGE_NAME@ \- FreeRDP X11 client
|
||||
.SH "SYNOPSIS"
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@\fR
|
||||
[file] [options] [/v:server[:port]]
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@\fR
|
||||
is an X11 Remote Desktop Protocol (RDP) client which is part of the FreeRDP project\&. An RDP server is built\-in to many editions of Windows\&. Alternative servers included ogon, gnome\-remote\-desktop, xrdp and VRDP (VirtualBox)\&.
|
||||
11
third_party/FreeRDP/client/X11/resource/close.xbm
vendored
Normal file
11
third_party/FreeRDP/client/X11/resource/close.xbm
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#define close_width 24
|
||||
#define close_height 24
|
||||
static unsigned char close_bits[] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x7c, 0xfe, 0xff, 0x38, 0xfe, 0xff, 0x11, 0xff, 0xff, 0x83, 0xff,
|
||||
0xff, 0xc7, 0xff, 0xff, 0x83, 0xff, 0xff, 0x11, 0xff, 0xff, 0x38, 0xfe,
|
||||
0xff, 0x7c, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
11
third_party/FreeRDP/client/X11/resource/lock.xbm
vendored
Normal file
11
third_party/FreeRDP/client/X11/resource/lock.xbm
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#define lock_width 24
|
||||
#define lock_height 24
|
||||
static unsigned char lock_bits[] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff,
|
||||
0xff, 0x83, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xc7, 0xff,
|
||||
0xff, 0x00, 0xfe, 0xff, 0x00, 0xfe, 0xff, 0xef, 0xff, 0xff, 0xef, 0xff,
|
||||
0xff, 0xef, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
11
third_party/FreeRDP/client/X11/resource/minimize.xbm
vendored
Normal file
11
third_party/FreeRDP/client/X11/resource/minimize.xbm
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#define minimize_width 24
|
||||
#define minimize_height 24
|
||||
static unsigned char minimize_bits[] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xfc,
|
||||
0x3f, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
11
third_party/FreeRDP/client/X11/resource/restore.xbm
vendored
Normal file
11
third_party/FreeRDP/client/X11/resource/restore.xbm
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#define restore_width 24
|
||||
#define restore_height 24
|
||||
static unsigned char restore_bits[] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x3b, 0xff, 0x7f, 0x20, 0xff,
|
||||
0x7f, 0x20, 0xff, 0x7f, 0x07, 0xff, 0x7f, 0xe7, 0xff, 0x7f, 0xe7, 0xff,
|
||||
0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
11
third_party/FreeRDP/client/X11/resource/unlock.xbm
vendored
Normal file
11
third_party/FreeRDP/client/X11/resource/unlock.xbm
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#define unlock_width 24
|
||||
#define unlock_height 24
|
||||
static unsigned char unlock_bits[] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf3, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x73, 0xfe, 0xff, 0x03, 0xfe,
|
||||
0x3f, 0x00, 0xfe, 0xff, 0x03, 0xfe, 0xff, 0x73, 0xfe, 0xff, 0xf3, 0xff,
|
||||
0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
132
third_party/FreeRDP/client/X11/xf_channels.c
vendored
Normal file
132
third_party/FreeRDP/client/X11/xf_channels.c
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Client Channels
|
||||
*
|
||||
* Copyright 2013 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 <freerdp/gdi/video.h>
|
||||
#include "xf_channels.h"
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
#include "xf_gfx.h"
|
||||
#if defined(CHANNEL_TSMF_CLIENT)
|
||||
#include "xf_tsmf.h"
|
||||
#endif
|
||||
#include "xf_rail.h"
|
||||
#include "xf_cliprdr.h"
|
||||
#include "xf_disp.h"
|
||||
#include "xf_video.h"
|
||||
|
||||
void xf_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(e);
|
||||
WINPR_ASSERT(e->name);
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (FALSE)
|
||||
{
|
||||
}
|
||||
#if defined(CHANNEL_TSMF_CLIENT)
|
||||
else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_tsmf_init(xfc, (TsmfClientContext*)e->pInterface);
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_rail_init(xfc, (RailClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_cliprdr_init(xfc, (CliprdrClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_disp_init(xfc->xfDisp, (DispClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_SoftwareGdi))
|
||||
gdi_video_control_init(xfc->common.context.gdi, (VideoClientContext*)e->pInterface);
|
||||
else
|
||||
xf_video_control_init(xfc, (VideoClientContext*)e->pInterface);
|
||||
}
|
||||
else
|
||||
freerdp_client_OnChannelConnectedEventHandler(context, e);
|
||||
}
|
||||
|
||||
void xf_OnChannelDisconnectedEventHandler(void* context, const ChannelDisconnectedEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(e);
|
||||
WINPR_ASSERT(e->name);
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (FALSE)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_disp_uninit(xfc->xfDisp, (DispClientContext*)e->pInterface);
|
||||
}
|
||||
#if defined(CHANNEL_TSMF_CLIENT)
|
||||
else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_tsmf_uninit(xfc, (TsmfClientContext*)e->pInterface);
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_rail_uninit(xfc, (RailClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_cliprdr_uninit(xfc, (CliprdrClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_SoftwareGdi))
|
||||
gdi_video_control_uninit(xfc->common.context.gdi, (VideoClientContext*)e->pInterface);
|
||||
else
|
||||
xf_video_control_uninit(xfc, (VideoClientContext*)e->pInterface);
|
||||
}
|
||||
else
|
||||
freerdp_client_OnChannelDisconnectedEventHandler(context, e);
|
||||
}
|
||||
37
third_party/FreeRDP/client/X11/xf_channels.h
vendored
Normal file
37
third_party/FreeRDP/client/X11/xf_channels.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Client Channels
|
||||
*
|
||||
* Copyright 2013 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_X11_CHANNELS_H
|
||||
#define FREERDP_CLIENT_X11_CHANNELS_H
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/client/rdpei.h>
|
||||
#include <freerdp/client/rail.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
#include <freerdp/client/encomsp.h>
|
||||
#include <freerdp/client/disp.h>
|
||||
#include <freerdp/client/geometry.h>
|
||||
#include <freerdp/client/video.h>
|
||||
|
||||
void xf_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e);
|
||||
void xf_OnChannelDisconnectedEventHandler(void* context, const ChannelDisconnectedEventArgs* e);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_CHANNELS_H */
|
||||
2104
third_party/FreeRDP/client/X11/xf_client.c
vendored
Normal file
2104
third_party/FreeRDP/client/X11/xf_client.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
53
third_party/FreeRDP/client/X11/xf_client.h
vendored
Normal file
53
third_party/FreeRDP/client/X11/xf_client.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Client Interface
|
||||
*
|
||||
* Copyright 2013 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_X11_CLIENT_H
|
||||
#define FREERDP_CLIENT_X11_CLIENT_H
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client.h>
|
||||
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/gdi/dc.h>
|
||||
#include <freerdp/gdi/region.h>
|
||||
|
||||
#include <freerdp/channels/channels.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Client Interface
|
||||
*/
|
||||
|
||||
FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_CLIENT_H */
|
||||
2717
third_party/FreeRDP/client/X11/xf_cliprdr.c
vendored
Normal file
2717
third_party/FreeRDP/client/X11/xf_cliprdr.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
43
third_party/FreeRDP/client/X11/xf_cliprdr.h
vendored
Normal file
43
third_party/FreeRDP/client/X11/xf_cliprdr.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Clipboard Redirection
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
*
|
||||
* 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_X11_CLIPRDR_H
|
||||
#define FREERDP_CLIENT_X11_CLIPRDR_H
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "xf_types.h"
|
||||
|
||||
typedef struct xf_clipboard xfClipboard;
|
||||
|
||||
void xf_clipboard_free(xfClipboard* clipboard);
|
||||
|
||||
WINPR_ATTR_MALLOC(xf_clipboard_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction);
|
||||
|
||||
void xf_cliprdr_init(xfContext* xfc, CliprdrClientContext* cliprdr);
|
||||
void xf_cliprdr_uninit(xfContext* xfc, CliprdrClientContext* cliprdr);
|
||||
|
||||
void xf_cliprdr_handle_xevent(xfContext* xfc, const XEvent* event);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_CLIPRDR_H */
|
||||
35
third_party/FreeRDP/client/X11/xf_debug.h
vendored
Normal file
35
third_party/FreeRDP/client/X11/xf_debug.h
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 debug helper header
|
||||
*
|
||||
* Copyright 2025 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <freerdp/config.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#define DBG_TAG CLIENT_TAG("x11")
|
||||
|
||||
#ifdef WITH_DEBUG_X11
|
||||
#define DEBUG_X11(...) WLog_DBG(DBG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_X11(...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
589
third_party/FreeRDP/client/X11/xf_disp.c
vendored
Normal file
589
third_party/FreeRDP/client/X11/xf_disp.c
vendored
Normal file
@@ -0,0 +1,589 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Display Control channel
|
||||
*
|
||||
* Copyright 2017 David Fort <contact@hardening-consulting.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 <math.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include <freerdp/timer.h>
|
||||
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#ifdef WITH_XRANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/randr.h>
|
||||
|
||||
#if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105
|
||||
#define USABLE_XRANDR
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "xfreerdp.h"
|
||||
#include "xf_disp.h"
|
||||
#include "xf_monitor.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("x11disp")
|
||||
#define RESIZE_MIN_DELAY_NS 200000000UL /* minimum delay in ms between two resizes */
|
||||
|
||||
struct s_xfDispContext
|
||||
{
|
||||
xfContext* xfc;
|
||||
DispClientContext* disp;
|
||||
BOOL haveXRandr;
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
UINT32 lastSentWidth;
|
||||
UINT32 lastSentHeight;
|
||||
BYTE reserved[4];
|
||||
UINT64 lastSentDate;
|
||||
UINT32 targetWidth;
|
||||
UINT32 targetHeight;
|
||||
BOOL activated;
|
||||
BOOL fullscreen;
|
||||
UINT16 lastSentDesktopOrientation;
|
||||
BYTE reserved2[2];
|
||||
UINT32 lastSentDesktopScaleFactor;
|
||||
UINT32 lastSentDeviceScaleFactor;
|
||||
BYTE reserved3[4];
|
||||
FreeRDP_TimerID timerID;
|
||||
};
|
||||
|
||||
static BOOL xf_disp_check_context(void* context, xfContext** ppXfc, xfDispContext** ppXfDisp,
|
||||
rdpSettings** ppSettings);
|
||||
static BOOL xf_disp_sendResize(xfDispContext* xfDisp, BOOL fromTimer);
|
||||
static UINT xf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors,
|
||||
UINT32 nmonitors);
|
||||
|
||||
static BOOL xf_disp_settings_changed(xfDispContext* xfDisp)
|
||||
{
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfDisp);
|
||||
WINPR_ASSERT(xfDisp->xfc);
|
||||
|
||||
settings = xfDisp->xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (xfDisp->lastSentWidth != xfDisp->targetWidth)
|
||||
return TRUE;
|
||||
|
||||
if (xfDisp->lastSentHeight != xfDisp->targetHeight)
|
||||
return TRUE;
|
||||
|
||||
if (xfDisp->lastSentDesktopOrientation !=
|
||||
freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation))
|
||||
return TRUE;
|
||||
|
||||
if (xfDisp->lastSentDesktopScaleFactor !=
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor))
|
||||
return TRUE;
|
||||
|
||||
if (xfDisp->lastSentDeviceScaleFactor !=
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor))
|
||||
return TRUE;
|
||||
|
||||
if (xfDisp->fullscreen != xfDisp->xfc->fullscreen)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL xf_update_last_sent(xfDispContext* xfDisp)
|
||||
{
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfDisp);
|
||||
WINPR_ASSERT(xfDisp->xfc);
|
||||
|
||||
settings = xfDisp->xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
xfDisp->lastSentWidth = xfDisp->targetWidth;
|
||||
xfDisp->lastSentHeight = xfDisp->targetHeight;
|
||||
xfDisp->lastSentDesktopOrientation =
|
||||
freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
|
||||
xfDisp->lastSentDesktopScaleFactor =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
|
||||
xfDisp->lastSentDeviceScaleFactor =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
|
||||
xfDisp->fullscreen = xfDisp->xfc->fullscreen;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static uint64_t xf_disp_OnTimer(rdpContext* context, WINPR_ATTR_UNUSED void* userdata,
|
||||
WINPR_ATTR_UNUSED FreeRDP_TimerID timerID,
|
||||
WINPR_ATTR_UNUSED uint64_t timestamp,
|
||||
WINPR_ATTR_UNUSED uint64_t interval)
|
||||
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
xfDispContext* xfDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
|
||||
return interval;
|
||||
|
||||
if (!xfDisp->activated)
|
||||
return interval;
|
||||
|
||||
xf_disp_sendResize(xfDisp, TRUE);
|
||||
xfDisp->timerID = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL update_timer(xfDispContext* xfDisp, uint64_t intervalNS)
|
||||
{
|
||||
WINPR_ASSERT(xfDisp);
|
||||
|
||||
if (xfDisp->timerID == 0)
|
||||
{
|
||||
rdpContext* context = &xfDisp->xfc->common.context;
|
||||
|
||||
xfDisp->timerID = freerdp_timer_add(context, intervalNS, xf_disp_OnTimer, nullptr, true);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xf_disp_sendResize(xfDispContext* xfDisp, BOOL fromTimer)
|
||||
{
|
||||
DISPLAY_CONTROL_MONITOR_LAYOUT layout = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (!xfDisp || !xfDisp->xfc)
|
||||
return FALSE;
|
||||
|
||||
/* If there is already a timer running skip the update and wait for the timer to expire. */
|
||||
if ((xfDisp->timerID != 0) && !fromTimer)
|
||||
return TRUE;
|
||||
|
||||
xfContext* xfc = xfDisp->xfc;
|
||||
rdpSettings* settings = xfc->common.context.settings;
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
if (!xfDisp->activated || !xfDisp->disp)
|
||||
return update_timer(xfDisp, RESIZE_MIN_DELAY_NS);
|
||||
|
||||
const uint64_t diff = winpr_GetTickCount64NS() - xfDisp->lastSentDate;
|
||||
if (diff < RESIZE_MIN_DELAY_NS)
|
||||
{
|
||||
const uint64_t interval = RESIZE_MIN_DELAY_NS - diff;
|
||||
return update_timer(xfDisp, interval);
|
||||
}
|
||||
|
||||
if (!xf_disp_settings_changed(xfDisp))
|
||||
return TRUE;
|
||||
|
||||
xfDisp->lastSentDate = winpr_GetTickCount64NS();
|
||||
|
||||
const UINT32 mcount = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
|
||||
if (mcount > 1)
|
||||
{
|
||||
const rdpMonitor* monitors =
|
||||
freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray);
|
||||
if (xf_disp_sendLayout(xfDisp->disp, monitors, mcount) != CHANNEL_RC_OK)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
|
||||
layout.Top = layout.Left = 0;
|
||||
layout.Width = xfDisp->targetWidth;
|
||||
layout.Height = xfDisp->targetHeight;
|
||||
layout.Orientation = freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
|
||||
layout.DesktopScaleFactor =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
|
||||
layout.DeviceScaleFactor = freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
|
||||
|
||||
const double dw = xfDisp->targetWidth / 75.0 * 25.4;
|
||||
const double dh = xfDisp->targetHeight / 75.0 * 25.4;
|
||||
layout.PhysicalWidth = (UINT32)lround(dw);
|
||||
layout.PhysicalHeight = (UINT32)lround(dh);
|
||||
|
||||
if (IFCALLRESULT(CHANNEL_RC_OK, xfDisp->disp->SendMonitorLayout, xfDisp->disp, 1,
|
||||
&layout) != CHANNEL_RC_OK)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return xf_update_last_sent(xfDisp);
|
||||
}
|
||||
|
||||
static BOOL xf_disp_queueResize(xfDispContext* xfDisp, UINT32 width, UINT32 height)
|
||||
{
|
||||
if ((xfDisp->targetWidth == (INT64)width) && (xfDisp->targetHeight == (INT64)height))
|
||||
return TRUE;
|
||||
xfDisp->targetWidth = width;
|
||||
xfDisp->targetHeight = height;
|
||||
return xf_disp_sendResize(xfDisp, FALSE);
|
||||
}
|
||||
|
||||
static BOOL xf_disp_set_window_resizable(xfDispContext* xfDisp)
|
||||
{
|
||||
XSizeHints* size_hints = nullptr;
|
||||
|
||||
if (!(size_hints = XAllocSizeHints()))
|
||||
return FALSE;
|
||||
|
||||
size_hints->flags = PMinSize | PMaxSize | PWinGravity;
|
||||
size_hints->win_gravity = NorthWestGravity;
|
||||
size_hints->min_width = size_hints->min_height = 320;
|
||||
size_hints->max_width = size_hints->max_height = 8192;
|
||||
|
||||
if (xfDisp->xfc->window)
|
||||
XSetWMNormalHints(xfDisp->xfc->display, xfDisp->xfc->window->handle, size_hints);
|
||||
|
||||
XFree(size_hints);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xf_disp_check_context(void* context, xfContext** ppXfc, xfDispContext** ppXfDisp,
|
||||
rdpSettings** ppSettings)
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
|
||||
if (!context)
|
||||
return FALSE;
|
||||
|
||||
xfc = (xfContext*)context;
|
||||
|
||||
if (!(xfc->xfDisp))
|
||||
return FALSE;
|
||||
|
||||
if (!xfc->common.context.settings)
|
||||
return FALSE;
|
||||
|
||||
*ppXfc = xfc;
|
||||
*ppXfDisp = xfc->xfDisp;
|
||||
*ppSettings = xfc->common.context.settings;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void xf_disp_OnActivated(void* context, const ActivatedEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
xfDispContext* xfDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
|
||||
return;
|
||||
|
||||
if (xfDisp->activated && !xfc->fullscreen)
|
||||
{
|
||||
xf_disp_set_window_resizable(xfDisp);
|
||||
|
||||
if (e->firstActivation)
|
||||
return;
|
||||
|
||||
xf_disp_sendResize(xfDisp, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_disp_OnGraphicsReset(void* context, const GraphicsResetEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
xfDispContext* xfDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_UNUSED(e);
|
||||
|
||||
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
|
||||
return;
|
||||
|
||||
if (xfDisp->activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
{
|
||||
xf_disp_set_window_resizable(xfDisp);
|
||||
xf_disp_sendResize(xfDisp, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_disp_OnWindowStateChange(void* context, const WindowStateChangeEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
xfDispContext* xfDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_UNUSED(e);
|
||||
|
||||
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
|
||||
return;
|
||||
|
||||
if (!xfDisp->activated || !xfc->fullscreen)
|
||||
return;
|
||||
|
||||
xf_disp_sendResize(xfDisp, FALSE);
|
||||
}
|
||||
|
||||
xfDispContext* xf_disp_new(xfContext* xfc)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
wPubSub* pubSub = xfc->common.context.pubSub;
|
||||
WINPR_ASSERT(pubSub);
|
||||
|
||||
const rdpSettings* settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (PubSub_SubscribeActivated(pubSub, xf_disp_OnActivated) < 0)
|
||||
return nullptr;
|
||||
if (PubSub_SubscribeGraphicsReset(pubSub, xf_disp_OnGraphicsReset) < 0)
|
||||
return nullptr;
|
||||
if (PubSub_SubscribeWindowStateChange(pubSub, xf_disp_OnWindowStateChange) < 0)
|
||||
return nullptr;
|
||||
|
||||
xfDispContext* ret = calloc(1, sizeof(xfDispContext));
|
||||
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
|
||||
ret->xfc = xfc;
|
||||
#ifdef USABLE_XRANDR
|
||||
|
||||
if (XRRQueryExtension(xfc->display, &ret->eventBase, &ret->errorBase))
|
||||
{
|
||||
ret->haveXRandr = TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
ret->lastSentWidth = ret->targetWidth =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
||||
ret->lastSentHeight = ret->targetHeight =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xf_disp_free(xfDispContext* disp)
|
||||
{
|
||||
if (!disp)
|
||||
return;
|
||||
|
||||
if (disp->xfc)
|
||||
{
|
||||
wPubSub* pubSub = disp->xfc->common.context.pubSub;
|
||||
PubSub_UnsubscribeActivated(pubSub, xf_disp_OnActivated);
|
||||
PubSub_UnsubscribeGraphicsReset(pubSub, xf_disp_OnGraphicsReset);
|
||||
PubSub_UnsubscribeWindowStateChange(pubSub, xf_disp_OnWindowStateChange);
|
||||
}
|
||||
|
||||
free(disp);
|
||||
}
|
||||
|
||||
UINT xf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors, UINT32 nmonitors)
|
||||
{
|
||||
UINT ret = CHANNEL_RC_OK;
|
||||
xfDispContext* xfDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
DISPLAY_CONTROL_MONITOR_LAYOUT* layouts = nullptr;
|
||||
|
||||
WINPR_ASSERT(disp);
|
||||
WINPR_ASSERT(monitors);
|
||||
WINPR_ASSERT(nmonitors > 0);
|
||||
|
||||
xfDisp = (xfDispContext*)disp->custom;
|
||||
WINPR_ASSERT(xfDisp);
|
||||
WINPR_ASSERT(xfDisp->xfc);
|
||||
|
||||
settings = xfDisp->xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
|
||||
|
||||
if (!layouts)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
for (UINT32 i = 0; i < nmonitors; i++)
|
||||
{
|
||||
const rdpMonitor* monitor = &monitors[i];
|
||||
DISPLAY_CONTROL_MONITOR_LAYOUT* layout = &layouts[i];
|
||||
|
||||
layout->Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
|
||||
layout->Left = monitor->x;
|
||||
layout->Top = monitor->y;
|
||||
layout->Width = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
|
||||
layout->Height = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
|
||||
layout->Orientation = ORIENTATION_LANDSCAPE;
|
||||
layout->PhysicalWidth = monitor->attributes.physicalWidth;
|
||||
layout->PhysicalHeight = monitor->attributes.physicalHeight;
|
||||
|
||||
switch (monitor->attributes.orientation)
|
||||
{
|
||||
case 90:
|
||||
layout->Orientation = ORIENTATION_PORTRAIT;
|
||||
break;
|
||||
|
||||
case 180:
|
||||
layout->Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
break;
|
||||
|
||||
case 270:
|
||||
layout->Orientation = ORIENTATION_PORTRAIT_FLIPPED;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
default:
|
||||
/* MS-RDPEDISP - 2.2.2.2.1:
|
||||
* Orientation (4 bytes): A 32-bit unsigned integer that specifies the
|
||||
* orientation of the monitor in degrees. Valid values are 0, 90, 180
|
||||
* or 270
|
||||
*
|
||||
* So we default to ORIENTATION_LANDSCAPE
|
||||
*/
|
||||
layout->Orientation = ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
}
|
||||
|
||||
layout->DesktopScaleFactor =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
|
||||
layout->DeviceScaleFactor =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
|
||||
}
|
||||
|
||||
ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, nmonitors, layouts);
|
||||
free(layouts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL xf_disp_handle_xevent(xfContext* xfc, const XEvent* event)
|
||||
{
|
||||
xfDispContext* xfDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
UINT32 maxWidth = 0;
|
||||
UINT32 maxHeight = 0;
|
||||
|
||||
if (!xfc || !event)
|
||||
return FALSE;
|
||||
|
||||
xfDisp = xfc->xfDisp;
|
||||
|
||||
if (!xfDisp)
|
||||
return FALSE;
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
if (!xfDisp->haveXRandr || !xfDisp->disp)
|
||||
return TRUE;
|
||||
|
||||
#ifdef USABLE_XRANDR
|
||||
|
||||
if (event->type != xfDisp->eventBase + RRScreenChangeNotify)
|
||||
return TRUE;
|
||||
|
||||
#endif
|
||||
|
||||
WLog_DBG(TAG, "RRScreenChangeNotify event");
|
||||
|
||||
xf_detect_monitors(xfc, &maxWidth, &maxHeight);
|
||||
const rdpMonitor* monitors = freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray);
|
||||
const UINT32 mcount = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
|
||||
return xf_disp_sendLayout(xfDisp->disp, monitors, mcount) == CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
BOOL xf_disp_handle_configureNotify(xfContext* xfc, int width, int height)
|
||||
{
|
||||
xfDispContext* xfDisp = nullptr;
|
||||
|
||||
if (!xfc)
|
||||
return FALSE;
|
||||
|
||||
xfDisp = xfc->xfDisp;
|
||||
|
||||
if (!xfDisp)
|
||||
return FALSE;
|
||||
|
||||
WLog_DBG(TAG, "ConfigureNotify (%dx%d)", width, height);
|
||||
return xf_disp_queueResize(xfDisp, WINPR_ASSERTING_INT_CAST(uint32_t, width),
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, height));
|
||||
}
|
||||
|
||||
static UINT xf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
|
||||
UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
|
||||
{
|
||||
/* we're called only if dynamic resolution update is activated */
|
||||
xfDispContext* xfDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(disp);
|
||||
|
||||
xfDisp = (xfDispContext*)disp->custom;
|
||||
WINPR_ASSERT(xfDisp);
|
||||
WINPR_ASSERT(xfDisp->xfc);
|
||||
|
||||
settings = xfDisp->xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
WLog_DBG(TAG,
|
||||
"DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 " MaxMonitorAreaFactorA: %" PRIu32
|
||||
" MaxMonitorAreaFactorB: %" PRIu32 "",
|
||||
maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
|
||||
xfDisp->activated = TRUE;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
|
||||
return xf_disp_set_window_resizable(xfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
BOOL xf_disp_init(xfDispContext* xfDisp, DispClientContext* disp)
|
||||
{
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
if (!xfDisp || !xfDisp->xfc || !disp)
|
||||
return FALSE;
|
||||
|
||||
settings = xfDisp->xfc->common.context.settings;
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
xfDisp->disp = disp;
|
||||
disp->custom = (void*)xfDisp;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))
|
||||
{
|
||||
disp->DisplayControlCaps = xf_DisplayControlCaps;
|
||||
#ifdef USABLE_XRANDR
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
{
|
||||
/* ask X11 to notify us of screen changes */
|
||||
XRRSelectInput(xfDisp->xfc->display, DefaultRootWindow(xfDisp->xfc->display),
|
||||
RRScreenChangeNotifyMask);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "Channel %s opened", DISP_CHANNEL_NAME);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xf_disp_uninit(xfDispContext* xfDisp, DispClientContext* disp)
|
||||
{
|
||||
if (!xfDisp || !disp)
|
||||
return FALSE;
|
||||
|
||||
WLog_DBG(TAG, "Channel %s closed", DISP_CHANNEL_NAME);
|
||||
xfDisp->disp = nullptr;
|
||||
return TRUE;
|
||||
}
|
||||
44
third_party/FreeRDP/client/X11/xf_disp.h
vendored
Normal file
44
third_party/FreeRDP/client/X11/xf_disp.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Display Control channel
|
||||
*
|
||||
* Copyright 2017 David Fort <contact@hardening-consulting.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_X11_DISP_H
|
||||
#define FREERDP_CLIENT_X11_DISP_H
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/client/disp.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "xf_types.h"
|
||||
|
||||
typedef struct s_xfDispContext xfDispContext;
|
||||
|
||||
FREERDP_API BOOL xf_disp_init(xfDispContext* xfDisp, DispClientContext* disp);
|
||||
FREERDP_API BOOL xf_disp_uninit(xfDispContext* xfDisp, DispClientContext* disp);
|
||||
|
||||
void xf_disp_free(xfDispContext* disp);
|
||||
|
||||
WINPR_ATTR_MALLOC(xf_disp_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
xfDispContext* xf_disp_new(xfContext* xfc);
|
||||
|
||||
BOOL xf_disp_handle_xevent(xfContext* xfc, const XEvent* event);
|
||||
BOOL xf_disp_handle_configureNotify(xfContext* xfc, int width, int height);
|
||||
void xf_disp_resized(xfDispContext* disp);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_DISP_H */
|
||||
1433
third_party/FreeRDP/client/X11/xf_event.c
vendored
Normal file
1433
third_party/FreeRDP/client/X11/xf_event.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
61
third_party/FreeRDP/client/X11/xf_event.h
vendored
Normal file
61
third_party/FreeRDP/client/X11/xf_event.h
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Event Handling
|
||||
*
|
||||
* Copyright 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_X11_EVENT_H
|
||||
#define FREERDP_CLIENT_X11_EVENT_H
|
||||
|
||||
#include "xf_keyboard.h"
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
const char* x11_event_string(int event);
|
||||
|
||||
BOOL xf_event_action_script_init(xfContext* xfc);
|
||||
void xf_event_action_script_free(xfContext* xfc);
|
||||
|
||||
BOOL xf_event_process(freerdp* instance, const XEvent* event);
|
||||
void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs,
|
||||
...);
|
||||
|
||||
void xf_event_adjust_coordinates(xfContext* xfc, int* x, int* y);
|
||||
void xf_adjust_coordinates_to_screen(xfContext* xfc, UINT32* x, UINT32* y);
|
||||
|
||||
#define xf_generic_MotionNotify(xfc, x, y, window, app) \
|
||||
xf_generic_MotionNotify_((xfc), (x), (y), (window), (app), __FILE__, __func__, __LINE__)
|
||||
BOOL xf_generic_MotionNotify_(xfContext* xfc, int x, int y, Window window, BOOL app,
|
||||
const char* file, const char* fkt, size_t line);
|
||||
|
||||
#define xf_generic_RawMotionNotify(xfc, x, y, window, app) \
|
||||
xf_generic_RawMotionNotify_((xfc), (x), (y), (window), (app), __FILE__, __func__, __LINE__)
|
||||
BOOL xf_generic_RawMotionNotify_(xfContext* xfc, int x, int y, Window window, BOOL app,
|
||||
const char* file, const char* fkt, size_t line);
|
||||
|
||||
#define xf_generic_ButtonEvent(xfc, x, y, button, window, app, down) \
|
||||
xf_generic_ButtonEvent_((xfc), (x), (y), (button), (window), (app), (down), __FILE__, \
|
||||
__func__, __LINE__)
|
||||
BOOL xf_generic_ButtonEvent_(xfContext* xfc, int x, int y, int button, Window window, BOOL app,
|
||||
BOOL down, const char* file, const char* fkt, size_t line);
|
||||
|
||||
#define xf_generic_RawButtonEvent(xfc, button, app, down) \
|
||||
xf_generic_RawButtonEvent_((xfc), (button), (app), (down), __FILE__, __func__, __LINE__)
|
||||
BOOL xf_generic_RawButtonEvent_(xfContext* xfc, int button, BOOL app, BOOL down, const char* file,
|
||||
const char* fkt, size_t line);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_EVENT_H */
|
||||
959
third_party/FreeRDP/client/X11/xf_floatbar.c
vendored
Normal file
959
third_party/FreeRDP/client/X11/xf_floatbar.c
vendored
Normal file
@@ -0,0 +1,959 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Windows
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");n
|
||||
* 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 <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/cursorfont.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#include "xf_floatbar.h"
|
||||
#include "xf_utils.h"
|
||||
#include "resource/close.xbm"
|
||||
#include "resource/lock.xbm"
|
||||
#include "resource/unlock.xbm"
|
||||
#include "resource/minimize.xbm"
|
||||
#include "resource/restore.xbm"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("x11")
|
||||
|
||||
#define FLOATBAR_HEIGHT 26
|
||||
#define FLOATBAR_DEFAULT_WIDTH 576
|
||||
#define FLOATBAR_MIN_WIDTH 200
|
||||
#define FLOATBAR_BORDER 24
|
||||
#define FLOATBAR_BUTTON_WIDTH 24
|
||||
#define FLOATBAR_COLOR_BACKGROUND "RGB:31/6c/a9"
|
||||
#define FLOATBAR_COLOR_BORDER "RGB:75/9a/c8"
|
||||
#define FLOATBAR_COLOR_FOREGROUND "RGB:FF/FF/FF"
|
||||
|
||||
#define XF_FLOATBAR_MODE_NONE 0
|
||||
#define XF_FLOATBAR_MODE_DRAGGING 1
|
||||
#define XF_FLOATBAR_MODE_RESIZE_LEFT 2
|
||||
#define XF_FLOATBAR_MODE_RESIZE_RIGHT 3
|
||||
|
||||
#define XF_FLOATBAR_BUTTON_CLOSE 1
|
||||
#define XF_FLOATBAR_BUTTON_RESTORE 2
|
||||
#define XF_FLOATBAR_BUTTON_MINIMIZE 3
|
||||
#define XF_FLOATBAR_BUTTON_LOCKED 4
|
||||
|
||||
typedef BOOL (*OnClick)(xfFloatbar*);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int type;
|
||||
bool focus;
|
||||
bool clicked;
|
||||
OnClick onclick;
|
||||
Window handle;
|
||||
} xfFloatbarButton;
|
||||
|
||||
struct xf_floatbar
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int mode;
|
||||
int last_motion_x_root;
|
||||
int last_motion_y_root;
|
||||
BOOL locked;
|
||||
xfFloatbarButton* buttons[4];
|
||||
Window handle;
|
||||
BOOL hasCursor;
|
||||
xfContext* xfc;
|
||||
DWORD flags;
|
||||
BOOL created;
|
||||
Window root_window;
|
||||
char* title;
|
||||
XFontSet fontSet;
|
||||
};
|
||||
|
||||
static xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type);
|
||||
|
||||
static BOOL xf_floatbar_button_onclick_close(xfFloatbar* floatbar)
|
||||
{
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
|
||||
return freerdp_abort_connect_context(&floatbar->xfc->common.context);
|
||||
}
|
||||
|
||||
static BOOL xf_floatbar_button_onclick_minimize(xfFloatbar* floatbar)
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
|
||||
if (!floatbar || !floatbar->xfc)
|
||||
return FALSE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
xf_SetWindowMinimized(xfc, xfc->window);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL xf_floatbar_button_onclick_restore(xfFloatbar* floatbar)
|
||||
{
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
|
||||
xf_toggle_fullscreen(floatbar->xfc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL xf_floatbar_button_onclick_locked(xfFloatbar* floatbar)
|
||||
{
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
|
||||
floatbar->locked = !((floatbar->locked));
|
||||
return xf_floatbar_hide_and_show(floatbar);
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar, int y)
|
||||
{
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
|
||||
floatbar->last_motion_y_root = y;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar)
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
|
||||
if (!floatbar || !floatbar->xfc)
|
||||
return FALSE;
|
||||
|
||||
if (!floatbar->created)
|
||||
return TRUE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
|
||||
if (!floatbar->locked)
|
||||
{
|
||||
if ((floatbar->mode == XF_FLOATBAR_MODE_NONE) && (floatbar->last_motion_y_root > 10) &&
|
||||
(floatbar->y > (FLOATBAR_HEIGHT * -1)))
|
||||
{
|
||||
floatbar->y = floatbar->y - 1;
|
||||
LogDynAndXMoveWindow(xfc->log, xfc->display, floatbar->handle, floatbar->x,
|
||||
floatbar->y);
|
||||
}
|
||||
else if (floatbar->y < 0 && (floatbar->last_motion_y_root < 10))
|
||||
{
|
||||
floatbar->y = floatbar->y + 1;
|
||||
LogDynAndXMoveWindow(xfc->log, xfc->display, floatbar->handle, floatbar->x,
|
||||
floatbar->y);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL create_floatbar(xfFloatbar* floatbar)
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
Status status = 0;
|
||||
XWindowAttributes attr = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
if (floatbar->created)
|
||||
return TRUE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
|
||||
status = XGetWindowAttributes(xfc->display, floatbar->root_window, &attr);
|
||||
if (status == 0)
|
||||
{
|
||||
WLog_WARN(TAG, "XGetWindowAttributes failed");
|
||||
return FALSE;
|
||||
}
|
||||
floatbar->x = attr.x + attr.width / 2 - FLOATBAR_DEFAULT_WIDTH / 2;
|
||||
floatbar->y = 0;
|
||||
|
||||
if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
|
||||
floatbar->y = -FLOATBAR_HEIGHT + 1;
|
||||
|
||||
floatbar->handle = LogDynAndXCreateWindow(
|
||||
xfc->log, xfc->display, floatbar->root_window, floatbar->x, 0, FLOATBAR_DEFAULT_WIDTH,
|
||||
FLOATBAR_HEIGHT, 0, CopyFromParent, InputOutput, CopyFromParent, 0, nullptr);
|
||||
floatbar->width = FLOATBAR_DEFAULT_WIDTH;
|
||||
floatbar->height = FLOATBAR_HEIGHT;
|
||||
floatbar->mode = XF_FLOATBAR_MODE_NONE;
|
||||
floatbar->buttons[0] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_CLOSE);
|
||||
floatbar->buttons[1] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_RESTORE);
|
||||
floatbar->buttons[2] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_MINIMIZE);
|
||||
floatbar->buttons[3] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_LOCKED);
|
||||
XSelectInput(xfc->display, floatbar->handle,
|
||||
ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
|
||||
FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask |
|
||||
PropertyChangeMask);
|
||||
floatbar->created = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar, bool fullscreen)
|
||||
{
|
||||
int size = 0;
|
||||
bool visible = False;
|
||||
xfContext* xfc = nullptr;
|
||||
|
||||
if (!floatbar || !floatbar->xfc)
|
||||
return FALSE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
WINPR_ASSERT(xfc->display);
|
||||
|
||||
/* Only visible if enabled */
|
||||
if (floatbar->flags & 0x0001)
|
||||
{
|
||||
/* Visible if fullscreen and flag visible in fullscreen mode */
|
||||
visible |= ((floatbar->flags & 0x0010) != 0) && fullscreen;
|
||||
/* Visible if window and flag visible in window mode */
|
||||
visible |= ((floatbar->flags & 0x0020) != 0) && !fullscreen;
|
||||
}
|
||||
|
||||
if (visible)
|
||||
{
|
||||
if (!create_floatbar(floatbar))
|
||||
return FALSE;
|
||||
|
||||
LogDynAndXMapWindow(xfc->log, xfc->display, floatbar->handle);
|
||||
size = ARRAYSIZE(floatbar->buttons);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
xfFloatbarButton* button = floatbar->buttons[i];
|
||||
LogDynAndXMapWindow(xfc->log, xfc->display, button->handle);
|
||||
}
|
||||
|
||||
/* If default is hidden (and not sticky) don't show on fullscreen state changes */
|
||||
if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
|
||||
floatbar->y = -FLOATBAR_HEIGHT + 1;
|
||||
|
||||
xf_floatbar_hide_and_show(floatbar);
|
||||
}
|
||||
else if (floatbar->created)
|
||||
{
|
||||
XUnmapSubwindows(xfc->display, floatbar->handle);
|
||||
LogDynAndXUnmapWindow(xfc->log, xfc->display, floatbar->handle);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type)
|
||||
{
|
||||
xfFloatbarButton* button = nullptr;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(floatbar->xfc);
|
||||
WINPR_ASSERT(floatbar->xfc->display);
|
||||
WINPR_ASSERT(floatbar->handle);
|
||||
|
||||
button = (xfFloatbarButton*)calloc(1, sizeof(xfFloatbarButton));
|
||||
button->type = type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case XF_FLOATBAR_BUTTON_CLOSE:
|
||||
button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
|
||||
button->onclick = xf_floatbar_button_onclick_close;
|
||||
break;
|
||||
|
||||
case XF_FLOATBAR_BUTTON_RESTORE:
|
||||
button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
|
||||
button->onclick = xf_floatbar_button_onclick_restore;
|
||||
break;
|
||||
|
||||
case XF_FLOATBAR_BUTTON_MINIMIZE:
|
||||
button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
|
||||
button->onclick = xf_floatbar_button_onclick_minimize;
|
||||
break;
|
||||
|
||||
case XF_FLOATBAR_BUTTON_LOCKED:
|
||||
button->x = FLOATBAR_BORDER;
|
||||
button->onclick = xf_floatbar_button_onclick_locked;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
button->y = 0;
|
||||
button->focus = FALSE;
|
||||
button->handle =
|
||||
LogDynAndXCreateWindow(floatbar->xfc->log, floatbar->xfc->display, floatbar->handle,
|
||||
button->x, 0, FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH, 0,
|
||||
CopyFromParent, InputOutput, CopyFromParent, 0, nullptr);
|
||||
XSelectInput(floatbar->xfc->display, button->handle,
|
||||
ExposureMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
|
||||
LeaveWindowMask | EnterWindowMask | StructureNotifyMask);
|
||||
return button;
|
||||
}
|
||||
|
||||
xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window, const char* title, DWORD flags)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
WINPR_ASSERT(title);
|
||||
|
||||
/* Floatbar not enabled */
|
||||
if ((flags & 0x0001) == 0)
|
||||
return nullptr;
|
||||
|
||||
if (!xfc)
|
||||
return nullptr;
|
||||
|
||||
/* Force disable with remote app */
|
||||
if (xfc->remote_app)
|
||||
return nullptr;
|
||||
|
||||
xfFloatbar* floatbar = (xfFloatbar*)calloc(1, sizeof(xfFloatbar));
|
||||
|
||||
if (!floatbar)
|
||||
return nullptr;
|
||||
|
||||
floatbar->title = _strdup(title);
|
||||
|
||||
if (!floatbar->title)
|
||||
goto fail;
|
||||
|
||||
floatbar->root_window = window;
|
||||
floatbar->flags = flags;
|
||||
floatbar->xfc = xfc;
|
||||
floatbar->locked = (flags & 0x0002) != 0;
|
||||
xf_floatbar_toggle_fullscreen(floatbar, FALSE);
|
||||
|
||||
{
|
||||
char** missingList = nullptr;
|
||||
int missingCount = 0;
|
||||
char* defString = nullptr;
|
||||
floatbar->fontSet = XCreateFontSet(floatbar->xfc->display, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
|
||||
&missingList, &missingCount, &defString);
|
||||
|
||||
if (floatbar->fontSet == nullptr)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create fontset");
|
||||
}
|
||||
XFreeStringList(missingList);
|
||||
}
|
||||
return floatbar;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
xf_floatbar_free(floatbar);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static unsigned long xf_floatbar_get_color(xfFloatbar* floatbar, char* rgb_value)
|
||||
{
|
||||
XColor color;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(floatbar->xfc);
|
||||
|
||||
Display* display = floatbar->xfc->display;
|
||||
WINPR_ASSERT(display);
|
||||
|
||||
Colormap cmap = DefaultColormap(display, XDefaultScreen(display));
|
||||
XParseColor(display, cmap, rgb_value, &color);
|
||||
XAllocColor(display, cmap, &color);
|
||||
return color.pixel;
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_expose(xfFloatbar* floatbar)
|
||||
{
|
||||
GC gc = nullptr;
|
||||
GC shape_gc = nullptr;
|
||||
Pixmap pmap = 0;
|
||||
XPoint shape[5] = WINPR_C_ARRAY_INIT;
|
||||
XPoint border[5] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(floatbar->xfc);
|
||||
|
||||
Display* display = floatbar->xfc->display;
|
||||
WINPR_ASSERT(display);
|
||||
|
||||
/* create the pixmap that we'll use for shaping the window */
|
||||
pmap = LogDynAndXCreatePixmap(floatbar->xfc->log, display, floatbar->handle,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->width),
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->height), 1);
|
||||
gc = LogDynAndXCreateGC(floatbar->xfc->log, display, floatbar->handle, 0, 0);
|
||||
shape_gc = LogDynAndXCreateGC(floatbar->xfc->log, display, pmap, 0, 0);
|
||||
/* points for drawing the floatbar */
|
||||
shape[0].x = 0;
|
||||
shape[0].y = 0;
|
||||
shape[1].x = WINPR_ASSERTING_INT_CAST(short, floatbar->width);
|
||||
shape[1].y = 0;
|
||||
shape[2].x = WINPR_ASSERTING_INT_CAST(short, shape[1].x - FLOATBAR_BORDER);
|
||||
shape[2].y = FLOATBAR_HEIGHT;
|
||||
shape[3].x = WINPR_ASSERTING_INT_CAST(short, shape[0].x + FLOATBAR_BORDER);
|
||||
shape[3].y = FLOATBAR_HEIGHT;
|
||||
shape[4].x = shape[0].x;
|
||||
shape[4].y = shape[0].y;
|
||||
/* points for drawing the border of the floatbar */
|
||||
border[0].x = shape[0].x;
|
||||
border[0].y = WINPR_ASSERTING_INT_CAST(short, shape[0].y - 1);
|
||||
border[1].x = WINPR_ASSERTING_INT_CAST(short, shape[1].x - 1);
|
||||
border[1].y = WINPR_ASSERTING_INT_CAST(short, shape[1].y - 1);
|
||||
border[2].x = shape[2].x;
|
||||
border[2].y = WINPR_ASSERTING_INT_CAST(short, shape[2].y - 1);
|
||||
border[3].x = WINPR_ASSERTING_INT_CAST(short, shape[3].x - 1);
|
||||
border[3].y = WINPR_ASSERTING_INT_CAST(short, shape[3].y - 1);
|
||||
border[4].x = border[0].x;
|
||||
border[4].y = border[0].y;
|
||||
/* Fill all pixels with 0 */
|
||||
LogDynAndXSetForeground(floatbar->xfc->log, display, shape_gc, 0);
|
||||
LogDynAndXFillRectangle(floatbar->xfc->log, display, pmap, shape_gc, 0, 0,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->width),
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->height));
|
||||
/* Fill all pixels which should be shown with 1 */
|
||||
LogDynAndXSetForeground(floatbar->xfc->log, display, shape_gc, 1);
|
||||
XFillPolygon(display, pmap, shape_gc, shape, 5, 0, CoordModeOrigin);
|
||||
XShapeCombineMask(display, floatbar->handle, ShapeBounding, 0, 0, pmap, ShapeSet);
|
||||
/* draw the float bar */
|
||||
LogDynAndXSetForeground(floatbar->xfc->log, display, gc,
|
||||
xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
|
||||
XFillPolygon(display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin);
|
||||
/* draw an border for the floatbar */
|
||||
LogDynAndXSetForeground(floatbar->xfc->log, display, gc,
|
||||
xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
|
||||
XDrawLines(display, floatbar->handle, gc, border, 5, CoordModeOrigin);
|
||||
/* draw the host name connected to (limit to maximum file name) */
|
||||
const size_t len = strnlen(floatbar->title, MAX_PATH);
|
||||
LogDynAndXSetForeground(floatbar->xfc->log, display, gc,
|
||||
xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
|
||||
|
||||
WINPR_ASSERT(len <= INT32_MAX / 2);
|
||||
const int fx = floatbar->width / 2 - (int)len * 2;
|
||||
if (floatbar->fontSet != nullptr)
|
||||
{
|
||||
XmbDrawString(display, floatbar->handle, floatbar->fontSet, gc, fx, 15, floatbar->title,
|
||||
(int)len);
|
||||
}
|
||||
else
|
||||
{
|
||||
XDrawString(display, floatbar->handle, gc, fx, 15, floatbar->title, (int)len);
|
||||
}
|
||||
LogDynAndXFreeGC(floatbar->xfc->log, display, gc);
|
||||
LogDynAndXFreeGC(floatbar->xfc->log, display, shape_gc);
|
||||
}
|
||||
|
||||
static xfFloatbarButton* xf_floatbar_get_button(xfFloatbar* floatbar, Window window)
|
||||
{
|
||||
WINPR_ASSERT(floatbar);
|
||||
const size_t size = ARRAYSIZE(floatbar->buttons);
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
xfFloatbarButton* button = floatbar->buttons[i];
|
||||
if (button->handle == window)
|
||||
{
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_update_positon(xfFloatbar* floatbar)
|
||||
{
|
||||
xfFloatbarButton* button = nullptr;
|
||||
WINPR_ASSERT(floatbar);
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
const size_t size = ARRAYSIZE(floatbar->buttons);
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
button = floatbar->buttons[i];
|
||||
|
||||
switch (button->type)
|
||||
{
|
||||
case XF_FLOATBAR_BUTTON_CLOSE:
|
||||
button->x =
|
||||
floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
|
||||
break;
|
||||
|
||||
case XF_FLOATBAR_BUTTON_RESTORE:
|
||||
button->x =
|
||||
floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
|
||||
break;
|
||||
|
||||
case XF_FLOATBAR_BUTTON_MINIMIZE:
|
||||
button->x =
|
||||
floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
LogDynAndXMoveWindow(xfc->log, xfc->display, button->handle, button->x, button->y);
|
||||
xf_floatbar_event_expose(floatbar);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_expose(xfFloatbar* floatbar, Window window)
|
||||
{
|
||||
xfFloatbarButton* button = xf_floatbar_get_button(floatbar, window);
|
||||
static unsigned char* bits;
|
||||
GC gc = nullptr;
|
||||
Pixmap pattern = 0;
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
|
||||
if (!button)
|
||||
return;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
WINPR_ASSERT(xfc->window);
|
||||
|
||||
gc = LogDynAndXCreateGC(xfc->log, xfc->display, button->handle, 0, 0);
|
||||
floatbar = xfc->window->floatbar;
|
||||
WINPR_ASSERT(floatbar);
|
||||
|
||||
switch (button->type)
|
||||
{
|
||||
case XF_FLOATBAR_BUTTON_CLOSE:
|
||||
bits = close_bits;
|
||||
break;
|
||||
|
||||
case XF_FLOATBAR_BUTTON_RESTORE:
|
||||
bits = restore_bits;
|
||||
break;
|
||||
|
||||
case XF_FLOATBAR_BUTTON_MINIMIZE:
|
||||
bits = minimize_bits;
|
||||
break;
|
||||
|
||||
case XF_FLOATBAR_BUTTON_LOCKED:
|
||||
if (floatbar->locked)
|
||||
bits = lock_bits;
|
||||
else
|
||||
bits = unlock_bits;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pattern = XCreateBitmapFromData(xfc->display, button->handle, (const char*)bits,
|
||||
FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH);
|
||||
|
||||
if (!(button->focus))
|
||||
LogDynAndXSetForeground(floatbar->xfc->log, xfc->display, gc,
|
||||
xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
|
||||
else
|
||||
LogDynAndXSetForeground(floatbar->xfc->log, xfc->display, gc,
|
||||
xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
|
||||
|
||||
LogDynAndXSetBackground(xfc->log, xfc->display, gc,
|
||||
xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
|
||||
XCopyPlane(xfc->display, pattern, button->handle, gc, 0, 0, FLOATBAR_BUTTON_WIDTH,
|
||||
FLOATBAR_BUTTON_WIDTH, 0, 0, 1);
|
||||
LogDynAndXFreePixmap(xfc->log, xfc->display, pattern);
|
||||
LogDynAndXFreeGC(xfc->log, xfc->display, gc);
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_buttonpress(xfFloatbar* floatbar, const XButtonEvent* event)
|
||||
{
|
||||
WINPR_ASSERT(event);
|
||||
xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event->window);
|
||||
|
||||
if (button)
|
||||
button->clicked = TRUE;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_buttonrelease(xfFloatbar* floatbar, const XButtonEvent* event)
|
||||
{
|
||||
xfFloatbarButton* button = nullptr;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
button = xf_floatbar_get_button(floatbar, event->window);
|
||||
|
||||
if (button)
|
||||
{
|
||||
if (button->clicked)
|
||||
button->onclick(floatbar);
|
||||
button->clicked = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_buttonpress(xfFloatbar* floatbar, const XButtonEvent* event)
|
||||
{
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
switch (event->button)
|
||||
{
|
||||
case Button1:
|
||||
if (event->x <= FLOATBAR_BORDER)
|
||||
floatbar->mode = XF_FLOATBAR_MODE_RESIZE_LEFT;
|
||||
else if (event->x >= (floatbar->width - FLOATBAR_BORDER))
|
||||
floatbar->mode = XF_FLOATBAR_MODE_RESIZE_RIGHT;
|
||||
else
|
||||
floatbar->mode = XF_FLOATBAR_MODE_DRAGGING;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_buttonrelease(xfFloatbar* floatbar, const XButtonEvent* event)
|
||||
{
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
switch (event->button)
|
||||
{
|
||||
case Button1:
|
||||
floatbar->mode = XF_FLOATBAR_MODE_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_resize(xfFloatbar* floatbar, const XMotionEvent* event)
|
||||
{
|
||||
int x = 0;
|
||||
int width = 0;
|
||||
int movement = 0;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
|
||||
/* calculate movement which happened on the root window */
|
||||
movement = event->x_root - floatbar->last_motion_x_root;
|
||||
|
||||
/* set x and width depending if movement happens on the left or right */
|
||||
if (floatbar->mode == XF_FLOATBAR_MODE_RESIZE_LEFT)
|
||||
{
|
||||
x = floatbar->x + movement;
|
||||
width = floatbar->width + movement * -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = floatbar->x;
|
||||
width = floatbar->width + movement;
|
||||
}
|
||||
|
||||
/* only resize and move window if still above minimum width */
|
||||
if (FLOATBAR_MIN_WIDTH < width)
|
||||
{
|
||||
LogDynAndXMoveResizeWindow(xfc->log, xfc->display, floatbar->handle, x, 0,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, width),
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->height));
|
||||
floatbar->x = x;
|
||||
floatbar->width = width;
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_dragging(xfFloatbar* floatbar, const XMotionEvent* event)
|
||||
{
|
||||
int x = 0;
|
||||
int movement = 0;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(event);
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->window);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
|
||||
/* calculate movement and new x position */
|
||||
movement = event->x_root - floatbar->last_motion_x_root;
|
||||
x = floatbar->x + movement;
|
||||
|
||||
/* do nothing if floatbar would be moved out of the window */
|
||||
if (x < 0 || (x + floatbar->width) > xfc->window->width)
|
||||
return;
|
||||
|
||||
/* move window to new x position */
|
||||
LogDynAndXMoveWindow(xfc->log, xfc->display, floatbar->handle, x, 0);
|
||||
/* update struct values for the next event */
|
||||
floatbar->last_motion_x_root = floatbar->last_motion_x_root + movement;
|
||||
floatbar->x = x;
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_motionnotify(xfFloatbar* floatbar, const XMotionEvent* event)
|
||||
{
|
||||
int mode = 0;
|
||||
Cursor cursor = 0;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
|
||||
mode = floatbar->mode;
|
||||
cursor = XCreateFontCursor(xfc->display, XC_arrow);
|
||||
|
||||
if ((event->state & Button1Mask) && (mode > XF_FLOATBAR_MODE_DRAGGING))
|
||||
{
|
||||
xf_floatbar_resize(floatbar, event);
|
||||
}
|
||||
else if ((event->state & Button1Mask) && (mode == XF_FLOATBAR_MODE_DRAGGING))
|
||||
{
|
||||
xf_floatbar_dragging(floatbar, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (event->x <= FLOATBAR_BORDER || event->x >= floatbar->width - FLOATBAR_BORDER)
|
||||
cursor = XCreateFontCursor(xfc->display, XC_sb_h_double_arrow);
|
||||
}
|
||||
|
||||
XDefineCursor(xfc->display, xfc->window->handle, cursor);
|
||||
XFreeCursor(xfc->display, cursor);
|
||||
floatbar->last_motion_x_root = event->x_root;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_focusin(xfFloatbar* floatbar, const XAnyEvent* event)
|
||||
{
|
||||
xfFloatbarButton* button = nullptr;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
button = xf_floatbar_get_button(floatbar, event->window);
|
||||
|
||||
if (button)
|
||||
{
|
||||
button->focus = TRUE;
|
||||
xf_floatbar_button_event_expose(floatbar, event->window);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_focusout(xfFloatbar* floatbar, const XAnyEvent* event)
|
||||
{
|
||||
xfFloatbarButton* button = nullptr;
|
||||
|
||||
WINPR_ASSERT(floatbar);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
button = xf_floatbar_get_button(floatbar, event->window);
|
||||
|
||||
if (button)
|
||||
{
|
||||
button->focus = FALSE;
|
||||
xf_floatbar_button_event_expose(floatbar, event->window);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_focusout(xfFloatbar* floatbar)
|
||||
{
|
||||
WINPR_ASSERT(floatbar);
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
if (xfc->pointer)
|
||||
{
|
||||
WINPR_ASSERT(xfc->window);
|
||||
WINPR_ASSERT(xfc->pointer);
|
||||
XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_check_event(xfFloatbar* floatbar, const XEvent* event)
|
||||
{
|
||||
if (!floatbar || !floatbar->xfc || !event)
|
||||
return FALSE;
|
||||
|
||||
if (!floatbar->created)
|
||||
return FALSE;
|
||||
|
||||
if (event->xany.window == floatbar->handle)
|
||||
return TRUE;
|
||||
|
||||
size_t size = ARRAYSIZE(floatbar->buttons);
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
const xfFloatbarButton* button = floatbar->buttons[i];
|
||||
|
||||
if (event->xany.window == button->handle)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_event_process(xfFloatbar* floatbar, const XEvent* event)
|
||||
{
|
||||
if (!floatbar || !floatbar->xfc || !event)
|
||||
return FALSE;
|
||||
|
||||
if (!floatbar->created)
|
||||
return FALSE;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case Expose:
|
||||
if (event->xexpose.window == floatbar->handle)
|
||||
xf_floatbar_event_expose(floatbar);
|
||||
else
|
||||
xf_floatbar_button_event_expose(floatbar, event->xexpose.window);
|
||||
|
||||
break;
|
||||
|
||||
case MotionNotify:
|
||||
xf_floatbar_event_motionnotify(floatbar, &event->xmotion);
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_event_buttonpress(floatbar, &event->xbutton);
|
||||
else
|
||||
xf_floatbar_button_event_buttonpress(floatbar, &event->xbutton);
|
||||
|
||||
break;
|
||||
|
||||
case ButtonRelease:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_event_buttonrelease(floatbar, &event->xbutton);
|
||||
else
|
||||
xf_floatbar_button_event_buttonrelease(floatbar, &event->xbutton);
|
||||
|
||||
break;
|
||||
|
||||
case EnterNotify:
|
||||
case FocusIn:
|
||||
if (event->xany.window != floatbar->handle)
|
||||
xf_floatbar_button_event_focusin(floatbar, &event->xany);
|
||||
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
case FocusOut:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_event_focusout(floatbar);
|
||||
else
|
||||
xf_floatbar_button_event_focusout(floatbar, &event->xany);
|
||||
|
||||
break;
|
||||
|
||||
case ConfigureNotify:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_button_update_positon(floatbar);
|
||||
|
||||
break;
|
||||
|
||||
case PropertyNotify:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_button_update_positon(floatbar);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return floatbar->handle == event->xany.window;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_free(xfContext* xfc, xfFloatbarButton* button)
|
||||
{
|
||||
if (!button)
|
||||
return;
|
||||
|
||||
if (button->handle)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->display);
|
||||
LogDynAndXUnmapWindow(xfc->log, xfc->display, button->handle);
|
||||
LogDynAndXDestroyWindow(xfc->log, xfc->display, button->handle);
|
||||
}
|
||||
|
||||
free(button);
|
||||
}
|
||||
|
||||
void xf_floatbar_free(xfFloatbar* floatbar)
|
||||
{
|
||||
size_t size = 0;
|
||||
xfContext* xfc = nullptr;
|
||||
|
||||
if (!floatbar)
|
||||
return;
|
||||
|
||||
free(floatbar->title);
|
||||
xfc = floatbar->xfc;
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
size = ARRAYSIZE(floatbar->buttons);
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
xf_floatbar_button_free(xfc, floatbar->buttons[i]);
|
||||
floatbar->buttons[i] = nullptr;
|
||||
}
|
||||
|
||||
if (floatbar->handle)
|
||||
{
|
||||
WINPR_ASSERT(xfc->display);
|
||||
LogDynAndXUnmapWindow(xfc->log, xfc->display, floatbar->handle);
|
||||
LogDynAndXDestroyWindow(xfc->log, xfc->display, floatbar->handle);
|
||||
}
|
||||
|
||||
free(floatbar);
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_is_locked(xfFloatbar* floatbar)
|
||||
{
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
return floatbar->mode != XF_FLOATBAR_MODE_NONE;
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_is_window(xfFloatbar* floatbar, Window window)
|
||||
{
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
return floatbar->handle == window;
|
||||
}
|
||||
|
||||
BOOL xfc_is_floatbar_window(xfContext* xfc, Window window)
|
||||
{
|
||||
if (!xfc || !xfc->window)
|
||||
return FALSE;
|
||||
return xf_floatbar_is_window(xfc->window->floatbar, window);
|
||||
}
|
||||
45
third_party/FreeRDP/client/X11/xf_floatbar.h
vendored
Normal file
45
third_party/FreeRDP/client/X11/xf_floatbar.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Windows
|
||||
*
|
||||
* 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_X11_FLOATBAR_H
|
||||
#define FREERDP_CLIENT_X11_FLOATBAR_H
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "xf_types.h"
|
||||
|
||||
typedef struct xf_floatbar xfFloatbar;
|
||||
|
||||
void xf_floatbar_free(xfFloatbar* floatbar);
|
||||
|
||||
WINPR_ATTR_MALLOC(xf_floatbar_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window, const char* title, DWORD flags);
|
||||
|
||||
BOOL xf_floatbar_is_window(xfFloatbar* floatbar, Window window);
|
||||
BOOL xf_floatbar_is_locked(xfFloatbar* floatbar);
|
||||
BOOL xf_floatbar_event_process(xfFloatbar* floatbar, const XEvent* event);
|
||||
BOOL xf_floatbar_check_event(xfFloatbar* floatbar, const XEvent* event);
|
||||
BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar, bool fullscreen);
|
||||
BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar);
|
||||
BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar, int y);
|
||||
|
||||
BOOL xfc_is_floatbar_window(xfContext* xfc, Window window);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_FLOATBAR_H */
|
||||
537
third_party/FreeRDP/client/X11/xf_gfx.c
vendored
Normal file
537
third_party/FreeRDP/client/X11/xf_gfx.c
vendored
Normal file
@@ -0,0 +1,537 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Graphics Pipeline
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2016 Thincast Technologies GmbH
|
||||
*
|
||||
* 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 <math.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include "xf_gfx.h"
|
||||
#include "xf_rail.h"
|
||||
#include "xf_utils.h"
|
||||
#include "xf_window.h"
|
||||
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#define TAG CLIENT_TAG("x11")
|
||||
|
||||
static UINT xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
|
||||
{
|
||||
UINT rc = ERROR_INTERNAL_ERROR;
|
||||
UINT32 surfaceX = 0;
|
||||
UINT32 surfaceY = 0;
|
||||
RECTANGLE_16 surfaceRect = WINPR_C_ARRAY_INIT;
|
||||
UINT32 nbRects = 0;
|
||||
const RECTANGLE_16* rects = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(surface);
|
||||
|
||||
rdpGdi* gdi = xfc->common.context.gdi;
|
||||
WINPR_ASSERT(gdi);
|
||||
|
||||
rdpSettings* settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
surfaceX = surface->gdi.outputOriginX;
|
||||
surfaceY = surface->gdi.outputOriginY;
|
||||
surfaceRect.left = 0;
|
||||
surfaceRect.top = 0;
|
||||
surfaceRect.right = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.mappedWidth);
|
||||
surfaceRect.bottom = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.mappedHeight);
|
||||
LogDynAndXSetClipMask(xfc->log, xfc->display, xfc->gc, None);
|
||||
LogDynAndXSetFunction(xfc->log, xfc->display, xfc->gc, GXcopy);
|
||||
LogDynAndXSetFillStyle(xfc->log, xfc->display, xfc->gc, FillSolid);
|
||||
if (!region16_intersect_rect(&(surface->gdi.invalidRegion), &(surface->gdi.invalidRegion),
|
||||
&surfaceRect))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
WINPR_ASSERT(surface->gdi.mappedWidth);
|
||||
WINPR_ASSERT(surface->gdi.mappedHeight);
|
||||
const double sx = 1.0 * surface->gdi.outputTargetWidth / (double)surface->gdi.mappedWidth;
|
||||
const double sy = 1.0 * surface->gdi.outputTargetHeight / (double)surface->gdi.mappedHeight;
|
||||
|
||||
if (!(rects = region16_rects(&surface->gdi.invalidRegion, &nbRects)))
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
xf_lock_x11(xfc);
|
||||
for (UINT32 x = 0; x < nbRects; x++)
|
||||
{
|
||||
const RECTANGLE_16* rect = &rects[x];
|
||||
const UINT32 nXSrc = rect->left;
|
||||
const UINT32 nYSrc = rect->top;
|
||||
const UINT32 swidth = rect->right - nXSrc;
|
||||
const UINT32 sheight = rect->bottom - nYSrc;
|
||||
const UINT32 nXDst = (UINT32)lround(1.0 * surfaceX + nXSrc * sx);
|
||||
const UINT32 nYDst = (UINT32)lround(1.0 * surfaceY + nYSrc * sy);
|
||||
const UINT32 dwidth = (UINT32)lround(1.0 * swidth * sx);
|
||||
const UINT32 dheight = (UINT32)lround(1.0 * sheight * sy);
|
||||
|
||||
if (surface->stage)
|
||||
{
|
||||
if (!freerdp_image_scale(surface->stage, gdi->dstFormat, surface->stageScanline, nXSrc,
|
||||
nYSrc, dwidth, dheight, surface->gdi.data, surface->gdi.format,
|
||||
surface->gdi.scanline, nXSrc, nYSrc, swidth, sheight))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (xfc->remote_app)
|
||||
{
|
||||
LogDynAndXPutImage(xfc->log, xfc->display, xfc->primary, xfc->gc, surface->image,
|
||||
WINPR_ASSERTING_INT_CAST(int, nXSrc),
|
||||
WINPR_ASSERTING_INT_CAST(int, nYSrc),
|
||||
WINPR_ASSERTING_INT_CAST(int, nXDst),
|
||||
WINPR_ASSERTING_INT_CAST(int, nYDst), dwidth, dheight);
|
||||
xf_rail_paint_surface(xfc, surface->gdi.windowId, rect);
|
||||
}
|
||||
else
|
||||
#ifdef WITH_XRENDER
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ||
|
||||
freerdp_settings_get_bool(settings, FreeRDP_MultiTouchGestures))
|
||||
{
|
||||
LogDynAndXPutImage(xfc->log, xfc->display, xfc->primary, xfc->gc, surface->image,
|
||||
WINPR_ASSERTING_INT_CAST(int, nXSrc),
|
||||
WINPR_ASSERTING_INT_CAST(int, nYSrc),
|
||||
WINPR_ASSERTING_INT_CAST(int, nXDst),
|
||||
WINPR_ASSERTING_INT_CAST(int, nYDst), dwidth, dheight);
|
||||
xf_draw_screen(xfc, WINPR_ASSERTING_INT_CAST(int32_t, nXDst),
|
||||
WINPR_ASSERTING_INT_CAST(int32_t, nYDst),
|
||||
WINPR_ASSERTING_INT_CAST(int32_t, dwidth),
|
||||
WINPR_ASSERTING_INT_CAST(int32_t, dheight));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LogDynAndXPutImage(xfc->log, xfc->display, xfc->drawable, xfc->gc, surface->image,
|
||||
WINPR_ASSERTING_INT_CAST(int, nXSrc),
|
||||
WINPR_ASSERTING_INT_CAST(int, nYSrc),
|
||||
WINPR_ASSERTING_INT_CAST(int, nXDst),
|
||||
WINPR_ASSERTING_INT_CAST(int, nYDst), dwidth, dheight);
|
||||
}
|
||||
}
|
||||
|
||||
rc = CHANNEL_RC_OK;
|
||||
fail:
|
||||
region16_clear(&surface->gdi.invalidRegion);
|
||||
LogDynAndXSetClipMask(xfc->log, xfc->display, xfc->gc, None);
|
||||
LogDynAndXSync(xfc->log, xfc->display, False);
|
||||
xf_unlock_x11(xfc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static UINT xf_WindowUpdate(RdpgfxClientContext* context, xfGfxSurface* surface)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(surface);
|
||||
return IFCALLRESULT(CHANNEL_RC_OK, context->UpdateWindowFromSurface, context, &surface->gdi);
|
||||
}
|
||||
|
||||
static UINT xf_UpdateSurfaces(RdpgfxClientContext* context)
|
||||
{
|
||||
UINT16 count = 0;
|
||||
UINT status = CHANNEL_RC_OK;
|
||||
UINT16* pSurfaceIds = nullptr;
|
||||
rdpGdi* gdi = (rdpGdi*)context->custom;
|
||||
xfContext* xfc = nullptr;
|
||||
|
||||
if (!gdi)
|
||||
return status;
|
||||
|
||||
if (gdi->suppressOutput)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
xfc = (xfContext*)gdi->context;
|
||||
EnterCriticalSection(&context->mux);
|
||||
status = context->GetSurfaceIds(context, &pSurfaceIds, &count);
|
||||
if (status != CHANNEL_RC_OK)
|
||||
goto fail;
|
||||
|
||||
for (UINT32 index = 0; index < count; index++)
|
||||
{
|
||||
xfGfxSurface* surface = (xfGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
|
||||
|
||||
if (!surface)
|
||||
continue;
|
||||
|
||||
/* If UpdateSurfaceArea callback is available, the output has already been updated. */
|
||||
if (context->UpdateSurfaceArea)
|
||||
{
|
||||
if (surface->gdi.handleInUpdateSurfaceArea)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (surface->gdi.outputMapped)
|
||||
status = xf_OutputUpdate(xfc, surface);
|
||||
else if (surface->gdi.windowMapped)
|
||||
status = xf_WindowUpdate(context, surface);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
fail:
|
||||
free(pSurfaceIds);
|
||||
LeaveCriticalSection(&context->mux);
|
||||
return status;
|
||||
}
|
||||
|
||||
UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height)
|
||||
{
|
||||
UINT16 count = 0;
|
||||
UINT status = ERROR_INTERNAL_ERROR;
|
||||
RECTANGLE_16 invalidRect = WINPR_C_ARRAY_INIT;
|
||||
RECTANGLE_16 intersection = WINPR_C_ARRAY_INIT;
|
||||
UINT16* pSurfaceIds = nullptr;
|
||||
RdpgfxClientContext* context = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xfc->common.context.gdi);
|
||||
|
||||
context = xfc->common.context.gdi->gfx;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
invalidRect.left = WINPR_ASSERTING_INT_CAST(UINT16, x);
|
||||
invalidRect.top = WINPR_ASSERTING_INT_CAST(UINT16, y);
|
||||
invalidRect.right = WINPR_ASSERTING_INT_CAST(UINT16, x + width);
|
||||
invalidRect.bottom = WINPR_ASSERTING_INT_CAST(UINT16, y + height);
|
||||
status = context->GetSurfaceIds(context, &pSurfaceIds, &count);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
goto fail;
|
||||
|
||||
if (!TryEnterCriticalSection(&context->mux))
|
||||
{
|
||||
free(pSurfaceIds);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
for (UINT32 index = 0; index < count; index++)
|
||||
{
|
||||
RECTANGLE_16 surfaceRect = WINPR_C_ARRAY_INIT;
|
||||
xfGfxSurface* surface = (xfGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
|
||||
|
||||
if (!surface || (!surface->gdi.outputMapped && !surface->gdi.windowMapped))
|
||||
continue;
|
||||
|
||||
surfaceRect.left = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.outputOriginX);
|
||||
surfaceRect.top = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.outputOriginY);
|
||||
surfaceRect.right = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.outputOriginX +
|
||||
surface->gdi.outputTargetWidth);
|
||||
surfaceRect.bottom = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.outputOriginY +
|
||||
surface->gdi.outputTargetHeight);
|
||||
|
||||
if (rectangles_intersection(&invalidRect, &surfaceRect, &intersection))
|
||||
{
|
||||
/* Invalid rects are specified relative to surface origin */
|
||||
intersection.left -= surfaceRect.left;
|
||||
intersection.top -= surfaceRect.top;
|
||||
intersection.right -= surfaceRect.left;
|
||||
intersection.bottom -= surfaceRect.top;
|
||||
if (!region16_union_rect(&surface->gdi.invalidRegion, &surface->gdi.invalidRegion,
|
||||
&intersection))
|
||||
{
|
||||
free(pSurfaceIds);
|
||||
LeaveCriticalSection(&context->mux);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(pSurfaceIds);
|
||||
LeaveCriticalSection(&context->mux);
|
||||
IFCALLRET(context->UpdateSurfaces, status, context);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
goto fail;
|
||||
|
||||
fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
static UINT32 x11_pad_scanline(UINT32 scanline, UINT32 inPad)
|
||||
{
|
||||
/* Ensure X11 alignment is met */
|
||||
if (inPad > 0)
|
||||
{
|
||||
const UINT32 align = inPad / 8;
|
||||
const UINT32 pad = align - scanline % align;
|
||||
|
||||
if (align != pad)
|
||||
scanline += pad;
|
||||
}
|
||||
|
||||
/* 16 byte alignment is required for ASM optimized code */
|
||||
if (scanline % 16)
|
||||
scanline += 16 - scanline % 16;
|
||||
|
||||
return scanline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_CreateSurface(RdpgfxClientContext* context,
|
||||
const RDPGFX_CREATE_SURFACE_PDU* createSurface)
|
||||
{
|
||||
UINT ret = CHANNEL_RC_NO_MEMORY;
|
||||
size_t size = 0;
|
||||
xfGfxSurface* surface = nullptr;
|
||||
rdpGdi* gdi = (rdpGdi*)context->custom;
|
||||
xfContext* xfc = (xfContext*)gdi->context;
|
||||
surface = (xfGfxSurface*)calloc(1, sizeof(xfGfxSurface));
|
||||
|
||||
if (!surface)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
surface->gdi.codecs = context->codecs;
|
||||
|
||||
if (!surface->gdi.codecs)
|
||||
{
|
||||
WLog_ERR(TAG, "global GDI codecs aren't set");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
surface->gdi.surfaceId = createSurface->surfaceId;
|
||||
surface->gdi.width = x11_pad_scanline(createSurface->width, 0);
|
||||
surface->gdi.height = x11_pad_scanline(createSurface->height, 0);
|
||||
surface->gdi.mappedWidth = createSurface->width;
|
||||
surface->gdi.mappedHeight = createSurface->height;
|
||||
surface->gdi.outputTargetWidth = createSurface->width;
|
||||
surface->gdi.outputTargetHeight = createSurface->height;
|
||||
|
||||
switch (createSurface->pixelFormat)
|
||||
{
|
||||
case GFX_PIXEL_FORMAT_ARGB_8888:
|
||||
surface->gdi.format = PIXEL_FORMAT_BGRA32;
|
||||
break;
|
||||
|
||||
case GFX_PIXEL_FORMAT_XRGB_8888:
|
||||
surface->gdi.format = PIXEL_FORMAT_BGRX32;
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown pixelFormat 0x%" PRIx32 "", createSurface->pixelFormat);
|
||||
ret = ERROR_INTERNAL_ERROR;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
surface->gdi.scanline = surface->gdi.width * FreeRDPGetBytesPerPixel(surface->gdi.format);
|
||||
surface->gdi.scanline = x11_pad_scanline(surface->gdi.scanline,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, xfc->scanline_pad));
|
||||
size = 1ull * surface->gdi.scanline * surface->gdi.height;
|
||||
surface->gdi.data = (BYTE*)winpr_aligned_malloc(size, 16);
|
||||
|
||||
if (!surface->gdi.data)
|
||||
{
|
||||
WLog_ERR(TAG, "unable to allocate GDI data");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ZeroMemory(surface->gdi.data, size);
|
||||
|
||||
if (FreeRDPAreColorFormatsEqualNoAlpha(gdi->dstFormat, surface->gdi.format))
|
||||
{
|
||||
WINPR_ASSERT(xfc->depth != 0);
|
||||
surface->image = LogDynAndXCreateImage(
|
||||
xfc->log, xfc->display, xfc->visual, WINPR_ASSERTING_INT_CAST(uint32_t, xfc->depth),
|
||||
ZPixmap, 0, (char*)surface->gdi.data, surface->gdi.mappedWidth,
|
||||
surface->gdi.mappedHeight, xfc->scanline_pad,
|
||||
WINPR_ASSERTING_INT_CAST(int, surface->gdi.scanline));
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT32 width = surface->gdi.width;
|
||||
UINT32 bytes = FreeRDPGetBytesPerPixel(gdi->dstFormat);
|
||||
surface->stageScanline = width * bytes;
|
||||
surface->stageScanline = x11_pad_scanline(
|
||||
surface->stageScanline, WINPR_ASSERTING_INT_CAST(uint32_t, xfc->scanline_pad));
|
||||
size = 1ull * surface->stageScanline * surface->gdi.height;
|
||||
surface->stage = (BYTE*)winpr_aligned_malloc(size, 16);
|
||||
|
||||
if (!surface->stage)
|
||||
{
|
||||
WLog_ERR(TAG, "unable to allocate stage buffer");
|
||||
goto out_free_gdidata;
|
||||
}
|
||||
|
||||
ZeroMemory(surface->stage, size);
|
||||
WINPR_ASSERT(xfc->depth != 0);
|
||||
surface->image = LogDynAndXCreateImage(
|
||||
xfc->log, xfc->display, xfc->visual, WINPR_ASSERTING_INT_CAST(uint32_t, xfc->depth),
|
||||
ZPixmap, 0, (char*)surface->stage, surface->gdi.mappedWidth, surface->gdi.mappedHeight,
|
||||
xfc->scanline_pad, WINPR_ASSERTING_INT_CAST(int, surface->stageScanline));
|
||||
}
|
||||
|
||||
if (!surface->image)
|
||||
{
|
||||
WLog_ERR(TAG, "an error occurred when creating the XImage");
|
||||
goto error_surface_image;
|
||||
}
|
||||
|
||||
surface->image->byte_order = LSBFirst;
|
||||
surface->image->bitmap_bit_order = LSBFirst;
|
||||
|
||||
region16_init(&surface->gdi.invalidRegion);
|
||||
|
||||
if (context->SetSurfaceData(context, surface->gdi.surfaceId, (void*)surface) != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "an error occurred during SetSurfaceData");
|
||||
goto error_set_surface_data;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
error_set_surface_data:
|
||||
surface->image->data = nullptr;
|
||||
XDestroyImage(surface->image);
|
||||
error_surface_image:
|
||||
winpr_aligned_free(surface->stage);
|
||||
out_free_gdidata:
|
||||
winpr_aligned_free(surface->gdi.data);
|
||||
out_free:
|
||||
free(surface);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_DeleteSurface(RdpgfxClientContext* context,
|
||||
const RDPGFX_DELETE_SURFACE_PDU* deleteSurface)
|
||||
{
|
||||
rdpCodecs* codecs = nullptr;
|
||||
|
||||
UINT status = 0;
|
||||
EnterCriticalSection(&context->mux);
|
||||
xfGfxSurface* surface =
|
||||
(xfGfxSurface*)context->GetSurfaceData(context, deleteSurface->surfaceId);
|
||||
|
||||
if (surface)
|
||||
{
|
||||
if (surface->gdi.windowMapped)
|
||||
{
|
||||
status = IFCALLRESULT(CHANNEL_RC_OK, context->UnmapWindowForSurface, context,
|
||||
surface->gdi.windowId);
|
||||
if (status != CHANNEL_RC_OK)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef WITH_GFX_H264
|
||||
h264_context_free(surface->gdi.h264);
|
||||
#endif
|
||||
surface->image->data = nullptr;
|
||||
XDestroyImage(surface->image);
|
||||
winpr_aligned_free(surface->gdi.data);
|
||||
winpr_aligned_free(surface->stage);
|
||||
region16_uninit(&surface->gdi.invalidRegion);
|
||||
codecs = surface->gdi.codecs;
|
||||
free(surface);
|
||||
}
|
||||
|
||||
status = context->SetSurfaceData(context, deleteSurface->surfaceId, nullptr);
|
||||
|
||||
if (codecs && codecs->progressive)
|
||||
progressive_delete_surface_context(codecs->progressive, deleteSurface->surfaceId);
|
||||
|
||||
fail:
|
||||
LeaveCriticalSection(&context->mux);
|
||||
return status;
|
||||
}
|
||||
|
||||
static UINT xf_UnmapWindowForSurface(RdpgfxClientContext* context, UINT64 windowID)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
rdpGdi* gdi = (rdpGdi*)context->custom;
|
||||
WINPR_ASSERT(gdi);
|
||||
|
||||
xfContext* xfc = (xfContext*)gdi->context;
|
||||
WINPR_ASSERT(gdi->context);
|
||||
|
||||
if (freerdp_settings_get_bool(gdi->context->settings, FreeRDP_RemoteApplicationMode))
|
||||
{
|
||||
xfAppWindow* appWindow = xf_rail_get_window(xfc, windowID, FALSE);
|
||||
if (appWindow)
|
||||
xf_AppWindowDestroyImage(appWindow);
|
||||
xf_rail_return_window(appWindow, FALSE);
|
||||
}
|
||||
|
||||
WLog_WARN(TAG, "function not implemented");
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static UINT xf_UpdateWindowFromSurface(RdpgfxClientContext* context, gdiGfxSurface* surface)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(surface);
|
||||
|
||||
rdpGdi* gdi = (rdpGdi*)context->custom;
|
||||
WINPR_ASSERT(gdi);
|
||||
|
||||
xfContext* xfc = (xfContext*)gdi->context;
|
||||
WINPR_ASSERT(gdi->context);
|
||||
|
||||
if (freerdp_settings_get_bool(gdi->context->settings, FreeRDP_RemoteApplicationMode))
|
||||
return xf_AppUpdateWindowFromSurface(xfc, surface);
|
||||
|
||||
WLog_WARN(TAG, "function not implemented");
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx)
|
||||
{
|
||||
rdpGdi* gdi = nullptr;
|
||||
const rdpSettings* settings = nullptr;
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(gfx);
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
gdi = xfc->common.context.gdi;
|
||||
|
||||
gdi_graphics_pipeline_init(gdi, gfx);
|
||||
|
||||
if (!freerdp_settings_get_bool(settings, FreeRDP_SoftwareGdi))
|
||||
{
|
||||
gfx->UpdateSurfaces = xf_UpdateSurfaces;
|
||||
gfx->CreateSurface = xf_CreateSurface;
|
||||
gfx->DeleteSurface = xf_DeleteSurface;
|
||||
}
|
||||
|
||||
gfx->UpdateWindowFromSurface = xf_UpdateWindowFromSurface;
|
||||
gfx->UnmapWindowForSurface = xf_UnmapWindowForSurface;
|
||||
}
|
||||
|
||||
void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx)
|
||||
{
|
||||
rdpGdi* gdi = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
gdi = xfc->common.context.gdi;
|
||||
gdi_graphics_pipeline_uninit(gdi, gfx);
|
||||
}
|
||||
45
third_party/FreeRDP/client/X11/xf_gfx.h
vendored
Normal file
45
third_party/FreeRDP/client/X11/xf_gfx.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Graphics Pipeline
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2016 Thincast Technologies GmbH
|
||||
* Copyright 2016 Armin Novak <armin.novak@thincast.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_X11_GFX_H
|
||||
#define FREERDP_CLIENT_X11_GFX_H
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
#include <freerdp/gdi/gfx.h>
|
||||
|
||||
struct xf_gfx_surface
|
||||
{
|
||||
gdiGfxSurface gdi;
|
||||
BYTE* stage;
|
||||
UINT32 stageScanline;
|
||||
XImage* image;
|
||||
};
|
||||
typedef struct xf_gfx_surface xfGfxSurface;
|
||||
|
||||
UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height);
|
||||
|
||||
void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx);
|
||||
|
||||
void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_GFX_H */
|
||||
532
third_party/FreeRDP/client/X11/xf_graphics.c
vendored
Normal file
532
third_party/FreeRDP/client/X11/xf_graphics.c
vendored
Normal file
@@ -0,0 +1,532 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Graphical Objects
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2016 Thincast Technologies GmbH
|
||||
* Copyright 2016 Armin Novak <armin.novak@thincast.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 <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#ifdef WITH_XCURSOR
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
#endif
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/codec/bitmap.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
|
||||
#include "xf_graphics.h"
|
||||
#include "xf_event.h"
|
||||
#include "xf_utils.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("x11")
|
||||
|
||||
static BOOL xf_Pointer_Set(rdpContext* context, rdpPointer* pointer);
|
||||
|
||||
BOOL xf_decode_color(xfContext* xfc, const UINT32 srcColor, XColor* color)
|
||||
{
|
||||
UINT32 SrcFormat = 0;
|
||||
BYTE r = 0;
|
||||
BYTE g = 0;
|
||||
BYTE b = 0;
|
||||
BYTE a = 0;
|
||||
|
||||
if (!xfc || !color)
|
||||
return FALSE;
|
||||
|
||||
rdpGdi* gdi = xfc->common.context.gdi;
|
||||
|
||||
if (!gdi)
|
||||
return FALSE;
|
||||
|
||||
rdpSettings* settings = xfc->common.context.settings;
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
switch (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth))
|
||||
{
|
||||
case 32:
|
||||
case 24:
|
||||
SrcFormat = PIXEL_FORMAT_BGR24;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
SrcFormat = PIXEL_FORMAT_RGB16;
|
||||
break;
|
||||
|
||||
case 15:
|
||||
SrcFormat = PIXEL_FORMAT_RGB15;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
SrcFormat = PIXEL_FORMAT_RGB8;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FreeRDPSplitColor(srcColor, SrcFormat, &r, &g, &b, &a, &gdi->palette);
|
||||
color->blue = (unsigned short)(b << 8);
|
||||
color->green = (unsigned short)(g << 8);
|
||||
color->red = (unsigned short)(r << 8);
|
||||
color->flags = DoRed | DoGreen | DoBlue;
|
||||
|
||||
return (XAllocColor(xfc->display, xfc->colormap, color) != 0);
|
||||
}
|
||||
|
||||
static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, rdpPointer* pointer,
|
||||
Cursor* cursor)
|
||||
{
|
||||
#if defined(WITH_XCURSOR) && defined(WITH_XRENDER)
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
xfPointer* xpointer = (xfPointer*)pointer;
|
||||
XcursorImage ci = WINPR_C_ARRAY_INIT;
|
||||
int cursorIndex = -1;
|
||||
|
||||
if (!context || !pointer || !context->gdi)
|
||||
return FALSE;
|
||||
|
||||
rdpSettings* settings = xfc->common.context.settings;
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
const double dw = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
||||
const double xscale =
|
||||
(freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ? 1.0 * xfc->scaledWidth / dw
|
||||
: 1);
|
||||
const double dh = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
||||
const double yscale =
|
||||
(freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ? 1.0 * xfc->scaledHeight / dh
|
||||
: 1);
|
||||
const UINT32 xTargetSize = MAX(1, (UINT32)lround(1.0 * pointer->width * xscale));
|
||||
const UINT32 yTargetSize = MAX(1, (UINT32)lround(1.0 * pointer->height * yscale));
|
||||
|
||||
WLog_DBG(TAG, "scaled: %" PRId32 "x%" PRId32 ", desktop: %" PRIu32 "x%" PRIu32,
|
||||
xfc->scaledWidth, xfc->scaledHeight,
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
|
||||
for (UINT32 i = 0; i < xpointer->nCursors; i++)
|
||||
{
|
||||
if ((xpointer->cursorWidths[i] == xTargetSize) &&
|
||||
(xpointer->cursorHeights[i] == yTargetSize))
|
||||
{
|
||||
cursorIndex = WINPR_ASSERTING_INT_CAST(int, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (cursorIndex == -1)
|
||||
{
|
||||
UINT32 CursorFormat = 0;
|
||||
xf_lock_x11(xfc);
|
||||
|
||||
if (!xfc->invert)
|
||||
CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_ABGR32;
|
||||
else
|
||||
CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_ARGB32;
|
||||
|
||||
if (xpointer->nCursors == xpointer->mCursors)
|
||||
{
|
||||
void* tmp2 = nullptr;
|
||||
xpointer->mCursors = (xpointer->mCursors == 0 ? 1 : xpointer->mCursors * 2);
|
||||
|
||||
tmp2 = realloc(xpointer->cursorWidths, sizeof(UINT32) * xpointer->mCursors);
|
||||
if (!tmp2)
|
||||
{
|
||||
xf_unlock_x11(xfc);
|
||||
return FALSE;
|
||||
}
|
||||
xpointer->cursorWidths = tmp2;
|
||||
|
||||
tmp2 = realloc(xpointer->cursorHeights, sizeof(UINT32) * xpointer->mCursors);
|
||||
if (!tmp2)
|
||||
{
|
||||
xf_unlock_x11(xfc);
|
||||
return FALSE;
|
||||
}
|
||||
xpointer->cursorHeights = (UINT32*)tmp2;
|
||||
|
||||
tmp2 = realloc(xpointer->cursors, sizeof(Cursor) * xpointer->mCursors);
|
||||
if (!tmp2)
|
||||
{
|
||||
xf_unlock_x11(xfc);
|
||||
return FALSE;
|
||||
}
|
||||
xpointer->cursors = (Cursor*)tmp2;
|
||||
}
|
||||
|
||||
ci.version = XCURSOR_IMAGE_VERSION;
|
||||
ci.size = sizeof(ci);
|
||||
ci.width = xTargetSize;
|
||||
ci.height = yTargetSize;
|
||||
ci.xhot = (XcursorDim)lround(1.0 * pointer->xPos * xscale);
|
||||
ci.yhot = (XcursorDim)lround(1.0 * pointer->yPos * yscale);
|
||||
const size_t size = 1ull * ci.height * ci.width * FreeRDPGetBytesPerPixel(CursorFormat);
|
||||
|
||||
void* tmp = winpr_aligned_malloc(size, 16);
|
||||
if (!tmp)
|
||||
{
|
||||
xf_unlock_x11(xfc);
|
||||
return FALSE;
|
||||
}
|
||||
ci.pixels = (XcursorPixel*)tmp;
|
||||
|
||||
const double xs = fabs(fabs(xscale) - 1.0);
|
||||
const double ys = fabs(fabs(yscale) - 1.0);
|
||||
|
||||
WLog_DBG(TAG,
|
||||
"cursorIndex %" PRId32 " scaling pointer %" PRIu32 "x%" PRIu32 " --> %" PRIu32
|
||||
"x%" PRIu32 " [%lfx%lf]",
|
||||
cursorIndex, pointer->width, pointer->height, ci.width, ci.height, xscale, yscale);
|
||||
if ((xs > DBL_EPSILON) || (ys > DBL_EPSILON))
|
||||
{
|
||||
if (!freerdp_image_scale((BYTE*)ci.pixels, CursorFormat, 0, 0, 0, ci.width, ci.height,
|
||||
(BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0,
|
||||
pointer->width, pointer->height))
|
||||
{
|
||||
winpr_aligned_free(tmp);
|
||||
xf_unlock_x11(xfc);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ci.pixels = xpointer->cursorPixels;
|
||||
}
|
||||
|
||||
const size_t idx = xpointer->nCursors;
|
||||
xpointer->cursorWidths[idx] = ci.width;
|
||||
xpointer->cursorHeights[idx] = ci.height;
|
||||
xpointer->cursors[idx] = XcursorImageLoadCursor(xfc->display, &ci);
|
||||
cursorIndex = WINPR_ASSERTING_INT_CAST(int, idx);
|
||||
xpointer->nCursors += 1;
|
||||
|
||||
winpr_aligned_free(tmp);
|
||||
|
||||
xf_unlock_x11(xfc);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "using cached cursor %" PRId32, cursorIndex);
|
||||
}
|
||||
|
||||
cursor[0] = xpointer->cursors[cursorIndex];
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Pointer Class */
|
||||
static Window xf_Pointer_get_window(xfContext* xfc)
|
||||
{
|
||||
if (!xfc)
|
||||
{
|
||||
WLog_WARN(TAG, "xf_Pointer: Invalid context");
|
||||
return 0;
|
||||
}
|
||||
if (xfc->remote_app)
|
||||
{
|
||||
Window w = 0;
|
||||
xf_AppWindowsLock(xfc);
|
||||
if (!xfc->appWindow)
|
||||
WLog_WARN(TAG, "xf_Pointer: Invalid appWindow");
|
||||
else
|
||||
w = xfc->appWindow->handle;
|
||||
xf_AppWindowsUnlock(xfc);
|
||||
return w;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!xfc->window)
|
||||
{
|
||||
WLog_WARN(TAG, "xf_Pointer: Invalid window");
|
||||
return 0;
|
||||
}
|
||||
return xfc->window->handle;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL xf_pointer_update_scale(xfContext* xfc)
|
||||
{
|
||||
xfPointer* pointer = nullptr;
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
pointer = xfc->pointer;
|
||||
if (!pointer)
|
||||
return TRUE;
|
||||
|
||||
return xf_Pointer_Set(&xfc->common.context, &xfc->pointer->pointer);
|
||||
}
|
||||
|
||||
static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
#ifdef WITH_XCURSOR
|
||||
UINT32 CursorFormat = 0;
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
xfPointer* xpointer = (xfPointer*)pointer;
|
||||
|
||||
if (!context || !pointer || !context->gdi)
|
||||
goto fail;
|
||||
|
||||
if (!xfc->invert)
|
||||
CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_ABGR32;
|
||||
else
|
||||
CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_ARGB32;
|
||||
|
||||
xpointer->nCursors = 0;
|
||||
xpointer->mCursors = 0;
|
||||
|
||||
{
|
||||
const size_t size =
|
||||
1ull * pointer->height * pointer->width * FreeRDPGetBytesPerPixel(CursorFormat);
|
||||
|
||||
xpointer->cursorPixels = (XcursorPixel*)winpr_aligned_malloc(size, 16);
|
||||
if (!xpointer->cursorPixels)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!freerdp_image_copy_from_pointer_data(
|
||||
(BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0, pointer->width, pointer->height,
|
||||
pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData,
|
||||
pointer->lengthAndMask, pointer->xorBpp, &context->gdi->palette))
|
||||
goto fail;
|
||||
|
||||
#endif
|
||||
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
WLog_DBG(TAG, "%p", WINPR_CXX_COMPAT_CAST(const void*, rc ? pointer : nullptr));
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
WLog_DBG(TAG, "%p", WINPR_CXX_COMPAT_CAST(const void*, pointer));
|
||||
|
||||
#ifdef WITH_XCURSOR
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
xfPointer* xpointer = (xfPointer*)pointer;
|
||||
|
||||
xf_lock_x11(xfc);
|
||||
|
||||
winpr_aligned_free(xpointer->cursorPixels);
|
||||
free(xpointer->cursorWidths);
|
||||
free(xpointer->cursorHeights);
|
||||
|
||||
for (UINT32 i = 0; i < xpointer->nCursors; i++)
|
||||
{
|
||||
XFreeCursor(xfc->display, xpointer->cursors[i]);
|
||||
}
|
||||
|
||||
free(xpointer->cursors);
|
||||
xpointer->nCursors = 0;
|
||||
xpointer->mCursors = 0;
|
||||
|
||||
xf_unlock_x11(xfc);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOL xf_Pointer_Set(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
WLog_DBG(TAG, "%p", WINPR_CXX_COMPAT_CAST(const void*, pointer));
|
||||
#ifdef WITH_XCURSOR
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
Window handle = xf_Pointer_get_window(xfc);
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(pointer);
|
||||
|
||||
xfc->pointer = (xfPointer*)pointer;
|
||||
|
||||
/* in RemoteApp mode, window can be null if none has had focus */
|
||||
|
||||
if (handle)
|
||||
{
|
||||
if (!xf_Pointer_GetCursorForCurrentScale(context, pointer, &(xfc->pointer->cursor)))
|
||||
return FALSE;
|
||||
xf_lock_x11(xfc);
|
||||
XDefineCursor(xfc->display, handle, xfc->pointer->cursor);
|
||||
xf_unlock_x11(xfc);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_WARN(TAG, "handle=%lu", handle);
|
||||
}
|
||||
xfc->isCursorHidden = false;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL xf_Pointer_SetNull(rdpContext* context)
|
||||
{
|
||||
WLog_DBG(TAG, "called");
|
||||
#ifdef WITH_XCURSOR
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
static Cursor nullcursor = None;
|
||||
Window handle = xf_Pointer_get_window(xfc);
|
||||
xf_lock_x11(xfc);
|
||||
|
||||
if (nullcursor == None)
|
||||
{
|
||||
XcursorImage ci = WINPR_C_ARRAY_INIT;
|
||||
XcursorPixel xp = 0;
|
||||
|
||||
ci.version = XCURSOR_IMAGE_VERSION;
|
||||
ci.size = sizeof(ci);
|
||||
ci.width = ci.height = 1;
|
||||
ci.xhot = ci.yhot = 0;
|
||||
ci.pixels = &xp;
|
||||
nullcursor = XcursorImageLoadCursor(xfc->display, &ci);
|
||||
}
|
||||
|
||||
xfc->pointer = nullptr;
|
||||
|
||||
if ((handle) && (nullcursor != None))
|
||||
XDefineCursor(xfc->display, handle, nullcursor);
|
||||
|
||||
xf_unlock_x11(xfc);
|
||||
xfc->isCursorHidden = true;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL xf_Pointer_SetDefault(rdpContext* context)
|
||||
{
|
||||
WLog_DBG(TAG, "called");
|
||||
#ifdef WITH_XCURSOR
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
Window handle = xf_Pointer_get_window(xfc);
|
||||
xf_lock_x11(xfc);
|
||||
xfc->pointer = nullptr;
|
||||
|
||||
if (handle)
|
||||
XUndefineCursor(xfc->display, handle);
|
||||
|
||||
xf_unlock_x11(xfc);
|
||||
xfc->isCursorHidden = false;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
|
||||
{
|
||||
xfContext* xfc = (xfContext*)context;
|
||||
XWindowAttributes current = WINPR_C_ARRAY_INIT;
|
||||
XSetWindowAttributes tmp = WINPR_C_ARRAY_INIT;
|
||||
BOOL ret = FALSE;
|
||||
Status rc = 0;
|
||||
Window handle = xf_Pointer_get_window(xfc);
|
||||
|
||||
if (!handle)
|
||||
{
|
||||
WLog_WARN(TAG, "focus %d, handle%lu", xfc->focused, handle);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "%" PRIu32 "x%" PRIu32, x, y);
|
||||
if (!xfc->focused)
|
||||
return TRUE;
|
||||
|
||||
xf_adjust_coordinates_to_screen(xfc, &x, &y);
|
||||
|
||||
xf_lock_x11(xfc);
|
||||
|
||||
rc = XGetWindowAttributes(xfc->display, handle, ¤t);
|
||||
if (rc == 0)
|
||||
{
|
||||
WLog_WARN(TAG, "XGetWindowAttributes==%d", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp.event_mask = (current.your_event_mask & ~(PointerMotionMask));
|
||||
|
||||
rc = LogDynAndXChangeWindowAttributes(xfc->log, xfc->display, handle, CWEventMask, &tmp);
|
||||
if (rc == 0)
|
||||
goto out;
|
||||
|
||||
rc = XWarpPointer(xfc->display, handle, handle, 0, 0, 0, 0, WINPR_ASSERTING_INT_CAST(int, x),
|
||||
WINPR_ASSERTING_INT_CAST(int, y));
|
||||
if (rc == 0)
|
||||
WLog_WARN(TAG, "XWarpPointer==%d", rc);
|
||||
tmp.event_mask = current.your_event_mask;
|
||||
LogDynAndXChangeWindowAttributes(xfc->log, xfc->display, handle, CWEventMask, &tmp);
|
||||
ret = TRUE;
|
||||
out:
|
||||
xf_unlock_x11(xfc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Graphics Module */
|
||||
BOOL xf_register_pointer(rdpGraphics* graphics)
|
||||
{
|
||||
rdpPointer pointer = WINPR_C_ARRAY_INIT;
|
||||
|
||||
pointer.size = sizeof(xfPointer);
|
||||
pointer.New = xf_Pointer_New;
|
||||
pointer.Free = xf_Pointer_Free;
|
||||
pointer.Set = xf_Pointer_Set;
|
||||
pointer.SetNull = xf_Pointer_SetNull;
|
||||
pointer.SetDefault = xf_Pointer_SetDefault;
|
||||
pointer.SetPosition = xf_Pointer_SetPosition;
|
||||
graphics_register_pointer(graphics, &pointer);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT32 xf_get_local_color_format(xfContext* xfc, BOOL aligned)
|
||||
{
|
||||
UINT32 DstFormat = 0;
|
||||
BOOL invert = FALSE;
|
||||
|
||||
if (!xfc)
|
||||
return 0;
|
||||
|
||||
invert = xfc->invert;
|
||||
|
||||
WINPR_ASSERT(xfc->depth != 0);
|
||||
if (xfc->depth == 32)
|
||||
DstFormat = (!invert) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_BGRA32;
|
||||
else if (xfc->depth == 30)
|
||||
DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32_DEPTH30 : PIXEL_FORMAT_BGRX32_DEPTH30;
|
||||
else if (xfc->depth == 24)
|
||||
{
|
||||
if (aligned)
|
||||
DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32 : PIXEL_FORMAT_BGRX32;
|
||||
else
|
||||
DstFormat = (!invert) ? PIXEL_FORMAT_RGB24 : PIXEL_FORMAT_BGR24;
|
||||
}
|
||||
else if (xfc->depth == 16)
|
||||
DstFormat = PIXEL_FORMAT_RGB16;
|
||||
else if (xfc->depth == 15)
|
||||
DstFormat = PIXEL_FORMAT_RGB15;
|
||||
else
|
||||
DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32 : PIXEL_FORMAT_BGRX32;
|
||||
|
||||
return DstFormat;
|
||||
}
|
||||
33
third_party/FreeRDP/client/X11/xf_graphics.h
vendored
Normal file
33
third_party/FreeRDP/client/X11/xf_graphics.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Graphical Objects
|
||||
*
|
||||
* Copyright 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_X11_GRAPHICS_H
|
||||
#define FREERDP_CLIENT_X11_GRAPHICS_H
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
BOOL xf_register_pointer(rdpGraphics* graphics);
|
||||
|
||||
BOOL xf_decode_color(xfContext* xfc, UINT32 srcColor, XColor* color);
|
||||
UINT32 xf_get_local_color_format(xfContext* xfc, BOOL aligned);
|
||||
|
||||
BOOL xf_pointer_update_scale(xfContext* xfc);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_GRAPHICS_H */
|
||||
920
third_party/FreeRDP/client/X11/xf_input.c
vendored
Normal file
920
third_party/FreeRDP/client/X11/xf_input.c
vendored
Normal file
@@ -0,0 +1,920 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Input
|
||||
*
|
||||
* Copyright 2013 Corey Clayton <can.of.tuna@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 <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#ifdef WITH_XCURSOR
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XI
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "xf_event.h"
|
||||
#include "xf_input.h"
|
||||
#include "xf_utils.h"
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("x11")
|
||||
|
||||
#ifdef WITH_XI
|
||||
|
||||
#define PAN_THRESHOLD 50
|
||||
#define ZOOM_THRESHOLD 10
|
||||
|
||||
#define MIN_FINGER_DIST 5
|
||||
|
||||
static int xf_input_event(xfContext* xfc, WINPR_ATTR_UNUSED const XEvent* xevent,
|
||||
XIDeviceEvent* event, int evtype);
|
||||
|
||||
#ifdef DEBUG_XINPUT
|
||||
static const char* xf_input_get_class_string(int class)
|
||||
{
|
||||
if (class == XIKeyClass)
|
||||
return "XIKeyClass";
|
||||
else if (class == XIButtonClass)
|
||||
return "XIButtonClass";
|
||||
else if (class == XIValuatorClass)
|
||||
return "XIValuatorClass";
|
||||
else if (class == XIScrollClass)
|
||||
return "XIScrollClass";
|
||||
else if (class == XITouchClass)
|
||||
return "XITouchClass";
|
||||
|
||||
return "XIUnknownClass";
|
||||
}
|
||||
#endif
|
||||
|
||||
static BOOL register_input_events(xfContext* xfc, Window window)
|
||||
{
|
||||
#define MAX_NR_MASKS 64
|
||||
int ndevices = 0;
|
||||
int nmasks = 0;
|
||||
XIEventMask evmasks[MAX_NR_MASKS] = WINPR_C_ARRAY_INIT;
|
||||
BYTE masks[MAX_NR_MASKS][XIMaskLen(XI_LASTEVENT)] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
rdpSettings* settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
XIDeviceInfo* info = XIQueryDevice(xfc->display, XIAllDevices, &ndevices);
|
||||
|
||||
for (int i = 0; i < MIN(ndevices, MAX_NR_MASKS); i++)
|
||||
{
|
||||
BOOL used = FALSE;
|
||||
XIDeviceInfo* dev = &info[i];
|
||||
|
||||
evmasks[nmasks].mask = masks[nmasks];
|
||||
evmasks[nmasks].mask_len = sizeof(masks[0]);
|
||||
evmasks[nmasks].deviceid = dev->deviceid;
|
||||
|
||||
/* Ignore virtual core pointer */
|
||||
if (strcmp(dev->name, "Virtual core pointer") == 0)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < dev->num_classes; j++)
|
||||
{
|
||||
const XIAnyClassInfo* c_class = dev->classes[j];
|
||||
|
||||
switch (c_class->type)
|
||||
{
|
||||
case XITouchClass:
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_MultiTouchInput))
|
||||
{
|
||||
const XITouchClassInfo* t = (const XITouchClassInfo*)c_class;
|
||||
if (t->mode == XIDirectTouch)
|
||||
{
|
||||
WLog_DBG(
|
||||
TAG,
|
||||
"%s %s touch device (id: %d, mode: %d), supporting %d touches.",
|
||||
dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent",
|
||||
dev->deviceid, t->mode, t->num_touches);
|
||||
XISetMask(masks[nmasks], XI_TouchBegin);
|
||||
XISetMask(masks[nmasks], XI_TouchUpdate);
|
||||
XISetMask(masks[nmasks], XI_TouchEnd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XIButtonClass:
|
||||
{
|
||||
const XIButtonClassInfo* t = (const XIButtonClassInfo*)c_class;
|
||||
WLog_DBG(TAG, "%s button device (id: %d, mode: %d)", dev->name, dev->deviceid,
|
||||
t->num_buttons);
|
||||
XISetMask(masks[nmasks], XI_ButtonPress);
|
||||
XISetMask(masks[nmasks], XI_ButtonRelease);
|
||||
XISetMask(masks[nmasks], XI_Motion);
|
||||
used = TRUE;
|
||||
break;
|
||||
}
|
||||
case XIValuatorClass:
|
||||
{
|
||||
static wLog* log = nullptr;
|
||||
if (!log)
|
||||
log = WLog_Get(TAG);
|
||||
|
||||
const XIValuatorClassInfo* t = (const XIValuatorClassInfo*)c_class;
|
||||
char* name =
|
||||
t->label ? Safe_XGetAtomName(log, xfc->display, t->label) : nullptr;
|
||||
|
||||
WLog_Print(log, WLOG_DEBUG,
|
||||
"%s device (id: %d) valuator %d label %s range %f - %f", dev->name,
|
||||
dev->deviceid, t->number, name ? name : "None", t->min, t->max);
|
||||
free(name);
|
||||
|
||||
if (t->number == 2)
|
||||
{
|
||||
double max_pressure = t->max;
|
||||
|
||||
char devName[200] = WINPR_C_ARRAY_INIT;
|
||||
strncpy(devName, dev->name, ARRAYSIZE(devName) - 1);
|
||||
CharLowerBuffA(devName, ARRAYSIZE(devName));
|
||||
|
||||
if (strstr(devName, "eraser") != nullptr)
|
||||
{
|
||||
if (freerdp_client_handle_pen(&xfc->common,
|
||||
FREERDP_PEN_REGISTER |
|
||||
FREERDP_PEN_IS_INVERTED |
|
||||
FREERDP_PEN_HAS_PRESSURE,
|
||||
dev->deviceid, max_pressure))
|
||||
WLog_DBG(TAG, "registered eraser");
|
||||
}
|
||||
else if (strstr(devName, "stylus") != nullptr ||
|
||||
strstr(devName, "pen") != nullptr)
|
||||
{
|
||||
if (freerdp_client_handle_pen(
|
||||
&xfc->common, FREERDP_PEN_REGISTER | FREERDP_PEN_HAS_PRESSURE,
|
||||
dev->deviceid, max_pressure))
|
||||
WLog_DBG(TAG, "registered pen");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (used)
|
||||
nmasks++;
|
||||
}
|
||||
|
||||
XIFreeDeviceInfo(info);
|
||||
|
||||
if (nmasks > 0)
|
||||
{
|
||||
Status xstatus = XISelectEvents(xfc->display, window, evmasks, nmasks);
|
||||
if (xstatus != 0)
|
||||
WLog_WARN(TAG, "XISelectEvents returned %d", xstatus);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL register_raw_events(xfContext* xfc, Window window)
|
||||
{
|
||||
XIEventMask mask;
|
||||
unsigned char mask_bytes[XIMaskLen(XI_LASTEVENT)] = WINPR_C_ARRAY_INIT;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_MouseUseRelativeMove))
|
||||
{
|
||||
XISetMask(mask_bytes, XI_RawMotion);
|
||||
XISetMask(mask_bytes, XI_RawButtonPress);
|
||||
XISetMask(mask_bytes, XI_RawButtonRelease);
|
||||
|
||||
mask.deviceid = XIAllMasterDevices;
|
||||
mask.mask_len = sizeof(mask_bytes);
|
||||
mask.mask = mask_bytes;
|
||||
|
||||
XISelectEvents(xfc->display, window, &mask, 1);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL register_device_events(xfContext* xfc, Window window)
|
||||
{
|
||||
XIEventMask mask = WINPR_C_ARRAY_INIT;
|
||||
unsigned char mask_bytes[XIMaskLen(XI_LASTEVENT)] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
XISetMask(mask_bytes, XI_DeviceChanged);
|
||||
XISetMask(mask_bytes, XI_HierarchyChanged);
|
||||
|
||||
mask.deviceid = XIAllDevices;
|
||||
mask.mask_len = sizeof(mask_bytes);
|
||||
mask.mask = mask_bytes;
|
||||
|
||||
XISelectEvents(xfc->display, window, &mask, 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int xf_input_init(xfContext* xfc, Window window)
|
||||
{
|
||||
int major = XI_2_Major;
|
||||
int minor = XI_2_Minor;
|
||||
int opcode = 0;
|
||||
int event = 0;
|
||||
int error = 0;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
xfc->firstDist = -1.0;
|
||||
xfc->z_vector = 0;
|
||||
xfc->px_vector = 0;
|
||||
xfc->py_vector = 0;
|
||||
xfc->active_contacts = 0;
|
||||
|
||||
if (!XQueryExtension(xfc->display, "XInputExtension", &opcode, &event, &error))
|
||||
{
|
||||
WLog_WARN(TAG, "XInput extension not available.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
xfc->XInputOpcode = opcode;
|
||||
XIQueryVersion(xfc->display, &major, &minor);
|
||||
|
||||
if ((major < XI_2_Major) || ((major == XI_2_Major) && (minor < 2)))
|
||||
{
|
||||
WLog_WARN(TAG, "Server does not support XI 2.2");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int scr = DefaultScreen(xfc->display);
|
||||
Window root = RootWindow(xfc->display, scr);
|
||||
|
||||
if (!register_raw_events(xfc, root))
|
||||
return -1;
|
||||
if (!register_input_events(xfc, window))
|
||||
return -1;
|
||||
if (!register_device_events(xfc, window))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL xf_input_is_duplicate(xfContext* xfc, const XGenericEventCookie* cookie)
|
||||
{
|
||||
const XIDeviceEvent* event = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(cookie);
|
||||
|
||||
event = cookie->data;
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
return ((xfc->lastEvent.time == event->time) && (xfc->lastEvType == cookie->evtype) &&
|
||||
(xfc->lastEvent.detail == event->detail) &&
|
||||
(fabs(xfc->lastEvent.event_x - event->event_x) < DBL_EPSILON) &&
|
||||
(fabs(xfc->lastEvent.event_y - event->event_y) < DBL_EPSILON));
|
||||
}
|
||||
|
||||
static void xf_input_save_last_event(xfContext* xfc, const XGenericEventCookie* cookie)
|
||||
{
|
||||
const XIDeviceEvent* event = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(cookie);
|
||||
|
||||
event = cookie->data;
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
xfc->lastEvType = cookie->evtype;
|
||||
xfc->lastEvent.time = event->time;
|
||||
xfc->lastEvent.detail = event->detail;
|
||||
xfc->lastEvent.event_x = event->event_x;
|
||||
xfc->lastEvent.event_y = event->event_y;
|
||||
}
|
||||
|
||||
static void xf_input_detect_pan(xfContext* xfc)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
rdpContext* ctx = &xfc->common.context;
|
||||
WINPR_ASSERT(ctx);
|
||||
|
||||
if (xfc->active_contacts != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const double dx[] = { xfc->contacts[0].pos_x - xfc->contacts[0].last_x,
|
||||
xfc->contacts[1].pos_x - xfc->contacts[1].last_x };
|
||||
const double dy[] = { xfc->contacts[0].pos_y - xfc->contacts[0].last_y,
|
||||
xfc->contacts[1].pos_y - xfc->contacts[1].last_y };
|
||||
const double px = fabs(dx[0]) < fabs(dx[1]) ? dx[0] : dx[1];
|
||||
const double py = fabs(dy[0]) < fabs(dy[1]) ? dy[0] : dy[1];
|
||||
xfc->px_vector += px;
|
||||
xfc->py_vector += py;
|
||||
const double dist_x = fabs(xfc->contacts[0].pos_x - xfc->contacts[1].pos_x);
|
||||
const double dist_y = fabs(xfc->contacts[0].pos_y - xfc->contacts[1].pos_y);
|
||||
|
||||
if (dist_y > MIN_FINGER_DIST)
|
||||
{
|
||||
if (xfc->px_vector > PAN_THRESHOLD)
|
||||
{
|
||||
{
|
||||
PanningChangeEventArgs e;
|
||||
EventArgsInit(&e, "xfreerdp");
|
||||
e.dx = 5;
|
||||
e.dy = 0;
|
||||
PubSub_OnPanningChange(ctx->pubSub, xfc, &e);
|
||||
}
|
||||
xfc->px_vector = 0;
|
||||
xfc->py_vector = 0;
|
||||
xfc->z_vector = 0;
|
||||
}
|
||||
else if (xfc->px_vector < -PAN_THRESHOLD)
|
||||
{
|
||||
{
|
||||
PanningChangeEventArgs e;
|
||||
EventArgsInit(&e, "xfreerdp");
|
||||
e.dx = -5;
|
||||
e.dy = 0;
|
||||
PubSub_OnPanningChange(ctx->pubSub, xfc, &e);
|
||||
}
|
||||
xfc->px_vector = 0;
|
||||
xfc->py_vector = 0;
|
||||
xfc->z_vector = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dist_x > MIN_FINGER_DIST)
|
||||
{
|
||||
if (xfc->py_vector > PAN_THRESHOLD)
|
||||
{
|
||||
{
|
||||
PanningChangeEventArgs e;
|
||||
EventArgsInit(&e, "xfreerdp");
|
||||
e.dx = 0;
|
||||
e.dy = 5;
|
||||
PubSub_OnPanningChange(ctx->pubSub, xfc, &e);
|
||||
}
|
||||
xfc->py_vector = 0;
|
||||
xfc->px_vector = 0;
|
||||
xfc->z_vector = 0;
|
||||
}
|
||||
else if (xfc->py_vector < -PAN_THRESHOLD)
|
||||
{
|
||||
{
|
||||
PanningChangeEventArgs e;
|
||||
EventArgsInit(&e, "xfreerdp");
|
||||
e.dx = 0;
|
||||
e.dy = -5;
|
||||
PubSub_OnPanningChange(ctx->pubSub, xfc, &e);
|
||||
}
|
||||
xfc->py_vector = 0;
|
||||
xfc->px_vector = 0;
|
||||
xfc->z_vector = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_input_detect_pinch(xfContext* xfc)
|
||||
{
|
||||
ZoomingChangeEventArgs e = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
rdpContext* ctx = &xfc->common.context;
|
||||
WINPR_ASSERT(ctx);
|
||||
|
||||
if (xfc->active_contacts != 2)
|
||||
{
|
||||
xfc->firstDist = -1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* first calculate the distance */
|
||||
const double dist = sqrt(pow(xfc->contacts[1].pos_x - xfc->contacts[0].last_x, 2.0) +
|
||||
pow(xfc->contacts[1].pos_y - xfc->contacts[0].last_y, 2.0));
|
||||
|
||||
/* if this is the first 2pt touch */
|
||||
if (xfc->firstDist <= 0)
|
||||
{
|
||||
xfc->firstDist = dist;
|
||||
xfc->lastDist = xfc->firstDist;
|
||||
xfc->z_vector = 0;
|
||||
xfc->px_vector = 0;
|
||||
xfc->py_vector = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double delta = xfc->lastDist - dist;
|
||||
|
||||
if (delta > 1.0)
|
||||
delta = 1.0;
|
||||
|
||||
if (delta < -1.0)
|
||||
delta = -1.0;
|
||||
|
||||
/* compare the current distance to the first one */
|
||||
xfc->z_vector += delta;
|
||||
xfc->lastDist = dist;
|
||||
|
||||
if (xfc->z_vector > ZOOM_THRESHOLD)
|
||||
{
|
||||
EventArgsInit(&e, "xfreerdp");
|
||||
e.dx = e.dy = -10;
|
||||
PubSub_OnZoomingChange(ctx->pubSub, xfc, &e);
|
||||
xfc->z_vector = 0;
|
||||
xfc->px_vector = 0;
|
||||
xfc->py_vector = 0;
|
||||
}
|
||||
|
||||
if (xfc->z_vector < -ZOOM_THRESHOLD)
|
||||
{
|
||||
EventArgsInit(&e, "xfreerdp");
|
||||
e.dx = e.dy = 10;
|
||||
PubSub_OnZoomingChange(ctx->pubSub, xfc, &e);
|
||||
xfc->z_vector = 0;
|
||||
xfc->px_vector = 0;
|
||||
xfc->py_vector = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_input_touch_begin(xfContext* xfc, const XIDeviceEvent* event)
|
||||
{
|
||||
WINPR_UNUSED(xfc);
|
||||
for (int i = 0; i < MAX_CONTACTS; i++)
|
||||
{
|
||||
if (xfc->contacts[i].id == 0)
|
||||
{
|
||||
xfc->contacts[i].id = event->detail;
|
||||
xfc->contacts[i].count = 1;
|
||||
xfc->contacts[i].pos_x = event->event_x;
|
||||
xfc->contacts[i].pos_y = event->event_y;
|
||||
xfc->active_contacts++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_input_touch_update(xfContext* xfc, const XIDeviceEvent* event)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
for (int i = 0; i < MAX_CONTACTS; i++)
|
||||
{
|
||||
if (xfc->contacts[i].id == event->detail)
|
||||
{
|
||||
xfc->contacts[i].count++;
|
||||
xfc->contacts[i].last_x = xfc->contacts[i].pos_x;
|
||||
xfc->contacts[i].last_y = xfc->contacts[i].pos_y;
|
||||
xfc->contacts[i].pos_x = event->event_x;
|
||||
xfc->contacts[i].pos_y = event->event_y;
|
||||
xf_input_detect_pinch(xfc);
|
||||
xf_input_detect_pan(xfc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_input_touch_end(xfContext* xfc, const XIDeviceEvent* event)
|
||||
{
|
||||
WINPR_UNUSED(xfc);
|
||||
for (int i = 0; i < MAX_CONTACTS; i++)
|
||||
{
|
||||
if (xfc->contacts[i].id == event->detail)
|
||||
{
|
||||
xfc->contacts[i].id = 0;
|
||||
xfc->contacts[i].count = 0;
|
||||
xfc->active_contacts--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int xf_input_handle_event_local(xfContext* xfc, const XEvent* event)
|
||||
{
|
||||
union
|
||||
{
|
||||
const XGenericEventCookie* cc;
|
||||
XGenericEventCookie* vc;
|
||||
} cookie;
|
||||
cookie.cc = &event->xcookie;
|
||||
XGetEventData(xfc->display, cookie.vc);
|
||||
|
||||
if ((cookie.cc->type == GenericEvent) && (cookie.cc->extension == xfc->XInputOpcode))
|
||||
{
|
||||
switch (cookie.cc->evtype)
|
||||
{
|
||||
case XI_TouchBegin:
|
||||
if (xf_input_is_duplicate(xfc, cookie.cc) == FALSE)
|
||||
xf_input_touch_begin(xfc, cookie.cc->data);
|
||||
|
||||
xf_input_save_last_event(xfc, cookie.cc);
|
||||
break;
|
||||
|
||||
case XI_TouchUpdate:
|
||||
if (xf_input_is_duplicate(xfc, cookie.cc) == FALSE)
|
||||
xf_input_touch_update(xfc, cookie.cc->data);
|
||||
|
||||
xf_input_save_last_event(xfc, cookie.cc);
|
||||
break;
|
||||
|
||||
case XI_TouchEnd:
|
||||
if (xf_input_is_duplicate(xfc, cookie.cc) == FALSE)
|
||||
xf_input_touch_end(xfc, cookie.cc->data);
|
||||
|
||||
xf_input_save_last_event(xfc, cookie.cc);
|
||||
break;
|
||||
|
||||
default:
|
||||
xf_input_event(xfc, event, cookie.cc->data, cookie.cc->evtype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XFreeEventData(xfc->display, cookie.vc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xf_input_hide_cursor(xfContext* xfc)
|
||||
{
|
||||
#ifdef WITH_XCURSOR
|
||||
|
||||
if (!xfc->cursorHidden)
|
||||
{
|
||||
XcursorImage ci = WINPR_C_ARRAY_INIT;
|
||||
XcursorPixel xp = 0;
|
||||
static Cursor nullcursor = None;
|
||||
xf_lock_x11(xfc);
|
||||
ci.version = XCURSOR_IMAGE_VERSION;
|
||||
ci.size = sizeof(ci);
|
||||
ci.width = ci.height = 1;
|
||||
ci.xhot = ci.yhot = 0;
|
||||
ci.pixels = &xp;
|
||||
nullcursor = XcursorImageLoadCursor(xfc->display, &ci);
|
||||
|
||||
if ((xfc->window) && (nullcursor != None))
|
||||
XDefineCursor(xfc->display, xfc->window->handle, nullcursor);
|
||||
|
||||
xfc->cursorHidden = TRUE;
|
||||
xf_unlock_x11(xfc);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void xf_input_show_cursor(xfContext* xfc)
|
||||
{
|
||||
#ifdef WITH_XCURSOR
|
||||
xf_lock_x11(xfc);
|
||||
|
||||
if (xfc->cursorHidden)
|
||||
{
|
||||
if (xfc->window)
|
||||
{
|
||||
if (!xfc->pointer)
|
||||
XUndefineCursor(xfc->display, xfc->window->handle);
|
||||
else
|
||||
XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor);
|
||||
}
|
||||
|
||||
xfc->cursorHidden = FALSE;
|
||||
}
|
||||
|
||||
xf_unlock_x11(xfc);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int touchId = 0;
|
||||
RdpeiClientContext* rdpei = xfc->common.rdpei;
|
||||
|
||||
if (!rdpei)
|
||||
return 0;
|
||||
|
||||
xf_input_hide_cursor(xfc);
|
||||
touchId = event->detail;
|
||||
x = (int)event->event_x;
|
||||
y = (int)event->event_y;
|
||||
xf_event_adjust_coordinates(xfc, &x, &y);
|
||||
|
||||
switch (evtype)
|
||||
{
|
||||
case XI_TouchBegin:
|
||||
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_DOWN, touchId, 0, x, y);
|
||||
break;
|
||||
case XI_TouchUpdate:
|
||||
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_MOTION, touchId, 0, x, y);
|
||||
break;
|
||||
case XI_TouchEnd:
|
||||
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_UP, touchId, 0, x, y);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL xf_input_pen_remote(xfContext* xfc, XIDeviceEvent* event, int evtype, int deviceid)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
RdpeiClientContext* rdpei = xfc->common.rdpei;
|
||||
|
||||
if (!rdpei)
|
||||
return FALSE;
|
||||
|
||||
xf_input_hide_cursor(xfc);
|
||||
x = (int)event->event_x;
|
||||
y = (int)event->event_y;
|
||||
xf_event_adjust_coordinates(xfc, &x, &y);
|
||||
|
||||
double pressure = 0.0;
|
||||
double* val = event->valuators.values;
|
||||
for (int i = 0; i < MIN(event->valuators.mask_len * 8, 3); i++)
|
||||
{
|
||||
if (XIMaskIsSet(event->valuators.mask, i))
|
||||
{
|
||||
double value = *val++;
|
||||
if (i == 2)
|
||||
pressure = value;
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 flags = FREERDP_PEN_HAS_PRESSURE;
|
||||
if ((evtype == XI_ButtonPress) || (evtype == XI_ButtonRelease))
|
||||
{
|
||||
WLog_DBG(TAG, "pen button %d", event->detail);
|
||||
switch (event->detail)
|
||||
{
|
||||
case 1:
|
||||
break;
|
||||
case 3:
|
||||
flags |= FREERDP_PEN_BARREL_PRESSED;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (evtype)
|
||||
{
|
||||
case XI_ButtonPress:
|
||||
flags |= FREERDP_PEN_PRESS;
|
||||
if (!freerdp_client_handle_pen(&xfc->common, flags, deviceid, x, y, pressure))
|
||||
return FALSE;
|
||||
break;
|
||||
case XI_Motion:
|
||||
flags |= FREERDP_PEN_MOTION;
|
||||
if (!freerdp_client_handle_pen(&xfc->common, flags, deviceid, x, y, pressure))
|
||||
return FALSE;
|
||||
break;
|
||||
case XI_ButtonRelease:
|
||||
flags |= FREERDP_PEN_RELEASE;
|
||||
if (!freerdp_client_handle_pen(&xfc->common, flags, deviceid, x, y, pressure))
|
||||
return FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int xf_input_pens_unhover(xfContext* xfc)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
freerdp_client_pen_cancel_all(&xfc->common);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool xf_use_rel_mouse(xfContext* xfc)
|
||||
{
|
||||
if (!freerdp_client_use_relative_mouse_events(&xfc->common))
|
||||
return false;
|
||||
if (!xfc->isCursorHidden)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int xf_input_event(xfContext* xfc, WINPR_ATTR_UNUSED const XEvent* xevent, XIDeviceEvent* event,
|
||||
int evtype)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(xevent);
|
||||
WINPR_ASSERT(event);
|
||||
|
||||
xfWindow* window = xfc->window;
|
||||
if (window)
|
||||
{
|
||||
if (xf_floatbar_is_locked(window->floatbar))
|
||||
return 0;
|
||||
}
|
||||
|
||||
xf_input_show_cursor(xfc);
|
||||
|
||||
switch (evtype)
|
||||
{
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
xfc->xi_event = !xfc->common.mouse_grabbed || !xf_use_rel_mouse(xfc);
|
||||
|
||||
if (xfc->xi_event)
|
||||
{
|
||||
if (!xfc_is_floatbar_window(xfc, event->event) || (evtype != XI_ButtonPress))
|
||||
{
|
||||
xf_generic_ButtonEvent(xfc, (int)event->event_x, (int)event->event_y,
|
||||
event->detail, event->event, xfc->remote_app,
|
||||
evtype == XI_ButtonPress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case XI_Motion:
|
||||
xfc->xi_event = !xfc->common.mouse_grabbed || !xf_use_rel_mouse(xfc);
|
||||
|
||||
if (xfc->xi_event)
|
||||
{
|
||||
xf_generic_MotionNotify(xfc, (int)event->event_x, (int)event->event_y, event->event,
|
||||
xfc->remote_app);
|
||||
}
|
||||
break;
|
||||
case XI_RawButtonPress:
|
||||
case XI_RawButtonRelease:
|
||||
xfc->xi_rawevent = xfc->common.mouse_grabbed && xf_use_rel_mouse(xfc);
|
||||
|
||||
if (xfc->xi_rawevent)
|
||||
{
|
||||
const XIRawEvent* ev = (const XIRawEvent*)event;
|
||||
xf_generic_RawButtonEvent(xfc, ev->detail, xfc->remote_app,
|
||||
evtype == XI_RawButtonPress);
|
||||
}
|
||||
break;
|
||||
case XI_RawMotion:
|
||||
xfc->xi_rawevent = xfc->common.mouse_grabbed && xf_use_rel_mouse(xfc);
|
||||
|
||||
if (xfc->xi_rawevent)
|
||||
{
|
||||
const XIRawEvent* ev = (const XIRawEvent*)event;
|
||||
double x = 0.0;
|
||||
double y = 0.0;
|
||||
if (XIMaskIsSet(ev->valuators.mask, 0))
|
||||
x = ev->raw_values[0];
|
||||
if (XIMaskIsSet(ev->valuators.mask, 1))
|
||||
y = ev->raw_values[1];
|
||||
|
||||
xf_generic_RawMotionNotify(xfc, (int)x, (int)y, event->event, xfc->remote_app);
|
||||
}
|
||||
break;
|
||||
case XI_DeviceChanged:
|
||||
{
|
||||
const XIDeviceChangedEvent* ev = (const XIDeviceChangedEvent*)event;
|
||||
if (ev->reason != XIDeviceChange)
|
||||
break;
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* 1. Register only changed devices.
|
||||
* 2. Both `XIDeviceChangedEvent` and `XIHierarchyEvent` have no target
|
||||
* `Window` which is used to register xinput events. So assume
|
||||
* `xfc->window` created by `xf_CreateDesktopWindow` is the same
|
||||
* `Window` we registered.
|
||||
*/
|
||||
if (xfc->window)
|
||||
register_input_events(xfc, xfc->window->handle);
|
||||
}
|
||||
break;
|
||||
case XI_HierarchyChanged:
|
||||
if (xfc->window)
|
||||
register_input_events(xfc, xfc->window->handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_WARN(TAG, "Unhandled event %d: Event was registered but is not handled!", evtype);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xf_input_handle_event_remote(xfContext* xfc, const XEvent* event)
|
||||
{
|
||||
union
|
||||
{
|
||||
const XGenericEventCookie* cc;
|
||||
XGenericEventCookie* vc;
|
||||
} cookie;
|
||||
cookie.cc = &event->xcookie;
|
||||
XGetEventData(xfc->display, cookie.vc);
|
||||
|
||||
if ((cookie.cc->type == GenericEvent) && (cookie.cc->extension == xfc->XInputOpcode))
|
||||
{
|
||||
switch (cookie.cc->evtype)
|
||||
{
|
||||
case XI_TouchBegin:
|
||||
xf_input_pens_unhover(xfc);
|
||||
/* fallthrough */
|
||||
WINPR_FALLTHROUGH
|
||||
case XI_TouchUpdate:
|
||||
case XI_TouchEnd:
|
||||
xf_input_touch_remote(xfc, cookie.cc->data, cookie.cc->evtype);
|
||||
break;
|
||||
case XI_ButtonPress:
|
||||
case XI_Motion:
|
||||
case XI_ButtonRelease:
|
||||
{
|
||||
WLog_DBG(TAG, "checking for pen");
|
||||
XIDeviceEvent* deviceEvent = (XIDeviceEvent*)cookie.cc->data;
|
||||
int deviceid = deviceEvent->deviceid;
|
||||
|
||||
if (freerdp_client_is_pen(&xfc->common, deviceid))
|
||||
{
|
||||
if (!xf_input_pen_remote(xfc, cookie.cc->data, cookie.cc->evtype, deviceid))
|
||||
{
|
||||
// XXX: don't show cursor
|
||||
xf_input_event(xfc, event, cookie.cc->data, cookie.cc->evtype);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* fallthrough */
|
||||
WINPR_FALLTHROUGH
|
||||
default:
|
||||
xf_input_pens_unhover(xfc);
|
||||
xf_input_event(xfc, event, cookie.cc->data, cookie.cc->evtype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XFreeEventData(xfc->display, cookie.vc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int xf_input_init(xfContext* xfc, Window window)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int xf_input_handle_event(xfContext* xfc, const XEvent* event)
|
||||
{
|
||||
#ifdef WITH_XI
|
||||
const rdpSettings* settings = nullptr;
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_MultiTouchInput))
|
||||
{
|
||||
return xf_input_handle_event_remote(xfc, event);
|
||||
}
|
||||
else if (freerdp_settings_get_bool(settings, FreeRDP_MultiTouchGestures))
|
||||
{
|
||||
return xf_input_handle_event_local(xfc, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
return xf_input_handle_event_local(xfc, event);
|
||||
}
|
||||
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
34
third_party/FreeRDP/client/X11/xf_input.h
vendored
Normal file
34
third_party/FreeRDP/client/X11/xf_input.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Input
|
||||
*
|
||||
* Copyright 2013 Corey Clayton <can.of.tuna@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_X11_INPUT_H
|
||||
#define FREERDP_CLIENT_X11_INPUT_H
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
#ifdef WITH_XI
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif
|
||||
|
||||
int xf_input_init(xfContext* xfc, Window window);
|
||||
int xf_input_handle_event(xfContext* xfc, const XEvent* event);
|
||||
bool xf_use_rel_mouse(xfContext* xfc);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_INPUT_H */
|
||||
1550
third_party/FreeRDP/client/X11/xf_keyboard.c
vendored
Normal file
1550
third_party/FreeRDP/client/X11/xf_keyboard.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
47
third_party/FreeRDP/client/X11/xf_keyboard.h
vendored
Normal file
47
third_party/FreeRDP/client/X11/xf_keyboard.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Keyboard Handling
|
||||
*
|
||||
* Copyright 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_X11_XF_KEYBOARD_H
|
||||
#define FREERDP_CLIENT_X11_XF_KEYBOARD_H
|
||||
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
BOOL xf_keyboard_init(xfContext* xfc);
|
||||
void xf_keyboard_free(xfContext* xfc);
|
||||
|
||||
BOOL xf_keyboard_action_script_init(xfContext* xfc);
|
||||
|
||||
void xf_keyboard_key_press(xfContext* xfc, const XKeyEvent* event, KeySym keysym);
|
||||
void xf_keyboard_key_release(xfContext* xfc, const XKeyEvent* event, KeySym keysym);
|
||||
|
||||
void xf_keyboard_release_all_keypress(xfContext* xfc);
|
||||
|
||||
void xf_keyboard_focus_in(xfContext* xfc);
|
||||
BOOL xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags);
|
||||
BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
|
||||
UINT32 imeConvMode);
|
||||
|
||||
BOOL xf_ungrab(xfContext* xfc);
|
||||
|
||||
void xf_button_map_init(xfContext* xfc);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_XF_KEYBOARD_H */
|
||||
672
third_party/FreeRDP/client/X11/xf_monitor.c
vendored
Normal file
672
third_party/FreeRDP/client/X11/xf_monitor.c
vendored
Normal file
@@ -0,0 +1,672 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Monitor Handling
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2017 David Fort <contact@hardening-consulting.com>
|
||||
* Copyright 2018 Kai Harms <kharms@rangee.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 <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#define TAG CLIENT_TAG("x11")
|
||||
|
||||
#ifdef WITH_XINERAMA
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XRANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/randr.h>
|
||||
|
||||
#if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105
|
||||
#define USABLE_XRANDR
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "xf_monitor.h"
|
||||
#include "xf_utils.h"
|
||||
|
||||
/* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071
|
||||
*/
|
||||
|
||||
int xf_list_monitors(xfContext* xfc)
|
||||
{
|
||||
WINPR_UNUSED(xfc);
|
||||
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int nmonitors = 0;
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
|
||||
if (!display)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to open X display");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(USABLE_XRANDR)
|
||||
|
||||
if (XRRQueryExtension(display, &major, &minor) &&
|
||||
(XRRQueryVersion(display, &major, &minor) == True) && (major * 100 + minor >= 105))
|
||||
{
|
||||
XRRMonitorInfo* monitors =
|
||||
XRRGetMonitors(display, DefaultRootWindow(display), 1, &nmonitors);
|
||||
|
||||
for (int i = 0; i < nmonitors; i++)
|
||||
{
|
||||
printf(" %s [%d] %dx%d\t+%d+%d\n", monitors[i].primary ? "*" : " ", i,
|
||||
monitors[i].width, monitors[i].height, monitors[i].x, monitors[i].y);
|
||||
}
|
||||
|
||||
XRRFreeMonitors(monitors);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef WITH_XINERAMA
|
||||
if (XineramaQueryExtension(display, &major, &minor))
|
||||
{
|
||||
if (XineramaIsActive(display))
|
||||
{
|
||||
XineramaScreenInfo* screen = XineramaQueryScreens(display, &nmonitors);
|
||||
|
||||
for (int i = 0; i < nmonitors; i++)
|
||||
{
|
||||
printf(" %s [%d] %hdx%hd\t+%hd+%hd\n", (i == 0) ? "*" : " ", i,
|
||||
screen[i].width, screen[i].height, screen[i].x_org, screen[i].y_org);
|
||||
}
|
||||
|
||||
XFree(screen);
|
||||
}
|
||||
}
|
||||
else
|
||||
#else
|
||||
{
|
||||
Screen* screen = ScreenOfDisplay(display, DefaultScreen(display));
|
||||
printf(" * [0] %dx%d\t+0+0\n", WidthOfScreen(screen), HeightOfScreen(screen));
|
||||
}
|
||||
|
||||
#endif
|
||||
LogDynAndXCloseDisplay(xfc->log, display);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL xf_is_monitor_id_active(xfContext* xfc, UINT32 id)
|
||||
{
|
||||
const rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
const UINT32 NumMonitorIds = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
|
||||
if (NumMonitorIds == 0)
|
||||
return TRUE;
|
||||
|
||||
for (UINT32 index = 0; index < NumMonitorIds; index++)
|
||||
{
|
||||
const UINT32* cur = freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index);
|
||||
if (cur && (*cur == id))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
UINT32 monitor_index = 0;
|
||||
BOOL primaryMonitorFound = FALSE;
|
||||
int mouse_x = 0;
|
||||
int mouse_y = 0;
|
||||
int _dummy_i = 0;
|
||||
Window _dummy_w = 0;
|
||||
UINT32 current_monitor = 0;
|
||||
Screen* screen = nullptr;
|
||||
#if defined WITH_XINERAMA || defined WITH_XRANDR
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
#endif
|
||||
#if defined(USABLE_XRANDR)
|
||||
XRRMonitorInfo* rrmonitors = nullptr;
|
||||
BOOL useXRandr = FALSE;
|
||||
#endif
|
||||
|
||||
if (!xfc || !pMaxWidth || !pMaxHeight || !xfc->common.context.settings)
|
||||
return FALSE;
|
||||
|
||||
rdpSettings* settings = xfc->common.context.settings;
|
||||
VIRTUAL_SCREEN* vscreen = &xfc->vscreen;
|
||||
|
||||
*pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
||||
*pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
||||
|
||||
if (freerdp_settings_get_uint64(settings, FreeRDP_ParentWindowId) > 0)
|
||||
{
|
||||
xfc->workArea.x = 0;
|
||||
xfc->workArea.y = 0;
|
||||
xfc->workArea.width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
||||
xfc->workArea.height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* get mouse location */
|
||||
if (!XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), &_dummy_w, &_dummy_w,
|
||||
&mouse_x, &mouse_y, &_dummy_i, &_dummy_i, (void*)&_dummy_i))
|
||||
mouse_x = mouse_y = 0;
|
||||
|
||||
#if defined(USABLE_XRANDR)
|
||||
|
||||
if (XRRQueryExtension(xfc->display, &major, &minor) &&
|
||||
(XRRQueryVersion(xfc->display, &major, &minor) == True) && (major * 100 + minor >= 105))
|
||||
{
|
||||
int nmonitors = 0;
|
||||
rrmonitors = XRRGetMonitors(xfc->display, DefaultRootWindow(xfc->display), 1, &nmonitors);
|
||||
|
||||
if ((nmonitors < 0) || (nmonitors > 16))
|
||||
vscreen->nmonitors = 0;
|
||||
else
|
||||
vscreen->nmonitors = (UINT32)nmonitors;
|
||||
|
||||
if (vscreen->nmonitors)
|
||||
{
|
||||
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
|
||||
{
|
||||
MONITOR_INFO* cur_vscreen = &vscreen->monitors[i];
|
||||
const XRRMonitorInfo* cur_monitor = &rrmonitors[i];
|
||||
|
||||
cur_vscreen->area.left = WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->x);
|
||||
cur_vscreen->area.top = WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->y);
|
||||
cur_vscreen->area.right =
|
||||
WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->x + cur_monitor->width - 1);
|
||||
cur_vscreen->area.bottom =
|
||||
WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->y + cur_monitor->height - 1);
|
||||
cur_vscreen->primary = cur_monitor->primary > 0;
|
||||
}
|
||||
}
|
||||
|
||||
useXRandr = TRUE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef WITH_XINERAMA
|
||||
if (XineramaQueryExtension(xfc->display, &major, &minor) && XineramaIsActive(xfc->display))
|
||||
{
|
||||
int nmonitors = 0;
|
||||
XineramaScreenInfo* screenInfo = XineramaQueryScreens(xfc->display, &nmonitors);
|
||||
|
||||
if ((nmonitors < 0) || (nmonitors > 16))
|
||||
vscreen->nmonitors = 0;
|
||||
else
|
||||
vscreen->nmonitors = (UINT32)nmonitors;
|
||||
|
||||
if (vscreen->nmonitors)
|
||||
{
|
||||
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
|
||||
{
|
||||
MONITOR_INFO* monitor = &vscreen->monitors[i];
|
||||
monitor->area.left = WINPR_ASSERTING_INT_CAST(uint16_t, screenInfo[i].x_org);
|
||||
monitor->area.top = WINPR_ASSERTING_INT_CAST(uint16_t, screenInfo[i].y_org);
|
||||
monitor->area.right = WINPR_ASSERTING_INT_CAST(
|
||||
uint16_t, screenInfo[i].x_org + screenInfo[i].width - 1);
|
||||
monitor->area.bottom = WINPR_ASSERTING_INT_CAST(
|
||||
uint16_t, screenInfo[i].y_org + screenInfo[i].height - 1);
|
||||
}
|
||||
}
|
||||
|
||||
XFree(screenInfo);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Both XRandR and Xinerama are either not compiled in or are not working, do nothing.
|
||||
*/
|
||||
}
|
||||
|
||||
rdpMonitor* rdpmonitors = calloc(vscreen->nmonitors + 1, sizeof(rdpMonitor));
|
||||
if (!rdpmonitors)
|
||||
goto fail;
|
||||
|
||||
xfc->fullscreenMonitors.top = 0;
|
||||
xfc->fullscreenMonitors.bottom = 0;
|
||||
xfc->fullscreenMonitors.left = 0;
|
||||
xfc->fullscreenMonitors.right = 0;
|
||||
|
||||
/* Determine which monitor that the mouse cursor is on */
|
||||
if (vscreen->monitors)
|
||||
{
|
||||
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
|
||||
{
|
||||
const MONITOR_INFO* monitor = &vscreen->monitors[i];
|
||||
|
||||
if ((mouse_x >= monitor->area.left) && (mouse_x <= monitor->area.right) &&
|
||||
(mouse_y >= monitor->area.top) && (mouse_y <= monitor->area.bottom))
|
||||
{
|
||||
current_monitor = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Even for a single monitor, we need to calculate the virtual screen to support
|
||||
window managers that do not implement all X window state hints.
|
||||
|
||||
If the user did not request multiple monitor or is using workarea
|
||||
without remote app, we force the number of monitors be 1 so later
|
||||
the rest of the client don't end up using more monitors than the user desires.
|
||||
*/
|
||||
if ((!freerdp_settings_get_bool(settings, FreeRDP_UseMultimon) &&
|
||||
!freerdp_settings_get_bool(settings, FreeRDP_SpanMonitors)) ||
|
||||
(freerdp_settings_get_bool(settings, FreeRDP_Workarea) &&
|
||||
!freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode)))
|
||||
{
|
||||
/* If no monitors were specified on the command-line then set the current monitor as active
|
||||
*/
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 0)
|
||||
{
|
||||
UINT32 id = current_monitor;
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, &id, 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Always sets number of monitors from command-line to just 1.
|
||||
* If the monitor is invalid then we will default back to current monitor
|
||||
* later as a fallback. So, there is no need to validate command-line entry here.
|
||||
*/
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_NumMonitorIds, 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* WORKAROUND: With Remote Application Mode - using NET_WM_WORKAREA
|
||||
* causes issues with the ability to fully size the window vertically
|
||||
* (the bottom of the window area is never updated). So, we just set
|
||||
* the workArea to match the full Screen width/height.
|
||||
*/
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode) || !xf_GetWorkArea(xfc))
|
||||
{
|
||||
/*
|
||||
if only 1 monitor is enabled, use monitor area
|
||||
this is required in case of a screen composed of more than one monitor
|
||||
but user did not enable multimonitor
|
||||
*/
|
||||
if ((freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 1) &&
|
||||
(vscreen->nmonitors > current_monitor))
|
||||
{
|
||||
MONITOR_INFO* monitor = vscreen->monitors + current_monitor;
|
||||
|
||||
if (!monitor)
|
||||
goto fail;
|
||||
|
||||
xfc->workArea.x = monitor->area.left;
|
||||
xfc->workArea.y = monitor->area.top;
|
||||
xfc->workArea.width = monitor->area.right - monitor->area.left + 1;
|
||||
xfc->workArea.height = monitor->area.bottom - monitor->area.top + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
xfc->workArea.x = 0;
|
||||
xfc->workArea.y = 0;
|
||||
xfc->workArea.width = WINPR_ASSERTING_INT_CAST(uint32_t, WidthOfScreen(xfc->screen));
|
||||
xfc->workArea.height = WINPR_ASSERTING_INT_CAST(uint32_t, HeightOfScreen(xfc->screen));
|
||||
}
|
||||
}
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
{
|
||||
*pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, WidthOfScreen(xfc->screen));
|
||||
*pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, HeightOfScreen(xfc->screen));
|
||||
}
|
||||
else if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
|
||||
{
|
||||
*pMaxWidth = xfc->workArea.width;
|
||||
*pMaxHeight = xfc->workArea.height;
|
||||
}
|
||||
else if (freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen))
|
||||
{
|
||||
/* If we have specific monitor information then limit the PercentScreen value
|
||||
* to only affect the current monitor vs. the entire desktop
|
||||
*/
|
||||
if (vscreen->nmonitors > 0)
|
||||
{
|
||||
if (!vscreen->monitors)
|
||||
goto fail;
|
||||
|
||||
const MONITOR_INFO* vmonitor = &vscreen->monitors[current_monitor];
|
||||
const RECTANGLE_16* area = &vmonitor->area;
|
||||
|
||||
*pMaxWidth = area->right - area->left + 1;
|
||||
*pMaxHeight = area->bottom - area->top + 1;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
|
||||
*pMaxWidth = ((area->right - area->left + 1) *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
|
||||
*pMaxHeight = ((area->bottom - area->top + 1) *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pMaxWidth = xfc->workArea.width;
|
||||
*pMaxHeight = xfc->workArea.height;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
|
||||
*pMaxWidth = (xfc->workArea.width *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
|
||||
*pMaxHeight = (xfc->workArea.height *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
}
|
||||
}
|
||||
else if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) &&
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight))
|
||||
{
|
||||
*pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
||||
*pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
||||
}
|
||||
|
||||
/* Create array of all active monitors by taking into account monitors requested on the
|
||||
* command-line */
|
||||
{
|
||||
size_t nmonitors = 0;
|
||||
{
|
||||
UINT32 nr = 0;
|
||||
|
||||
{
|
||||
const UINT32* ids = freerdp_settings_get_pointer(settings, FreeRDP_MonitorIds);
|
||||
if (ids)
|
||||
nr = *ids;
|
||||
}
|
||||
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
|
||||
{
|
||||
MONITOR_ATTRIBUTES* attrs = nullptr;
|
||||
|
||||
if (!xf_is_monitor_id_active(xfc, i))
|
||||
continue;
|
||||
|
||||
if (!vscreen->monitors)
|
||||
goto fail;
|
||||
|
||||
rdpMonitor* monitor = &rdpmonitors[nmonitors];
|
||||
const RECTANGLE_16* area = &vscreen->monitors[i].area;
|
||||
monitor->x =
|
||||
WINPR_ASSERTING_INT_CAST(
|
||||
int32_t,
|
||||
area->left*(
|
||||
freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
|
||||
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
|
||||
: 100)) /
|
||||
100;
|
||||
monitor->y =
|
||||
WINPR_ASSERTING_INT_CAST(
|
||||
int32_t,
|
||||
area->top*(
|
||||
freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight)
|
||||
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
|
||||
: 100)) /
|
||||
100;
|
||||
monitor->width =
|
||||
WINPR_ASSERTING_INT_CAST(
|
||||
int32_t,
|
||||
(area->right - area->left + 1) *
|
||||
(freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
|
||||
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
|
||||
: 100)) /
|
||||
100;
|
||||
monitor->height =
|
||||
WINPR_ASSERTING_INT_CAST(
|
||||
int32_t,
|
||||
(area->bottom - area->top + 1) *
|
||||
(freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight)
|
||||
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
|
||||
: 100)) /
|
||||
100;
|
||||
monitor->orig_screen = i;
|
||||
#ifdef USABLE_XRANDR
|
||||
|
||||
if (useXRandr && rrmonitors)
|
||||
{
|
||||
Rotation rot = 0;
|
||||
Rotation ret = 0;
|
||||
attrs = &monitor->attributes;
|
||||
attrs->physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rrmonitors[i].mwidth);
|
||||
attrs->physicalHeight =
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, rrmonitors[i].mheight);
|
||||
ret = XRRRotations(xfc->display, WINPR_ASSERTING_INT_CAST(int, i), &rot);
|
||||
switch (rot & ret)
|
||||
{
|
||||
|
||||
case RR_Rotate_90:
|
||||
attrs->orientation = ORIENTATION_PORTRAIT;
|
||||
break;
|
||||
case RR_Rotate_180:
|
||||
attrs->orientation = ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
break;
|
||||
case RR_Rotate_270:
|
||||
attrs->orientation = ORIENTATION_PORTRAIT_FLIPPED;
|
||||
break;
|
||||
case RR_Rotate_0:
|
||||
default:
|
||||
attrs->orientation = ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (i == nr)
|
||||
{
|
||||
monitor->is_primary = TRUE;
|
||||
primaryMonitorFound = TRUE;
|
||||
}
|
||||
|
||||
nmonitors++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no monitor is active(bogus command-line monitor specification) - then lets try to
|
||||
* fallback to go fullscreen on the current monitor only */
|
||||
if ((nmonitors == 0) && (vscreen->nmonitors > 0))
|
||||
{
|
||||
if (!vscreen->monitors)
|
||||
goto fail;
|
||||
|
||||
const MONITOR_INFO* vmonitor = &vscreen->monitors[current_monitor];
|
||||
const RECTANGLE_16* area = &vmonitor->area;
|
||||
|
||||
const INT32 width = area->right - area->left + 1;
|
||||
const INT32 height = area->bottom - area->top + 1;
|
||||
const INT32 maxw =
|
||||
((width < 0) || ((UINT32)width < *pMaxWidth)) ? width : (INT32)*pMaxWidth;
|
||||
const INT32 maxh =
|
||||
((height < 0) || ((UINT32)height < *pMaxHeight)) ? width : (INT32)*pMaxHeight;
|
||||
|
||||
rdpMonitor* monitor = &rdpmonitors[0];
|
||||
if (!monitor)
|
||||
goto fail;
|
||||
|
||||
monitor->x = area->left;
|
||||
monitor->y = area->top;
|
||||
monitor->width = maxw;
|
||||
monitor->height = maxh;
|
||||
monitor->orig_screen = current_monitor;
|
||||
nmonitors = 1;
|
||||
}
|
||||
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, nmonitors)))
|
||||
goto fail;
|
||||
|
||||
/* If we have specific monitor information */
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 0)
|
||||
{
|
||||
const rdpMonitor* cmonitor = &rdpmonitors[0];
|
||||
if (!cmonitor)
|
||||
goto fail;
|
||||
|
||||
/* Initialize bounding rectangle for all monitors */
|
||||
int vX = cmonitor->x;
|
||||
int vY = cmonitor->y;
|
||||
int vR = vX + cmonitor->width;
|
||||
int vB = vY + cmonitor->height;
|
||||
const int32_t corig = WINPR_ASSERTING_INT_CAST(int32_t, cmonitor->orig_screen);
|
||||
xfc->fullscreenMonitors.top = corig;
|
||||
xfc->fullscreenMonitors.bottom = corig;
|
||||
xfc->fullscreenMonitors.left = corig;
|
||||
xfc->fullscreenMonitors.right = corig;
|
||||
|
||||
/* Calculate bounding rectangle around all monitors to be used AND
|
||||
* also set the Xinerama indices which define left/top/right/bottom monitors.
|
||||
*/
|
||||
for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
|
||||
{
|
||||
rdpMonitor* monitor = &rdpmonitors[i];
|
||||
|
||||
/* does the same as gdk_rectangle_union */
|
||||
const int destX = MIN(vX, monitor->x);
|
||||
const int destY = MIN(vY, monitor->y);
|
||||
const int destR = MAX(vR, monitor->x + monitor->width);
|
||||
const int destB = MAX(vB, monitor->y + monitor->height);
|
||||
const int32_t orig = WINPR_ASSERTING_INT_CAST(int32_t, monitor->orig_screen);
|
||||
|
||||
if (vX != destX)
|
||||
xfc->fullscreenMonitors.left = orig;
|
||||
|
||||
if (vY != destY)
|
||||
xfc->fullscreenMonitors.top = orig;
|
||||
|
||||
if (vR != destR)
|
||||
xfc->fullscreenMonitors.right = orig;
|
||||
|
||||
if (vB != destB)
|
||||
xfc->fullscreenMonitors.bottom = orig;
|
||||
|
||||
vX = destX;
|
||||
vY = destY;
|
||||
vR = destR;
|
||||
vB = destB;
|
||||
}
|
||||
|
||||
vscreen->area.left = 0;
|
||||
const int r = vR - vX - 1;
|
||||
vscreen->area.right = WINPR_ASSERTING_INT_CAST(UINT16, r);
|
||||
vscreen->area.top = 0;
|
||||
const int b = vB - vY - 1;
|
||||
vscreen->area.bottom = WINPR_ASSERTING_INT_CAST(UINT16, b);
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
|
||||
{
|
||||
INT64 bottom = 1LL * xfc->workArea.height + xfc->workArea.y - 1LL;
|
||||
vscreen->area.top = WINPR_ASSERTING_INT_CAST(UINT16, xfc->workArea.y);
|
||||
vscreen->area.bottom = WINPR_ASSERTING_INT_CAST(UINT16, bottom);
|
||||
}
|
||||
|
||||
if (!primaryMonitorFound)
|
||||
{
|
||||
/* If we have a command line setting we should use it */
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) > 0)
|
||||
{
|
||||
/* The first monitor is the first in the setting which should be used */
|
||||
UINT32* ids = freerdp_settings_get_pointer_array_writable(
|
||||
settings, FreeRDP_MonitorIds, 0);
|
||||
if (ids)
|
||||
monitor_index = *ids;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is the same as when we would trust the Xinerama results..
|
||||
and set the monitor index to zero.
|
||||
The monitor listed with /list:monitor on index zero is always the primary
|
||||
*/
|
||||
screen = DefaultScreenOfDisplay(xfc->display);
|
||||
monitor_index =
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, XScreenNumberOfScreen(screen));
|
||||
}
|
||||
|
||||
UINT32 j = monitor_index;
|
||||
rdpMonitor* pmonitor = &rdpmonitors[j];
|
||||
|
||||
/* If the "default" monitor is not 0,0 use it */
|
||||
if ((pmonitor->x != 0) || (pmonitor->y != 0))
|
||||
{
|
||||
pmonitor->is_primary = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lets try to see if there is a monitor with a 0,0 coordinate and use it as a
|
||||
* fallback*/
|
||||
for (UINT32 i = 0;
|
||||
i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
|
||||
{
|
||||
rdpMonitor* monitor = &rdpmonitors[i];
|
||||
if (!primaryMonitorFound && monitor->x == 0 && monitor->y == 0)
|
||||
{
|
||||
monitor->is_primary = TRUE;
|
||||
primaryMonitorFound = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the desktop width and height according to the bounding rectangle around the
|
||||
* active monitors */
|
||||
*pMaxWidth = MIN(*pMaxWidth, (UINT32)vscreen->area.right - vscreen->area.left + 1);
|
||||
*pMaxHeight = MIN(*pMaxHeight, (UINT32)vscreen->area.bottom - vscreen->area.top + 1);
|
||||
}
|
||||
|
||||
/* some 2008 server freeze at logon if we announce support for monitor layout PDU with
|
||||
* #monitors < 2. So let's announce it only if we have more than 1 monitor.
|
||||
*/
|
||||
nmonitors = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
|
||||
if (nmonitors > 1)
|
||||
{
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = freerdp_settings_set_monitor_def_array_sorted(settings, rdpmonitors, nmonitors);
|
||||
}
|
||||
|
||||
fail:
|
||||
#ifdef USABLE_XRANDR
|
||||
|
||||
if (rrmonitors)
|
||||
XRRFreeMonitors(rrmonitors);
|
||||
|
||||
#endif
|
||||
free(rdpmonitors);
|
||||
return rc;
|
||||
}
|
||||
33
third_party/FreeRDP/client/X11/xf_monitor.h
vendored
Normal file
33
third_party/FreeRDP/client/X11/xf_monitor.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Monitor Handling
|
||||
*
|
||||
* Copyright 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_X11_MONITOR_H
|
||||
#define FREERDP_CLIENT_X11_MONITOR_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/types.h>
|
||||
|
||||
#include "xf_types.h"
|
||||
|
||||
FREERDP_API int xf_list_monitors(xfContext* xfc);
|
||||
FREERDP_API BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight);
|
||||
FREERDP_API void xf_monitors_free(xfContext* xfc);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_MONITOR_H */
|
||||
1420
third_party/FreeRDP/client/X11/xf_rail.c
vendored
Normal file
1420
third_party/FreeRDP/client/X11/xf_rail.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
145
third_party/FreeRDP/client/X11/xf_rail.h
vendored
Normal file
145
third_party/FreeRDP/client/X11/xf_rail.h
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 RAIL
|
||||
*
|
||||
* Copyright 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_X11_RAIL_H
|
||||
#define FREERDP_CLIENT_X11_RAIL_H
|
||||
|
||||
#include <freerdp/client/rail.h>
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "xf_types.h"
|
||||
|
||||
enum xf_localmove_state
|
||||
{
|
||||
LMS_NOT_ACTIVE,
|
||||
LMS_STARTING,
|
||||
LMS_ACTIVE,
|
||||
LMS_TERMINATING
|
||||
};
|
||||
|
||||
struct xf_localmove
|
||||
{
|
||||
int root_x;
|
||||
int root_y;
|
||||
int window_x;
|
||||
int window_y;
|
||||
enum xf_localmove_state state;
|
||||
int direction;
|
||||
};
|
||||
typedef struct xf_localmove xfLocalMove;
|
||||
|
||||
struct xf_app_window
|
||||
{
|
||||
xfContext* xfc;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
char* title;
|
||||
|
||||
UINT32 surfaceId;
|
||||
UINT64 windowId;
|
||||
UINT32 ownerWindowId;
|
||||
|
||||
UINT32 dwStyle;
|
||||
UINT32 dwExStyle;
|
||||
UINT32 showState;
|
||||
|
||||
INT32 clientOffsetX;
|
||||
INT32 clientOffsetY;
|
||||
UINT32 clientAreaWidth;
|
||||
UINT32 clientAreaHeight;
|
||||
|
||||
INT32 windowOffsetX;
|
||||
INT32 windowOffsetY;
|
||||
INT32 windowClientDeltaX;
|
||||
INT32 windowClientDeltaY;
|
||||
UINT32 windowWidth;
|
||||
UINT32 windowHeight;
|
||||
UINT32 numWindowRects;
|
||||
RECTANGLE_16* windowRects;
|
||||
|
||||
INT32 visibleOffsetX;
|
||||
INT32 visibleOffsetY;
|
||||
UINT32 numVisibilityRects;
|
||||
RECTANGLE_16* visibilityRects;
|
||||
|
||||
UINT32 localWindowOffsetCorrX;
|
||||
UINT32 localWindowOffsetCorrY;
|
||||
|
||||
UINT32 resizeMarginLeft;
|
||||
UINT32 resizeMarginTop;
|
||||
UINT32 resizeMarginRight;
|
||||
UINT32 resizeMarginBottom;
|
||||
|
||||
GC gc;
|
||||
int shmid;
|
||||
Window handle;
|
||||
Window* xfwin;
|
||||
BOOL fullscreen;
|
||||
BOOL decorations;
|
||||
BOOL is_mapped;
|
||||
BOOL is_transient;
|
||||
xfLocalMove local_move;
|
||||
BYTE rail_state;
|
||||
BOOL maxVert;
|
||||
BOOL maxHorz;
|
||||
BOOL minimized;
|
||||
BOOL rail_ignore_configure;
|
||||
|
||||
Pixmap pixmap;
|
||||
XImage* image;
|
||||
};
|
||||
typedef struct xf_app_window xfAppWindow;
|
||||
typedef struct xf_rail_icon_cache xfRailIconCache;
|
||||
|
||||
BOOL xf_rail_paint(xfContext* xfc, const RECTANGLE_16* rect);
|
||||
BOOL xf_rail_paint_surface(xfContext* xfc, UINT64 windowId, const RECTANGLE_16* rect);
|
||||
|
||||
BOOL xf_rail_send_client_system_command(xfContext* xfc, UINT64 windowId, UINT16 command);
|
||||
BOOL xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled);
|
||||
BOOL xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow);
|
||||
BOOL xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow);
|
||||
BOOL xf_rail_enable_remoteapp_mode(xfContext* xfc);
|
||||
BOOL xf_rail_disable_remoteapp_mode(xfContext* xfc);
|
||||
|
||||
xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, INT32 x, INT32 y, UINT32 width,
|
||||
UINT32 height, UINT32 surfaceId);
|
||||
|
||||
#define xf_rail_return_window(window, alreadyLocked) \
|
||||
xf_rail_return_windowFrom((window), (alreadyLocked), __FILE__, __func__, __LINE__)
|
||||
void xf_rail_return_windowFrom(xfAppWindow* window, BOOL alreadyLocked, const char* file,
|
||||
const char* fkt, size_t line);
|
||||
|
||||
#define xf_rail_get_window(xfc, id, alreadyLocked) \
|
||||
xf_rail_get_windowFrom((xfc), (id), (alreadyLocked), __FILE__, __func__, __LINE__)
|
||||
|
||||
WINPR_ATTR_MALLOC(xf_rail_return_windowFrom, 1)
|
||||
xfAppWindow* xf_rail_get_windowFrom(xfContext* xfc, UINT64 id, BOOL alreadyLocked, const char* file,
|
||||
const char* fkt, size_t line);
|
||||
|
||||
BOOL xf_rail_del_window(xfContext* xfc, UINT64 id);
|
||||
|
||||
int xf_rail_init(xfContext* xfc, RailClientContext* rail);
|
||||
int xf_rail_uninit(xfContext* xfc, RailClientContext* rail);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_RAIL_H */
|
||||
479
third_party/FreeRDP/client/X11/xf_tsmf.c
vendored
Normal file
479
third_party/FreeRDP/client/X11/xf_tsmf.c
vendored
Normal file
@@ -0,0 +1,479 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Video Redirection
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
*
|
||||
* 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 <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
|
||||
#include "xf_tsmf.h"
|
||||
#include "xf_utils.h"
|
||||
|
||||
#ifdef WITH_XV
|
||||
|
||||
#include <X11/extensions/Xv.h>
|
||||
#include <X11/extensions/Xvlib.h>
|
||||
|
||||
static long xv_port = 0;
|
||||
|
||||
struct xf_xv_context
|
||||
{
|
||||
XvPortID xv_port;
|
||||
Atom xv_colorkey_atom;
|
||||
int xv_image_size;
|
||||
int xv_shmid;
|
||||
char* xv_shmaddr;
|
||||
UINT32* xv_pixfmts;
|
||||
};
|
||||
typedef struct xf_xv_context xfXvContext;
|
||||
|
||||
#define TAG CLIENT_TAG("x11")
|
||||
|
||||
static BOOL xf_tsmf_is_format_supported(xfXvContext* xv, UINT32 pixfmt)
|
||||
{
|
||||
if (!xv->xv_pixfmts)
|
||||
return FALSE;
|
||||
|
||||
for (int i = 0; xv->xv_pixfmts[i]; i++)
|
||||
{
|
||||
if (xv->xv_pixfmts[i] == pixfmt)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT* event)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
UINT32 width = 0;
|
||||
UINT32 height = 0;
|
||||
BYTE* data1 = nullptr;
|
||||
BYTE* data2 = nullptr;
|
||||
UINT32 pixfmt = 0;
|
||||
UINT32 xvpixfmt = 0;
|
||||
XvImage* image = nullptr;
|
||||
int colorkey = 0;
|
||||
int numRects = 0;
|
||||
xfContext* xfc = nullptr;
|
||||
xfXvContext* xv = nullptr;
|
||||
XRectangle* xrects = nullptr;
|
||||
XShmSegmentInfo shminfo;
|
||||
BOOL converti420yv12 = FALSE;
|
||||
|
||||
if (!tsmf)
|
||||
return -1;
|
||||
|
||||
xfc = (xfContext*)tsmf->custom;
|
||||
|
||||
if (!xfc)
|
||||
return -1;
|
||||
|
||||
xv = (xfXvContext*)xfc->xv_context;
|
||||
|
||||
if (!xv)
|
||||
return -1;
|
||||
|
||||
if (xv->xv_port == 0)
|
||||
return -1001;
|
||||
|
||||
/* In case the player is minimized */
|
||||
if (event->x < -2048 || event->y < -2048 || event->numVisibleRects == 0)
|
||||
{
|
||||
return -1002;
|
||||
}
|
||||
|
||||
xrects = nullptr;
|
||||
numRects = event->numVisibleRects;
|
||||
|
||||
if (numRects > 0)
|
||||
{
|
||||
xrects = (XRectangle*)calloc(numRects, sizeof(XRectangle));
|
||||
|
||||
if (!xrects)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < numRects; i++)
|
||||
{
|
||||
x = event->x + event->visibleRects[i].left;
|
||||
y = event->y + event->visibleRects[i].top;
|
||||
width = event->visibleRects[i].right - event->visibleRects[i].left;
|
||||
height = event->visibleRects[i].bottom - event->visibleRects[i].top;
|
||||
|
||||
xrects[i].x = WINPR_ASSERTING_INT_CAST(short, x);
|
||||
xrects[i].y = WINPR_ASSERTING_INT_CAST(short, y);
|
||||
xrects[i].width = width;
|
||||
xrects[i].height = height;
|
||||
}
|
||||
}
|
||||
|
||||
if (xv->xv_colorkey_atom != None)
|
||||
{
|
||||
XvGetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, &colorkey);
|
||||
LogDynAndXSetFunction(xfc->log, xfc->display, xfc->gc, GXcopy);
|
||||
LogDynAndXSetFillStyle(xfc->log, xfc->display, xfc->gc, FillSolid);
|
||||
LogDynAndXSetForeground(xfc->log, xfc->display, xfc->gc, colorkey);
|
||||
|
||||
if (event->numVisibleRects < 1)
|
||||
{
|
||||
LogDynAndXSetClipMask(xfc->log, xfc->display, xfc->gc, None);
|
||||
}
|
||||
else
|
||||
{
|
||||
XFillRectangles(xfc->display, xfc->window->handle, xfc->gc, xrects, numRects);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDynAndXSetFunction(xfc->log, xfc->display, xfc->gc, GXcopy);
|
||||
LogDynAndXSetFillStyle(xfc->log, xfc->display, xfc->gc, FillSolid);
|
||||
|
||||
if (event->numVisibleRects < 1)
|
||||
{
|
||||
LogDynAndXSetClipMask(xfc->log, xfc->display, xfc->gc, None);
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetClipRectangles(xfc->display, xfc->gc, 0, 0, xrects, numRects, YXBanded);
|
||||
}
|
||||
}
|
||||
|
||||
pixfmt = event->framePixFmt;
|
||||
|
||||
if (xf_tsmf_is_format_supported(xv, pixfmt))
|
||||
{
|
||||
xvpixfmt = pixfmt;
|
||||
}
|
||||
else if (pixfmt == RDP_PIXFMT_I420 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_YV12))
|
||||
{
|
||||
xvpixfmt = RDP_PIXFMT_YV12;
|
||||
converti420yv12 = TRUE;
|
||||
}
|
||||
else if (pixfmt == RDP_PIXFMT_YV12 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_I420))
|
||||
{
|
||||
xvpixfmt = RDP_PIXFMT_I420;
|
||||
converti420yv12 = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "pixel format 0x%" PRIX32 " not supported by hardware.", pixfmt);
|
||||
free(xrects);
|
||||
return -1003;
|
||||
}
|
||||
|
||||
image = XvShmCreateImage(xfc->display, xv->xv_port, WINPR_ASSERTING_INT_CAST(int, xvpixfmt), 0,
|
||||
event->frameWidth, event->frameHeight, &shminfo);
|
||||
|
||||
if (xv->xv_image_size != image->data_size)
|
||||
{
|
||||
if (xv->xv_image_size > 0)
|
||||
{
|
||||
shmdt(xv->xv_shmaddr);
|
||||
shmctl(xv->xv_shmid, IPC_RMID, nullptr);
|
||||
}
|
||||
|
||||
xv->xv_image_size = image->data_size;
|
||||
xv->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
|
||||
xv->xv_shmaddr = shmat(xv->xv_shmid, 0, 0);
|
||||
}
|
||||
|
||||
shminfo.shmid = xv->xv_shmid;
|
||||
shminfo.shmaddr = image->data = xv->xv_shmaddr;
|
||||
shminfo.readOnly = FALSE;
|
||||
|
||||
if (!XShmAttach(xfc->display, &shminfo))
|
||||
{
|
||||
XFree(image);
|
||||
free(xrects);
|
||||
WLog_DBG(TAG, "XShmAttach failed.");
|
||||
return -1004;
|
||||
}
|
||||
|
||||
/* The video driver may align each line to a different size
|
||||
and we need to convert our original image data. */
|
||||
switch (pixfmt)
|
||||
{
|
||||
case RDP_PIXFMT_I420:
|
||||
case RDP_PIXFMT_YV12:
|
||||
/* Y */
|
||||
if (image->pitches[0] == event->frameWidth)
|
||||
{
|
||||
CopyMemory(image->data + image->offsets[0], event->frameData,
|
||||
1ULL * event->frameWidth * event->frameHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < event->frameHeight; i++)
|
||||
{
|
||||
CopyMemory(image->data + 1ULL * image->offsets[0] +
|
||||
1ULL * i * image->pitches[0],
|
||||
event->frameData + 1ULL * i * event->frameWidth, event->frameWidth);
|
||||
}
|
||||
}
|
||||
/* UV */
|
||||
/* Conversion between I420 and YV12 is to simply swap U and V */
|
||||
if (!converti420yv12)
|
||||
{
|
||||
data1 = event->frameData + 1ULL * event->frameWidth * event->frameHeight;
|
||||
data2 = event->frameData + 1ULL * event->frameWidth * event->frameHeight +
|
||||
1ULL * event->frameWidth * event->frameHeight / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
data2 = event->frameData + 1ULL * event->frameWidth * event->frameHeight;
|
||||
data1 = event->frameData + 1ULL * event->frameWidth * event->frameHeight +
|
||||
1ULL * event->frameWidth * event->frameHeight / 4;
|
||||
image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420;
|
||||
}
|
||||
|
||||
if (image->pitches[1] * 2 == event->frameWidth)
|
||||
{
|
||||
CopyMemory(image->data + image->offsets[1], data1,
|
||||
event->frameWidth * event->frameHeight / 4);
|
||||
CopyMemory(image->data + image->offsets[2], data2,
|
||||
event->frameWidth * event->frameHeight / 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < event->frameHeight / 2; i++)
|
||||
{
|
||||
CopyMemory(image->data + 1ULL * image->offsets[1] +
|
||||
1ULL * i * image->pitches[1],
|
||||
data1 + 1ULL * i * event->frameWidth / 2, event->frameWidth / 2);
|
||||
CopyMemory(image->data + 1ULL * image->offsets[2] +
|
||||
1ULL * i * image->pitches[2],
|
||||
data2 + 1ULL * i * event->frameWidth / 2, event->frameWidth / 2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (image->data_size < 0)
|
||||
{
|
||||
free(xrects);
|
||||
return -2000;
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t size = ((UINT32)image->data_size <= event->frameSize)
|
||||
? (UINT32)image->data_size
|
||||
: event->frameSize;
|
||||
CopyMemory(image->data, event->frameData, size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc, image, 0, 0,
|
||||
image->width, image->height, event->x, event->y, event->width, event->height,
|
||||
FALSE);
|
||||
|
||||
if (xv->xv_colorkey_atom == None)
|
||||
LogDynAndXSetClipMask(xfc->log, xfc->display, xfc->gc, None);
|
||||
|
||||
LogDynAndXSync(xfc->log, xfc->display, FALSE);
|
||||
|
||||
XShmDetach(xfc->display, &shminfo);
|
||||
XFree(image);
|
||||
|
||||
free(xrects);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int version = 0;
|
||||
unsigned int release = 0;
|
||||
unsigned int event_base = 0;
|
||||
unsigned int error_base = 0;
|
||||
unsigned int request_base = 0;
|
||||
unsigned int num_adaptors = 0;
|
||||
xfXvContext* xv = nullptr;
|
||||
XvAdaptorInfo* ai = nullptr;
|
||||
XvAttribute* attr = nullptr;
|
||||
XvImageFormatValues* fo = nullptr;
|
||||
|
||||
if (xfc->xv_context)
|
||||
return 1; /* context already created */
|
||||
|
||||
xv = (xfXvContext*)calloc(1, sizeof(xfXvContext));
|
||||
|
||||
if (!xv)
|
||||
return -1;
|
||||
|
||||
xfc->xv_context = xv;
|
||||
|
||||
xv->xv_colorkey_atom = None;
|
||||
xv->xv_image_size = 0;
|
||||
xv->xv_port = xv_port;
|
||||
|
||||
if (!XShmQueryExtension(xfc->display))
|
||||
{
|
||||
WLog_DBG(TAG, "no xshm available.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret =
|
||||
XvQueryExtension(xfc->display, &version, &release, &request_base, &event_base, &error_base);
|
||||
|
||||
if (ret != Success)
|
||||
{
|
||||
WLog_DBG(TAG, "XvQueryExtension failed %d.", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "version %u release %u", version, release);
|
||||
|
||||
ret = XvQueryAdaptors(xfc->display, DefaultRootWindow(xfc->display), &num_adaptors, &ai);
|
||||
|
||||
if (ret != Success)
|
||||
{
|
||||
WLog_DBG(TAG, "XvQueryAdaptors failed %d.", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num_adaptors; i++)
|
||||
{
|
||||
WLog_DBG(TAG, "adapter port %lu-%lu (%s)", ai[i].base_id,
|
||||
ai[i].base_id + ai[i].num_ports - 1, ai[i].name);
|
||||
|
||||
if (xv->xv_port == 0 && i == num_adaptors - 1)
|
||||
xv->xv_port = ai[i].base_id;
|
||||
}
|
||||
|
||||
if (num_adaptors > 0)
|
||||
XvFreeAdaptorInfo(ai);
|
||||
|
||||
if (xv->xv_port == 0)
|
||||
{
|
||||
WLog_DBG(TAG, "no adapter selected, video frames will not be processed.");
|
||||
return -1;
|
||||
}
|
||||
WLog_DBG(TAG, "selected %ld", xv->xv_port);
|
||||
|
||||
attr = XvQueryPortAttributes(xfc->display, xv->xv_port, &ret);
|
||||
|
||||
unsigned int i = 0;
|
||||
for (; i < (unsigned int)ret; i++)
|
||||
{
|
||||
if (strcmp(attr[i].name, "XV_COLORKEY") == 0)
|
||||
{
|
||||
static wLog* log = nullptr;
|
||||
if (!log)
|
||||
log = WLog_Get(TAG);
|
||||
xv->xv_colorkey_atom = Logging_XInternAtom(log, xfc->display, "XV_COLORKEY", FALSE);
|
||||
XvSetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom,
|
||||
attr[i].min_value + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(attr);
|
||||
|
||||
WLog_DBG(TAG, "xf_tsmf_init: pixel format ");
|
||||
|
||||
fo = XvListImageFormats(xfc->display, xv->xv_port, &ret);
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
xv->xv_pixfmts = (UINT32*)calloc((ret + 1), sizeof(UINT32));
|
||||
|
||||
size_t x = 0;
|
||||
for (; x < (size_t)ret; x++)
|
||||
{
|
||||
xv->xv_pixfmts[x] = fo[x].id;
|
||||
WLog_DBG(TAG, "%c%c%c%c ", ((char*)(xv->xv_pixfmts + x))[0],
|
||||
((char*)(xv->xv_pixfmts + x))[1], ((char*)(xv->xv_pixfmts + x))[2],
|
||||
((char*)(xv->xv_pixfmts + x))[3]);
|
||||
}
|
||||
xv->xv_pixfmts[x] = 0;
|
||||
}
|
||||
XFree(fo);
|
||||
|
||||
if (tsmf)
|
||||
{
|
||||
xfc->tsmf = tsmf;
|
||||
tsmf->custom = (void*)xfc;
|
||||
|
||||
tsmf->FrameEvent = xf_tsmf_xv_video_frame_event;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int xf_tsmf_xv_uninit(xfContext* xfc, TsmfClientContext* tsmf)
|
||||
{
|
||||
xfXvContext* xv = (xfXvContext*)xfc->xv_context;
|
||||
|
||||
WINPR_UNUSED(tsmf);
|
||||
if (xv)
|
||||
{
|
||||
if (xv->xv_image_size > 0)
|
||||
{
|
||||
shmdt(xv->xv_shmaddr);
|
||||
shmctl(xv->xv_shmid, IPC_RMID, nullptr);
|
||||
}
|
||||
if (xv->xv_pixfmts)
|
||||
{
|
||||
free(xv->xv_pixfmts);
|
||||
xv->xv_pixfmts = nullptr;
|
||||
}
|
||||
free(xv);
|
||||
xfc->xv_context = nullptr;
|
||||
}
|
||||
|
||||
if (xfc->tsmf)
|
||||
{
|
||||
xfc->tsmf->custom = nullptr;
|
||||
xfc->tsmf = nullptr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int xf_tsmf_init(xfContext* xfc, TsmfClientContext* tsmf)
|
||||
{
|
||||
#ifdef WITH_XV
|
||||
return xf_tsmf_xv_init(xfc, tsmf);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf)
|
||||
{
|
||||
#ifdef WITH_XV
|
||||
return xf_tsmf_xv_uninit(xfc, tsmf);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
29
third_party/FreeRDP/client/X11/xf_tsmf.h
vendored
Normal file
29
third_party/FreeRDP/client/X11/xf_tsmf.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Video Redirection
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
*
|
||||
* 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_X11_TSMF_H
|
||||
#define FREERDP_CLIENT_X11_TSMF_H
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
int xf_tsmf_init(xfContext* xfc, TsmfClientContext* tsmf);
|
||||
int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_TSMF_H */
|
||||
42
third_party/FreeRDP/client/X11/xf_types.h
vendored
Normal file
42
third_party/FreeRDP/client/X11/xf_types.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Client
|
||||
*
|
||||
* Copyright 2026 Thincast Technologies GmbH
|
||||
* Copyright 2026 Armin Novak <armin.novak@thincast.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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <freerdp/types.h>
|
||||
|
||||
/* Forward declarations */
|
||||
typedef struct xf_context xfContext;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RECTANGLE_16 area;
|
||||
RECTANGLE_16 workarea;
|
||||
BOOL primary;
|
||||
} MONITOR_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 nmonitors;
|
||||
RECTANGLE_16 area;
|
||||
RECTANGLE_16 workarea;
|
||||
MONITOR_INFO* monitors;
|
||||
} VIRTUAL_SCREEN;
|
||||
769
third_party/FreeRDP/client/X11/xf_utils.c
vendored
Normal file
769
third_party/FreeRDP/client/X11/xf_utils.c
vendored
Normal file
@@ -0,0 +1,769 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 helper utilities
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyringht 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/path.h>
|
||||
|
||||
#include "xf_utils.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
#include <freerdp/utils/helpers.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#define TAG CLIENT_TAG("xfreerdp.utils")
|
||||
|
||||
static const DWORD log_level = WLOG_TRACE;
|
||||
|
||||
static const char* error_to_string(wLog* log, Display* display, int error, char* buffer,
|
||||
size_t size)
|
||||
{
|
||||
WINPR_ASSERT(size <= INT32_MAX);
|
||||
const int rc = XGetErrorText(display, error, buffer, (int)size);
|
||||
if (rc != Success)
|
||||
WLog_Print(log, WLOG_WARN, "XGetErrorText returned %d", rc);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(6, 7)
|
||||
static void write_log(wLog* log, DWORD level, const char* fname, const char* fkt, size_t line,
|
||||
WINPR_FORMAT_ARG const char* fmt, ...)
|
||||
{
|
||||
va_list ap = WINPR_C_ARRAY_INIT;
|
||||
va_start(ap, fmt);
|
||||
WLog_PrintTextMessageVA(log, level, line, fname, fkt, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static BOOL ignore_code(int rc, size_t count, va_list ap)
|
||||
{
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
const int val = va_arg(ap, int);
|
||||
if (rc == val)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* libx11 return codes are not really well documented, so checked against
|
||||
* https://gitlab.freedesktop.org/xorg/lib/libx11.git */
|
||||
static int write_result_log_va(wLog* log, DWORD level, const char* fname, const char* fkt,
|
||||
size_t line, Display* display, char* name, int rc, size_t count,
|
||||
va_list ap)
|
||||
{
|
||||
const BOOL ignore = ignore_code(rc, count, ap);
|
||||
if (!ignore)
|
||||
{
|
||||
char buffer[128] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (WLog_IsLevelActive(log, level))
|
||||
{
|
||||
WLog_PrintTextMessage(log, level, line, fname, fkt, "%s returned %s", name,
|
||||
error_to_string(log, display, rc, buffer, sizeof(buffer)));
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int write_result_log_expect_success(wLog* log, DWORD level, const char* fname,
|
||||
const char* fkt, size_t line, Display* display,
|
||||
char* name, int rc)
|
||||
{
|
||||
if (rc != Success)
|
||||
{
|
||||
va_list ap = WINPR_C_ARRAY_INIT;
|
||||
(void)write_result_log_va(log, level, fname, fkt, line, display, name, rc, 0, ap);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int write_result_log_expect_one(wLog* log, DWORD level, const char* fname, const char* fkt,
|
||||
size_t line, Display* display, char* name, int rc)
|
||||
{
|
||||
if (rc != 1)
|
||||
{
|
||||
va_list ap = WINPR_C_ARRAY_INIT;
|
||||
(void)write_result_log_va(log, level, fname, fkt, line, display, name, rc, 0, ap);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
char* Safe_XGetAtomNameEx(wLog* log, Display* display, Atom atom, const char* varname)
|
||||
{
|
||||
WLog_Print(log, log_level, "XGetAtomName(%s, 0x%08lx)", varname, atom);
|
||||
if (atom == None)
|
||||
return strdup("Atom_None");
|
||||
return XGetAtomName(display, atom);
|
||||
}
|
||||
|
||||
Atom Logging_XInternAtom(wLog* log, Display* display, _Xconst char* atom_name, Bool only_if_exists)
|
||||
{
|
||||
Atom atom = XInternAtom(display, atom_name, only_if_exists);
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
WLog_Print(log, log_level, "XInternAtom(%p, %s, %s) -> 0x%08" PRIx32, (void*)display,
|
||||
atom_name, only_if_exists ? "True" : "False",
|
||||
WINPR_CXX_COMPAT_CAST(UINT32, atom));
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
|
||||
const char* x11_error_to_string(xfContext* xfc, int error, char* buffer, size_t size)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
return error_to_string(xfc->log, xfc->display, error, buffer, size);
|
||||
}
|
||||
|
||||
int LogDynAndXChangeProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Atom property, Atom type, int format,
|
||||
int mode, const unsigned char* data, int nelements)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
char* propstr = Safe_XGetAtomName(log, display, property);
|
||||
char* typestr = Safe_XGetAtomName(log, display, type);
|
||||
write_log(log, log_level, file, fkt, line,
|
||||
"XChangeProperty(%p, %lu, %s [%lu], %s [%lu], %d, %d, %p, %d)", (void*)display, w,
|
||||
propstr, property, typestr, type, format, mode, (const void*)data, nelements);
|
||||
XFree(propstr);
|
||||
XFree(typestr);
|
||||
}
|
||||
const int rc = XChangeProperty(display, w, property, type, format, mode, data, nelements);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XChangeProperty",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXDeleteProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Atom property)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
char* propstr = Safe_XGetAtomName(log, display, property);
|
||||
write_log(log, log_level, file, fkt, line, "XDeleteProperty(%p, %lu, %s [%lu])",
|
||||
(void*)display, w, propstr, property);
|
||||
XFree(propstr);
|
||||
}
|
||||
const int rc = XDeleteProperty(display, w, property);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XDeleteProperty",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXConvertSelection_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Atom selection, Atom target, Atom property,
|
||||
Window requestor, Time time)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
char* selectstr = Safe_XGetAtomName(log, display, selection);
|
||||
char* targetstr = Safe_XGetAtomName(log, display, target);
|
||||
char* propstr = Safe_XGetAtomName(log, display, property);
|
||||
write_log(log, log_level, file, fkt, line,
|
||||
"XConvertSelection(%p, %s [%lu], %s [%lu], %s [%lu], %lu, %lu)", (void*)display,
|
||||
selectstr, selection, targetstr, target, propstr, property, requestor, time);
|
||||
XFree(propstr);
|
||||
XFree(targetstr);
|
||||
XFree(selectstr);
|
||||
}
|
||||
const int rc = XConvertSelection(display, selection, target, property, requestor, time);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
|
||||
"XConvertSelection", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXGetWindowProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Atom property, long long_offset,
|
||||
long long_length, int c_delete, Atom req_type,
|
||||
Atom* actual_type_return, int* actual_format_return,
|
||||
unsigned long* nitems_return, unsigned long* bytes_after_return,
|
||||
unsigned char** prop_return)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
char* propstr = Safe_XGetAtomName(log, display, property);
|
||||
char* req_type_str = Safe_XGetAtomName(log, display, req_type);
|
||||
write_log(
|
||||
log, log_level, file, fkt, line,
|
||||
"XGetWindowProperty(%p, %lu, %s [%lu], %ld, %ld, %d, %s [%lu], %p, %p, %p, %p, %p)",
|
||||
(void*)display, w, propstr, property, long_offset, long_length, c_delete, req_type_str,
|
||||
req_type, (void*)actual_type_return, (void*)actual_format_return, (void*)nitems_return,
|
||||
(void*)bytes_after_return, (void*)prop_return);
|
||||
XFree(propstr);
|
||||
XFree(req_type_str);
|
||||
}
|
||||
const int rc = XGetWindowProperty(display, w, property, long_offset, long_length, c_delete,
|
||||
req_type, actual_type_return, actual_format_return,
|
||||
nitems_return, bytes_after_return, prop_return);
|
||||
return write_result_log_expect_success(log, WLOG_WARN, file, fkt, line, display,
|
||||
"XGetWindowProperty", rc);
|
||||
}
|
||||
|
||||
BOOL IsGnome(void)
|
||||
{
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
char* env = getenv("DESKTOP_SESSION");
|
||||
return (env != nullptr && strcmp(env, "gnome") == 0);
|
||||
}
|
||||
|
||||
BOOL run_action_script(xfContext* xfc, const char* what, const char* arg, fn_action_script_run fkt,
|
||||
void* user)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
FILE* keyScript = nullptr;
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
rdpSettings* settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
const char* ActionScript = freerdp_settings_get_string(settings, FreeRDP_ActionScript);
|
||||
|
||||
xfc->actionScriptExists = winpr_PathFileExists(ActionScript);
|
||||
|
||||
if (!xfc->actionScriptExists)
|
||||
{
|
||||
WLog_DBG(TAG, "[ActionScript] no such script '%s'", ActionScript);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
char command[2048] = WINPR_C_ARRAY_INIT;
|
||||
(void)sprintf_s(command, sizeof(command), "%s %s", ActionScript, what);
|
||||
keyScript = popen(command, "r");
|
||||
|
||||
if (!keyScript)
|
||||
{
|
||||
WLog_ERR(TAG, "[ActionScript] Failed to execute '%s'", command);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
BOOL read_data = FALSE;
|
||||
char buffer[2048] = WINPR_C_ARRAY_INIT;
|
||||
while (fgets(buffer, sizeof(buffer), keyScript) != nullptr)
|
||||
{
|
||||
char* context = nullptr;
|
||||
(void)strtok_s(buffer, "\n", &context);
|
||||
|
||||
if (fkt)
|
||||
{
|
||||
if (!fkt(xfc, buffer, strnlen(buffer, sizeof(buffer)), user, what, arg))
|
||||
goto fail;
|
||||
}
|
||||
read_data = TRUE;
|
||||
}
|
||||
|
||||
rc = read_data;
|
||||
}
|
||||
if (!rc)
|
||||
WLog_ERR(TAG, "[ActionScript] No data returned from command '%s'", command);
|
||||
}
|
||||
fail:
|
||||
if (keyScript)
|
||||
pclose(keyScript);
|
||||
const BOOL res = rc || !xfc->actionScriptExists;
|
||||
if (!rc)
|
||||
xfc->actionScriptExists = FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
int LogDynAndXCopyArea_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Pixmap src, Window dest, GC gc, int src_x, int src_y,
|
||||
unsigned int width, unsigned int height, int dest_x, int dest_y)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
XWindowAttributes attr = WINPR_C_ARRAY_INIT;
|
||||
const Status rc = XGetWindowAttributes(display, dest, &attr);
|
||||
|
||||
write_log(log, log_level, file, fkt, line,
|
||||
"XCopyArea(%p, src: {%lu}, dest: [%d]{%lu, %lu, %d}, gc: {%p}, src_x: {%d}, "
|
||||
"src_y: {%d}, "
|
||||
"width: {%u}, "
|
||||
"height: {%u}, dest_x: {%d}, dest_y: {%d})",
|
||||
(void*)display, src, rc, dest, attr.root, attr.depth, (void*)gc, src_x, src_y,
|
||||
width, height, dest_x, dest_y);
|
||||
}
|
||||
|
||||
if ((width == 0) || (height == 0))
|
||||
{
|
||||
const DWORD lvl = WLOG_WARN;
|
||||
if (WLog_IsLevelActive(log, lvl))
|
||||
write_log(log, lvl, file, fkt, line, "XCopyArea(width=%u, height=%u) !", width, height);
|
||||
return Success;
|
||||
}
|
||||
|
||||
const int rc = XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XCopyArea", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXPutImage_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Drawable d, GC gc, XImage* image, int src_x, int src_y,
|
||||
int dest_x, int dest_y, unsigned int width, unsigned int height)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line,
|
||||
"XPutImage(%p, d: {%lu}, gc: {%p}, image: [%p]{%d}, src_x: {%d}, src_y: {%d}, "
|
||||
"dest_x: {%d}, "
|
||||
"dest_y: {%d}, width: {%u}, "
|
||||
"height: {%u})",
|
||||
(void*)display, d, (void*)gc, (void*)image, image ? image->depth : -1, src_x,
|
||||
src_y, dest_x, dest_y, width, height);
|
||||
}
|
||||
|
||||
if ((width == 0) || (height == 0))
|
||||
{
|
||||
const DWORD lvl = WLOG_WARN;
|
||||
if (WLog_IsLevelActive(log, lvl))
|
||||
write_log(log, lvl, file, fkt, line, "XPutImage(width=%u, height=%u) !", width, height);
|
||||
return Success;
|
||||
}
|
||||
|
||||
const int rc = XPutImage(display, d, gc, image, src_x, src_y, dest_x, dest_y, width, height);
|
||||
return write_result_log_expect_success(log, WLOG_WARN, file, fkt, line, display, "XPutImage",
|
||||
rc);
|
||||
}
|
||||
|
||||
/* be careful here.
|
||||
* XSendEvent returns Status, but implementation always returns 1
|
||||
*/
|
||||
Status LogDynAndXSendEvent_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, int propagate, long event_mask,
|
||||
XEvent* event_send)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line,
|
||||
"XSendEvent(d: {%p}, w: {%lu}, propagate: {%d}, event_mask: {%ld}, "
|
||||
"event_send: [%p]{TODO})",
|
||||
(void*)display, w, propagate, event_mask, (void*)event_send);
|
||||
}
|
||||
|
||||
const int rc = XSendEvent(display, w, propagate, event_mask, event_send);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSendEvent", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXFlush_ex(wLog* log, const char* file, const char* fkt, size_t line, Display* display)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XFlush(%p)", (void*)display);
|
||||
}
|
||||
|
||||
const int rc = XFlush(display);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XFlush", rc);
|
||||
}
|
||||
|
||||
Window LogDynAndXGetSelectionOwner_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Atom selection)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
char* selectionstr = Safe_XGetAtomName(log, display, selection);
|
||||
write_log(log, log_level, file, fkt, line, "XGetSelectionOwner(%p, %s)", (void*)display,
|
||||
selectionstr);
|
||||
XFree(selectionstr);
|
||||
}
|
||||
return XGetSelectionOwner(display, selection);
|
||||
}
|
||||
|
||||
int LogDynAndXDestroyWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window window)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XDestroyWindow(%p, %lu)", (void*)display,
|
||||
window);
|
||||
}
|
||||
const int rc = XDestroyWindow(display, window);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XDestroyWindow",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSync_ex(wLog* log, const char* file, const char* fkt, size_t line, Display* display,
|
||||
Bool discard)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XSync(%p, %d)", (void*)display, discard);
|
||||
}
|
||||
const int rc = XSync(display, discard);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSync", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXChangeWindowAttributes_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window window, unsigned long valuemask,
|
||||
XSetWindowAttributes* attributes)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XChangeWindowAttributes(%p, %lu, 0x%08lu, %p)",
|
||||
(void*)display, window, valuemask, (void*)attributes);
|
||||
}
|
||||
const int rc = XChangeWindowAttributes(display, window, valuemask, attributes);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
|
||||
"XChangeWindowAttributes", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSetTransientForHint_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window window, Window prop_window)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XSetTransientForHint(%p, %lu, %lu)",
|
||||
(void*)display, window, prop_window);
|
||||
}
|
||||
const int rc = XSetTransientForHint(display, window, prop_window);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
|
||||
"XSetTransientForHint", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXCloseDisplay_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XCloseDisplay(%p)", (void*)display);
|
||||
}
|
||||
const int rc = XCloseDisplay(display);
|
||||
return write_result_log_expect_success(log, WLOG_WARN, file, fkt, line, display,
|
||||
"XCloseDisplay", rc);
|
||||
}
|
||||
|
||||
XImage* LogDynAndXCreateImage_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Visual* visual, unsigned int depth, int format,
|
||||
int offset, char* data, unsigned int width, unsigned int height,
|
||||
int bitmap_pad, int bytes_per_line)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XCreateImage(%p)", (void*)display);
|
||||
}
|
||||
return XCreateImage(display, visual, depth, format, offset, data, width, height, bitmap_pad,
|
||||
bytes_per_line);
|
||||
}
|
||||
|
||||
Window LogDynAndXCreateWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window parent, int x, int y, unsigned int width,
|
||||
unsigned int height, unsigned int border_width, int depth,
|
||||
unsigned int c_class, Visual* visual, unsigned long valuemask,
|
||||
XSetWindowAttributes* attributes)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XCreateWindow(%p)", (void*)display);
|
||||
}
|
||||
return XCreateWindow(display, parent, x, y, width, height, border_width, depth, c_class, visual,
|
||||
valuemask, attributes);
|
||||
}
|
||||
|
||||
GC LogDynAndXCreateGC_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Drawable d, unsigned long valuemask, XGCValues* values)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XCreateGC(%p)", (void*)display);
|
||||
}
|
||||
return XCreateGC(display, d, valuemask, values);
|
||||
}
|
||||
|
||||
int LogDynAndXFreeGC_ex(wLog* log, const char* file, const char* fkt, size_t line, Display* display,
|
||||
GC gc)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XFreeGC(%p)", (void*)display);
|
||||
}
|
||||
const int rc = XFreeGC(display, gc);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XFreeGC", rc);
|
||||
}
|
||||
|
||||
Pixmap LogDynAndXCreatePixmap_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Drawable d, unsigned int width,
|
||||
unsigned int height, unsigned int depth)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XCreatePixmap(%p, 0x%08lu, %u, %u, %u)",
|
||||
(void*)display, d, width, height, depth);
|
||||
}
|
||||
return XCreatePixmap(display, d, width, height, depth);
|
||||
}
|
||||
|
||||
int LogDynAndXFreePixmap_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Pixmap pixmap)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XFreePixmap(%p)", (void*)display);
|
||||
}
|
||||
const int rc = XFreePixmap(display, pixmap);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XFreePixmap", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSetSelectionOwner_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Atom selection, Window owner, Time time)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
char* selectionstr = Safe_XGetAtomName(log, display, selection);
|
||||
write_log(log, log_level, file, fkt, line, "XSetSelectionOwner(%p, %s, 0x%08lu, %lu)",
|
||||
(void*)display, selectionstr, owner, time);
|
||||
XFree(selectionstr);
|
||||
}
|
||||
const int rc = XSetSelectionOwner(display, selection, owner, time);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
|
||||
"XSetSelectionOwner", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSetForeground_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, unsigned long foreground)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XSetForeground(%p, %p, 0x%08lu)",
|
||||
(void*)display, (void*)gc, foreground);
|
||||
}
|
||||
const int rc = XSetForeground(display, gc, foreground);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetForeground",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXMoveWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, int x, int y)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XMoveWindow(%p, 0x%08lu, %d, %d)",
|
||||
(void*)display, w, x, y);
|
||||
}
|
||||
const int rc = XMoveWindow(display, w, x, y);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XMoveWindow", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSetFillStyle_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, int fill_style)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XSetFillStyle(%p, %p, %d)", (void*)display,
|
||||
(void*)gc, fill_style);
|
||||
}
|
||||
const int rc = XSetFillStyle(display, gc, fill_style);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetFillStyle",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSetFunction_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, int function)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XSetFunction(%p, %p, %d)", (void*)display,
|
||||
(void*)gc, function);
|
||||
}
|
||||
const int rc = XSetFunction(display, gc, function);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetFunction",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXRaiseWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XRaiseWindow(%p, %lu)", (void*)display, w);
|
||||
}
|
||||
const int rc = XRaiseWindow(display, w);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XRaiseWindow",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXMapWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XMapWindow(%p, %lu)", (void*)display, w);
|
||||
}
|
||||
const int rc = XMapWindow(display, w);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XMapWindow", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXUnmapWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XUnmapWindow(%p, %lu)", (void*)display, w);
|
||||
}
|
||||
const int rc = XUnmapWindow(display, w);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XUnmapWindow",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXMoveResizeWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, int x, int y, unsigned int width,
|
||||
unsigned int height)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XMoveResizeWindow(%p, %lu, %d, %d, %u, %u)",
|
||||
(void*)display, w, x, y, width, height);
|
||||
}
|
||||
const int rc = XMoveResizeWindow(display, w, x, y, width, height);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
|
||||
"XMoveResizeWindow", rc);
|
||||
}
|
||||
|
||||
Status LogDynAndXWithdrawWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, int screen_number)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XWithdrawWindow(%p, %lu, %d)", (void*)display,
|
||||
w, screen_number);
|
||||
}
|
||||
const Status rc = XWithdrawWindow(display, w, screen_number);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XWithdrawWindow",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXResizeWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, unsigned int width, unsigned int height)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XResizeWindow(%p, %lu, %u, %u)", (void*)display,
|
||||
w, width, height);
|
||||
}
|
||||
const int rc = XResizeWindow(display, w, width, height);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XResizeWindow",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXClearWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XClearWindow(%p, %lu)", (void*)display, w);
|
||||
}
|
||||
const int rc = XClearWindow(display, w);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XClearWindow",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSetBackground_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, unsigned long background)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XSetBackground(%p, %p, %lu)", (void*)display,
|
||||
(void*)gc, background);
|
||||
}
|
||||
const int rc = XSetBackground(display, gc, background);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetBackground",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSetClipMask_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, Pixmap pixmap)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XSetClipMask(%p, %p, %lu)", (void*)display,
|
||||
(void*)gc, pixmap);
|
||||
}
|
||||
const int rc = XSetClipMask(display, gc, pixmap);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetClipMask",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXFillRectangle_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, GC gc, int x, int y, unsigned int width,
|
||||
unsigned int height)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XFillRectangle(%p, %lu, %p, %d, %d, %u, %u)",
|
||||
(void*)display, w, (void*)gc, x, y, width, height);
|
||||
}
|
||||
const int rc = XFillRectangle(display, w, gc, x, y, width, height);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XFillRectangle",
|
||||
rc);
|
||||
}
|
||||
|
||||
int LogDynAndXSetRegion_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, Region r)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XSetRegion(%p, %p, %p)", (void*)display,
|
||||
(void*)gc, (void*)r);
|
||||
}
|
||||
const int rc = XSetRegion(display, gc, r);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetRegion", rc);
|
||||
}
|
||||
|
||||
int LogDynAndXReparentWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Window parent, int x, int y)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XReparentWindow(%p, %lu, %lu, %d, %d)",
|
||||
(void*)display, w, parent, x, y);
|
||||
}
|
||||
const int rc = XReparentWindow(display, w, parent, x, y);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XReparentWindow",
|
||||
rc);
|
||||
}
|
||||
|
||||
char* getConfigOption(BOOL system, const char* option)
|
||||
{
|
||||
char* res = nullptr;
|
||||
WINPR_JSON* file = freerdp_GetJSONConfigFile(system, "xfreerdp.json");
|
||||
if (!file)
|
||||
return nullptr;
|
||||
|
||||
WINPR_JSON* obj = WINPR_JSON_GetObjectItemCaseSensitive(file, option);
|
||||
if (obj)
|
||||
{
|
||||
const char* val = WINPR_JSON_GetStringValue(obj);
|
||||
if (val)
|
||||
res = _strdup(val);
|
||||
}
|
||||
WINPR_JSON_Delete(file);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int LogDynAndXRestackWindows_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window* windows, int nwindows)
|
||||
{
|
||||
if (WLog_IsLevelActive(log, log_level))
|
||||
{
|
||||
write_log(log, log_level, file, fkt, line, "XRestackWindows(%p, %p, %d)", (void*)display,
|
||||
(const void*)windows, nwindows);
|
||||
}
|
||||
const int rc = XRestackWindows(display, windows, nwindows);
|
||||
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XRestackWindows",
|
||||
rc);
|
||||
}
|
||||
300
third_party/FreeRDP/client/X11/xf_utils.h
vendored
Normal file
300
third_party/FreeRDP/client/X11/xf_utils.h
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 helper utilities
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyringht 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include "xfreerdp.h"
|
||||
|
||||
const char* x11_error_to_string(xfContext* xfc, int error, char* buffer, size_t size);
|
||||
|
||||
#define X_GET_ATOM_VAR_NAME(x) #x
|
||||
#define Safe_XGetAtomName(log, display, atom) \
|
||||
Safe_XGetAtomNameEx((log), (display), (atom), X_GET_ATOM_VAR_NAME(atom))
|
||||
char* Safe_XGetAtomNameEx(wLog* log, Display* display, Atom atom, const char* varname);
|
||||
Atom Logging_XInternAtom(wLog* log, Display* display, _Xconst char* atom_name, Bool only_if_exists);
|
||||
|
||||
typedef BOOL (*fn_action_script_run)(xfContext* xfc, const char* buffer, size_t size, void* user,
|
||||
const char* what, const char* arg);
|
||||
BOOL run_action_script(xfContext* xfc, const char* what, const char* arg, fn_action_script_run fkt,
|
||||
void* user);
|
||||
|
||||
#define LogDynAndXCreatePixmap(log, display, d, width, height, depth) \
|
||||
LogDynAndXCreatePixmap_ex((log), __FILE__, __func__, __LINE__, (display), (d), (width), \
|
||||
(height), (depth))
|
||||
|
||||
Pixmap LogDynAndXCreatePixmap_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Drawable d, unsigned int width,
|
||||
unsigned int height, unsigned int depth);
|
||||
|
||||
#define LogDynAndXFreePixmap(log, display, pixmap) \
|
||||
LogDynAndXFreePixmap_ex(log, __FILE__, __func__, __LINE__, (display), (pixmap))
|
||||
|
||||
int LogDynAndXFreePixmap_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Pixmap pixmap);
|
||||
|
||||
#define LogDynAndXCreateWindow(log, display, parent, x, y, width, height, border_width, depth, \
|
||||
class, visual, valuemask, attributes) \
|
||||
LogDynAndXCreateWindow_ex((log), __FILE__, __func__, __LINE__, (display), (parent), (x), (y), \
|
||||
(width), (height), (border_width), (depth), (class), (visual), \
|
||||
(valuemask), (attributes))
|
||||
|
||||
Window LogDynAndXCreateWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window parent, int x, int y, unsigned int width,
|
||||
unsigned int height, unsigned int border_width, int depth,
|
||||
unsigned int c_class, Visual* visual, unsigned long valuemask,
|
||||
XSetWindowAttributes* attributes);
|
||||
|
||||
#define LogDynAndXRaiseWindow(log, display, w) \
|
||||
LogDynAndXRaiseWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w))
|
||||
|
||||
int LogDynAndXRaiseWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w);
|
||||
|
||||
#define LogDynAndXMapWindow(log, display, w) \
|
||||
LogDynAndXMapWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w))
|
||||
|
||||
int LogDynAndXMapWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w);
|
||||
|
||||
#define LogDynAndXUnmapWindow(log, display, w) \
|
||||
LogDynAndXUnmapWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w))
|
||||
|
||||
int LogDynAndXUnmapWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w);
|
||||
|
||||
#define LogDynAndXMoveResizeWindow(log, display, w, x, y, width, height) \
|
||||
LogDynAndXMoveResizeWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w), (x), (y), \
|
||||
(width), (height))
|
||||
|
||||
int LogDynAndXMoveResizeWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, int x, int y, unsigned int width,
|
||||
unsigned int height);
|
||||
|
||||
#define LogDynAndXWithdrawWindow(log, display, w, screen_number) \
|
||||
LogDynAndXWithdrawWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w), \
|
||||
(screen_number))
|
||||
|
||||
Status LogDynAndXWithdrawWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, int screen_number);
|
||||
|
||||
#define LogDynAndXMoveWindow(log, display, w, x, y) \
|
||||
LogDynAndXMoveWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w), (x), (y))
|
||||
|
||||
int LogDynAndXMoveWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, int x, int y);
|
||||
|
||||
#define LogDynAndXResizeWindow(log, display, w, width, height) \
|
||||
LogDynAndXResizeWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w), (width), \
|
||||
(height))
|
||||
|
||||
int LogDynAndXResizeWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, unsigned int width, unsigned int height);
|
||||
|
||||
#define LogDynAndXClearWindow(log, display, w) \
|
||||
LogDynAndXClearWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w))
|
||||
|
||||
int LogDynAndXClearWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w);
|
||||
|
||||
#define LogDynAndXGetWindowProperty(log, display, w, property, long_offset, long_length, delete, \
|
||||
req_type, actual_type_return, actual_format_return, \
|
||||
nitems_return, bytes_after_return, prop_return) \
|
||||
LogDynAndXGetWindowProperty_ex((log), __FILE__, __func__, __LINE__, (display), (w), \
|
||||
(property), (long_offset), (long_length), (delete), (req_type), \
|
||||
(actual_type_return), (actual_format_return), (nitems_return), \
|
||||
(bytes_after_return), (prop_return))
|
||||
|
||||
int LogDynAndXGetWindowProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Atom property, long long_offset,
|
||||
long long_length, Bool c_delete, Atom req_type,
|
||||
Atom* actual_type_return, int* actual_format_return,
|
||||
unsigned long* nitems_return, unsigned long* bytes_after_return,
|
||||
unsigned char** prop_return);
|
||||
|
||||
#define LogDynAndXReparentWindow(log, display, w, parent, x, y) \
|
||||
LogDynAndXReparentWindow_ex((log), __FILE__, __func__, __LINE__, (display), (w), (parent), \
|
||||
(x), (y))
|
||||
|
||||
int LogDynAndXReparentWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Window parent, int x, int y);
|
||||
|
||||
#define LogDynAndXChangeProperty(log, display, w, property, type, format, mode, data, nelements) \
|
||||
LogDynAndXChangeProperty_ex((log), __FILE__, __func__, __LINE__, (display), (w), (property), \
|
||||
(type), (format), (mode), (data), (nelements))
|
||||
int LogDynAndXChangeProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Atom property, Atom type, int format,
|
||||
int mode, _Xconst unsigned char* data, int nelements);
|
||||
|
||||
#define LogDynAndXDeleteProperty(log, display, w, property) \
|
||||
LogDynAndXDeleteProperty_ex((log), __FILE__, __func__, __LINE__, (display), (w), (property))
|
||||
int LogDynAndXDeleteProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Atom property);
|
||||
|
||||
#define LogDynAndXConvertSelection(log, display, selection, target, property, requestor, time) \
|
||||
LogDynAndXConvertSelection_ex((log), __FILE__, __func__, __LINE__, (display), (selection), \
|
||||
(target), (property), (requestor), (time))
|
||||
int LogDynAndXConvertSelection_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Atom selection, Atom target, Atom property,
|
||||
Window requestor, Time time);
|
||||
|
||||
#define LogDynAndXCreateGC(log, display, d, valuemask, values) \
|
||||
LogDynAndXCreateGC_ex(log, __FILE__, __func__, __LINE__, (display), (d), (valuemask), (values))
|
||||
|
||||
GC LogDynAndXCreateGC_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Drawable d, unsigned long valuemask, XGCValues* values);
|
||||
|
||||
#define LogDynAndXFreeGC(log, display, gc) \
|
||||
LogDynAndXFreeGC_ex(log, __FILE__, __func__, __LINE__, (display), (gc))
|
||||
|
||||
int LogDynAndXFreeGC_ex(wLog* log, const char* file, const char* fkt, size_t line, Display* display,
|
||||
GC gc);
|
||||
|
||||
#define LogDynAndXCreateImage(log, display, visual, depth, format, offset, data, width, height, \
|
||||
bitmap_pad, bytes_per_line) \
|
||||
LogDynAndXCreateImage_ex(log, __FILE__, __func__, __LINE__, (display), (visual), (depth), \
|
||||
(format), (offset), (data), (width), (height), (bitmap_pad), \
|
||||
(bytes_per_line))
|
||||
XImage* LogDynAndXCreateImage_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Visual* visual, unsigned int depth, int format,
|
||||
int offset, char* data, unsigned int width, unsigned int height,
|
||||
int bitmap_pad, int bytes_per_line);
|
||||
|
||||
#define LogDynAndXPutImage(log, display, d, gc, image, src_x, src_y, dest_x, dest_y, width, \
|
||||
height) \
|
||||
LogDynAndXPutImage_ex(log, __FILE__, __func__, __LINE__, (display), (d), (gc), (image), \
|
||||
(src_x), (src_y), (dest_x), (dest_y), (width), (height))
|
||||
int LogDynAndXPutImage_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Drawable d, GC gc, XImage* image, int src_x, int src_y,
|
||||
int dest_x, int dest_y, unsigned int width, unsigned int height);
|
||||
|
||||
#define LogDynAndXCopyArea(log, display, src, dest, gc, src_x, src_y, width, height, dest_x, \
|
||||
dest_y) \
|
||||
LogDynAndXCopyArea_ex(log, __FILE__, __func__, __LINE__, (display), (src), (dest), (gc), \
|
||||
(src_x), (src_y), (width), (height), (dest_x), (dest_y))
|
||||
extern int LogDynAndXCopyArea_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Pixmap src, Window dest, GC gc, int src_x,
|
||||
int src_y, unsigned int width, unsigned int height, int dest_x,
|
||||
int dest_y);
|
||||
|
||||
#define LogDynAndXSendEvent(log, display, w, propagate, event_mask, event_send) \
|
||||
LogDynAndXSendEvent_ex(log, __FILE__, __func__, __LINE__, (display), (w), (propagate), \
|
||||
(event_mask), (event_send))
|
||||
extern Status LogDynAndXSendEvent_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, Bool propagate, long event_mask,
|
||||
XEvent* event_send);
|
||||
|
||||
#define LogDynAndXFlush(log, display) \
|
||||
LogDynAndXFlush_ex(log, __FILE__, __func__, __LINE__, (display))
|
||||
extern Status LogDynAndXFlush_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display);
|
||||
|
||||
#define LogDynAndXSync(log, display, discard) \
|
||||
LogDynAndXSync_ex(log, __FILE__, __func__, __LINE__, (display), (discard))
|
||||
extern int LogDynAndXSync_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Bool discard);
|
||||
|
||||
#define LogDynAndXGetSelectionOwner(log, display, selection) \
|
||||
LogDynAndXGetSelectionOwner_ex(log, __FILE__, __func__, __LINE__, (display), (selection))
|
||||
extern Window LogDynAndXGetSelectionOwner_ex(wLog* log, const char* file, const char* fkt,
|
||||
size_t line, Display* display, Atom selection);
|
||||
|
||||
#define LogDynAndXSetSelectionOwner(log, display, selection, owner, time) \
|
||||
LogDynAndXSetSelectionOwner_ex(log, __FILE__, __func__, __LINE__, (display), (selection), \
|
||||
(owner), (time))
|
||||
extern int LogDynAndXSetSelectionOwner_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Atom selection, Window owner,
|
||||
Time time);
|
||||
|
||||
#define LogDynAndXDestroyWindow(log, display, window) \
|
||||
LogDynAndXDestroyWindow_ex(log, __FILE__, __func__, __LINE__, (display), (window))
|
||||
extern int LogDynAndXDestroyWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window window);
|
||||
|
||||
#define LogDynAndXChangeWindowAttributes(log, display, window, valuemask, attributes) \
|
||||
LogDynAndXChangeWindowAttributes_ex(log, __FILE__, __func__, __LINE__, (display), (window), \
|
||||
(valuemask), (attributes))
|
||||
extern int LogDynAndXChangeWindowAttributes_ex(wLog* log, const char* file, const char* fkt,
|
||||
size_t line, Display* display, Window window,
|
||||
unsigned long valuemask,
|
||||
XSetWindowAttributes* attributes);
|
||||
|
||||
#define LogDynAndXSetTransientForHint(log, display, window, prop_window) \
|
||||
LogDynAndXSetTransientForHint_ex(log, __FILE__, __func__, __LINE__, (display), (window), \
|
||||
(prop_window))
|
||||
extern int LogDynAndXSetTransientForHint_ex(wLog* log, const char* file, const char* fkt,
|
||||
size_t line, Display* display, Window window,
|
||||
Window prop_window);
|
||||
|
||||
#define LogDynAndXCloseDisplay(log, display) \
|
||||
LogDynAndXCloseDisplay_ex(log, __FILE__, __func__, __LINE__, (display))
|
||||
extern int LogDynAndXCloseDisplay_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display);
|
||||
|
||||
#define LogDynAndXSetClipMask(log, display, gc, pixmap) \
|
||||
LogDynAndXSetClipMask_ex(log, __FILE__, __func__, __LINE__, (display), (gc), (pixmap))
|
||||
extern int LogDynAndXSetClipMask_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, Pixmap pixmap);
|
||||
|
||||
#define LogDynAndXSetRegion(log, display, gc, r) \
|
||||
LogDynAndXSetRegion_ex(log, __FILE__, __func__, __LINE__, (display), (gc), (r))
|
||||
extern int LogDynAndXSetRegion_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, Region r);
|
||||
|
||||
#define LogDynAndXSetBackground(log, display, gc, background) \
|
||||
LogDynAndXSetBackground_ex(log, __FILE__, __func__, __LINE__, (display), (gc), (background))
|
||||
extern int LogDynAndXSetBackground_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, unsigned long background);
|
||||
|
||||
#define LogDynAndXSetForeground(log, display, gc, foreground) \
|
||||
LogDynAndXSetForeground_ex(log, __FILE__, __func__, __LINE__, (display), (gc), (foreground))
|
||||
extern int LogDynAndXSetForeground_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, unsigned long foreground);
|
||||
|
||||
#define LogDynAndXSetFillStyle(log, display, gc, fill_style) \
|
||||
LogDynAndXSetFillStyle_ex(log, __FILE__, __func__, __LINE__, (display), (gc), (fill_style))
|
||||
extern int LogDynAndXSetFillStyle_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, int fill_style);
|
||||
|
||||
#define LogDynAndXFillRectangle(log, display, w, gc, x, y, width, height) \
|
||||
LogDynAndXFillRectangle_ex(log, __FILE__, __func__, __LINE__, (display), (w), (gc), (x), (y), \
|
||||
(width), (height))
|
||||
extern int LogDynAndXFillRectangle_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window w, GC gc, int x, int y,
|
||||
unsigned int width, unsigned int height);
|
||||
|
||||
#define LogDynAndXSetFunction(log, display, gc, function) \
|
||||
LogDynAndXSetFunction_ex(log, __FILE__, __func__, __LINE__, (display), (gc), (function))
|
||||
extern int LogDynAndXSetFunction_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, GC gc, int function);
|
||||
|
||||
#define LogDynAndXRestackWindows(log, display, windows, count) \
|
||||
LogDynAndXRestackWindows_ex(log, __FILE__, __func__, __LINE__, (display), (windows), (count))
|
||||
extern int LogDynAndXRestackWindows_ex(wLog* log, const char* file, const char* fkt, size_t line,
|
||||
Display* display, Window* windows, int nwindows);
|
||||
|
||||
BOOL IsGnome(void);
|
||||
|
||||
char* getConfigOption(BOOL system, const char* option);
|
||||
|
||||
const char* request_code_2_str(int code);
|
||||
141
third_party/FreeRDP/client/X11/xf_video.c
vendored
Normal file
141
third_party/FreeRDP/client/X11/xf_video.c
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Video Optimized Remoting Virtual Channel Extension for X11
|
||||
*
|
||||
* Copyright 2017 David Fort <contact@hardening-consulting.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/assert.h>
|
||||
#include <freerdp/client/geometry.h>
|
||||
#include <freerdp/client/video.h>
|
||||
#include <freerdp/gdi/video.h>
|
||||
|
||||
#include "xf_video.h"
|
||||
#include "xf_utils.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("video")
|
||||
|
||||
typedef struct
|
||||
{
|
||||
VideoSurface base;
|
||||
XImage* image;
|
||||
} xfVideoSurface;
|
||||
|
||||
static VideoSurface* xfVideoCreateSurface(VideoClientContext* video, UINT32 x, UINT32 y,
|
||||
UINT32 width, UINT32 height)
|
||||
{
|
||||
xfContext* xfc = nullptr;
|
||||
xfVideoSurface* ret = nullptr;
|
||||
|
||||
WINPR_ASSERT(video);
|
||||
ret = (xfVideoSurface*)VideoClient_CreateCommonContext(sizeof(xfContext), x, y, width, height);
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
|
||||
xfc = (xfContext*)video->custom;
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
ret->image = LogDynAndXCreateImage(xfc->log, xfc->display, xfc->visual,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, xfc->depth), ZPixmap, 0,
|
||||
(char*)ret->base.data, width, height, 8,
|
||||
WINPR_ASSERTING_INT_CAST(int, ret->base.scanline));
|
||||
|
||||
if (!ret->image)
|
||||
{
|
||||
WLog_ERR(TAG, "unable to create surface image");
|
||||
VideoClient_DestroyCommonContext(&ret->base);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &ret->base;
|
||||
}
|
||||
|
||||
static BOOL xfVideoShowSurface(VideoClientContext* video, const VideoSurface* surface,
|
||||
WINPR_ATTR_UNUSED UINT32 destinationWidth,
|
||||
WINPR_ATTR_UNUSED UINT32 destinationHeight)
|
||||
{
|
||||
const xfVideoSurface* xfSurface = (const xfVideoSurface*)surface;
|
||||
xfContext* xfc = nullptr;
|
||||
const rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(video);
|
||||
WINPR_ASSERT(xfSurface);
|
||||
|
||||
xfc = video->custom;
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
#ifdef WITH_XRENDER
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ||
|
||||
freerdp_settings_get_bool(settings, FreeRDP_MultiTouchGestures))
|
||||
{
|
||||
LogDynAndXPutImage(xfc->log, xfc->display, xfc->primary, xfc->gc, xfSurface->image, 0, 0,
|
||||
WINPR_ASSERTING_INT_CAST(int, surface->x),
|
||||
WINPR_ASSERTING_INT_CAST(int, surface->y), surface->w, surface->h);
|
||||
xf_draw_screen(xfc, WINPR_ASSERTING_INT_CAST(int32_t, surface->x),
|
||||
WINPR_ASSERTING_INT_CAST(int32_t, surface->y),
|
||||
WINPR_ASSERTING_INT_CAST(int32_t, surface->w),
|
||||
WINPR_ASSERTING_INT_CAST(int32_t, surface->h));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LogDynAndXPutImage(xfc->log, xfc->display, xfc->drawable, xfc->gc, xfSurface->image, 0, 0,
|
||||
WINPR_ASSERTING_INT_CAST(int, surface->x),
|
||||
WINPR_ASSERTING_INT_CAST(int, surface->y), surface->w, surface->h);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL xfVideoDeleteSurface(VideoClientContext* video, VideoSurface* surface)
|
||||
{
|
||||
xfVideoSurface* xfSurface = (xfVideoSurface*)surface;
|
||||
|
||||
WINPR_UNUSED(video);
|
||||
|
||||
if (xfSurface)
|
||||
XFree(xfSurface->image);
|
||||
|
||||
VideoClient_DestroyCommonContext(surface);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void xf_video_control_init(xfContext* xfc, VideoClientContext* video)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
WINPR_ASSERT(video);
|
||||
|
||||
gdi_video_control_init(xfc->common.context.gdi, video);
|
||||
|
||||
/* X11 needs to be able to handle 32bpp colors directly. */
|
||||
if (xfc->depth >= 24)
|
||||
{
|
||||
video->custom = xfc;
|
||||
video->createSurface = xfVideoCreateSurface;
|
||||
video->showSurface = xfVideoShowSurface;
|
||||
video->deleteSurface = xfVideoDeleteSurface;
|
||||
}
|
||||
}
|
||||
|
||||
void xf_video_control_uninit(xfContext* xfc, VideoClientContext* video)
|
||||
{
|
||||
WINPR_ASSERT(xfc);
|
||||
gdi_video_control_uninit(xfc->common.context.gdi, video);
|
||||
}
|
||||
37
third_party/FreeRDP/client/X11/xf_video.h
vendored
Normal file
37
third_party/FreeRDP/client/X11/xf_video.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Video Optimized Remoting Virtual Channel Extension for X11
|
||||
*
|
||||
* Copyright 2017 David Fort <contact@hardening-consulting.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 CLIENT_X11_XF_VIDEO_H_
|
||||
#define CLIENT_X11_XF_VIDEO_H_
|
||||
|
||||
#include <freerdp/client/video.h>
|
||||
|
||||
#include "xf_types.h"
|
||||
|
||||
typedef struct s_xfVideoContext xfVideoContext;
|
||||
|
||||
void xf_video_control_init(xfContext* xfc, VideoClientContext* video);
|
||||
void xf_video_control_uninit(xfContext* xfc, VideoClientContext* video);
|
||||
|
||||
void xf_video_free(xfVideoContext* context);
|
||||
|
||||
WINPR_ATTR_MALLOC(xf_video_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
xfVideoContext* xf_video_new(xfContext* xfc);
|
||||
|
||||
#endif /* CLIENT_X11_XF_VIDEO_H_ */
|
||||
1647
third_party/FreeRDP/client/X11/xf_window.c
vendored
Normal file
1647
third_party/FreeRDP/client/X11/xf_window.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
140
third_party/FreeRDP/client/X11/xf_window.h
vendored
Normal file
140
third_party/FreeRDP/client/X11/xf_window.h
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Windows
|
||||
*
|
||||
* Copyright 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_X11_WINDOW_H
|
||||
#define FREERDP_CLIENT_X11_WINDOW_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <winpr/platform.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/gdi/gfx.h>
|
||||
|
||||
#include "xf_types.h"
|
||||
#include "xf_rail.h"
|
||||
#include "xf_floatbar.h"
|
||||
|
||||
typedef struct xf_window xfWindow;
|
||||
|
||||
// Extended ICCM flags http://standards.freedesktop.org/wm-spec/wm-spec-latest.html
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
|
||||
|
||||
#define NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
|
||||
#define NET_WM_MOVERESIZE_SIZE_TOP 1
|
||||
#define NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
|
||||
#define NET_WM_MOVERESIZE_SIZE_RIGHT 3
|
||||
#define NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
|
||||
#define NET_WM_MOVERESIZE_SIZE_BOTTOM 5
|
||||
#define NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
|
||||
#define NET_WM_MOVERESIZE_SIZE_LEFT 7
|
||||
#define NET_WM_MOVERESIZE_MOVE 8 /* movement only */
|
||||
#define NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
|
||||
#define NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
|
||||
#define NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
|
||||
|
||||
#define NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||
#define NET_WM_STATE_ADD 1 /* add/set property */
|
||||
#define NET_WM_STATE_TOGGLE 2 /* toggle property */
|
||||
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
|
||||
struct xf_window
|
||||
{
|
||||
GC gc;
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
int width;
|
||||
int height;
|
||||
int shmid;
|
||||
Window handle;
|
||||
Window* xfwin;
|
||||
xfFloatbar* floatbar;
|
||||
BOOL decorations;
|
||||
BOOL is_mapped;
|
||||
BOOL is_transient;
|
||||
};
|
||||
|
||||
void xf_ewmhints_init(xfContext* xfc);
|
||||
|
||||
BOOL xf_GetWorkArea(xfContext* xfc);
|
||||
|
||||
void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen);
|
||||
void xf_SetWindowMinimized(xfContext* xfc, xfWindow* window);
|
||||
void xf_SetWindowDecorations(xfContext* xfc, Window window, BOOL show);
|
||||
void xf_SetWindowUnlisted(xfContext* xfc, Window window);
|
||||
|
||||
void xf_DestroyDesktopWindow(xfContext* xfc, xfWindow* window);
|
||||
|
||||
WINPR_ATTR_MALLOC(xf_DestroyDesktopWindow, 2)
|
||||
xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, int height);
|
||||
|
||||
void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int height);
|
||||
|
||||
Window xf_CreateDummyWindow(xfContext* xfc);
|
||||
void xf_DestroyDummyWindow(xfContext* xfc, Window window);
|
||||
|
||||
BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int length,
|
||||
unsigned long* nitems, unsigned long* bytes, BYTE** prop);
|
||||
void xf_SendClientEvent(xfContext* xfc, Window window, Atom atom, unsigned int numArgs, ...);
|
||||
|
||||
BOOL xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow);
|
||||
int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow);
|
||||
|
||||
BOOL xf_AppWindowResize(xfContext* xfc, xfAppWindow* appWindow);
|
||||
|
||||
void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, const char* name);
|
||||
void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height);
|
||||
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, UINT32 rectsOffsetX,
|
||||
UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects);
|
||||
void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style);
|
||||
void xf_SetWindowActions(xfContext* xfc, xfAppWindow* appWindow);
|
||||
void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width,
|
||||
int height);
|
||||
UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface);
|
||||
|
||||
void xf_AppWindowDestroyImage(xfAppWindow* appWindow);
|
||||
void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow);
|
||||
void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth, int maxHeight,
|
||||
int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight,
|
||||
int maxTrackWidth, int maxTrackHeight);
|
||||
void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction, int x, int y);
|
||||
void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow);
|
||||
|
||||
#define xf_AppWindowFromX11Window(xfc, wnd) \
|
||||
xf_AppWindowFromX11WindowFrom((xfc), (wnd), __FILE__, __func__, __LINE__)
|
||||
WINPR_ATTR_MALLOC(xf_rail_return_windowFrom, 1)
|
||||
xfAppWindow* xf_AppWindowFromX11WindowFrom(xfContext* xfc, Window wnd, const char* file,
|
||||
const char* fkt, size_t line);
|
||||
|
||||
#define xf_AppWindowsLock(xfc) xfAppWindowsLockFrom((xfc), __FILE__, __func__, __LINE__)
|
||||
void xfAppWindowsLockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line);
|
||||
|
||||
#define xf_AppWindowsUnlock(xfc) xfAppWindowsUnlockFrom((xfc), __FILE__, __func__, __LINE__)
|
||||
void xfAppWindowsUnlockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line);
|
||||
|
||||
const char* window_styles_to_string(UINT32 style, char* buffer, size_t length);
|
||||
const char* window_styles_ex_to_string(UINT32 styleEx, char* buffer, size_t length);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_WINDOW_H */
|
||||
157
third_party/FreeRDP/client/X11/xf_x11_utils.c
vendored
Normal file
157
third_party/FreeRDP/client/X11/xf_x11_utils.c
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 helper utilities
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyringht 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Do not include! X11 has conflicting defines #include "xf_utils.h"
|
||||
const char* request_code_2_str(int code);
|
||||
|
||||
#include <X11/Xproto.h>
|
||||
|
||||
const char* request_code_2_str(int code)
|
||||
{
|
||||
#define CASE2STR(x) \
|
||||
case x: \
|
||||
return #x
|
||||
switch (code)
|
||||
{
|
||||
CASE2STR(X_CreateWindow);
|
||||
CASE2STR(X_ChangeWindowAttributes);
|
||||
CASE2STR(X_GetWindowAttributes);
|
||||
CASE2STR(X_DestroyWindow);
|
||||
CASE2STR(X_DestroySubwindows);
|
||||
CASE2STR(X_ChangeSaveSet);
|
||||
CASE2STR(X_ReparentWindow);
|
||||
CASE2STR(X_MapWindow);
|
||||
CASE2STR(X_MapSubwindows);
|
||||
CASE2STR(X_UnmapWindow);
|
||||
CASE2STR(X_UnmapSubwindows);
|
||||
CASE2STR(X_ConfigureWindow);
|
||||
CASE2STR(X_CirculateWindow);
|
||||
CASE2STR(X_GetGeometry);
|
||||
CASE2STR(X_QueryTree);
|
||||
CASE2STR(X_InternAtom);
|
||||
CASE2STR(X_GetAtomName);
|
||||
CASE2STR(X_ChangeProperty);
|
||||
CASE2STR(X_DeleteProperty);
|
||||
CASE2STR(X_GetProperty);
|
||||
CASE2STR(X_ListProperties);
|
||||
CASE2STR(X_SetSelectionOwner);
|
||||
CASE2STR(X_GetSelectionOwner);
|
||||
CASE2STR(X_ConvertSelection);
|
||||
CASE2STR(X_SendEvent);
|
||||
CASE2STR(X_GrabPointer);
|
||||
CASE2STR(X_UngrabPointer);
|
||||
CASE2STR(X_GrabButton);
|
||||
CASE2STR(X_UngrabButton);
|
||||
CASE2STR(X_ChangeActivePointerGrab);
|
||||
CASE2STR(X_GrabKeyboard);
|
||||
CASE2STR(X_UngrabKeyboard);
|
||||
CASE2STR(X_GrabKey);
|
||||
CASE2STR(X_UngrabKey);
|
||||
CASE2STR(X_AllowEvents);
|
||||
CASE2STR(X_GrabServer);
|
||||
CASE2STR(X_UngrabServer);
|
||||
CASE2STR(X_QueryPointer);
|
||||
CASE2STR(X_GetMotionEvents);
|
||||
CASE2STR(X_TranslateCoords);
|
||||
CASE2STR(X_WarpPointer);
|
||||
CASE2STR(X_SetInputFocus);
|
||||
CASE2STR(X_GetInputFocus);
|
||||
CASE2STR(X_QueryKeymap);
|
||||
CASE2STR(X_OpenFont);
|
||||
CASE2STR(X_CloseFont);
|
||||
CASE2STR(X_QueryFont);
|
||||
CASE2STR(X_QueryTextExtents);
|
||||
CASE2STR(X_ListFonts);
|
||||
CASE2STR(X_ListFontsWithInfo);
|
||||
CASE2STR(X_SetFontPath);
|
||||
CASE2STR(X_GetFontPath);
|
||||
CASE2STR(X_CreatePixmap);
|
||||
CASE2STR(X_FreePixmap);
|
||||
CASE2STR(X_CreateGC);
|
||||
CASE2STR(X_ChangeGC);
|
||||
CASE2STR(X_CopyGC);
|
||||
CASE2STR(X_SetDashes);
|
||||
CASE2STR(X_SetClipRectangles);
|
||||
CASE2STR(X_FreeGC);
|
||||
CASE2STR(X_ClearArea);
|
||||
CASE2STR(X_CopyArea);
|
||||
CASE2STR(X_CopyPlane);
|
||||
CASE2STR(X_PolyPoint);
|
||||
CASE2STR(X_PolyLine);
|
||||
CASE2STR(X_PolySegment);
|
||||
CASE2STR(X_PolyRectangle);
|
||||
CASE2STR(X_PolyArc);
|
||||
CASE2STR(X_FillPoly);
|
||||
CASE2STR(X_PolyFillRectangle);
|
||||
CASE2STR(X_PolyFillArc);
|
||||
CASE2STR(X_PutImage);
|
||||
CASE2STR(X_GetImage);
|
||||
CASE2STR(X_PolyText8);
|
||||
CASE2STR(X_PolyText16);
|
||||
CASE2STR(X_ImageText8);
|
||||
CASE2STR(X_ImageText16);
|
||||
CASE2STR(X_CreateColormap);
|
||||
CASE2STR(X_FreeColormap);
|
||||
CASE2STR(X_CopyColormapAndFree);
|
||||
CASE2STR(X_InstallColormap);
|
||||
CASE2STR(X_UninstallColormap);
|
||||
CASE2STR(X_ListInstalledColormaps);
|
||||
CASE2STR(X_AllocColor);
|
||||
CASE2STR(X_AllocNamedColor);
|
||||
CASE2STR(X_AllocColorCells);
|
||||
CASE2STR(X_AllocColorPlanes);
|
||||
CASE2STR(X_FreeColors);
|
||||
CASE2STR(X_StoreColors);
|
||||
CASE2STR(X_StoreNamedColor);
|
||||
CASE2STR(X_QueryColors);
|
||||
CASE2STR(X_LookupColor);
|
||||
CASE2STR(X_CreateCursor);
|
||||
CASE2STR(X_CreateGlyphCursor);
|
||||
CASE2STR(X_FreeCursor);
|
||||
CASE2STR(X_RecolorCursor);
|
||||
CASE2STR(X_QueryBestSize);
|
||||
CASE2STR(X_QueryExtension);
|
||||
CASE2STR(X_ListExtensions);
|
||||
CASE2STR(X_ChangeKeyboardMapping);
|
||||
CASE2STR(X_GetKeyboardMapping);
|
||||
CASE2STR(X_ChangeKeyboardControl);
|
||||
CASE2STR(X_GetKeyboardControl);
|
||||
CASE2STR(X_Bell);
|
||||
CASE2STR(X_ChangePointerControl);
|
||||
CASE2STR(X_GetPointerControl);
|
||||
CASE2STR(X_SetScreenSaver);
|
||||
CASE2STR(X_GetScreenSaver);
|
||||
CASE2STR(X_ChangeHosts);
|
||||
CASE2STR(X_ListHosts);
|
||||
CASE2STR(X_SetAccessControl);
|
||||
CASE2STR(X_SetCloseDownMode);
|
||||
CASE2STR(X_KillClient);
|
||||
CASE2STR(X_RotateProperties);
|
||||
CASE2STR(X_ForceScreenSaver);
|
||||
CASE2STR(X_SetPointerMapping);
|
||||
CASE2STR(X_GetPointerMapping);
|
||||
CASE2STR(X_SetModifierMapping);
|
||||
CASE2STR(X_GetModifierMapping);
|
||||
CASE2STR(X_NoOperation);
|
||||
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
422
third_party/FreeRDP/client/X11/xfreerdp.h
vendored
Normal file
422
third_party/FreeRDP/client/X11/xfreerdp.h
vendored
Normal file
@@ -0,0 +1,422 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Client
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2016 Thincast Technologies GmbH
|
||||
* Copyright 2016 Armin Novak <armin.novak@thincast.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_X11_FREERDP_H
|
||||
#define FREERDP_CLIENT_X11_FREERDP_H
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include "xf_types.h"
|
||||
#include "xf_disp.h"
|
||||
#include "xf_cliprdr.h"
|
||||
#include "xf_video.h"
|
||||
#include "xf_rail.h"
|
||||
|
||||
#ifdef WITH_XCURSOR
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XI
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif
|
||||
|
||||
#include <freerdp/api.h>
|
||||
|
||||
#include "xf_window.h"
|
||||
#include "xf_monitor.h"
|
||||
#include "xf_channels.h"
|
||||
|
||||
#if defined(CHANNEL_TSMF_CLIENT)
|
||||
#include <freerdp/client/tsmf.h>
|
||||
#endif
|
||||
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
#include <freerdp/codec/nsc.h>
|
||||
#include <freerdp/codec/clear.h>
|
||||
#include <freerdp/codec/color.h>
|
||||
#include <freerdp/codec/bitmap.h>
|
||||
#include <freerdp/codec/h264.h>
|
||||
#include <freerdp/codec/progressive.h>
|
||||
#include <freerdp/codec/region.h>
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
#include <freerdp/client.h>
|
||||
|
||||
#if !defined(XcursorUInt)
|
||||
typedef unsigned int XcursorUInt;
|
||||
#endif
|
||||
|
||||
#if !defined(XcursorPixel)
|
||||
typedef XcursorUInt XcursorPixel;
|
||||
#endif
|
||||
|
||||
struct xf_FullscreenMonitors
|
||||
{
|
||||
INT32 top;
|
||||
INT32 bottom;
|
||||
INT32 left;
|
||||
INT32 right;
|
||||
};
|
||||
typedef struct xf_FullscreenMonitors xfFullscreenMonitors;
|
||||
|
||||
struct xf_WorkArea
|
||||
{
|
||||
INT32 x;
|
||||
INT32 y;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
};
|
||||
typedef struct xf_WorkArea xfWorkArea;
|
||||
|
||||
struct xf_pointer
|
||||
{
|
||||
rdpPointer pointer;
|
||||
XcursorPixel* cursorPixels;
|
||||
UINT32 nCursors;
|
||||
UINT32 mCursors;
|
||||
UINT32* cursorWidths;
|
||||
UINT32* cursorHeights;
|
||||
Cursor* cursors;
|
||||
Cursor cursor;
|
||||
};
|
||||
typedef struct xf_pointer xfPointer;
|
||||
|
||||
struct xf_bitmap
|
||||
{
|
||||
rdpBitmap bitmap;
|
||||
Pixmap pixmap;
|
||||
XImage* image;
|
||||
};
|
||||
typedef struct xf_bitmap xfBitmap;
|
||||
|
||||
struct xf_glyph
|
||||
{
|
||||
rdpGlyph glyph;
|
||||
Pixmap pixmap;
|
||||
};
|
||||
typedef struct xf_glyph xfGlyph;
|
||||
|
||||
/* Number of buttons that are mapped from X11 to RDP button events. */
|
||||
#define NUM_BUTTONS_MAPPED 11
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 button;
|
||||
UINT16 flags;
|
||||
} button_map;
|
||||
|
||||
#if defined(WITH_XI)
|
||||
#define MAX_CONTACTS 20
|
||||
|
||||
typedef struct touch_contact
|
||||
{
|
||||
int id;
|
||||
int count;
|
||||
double pos_x;
|
||||
double pos_y;
|
||||
double last_x;
|
||||
double last_y;
|
||||
|
||||
} touchContact;
|
||||
|
||||
#endif
|
||||
|
||||
struct xf_context
|
||||
{
|
||||
rdpClientContext common;
|
||||
|
||||
GC gc;
|
||||
int xfds;
|
||||
int depth;
|
||||
|
||||
GC gc_mono;
|
||||
BOOL invert;
|
||||
Screen* screen;
|
||||
XImage* image;
|
||||
Pixmap primary;
|
||||
Pixmap drawing;
|
||||
Visual* visual;
|
||||
Display* display;
|
||||
Drawable drawable;
|
||||
Pixmap bitmap_mono;
|
||||
Colormap colormap;
|
||||
int screen_number;
|
||||
int scanline_pad;
|
||||
BOOL big_endian;
|
||||
BOOL fullscreen;
|
||||
BOOL decorations;
|
||||
BOOL grab_keyboard;
|
||||
BOOL unobscured;
|
||||
BOOL debug;
|
||||
HANDLE x11event;
|
||||
xfWindow* window;
|
||||
xfAppWindow* appWindow;
|
||||
xfPointer* pointer;
|
||||
xfWorkArea workArea;
|
||||
xfFullscreenMonitors fullscreenMonitors;
|
||||
int current_desktop;
|
||||
BOOL remote_app;
|
||||
HANDLE mutex;
|
||||
BOOL UseXThreads;
|
||||
BOOL cursorHidden;
|
||||
|
||||
UINT32 bitmap_size;
|
||||
BYTE* bitmap_buffer;
|
||||
|
||||
BOOL frame_begin;
|
||||
|
||||
int XInputOpcode;
|
||||
|
||||
int savedWidth;
|
||||
int savedHeight;
|
||||
int savedPosX;
|
||||
int savedPosY;
|
||||
|
||||
#ifdef WITH_XRENDER
|
||||
int scaledWidth;
|
||||
int scaledHeight;
|
||||
int offset_x;
|
||||
int offset_y;
|
||||
#endif
|
||||
|
||||
BOOL focused;
|
||||
BOOL mouse_active;
|
||||
BOOL fullscreen_toggle;
|
||||
BOOL KeyboardState[256];
|
||||
XModifierKeymap* modifierMap;
|
||||
wArrayList* keyCombinations;
|
||||
wArrayList* xevents;
|
||||
BOOL actionScriptExists;
|
||||
|
||||
int attribs_mask;
|
||||
XSetWindowAttributes attribs;
|
||||
BOOL complex_regions;
|
||||
VIRTUAL_SCREEN vscreen;
|
||||
#if defined(CHANNEL_TSMF_CLIENT)
|
||||
void* xv_context;
|
||||
#endif
|
||||
|
||||
Atom* supportedAtoms;
|
||||
unsigned long supportedAtomCount;
|
||||
|
||||
Atom UTF8_STRING;
|
||||
|
||||
Atom XWAYLAND_MAY_GRAB_KEYBOARD;
|
||||
|
||||
Atom NET_WM_ICON;
|
||||
Atom MOTIF_WM_HINTS;
|
||||
Atom NET_NUMBER_OF_DESKTOPS;
|
||||
Atom NET_CURRENT_DESKTOP;
|
||||
Atom NET_WORKAREA;
|
||||
|
||||
Atom NET_SUPPORTED;
|
||||
Atom NET_SUPPORTING_WM_CHECK;
|
||||
|
||||
Atom NET_WM_STATE;
|
||||
Atom NET_WM_STATE_MODAL;
|
||||
Atom NET_WM_STATE_STICKY;
|
||||
Atom NET_WM_STATE_MAXIMIZED_VERT;
|
||||
Atom NET_WM_STATE_MAXIMIZED_HORZ;
|
||||
Atom NET_WM_STATE_SHADED;
|
||||
Atom NET_WM_STATE_SKIP_TASKBAR;
|
||||
Atom NET_WM_STATE_SKIP_PAGER;
|
||||
Atom NET_WM_STATE_HIDDEN;
|
||||
Atom NET_WM_STATE_FULLSCREEN;
|
||||
Atom NET_WM_STATE_ABOVE;
|
||||
Atom NET_WM_STATE_BELOW;
|
||||
Atom NET_WM_STATE_DEMANDS_ATTENTION;
|
||||
|
||||
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;
|
||||
Atom NET_WM_WINDOW_TYPE_UTILITY;
|
||||
Atom NET_WM_WINDOW_TYPE_POPUP;
|
||||
Atom NET_WM_WINDOW_TYPE_POPUP_MENU;
|
||||
Atom NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
|
||||
|
||||
Atom NET_WM_MOVERESIZE;
|
||||
Atom NET_MOVERESIZE_WINDOW;
|
||||
|
||||
Atom WM_STATE;
|
||||
Atom WM_PROTOCOLS;
|
||||
Atom WM_DELETE_WINDOW;
|
||||
|
||||
/* Allow actions */
|
||||
Atom NET_WM_ALLOWED_ACTIONS;
|
||||
|
||||
Atom NET_WM_ACTION_CLOSE;
|
||||
Atom NET_WM_ACTION_MINIMIZE;
|
||||
Atom NET_WM_ACTION_MOVE;
|
||||
Atom NET_WM_ACTION_RESIZE;
|
||||
Atom NET_WM_ACTION_MAXIMIZE_HORZ;
|
||||
Atom NET_WM_ACTION_MAXIMIZE_VERT;
|
||||
Atom NET_WM_ACTION_FULLSCREEN;
|
||||
Atom NET_WM_ACTION_CHANGE_DESKTOP;
|
||||
|
||||
/* Channels */
|
||||
#if defined(CHANNEL_TSMF_CLIENT)
|
||||
TsmfClientContext* tsmf;
|
||||
#endif
|
||||
|
||||
xfClipboard* clipboard;
|
||||
CliprdrClientContext* cliprdr;
|
||||
xfVideoContext* xfVideo;
|
||||
xfDispContext* xfDisp;
|
||||
|
||||
RailClientContext* rail;
|
||||
wHashTable* railWindows;
|
||||
xfRailIconCache* railIconCache;
|
||||
|
||||
#if defined(WITH_VERBOSE_WINPR_ASSERT)
|
||||
BOOL isRailWindowsLocked;
|
||||
#endif
|
||||
|
||||
BOOL xkbAvailable;
|
||||
BOOL xrenderAvailable;
|
||||
|
||||
/* value to be sent over wire for each logical client mouse button */
|
||||
button_map button_map[NUM_BUTTONS_MAPPED];
|
||||
BYTE savedMaximizedState;
|
||||
UINT32 locked;
|
||||
BOOL wasRightCtrlAlreadyPressed;
|
||||
BOOL ungrabKeyboardWithRightCtrl;
|
||||
|
||||
#if defined(WITH_XI)
|
||||
touchContact contacts[MAX_CONTACTS];
|
||||
int active_contacts;
|
||||
int lastEvType;
|
||||
XIDeviceEvent lastEvent;
|
||||
double firstDist;
|
||||
double lastDist;
|
||||
double z_vector;
|
||||
double px_vector;
|
||||
double py_vector;
|
||||
#endif
|
||||
BOOL xi_rawevent;
|
||||
BOOL xi_event;
|
||||
HANDLE pipethread;
|
||||
wLog* log;
|
||||
FREERDP_REMAP_TABLE* remap_table;
|
||||
DWORD X11_KEYCODE_TO_VIRTUAL_SCANCODE[256];
|
||||
bool isCursorHidden;
|
||||
bool isActionScriptAllowed;
|
||||
};
|
||||
|
||||
BOOL xf_create_window(xfContext* xfc);
|
||||
void xf_destroy_window(xfContext* xfc);
|
||||
|
||||
BOOL xf_create_image(xfContext* xfc);
|
||||
void xf_toggle_fullscreen(xfContext* xfc);
|
||||
void xf_minimize(xfContext* xfc);
|
||||
|
||||
enum XF_EXIT_CODE
|
||||
{
|
||||
/* section 0-15: protocol-independent codes */
|
||||
XF_EXIT_SUCCESS = 0,
|
||||
XF_EXIT_DISCONNECT = 1,
|
||||
XF_EXIT_LOGOFF = 2,
|
||||
XF_EXIT_IDLE_TIMEOUT = 3,
|
||||
XF_EXIT_LOGON_TIMEOUT = 4,
|
||||
XF_EXIT_CONN_REPLACED = 5,
|
||||
XF_EXIT_OUT_OF_MEMORY = 6,
|
||||
XF_EXIT_CONN_DENIED = 7,
|
||||
XF_EXIT_CONN_DENIED_FIPS = 8,
|
||||
XF_EXIT_USER_PRIVILEGES = 9,
|
||||
XF_EXIT_FRESH_CREDENTIALS_REQUIRED = 10,
|
||||
XF_EXIT_DISCONNECT_BY_USER = 11,
|
||||
|
||||
/* section 16-31: license error set */
|
||||
XF_EXIT_LICENSE_INTERNAL = 16,
|
||||
XF_EXIT_LICENSE_NO_LICENSE_SERVER = 17,
|
||||
XF_EXIT_LICENSE_NO_LICENSE = 18,
|
||||
XF_EXIT_LICENSE_BAD_CLIENT_MSG = 19,
|
||||
XF_EXIT_LICENSE_HWID_DOESNT_MATCH = 20,
|
||||
XF_EXIT_LICENSE_BAD_CLIENT = 21,
|
||||
XF_EXIT_LICENSE_CANT_FINISH_PROTOCOL = 22,
|
||||
XF_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL = 23,
|
||||
XF_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION = 24,
|
||||
XF_EXIT_LICENSE_CANT_UPGRADE = 25,
|
||||
XF_EXIT_LICENSE_NO_REMOTE_CONNECTIONS = 26,
|
||||
|
||||
/* section 32-127: RDP protocol error set */
|
||||
XF_EXIT_RDP = 32,
|
||||
|
||||
/* section 128-254: xfreerdp specific exit codes */
|
||||
XF_EXIT_PARSE_ARGUMENTS = 128,
|
||||
XF_EXIT_MEMORY = 129,
|
||||
XF_EXIT_PROTOCOL = 130,
|
||||
XF_EXIT_CONN_FAILED = 131,
|
||||
XF_EXIT_AUTH_FAILURE = 132,
|
||||
XF_EXIT_NEGO_FAILURE = 133,
|
||||
XF_EXIT_LOGON_FAILURE = 134,
|
||||
XF_EXIT_ACCOUNT_LOCKED_OUT = 135,
|
||||
XF_EXIT_PRE_CONNECT_FAILED = 136,
|
||||
XF_EXIT_CONNECT_UNDEFINED = 137,
|
||||
XF_EXIT_POST_CONNECT_FAILED = 138,
|
||||
XF_EXIT_DNS_ERROR = 139,
|
||||
XF_EXIT_DNS_NAME_NOT_FOUND = 140,
|
||||
XF_EXIT_CONNECT_FAILED = 141,
|
||||
XF_EXIT_MCS_CONNECT_INITIAL_ERROR = 142,
|
||||
XF_EXIT_TLS_CONNECT_FAILED = 143,
|
||||
XF_EXIT_INSUFFICIENT_PRIVILEGES = 144,
|
||||
XF_EXIT_CONNECT_CANCELLED = 145,
|
||||
|
||||
XF_EXIT_CONNECT_TRANSPORT_FAILED = 147,
|
||||
XF_EXIT_CONNECT_PASSWORD_EXPIRED = 148,
|
||||
XF_EXIT_CONNECT_PASSWORD_MUST_CHANGE = 149,
|
||||
XF_EXIT_CONNECT_KDC_UNREACHABLE = 150,
|
||||
XF_EXIT_CONNECT_ACCOUNT_DISABLED = 151,
|
||||
XF_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED = 152,
|
||||
XF_EXIT_CONNECT_CLIENT_REVOKED = 153,
|
||||
XF_EXIT_CONNECT_WRONG_PASSWORD = 154,
|
||||
XF_EXIT_CONNECT_ACCESS_DENIED = 155,
|
||||
XF_EXIT_CONNECT_ACCOUNT_RESTRICTION = 156,
|
||||
XF_EXIT_CONNECT_ACCOUNT_EXPIRED = 157,
|
||||
XF_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED = 158,
|
||||
XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS = 159,
|
||||
XF_EXIT_CONNECT_TARGET_BOOTING = 160,
|
||||
XF_EXIT_CODE_LAST = XF_EXIT_CONNECT_TARGET_BOOTING,
|
||||
XF_EXIT_UNKNOWN = 255,
|
||||
};
|
||||
|
||||
#define xf_lock_x11(xfc) xf_lock_x11_(xfc, __func__)
|
||||
#define xf_unlock_x11(xfc) xf_unlock_x11_(xfc, __func__)
|
||||
|
||||
void xf_lock_x11_(xfContext* xfc, const char* fkt);
|
||||
void xf_unlock_x11_(xfContext* xfc, const char* fkt);
|
||||
|
||||
BOOL xf_picture_transform_required(xfContext* xfc);
|
||||
|
||||
#define xf_draw_screen(_xfc, _x, _y, _w, _h) \
|
||||
xf_draw_screen_((_xfc), (_x), (_y), (_w), (_h), __func__, __FILE__, __LINE__)
|
||||
void xf_draw_screen_(xfContext* xfc, int x, int y, int w, int h, const char* fkt, const char* file,
|
||||
int line);
|
||||
|
||||
BOOL xf_keyboard_update_modifier_map(xfContext* xfc);
|
||||
|
||||
int xf_exit_code_from_disconnect_reason(DWORD reason);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_FREERDP_H */
|
||||
870
third_party/FreeRDP/client/X11/xkb_layout_ids.c
vendored
Normal file
870
third_party/FreeRDP/client/X11/xkb_layout_ids.c
vendored
Normal file
@@ -0,0 +1,870 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* RDP Keyboard layout ID detection from common X11 xkb keyboard layout names
|
||||
*
|
||||
* Copyright 2009-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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include "xkb_layout_ids.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include "xf_debug.h"
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* variant; /* XKB Keyboard layout variant */
|
||||
INT64 keyboardLayoutID; /* Keyboard Layout ID */
|
||||
} XKB_VARIANT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* layout; /* XKB Keyboard layout */
|
||||
INT64 keyboardLayoutID; /* Keyboard Layout ID */
|
||||
const XKB_VARIANT* variants;
|
||||
} XKB_LAYOUT;
|
||||
|
||||
/* Those have been generated automatically and are waiting to be filled by hand */
|
||||
|
||||
/* USA */
|
||||
static const XKB_VARIANT us_variants[] = {
|
||||
{ "chr", 0 }, /* Cherokee */
|
||||
{ "euro", 0 }, /* With EuroSign on 5 */
|
||||
{ "intl", KBD_UNITED_STATES_INTERNATIONAL }, /* International (with dead keys) */
|
||||
{ "alt-intl",
|
||||
KBD_UNITED_STATES_INTERNATIONAL }, /* Alternative international (former us_intl) */
|
||||
{ "colemak", 0 }, /* Colemak */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "dvorak-intl", KBD_UNITED_STATES_DVORAK }, /* Dvorak international */
|
||||
{ "dvorak-l", KBD_UNITED_STATES_DVORAK_FOR_LEFT_HAND }, /* Left handed Dvorak */
|
||||
{ "dvorak-r", KBD_UNITED_STATES_DVORAK_FOR_RIGHT_HAND }, /* Right handed Dvorak */
|
||||
{ "dvorak-classic", KBD_UNITED_STATES_DVORAK }, /* Classic Dvorak */
|
||||
{ "dvp", KBD_UNITED_STATES_DVORAK_PROGRAMMER }, /* Programmer Dvorak */
|
||||
{ "rus", 0 }, /* Russian phonetic */
|
||||
{ "mac", KBD_US }, /* Macintosh */
|
||||
{ "altgr-intl", KBD_UNITED_STATES_INTERNATIONAL }, /* International (AltGr dead keys) */
|
||||
{ "olpc2", KBD_US }, /* Group toggle on multiply/divide key */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Afghanistan */
|
||||
static const XKB_VARIANT af_variants[] = {
|
||||
{ "ps", KBD_PASHTO }, /* Pashto */
|
||||
{ "uz", KBD_UZBEK_CYRILLIC }, /* Southern Uzbek */
|
||||
{ "olpc-ps", KBD_PASHTO }, /* OLPC Pashto */
|
||||
{ "olpc-fa", 0 }, /* OLPC Dari */
|
||||
{ "olpc-uz", KBD_UZBEK_CYRILLIC }, /* OLPC Southern Uzbek */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Arabic */
|
||||
static const XKB_VARIANT ara_variants[] = {
|
||||
{ "azerty", KBD_ARABIC_102_AZERTY }, /* azerty */
|
||||
{ "azerty_digits", KBD_ARABIC_102_AZERTY }, /* azerty/digits */
|
||||
{ "digits", KBD_ARABIC_102_AZERTY }, /* digits */
|
||||
{ "qwerty", KBD_ARABIC_101 }, /* qwerty */
|
||||
{ "qwerty_digits", KBD_ARABIC_101 }, /* qwerty/digits */
|
||||
{ "buckwalter", KBD_US_ENGLISH_TABLE_FOR_IBM_ARABIC_238_L }, /* Buckwalter */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Armenia */
|
||||
static const XKB_VARIANT am_variants[] = {
|
||||
{ "phonetic", 0 }, /* Phonetic */
|
||||
{ "phonetic-alt", 0 }, /* Alternative Phonetic */
|
||||
{ "eastern", KBD_ARMENIAN_EASTERN }, /* Eastern */
|
||||
{ "western", KBD_ARMENIAN_WESTERN }, /* Western */
|
||||
{ "eastern-alt", KBD_ARMENIAN_EASTERN }, /* Alternative Eastern */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Azerbaijan */
|
||||
static const XKB_VARIANT az_variants[] = {
|
||||
{ "cyrillic", KBD_AZERI_CYRILLIC }, /* Cyrillic */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Belarus */
|
||||
static const XKB_VARIANT by_variants[] = {
|
||||
{ "winkeys", KBD_BELARUSIAN }, /* Winkeys */
|
||||
{ "latin", KBD_BELARUSIAN }, /* Latin */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Belgium */
|
||||
static const XKB_VARIANT be_variants[] = {
|
||||
{ "oss", KBD_BELGIAN_FRENCH }, /* Alternative */
|
||||
{ "oss_latin9", KBD_BELGIAN_FRENCH }, /* Alternative, latin-9 only */
|
||||
{ "oss_sundeadkeys", KBD_BELGIAN_PERIOD }, /* Alternative, Sun dead keys */
|
||||
{ "iso-alternate", KBD_BELGIAN_COMMA }, /* ISO Alternate */
|
||||
{ "nodeadkeys", KBD_BELGIAN_COMMA }, /* Eliminate dead keys */
|
||||
{ "sundeadkeys", KBD_BELGIAN_PERIOD }, /* Sun dead keys */
|
||||
{ "wang", KBD_BELGIAN_FRENCH }, /* Wang model 724 azerty */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Bangladesh */
|
||||
static const XKB_VARIANT bd_variants[] = {
|
||||
{ "probhat", KBD_BENGALI_INSCRIPT }, /* Probhat */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* India */
|
||||
static const XKB_VARIANT in_variants[] = {
|
||||
{ "ben", KBD_BENGALI }, /* Bengali */
|
||||
{ "ben_probhat", KBD_BENGALI_INSCRIPT }, /* Bengali Probhat */
|
||||
{ "guj", KBD_GUJARATI }, /* Gujarati */
|
||||
{ "guru", 0 }, /* Gurmukhi */
|
||||
{ "jhelum", 0 }, /* Gurmukhi Jhelum */
|
||||
{ "kan", KBD_KANNADA }, /* Kannada */
|
||||
{ "mal", KBD_MALAYALAM }, /* Malayalam */
|
||||
{ "mal_lalitha", KBD_MALAYALAM }, /* Malayalam Lalitha */
|
||||
{ "ori", 0 }, /* Oriya */
|
||||
{ "tam_unicode", KBD_TAMIL }, /* Tamil Unicode */
|
||||
{ "tam_TAB", KBD_TAMIL }, /* Tamil TAB Typewriter */
|
||||
{ "tam_TSCII", KBD_TAMIL }, /* Tamil TSCII Typewriter */
|
||||
{ "tam", KBD_TAMIL }, /* Tamil */
|
||||
{ "tel", KBD_TELUGU }, /* Telugu */
|
||||
{ "urd-phonetic", KBD_URDU }, /* Urdu, Phonetic */
|
||||
{ "urd-phonetic3", KBD_URDU }, /* Urdu, Alternative phonetic */
|
||||
{ "urd-winkeys", KBD_URDU }, /* Urdu, Winkeys */
|
||||
{ "bolnagri", KBD_HINDI_TRADITIONAL }, /* Hindi Bolnagri */
|
||||
{ "hin-wx", KBD_HINDI_TRADITIONAL }, /* Hindi Wx */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Bosnia and Herzegovina */
|
||||
static const XKB_VARIANT ba_variants[] = {
|
||||
{ "alternatequotes", KBD_BOSNIAN }, /* Use guillemets for quotes */
|
||||
{ "unicode", KBD_BOSNIAN }, /* Use Bosnian digraphs */
|
||||
{ "unicodeus", KBD_BOSNIAN }, /* US keyboard with Bosnian digraphs */
|
||||
{ "us", KBD_BOSNIAN_CYRILLIC }, /* US keyboard with Bosnian letters */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Brazil */
|
||||
static const XKB_VARIANT br_variants[] = {
|
||||
{ "nodeadkeys", KBD_PORTUGUESE_BRAZILIAN_ABNT2 }, /* Eliminate dead keys */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "nativo", KBD_PORTUGUESE_BRAZILIAN_ABNT2 }, /* Nativo */
|
||||
{ "nativo-us", KBD_PORTUGUESE_BRAZILIAN_ABNT2 }, /* Nativo for USA keyboards */
|
||||
{ "nativo-epo", KBD_PORTUGUESE_BRAZILIAN_ABNT2 }, /* Nativo for Esperanto */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Bulgaria */
|
||||
static const XKB_VARIANT bg_variants[] = {
|
||||
{ "phonetic", KBD_BULGARIAN_LATIN }, /* Traditional Phonetic */
|
||||
{ "bas_phonetic", KBD_BULGARIAN_LATIN }, /* Standard Phonetic */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Morocco */
|
||||
static const XKB_VARIANT ma_variants[] = {
|
||||
{ "french", KBD_FRENCH }, /* French */
|
||||
{ "tifinagh", 0 }, /* Tifinagh */
|
||||
{ "tifinagh-alt", 0 }, /* Tifinagh Alternative */
|
||||
{ "tifinagh-alt-phonetic", 0 }, /* Tifinagh Alternative Phonetic */
|
||||
{ "tifinagh-extended", 0 }, /* Tifinagh Extended */
|
||||
{ "tifinagh-phonetic", 0 }, /* Tifinagh Phonetic */
|
||||
{ "tifinagh-extended-phonetic", 0 }, /* Tifinagh Extended Phonetic */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Canada */
|
||||
static const XKB_VARIANT ca_variants[] = {
|
||||
{ "fr", KBD_CANADIAN_FRENCH }, /* French Dvorak */
|
||||
{ "fr-dvorak", KBD_UNITED_STATES_DVORAK }, /* French Dvorak */
|
||||
{ "fr-legacy", KBD_CANADIAN_FRENCH_LEGACY }, /* French (legacy) */
|
||||
{ "multix", KBD_CANADIAN_MULTILINGUAL_STANDARD }, /* Multilingual */
|
||||
{ "multi", KBD_CANADIAN_MULTILINGUAL_STANDARD }, /* Multilingual, first part */
|
||||
{ "multi-2gr", KBD_CANADIAN_MULTILINGUAL_STANDARD }, /* Multilingual, second part */
|
||||
{ "ike", KBD_INUKTITUT_LATIN }, /* Inuktitut */
|
||||
{ "shs" /* codespell:ignore shs */, 0 }, /* Secwepemctsin */
|
||||
{ "kut", 0 }, /* Ktunaxa */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* China */
|
||||
static const XKB_VARIANT cn_variants[] = {
|
||||
{ "tib", 0 }, /* Tibetan */
|
||||
{ "tib_asciinum", 0 }, /* Tibetan (with ASCII numerals) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Croatia */
|
||||
static const XKB_VARIANT hr_variants[] = {
|
||||
{ "alternatequotes", KBD_CROATIAN }, /* Use guillemets for quotes */
|
||||
{ "unicode", KBD_CROATIAN }, /* Use Croatian digraphs */
|
||||
{ "unicodeus", KBD_CROATIAN }, /* US keyboard with Croatian digraphs */
|
||||
{ "us", KBD_CROATIAN }, /* US keyboard with Croatian letters */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Czechia */
|
||||
static const XKB_VARIANT cz_variants[] = {
|
||||
{ "bksl", KBD_CZECH_PROGRAMMERS }, /* With <\|> key */
|
||||
{ "qwerty", KBD_CZECH_QWERTY }, /* qwerty */
|
||||
{ "qwerty_bksl", KBD_CZECH_QWERTY }, /* qwerty, extended Backslash */
|
||||
{ "ucw", KBD_CZECH }, /* UCW layout (accented letters only) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Denmark */
|
||||
static const XKB_VARIANT dk_variants[] = {
|
||||
{ "nodeadkeys", KBD_DANISH }, /* Eliminate dead keys */
|
||||
{ "mac", KBD_DANISH }, /* Macintosh */
|
||||
{ "mac_nodeadkeys", KBD_DANISH }, /* Macintosh, eliminate dead keys */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Netherlands */
|
||||
static const XKB_VARIANT nl_variants[] = {
|
||||
{ "sundeadkeys", KBD_SWISS_FRENCH }, /* Sun dead keys */
|
||||
{ "mac", KBD_SWISS_FRENCH }, /* Macintosh */
|
||||
{ "std", KBD_SWISS_FRENCH }, /* Standard */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Estonia */
|
||||
static const XKB_VARIANT ee_variants[] = {
|
||||
{ "nodeadkeys", KBD_US }, /* Eliminate dead keys */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "us", KBD_UNITED_STATES_INTERNATIONAL }, /* US keyboard with Estonian letters */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Iran */
|
||||
static const XKB_VARIANT ir_variants[] = {
|
||||
{ "pro", 0 }, /* Pro */
|
||||
{ "keypad", 0 }, /* Keypad */
|
||||
{ "pro_keypad", 0 }, /* Pro Keypad */
|
||||
{ "ku", 0 }, /* Kurdish, Latin Q */
|
||||
{ "ku_f", 0 }, /* Kurdish, (F) */
|
||||
{ "ku_alt", 0 }, /* Kurdish, Latin Alt-Q */
|
||||
{ "ku_ara", 0 }, /* Kurdish, Arabic-Latin */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Iraq */
|
||||
static const XKB_VARIANT iq_variants[] = {
|
||||
{ "ku", 0 }, /* Kurdish, Latin Q */
|
||||
{ "ku_f", 0 }, /* Kurdish, (F) */
|
||||
{ "ku_alt", 0 }, /* Kurdish, Latin Alt-Q */
|
||||
{ "ku_ara", 0 }, /* Kurdish, Arabic-Latin */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Faroe Islands */
|
||||
static const XKB_VARIANT fo_variants[] = {
|
||||
{ "nodeadkeys", 0 }, /* Eliminate dead keys */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Finland */
|
||||
static const XKB_VARIANT fi_variants[] = {
|
||||
{ "nodeadkeys", 0 }, /* Eliminate dead keys */
|
||||
{ "smi", 0 }, /* Northern Saami */
|
||||
{ "classic", 0 }, /* Classic */
|
||||
{ "mac", 0 }, /* Macintosh */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* France */
|
||||
static const XKB_VARIANT fr_variants[] = {
|
||||
{ "nodeadkeys", 0 }, /* Eliminate dead keys */
|
||||
{ "sundeadkeys", 0 }, /* Sun dead keys */
|
||||
{ "oss", 0 }, /* Alternative */
|
||||
{ "oss_latin9", 0 }, /* Alternative, latin-9 only */
|
||||
{ "oss_nodeadkeys", 0 }, /* Alternative, eliminate dead keys */
|
||||
{ "oss_sundeadkeys", 0 }, /* Alternative, Sun dead keys */
|
||||
{ "latin9", 0 }, /* (Legacy) Alternative */
|
||||
{ "latin9_nodeadkeys", 0 }, /* (Legacy) Alternative, eliminate dead keys */
|
||||
{ "latin9_sundeadkeys", 0 }, /* (Legacy) Alternative, Sun dead keys */
|
||||
{ "bepo", KBD_FRENCH_BEPO }, /* Bepo, ergonomic, Dvorak way */
|
||||
{ "bepo_latin9", 0 }, /* Bepo, ergonomic, Dvorak way, latin-9 only */
|
||||
{ "dvorak", 0 }, /* Dvorak */
|
||||
{ "mac", 0 }, /* Macintosh */
|
||||
{ "bre", 0 }, /* Breton */
|
||||
{ "oci", 0 }, /* Occitan */
|
||||
{ "geo", 0 }, /* Georgian AZERTY Tskapo */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Ghana */
|
||||
static const XKB_VARIANT gh_variants[] = {
|
||||
{ "generic", 0 }, /* Multilingual */
|
||||
{ "akan", 0 }, /* Akan */
|
||||
{ "ewe", 0 }, /* Ewe */
|
||||
{ "fula", 0 }, /* Fula */
|
||||
{ "ga", 0 }, /* Ga */
|
||||
{ "hausa", 0 }, /* Hausa */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Georgia */
|
||||
static const XKB_VARIANT ge_variants[] = {
|
||||
{ "ergonomic", 0 }, /* Ergonomic */
|
||||
{ "mess", 0 }, /* MESS */
|
||||
{ "ru", 0 }, /* Russian */
|
||||
{ "os", 0 }, /* Ossetian */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Germany */
|
||||
static const XKB_VARIANT de_variants[] = {
|
||||
{ "deadacute", KBD_GERMAN }, /* Dead acute */
|
||||
{ "deadgraveacute", KBD_GERMAN }, /* Dead grave acute */
|
||||
{ "nodeadkeys", KBD_GERMAN }, /* Eliminate dead keys */
|
||||
{ "ro", KBD_GERMAN }, /* Romanian keyboard with German letters */
|
||||
{ "ro_nodeadkeys",
|
||||
KBD_GERMAN }, /* Romanian keyboard with German letters, eliminate dead keys */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "sundeadkeys", KBD_GERMAN }, /* Sun dead keys */
|
||||
{ "neo", KBD_GERMAN_NEO }, /* Neo 2 */
|
||||
{ "mac", KBD_GERMAN }, /* Macintosh */
|
||||
{ "mac_nodeadkeys", KBD_GERMAN }, /* Macintosh, eliminate dead keys */
|
||||
{ "dsb", KBD_GERMAN }, /* Lower Sorbian */
|
||||
{ "dsb_qwertz", KBD_GERMAN }, /* Lower Sorbian (qwertz) */
|
||||
{ "qwerty", KBD_GERMAN_IBM }, /* qwerty */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Greece */
|
||||
static const XKB_VARIANT gr_variants[] = {
|
||||
{ "simple", KBD_GREEK_220 }, /* Simple */
|
||||
{ "extended", KBD_GREEK_319 }, /* Extended */
|
||||
{ "nodeadkeys", KBD_GREEK_319 }, /* Eliminate dead keys */
|
||||
{ "polytonic", KBD_GREEK_POLYTONIC }, /* Polytonic */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Hungary */
|
||||
static const XKB_VARIANT hu_variants[] = {
|
||||
{ "standard", KBD_HUNGARIAN_101_KEY }, /* Standard */
|
||||
{ "nodeadkeys", KBD_HUNGARIAN_101_KEY }, /* Eliminate dead keys */
|
||||
{ "qwerty", KBD_HUNGARIAN_101_KEY }, /* qwerty */
|
||||
{ "101_qwertz_comma_dead", KBD_HUNGARIAN_101_KEY }, /* 101/qwertz/comma/Dead keys */
|
||||
{ "101_qwertz_comma_nodead", KBD_HUNGARIAN_101_KEY }, /* 101/qwertz/comma/Eliminate dead keys */
|
||||
{ "101_qwertz_dot_dead", KBD_HUNGARIAN_101_KEY }, /* 101/qwertz/dot/Dead keys */
|
||||
{ "101_qwertz_dot_nodead", KBD_HUNGARIAN_101_KEY }, /* 101/qwertz/dot/Eliminate dead keys */
|
||||
{ "101_qwerty_comma_dead", KBD_HUNGARIAN_101_KEY }, /* 101/qwerty/comma/Dead keys */
|
||||
{ "101_qwerty_comma_nodead", KBD_HUNGARIAN_101_KEY }, /* 101/qwerty/comma/Eliminate dead keys */
|
||||
{ "101_qwerty_dot_dead", KBD_HUNGARIAN_101_KEY }, /* 101/qwerty/dot/Dead keys */
|
||||
{ "101_qwerty_dot_nodead", KBD_HUNGARIAN_101_KEY }, /* 101/qwerty/dot/Eliminate dead keys */
|
||||
{ "102_qwertz_comma_dead", KBD_HUNGARIAN_101_KEY }, /* 102/qwertz/comma/Dead keys */
|
||||
{ "102_qwertz_comma_nodead", KBD_HUNGARIAN_101_KEY }, /* 102/qwertz/comma/Eliminate dead keys */
|
||||
{ "102_qwertz_dot_dead", KBD_HUNGARIAN_101_KEY }, /* 102/qwertz/dot/Dead keys */
|
||||
{ "102_qwertz_dot_nodead", KBD_HUNGARIAN_101_KEY }, /* 102/qwertz/dot/Eliminate dead keys */
|
||||
{ "102_qwerty_comma_dead", KBD_HUNGARIAN_101_KEY }, /* 102/qwerty/comma/Dead keys */
|
||||
{ "102_qwerty_comma_nodead", KBD_HUNGARIAN_101_KEY }, /* 102/qwerty/comma/Eliminate dead keys */
|
||||
{ "102_qwerty_dot_dead", KBD_HUNGARIAN_101_KEY }, /* 102/qwerty/dot/Dead keys */
|
||||
{ "102_qwerty_dot_nodead", KBD_HUNGARIAN_101_KEY }, /* 102/qwerty/dot/Eliminate dead keys */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Iceland */
|
||||
static const XKB_VARIANT is_variants[] = {
|
||||
{ "Sundeadkeys", KBD_ICELANDIC }, /* Sun dead keys */
|
||||
{ "nodeadkeys", KBD_ICELANDIC }, /* Eliminate dead keys */
|
||||
{ "mac", KBD_ICELANDIC }, /* Macintosh */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Israel */
|
||||
static const XKB_VARIANT il_variants[] = {
|
||||
{ "lyx", KBD_HEBREW }, /* lyx */
|
||||
{ "phonetic", KBD_HEBREW }, /* Phonetic */
|
||||
{ "biblical", KBD_HEBREW }, /* Biblical Hebrew (Tiro) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Italy */
|
||||
static const XKB_VARIANT it_variants[] = {
|
||||
{ "nodeadkeys", KBD_ITALIAN_142 }, /* Eliminate dead keys */
|
||||
{ "mac", KBD_ITALIAN }, /* Macintosh */
|
||||
{ "geo", KBD_GEORGIAN }, /* Georgian */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Japan */
|
||||
static const XKB_VARIANT jp_variants[] = {
|
||||
{ "kana", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002 }, /* Kana */
|
||||
{ "OADG109A", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002 }, /* OADG 109A */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Kyrgyzstan */
|
||||
static const XKB_VARIANT kg_variants[] = {
|
||||
{ "phonetic", KBD_KYRGYZ_CYRILLIC }, /* Phonetic */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Kazakhstan */
|
||||
static const XKB_VARIANT kz_variants[] = {
|
||||
{ "ruskaz", KBD_KAZAKH }, /* Russian with Kazakh */
|
||||
{ "kazrus", KBD_KAZAKH }, /* Kazakh with Russian */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Latin America */
|
||||
static const XKB_VARIANT latam_variants[] = {
|
||||
{ "nodeadkeys", KBD_LATIN_AMERICAN }, /* Eliminate dead keys */
|
||||
{ "deadtilde", KBD_LATIN_AMERICAN }, /* Include dead tilde */
|
||||
{ "sundeadkeys", KBD_LATIN_AMERICAN }, /* Sun dead keys */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Lithuania */
|
||||
static const XKB_VARIANT lt_variants[] = {
|
||||
{ "std", KBD_LITHUANIAN }, /* Standard */
|
||||
{ "us", KBD_LITHUANIAN_IBM }, /* US keyboard with Lithuanian letters */
|
||||
{ "ibm", KBD_LITHUANIAN_IBM }, /* IBM (LST 1205-92) */
|
||||
{ "lekp", KBD_LITHUANIAN }, /* LEKP */
|
||||
{ "lekpa", KBD_LITHUANIAN }, /* LEKPa */
|
||||
{ "balticplus", KBD_LITHUANIAN }, /* Baltic+ */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Latvia */
|
||||
static const XKB_VARIANT lv_variants[] = {
|
||||
{ "apostrophe", KBD_LATVIAN }, /* Apostrophe (') variant */
|
||||
{ "tilde", KBD_LATVIAN }, /* Tilde (~) variant */
|
||||
{ "fkey", KBD_LATVIAN }, /* F-letter (F) variant */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Montenegro */
|
||||
static const XKB_VARIANT me_variants[] = {
|
||||
{ "cyrillic", 0 }, /* Cyrillic */
|
||||
{ "cyrillicyz", 0 }, /* Cyrillic, Z and ZHE swapped */
|
||||
{ "latinunicode", 0 }, /* Latin unicode */
|
||||
{ "latinyz", 0 }, /* Latin qwerty */
|
||||
{ "latinunicodeyz", 0 }, /* Latin unicode qwerty */
|
||||
{ "cyrillicalternatequotes", 0 }, /* Cyrillic with guillemets */
|
||||
{ "latinalternatequotes", 0 }, /* Latin with guillemets */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Macedonia */
|
||||
static const XKB_VARIANT mk_variants[] = {
|
||||
{ "nodeadkeys", KBD_FYRO_MACEDONIAN }, /* Eliminate dead keys */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Malta */
|
||||
static const XKB_VARIANT mt_variants[] = {
|
||||
{ "us", KBD_MALTESE_48_KEY }, /* Maltese keyboard with US layout */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Norway */
|
||||
static const XKB_VARIANT no_variants[] = {
|
||||
{ "nodeadkeys", KBD_NORWEGIAN }, /* Eliminate dead keys */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "smi", KBD_NORWEGIAN_WITH_SAMI }, /* Northern Saami */
|
||||
{ "smi_nodeadkeys", KBD_SAMI_EXTENDED_NORWAY }, /* Northern Saami, eliminate dead keys */
|
||||
{ "mac", KBD_NORWEGIAN }, /* Macintosh */
|
||||
{ "mac_nodeadkeys", KBD_SAMI_EXTENDED_NORWAY }, /* Macintosh, eliminate dead keys */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Poland */
|
||||
static const XKB_VARIANT pl_variants[] = {
|
||||
{ "qwertz", KBD_POLISH_214 }, /* qwertz */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "dvorak_quotes", KBD_UNITED_STATES_DVORAK }, /* Dvorak, Polish quotes on quotemark key */
|
||||
{ "dvorak_altquotes", KBD_UNITED_STATES_DVORAK }, /* Dvorak, Polish quotes on key 1 */
|
||||
{ "csb", 0 }, /* Kashubian */
|
||||
{ "ru_phonetic_dvorak", KBD_UNITED_STATES_DVORAK }, /* Russian phonetic Dvorak */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Portugal */
|
||||
static const XKB_VARIANT pt_variants[] = {
|
||||
{ "nodeadkeys", KBD_PORTUGUESE }, /* Eliminate dead keys */
|
||||
{ "sundeadkeys", KBD_PORTUGUESE }, /* Sun dead keys */
|
||||
{ "mac", KBD_PORTUGUESE }, /* Macintosh */
|
||||
{ "mac_nodeadkeys", KBD_PORTUGUESE }, /* Macintosh, eliminate dead keys */
|
||||
{ "mac_sundeadkeys", KBD_PORTUGUESE }, /* Macintosh, Sun dead keys */
|
||||
{ "nativo", KBD_PORTUGUESE }, /* Nativo */
|
||||
{ "nativo-us", KBD_PORTUGUESE }, /* Nativo for USA keyboards */
|
||||
{ "nativo-epo", KBD_PORTUGUESE }, /* Nativo for Esperanto */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Romania */
|
||||
static const XKB_VARIANT ro_variants[] = {
|
||||
{ "cedilla", KBD_ROMANIAN }, /* Cedilla */
|
||||
{ "std", KBD_ROMANIAN }, /* Standard */
|
||||
{ "std_cedilla", KBD_ROMANIAN }, /* Standard (Cedilla) */
|
||||
{ "winkeys", KBD_ROMANIAN }, /* Winkeys */
|
||||
{ "crh_f", KBD_TURKISH_F }, /* Crimean Tatar (Turkish F) */
|
||||
{ "crh_alt", KBD_TURKISH_Q }, /* Crimean Tatar (Turkish Alt-Q) */
|
||||
{ "crh_dobruca1", KBD_TATAR }, /* Crimean Tatar (Dobruca-1 Q) */
|
||||
{ "crh_dobruca2", KBD_TATAR }, /* Crimean Tatar (Dobruca-2 Q) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Russia */
|
||||
static const XKB_VARIANT ru_variants[] = {
|
||||
{ "phonetic", KBD_RUSSIAN }, /* Phonetic */
|
||||
{ "phonetic_winkeys", KBD_RUSSIAN }, /* Phonetic Winkeys */
|
||||
{ "typewriter", KBD_RUSSIAN_TYPEWRITER }, /* Typewriter */
|
||||
{ "legacy", KBD_RUSSIAN }, /* Legacy */
|
||||
{ "tt", KBD_TATAR }, /* Tatar */
|
||||
{ "os_legacy", 0 }, /* Ossetian, legacy */
|
||||
{ "os_winkeys", 0 }, /* Ossetian, Winkeys */
|
||||
{ "cv", 0 }, /* Chuvash */
|
||||
{ "cv_latin", 0 }, /* Chuvash Latin */
|
||||
{ "udm", 0 }, /* Udmurt */
|
||||
{ "kom", 0 }, /* Komi */
|
||||
{ "sah", 0 }, /* Yakut */
|
||||
{ "xal", 0 }, /* Kalmyk */
|
||||
{ "dos", 0 }, /* DOS */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Serbia */
|
||||
static const XKB_VARIANT rs_variants[] = {
|
||||
{ "yz", KBD_SERBIAN_CYRILLIC }, /* Z and ZHE swapped */
|
||||
{ "latin", KBD_SERBIAN_LATIN }, /* Latin */
|
||||
{ "latinunicode", KBD_SERBIAN_LATIN }, /* Latin Unicode */
|
||||
{ "latinyz", KBD_SERBIAN_LATIN }, /* Latin qwerty */
|
||||
{ "latinunicodeyz", KBD_SERBIAN_LATIN }, /* Latin Unicode qwerty */
|
||||
{ "alternatequotes", KBD_SERBIAN_CYRILLIC }, /* With guillemets */
|
||||
{ "latinalternatequotes", KBD_SERBIAN_LATIN }, /* Latin with guillemets */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Slovenia */
|
||||
static const XKB_VARIANT si_variants[] = {
|
||||
{ "alternatequotes", KBD_SLOVENIAN }, /* Use guillemets for quotes */
|
||||
{ "us", KBD_UNITED_STATES_INTERNATIONAL }, /* US keyboard with Slovenian letters */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Slovakia */
|
||||
static const XKB_VARIANT sk_variants[] = {
|
||||
{ "bksl", KBD_SLOVAK }, /* Extended Backslash */
|
||||
{ "qwerty", KBD_SLOVAK_QWERTY }, /* qwerty */
|
||||
{ "qwerty_bksl", KBD_SLOVAK_QWERTY }, /* qwerty, extended Backslash */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Spain */
|
||||
static const XKB_VARIANT es_variants[] = {
|
||||
{ "nodeadkeys", KBD_SPANISH_VARIATION }, /* Eliminate dead keys */
|
||||
{ "deadtilde", KBD_SPANISH_VARIATION }, /* Include dead tilde */
|
||||
{ "sundeadkeys", KBD_SPANISH }, /* Sun dead keys */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "ast", KBD_SPANISH_VARIATION }, /* Asturian variant with bottom-dot H and bottom-dot L */
|
||||
{ "cat", KBD_SPANISH_VARIATION }, /* Catalan variant with middle-dot L */
|
||||
{ "mac", KBD_SPANISH }, /* Macintosh */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Sweden */
|
||||
static const XKB_VARIANT se_variants[] = {
|
||||
{ "nodeadkeys", KBD_SWEDISH }, /* Eliminate dead keys */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "rus", KBD_RUSSIAN }, /* Russian phonetic */
|
||||
{ "rus_nodeadkeys", KBD_RUSSIAN }, /* Russian phonetic, eliminate dead keys */
|
||||
{ "smi", KBD_SWEDISH_WITH_SAMI }, /* Northern Saami */
|
||||
{ "mac", KBD_SWEDISH }, /* Macintosh */
|
||||
{ "svdvorak", KBD_UNITED_STATES_DVORAK }, /* Svdvorak */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Switzerland */
|
||||
static const XKB_VARIANT ch_variants[] = {
|
||||
{ "de_nodeadkeys", KBD_SWISS_GERMAN }, /* German, eliminate dead keys */
|
||||
{ "de_sundeadkeys", KBD_SWISS_GERMAN }, /* German, Sun dead keys */
|
||||
{ "fr", KBD_SWISS_FRENCH }, /* French */
|
||||
{ "fr_nodeadkeys", KBD_SWISS_FRENCH }, /* French, eliminate dead keys */
|
||||
{ "fr_sundeadkeys", KBD_SWISS_FRENCH }, /* French, Sun dead keys */
|
||||
{ "fr_mac", KBD_SWISS_FRENCH }, /* French (Macintosh) */
|
||||
{ "de_mac", KBD_SWISS_GERMAN }, /* German (Macintosh) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Syria */
|
||||
static const XKB_VARIANT sy_variants[] = {
|
||||
{ "syc", KBD_SYRIAC }, /* Syriac */
|
||||
{ "syc_phonetic", KBD_SYRIAC_PHONETIC }, /* Syriac phonetic */
|
||||
{ "ku", 0 }, /* Kurdish, Latin Q */
|
||||
{ "ku_f", 0 }, /* Kurdish, (F) */
|
||||
{ "ku_alt", 0 }, /* Kurdish, Latin Alt-Q */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Tajikistan */
|
||||
static const XKB_VARIANT tj_variants[] = {
|
||||
{ "legacy", 0 }, /* Legacy */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Sri Lanka */
|
||||
static const XKB_VARIANT lk_variants[] = {
|
||||
{ "tam_unicode", KBD_TAMIL }, /* Tamil Unicode */
|
||||
{ "tam_TAB", KBD_TAMIL }, /* Tamil TAB Typewriter */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Thailand */
|
||||
static const XKB_VARIANT th_variants[] = {
|
||||
{ "tis", KBD_THAI_KEDMANEE_NON_SHIFTLOCK }, /* TIS-820.2538 */
|
||||
{ "pat", KBD_THAI_PATTACHOTE }, /* Pattachote */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Turkey */
|
||||
static const XKB_VARIANT tr_variants[] = {
|
||||
{ "f", KBD_TURKISH_F }, /* (F) */
|
||||
{ "alt", KBD_TURKISH_Q }, /* Alt-Q */
|
||||
{ "sundeadkeys", KBD_TURKISH_F }, /* Sun dead keys */
|
||||
{ "ku", 0 }, /* Kurdish, Latin Q */
|
||||
{ "ku_f", 0 }, /* Kurdish, (F) */
|
||||
{ "ku_alt", 0 }, /* Kurdish, Latin Alt-Q */
|
||||
{ "intl", KBD_TURKISH_F }, /* International (with dead keys) */
|
||||
{ "crh", KBD_TATAR }, /* Crimean Tatar (Turkish Q) */
|
||||
{ "crh_f", KBD_TURKISH_F }, /* Crimean Tatar (Turkish F) */
|
||||
{ "crh_alt", KBD_TURKISH_Q }, /* Crimean Tatar (Turkish Alt-Q) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Ukraine */
|
||||
static const XKB_VARIANT ua_variants[] = {
|
||||
{ "phonetic", KBD_UKRAINIAN }, /* Phonetic */
|
||||
{ "typewriter", KBD_UKRAINIAN }, /* Typewriter */
|
||||
{ "winkeys", KBD_UKRAINIAN }, /* Winkeys */
|
||||
{ "legacy", KBD_UKRAINIAN }, /* Legacy */
|
||||
{ "rstu", KBD_UKRAINIAN }, /* Standard RSTU */
|
||||
{ "rstu_ru", KBD_UKRAINIAN }, /* Standard RSTU on Russian layout */
|
||||
{ "homophonic", KBD_UKRAINIAN }, /* Homophonic */
|
||||
{ "crh", KBD_TATAR }, /* Crimean Tatar (Turkish Q) */
|
||||
{ "crh_f", KBD_TURKISH_F }, /* Crimean Tatar (Turkish F) */
|
||||
{ "crh_alt", KBD_TURKISH_Q }, /* Crimean Tatar (Turkish Alt-Q) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* United Kingdom */
|
||||
static const XKB_VARIANT gb_variants[] = {
|
||||
{ "extd", KBD_UNITED_KINGDOM_EXTENDED }, /* Extended - Winkeys */
|
||||
{ "intl", KBD_UNITED_KINGDOM_EXTENDED }, /* International (with dead keys) */
|
||||
{ "dvorak", KBD_UNITED_STATES_DVORAK }, /* Dvorak */
|
||||
{ "dvorakukp", KBD_UNITED_STATES_DVORAK }, /* Dvorak (UK Punctuation) */
|
||||
{ "mac", KBD_UNITED_KINGDOM }, /* Macintosh */
|
||||
{ "colemak", 0 }, /* Colemak */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Uzbekistan */
|
||||
static const XKB_VARIANT uz_variants[] = {
|
||||
{ "latin", 0 }, /* Latin */
|
||||
{ "crh", KBD_TATAR }, /* Crimean Tatar (Turkish Q) */
|
||||
{ "crh_f", KBD_TURKISH_F }, /* Crimean Tatar (Turkish F) */
|
||||
{ "crh_alt", KBD_TURKISH_Q }, /* Crimean Tatar (Turkish Alt-Q) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Korea, Republic of */
|
||||
static const XKB_VARIANT kr_variants[] = {
|
||||
{ "kr104", KBD_KOREAN_INPUT_SYSTEM_IME_2000 }, /* 101/104 key Compatible */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Ireland */
|
||||
static const XKB_VARIANT ie_variants[] = {
|
||||
{ "CloGaelach", KBD_GAELIC }, /* CloGaelach */
|
||||
{ "UnicodeExpert", KBD_GAELIC }, /* UnicodeExpert */
|
||||
{ "ogam", KBD_GAELIC }, /* Ogham */
|
||||
{ "ogam_is434", KBD_GAELIC }, /* Ogham IS434 */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Pakistan */
|
||||
static const XKB_VARIANT pk_variants[] = {
|
||||
{ "urd-crulp", 0 }, /* CRULP */
|
||||
{ "urd-nla", 0 }, /* NLA */
|
||||
{ "ara", KBD_ARABIC_101 }, /* Arabic */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Esperanto */
|
||||
static const XKB_VARIANT epo_variants[] = {
|
||||
{ "legacy", 0 }, /* displaced semicolon and quote (obsolete) */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Nigeria */
|
||||
static const XKB_VARIANT ng_variants[] = {
|
||||
{ "igbo", 0 }, /* Igbo */
|
||||
{ "yoruba", 0 }, /* Yoruba */
|
||||
{ "hausa", 0 }, /* Hausa */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Braille */
|
||||
static const XKB_VARIANT brai_variants[] = {
|
||||
{ "left_hand", 0 }, /* Left hand */
|
||||
{ "right_hand", 0 }, /* Right hand */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
/* Turkmenistan */
|
||||
static const XKB_VARIANT tm_variants[] = {
|
||||
{ "alt", KBD_TURKISH_Q }, /* Alt-Q */
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
static const XKB_LAYOUT xkbLayouts[] = {
|
||||
{ "us", KBD_US, us_variants }, /* USA */
|
||||
{ "ad", 0, nullptr }, /* Andorra */
|
||||
{ "af", KBD_FARSI, af_variants }, /* Afghanistan */
|
||||
{ "ara", KBD_ARABIC_101, ara_variants }, /* Arabic */
|
||||
{ "al", 0, nullptr }, /* Albania */
|
||||
{ "am", KBD_ARMENIAN_EASTERN, am_variants }, /* Armenia */
|
||||
{ "az", KBD_AZERI_CYRILLIC, az_variants }, /* Azerbaijan */
|
||||
{ "by", KBD_BELARUSIAN, by_variants }, /* Belarus */
|
||||
{ "be", KBD_BELGIAN_FRENCH, be_variants }, /* Belgium */
|
||||
{ "bd", KBD_BENGALI, bd_variants }, /* Bangladesh */
|
||||
{ "in", KBD_HINDI_TRADITIONAL, in_variants }, /* India */
|
||||
{ "ba", KBD_CROATIAN, ba_variants }, /* Bosnia and Herzegovina */
|
||||
{ "br", KBD_PORTUGUESE_BRAZILIAN_ABNT, br_variants }, /* Brazil */
|
||||
{ "bg", KBD_BULGARIAN_LATIN, bg_variants }, /* Bulgaria */
|
||||
{ "ma", KBD_FRENCH, ma_variants }, /* Morocco */
|
||||
{ "mm", 0, nullptr }, /* Myanmar */
|
||||
{ "ca", KBD_US, ca_variants }, /* Canada */
|
||||
{ "cd", 0, nullptr }, /* Congo, Democratic Republic of the */
|
||||
{ "cn", KBD_CHINESE_TRADITIONAL_PHONETIC, cn_variants }, /* China */
|
||||
{ "hr", KBD_CROATIAN, hr_variants }, /* Croatia */
|
||||
{ "cz", KBD_CZECH, cz_variants }, /* Czechia */
|
||||
{ "dk", KBD_DANISH, dk_variants }, /* Denmark */
|
||||
{ "nl", KBD_DUTCH, nl_variants }, /* Netherlands */
|
||||
{ "bt", 0, nullptr }, /* Bhutan */
|
||||
{ "ee", KBD_ESTONIAN, ee_variants }, /* Estonia */
|
||||
{ "ir", 0, ir_variants }, /* Iran */
|
||||
{ "iq", 0, iq_variants }, /* Iraq */
|
||||
{ "fo", 0, fo_variants }, /* Faroe Islands */
|
||||
{ "fi", KBD_FINNISH, fi_variants }, /* Finland */
|
||||
{ "fr", KBD_FRENCH, fr_variants }, /* France */
|
||||
{ "gh", 0, gh_variants }, /* Ghana */
|
||||
{ "gn", 0, nullptr }, /* Guinea */
|
||||
{ "ge", KBD_GEORGIAN, ge_variants }, /* Georgia */
|
||||
{ "at", KBD_GERMAN, de_variants }, /* Austria */
|
||||
{ "de", KBD_GERMAN, de_variants }, /* Germany */
|
||||
{ "gr", KBD_GREEK, gr_variants }, /* Greece */
|
||||
{ "hu", KBD_HUNGARIAN, hu_variants }, /* Hungary */
|
||||
{ "is", KBD_ICELANDIC, is_variants }, /* Iceland */
|
||||
{ "il", KBD_HEBREW, il_variants }, /* Israel */
|
||||
{ "it", KBD_ITALIAN, it_variants }, /* Italy */
|
||||
{ "jp", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002, jp_variants }, /* Japan */
|
||||
{ "kg", 0, kg_variants }, /* Kyrgyzstan */
|
||||
{ "kh", 0, nullptr }, /* Cambodia */
|
||||
{ "kz", KBD_KAZAKH, kz_variants }, /* Kazakhstan */
|
||||
{ "la", 0, nullptr }, /* Laos */
|
||||
{ "latam", KBD_LATIN_AMERICAN, latam_variants }, /* Latin America */
|
||||
{ "lt", KBD_LITHUANIAN, lt_variants }, /* Lithuania */
|
||||
{ "lv", KBD_LATVIAN, lv_variants }, /* Latvia */
|
||||
{ "mao", KBD_MAORI, nullptr }, /* Maori */
|
||||
{ "me", KBD_SERBIAN_LATIN, me_variants }, /* Montenegro */
|
||||
{ "mk", KBD_FYRO_MACEDONIAN, mk_variants }, /* Macedonia */
|
||||
{ "mt", KBD_MALTESE_48_KEY, mt_variants }, /* Malta */
|
||||
{ "mn", KBD_MONGOLIAN_CYRILLIC, nullptr }, /* Mongolia */
|
||||
{ "no", KBD_NORWEGIAN, no_variants }, /* Norway */
|
||||
{ "pl", KBD_POLISH_PROGRAMMERS, pl_variants }, /* Poland */
|
||||
{ "pt", KBD_PORTUGUESE, pt_variants }, /* Portugal */
|
||||
{ "ro", KBD_ROMANIAN, ro_variants }, /* Romania */
|
||||
{ "ru", KBD_RUSSIAN, ru_variants }, /* Russia */
|
||||
{ "rs", KBD_SERBIAN_LATIN, rs_variants }, /* Serbia */
|
||||
{ "si", KBD_SLOVENIAN, si_variants }, /* Slovenia */
|
||||
{ "sk", KBD_SLOVAK, sk_variants }, /* Slovakia */
|
||||
{ "es", KBD_SPANISH, es_variants }, /* Spain */
|
||||
{ "se", KBD_SWEDISH, se_variants }, /* Sweden */
|
||||
{ "ch", KBD_SWISS_GERMAN, ch_variants }, /* Switzerland */
|
||||
{ "sy", KBD_SYRIAC, sy_variants }, /* Syria */
|
||||
{ "tj", 0, tj_variants }, /* Tajikistan */
|
||||
{ "lk", 0, lk_variants }, /* Sri Lanka */
|
||||
{ "th", KBD_THAI_KEDMANEE, th_variants }, /* Thailand */
|
||||
{ "tr", KBD_TURKISH_Q, tr_variants }, /* Turkey */
|
||||
{ "ua", KBD_UKRAINIAN, ua_variants }, /* Ukraine */
|
||||
{ "gb", KBD_UNITED_KINGDOM, gb_variants }, /* United Kingdom */
|
||||
{ "uz", KBD_UZBEK_CYRILLIC, uz_variants }, /* Uzbekistan */
|
||||
{ "vn", KBD_VIETNAMESE, nullptr }, /* Vietnam */
|
||||
{ "kr", KBD_KOREAN_INPUT_SYSTEM_IME_2000, kr_variants }, /* Korea, Republic of */
|
||||
{ "ie", KBD_UNITED_KINGDOM, ie_variants }, /* Ireland */
|
||||
{ "pk", 0, pk_variants }, /* Pakistan */
|
||||
{ "mv", 0, nullptr }, /* Maldives */
|
||||
{ "za", KBD_US, nullptr }, /* South Africa */
|
||||
{ "epo", 0, epo_variants }, /* Esperanto */
|
||||
{ "np", KBD_NEPALI, nullptr }, /* Nepal */
|
||||
{ "ng", 0, ng_variants }, /* Nigeria */
|
||||
{ "et", 0, nullptr }, /* Ethiopia */
|
||||
{ "sn", 0, nullptr }, /* Senegal */
|
||||
{ "brai", 0, brai_variants }, /* Braille */
|
||||
{ "tm", KBD_TURKISH_Q, tm_variants }, /* Turkmenistan */
|
||||
};
|
||||
|
||||
static uint32_t convert(int64_t val)
|
||||
{
|
||||
WINPR_ASSERT(val <= UINT32_MAX);
|
||||
WINPR_ASSERT(val >= INT32_MIN);
|
||||
return WINPR_CXX_COMPAT_CAST(uint32_t, val);
|
||||
}
|
||||
|
||||
static UINT32 find_keyboard_layout_variant(const XKB_LAYOUT* layout, const char* variant)
|
||||
{
|
||||
WINPR_ASSERT(layout);
|
||||
WINPR_ASSERT(variant);
|
||||
|
||||
const XKB_VARIANT* variants = layout->variants;
|
||||
if (variants)
|
||||
{
|
||||
const XKB_VARIANT* var = variants;
|
||||
while (var->variant && (strlen(var->variant) != 0))
|
||||
{
|
||||
if (strcmp(var->variant, variant) == 0)
|
||||
return convert(var->keyboardLayoutID);
|
||||
var++;
|
||||
}
|
||||
}
|
||||
|
||||
return convert(layout->keyboardLayoutID);
|
||||
}
|
||||
|
||||
UINT32 xf_find_keyboard_layout_in_xorg_rules(const char* layout, const char* variant)
|
||||
{
|
||||
if ((layout == nullptr) || (variant == nullptr))
|
||||
return 0;
|
||||
|
||||
DEBUG_X11("xkbLayout: %s\txkbVariant: %s", layout, variant);
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE(xkbLayouts); i++)
|
||||
{
|
||||
const XKB_LAYOUT* cur = &xkbLayouts[i];
|
||||
if (strcmp(cur->layout, layout) == 0)
|
||||
return find_keyboard_layout_variant(cur, variant);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
28
third_party/FreeRDP/client/X11/xkb_layout_ids.h
vendored
Normal file
28
third_party/FreeRDP/client/X11/xkb_layout_ids.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* RDP Keyboard layout ID detection from common X11 xkb keyboard layout names
|
||||
*
|
||||
* Copyright 2009-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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_LOCALE_XKB_LAYOUT_IDS_H
|
||||
#define FREERDP_LIB_LOCALE_XKB_LAYOUT_IDS_H
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/api.h>
|
||||
|
||||
FREERDP_LOCAL UINT32 xf_find_keyboard_layout_in_xorg_rules(const char* layout, const char* variant);
|
||||
|
||||
#endif /* FREERDP_LIB_LOCALE_XKB_LAYOUT_IDS_H */
|
||||
Reference in New Issue
Block a user