/*
 * Remmina - The GTK+ Remote Desktop Client
 * Copyright (C) 2010-2011 Vic Lee
 * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
 * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU General Public License in all respects
 *  for all of the code used other than OpenSSL. *  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so. *  If you
 *  do not wish to do so, delete this exception statement from your
 *  version. *  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 *
 */

#include "rdp_settings.h"
#include <freerdp/locale/keyboard.h>

static guint keyboard_layout = 0;
static guint rdp_keyboard_layout = 0;
static gchar *rdp_keyboard_remapping_list = NULL;

static void remmina_rdp_settings_kbd_init(void)
{
	TRACE_CALL(__func__);
#if FREERDP_CHECK_VERSION(2, 3, 0)
	rdp_keyboard_remapping_list = g_strdup(
			remmina_plugin_service->pref_get_value("rdp_kbd_remap"));
	REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rdp_keyboard_remapping_list);
	keyboard_layout = freerdp_keyboard_init_ex(rdp_keyboard_layout, rdp_keyboard_remapping_list);
#else
	keyboard_layout = freerdp_keyboard_init(rdp_keyboard_layout);
#endif
}

void remmina_rdp_settings_init(void)
{
	TRACE_CALL(__func__);
	gchar *value;

	value = remmina_plugin_service->pref_get_value("rdp_keyboard_layout");

	if (value && value[0])
		rdp_keyboard_layout = strtoul(value, NULL, 16);

	g_free(value);

	remmina_rdp_settings_kbd_init();
}

guint remmina_rdp_settings_get_keyboard_layout(void)
{
	TRACE_CALL(__func__);
	return keyboard_layout;
}

#define REMMINA_TYPE_PLUGIN_RDPSET_GRID         (remmina_rdp_settings_grid_get_type())
#define REMMINA_RDPSET_GRID(obj)                        (G_TYPE_CHECK_INSTANCE_CAST((obj), REMMINA_TYPE_PLUGIN_RDPSET_GRID, RemminaPluginRdpsetGrid))
#define REMMINA_RDPSET_GRID_CLASS(klass)                (G_TYPE_CHECK_CLASS_CAST((klass), REMMINA_TYPE_PLUGIN_RDPSET_GRID, RemminaPluginRdpsetGridClass))
#define REMMINA_IS_PLUGIN_RDPSET_GRID(obj)              (G_TYPE_CHECK_INSTANCE_TYPE((obj), REMMINA_TYPE_PLUGIN_RDPSET_GRID))
#define REMMINA_IS_PLUGIN_RDPSET_GRID_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE((klass), REMMINA_TYPE_PLUGIN_RDPSET_GRID))
#define REMMINA_RDPSET_GRID_GET_CLASS(obj)              (G_TYPE_INSTANCE_GET_CLASS((obj), REMMINA_TYPE_PLUGIN_RDPSET_GRID, RemminaPluginRdpsetGridClass))

typedef struct _RemminaPluginRdpsetGrid {
	GtkGrid		grid;

	GtkWidget *	keyboard_layout_label;
	GtkWidget *	keyboard_layout_combo;
	GtkListStore *	keyboard_layout_store;

	GtkWidget *	quality_combo;
	GtkListStore *	quality_store;
	GtkWidget *	wallpaper_check;
	GtkWidget *	windowdrag_check;
	GtkWidget *	menuanimation_check;
	GtkWidget *	theme_check;
	GtkWidget *	cursorshadow_check;
	GtkWidget *	cursorblinking_check;
	GtkWidget *	fontsmoothing_check;
	GtkWidget *	composition_check;
	GtkWidget *	use_client_keymap_check;
	GtkWidget *	disable_smooth_scrolling_check;
	GtkWidget *	reconnect_attempts;
	GtkWidget *	kbd_remap;

	/* FreeRDP /scale-desktop: Scaling of desktop app */
	GtkWidget *	desktop_scale_factor_spin;
	/* FreeRDP /scale-device: Scaling of appstore app */
	GtkListStore *	device_scale_factor_store;
	GtkWidget *	device_scale_factor_combo;
	/* FreeRDP /orientation: Orientation of display */
	GtkListStore *	desktop_orientation_store;
	GtkWidget *	desktop_orientation_combo;

	guint		quality_values[10];
} RemminaPluginRdpsetGrid;

