Merge pull request #1962 from matt335672/imlib2

Add imlib2 support for login screen customisation (#1962)
This commit is contained in:
matt335672 2021-09-01 10:19:11 +01:00 committed by GitHub
commit 63c3ca4ddd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 2318 additions and 883 deletions

View File

@ -6,11 +6,11 @@ FreeBSD_task:
freebsd_instance:
image_family: freebsd-12-2
prepare_script:
- pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs check
- pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs check imlib2
- git submodule update --init --recursive
configure_script:
- ./bootstrap
- env CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure --localstatedir=/var --enable-strict-locations --with-pkgconfigdir=/usr/local/libdata/pkgconfig --enable-strict-locations --enable-ipv6 --enable-opus --enable-jpeg --enable-fdkaac --enable-painter --enable-pixman --enable-fuse
- env CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure --localstatedir=/var --enable-strict-locations --with-pkgconfigdir=/usr/local/libdata/pkgconfig --enable-strict-locations --enable-ipv6 --enable-opus --enable-jpeg --enable-fdkaac --enable-painter --enable-pixman --enable-fuse --with-imlib2
build_script:
- make -j $(sysctl -n hw.ncpu || echo 4)
install_script:

View File

@ -94,10 +94,10 @@ jobs:
--disable-pixman"
CONF_FLAGS_amd64_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame
--enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter
--enable-pixman"
--enable-pixman --with-imlib2"
CONF_FLAGS_i386_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame
--enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter
--disable-pixman --host=i686-linux"
--disable-pixman --with-imlib2 --host=i686-linux"
PKG_CONFIG_PATH_i386: "/usr/lib/i386-linux-gnu/pkgconfig"
CFLAGS_i386: "-m32"

View File

@ -166,6 +166,8 @@ AC_ARG_ENABLE(rdpsndaudin, AS_HELP_STRING([--enable-rdpsndaudin],
[], [enable_rdpsndaudin=no])
AM_CONDITIONAL(XRDP_RDPSNDAUDIN, [test x$enable_rdpsndaudin = xyes])
AC_ARG_WITH(imlib2, AC_HELP_STRING([--with-imlib2=ARG], [imlib2 library to use for non-BMP backgrounds (ARG=yes/no/<abs-path>)]),,)
# Obsolete options
AC_ARG_ENABLE(xrdpdebug, AS_HELP_STRING([--enable-xrdpdebug],
[This option is no longer supported - use --enable-devel-all]))
@ -216,6 +218,44 @@ AC_CHECK_HEADER([security/_pam_types.h],
AC_CHECK_HEADER([security/pam_constants.h],
[AC_DEFINE([HAVE_PAM_CONSTANTS_H], 1, [Using OpenPAM], [])])
# Find imlib2
case "$with_imlib2" in
'' | no) AC_MSG_NOTICE([imlib2 will not be supported])
use_imlib2=no
;;
yes)
PKG_CHECK_MODULES([IMLIB2], [imlib2 >= 1.4.10],
[use_imlib2=yes],
[AC_MSG_ERROR([please install libimlib2-dev or imlib2-devel])])
;;
/*) AC_MSG_CHECKING([for imlib2 in $with_imlib2])
if test -d $with_imlib2/lib; then
IMLIB2_LIBS="-L$with_imlib2/lib -lImlib2"
elif test -d $with_imlib2/lib64; then
IMLIB2_LIBS="-L$with_imlib2/lib64 -lImlib2"
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([Can't find libImlib2 in $with_imlib2])
fi
if test -f $with_imlib2/include/Imlib2.h; then
IMLIB2_CFLAGS="-I $with_imlib2/include"
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([Can't find $with_imlib2/include/Imlib2.h])
fi
AC_MSG_RESULT([yes])
AC_SUBST([IMLIB2_LIBS])
AC_SUBST([IMLIB2_CFLAGS])
use_imlib2=yes
;;
*) AC_MSG_ERROR([--with-imlib2 needs yes/no or absolute path])
esac
if test x$use_imlib2 = xyes; then
AC_DEFINE([USE_IMLIB2],1, [Compile with imlib2 support])
fi
# Check only one auth mechanism is specified, and give it a name
auth_cnt=0
auth_mech="Builtin"
@ -454,6 +494,7 @@ AC_CONFIG_FILES([
tests/Makefile
tests/common/Makefile
tests/memtest/Makefile
tests/xrdp/Makefile
tools/Makefile
tools/devel/Makefile
tools/devel/tcp_proxy/Makefile
@ -485,6 +526,12 @@ echo " vsock $enable_vsock"
echo " auth mechanism $auth_mech"
echo " rdpsndaudin $enable_rdpsndaudin"
echo
if test x$use_imlib2 = xyes; then
echo " with imlib2 yes"
else
echo " with imlib2 no"
fi
echo
echo " development logging $devel_logging"
echo " development streamcheck $devel_streamcheck"
echo ""

View File

@ -50,6 +50,7 @@ in
libjpeg-dev \
libmp3lame-dev \
libfdk-aac-dev \
libimlib2-dev \
libopus-dev \
libpixman-1-dev"
;;
@ -66,6 +67,7 @@ in
libgl1-mesa-dev:i386 \
libglu1-mesa-dev:i386 \
libjpeg-dev:i386 \
libimlib2-dev:i386 \
libmp3lame-dev:i386 \
libfdk-aac-dev:i386 \
libopus-dev:i386 \

View File

@ -4,4 +4,5 @@ EXTRA_DIST = \
SUBDIRS = \
common \
memtest
memtest \
xrdp

41
tests/xrdp/Makefile.am Normal file
View File

@ -0,0 +1,41 @@
AM_CPPFLAGS = \
-I$(top_builddir) \
-I$(top_srcdir)/xrdp \
-I$(top_srcdir)/libxrdp \
-I$(top_srcdir)/common \
$(IMLIB2_CFLAGS)
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
$(top_srcdir)/tap-driver.sh
PACKAGE_STRING="XRDP daemon"
EXTRA_DIST = \
test_4bit.bmp \
test_8bit.bmp \
test_24bit.bmp \
test_not4_4bit.bmp \
test_not4_8bit.bmp \
test_not4_24bit.bmp \
test1.jpg \
test_alpha_blend.png
TESTS = test_xrdp
check_PROGRAMS = test_xrdp
test_xrdp_SOURCES = \
test_xrdp.h \
test_xrdp_main.c \
test_bitmap_load.c
test_xrdp_CFLAGS = \
-D IMAGEDIR=\"$(srcdir)\" \
@CHECK_CFLAGS@
test_xrdp_LDADD = \
$(top_builddir)/xrdp/xrdp_bitmap_load.o \
$(top_builddir)/xrdp/xrdp_bitmap_common.o \
$(top_builddir)/xrdp/funcs.o \
$(top_builddir)/common/libcommon.la \
$(IMLIB2_LIBS) \
@CHECK_LIBS@

BIN
tests/xrdp/test1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
tests/xrdp/test_24bit.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
tests/xrdp/test_4bit.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
tests/xrdp/test_8bit.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,337 @@
#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include "test_xrdp.h"
#include "xrdp.h"
/* Where the image files are located */
#ifndef IMAGEDIR
#define IMAGEDIR "."
#endif
/* Handy color definitions. These are variables so they are displayed
* in assert messages if tests fail */
static int RED = COLOR24RGB(255, 0, 0);
static int GREEN = COLOR24RGB(0, 255, 0);
static int BLUE = COLOR24RGB(0, 0, 255);
static int WHITE = COLOR24RGB(255, 255, 255);
/* Virtual desktop maxima and minima [MS-RDPBCGR] 2.2.1.3.6 */
#define MAX_VDESKTOP_WIDTH 32766
#define MAX_VDESKTOP_HEIGHT 32766
#define MIN_VDESKTOP_WIDTH 200
#define MIN_VDESKTOP_HEIGHT 200
/* Characteristics of the test bitmap(s) */
#define TEST_BM_WIDTH 256
#define TEST_BM_HEIGHT 256
#define TEST_NOT4_BM_WIDTH 62
#define TEST_NOT4_BM_HEIGHT 62
#define TEST_BM_TOP_LEFT_PIXEL RED
#define TEST_BM_TOP_RIGHT_PIXEL GREEN
#define TEST_BM_BOTTOM_LEFT_PIXEL BLUE
#define TEST_BM_BOTTOM_RIGHT_PIXEL WHITE
/*
* Scaling bitmaps properly will introduce color changes with dithering.
* Also some filetypes use compression, and these do not represent colors
* perfectly.
*
* This is the Pythagorean distance we allow between two colors for them to
* be considered close enough to each other */
#define MAX_SIMILAR_COLOR_DISTANCE 3
void setup(void)
{
}
void teardown(void)
{
}
/* Tests an error is returned for a non-existent file */
START_TEST(test_bitmap_load__with_invalid_image__fail)
{
struct xrdp_wm *wm = NULL;
int result;
struct xrdp_bitmap *bm = xrdp_bitmap_create(4, 4, 32, WND_TYPE_IMAGE, wm);
ck_assert_ptr_ne(bm, NULL);
result = xrdp_bitmap_load(bm, "/dev/null", NULL, 0, XBLT_NONE, 0, 0);
ck_assert_int_ne(result, 0);
xrdp_bitmap_delete(bm);
}
END_TEST
/* Checks a particular pixmap value is expected */
static void
check_pixel(struct xrdp_bitmap *bm, int i, int j, int expected)
{
int pixel = xrdp_bitmap_get_pixel(bm, i, j);
if (pixel != expected)
{
ck_abort_msg("Pixmap (%d,%d) expected 0x%06x, got 0x%06x",
i, j, expected, pixel);
}
}
/* Calculates whether two colors are close enough to be considered the same */
static void
check_is_close_color(struct xrdp_bitmap *bm, int i, int j, int expected)
{
int pixel = xrdp_bitmap_get_pixel(bm, i, j);
int r1;
int g1;
int b1;
int r2;
int g2;
int b2;
int variance;
SPLITCOLOR32(r1, g1, b1, pixel);
SPLITCOLOR32(r2, g2, b2, expected);
variance = ((r1 - r2) * (r1 - r2) +
(g1 - g2) * (g1 - g2) +
(b1 - b2) * (b1 - b2));
if (variance > MAX_SIMILAR_COLOR_DISTANCE * MAX_SIMILAR_COLOR_DISTANCE)
{
ck_abort_msg("Pixmap (%d,%d) expected 0x%06x, got 0x%06x"
" which exceeds distance of %d",
i, j, expected, pixel, MAX_SIMILAR_COLOR_DISTANCE);
}
}
/* Check we can load images of various depths with various transforms */
static void
load_and_transform_img(const char *name,
enum xrdp_bitmap_load_transform transform,
int twidth, int theight)
{
struct xrdp_wm *wm = NULL;
int result;
int width;
int height;
char full_name[256];
struct xrdp_bitmap *bm = xrdp_bitmap_create(4, 4, 32, WND_TYPE_IMAGE, wm);
ck_assert_ptr_ne(bm, NULL);
g_snprintf(full_name, sizeof(full_name), IMAGEDIR "/%s", name);
result = xrdp_bitmap_load(bm, full_name, NULL, HCOLOR(bm->bpp, WHITE),
transform, twidth, theight);
ck_assert_int_eq(result, 0);
/* Bitmap right size? */
if (transform == XBLT_NONE)
{
width = TEST_BM_WIDTH;
height = TEST_BM_HEIGHT;
ck_assert_int_eq(bm->width, TEST_BM_WIDTH);
ck_assert_int_eq(bm->height, TEST_BM_HEIGHT);
}
else
{
width = twidth;
height = theight;
ck_assert_int_eq(bm->width, twidth);
ck_assert_int_eq(bm->height, theight);
}
/* Corners OK? Allow for dithering */
check_is_close_color(bm, 0, 0, TEST_BM_TOP_LEFT_PIXEL);
check_is_close_color(bm, width - 1, 0, TEST_BM_TOP_RIGHT_PIXEL);
check_is_close_color(bm, 0, height - 1, TEST_BM_BOTTOM_LEFT_PIXEL);
check_is_close_color(bm, width - 1, height - 1, TEST_BM_BOTTOM_RIGHT_PIXEL);
xrdp_bitmap_delete(bm);
}
/* Check we can load bitmaps that aren't a multiple of 4 pixels wide */
static void
load_not4_img(const char *name)
{
struct xrdp_wm *wm = NULL;
int result;
const int width = TEST_NOT4_BM_WIDTH;
const int height = TEST_NOT4_BM_HEIGHT;
char full_name[256];
int i;
int j;
struct xrdp_bitmap *bm = xrdp_bitmap_create(4, 4, 32, WND_TYPE_IMAGE, wm);
ck_assert_ptr_ne(bm, NULL);
g_snprintf(full_name, sizeof(full_name), IMAGEDIR "/%s", name);
result = xrdp_bitmap_load(bm, full_name, NULL, HCOLOR(bm->bpp, WHITE),
XBLT_NONE, 0, 0);
ck_assert_int_eq(result, 0);
/* Bitmap right size? */
ck_assert_int_eq(bm->width, TEST_NOT4_BM_WIDTH);
ck_assert_int_eq(bm->height, TEST_NOT4_BM_HEIGHT);
/* Check all data */
for (i = 0 ; i < width / 2 ; ++i)
{
for (j = 0 ; j < height / 2 ; ++j)
{
check_pixel(bm, i, j, TEST_BM_TOP_LEFT_PIXEL);
check_pixel(bm, i + width / 2, j, TEST_BM_TOP_RIGHT_PIXEL);
check_pixel(bm, i, j + height / 2, TEST_BM_BOTTOM_LEFT_PIXEL);
check_pixel(bm, i + width / 2, j + height / 2,
TEST_BM_BOTTOM_RIGHT_PIXEL);
}
}
xrdp_bitmap_delete(bm);
}
START_TEST(test_bitmap_load__4_bit__ok)
{
load_and_transform_img("test_4bit.bmp", XBLT_NONE, 0, 0);
}
END_TEST
START_TEST(test_bitmap_load__8_bit__ok)
{
load_and_transform_img("test_8bit.bmp", XBLT_NONE, 0, 0);
}
END_TEST
START_TEST(test_bitmap_load__24_bit__ok)
{
load_and_transform_img("test_24bit.bmp", XBLT_NONE, 0, 0);
}
END_TEST
START_TEST(test_bitmap_load__max_width_zoom__ok)
{
load_and_transform_img("test_24bit.bmp",
XBLT_ZOOM, MAX_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT);
}
END_TEST
START_TEST(test_bitmap_load__max_height_zoom__ok)
{
load_and_transform_img("test_24bit.bmp",
XBLT_ZOOM, MIN_VDESKTOP_WIDTH, MAX_VDESKTOP_HEIGHT);
}
END_TEST
START_TEST(test_bitmap_load__min_zoom__ok)
{
load_and_transform_img("test_24bit.bmp",
XBLT_ZOOM, MIN_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT);
}
END_TEST
START_TEST(test_bitmap_load__max_width_scale__ok)
{
load_and_transform_img("test_24bit.bmp",
XBLT_SCALE, MAX_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT);
}
END_TEST
START_TEST(test_bitmap_load__max_height_scale__ok)
{
load_and_transform_img("test_24bit.bmp",
XBLT_SCALE, MIN_VDESKTOP_WIDTH, MAX_VDESKTOP_HEIGHT);
}
END_TEST
START_TEST(test_bitmap_load__min_scale__ok)
{
load_and_transform_img("test_24bit.bmp",
XBLT_SCALE, MIN_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT);
}
END_TEST
START_TEST(test_bitmap_load__not_4_pixels_wide_4_bit__ok)
{
load_not4_img("test_not4_4bit.bmp");
}
END_TEST
START_TEST(test_bitmap_load__not_4_pixels_wide_8_bit__ok)
{
load_not4_img("test_not4_8bit.bmp");
}
END_TEST
START_TEST(test_bitmap_load__not_4_pixels_wide_24_bit__ok)
{
load_not4_img("test_not4_24bit.bmp");
}
END_TEST
#ifdef USE_IMLIB2
START_TEST(test_png_load__blend_ok)
{
load_and_transform_img("test_alpha_blend.png", XBLT_NONE, 0, 0);
}
END_TEST
START_TEST(test_jpg_load__ok)
{
load_and_transform_img("test1.jpg", XBLT_NONE, 0, 0);
}
END_TEST
#endif
/******************************************************************************/
Suite *
make_suite_test_bitmap_load(void)
{
Suite *s;
TCase *tc_bitmap_load;
#ifdef USE_IMLIB2
TCase *tc_other_load;
#endif
s = suite_create("BitmapLoad");
tc_bitmap_load = tcase_create("xrdp_bitmap_load");
tcase_add_checked_fixture(tc_bitmap_load, setup, teardown);
tcase_add_test(tc_bitmap_load, test_bitmap_load__with_invalid_image__fail);
tcase_add_test(tc_bitmap_load, test_bitmap_load__4_bit__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__8_bit__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__24_bit__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__max_width_zoom__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__max_height_zoom__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__min_zoom__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__max_width_scale__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__max_height_scale__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__min_scale__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__not_4_pixels_wide_4_bit__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__not_4_pixels_wide_8_bit__ok);
tcase_add_test(tc_bitmap_load, test_bitmap_load__not_4_pixels_wide_24_bit__ok);
suite_add_tcase(s, tc_bitmap_load);
#ifdef USE_IMLIB2
tc_other_load = tcase_create("xrdp_other_load");
tcase_add_checked_fixture(tc_other_load, setup, teardown);
tcase_add_test(tc_other_load, test_png_load__blend_ok);
tcase_add_test(tc_other_load, test_jpg_load__ok);
suite_add_tcase(s, tc_other_load);
#endif
return s;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

8
tests/xrdp/test_xrdp.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef TEST_XRDP_H
#define TEST_XRDP_H
#include <check.h>
Suite *make_suite_test_bitmap_load(void);
#endif /* TEST_XRDP_H */

View File

@ -0,0 +1,62 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2021
*
* 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.
*
* Test driver for XRDP routines
*
* If you want to run this driver under valgrind to check for memory leaks,
* use the following command line:-
*
* CK_FORK=no valgrind --leak-check=full --show-leak-kinds=all \
* .libs/test_xrdp
*
* without the 'CK_FORK=no', memory still allocated by the test driver will
* be logged
*/
#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include "log.h"
#include "os_calls.h"
#include "test_xrdp.h"
#include <stdlib.h>
int main (void)
{
int number_failed;
SRunner *sr;
struct log_config *logging;
/* Configure the logging sub-system so that functions can use
* the log functions as appropriate */
logging = log_config_init_for_console(LOG_LEVEL_INFO,
g_getenv("TEST_LOG_LEVEL"));
log_start_from_param(logging);
log_config_free(logging);
sr = srunner_create (make_suite_test_bitmap_load());
srunner_set_tap(sr, "-");
srunner_run_all (sr, CK_ENV);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
log_end();
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@ -12,7 +12,8 @@ AM_CPPFLAGS = \
-DXRDP_SOCKET_PATH=\"${socketdir}\" \
-I$(top_builddir) \
-I$(top_srcdir)/common \
-I$(top_srcdir)/libxrdp
-I$(top_srcdir)/libxrdp \
$(IMLIB2_CFLAGS)
XRDP_EXTRA_LIBS =
@ -43,6 +44,8 @@ xrdp_SOURCES = \
xrdp.c \
xrdp.h \
xrdp_bitmap.c \
xrdp_bitmap_load.c \
xrdp_bitmap_common.c \
xrdp_cache.c \
xrdp_encoder.c \
xrdp_encoder.h \
@ -59,6 +62,7 @@ xrdp_SOURCES = \
xrdp_LDADD = \
$(top_builddir)/common/libcommon.la \
$(top_builddir)/libxrdp/libxrdp.la \
$(IMLIB2_LIBS) \
$(XRDP_EXTRA_LIBS)
xrdpsysconfdir=$(sysconfdir)/xrdp

View File

@ -185,7 +185,7 @@ int
xrdp_region_get_rect(struct xrdp_region *self, int index,
struct xrdp_rect *rect);
/* xrdp_bitmap.c */
/* xrdp_bitmap_common.c */
struct xrdp_bitmap *
xrdp_bitmap_create(int width, int height, int bpp,
int type, struct xrdp_wm *wm);
@ -195,15 +195,9 @@ xrdp_bitmap_create_with_data(int width, int height,
struct xrdp_wm *wm);
void
xrdp_bitmap_delete(struct xrdp_bitmap *self);
struct xrdp_bitmap *
xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id);
int
xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused);
int
xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height);
int
xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, int *palette);
int
xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y);
int
xrdp_bitmap_set_pixel(struct xrdp_bitmap *self, int x, int y, int pixel);
@ -211,6 +205,12 @@ int
xrdp_bitmap_copy_box(struct xrdp_bitmap *self,
struct xrdp_bitmap *dest,
int x, int y, int cx, int cy);
/* xrdp_bitmap.c */
struct xrdp_bitmap *
xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id);
int
xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused);
int
xrdp_bitmap_hash_crc(struct xrdp_bitmap *self);
int
@ -239,6 +239,35 @@ xrdp_bitmap_get_screen_clip(struct xrdp_bitmap *self,
struct xrdp_rect *rect,
int *dx, int *dy);
/* xrdp_bitmap_load.c */
/**
* Loads a bitmap from a file and (optionally) transforms it
*
* @param self from rdp_bitmap_create()
* @param filename Filename to load
* @param[in] palette For 8-bit conversions. Currently unused
* @param background Background color for alpha-blending
* @param transform Transform to apply to the image after loading
* @param twidth target width if transform != XBLT_NONE
* @param theight target height if transform != XBLT_NONE
* @return 0 for success.
*
* The background color is only used if the specified image contains
* an alpha layer. It is in HCOLOR format, and the bpp must correspond to
* the bpp used to create 'self'.
*
* After a successful call, the bitmap is resized to the image file size.
*
* If the call is not successful, the bitmap will be in an indeterminate
* state and should not be used.
*/
int
xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename,
const int *palette,
int background,
enum xrdp_bitmap_load_transform transform,
int twidth,
int theight);
/* xrdp_painter.c */
struct xrdp_painter *
xrdp_painter_create(struct xrdp_wm *wm, struct xrdp_session *session);

