#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
uint32_t listenaddr = 0;
short srvport = 9302;
uint32_t *allowedaddr = NULL;
size_t numallowedaddr = 0;
int srvloop = 1;
Display *dp;
typedef struct Client {
int fd;
struct sockaddr_in addr;
} Client;
#define XPROP_MAX_LENGTH 4096/4
int get_desktop() {
Atom curdesktop = XInternAtom(dp, "_NET_CURRENT_DESKTOP", False);
Atom type;
int format;
unsigned long nitems;
unsigned long size;
unsigned long bytes_after;
unsigned char *value;
if(XGetWindowProperty(dp, DefaultRootWindow(dp), curdesktop, 0, XPROP_MAX_LENGTH, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &value) != Success) {
return 0;
}
int *desktop = (int*)value;
return *desktop;
}
void switch_desktop(int desktop) {
XEvent event;
event.xclient.type = ClientMessage;
event.xclient.serial = 0;
event.xclient.send_event = True;
event.xclient.message_type = XInternAtom(dp, "_NET_CURRENT_DESKTOP", False);
event.xclient.window = DefaultRootWindow(dp);
event.xclient.format = 32;
event.xclient.data.l[0] = desktop;
if(!XSendEvent(dp, DefaultRootWindow(dp), False, SubstructureRedirectMask | SubstructureNotifyMask, &event)) {
fprintf(stderr, "XSendEvent failed\n");
}
}
int load_config() {
return 0;
}
int create_server_socket(uint32_t addr, short port) {
int ssock = -1;
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(addr);
servaddr.sin_port = htons(port);
if((ssock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return -1;
}
int o = 1;
setsockopt(
ssock,
SOL_SOCKET, SO_REUSEADDR,
&o,
sizeof(int));
if(bind(ssock, (struct sockaddr*)&servaddr, sizeof(servaddr))) {
perror("bind");
return -1;
}
return ssock;
}
void* client_thread(void *data) {
Client *client = data;
FILE *stream = fdopen(client->fd, "r");
char *line = NULL;
size_t len = 0;
ssize_t n;
while((n = getline(&line, &len, stream)) > 0) {
if(line[n-1] == '\n') {
line[n-1] = '\0';
}
int desktop = get_desktop();
if(!strcmp(line, "up")) {
printf("up\n");
switch_desktop(desktop - 1);
} else if(!strcmp(line, "down")) {
printf("down\n");
switch_desktop(desktop + 1);
} else if(!strcmp(line, "left")) {
printf("left\n");
switch_desktop(desktop - 1);
} else if(!strcmp(line, "right")) {
printf("right\n");
switch_desktop(desktop + 1);
} else {
int desktop = atoi(line);
printf("desktop: %d\n", desktop);
switch_desktop(desktop);
}
XFlush(dp);
}
fclose(stream);
free(client);
XFlush(dp);
return NULL;
}
int main(int argc, char** argv) {
if(load_config()) {
fprintf(stderr, "Cannot load config\n");
return 1;
}
dp = XOpenDisplay(NULL);
if(!dp) {
fprintf(stderr, "Cannot open X Display\n");
return 1;
}
int ssock = create_server_socket(listenaddr, srvport);
if(ssock < 0) {
return 1;
}
if(listen(ssock, 16)) {
perror("listen");
}
while(srvloop) {
struct sockaddr_in ca;
socklen_t length = sizeof(ca);
int clientfd;
clientfd = accept(
ssock,
(struct sockaddr*)&ca,
&length);
if (clientfd == -1) {
perror("accept");
break;
}
Client *client = malloc(sizeof(Client));
client->fd = clientfd;
client->addr = ca;
pthread_t t;
if(pthread_create(&t, NULL, client_thread, client)) {
perror("pthread_create");
close(clientfd);
free(client);
}
pthread_detach(t);
}
close(ssock);
return 0;
}