Commit a6ed61b7 authored by Przemo Firszt's avatar Przemo Firszt Committed by Bastien Nocera
Browse files

wacom: Add OLED handling for Intuos4

https://bugzilla.gnome.org/show_bug.cgi?id=671072
parent 5669574c
......@@ -53,6 +53,7 @@ UPOWER_GLIB_REQUIRED_VERSION=0.9.1
PA_REQUIRED_VERSION=2.0
LIBWACOM_REQUIRED_VERSION=0.7
LIBRSVG_REQUIRED_VERSION=2.36.2
PANGO_REQUIRED_VERSION=1.20.0
UPOWER_REQUIRED_VERSION=0.9.11
IBUS_REQUIRED_VERSION=1.4.99
GSETTINGS_DESKTOP_SCHEMAS_REQUIRED_VERSION=3.7.2.1
......@@ -253,8 +254,8 @@ case $host_os in
have_wacom=no
else
if test x$enable_gudev != xno; then
PKG_CHECK_MODULES(WACOM, [libwacom >= $LIBWACOM_REQUIRED_VERSION x11 xi xtst gudev-1.0 gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION xorg-wacom librsvg-2.0 >= $LIBRSVG_REQUIRED_VERSION libnotify >= $LIBNOTIFY_REQUIRED_VERSION
])
PKG_CHECK_MODULES(WACOM, [libwacom >= $LIBWACOM_REQUIRED_VERSION x11 xi xtst gudev-1.0 gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION xorg-wacom librsvg-2.0 >= $LIBRSVG_REQUIRED_VERSION libnotify >= $LIBNOTIFY_REQUIRED_VERSION pango >= $PANGO_REQUIRED_VERSION])
PKG_CHECK_MODULES(WACOM_OLED, [gudev-1.0])
else
AC_MSG_ERROR([GUdev is necessary to compile Wacom support])
fi
......
......@@ -107,5 +107,10 @@
<_summary>Key combinations for a touchring or touchstrip custom action</_summary>
<_description>The keyboard shortcuts generated when a touchring or touchstrip is used for custom actions (up followed by down).</_description>
</key>
<key name="oled-label" type="s">
<default>''</default>
<_summary>Button label for OLED display.</_summary>
<_description>Label will be rendered to OLED display belonging to the button</_description>
</key>
</schema>
</schemalist>
......@@ -8,6 +8,8 @@ libgsdwacom_la_SOURCES = \
gsd-wacom-manager.c \
gsd-wacom-osd-window.h \
gsd-wacom-osd-window.c \
gsd-wacom-oled.h \
gsd-wacom-oled.c \
gsd-wacom-device.c \
gsd-wacom-device.h \
gsd-wacom-resources.c
......@@ -52,18 +54,27 @@ polkit_policy_DATA = $(polkit_policy_in_files:.policy.in=.policy)
# so it always gets included in the tarball
gsd_wacom_led_helper_SOURCES = gsd-wacom-led-helper.c
gsd_wacom_oled_helper_SOURCES = gsd-wacom-oled-helper.c
EXTRA_DIST = $(gsd_wacom_led_helper_SOURCES) wacom.gresource.xml tablet-layout.css
EXTRA_DIST = $(gsd_wacom_led_helper_SOURCES) wacom.gresource.xml tablet-layout.css \
$(gsd_wacom_oled_helper_SOURCES)
if HAVE_GUDEV
libexec_PROGRAMS = gsd-wacom-led-helper
libexec_PROGRAMS = gsd-wacom-led-helper gsd-wacom-oled-helper
gsd_wacom_led_helper_LDFLAGS = \
$(BACKLIGHT_HELPER_LIBS) \
-lm
gsd_wacom_oled_helper_LDFLAGS = \
$(WACOM_OLED_LIBS) \
-lm
gsd_wacom_led_helper_CFLAGS = \
$(BACKLIGHT_HELPER_CFLAGS)
gsd_wacom_oled_helper_CFLAGS = \
$(WACOM_OLED_CFLAGS)
else
libexec_PROGRAMS =
endif
......@@ -78,6 +89,8 @@ gsd_test_wacom_SOURCES = \
gsd-wacom-manager.h \
gsd-wacom-osd-window.h \
gsd-wacom-osd-window.c \
gsd-wacom-oled.h \
gsd-wacom-oled.c \
gsd-wacom-device.c \
gsd-wacom-device.h \
gsd-wacom-resources.c
......
......@@ -258,7 +258,8 @@ gsd_wacom_tablet_button_new (const char *name,
GsdWacomTabletButtonPos pos,
int group_id,
int idx,
int status_led)
int status_led,
int has_oled)
{
GsdWacomTabletButton *ret;
......@@ -277,6 +278,7 @@ gsd_wacom_tablet_button_new (const char *name,
ret->type = type;
ret->pos = pos;
ret->status_led = status_led;
ret->has_oled = has_oled;
return ret;
}
......@@ -1080,7 +1082,8 @@ gsd_wacom_device_add_ring_modes (WacomDevice *wacom_device,
WACOM_TABLET_BUTTON_POS_LEFT,
group,
0,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
0));
} else {
for (i = 1; i <= num_modes; i++) {
name = g_strdup_printf (_("Left Ring Mode #%d"), i);
......@@ -1092,7 +1095,8 @@ gsd_wacom_device_add_ring_modes (WacomDevice *wacom_device,
WACOM_TABLET_BUTTON_POS_LEFT,
group,
i - 1,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
0));
g_free (name);
g_free (id);
}
......@@ -1109,7 +1113,8 @@ gsd_wacom_device_add_ring_modes (WacomDevice *wacom_device,
WACOM_TABLET_BUTTON_POS_RIGHT,
group,
0,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
0));
} else {
for (i = 1; i <= num_modes; i++) {
name = g_strdup_printf (_("Right Ring Mode #%d"), i);
......@@ -1121,7 +1126,8 @@ gsd_wacom_device_add_ring_modes (WacomDevice *wacom_device,
WACOM_TABLET_BUTTON_POS_RIGHT,
group,
i - 1,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
0));
g_free (name);
g_free (id);
}
......@@ -1160,7 +1166,8 @@ gsd_wacom_device_add_strip_modes (WacomDevice *wacom_device,
WACOM_TABLET_BUTTON_POS_LEFT,
group,
0,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
0));
} else {
for (i = 1; i <= num_modes; i++) {
name = g_strdup_printf (_("Left Touchstrip Mode #%d"), i);
......@@ -1172,7 +1179,8 @@ gsd_wacom_device_add_strip_modes (WacomDevice *wacom_device,
WACOM_TABLET_BUTTON_POS_LEFT,
group,
i - 1,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
0));
g_free (name);
g_free (id);
}
......@@ -1189,7 +1197,8 @@ gsd_wacom_device_add_strip_modes (WacomDevice *wacom_device,
WACOM_TABLET_BUTTON_POS_RIGHT,
group,
0,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
0));
} else {
for (i = 1; i <= num_modes; i++) {
name = g_strdup_printf (_("Right Touchstrip Mode #%d"), i);
......@@ -1201,7 +1210,8 @@ gsd_wacom_device_add_strip_modes (WacomDevice *wacom_device,
WACOM_TABLET_BUTTON_POS_RIGHT,
group,
i - 1,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
0));
g_free (name);
g_free (id);
}
......@@ -1259,6 +1269,7 @@ gsd_wacom_device_add_buttons_dir (WacomDevice *wacom_device,
GList *l;
guint num_buttons, i, button_num;
char *name, *id;
gboolean has_oled;
l = NULL;
button_num = 1;
......@@ -1275,6 +1286,8 @@ gsd_wacom_device_add_buttons_dir (WacomDevice *wacom_device,
name = g_strdup_printf (button_str, button_num++);
id = g_strdup_printf ("%s%c", button_str_id, i);
if (libwacom_get_button_flag (wacom_device, i) & WACOM_BUTTON_OLED)
has_oled = TRUE;
l = g_list_append (l, gsd_wacom_tablet_button_new (name,
id,
settings_path,
......@@ -1282,7 +1295,8 @@ gsd_wacom_device_add_buttons_dir (WacomDevice *wacom_device,
gsd_wacom_device_button_pos (flags),
flags_to_group (flags),
-1,
GSD_WACOM_NO_LED));
GSD_WACOM_NO_LED,
has_oled));
g_free (name);
g_free (id);
}
......@@ -1310,7 +1324,8 @@ gsd_wacom_device_add_buttons_dir (WacomDevice *wacom_device,
gsd_wacom_device_button_pos (flags),
flags_to_group (flags),
-1,
status_led));
status_led,
FALSE));
g_free (name);
g_free (id);
}
......
......@@ -123,6 +123,7 @@ typedef struct
GsdWacomTabletButtonPos pos;
int group_id, idx;
int status_led;
int has_oled;
} GsdWacomTabletButton;
void gsd_wacom_tablet_button_free (GsdWacomTabletButton *button);
......
......@@ -49,6 +49,7 @@
#include "gnome-settings-profile.h"
#include "gsd-wacom-manager.h"
#include "gsd-wacom-device.h"
#include "gsd-wacom-oled.h"
#include "gsd-wacom-osd-window.h"
#define GSD_WACOM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_WACOM_MANAGER, GsdWacomManagerPrivate))
......@@ -68,9 +69,10 @@
#define KEY_PRESSURECURVE "pressurecurve"
/* Button settings */
#define KEY_ACTION_TYPE "action-type"
#define KEY_CUSTOM_ACTION "custom-action"
#define KEY_ACTION_TYPE "action-type"
#define KEY_CUSTOM_ACTION "custom-action"
#define KEY_CUSTOM_ELEVATOR_ACTION "custom-elevator-action"
#define OLED_LABEL "oled-label"
/* See "Wacom Pressure Threshold" */
#define DEFAULT_PRESSURE_THRESHOLD 27
......@@ -701,7 +703,7 @@ reset_pad_buttons (GsdWacomDevice *device)
XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev);
/* Reset all the LEDs */
/* Reset all the LEDs and OLEDs*/
buttons = gsd_wacom_device_get_buttons (device);
for (l = buttons; l != NULL; l = l->next) {
GsdWacomTabletButton *button = l->data;
......@@ -709,16 +711,36 @@ reset_pad_buttons (GsdWacomDevice *device)
button->status_led != GSD_WACOM_NO_LED) {
set_led (device, button, 1);
}
}
if (button->has_oled) {
char *label;
label = g_settings_get_string (button->settings, OLED_LABEL);
set_oled (device, button->id, label);
g_free (label);
}
}
g_list_free (buttons);
}
static void
gsettings_oled_changed (GSettings *settings,
gchar *key,
GsdWacomTabletButton *button)
{
GsdWacomDevice *device;
char *label;
label = g_settings_get_string (settings, OLED_LABEL);
device = g_object_get_data (G_OBJECT (button->settings), "parent-device");
set_oled (device, button->id, label);
}
static void
set_wacom_settings (GsdWacomManager *manager,
GsdWacomDevice *device)
{
GsdWacomDeviceType type;
GSettings *settings;
GList *buttons, *l;
g_debug ("Applying settings for device '%s' (type: %s)",
gsd_wacom_device_get_tool_name (device),
......@@ -756,6 +778,18 @@ set_wacom_settings (GsdWacomManager *manager,
id = get_device_id (device);
reset_pad_buttons (device);
grab_button (id, TRUE, manager->priv->screen);
buttons = gsd_wacom_device_get_buttons (device);
for (l = buttons; l != NULL; l = l->next) {
GsdWacomTabletButton *button = l->data;
if (button->has_oled) {
g_signal_connect (G_OBJECT (button->settings), "changed::oled-label",
G_CALLBACK (gsettings_oled_changed), button);
g_object_set_data (G_OBJECT (button->settings), "parent-device", device);
}
}
g_list_free (buttons);
return;
}
......
/*
* Copyright (C) 2012 Przemo Firszt <przemo@firszt.eu>
*
* The code is derived from gsd-wacom-led-helper.c
* written by:
* Copyright (C) 2010-2011 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2012 Bastien Nocera <hadess@hadess.net>
*
* Licensed under the GNU General Public License Version 2
*
* 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.
*/
#include <unistd.h>
#include <stdlib.h>
#include "config.h"
#include <glib.h>
#include <locale.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <gudev/gudev.h>
static gboolean
gsd_wacom_oled_helper_write (const gchar *filename, gchar *buffer, GError **error)
{
guchar *image;
gint retval;
gsize length;
gint fd = -1;
gboolean ret = TRUE;
fd = open (filename, O_WRONLY);
if (fd < 0) {
ret = FALSE;
g_set_error (error, 1, 0, "failed to open filename: %s", filename);
goto out;
}
image = g_base64_decode (buffer, &length);
if (!image)
goto out;
/* write to device file */
retval = write (fd, image, length);
if (retval != length) {
ret = FALSE;
g_set_error (error, 1, 0, "writing to %s failed", filename);
goto out;
}
out:
if (fd >= 0)
close (fd);
g_free (image);
return ret;
}
static char *
get_oled_sysfs_path (GUdevDevice *device,
int button_num)
{
char *status;
char *filename;
status = g_strdup_printf ("button%d_rawimg", button_num);
filename = g_build_filename (g_udev_device_get_sysfs_path (device), "wacom_led", status, NULL);
g_free (status);
return filename;
}
static char *path = NULL;
static char *buffer = "";
static int button_num = -1;
const GOptionEntry options[] = {
{ "path", '\0', 0, G_OPTION_ARG_FILENAME, &path, "Device path for the Wacom device", NULL },
{ "buffer", '\0', 0, G_OPTION_ARG_STRING, &buffer, "Image to set base64 encoded", NULL },
{ "button", '\0', 0, G_OPTION_ARG_INT, &button_num, "Which button icon to set", NULL },
{ NULL}
};
int main (int argc, char **argv)
{
GOptionContext *context;
GUdevClient *client;
GUdevDevice *device, *parent;
int uid, euid;
char *filename;
GError *error = NULL;
const char * const subsystems[] = { "input", NULL };
/* get calling process */
uid = getuid ();
euid = geteuid ();
if (uid != 0 || euid != 0) {
g_print ("This program can only be used by the root user\n");
return 1;
}
context = g_option_context_new (NULL);
g_option_context_set_summary (context, "GNOME Settings Daemon Wacom OLED Icon Helper");
g_option_context_add_main_entries (context, options, NULL);
g_option_context_parse (context, &argc, &argv, NULL);
if (path == NULL ||
button_num < 0) {
char *txt;
txt = g_option_context_get_help (context, FALSE, NULL);
g_print ("%s", txt);
g_free (txt);
g_option_context_free (context);
return 1;
}
g_option_context_free (context);
client = g_udev_client_new (subsystems);
device = g_udev_client_query_by_device_file (client, path);
if (device == NULL) {
g_debug ("Could not find device '%s' in udev database", path);
goto bail;
}
if (g_udev_device_get_property_as_boolean (device, "ID_INPUT_TABLET") == FALSE &&
g_udev_device_get_property_as_boolean (device, "ID_INPUT_TOUCHPAD") == FALSE) {
g_debug ("Device '%s' is not a Wacom tablet", path);
goto bail;
}
if (g_strcmp0 (g_udev_device_get_property (device, "ID_BUS"), "usb") != 0) {
/* FIXME handle Bluetooth OLEDs too */
g_debug ("Non-USB OLEDs setting is not (yet) supported");
goto bail;
}
parent = g_udev_device_get_parent_with_subsystem (device, "usb", "usb_interface");
if (parent == NULL) {
g_debug ("Could not find parent USB device for '%s'", path);
goto bail;
}
g_object_unref (device);
device = parent;
filename = get_oled_sysfs_path (device, button_num);
if (gsd_wacom_oled_helper_write (filename, buffer, &error) == FALSE) {
g_debug ("Could not set OLED icon for '%s': %s", path, error->message);
g_error_free (error);
g_free (filename);
goto bail;
}
g_free (filename);
g_debug ("Successfully set OLED icon for '%s', button %d", path, button_num);
g_object_unref (device);
g_object_unref (client);
return 0;
bail:
if (device != NULL)
g_object_unref (device);
if (client != NULL)
g_object_unref (client);
return 1;
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2013 Przemo Firszt <przemo@firszt.eu>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include <unistd.h>
#include <math.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libwacom/libwacom.h>
#include <gtk/gtk.h>
#include "gsd-wacom-device.h"
#include "gsd-wacom-oled.h"
static void
oled_scramble_icon (guchar* image)
{
unsigned char buf[MAX_IMAGE_SIZE];
int x, y, i;
unsigned char l1, l2, h1, h2;
for (i = 0; i < MAX_IMAGE_SIZE; i++)
buf[i] = image[i];
for (y = 0; y < (OLED_HEIGHT / 2); y++) {
for (x = 0; x < (OLED_WIDTH / 2); x++) {
l1 = (0x0F & (buf[OLED_HEIGHT - 1 - x + OLED_WIDTH * y]));
l2 = (0x0F & (buf[OLED_HEIGHT - 1 - x + OLED_WIDTH * y] >> 4));
h1 = (0xF0 & (buf[OLED_WIDTH - 1 - x + OLED_WIDTH * y] << 4));
h2 = (0xF0 & (buf[OLED_WIDTH - 1 - x + OLED_WIDTH * y]));
image[2 * x + OLED_WIDTH * y] = h1 | l1;
image[2 * x + 1 + OLED_WIDTH * y] = h2 | l2;
}
}
}
static void
oled_surface_to_image (guchar *image,
cairo_surface_t *surface)
{
unsigned char *csurf;
int i, x, y;
unsigned char lo, hi;
cairo_surface_flush (surface);
csurf = cairo_image_surface_get_data (surface);
i = 0;
for (y = 0; y < OLED_HEIGHT; y++) {
for (x = 0; x < (OLED_WIDTH / 2); x++) {
hi = 0xf0 & csurf[4 * OLED_WIDTH * y + 8 * x + 1];
lo = 0x0f & (csurf[4 * OLED_WIDTH * y + 8 * x + 5] >> 4);
image[i] = hi | lo;
i++;
}
}
}
static void
oled_split_text (char *label,
char *line1,
char *line2)
{
char delimiters[5] = "+-_ ";
char **token;
int token_len[MAX_TOKEN];
gsize length;
int i;
if (g_utf8_strlen (label, LABEL_SIZE) <= MAX_1ST_LINE_LEN) {
g_utf8_strncpy (line1, label, MAX_1ST_LINE_LEN);
return;
}
token = g_strsplit_set (label, delimiters, -1);
if (g_utf8_strlen (token[0], LABEL_SIZE) > MAX_1ST_LINE_LEN) {
g_utf8_strncpy (line1, label, MAX_1ST_LINE_LEN);
g_utf8_strncpy (line2, label + MAX_1ST_LINE_LEN, LABEL_SIZE - MAX_1ST_LINE_LEN);
return;
}
for (i = 0; token[i] != NULL; i++)
token_len[i] = g_utf8_strlen (token[i], LABEL_SIZE);
length = token_len[0];
i = 0;
while ((length + token_len[i + 1] + 1) <= MAX_1ST_LINE_LEN) {
i++;
length = length + token_len[i] + 1;
}
g_utf8_strncpy (line1, label, length);
g_utf8_strncpy (line2, label + length + 1, LABEL_SIZE - length);
return;
}
static void
oled_render_text (char *label,
guchar *image)
{
cairo_t *cr;
cairo_surface_t *surface;
PangoFontDescription *desc;
PangoLayout *layout;
int width, height;
double dx, dy;
char line1[LABEL_SIZE + 1] = "";
char line2[LABEL_SIZE + 1] = "";
char *buf;
oled_split_text (label ,line1, line2);
buf = g_strdup_printf ("%s\n%s", line1, line2);