View File

@ -129,12 +129,27 @@ ls_height=430
; login screen background color in RGB format
ls_bg_color=dedede
; optional background image filename (bmp format).
; optional background image filename. BMP format is always supported,
; but other formats will be supported if xrdp is build with imlib2
; The transform can be one of the following:-
; none : No transformation. Image is placed in bottom-right corner
; of the screen.
; scale : Image is scaled to the screen size. The image aspect
; ratio is not preserved.
; zoom : Image is scaled to the screen size. The image aspect
; ratio is preserved by clipping the image.
#ls_background_image=
#ls_background_transform=none
; logo
; full path to bmp-file or file in shared folder
; full path to file or file in shared folder. BMP format is always supported,
; but other formats will be supported if xrdp is build with imlib2
; For transform values, see 'ls_background_transform'. The logo width and
; logo height are ignored for a transform of 'none'.
ls_logo_filename=
#ls_logo_transform=none
#ls_logo_width=240
#ls_logo_height=140
ls_logo_x_pos=55
ls_logo_y_pos=50

View File

@ -25,8 +25,6 @@
#include <config_ac.h>
#endif
#include <limits.h>
#include "xrdp.h"
#include "log.h"
#include "string_calls.h"
@ -86,258 +84,6 @@ static const unsigned int g_crc_table[256] =
(in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8)
#define CRC_END(in_crc) (in_crc) = ((in_crc) ^ 0xFFFFFFFF)
/*****************************************************************************/
/* Allocate bitmap for specified dimensions, checking for int overflow */
static char *
alloc_bitmap_data(int width, int height, int Bpp)
{
char *result = NULL;
if (width > 0 && height > 0 && Bpp > 0)
{
int len = width;
/* g_malloc() currently takes an 'int' size */
if (len < INT_MAX / height)
{
len *= height;
if (len < INT_MAX / Bpp)
{
len *= Bpp;
result = (char *)malloc(len);
}
}
}
return result;
}
/*****************************************************************************/
struct xrdp_bitmap *
xrdp_bitmap_create(int width, int height, int bpp,
int type, struct xrdp_wm *wm)
{
struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL;
int Bpp = 0;
self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1);
self->type = type;
self->width = width;
self->height = height;
self->bpp = bpp;
Bpp = 4;
switch (bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE)
{
self->data = alloc_bitmap_data(width, height, Bpp);
if (self->data == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d",
width, height, Bpp);
g_free(self);
return NULL;
}
}
#if defined(XRDP_PAINTER)
if (self->type == WND_TYPE_SCREEN) /* noorders */
{
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_bitmap_create: noorders");
self->data = alloc_bitmap_data(width, height, Bpp);
if (self->data == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d",
width, height, Bpp);
g_free(self);
return NULL;
}
}
#endif
if (self->type != WND_TYPE_BITMAP)
{
self->child_list = list_create();
}
self->line_size = width * Bpp;
if (self->type == WND_TYPE_COMBO)
{
self->string_list = list_create();
self->string_list->auto_free = 1;
self->data_list = list_create();
self->data_list->auto_free = 1;
}
self->wm = wm;
return self;
}
/*****************************************************************************/
struct xrdp_bitmap *
xrdp_bitmap_create_with_data(int width, int height,
int bpp, char *data,
struct xrdp_wm *wm)
{
struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL;
int Bpp;
#if defined(NEED_ALIGN)
tintptr data_as_int;
#endif
self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1);
self->type = WND_TYPE_BITMAP;
self->width = width;
self->height = height;
self->bpp = bpp;
self->wm = wm;
Bpp = 4;
switch (bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
self->line_size = width * Bpp;
#if defined(NEED_ALIGN)
data_as_int = (tintptr) data;
if (((bpp >= 24) && (data_as_int & 3)) ||
(((bpp == 15) || (bpp == 16)) && (data_as_int & 1)))
{
/* got to copy data here, it's not aligned
other calls in this file assume alignment */
self->data = (char *)g_malloc(width * height * Bpp, 0);
g_memcpy(self->data, data, width * height * Bpp);
return self;
}
#endif
self->data = data;
self->do_not_free_data = 1;
return self;
}
/*****************************************************************************/
void
xrdp_bitmap_delete(struct xrdp_bitmap *self)
{
int i = 0;
struct xrdp_mod_data *mod_data = (struct xrdp_mod_data *)NULL;
if (self == 0)
{
return;
}
if (self->wm != 0)
{
if (self->wm->focused_window != 0)
{
if (self->wm->focused_window->focused_control == self)
{
self->wm->focused_window->focused_control = 0;
}
}
if (self->wm->focused_window == self)
{
self->wm->focused_window = 0;
}
if (self->wm->dragging_window == self)
{
self->wm->dragging_window = 0;
}
if (self->wm->button_down == self)
{
self->wm->button_down = 0;
}
if (self->wm->popup_wnd == self)
{
self->wm->popup_wnd = 0;
}
if (self->wm->login_window == self)
{
self->wm->login_window = 0;
}
if (self->wm->log_wnd == self)
{
self->wm->log_wnd = 0;
}
}
if (self->child_list != 0)
{
for (i = self->child_list->count - 1; i >= 0; i--)
{
xrdp_bitmap_delete((struct xrdp_bitmap *)self->child_list->items[i]);
}
list_delete(self->child_list);
}
if (self->parent != 0)
{
i = list_index_of(self->parent->child_list, (long)self);
if (i >= 0)
{
list_remove_item(self->parent->child_list, i);
}
}
if (self->string_list != 0) /* for combo */
{
list_delete(self->string_list);
}
if (self->data_list != 0) /* for combo */
{
for (i = 0; i < self->data_list->count; i++)
{
mod_data = (struct xrdp_mod_data *)list_get_item(self->data_list, i);
if (mod_data != 0)
{
list_delete(mod_data->names);
list_delete(mod_data->values);
}
}
list_delete(self->data_list);
}
if (!self->do_not_free_data)
{
g_free(self->data);
}
g_free(self->caption1);
g_free(self);
}
/*****************************************************************************/
struct xrdp_bitmap *
xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id)
@ -401,593 +147,6 @@ xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused)
return 0;
}
/*****************************************************************************/
static int
xrdp_bitmap_get_index(struct xrdp_bitmap *self, int *palette, int color)
{
int r = 0;
int g = 0;
int b = 0;
r = (color & 0xff0000) >> 16;
g = (color & 0x00ff00) >> 8;
b = (color & 0x0000ff) >> 0;
r = (r >> 5) << 0;
g = (g >> 5) << 3;
b = (b >> 6) << 6;
return (b | g | r);
}
/*****************************************************************************/
/* returns error */
int
xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
{
int Bpp = 0;
if ((width == self->width) && (height == self->height))
{
return 0;
}
if (self->do_not_free_data)
{
return 1;
}
self->width = width;
self->height = height;
Bpp = 4;
switch (self->bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
g_free(self->data);
self->data = (char *)g_malloc(width * height * Bpp, 0);
self->line_size = width * Bpp;
return 0;
}
/*****************************************************************************/
/* load a bmp file */
/* return 0 ok */
/* return 1 error */
int
xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, int *palette)
{
int fd = 0;
int len = 0;
int i = 0;
int j = 0;
int k = 0;
int color = 0;
int size = 0;
int palette1[256];
char type1[4];
struct xrdp_bmp_header header;
struct stream *s = (struct stream *)NULL;
g_memset(palette1, 0, sizeof(int) * 256);
g_memset(type1, 0, sizeof(char) * 4);
g_memset(&header, 0, sizeof(struct xrdp_bmp_header));
if (!g_file_exist(filename))
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] "
"does not exist", filename);
return 1;
}
fd = g_file_open(filename);
if (fd != -1)
{
/* read file type */
if (g_file_read(fd, type1, 2) != 2)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] "
"read error", filename);
g_file_close(fd);
return 1;
}
if ((type1[0] != 'B') || (type1[1] != 'M'))
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] "
"not BMP file", filename);
g_file_close(fd);
return 1;
}
/* read file size */
make_stream(s);
init_stream(s, 8192);
if (g_file_read(fd, s->data, 4) != 4)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: missing length in file %s",
filename);
free_stream(s);
g_file_close(fd);
return 1;
}
s->end = s->data + 4;
in_uint32_le(s, size);
/* read bmp header */
if (g_file_seek(fd, 14) < 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: seek error in file %s",
filename);
free_stream(s);
g_file_close(fd);
return 1;
}
init_stream(s, 8192);
len = g_file_read(fd, s->data, 40); /* size better be 40 */
if (len != 40)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: "
"unexpected read length %d in file %s",
len, filename);
free_stream(s);
g_file_close(fd);
return 1;
}
s->end = s->data + len;
in_uint32_le(s, header.size);
in_uint32_le(s, header.image_width);
in_uint32_le(s, header.image_height);
in_uint16_le(s, header.planes);
in_uint16_le(s, header.bit_count);
in_uint32_le(s, header.compression);
in_uint32_le(s, header.image_size);
in_uint32_le(s, header.x_pels_per_meter);
in_uint32_le(s, header.y_pels_per_meter);
in_uint32_le(s, header.clr_used);
in_uint32_le(s, header.clr_important);
if ((header.bit_count != 4) && (header.bit_count != 8) &&
(header.bit_count != 24))
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] "
"bad bpp %d", filename, header.bit_count);
free_stream(s);
g_file_close(fd);
return 1;
}
if (header.bit_count == 24) /* 24 bit bitmap */
{
if (g_file_seek(fd, 14 + header.size) < 0)
{
LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: seek error in file %s",
filename);
}
xrdp_bitmap_resize(self, header.image_width, header.image_height);
size = header.image_width * header.image_height * 3;
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
/* read data */
for (i = header.image_height - 1; i >= 0; i--)
{
size = header.image_width * 3;
k = g_file_read(fd, s->data + i * size, size);
if (k != size)
{
LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: error bitmap "
"file [%s] read", filename);
}
}
for (i = 0; i < self->height; i++)
{
for (j = 0; j < self->width; j++)
{
in_uint8(s, k);
color = k;
in_uint8(s, k);
color |= k << 8;
in_uint8(s, k);
color |= k << 16;
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, i, color);
}
}
}
else if (header.bit_count == 8) /* 8 bit bitmap */
{
/* read palette */
if (g_file_seek(fd, 14 + header.size) < 0)
{
LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: seek error in file %s",
filename);
}
size = header.clr_used * sizeof(int);
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
len = g_file_read(fd, s->data, size);
if (len != size)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: "
"unexpected read length in file %s",
filename);
}
for (i = 0; i < header.clr_used; i++)
{
in_uint32_le(s, palette1[i]);
}
xrdp_bitmap_resize(self, header.image_width, header.image_height);
size = header.image_width * header.image_height;
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
/* read data */
for (i = header.image_height - 1; i >= 0; i--)
{
size = header.image_width;
k = g_file_read(fd, s->data + i * size, size);
if (k != size)
{
LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: error bitmap "
"file [%s] read", filename);
}
}
for (i = 0; i < self->height; i++)
{
for (j = 0; j < self->width; j++)
{
in_uint8(s, k);
color = palette1[k];
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, i, color);
}
}
}
else if (header.bit_count == 4) /* 4 bit bitmap */
{
/* read palette */
if (g_file_seek(fd, 14 + header.size) < 0)
{
LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: seek error in file %s",
filename);
}
size = header.clr_used * sizeof(int);
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
len = g_file_read(fd, s->data, size);
if (len != size)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: "
"unexpected read length in file %s",
filename);
}
for (i = 0; i < header.clr_used; i++)
{
in_uint32_le(s, palette1[i]);
}
xrdp_bitmap_resize(self, header.image_width, header.image_height);
size = (header.image_width * header.image_height) / 2;
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
/* read data */
for (i = header.image_height - 1; i >= 0; i--)
{
size = header.image_width / 2;
k = g_file_read(fd, s->data + i * size, size);
if (k != size)
{
LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: error bitmap "
"file [%s] read", filename);
}
}
for (i = 0; i < self->height; i++)
{
for (j = 0; j < self->width; j++)
{
if ((j & 1) == 0)
{
in_uint8(s, k);
color = (k >> 4) & 0xf;
}
else
{
color = k & 0xf;
}
color = palette1[color];
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, i, color);
}
}
}
g_file_close(fd);
free_stream(s);
}
else
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error loading bitmap "
"from file [%s]", filename);
return 1;
}
return 0;
}
/*****************************************************************************/
int
xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y)
{
if (self == 0)
{
return 0;
}
if (self->data == 0)
{
return 0;
}
if (x >= 0 && x < self->width && y >= 0 && y < self->height)
{
if (self->bpp == 8)
{
return GETPIXEL8(self->data, x, y, self->width);
}
else if (self->bpp == 15 || self->bpp == 16)
{
return GETPIXEL16(self->data, x, y, self->width);
}
else if (self->bpp >= 24)
{
return GETPIXEL32(self->data, x, y, self->width);
}
}
return 0;
}
/*****************************************************************************/
int
xrdp_bitmap_set_pixel(struct xrdp_bitmap *self, int x, int y, int pixel)
{
if (self == 0)
{
return 0;
}
if (self->data == 0)
{
return 0;
}
if (x >= 0 && x < self->width && y >= 0 && y < self->height)
{
if (self->bpp == 8)
{
SETPIXEL8(self->data, x, y, self->width, pixel);
}
else if (self->bpp == 15 || self->bpp == 16)
{
SETPIXEL16(self->data, x, y, self->width, pixel);
}
else if (self->bpp >= 24)
{
SETPIXEL32(self->data, x, y, self->width, pixel);
}
}
return 0;
}
/*****************************************************************************/
/* copy part of self at x, y to 0, 0 in dest */
/* returns error */
int
xrdp_bitmap_copy_box(struct xrdp_bitmap *self,
struct xrdp_bitmap *dest,
int x, int y, int cx, int cy)
{
int i;
int destx;
int desty;
int incs;
int incd;
tui8 *s8;
tui8 *d8;
tui16 *s16;
tui16 *d16;
tui32 *s32;
tui32 *d32;
if (self == 0)
{
return 1;
}
if (dest == 0)
{
return 1;
}
if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE)
{
return 1;
}
if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE)
{
return 1;
}
if (self->bpp != dest->bpp)
{
return 1;
}
destx = 0;
desty = 0;
if (!check_bounds(self, &x, &y, &cx, &cy))
{
return 1;
}
if (!check_bounds(dest, &destx, &desty, &cx, &cy))
{
return 1;
}
if (self->bpp >= 24)
{
s32 = ((tui32 *)(self->data)) + (self->width * y + x);
d32 = ((tui32 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d32, s32, cx * 4);
s32 += cx;
d32 += cx;
s32 += incs;
d32 += incd;
}
}
else if (self->bpp == 15 || self->bpp == 16)
{
s16 = ((tui16 *)(self->data)) + (self->width * y + x);
d16 = ((tui16 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d16, s16, cx * 2);
s16 += cx;
d16 += cx;
s16 += incs;
d16 += incd;
}
}
else if (self->bpp == 8)
{
s8 = ((tui8 *)(self->data)) + (self->width * y + x);
d8 = ((tui8 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d8, s8, cx);
s8 += cx;
d8 += cx;
s8 += incs;
d8 += incd;
}
}
else
{
return 1;
}
return 0;
}
/*****************************************************************************/
int
xrdp_bitmap_hash_crc(struct xrdp_bitmap *self)

509
xrdp/xrdp_bitmap_common.c Normal file
View File

@ -0,0 +1,509 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2014
*
* 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.
*
* Common bitmap functions for all xrdp_bitmap*.c files
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <limits.h>
#include "xrdp.h"
/*****************************************************************************/
/* Allocate bitmap for specified dimensions, checking for int overflow */
static char *
alloc_bitmap_data(int width, int height, int Bpp)
{
char *result = NULL;
if (width > 0 && height > 0 && Bpp > 0)
{
int len = width;
/* g_malloc() currently takes an 'int' size */
if (len < INT_MAX / height)
{
len *= height;
if (len < INT_MAX / Bpp)
{
len *= Bpp;
result = (char *)malloc(len);
}
}
}
return result;
}
/*****************************************************************************/
struct xrdp_bitmap *
xrdp_bitmap_create(int width, int height, int bpp,
int type, struct xrdp_wm *wm)
{
struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL;
int Bpp = 0;
self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1);
if (self == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: no memory");
return self;
}
self->type = type;
self->width = width;
self->height = height;
self->bpp = bpp;
Bpp = 4;
switch (bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE)
{
self->data = alloc_bitmap_data(width, height, Bpp);
if (self->data == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d",
width, height, Bpp);
g_free(self);
return NULL;
}
}
#if defined(XRDP_PAINTER)
if (self->type == WND_TYPE_SCREEN) /* noorders */
{
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_bitmap_create: noorders");
self->data = alloc_bitmap_data(width, height, Bpp);
if (self->data == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d",
width, height, Bpp);
g_free(self);
return NULL;
}
}
#endif
if (self->type != WND_TYPE_BITMAP)
{
self->child_list = list_create();
}
self->line_size = width * Bpp;
if (self->type == WND_TYPE_COMBO)
{
self->string_list = list_create();
self->string_list->auto_free = 1;
self->data_list = list_create();
self->data_list->auto_free = 1;
}
self->wm = wm;
return self;
}
/*****************************************************************************/
struct xrdp_bitmap *
xrdp_bitmap_create_with_data(int width, int height,
int bpp, char *data,
struct xrdp_wm *wm)
{
struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL;
int Bpp;
#if defined(NEED_ALIGN)
tintptr data_as_int;
#endif
self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1);
self->type = WND_TYPE_BITMAP;
self->width = width;
self->height = height;
self->bpp = bpp;
self->wm = wm;
Bpp = 4;
switch (bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
self->line_size = width * Bpp;
#if defined(NEED_ALIGN)
data_as_int = (tintptr) data;
if (((bpp >= 24) && (data_as_int & 3)) ||
(((bpp == 15) || (bpp == 16)) && (data_as_int & 1)))
{
/* got to copy data here, it's not aligned
other calls in this file assume alignment */
self->data = (char *)g_malloc(width * height * Bpp, 0);
g_memcpy(self->data, data, width * height * Bpp);
return self;
}
#endif
self->data = data;
self->do_not_free_data = 1;
return self;
}
/*****************************************************************************/
void
xrdp_bitmap_delete(struct xrdp_bitmap *self)
{
int i = 0;
struct xrdp_mod_data *mod_data = (struct xrdp_mod_data *)NULL;
if (self == 0)
{
return;
}
if (self->wm != 0)
{
if (self->wm->focused_window != 0)
{
if (self->wm->focused_window->focused_control == self)
{
self->wm->focused_window->focused_control = 0;
}
}
if (self->wm->focused_window == self)
{
self->wm->focused_window = 0;
}
if (self->wm->dragging_window == self)
{
self->wm->dragging_window = 0;
}
if (self->wm->button_down == self)
{
self->wm->button_down = 0;
}
if (self->wm->popup_wnd == self)
{
self->wm->popup_wnd = 0;
}
if (self->wm->login_window == self)
{
self->wm->login_window = 0;
}
if (self->wm->log_wnd == self)
{
self->wm->log_wnd = 0;
}
}
if (self->child_list != 0)
{
for (i = self->child_list->count - 1; i >= 0; i--)
{
xrdp_bitmap_delete((struct xrdp_bitmap *)self->child_list->items[i]);
}
list_delete(self->child_list);
}
if (self->parent != 0)
{
i = list_index_of(self->parent->child_list, (long)self);
if (i >= 0)
{
list_remove_item(self->parent->child_list, i);
}
}
if (self->string_list != 0) /* for combo */
{
list_delete(self->string_list);
}
if (self->data_list != 0) /* for combo */
{
for (i = 0; i < self->data_list->count; i++)
{
mod_data = (struct xrdp_mod_data *)list_get_item(self->data_list, i);
if (mod_data != 0)
{
list_delete(mod_data->names);
list_delete(mod_data->values);
}
}
list_delete(self->data_list);
}
if (!self->do_not_free_data)
{
g_free(self->data);
}
g_free(self->caption1);
g_free(self);
}
/*****************************************************************************/
/* returns error */
int
xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
{
int Bpp = 0;
if ((width == self->width) && (height == self->height))
{
return 0;
}
if (self->do_not_free_data)
{
return 1;
}
self->width = width;
self->height = height;
Bpp = 4;
switch (self->bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
g_free(self->data);
self->data = (char *)g_malloc(width * height * Bpp, 0);
self->line_size = width * Bpp;
return 0;
}
/*****************************************************************************/
int
xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y)
{
if (self == 0)
{
return 0;
}
if (self->data == 0)
{
return 0;
}
if (x >= 0 && x < self->width && y >= 0 && y < self->height)
{
if (self->bpp == 8)
{
return GETPIXEL8(self->data, x, y, self->width);
}
else if (self->bpp == 15 || self->bpp == 16)
{
return GETPIXEL16(self->data, x, y, self->width);
}
else if (self->bpp >= 24)
{
return GETPIXEL32(self->data, x, y, self->width);
}
}
return 0;
}
/*****************************************************************************/
int
xrdp_bitmap_set_pixel(struct xrdp_bitmap *self, int x, int y, int pixel)
{
if (self == 0)
{
return 0;
}
if (self->data == 0)
{
return 0;
}
if (x >= 0 && x < self->width && y >= 0 && y < self->height)
{
if (self->bpp == 8)
{
SETPIXEL8(self->data, x, y, self->width, pixel);
}
else if (self->bpp == 15 || self->bpp == 16)
{
SETPIXEL16(self->data, x, y, self->width, pixel);
}
else if (self->bpp >= 24)
{
SETPIXEL32(self->data, x, y, self->width, pixel);
}
}
return 0;
}
/*****************************************************************************/
/* copy part of self at x, y to 0, 0 in dest */
/* returns error */
int
xrdp_bitmap_copy_box(struct xrdp_bitmap *self,
struct xrdp_bitmap *dest,
int x, int y, int cx, int cy)
{
int i;
int destx;
int desty;
int incs;
int incd;
tui8 *s8;
tui8 *d8;
tui16 *s16;
tui16 *d16;
tui32 *s32;
tui32 *d32;
if (self == 0)
{
return 1;
}
if (dest == 0)
{
return 1;
}
if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE)
{
return 1;
}
if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE)
{
return 1;
}
if (self->bpp != dest->bpp)
{
return 1;
}
destx = 0;
desty = 0;
if (!check_bounds(self, &x, &y, &cx, &cy))
{
return 1;
}
if (!check_bounds(dest, &destx, &desty, &cx, &cy))
{
return 1;
}
if (self->bpp >= 24)
{
s32 = ((tui32 *)(self->data)) + (self->width * y + x);
d32 = ((tui32 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d32, s32, cx * 4);
s32 += cx;
d32 += cx;
s32 += incs;
d32 += incd;
}
}
else if (self->bpp == 15 || self->bpp == 16)
{
s16 = ((tui16 *)(self->data)) + (self->width * y + x);
d16 = ((tui16 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d16, s16, cx * 2);
s16 += cx;
d16 += cx;
s16 += incs;
d16 += incd;
}
}
else if (self->bpp == 8)
{
s8 = ((tui8 *)(self->data)) + (self->width * y + x);
d8 = ((tui8 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d8, s8, cx);
s8 += cx;
d8 += cx;
s8 += incs;
d8 += incd;
}
}
else
{
return 1;
}
return 0;
}

