mowc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/mowc
Log | Files | Refs

dialer.c (12321B)


      1 #include <poll.h>
      2 #include <signal.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <sys/socket.h>
      7 #include <sys/un.h>
      8 #include <unistd.h>
      9 #include <wld/wayland.h>
     10 #include <wld/wld.h>
     11 #include <wayland-client.h>
     12 #include <xdg-shell-client-protocol.h>
     13 #include <text-input-unstable-v3-client-protocol.h>
     14 #include <atd.h>
     15 #include <encdec.h>
     16 
     17 #include "drw.h"
     18 #include "util.h"
     19 
     20 #define LENGTH(x)		 (sizeof x / sizeof x[0])
     21 #define STRINGTOKEYSYM(X) (XStringToxkb_keysym_t(X))
     22 #define TEXTW(X)		  (drw_fontset_getwidth(drw, (X)))
     23 
     24 enum {
     25 	SchemeNormal,
     26 	SchemeSetting,
     27 	SchemeSettingDown,
     28 	SchemeHangup,
     29 	SchemeHangupDown,
     30 	SchemeLast
     31 };
     32 
     33 enum button {
     34 	ButtonNone,
     35 	ButtonCall,
     36 	ButtonClear,
     37 };
     38 
     39 static const char *colors[SchemeLast][2] = {
     40 	/*     fg         bg       */
     41 	[SchemeNormal] = { "#ffffff", "#2222cc" },
     42 	[SchemeSetting] = { "#ffffff", "#22cc22" },
     43 	[SchemeHangup] = { "#ffffff", "#cc2222" },
     44 	[SchemeSettingDown] = { "#ffffff", "#008800" },
     45 	[SchemeHangupDown] = { "#ffffff", "#880000" },
     46 };
     47 
     48 #include "config.h"
     49 
     50 static Clr* scheme[SchemeLast];
     51 
     52 struct {
     53 	struct wl_display *dpy;
     54 	struct wl_compositor *cmp;
     55 	struct wl_seat *seat;
     56 	struct wl_touch *touch;
     57 	struct wl_surface *surface;
     58 	struct xdg_wm_base *wm;
     59 	struct xdg_surface *xdgsurface;
     60 	struct xdg_toplevel *toplevel;
     61 	struct zwp_text_input_manager_v3 *timanager;
     62 	struct zwp_text_input_v3 *textinput;
     63 	char number[PHONE_NUMBER_MAX_LEN + 1];
     64 	struct {
     65 		char commitbuf[4000];
     66 		uint32_t delbefore;
     67 		uint32_t delafter;
     68 	} tipending;
     69 	uint32_t textserial;
     70 
     71 	Drw *drw;
     72 
     73 	int32_t w, h;
     74 } wl;
     75 
     76 unsigned int tw, th;
     77 enum button pressed, current;
     78 
     79 int sock;
     80 struct pollfd fds[2];
     81 
     82 static void wmping(void *data, struct xdg_wm_base *wm, uint32_t serial);
     83 static void xdgsurfconfigure(void *data, struct xdg_surface *surf, uint32_t serial);
     84 static void toplevelconfigure(void *data, struct xdg_toplevel *toplevel, int32_t w, int32_t h, struct wl_array *states);
     85 static void toplevelclose(void *data, struct xdg_toplevel *toplevel);
     86 static void regglobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version);
     87 static void regglobalremove(void *data, struct wl_registry *registry, uint32_t name);
     88 static void draw(void);
     89 static void touchdown(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y);
     90 static void touchup(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id);
     91 static void touchmotion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y);
     92 static void touchframe(void *data, struct wl_touch *wl_touch);
     93 static void touchcancel(void *data, struct wl_touch *wl_touch);
     94 static void tienter(void *data, struct zwp_text_input_v3 *text_input, struct wl_surface *surface);
     95 static void tileave(void *data, struct zwp_text_input_v3 *text_input, struct wl_surface *surface);
     96 static void tipreedit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, const char *text, int32_t cursor_begin, int32_t cursor_end);
     97 static void ticommit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, const char *text);
     98 static void tidelete_surrounding_text(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t before_length, uint32_t after_length);
     99 static void tidone(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t serial);
    100 
    101 
    102 static struct wl_registry_listener reglistener = { regglobal, regglobalremove };
    103 
    104 static struct xdg_wm_base_listener wmlistener = { wmping };
    105 static struct xdg_surface_listener xdgsurflistener = { xdgsurfconfigure };
    106 static struct xdg_toplevel_listener toplevellistener =
    107 	{ toplevelconfigure, toplevelclose };
    108 static struct wl_touch_listener touchlistener =
    109 	{ touchdown, touchup, touchmotion, touchframe, touchcancel };
    110 static struct zwp_text_input_v3_listener tilistener = {
    111 	.enter = tienter,
    112 	.leave = tileave,
    113 	.preedit_string = tipreedit_string,
    114 	.commit_string = ticommit_string,
    115 	.delete_surrounding_text = tidelete_surrounding_text,
    116 	.done = tidone
    117 };
    118 
    119 
    120 void
    121 wmping(void *data, struct xdg_wm_base *wm, uint32_t serial)
    122 {
    123 	xdg_wm_base_pong(wm, serial);
    124 }
    125 
    126 void
    127 xdgsurfconfigure(void *data, struct xdg_surface *surf, uint32_t serial)
    128 {
    129 	xdg_surface_ack_configure(surf, serial);
    130 }
    131 
    132 void
    133 toplevelconfigure(void *data, struct xdg_toplevel *toplevel, int32_t w, int32_t h,
    134                   struct wl_array *states)
    135 {
    136 	if (w == wl.w && h == wl.h)
    137 		return;
    138 	if (w == 0 && h == 0)
    139 		return;
    140 
    141 	wl.w = w;
    142 	wl.h = h;
    143 }
    144 
    145 void
    146 toplevelclose(void *data, struct xdg_toplevel *toplevel)
    147 {
    148 	exit(0);
    149 }
    150 
    151 void
    152 regglobal(void *data, struct wl_registry *registry, uint32_t name,
    153           const char *interface, uint32_t version)
    154 {
    155 	if (strcmp(interface, "wl_compositor") == 0) {
    156 		wl.cmp = wl_registry_bind(registry, name,
    157 				&wl_compositor_interface, 3);
    158 	} else if (strcmp(interface, "xdg_wm_base") == 0) {
    159 		wl.wm = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
    160 		xdg_wm_base_add_listener(wl.wm, &wmlistener, NULL);
    161 	} else if (strcmp(interface, "wl_seat") == 0) {
    162 		wl.seat = wl_registry_bind(registry, name,
    163 				&wl_seat_interface, 4);
    164 	} else if (strcmp(interface, "zwp_text_input_manager_v3") == 0) {
    165 		wl.timanager = wl_registry_bind(registry, name, &zwp_text_input_manager_v3_interface, 1);
    166 	}
    167 }
    168 
    169 void
    170 regglobalremove(void *data, struct wl_registry *registry, uint32_t name)
    171 {
    172 }
    173 
    174 struct {
    175 	bool down;
    176 	uint32_t x, y;
    177 	int32_t id;
    178 } touchpoint;
    179 
    180 static enum button
    181 getpressed()
    182 {
    183 	if (touchpoint.x < wl.w / 2 && touchpoint.y > 3 * wl.h / 8 && touchpoint.y < wl.h / 2) {
    184 		return ButtonCall;
    185 	} else if (touchpoint.x > wl.w / 2 && touchpoint.y > 3 * wl.h / 8 && touchpoint.y < wl.h / 2) {
    186 		return ButtonClear;
    187 	}
    188 
    189 	return ButtonNone;
    190 }
    191 
    192 void
    193 touchdown(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y)
    194 {
    195 	if (touchpoint.down)
    196 		return;
    197 
    198 	touchpoint.down = true;
    199 	touchpoint.x = wl_fixed_to_int(x);
    200 	touchpoint.y = wl_fixed_to_int(y);
    201 	touchpoint.id = id;
    202 	current = pressed = getpressed();
    203 	draw();
    204 }
    205 
    206 int switchinput() {
    207 }
    208 
    209 void
    210 touchup(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id)
    211 {
    212 	if (touchpoint.id != id)
    213 		return;
    214 
    215 	touchpoint.down = false;
    216 
    217 	if (pressed == current) {
    218 		switch (pressed) {
    219 		case ButtonCall:
    220 			fprintf(stderr, "ButtonCall\n");
    221 			break;
    222 		case ButtonClear:
    223 			fprintf(stderr, "ButtonClear\n");
    224 			break;
    225 		}
    226 	}
    227 
    228 	current = pressed = ButtonNone;
    229 	draw();
    230 }
    231 
    232 void
    233 touchmotion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
    234 {
    235 	if (touchpoint.id != id)
    236 		return;
    237 
    238 	touchpoint.x = wl_fixed_to_int(x);
    239 	touchpoint.y = wl_fixed_to_int(y);
    240 	current = getpressed();
    241 	draw();
    242 }
    243 
    244 void
    245 touchframe(void *data, struct wl_touch *wl_touch)
    246 {
    247 }
    248 
    249 void touchcancel(void *data, struct wl_touch *wl_touch)
    250 {
    251 	touchpoint.down = false;
    252 }
    253 void
    254 tienter(void *data, struct zwp_text_input_v3 *text_input, struct wl_surface *surface)
    255 {
    256 	fprintf(stderr, "tienter\n");
    257 	zwp_text_input_v3_enable(text_input);
    258 	zwp_text_input_v3_set_content_type(text_input, ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE);
    259 	wl.textserial++;
    260 	zwp_text_input_v3_commit(text_input);
    261 }
    262 
    263 void
    264 tileave(void *data, struct zwp_text_input_v3 *text_input, struct wl_surface *surface)
    265 {
    266 	zwp_text_input_v3_disable(text_input);
    267 }
    268 
    269 void
    270 tipreedit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, const char *text, int32_t cursor_begin, int32_t cursor_end)
    271 {
    272 }
    273 
    274 void
    275 ticommit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, const char *text)
    276 {
    277 	fprintf(stderr, "TICOMMIT_STRING\n");
    278     strcpy(wl.tipending.commitbuf, text);
    279 }
    280 
    281 void
    282 tidelete_surrounding_text(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t before_length, uint32_t after_length)
    283 {
    284     wl.tipending.delbefore = before_length;
    285     wl.tipending.delafter = after_length;
    286 }
    287 
    288 void
    289 tidone(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t serial)
    290 {
    291 	fprintf(stderr, "TIDONE\n");
    292 	if (serial != wl.textserial)
    293 		return;
    294 
    295 	/* 2. Delete requested surrounding text */
    296 	size_t len = strlen(wl.number);
    297 	if (len > wl.tipending.delbefore)
    298 		wl.number[len - wl.tipending.delbefore] = 0;
    299 	else
    300 		wl.number[0] = 0;
    301 
    302 	/* 3. Insert commit string with the cursor at its end */
    303 	char *next = wl.tipending.commitbuf;
    304 	for (int i = 0; i < PHONE_NUMBER_MAX_LEN - len && *next != '\0'; i++, next++) {
    305 		/* we only accept characters that are valid in a phone number */
    306 		if (strchr(DIALING_DIGITS, *next) != NULL) {
    307 			wl.number[len+i] = *next;
    308 			wl.number[len+i+1] = '\0';
    309 		} else if (*next == '\n') {
    310 			atd_cmd_dial(fds[1].fd, wl.number);
    311 			fds[1].events = POLLIN;
    312 		}
    313 	}
    314 
    315 	fprintf(stderr, "number: %s\n", wl.number);
    316 
    317 	zwp_text_input_v3_commit(wl.textinput);
    318 	wl.textserial++;
    319 	wl.tipending.delbefore = 0;
    320 	wl.tipending.delafter = 0;
    321 	wl.tipending.commitbuf[0] = 0;
    322 
    323 	draw();
    324 }
    325 
    326 void
    327 draw()
    328 {
    329 	int height = wl.h / 8;
    330 	wld_set_target_surface(wl.drw->renderer, wl.drw->surface);
    331 
    332 	drw_setscheme(wl.drw, scheme[SchemeNormal]);
    333 	drw_rect(wl.drw, 0, 0, wl.w, wl.h - height, 1, 1);
    334 	drw_setfontset(wl.drw, &wl.drw->fonts[0]);
    335 	drw_font_getexts(&wl.drw->fonts[0], wl.number, strlen(wl.number), &tw, &th);
    336 	drw_text(wl.drw, wl.w / 2 - tw / 2, height, tw, th, 0, wl.number, 0);
    337 
    338 	drw_map(wl.drw, wl.surface, 0, 0, wl.w, wl.h);
    339 }
    340 
    341 void
    342 wlinit(void)
    343 {
    344 	struct wl_registry *registry;
    345 	int j;
    346 
    347 	wl.w = wl.h = 500;
    348 
    349 	if (!(wl.dpy = wl_display_connect(NULL)))
    350 		die("Can't open display\n");
    351 
    352 	registry = wl_display_get_registry(wl.dpy);
    353 	wl_registry_add_listener(registry, &reglistener, NULL);
    354 
    355 	wl_display_roundtrip(wl.dpy);
    356 
    357 	wl.drw = drw_create(wl.dpy);
    358 
    359 	if (!wl.seat)
    360 		die("Display has no seat\n");
    361 	if (!wl.wm)
    362 		die("Display has no window manager\n");
    363 	if (!wl.timanager)
    364 		die("Display has no text input manager\n");
    365 
    366 	if (!drw_fontset_create(wl.drw, (const char **) fonts, LENGTH(fonts)))
    367 		die("no fonts could be loaded");
    368 
    369 	wl.touch = wl_seat_get_touch(wl.seat);
    370 	wl_touch_add_listener(wl.touch, &touchlistener, NULL);
    371 	wl.textinput = zwp_text_input_manager_v3_get_text_input(wl.timanager, wl.seat);
    372 	zwp_text_input_v3_add_listener(wl.textinput, &tilistener, NULL);
    373 
    374 	wl_display_roundtrip(wl.dpy);
    375 
    376 	if (!wl.touch)
    377 		die("seat has no touch support\n");
    378 
    379 	/* init appearance */
    380 	for (j = 0; j < SchemeLast; j++)
    381 		scheme[j] = drw_scm_create(wl.drw, (const char **) colors[j], 2);
    382 
    383 	wl.surface = wl_compositor_create_surface(wl.cmp);
    384 	wl.xdgsurface = xdg_wm_base_get_xdg_surface(wl.wm, wl.surface);
    385 	xdg_surface_add_listener(wl.xdgsurface, &xdgsurflistener, NULL);
    386 	wl.toplevel = xdg_surface_get_toplevel(wl.xdgsurface);
    387 	xdg_toplevel_add_listener(wl.toplevel, &toplevellistener, NULL);
    388 	xdg_toplevel_set_app_id(wl.toplevel, "answer");
    389 
    390 	wl_display_roundtrip(wl.dpy);
    391 
    392 	if (wl.w == 0 || wl.h == 0) {
    393 		die("window has 0 dimension\n");
    394 	}
    395 
    396 	drw_resize(wl.drw, wl.surface, wl.w, wl.h);
    397 	draw();
    398 	wl_display_roundtrip(wl.dpy);
    399 }
    400 
    401 int
    402 main(int argc, char *argv[])
    403 {
    404     struct sockaddr_un addr = {
    405         .sun_family = AF_UNIX,
    406         .sun_path = "/tmp/atd-socket"
    407     };
    408 
    409     char status = 0;
    410     ssize_t ret;
    411 
    412     sock = socket(AF_UNIX, SOCK_STREAM, 0);
    413     if (sock == -1) {
    414         fprintf(stderr, "failed to open socket\n");
    415         return 1;
    416     }
    417 
    418     int con = connect(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
    419     if (con == -1) {
    420         fprintf(stderr, "failed to connect\n");
    421         close(sock);
    422         return 1;
    423     }
    424 
    425 	wlinit();
    426 
    427 	fds[0].fd = wl_display_get_fd(wl.dpy);
    428 	fds[0].events = POLLIN;
    429 	fds[1].fd = sock;
    430 	fds[1].events = 0;
    431 	while (true) {
    432 		if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) {
    433 			warn("poll failed\n");
    434 			break;
    435 		}
    436 
    437 		if (fds[0].revents & POLLIN) {
    438 			if (wl_display_dispatch(wl.dpy) == -1) {
    439 				warn("Wayland dispatch failed\n");
    440 				break;
    441 			}
    442 		}
    443 
    444 		if (fds[1].revents & POLLIN) {
    445 			ret = read(fds[1].fd, &status, 1);
    446 			if (ret == -1) {
    447 				warn("failed to read from atd\n");
    448 				break;
    449 			}
    450 
    451 			if (ret == 1) {
    452 				switch (status) {
    453 				case STATUS_OK:
    454 					exit(0);
    455 				case STATUS_ERROR:
    456 					warn("failed to dial number\n");
    457 				}
    458 			}
    459 		}
    460 
    461 		wl_display_flush(wl.dpy);
    462 	}
    463 
    464 	close(fds[1].fd);
    465 	return 1;
    466 }