841 lines
17 KiB
C
841 lines
17 KiB
C
/* blib - Library of useful things to hack the Blinkenlights
|
|
*
|
|
* Copyright (c) 2001-2002 The Blinkenlights Crew
|
|
* Michael Natterer <mitch@gimp.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <glib-object.h>
|
|
|
|
#include <blib/blib.h>
|
|
|
|
|
|
#define TEXT_TIMEOUT 200
|
|
#define BLINK_TIMEOUT 200
|
|
#define SCROLL_TIMEOUT 100
|
|
#define CHAR_WIDTH 3
|
|
#define CHAR_HEIGHT 5
|
|
#define CHAR_ADVANCE 4
|
|
#define LINE_ADVANCE 6
|
|
#define BLINK_STEPS 4
|
|
|
|
|
|
typedef struct _BChar BChar;
|
|
|
|
struct _BChar
|
|
{
|
|
gchar character;
|
|
gchar width;
|
|
guchar matrix[CHAR_WIDTH * CHAR_HEIGHT];
|
|
};
|
|
|
|
static const BChar unknown_char =
|
|
{
|
|
0, 3,
|
|
{ 1, 1, 1,
|
|
1, 1, 1,
|
|
1, 1, 1,
|
|
1, 1, 1,
|
|
1, 1, 1
|
|
}
|
|
};
|
|
|
|
static const BChar chars[] =
|
|
{
|
|
{ '0', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ '1', 3,
|
|
{ 1, 1, 0,
|
|
0, 1, 0,
|
|
0, 1, 0,
|
|
0, 1, 0,
|
|
0, 1, 0
|
|
}
|
|
},
|
|
{ '2', 3,
|
|
{ 0, 1, 1,
|
|
1, 0, 1,
|
|
0, 0, 1,
|
|
0, 1, 0,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ '3', 3,
|
|
{ 1, 1, 1,
|
|
0, 0, 1,
|
|
1, 1, 1,
|
|
0, 0, 1,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ '4', 3,
|
|
{ 1, 0, 1,
|
|
1, 0, 1,
|
|
1, 1, 1,
|
|
0, 0, 1,
|
|
0, 0, 1
|
|
}
|
|
},
|
|
{ '5', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 0,
|
|
1, 1, 1,
|
|
0, 0, 1,
|
|
1, 1, 0
|
|
}
|
|
},
|
|
{ '6', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 0,
|
|
1, 1, 1,
|
|
1, 0, 1,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ '7', 3,
|
|
{ 1, 1, 1,
|
|
0, 0, 1,
|
|
0, 1, 0,
|
|
1, 0, 0,
|
|
1, 0, 0
|
|
}
|
|
},
|
|
{ '8', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 1,
|
|
1, 1, 1,
|
|
1, 0, 1,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ '9', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 1,
|
|
1, 1, 1,
|
|
0, 0, 1,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
|
|
{ ':', 1,
|
|
{ 0, 0, 0,
|
|
1, 0, 0,
|
|
0, 0, 0,
|
|
1, 0, 0,
|
|
0, 0, 0
|
|
}
|
|
},
|
|
{ '.', 1,
|
|
{ 0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
1, 0, 0
|
|
}
|
|
},
|
|
|
|
{ 'A', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 1,
|
|
1, 1, 1,
|
|
1, 0, 1,
|
|
1, 0, 1
|
|
}
|
|
},
|
|
{ 'B', 3,
|
|
{ 1, 1, 0,
|
|
1, 0, 1,
|
|
1, 1, 0,
|
|
1, 0, 1,
|
|
1, 1, 0
|
|
}
|
|
},
|
|
{ 'C', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 0,
|
|
1, 0, 0,
|
|
1, 0, 0,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ 'D', 3,
|
|
{ 1, 1, 0,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 1, 0
|
|
}
|
|
},
|
|
{ 'E', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 0,
|
|
1, 1, 0,
|
|
1, 0, 0,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ 'F', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 0,
|
|
1, 1, 0,
|
|
1, 0, 0,
|
|
1, 0, 0
|
|
}
|
|
},
|
|
{ 'G', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 0,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ 'H', 3,
|
|
{ 1, 0, 1,
|
|
1, 0, 1,
|
|
1, 1, 1,
|
|
1, 0, 1,
|
|
1, 0, 1
|
|
}
|
|
},
|
|
{ 'I', 1,
|
|
{ 1, 0, 0,
|
|
1, 0, 0,
|
|
1, 0, 0,
|
|
1, 0, 0,
|
|
1, 0, 0
|
|
}
|
|
},
|
|
{ 'J', 3,
|
|
{ 0, 0, 1,
|
|
0, 0, 1,
|
|
0, 0, 1,
|
|
1, 0, 1,
|
|
0, 1, 0
|
|
}
|
|
},
|
|
{ 'K', 3,
|
|
{ 1, 0, 1,
|
|
1, 0, 1,
|
|
1, 1, 0,
|
|
1, 0, 1,
|
|
1, 0, 1
|
|
}
|
|
},
|
|
{ 'L', 3,
|
|
{ 1, 0, 0,
|
|
1, 0, 0,
|
|
1, 0, 0,
|
|
1, 0, 0,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ 'M', 3,
|
|
{ 1, 0, 1,
|
|
1, 1, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1
|
|
}
|
|
},
|
|
{ 'N', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1
|
|
}
|
|
},
|
|
{ 'O', 3,
|
|
{ 0, 1, 0,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
0, 1, 0
|
|
}
|
|
},
|
|
{ 'P', 3,
|
|
{ 1, 1, 0,
|
|
1, 0, 1,
|
|
1, 1, 0,
|
|
1, 0, 0,
|
|
1, 0, 0
|
|
}
|
|
},
|
|
{ 'Q', 3,
|
|
{ 0, 1, 0,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
0, 1, 1
|
|
}
|
|
},
|
|
{ 'R', 3,
|
|
{ 1, 1, 0,
|
|
1, 0, 1,
|
|
1, 1, 0,
|
|
1, 0, 1,
|
|
1, 0, 1
|
|
}
|
|
},
|
|
{ 'S', 3,
|
|
{ 1, 1, 1,
|
|
1, 0, 0,
|
|
1, 1, 1,
|
|
0, 0, 1,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ 'T', 3,
|
|
{ 1, 1, 1,
|
|
0, 1, 0,
|
|
0, 1, 0,
|
|
0, 1, 0,
|
|
0, 1, 0
|
|
}
|
|
},
|
|
{ 'U', 3,
|
|
{ 1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
{ 'V', 3,
|
|
{ 1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
0, 1, 0
|
|
}
|
|
},
|
|
{ 'W', 3,
|
|
{ 1, 0, 1,
|
|
1, 0, 1,
|
|
1, 0, 1,
|
|
1, 1, 1,
|
|
1, 0, 1
|
|
}
|
|
},
|
|
{ 'X', 3,
|
|
{ 1, 0, 1,
|
|
1, 0, 1,
|
|
0, 1, 0,
|
|
1, 0, 1,
|
|
1, 0, 1
|
|
}
|
|
},
|
|
{ 'Y', 3,
|
|
{ 1, 0, 1,
|
|
1, 0, 1,
|
|
0, 1, 0,
|
|
0, 1, 0,
|
|
0, 1, 0
|
|
}
|
|
},
|
|
{ 'Z', 3,
|
|
{ 1, 1, 1,
|
|
0, 0, 1,
|
|
0, 1, 0,
|
|
1, 0, 0,
|
|
1, 1, 1
|
|
}
|
|
},
|
|
};
|
|
|
|
typedef enum
|
|
{
|
|
SCROLL_UP,
|
|
CURSOR_BLINK,
|
|
FINISH
|
|
} AnimType;
|
|
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_STRING
|
|
};
|
|
|
|
|
|
#define B_TYPE_TEXT (b_type_text)
|
|
#define B_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), B_TYPE_TEXT, BText))
|
|
#define B_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), B_TYPE_TEXT, BTextClass))
|
|
#define B_IS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), B_TYPE_TEXT))
|
|
#define B_IS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), B_TYPE_TEXT))
|
|
|
|
typedef struct _BText BText;
|
|
typedef struct _BTextClass BTextClass;
|
|
|
|
struct _BText
|
|
{
|
|
BModule parent_instance;
|
|
|
|
gchar *string;
|
|
gchar *cursor_pos;
|
|
|
|
gint cursor_x;
|
|
gint cursor_y;
|
|
|
|
guchar bg_color;
|
|
guchar fg_color;
|
|
|
|
gint player_device_id;
|
|
|
|
gint timeout;
|
|
|
|
AnimType anim;
|
|
gint anim_steps;
|
|
|
|
gint cursor_size;
|
|
|
|
GRand *rand;
|
|
};
|
|
|
|
struct _BTextClass
|
|
{
|
|
BModuleClass parent_class;
|
|
};
|
|
|
|
|
|
static GType b_text_get_type (GTypeModule *module);
|
|
|
|
static void b_text_class_init (BTextClass *klass);
|
|
static void b_text_init (BText *text);
|
|
|
|
static void b_text_finalize (GObject *object);
|
|
static void b_text_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static gboolean b_text_query (gint width,
|
|
gint height,
|
|
gint channels,
|
|
gint maxval);
|
|
static gboolean b_text_prepare (BModule *module,
|
|
GError **error);
|
|
static void b_text_relax (BModule *module);
|
|
static void b_text_start (BModule *module);
|
|
static void b_text_stop (BModule *module);
|
|
static void b_text_event (BModule *module,
|
|
BModuleEvent *event);
|
|
static gint b_text_tick (BModule *module);
|
|
static void b_text_describe (BModule *module,
|
|
const gchar **title,
|
|
const gchar **description,
|
|
const gchar **author);
|
|
|
|
|
|
static BModuleClass * parent_class = NULL;
|
|
static GType b_type_text = 0;
|
|
|
|
|
|
G_MODULE_EXPORT gboolean
|
|
b_module_register (GTypeModule *module)
|
|
{
|
|
b_text_get_type (module);
|
|
return TRUE;
|
|
}
|
|
|
|
static GType
|
|
b_text_get_type (GTypeModule *module)
|
|
{
|
|
if (! b_type_text)
|
|
{
|
|
static const GTypeInfo text_info =
|
|
{
|
|
sizeof (BTextClass),
|
|
NULL, /* base_init */
|
|
NULL, /* base_finalize */
|
|
(GClassInitFunc) b_text_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (BText),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) b_text_init,
|
|
};
|
|
|
|
b_type_text = g_type_module_register_type (module,
|
|
B_TYPE_MODULE, "BText",
|
|
&text_info, 0);
|
|
}
|
|
|
|
return b_type_text;
|
|
}
|
|
|
|
static void
|
|
b_text_class_init (BTextClass *klass)
|
|
{
|
|
GObjectClass *object_class;
|
|
BModuleClass *module_class;
|
|
GParamSpec *param_spec;
|
|
|
|
object_class = G_OBJECT_CLASS (klass);
|
|
module_class = B_MODULE_CLASS (klass);
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
object_class->finalize = b_text_finalize;
|
|
object_class->set_property = b_text_set_property;
|
|
|
|
param_spec = g_param_spec_string ("string", NULL,
|
|
"The string to draw.",
|
|
"blinken\nbis die\nkotze\nkommt",
|
|
G_PARAM_CONSTRUCT | G_PARAM_WRITABLE);
|
|
g_object_class_install_property (object_class, PROP_STRING, param_spec);
|
|
|
|
module_class->max_players = 1;
|
|
|
|
module_class->query = b_text_query;
|
|
module_class->prepare = b_text_prepare;
|
|
module_class->relax = b_text_relax;
|
|
module_class->start = b_text_start;
|
|
module_class->stop = b_text_stop;
|
|
module_class->event = b_text_event;
|
|
module_class->tick = b_text_tick;
|
|
module_class->describe = b_text_describe;
|
|
}
|
|
|
|
static void
|
|
b_text_init (BText *text)
|
|
{
|
|
text->string = NULL;
|
|
|
|
text->anim_steps = 0;
|
|
text->player_device_id = -1;
|
|
|
|
text->rand = g_rand_new ();
|
|
}
|
|
|
|
static void
|
|
b_text_finalize (GObject *object)
|
|
{
|
|
BText *text;
|
|
|
|
text = B_TEXT (object);
|
|
|
|
if (text->string)
|
|
{
|
|
g_free (text->string);
|
|
text->string = NULL;
|
|
}
|
|
|
|
if (text->rand)
|
|
{
|
|
g_rand_free (text->rand);
|
|
text->rand = NULL;
|
|
}
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
b_text_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
BText *text;
|
|
|
|
text = B_TEXT (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_STRING:
|
|
g_free (text->string);
|
|
text->string = g_value_dup_string (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
b_text_query (gint width,
|
|
gint height,
|
|
gint channels,
|
|
gint maxval)
|
|
{
|
|
return (width >= 5 * CHAR_ADVANCE &&
|
|
height >= 2 * LINE_ADVANCE &&
|
|
channels == 1);
|
|
}
|
|
|
|
static gboolean
|
|
b_text_prepare (BModule *module,
|
|
GError **error)
|
|
{
|
|
BText *text;
|
|
|
|
text = B_TEXT (module);
|
|
|
|
text->bg_color = 0;
|
|
text->fg_color = module->maxval;
|
|
|
|
text->cursor_size = CHAR_WIDTH;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
b_text_relax (BModule *module)
|
|
{
|
|
}
|
|
|
|
static void
|
|
b_text_start (BModule *module)
|
|
{
|
|
BText *text = B_TEXT (module);
|
|
|
|
text->cursor_pos = text->string;
|
|
|
|
text->cursor_x = 0;
|
|
text->cursor_y = 0;
|
|
|
|
text->anim = CURSOR_BLINK;
|
|
text->anim_steps = BLINK_STEPS;
|
|
|
|
text->timeout = TEXT_TIMEOUT;
|
|
|
|
b_module_fill (module, text->bg_color);
|
|
|
|
b_module_ticker_start (module, text->timeout);
|
|
}
|
|
|
|
static void
|
|
b_text_stop (BModule *module)
|
|
{
|
|
BText *text;
|
|
|
|
text = B_TEXT (module);
|
|
|
|
text->player_device_id = -1;
|
|
}
|
|
|
|
static void
|
|
b_text_event (BModule *module,
|
|
BModuleEvent *event)
|
|
{
|
|
BText *text;
|
|
|
|
text = B_TEXT (module);
|
|
|
|
switch (event->type)
|
|
{
|
|
case B_EVENT_TYPE_KEY:
|
|
if (text->anim_steps)
|
|
return;
|
|
|
|
switch (event->key)
|
|
{
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case B_EVENT_TYPE_PLAYER_ENTERED:
|
|
if (text->player_device_id == -1)
|
|
{
|
|
text->player_device_id = event->device_id;
|
|
|
|
module->num_players++;
|
|
}
|
|
break;
|
|
|
|
case B_EVENT_TYPE_PLAYER_LEFT:
|
|
if (text->player_device_id == event->device_id)
|
|
{
|
|
text->player_device_id = -1;
|
|
|
|
module->num_players--;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gint
|
|
b_text_tick (BModule *module)
|
|
{
|
|
BText *text;
|
|
|
|
text = B_TEXT (module);
|
|
|
|
if (text->anim_steps > 0)
|
|
{
|
|
text->anim_steps--;
|
|
|
|
switch (text->anim)
|
|
{
|
|
case SCROLL_UP:
|
|
memmove (module->buffer,
|
|
module->buffer + module->width * module->channels,
|
|
module->width * (module->height - 1) * module->channels);
|
|
b_module_draw_line (module,
|
|
0, module->height - 1,
|
|
module->width - 1, module->height - 1,
|
|
text->bg_color);
|
|
text->timeout = SCROLL_TIMEOUT;
|
|
|
|
if (text->anim_steps == 0)
|
|
{
|
|
text->anim = CURSOR_BLINK;
|
|
text->anim_steps = BLINK_STEPS;
|
|
}
|
|
break;
|
|
|
|
case CURSOR_BLINK:
|
|
case FINISH:
|
|
b_module_draw_line (module,
|
|
text->cursor_x,
|
|
text->cursor_y + CHAR_HEIGHT - 1,
|
|
text->cursor_x + text->cursor_size - 1,
|
|
text->cursor_y + CHAR_HEIGHT - 1,
|
|
text->anim_steps % 2 ?
|
|
text->fg_color : text->bg_color);
|
|
|
|
if (text->anim == FINISH && text->anim_steps == 0)
|
|
{
|
|
b_module_request_stop (module);
|
|
return 0;
|
|
}
|
|
|
|
text->timeout = BLINK_TIMEOUT;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
text->timeout = TEXT_TIMEOUT;
|
|
|
|
if (text->cursor_pos && *text->cursor_pos)
|
|
{
|
|
gint advance = CHAR_WIDTH;
|
|
|
|
b_module_draw_line (module,
|
|
text->cursor_x,
|
|
text->cursor_y + CHAR_HEIGHT - 1,
|
|
text->cursor_x + text->cursor_size - 1,
|
|
text->cursor_y + CHAR_HEIGHT - 1,
|
|
text->bg_color);
|
|
|
|
if (! g_ascii_isspace (*text->cursor_pos))
|
|
{
|
|
const BChar *bchar = &unknown_char;
|
|
gint i, x, y;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (chars); i++)
|
|
{
|
|
if (chars[i].character == g_ascii_toupper (*text->cursor_pos))
|
|
bchar = &chars[i];
|
|
}
|
|
|
|
for (x = 0; x < CHAR_WIDTH; x++)
|
|
for (y = 0; y < CHAR_HEIGHT; y++)
|
|
{
|
|
if (bchar->matrix[y * CHAR_WIDTH + x])
|
|
b_module_draw_point (module,
|
|
text->cursor_x + x,
|
|
text->cursor_y + y,
|
|
text->fg_color);
|
|
else
|
|
b_module_draw_point (module,
|
|
text->cursor_x + x,
|
|
text->cursor_y + y,
|
|
text->bg_color);
|
|
}
|
|
|
|
advance = bchar->width + 1;
|
|
}
|
|
|
|
text->cursor_x += advance;
|
|
|
|
if (*text->cursor_pos == '\n' ||
|
|
(text->cursor_x + CHAR_WIDTH > module->width))
|
|
{
|
|
text->cursor_pos++;
|
|
|
|
/* no whitespace at the start of a line */
|
|
if (g_ascii_isspace (*text->cursor_pos) &&
|
|
(*text->cursor_pos != '\n' ||
|
|
(text->cursor_x + CHAR_WIDTH > module->width)))
|
|
text->cursor_pos++;
|
|
|
|
text->cursor_x = 0;
|
|
text->cursor_y += LINE_ADVANCE;
|
|
|
|
text->anim = CURSOR_BLINK;
|
|
text->anim_steps = BLINK_STEPS;
|
|
}
|
|
else
|
|
{
|
|
text->cursor_pos++;
|
|
|
|
if (g_rand_double (text->rand) > 0.5)
|
|
b_module_draw_line (module,
|
|
text->cursor_x,
|
|
text->cursor_y + CHAR_HEIGHT - 1,
|
|
text->cursor_x + text->cursor_size - 1,
|
|
text->cursor_y + CHAR_HEIGHT - 1,
|
|
text->fg_color);
|
|
}
|
|
|
|
if (text->cursor_y + CHAR_HEIGHT > module->height)
|
|
{
|
|
text->cursor_y -= LINE_ADVANCE;
|
|
|
|
text->anim = SCROLL_UP;
|
|
text->anim_steps = LINE_ADVANCE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
text->anim = FINISH;
|
|
text->anim_steps = BLINK_STEPS * 4;
|
|
text->timeout = BLINK_TIMEOUT;
|
|
}
|
|
}
|
|
|
|
b_module_paint (module);
|
|
|
|
return text->timeout;
|
|
}
|
|
|
|
static void
|
|
b_text_describe (BModule *module,
|
|
const gchar **title,
|
|
const gchar **description,
|
|
const gchar **author)
|
|
{
|
|
*title = "BText";
|
|
*description = "Text display";
|
|
*author = "Michael Natterer";
|
|
}
|