1099
xrdp/xrdp_bitmap_load.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -643,7 +643,9 @@ xrdp_login_wnd_create(struct xrdp_wm *self)
int log_width;
int log_height;
int regular;
int primary_x_offset;
int primary_width; /* Dimensions of primary screen */
int primary_height;
int primary_x_offset; /* Offset of centre of primary screen */
int primary_y_offset;
int index;
int x;
@ -653,8 +655,10 @@ xrdp_login_wnd_create(struct xrdp_wm *self)
globals = &self->xrdp_config->cfg_globals;
primary_x_offset = self->screen->width / 2;
primary_y_offset = self->screen->height / 2;
primary_width = self->screen->width;
primary_height = self->screen->height;
primary_x_offset = primary_width / 2;
primary_y_offset = primary_height / 2;
log_width = globals->ls_width;
log_height = globals->ls_height;
@ -686,8 +690,10 @@ xrdp_login_wnd_create(struct xrdp_wm *self)
cx = self->client_info->minfo_wm[index].right;
cy = self->client_info->minfo_wm[index].bottom;
primary_x_offset = x + ((cx - x) / 2);
primary_y_offset = y + ((cy - y) / 2);
primary_width = cx - x;
primary_height = cy - y;
primary_x_offset = x + (primary_width / 2);
primary_y_offset = y + (primary_height / 2);
break;
}
}
@ -725,27 +731,62 @@ xrdp_login_wnd_create(struct xrdp_wm *self)
{
/* Load the background image. */
/* If no file is specified no default image will be loaded. */
/* We only load the image if bpp > 8 */
if (globals->ls_background_image[0] != 0 && self->screen->bpp > 8)
/* We only load the image if bpp > 8, and if the user hasn't
* disabled wallpaer in the performance settings */
if (globals->ls_background_image[0] != 0)
{
char fileName[256] ;
but = xrdp_bitmap_create(4, 4, self->screen->bpp, WND_TYPE_IMAGE, self);
if (globals->ls_background_image[0] == '/')
if (self->screen->bpp <= 8)
{
g_snprintf(fileName, 255, "%s", globals->ls_background_image);
LOG(LOG_LEVEL_INFO, "Login background not loaded for bpp=%d",
self->screen->bpp);
}
else if ((self->client_info->rdp5_performanceflags &
RDP5_NO_WALLPAPER) != 0)
{
LOG(LOG_LEVEL_INFO, "Login background not loaded as client "
"has requested PERF_DISABLE_WALLPAPER");
}
else
{
g_snprintf(fileName, 255, "%s/%s",
XRDP_SHARE_PATH, globals->ls_background_image);
char fileName[256] ;
but = xrdp_bitmap_create(4, 4, self->screen->bpp,
WND_TYPE_IMAGE, self);
if (globals->ls_background_image[0] == '/')
{
g_snprintf(fileName, 255, "%s",
globals->ls_background_image);
}
else
{
g_snprintf(fileName, 255, "%s/%s",
XRDP_SHARE_PATH, globals->ls_background_image);
}
LOG(LOG_LEVEL_DEBUG, "We try to load the following background file: %s", fileName);
if (globals->ls_background_transform == XBLT_NONE)
{
xrdp_bitmap_load(but, fileName, self->palette,
globals->ls_top_window_bg_color,
globals->ls_background_transform,
0, 0);
/* Place the background in the bottom right corner */
but->left = primary_x_offset + (primary_width / 2) -
but->width;
but->top = primary_y_offset + (primary_height / 2) -
but->height;
}
else
{
xrdp_bitmap_load(but, fileName, self->palette,
globals->ls_top_window_bg_color,
globals->ls_background_transform,
primary_width, primary_height);
but->left = primary_x_offset - (primary_width / 2);
but->top = primary_y_offset - (primary_height / 2);
}
but->parent = self->screen;
but->owner = self->screen;
list_add_item(self->screen->child_list, (long)but);
}
LOG(LOG_LEVEL_DEBUG, "We try to load the following background file: %s", fileName);
xrdp_bitmap_load(but, fileName, self->palette);
but->parent = self->screen;
but->owner = self->screen;
but->left = self->screen->width - but->width;
but->top = self->screen->height - but->height;
list_add_item(self->screen->child_list, (long)but);
}
/* if logo image not specified, use default */
@ -762,7 +803,11 @@ xrdp_login_wnd_create(struct xrdp_wm *self)
g_snprintf(globals->ls_logo_filename, 255, "%s/ad256.bmp", XRDP_SHARE_PATH);
}
xrdp_bitmap_load(but, globals->ls_logo_filename, self->palette);
xrdp_bitmap_load(but, globals->ls_logo_filename, self->palette,
globals->ls_bg_color,
globals->ls_logo_transform,
globals->ls_logo_width,
globals->ls_logo_height);
but->parent = self->login_window;
but->owner = self->login_window;
but->left = globals->ls_logo_x_pos;
@ -831,6 +876,42 @@ xrdp_login_wnd_create(struct xrdp_wm *self)
return 0;
}
/**
* Map a bitmap transform string to a value
*
* @param param Param we're trying to read
* @param str String we're trying to map
*
* @return enum xrdp_bitmap_load_transform value
*
* A warning is logged if the string is not recognised
*****************************************************************************/
static enum xrdp_bitmap_load_transform
bitmap_transform_str_to_val(const char *param, const char *str)
{
enum xrdp_bitmap_load_transform rv;
if (g_strcmp(str, "none") == 0)
{
rv = XBLT_NONE;
}
else if (g_strcmp(str, "scale") == 0)
{
rv = XBLT_SCALE;
}
else if (g_strcmp(str, "zoom") == 0)
{
rv = XBLT_ZOOM;
}
else
{
LOG(LOG_LEVEL_WARNING, "Param '%s' has unrecognised value '%s'"
" - assuming 'none'", param, str);
rv = XBLT_NONE;
}
return rv;
}
/**
* Load configuration from xrdp.ini file
*
@ -866,6 +947,8 @@ load_xrdp_config(struct xrdp_config *config, const char *xrdp_ini, int bpp)
globals->ls_bg_color = HCOLOR(bpp, xrdp_wm_htoi("dedede"));
globals->ls_width = 350;
globals->ls_height = 350;
globals->ls_background_transform = XBLT_NONE;
globals->ls_logo_transform = XBLT_NONE;
globals->ls_logo_x_pos = 63;
globals->ls_logo_y_pos = 50;
globals->ls_label_x_pos = 30;
@ -1103,16 +1186,39 @@ load_xrdp_config(struct xrdp_config *config, const char *xrdp_ini, int bpp)
globals->ls_title[255] = 0;
}
else if (g_strncmp(n, "ls_logo_filename", 255) == 0)
{
g_strncpy(globals->ls_logo_filename, v, 255);
globals->ls_logo_filename[255] = 0;
}
else if (g_strncmp(n, "ls_background_image", 255) == 0)
{
g_strncpy(globals->ls_background_image, v, 255);
globals->ls_background_image[255] = 0;
}
else if (g_strncmp(n, "ls_background_transform", 255) == 0)
{
globals->ls_background_transform =
bitmap_transform_str_to_val(n, v);
}
else if (g_strncmp(n, "ls_logo_filename", 255) == 0)
{
g_strncpy(globals->ls_logo_filename, v, 255);
globals->ls_logo_filename[255] = 0;
}
else if (g_strncmp(n, "ls_logo_transform", 255) == 0)
{
globals->ls_logo_transform = bitmap_transform_str_to_val(n, v);
}
else if (g_strncmp(n, "ls_logo_width", 64) == 0)
{
globals->ls_logo_width = g_atoi(v);
}
else if (g_strncmp(n, "ls_logo_height", 64) == 0)
{
globals->ls_logo_height = g_atoi(v);
}
else if (g_strncmp(n, "ls_logo_x_pos", 64) == 0)
{
globals->ls_logo_x_pos = g_atoi(v);

View File

@ -168,6 +168,16 @@ struct xrdp_mod
struct source_info *si;
};
/**
* Transform to apply to loaded images
*/
enum xrdp_bitmap_load_transform
{
XBLT_NONE = 0,
XBLT_SCALE,
XBLT_ZOOM
};
/* header for bmp file */
struct xrdp_bmp_header
{
@ -634,8 +644,14 @@ struct xrdp_cfg_globals
int ls_width; /* window width */
int ls_height; /* window height */
int ls_bg_color; /* background color */
char ls_logo_filename[256]; /* logo filename */
char ls_background_image[256]; /* background image file name */
enum xrdp_bitmap_load_transform ls_background_transform;
/* transform to apply to background image */
char ls_logo_filename[256]; /* logo filename */
enum xrdp_bitmap_load_transform ls_logo_transform;
/* transform to apply to logo */
int ls_logo_width; /* logo width (optional) */
int ls_logo_height; /* logo height (optional) */
int ls_logo_x_pos; /* logo x co-ordinate */
int ls_logo_y_pos; /* logo y co-ordinate */
int ls_label_x_pos; /* x pos of labels */