typedef struct _RemminaPluginRdpsetGridClass {
	GtkGridClass parent_class;
} RemminaPluginRdpsetGridClass;

GType remmina_rdp_settings_grid_get_type(void) G_GNUC_CONST;

G_DEFINE_TYPE(RemminaPluginRdpsetGrid, remmina_rdp_settings_grid, GTK_TYPE_GRID)

static void remmina_rdp_settings_grid_class_init(RemminaPluginRdpsetGridClass *klass)
{
	TRACE_CALL(__func__);
}

static void remmina_rdp_settings_grid_destroy(GtkWidget *widget, gpointer data)
{
	TRACE_CALL(__func__);
	gchar *s;
	guint new_layout;
	GtkTreeIter iter;
	RemminaPluginRdpsetGrid *grid;
	gint val;

	grid = REMMINA_RDPSET_GRID(widget);

	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(grid->keyboard_layout_combo), &iter)) {
		gtk_tree_model_get(GTK_TREE_MODEL(grid->keyboard_layout_store), &iter, 0, &new_layout, -1);

		if (new_layout != rdp_keyboard_layout) {
			rdp_keyboard_layout = new_layout;
			s = g_strdup_printf("%X", new_layout);
			remmina_plugin_service->pref_set_value("rdp_keyboard_layout", s);
			g_free(s);

			remmina_rdp_settings_kbd_init();
		}
	}

	remmina_plugin_service->pref_set_value("rdp_use_client_keymap",
					       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->use_client_keymap_check)) ? "1" : "0");

	remmina_plugin_service->pref_set_value("rdp_disable_smooth_scrolling",
					       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->disable_smooth_scrolling_check)) ? "1" : "0");

	remmina_plugin_service->pref_set_value("rdp_reconnect_attempts",
					       gtk_entry_get_text(GTK_ENTRY(grid->reconnect_attempts)));

	remmina_plugin_service->pref_set_value("rdp_kbd_remap",
					       gtk_entry_get_text(GTK_ENTRY(grid->kbd_remap)));

	s = g_strdup_printf("%X", grid->quality_values[0]);
	remmina_plugin_service->pref_set_value("rdp_quality_0", s);
	g_free(s);

	s = g_strdup_printf("%X", grid->quality_values[1]);
	remmina_plugin_service->pref_set_value("rdp_quality_1", s);
	g_free(s);

	s = g_strdup_printf("%X", grid->quality_values[2]);
	remmina_plugin_service->pref_set_value("rdp_quality_2", s);
	g_free(s);

	s = g_strdup_printf("%X", grid->quality_values[9]);
	remmina_plugin_service->pref_set_value("rdp_quality_9", s);
	g_free(s);

	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(grid->device_scale_factor_combo), &iter))
		gtk_tree_model_get(GTK_TREE_MODEL(grid->device_scale_factor_store), &iter, 0, &val, -1);
	else
		val = 0;
	s = g_strdup_printf("%d", val);
	remmina_plugin_service->pref_set_value("rdp_deviceScaleFactor", s);
	g_free(s);

	val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(grid->desktop_scale_factor_spin));
	s = g_strdup_printf("%d", val);
	remmina_plugin_service->pref_set_value("rdp_desktopScaleFactor", s);
	g_free(s);

	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(grid->desktop_orientation_combo), &iter))
		gtk_tree_model_get(GTK_TREE_MODEL(grid->desktop_orientation_store), &iter, 0, &val, -1);
	else
		val = 0;
	s = g_strdup_printf("%d", val);
	remmina_plugin_service->pref_set_value("rdp_desktopOrientation", s);
	g_free(s);
}

