diff options
Diffstat (limited to 'desktop')
40 files changed, 557 insertions, 0 deletions
diff --git a/desktop/Makefile b/desktop/Makefile new file mode 100644 index 0000000..49e6f7a --- /dev/null +++ b/desktop/Makefile @@ -0,0 +1,29 @@ +LIBS = gtk+-2.0 glib-2.0 cairo pango gdk-pixbuf-2.0 atk libwebsockets x11 +CC = gcc +CCFLAGS = -Wall -std=c99 -pthread `pkg-config --cflags --libs ${LIBS}` +LDFLAGS = -lm +BINARIES = vkpc + +all : vkpc + +vkpc : server.o grab.o vector.o main.o + ${CC} ${CCFLAGS} server.o grab.o vector.o main.o ${LDFLAGS} -o vkpc + +server.o : server.c + ${CC} ${CCFLAGS} -c server.c + +grab.o : grab.c + ${CC} ${CCFLAGS} -c grab.c + +vector.o : vector.c + ${CC} ${CCFLAGS} -c vector.c + +main.o : main.c + ${CC} ${CCFLAGS} -c main.c + +install: + cp vkpc /usr/bin + sh install_icons.sh + +clean: + rm -f $(BINARIES) *.o diff --git a/desktop/grab.c b/desktop/grab.c new file mode 100644 index 0000000..716b0c6 --- /dev/null +++ b/desktop/grab.c @@ -0,0 +1,51 @@ +#include <stdio.h> +#include <stdbool.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/XF86keysym.h> +#include "grab.h" + +static int error_handler(Display *dpy, XErrorEvent *err) { + fprintf(stderr, "Failed to grab key!\n"); + return 0; +} + +void grab_init(void (*handler)(enum HotkeyEvent e)) { + Display *dpy = XOpenDisplay(0); + Window root = DefaultRootWindow(dpy); + XEvent ev; + + struct Hotkey hotkeys[HOTKEYS_COUNT] = { + { HK_PAUSE, XKeysymToKeycode(dpy, XF86XK_AudioPause) }, + { HK_PLAY, XKeysymToKeycode(dpy, XF86XK_AudioPlay) }, + { HK_NEXT, XKeysymToKeycode(dpy, XF86XK_AudioNext) }, + { HK_PREV, XKeysymToKeycode(dpy, XF86XK_AudioPrev) } + }; + + XSetErrorHandler(error_handler); + + for (int i = 0; i < HOTKEYS_COUNT; i++) { + XGrabKey(dpy, hotkeys[i].keycode, 0, root, false, GrabModeAsync, GrabModeAsync); + } + + XSelectInput(dpy, root, KeyPressMask); + while (true) { + XNextEvent(dpy, &ev); + + switch (ev.type) { + case KeyPress: ; + for (int i = 0; i < HOTKEYS_COUNT; i++) { + if (ev.xkey.keycode == hotkeys[i].keycode) { + (*handler)(hotkeys[i].event); + break; + } + } + break; + + default: + break; + } + } + + XCloseDisplay(dpy); +} diff --git a/desktop/grab.h b/desktop/grab.h new file mode 100644 index 0000000..762f9d8 --- /dev/null +++ b/desktop/grab.h @@ -0,0 +1,15 @@ +#ifndef GRAB_H__ +#define GRAB_H__ + +enum HotkeyEvent { + HK_PREV, HK_NEXT, HK_PAUSE, HK_PLAY, + HOTKEYS_COUNT +}; +struct Hotkey { + enum HotkeyEvent event; + int keycode; +}; + +void grab_init(); + +#endif diff --git a/desktop/icons/Faenza-Radiance/apps/16/vkpc.png b/desktop/icons/Faenza-Radiance/apps/16/vkpc.png Binary files differnew file mode 100644 index 0000000..1eaf260 --- /dev/null +++ b/desktop/icons/Faenza-Radiance/apps/16/vkpc.png diff --git a/desktop/icons/Faenza-Radiance/apps/22/vkpc.png b/desktop/icons/Faenza-Radiance/apps/22/vkpc.png Binary files differnew file mode 100644 index 0000000..03ec012 --- /dev/null +++ b/desktop/icons/Faenza-Radiance/apps/22/vkpc.png diff --git a/desktop/icons/Faenza-Radiance/apps/24/vkpc.png b/desktop/icons/Faenza-Radiance/apps/24/vkpc.png Binary files differnew file mode 100644 index 0000000..ad1fc6c --- /dev/null +++ b/desktop/icons/Faenza-Radiance/apps/24/vkpc.png diff --git a/desktop/icons/Faenza-Radiance/apps/32/vkpc.png b/desktop/icons/Faenza-Radiance/apps/32/vkpc.png Binary files differnew file mode 100644 index 0000000..4107fc3 --- /dev/null +++ b/desktop/icons/Faenza-Radiance/apps/32/vkpc.png diff --git a/desktop/icons/Faenza-Radiance/apps/48/vkpc.png b/desktop/icons/Faenza-Radiance/apps/48/vkpc.png Binary files differnew file mode 100644 index 0000000..041f8a6 --- /dev/null +++ b/desktop/icons/Faenza-Radiance/apps/48/vkpc.png diff --git a/desktop/icons/Faenza-Radiance/apps/64/vkpc.png b/desktop/icons/Faenza-Radiance/apps/64/vkpc.png Binary files differnew file mode 100644 index 0000000..ba1980d --- /dev/null +++ b/desktop/icons/Faenza-Radiance/apps/64/vkpc.png diff --git a/desktop/icons/Faenza-Radiance/apps/96/vkpc.png b/desktop/icons/Faenza-Radiance/apps/96/vkpc.png Binary files differnew file mode 100644 index 0000000..853b46d --- /dev/null +++ b/desktop/icons/Faenza-Radiance/apps/96/vkpc.png diff --git a/desktop/icons/Faenza/apps/16/vkpc.png b/desktop/icons/Faenza/apps/16/vkpc.png Binary files differnew file mode 100644 index 0000000..29e3991 --- /dev/null +++ b/desktop/icons/Faenza/apps/16/vkpc.png diff --git a/desktop/icons/Faenza/apps/22/vkpc.png b/desktop/icons/Faenza/apps/22/vkpc.png Binary files differnew file mode 100644 index 0000000..73daaa8 --- /dev/null +++ b/desktop/icons/Faenza/apps/22/vkpc.png diff --git a/desktop/icons/Faenza/apps/24/vkpc.png b/desktop/icons/Faenza/apps/24/vkpc.png Binary files differnew file mode 100644 index 0000000..3f1ca5e --- /dev/null +++ b/desktop/icons/Faenza/apps/24/vkpc.png diff --git a/desktop/icons/Faenza/apps/32/vkpc.png b/desktop/icons/Faenza/apps/32/vkpc.png Binary files differnew file mode 100644 index 0000000..3502985 --- /dev/null +++ b/desktop/icons/Faenza/apps/32/vkpc.png diff --git a/desktop/icons/Faenza/apps/48/vkpc.png b/desktop/icons/Faenza/apps/48/vkpc.png Binary files differnew file mode 100644 index 0000000..3f9ffa5 --- /dev/null +++ b/desktop/icons/Faenza/apps/48/vkpc.png diff --git a/desktop/icons/Faenza/apps/64/vkpc.png b/desktop/icons/Faenza/apps/64/vkpc.png Binary files differnew file mode 100644 index 0000000..7278517 --- /dev/null +++ b/desktop/icons/Faenza/apps/64/vkpc.png diff --git a/desktop/icons/Faenza/apps/96/vkpc.png b/desktop/icons/Faenza/apps/96/vkpc.png Binary files differnew file mode 100644 index 0000000..d0e8b61 --- /dev/null +++ b/desktop/icons/Faenza/apps/96/vkpc.png diff --git a/desktop/icons/hicolor/128x128/apps/vkpc.png b/desktop/icons/hicolor/128x128/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..7c5f49e --- /dev/null +++ b/desktop/icons/hicolor/128x128/apps/vkpc.png diff --git a/desktop/icons/hicolor/22x22/apps/vkpc.png b/desktop/icons/hicolor/22x22/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..0f9186c --- /dev/null +++ b/desktop/icons/hicolor/22x22/apps/vkpc.png diff --git a/desktop/icons/hicolor/24x24/apps/vkpc.png b/desktop/icons/hicolor/24x24/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..18b2b38 --- /dev/null +++ b/desktop/icons/hicolor/24x24/apps/vkpc.png diff --git a/desktop/icons/hicolor/32x32/apps/vkpc.png b/desktop/icons/hicolor/32x32/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..8cad27c --- /dev/null +++ b/desktop/icons/hicolor/32x32/apps/vkpc.png diff --git a/desktop/icons/hicolor/36x36/apps/vkpc.png b/desktop/icons/hicolor/36x36/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..6448800 --- /dev/null +++ b/desktop/icons/hicolor/36x36/apps/vkpc.png diff --git a/desktop/icons/hicolor/40x40/apps/vkpc.png b/desktop/icons/hicolor/40x40/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..df33c09 --- /dev/null +++ b/desktop/icons/hicolor/40x40/apps/vkpc.png diff --git a/desktop/icons/hicolor/48x48/apps/vkpc.png b/desktop/icons/hicolor/48x48/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..d34540e --- /dev/null +++ b/desktop/icons/hicolor/48x48/apps/vkpc.png diff --git a/desktop/icons/hicolor/64x64/apps/vkpc.png b/desktop/icons/hicolor/64x64/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..f94329a --- /dev/null +++ b/desktop/icons/hicolor/64x64/apps/vkpc.png diff --git a/desktop/icons/hicolor/72x72/apps/vkpc.png b/desktop/icons/hicolor/72x72/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..3f26601 --- /dev/null +++ b/desktop/icons/hicolor/72x72/apps/vkpc.png diff --git a/desktop/icons/hicolor/96x96/apps/vkpc.png b/desktop/icons/hicolor/96x96/apps/vkpc.png Binary files differnew file mode 100644 index 0000000..b05a855 --- /dev/null +++ b/desktop/icons/hicolor/96x96/apps/vkpc.png diff --git a/desktop/icons/ubuntu-mono-dark/16/vkpc.png b/desktop/icons/ubuntu-mono-dark/16/vkpc.png Binary files differnew file mode 100644 index 0000000..440e6b9 --- /dev/null +++ b/desktop/icons/ubuntu-mono-dark/16/vkpc.png diff --git a/desktop/icons/ubuntu-mono-dark/22/vkpc.png b/desktop/icons/ubuntu-mono-dark/22/vkpc.png Binary files differnew file mode 100644 index 0000000..6781df2 --- /dev/null +++ b/desktop/icons/ubuntu-mono-dark/22/vkpc.png diff --git a/desktop/icons/ubuntu-mono-dark/24/vkpc.png b/desktop/icons/ubuntu-mono-dark/24/vkpc.png Binary files differnew file mode 100644 index 0000000..e57de23 --- /dev/null +++ b/desktop/icons/ubuntu-mono-dark/24/vkpc.png diff --git a/desktop/icons/ubuntu-mono-light/16/vkpc.png b/desktop/icons/ubuntu-mono-light/16/vkpc.png Binary files differnew file mode 100644 index 0000000..dfb7295 --- /dev/null +++ b/desktop/icons/ubuntu-mono-light/16/vkpc.png diff --git a/desktop/icons/ubuntu-mono-light/22/vkpc.png b/desktop/icons/ubuntu-mono-light/22/vkpc.png Binary files differnew file mode 100644 index 0000000..adc4436 --- /dev/null +++ b/desktop/icons/ubuntu-mono-light/22/vkpc.png diff --git a/desktop/icons/ubuntu-mono-light/24/vkpc.png b/desktop/icons/ubuntu-mono-light/24/vkpc.png Binary files differnew file mode 100644 index 0000000..e04c84d --- /dev/null +++ b/desktop/icons/ubuntu-mono-light/24/vkpc.png diff --git a/desktop/info.h b/desktop/info.h new file mode 100644 index 0000000..f13bbdc --- /dev/null +++ b/desktop/info.h @@ -0,0 +1,13 @@ +#ifndef INFO_H__ +#define INFO_H__ + +#define APP_NAME "VK Player Controller" +#define APP_ABOUT "Use media buttons to switch between tracks." +#define APP_VERSION "0.1" +#define APP_AUTHOR "Eugene Z. <ch1p@ch1p.com>" +#define APP_URL "http://ch1p.com/vkpc/" + +#define SERVER_PORT 52178 +#define SERVER_HOST "localhost" + +#endif diff --git a/desktop/install_icons.sh b/desktop/install_icons.sh new file mode 100755 index 0000000..cbdb4e1 --- /dev/null +++ b/desktop/install_icons.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ICONS_PATH=/usr/share/icons +ICONS=( "Faenza" "Faenza-Radiance" "hicolor" "ubuntu-mono-dark" "ubuntu-mono-light" ) +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root." 1>&2 + exit 1 +fi + +for i in "${ICONS[@]}" +do + if [ -d "${ICONS_PATH}/$i" ]; then + cp -r ${DIR}/icons/$1/* ${ICONS_PATH}/$1 + fi +done diff --git a/desktop/main.c b/desktop/main.c new file mode 100644 index 0000000..8703991 --- /dev/null +++ b/desktop/main.c @@ -0,0 +1,140 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <pthread.h> +#include <gtk/gtk.h> + +#include "info.h" +#include "server.h" +#include "grab.h" + +static GtkStatusIcon *tray_icon; +static GtkWidget *menu; + +enum server_last_cmd_enum server_last_cmd = NONE; +static pthread_t grab_thread; +static pthread_t server_thread; + +pthread_mutex_t server_last_cmd_mutex; + +void tray_icon_on_click(GtkStatusIcon *status_icon, gpointer user_data) { + // left-click +} + +void tray_icon_on_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data) { + // right-click + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, activate_time); +} + +void menu_about(GtkWidget *widget, gpointer data) { + GtkWidget *about_dialog; + + const gchar *authors[] = { + APP_AUTHOR, + NULL + }; + + about_dialog = gtk_about_dialog_new(); + gtk_about_dialog_set_version((GtkAboutDialog *)about_dialog, APP_VERSION); + gtk_about_dialog_set_authors((GtkAboutDialog *)about_dialog, authors); + gtk_about_dialog_set_comments((GtkAboutDialog *)about_dialog, (const gchar *)APP_ABOUT); + gtk_about_dialog_set_name((GtkAboutDialog *)about_dialog, APP_NAME); + gtk_about_dialog_set_website((GtkAboutDialog *)about_dialog, APP_URL); + + g_signal_connect_swapped(about_dialog, "response", G_CALLBACK(gtk_widget_hide), about_dialog); + + gtk_widget_show(about_dialog); +} + +void menu_quit(GtkWidget *widget, gpointer data) { + // quit app + exit(0); +} + +void create_tray_icon() { + tray_icon = gtk_status_icon_new(); + + g_signal_connect(G_OBJECT(tray_icon), "activate", + G_CALLBACK(tray_icon_on_click), NULL); + g_signal_connect(G_OBJECT(tray_icon), "popup-menu", + G_CALLBACK(tray_icon_on_menu), NULL); + + gtk_status_icon_set_from_icon_name(tray_icon, "vkpc"); + gtk_status_icon_set_tooltip(tray_icon, APP_NAME); + gtk_status_icon_set_visible(tray_icon, true); +} + +void create_menu() { + GtkWidget *item; + menu = gtk_menu_new(); + + // About + item = gtk_image_menu_item_new_from_stock(GTK_STOCK_DIALOG_INFO, NULL); + gtk_menu_item_set_label((GtkMenuItem *)item, "About"); + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu_about), NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + + // Quit + item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); + gtk_menu_item_set_label((GtkMenuItem *)item, "Quit"); + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu_quit), NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); +} + +void handle_hotkeys(enum HotkeyEvent e) { + pthread_mutex_lock(&server_last_cmd_mutex); + switch (e) { + case HK_PLAY: + server_last_cmd = PLAY; + break; + + case HK_PAUSE: + server_last_cmd = PAUSE; + break; + + case HK_NEXT: + server_last_cmd = NEXT; + break; + + case HK_PREV: + server_last_cmd = PREV; + break; + + default: + break; + } + pthread_mutex_unlock(&server_last_cmd_mutex); +} + +void start_grab() { + int rc = pthread_create(&grab_thread, NULL, (void *)grab_init, handle_hotkeys); + if (rc) { + fprintf(stderr, "ERROR creating grab_thread, code = %d\n", rc); + exit(-1); + } +} + +void start_server() { + int rc = pthread_create(&server_thread, NULL, (void *)server_init, NULL); + if (rc) { + fprintf(stderr, "ERROR creating server_thread, code = %d\n", rc); + exit(-1); + } +} + +int main(int argc, char **argv) { + pthread_mutex_init(&server_last_cmd_mutex, NULL); + + start_grab(); + start_server(); + + gtk_init(&argc, &argv); + + create_tray_icon(); + create_menu(); + + gtk_main(); + return 0; +} diff --git a/desktop/server.c b/desktop/server.c new file mode 100644 index 0000000..a3c308f --- /dev/null +++ b/desktop/server.c @@ -0,0 +1,182 @@ +/** + * TODO: logging level + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <libwebsockets.h> +#include <stdbool.h> + +#include "server.h" +#include "vector.h" + +#define SERVER_PORT 52178 +#define SERVER_HOST "localhost" + +static struct libwebsocket_context *context; +static char *server_last_cmd_values[] = { + "none", "play", "pause", "next", "prev" +}; + +struct per_session_data { + bool established; + char *next_command; +}; +struct session { + struct per_session_data *pss; + struct libwebsocket *wsi; +}; +vector *sessions; + +static void add_session(struct libwebsocket *wsi, struct per_session_data *pss) { + struct session *s = malloc(sizeof(struct session)); + s->wsi = wsi; + s->pss = pss; + vector_add(sessions, s); +} + +static void delete_session(struct libwebsocket *wsi) { + for (int i = 0; i < vector_count(sessions); i++) { + struct session *s = vector_get(sessions, i); + if (s != NULL && s->wsi == wsi) { + printf("(delete_session) found, i=%d\n", i); + free(s); + vector_delete(sessions, i); + break; + } + } +} + +static void send_command_to_all(char *command) { + printf("Got command: %s\n", command); + for (int i = 0; i < vector_count(sessions); i++) { + struct session *s = (struct session *)vector_get(sessions, i); + s->pss->next_command = command; + libwebsocket_callback_on_writable(context, s->wsi); + } +} + +static int callback_http(struct libwebsocket_context *this, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, + void *in, + size_t len) +{ + switch (reason) { + case LWS_CALLBACK_HTTP: ; + libwebsocket_callback_on_writable(context, wsi); + break; + + case LWS_CALLBACK_HTTP_WRITEABLE: ; + char *response = "vkpc, world!"; + libwebsocket_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP); + return -1; + + default: + break; + } + return 0; +} + +static int callback_signaling(struct libwebsocket_context *this, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, + void *in, + size_t len) +{ + struct per_session_data *pss = (struct per_session_data *)user; + + switch (reason) { + case LWS_CALLBACK_ESTABLISHED: + lwsl_info("Connection established"); + + pss->established = true; + pss->next_command = NULL; + add_session(wsi, pss); + + libwebsocket_callback_on_writable(context, wsi); + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + if (pss->next_command != NULL) { + int length = strlen(pss->next_command); + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + length + LWS_SEND_BUFFER_POST_PADDING]; + unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; + + strcpy((char *)p, pss->next_command); + int m = libwebsocket_write(wsi, p, length, LWS_WRITE_TEXT); + + if (m < length) { + lwsl_err("ERROR while writing %d bytes to socket\n", length); + return -1; + } + + pss->next_command = NULL; + } + break; + + case LWS_CALLBACK_RECEIVE: + lwsl_info("Received: %s, length: %d\n", + (char *)in, (int)strlen((char *)in)); + break; + + case LWS_CALLBACK_CLOSED: + lwsl_info("Connection closed\n"); + delete_session(wsi); + break; + + default: + break; + } + + return 0; +} + +static struct libwebsocket_protocols protocols[] = { + { "http-only", callback_http, 0, 0 }, + { "signaling-protocol", callback_signaling, sizeof(struct per_session_data), 0 }, + { NULL, NULL, 0 } +}; + +void server_init() { + sessions = vector_create(); + + struct lws_context_creation_info info; + memset(&info, 0, sizeof(info)); + + info.port = SERVER_PORT; + info.iface = SERVER_HOST; + info.protocols = protocols; + info.extensions = libwebsocket_get_internal_extensions(); + info.ssl_cert_filepath = NULL; + info.ssl_private_key_filepath = NULL; + info.gid = -1; + info.uid = -1; + info.options = 0; + + context = libwebsocket_create_context(&info); + if (context == NULL) { + fprintf(stderr, "libwebsocket init failed\n"); + return; + } + + enum server_last_cmd_enum last_cmd = NONE; + while (1) { + pthread_mutex_lock(&server_last_cmd_mutex); + last_cmd = server_last_cmd; + server_last_cmd = NONE; + pthread_mutex_unlock(&server_last_cmd_mutex); + + if (last_cmd != NONE) { + send_command_to_all(server_last_cmd_values[last_cmd]); + } + + libwebsocket_service(context, 50); + } + + libwebsocket_context_destroy(context); + return; +} diff --git a/desktop/server.h b/desktop/server.h new file mode 100644 index 0000000..1b7af3f --- /dev/null +++ b/desktop/server.h @@ -0,0 +1,14 @@ +#include <pthread.h> + +#ifndef SERVER_H__ +#define SERVER_H__ + +enum server_last_cmd_enum { + NONE = 0, PLAY, PAUSE, NEXT, PREV +}; +extern enum server_last_cmd_enum server_last_cmd; +extern pthread_mutex_t server_last_cmd_mutex; + +void server_init(); + +#endif diff --git a/desktop/vector.c b/desktop/vector.c new file mode 100644 index 0000000..16b8804 --- /dev/null +++ b/desktop/vector.c @@ -0,0 +1,74 @@ +/** + * Based on https://gist.github.com/EmilHernvall/953968 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vector.h" + +vector * vector_create() { + vector *v; + v = malloc(sizeof(vector)); + + v->data = NULL; + v->size = 0; + v->count = 0; + + return v; +} + +int vector_count(vector *v) { + return v->count; +} + +void vector_add(vector *v, void *e) { + if (v->size == 0) { + v->size = 10; + v->data = malloc(sizeof(void *) * v->size); + memset(v->data, '\0', sizeof(void *) * v->size); + } + + if (v->size == v->count) { + v->size += 10; + v->data = realloc(v->data, sizeof(void *) * v->size); + } + + v->data[v->count++] = e; +} + +void vector_set(vector *v, int index, void *e) { + if (index >= v->count) { + return; + } + + v->data[index] = e; +} + +void * vector_get(vector *v, int index) { + if (index >= v->count) { + return NULL; + } + + return v->data[index]; +} + +void vector_delete(vector *v, int index) { + if (index >= v->count) { + return; + } + + for (int i = index+1; i < v->count; i++) { + v->data[i-1] = v->data[i]; + } + + v->data[--v->count] = NULL; +} + +void vector_free_data(vector *v) { + free(v->data); +} + +void vector_free(vector *v) { + free(v); +} diff --git a/desktop/vector.h b/desktop/vector.h new file mode 100644 index 0000000..c9e9c98 --- /dev/null +++ b/desktop/vector.h @@ -0,0 +1,23 @@ +/** + * Based on https://gist.github.com/EmilHernvall/953968 + */ + +#ifndef VECTOR_H__ +#define VECTOR_H__ + +typedef struct vector_ { + void **data; + int size; + int count; +} vector; + +vector * vector_create(); +int vector_count(vector *); +void vector_add(vector *, void *); +void vector_set(vector *, int, void *); +void *vector_get(vector *, int); +void vector_delete(vector*, int); +void vector_free_data(vector *); +void vector_free(vector *); + +#endif |