Add display server.
This commit is contained in:
parent
8e3f47ba0b
commit
c9cf4b01ba
5
Makefile
5
Makefile
|
@ -8,12 +8,15 @@ doc \
|
|||
libc \
|
||||
libm \
|
||||
dispd \
|
||||
libdisplay \
|
||||
libmount \
|
||||
libui \
|
||||
bench \
|
||||
carray \
|
||||
checksum \
|
||||
dhclient \
|
||||
disked \
|
||||
display \
|
||||
dnsconfig \
|
||||
editor \
|
||||
ext \
|
||||
|
@ -27,12 +30,14 @@ kblayout \
|
|||
kblayout-compiler \
|
||||
login \
|
||||
mkinitrd \
|
||||
nyan \
|
||||
ping \
|
||||
regress \
|
||||
rw \
|
||||
sf \
|
||||
sh \
|
||||
sysinstall \
|
||||
terminal \
|
||||
tix \
|
||||
trianglix \
|
||||
update-initrd \
|
||||
|
|
|
@ -192,6 +192,7 @@ fi
|
|||
set enable_src=true
|
||||
set enable_network_drivers=
|
||||
set enable_dhclient=true
|
||||
set enable_gui=true
|
||||
set enable_sshd=false
|
||||
|
||||
export version
|
||||
|
@ -204,6 +205,7 @@ export no_random_seed
|
|||
export enable_src
|
||||
export enable_network_drivers
|
||||
export enable_dhclient
|
||||
export enable_gui
|
||||
export enable_sshd
|
||||
EOF
|
||||
|
||||
|
@ -384,10 +386,11 @@ menuentry() {
|
|||
echo
|
||||
printf "menuentry \"Sortix (%s)\" {\n" "$1"
|
||||
if [ -n "$2" ]; then
|
||||
printf " load_sortix %s\n" "$2"
|
||||
#printf " load_sortix '"
|
||||
#printf '%s' "$2" | sed "s,','\\'',g"
|
||||
#printf "'\n"
|
||||
printf " if \$enable_gui; then\n"
|
||||
printf " load_sortix %s-gui\n" "$2"
|
||||
printf " else\n"
|
||||
printf " load_sortix %s\n" "$2"
|
||||
printf " fi\n"
|
||||
else
|
||||
printf " load_sortix\n"
|
||||
fi
|
||||
|
@ -400,7 +403,7 @@ menu_title="\$base_menu_title"
|
|||
hook_menu_pre
|
||||
EOF
|
||||
|
||||
menuentry "live environment" '-- /sbin/init'
|
||||
menuentry "live environment" '-- /sbin/init --target=single-user'
|
||||
menuentry "new installation" '-- /sbin/init --target=sysinstall'
|
||||
menuentry "upgrade existing installation" '-- /sbin/init --target=sysupgrade'
|
||||
|
||||
|
@ -428,6 +431,18 @@ menu_title="\$base_menu_title - Advanced Options"
|
|||
|
||||
hook_advanced_menu_pre
|
||||
|
||||
if "\$enable_gui"; then
|
||||
menuentry "Disable GUI" {
|
||||
enable_gui=false
|
||||
configfile /boot/grub/advanced.cfg
|
||||
}
|
||||
else
|
||||
menuentry "Enable GUI" {
|
||||
enable_gui=true
|
||||
configfile /boot/grub/advanced.cfg
|
||||
}
|
||||
fi
|
||||
|
||||
if "\$enable_src"; then
|
||||
menuentry "Disable loading source code" {
|
||||
enable_src=false
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
display
|
||||
*.o
|
||||
*.inc
|
|
@ -0,0 +1,42 @@
|
|||
SOFTWARE_MEANT_FOR_SORTIX=1
|
||||
include ../build-aux/platform.mak
|
||||
include ../build-aux/compiler.mak
|
||||
include ../build-aux/dirs.mak
|
||||
|
||||
OPTLEVEL?=-g -O2
|
||||
CFLAGS?=$(OPTLEVEL)
|
||||
|
||||
CFLAGS:=$(CFLAGS) -Wall -Wextra
|
||||
|
||||
PROGRAM=display
|
||||
|
||||
OBJS=\
|
||||
connection.o \
|
||||
display-code.o \
|
||||
display.o \
|
||||
server.o \
|
||||
window.o \
|
||||
|
||||
LIBS:=-lui
|
||||
|
||||
all: $(PROGRAM)
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
install $(PROGRAM) $(DESTDIR)$(BINDIR)
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $(OBJS) -o $@ $(LIBS)
|
||||
|
||||
display.o: arrow.inc
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
%.inc: %.rgb
|
||||
carray -cs -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(PROGRAM) *.o *.inc
|
Binary file not shown.
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* connection.c
|
||||
* Display protocol implementation.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/termmode.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
void connection_schedule_transmit(struct connection* connection,
|
||||
const void* buffer,
|
||||
size_t count)
|
||||
{
|
||||
assert(connection);
|
||||
size_t available = connection->outgoing_size - connection->outgoing_used;
|
||||
if ( available < count )
|
||||
{
|
||||
size_t required_size = connection->outgoing_used + count;
|
||||
unsigned char* new_outgoing = (unsigned char*) malloc(required_size);
|
||||
size_t first_part_available = connection->outgoing_size - connection->outgoing_offset;
|
||||
size_t first_part = connection->outgoing_used < first_part_available ?
|
||||
connection->outgoing_used :
|
||||
first_part_available;
|
||||
if ( connection->outgoing )
|
||||
{
|
||||
memcpy(new_outgoing, connection->outgoing +
|
||||
connection->outgoing_offset, first_part);
|
||||
size_t second_part = connection->outgoing_used - first_part;
|
||||
memcpy(new_outgoing + first_part, connection->outgoing, second_part);
|
||||
free(connection->outgoing);
|
||||
}
|
||||
connection->outgoing_offset = 0;
|
||||
connection->outgoing_size = required_size;
|
||||
connection->outgoing = new_outgoing;
|
||||
}
|
||||
|
||||
size_t used_offset = (connection->outgoing_offset + connection->outgoing_used) % connection->outgoing_size;
|
||||
size_t first_part_available = connection->outgoing_size - used_offset;
|
||||
size_t first_part = count < first_part_available ? count : first_part_available;
|
||||
memcpy(connection->outgoing + used_offset, buffer, first_part);
|
||||
size_t second_part = count - first_part;
|
||||
memcpy(connection->outgoing, (const unsigned char*) buffer + first_part, second_part);
|
||||
connection->outgoing_used += count;
|
||||
}
|
||||
|
||||
void connection_initialize(struct connection* connection,
|
||||
struct display* display,
|
||||
int fd)
|
||||
{
|
||||
memset(connection, 0, sizeof(*connection));
|
||||
connection->display = display;
|
||||
connection->fd = fd;
|
||||
}
|
||||
|
||||
struct window* connection_find_window_raw(struct connection* connection,
|
||||
uint32_t window_id)
|
||||
{
|
||||
if ( MAX_WINDOWS_PER_CONNECTION <= window_id )
|
||||
return NULL;
|
||||
return &connection->windows[window_id];
|
||||
}
|
||||
|
||||
struct window* connection_find_window(struct connection* connection,
|
||||
uint32_t window_id)
|
||||
{
|
||||
struct window* result = connection_find_window_raw(connection, window_id);
|
||||
if ( !result->created )
|
||||
return NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
#define CONNECTION_MESSAGE_HANDLER_NO_AUX(message_name) \
|
||||
void connection_handler_##message_name(struct connection* connection, \
|
||||
struct display_##message_name* msg, \
|
||||
void* auxilerary __attribute__((unused)), \
|
||||
size_t auxilerary_size __attribute__((unused)))
|
||||
|
||||
#define CONNECTION_MESSAGE_HANDLER(message_name) \
|
||||
void connection_handler_##message_name(struct connection* connection, \
|
||||
struct display_##message_name* msg, \
|
||||
unsigned char* auxilerary, \
|
||||
size_t auxilerary_size)
|
||||
|
||||
CONNECTION_MESSAGE_HANDLER_NO_AUX(shutdown)
|
||||
{
|
||||
(void) connection;
|
||||
if ( msg->code == 0 )
|
||||
exit(0);
|
||||
else if ( msg->code == 1 )
|
||||
exit(1);
|
||||
else if ( msg->code == 2 )
|
||||
exit(2);
|
||||
else
|
||||
exit(0);
|
||||
}
|
||||
|
||||
CONNECTION_MESSAGE_HANDLER_NO_AUX(create_window)
|
||||
{
|
||||
struct window* window = connection_find_window_raw(connection, msg->window_id);
|
||||
if ( !window )
|
||||
return;
|
||||
if ( window->created )
|
||||
return;
|
||||
window_initialize(window, connection, connection->display, msg->window_id);
|
||||
}
|
||||
|
||||
CONNECTION_MESSAGE_HANDLER_NO_AUX(destroy_window)
|
||||
{
|
||||
struct window* window = connection_find_window(connection, msg->window_id);
|
||||
if ( !window )
|
||||
return;
|
||||
window_destroy(window);
|
||||
}
|
||||
|
||||
CONNECTION_MESSAGE_HANDLER_NO_AUX(resize_window)
|
||||
{
|
||||
struct window* window = connection_find_window(connection, msg->window_id);
|
||||
if ( !window )
|
||||
return;
|
||||
window_client_resize(window, msg->width, msg->height);
|
||||
}
|
||||
|
||||
CONNECTION_MESSAGE_HANDLER(render_window)
|
||||
{
|
||||
struct window* window = connection_find_window(connection, msg->window_id);
|
||||
if ( !window )
|
||||
return;
|
||||
|
||||
struct framebuffer src;
|
||||
src.xres = msg->width;
|
||||
src.yres = msg->height;
|
||||
src.pitch = msg->width;
|
||||
src.buffer = (uint32_t*) auxilerary;
|
||||
|
||||
if ( auxilerary_size < sizeof(uint32_t) * src.xres * src.yres )
|
||||
return;
|
||||
|
||||
struct framebuffer dst =
|
||||
framebuffer_crop(window_client_buffer(window),
|
||||
msg->left, msg->top, msg->width, msg->height);
|
||||
|
||||
framebuffer_copy_to_framebuffer(dst, src);
|
||||
}
|
||||
|
||||
CONNECTION_MESSAGE_HANDLER(title_window)
|
||||
{
|
||||
struct window* window = connection_find_window(connection, msg->window_id);
|
||||
if ( !window )
|
||||
return;
|
||||
|
||||
const char* title = (char*) auxilerary;
|
||||
free(window->title);
|
||||
window->title = strndup(title, auxilerary_size);
|
||||
|
||||
window_render_frame(window);
|
||||
}
|
||||
|
||||
CONNECTION_MESSAGE_HANDLER_NO_AUX(show_window)
|
||||
{
|
||||
struct window* window = connection_find_window(connection, msg->window_id);
|
||||
if ( !window )
|
||||
return;
|
||||
window->show = true;
|
||||
}
|
||||
|
||||
CONNECTION_MESSAGE_HANDLER_NO_AUX(hide_window)
|
||||
{
|
||||
struct window* window = connection_find_window(connection, msg->window_id);
|
||||
if ( !window )
|
||||
return;
|
||||
window->show = false;
|
||||
}
|
||||
|
||||
typedef void (*connection_message_handler)(struct connection* connection,
|
||||
void* msg,
|
||||
void* auxilerary,
|
||||
size_t auxilerary_size);
|
||||
|
||||
struct connection_message_handler_registration
|
||||
{
|
||||
connection_message_handler handler;
|
||||
size_t message_size;
|
||||
};
|
||||
|
||||
#define REGISTER_CONNECTION_MESSAGE_HANDLER(message_name) \
|
||||
{ (connection_message_handler) connection_handler_##message_name, \
|
||||
sizeof(struct display_##message_name) }
|
||||
|
||||
struct connection_message_handler_registration connection_message_handlers[] =
|
||||
{
|
||||
REGISTER_CONNECTION_MESSAGE_HANDLER(create_window),
|
||||
REGISTER_CONNECTION_MESSAGE_HANDLER(destroy_window),
|
||||
REGISTER_CONNECTION_MESSAGE_HANDLER(resize_window),
|
||||
REGISTER_CONNECTION_MESSAGE_HANDLER(render_window),
|
||||
REGISTER_CONNECTION_MESSAGE_HANDLER(title_window),
|
||||
REGISTER_CONNECTION_MESSAGE_HANDLER(show_window),
|
||||
REGISTER_CONNECTION_MESSAGE_HANDLER(hide_window),
|
||||
REGISTER_CONNECTION_MESSAGE_HANDLER(shutdown),
|
||||
};
|
||||
|
||||
size_t num_connection_message_handlers = sizeof(connection_message_handlers) /
|
||||
sizeof(connection_message_handlers[0]);
|
||||
|
||||
short connection_interested_poll_events(struct connection* connection)
|
||||
{
|
||||
return POLLIN | (connection->outgoing_used ? POLLOUT : 0);
|
||||
}
|
||||
|
||||
void connection_can_read(struct connection* connection)
|
||||
{
|
||||
while ( connection->packet_header_received < sizeof(connection->packet_header) )
|
||||
{
|
||||
ssize_t amount = read(connection->fd,
|
||||
(unsigned char*) &connection->packet_header +
|
||||
connection->packet_header_received,
|
||||
sizeof(connection->packet_header) -
|
||||
connection->packet_header_received);
|
||||
if ( amount < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) )
|
||||
return;
|
||||
if ( amount < 0 || amount == 0 )
|
||||
return; // TODO: No longer signal interest in reading and disconnect.
|
||||
connection->packet_header_received += amount;
|
||||
}
|
||||
|
||||
size_t packet_length = connection->packet_header.message_length;
|
||||
|
||||
if ( !connection->packet )
|
||||
connection->packet = (unsigned char*) malloc(packet_length);
|
||||
|
||||
while ( connection->packet_received < packet_length )
|
||||
{
|
||||
ssize_t amount = read(connection->fd,
|
||||
connection->packet + connection->packet_received,
|
||||
packet_length - connection->packet_received);
|
||||
if ( amount < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) )
|
||||
return;
|
||||
if ( amount < 0 || amount == 0 )
|
||||
return; // TODO: No longer signal interest in reading and disconnect.
|
||||
connection->packet_received += amount;
|
||||
}
|
||||
|
||||
size_t packet_id = connection->packet_header.message_id;
|
||||
|
||||
if ( packet_id < num_connection_message_handlers )
|
||||
{
|
||||
struct connection_message_handler_registration* handler =
|
||||
&connection_message_handlers[packet_id];
|
||||
unsigned char* auxilerary = connection->packet + handler->message_size;
|
||||
size_t auxilerary_size = packet_length - handler->message_size;
|
||||
handler->handler(connection, connection->packet,
|
||||
auxilerary, auxilerary_size);
|
||||
}
|
||||
|
||||
connection->packet_header_received = 0;
|
||||
free(connection->packet);
|
||||
connection->packet = NULL;
|
||||
connection->packet_received = 0;
|
||||
|
||||
// TODO: Check if we can received another packet, but only if we haven't
|
||||
// done so much work that the display server is starved.
|
||||
}
|
||||
|
||||
void connection_can_write(struct connection* connection)
|
||||
{
|
||||
while ( connection->outgoing_used )
|
||||
{
|
||||
size_t available = connection->outgoing_size - connection->outgoing_offset;
|
||||
size_t count = connection->outgoing_used < available ? connection->outgoing_used : available;
|
||||
ssize_t amount = write(connection->fd, connection->outgoing + connection->outgoing_offset, count);
|
||||
if ( amount < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) )
|
||||
return;
|
||||
if ( amount < 0 || amount == 0 )
|
||||
return; // TODO: No longer signal interest in writing and disconnect.
|
||||
connection->outgoing_offset = (connection->outgoing_offset + amount) % connection->outgoing_size;
|
||||
connection->outgoing_used -= amount;
|
||||
}
|
||||
|
||||
free(connection->outgoing);
|
||||
connection->outgoing = NULL;
|
||||
connection->outgoing_used = 0;
|
||||
connection->outgoing_size = 0;
|
||||
}
|
||||
|
||||
void connection_destroy(struct connection* connection)
|
||||
{
|
||||
for ( size_t i = 0; i < MAX_WINDOWS_PER_CONNECTION; i++ )
|
||||
{
|
||||
if ( !connection->windows[i].created )
|
||||
continue;
|
||||
window_destroy(&connection->windows[i]);
|
||||
}
|
||||
close(connection->fd);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* connection.h
|
||||
* Display protocol implementation.
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <display-protocol.h>
|
||||
|
||||
#include "window.h"
|
||||
|
||||
struct display;
|
||||
struct window;
|
||||
|
||||
#define MAX_WINDOWS_PER_CONNECTION 256
|
||||
|
||||
struct connection
|
||||
{
|
||||
struct display* display;
|
||||
struct window windows[MAX_WINDOWS_PER_CONNECTION];
|
||||
struct display_packet_header packet_header;
|
||||
size_t packet_header_received;
|
||||
unsigned char* packet;
|
||||
size_t packet_received;
|
||||
unsigned char* outgoing;
|
||||
size_t outgoing_offset;
|
||||
size_t outgoing_used;
|
||||
size_t outgoing_size;
|
||||
int fd;
|
||||
};
|
||||
|
||||
void connection_schedule_transmit(struct connection* connection,
|
||||
const void* buffer,
|
||||
size_t count);
|
||||
void connection_initialize(struct connection* connection,
|
||||
struct display* display,
|
||||
int fd);
|
||||
struct window* connection_find_window_raw(struct connection* connection,
|
||||
uint32_t window_id);
|
||||
struct window* connection_find_window(struct connection* connection,
|
||||
uint32_t window_id);
|
||||
short connection_interested_poll_events(struct connection* connection);
|
||||
void connection_can_read(struct connection* connection);
|
||||
void connection_can_write(struct connection* connection);
|
||||
void connection_destroy(struct connection* connection);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* damage-rect.c
|
||||
* Damage rectangles.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "damage-rect.h"
|
||||
|
||||
struct damage_rect damage_rect_add(struct damage_rect a, struct damage_rect b)
|
||||
{
|
||||
if ( !a.width || !a.height )
|
||||
return b;
|
||||
if ( !b.width || !b.height )
|
||||
return a;
|
||||
if ( a.left < b.left )
|
||||
b.width += b.left - a.left, b.left = a.left;
|
||||
if ( b.width < a.width )
|
||||
b.width = a.width;
|
||||
if ( a.top < b.top )
|
||||
b.height += b.top - a.top, b.top = a.top;
|
||||
if ( b.height < a.height )
|
||||
b.height = a.height;
|
||||
return b;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* damage-rect.h
|
||||
* Damage rectangles.
|
||||
*/
|
||||
|
||||
#ifndef DAMAGE_RECT_H
|
||||
#define DAMAGE_RECT_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct damage_rect
|
||||
{
|
||||
size_t left;
|
||||
size_t top;
|
||||
size_t width;
|
||||
size_t height;
|
||||
};
|
||||
|
||||
struct damage_rect damage_rect_add(struct damage_rect a, struct damage_rect b);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,575 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016, 2018 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* display-code.c
|
||||
* Display server logic.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/display.h>
|
||||
#include <sys/keycodes.h>
|
||||
#include <sys/ps2mouse.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <display-protocol.h>
|
||||
|
||||
#include "connection.h"
|
||||
#include "display.h"
|
||||
#include "pixel.h"
|
||||
#include "window.h"
|
||||
|
||||
extern struct framebuffer arrow_framebuffer;
|
||||
|
||||
void display_initialize(struct display* display)
|
||||
{
|
||||
memset(display, 0, sizeof(*display));
|
||||
}
|
||||
|
||||
void assert_is_well_formed_display_list(struct display* display)
|
||||
{
|
||||
struct window* last_window = NULL;
|
||||
struct window* iterator = display->bottom_window;
|
||||
while ( iterator )
|
||||
{
|
||||
assert(iterator->below_window == last_window);
|
||||
last_window = iterator;
|
||||
iterator = iterator->above_window;
|
||||
}
|
||||
assert(last_window == display->top_window);
|
||||
}
|
||||
|
||||
void assert_is_well_formed_display(struct display* display)
|
||||
{
|
||||
assert_is_well_formed_display_list(display);
|
||||
|
||||
bool found_active_window = display->active_window == NULL;
|
||||
bool found_tab_candidate = display->tab_candidate == NULL;
|
||||
struct window* iterator = display->bottom_window;
|
||||
while ( iterator )
|
||||
{
|
||||
if ( iterator == display->active_window )
|
||||
found_active_window = true;
|
||||
if ( iterator == display->tab_candidate )
|
||||
found_tab_candidate = true;
|
||||
iterator = iterator->above_window;
|
||||
}
|
||||
assert(found_active_window);
|
||||
assert(found_tab_candidate);
|
||||
}
|
||||
|
||||
void display_link_window_at_top(struct display* display, struct window* window)
|
||||
{
|
||||
assert_is_well_formed_display_list(display);
|
||||
|
||||
assert(!window->above_window);
|
||||
assert(!window->below_window);
|
||||
assert(display->top_window != window);
|
||||
assert(display->bottom_window != window);
|
||||
|
||||
if ( (window->below_window = display->top_window) )
|
||||
window->below_window->above_window = window;
|
||||
window->above_window = NULL;
|
||||
|
||||
display->top_window = window;
|
||||
if ( !display->bottom_window )
|
||||
display->bottom_window = window;
|
||||
|
||||
assert_is_well_formed_display_list(display);
|
||||
}
|
||||
|
||||
void display_unlink_window(struct display* display, struct window* window)
|
||||
{
|
||||
assert_is_well_formed_display_list(display);
|
||||
|
||||
assert(window->below_window || display->bottom_window == window);
|
||||
assert(window->above_window || display->top_window == window);
|
||||
|
||||
if ( window->below_window )
|
||||
window->below_window->above_window = window->above_window;
|
||||
else
|
||||
display->bottom_window = window->above_window;
|
||||
if ( window->above_window )
|
||||
window->above_window->below_window = window->below_window;
|
||||
else
|
||||
display->top_window = window->below_window;
|
||||
|
||||
assert(display->bottom_window != window);
|
||||
assert(display->top_window != window);
|
||||
|
||||
window->above_window = NULL;
|
||||
window->below_window = NULL;
|
||||
|
||||
assert_is_well_formed_display_list(display);
|
||||
}
|
||||
|
||||
void display_unlink_window_removal(struct display* display, struct window* window)
|
||||
{
|
||||
assert_is_well_formed_display_list(display);
|
||||
|
||||
if ( display->tab_candidate == window )
|
||||
if ( !(display->tab_candidate = window->below_window) )
|
||||
if ( (display->tab_candidate = display->top_window) == window )
|
||||
display->tab_candidate = NULL;
|
||||
|
||||
if ( display->active_window == window )
|
||||
display->active_window = NULL;
|
||||
|
||||
window->focus = false;
|
||||
|
||||
assert_is_well_formed_display_list(display);
|
||||
|
||||
display_unlink_window(display, window);
|
||||
|
||||
assert_is_well_formed_display_list(display);
|
||||
}
|
||||
|
||||
void display_unmark_active_window(struct display* display, struct window* window)
|
||||
{
|
||||
assert(display->active_window == window);
|
||||
window->focus = false;
|
||||
display->active_window = NULL;
|
||||
window_render_frame(window);
|
||||
}
|
||||
|
||||
void display_mark_active_window(struct display* display, struct window* window)
|
||||
{
|
||||
assert(!display->active_window);
|
||||
window->focus = true;
|
||||
display->active_window = window;
|
||||
window_render_frame(window);
|
||||
}
|
||||
|
||||
void display_update_active_window(struct display* display)
|
||||
{
|
||||
if ( !display->active_window && display->top_window )
|
||||
display_mark_active_window(display, display->top_window);
|
||||
}
|
||||
|
||||
void display_move_window_to_top(struct display* display, struct window* window)
|
||||
{
|
||||
display_unlink_window(display, window);
|
||||
display_link_window_at_top(display, window);
|
||||
}
|
||||
|
||||
void display_change_active_window(struct display* display, struct window* window)
|
||||
{
|
||||
if ( display->active_window == window )
|
||||
{
|
||||
display_move_window_to_top(display, window);
|
||||
return;
|
||||
}
|
||||
|
||||
display_unmark_active_window(display, display->active_window);
|
||||
display_mark_active_window(display, window);
|
||||
}
|
||||
|
||||
void display_set_active_window(struct display* display, struct window* window)
|
||||
{
|
||||
display_change_active_window(display, window);
|
||||
display_move_window_to_top(display, window);
|
||||
}
|
||||
|
||||
void display_add_window(struct display* display, struct window* window)
|
||||
{
|
||||
display_link_window_at_top(display, window);
|
||||
display_update_active_window(display);
|
||||
}
|
||||
|
||||
void display_remove_window(struct display* display, struct window* window)
|
||||
{
|
||||
display_unlink_window_removal(display, window);
|
||||
display_update_active_window(display);
|
||||
|
||||
assert(display->top_window != window);
|
||||
assert(display->bottom_window != window);
|
||||
struct window* last_window = NULL;
|
||||
struct window* iterator = display->bottom_window;
|
||||
while ( iterator )
|
||||
{
|
||||
assert(iterator != window);
|
||||
assert(iterator->below_window == last_window);
|
||||
last_window = iterator;
|
||||
iterator = iterator->above_window;
|
||||
}
|
||||
assert(last_window == display->top_window);
|
||||
|
||||
assert(!display->top_window || display->active_window);
|
||||
}
|
||||
|
||||
void display_composit(struct display* display, struct framebuffer fb)
|
||||
{
|
||||
struct damage_rect damage_rect = display->damage_rect;
|
||||
damage_rect.left = 0;
|
||||
damage_rect.top = 0;
|
||||
damage_rect.width = fb.xres;
|
||||
damage_rect.height = fb.yres;
|
||||
if ( !damage_rect.width || !damage_rect.height )
|
||||
return;
|
||||
|
||||
uint32_t bg_color = make_color(0x89 * 2/3, 0xc7 * 2/3, 0xff * 2/3);
|
||||
for ( size_t y = 0; y < damage_rect.height; y++ )
|
||||
for ( size_t x = 0; x < damage_rect.width; x++ )
|
||||
framebuffer_set_pixel(fb, damage_rect.left + x, damage_rect.top + y, bg_color);
|
||||
|
||||
for ( struct window* window = display->bottom_window;
|
||||
window;
|
||||
window = window->above_window )
|
||||
{
|
||||
if ( !window->show )
|
||||
continue;
|
||||
|
||||
size_t winfb_left;
|
||||
size_t winfb_top;
|
||||
struct framebuffer winfb = window->buffer;
|
||||
|
||||
if ( window->left < 0 )
|
||||
{
|
||||
winfb_left = 0;
|
||||
winfb = framebuffer_crop(winfb, -window->left, 0, winfb.xres, winfb.yres);
|
||||
}
|
||||
else
|
||||
winfb_left = window->left;
|
||||
|
||||
if ( window->top < 0 )
|
||||
{
|
||||
winfb_top = 0;
|
||||
winfb = framebuffer_crop(winfb, 0, -window->top, winfb.xres, winfb.yres);
|
||||
}
|
||||
else
|
||||
winfb_top = window->top;
|
||||
|
||||
size_t winfb_width = winfb.xres;
|
||||
size_t winfb_height = winfb.yres;
|
||||
|
||||
#if 0
|
||||
if ( winfb_left < damage_rect.left && winfb_width < damage_rect.left - winfb_left )
|
||||
continue;
|
||||
if ( winfb_left < damage_rect.left )
|
||||
winfb_left = damage_rect.left, winfb_width -= damage_rect.left - winfb_left;
|
||||
#endif
|
||||
|
||||
struct framebuffer fb_dst =
|
||||
framebuffer_crop(fb, winfb_left, winfb_top, winfb_width, winfb_height);
|
||||
|
||||
framebuffer_copy_to_framebuffer_blend(fb_dst, winfb);
|
||||
}
|
||||
|
||||
int pointer_hwidth = arrow_framebuffer.xres / 2;
|
||||
int pointer_hheight = arrow_framebuffer.yres / 2;
|
||||
|
||||
int pointer_x = display->pointer_x - pointer_hwidth;
|
||||
int pointer_y = display->pointer_y - pointer_hheight;
|
||||
|
||||
struct framebuffer arrow_render = arrow_framebuffer;
|
||||
if ( pointer_x < 0 )
|
||||
{
|
||||
arrow_render = framebuffer_crop(arrow_render, -pointer_x, 0, arrow_render.xres, arrow_render.yres);
|
||||
pointer_x = 0;
|
||||
}
|
||||
if ( pointer_y < 0 )
|
||||
{
|
||||
arrow_render = framebuffer_crop(arrow_render, 0, -pointer_y, arrow_render.xres, arrow_render.yres);
|
||||
pointer_y = 0;
|
||||
}
|
||||
|
||||
struct framebuffer fb_dst =
|
||||
framebuffer_crop(fb, pointer_x, pointer_y, fb.xres, fb.yres);
|
||||
|
||||
framebuffer_copy_to_framebuffer_blend(fb_dst, arrow_render);
|
||||
|
||||
memset(&damage_rect, 0, sizeof(damage_rect));
|
||||
}
|
||||
|
||||
void display_render(struct display* display)
|
||||
{
|
||||
struct dispmsg_crtc_mode mode;
|
||||
{
|
||||
struct dispmsg_get_crtc_mode msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msgid = DISPMSG_GET_CRTC_MODE;
|
||||
msg.device = 0; // TODO: Multi-screen support!
|
||||
msg.connector = 0; // TODO: Multi-screen support!
|
||||
|
||||
if ( dispmsg_issue(&msg, sizeof(msg)) != 0 )
|
||||
err(1, "dispmsg_issue: dispmsg_get_crtc_mode");
|
||||
|
||||
mode = msg.mode;
|
||||
}
|
||||
|
||||
if ( !(mode.control & DISPMSG_CONTROL_VALID) )
|
||||
errx(1, "No valid video mode was set");
|
||||
if ( mode.control & DISPMSG_CONTROL_VGA )
|
||||
errx(1, "A VGA text mode was set");
|
||||
if ( mode.fb_format != 32 )
|
||||
errx(1, "A 32-bit video mode wasn't set");
|
||||
|
||||
struct framebuffer fb;
|
||||
fb.xres = mode.view_xres;
|
||||
fb.yres = mode.view_yres;
|
||||
fb.pitch = mode.view_xres;
|
||||
size_t framebuffer_length = fb.xres * fb.yres;
|
||||
fb.buffer = (uint32_t*) malloc(sizeof(uint32_t) * framebuffer_length);
|
||||
size_t framebuffer_size = framebuffer_length * sizeof(fb.buffer[0]);
|
||||
|
||||
display_on_resolution_change(display, mode.view_xres, mode.view_yres);
|
||||
|
||||
display_composit(display, fb);
|
||||
|
||||
{
|
||||
struct dispmsg_write_memory msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msgid = DISPMSG_WRITE_MEMORY;
|
||||
msg.device = 0; // TODO: Multi-screen support!
|
||||
msg.offset = 0; // TODO: mode.fb_location!
|
||||
msg.size = framebuffer_size;
|
||||
msg.src = (uint8_t*) fb.buffer;
|
||||
|
||||
if ( dispmsg_issue(&msg, sizeof(msg)) != 0 )
|
||||
err(1, "dispmsg_issue: dispmsg_write_memory");
|
||||
}
|
||||
|
||||
// TODO: This could be recycled if the resolution did not change.
|
||||
free(fb.buffer);
|
||||
}
|
||||
|
||||
void display_keyboard_event(struct display* display, uint32_t codepoint)
|
||||
{
|
||||
struct window* window = display->active_window;
|
||||
|
||||
int kbkey = KBKEY_DECODE(codepoint);
|
||||
int abskbkey = kbkey < 0 ? -kbkey : kbkey;
|
||||
|
||||
if ( kbkey && (!window || !window->grab_input) )
|
||||
{
|
||||
switch ( abskbkey )
|
||||
{
|
||||
case KBKEY_LCTRL: display->key_lctrl = kbkey > 0; break;
|
||||
case KBKEY_LALT: display->key_lalt = kbkey > 0; break;
|
||||
}
|
||||
if ( display->key_lctrl && display->key_lalt && kbkey == KBKEY_DELETE )
|
||||
exit(0);
|
||||
if ( display->key_lctrl && display->key_lalt && kbkey == KBKEY_T )
|
||||
{
|
||||
if ( !fork() )
|
||||
{
|
||||
execlp("terminal", "terminal", (char*) NULL);
|
||||
_exit(127);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if ( display->key_lctrl && display->key_lalt && kbkey == -KBKEY_T )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( kbkey && window && !window->grab_input )
|
||||
{
|
||||
// TODO: Ctrl+Q when termninal has a way of handling it or not.
|
||||
if ( (display->key_lalt && kbkey == KBKEY_F4) /* ||
|
||||
(display->key_lctrl && kbkey == KBKEY_Q)*/ )
|
||||
{
|
||||
struct event_keyboard event;
|
||||
event.window_id = display->active_window->window_id;
|
||||
|
||||
struct display_packet_header header;
|
||||
header.message_id = EVENT_QUIT;
|
||||
header.message_length = sizeof(event);
|
||||
|
||||
assert(window->connection);
|
||||
|
||||
connection_schedule_transmit(window->connection, &header, sizeof(header));
|
||||
connection_schedule_transmit(window->connection, &event, sizeof(event));
|
||||
return;
|
||||
}
|
||||
|
||||
if ( display->key_lalt && kbkey == KBKEY_F10 )
|
||||
{
|
||||
window_toggle_maximized(display->active_window);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( display->key_lalt && kbkey == KBKEY_TAB )
|
||||
{
|
||||
if ( !display->tab_candidate )
|
||||
display->tab_candidate = display->active_window;
|
||||
struct window* old_candidate = display->tab_candidate;
|
||||
if ( !(display->tab_candidate = old_candidate->below_window) )
|
||||
display->tab_candidate = display->top_window;
|
||||
window_render_frame(old_candidate);
|
||||
window_render_frame(display->tab_candidate);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( kbkey == -KBKEY_LALT && display->tab_candidate )
|
||||
{
|
||||
if ( display->tab_candidate != display->active_window )
|
||||
display_set_active_window(display, display->tab_candidate);
|
||||
display->tab_candidate = NULL;
|
||||
window = display->active_window;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( display->key_lalt )
|
||||
{
|
||||
struct window* window = display->active_window;
|
||||
if ( kbkey == KBKEY_LEFT )
|
||||
{
|
||||
window_move(window, window->left - 10, window->top);
|
||||
return;
|
||||
}
|
||||
if ( kbkey == KBKEY_RIGHT )
|
||||
{
|
||||
window_move(window, window->left + 10, window->top);
|
||||
return;
|
||||
}
|
||||
if ( kbkey == KBKEY_UP )
|
||||
{
|
||||
window_move(window, window->left, window->top - 10);
|
||||
return;
|
||||
}
|
||||
if ( kbkey == KBKEY_DOWN )
|
||||
{
|
||||
window_move(window, window->left, window->top + 10);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* grab_inputbed_string = " - Input Grabbed";
|
||||
if ( kbkey == KBKEY_F11 && window && !window->grab_input )
|
||||
{
|
||||
// TODO: window->title can be null.
|
||||
char* new_title;
|
||||
if ( 0 <= asprintf(&new_title, "%s%s", window->title, grab_inputbed_string) )
|
||||
{
|
||||
window->grab_input = true;
|
||||
free(window->title);
|
||||
window->title = new_title;
|
||||
window_render_frame(window);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( kbkey == KBKEY_F12 && window && window->grab_input )
|
||||
{
|
||||
// TODO: Only remove from title if there.
|
||||
size_t grab_inputbed_string_len = strlen(grab_inputbed_string);
|
||||
window->title[strlen(window->title) - grab_inputbed_string_len] = '\0';
|
||||
window->grab_input = false;
|
||||
window_render_frame(window);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !window )
|
||||
return;
|
||||
|
||||
struct event_keyboard event;
|
||||
event.window_id = display->active_window->window_id;
|
||||
event.codepoint = codepoint;
|
||||
|
||||
struct display_packet_header header;
|
||||
header.message_id = EVENT_KEYBOARD;
|
||||
header.message_length = sizeof(event);
|
||||
|
||||
assert(window->connection);
|
||||
|
||||
connection_schedule_transmit(window->connection, &header, sizeof(header));
|
||||
connection_schedule_transmit(window->connection, &event, sizeof(event));
|
||||
}
|
||||
|
||||
void display_mouse_event(struct display* display, uint8_t byte)
|
||||
{
|
||||
if ( display->mouse_byte_count == 0 && !(byte & MOUSE_ALWAYS_1) )
|
||||
return;
|
||||
if ( display->mouse_byte_count < MOUSE_PACKET_SIZE )
|
||||
display->mouse_bytes[display->mouse_byte_count++] = byte;
|
||||
if ( display->mouse_byte_count < MOUSE_PACKET_SIZE )
|
||||
return;
|
||||
display->mouse_byte_count = 0;
|
||||
uint8_t* bytes = display->mouse_bytes;
|
||||
|
||||
int xm = MOUSE_X(bytes);
|
||||
int ym = MOUSE_Y(bytes);
|
||||
|
||||
int old_pointer_x = display->pointer_x;
|
||||
int old_pointer_y = display->pointer_y;
|
||||
|
||||
if ( xm*xm + ym*ym >= 2*2 )
|
||||
{
|
||||
xm *= 2;
|
||||
ym *= 2;
|
||||
}
|
||||
else if ( xm*xm + ym*ym >= 5*5 )
|
||||
{
|
||||
xm *= 3;
|
||||
ym *= 3;
|
||||
}
|
||||
display->pointer_x += xm;
|
||||
display->pointer_y += ym;
|
||||
|
||||
if ( display->pointer_x < 0 )
|
||||
display->pointer_x = 0;
|
||||
if ( display->pointer_y < 0 )
|
||||
display->pointer_y = 0;
|
||||
if ( display->screen_width <= (size_t) display->pointer_x )
|
||||
display->pointer_x = display->screen_width;
|
||||
if ( display->screen_height <= (size_t) display->pointer_y )
|
||||
display->pointer_y = display->screen_height;
|
||||
xm = display->pointer_x - old_pointer_x;
|
||||
ym = display->pointer_y - old_pointer_y;
|
||||
|
||||
struct window* window;
|
||||
for ( window = display->top_window; window; window = window->below_window )
|
||||
{
|
||||
if ( old_pointer_x < window->left )
|
||||
continue;
|
||||
if ( old_pointer_y < window->top )
|
||||
continue;
|
||||
if ( old_pointer_x > window->left + (ssize_t) window->width )
|
||||
continue;
|
||||
if ( old_pointer_y > window->top + (ssize_t) window->height )
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if ( !window )
|
||||
return;
|
||||
if ( window->window_state != WINDOW_STATE_REGULAR )
|
||||
return;
|
||||
|
||||
if ( bytes[0] & MOUSE_BUTTON_LEFT )
|
||||
{
|
||||
display_set_active_window(display, window);
|
||||
window_move(window, window->left + xm, window->top + ym);
|
||||
}
|
||||
}
|
||||
|
||||
void display_on_resolution_change(struct display* display, size_t width, size_t height)
|
||||
{
|
||||
if ( display->screen_width == width && display->screen_height == height )
|
||||
return;
|
||||
display->screen_width = width;
|
||||
display->screen_height = height;
|
||||
display->pointer_x = width / 2;
|
||||
display->pointer_y = height / 2;
|
||||
for ( struct window* window = display->bottom_window; window; window = window->above_window )
|
||||
window_on_display_resolution_change(window, display);
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* display.c
|
||||
* Display server.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "arrow.inc"
|
||||
|
||||
#include "display.h"
|
||||
#include "framebuffer.h"
|
||||
#include "server.h"
|
||||
|
||||
uint32_t arrow_buffer[48 * 48];
|
||||
struct framebuffer arrow_framebuffer = { 48, arrow_buffer, 48, 48 };
|
||||
|
||||
static void compact_arguments(int* argc, char*** argv)
|
||||
{
|
||||
for ( int i = 0; i < *argc; i++ )
|
||||
{
|
||||
while ( i < *argc && !(*argv)[i] )
|
||||
{
|
||||
for ( int n = i; n < *argc; n++ )
|
||||
(*argv)[n] = (*argv)[n+1];
|
||||
(*argc)--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
for ( int i = 1; i < argc; i++ )
|
||||
{
|
||||
const char* arg = argv[i];
|
||||
if ( arg[0] != '-' || !arg[1] )
|
||||
continue;
|
||||
argv[i] = NULL;
|
||||
if ( !strcmp(arg, "--") )
|
||||
break;
|
||||
if ( arg[1] != '-' )
|
||||
{
|
||||
char c;
|
||||
while ( (c = *++arg) ) switch ( c )
|
||||
{
|
||||
default:
|
||||
errx(1, "unknown option -- '%c'", c);
|
||||
}
|
||||
}
|
||||
else
|
||||
errx(1, "unknown option: %s", arg);
|
||||
}
|
||||
|
||||
compact_arguments(&argc, &argv);
|
||||
|
||||
memcpy(arrow_buffer, arrow, sizeof(arrow));
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
if ( getpgid(0) != getpid() )
|
||||
errx(1, "This program must be run in its own process group");
|
||||
|
||||
struct display display;
|
||||
display_initialize(&display);
|
||||
|
||||
struct server server;
|
||||
server_initialize(&server, &display);
|
||||
|
||||
if ( setenv("DISPLAY_SOCKET", server.server_path, 1) < 0 )
|
||||
err(1, "setenv");
|
||||
|
||||
if ( 1 < argc )
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if ( pid < 0 )
|
||||
warn("fork");
|
||||
else if ( pid == 0 )
|
||||
{
|
||||
execvp(argv[1], argv + 1);
|
||||
warn("%s", argv[1]);
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
|
||||
server_mainloop(&server);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* display.h
|
||||
* Display server.
|
||||
*/
|
||||
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
#include <sys/ps2mouse.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "damage-rect.h"
|
||||
#include "framebuffer.h"
|
||||
|
||||
struct window;
|
||||
|
||||
struct display
|
||||
{
|
||||
struct damage_rect damage_rect;
|
||||
struct window* top_window;
|
||||
struct window* bottom_window;
|
||||
struct window* active_window;
|
||||
struct window* tab_candidate;
|
||||
size_t screen_width;
|
||||
size_t screen_height;
|
||||
size_t num_tabs;
|
||||
bool key_lctrl;
|
||||
bool key_lalt;
|
||||
int pointer_x;
|
||||
int pointer_y;
|
||||
size_t mouse_byte_count;
|
||||
uint8_t mouse_bytes[MOUSE_PACKET_SIZE];
|
||||
};
|
||||
|
||||
void display_initialize(struct display* display);
|
||||
void assert_is_well_formed_display_list(struct display* display);
|
||||
void assert_is_well_formed_display(struct display* display);
|
||||
void display_link_window_at_top(struct display* display, struct window* window);
|
||||
void display_unlink_window(struct display* display, struct window* window);
|
||||
void display_unlink_window_removal(struct display* display, struct window* window);
|
||||
void display_unmark_active_window(struct display* display, struct window* window);
|
||||
void display_mark_active_window(struct display* display, struct window* window);
|
||||
void display_update_active_window(struct display* display);
|
||||
void display_move_window_to_top(struct display* display, struct window* window);
|
||||
void display_change_active_window(struct display* display, struct window* window);
|
||||
void display_set_active_window(struct display* display, struct window* window);
|
||||
void display_add_window(struct display* display, struct window* window);
|
||||
void display_remove_window(struct display* display, struct window* window);
|
||||
void display_composit(struct display* display, struct framebuffer fb);
|
||||
void display_render(struct display* display);
|
||||
void display_keyboard_event(struct display* display, uint32_t codepoint);
|
||||
void display_on_resolution_change(struct display* display, size_t width, size_t height);
|
||||
void display_mouse_event(struct display* display, uint8_t byte);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* server.c
|
||||
* Display server main loop.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/termmode.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <display-protocol.h>
|
||||
|
||||
#include "connection.h"
|
||||
#include "display.h"
|
||||
#include "server.h"
|
||||
#include "vgafont.h"
|
||||
|
||||
static int open_local_server_socket(const char* path, int flags)
|
||||
{
|
||||
size_t path_length = strlen(path);
|
||||
size_t addr_size = offsetof(struct sockaddr_un, sun_path) + path_length + 1;
|
||||
struct sockaddr_un* sockaddr = (struct sockaddr_un*) malloc(addr_size);
|
||||
if ( !sockaddr )
|
||||
return -1;
|
||||
sockaddr->sun_family = AF_LOCAL;
|
||||
strcpy(sockaddr->sun_path, path);
|
||||
int fd = socket(AF_LOCAL, SOCK_STREAM | flags, 0);
|
||||
if ( fd < 0 )
|
||||
return free(sockaddr), -1;
|
||||
if ( bind(fd, (const struct sockaddr*) sockaddr, addr_size) < 0 )
|
||||
return close(fd), free(sockaddr), -1;
|
||||
if ( listen(fd, 5) < 0 )
|
||||
return close(fd), free(sockaddr), -1;
|
||||
free(sockaddr);
|
||||
return fd;
|
||||
}
|
||||
|
||||
void server_initialize(struct server* server, struct display* display)
|
||||
{
|
||||
memset(server, 0, sizeof(*server));
|
||||
|
||||
server->display = display;
|
||||
|
||||
load_font();
|
||||
|
||||
server->tty_fd = 0;
|
||||
if ( !isatty(0) )
|
||||
{
|
||||
server->tty_fd = open("/dev/tty", O_RDONLY);
|
||||
if ( server->tty_fd < 0 )
|
||||
err(1, "/dev/tty");
|
||||
}
|
||||
|
||||
server->mouse_fd = open("/dev/mouse", O_RDONLY | O_CLOEXEC);
|
||||
if ( server->mouse_fd < 0 )
|
||||
err(1, "%s", "/dev/mouse");
|
||||
|
||||
server->server_path = "/run/display";
|
||||
server->server_fd = open_local_server_socket(server->server_path,
|
||||
SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
if ( server->server_fd < 0 )
|
||||
err(1, "open_local_server_socket: %s", server->server_path);
|
||||
|
||||
unsigned int termmode =
|
||||
TERMMODE_KBKEY | TERMMODE_UNICODE | TERMMODE_NONBLOCK;
|
||||
if ( settermmode(0, termmode) < 0 )
|
||||
err(1, "settermmode");
|
||||
|
||||
server->pfds_count = server_pfds_count(server);
|
||||
server->pfds = (struct pollfd*)
|
||||
reallocarray(NULL, sizeof(struct pollfd), server->pfds_count);
|
||||
if ( !server->pfds )
|
||||
err(1, "malloc");
|
||||
}
|
||||
|
||||
bool server_accept(struct server* server)
|
||||
{
|
||||
int client_fd = accept4(server->server_fd, NULL, NULL, SOCK_NONBLOCK);
|
||||
if ( client_fd < 0 )
|
||||
{
|
||||
warn("accept: %s", server->server_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( server->connections_used == server->connections_length )
|
||||
{
|
||||
size_t new_length = server->connections_length * 2;
|
||||
if ( !new_length )
|
||||
new_length = 16;
|
||||
struct connection** new_connections = (struct connection**)
|
||||
reallocarray(server->connections, new_length,
|
||||
sizeof(struct connection*));
|
||||
if ( !new_connections )
|
||||
{
|
||||
warn("dropped connection: %s: malloc", server->server_path);
|
||||
close(client_fd);
|
||||
return false;
|
||||
}
|
||||
server->connections = new_connections;
|
||||
server->connections_length = new_length;
|
||||
}
|
||||
|
||||
size_t new_pfds_count = server_pfds_count(server) + 1;
|
||||
struct pollfd* new_pfds = (struct pollfd*)
|
||||
reallocarray(server->pfds, sizeof(struct pollfd), new_pfds_count);
|
||||
if ( !new_pfds )
|
||||
{
|
||||
warn("dropped connection: %s: malloc", server->server_path);
|
||||
close(client_fd);
|
||||
return false;
|
||||
}
|
||||
server->pfds = new_pfds;
|
||||
server->pfds_count = new_pfds_count;
|
||||
|
||||
struct connection* connection = (struct connection*)
|
||||
malloc(sizeof(struct connection));
|
||||
if ( !connection )
|
||||
{
|
||||
warn("dropped connection: %s: malloc", server->server_path);
|
||||
close(client_fd);
|
||||
return false;
|
||||
}
|
||||
server->connections[server->connections_used++] = connection;
|
||||
connection_initialize(connection, server->display, client_fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t server_pfds_count(const struct server* server)
|
||||
{
|
||||
return 3 + server->connections_used;
|
||||
}
|
||||
|
||||
void server_poll(struct server* server)
|
||||
{
|
||||
int code;
|
||||
while ( 0 < waitpid(-1, &code, WNOHANG) )
|
||||
{
|
||||
}
|
||||
|
||||
struct pollfd* pfds = server->pfds;
|
||||
|
||||
pfds[0].fd = server->server_fd;
|
||||
pfds[0].events = POLLIN;
|
||||
pfds[0].revents = 0;
|
||||
pfds[1].fd = server->tty_fd;
|
||||
pfds[1].events = POLLIN;
|
||||
pfds[1].revents = 0;
|
||||
pfds[2].fd = server->mouse_fd;
|
||||
pfds[2].events = POLLIN;
|
||||
pfds[2].revents = 0;
|
||||
size_t cpfd_off = 3;
|
||||
|
||||
size_t connections_polled = server->connections_used;
|
||||
for ( size_t i = 0; i < connections_polled; i++ )
|
||||
{
|
||||
struct pollfd* pfd = &pfds[cpfd_off + i];
|
||||
struct connection* connection = server->connections[i];
|
||||
pfd->fd = connection->fd;
|
||||
pfd->events = connection_interested_poll_events(connection);
|
||||
pfd->revents = 0;
|
||||
}
|
||||
size_t pfds_used = cpfd_off + connections_polled;
|
||||
|
||||
int num_events = ppoll(pfds, pfds_used, NULL, NULL);
|
||||
if ( num_events < 0 )
|
||||
err(1, "poll");
|
||||
|
||||
if ( pfds[0].revents )
|
||||
{
|
||||
// TODO: Handle if this can actually happen.
|
||||
assert(!(pfds[0].revents & POLLERR));
|
||||
assert(!(pfds[0].revents & POLLHUP));
|
||||
assert(!(pfds[0].revents & POLLNVAL));
|
||||
|
||||
server_accept(server);
|
||||
}
|
||||
|
||||
if ( pfds[1].revents )
|
||||
{
|
||||
// TODO: Handle if this can actually happen.
|
||||
assert(!(pfds[1].revents & POLLERR));
|
||||
assert(!(pfds[1].revents & POLLHUP));
|
||||
assert(!(pfds[1].revents & POLLNVAL));
|
||||
|
||||
uint32_t codepoint;
|
||||
ssize_t size = sizeof(codepoint);
|
||||
while ( read(server->tty_fd, &codepoint, size) == size )
|
||||
display_keyboard_event(server->display, codepoint);
|
||||
}
|
||||
|
||||
if ( pfds[2].revents )
|
||||
{
|
||||
// TODO: Handle if this can actually happen.
|
||||
assert(!(pfds[2].revents & POLLERR));
|
||||
assert(!(pfds[2].revents & POLLHUP));
|
||||
assert(!(pfds[2].revents & POLLNVAL));
|
||||
|
||||
unsigned char events[64];
|
||||
ssize_t amount = read(server->mouse_fd, events, sizeof(events));
|
||||
for ( ssize_t i = 0; i < amount; i++ )
|
||||
display_mouse_event(server->display, events[i]);
|
||||
}
|
||||
|
||||
bool any_disconnect = false;
|
||||
for ( size_t i = 0; i < connections_polled; i++ )
|
||||
{
|
||||
struct pollfd* pfd = &pfds[cpfd_off + i];
|
||||
if ( !pfd->revents )
|
||||
continue;
|
||||
struct connection* connection = server->connections[i];
|
||||
if ( pfd->revents & (POLLERR | POLLHUP | POLLNVAL) &&
|
||||
!(pfd->revents & POLLIN) )
|
||||
{
|
||||
connection_destroy(connection);
|
||||
free(connection);
|
||||
server->connections[i] = NULL;
|
||||
any_disconnect = true;
|
||||
continue;
|
||||
}
|
||||
if ( pfd->revents & POLLOUT )
|
||||
connection_can_write(connection);
|
||||
if ( pfd->revents & POLLIN )
|
||||
connection_can_read(connection);
|
||||
}
|
||||
|
||||
// Compact the array down here so the pfds match the connections above.
|
||||
if ( any_disconnect )
|
||||
{
|
||||
size_t new_used = 0;
|
||||
for ( size_t i = 0; i < server->connections_used; i++ )
|
||||
{
|
||||
if ( server->connections[i] )
|
||||
server->connections[new_used++] = server->connections[i];
|
||||
}
|
||||
server->connections_used = new_used;
|
||||
}
|
||||
}
|
||||
|
||||
void server_mainloop(struct server* server)
|
||||
{
|
||||
while ( true )
|
||||
{
|
||||
// TODO: Only do this if a redraw is actually needed.
|
||||
display_render(server->display);
|
||||
server_poll(server);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* connection.h
|
||||
* Display server main loop.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct connection;
|
||||
struct display;
|
||||
struct pollfd;
|
||||
|
||||
struct server
|
||||
{
|
||||
struct display* display;
|
||||
const char* server_path;
|
||||
int server_fd;
|
||||
int tty_fd;
|
||||
int mouse_fd;
|
||||
struct connection** connections;
|
||||
size_t connections_used;
|
||||
size_t connections_length;
|
||||
struct pollfd* pfds;
|
||||
size_t pfds_count;
|
||||
};
|
||||
|
||||
void server_initialize(struct server* server, struct display* display);
|
||||
bool server_accept(struct server* server);
|
||||
size_t server_pfds_count(const struct server* server);
|
||||
void server_poll(struct server* server);
|
||||
void server_mainloop(struct server* server);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* window.c
|
||||
* Window abstraction.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <display-protocol.h>
|
||||
|
||||
#include "connection.h"
|
||||
#include "display.h"
|
||||
#include "framebuffer.h"
|
||||
#include "pixel.h"
|
||||
#include "vgafont.h"
|
||||
#include "window.h"
|
||||
|
||||
struct framebuffer window_client_buffer(struct window* window)
|
||||
{
|
||||
if ( window->window_state == WINDOW_STATE_MAXIMIZED )
|
||||
return framebuffer_crop(window->buffer, 0, TITLE_HEIGHT,
|
||||
window->width, window->height - TITLE_HEIGHT);
|
||||
return framebuffer_crop(window->buffer, BORDER_WIDTH, TITLE_HEIGHT,
|
||||
window->width - 2 * BORDER_WIDTH,
|
||||
window->height - TITLE_HEIGHT - BORDER_WIDTH);
|
||||
}
|
||||
|
||||
void window_render_frame(struct window* window)
|
||||
{
|
||||
if ( !window->width || !window->height )
|
||||
return;
|
||||
|
||||
bool has_focus = window->display->tab_candidate ?
|
||||
window->display->tab_candidate == window :
|
||||
window->display->active_window == window;
|
||||
|
||||
uint32_t glass_color = has_focus ? make_color_a(200, 200, 255, 192)
|
||||
: make_color_a(180, 180, 255, 128);
|
||||
uint32_t title_color = has_focus ? make_color_a(16, 16, 16, 240)
|
||||
: make_color_a(32, 32, 32, 200);
|
||||
|
||||
size_t start_x = 0;
|
||||
size_t start_y = 0;
|
||||
size_t end_x = window->width - 1;
|
||||
size_t end_y = window->height - 1;
|
||||
|
||||
bool maximized = window->window_state == WINDOW_STATE_MAXIMIZED;
|
||||
|
||||
int b0 = 0;
|
||||
int b1 = 1;
|
||||
int b2 = 2;
|
||||
int b3 = BORDER_WIDTH;
|
||||
int t0 = TITLE_HEIGHT;
|
||||
|
||||
for ( size_t y = start_y; y <= end_y; y++ )
|
||||
{
|
||||
for ( size_t x = start_x; x <= end_x; x++ )
|
||||
{
|
||||
uint32_t color;
|
||||
if ( maximized && y <= start_y + t0 )
|
||||
color = glass_color;
|
||||
else if ( maximized )
|
||||
continue;
|
||||
else if ( x == start_x + b0 || x == end_x - b0 ||
|
||||
y == start_y + b0 || y == end_y - b0 )
|
||||
color = make_color_a(0, 0, 0, 32);
|
||||
else if ( x == start_x + b1 || x == end_x - b1 ||
|
||||
y == start_y + b1 || y == end_y - b1 )
|
||||
color = make_color_a(0, 0, 0, 64);
|
||||
else if ( x == start_x + b2 || x == end_x - b2 ||
|
||||
y == start_y + b2 ||+ y == end_y - b2 )
|
||||
color = make_color(240, 240, 250);
|
||||
else if ( x < start_x + (b3-1) || x > end_x - (b3-1) ||
|
||||
y < start_y + (t0-1) || y > end_y - (b3-1) )
|
||||
color = glass_color;
|
||||
else if ( x == start_x + (b3-1) || x == end_x - (b3-1) ||
|
||||
y == start_y + (t0-1) || y == end_y - (b3-1) )
|
||||
color = make_color(64, 64, 64);
|
||||
else
|
||||
continue;
|
||||
framebuffer_set_pixel(window->buffer, x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
const char* tt = window->title ? window->title : "";
|
||||
size_t tt_max_width = window->width - 2 * BORDER_WIDTH;
|
||||
size_t tt_desired_width = render_text_width(tt);
|
||||
size_t tt_width = tt_desired_width < tt_max_width ? tt_desired_width : tt_max_width;
|
||||
size_t tt_height = FONT_HEIGHT;
|
||||
size_t tt_pos_x = BORDER_WIDTH + (tt_max_width - tt_width) / 2;
|
||||
size_t tt_pos_y = (TITLE_HEIGHT - FONT_HEIGHT) / 2 + 2;
|
||||
uint32_t tt_color = title_color;
|
||||
render_text(framebuffer_crop(window->buffer, tt_pos_x, tt_pos_y, tt_width, tt_height), tt, tt_color);
|
||||
}
|
||||
|
||||
void window_move(struct window* window, size_t left, size_t top)
|
||||
{
|
||||
window->left = left;
|
||||
window->top = top;
|
||||
}
|
||||
|
||||
void window_client_resize(struct window* window,
|
||||
size_t client_width,
|
||||
size_t client_height)
|
||||
{
|
||||
if ( window->window_state == WINDOW_STATE_MAXIMIZED )
|
||||
window->window_state = WINDOW_STATE_REGULAR;
|
||||
|
||||
free(window->buffer.buffer);
|
||||
|
||||
window->width = client_width + BORDER_WIDTH + BORDER_WIDTH;
|
||||
window->height = client_height + TITLE_HEIGHT + BORDER_WIDTH;
|
||||
|
||||
window->buffer.xres = window->width;
|
||||
window->buffer.yres = window->height;
|
||||
window->buffer.pitch = window->width;
|
||||
window->buffer.buffer = (uint32_t*)
|
||||
malloc(sizeof(uint32_t) * window->width * window->height);
|
||||
memset(window->buffer.buffer, 0, sizeof(uint32_t) * window->width * window->height);
|
||||
|
||||
window_render_frame(window);
|
||||
window_notify_client_resize(window);
|
||||
}
|
||||
|
||||
void window_resize(struct window* window, size_t width, size_t height)
|
||||
{
|
||||
if ( width < BORDER_WIDTH + BORDER_WIDTH )
|
||||
width = BORDER_WIDTH + BORDER_WIDTH;
|
||||
if ( height < TITLE_HEIGHT + BORDER_WIDTH )
|
||||
height = TITLE_HEIGHT + BORDER_WIDTH;
|
||||
size_t client_width = width - (BORDER_WIDTH + BORDER_WIDTH);
|
||||
size_t client_height = height - (TITLE_HEIGHT + BORDER_WIDTH);
|
||||
window_client_resize(window, client_width, client_height);
|
||||
}
|
||||
|
||||
static size_t next_window_position = 25;
|
||||
|
||||
void window_initialize(struct window* window,
|
||||
struct connection* connection,
|
||||
struct display* display,
|
||||
uint32_t window_id)
|
||||
{
|
||||
memset(window, 0, sizeof(*window));
|
||||
window->created = true;
|
||||
window->connection = connection;
|
||||
window->display = display;
|
||||
window->title = NULL;
|
||||
window->window_id = window_id;
|
||||
display_add_window(window->display, window);
|
||||
window->top = next_window_position;
|
||||
window->left = next_window_position;
|
||||
next_window_position += 30;
|
||||
window_client_resize(window, 0, 0);
|
||||
}
|
||||
|
||||
void window_destroy(struct window* window)
|
||||
{
|
||||
display_remove_window(window->display, window);
|
||||
free(window->buffer.buffer);
|
||||
free(window->title);
|
||||
memset(window, 0, sizeof(*window));
|
||||
window->created = false;
|
||||
}
|
||||
|
||||
void window_on_display_resolution_change(struct window* window, struct display* display)
|
||||
{
|
||||
// TODO: Potentially move window back inside screen?
|
||||
if ( window->window_state == WINDOW_STATE_MAXIMIZED )
|
||||
{
|
||||
// TODO: Change size of maximized window.
|
||||
(void) display;
|
||||
}
|
||||
}
|
||||
|
||||
void window_maximize(struct window* window)
|
||||
{
|
||||
if ( window->window_state == WINDOW_STATE_MAXIMIZED )
|
||||
return;
|
||||
window->saved_left = window->left;
|
||||
window->saved_top = window->top;
|
||||
window->saved_width = window->width;
|
||||
window->saved_height = window->height;
|
||||
|
||||
free(window->buffer.buffer);
|
||||
|
||||
window->top = 0;
|
||||
window->left = 0;
|
||||
window->width = window->display->screen_width;
|
||||
window->height = window->display->screen_height;
|
||||
|
||||
window->buffer.xres = window->width;
|
||||
window->buffer.yres = window->height;
|
||||
window->buffer.pitch = window->width;
|
||||
window->buffer.buffer = (uint32_t*)
|
||||
malloc(sizeof(uint32_t) * window->width * window->height);
|
||||
memset(window->buffer.buffer, 0, sizeof(uint32_t) * window->width * window->height);
|
||||
|
||||
window->window_state = WINDOW_STATE_MAXIMIZED;
|
||||
|
||||
window_render_frame(window);
|
||||
window_notify_client_resize(window);
|
||||
}
|
||||
|
||||
void window_restore(struct window* window)
|
||||
{
|
||||
if ( window->window_state != WINDOW_STATE_MAXIMIZED )
|
||||
return;
|
||||
window->top = window->saved_top;
|
||||
window->left = window->saved_left;
|
||||
window_client_resize(window, window->saved_width - 2 * BORDER_WIDTH, window->saved_height - TITLE_HEIGHT - BORDER_WIDTH);
|
||||
window_notify_client_resize(window);
|
||||
}
|
||||
|
||||
void window_toggle_maximized(struct window* window)
|
||||
{
|
||||
if ( window->window_state == WINDOW_STATE_MAXIMIZED )
|
||||
window_restore(window);
|
||||
else
|
||||
window_maximize(window);
|
||||
}
|
||||
|
||||
void window_notify_client_resize(struct window* window)
|
||||
{
|
||||
struct event_resize event;
|
||||
event.window_id = window->window_id;
|
||||
event.width = window_client_buffer(window).xres;
|
||||
event.height = window_client_buffer(window).yres;
|
||||
|
||||
struct display_packet_header header;
|
||||
header.message_id = EVENT_RESIZE;
|
||||
header.message_length = sizeof(event);
|
||||
|
||||
assert(window->connection);
|
||||
|
||||
connection_schedule_transmit(window->connection, &header, sizeof(header));
|
||||
connection_schedule_transmit(window->connection, &event, sizeof(event));
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016, 2018 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* window.h
|
||||
* Window abstraction.
|
||||
*/
|
||||
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "framebuffer.h"
|
||||
|
||||
struct connection;
|
||||
struct display;
|
||||
|
||||
static const size_t BORDER_WIDTH = 8;
|
||||
static const size_t TITLE_HEIGHT = 28;
|
||||
|
||||
enum window_state
|
||||
{
|
||||
WINDOW_STATE_REGULAR,
|
||||
WINDOW_STATE_MAXIMIZED,
|
||||
WINDOW_STATE_MINIMIZED,
|
||||
};
|
||||
|
||||
struct window
|
||||
{
|
||||
struct display* display;
|
||||
struct connection* connection;
|
||||
struct window* above_window;
|
||||
struct window* below_window;
|
||||
struct framebuffer buffer;
|
||||
char* title;
|
||||
ssize_t left;
|
||||
ssize_t top;
|
||||
size_t width;
|
||||
size_t height;
|
||||
ssize_t saved_left;
|
||||
ssize_t saved_top;
|
||||
size_t saved_width;
|
||||
size_t saved_height;
|
||||
uint32_t window_id;
|
||||
enum window_state window_state;
|
||||
bool created;
|
||||
bool show;
|
||||
bool focus;
|
||||
bool grab_input;
|
||||
};
|
||||
|
||||
struct framebuffer window_client_buffer(struct window* window);
|
||||
void window_render_frame(struct window* window);
|
||||
void window_move(struct window* window, size_t left, size_t top);
|
||||
void window_resize(struct window* window, size_t width, size_t height);
|
||||
void window_client_resize(struct window* window, size_t client_width, size_t client_height);
|
||||
void window_initialize(struct window* window, struct connection* connection, struct display* display, uint32_t window_id);
|
||||
void window_destroy(struct window* window);
|
||||
void window_on_display_resolution_change(struct window* window, struct display* display);
|
||||
void window_maximize(struct window* window);
|
||||
void window_restore(struct window* window);
|
||||
void window_toggle_maximized(struct window* window);
|
||||
void window_notify_client_resize(struct window* window);
|
||||
|
||||
#endif
|
|
@ -15,7 +15,7 @@ BINARIES:=\
|
|||
asteroids \
|
||||
aquatinspitz \
|
||||
|
||||
LIBS:=-ldispd
|
||||
LIBS:=-ldispd -ldisplay
|
||||
|
||||
all: $(BINARIES)
|
||||
|
||||
|
|
|
@ -36,7 +36,11 @@
|
|||
#include <timespec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <dispd.h>
|
||||
#include <display.h>
|
||||
|
||||
uint32_t WINDOW_ID = 0;
|
||||
uint32_t WINDOW_WIDTH = 800;
|
||||
uint32_t WINDOW_HEIGHT = 512;
|
||||
|
||||
static inline float RandomFloat()
|
||||
{
|
||||
|
@ -60,7 +64,7 @@ static inline float RandomAngle()
|
|||
|
||||
static inline uint32_t MakeColor(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return b << 0UL | g << 8UL | r << 16UL;
|
||||
return b << 0UL | g << 8UL | r << 16UL | 0xFF << 24UL;
|
||||
}
|
||||
|
||||
static const size_t STARFIELD_WIDTH = 512UL;
|
||||
|
@ -110,31 +114,6 @@ bool pop_is_key_just_down(int abskbkey)
|
|||
return true;
|
||||
}
|
||||
|
||||
void FetchKeyboardInput()
|
||||
{
|
||||
// Read the keyboard input from the user.
|
||||
const unsigned termmode = TERMMODE_KBKEY
|
||||
| TERMMODE_SIGNAL
|
||||
| TERMMODE_NONBLOCK;
|
||||
if ( settermmode(0, termmode) )
|
||||
error(1, errno, "settermmode");
|
||||
uint32_t codepoint;
|
||||
ssize_t numbytes;
|
||||
while ( 0 < (numbytes = read(0, &codepoint, sizeof(codepoint))) )
|
||||
{
|
||||
int kbkey = KBKEY_DECODE(codepoint);
|
||||
if( !kbkey )
|
||||
continue;
|
||||
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
|
||||
if ( MAXKEYNUM <= (size_t) abskbkey )
|
||||
continue;
|
||||
bool is_key_down_event = 0 < kbkey;
|
||||
if ( !keysdown[abskbkey] && is_key_down_event )
|
||||
keyspending[abskbkey] = true;
|
||||
keysdown[abskbkey] = is_key_down_event;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t xres;
|
||||
static size_t yres;
|
||||
static size_t bpp;
|
||||
|
@ -1143,25 +1122,85 @@ void Render()
|
|||
obj->Render();
|
||||
}
|
||||
}
|
||||
void RunFrame(struct dispd_window* window)
|
||||
|
||||
void on_disconnect(void*)
|
||||
{
|
||||
struct dispd_framebuffer* fb = dispd_begin_render(window);
|
||||
if ( !fb )
|
||||
{
|
||||
error(0, 0, "unable to begin rendering dispd window");
|
||||
gamerunning = false;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void on_quit(void*, uint32_t)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void on_resize(void*, uint32_t window_id, uint32_t width, uint32_t height)
|
||||
{
|
||||
if ( window_id != WINDOW_ID )
|
||||
return;
|
||||
WINDOW_WIDTH = width;
|
||||
WINDOW_HEIGHT = height;
|
||||
}
|
||||
|
||||
void on_keyboard(void*, uint32_t window_id, uint32_t codepoint)
|
||||
{
|
||||
if ( window_id != WINDOW_ID )
|
||||
return;
|
||||
int kbkey = KBKEY_DECODE(codepoint);
|
||||
if( !kbkey )
|
||||
return;
|
||||
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
|
||||
if ( MAXKEYNUM <= (size_t) abskbkey )
|
||||
return;
|
||||
bool is_key_down_event = 0 < kbkey;
|
||||
if ( !keysdown[abskbkey] && is_key_down_event )
|
||||
keyspending[abskbkey] = true;
|
||||
keysdown[abskbkey] = is_key_down_event;
|
||||
}
|
||||
|
||||
void RunFrame(struct display_connection* connection)
|
||||
{
|
||||
struct display_event_handlers handlers;
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
handlers.disconnect_handler = on_disconnect;
|
||||
handlers.quit_handler = on_quit;
|
||||
handlers.resize_handler = on_resize;
|
||||
handlers.keyboard_handler = on_keyboard;
|
||||
|
||||
while ( display_poll_event(connection, &handlers) == 0 );
|
||||
|
||||
size_t old_framesize = framesize;
|
||||
|
||||
xres = WINDOW_WIDTH;
|
||||
yres = WINDOW_HEIGHT;
|
||||
bpp = 32;
|
||||
linesize = WINDOW_WIDTH;
|
||||
framesize = WINDOW_WIDTH * sizeof(uint32_t) * WINDOW_HEIGHT;
|
||||
if ( old_framesize != framesize )
|
||||
{
|
||||
free(buf);
|
||||
buf = (uint32_t*) malloc(framesize);
|
||||
}
|
||||
xres = dispd_get_framebuffer_width(fb);
|
||||
yres = dispd_get_framebuffer_height(fb);
|
||||
bpp = dispd_get_framebuffer_format(fb);
|
||||
linesize = dispd_get_framebuffer_pitch(fb) / (bpp / 8);
|
||||
framesize = dispd_get_framebuffer_pitch(fb) * yres;
|
||||
buf = (uint32_t*) dispd_get_framebuffer_data(fb);
|
||||
FetchKeyboardInput();
|
||||
|
||||
GameLogic();
|
||||
Render();
|
||||
dispd_finish_render(fb);
|
||||
|
||||
static int fps_counter = 0;
|
||||
fps_counter++;
|
||||
static time_t last_frame_sec = 0;
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if ( now.tv_sec != last_frame_sec )
|
||||
{
|
||||
char* title = NULL;
|
||||
asprintf(&title, "Asteroids (fps %i)", fps_counter);
|
||||
display_title_window(connection, WINDOW_ID, title);
|
||||
free(title);
|
||||
fps_counter = 0;
|
||||
last_frame_sec = now.tv_sec;
|
||||
}
|
||||
|
||||
display_render_window(connection, WINDOW_ID, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, buf);
|
||||
display_show_window(connection, WINDOW_ID);
|
||||
}
|
||||
|
||||
void InitGame()
|
||||
|
@ -1172,64 +1211,24 @@ void InitGame()
|
|||
new AsteroidField;
|
||||
}
|
||||
|
||||
static struct termios saved_tio;
|
||||
|
||||
static void restore_terminal_on_exit(void)
|
||||
{
|
||||
tcsetattr(0, TCSAFLUSH, &saved_tio);
|
||||
}
|
||||
|
||||
static void restore_terminal_on_signal(int signum)
|
||||
{
|
||||
if ( signum == SIGTSTP )
|
||||
{
|
||||
struct termios tio;
|
||||
tcgetattr(0, &tio);
|
||||
tcsetattr(0, TCSAFLUSH, &saved_tio);
|
||||
raise(SIGSTOP);
|
||||
tcgetattr(0, &saved_tio);
|
||||
tcsetattr(0, TCSAFLUSH, &tio);
|
||||
return;
|
||||
}
|
||||
tcsetattr(0, TCSAFLUSH, &saved_tio);
|
||||
raise(signum);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if ( !isatty(0) )
|
||||
error(1, errno, "standard input");
|
||||
if ( tcgetattr(0, &saved_tio) < 0 )
|
||||
error(1, errno, "tcsetattr: standard input");
|
||||
if ( atexit(restore_terminal_on_exit) != 0 )
|
||||
error(1, errno, "atexit");
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = restore_terminal_on_signal;
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
sa.sa_flags = SA_RESETHAND;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
struct display_connection* connection = display_connect_default();
|
||||
if ( !connection && errno == ECONNREFUSED )
|
||||
display_spawn(argc, argv);
|
||||
if ( !connection )
|
||||
error(1, errno, "Could not connect to display server");
|
||||
|
||||
if ( !dispd_initialize(&argc, &argv) )
|
||||
error(1, 0, "couldn't initialize dispd library");
|
||||
struct dispd_session* session = dispd_attach_default_session();
|
||||
if ( !session )
|
||||
error(1, 0, "couldn't attach to dispd default session");
|
||||
if ( !dispd_session_setup_game_rgba(session) )
|
||||
error(1, 0, "couldn't setup dispd rgba session");
|
||||
struct dispd_window* window = dispd_create_window_game_rgba(session);
|
||||
if ( !window )
|
||||
error(1, 0, "couldn't create dispd rgba window");
|
||||
display_create_window(connection, WINDOW_ID);
|
||||
display_resize_window(connection, WINDOW_ID, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
display_title_window(connection, WINDOW_ID, "Asteroids");
|
||||
|
||||
InitGame();
|
||||
gamerunning = true;
|
||||
for ( framenum = 0; gamerunning; framenum++ )
|
||||
RunFrame(window);
|
||||
RunFrame(connection);
|
||||
|
||||
dispd_destroy_window(window);
|
||||
dispd_detach_session(session);
|
||||
display_disconnect(connection);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
gears
|
|
@ -0,0 +1,26 @@
|
|||
include ../build-aux/compiler.mak
|
||||
include ../build-aux/version.mak
|
||||
include ../build-aux/dirs.mak
|
||||
|
||||
OPTLEVEL?=-g -O2
|
||||
CXXFLAGS?=$(OPTLEVEL)
|
||||
|
||||
CPPFLAGS:=$(CPPFLAGS)
|
||||
CXXFLAGS:=$(CXXFLAGS) -Wall -Wextra -fno-exceptions -fno-rtti
|
||||
|
||||
BINARY:=gears
|
||||
LIBS:=-lOSMesa -ldisplay
|
||||
|
||||
all: $(BINARY)
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
%: %.cpp
|
||||
$(CXX) -std=gnu++11 $(CPPFLAGS) $(CXXFLAGS) $< -o $@ $(LIBS)
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
install $(BINARY) $(DESTDIR)$(BINDIR)
|
||||
|
||||
clean:
|
||||
rm -f $(BINARY)
|
|
@ -0,0 +1,437 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Brian Paul 1999, 2000, 2001.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
gears.cpp
|
||||
Classic OpenGL test program that render colored rotating gears.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/keycodes.h>
|
||||
#include <sys/termmode.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <timespec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <display.h>
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/osmesa.h>
|
||||
|
||||
struct context
|
||||
{
|
||||
uint32_t window_id;
|
||||
uint32_t window_width;
|
||||
uint32_t window_height;
|
||||
bool need_exit;
|
||||
bool key_a;
|
||||
bool key_c;
|
||||
bool key_d;
|
||||
bool key_e;
|
||||
bool key_q;
|
||||
bool key_s;
|
||||
bool key_w;
|
||||
bool key_up;
|
||||
bool key_down;
|
||||
bool key_left;
|
||||
bool key_right;
|
||||
bool key_pgup;
|
||||
bool key_pgdown;
|
||||
};
|
||||
|
||||
void on_disconnect(void* context_pointer)
|
||||
{
|
||||
struct context* context = (struct context*) context_pointer;
|
||||
context->need_exit = true;
|
||||
}
|
||||
|
||||
void on_quit(void* context_pointer, uint32_t window_id)
|
||||
{
|
||||
struct context* context = (struct context*) context_pointer;
|
||||
if ( window_id != context->window_id )
|
||||
return;
|
||||
context->need_exit = true;
|
||||
}
|
||||
|
||||
void on_resize(void* context_pointer, uint32_t window_id, uint32_t width, uint32_t height)
|
||||
{
|
||||
struct context* context = (struct context*) context_pointer;
|
||||
if ( window_id != context->window_id )
|
||||
return;
|
||||
context->window_width = width;
|
||||
context->window_height = height;
|
||||
}
|
||||
|
||||
void on_keyboard(void* context_pointer, uint32_t window_id, uint32_t codepoint)
|
||||
{
|
||||
struct context* context = (struct context*) context_pointer;
|
||||
if ( window_id != context->window_id )
|
||||
return;
|
||||
int kbkey = KBKEY_DECODE(codepoint);
|
||||
if ( !kbkey )
|
||||
return;
|
||||
unsigned int abskbkey = kbkey < 0 ? - (unsigned int) kbkey :
|
||||
(unsigned int) kbkey;
|
||||
switch ( abskbkey )
|
||||
{
|
||||
case KBKEY_A: context->key_a = 0 < kbkey; break;
|
||||
case KBKEY_C: context->key_c = 0 < kbkey; break;
|
||||
case KBKEY_D: context->key_d = 0 < kbkey; break;
|
||||
case KBKEY_E: context->key_e = 0 < kbkey; break;
|
||||
case KBKEY_Q: context->key_q = 0 < kbkey; break;
|
||||
case KBKEY_S: context->key_s = 0 < kbkey; break;
|
||||
case KBKEY_W: context->key_w = 0 < kbkey; break;
|
||||
case KBKEY_UP: context->key_up = 0 < kbkey; break;
|
||||
case KBKEY_DOWN: context->key_down = 0 < kbkey; break;
|
||||
case KBKEY_LEFT: context->key_left = 0 < kbkey; break;
|
||||
case KBKEY_RIGHT: context->key_right = 0 < kbkey; break;
|
||||
case KBKEY_PGUP: context->key_pgup = 0 < kbkey; break;
|
||||
case KBKEY_PGDOWN: context->key_pgdown = 0 < kbkey; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
|
||||
GLint teeth, GLfloat tooth_depth)
|
||||
{
|
||||
GLint i;
|
||||
GLfloat r0, r1, r2;
|
||||
GLfloat angle, da;
|
||||
GLfloat u, v, len;
|
||||
|
||||
r0 = inner_radius;
|
||||
r1 = outer_radius - tooth_depth / 2.0;
|
||||
r2 = outer_radius + tooth_depth / 2.0;
|
||||
|
||||
da = 2.0 * M_PI / teeth / 4.0;
|
||||
|
||||
glShadeModel(GL_FLAT);
|
||||
|
||||
glNormal3f(0.0, 0.0, 1.0);
|
||||
|
||||
// Draw the front face.
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for ( i = 0; i <= teeth; i++ )
|
||||
{
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
|
||||
if ( i < teeth )
|
||||
{
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
width * 0.5);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Draw the front sides of teeth.
|
||||
glBegin(GL_QUADS);
|
||||
da = 2.0 * M_PI / teeth / 4.0;
|
||||
for ( i = 0; i < teeth; i++ )
|
||||
{
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
|
||||
width * 0.5);
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
width * 0.5);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glNormal3f(0.0, 0.0, -1.0);
|
||||
|
||||
// Draw the back face.
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for ( i = 0; i <= teeth; i++ )
|
||||
{
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
|
||||
if ( i < teeth )
|
||||
{
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
-width * 0.5);
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Draw the back sides of teeth.
|
||||
glBegin(GL_QUADS);
|
||||
da = 2.0 * M_PI / teeth / 4.0;
|
||||
for ( i = 0; i < teeth; i++ )
|
||||
{
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
-width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
|
||||
-width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Draw the outward faces of teeth.
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i < teeth; i++)
|
||||
{
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
|
||||
u = r2 * cos(angle + da) - r1 * cos(angle);
|
||||
v = r2 * sin(angle + da) - r1 * sin(angle);
|
||||
len = sqrt(u * u + v * v);
|
||||
u /= len;
|
||||
v /= len;
|
||||
glNormal3f(v, -u, 0.0);
|
||||
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
|
||||
glNormal3f(cos(angle), sin(angle), 0.0);
|
||||
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
|
||||
width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
|
||||
-width * 0.5);
|
||||
u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
|
||||
v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
|
||||
glNormal3f(v, -u, 0.0);
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
width * 0.5);
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
-width * 0.5);
|
||||
glNormal3f(cos(angle), sin(angle), 0.0);
|
||||
}
|
||||
|
||||
glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
|
||||
glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
|
||||
|
||||
glEnd();
|
||||
|
||||
glShadeModel(GL_SMOOTH);
|
||||
|
||||
// Draw the inside radius cylinder.
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for ( i = 0; i <= teeth; i++ )
|
||||
{
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
glNormal3f(-cos(angle), -sin(angle), 0.0);
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
|
||||
static GLint gear1, gear2, gear3;
|
||||
static GLfloat angle = 0.0;
|
||||
|
||||
static void draw(int width, int height)
|
||||
{
|
||||
GLfloat h = (GLfloat) height / (GLfloat) width;
|
||||
|
||||
glViewport(0, 0, (GLint) width, (GLint) height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.0, 0.0, -40.0);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix();
|
||||
glRotatef(view_rotx, 1.0, 0.0, 0.0);
|
||||
glRotatef(view_roty, 0.0, 1.0, 0.0);
|
||||
glRotatef(view_rotz, 0.0, 0.0, 1.0);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-3.0, -2.0, 0.0);
|
||||
glRotatef(angle, 0.0, 0.0, 1.0);
|
||||
glCallList(gear1);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(3.1, -2.0, 0.0);
|
||||
glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
|
||||
glCallList(gear2);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-3.1, 4.2, 0.0);
|
||||
glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
|
||||
glCallList(gear3);
|
||||
glPopMatrix();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
static void init()
|
||||
{
|
||||
static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
|
||||
static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
|
||||
static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
|
||||
static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, pos);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
// Make the gears.
|
||||
gear1 = glGenLists(1);
|
||||
glNewList(gear1, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
|
||||
gear(1.0, 4.0, 1.0, 20, 0.7);
|
||||
glEndList();
|
||||
|
||||
gear2 = glGenLists(1);
|
||||
glNewList(gear2, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
|
||||
gear(0.5, 2.0, 2.0, 10, 0.7);
|
||||
glEndList();
|
||||
|
||||
gear3 = glGenLists(1);
|
||||
glNewList(gear3, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
|
||||
gear(1.3, 2.0, 0.5, 10, 0.7);
|
||||
glEndList();
|
||||
|
||||
glEnable(GL_NORMALIZE);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
struct display_connection* connection = display_connect_default();
|
||||
if ( !connection && errno == ECONNREFUSED )
|
||||
display_spawn(argc, argv);
|
||||
if ( !connection )
|
||||
error(1, errno, "Could not connect to display server");
|
||||
|
||||
struct context context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.window_id = 0;
|
||||
context.window_width = 600;
|
||||
context.window_height = 600;
|
||||
|
||||
display_create_window(connection, context.window_id);
|
||||
display_resize_window(connection, context.window_id, context.window_width, context.window_height);
|
||||
display_title_window(connection, context.window_id, "Gears");
|
||||
|
||||
uint32_t width = context.window_width;
|
||||
uint32_t height = context.window_height;
|
||||
|
||||
uint32_t* framebuffer = new uint32_t[context.window_width * context.window_height];
|
||||
memset(framebuffer, 0, sizeof(framebuffer[0]) * context.window_width * context.window_height);
|
||||
|
||||
OSMesaContext gl_ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
|
||||
|
||||
struct timespec start_ts;
|
||||
struct timespec last_ts = timespec_make(0, 0);
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_ts);
|
||||
|
||||
bool first_frame = true;
|
||||
while ( !context.need_exit )
|
||||
{
|
||||
struct timespec now_ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now_ts);
|
||||
struct timespec current_ts = timespec_sub(now_ts, start_ts);
|
||||
float current_time = current_ts.tv_sec + current_ts.tv_nsec / 1000000000.0;
|
||||
struct timespec delta_ts = timespec_sub(current_ts, last_ts);
|
||||
float delta_time = delta_ts.tv_sec + delta_ts.tv_nsec / 1000000000.0;
|
||||
|
||||
if ( width != context.window_width || height != context.window_height )
|
||||
{
|
||||
delete[] framebuffer;
|
||||
framebuffer = new uint32_t[context.window_width * context.window_height];
|
||||
memset(framebuffer, 0, sizeof(framebuffer[0]) * context.window_width * context.window_height);
|
||||
width = context.window_width;
|
||||
height = context.window_height;
|
||||
}
|
||||
|
||||
if ( !OSMesaMakeCurrent(gl_ctx, (uint8_t*) framebuffer, GL_UNSIGNED_BYTE,
|
||||
width, height) )
|
||||
error(1, errno, "`OSMesaMakeCurrent'");
|
||||
|
||||
angle = current_time * 100;
|
||||
|
||||
if ( context.key_a || context.key_left )
|
||||
view_roty += 90.0 * delta_time;
|
||||
if ( context.key_d || context.key_right )
|
||||
view_roty -= 90.0 * delta_time;
|
||||
if ( context.key_w || context.key_up )
|
||||
view_rotx += 90.0 * delta_time;
|
||||
if ( context.key_s || context.key_down )
|
||||
view_rotx -= 90.0 * delta_time;
|
||||
if ( context.key_q || context.key_pgup )
|
||||
view_rotz += 90.0 * delta_time;
|
||||
if ( context.key_e || context.key_pgdown )
|
||||
view_rotz -= 90.0 * delta_time;
|
||||
if ( context.key_c )
|
||||
context.need_exit = true;
|
||||
|
||||
if ( first_frame )
|
||||
init();
|
||||
|
||||
draw(width, height);
|
||||
|
||||
display_render_window(connection, context.window_id, 0, 0, context.window_width, context.window_height, framebuffer);
|
||||
|
||||
if ( first_frame )
|
||||
display_show_window(connection, context.window_id);
|
||||
|
||||
last_ts = current_ts;
|
||||
|
||||
first_frame = false;
|
||||
|
||||
struct display_event_handlers handlers;
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
handlers.context = &context;
|
||||
handlers.disconnect_handler = on_disconnect;
|
||||
handlers.quit_handler = on_quit;
|
||||
handlers.resize_handler = on_resize;
|
||||
handlers.keyboard_handler = on_keyboard;
|
||||
while ( display_poll_event(connection, &handlers) == 0 );
|
||||
}
|
||||
|
||||
delete[] framebuffer;
|
||||
|
||||
OSMesaDestroyContext(gl_ctx);
|
||||
|
||||
display_disconnect(connection);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
tix.version=1
|
||||
tix.class=srctix
|
||||
pkg.name=gears
|
||||
pkg.build-libraries=libGL
|
||||
pkg.license=MIT
|
||||
pkg.build-system=sortix-usual-makefile
|
|
@ -0,0 +1,2 @@
|
|||
*.a
|
||||
*.o
|
|
@ -0,0 +1,34 @@
|
|||
SOFTWARE_MEANT_FOR_SORTIX=1
|
||||
include ../build-aux/platform.mak
|
||||
include ../build-aux/compiler.mak
|
||||
include ../build-aux/dirs.mak
|
||||
|
||||
OPTLEVEL?=-g -O2
|
||||
CFLAGS?=$(OPTLEVEL)
|
||||
|
||||
CFLAGS:=$(CFLAGS) -Wall -Wextra
|
||||
CPPFLAGS:=$(CPPFLAGS) -Iinclude
|
||||
|
||||
LIBRARY=libdisplay.a
|
||||
|
||||
OBJS=\
|
||||
libdisplay.o \
|
||||
|
||||
all: $(LIBRARY)
|
||||
|
||||
.PHONY: all install uninstall clean
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||
cp $(LIBRARY) $(DESTDIR)$(LIBDIR)
|
||||
mkdir -p $(DESTDIR)$(INCLUDEDIR)
|
||||
cp -RTv include $(DESTDIR)$(INCLUDEDIR)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
$(LIBRARY): $(OBJS)
|
||||
$(AR) rcs $@ $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(LIBRARY) *.o *.a
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* display-protocol.h
|
||||
* Display protocol.
|
||||
*/
|
||||
|
||||
#ifndef DISPLAY_PROTOCOL_H
|
||||
#define DISPLAY_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct display_packet_header
|
||||
{
|
||||
uint32_t message_id;
|
||||
uint32_t message_length;
|
||||
};
|
||||
|
||||
#define DISPLAY_CREATE_WINDOW 0
|
||||
struct display_create_window
|
||||
{
|
||||
uint32_t window_id;
|
||||
};
|
||||
|
||||
#define DISPLAY_DESTROY_WINDOW 1
|
||||
struct display_destroy_window
|
||||
{
|
||||
uint32_t window_id;
|
||||
};
|
||||
|
||||
#define DISPLAY_RESIZE_WINDOW 2
|
||||
struct display_resize_window
|
||||
{
|
||||
uint32_t window_id;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
#define DISPLAY_RENDER_WINDOW 3
|
||||
struct display_render_window
|
||||
{
|
||||
uint32_t window_id;
|
||||
uint32_t left;
|
||||
uint32_t top;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
/* width * height * sizeof(uint32_t) image bytes follows */
|
||||
};
|
||||
|
||||
#define DISPLAY_TITLE_WINDOW 4
|
||||
struct display_title_window
|
||||
{
|
||||
uint32_t window_id;
|
||||
/* An UTF-8 string follows */
|
||||
};
|
||||
|
||||
#define DISPLAY_SHOW_WINDOW 5
|
||||
struct display_show_window
|
||||
{
|
||||
uint32_t window_id;
|
||||
};
|
||||
|
||||
#define DISPLAY_HIDE_WINDOW 6
|
||||
struct display_hide_window
|
||||
{
|
||||
uint32_t window_id;
|
||||
};
|
||||
|
||||
#define DISPLAY_SHUTDOWN 7
|
||||
struct display_shutdown
|
||||
{
|
||||
uint32_t code;
|
||||
};
|
||||
|
||||
#define EVENT_DISCONNECT 0
|
||||
struct event_disconnect
|
||||
{
|
||||
};
|
||||
|
||||
#define EVENT_QUIT 1
|
||||
struct event_quit
|
||||
{
|
||||
uint32_t window_id;
|
||||
};
|
||||
|
||||
#define EVENT_RESIZE 2
|
||||
struct event_resize
|
||||
{
|
||||
uint32_t window_id;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
#define EVENT_KEYBOARD 3
|
||||
struct event_keyboard
|
||||
{
|
||||
uint32_t window_id;
|
||||
uint32_t codepoint;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* display.h
|
||||
* Display client library.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_DISPLAY_H
|
||||
#define INCLUDE_DISPLAY_H
|
||||
|
||||
#include <poll.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct display_connection;
|
||||
|
||||
int display_spawn(int argc, char** argv);
|
||||
|
||||
struct display_connection* display_connect(const char* socket_path);
|
||||
struct display_connection* display_connect_default(void);
|
||||
void display_disconnect(struct display_connection* connection);
|
||||
|
||||
int display_connection_fd(struct display_connection* connection);
|
||||
|
||||
void display_shutdown(struct display_connection* connection, uint32_t code);
|
||||
|
||||
void display_create_window(struct display_connection* connection,
|
||||
uint32_t window_id);
|
||||
void display_destroy_window(struct display_connection* connection,
|
||||
uint32_t window_id);
|
||||
void display_resize_window(struct display_connection* connection,
|
||||
uint32_t window_id,
|
||||
uint32_t width, uint32_t
|
||||
height);
|
||||
void display_render_window(struct display_connection* connection,
|
||||
uint32_t window_id,
|
||||
uint32_t left,
|
||||
uint32_t top,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t* data);
|
||||
void display_title_window(struct display_connection* connection,
|
||||
uint32_t window_id,
|
||||
const char* title);
|
||||
void display_show_window(struct display_connection* connection,
|
||||
uint32_t window_id);
|
||||
void display_hide_window(struct display_connection* connection,
|
||||
uint32_t window_id);
|
||||
|
||||
typedef void (*display_event_disconnect_handler_t)(void*);
|
||||
typedef void (*display_event_quit_handler_t)(void*, uint32_t);
|
||||
typedef void (*display_event_resize_handler_t)(void*, uint32_t, uint32_t,
|
||||
uint32_t);
|
||||
typedef void (*display_event_keyboard_handler_t)(void*, uint32_t, uint32_t);
|
||||
|
||||
struct display_event_handlers
|
||||
{
|
||||
void* context;
|
||||
display_event_disconnect_handler_t disconnect_handler;
|
||||
display_event_quit_handler_t quit_handler;
|
||||
display_event_resize_handler_t resize_handler;
|
||||
display_event_keyboard_handler_t keyboard_handler;
|
||||
};
|
||||
|
||||
int display_poll_event(struct display_connection* connection,
|
||||
struct display_event_handlers* handlers);
|
||||
int display_wait_event(struct display_connection* connection,
|
||||
struct display_event_handlers* handlers);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,859 @@
|
|||
/*
|
||||
* Pop Tart Cat animation frames
|
||||
* Adapted from ToAruOS.
|
||||
*/
|
||||
#ifndef INCLUDE_NYAN_H
|
||||
#define INCLUDE_NYAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static const char* const nyan_frame0[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
".,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,>>>>>>>,,,,,,,,>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,",
|
||||
"&&&+++++++&&&&&&&&'''++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++**''+'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'**'''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,",
|
||||
"+++#######++++++++''**''@$$$$$$-'*************',,,,,,,,,,,,,,,,,",
|
||||
"###################''**'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,",
|
||||
"####################''''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,",
|
||||
"###=======########====''@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,",
|
||||
"======================='@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,",
|
||||
"===;;;;;;;.=======;;;;'''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;'***''''''''''''''''''',,,,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;'**'','*',,,,,'*','**',,,,,,,,,,,,,,,,,,,,,",
|
||||
";;;,,,,.,,;;;.;;;;,,,'''',,'',,,,,,,'',,'',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame1[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,>>>>>>>,,,,,,,,>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,",
|
||||
"&&&+++++++&&&&&&&&+++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++'+++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'*'++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,",
|
||||
"+++#######++++++++'*''''@$$$$$$-$'*************',,,,,,,,,,,,,,,,",
|
||||
"###################****'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,",
|
||||
"###################''**'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,",
|
||||
"###=======########==='''@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,",
|
||||
"======================='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,",
|
||||
"===;;;;;;;========;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;'**','*',,,,,,**','**',,,,,,,,,,,,,,,,,,,,",
|
||||
";;;,,.,,,,;;;;;;;;,,,,''',,,'',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,..,,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame2[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,..,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,.",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.",
|
||||
">>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,",
|
||||
"++&&&&&&&++++++++&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,",
|
||||
"##+++++++########++++++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,",
|
||||
"######################''@$$$$$$-$'*************',,,,,,,,,,,,,,,,",
|
||||
"###################'''''@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,",
|
||||
"==#######========#'****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,",
|
||||
"==================='''='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,",
|
||||
";;=======;;;;;;;;======'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,",
|
||||
";.;;;;;;;;;;;;;;;;;;;;;'*'''''''''''''''''''',,,,,,,,,,,,,,,,,,,",
|
||||
".,.;;;;;;,,,,,,,,;;;;;;'**',**',,,,,,**','**',,,,,,,,,,,,,,,,,,,",
|
||||
",.,,,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame3[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,",
|
||||
">>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,",
|
||||
"++&&&&&&&++++++++&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,",
|
||||
"##+++++++########++++++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,",
|
||||
"#####################'''@$$$$$$-$'*************',,,,,,,,,,,,,,,,",
|
||||
"###################''**'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,",
|
||||
"==#######========##****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,",
|
||||
"=================='*'=='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,",
|
||||
";;=======;;;;;;;;=='==='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,",
|
||||
",,;;;;;;;,,,,,,,,;;;;;'**','*',,,,,,'*','**',,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,'',,''',,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame4[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,",
|
||||
",,,>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,",
|
||||
"&&&+++++++&&&&&&&&+++++'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'''++'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,",
|
||||
"+++#######+++++++'**''''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,",
|
||||
"#################'****''@$$$$$$-'*************',,,,,,,,,,,,,,,,,",
|
||||
"##################''''*'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,",
|
||||
"###=======########==='''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,",
|
||||
"======================='@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,",
|
||||
"===;;;;;;;========;;;;''@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;''''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;'***'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,",
|
||||
";;;,,,,,,,;;;;;;;;,,'**','**,,,,,,'**,'**',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,'',,''',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,..,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame5[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$''$$$@@','',,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$'**'-$$@''**',,,,,,,,,,,,,,,,,,",
|
||||
"&&&+++++++&&&&&&&&+++++'@$$$$$$$$'***$$$@'***',,,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++'+++'@$$$$$-$$'***''''****',,,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'*'++'@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,",
|
||||
"+++#######++++++++'*''''@$$$$$$$'*************',,,,,,,,,,,,,,,,,",
|
||||
"###################****'@$$$$$$-'***.'****.'**',,,,,,,,,,,,,,,,,",
|
||||
"###################''**'@$-$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,",
|
||||
"###=======########==='''@$$$$$$$'*%%********%%',,,,,,,,,,,,,,,,,",
|
||||
"======================='@@$$$-$$$'***''''''**',,,,,,,,,,,,,,,,,,",
|
||||
"===;;;;;;;========;;;;''@@@$$$$$$$'*********',,,,,,,,,,,,,,,,,,.",
|
||||
";;;;;;;;;;;;;;;;;;;;;'*''@@@@@@@@@@''''''''',,,,,,,,,,,,,,,,,,,.",
|
||||
";;;;;;;;;;;;;;;;;;;;'***''''''''''''''''*',,,,,,,,,,,,,,,,,,,,,,",
|
||||
";;;,,,,,,,;;;;;;;;,,'**','**,,,,,,'**,'**',,,,,,,,,,,,,,,,,,..,.",
|
||||
",,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame6[] = {
|
||||
".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,..,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>,,,,,,,>>>>>>>>,,,,,,,'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,",
|
||||
"++&&&&&&&++++++++&'''&&'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'*''+'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'**'''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,",
|
||||
"##+++++++########++'**''@$$$$$$-'*************',,,,,,,,,,,,,,,,,",
|
||||
"###################''**'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,",
|
||||
"####################''''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,",
|
||||
"==#######========#####''@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,",
|
||||
"======================='@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,",
|
||||
";;=======;;;;;;;;====='''@@@@@@@@@'*********',,,,,,,,,,,.,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;'***''''''''''''''''''',,,,,,,,,,.,,,.,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;'**'','*',,,,,'**,'**',,,,,,,,,,,,,,,,,,,,,",
|
||||
",,;;;;;;;,,,,,,,,;;;;'''',,'',,,,,,,'',,'',,,,,,,,,,,.,,,,,.,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame7[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>,,,,,,,>>>>>>>>,,,,,,,'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,",
|
||||
"++&&&&&&&++++++++&&&&&&'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++'+++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'*'++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,",
|
||||
"##+++++++########+'*''''@$$$$$$-$'*************',,,,,,,,,,,,,,,,",
|
||||
"###################****'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,",
|
||||
"###################''**'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,",
|
||||
"==#######========####'''@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,",
|
||||
"======================='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,",
|
||||
";;=======;;;;;;;;======''@@@@@@@@@@'*********',,,.,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;'**','*',,,,,,**','**',,,,,,,,,,,,,,,,,,,,",
|
||||
",,;;;;;;;,,,,,,,,;;;;;''',,,'',,,,,,''',,''',,.,,,,.,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame8[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,..,...,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,",
|
||||
"&&&+++++++&&&&&&&&+++++'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,",
|
||||
"+++#######++++++++#####'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,",
|
||||
"######################''@$$$$$$-$'*************',,,,,,,,,,,,,,,,",
|
||||
"###################'''''@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,",
|
||||
"###=======########'****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,",
|
||||
"==================='''='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,",
|
||||
"===;;;;;;;========;;;;;'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;;'*'''''''''''''''''''',,,,,,,,,,,,,,,,,,,",
|
||||
";;;,,,,,,,;;;;;;;;,,,,,'**',**',,,,,,**'.'**',,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame9[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,",
|
||||
"&&&+++++++&&&&&&&&+++++'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,",
|
||||
"+++#######++++++++#####'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,",
|
||||
"#####################'''@$$$$$$-$'*************',,,,,,,,,,,,,,,,",
|
||||
"###################''**'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,",
|
||||
"###=======########=****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,",
|
||||
"=================='*'=='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,",
|
||||
"===;;;;;;;========;';;;'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,",
|
||||
";;;,,,,,,,;;;;;;;;,,,,'**','*',,..,.**','**',,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,''',,,'',,,,.,''',,''',,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame10[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,",
|
||||
"++&&&&&&&++++++++&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++++++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'''++'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,",
|
||||
"##+++++++########'**''''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,",
|
||||
"#################'****''@$$$$$$-'*************',,,,,,,,,,,,,,,,,",
|
||||
"##################''''*'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,",
|
||||
"==#######========####'''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,",
|
||||
"======================='@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,",
|
||||
";;=======;;;;;;;;=====''@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;;''''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;'***'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,",
|
||||
",,;;;;;;;,,,,,,,,;;;'**'.'**..,,,,'**''**',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,''',''',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
".,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const nyan_frame11[] = {
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,",
|
||||
">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$''$$$@@','',,,,,,,,,,,,,,,,,,,",
|
||||
"&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$'**'-$$@''**',,,,,,,,,,,,,,,,,,",
|
||||
"++&&&&&&&++++++++&&&&&&'@$$$$$$$$'***$$$@'***',,,,,,,,,,,,,,,,,,",
|
||||
"+++++++++++++++++++'+++'@$$$$$-$$'***''''****',,,,,,,,,,,,,,,,,,",
|
||||
"++++++++++++++++++'*'++'@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,",
|
||||
"##+++++++########+'*''''@$$$$$$$'*************',,,,,,,,,,,,,,,,,",
|
||||
"###################****'@$$$$$$-'***.'****.'**',,,,,,,,,,,,,,,,,",
|
||||
"###################''**'@$-$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,",
|
||||
"==#######========####'''@$$$$$$$'*%%********%%',,,,,,,,,,,,,,,,,",
|
||||
"======================='@@$$$-$$$'***''''''**',,,,,,,,,,,,,,,,,,",
|
||||
";;=======;;;;;;;;=.===''@@@$$$$$$$'*********',,,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;.'*''@@@@@@@@@@''''''''',,,,,,,,,,,,,,,,,,,,",
|
||||
";;;;;;;;;;;;;;;;;;;;'***''''''''''''''''*',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,;;;;;;;,,,,,,,.;;;'**','**,,,,,,'**''**',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",
|
||||
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"};
|
||||
|
||||
static const char* const* const nyan_frames[] = {
|
||||
nyan_frame0,
|
||||
nyan_frame1,
|
||||
nyan_frame2,
|
||||
nyan_frame3,
|
||||
nyan_frame4,
|
||||
nyan_frame5,
|
||||
nyan_frame6,
|
||||
nyan_frame7,
|
||||
nyan_frame8,
|
||||
nyan_frame9,
|
||||
nyan_frame10,
|
||||
nyan_frame11,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define NYAN_FRAME_WIDTH 64
|
||||
#define NYAN_FRAME_HEIGHT 64
|
||||
|
||||
static inline uint8_t nyan_palette_of_char(char c)
|
||||
{
|
||||
if ( c == ',' ) return 1;
|
||||
if ( c == '.' ) return 2;
|
||||
if ( c == '\'') return 3;
|
||||
if ( c == '@' ) return 4;
|
||||
if ( c == '$' ) return 5;
|
||||
if ( c == '-' ) return 6;
|
||||
if ( c == '>' ) return 7;
|
||||
if ( c == '&' ) return 8;
|
||||
if ( c == '+' ) return 9;
|
||||
if ( c == '#' ) return 10;
|
||||
if ( c == '=' ) return 11;
|
||||
if ( c == ';' ) return 12;
|
||||
if ( c == '*' ) return 13;
|
||||
if ( c == '%' ) return 14;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const uint8_t nyan_palette[1+14][4] =
|
||||
{
|
||||
{ 0, 0, 0, 0 }, // 0; Unused entry
|
||||
{ 0, 0, 97, 200 }, // 1: , = Blue background
|
||||
{ 255, 255, 255, 255 }, // 2: . = White stars
|
||||
{ 46, 52, 54, 255 }, // 3: ' = Black border
|
||||
{ 255, 255, 215, 255 }, // 4: @ = Tan poptart
|
||||
{ 215, 135, 175, 255 }, // 5: $ = Pink potart
|
||||
{ 215, 0, 135, 255 }, // 6: - = Red poptart
|
||||
{ 239, 41, 41, 255 }, // 7: > = Red rainbow
|
||||
{ 255, 95, 0, 255 }, // 8: & = Orange rainbow
|
||||
{ 252, 233, 79, 255 }, // 9: + = Yellow rainbow
|
||||
{ 138, 226, 52, 255 }, // 10: # = Green rainbow
|
||||
{ 0, 135, 255, 255 }, // 11: = = Light blue rainbow
|
||||
{ 0, 0, 175, 255 }, // 12: ; = Dark blue rainbow
|
||||
{ 85, 87, 83, 255 }, // 13: * = Grey cat face
|
||||
{ 85, 87, 83, 255 }, // 14: % = Pink cheeks
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* libdisplay.c
|
||||
* Display client library.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <ioleast.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <display.h>
|
||||
|
||||
#include "display-protocol.h"
|
||||
|
||||
int display_spawn(int argc, char** argv)
|
||||
{
|
||||
// TODO: Overflow.
|
||||
char** new_argv = malloc((2 + argc + 1) * sizeof(char*));
|
||||
if ( !new_argv )
|
||||
return -1;
|
||||
new_argv[0] = (char*) "display";
|
||||
// TODO: Start the compositor in a special close-after-program-exists mode?
|
||||
// And maybe go fullscreen / maximized by default?
|
||||
new_argv[1] = (char*) "--";
|
||||
for ( int i = 0; i < argc; i++ )
|
||||
new_argv[2 + i] = argv[i];
|
||||
new_argv[2 + argc] = NULL;
|
||||
execvp(new_argv[0], new_argv);
|
||||
free(new_argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int open_local_client_socket(const char* path, int flags)
|
||||
{
|
||||
size_t path_length = strlen(path);
|
||||
size_t addr_size = offsetof(struct sockaddr_un, sun_path) + path_length + 1;
|
||||
struct sockaddr_un* sockaddr = (struct sockaddr_un*) malloc(addr_size);
|
||||
if ( !sockaddr )
|
||||
return -1;
|
||||
sockaddr->sun_family = AF_LOCAL;
|
||||
strcpy(sockaddr->sun_path, path);
|
||||
int fd = socket(AF_LOCAL, SOCK_STREAM | flags, 0);
|
||||
if ( fd < 0 )
|
||||
return free(sockaddr), -1;
|
||||
if ( connect(fd, (const struct sockaddr*) sockaddr, addr_size) < 0 )
|
||||
return close(fd), free(sockaddr), -1;
|
||||
free(sockaddr);
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct display_connection
|
||||
{
|
||||
int fd;
|
||||
struct display_packet_header header;
|
||||
size_t header_bytes;
|
||||
uint8_t* payload;
|
||||
size_t payload_bytes;
|
||||
};
|
||||
|
||||
struct display_connection* display_connect(const char* socket_path)
|
||||
{
|
||||
struct display_connection* connection =
|
||||
(struct display_connection*) malloc(sizeof(struct display_connection));
|
||||
if ( !connection )
|
||||
return NULL;
|
||||
memset(connection, 0, sizeof(*connection));
|
||||
if ( (connection->fd = open_local_client_socket(socket_path, 0)) < 0 )
|
||||
return free(connection), (struct display_connection*) NULL;
|
||||
size_t send_buffer_size = 2 * 1024 * 1024;
|
||||
setsockopt(connection->fd, SOL_SOCKET, SO_SNDBUF, &send_buffer_size, sizeof(send_buffer_size));
|
||||
return connection;
|
||||
}
|
||||
|
||||
struct display_connection* display_connect_default(void)
|
||||
{
|
||||
return display_connect(getenv("DISPLAY_SOCKET") ?
|
||||
getenv("DISPLAY_SOCKET") :
|
||||
"/run/display");
|
||||
}
|
||||
|
||||
void display_disconnect(struct display_connection* connection)
|
||||
{
|
||||
free(connection->payload);
|
||||
close(connection->fd);
|
||||
free(connection);
|
||||
}
|
||||
|
||||
int display_connection_fd(struct display_connection* connection)
|
||||
{
|
||||
return connection->fd;
|
||||
}
|
||||
|
||||
static void send_message(struct display_connection* connection, uint32_t message_id,
|
||||
const void* message, size_t message_size,
|
||||
const void* auxilerary, size_t auxilerary_size)
|
||||
{
|
||||
struct display_packet_header header;
|
||||
header.message_id = message_id;
|
||||
header.message_length = message_size + auxilerary_size;
|
||||
writeall(connection->fd, &header, sizeof(header));
|
||||
writeall(connection->fd, message, message_size);
|
||||
writeall(connection->fd, auxilerary, auxilerary_size);
|
||||
}
|
||||
|
||||
static void send_message_no_aux(struct display_connection* connection, uint32_t message_id,
|
||||
const void* message, size_t message_size)
|
||||
{
|
||||
send_message(connection, message_id, message, message_size, 0, 0);
|
||||
}
|
||||
|
||||
void display_shutdown(struct display_connection* connection, uint32_t code)
|
||||
{
|
||||
struct display_shutdown msg;
|
||||
msg.code = code;
|
||||
send_message_no_aux(connection, DISPLAY_SHUTDOWN, &msg, sizeof(msg));
|
||||
}
|
||||
|
||||
void display_create_window(struct display_connection* connection, uint32_t window_id)
|
||||
{
|
||||
struct display_create_window msg;
|
||||
msg.window_id = window_id;
|
||||
send_message_no_aux(connection, DISPLAY_CREATE_WINDOW, &msg, sizeof(msg));
|
||||
}
|
||||
|
||||
void display_destroy_window(struct display_connection* connection, uint32_t window_id)
|
||||
{
|
||||
struct display_destroy_window msg;
|
||||
msg.window_id = window_id;
|
||||
send_message_no_aux(connection, DISPLAY_DESTROY_WINDOW, &msg, sizeof(msg));
|
||||
}
|
||||
|
||||
void display_resize_window(struct display_connection* connection, uint32_t window_id, uint32_t width, uint32_t height)
|
||||
{
|
||||
struct display_resize_window msg;
|
||||
msg.window_id = window_id;
|
||||
msg.width = width;
|
||||
msg.height = height;
|
||||
send_message_no_aux(connection, DISPLAY_RESIZE_WINDOW, &msg, sizeof(msg));
|
||||
}
|
||||
|
||||
void display_render_window(struct display_connection* connection, uint32_t window_id, uint32_t left, uint32_t top, uint32_t width, uint32_t height, uint32_t* data)
|
||||
{
|
||||
struct display_render_window msg;
|
||||
msg.window_id = window_id;
|
||||
msg.left = left;
|
||||
msg.top = top;
|
||||
msg.width = width;
|
||||
msg.height = height;
|
||||
send_message(connection, DISPLAY_RENDER_WINDOW, &msg, sizeof(msg),
|
||||
data, sizeof(uint32_t) * width * height);
|
||||
}
|
||||
|
||||
void display_title_window(struct display_connection* connection, uint32_t window_id, const char* title)
|
||||
{
|
||||
struct display_title_window msg;
|
||||
msg.window_id = window_id;
|
||||
send_message(connection, DISPLAY_TITLE_WINDOW, &msg, sizeof(msg), title, strlen(title));
|
||||
}
|
||||
|
||||
void display_show_window(struct display_connection* connection, uint32_t window_id)
|
||||
{
|
||||
struct display_show_window msg;
|
||||
msg.window_id = window_id;
|
||||
send_message_no_aux(connection, DISPLAY_SHOW_WINDOW, &msg, sizeof(msg));
|
||||
}
|
||||
|
||||
void display_hide_window(struct display_connection* connection, uint32_t window_id)
|
||||
{
|
||||
struct display_hide_window msg;
|
||||
msg.window_id = window_id;
|
||||
send_message_no_aux(connection, DISPLAY_HIDE_WINDOW, &msg, sizeof(msg));
|
||||
}
|
||||
|
||||
static bool display_read_event(struct display_connection* connection)
|
||||
{
|
||||
while ( connection->header_bytes < sizeof(connection->header) )
|
||||
{
|
||||
errno = 0;
|
||||
ssize_t amount = read(connection->fd,
|
||||
(uint8_t*) &connection->header + connection->header_bytes,
|
||||
sizeof(connection->header) - connection->header_bytes);
|
||||
if ( amount < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) )
|
||||
break;
|
||||
if ( amount < 0 )
|
||||
break;
|
||||
if ( amount == 0 )
|
||||
return false;
|
||||
connection->header_bytes += amount;
|
||||
}
|
||||
if ( connection->header_bytes == sizeof(connection->header) &&
|
||||
!connection->payload )
|
||||
{
|
||||
connection->payload = (uint8_t*) malloc(connection->header.message_length);
|
||||
connection->payload_bytes = 0;
|
||||
}
|
||||
while ( connection->header_bytes == sizeof(connection->header) &&
|
||||
connection->payload &&
|
||||
connection->payload_bytes < connection->header.message_length )
|
||||
{
|
||||
errno = 0;
|
||||
ssize_t amount = read(connection->fd,
|
||||
connection->payload + connection->payload_bytes,
|
||||
connection->header.message_length - connection->payload_bytes);
|
||||
if ( amount < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) )
|
||||
break;
|
||||
if ( amount < 0 )
|
||||
break;
|
||||
if ( amount == 0 )
|
||||
return false;
|
||||
connection->payload_bytes += amount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int display_dispatch_event(struct display_connection* connection, struct display_event_handlers* handlers)
|
||||
{
|
||||
if ( connection->header_bytes == sizeof(connection->header) &&
|
||||
connection->payload &&
|
||||
connection->payload_bytes == connection->header.message_length )
|
||||
{
|
||||
// TODO: == instead of <= due to warning. Maybe all should be changed to
|
||||
// use == instead.
|
||||
if ( connection->header.message_id == EVENT_DISCONNECT &&
|
||||
connection->header.message_length ==/*>=*/ sizeof(struct event_disconnect) )
|
||||
{
|
||||
struct event_disconnect* event = (struct event_disconnect*) connection->payload;
|
||||
(void) event;
|
||||
if ( handlers->disconnect_handler )
|
||||
handlers->disconnect_handler(handlers->context);
|
||||
else
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ( connection->header.message_id == EVENT_QUIT &&
|
||||
connection->header.message_length >= sizeof(struct event_quit) )
|
||||
{
|
||||
struct event_quit* event = (struct event_quit*) connection->payload;
|
||||
if ( handlers->quit_handler )
|
||||
handlers->quit_handler(handlers->context, event->window_id);
|
||||
else
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ( connection->header.message_id == EVENT_RESIZE &&
|
||||
connection->header.message_length >= sizeof(struct event_resize) )
|
||||
{
|
||||
struct event_resize* event = (struct event_resize*) connection->payload;
|
||||
if ( handlers->resize_handler )
|
||||
handlers->resize_handler(handlers->context, event->window_id, event->width, event->height);
|
||||
}
|
||||
|
||||
if ( connection->header.message_id == EVENT_KEYBOARD &&
|
||||
connection->header.message_length >= sizeof(struct event_keyboard) )
|
||||
{
|
||||
struct event_keyboard* event = (struct event_keyboard*) connection->payload;
|
||||
if ( handlers->keyboard_handler )
|
||||
handlers->keyboard_handler(handlers->context, event->window_id, event->codepoint);
|
||||
}
|
||||
|
||||
connection->header_bytes = 0;
|
||||
free(connection->payload), connection->payload = NULL;
|
||||
connection->payload_bytes = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int display_event_read_hangup(struct display_event_handlers* handlers)
|
||||
{
|
||||
if ( handlers->disconnect_handler )
|
||||
handlers->disconnect_handler(handlers->context);
|
||||
else
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int display_poll_event(struct display_connection* connection, struct display_event_handlers* handlers)
|
||||
{
|
||||
fcntl(connection->fd, F_SETFL, fcntl(connection->fd, F_GETFL) | O_NONBLOCK);
|
||||
bool read_success = display_read_event(connection);
|
||||
fcntl(connection->fd, F_SETFL, fcntl(connection->fd, F_GETFL) & ~O_NONBLOCK);
|
||||
if ( !read_success )
|
||||
return display_event_read_hangup(handlers);
|
||||
return display_dispatch_event(connection, handlers);
|
||||
}
|
||||
|
||||
int display_wait_event(struct display_connection* connection, struct display_event_handlers* handlers)
|
||||
{
|
||||
if ( !display_read_event(connection) )
|
||||
return display_event_read_hangup(handlers);
|
||||
return display_dispatch_event(connection, handlers);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
*.a
|
||||
*.o
|
|
@ -0,0 +1,36 @@
|
|||
SOFTWARE_MEANT_FOR_SORTIX=1
|
||||
include ../build-aux/platform.mak
|
||||
include ../build-aux/compiler.mak
|
||||
include ../build-aux/dirs.mak
|
||||
|
||||
OPTLEVEL?=-g -O2
|
||||
CFLAGS?=$(OPTLEVEL)
|
||||
|
||||
CFLAGS:=$(CFLAGS) -Wall -Wextra
|
||||
CPPFLAGS:=$(CPPFLAGS) -Iinclude
|
||||
|
||||
LIBRARY=libui.a
|
||||
|
||||
OBJS=\
|
||||
framebuffer.o \
|
||||
pixel.o \
|
||||
vgafont.o \
|
||||
|
||||
all: $(LIBRARY)
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||
cp $(LIBRARY) $(DESTDIR)$(LIBDIR)
|
||||
mkdir -p $(DESTDIR)$(INCLUDEDIR)
|
||||
cp -RTv include $(DESTDIR)$(INCLUDEDIR)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
$(LIBRARY): $(OBJS)
|
||||
$(AR) rcs $@ $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(LIBRARY) *.o *.a
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* framebuffer.c
|
||||
* Framebuffer functions.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "framebuffer.h"
|
||||
#include "pixel.h"
|
||||
|
||||
struct framebuffer framebuffer_crop(struct framebuffer fb,
|
||||
size_t left,
|
||||
size_t top,
|
||||
size_t width,
|
||||
size_t height)
|
||||
{
|
||||
// Crop the framebuffer horizontally.
|
||||
if ( fb.xres < left )
|
||||
left = fb.xres;
|
||||
fb.buffer += left;
|
||||
fb.xres -= left;
|
||||
if ( width < fb.xres )
|
||||
fb.xres = width;
|
||||
|
||||
// Crop the framebuffer vertically.
|
||||
if ( fb.yres < top )
|
||||
top = fb.yres;
|
||||
fb.buffer += top * fb.pitch;
|
||||
fb.yres -= top;
|
||||
if ( height < fb.yres )
|
||||
fb.yres = height;
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
void framebuffer_copy_to_framebuffer(const struct framebuffer dst,
|
||||
const struct framebuffer src)
|
||||
{
|
||||
for ( size_t y = 0; y < src.yres; y++ )
|
||||
for ( size_t x = 0; x < src.xres; x++ )
|
||||
framebuffer_set_pixel(dst, x, y, framebuffer_get_pixel(src, x, y));
|
||||
}
|
||||
|
||||
void framebuffer_copy_to_framebuffer_blend(const struct framebuffer dst,
|
||||
const struct framebuffer src)
|
||||
{
|
||||
for ( size_t y = 0; y < src.yres; y++ )
|
||||
{
|
||||
for ( size_t x = 0; x < src.xres; x++ )
|
||||
{
|
||||
uint32_t bg = framebuffer_get_pixel(dst, x, y);
|
||||
uint32_t fg = framebuffer_get_pixel(src, x, y);
|
||||
framebuffer_set_pixel(dst, x, y, blend_pixel(bg, fg));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* framebuffer.h
|
||||
* Framebuffer functions.
|
||||
*/
|
||||
|
||||
#ifndef FRAMEBUFFER_H
|
||||
#define FRAMEBUFFER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct framebuffer
|
||||
{
|
||||
size_t pitch;
|
||||
uint32_t* buffer;
|
||||
size_t xres;
|
||||
size_t yres;
|
||||
};
|
||||
|
||||
static inline uint32_t framebuffer_get_pixel(const struct framebuffer fb,
|
||||
size_t x,
|
||||
size_t y)
|
||||
{
|
||||
if ( fb.xres <= x || fb.yres <= y )
|
||||
return 0;
|
||||
return fb.buffer[y * fb.pitch + x];
|
||||
}
|
||||
|
||||
static inline void framebuffer_set_pixel(const struct framebuffer fb,
|
||||
size_t x,
|
||||
size_t y,
|
||||
uint32_t value)
|
||||
{
|
||||
if ( fb.xres <= x || fb.yres <= y )
|
||||
return;
|
||||
fb.buffer[y * fb.pitch + x] = value;
|
||||
}
|
||||
|
||||
struct framebuffer framebuffer_crop(struct framebuffer fb,
|
||||
size_t left,
|
||||
size_t top,
|
||||
size_t width,
|
||||
size_t height);
|
||||
void framebuffer_copy_to_framebuffer(const struct framebuffer dst,
|
||||
const struct framebuffer src);
|
||||
void framebuffer_copy_to_framebuffer_blend(const struct framebuffer dst,
|
||||
const struct framebuffer src);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* pixel.h
|
||||
* Pixel functions.
|
||||
*/
|
||||
|
||||
#ifndef PIXEL_H
|
||||
#define PIXEL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// TODO: This isn't the only pixel format in the world!
|
||||
union color_rgba8
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
uint8_t a;
|
||||
};
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
static inline uint32_t make_color_a(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||
{
|
||||
union color_rgba8 color;
|
||||
color.r = r;
|
||||
color.g = g;
|
||||
color.b = b;
|
||||
color.a = a;
|
||||
return color.value;
|
||||
}
|
||||
|
||||
static inline uint32_t make_color(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return make_color_a(r, g, b, 255);
|
||||
}
|
||||
|
||||
uint32_t blend_pixel(uint32_t bg_value, uint32_t fg_value);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* vgafont.h
|
||||
* VGA font rendering.
|
||||
*/
|
||||
|
||||
#ifndef VGAFONT_H
|
||||
#define VGAFONT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "framebuffer.h"
|
||||
|
||||
#define FONT_REALWIDTH 8
|
||||
#define FONT_WIDTH 9
|
||||
#define FONT_HEIGHT 16
|
||||
#define FONT_CHARSIZE (FONT_REALWIDTH * FONT_HEIGHT / 8)
|
||||
#define FONT_NUMCHARS 256
|
||||
|
||||
extern uint8_t font[FONT_CHARSIZE * FONT_NUMCHARS];
|
||||
|
||||
void load_font(void);
|
||||
void render_char(struct framebuffer fb, wchar_t c, uint32_t color);
|
||||
void render_text(struct framebuffer fb, const char* str, uint32_t color);
|
||||
size_t render_text_columns(const char* str);
|
||||
size_t render_text_width(const char* str);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* pixel.c
|
||||
* Pixel functions.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pixel.h"
|
||||
|
||||
uint32_t blend_pixel(uint32_t bg_value, uint32_t fg_value)
|
||||
{
|
||||
union color_rgba8 fg; fg.value = fg_value;
|
||||
union color_rgba8 bg; bg.value = bg_value;
|
||||
if ( fg.a == 255 )
|
||||
return fg.value;
|
||||
if ( fg.a == 0 )
|
||||
return bg.value;
|
||||
union color_rgba8 ret;
|
||||
ret.a = 255;
|
||||
ret.r = ((255-fg.a)*bg.r + fg.a*fg.r) / 256;
|
||||
ret.g = ((255-fg.a)*bg.g + fg.a*fg.g) / 256;
|
||||
ret.b = ((255-fg.a)*bg.b + fg.a*fg.b) / 256;
|
||||
return ret.value;
|
||||
}
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* vgafont.c
|
||||
* VGA font rendering.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <ioleast.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "framebuffer.h"
|
||||
#include "vgafont.h"
|
||||
|
||||
static const wchar_t REPLACEMENT_CHARACTER = 0xFFFD;
|
||||
|
||||
uint8_t font[FONT_CHARSIZE * FONT_NUMCHARS];
|
||||
|
||||
void load_font(void)
|
||||
{
|
||||
int fd = open("/dev/vgafont", O_RDONLY);
|
||||
if ( fd < 0 )
|
||||
err(1, "/dev/vgafont");
|
||||
if ( readall(fd, font, sizeof(font)) != sizeof(font) )
|
||||
err(1, "/dev/vgafont");
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Code_page_437
|
||||
static inline int map_wide_to_vga_font(wchar_t c)
|
||||
{
|
||||
if ( 32 <= c && c < 127 )
|
||||
return (int) c;
|
||||
switch ( c )
|
||||
{
|
||||
case L'☺': return 1;
|
||||
case L'☻': return 2;
|
||||
case L'♥': return 3;
|
||||
case L'♦': return 4;
|
||||
case L'♣': return 5;
|
||||
case L'♠': return 6;
|
||||
case L'•': return 7;
|
||||
case L'◘': return 8;
|
||||
case L'○': return 9;
|
||||
case L'◙': return 10;
|
||||
case L'♂': return 11;
|
||||
case L'♀': return 12;
|
||||
case L'♪': return 13;
|
||||
case L'♬': return 14;
|
||||
case L'☼': return 15;
|
||||
case L'►': return 16;
|
||||
case L'◄': return 17;
|
||||
case L'↕': return 18;
|
||||
case L'‼': return 19;
|
||||
case L'¶': return 20;
|
||||
case L'§': return 21;
|
||||
case L'▬': return 22;
|
||||
case L'↨': return 23;
|
||||
case L'↑': return 24;
|
||||
case L'↓': return 25;
|
||||
case L'→': return 26;
|
||||
case L'←': return 27;
|
||||
case L'∟': return 28;
|
||||
case L'↔': return 29;
|
||||
case L'▲': return 30;
|
||||
case L'▼': return 31;
|
||||
case L'⌂': return 127;
|
||||
case L'Ç': return 128;
|
||||
case L'ü': return 129;
|
||||
case L'é': return 130;
|
||||
case L'â': return 131;
|
||||
case L'ä': return 132;
|
||||
case L'à': return 133;
|
||||
case L'å': return 134;
|
||||
case L'ç': return 135;
|
||||
case L'ê': return 136;
|
||||
case L'ë': return 137;
|
||||
case L'è': return 138;
|
||||
case L'ï': return 139;
|
||||
case L'î': return 140;
|
||||
case L'ì': return 141;
|
||||
case L'Ä': return 142;
|
||||
case L'Å': return 143;
|
||||
case L'É': return 144;
|
||||
case L'æ': return 145;
|
||||
case L'Æ': return 146;
|
||||
case L'ô': return 147;
|
||||
case L'ö': return 148;
|
||||
case L'ò': return 149;
|
||||
case L'û': return 150;
|
||||
case L'ù': return 151;
|
||||
case L'ÿ': return 152;
|
||||
case L'Ö': return 153;
|
||||
case L'Ü': return 154;
|
||||
case L'¢': return 155;
|
||||
case L'£': return 156;
|
||||
case L'¥': return 157;
|
||||
case L'₧': return 158;
|
||||
case L'ƒ': return 159;
|
||||
case L'á': return 160;
|
||||
case L'í': return 161;
|
||||
case L'ó': return 162;
|
||||
case L'ú': return 163;
|
||||
case L'ñ': return 164;
|
||||
case L'Ñ': return 165;
|
||||
case L'ª': return 166;
|
||||
case L'º': return 167;
|
||||
case L'¿': return 168;
|
||||
case L'⌐': return 169;
|
||||
case L'¬': return 170;
|
||||
case L'½': return 171;
|
||||
case L'¼': return 172;
|
||||
case L'¡': return 173;
|
||||
case L'«': return 174;
|
||||
case L'»': return 175;
|
||||
case L'░': return 176;
|
||||
case L'▒': return 177;
|
||||
case L'▓': return 178;
|
||||
case L'│': return 179;
|
||||
case L'┤': return 180;
|
||||
case L'╡': return 181;
|
||||
case L'╢': return 182;
|
||||
case L'╖': return 183;
|
||||
case L'╕': return 184;
|
||||
case L'╣': return 185;
|
||||
case L'║': return 186;
|
||||
case L'╗': return 187;
|
||||
case L'╝': return 188;
|
||||
case L'╜': return 189;
|
||||
case L'╛': return 190;
|
||||
case L'┐': return 191;
|
||||
case L'└': return 192;
|
||||
case L'┴': return 193;
|
||||
case L'┬': return 194;
|
||||
case L'├': return 195;
|
||||
case L'─': return 196;
|
||||
case L'┼': return 197;
|
||||
case L'╞': return 198;
|
||||
case L'╟': return 199;
|
||||
case L'╚': return 200;
|
||||
case L'╔': return 201;
|
||||
case L'╩': return 202;
|
||||
case L'╦': return 203;
|
||||
case L'╠': return 204;
|
||||
case L'═': return 205;
|
||||
case L'╬': return 206;
|
||||
case L'╧': return 207;
|
||||
case L'╨': return 208;
|
||||
case L'╤': return 209;
|
||||
case L'╥': return 210;
|
||||
case L'╙': return 211;
|
||||
case L'╘': return 212;
|
||||
case L'╒': return 213;
|
||||
case L'╓': return 214;
|
||||
case L'╫': return 215;
|
||||
case L'╪': return 216;
|
||||
case L'┘': return 217;
|
||||
case L'┌': return 218;
|
||||
case L'█': return 219;
|
||||
case L'▄': return 220;
|
||||
case L'▌': return 221;
|
||||
case L'▐': return 222;
|
||||
case L'▀': return 223;
|
||||
case L'α': return 224;
|
||||
case L'ß': return 225; /* German sharp S U+00DF */
|
||||
case L'β': return 225; /* Greek lowercase beta U+03B2 */
|
||||
case L'Γ': return 226;
|
||||
case L'π': return 227;
|
||||
case L'Σ': return 228; /* Greek uppercase sigma U+03A3 */
|
||||
case L'∑': return 228; /* n-ary summation sign U+2211 (replacement) */
|
||||
case L'σ': return 229;
|
||||
case L'µ': return 230;
|
||||
case L'τ': return 231;
|
||||
case L'Φ': return 232;
|
||||
case L'Θ': return 233;
|
||||
case L'Ω': return 234;
|
||||
case L'δ': return 235; /* Greek lowercase delta U+03B4 */
|
||||
case L'ð': return 235; /* Icelandic lowercase eth U+00F0 (replacement) */
|
||||
case L'∂': return 235; /* Partial derivative sign U+2202 (replacement) */
|
||||
case L'∞': return 236;
|
||||
case L'φ': return 237; /* Greek lowercase phi U+03C6 */
|
||||
case L'∅': return 237; /* Empty set sign U+2205 (replacement) */
|
||||
case L'ϕ': return 237; /* Greek phi symbol in italics U+03D5 (replacement) */
|
||||
case L'⌀': return 237; /* Diameter sign U+2300 (replacement) */
|
||||
case L'ø': return 237; /* Latin lowercase O with stroke U+00F8 (replacement) */
|
||||
case L'Ø': return 237; /* Latin uppercase O with stroke U+00D8 (replacement) */
|
||||
case L'ε': return 238; /* Greek lowercase epsilon U+03B5 */
|
||||
case L'∈': return 238; /* Element-of sign U+2208 */
|
||||
case L'€': return 238; /* Euro sign U+20AC */
|
||||
case L'∩': return 239;
|
||||
case L'≡': return 240;
|
||||
case L'±': return 241;
|
||||
case L'≥': return 242;
|
||||
case L'≤': return 243;
|
||||
case L'⌠': return 244;
|
||||
case L'⌡': return 245;
|
||||
case L'÷': return 246;
|
||||
case L'≈': return 247;
|
||||
case L'°': return 248;
|
||||
case L'∙': return 249;
|
||||
case L'·': return 250;
|
||||
case L'√': return 251;
|
||||
case L'ⁿ': return 252;
|
||||
case L'²': return 253;
|
||||
case L'■': return 254;
|
||||
default: return 0 <= c && c < 256 ? c : -1;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t font_replacement_character[16] =
|
||||
{
|
||||
0b00000000,
|
||||
0b00010000,
|
||||
0b00111000,
|
||||
0b01000100,
|
||||
0b10111010,
|
||||
0b10111010,
|
||||
0b11110110,
|
||||
0b11101110,
|
||||
0b11101110,
|
||||
0b11111110,
|
||||
0b01101100,
|
||||
0b00101000,
|
||||
0b00010000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
};
|
||||
|
||||
static inline const uint8_t* get_character_font(const uint8_t* font, int remap)
|
||||
{
|
||||
if ( remap < 0 )
|
||||
return font_replacement_character;
|
||||
return font + 16 * remap;
|
||||
}
|
||||
|
||||
void render_char(struct framebuffer fb, wchar_t wc, uint32_t color)
|
||||
{
|
||||
// TODO: Special case the rendering of some block drawing characters like in
|
||||
// the kernel so pstree looks nice.
|
||||
int remap = map_wide_to_vga_font(wc);
|
||||
const uint8_t* charfont = get_character_font(font, remap);
|
||||
uint32_t buffer[FONT_HEIGHT * (FONT_REALWIDTH+1)];
|
||||
for ( size_t y = 0; y < FONT_HEIGHT; y++ )
|
||||
{
|
||||
uint8_t line_bitmap = charfont[y];
|
||||
for ( size_t x = 0; x < FONT_REALWIDTH; x++ )
|
||||
buffer[y * (FONT_REALWIDTH+1) + x] = line_bitmap & 1U << (7 - x) ? color : 0;
|
||||
uint32_t last_color = 0;
|
||||
if ( 0xB0 <= remap && remap <= 0xDF && (line_bitmap & 1) )
|
||||
last_color = color;
|
||||
buffer[y * (FONT_REALWIDTH+1) + 8] = last_color;
|
||||
}
|
||||
|
||||
struct framebuffer character_fb;
|
||||
character_fb.xres = FONT_WIDTH;
|
||||
character_fb.yres = FONT_HEIGHT;
|
||||
character_fb.pitch = character_fb.xres;
|
||||
character_fb.buffer = buffer;
|
||||
|
||||
framebuffer_copy_to_framebuffer_blend(fb, character_fb);
|
||||
}
|
||||
|
||||
void render_text(struct framebuffer fb, const char* str, uint32_t color)
|
||||
{
|
||||
mbstate_t ps;
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
size_t column = 0;
|
||||
for ( size_t i = 0; true; i++ )
|
||||
{
|
||||
wchar_t wc;
|
||||
size_t amount = mbrtowc(&wc, str + i, 1, &ps);
|
||||
if ( amount == (size_t) -2 )
|
||||
continue;
|
||||
if ( amount == (size_t) -1 )
|
||||
{
|
||||
wc = REPLACEMENT_CHARACTER;
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
}
|
||||
if ( amount == (size_t) 0 )
|
||||
break;
|
||||
int width = wcwidth(wc);
|
||||
if ( 0 < width )
|
||||
{
|
||||
render_char(framebuffer_crop(fb, FONT_REALWIDTH * column, 0,
|
||||
fb.xres, fb.yres), str[i], color);
|
||||
column += width; // TODO: Overflow.
|
||||
}
|
||||
if ( amount == (size_t) -1 && str[i] == '\0' )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t render_text_columns(const char* str)
|
||||
{
|
||||
mbstate_t ps;
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
size_t column = 0;
|
||||
for ( size_t i = 0; true; i++ )
|
||||
{
|
||||
wchar_t wc;
|
||||
size_t amount = mbrtowc(&wc, str + i, 1, &ps);
|
||||
if ( amount == (size_t) -2 )
|
||||
continue;
|
||||
if ( amount == (size_t) -1 )
|
||||
{
|
||||
wc = REPLACEMENT_CHARACTER;
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
}
|
||||
if ( amount == (size_t) 0 )
|
||||
break;
|
||||
int width = wcwidth(wc);
|
||||
if ( 0 < width )
|
||||
column += width; // TODO: Overflow.
|
||||
if ( amount == (size_t) -1 && str[i] == '\0' )
|
||||
break;
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
size_t render_text_width(const char* str)
|
||||
{
|
||||
// TODO: Overflow.
|
||||
return FONT_WIDTH * render_text_columns(str);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
nyan
|
||||
*.o
|
|
@ -0,0 +1,33 @@
|
|||
SOFTWARE_MEANT_FOR_SORTIX=1
|
||||
include ../build-aux/platform.mak
|
||||
include ../build-aux/compiler.mak
|
||||
include ../build-aux/dirs.mak
|
||||
|
||||
OPTLEVEL?=-g -O2
|
||||
CFLAGS?=$(OPTLEVEL)
|
||||
|
||||
CFLAGS:=$(CFLAGS) -Wall -Wextra
|
||||
|
||||
PROGRAM=nyan
|
||||
|
||||
OBJS=\
|
||||
nyan.o \
|
||||
|
||||
LIBS:=-lui -ldisplay
|
||||
|
||||
all: $(PROGRAM)
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
install $(PROGRAM) $(DESTDIR)$(BINDIR)
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $(OBJS) -o $@ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(PROGRAM) *.o
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* nyan.c
|
||||
* Window with animated nyancat.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/keycodes.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <ioleast.h>
|
||||
#include <locale.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <timespec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <display.h>
|
||||
#include <nyan.h>
|
||||
|
||||
#include "pixel.h"
|
||||
|
||||
uint32_t WINDOW_ID = 0;
|
||||
uint32_t WINDOW_WIDTH = 0;
|
||||
uint32_t WINDOW_HEIGHT = 0;
|
||||
|
||||
bool need_redraw = true;
|
||||
bool need_show = true;
|
||||
bool need_exit = false;
|
||||
|
||||
void on_disconnect(void* ctx)
|
||||
{
|
||||
(void) ctx;
|
||||
need_exit = true;
|
||||
}
|
||||
|
||||
void on_quit(void* ctx, uint32_t window_id)
|
||||
{
|
||||
(void) ctx;
|
||||
if ( window_id != WINDOW_ID )
|
||||
return;
|
||||
need_exit = true;
|
||||
}
|
||||
|
||||
void on_resize(void* ctx, uint32_t window_id, uint32_t width, uint32_t height)
|
||||
{
|
||||
(void) ctx;
|
||||
if ( window_id != WINDOW_ID )
|
||||
return;
|
||||
need_redraw = true;
|
||||
WINDOW_WIDTH = width;
|
||||
WINDOW_HEIGHT = height;
|
||||
}
|
||||
|
||||
void on_keyboard(void* ctx, uint32_t window_id, uint32_t codepoint)
|
||||
{
|
||||
(void) ctx;
|
||||
if ( window_id != WINDOW_ID )
|
||||
return;
|
||||
(void) codepoint;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
struct display_connection* connection = display_connect_default();
|
||||
if ( !connection && errno == ECONNREFUSED )
|
||||
display_spawn(argc, argv);
|
||||
if ( !connection )
|
||||
error(1, errno, "Could not connect to display server");
|
||||
|
||||
WINDOW_WIDTH = 600;
|
||||
WINDOW_HEIGHT = 600;
|
||||
|
||||
display_create_window(connection, WINDOW_ID);
|
||||
display_resize_window(connection, WINDOW_ID, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
display_title_window(connection, WINDOW_ID, "Nyanyanyanyanyanyanya...");
|
||||
|
||||
struct timespec frame_duration = timespec_make(0, 90 * 1000 * 1000);
|
||||
|
||||
struct timespec last_frame;
|
||||
clock_gettime(CLOCK_MONOTONIC, &last_frame);
|
||||
|
||||
int frame_num = 0;
|
||||
|
||||
while ( !need_exit )
|
||||
{
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
struct timespec since_last_frame = timespec_sub(now, last_frame);
|
||||
|
||||
if ( !need_redraw && timespec_lt(since_last_frame, frame_duration) )
|
||||
{
|
||||
struct timespec remainder = timespec_sub(frame_duration, since_last_frame);
|
||||
if ( timespec_lt(remainder, timespec_make(0, 10 * 1000 * 1000)) )
|
||||
remainder = timespec_make(0, 10 * 1000 * 1000);
|
||||
nanosleep(&remainder, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
while ( timespec_le(frame_duration, since_last_frame) )
|
||||
{
|
||||
if ( !nyan_frames[++frame_num] )
|
||||
frame_num = 0;
|
||||
need_redraw = true;
|
||||
since_last_frame = timespec_sub(since_last_frame, frame_duration);
|
||||
}
|
||||
|
||||
if ( need_redraw )
|
||||
{
|
||||
last_frame = now;
|
||||
|
||||
uint32_t* framebuffer = (uint32_t*) malloc(sizeof(uint32_t) * WINDOW_WIDTH * WINDOW_HEIGHT);
|
||||
|
||||
const char* const* frame = nyan_frames[frame_num];
|
||||
for ( size_t y = 0; y < WINDOW_HEIGHT; y++ )
|
||||
{
|
||||
int yi = y * NYAN_FRAME_HEIGHT / WINDOW_HEIGHT;
|
||||
const char* line = frame[yi];
|
||||
for ( size_t x = 0; x < WINDOW_WIDTH; x++ )
|
||||
{
|
||||
int xi = x * NYAN_FRAME_WIDTH / WINDOW_WIDTH;
|
||||
char elem = line[xi];
|
||||
const uint8_t* cc = nyan_palette[nyan_palette_of_char(elem)];
|
||||
framebuffer[y * WINDOW_WIDTH + x] = make_color_a(cc[0], cc[1], cc[2], cc[3]);;
|
||||
}
|
||||
}
|
||||
|
||||
display_render_window(connection, WINDOW_ID, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, framebuffer);
|
||||
|
||||
free(framebuffer);
|
||||
|
||||
need_redraw = false;
|
||||
}
|
||||
|
||||
if ( need_show )
|
||||
{
|
||||
display_show_window(connection, WINDOW_ID);
|
||||
need_show = false;
|
||||
}
|
||||
|
||||
struct display_event_handlers handlers;
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
handlers.disconnect_handler = on_disconnect;
|
||||
handlers.quit_handler = on_quit;
|
||||
handlers.resize_handler = on_resize;
|
||||
handlers.keyboard_handler = on_keyboard;
|
||||
while ( display_poll_event(connection, &handlers) == 0 );
|
||||
}
|
||||
|
||||
display_disconnect(connection);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
require base no-await
|
||||
require local no-await
|
||||
|
||||
tty tty0
|
||||
need tty
|
||||
|
||||
cd "$HOME"
|
||||
exit-code-meaning poweroff-reboot
|
||||
# TODO: $SHELL?
|
||||
exec display terminal sh
|
|
@ -0,0 +1,11 @@
|
|||
require base no-await
|
||||
require local no-await
|
||||
|
||||
tty tty0
|
||||
need tty
|
||||
|
||||
# TODO:
|
||||
#program=sysinstall
|
||||
#exec "$program"
|
||||
exec display terminal sysinstall
|
||||
exit-code-meaning poweroff-reboot
|
|
@ -0,0 +1,11 @@
|
|||
require base no-await
|
||||
require local no-await
|
||||
|
||||
tty tty0
|
||||
need tty
|
||||
|
||||
# TODO:
|
||||
#program=sysupgrade
|
||||
#exec "$program"
|
||||
exec display terminal sysupgrade
|
||||
exit-code-meaning poweroff-reboot
|
|
@ -106,6 +106,16 @@ It depends on the
|
|||
and
|
||||
.Sy local
|
||||
daemons.
|
||||
.It Sy single-user-gui
|
||||
Like
|
||||
.Sy single-user ,
|
||||
but runs the root shell in
|
||||
.Xr terminal 1
|
||||
inside the
|
||||
.Xr display 8
|
||||
graphical user interface environment.
|
||||
This operating system mode is insecure because it boots straight to root access
|
||||
without a password.
|
||||
.It Sy sysinstall
|
||||
Starts the operating system installer.
|
||||
It starts the
|
||||
|
@ -119,6 +129,16 @@ It depends on the
|
|||
and
|
||||
.Sy local
|
||||
daemons.
|
||||
.It Sy sysinstall-gui
|
||||
Like
|
||||
.Sy sysinstall ,
|
||||
but runs it in
|
||||
.Xr terminal 1
|
||||
inside the
|
||||
.Xr display 8
|
||||
graphical user interface environment.
|
||||
This operating system mode is insecure because it boots straight to root access
|
||||
without a password.
|
||||
.It Sy sysupgrade
|
||||
Starts the operating system upgrader.
|
||||
It starts the
|
||||
|
@ -132,6 +152,16 @@ It depends on the
|
|||
and
|
||||
.Sy local
|
||||
daemons.
|
||||
.It Sy sysupgrade-gui
|
||||
Like
|
||||
.Sy sysupgrade ,
|
||||
but runs it in
|
||||
.Xr terminal 1
|
||||
inside the
|
||||
.Xr display 8
|
||||
graphical user interface environment.
|
||||
This operating system mode is insecure because it boots straight to root access
|
||||
without a password.
|
||||
.El
|
||||
.Pp
|
||||
The following daemons are provided by the system:
|
||||
|
|
|
@ -510,6 +510,12 @@ ssh-keygen -t rsa -f liveconfig/root/.ssh/id_rsa -N "" -C "root@$hostname"
|
|||
Consider omitting the
|
||||
.Fl N
|
||||
option and password protect the private key to protect it in the case of a leak.
|
||||
.Ss Boot to Console Instead of GUI By Default
|
||||
To customize a release so it boots to a console instead of the GUI:
|
||||
.Bd -literal
|
||||
tix-iso-bootconfig --disable-gui bootconfig
|
||||
tix-iso-add sortix.iso bootconfig
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr xorriso 1 ,
|
||||
.Xr development 7 ,
|
||||
|
|
|
@ -57,13 +57,13 @@ install: all
|
|||
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-init
|
||||
|
||||
sysinstall: $(SYSINSTALL_OBJS)
|
||||
$(CC) $(SYSINSTALL_OBJS) -o $@ -lmount
|
||||
$(CC) $(SYSINSTALL_OBJS) -o $@ -lmount -ldisplay
|
||||
|
||||
sysmerge: $(SYSMERGE_OBJS)
|
||||
$(CC) $(SYSMERGE_OBJS) -o $@ -lmount
|
||||
|
||||
sysupgrade: $(SYSUPGRADE_OBJS)
|
||||
$(CC) $(SYSUPGRADE_OBJS) -o $@ -lmount
|
||||
$(CC) $(SYSUPGRADE_OBJS) -o $@ -lmount -ldisplay
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -std=gnu11 -c $< -o $@
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <termios.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <display.h>
|
||||
|
||||
#include "execute.h"
|
||||
#include "interactive.h"
|
||||
|
||||
|
@ -234,3 +236,15 @@ bool missing_program(const char* program)
|
|||
warnx("%s: Program is absent", program);
|
||||
return true;
|
||||
}
|
||||
|
||||
void gui_shutdown(int code)
|
||||
{
|
||||
if ( getenv("DISPLAY_SOCKET") )
|
||||
{
|
||||
struct display_connection* connection = display_connect_default();
|
||||
if ( connection )
|
||||
display_shutdown(connection, code);
|
||||
else
|
||||
warn("display_connect_default");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,5 +40,6 @@ void password(char* buffer,
|
|||
size_t buffer_size,
|
||||
const char* question);
|
||||
bool missing_program(const char* program);
|
||||
void gui_shutdown(int code);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -339,6 +339,7 @@ static bool etc_made = false;
|
|||
static char etc[] = "/tmp/etc.XXXXXX";
|
||||
static bool fs_made = false;
|
||||
static char fs[] = "/tmp/fs.XXXXXX";
|
||||
static int exit_gui_code = -1;
|
||||
|
||||
static void unmount_all_but_root(void)
|
||||
{
|
||||
|
@ -367,6 +368,14 @@ void exit_handler(void)
|
|||
rmdir(fs);
|
||||
if ( etc_made )
|
||||
execute((const char*[]) { "rm", "-rf", etc, NULL }, "");
|
||||
if ( 0 <= exit_gui_code )
|
||||
gui_shutdown(exit_gui_code);
|
||||
}
|
||||
|
||||
void exit_gui(int code)
|
||||
{
|
||||
exit_gui_code = code;
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
@ -471,6 +480,7 @@ int main(void)
|
|||
|
||||
install_configurationf("upgrade.conf", "a", "src = yes\n");
|
||||
|
||||
// TODO: GUI support.
|
||||
bool kblayout_setable = 0 <= tcgetblob(0, "kblayout", NULL, 0);
|
||||
while ( kblayout_setable )
|
||||
{
|
||||
|
@ -829,7 +839,7 @@ int main(void)
|
|||
{
|
||||
prompt(input, sizeof(input),
|
||||
"Install " BRAND_DISTRIBUTION_NAME "? "
|
||||
"(yes/no/poweroff/reboot/halt)", "yes");
|
||||
"(yes/no/exit/poweroff/reboot/halt)", "yes");
|
||||
if ( !strcasecmp(input, "yes") )
|
||||
break;
|
||||
else if ( !strcasecmp(input, "no") )
|
||||
|
@ -840,12 +850,14 @@ int main(void)
|
|||
"'halt' to cancel the installation.\n");
|
||||
continue;
|
||||
}
|
||||
else if ( !strcasecmp(input, "poweroff") )
|
||||
else if ( !strcasecmp(input, "exit") )
|
||||
exit(0);
|
||||
else if ( !strcasecmp(input, "poweroff") )
|
||||
exit_gui(0);
|
||||
else if ( !strcasecmp(input, "reboot") )
|
||||
exit(1);
|
||||
exit_gui(1);
|
||||
else if ( !strcasecmp(input, "halt") )
|
||||
exit(2);
|
||||
exit_gui(2);
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
@ -1277,14 +1289,16 @@ int main(void)
|
|||
while ( true )
|
||||
{
|
||||
prompt(input, sizeof(input),
|
||||
"What now? (poweroff/reboot/halt/boot)", "boot");
|
||||
if ( !strcasecmp(input, "poweroff") )
|
||||
"What now? (exit/poweroff/reboot/halt/boot)", "boot");
|
||||
if ( !strcasecmp(input, "exit") )
|
||||
exit(0);
|
||||
if ( !strcasecmp(input, "reboot") )
|
||||
exit(1);
|
||||
if ( !strcasecmp(input, "halt") )
|
||||
exit(2);
|
||||
if ( !strcasecmp(input, "boot") )
|
||||
else if ( !strcasecmp(input, "poweroff") )
|
||||
exit_gui(0);
|
||||
else if ( !strcasecmp(input, "reboot") )
|
||||
exit_gui(1);
|
||||
else if ( !strcasecmp(input, "halt") )
|
||||
exit_gui(2);
|
||||
else if ( !strcasecmp(input, "boot") )
|
||||
{
|
||||
unmount_all_but_root();
|
||||
unsetenv("SYSINSTALL_TARGET");
|
||||
|
|
|
@ -71,6 +71,7 @@ static struct mountpoint* mountpoints;
|
|||
static size_t mountpoints_used;
|
||||
static bool fs_made = false;
|
||||
static char fs[] = "/tmp/fs.XXXXXX";
|
||||
static int exit_gui_code = -1;
|
||||
|
||||
static bool add_installation(struct blockdevice* bdev,
|
||||
struct release* release,
|
||||
|
@ -327,6 +328,14 @@ void exit_handler(void)
|
|||
}
|
||||
if ( fs_made )
|
||||
rmdir(fs);
|
||||
if ( 0 <= exit_gui_code )
|
||||
gui_shutdown(exit_gui_code);
|
||||
}
|
||||
|
||||
void exit_gui(int code)
|
||||
{
|
||||
exit_gui_code = code;
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
@ -775,7 +784,7 @@ int main(void)
|
|||
while ( true )
|
||||
{
|
||||
promptx(input, sizeof(input),
|
||||
"Upgrade? (yes/no/poweroff/reboot/halt)", "yes", true);
|
||||
"Upgrade? (yes/no/exit/poweroff/reboot/halt)", "yes", true);
|
||||
if ( !strcasecmp(input, "yes") )
|
||||
break;
|
||||
else if ( !strcasecmp(input, "no") )
|
||||
|
@ -788,12 +797,14 @@ int main(void)
|
|||
"'halt' or cancel the upgrade.\n");
|
||||
continue;
|
||||
}
|
||||
else if ( !strcasecmp(input, "poweroff") )
|
||||
else if ( !strcasecmp(input, "exit") )
|
||||
exit(0);
|
||||
else if ( !strcasecmp(input, "poweroff") )
|
||||
exit_gui(0);
|
||||
else if ( !strcasecmp(input, "reboot") )
|
||||
exit(1);
|
||||
exit_gui(1);
|
||||
else if ( !strcasecmp(input, "halt") )
|
||||
exit(2);
|
||||
exit_gui(2);
|
||||
else if ( !strcasecmp(input, "!") )
|
||||
break;
|
||||
else
|
||||
|
@ -931,12 +942,14 @@ int main(void)
|
|||
while ( true )
|
||||
{
|
||||
prompt(input, sizeof(input),
|
||||
"What now? (poweroff/reboot/halt)", "reboot");
|
||||
if ( !strcasecmp(input, "poweroff") )
|
||||
return 0;
|
||||
if ( !strcasecmp(input, "reboot") )
|
||||
return 1;
|
||||
if ( !strcasecmp(input, "halt") )
|
||||
return 2;
|
||||
"What now? (exit/poweroff/reboot/halt)", "reboot");
|
||||
if ( !strcasecmp(input, "exit") )
|
||||
exit(0);
|
||||
else if ( !strcasecmp(input, "poweroff") )
|
||||
exit_gui(0);
|
||||
else if ( !strcasecmp(input, "reboot") )
|
||||
exit_gui(1);
|
||||
else if ( !strcasecmp(input, "halt") )
|
||||
exit_gui(2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
terminal
|
||||
*.o
|
|
@ -0,0 +1,33 @@
|
|||
SOFTWARE_MEANT_FOR_SORTIX=1
|
||||
include ../build-aux/platform.mak
|
||||
include ../build-aux/compiler.mak
|
||||
include ../build-aux/dirs.mak
|
||||
|
||||
OPTLEVEL?=-g -O2
|
||||
CFLAGS?=$(OPTLEVEL)
|
||||
|
||||
CFLAGS:=$(CFLAGS) -Wall -Wextra
|
||||
|
||||
PROGRAM=terminal
|
||||
|
||||
OBJS=\
|
||||
terminal.o \
|
||||
|
||||
LIBS:=-lui -ldisplay
|
||||
|
||||
all: $(PROGRAM)
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
install $(PROGRAM) $(DESTDIR)$(BINDIR)
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $(OBJS) -o $@ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(PROGRAM) *.o
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* palette.h
|
||||
* Console color palette, matches the xterm palette with tango colors.
|
||||
*/
|
||||
|
||||
#ifndef PALETTE_H
|
||||
#define PALETTE_H
|
||||
|
||||
static const uint32_t palette[256] =
|
||||
{
|
||||
0x000000,
|
||||
0xcc0000,
|
||||
0x3e9a06,
|
||||
0xc4a000,
|
||||
0x3465a4,
|
||||
0x75507b,
|
||||
0x06989a,
|
||||
0xbfbfbf,
|
||||
0x555753,
|
||||
0xef2929,
|
||||
0x8ae234,
|
||||
0xfce94f,
|
||||
0x729fcf,
|
||||
0xad7fa8,
|
||||
0x34e2e2,
|
||||
0xffffff,
|
||||
0x000000,
|
||||
0x00005f,
|
||||
0x000087,
|
||||
0x0000af,
|
||||
0x0000d7,
|
||||
0x0000ff,
|
||||
0x005f00,
|
||||
0x005f5f,
|
||||
0x005f87,
|
||||
0x005faf,
|
||||
0x005fd7,
|
||||
0x005fff,
|
||||
0x008700,
|
||||
0x00875f,
|
||||
0x008787,
|
||||
0x0087af,
|
||||
0x0087d7,
|
||||
0x0087ff,
|
||||
0x00af00,
|
||||
0x00af5f,
|
||||
0x00af87,
|
||||
0x00afaf,
|
||||
0x00afd7,
|
||||
0x00afff,
|
||||
0x00d700,
|
||||
0x00d75f,
|
||||
0x00d787,
|
||||
0x00d7af,
|
||||
0x00d7d7,
|
||||
0x00d7ff,
|
||||
0x00ff00,
|
||||
0x00ff5f,
|
||||
0x00ff87,
|
||||
0x00ffaf,
|
||||
0x00ffd7,
|
||||
0x00ffff,
|
||||
0x5f0000,
|
||||
0x5f005f,
|
||||
0x5f0087,
|
||||
0x5f00af,
|
||||
0x5f00d7,
|
||||
0x5f00ff,
|
||||
0x5f5f00,
|
||||
0x5f5f5f,
|
||||
0x5f5f87,
|
||||
0x5f5faf,
|
||||
0x5f5fd7,
|
||||
0x5f5fff,
|
||||
0x5f8700,
|
||||
0x5f875f,
|
||||
0x5f8787,
|
||||
0x5f87af,
|
||||
0x5f87d7,
|
||||
0x5f87ff,
|
||||
0x5faf00,
|
||||
0x5faf5f,
|
||||
0x5faf87,
|
||||
0x5fafaf,
|
||||
0x5fafd7,
|
||||
0x5fafff,
|
||||
0x5fd700,
|
||||
0x5fd75f,
|
||||
0x5fd787,
|
||||
0x5fd7af,
|
||||
0x5fd7d7,
|
||||
0x5fd7ff,
|
||||
0x5fff00,
|
||||
0x5fff5f,
|
||||
0x5fff87,
|
||||
0x5fffaf,
|
||||
0x5fffd7,
|
||||
0x5fffff,
|
||||
0x870000,
|
||||
0x87005f,
|
||||
0x870087,
|
||||
0x8700af,
|
||||
0x8700d7,
|
||||
0x8700ff,
|
||||
0x875f00,
|
||||
0x875f5f,
|
||||
0x875f87,
|
||||
0x875faf,
|
||||
0x875fd7,
|
||||
0x875fff,
|
||||
0x878700,
|
||||
0x87875f,
|
||||
0x878787,
|
||||
0x8787af,
|
||||
0x8787d7,
|
||||
0x8787ff,
|
||||
0x87af00,
|
||||
0x87af5f,
|
||||
0x87af87,
|
||||
0x87afaf,
|
||||
0x87afd7,
|
||||
0x87afff,
|
||||
0x87d700,
|
||||
0x87d75f,
|
||||
0x87d787,
|
||||
0x87d7af,
|
||||
0x87d7d7,
|
||||
0x87d7ff,
|
||||
0x87ff00,
|
||||
0x87ff5f,
|
||||
0x87ff87,
|
||||
0x87ffaf,
|
||||
0x87ffd7,
|
||||
0x87ffff,
|
||||
0xaf0000,
|
||||
0xaf005f,
|
||||
0xaf0087,
|
||||
0xaf00af,
|
||||
0xaf00d7,
|
||||
0xaf00ff,
|
||||
0xaf5f00,
|
||||
0xaf5f5f,
|
||||
0xaf5f87,
|
||||
0xaf5faf,
|
||||
0xaf5fd7,
|
||||
0xaf5fff,
|
||||
0xaf8700,
|
||||
0xaf875f,
|
||||
0xaf8787,
|
||||
0xaf87af,
|
||||
0xaf87d7,
|
||||
0xaf87ff,
|
||||
0xafaf00,
|
||||
0xafaf5f,
|
||||
0xafaf87,
|
||||
0xafafaf,
|
||||
0xafafd7,
|
||||
0xafafff,
|
||||
0xafd700,
|
||||
0xafd75f,
|
||||
0xafd787,
|
||||
0xafd7af,
|
||||
0xafd7d7,
|
||||
0xafd7ff,
|
||||
0xafff00,
|
||||
0xafff5f,
|
||||
0xafff87,
|
||||
0xafffaf,
|
||||
0xafffd7,
|
||||
0xafffff,
|
||||
0xd70000,
|
||||
0xd7005f,
|
||||
0xd70087,
|
||||
0xd700af,
|
||||
0xd700d7,
|
||||
0xd700ff,
|
||||
0xd75f00,
|
||||
0xd75f5f,
|
||||
0xd75f87,
|
||||
0xd75faf,
|
||||
0xd75fd7,
|
||||
0xd75fff,
|
||||
0xd78700,
|
||||
0xd7875f,
|
||||
0xd78787,
|
||||
0xd787af,
|
||||
0xd787d7,
|
||||
0xd787ff,
|
||||
0xd7af00,
|
||||
0xd7af5f,
|
||||
0xd7af87,
|
||||
0xd7afaf,
|
||||
0xd7afd7,
|
||||
0xd7afff,
|
||||
0xd7d700,
|
||||
0xd7d75f,
|
||||
0xd7d787,
|
||||
0xd7d7af,
|
||||
0xd7d7d7,
|
||||
0xd7d7ff,
|
||||
0xd7ff00,
|
||||
0xd7ff5f,
|
||||
0xd7ff87,
|
||||
0xd7ffaf,
|
||||
0xd7ffd7,
|
||||
0xd7ffff,
|
||||
0xff0000,
|
||||
0xff005f,
|
||||
0xff0087,
|
||||
0xff00af,
|
||||
0xff00d7,
|
||||
0xff00ff,
|
||||
0xff5f00,
|
||||
0xff5f5f,
|
||||
0xff5f87,
|
||||
0xff5faf,
|
||||
0xff5fd7,
|
||||
0xff5fff,
|
||||
0xff8700,
|
||||
0xff875f,
|
||||
0xff8787,
|
||||
0xff87af,
|
||||
0xff87d7,
|
||||
0xff87ff,
|
||||
0xffaf00,
|
||||
0xffaf5f,
|
||||
0xffaf87,
|
||||
0xffafaf,
|
||||
0xffafd7,
|
||||
0xffafff,
|
||||
0xffd700,
|
||||
0xffd75f,
|
||||
0xffd787,
|
||||
0xffd7af,
|
||||
0xffd7d7,
|
||||
0xffd7ff,
|
||||
0xffff00,
|
||||
0xffff5f,
|
||||
0xffff87,
|
||||
0xffffaf,
|
||||
0xffffd7,
|
||||
0xffffff,
|
||||
0x080808,
|
||||
0x121212,
|
||||
0x1c1c1c,
|
||||
0x262626,
|
||||
0x303030,
|
||||
0x3a3a3a,
|
||||
0x444444,
|
||||
0x4e4e4e,
|
||||
0x585858,
|
||||
0x626262,
|
||||
0x6c6c6c,
|
||||
0x767676,
|
||||
0x808080,
|
||||
0x8a8a8a,
|
||||
0x949494,
|
||||
0x9e9e9e,
|
||||
0xa8a8a8,
|
||||
0xb2b2b2,
|
||||
0xbcbcbc,
|
||||
0xc6c6c6,
|
||||
0xd0d0d0,
|
||||
0xdadada,
|
||||
0xe4e4e4,
|
||||
0xeeeeee,
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -23,6 +23,7 @@ default=
|
|||
directory=
|
||||
enable_append_title=true
|
||||
enable_dhclient=
|
||||
enable_gui=
|
||||
enable_network_drivers=
|
||||
enable_src=
|
||||
enable_sshd=
|
||||
|
@ -54,11 +55,13 @@ for argument do
|
|||
--default) previous_option=default ;;
|
||||
--disable-append-title) enable_append_title=false ;;
|
||||
--disable-dhclient) enable_dhclient=false ;;
|
||||
--disable-gui) enable_gui=false ;;
|
||||
--disable-network-drivers) enable_network_drivers=false ;;
|
||||
--disable-src) enable_src=false ;;
|
||||
--disable-sshd) enable_sshd=false ;;
|
||||
--enable-append-title) enable_append_title=true ;;
|
||||
--enable-dhclient) enable_dhclient=true ;;
|
||||
--enable-gui) enable_gui=true ;;
|
||||
--enable-network-drivers) enable_network_drivers=true ;;
|
||||
--enable-src) enable_src=true ;;
|
||||
--enable-sshd) enable_sshd=true ;;
|
||||
|
@ -142,6 +145,7 @@ mkdir -p -- "$directory/boot/grub"
|
|||
printf 'timeout="%s"\n' "$timeout"
|
||||
fi
|
||||
print_enable_default_bool "$enable_dhclient" dhclient dhclient
|
||||
print_enable_default_bool "$enable_gui" gui gui
|
||||
print_enable_default "$enable_network_drivers" network_drivers network-drivers
|
||||
print_enable_default_bool "$enable_src" src src
|
||||
print_enable_default_bool "$enable_sshd" sshd sshd
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
.Op Fl \-default Ns = Ns Ar default-boot-menu-option
|
||||
.Op Fl \-disable-append-title
|
||||
.Op Fl \-disable-dhclient
|
||||
.Op Fl \-disable-gui
|
||||
.Op Fl \-disable-network-drivers
|
||||
.Op Fl \-disable-src
|
||||
.Op Fl \-disable-sshd
|
||||
.Op Fl \-enable-append-title
|
||||
.Op Fl \-enable-dhclient
|
||||
.Op Fl \-enable-gui
|
||||
.Op Fl \-enable-network-drivers
|
||||
.Op Fl \-enable-src
|
||||
.Op Fl \-enable-sshd
|
||||
|
@ -102,6 +104,16 @@ GRUB variable to
|
|||
causing the bootloader to load additional configuration that turns off the
|
||||
.Xr dhclient 8
|
||||
daemon on boot.
|
||||
.It Fl \-disable-gui
|
||||
Disable the GUI by setting the
|
||||
.Sy enable_gui
|
||||
GRUB variable to
|
||||
.Sy false ,
|
||||
which makes the bootloader configuration not append
|
||||
.Sy -gui
|
||||
to the requested
|
||||
.Xr init 8
|
||||
target.
|
||||
.It Fl \-disable-network-drivers
|
||||
Disable network drivers by setting the
|
||||
.Sy enable_network_drivers
|
||||
|
@ -141,6 +153,16 @@ GRUB variable to
|
|||
selecting the default behavior of starting the
|
||||
.Xr dhclient 8
|
||||
daemon.
|
||||
.It Fl \-enable-gui
|
||||
Enable the GUI by setting the
|
||||
.Sy enable_gui
|
||||
GRUB variable to
|
||||
.Sy true ,
|
||||
which makes the bootloader configuration append
|
||||
.Sy -gui
|
||||
to the requested
|
||||
.Xr init 8
|
||||
target.
|
||||
.It Fl \-enable-network-drivers
|
||||
Enable network drivers by setting the
|
||||
.Sy enable_network_drivers
|
||||
|
@ -308,6 +330,12 @@ automatically using the SSH configuration found in the liveconfig directory:
|
|||
tix-iso-bootconfig --liveconfig=liveconfig --enable-sshd bootconfig
|
||||
tix-iso-add sortix.iso bootconfig
|
||||
.Ed
|
||||
.Ss Boot to Console Instead of GUI By Default
|
||||
To customize a release so it boots to a console instead of the GUI:
|
||||
.Bd -literal
|
||||
tix-iso-bootconfig --disable-gui bootconfig
|
||||
tix-iso-add sortix.iso bootconfig
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr xorriso 1 ,
|
||||
.Xr kernel 7 ,
|
||||
|
|
|
@ -15,7 +15,7 @@ LIBS:=-ldispd
|
|||
|
||||
all: $(BINARY)
|
||||
|
||||
.PHONY: all install uninstall clean
|
||||
.PHONY: all install clean
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
|
|
|
@ -29,7 +29,10 @@
|
|||
|
||||
static void suggest_logout(void)
|
||||
{
|
||||
fprintf(stderr, " Exiting your shell normally to logout.\n");
|
||||
if ( getenv("DISPLAY_SOCKET") )
|
||||
fprintf(stderr, " Pressing Ctrl-Alt-Del to exit desktop.\n");
|
||||
else
|
||||
fprintf(stderr, " Exiting your shell normally to logout.\n");
|
||||
}
|
||||
|
||||
enum category
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
video-player
|
|
@ -0,0 +1,26 @@
|
|||
include ../build-aux/compiler.mak
|
||||
include ../build-aux/version.mak
|
||||
include ../build-aux/dirs.mak
|
||||
|
||||
OPTLEVEL?=-g -O2
|
||||
CXXFLAGS?=$(OPTLEVEL)
|
||||
|
||||
CPPFLAGS:=$(CPPFLAGS)
|
||||
CXXFLAGS:=$(CXXFLAGS) -Wall -Wextra -fno-exceptions -fno-rtti
|
||||
|
||||
BINARY:=video-player
|
||||
LIBS:=-lswscale -lavformat -lavcodec -lavutil -ldisplay
|
||||
|
||||
all: $(BINARY)
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
%: %.cpp
|
||||
$(CXX) -std=gnu++11 $(CPPFLAGS) $(CXXFLAGS) $< -o $@ $(LIBS)
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
install $(BINARY) $(DESTDIR)$(BINDIR)
|
||||
|
||||
clean:
|
||||
rm -f $(BINARY)
|
|
@ -0,0 +1,5 @@
|
|||
tix.version=1
|
||||
tix.class=srctix
|
||||
pkg.name=video-player
|
||||
pkg.build-libraries=libav
|
||||
pkg.build-system=sortix-usual-makefile
|
|
@ -0,0 +1,274 @@
|
|||
#define __STDC_CONSTANT_MACROS
|
||||
#define __STDC_LIMIT_MACROS
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <timespec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <display.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
} // extern "C"
|
||||
|
||||
uint32_t WINDOW_ID = 0;
|
||||
uint32_t WINDOW_WIDTH = 0;
|
||||
uint32_t WINDOW_HEIGHT = 0;
|
||||
|
||||
bool need_show = true;
|
||||
bool need_exit = false;
|
||||
|
||||
uint32_t* framebuffer = NULL;
|
||||
size_t framebuffer_size = 0;
|
||||
|
||||
void on_disconnect(void*)
|
||||
{
|
||||
need_exit = true;
|
||||
}
|
||||
|
||||
void on_quit(void*, uint32_t window_id)
|
||||
{
|
||||
if ( window_id != WINDOW_ID )
|
||||
return;
|
||||
need_exit = true;
|
||||
}
|
||||
|
||||
void on_resize(void*, uint32_t window_id, uint32_t width, uint32_t height)
|
||||
{
|
||||
if ( window_id != WINDOW_ID )
|
||||
return;
|
||||
WINDOW_WIDTH = width;
|
||||
WINDOW_HEIGHT = height;
|
||||
}
|
||||
|
||||
void on_keyboard(void*, uint32_t window_id, uint32_t)
|
||||
{
|
||||
if ( window_id != WINDOW_ID )
|
||||
return;
|
||||
}
|
||||
|
||||
static void DisplayVideoFrame(AVFrame* frame, struct display_connection* connection)
|
||||
{
|
||||
size_t framebuffer_needed = sizeof(uint32_t) * WINDOW_WIDTH * WINDOW_HEIGHT;
|
||||
if ( framebuffer_size != framebuffer_needed )
|
||||
{
|
||||
framebuffer = (uint32_t*) realloc(framebuffer, framebuffer_size = framebuffer_needed);
|
||||
memset(framebuffer, 255, framebuffer_needed);
|
||||
}
|
||||
|
||||
SwsContext* sws_ctx = sws_getContext(frame->width, frame->height,
|
||||
(PixelFormat) frame->format, WINDOW_WIDTH,
|
||||
WINDOW_HEIGHT, PIX_FMT_RGB32, SWS_BILINEAR,
|
||||
NULL, NULL, NULL);
|
||||
assert(sws_ctx);
|
||||
|
||||
uint8_t* data_arr[1] = { (uint8_t*) framebuffer };
|
||||
int stride_arr[1] = { (int) (sizeof(framebuffer[0]) * WINDOW_WIDTH) };
|
||||
sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, data_arr,
|
||||
stride_arr);
|
||||
|
||||
sws_freeContext(sws_ctx);
|
||||
|
||||
display_render_window(connection, WINDOW_ID, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, framebuffer);
|
||||
|
||||
struct display_event_handlers handlers;
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
handlers.disconnect_handler = on_disconnect;
|
||||
handlers.quit_handler = on_quit;
|
||||
handlers.resize_handler = on_resize;
|
||||
handlers.keyboard_handler = on_keyboard;
|
||||
while ( display_poll_event(connection, &handlers) == 0 );
|
||||
}
|
||||
|
||||
bool PlayVideo(const char* path, struct display_connection* connection)
|
||||
{
|
||||
bool ret = false;
|
||||
int av_error;
|
||||
AVFormatContext* format_ctx = NULL;
|
||||
int video_stream_id;
|
||||
int audio_stream_id;
|
||||
AVStream* video_stream = NULL;
|
||||
AVStream* audio_stream = NULL;
|
||||
AVCodec* video_codec = NULL;
|
||||
AVCodec* audio_codec = NULL;
|
||||
AVCodecContext* video_codec_ctx = NULL;
|
||||
AVCodecContext* audio_codec_ctx = NULL;
|
||||
AVFrame* video_frame = NULL;
|
||||
AVFrame* audio_frame = NULL;
|
||||
AVPacket packet;
|
||||
|
||||
if ( (av_error = avformat_open_input(&format_ctx, path, NULL, NULL)) < 0 )
|
||||
{
|
||||
error(0, 0, "%s: cannot open: %i\n", path, av_error);
|
||||
goto cleanup_done;
|
||||
}
|
||||
|
||||
if ( (av_error = avformat_find_stream_info(format_ctx, NULL)) < 0 )
|
||||
{
|
||||
error(0, 0, "%s: avformat_find_stream_info: %i\n", path, av_error);
|
||||
goto cleanup_input;
|
||||
}
|
||||
|
||||
video_stream_id = av_find_best_stream(format_ctx, AVMEDIA_TYPE_VIDEO, -1,
|
||||
-1, &video_codec, 0);
|
||||
audio_stream_id = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1,
|
||||
-1, &audio_codec, 0);
|
||||
|
||||
if ( 0 <= video_stream_id )
|
||||
video_stream = format_ctx->streams[video_stream_id];
|
||||
if ( 0 <= audio_stream_id )
|
||||
audio_stream = format_ctx->streams[audio_stream_id];
|
||||
|
||||
if ( !video_stream )
|
||||
{
|
||||
error(0, 0, "%s: no video stream found\n", path);
|
||||
goto cleanup_input;
|
||||
}
|
||||
|
||||
if ( video_codec && !(video_codec_ctx = avcodec_alloc_context3(video_codec)))
|
||||
goto cleanup_input;
|
||||
if ( audio_codec && !(audio_codec_ctx = avcodec_alloc_context3(audio_codec)))
|
||||
goto cleanup_video_codec_ctx;
|
||||
|
||||
if ( video_codec_ctx )
|
||||
{
|
||||
video_codec_ctx->extradata = video_stream->codec->extradata;
|
||||
video_codec_ctx->extradata_size = video_stream->codec->extradata_size;
|
||||
if ( (av_error = avcodec_open2(video_codec_ctx, NULL, NULL)) < 0 )
|
||||
goto cleanup_audio_codec_ctx;
|
||||
}
|
||||
if ( audio_codec_ctx )
|
||||
{
|
||||
audio_codec_ctx->extradata = audio_stream->codec->extradata;
|
||||
audio_codec_ctx->extradata_size = audio_stream->codec->extradata_size;
|
||||
if ( (av_error = avcodec_open2(audio_codec_ctx, NULL, NULL)) < 0 )
|
||||
goto cleanup_audio_codec_ctx;
|
||||
}
|
||||
|
||||
if ( !(video_frame = avcodec_alloc_frame()) )
|
||||
goto cleanup_audio_codec_ctx;
|
||||
if ( !(audio_frame = avcodec_alloc_frame()) )
|
||||
goto cleanup_video_frame;
|
||||
|
||||
struct timespec next_frame_at;
|
||||
clock_gettime(CLOCK_MONOTONIC, &next_frame_at);
|
||||
|
||||
while ( !need_exit && 0 <= (av_error = av_read_frame(format_ctx, &packet)) )
|
||||
{
|
||||
int stream_index = packet.stream_index;
|
||||
int packet_off = 0;
|
||||
while ( stream_index == video_stream->index && packet_off < packet.size )
|
||||
{
|
||||
packet.data += packet_off; packet.size -= packet_off;
|
||||
int got_frame;
|
||||
int bytes_used = avcodec_decode_video2(video_codec_ctx, video_frame,
|
||||
&got_frame, &packet);
|
||||
packet.data -= packet_off; packet.size += packet_off;
|
||||
|
||||
if ( (av_error = bytes_used) < 0 )
|
||||
goto break_decode_loop;
|
||||
if ( !got_frame )
|
||||
break;
|
||||
packet_off += bytes_used;
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
while ( timespec_le(now, next_frame_at) )
|
||||
{
|
||||
struct timespec left = timespec_sub(next_frame_at, now);
|
||||
clock_nanosleep(CLOCK_MONOTONIC, 0, &left, NULL);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
}
|
||||
|
||||
DisplayVideoFrame(video_frame, connection);
|
||||
|
||||
uintmax_t usecs = video_codec_ctx->ticks_per_frame * 1000000 *
|
||||
video_codec_ctx->time_base.num /
|
||||
video_codec_ctx->time_base.den;
|
||||
next_frame_at = timespec_add(next_frame_at, timespec_make(0, usecs * 1000));
|
||||
}
|
||||
while ( stream_index == audio_stream->index && packet_off < packet.size )
|
||||
{
|
||||
// TODO: Add sound support when an backend is available.
|
||||
packet_off = packet.size;
|
||||
}
|
||||
}
|
||||
break_decode_loop:
|
||||
|
||||
// TODO: Determine whether the are here because of EOF or whether an error
|
||||
// occured and we need to print an error.
|
||||
// TODO: Do we need to clean up the last packet or does the av_read_frame
|
||||
// function do that for us upon error?
|
||||
ret = true;
|
||||
|
||||
goto cleanup_audio_frame;
|
||||
cleanup_audio_frame:
|
||||
if ( audio_frame )
|
||||
#if 55 <= LIBAVCODEC_VERSION_MAJOR
|
||||
avcodec_free_frame(&audio_frame);
|
||||
#else
|
||||
av_free(audio_frame);
|
||||
#endif
|
||||
cleanup_video_frame:
|
||||
if ( video_frame )
|
||||
#if 55 <= LIBAVCODEC_VERSION_MAJOR
|
||||
avcodec_free_frame(&video_frame);
|
||||
#else
|
||||
av_free(video_frame);
|
||||
#endif
|
||||
cleanup_audio_codec_ctx:
|
||||
if ( audio_codec_ctx )
|
||||
{
|
||||
audio_codec_ctx->extradata = NULL;
|
||||
avcodec_close(audio_codec_ctx);
|
||||
av_free(audio_codec_ctx);
|
||||
}
|
||||
cleanup_video_codec_ctx:
|
||||
if ( video_codec_ctx )
|
||||
{
|
||||
video_codec_ctx->extradata = NULL;
|
||||
avcodec_close(video_codec_ctx);
|
||||
av_free(video_codec_ctx);
|
||||
}
|
||||
cleanup_input:
|
||||
avformat_close_input(&format_ctx);
|
||||
cleanup_done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
struct display_connection* connection = display_connect_default();
|
||||
if ( !connection && errno == ECONNREFUSED )
|
||||
display_spawn(argc, argv);
|
||||
if ( !connection )
|
||||
error(1, errno, "Could not connect to display server");
|
||||
|
||||
av_register_all();
|
||||
|
||||
WINDOW_WIDTH = 800;
|
||||
WINDOW_HEIGHT = 450;
|
||||
|
||||
display_create_window(connection, WINDOW_ID);
|
||||
display_resize_window(connection, WINDOW_ID, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
display_show_window(connection, WINDOW_ID);
|
||||
|
||||
for ( int i = 1; i < argc; i++ )
|
||||
{
|
||||
display_title_window(connection, WINDOW_ID, argv[i]);
|
||||
if ( !PlayVideo(argv[i], connection) )
|
||||
return 1;
|
||||
}
|
||||
|
||||
display_disconnect(connection);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue