From 49e9e4a55613bc94c39d4ce98018a8fc4962893c Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Thu, 29 Jul 2021 13:04:59 +0900 Subject: [PATCH] toastd: initial prototype --- apps/toastd.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 apps/toastd.c diff --git a/apps/toastd.c b/apps/toastd.c new file mode 100644 index 00000000..6eb0173f --- /dev/null +++ b/apps/toastd.c @@ -0,0 +1,108 @@ +/** + * @brief Toast notification daemon. + * @file apps/toastd.c + * + * Provides an endpoint for applications to post notifications + * which are displayed in pop-up "toasts" in the upper-right + * corner of the screen without stealing focus. + * + * @copyright 2021 K. Lange + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static yutani_t * yctx; +static FILE * pex_endpoint = NULL; +static sprite_t background_sprite; + +#define PAD_RIGHT 10 +#define PAD_TOP 48 + +int main(int argc, char * argv[]) { + /* Make sure we were actually expecting to be run... */ + if (argc < 2 || strcmp(argv[1],"--really")) { + fprintf(stderr, + "%s: Toast notification daemon\n" + "\n" + " Displays popup notifications from other\n" + " applications in the corner of the screen.\n" + " You probably don't want to run this directly - it is\n" + " started automatically by the session manager.\n", argv[0]); + return 1; + } + /* Daemonize... */ + if (!fork()) { + /* Connect to display server... */ + yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: Failed to connect to compositor.\n", argv[0]); + } + /* Open pex endpoint to receive notifications... */ + pex_endpoint = pex_bind("toast"); + if (!pex_endpoint) { + fprintf(stderr, "%s: Failed to establish socket.\n", argv[0]); + } + /* Set up our text rendering and sprite contexts... */ + markup_text_init(); + load_sprite(&background_sprite, "/usr/share/ttk/toast/default.png"); + /* Make a test window? */ + yutani_window_t * wina = yutani_window_create_flags(yctx, background_sprite.width, background_sprite.height, YUTANI_WINDOW_FLAG_NO_STEAL_FOCUS | YUTANI_WINDOW_FLAG_ALT_ANIMATION); + yutani_window_move(yctx, wina, yctx->display_width - background_sprite.width - PAD_RIGHT, PAD_TOP); /* We need to be able to query the panel location... */ + gfx_context_t * ctx = init_graphics_yutani_double_buffer(wina); + draw_fill(ctx, rgba(0,0,0,0)); + draw_sprite(ctx, &background_sprite, 0, 0); + /* Wait for messages from pex, or from compositor... */ + markup_draw_string(ctx,10,26,"

Welcome!


This is a sample toast notification.",rgb(255,255,255)); + flip(ctx); + yutani_flip(yctx, wina); + + int should_exit = 0; + while (!should_exit) { + int fds[1] = {fileno(yctx->sock)}; + int index = fswait2(1,fds,20); + if (index == 0) { + yutani_msg_t * m = yutani_poll(yctx); + while (m) { + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { + should_exit = 1; + sched_yield(); + } + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { + yutani_window_drag_start(yctx, wina); + } + } + break; + case YUTANI_MSG_WINDOW_CLOSE: + case YUTANI_MSG_SESSION_END: + should_exit = 1; + break; + default: + break; + } + free(m); + m = yutani_poll_async(yctx); + } + } + } + + yutani_close(yctx, wina); + } + return 0; +}