static void remmina_rdp_settings_grid_load_layout(RemminaPluginRdpsetGrid *grid)
{
	TRACE_CALL(__func__);
	gint i;
	gchar *s;
	GtkTreeIter iter;
	RDP_KEYBOARD_LAYOUT *layouts;

	gtk_list_store_append(grid->keyboard_layout_store, &iter);
	gtk_list_store_set(grid->keyboard_layout_store, &iter, 0, 0, 1, _("<Auto-detect>"), -1);

	if (rdp_keyboard_layout == 0)
		gtk_combo_box_set_active(GTK_COMBO_BOX(grid->keyboard_layout_combo), 0);

	gtk_label_set_text(GTK_LABEL(grid->keyboard_layout_label), "-");

	layouts = freerdp_keyboard_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD | RDP_KEYBOARD_LAYOUT_TYPE_VARIANT);

	for (i = 0; layouts[i].code; i++) {
		s = g_strdup_printf("%08X - %s", layouts[i].code, layouts[i].name);
		gtk_list_store_append(grid->keyboard_layout_store, &iter);
		gtk_list_store_set(grid->keyboard_layout_store, &iter, 0, layouts[i].code, 1, s, -1);

		if (rdp_keyboard_layout == layouts[i].code)
			gtk_combo_box_set_active(GTK_COMBO_BOX(grid->keyboard_layout_combo), i + 1);

		if (keyboard_layout == layouts[i].code)
			gtk_label_set_text(GTK_LABEL(grid->keyboard_layout_label), s);

		g_free(s);
	}

	freerdp_keyboard_layouts_free(layouts);
}

static void remmina_rdp_settings_grid_load_devicescalefactor_combo(RemminaPluginRdpsetGrid *grid)
{
	TRACE_CALL(__func__);
	GtkTreeIter iter;

	gtk_list_store_append(grid->device_scale_factor_store, &iter);
	gtk_list_store_set(grid->device_scale_factor_store, &iter, 0, 0, 1, _("<Not set>"), -1);
	gtk_list_store_append(grid->device_scale_factor_store, &iter);
	gtk_list_store_set(grid->device_scale_factor_store, &iter, 0, 100, 1, "100%", -1);
	gtk_list_store_append(grid->device_scale_factor_store, &iter);
	gtk_list_store_set(grid->device_scale_factor_store, &iter, 0, 140, 1, "140%", -1);
	gtk_list_store_append(grid->device_scale_factor_store, &iter);
	gtk_list_store_set(grid->device_scale_factor_store, &iter, 0, 180, 1, "180%", -1);
}

static void remmina_rdp_settings_grid_load_desktoporientation_combo(RemminaPluginRdpsetGrid *grid)
{
	TRACE_CALL(__func__);
	GtkTreeIter iter;

	gtk_list_store_append(grid->desktop_orientation_store, &iter);
	gtk_list_store_set(grid->desktop_orientation_store, &iter, 0, 0, 1, "0°", -1);
	gtk_list_store_append(grid->desktop_orientation_store, &iter);
	gtk_list_store_set(grid->desktop_orientation_store, &iter, 0, 90, 1, "90°", -1);
	gtk_list_store_append(grid->desktop_orientation_store, &iter);
	gtk_list_store_set(grid->desktop_orientation_store, &iter, 0, 180, 1, "180°", -1);
	gtk_list_store_append(grid->desktop_orientation_store, &iter);
	gtk_list_store_set(grid->desktop_orientation_store, &iter, 0, 270, 1, "270°", -1);
}

