summaryrefslogtreecommitdiff
path: root/rcm-client-receive.c
diff options
context:
space:
mode:
Diffstat (limited to 'rcm-client-receive.c')
-rw-r--r--rcm-client-receive.c612
1 files changed, 612 insertions, 0 deletions
diff --git a/rcm-client-receive.c b/rcm-client-receive.c
new file mode 100644
index 0000000..8abc64a
--- /dev/null
+++ b/rcm-client-receive.c
@@ -0,0 +1,612 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <math.h>
+#include <inttypes.h>
+#include <gtk/gtk.h>
+
+#include "generated.h"
+#include "rcm-client-main.h"
+#include "rcm-client-receive.h"
+
+#define WINDOW_WIDTH 300
+#define WINDOW_HEIGHT 300
+
+struct remote {
+ GList *buttons;
+ guint width;
+ guint height;
+ struct rcbutton *hover;
+};
+
+struct rcbutton {
+ char *name;
+ bool clicked;
+ guint x;
+ guint y;
+ guint row;
+ guint col;
+ guint rows;
+ guint cols;
+ guint width;
+ guint height;
+ guint padding;
+ guint corner_radius;
+ struct rcbutton *next;
+ GdkRGBA *color;
+ void (*on_hover)(struct rcbutton *rcb, GtkWidget *widget, bool hover);
+};
+
+static struct remote *remote = NULL;
+
+static void
+curve_rectangle(cairo_t * cr, gdouble x0, gdouble y0,
+ gdouble width, gdouble height, gdouble radius)
+{
+ gdouble x1, y1;
+
+ if (!width || !height)
+ return;
+
+ x1 = x0 + width;
+ y1 = y0 + height;
+
+ radius = MIN (radius, MIN (width / 2, height / 2));
+
+ cairo_move_to (cr, x0, y0 + radius);
+ cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI,
+ 3 * M_PI / 2);
+ cairo_line_to (cr, x1 - radius, y0);
+ cairo_arc (cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2,
+ 2 * M_PI);
+ cairo_line_to (cr, x1, y1 - radius);
+ cairo_arc (cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
+ cairo_line_to (cr, x0 + radius, y1);
+ cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
+
+ cairo_close_path (cr);
+}
+
+GdkRGBA *c;
+GdkRGBA *cd;
+GdkRGBA *cre;
+GdkRGBA *cb;
+GdkRGBA cgreen;
+GdkRGBA cred;
+
+static void
+draw_curve_rectangle(cairo_t * cr, struct rcbutton *rcb)
+{
+ double tx, ty;
+ cairo_text_extents_t extents;
+ const char *label = rcb->name ? rcb->name : "?";
+
+ curve_rectangle(cr, rcb->x, rcb->y,
+ rcb->width, rcb->height, rcb->corner_radius);
+
+ if (rcb->color)
+ gdk_cairo_set_source_rgba(cr, rcb->color);
+ else
+ gdk_cairo_set_source_rgba(cr, rcb->clicked ? cre : cd);
+ cairo_fill_preserve(cr);
+
+ gdk_cairo_set_source_rgba(cr, cb);
+ cairo_set_line_width(cr, 1.0);
+ cairo_stroke(cr);
+ /*
+ if (filled)
+ cairo_fill(cr);
+ else {
+ cairo_set_line_width(cr, 1.0);
+ cairo_stroke(cr);
+ }
+ */
+
+ cairo_save(cr);
+ cairo_rectangle(cr,
+ rcb->x + rcb->padding,
+ rcb->y + rcb->padding,
+ rcb->width - rcb->padding * 2,
+ rcb->height - rcb->padding * 2);
+ cairo_clip(cr);
+ cairo_set_font_size(cr, 13);
+ cairo_text_extents (cr, label, &extents);
+ tx = rcb->x + (rcb->width / 2) - (extents.width / 2 + extents.x_bearing);
+ ty = rcb->y + (rcb->height / 2) - (extents.height / 2 + extents.y_bearing);
+ cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
+ cairo_move_to(cr, tx, ty);
+ cairo_show_text(cr, label);
+ cairo_restore(cr);
+ cairo_new_sub_path(cr);
+}
+
+#define SPACING 5
+#define PADDING 5
+#define BW 56
+#define BH 56
+
+static gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+ struct rcbutton *rcb;
+ guint w = 0, h = 0;
+
+ /* Set color for background */
+ gdk_cairo_set_source_rgba(cr, c);
+
+ /* fill in the background color*/
+ cairo_paint(cr);
+
+ GList *l;
+
+ for (l = remote->buttons; l; l = l->next) {
+ rcb = l->data;
+
+ draw_curve_rectangle(cr, rcb);
+
+ if (rcb->x + rcb->width > w)
+ w = rcb->x + rcb->width;
+
+ if (rcb->y + rcb->height > h)
+ h = rcb->y + rcb->height;
+ }
+
+ w += (SPACING + BW) / 2;
+ h += (SPACING + BH) / 2;
+
+ /*->name ? rcb->name : "?", false,
+ rcb->clicked ? cre : cd,
+ rcb->x, rcb->y, rcb->width, rcb->height,
+ rcb->padding, rcb->corner_radius);
+*/
+ gtk_widget_set_size_request(widget, w, h);
+ gtk_widget_set_halign(widget, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign(widget, GTK_ALIGN_CENTER);
+ gtk_widget_set_margin_top(widget, BH / 2);
+ gtk_widget_set_margin_bottom(widget, BH / 2);
+ gtk_widget_set_margin_start(widget, BW / 2);
+ gtk_widget_set_margin_end(widget, BW / 2);
+
+
+ return FALSE;
+}
+
+#if 0
+static struct rcbutton *new_button(const char *name, guint row, guint col)
+{
+ struct rcbutton *rcb;
+
+ rcb = g_malloc(sizeof(*rcb));
+ rcb->name = strdup(name);
+ rcb->clicked = false;
+ rcb->x = (SPACING + BW) * (col) + (SPACING + BW) / 2;
+ rcb->y = (SPACING + BH) * (row) + (SPACING + BH) / 2;
+ rcb->width = BW;
+ rcb->height = BH;
+ rcb->padding = PADDING;
+ rcb->corner_radius = 3;
+ rcb->color = NULL;
+ return rcb;
+}
+#endif
+
+static void
+button_calculate_position(struct rcbutton *rcb)
+{
+ rcb->x = (SPACING + BW) * (rcb->col) + (SPACING + BW) / 2;
+ rcb->y = (SPACING + BH) * (rcb->row) + (SPACING + BH) / 2;
+ rcb->width = BW + (rcb->cols - 1) * (BW + SPACING);
+ rcb->height = BH + (rcb->rows - 1) * (BH + SPACING);
+}
+
+static void
+move_buttons(gint row, gint col)
+{
+ GList *l;
+
+ for (l = remote->buttons; l; l = l->next) {
+ struct rcbutton *rcb = l->data;
+
+ rcb->row += row;
+ rcb->col += col;
+ button_calculate_position(rcb);
+ }
+}
+
+static struct rcbutton *
+new_button_add(const char *name, GdkRGBA *color,
+ guint x, guint y, guint w, guint h)
+{
+ struct rcbutton *rcb;
+
+ rcb = g_malloc0(sizeof(*rcb));
+ rcb->name = strdup(name);
+ rcb->clicked = false;
+ rcb->col = x;
+ rcb->row = y;
+ rcb->cols = w;
+ rcb->rows = h;
+ button_calculate_position(rcb);
+ rcb->padding = PADDING;
+ rcb->corner_radius = 3;
+ rcb->color = color;
+ remote->buttons = g_list_append(remote->buttons, rcb);
+ remote->width = MAX(remote->width, w);
+ remote->height = MAX(remote->height, h);
+ return rcb;
+}
+
+#if 0
+static struct rcbutton *new_button_addr(const char *name, guint row, guint col)
+{
+ struct rcbutton *rcb;
+
+ rcb = g_malloc(sizeof(*rcb));
+ rcb->name = strdup(name);
+ rcb->clicked = false;
+ rcb->x = (SPACING + BW) / 2;
+ rcb->y = (SPACING + BH) / 2;
+ rcb->width = (SPACING + BW) * (col) - SPACING;
+ rcb->height = BH;
+ rcb->padding = PADDING;
+ rcb->corner_radius = 3;
+ rcb->color = &cred;
+ return rcb;
+}
+#endif
+static void
+button_redraw(struct rcbutton *rcb, GtkWidget *widget)
+{
+ printf("Asked to redraw: X,Y,W,H - %u,%u,%u,%u\n",
+ rcb->x - 1, rcb->y - 1, rcb->width + 2, rcb->height + 2);
+ gtk_widget_queue_draw_area(widget, rcb->x - 1, rcb->y - 1,
+ rcb->width + 2, rcb->height + 2);
+}
+
+static gboolean
+button_press_event_cb(GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ struct rcbutton *rcb;
+ GList *l;
+ char buf[1024];
+
+ if (event->button != GDK_BUTTON_PRIMARY)
+ return true;
+
+ for (l = remote->buttons; l; l = l->next) {
+ rcb = l->data;
+
+ if (event->x < rcb->x || event->x > (rcb->x + rcb->width))
+ continue;
+
+ if (event->y < rcb->y || event->y > (rcb->y + rcb->height))
+ continue;
+
+ rcb->clicked = true;
+ button_redraw(rcb, widget);
+ sprintf(buf, "Button at %ux%u clicked\n", rcb->x, rcb->y);
+ poke_objects();
+ poke_objects2();
+ }
+
+ return true;
+}
+
+static gboolean
+button_release_event_cb(GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ struct rcbutton *rcb;
+ GList *l;
+
+ if (event->button != GDK_BUTTON_PRIMARY)
+ return true;
+
+ for (l = remote->buttons; l; l = l->next) {
+ rcb = l->data;
+
+ if (!rcb->clicked)
+ continue;
+
+ rcb->clicked = false;
+
+ button_redraw(rcb, widget);
+ }
+
+ return true;
+}
+
+static gboolean
+motion_notify_event_cb (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer data)
+{
+ struct rcbutton *rcb;
+ static GdkCursor *cursor = NULL;
+ GdkWindow* win = gtk_widget_get_parent_window(widget);
+ GList *l;
+
+ if (!cursor)
+ cursor = gdk_cursor_new_for_display(gdk_window_get_display(win), GDK_HAND1);
+
+ for (l = remote->buttons; l; l = l->next) {
+ rcb = l->data;
+
+ if (event->x < rcb->x || event->x > (rcb->x + rcb->width))
+ continue;
+
+ if (event->y < rcb->y || event->y > (rcb->y + rcb->height))
+ continue;
+
+ break;
+ }
+
+ if (!l)
+ rcb = NULL;
+
+ if (remote->hover == rcb)
+ return true;
+
+ gdk_window_set_cursor(win, rcb ? cursor : NULL);
+
+ if (remote->hover && remote->hover->on_hover) {
+ remote->hover->on_hover(remote->hover, widget, false);
+ remote->hover = NULL;
+ }
+
+ if (rcb && rcb->on_hover) {
+ rcb->on_hover(rcb, widget, true);
+ remote->hover = rcb;
+ }
+
+ return true;
+}
+
+static GtkWidget *scrollda = NULL;
+
+void rcng_client_receive_destroy_ui()
+{
+ if (scrollda)
+ gtk_widget_destroy(scrollda);
+
+ scrollda = NULL;
+}
+
+static gint own_page_num = -1;
+static GtkWidget *header_button = NULL;
+static GtkWidget *da;
+
+#if 0
+static void
+edit_keymap_done(GtkButton *button, gpointer user_data)
+{
+
+}
+#endif
+static void
+on_hover_delete(struct rcbutton *rcb, GtkWidget *widget, bool hover)
+{
+ if (hover) {
+ if (rcb->col == 0 && rcb->cols == 1) {
+ rcb->cols = 2 + remote->width;
+ button_calculate_position(rcb);
+ button_redraw(rcb, widget);
+ } else if (rcb->row == 0 && rcb->rows == 1) {
+ rcb->rows = 2 + remote->height;
+ button_calculate_position(rcb);
+ button_redraw(rcb, widget);
+ }
+ } else {
+ if (rcb->col == 0 && rcb->cols != 1) {
+ button_redraw(rcb, widget);
+ rcb->cols = 1;
+ button_calculate_position(rcb);
+ } else if (rcb->row == 0 && rcb->rows != 1) {
+ button_redraw(rcb, widget);
+ rcb->rows = 1;
+ button_calculate_position(rcb);
+ }
+ }
+
+}
+
+static void
+edit_keymap(GtkButton *button, gpointer user_data)
+{
+ guint i;
+ gboolean *do_edit = user_data;
+ struct rcbutton *rcb;
+
+ g_print("Button clicked\n");
+ g_print("Remote width: %u x %u\n", remote->width, remote->height);
+ if (remote->width < 1 || remote->height < 1)
+ return;
+
+ if (!*do_edit) {
+ move_buttons(2, 2);
+ new_button_add("+", &cgreen, 2, 1, remote->width, 1);
+ new_button_add("+", &cgreen, 2, 2 + remote->height, remote->width, 1);
+ new_button_add("+", &cgreen, 1, 2, 1, remote->height);
+ new_button_add("+", &cgreen, 2 + remote->width, 2, 1, remote->height);
+
+ for (i = 0; i < remote->height; i++) {
+ rcb = new_button_add("-", &cred, 0, 2 + i, 1, 1);
+ rcb->on_hover = on_hover_delete;
+ }
+
+ for (i = 0; i < remote->width; i++) {
+ rcb = new_button_add("-", &cred, 2 + i, 0, 1, 1);
+ rcb->on_hover = on_hover_delete;
+ }
+
+ /*
+ new_button_add("+", &cgreen, 5, 2, 1, 7);
+ new_button_add("+", &cgreen, 2, 4, 1, 1);
+ new_button_add("+", &cgreen, 2, 4, 10, 10);
+ new_button_add("+", &cgreen, 2, 4, 10, 10);
+ new_button_add("-", &cred, 2, 2, 0, 0);
+ new_button_add("Del", &cred, 3, 3, 0, 0);
+ */
+
+ gtk_widget_queue_draw(da);
+ *do_edit = true;
+ } else {
+ GList *l = remote->buttons;
+
+ while (l) {
+ GList *next = l->next;
+ struct rcbutton *rcb = l->data;
+
+ if (rcb->color) {
+ g_free(rcb);
+ remote->buttons = g_list_delete_link (remote->buttons, l);
+ }
+
+ l = next;
+ }
+ move_buttons(-2, -2);
+ gtk_widget_queue_draw(da);
+ *do_edit = false;
+
+ }
+}
+
+static void
+on_notebook_page_change(GtkNotebook *notebook, GtkWidget *page, guint new_page_num,
+ gpointer user_data)
+{
+ static gboolean do_edit = false;
+
+ if (new_page_num != own_page_num) {
+ if (header_button) {
+ gtk_widget_destroy(header_button);
+ header_button = NULL;
+ do_edit = false;
+ }
+ return;
+ }
+
+ GtkWidget *test = gtk_button_new_from_icon_name("gtk-add", GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_label(GTK_BUTTON(test), "Edit Keymap");
+ gtk_button_set_always_show_image(GTK_BUTTON(test), TRUE);
+ g_signal_connect(test, "clicked", G_CALLBACK(edit_keymap), &do_edit);
+ gtk_widget_show_all(test);
+ gtk_header_bar_pack_end(GTK_HEADER_BAR(global->header), test);
+ header_button = test;
+ g_print("Page change: %i -> %u\n", own_page_num, new_page_num);
+}
+
+void rcng_client_receive_init_ui(GDBusObject *new_hw)
+{
+ GtkStateFlags state;
+ GtkStyleContext *style_context;
+ static bool first = true;
+
+ if (first) {
+ g_signal_connect(global->notebook, "switch-page", G_CALLBACK(on_notebook_page_change), NULL);
+ first = false;
+ }
+
+ rcng_client_receive_destroy_ui();
+
+ GDBusInterface *interface;
+ interface = g_dbus_object_get_interface(new_hw, "org.gnome.RemoteControlManager.Device");
+ if (!interface)
+ return;
+
+ /* FIXME: if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a(uuuuaa{sv}))"))) */
+
+ gchar **keymaps = NULL;
+ RCDevice *object = RCDEVICE(interface);
+ rcdevice_call_list_keymaps_sync(object, &keymaps, NULL, NULL);
+ g_print("I should look at keymap: %s\n", keymaps[0]);
+
+ guint16 km_width;
+ guint16 km_height;
+ GVariant *km_entries = NULL;
+ rcdevice_call_get_keymap_sync(object, keymaps[0], &km_width, &km_height,
+ &km_entries, NULL, NULL);
+
+ g_free(keymaps);
+ remote = g_malloc0(sizeof(*remote));
+ remote->width = km_width;
+ remote->height = km_height;
+
+ g_print("type of keymaps is %s\n", g_variant_get_type_string(km_entries));
+ GVariantIter iter;
+ gsize n_items;
+ GVariant *item;
+
+ style_context = gtk_widget_get_style_context(GTK_WIDGET(global->window));
+ state = gtk_widget_get_state_flags(GTK_WIDGET(global->window));
+ gtk_style_context_get(style_context, state, "background-color", &c, NULL);
+
+ cd = gdk_rgba_copy(c);
+ cd->red *= 0.7;
+ cd->green *= 0.7;
+ cd->blue *= 0.7;
+
+ cre = gdk_rgba_copy(c);
+ cre->red *= 2.0;
+
+ cb = gdk_rgba_copy(c);
+ cb->red = 0.0;
+ cb->green = 0.0;
+ cb->blue = 0.0;
+ cb->alpha = 1.0;
+
+ gdk_rgba_parse(&cgreen, "#a9b68f");
+ gdk_rgba_parse(&cred, "#cf8989");
+ cred.alpha = 0.8;
+
+ n_items = g_variant_iter_init(&iter, km_entries);
+ g_print("Key items: %zu\n", n_items);
+ guint row = 0;
+ guint col = 0;
+
+ while (g_variant_iter_loop (&iter, "@a{sv}", &item)) {
+ gchar *protocol;
+ guint64 scancode;
+ gchar *keycode;
+
+ g_variant_lookup(item, "protocol", "s", &protocol);
+ g_variant_lookup(item, "scancode", "t", &scancode);
+ g_variant_lookup(item, "keycode", "s", &keycode);
+
+ new_button_add(keycode, NULL, col, row, 1, 1);
+
+ col++;
+ if (col >= km_width) {
+ col = 0;
+ row++;
+ }
+
+ printf("Got a key: %s:0x%08" PRIx64 ":%s\n", protocol, scancode, keycode);
+ }
+
+ da = gtk_drawing_area_new();
+// gtk_widget_set_size_request (da, WINDOW_WIDTH, WINDOW_HEIGHT);
+ g_signal_connect (da, "draw", G_CALLBACK(draw_cb), NULL);
+
+ g_signal_connect(da, "button-press-event",
+ G_CALLBACK (button_press_event_cb), NULL);
+
+ g_signal_connect(da, "button-release-event",
+ G_CALLBACK (button_release_event_cb), NULL);
+
+ g_signal_connect(da, "motion-notify-event",
+ G_CALLBACK (motion_notify_event_cb), NULL);
+
+ gtk_widget_set_events (da, gtk_widget_get_events (da)
+ | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
+
+ scrollda = gtk_scrolled_window_new(NULL, NULL);
+
+ gtk_container_add(GTK_CONTAINER(scrollda), da);
+ gtk_widget_show_all(scrollda);
+ own_page_num = gtk_notebook_append_page(global->notebook, scrollda, gtk_label_new("Receive"));
+}
+