toastd: Finish things up, I guess.
This commit is contained in:
parent
6006ab975e
commit
f0de4abfb8
178
apps/toastd.c
178
apps/toastd.c
@ -13,19 +13,96 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <time.h>
|
||||
#include <sys/fswait.h>
|
||||
#include <toaru/pex.h>
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/markup_text.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/json.h>
|
||||
#include <toaru/list.h>
|
||||
|
||||
typedef struct JSON_Value JSON_Value;
|
||||
|
||||
static yutani_t * yctx;
|
||||
static FILE * pex_endpoint = NULL;
|
||||
static sprite_t background_sprite;
|
||||
static list_t * windows = NULL;
|
||||
static list_t * garbage = NULL;
|
||||
|
||||
struct ToastNotification {
|
||||
yutani_window_t * window;
|
||||
struct timespec created;
|
||||
int duration;
|
||||
};
|
||||
|
||||
#define PAD_RIGHT 10
|
||||
#define PAD_TOP 48
|
||||
|
||||
static void handle_msg(JSON_Value * msg) {
|
||||
if (msg->type != JSON_TYPE_OBJECT) {
|
||||
fprintf(stderr, "expected an object, but json value was of type %d\n", msg->type);
|
||||
return;
|
||||
}
|
||||
|
||||
JSON_Value * msg_body = JSON_KEY(msg, "body");
|
||||
|
||||
if (!msg_body) {
|
||||
fprintf(stderr, "missing 'body'\n");
|
||||
return;
|
||||
}
|
||||
if (msg_body->type != JSON_TYPE_STRING) {
|
||||
fprintf(stderr, "'body' should have been a string, but got type %d instead\n", msg_body->type);
|
||||
return;
|
||||
}
|
||||
|
||||
/* At this point, we're going to show something, at least... */
|
||||
yutani_window_t * win = yutani_window_create_flags(yctx,
|
||||
background_sprite.width,
|
||||
background_sprite.height,
|
||||
YUTANI_WINDOW_FLAG_NO_STEAL_FOCUS | YUTANI_WINDOW_FLAG_ALT_ANIMATION);
|
||||
|
||||
/* TODO: We need to figure out how to place this... */
|
||||
yutani_window_move(yctx, win, yctx->display_width - background_sprite.width - PAD_RIGHT, PAD_TOP + background_sprite.height * windows->length);
|
||||
|
||||
struct ToastNotification * notification = malloc(sizeof(struct ToastNotification));
|
||||
notification->window = win;
|
||||
clock_gettime(CLOCK_MONOTONIC, ¬ification->created);
|
||||
list_insert(windows, notification);
|
||||
|
||||
JSON_Value * msg_duration = JSON_KEY(msg,"duration");
|
||||
if (msg_duration && msg_duration->type == JSON_TYPE_NUMBER) {
|
||||
notification->duration = msg_duration->number;
|
||||
} else {
|
||||
notification->duration = 5;
|
||||
}
|
||||
|
||||
/* Establish the rendering context for this window, we'll only need it for a bit.
|
||||
* We won't even both double buffering... */
|
||||
gfx_context_t * ctx = init_graphics_yutani(win);
|
||||
draw_fill(ctx, rgba(0,0,0,0));
|
||||
draw_sprite(ctx, &background_sprite, 0, 0);
|
||||
int textOffset = 0;
|
||||
|
||||
/* Does it have an icon? */
|
||||
JSON_Value * msg_icon = JSON_KEY(msg, "icon");
|
||||
if (msg_icon && msg_icon->type == JSON_TYPE_STRING) {
|
||||
/* Just ignore the icon if it's not a string... */
|
||||
sprite_t myIcon;
|
||||
if (!load_sprite(&myIcon, msg_icon->string)) {
|
||||
/* Is this a reasonable icon to display? */
|
||||
if (myIcon.width < 100) {
|
||||
textOffset = myIcon.width + 4; /* Sounds like a fine padding... */
|
||||
draw_sprite(ctx, &myIcon, 10, (background_sprite.height - myIcon.height) / 2);
|
||||
}
|
||||
free(myIcon.bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
markup_draw_string(ctx, 10 + textOffset, 26, msg_body->string, rgb(255,255,255));
|
||||
yutani_flip(yctx, win);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
/* Make sure we were actually expecting to be run... */
|
||||
if (argc < 2 || strcmp(argv[1],"--really")) {
|
||||
@ -53,43 +130,17 @@ int main(int argc, char * argv[]) {
|
||||
/* 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,"<b><h1>Welcome!</h1></b><br>This is a sample <i>toast</i> notification.",rgb(255,255,255));
|
||||
flip(ctx);
|
||||
yutani_flip(yctx, wina);
|
||||
windows = list_create();
|
||||
garbage = list_create();
|
||||
|
||||
int should_exit = 0;
|
||||
while (!should_exit) {
|
||||
int fds[1] = {fileno(yctx->sock)};
|
||||
int index = fswait2(1,fds,20);
|
||||
int fds[2] = {fileno(yctx->sock),fileno(pex_endpoint)};
|
||||
int index = fswait2(2,fds,windows->length ? 20 : -1);
|
||||
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;
|
||||
@ -99,10 +150,73 @@ int main(int argc, char * argv[]) {
|
||||
free(m);
|
||||
m = yutani_poll_async(yctx);
|
||||
}
|
||||
} else if (index == 1) {
|
||||
pex_packet_t * p = calloc(PACKET_SIZE, 1);
|
||||
pex_listen(pex_endpoint, p);
|
||||
|
||||
JSON_Value * msg = json_parse((char*)p->data);
|
||||
|
||||
if (msg) {
|
||||
handle_msg(msg);
|
||||
json_free(msg);
|
||||
}
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
if (windows->length) {
|
||||
/* Check all the existing toasts for expired ones... */
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
foreach(node, windows) {
|
||||
struct ToastNotification * notification = node->value;
|
||||
|
||||
/* How long has it been since this notification was created? */
|
||||
struct timespec diff;
|
||||
diff.tv_sec = now.tv_sec - notification->created.tv_sec;
|
||||
diff.tv_nsec = now.tv_nsec - notification->created.tv_nsec;
|
||||
if (diff.tv_nsec < 0) { diff.tv_sec--; diff.tv_nsec += 1000000000L; }
|
||||
|
||||
if (diff.tv_sec >= notification->duration) {
|
||||
if (notification->window) {
|
||||
yutani_close(yctx, notification->window);
|
||||
notification->window = NULL;
|
||||
}
|
||||
if (diff.tv_sec >= notification->duration + 1) {
|
||||
list_insert(garbage, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Expunge garbage */
|
||||
if (garbage->length) {
|
||||
while (garbage->length) {
|
||||
node_t * n = list_pop(garbage);
|
||||
node_t * node = n->value;
|
||||
free(n);
|
||||
list_delete(windows, node);
|
||||
free(node->value);
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Figure out if we need to move anything */
|
||||
if (index == 2) {
|
||||
int index = 0;
|
||||
foreach(node, windows) {
|
||||
struct ToastNotification * notification = node->value;
|
||||
if (notification->window && notification->window->y > PAD_TOP + background_sprite.height * index) {
|
||||
yutani_window_move(yctx, notification->window, notification->window->x, notification->window->y - 4);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yutani_close(yctx, wina);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
if stat -Lq /usr/share/fonts/DejaVuSansMono.ttf then export FREETYPE_PROPERTIES="truetype:interpreter-version=35"
|
||||
cd ~/Desktop
|
||||
file-browser --wallpaper &
|
||||
toastd --really # Daemonizes
|
||||
cd ~
|
||||
tutorial &
|
||||
exec panel --really
|
||||
|
Loading…
Reference in New Issue
Block a user