static void remmina_rdp_settings_grid_load_quality(RemminaPluginRdpsetGrid *grid)
{
	TRACE_CALL(__func__);
	gchar *value;
	GtkTreeIter iter;

	gtk_list_store_append(grid->quality_store, &iter);
	gtk_list_store_set(grid->quality_store, &iter, 0, -1, 1, _("<Choose a quality level to edit…>"), -1);
	gtk_list_store_append(grid->quality_store, &iter);
	gtk_list_store_set(grid->quality_store, &iter, 0, 0, 1, _("Poor (fastest)"), -1);
	gtk_list_store_append(grid->quality_store, &iter);
	gtk_list_store_set(grid->quality_store, &iter, 0, 1, 1, _("Medium"), -1);
	gtk_list_store_append(grid->quality_store, &iter);
	gtk_list_store_set(grid->quality_store, &iter, 0, 2, 1, _("Good"), -1);
	gtk_list_store_append(grid->quality_store, &iter);
	gtk_list_store_set(grid->quality_store, &iter, 0, 9, 1, _("Best (slowest)"), -1);

	memset(grid->quality_values, 0, sizeof(grid->quality_values));

	value = remmina_plugin_service->pref_get_value("rdp_quality_0");
	grid->quality_values[0] = (value && value[0] ? strtoul(value, NULL, 16) : DEFAULT_QUALITY_0);
	g_free(value);

	value = remmina_plugin_service->pref_get_value("rdp_quality_1");
	grid->quality_values[1] = (value && value[0] ? strtoul(value, NULL, 16) : DEFAULT_QUALITY_1);
	g_free(value);

	value = remmina_plugin_service->pref_get_value("rdp_quality_2");
	grid->quality_values[2] = (value && value[0] ? strtoul(value, NULL, 16) : DEFAULT_QUALITY_2);
	g_free(value);

	value = remmina_plugin_service->pref_get_value("rdp_quality_9");
	grid->quality_values[9] = (value && value[0] ? strtoul(value, NULL, 16) : DEFAULT_QUALITY_9);
	g_free(value);
}

static void remmina_rdp_settings_appscale_on_changed(GtkComboBox *widget, RemminaPluginRdpsetGrid *grid)
{
	TRACE_CALL(__func__);
	GtkTreeIter iter;
	guint i = 0;

	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(grid->device_scale_factor_combo), &iter))
		gtk_tree_model_get(GTK_TREE_MODEL(grid->device_scale_factor_store), &iter, 0, &i, -1);
	if (i == 0) {
		gtk_widget_set_sensitive(GTK_WIDGET(grid->desktop_scale_factor_spin), FALSE);
		gtk_spin_button_set_range(GTK_SPIN_BUTTON(grid->desktop_scale_factor_spin), 0, 0);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(grid->desktop_scale_factor_spin), 0);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(grid->desktop_scale_factor_spin), TRUE);
		gtk_spin_button_set_range(GTK_SPIN_BUTTON(grid->desktop_scale_factor_spin), 100, 500);
		// gtk_spin_button_set_value(GTK_SPIN_BUTTON(grid->desktop_scale_factor_spin), i);
	}
}

