diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 38 | ||||
-rw-r--r-- | RemoteControlManager.xml | 31 | ||||
-rw-r--r-- | rcm-client-hardware-info.c | 74 | ||||
-rw-r--r-- | rcm-client-hardware-info.h | 3 | ||||
-rw-r--r-- | rcm-client-hardware-list.c | 140 | ||||
-rw-r--r-- | rcm-client-hardware-list.h | 6 | ||||
-rw-r--r-- | rcm-client-main.c | 216 | ||||
-rw-r--r-- | rcm-client-main.h | 10 | ||||
-rw-r--r-- | rcm-client-receive.c | 612 | ||||
-rw-r--r-- | rcm-client-receive.h | 4 | ||||
-rw-r--r-- | rcm-client-transmit.c | 31 | ||||
-rw-r--r-- | rcm-client-transmit.h | 4 | ||||
-rw-r--r-- | rcm-server-keymap.c | 61 | ||||
-rw-r--r-- | rcm-server-keymap.h | 5 | ||||
-rw-r--r-- | rcm-server-main.c (renamed from rcm-server.c) | 9 | ||||
-rw-r--r-- | rcm-server-main.h (renamed from rcm-server.h) | 0 |
17 files changed, 1229 insertions, 17 deletions
@@ -1,4 +1,6 @@ *.o rcm-server +rcm-client *.swp keymaps +generated.* @@ -11,16 +11,26 @@ GENERIC_CFLAGS = -g -Wall -Werror -D_FILE_OFFSET_BITS=64 \ EXTRA_CFLAGS = GENERIC_LDFLAGS = EXTRA_LDFLAGS = + RCM_PACKAGES = libudev libsystemd RCM_CFLAGS = ${GENERIC_CFLAGS} ${EXTRA_CFLAGS} $(shell pkg-config --cflags ${RCM_PACKAGES}) RCM_LDFLAGS = ${GENERIC_LDFLAGS} ${EXTRA_LDFLAGS} $(shell pkg-config --libs ${RCM_PACKAGES}) +RCM_COMPILE = $(CC) $(RCM_CFLAGS) +RCM_LINK = $(CC) $(RCM_CFLAGS) $(RCM_LDFLAGS) +RCM_OBJECTS = rcm-server-main.o rcm-server-keymap.o +RCM_HEADERS = rcm-server-main.h rcm-server-keymap.h utils.h + +RCC_PACKAGES = gtk+-3.0 +RCC_CFLAGS = ${GENERIC_CFLAGS} ${EXTRA_CFLAGS} $(shell pkg-config --cflags ${RCC_PACKAGES}) +RCC_LDFLAGS = ${GENERIC_LDFLAGS} ${EXTRA_LDFLAGS} $(shell pkg-config --libs ${RCC_PACKAGES}) +RCC_COMPILE = $(CC) $(RCC_CFLAGS) +RCC_LINK = $(CC) $(RCC_CFLAGS) $(RCC_LDFLAGS) +RCC_OBJECTS = rcm-client-main.o rcm-client-hardware-list.o rcm-client-hardware-info.o rcm-client-receive.o rcm-client-transmit.o generated.o +RCC_HEADERS = rcm-client-main.h rcm-client-hardware-list.h rcm-client-hardware-info.h rcm-client-receive.h rcm-client-transmit.h generated.h + INSTALL = install -c INSTALL_PROGRAM = ${INSTALL} INSTALL_DATA = ${INSTALL} -m 644 -RCM_COMPILE = $(CC) $(RCM_CFLAGS) -RCM_LINK = $(CC) $(RCM_CFLAGS) $(RCM_LDFLAGS) -RCM_SERVER_OBJ = rcm-server.o rcm-server-keymap.o -RCM_SERVER_HDR = rcm-server.h rcm-server-keymap.h utils.h DESTDIR ?= prefix = /usr @@ -33,13 +43,25 @@ mandir = ${prefix}/share/man # Targets # -all: rcm-server +all: rcm-server rcm-client .DEFAULT: all -%.o: %.c $(RCM_SERVER_HDR) +rcm-client-%.o: rcm-client-%.c $(RCC_HEADERS) + $(RCC_COMPILE) -o $@ -c $< + +generated.o: generated.c generated.h + $(RCC_COMPILE) -o $@ -c $< + +generated.c generated.h: RemoteControlManager.xml + gdbus-codegen --interface-prefix org.gnome --c-generate-object-manager --generate-c-code generated RemoteControlManager.xml + +rcm-client: $(RCC_OBJECTS) + $(RCC_LINK) -o $@ $^ + +rcm-server-%.o: rcm-server-%.c $(RCM_HEADERS) $(RCM_COMPILE) -o $@ -c $< -rcm-server: $(RCM_SERVER_OBJ) +rcm-server: $(RCM_OBJECTS) $(RCM_LINK) -o $@ $^ install: all @@ -49,7 +71,7 @@ uninstall: - rm -f $(DESTDIR)$(usrbindir)/rcm-server clean: - - rm -f *.o rcm-server + - rm -f generated.[ch] *.o rcm-server rcm-client .PHONY: install uninstall clean all diff --git a/RemoteControlManager.xml b/RemoteControlManager.xml new file mode 100644 index 0000000..ede8f69 --- /dev/null +++ b/RemoteControlManager.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<node name="/org/gnome/RemoteControlManager"> + <interface name='org.gnome.RemoteControlManager.Device'> + <annotation name="org.gtk.GDBus.C.Name" value="RCDevice"/> + <method name='EchoString'> + <arg type='s' name='greeting' direction='in'/> + <arg type='s' name='response' direction='out'/> + </method> + <method name='ListKeymaps'> + <arg type='as' name='keymap_names' direction='out'/> + </method> + <method name='GetKeymap'> + <arg type='s' name='keymap_name' direction='in'/> + <arg type='q' name='keymap_width' direction='out'/> + <arg type='q' name='keymap_height' direction='out'/> + <arg type='aa{sv}' name='keymap_entries' direction='out'/> + </method> + <signal name='VelocityChanged'> + <arg type='s' name='event'/> + </signal> + <property name='DriverName' type='s' access='read'/> + <property name='KernelKeymapName' type='s' access='read'/> + <property name='GetHardwareType' type='s' access='read'/> + </interface> + <interface name='org.gnome.RemoteControlManager.IRDevice'> + <annotation name="org.gtk.GDBus.C.Name" value="RCIRDevice"/> + <method name='GetIRRXParameters'> + <arg type='a{sv}' name='ir_rx_parameters' direction='out'/> + </method> + </interface> +</node> diff --git a/rcm-client-hardware-info.c b/rcm-client-hardware-info.c new file mode 100644 index 0000000..662f526 --- /dev/null +++ b/rcm-client-hardware-info.c @@ -0,0 +1,74 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <math.h> +#include <gtk/gtk.h> + +#include "generated.h" +#include "rcm-client-main.h" +#include "rcm-client-hardware-list.h" +#include "rcm-client-hardware-info.h" +#include "rcm-client-receive.h" +#include "rcm-client-transmit.h" + +static GtkWidget *info = NULL; +static GDBusObject *hw = NULL; + +void +rcng_client_hardware_init_info_ui(GDBusObject *new_hw) +{ + GtkWidget *icon; + GtkWidget *hbox; + GtkWidget *title; + GtkWidget *line; + + if (new_hw == hw) + return; + + hw = new_hw; + if (info) + gtk_widget_destroy(info); + info = NULL; + rcng_client_receive_destroy_ui(); + rcng_client_transmit_destroy_ui(); + + if (!hw) + return; + + icon = gtk_image_new_from_icon_name("gtk-harddisk", GTK_ICON_SIZE_DIALOG); + gtk_widget_set_valign(icon, GTK_ALIGN_START); + gtk_widget_set_halign(icon, GTK_ALIGN_START); + gtk_widget_set_margin_start(icon, 12); + gtk_widget_set_margin_end(icon, 12); + + hbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); + + title = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(title), "<b>Hardware</b>"); + gtk_widget_set_halign(title, GTK_ALIGN_START); + gtk_box_pack_start(GTK_BOX(hbox), title, FALSE, FALSE, 0); + + line = gtk_label_new("Apan 1"); + gtk_widget_set_halign(line, GTK_ALIGN_START); + gtk_box_pack_start(GTK_BOX(hbox), line, FALSE, FALSE, 0); + + line = gtk_label_new("Apan 2"); + line = gtk_label_new(g_dbus_object_get_object_path(hw)); + gtk_widget_set_halign(line, GTK_ALIGN_START); + gtk_box_pack_start(GTK_BOX(hbox), line, FALSE, FALSE, 0); + + info = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_margin_start(info, 12); + gtk_widget_set_margin_end(info, 12); + gtk_widget_set_margin_top(info, 12); + gtk_widget_set_margin_bottom(info, 12); + gtk_box_pack_start(GTK_BOX(info), icon, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(info), hbox, FALSE, FALSE, 0); + + gtk_widget_show_all(info); + gtk_notebook_append_page(global->notebook, info, gtk_label_new("Details")); + gtk_notebook_set_current_page(global->notebook, 1); + + rcng_client_receive_init_ui(new_hw); +} diff --git a/rcm-client-hardware-info.h b/rcm-client-hardware-info.h new file mode 100644 index 0000000..37e65f0 --- /dev/null +++ b/rcm-client-hardware-info.h @@ -0,0 +1,3 @@ + +void rcng_client_hardware_init_info_ui(GDBusObject *); + diff --git a/rcm-client-hardware-list.c b/rcm-client-hardware-list.c new file mode 100644 index 0000000..eec0d03 --- /dev/null +++ b/rcm-client-hardware-list.c @@ -0,0 +1,140 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <math.h> +#include <gtk/gtk.h> + +#include "generated.h" +#include "rcm-client-main.h" +#include "rcm-client-hardware-list.h" +#include "rcm-client-hardware-info.h" + +static GtkWidget *status_msg; +static GtkWidget *hw_list_box; +static GtkWidget *stack; +static GList *hw_list = NULL; + +struct hwentry { + GDBusObject *hw; + GtkWidget *widget; +}; + +static gint +find_hwentry_by_object(gconstpointer a, gconstpointer user_data) +{ + const struct hwentry *hwe = a; + + return hwe->hw == user_data ? 0 : -1; +} + +static gint +find_hwentry_by_widget(gconstpointer a, gconstpointer user_data) +{ + const struct hwentry *hwe = a; + + return hwe->widget == user_data ? 0 : -1; +} + +void rcng_client_hardware_list_remove(GDBusObject *hw) +{ + GList *entry; + struct hwentry *hwe; + + entry = g_list_find_custom(hw_list, hw, find_hwentry_by_object); + if (!entry) + return; + + hwe = entry->data; + hw_list = g_list_remove_all(hw_list, hwe); + + g_print(" - Object removed %s\n", g_dbus_object_get_object_path(hwe->hw)); + gtk_widget_destroy(hwe->widget); + g_free(hwe); + + if (!hw_list) + gtk_stack_set_visible_child(GTK_STACK(stack), status_msg); +} + +void rcng_client_hardware_list_add(GDBusObject *hw) +{ + GList *interfaces; + GList *ll; + GtkWidget *box; + GtkWidget *icon; + GtkWidget *label; + struct hwentry *hwe; + + g_print(" - Object at %s\n", g_dbus_object_get_object_path(hw)); + + interfaces = g_dbus_object_get_interfaces(hw); + for (ll = interfaces; ll != NULL; ll = ll->next) { + GDBusInterface *interface = G_DBUS_INTERFACE(ll->data); + g_print (" - Interface %s\n", g_dbus_interface_get_info(interface)->name); + } + g_list_free_full (interfaces, g_object_unref); + + if (!hw_list) + gtk_stack_set_visible_child(GTK_STACK(stack), hw_list_box); + + box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + icon = gtk_image_new_from_icon_name("gtk-harddisk", GTK_ICON_SIZE_DIALOG); + gtk_widget_set_valign(icon, GTK_ALIGN_START); + gtk_widget_set_halign(icon, GTK_ALIGN_START); + gtk_widget_set_margin_start(icon, 12); + gtk_widget_set_margin_end(icon, 12); + label = gtk_label_new(g_dbus_object_get_object_path(hw)); + gtk_box_pack_start(GTK_BOX(box), icon, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); + gtk_widget_show_all(box); + + gtk_list_box_insert(GTK_LIST_BOX(hw_list_box), box, -1); + + hwe = g_malloc(sizeof(*hwe)); + hwe->hw = hw; + hwe->widget = box; + hw_list = g_list_append(hw_list, hwe); +} + +static void +on_hw_selected(GtkListBox *box, + GtkListBoxRow *row, + gpointer user_data) +{ + GList *entry; + GtkWidget *child; + struct hwentry *hwe; + + child = row ? gtk_bin_get_child(GTK_BIN(row)) : NULL; + entry = g_list_find_custom(hw_list, child, find_hwentry_by_widget); + hwe = entry ? entry->data : NULL; + + rcng_client_hardware_init_info_ui(hwe ? hwe->hw : NULL); +} + +void rcng_client_hardware_list_update_status(gchar *status) +{ + gtk_label_set_text(GTK_LABEL(status_msg), status); +} + +void rcng_client_hardware_list_init_ui() +{ + stack = gtk_stack_new(); + gtk_widget_set_margin_start(stack, 12); + gtk_widget_set_margin_end(stack, 12); + gtk_widget_set_margin_top(stack, 12); + gtk_widget_set_margin_bottom(stack, 12); + gtk_stack_set_transition_type(GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE); + + status_msg = gtk_label_new("Connecting to server..."); + gtk_stack_add_named(GTK_STACK(stack), status_msg, "nohw"); + gtk_stack_set_visible_child(GTK_STACK(stack), status_msg); + + hw_list_box = gtk_list_box_new(); + gtk_stack_add_named(GTK_STACK(stack), hw_list_box, "yeshw"); + g_signal_connect(hw_list_box, "row-selected", G_CALLBACK(on_hw_selected), NULL); + + gtk_notebook_append_page(global->notebook, stack, gtk_label_new("Hardware")); +} + + diff --git a/rcm-client-hardware-list.h b/rcm-client-hardware-list.h new file mode 100644 index 0000000..47314e0 --- /dev/null +++ b/rcm-client-hardware-list.h @@ -0,0 +1,6 @@ + +void rcng_client_hardware_list_remove(GDBusObject *); +void rcng_client_hardware_list_add(GDBusObject *); +void rcng_client_hardware_list_init_ui(); +void rcng_client_hardware_list_update_status(gchar *); + diff --git a/rcm-client-main.c b/rcm-client-main.c new file mode 100644 index 0000000..cd119a3 --- /dev/null +++ b/rcm-client-main.c @@ -0,0 +1,216 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <math.h> +#include <gtk/gtk.h> + +#include "generated.h" +#include "rcm-client-main.h" +#include "rcm-client-hardware-list.h" + +#define WINDOW_WIDTH 300 +#define WINDOW_HEIGHT 300 + +static GDBusObjectManager *mgr = NULL; + +struct global_variables *global; + +void +poke_objects() +{ + GList *objects; + GList *l; + GDBusObjectManager *manager = mgr; + + objects = g_dbus_object_manager_get_objects (manager); + for (l = objects; l != NULL; l = l->next) + { + GDBusInterface *interface; + + interface = g_dbus_object_get_interface(G_DBUS_OBJECT(l->data), + "org.gnome.RemoteControlManager.Device"); + if (!interface) { + g_print("That's weird, an object which is not a device...\n"); + continue; + } + + RCDevice *object = RCDEVICE(interface); + gchar *reply = NULL; + rcdevice_call_echo_string_sync(object, "Roeven", &reply, NULL, NULL); + printf("Called object %s: %s\n", g_dbus_object_get_object_path (G_DBUS_OBJECT(l->data)), reply); + printf("Driver name is: %s\n", rcdevice_get_driver_name(object)); + printf("Keymap name is: %s\n", rcdevice_get_kernel_keymap_name(object)); + g_free(reply); + + g_object_unref(interface); + } + g_list_free_full (objects, g_object_unref); +} + +void +poke_objects2() +{ + GList *objects; + GList *l; + GDBusObjectManager *manager = mgr; + + objects = g_dbus_object_manager_get_objects (manager); + for (l = objects; l != NULL; l = l->next) + { + GDBusInterface *interface; + + interface = g_dbus_object_get_interface(G_DBUS_OBJECT(l->data), + "org.gnome.RemoteControlManager.IRDevice"); + if (!interface) { + g_print("That's weird, an object which is not an ir device...\n"); + continue; + } + + RCIRDevice *object = RCIRDEVICE(interface); + GVariant *reply = NULL; + rcirdevice_call_get_irrxparameters_sync(object, &reply, NULL, NULL); + + printf("Got a reply %p\n", reply); + gchar *ans = NULL; + + g_variant_lookup(reply, "name", "s", &ans); + printf("The rsult is %s\n", ans); +/* + printf("Called object %s: %s\n", g_dbus_object_get_object_path (G_DBUS_OBJECT(l->data)), reply); + printf("Driver name is: %s\n", rcdevice_get_driver_name(object)); + printf("Keymap name is: %s\n", rcdevice_get_kernel_keymap_name(object)); + */ + //g_free(reply); + + g_object_unref(interface); + } + g_list_free_full (objects, g_object_unref); +} + +static void +on_object_added(GDBusObjectManager *manager, + GDBusObject *object, + gpointer user_data) +{ + g_print("Added object at %s\n", g_dbus_object_get_object_path(object)); + rcng_client_hardware_list_add(object); +} + +static void +on_object_removed(GDBusObjectManager *manager, + GDBusObject *object, + gpointer user_data) +{ + g_print("Removed object at %s\n", g_dbus_object_get_object_path(object)); + rcng_client_hardware_list_remove(object); +} + +static void +on_owner_change(GDBusObjectManager *manager, gpointer user_data) +{ + g_print("Owner changed, now: %s\n", g_dbus_object_manager_client_get_name_owner(G_DBUS_OBJECT_MANAGER_CLIENT(manager))); + + if (!g_dbus_object_manager_client_get_name_owner(G_DBUS_OBJECT_MANAGER_CLIENT(manager))) + rcng_client_hardware_list_update_status("Server not running...\n"); + else + rcng_client_hardware_list_update_status("No hardware connected..."); +} + +static void +manager_ready_cb(GObject *source, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GList *objects; + GList *l; + + mgr = object_manager_client_new_for_bus_finish(res, &error); + if (!mgr) { + gchar *msg; + + msg = g_strdup_printf("Error creating object manager client: %s", + error->message); + rcng_client_hardware_list_update_status(msg); + + g_free(msg); + g_error_free(error); + return; + } + + g_signal_connect(mgr, "object-added", G_CALLBACK(on_object_added), NULL); + g_signal_connect(mgr, "object-removed", G_CALLBACK(on_object_removed), NULL); + g_signal_connect(mgr, "notify::name-owner", G_CALLBACK(on_owner_change), NULL); + + on_owner_change(mgr, NULL); + g_print("Object manager at %s\n", g_dbus_object_manager_get_object_path(mgr)); + objects = g_dbus_object_manager_get_objects(mgr); + for (l = objects; l != NULL; l = l->next) { + rcng_client_hardware_list_add(G_DBUS_OBJECT(l->data)); + rcng_client_hardware_list_add(G_DBUS_OBJECT(l->data)); + } + + g_list_free_full (objects, g_object_unref); + +} + +int main (int argc, char *argv[]) +{ + GtkWidget *win; + GdkScreen *screen; + gint monitor; + GdkRectangle rect; + + global = g_malloc(sizeof(*global)); + + gtk_init (&argc, &argv); + + object_manager_client_new_for_bus(G_BUS_TYPE_SESSION, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, + "org.gnome.RemoteControlManager", + "/org/gnome/RemoteControlManager", + NULL, manager_ready_cb, NULL); + + win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + global->window = GTK_WINDOW(win); + g_signal_connect(win, "destroy", G_CALLBACK (gtk_main_quit), NULL); + + screen = gtk_window_get_screen(global->window); + monitor = gdk_screen_get_monitor_at_point(screen, 0, 0); + gdk_screen_get_monitor_geometry(screen, monitor, &rect); + gtk_window_set_default_size(global->window, + rect.width * 4 / 5, + rect.height * 1 / 2); + + global->header = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_header_bar_set_title(global->header, "Remote Control Configuration"); + gtk_header_bar_set_has_subtitle(global->header, FALSE); + gtk_header_bar_set_show_close_button(global->header, TRUE); + gtk_window_set_titlebar(global->window, GTK_WIDGET(global->header)); + + /* + GtkWidget *label; + label = gtk_label_new("Pack Start"); + gtk_header_bar_pack_start(GTK_HEADER_BAR(header), label); + label = gtk_label_new("Pack End"); + gtk_header_bar_pack_end(GTK_HEADER_BAR(header), label); + GtkWidget *test = gtk_button_new_from_icon_name("gtk-add", GTK_ICON_SIZE_BUTTON); + gtk_button_set_label(GTK_BUTTON(test), "Test"); + gtk_button_set_always_show_image(GTK_BUTTON(test), TRUE); + gtk_header_bar_pack_end(GTK_HEADER_BAR(header), test); + */ + + + global->notebook = GTK_NOTEBOOK(gtk_notebook_new()); + gtk_notebook_set_tab_pos(global->notebook, GTK_POS_LEFT); + + rcng_client_hardware_list_init_ui(global->notebook); + + gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(global->notebook)); + //gtk_window_set_title(window, "Remote Control Configuration"); + gtk_window_set_icon_name(global->window, "gnome-multimedia"); + gtk_widget_show_all(win); + + gtk_main(); + + return 0; +} diff --git a/rcm-client-main.h b/rcm-client-main.h new file mode 100644 index 0000000..d27fb24 --- /dev/null +++ b/rcm-client-main.h @@ -0,0 +1,10 @@ +void poke_objects(); +void poke_objects2(); + +struct global_variables { + GtkWindow *window; + GtkHeaderBar *header; + GtkNotebook *notebook; +}; + +extern struct global_variables *global; 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")); +} + diff --git a/rcm-client-receive.h b/rcm-client-receive.h new file mode 100644 index 0000000..19adad0 --- /dev/null +++ b/rcm-client-receive.h @@ -0,0 +1,4 @@ + +void rcng_client_receive_destroy_ui(); +void rcng_client_receive_init_ui(GDBusObject *new_hw); + diff --git a/rcm-client-transmit.c b/rcm-client-transmit.c new file mode 100644 index 0000000..62b0a7f --- /dev/null +++ b/rcm-client-transmit.c @@ -0,0 +1,31 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <math.h> +#include <gtk/gtk.h> + +#include "generated.h" +#include "rcm-client-main.h" +#include "rcm-client-transmit.h" + +static GtkWidget *label = NULL; + +void rcng_client_transmit_destroy_ui() +{ + if (label) + gtk_widget_destroy(label); + + label = NULL; +} + +void rcng_client_transmit_init_ui() +{ + GtkWidget *label; + + rcng_client_transmit_destroy_ui(); + label = gtk_label_new("Transmitting"); + gtk_widget_show_all(label); + gtk_notebook_append_page(global->notebook, label, gtk_label_new("Transmit")); +} + diff --git a/rcm-client-transmit.h b/rcm-client-transmit.h new file mode 100644 index 0000000..92b3786 --- /dev/null +++ b/rcm-client-transmit.h @@ -0,0 +1,4 @@ + +void rcng_client_transmit_destroy_ui(); +void rcng_client_transmit_init_ui(); + diff --git a/rcm-server-keymap.c b/rcm-server-keymap.c index d0f772e..39b4440 100644 --- a/rcm-server-keymap.c +++ b/rcm-server-keymap.c @@ -14,7 +14,7 @@ #include <limits.h> #include "utils.h" -#include "rcm-server.h" +#include "rcm-server-main.h" #include "rcm-server-keymap.h" enum ini_section { @@ -63,6 +63,33 @@ static int strtol_strict(const char *str, int *result) return 0; } +static int strtoull_strict(const char *str, uint64_t *result) +{ + char *end; + unsigned long long val; + + errno = 0; + val = strtoull(str, &end, 16); + + if (errno == ERANGE && (val == ULLONG_MAX || val == 0)) + return -EINVAL; + + if (errno != 0 && val == 0) + return -EINVAL; + + if (end == str) + return -EINVAL; + + if (*end != '\0') + return -EINVAL; + + if (val > UINT64_MAX) + return -EINVAL; + + *result = val; + return 0; +} + static int keymap_parse(FILE *fp, char **line, size_t *buf_size, struct keymap *keymap, uint16_t *rows_return, uint16_t *cols_return, @@ -142,9 +169,37 @@ keymap_parse(FILE *fp, char **line, size_t *buf_size, struct keymap *keymap, break; case INI_SECTION_KEYMAP: if (!strcasecmp(p, "Map")) { + char *protocol; + char *scanstr; + char *keycode; + char *end; + uint64_t scancode; + + printf("Map %s\n", tmp); + protocol = strtok(tmp, " :"); + scanstr = strtok(NULL, " :"); + keycode = strtok(NULL, " :"); + end = strtok(NULL, " :"); + + if (!protocol || !scancode || !keycode || end) { + fprintf(stderr, "Invalid map directive\n"); + return -ENOMEM; + } + + r = strtoull_strict(scanstr, &scancode); + if (r < 0) { + fprintf(stderr, "Invalid scancode value\n"); + return r; + } + + printf("Map means protocol %s scancode 0x%08" PRIx64 " keycode %s\n", + protocol, scancode, keycode); + if (keymap) { - keymap->keycodes[keycode_count].name = "apan"; - keymap->keycodes[keycode_count].value = "papan"; + /* FIXME: leaks */ + keymap->keycodes[keycode_count].protocol = strdup(protocol); + keymap->keycodes[keycode_count].scancode = scancode; + keymap->keycodes[keycode_count].keycode = strdup(keycode); } keycode_count++; } else { diff --git a/rcm-server-keymap.h b/rcm-server-keymap.h index 6ece017..8676fbc 100644 --- a/rcm-server-keymap.h +++ b/rcm-server-keymap.h @@ -2,8 +2,9 @@ #define foorcmserverkeymaphfoo struct keycode { - char *name; - char *value; + char *protocol; + uint64_t scancode; + char *keycode; }; struct keymap { diff --git a/rcm-server.c b/rcm-server-main.c index 11223b1..02387a1 100644 --- a/rcm-server.c +++ b/rcm-server-main.c @@ -9,7 +9,7 @@ #include <errno.h> #include "utils.h" -#include "rcm-server.h" +#include "rcm-server-main.h" #include "rcm-server-keymap.h" static int @@ -153,9 +153,10 @@ method_getkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error) goto out; for (i = 0; i < (keymap->rows * keymap->cols); i++) { - r = sd_bus_message_append(reply, "a{sv}", 2, - "name", "s", keymap->layout[i]->name, - "keycode", "s", keymap->layout[i]->value); + r = sd_bus_message_append(reply, "a{sv}", 3, + "protocol", "s", keymap->layout[i]->protocol, + "scancode", "t", keymap->layout[i]->scancode, + "keycode", "s", keymap->layout[i]->keycode); if (r < 0) goto out; } diff --git a/rcm-server.h b/rcm-server-main.h index 188ffab..188ffab 100644 --- a/rcm-server.h +++ b/rcm-server-main.h |