toaruos/userspace/gui/core/panel.c

341 lines
6.9 KiB
C
Raw Normal View History

2012-03-15 00:04:12 +04:00
/* vim: tabstop=4 shiftwidth=4 noexpandtab
*
* Panel
*
* Provides a graphical panel with a clock, and
* hopefully more things in the future.
2012-03-15 00:04:12 +04:00
*/
2012-03-08 09:44:02 +04:00
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <time.h>
2013-05-03 10:33:57 +04:00
#include <unistd.h>
#include <sys/time.h>
#include <sys/utsname.h>
2012-03-08 09:44:02 +04:00
#define PANEL_HEIGHT 28
2014-04-16 06:45:56 +04:00
#include "lib/pthread.h"
#include "lib/yutani.h"
2012-03-08 09:44:02 +04:00
#include "lib/graphics.h"
#include "lib/shmemfonts.h"
2012-03-08 09:44:02 +04:00
sprite_t * sprites[128];
sprite_t alpha_tmp;
gfx_context_t * ctx;
2014-04-16 06:45:56 +04:00
yutani_t * yctx;
yutani_window_t * panel;
list_t * window_list;
volatile int lock = 0;
volatile int drawlock = 0;
size_t bg_size;
char * bg_blob;
2014-04-16 06:45:56 +04:00
int width;
int height;
2012-03-08 09:44:02 +04:00
int center_x(int x) {
2014-04-16 06:45:56 +04:00
return (width - x) / 2;
2012-03-08 09:44:02 +04:00
}
int center_y(int y) {
2014-04-16 06:45:56 +04:00
return (height - y) / 2;
2012-03-08 09:44:02 +04:00
}
static void spin_lock(int volatile * lock) {
while(__sync_lock_test_and_set(lock, 0x01)) {
syscall_yield();
}
}
static void spin_unlock(int volatile * lock) {
__sync_lock_release(lock);
}
2012-03-08 09:44:02 +04:00
void init_sprite(int i, char * filename, char * alpha) {
sprites[i] = malloc(sizeof(sprite_t));
load_sprite(sprites[i], filename);
if (alpha) {
sprites[i]->alpha = 1;
load_sprite(&alpha_tmp, alpha);
sprites[i]->masks = alpha_tmp.bitmap;
} else {
sprites[i]->alpha = ALPHA_OPAQUE;
2012-03-08 09:44:02 +04:00
}
}
2012-09-20 08:16:21 +04:00
void init_sprite_png(int i, char * filename) {
sprites[i] = malloc(sizeof(sprite_t));
load_sprite_png(sprites[i], filename);
}
2014-04-20 12:24:10 +04:00
void redraw(void);
2012-03-08 09:44:02 +04:00
#define FONT_SIZE 14
2013-05-03 10:33:57 +04:00
#define TIME_LEFT 108
#define DATE_WIDTH 70
2012-03-08 09:44:02 +04:00
volatile int _continue = 1;
2014-04-20 12:24:10 +04:00
/* honestly no way we're gonna fit more at the moment... */
int icon_lefts[20] = {0};
int icon_wids[20] = {0};
int focused_app = -1;
2014-05-03 23:22:16 +04:00
struct window_ad {
uint32_t flags;
char * name;
char * icon;
char * strings;
};
void sig_int(int sig) {
printf("Received shutdown signal in panel!\n");
_continue = 0;
}
2014-04-20 12:24:10 +04:00
void set_focused(int i) {
if (focused_app != i) {
focused_app = i;
redraw();
}
}
void panel_check_click(struct yutani_msg_window_mouse_event * evt) {
if (evt->command == YUTANI_MOUSE_EVENT_CLICK) {
2012-09-20 08:16:21 +04:00
printf("Click!\n");
2014-04-16 06:45:56 +04:00
if (evt->new_x >= width - 24 ) {
yutani_session_end(yctx);
2012-09-20 08:16:21 +04:00
_continue = 0;
2014-04-20 12:24:10 +04:00
} else {
for (int i = 0; i < 18; ++i) {
if (evt->new_x >= icon_lefts[i] && evt->new_x < icon_lefts[i+1]) {
if (icon_wids[i]) {
yutani_focus_window(yctx, icon_wids[i]);
}
break;
}
}
}
} else if (evt->command == YUTANI_MOUSE_EVENT_MOVE || evt->command == YUTANI_MOUSE_EVENT_ENTER) {
2014-04-20 12:24:10 +04:00
if (evt->new_y < PANEL_HEIGHT) {
for (int i = 0; i < 18; ++i) {
if (icon_lefts[i] == 0) {
set_focused(-1);
break;
}
if (evt->new_x >= icon_lefts[i] && evt->new_x < icon_lefts[i+1]) {
set_focused(i);
break;
}
}
} else {
set_focused(-1);
2012-09-20 08:16:21 +04:00
}
} else if (evt->command == YUTANI_MOUSE_EVENT_LEAVE) {
set_focused(-1);
2012-09-20 08:16:21 +04:00
}
}
void redraw(void) {
spin_lock(&drawlock);
struct timeval now;
int last = 0;
struct tm * timeinfo;
char buffer[80];
uint32_t txt_color = rgb(230,230,230);
int t = 0;
memcpy(ctx->backbuffer, bg_blob, bg_size);
gettimeofday(&now, NULL);
last = now.tv_sec;
timeinfo = localtime((time_t *)&now.tv_sec);
strftime(buffer, 80, "%H:%M:%S", timeinfo);
set_font_face(FONT_SANS_SERIF_BOLD);
set_font_size(16);
draw_string(ctx, width - TIME_LEFT, 19, txt_color, buffer);
strftime(buffer, 80, "%A", timeinfo);
set_font_face(FONT_SANS_SERIF);
set_font_size(9);
t = draw_string_width(buffer);
t = (DATE_WIDTH - t) / 2;
draw_string(ctx, width - TIME_LEFT - DATE_WIDTH + t, 11, txt_color, buffer);
strftime(buffer, 80, "%h %e", timeinfo);
set_font_face(FONT_SANS_SERIF_BOLD);
set_font_size(9);
t = draw_string_width(buffer);
t = (DATE_WIDTH - t) / 2;
draw_string(ctx, width - TIME_LEFT - DATE_WIDTH + t, 21, txt_color, buffer);
set_font_face(FONT_SANS_SERIF_BOLD);
set_font_size(14);
draw_string(ctx, 10, 18, txt_color, "Applications");
2014-04-20 12:24:10 +04:00
int i = 0, j = 0;
spin_lock(&lock);
if (window_list) {
foreach(node, window_list) {
2014-05-03 23:22:16 +04:00
struct window_ad * ad = node->value;
char * s = ad->name;
set_font_face(FONT_SANS_SERIF);
set_font_size(14);
2014-04-20 12:24:10 +04:00
if (j == focused_app) {
draw_string(ctx, 140 + i, 18, rgb(142,216,255), s);
} else {
2014-05-03 23:22:16 +04:00
if (ad->flags & 1) {
draw_string(ctx, 140 + i, 18, rgb(255,0,0), s);
} else {
draw_string(ctx, 140 + i, 18, txt_color, s);
}
2014-04-20 12:24:10 +04:00
}
if (j < 18) {
icon_lefts[j] = 140 + i;
j++;
}
i += draw_string_width(s) + 20;
}
2014-04-20 12:24:10 +04:00
if (j < 19) {
icon_lefts[j] = 140 + i;
icon_lefts[j+1] = 0;
}
}
spin_unlock(&lock);
draw_sprite(ctx, sprites[1], width - 23, 1); /* Logout button */
flip(ctx);
yutani_flip(yctx, panel);
spin_unlock(&drawlock);
}
2014-04-20 12:24:10 +04:00
void update_window_list(void) {
yutani_query_windows(yctx);
list_t * new_window_list = list_create();
2014-04-20 12:24:10 +04:00
int i = 0;
while (1) {
yutani_msg_t * m = yutani_wait_for(yctx, YUTANI_MSG_WINDOW_ADVERTISE);
struct yutani_msg_window_advertise * wa = (void*)m->data;
if (wa->size == 0) {
free(m);
break;
}
2014-04-20 12:24:10 +04:00
if (i < 19) {
icon_wids[i] = wa->wid;
icon_wids[i+1] = 0;
}
2014-05-03 23:22:16 +04:00
struct window_ad * ad = malloc(sizeof(struct window_ad));
2014-05-03 23:07:03 +04:00
char * s = malloc(wa->size);
memcpy(s, wa->strings, wa->size);
2014-05-03 23:22:16 +04:00
ad->name = &s[wa->offsets[0]];
ad->icon = &s[wa->offsets[1]];
ad->strings = s;
ad->flags = wa->flags;
2014-05-03 23:07:03 +04:00
2014-05-03 23:22:16 +04:00
list_insert(new_window_list, ad);
free(m);
2014-04-20 12:24:10 +04:00
i++;
}
spin_lock(&lock);
if (window_list) {
2014-05-03 23:22:16 +04:00
foreach(node, window_list) {
struct window_ad * ad = (void*)node->value;
free(ad->strings);
free(ad);
}
list_free(window_list);
free(window_list);
}
window_list = new_window_list;
spin_unlock(&lock);
redraw();
}
2014-04-16 06:45:56 +04:00
void * clock_thread(void * garbage) {
while (_continue) {
redraw();
2013-05-03 10:33:57 +04:00
usleep(500000);
2012-03-08 09:44:02 +04:00
}
2014-04-16 06:45:56 +04:00
}
int main (int argc, char ** argv) {
yctx = yutani_init();
width = yctx->display_width;
height = yctx->display_height;
init_shmemfonts();
set_font_size(14);
/* Create the panel */
panel = yutani_window_create(yctx, width, PANEL_HEIGHT);
yutani_set_stack(yctx, panel, YUTANI_ZORDER_TOP);
ctx = init_graphics_yutani_double_buffer(panel);
draw_fill(ctx, rgba(0,0,0,0));
flip(ctx);
yutani_flip(yctx, panel);
window_list = NULL;
yutani_subscribe_windows(yctx);
2014-04-16 06:45:56 +04:00
init_sprite_png(0, "/usr/share/panel.png");
init_sprite_png(1, "/usr/share/icons/panel-shutdown.png");
syscall_signal(2, sig_int);
for (uint32_t i = 0; i < width; i += sprites[0]->width) {
draw_sprite(ctx, sprites[0], i, 0);
}
bg_size = panel->width * panel->height * sizeof(uint32_t);
bg_blob = malloc(bg_size);
memcpy(bg_blob, ctx->backbuffer, bg_size);
2014-04-16 06:45:56 +04:00
pthread_t _clock_thread;
pthread_create(&_clock_thread, NULL, clock_thread, NULL);
update_window_list();
2014-04-16 06:45:56 +04:00
while (_continue) {
yutani_msg_t * m = yutani_poll(yctx);
if (m) {
switch (m->type) {
case YUTANI_MSG_NOTIFY:
update_window_list();
break;
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
panel_check_click((struct yutani_msg_window_mouse_event *)m->data);
break;
default:
break;
}
2014-04-16 06:45:56 +04:00
free(m);
}
}
2012-03-08 09:44:02 +04:00
2014-04-16 06:45:56 +04:00
yutani_close(yctx, panel);
yutani_unsubscribe_windows(yctx);
2012-03-08 09:44:02 +04:00
return 0;
}