static void remmina_rdp_settings_quality_on_changed(GtkComboBox *widget, RemminaPluginRdpsetGrid *grid)
{
	TRACE_CALL(__func__);
	guint v;
	guint i = 0;
	GtkTreeIter iter;
	gboolean sensitive;

	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(grid->quality_combo), &iter)) {
		gtk_tree_model_get(GTK_TREE_MODEL(grid->quality_store), &iter, 0, &i, -1);
		sensitive = (i != -1);

		if (sensitive)
			v = grid->quality_values[i];
		else
			v = 0x3f;       /* All checkboxes disabled */

		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grid->wallpaper_check), (v & 1) == 0);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grid->windowdrag_check), (v & 2) == 0);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grid->menuanimation_check), (v & 4) == 0);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grid->theme_check), (v & 8) == 0);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grid->cursorshadow_check), (v & 0x20) == 0);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grid->cursorblinking_check), (v & 0x40) == 0);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grid->fontsmoothing_check), (v & 0x80) != 0);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grid->composition_check), (v & 0x100) != 0);


		gtk_widget_set_sensitive(GTK_WIDGET(grid->wallpaper_check), sensitive);
		gtk_widget_set_sensitive(GTK_WIDGET(grid->windowdrag_check), sensitive);
		gtk_widget_set_sensitive(GTK_WIDGET(grid->menuanimation_check), sensitive);
		gtk_widget_set_sensitive(GTK_WIDGET(grid->theme_check), sensitive);
		gtk_widget_set_sensitive(GTK_WIDGET(grid->cursorshadow_check), sensitive);
		gtk_widget_set_sensitive(GTK_WIDGET(grid->cursorblinking_check), sensitive);
		gtk_widget_set_sensitive(GTK_WIDGET(grid->fontsmoothing_check), sensitive);
		gtk_widget_set_sensitive(GTK_WIDGET(grid->composition_check), sensitive);
	}
}

static void remmina_rdp_settings_quality_option_on_toggled(GtkToggleButton *togglebutton, RemminaPluginRdpsetGrid *grid)
{
	TRACE_CALL(__func__);
	guint v;
	guint i = 0;
	GtkTreeIter iter;

	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(grid->quality_combo), &iter)) {
		gtk_tree_model_get(GTK_TREE_MODEL(grid->quality_store), &iter, 0, &i, -1);
		if (i != -1) {
			v = 0;
			v |= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->wallpaper_check)) ? 0 : 1);
			v |= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->windowdrag_check)) ? 0 : 2);
			v |= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->menuanimation_check)) ? 0 : 4);
			v |= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->theme_check)) ? 0 : 8);
			v |= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->cursorshadow_check)) ? 0 : 0x20);
			v |= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->cursorblinking_check)) ? 0 : 0x40);
			v |= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->fontsmoothing_check)) ? 0x80 : 0);
			v |= (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grid->composition_check)) ? 0x100 : 0);
			grid->quality_values[i] = v;
		}
	}
}

static void remmina_rdp_settings_set_combo_active_item(GtkComboBox *combo, int itemval)
{
	GtkTreeIter iter;
	int i;
	GtkTreeModel *m;
	gboolean valid;

	m = gtk_combo_box_get_model(combo);
	if (!m)
		return;

	valid = gtk_tree_model_get_iter_first(m, &iter);
	while (valid) {
		gtk_tree_model_get(m, &iter, 0, &i, -1);
		if (i == itemval)
			gtk_combo_box_set_active_iter(combo, &iter);
		valid = gtk_tree_model_iter_next(m, &iter);
	}
}

static void remmina_rdp_settings_grid_init(RemminaPluginRdpsetGrid *grid)
{
	TRACE_CALL(__func__);
	gchar *s;
	GtkWidget *widget;
	GtkCellRenderer *renderer;
	int desktopOrientation, desktopScaleFactor, deviceScaleFactor;

	/* Create the grid */
	g_signal_connect(G_OBJECT(grid), "destroy", G_CALLBACK(remmina_rdp_settings_grid_destroy), NULL);
	gtk_grid_set_row_homogeneous(GTK_GRID(grid), FALSE);
	gtk_grid_set_column_homogeneous(GTK_GRID(grid), FALSE);
	gtk_container_set_border_width(GTK_CONTAINER(grid), 8);
	gtk_grid_set_row_spacing(GTK_GRID(grid), 4);
	gtk_grid_set_column_spacing(GTK_GRID(grid), 4);

	/* Create the content */
	widget = gtk_label_new(_("Keyboard layout"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_end(GTK_WIDGET(widget), 6);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 18);
	gtk_widget_set_margin_top(GTK_WIDGET(widget), 18);
	gtk_grid_attach(GTK_GRID(grid), widget, 0, 0, 1, 1);

	grid->keyboard_layout_store = gtk_list_store_new(2, G_TYPE_UINT, G_TYPE_STRING);
	widget = gtk_combo_box_new_with_model(GTK_TREE_MODEL(grid->keyboard_layout_store));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 0, 2, 1);

	renderer = gtk_cell_renderer_text_new();
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 1);
	grid->keyboard_layout_combo = widget;

	widget = gtk_label_new("-");
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 1, 2, 1);
	grid->keyboard_layout_label = widget;

	remmina_rdp_settings_grid_load_layout(grid);

	widget = gtk_check_button_new_with_label(_("Use client keyboard mapping"));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 2, 1, 1);
	grid->use_client_keymap_check = widget;

	s = remmina_plugin_service->pref_get_value("rdp_use_client_keymap");
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
				     s && s[0] == '1' ? TRUE : FALSE);
	g_free(s);

	widget = gtk_label_new(_("Keyboard scancode remapping"));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 3, 1, 1);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	widget = gtk_entry_new();
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_END);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_grid_attach(GTK_GRID(grid), widget, 2, 3, 1, 1);
	gtk_entry_set_width_chars(GTK_ENTRY(widget), 32);
#if FREERDP_CHECK_VERSION(2, 3, 0)
	/* This is the default, but we set it to make things crystal clear */
	gtk_widget_set_sensitive (widget, TRUE);
	gtk_widget_set_tooltip_text(widget, _("List of key=value,… pairs to remap scancodes. E.g. 0x56=0x29,0x29=0x56"));
#else
	gtk_widget_set_sensitive (widget, FALSE);
	gtk_widget_set_tooltip_text(widget, _("FreeRDP > 2.3.0 is required to map scancodes"));
#endif
	s = remmina_plugin_service->pref_get_value("rdp_kbd_remap");
	if (s && s[0])
		gtk_entry_set_text(GTK_ENTRY(widget), s);
	g_free(s);
	grid->kbd_remap = widget;

	widget = gtk_label_new(_("Quality settings"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_end(GTK_WIDGET(widget), 6);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 18);
	gtk_grid_attach(GTK_GRID(grid), widget, 0, 4, 1, 1);

	grid->quality_store = gtk_list_store_new(2, G_TYPE_UINT, G_TYPE_STRING);
	widget = gtk_combo_box_new_with_model(GTK_TREE_MODEL(grid->quality_store));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 4, 2, 1);

	renderer = gtk_cell_renderer_text_new();
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 1);
	g_signal_connect(G_OBJECT(widget), "changed",
			 G_CALLBACK(remmina_rdp_settings_quality_on_changed), grid);
	grid->quality_combo = widget;

	remmina_rdp_settings_grid_load_quality(grid);

	widget = gtk_check_button_new_with_label(_("Wallpaper"));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 5, 1, 1);
	g_signal_connect(G_OBJECT(widget), "toggled",
			 G_CALLBACK(remmina_rdp_settings_quality_option_on_toggled), grid);
	grid->wallpaper_check = widget;

	widget = gtk_check_button_new_with_label(_("Window drag"));
	gtk_widget_show(widget);
	gtk_grid_attach(GTK_GRID(grid), widget, 2, 5, 1, 1);
	g_signal_connect(G_OBJECT(widget), "toggled",
			 G_CALLBACK(remmina_rdp_settings_quality_option_on_toggled), grid);
	grid->windowdrag_check = widget;

	widget = gtk_check_button_new_with_label(_("Menu animation"));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 6, 1, 1);
	g_signal_connect(G_OBJECT(widget), "toggled",
			 G_CALLBACK(remmina_rdp_settings_quality_option_on_toggled), grid);
	grid->menuanimation_check = widget;

	widget = gtk_check_button_new_with_label(_("Theme"));
	gtk_widget_show(widget);
	gtk_grid_attach(GTK_GRID(grid), widget, 2, 6, 1, 1);
	g_signal_connect(G_OBJECT(widget), "toggled",
			 G_CALLBACK(remmina_rdp_settings_quality_option_on_toggled), grid);
	grid->theme_check = widget;

	widget = gtk_check_button_new_with_label(_("Cursor shadow"));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 7, 1, 1);
	g_signal_connect(G_OBJECT(widget), "toggled",
			 G_CALLBACK(remmina_rdp_settings_quality_option_on_toggled), grid);
	grid->cursorshadow_check = widget;

	widget = gtk_check_button_new_with_label(_("Cursor blinking"));
	gtk_widget_show(widget);
	gtk_grid_attach(GTK_GRID(grid), widget, 2, 7, 1, 1);
	g_signal_connect(G_OBJECT(widget), "toggled",
			 G_CALLBACK(remmina_rdp_settings_quality_option_on_toggled), grid);
	grid->cursorblinking_check = widget;

	widget = gtk_check_button_new_with_label(_("Font smoothing"));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 8, 1, 1);
	g_signal_connect(G_OBJECT(widget), "toggled",
			 G_CALLBACK(remmina_rdp_settings_quality_option_on_toggled), grid);
	grid->fontsmoothing_check = widget;

	widget = gtk_check_button_new_with_label(_("Composition"));
	gtk_widget_show(widget);
	gtk_grid_attach(GTK_GRID(grid), widget, 2, 8, 1, 1);
	g_signal_connect(G_OBJECT(widget), "toggled",
			 G_CALLBACK(remmina_rdp_settings_quality_option_on_toggled), grid);
	grid->composition_check = widget;

	gtk_combo_box_set_active(GTK_COMBO_BOX(grid->quality_combo), 0);


	widget = gtk_label_new(_("Remote scale factor"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_end(GTK_WIDGET(widget), 6);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 18);
	gtk_grid_attach(GTK_GRID(grid), widget, 0, 9, 1, 1);

	grid->device_scale_factor_store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
	grid->desktop_orientation_store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);

	remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
	remmina_rdp_settings_grid_load_devicescalefactor_combo(grid);
	remmina_rdp_settings_grid_load_desktoporientation_combo(grid);

	widget = gtk_label_new(_("Desktop scale factor %"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 9, 1, 1);

	widget = gtk_spin_button_new_with_range(0, 10000, 1);
	gtk_widget_show(widget);
	gtk_grid_attach(GTK_GRID(grid), widget, 2, 9, 1, 1);
	grid->desktop_scale_factor_spin = widget;

	widget = gtk_label_new(_("Device scale factor %"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 10, 1, 1);

	widget = gtk_combo_box_new_with_model(GTK_TREE_MODEL(grid->device_scale_factor_store));
	gtk_widget_show(widget);
	gtk_grid_attach(GTK_GRID(grid), widget, 2, 10, 1, 1);

	renderer = gtk_cell_renderer_text_new();
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 1);
	grid->device_scale_factor_combo = widget;

	remmina_rdp_settings_set_combo_active_item(GTK_COMBO_BOX(grid->device_scale_factor_combo), deviceScaleFactor);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(grid->desktop_scale_factor_spin), (gdouble)desktopScaleFactor);

	g_signal_connect(G_OBJECT(widget), "changed",
			 G_CALLBACK(remmina_rdp_settings_appscale_on_changed), grid);
	remmina_rdp_settings_appscale_on_changed(GTK_COMBO_BOX(grid->device_scale_factor_combo), grid);

	widget = gtk_label_new(_("Desktop orientation"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_end(GTK_WIDGET(widget), 6);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 18);
	gtk_grid_attach(GTK_GRID(grid), widget, 0, 11, 1, 1);

	widget = gtk_combo_box_new_with_model(GTK_TREE_MODEL(grid->desktop_orientation_store));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 11, 2, 1);

	renderer = gtk_cell_renderer_text_new();
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 1);
	grid->desktop_orientation_combo = widget;

	remmina_rdp_settings_set_combo_active_item(GTK_COMBO_BOX(grid->desktop_orientation_combo), desktopOrientation);

	widget = gtk_label_new(_("Input device settings"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_end(GTK_WIDGET(widget), 6);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 18);
	gtk_grid_attach(GTK_GRID(grid), widget, 0, 12, 1, 1);

	widget = gtk_check_button_new_with_label(_("Disable smooth scrolling"));
	gtk_widget_show(widget);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 12, 2, 1);
	grid->disable_smooth_scrolling_check = widget;

	s = remmina_plugin_service->pref_get_value("rdp_disable_smooth_scrolling");
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
				     s && s[0] == '1' ? TRUE : FALSE);
	g_free(s);

	widget = gtk_label_new(_("General settings"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_end(GTK_WIDGET(widget), 6);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 18);
	gtk_grid_attach(GTK_GRID(grid), widget, 0, 13, 1, 1);
	widget = gtk_label_new(_("Reconnect attempts number"));
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_START);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_widget_set_margin_start(GTK_WIDGET(widget), 6);
	gtk_grid_attach(GTK_GRID(grid), widget, 1, 13, 1, 1);
	widget = gtk_entry_new();
	gtk_widget_show(widget);
	gtk_widget_set_halign(GTK_WIDGET(widget), GTK_ALIGN_END);
	gtk_widget_set_valign(GTK_WIDGET(widget), GTK_ALIGN_CENTER);
	gtk_grid_attach(GTK_GRID(grid), widget, 2, 13, 1, 1);
	gtk_entry_set_input_purpose(GTK_ENTRY(widget), GTK_INPUT_PURPOSE_NUMBER);
	gtk_entry_set_input_hints(GTK_ENTRY(widget), GTK_INPUT_HINT_NONE);
	gtk_widget_set_tooltip_text(widget, _("The maximum number of reconnect attempts upon an RDP disconnect (default: 20)"));
	s = remmina_plugin_service->pref_get_value("rdp_reconnect_attempts");
	if (s && s[0])
		gtk_entry_set_text(GTK_ENTRY(widget), s);
	g_free(s);
	grid->reconnect_attempts = widget;

}

GtkWidget *remmina_rdp_settings_new(RemminaPrefPlugin* plugin)
{
	TRACE_CALL(__func__);
	GtkWidget *widget;

	widget = GTK_WIDGET(g_object_new(REMMINA_TYPE_PLUGIN_RDPSET_GRID, NULL));
	gtk_widget_show(widget);

	return widget;
}

void remmina_rdp_settings_get_orientation_scale_prefs(int *desktopOrientation, int *desktopScaleFactor, int *deviceScaleFactor)
{
	TRACE_CALL(__func__);

	/* See https://msdn.microsoft.com/en-us/library/cc240510.aspx */

	int orientation, dpsf, desf;
	gchar *s;

	*desktopOrientation = *desktopScaleFactor = *deviceScaleFactor = 0;

	s = remmina_plugin_service->pref_get_value("rdp_desktopOrientation");
	orientation = s ? atoi(s) : 0;
	g_free(s);
	if (orientation != 90 && orientation != 180 && orientation != 270)
		orientation = 0;
	*desktopOrientation = orientation;

	s = remmina_plugin_service->pref_get_value("rdp_desktopScaleFactor");
	dpsf = s ? atoi(s) : 0;
	g_free(s);
	if (dpsf < 100 || dpsf > 500)
		return;

	s = remmina_plugin_service->pref_get_value("rdp_deviceScaleFactor");
	desf = s ? atoi(s) : 0;
	g_free(s);
	if (desf != 100 && desf != 140 && desf != 180)
		return;

	*desktopScaleFactor = dpsf;
	*deviceScaleFactor = desf;
}
