Compare commits

...

3 commits

Author SHA1 Message Date
Lephenixnoir
4728c6ecbe
jlabel: align top by default and wrap lines in a smarter way
With this change, unless wrapped_newline_spadcing is set (which it's not
by default), spaces around explicit newlines will no longer be skipped.
2024-09-14 12:21:07 +02:00
Lephenixnoir
33e9962209
jlabel: default line spacing to new font_t.line_distance property 2024-09-14 07:19:39 +02:00
Lephenixnoir
57a460894f
the entire new keyboard focus system, save for a few bits
I need to move on to gintctl so that'll be enough for now.
2024-09-13 22:00:29 +02:00
10 changed files with 267 additions and 67 deletions

View file

@ -46,8 +46,9 @@ New keyboard focus system.
b. There is a widget-scene call to give a widget active focus. If the widget b. There is a widget-scene call to give a widget active focus. If the widget
has policy FOCUS_ACCEPT or FOCUS_SCOPE, this call walks up the scope has policy FOCUS_ACCEPT or FOCUS_SCOPE, this call walks up the scope
chain and assigns new targets until it reaches the scene. If the widget chain and assigns new targets until it reaches the scene. If the widget
has policy FOCUS_NONE, this call just removes the surrounding scope's has is NULL, this call just removes the surrounding scope's target.
target. TODO: If the widget is FOCUS_REJECT, clear scopes from that widget up
until reaching the scene.
X. There is a widget-context call to relinquish one's own focus within the X. There is a widget-context call to relinquish one's own focus within the
parent scope. This is intended to differ from 2.b in that scopes might parent scope. This is intended to differ from 2.b in that scopes might
implement special logic for moving focus to a nearby widget. implement special logic for moving focus to a nearby widget.
@ -73,19 +74,20 @@ New keyboard focus system.
4. Behavior of built-in widgets 4. Behavior of built-in widgets
a. `jfileselect`, `jinput`, `jlist` have policy FOCUS_ACCEPT a. `jfileselect`, `jinput`, `jlist` have policy FOCUS_ACCEPT
b. `jscene` has policy FOCUS_SCOPE b. `jscene` has policy FOCUS_SCOPE
TODO: What about jframe?
c. `jfkeys` has policy `FOCUS_REJECT` and must be given events manually c. `jfkeys` has policy `FOCUS_REJECT` and must be given events manually
d. Widgets with a stack layout will try and give focus (within their d. Widgets with a stack layout will try and give focus (within their
surrounding scope) to the current element. If the element is complex, it surrounding scope) to the current element. If the element is complex, it
should be a focus scope. Similarly, widgets with invisible children will should be a focus scope. Similarly, widgets with invisible children will
move focus around to their direct children as needed to make sure focus move focus around to their direct children as needed to make sure focus
remains on a visible child. remains on a visible child.
TODO: Implement stack layout logic
5. Implementation 5. Implementation
a. Events are `FOCUS_CHANGED` when own FOCUSED and ACTIVE_FOCUSED flags have a. Events are `FOCUS_CHANGED` when own FOCUSED and ACTIVE_FOCUSED flags have
changed, and `FOCUS_TARGET_CHANGED` for scopes when the target changes. changed, and `FOCUS_TARGET_CHANGED` for scopes when the target changes.
NOTES: NOTES:
- Update focus flags when removing from parent
- Focus events don't propagate but are replicated, which adds some complexity - Focus events don't propagate but are replicated, which adds some complexity
- Focus scopes could have background focus for jfkeys (left for later). Hard - Focus scopes could have background focus for jfkeys (left for later). Hard
part is this isn't specified by jfkeys. part is this isn't specified by jfkeys.

View file

@ -67,7 +67,7 @@ typedef struct {
jalign block_valign; jalign block_valign;
/* Text alignment */ /* Text alignment */
jalign text_align; jalign text_align;
/* Pixels of spacing between each line, in addition to font->height */ /* Pixels of spacing between lines, in addition to font->line_distance */
int8_t line_spacing; int8_t line_spacing;
/* Text to display */ /* Text to display */
@ -76,12 +76,16 @@ typedef struct {
of line number n */ of line number n */
DECLARE_VEC(uint16_t, breaks); DECLARE_VEC(uint16_t, breaks);
/* Block width (maximum length of a rendered line) */
uint16_t block_width;
/* Text wrapping mode */ /* Text wrapping mode */
enum jwrapmode wrap_mode; enum jwrapmode wrap_mode;
/* Whether the text has been allocated by the label or supplied by user */ /* Whether the text has been allocated by the label or supplied by user */
int8_t owns_text; bool owns_text :1;
/* Block width (maximum length of a rendered line) */ /* Whether to preserve spaces around line-wrapping newlines */
uint16_t block_width; bool wrapped_newline_spacing :1;
uint :5;
/* Color and font of text; if NULL, gint's default font is used */ /* Color and font of text; if NULL, gint's default font is used */
int color; int color;
@ -130,5 +134,6 @@ void jlabel_set_line_spacing(jlabel *l, int line_spacing);
void jlabel_set_wrap_mode(jlabel *l, jwrapmode mode); void jlabel_set_wrap_mode(jlabel *l, jwrapmode mode);
void jlabel_set_text_color(jlabel *l, int color); void jlabel_set_text_color(jlabel *l, int color);
void jlabel_set_font(jlabel *l, font_t const *font); void jlabel_set_font(jlabel *l, font_t const *font);
void jlabel_set_wrapped_newline_spacing(jlabel *l, bool preserve);
#endif /* _J_JLABEL */ #endif /* _J_JLABEL */

View file

@ -21,8 +21,6 @@ typedef struct {
/* Location on screen */ /* Location on screen */
int16_t x, y; int16_t x, y;
/* Widget with focus */
jwidget *focus;
/* Circular event queue */ /* Circular event queue */
jevent queue[JSCENE_QUEUE_SIZE]; jevent queue[JSCENE_QUEUE_SIZE];

View file

@ -67,6 +67,9 @@ typedef struct jwidget {
jlayout_grid layout_grid; jlayout_grid layout_grid;
}; };
/* Focused subwidget for focus scopes */
struct jwidget *focus_scope_target;
/* Widget type, used to find polymorphic operations */ /* Widget type, used to find polymorphic operations */
uint8_t type; uint8_t type;
/* Number of children */ /* Number of children */
@ -91,8 +94,13 @@ typedef struct jwidget {
uint floating :1; uint floating :1;
/* Widget is clipped during rendering */ /* Widget is clipped during rendering */
uint clipped :1; uint clipped :1;
/* Focus policy */
uint focus_policy :2;
/* Focus flags */
uint focused :1;
uint active_focused :1;
uint :22; uint :18;
} jwidget; } jwidget;
@ -106,6 +114,17 @@ typedef enum {
} jwidget_border_style; } jwidget_border_style;
/* jwidget_focus_policy: Options for receiving and handling keyboard focus */
typedef enum {
/* The widget does not accept focus or interact with keyboard (default) */
J_FOCUS_POLICY_REJECT,
/* The widget accepts keyboard input and hides it from descendants */
J_FOCUS_POLICY_ACCEPT,
/* The widget accepts keyboard focus and forwards it to a descendant */
J_FOCUS_POLICY_SCOPE,
} jwidget_focus_policy_t;
/* jwidget_geometry: Built-in positioning and border geometry /* jwidget_geometry: Built-in positioning and border geometry
Every widget has a "geometry", which consists of a border and two layers of Every widget has a "geometry", which consists of a border and two layers of
@ -143,14 +162,13 @@ typedef struct jwidget_geometry {
} jwidget_geometry; } jwidget_geometry;
/* Downwards key event: widget is notified of a key press that ocurred while it /* Key press event; the widget has active focus and a key was pressed.
had active focus.
-> .data.key: Key event */ -> .data.key: Key event */
extern uint16_t JWIDGET_KEY; extern uint16_t JWIDGET_KEY;
/* Downwards focus-in event: the widget has just received focus */ /* The widget's focus state (either .focused or .active_focused) changed. */
extern uint16_t JWIDGET_FOCUS_IN; extern uint16_t JWIDGET_FOCUS_CHANGED;
/* Downwards focus-out event: the widget has just lost focus */ /* The widget is a scope and its target changed. */
extern uint16_t JWIDGET_FOCUS_OUT; extern uint16_t JWIDGET_FOCUS_TARGET_CHANGED;
//--- //---
// Creation and destruction // Creation and destruction
@ -395,6 +413,53 @@ bool jwidget_needs_update(void *w);
widgets if there has been changes. */ widgets if there has been changes. */
void jwidget_render(void *w, int x, int y); void jwidget_render(void *w, int x, int y);
//---
// Keyboard focus
//---
/* Change the widget's focus policy. This is usually done in the constructor
but can be done anytime. If the policy is changed to JWIDGET_FOCUS_REJECT
while the widget has focus, the focus will be lost. */
void jwidget_set_focus_policy(void *w, jwidget_focus_policy_t fp);
/* Check whether a widget is currently focused within its surrounding scope. */
GINLINE static bool jwidget_has_focus(void *w)
{
return ((jwidget *)w)->focused;
}
/* Check whether a widget is current in the key event propagation chain. */
GINLINE static bool jwidget_has_active_focus(void *w)
{
return ((jwidget *)w)->active_focused;
}
/* Change the target of a focus scope widget. */
void jwidget_scope_set_target(void *fs, void *target);
/* Get the target of a focus scope, NULL if none or not a scope. */
GINLINE static jwidget *jwidget_scope_get_target(void *fs)
{
return ((jwidget *)fs)->focus_scope_target;
}
/* Clear the target of a focus scope widget. */
GINLINE static void jwidget_scope_clear_focus(void *fs)
{
return jwidget_scope_set_target(fs, NULL);
}
/* Context function that returns the immediately surrounding scope that owns
this widget, NULL if there's none. Since jscene is a scope, in general there
should always be one. */
jwidget *jwidgetctx_enclosing_focus_scope(void *w);
/* Context function that gives w focus within its enclosing focus scope. */
void jwidgetctx_grab_focus(void *w);
/* Context function that drops the focus from w (if it has it) within its
enclosing focus scope. */
void jwidgetctx_drop_focus(void *w);
//--- //---
// Misc // Misc
//--- //---

View file

@ -52,6 +52,7 @@ jfileselect *jfileselect_create(void *parent)
if(!fs) return NULL; if(!fs) return NULL;
jwidget_init(&fs->widget, jfileselect_type_id, parent); jwidget_init(&fs->widget, jfileselect_type_id, parent);
jwidget_set_focus_policy(fs, J_FOCUS_POLICY_SCOPE);
jinput *input = jinput_create("Filename: ", 32, fs); jinput *input = jinput_create("Filename: ", 32, fs);
if(!input) { if(!input) {
@ -116,14 +117,14 @@ static void start_input(jfileselect *fs)
{ {
fs->input_mode = true; fs->input_mode = true;
jinput_clear(fs->saveas_input); jinput_clear(fs->saveas_input);
jwidget_event(fs->saveas_input, (jevent){ .type = JWIDGET_FOCUS_IN }); jwidget_scope_set_target(fs, fs->saveas_input);
fs->widget.update = true; fs->widget.update = true;
} }
static void stop_input(jfileselect *fs) static void stop_input(jfileselect *fs)
{ {
fs->input_mode = false; fs->input_mode = false;
jwidget_event(fs->saveas_input, (jevent){ .type = JWIDGET_FOCUS_OUT }); jwidget_scope_set_target(fs, NULL);
fs->widget.update = true; fs->widget.update = true;
} }

View file

@ -45,6 +45,7 @@ jinput *jinput_create(char const *prompt, size_t length, void *parent)
if(!i) return NULL; if(!i) return NULL;
jwidget_init(&i->widget, jinput_type_id, parent); jwidget_init(&i->widget, jinput_type_id, parent);
jwidget_set_focus_policy(i, J_FOCUS_POLICY_ACCEPT);
i->color = C_BLACK; i->color = C_BLACK;
jinput_set_font(i, NULL); jinput_set_font(i, NULL);
@ -242,14 +243,8 @@ static bool jinput_poly_event(void *i0, jevent e)
{ {
jinput *i = i0; jinput *i = i0;
if(e.type == JWIDGET_FOCUS_IN) { if(e.type == JWIDGET_FOCUS_CHANGED) {
i->cursor = i->size - 1; i->cursor = jwidget_has_focus(i) ? (i->size - 1) : -1;
i->mode = 0;
i->widget.update = 1;
}
if(e.type == JWIDGET_FOCUS_OUT) {
i->cursor = -1;
i->mode = 0; i->mode = 0;
i->widget.update = 1; i->widget.update = 1;
} }

View file

@ -21,16 +21,17 @@ jlabel *jlabel_create(char const *text, void *parent)
jwidget_init(&l->widget, jlabel_type_id, parent); jwidget_init(&l->widget, jlabel_type_id, parent);
l->block_halign = J_ALIGN_LEFT; l->block_halign = J_ALIGN_LEFT;
l->block_valign = J_ALIGN_MIDDLE; l->block_valign = J_ALIGN_TOP;
l->text_align = J_ALIGN_LEFT; l->text_align = J_ALIGN_LEFT;
l->line_spacing = 1; l->line_spacing = 0;
l->color = C_BLACK; l->color = C_BLACK;
l->font = NULL; l->font = NULL;
l->wrap_mode = J_WRAP_NONE; l->wrap_mode = J_WRAP_NONE;
l->text = text; l->text = text;
l->owns_text = false; l->owns_text = false;
l->wrapped_newline_spacing = false;
vec_init(&l->breaks_vec, sizeof *l->breaks); vec_init(&l->breaks_vec, sizeof *l->breaks);
@ -188,6 +189,12 @@ void jlabel_set_font(jlabel *l, font_t const *font)
l->widget.dirty = 1; l->widget.dirty = 1;
} }
void jlabel_set_wrapped_newline_spacing(jlabel *l, bool preserve)
{
l->wrapped_newline_spacing = preserve;
l->widget.dirty = 1;
}
//--- //---
// Polymorphic widget operations // Polymorphic widget operations
//--- //---
@ -236,7 +243,7 @@ static void jlabel_poly_layout(void *l0)
/* Start of line */ /* Start of line */
add_break(l, str - l->text); add_break(l, str - l->text);
/* A "\n" forces a newline in all wrap omdes */ /* A "\n" forces a newline in all wrap modes */
char const *end_of_line = strchrnul(str, '\n'); char const *end_of_line = strchrnul(str, '\n');
/* Also consider word or letters boundaries */ /* Also consider word or letters boundaries */
@ -257,14 +264,17 @@ static void jlabel_poly_layout(void *l0)
} }
} }
bool natural_break = (*end_of_line == '\n');
char const *next_start = end_of_line + (*end_of_line == '\n'); char const *next_start = end_of_line + (*end_of_line == '\n');
if(!natural_break && !l->wrapped_newline_spacing) {
/* Skip trailing spaces on this line */ /* Skip trailing spaces on this line */
while(end_of_line > str && end_of_line[-1] == ' ') while(end_of_line > str && end_of_line[-1] == ' ')
end_of_line--; end_of_line--;
/* Skip leading spaces on the next line */ /* Skip leading spaces on the next line */
while(next_start[0] == ' ') while(next_start[0] == ' ')
next_start++; next_start++;
}
add_break(l, end_of_line - l->text); add_break(l, end_of_line - l->text);
@ -295,7 +305,7 @@ static void jlabel_poly_render(void *l0, int x, int y)
/* Position the block vertically */ /* Position the block vertically */
int lines = l->breaks_vec.size / 2; int lines = l->breaks_vec.size / 2;
int block_height = lines * (f->line_height + l->line_spacing) - int block_height = lines * (f->line_distance + l->line_spacing) -
l->line_spacing; l->line_spacing;
if(l->block_valign == J_ALIGN_MIDDLE) if(l->block_valign == J_ALIGN_MIDDLE)
@ -331,7 +341,7 @@ static void jlabel_poly_render(void *l0, int x, int y)
dtext_opt(x + dx, y, l->color, C_NONE, DTEXT_LEFT, DTEXT_TOP, dtext_opt(x + dx, y, l->color, C_NONE, DTEXT_LEFT, DTEXT_TOP,
str, line_length); str, line_length);
y += f->line_height + l->line_spacing; y += f->line_distance + l->line_spacing;
str = l->text + l->breaks[i]; str = l->text + l->breaks[i];
} }

View file

@ -31,6 +31,7 @@ jlist *jlist_create(jlist_item_info_function info_function,
return NULL; return NULL;
jwidget_init(&l->widget, jlist_type_id, parent); jwidget_init(&l->widget, jlist_type_id, parent);
jwidget_set_focus_policy(l, J_FOCUS_POLICY_ACCEPT);
l->item_count = 0; l->item_count = 0;
l->items = NULL; l->items = NULL;

View file

@ -44,13 +44,17 @@ jscene *jscene_create(int x, int y, int w, int h, void *parent)
if(!s) return NULL; if(!s) return NULL;
jwidget_init(&s->widget, jscene_type_id, parent); jwidget_init(&s->widget, jscene_type_id, parent);
jwidget_set_focus_policy(s, J_FOCUS_POLICY_SCOPE);
jwidget_set_fixed_size(s, w, h); jwidget_set_fixed_size(s, w, h);
jlayout_set_vbox(s); jlayout_set_vbox(s);
/* The scene is where active focus originates */
s->widget.focused = 1;
s->widget.active_focused = 1;
s->x = x; s->x = x;
s->y = y; s->y = y;
s->focus = NULL;
s->queue_first = 0; s->queue_first = 0;
s->queue_next = 0; s->queue_next = 0;
s->lost_events = 0; s->lost_events = 0;
@ -128,27 +132,37 @@ void jscene_queue_event(jscene *s, jevent e)
void *jscene_focused_widget(jscene *s) void *jscene_focused_widget(jscene *s)
{ {
return s->focus; jwidget *w = &s->widget;
while(w->focus_scope_target)
w = w->focus_scope_target;
return w;
} }
void jscene_set_focused_widget(jscene *s, void *w0) void jscene_set_focused_widget(jscene *s, void *w0)
{ {
J_CAST(w) J_CAST(w)
/* Unfocus only at the top level */
if(!w) {
jwidget_scope_set_target(s, NULL);
return;
}
if(w->focus_policy == J_FOCUS_POLICY_REJECT)
return;
/* Check that (s) is an ancestor of (w) */ /* Check that (s) is an ancestor of (w) */
if(w) for(jwidget *anc = w; anc != (jwidget *)s; anc = anc->parent) { for(jwidget *anc = w; anc != (jwidget *)s; anc = anc->parent) {
if(anc == NULL) return; if(anc == NULL) return;
} }
/* Focus out old focused widget */ /* Set targets in every scope along the way up */
if(s->focus) jwidget_event(s->focus, jwidget *scope = w;
(jevent){ .type = JWIDGET_FOCUS_OUT, .source = s->focus }); while(scope != NULL) {
scope = jwidgetctx_enclosing_focus_scope(scope);
s->focus = w; jwidget_scope_set_target(scope, w);
w = scope;
/* Focus in newly-selected widget */ }
if(w) jwidget_event(w,
(jevent){ .type = JWIDGET_FOCUS_IN, .source = w });
} }
void jscene_show_and_focus(jscene *scene, void *w0) void jscene_show_and_focus(jscene *scene, void *w0)
@ -182,12 +196,13 @@ void jscene_show_and_focus(jscene *scene, void *w0)
bool jscene_process_key_event(jscene *scene, key_event_t event) bool jscene_process_key_event(jscene *scene, key_event_t event)
{ {
jwidget *candidate = scene->focus; jwidget *candidate = jscene_focused_widget(scene);
jevent e = { .type = JWIDGET_KEY, .key = event }; jevent e = { .type = JWIDGET_KEY, .key = event };
while(candidate) { while(candidate) {
if(jwidget_event(candidate, e)) return true; if(jwidget_event(candidate, e))
candidate = candidate->parent; return true;
candidate = jwidgetctx_enclosing_focus_scope(candidate);
} }
return false; return false;

View file

@ -31,9 +31,10 @@ static jwidget_poly *widget_types[WIDGET_TYPES_MAX] = {
}; };
/* Events */ /* Events */
uint16_t JWIDGET_KEY; J_DEFINE_EVENTS(
uint16_t JWIDGET_FOCUS_IN; JWIDGET_KEY,
uint16_t JWIDGET_FOCUS_OUT; JWIDGET_FOCUS_CHANGED,
JWIDGET_FOCUS_TARGET_CHANGED);
//--- //---
// Polymorphic functions for widgets // Polymorphic functions for widgets
@ -117,9 +118,13 @@ void jwidget_init(jwidget *w, int type, void *parent)
w->visible = 1; w->visible = 1;
w->floating = 0; w->floating = 0;
w->clipped = 0; w->clipped = 0;
w->focus_policy = J_FOCUS_POLICY_REJECT;
w->focused = 0;
w->active_focused = 0;
w->type = type; w->type = type;
w->geometry = NULL; w->geometry = NULL;
w->focus_scope_target = NULL;
w->x = 0; w->x = 0;
w->y = 0; w->y = 0;
@ -605,6 +610,10 @@ void jwidget_set_floating(void *w0, bool floating)
if(w->parent) w->parent->dirty = 1; if(w->parent) w->parent->dirty = 1;
} }
//---
// Rendering
//---
bool jwidget_clipped(void *w0) bool jwidget_clipped(void *w0)
{ {
J_CAST(w) J_CAST(w)
@ -620,10 +629,6 @@ void jwidget_set_clipped(void *w0, bool clipped)
w->update = 1; w->update = 1;
} }
//---
// Rendering
//---
void jwidget_render(void *w0, int x, int y) void jwidget_render(void *w0, int x, int y)
{ {
J_CAST(w) J_CAST(w)
@ -692,6 +697,117 @@ void jwidget_render(void *w0, int x, int y)
w->update = 0; w->update = 0;
} }
//---
// Keyboard focus
//---
void jwidget_set_focus_policy(void *w0, jwidget_focus_policy_t fp)
{
J_CAST(w)
if(w->focus_policy == fp)
return;
/* If this was a scope, clear it (otherwise the surrounding scope, which is
going to expand, could pick up a second, untargeted focused widget). */
if(w->focus_policy == J_FOCUS_POLICY_SCOPE)
jwidget_scope_clear_focus(w);
/* Remove focus if we're no longer accepting it */
if(fp == J_FOCUS_POLICY_REJECT && jwidget_has_focus(w))
jwidgetctx_drop_focus(w);
w->focus_policy = fp;
}
static void notify_focus_changed(jwidget *w)
{
jevent e;
e.source = w;
e.type = JWIDGET_FOCUS_CHANGED;
jwidget_event(w, e);
}
static void set_focus_chain_active(
jwidget *w, bool set, bool notify_toplevel, bool bottom_up)
{
bool recursive =
(w->focus_policy == J_FOCUS_POLICY_SCOPE && w->focus_scope_target);
if(recursive && bottom_up)
set_focus_chain_active(w->focus_scope_target, set, true, bottom_up);
w->active_focused = set;
if(notify_toplevel)
notify_focus_changed(w);
if(recursive && !bottom_up)
set_focus_chain_active(w->focus_scope_target, set, true, bottom_up);
}
void jwidget_scope_set_target(void *fs0, void *target0)
{
J_CAST(fs, target)
if(!fs || fs->focus_policy != J_FOCUS_POLICY_SCOPE
|| fs->focus_scope_target == target)
return;
jwidget *oldt = fs->focus_scope_target;
if(oldt) {
/* First, if we have active focus, remove it from the entire chain */
if(jwidget_has_active_focus(fs))
set_focus_chain_active(oldt, false, false, true);
/* Then, remove the focus flag from the scope target and notify it */
oldt->focused = 0;
notify_focus_changed(oldt);
}
fs->focus_scope_target = target;
if(target) {
/* Now, give focus to the new scope target */
target->focused = 1;
notify_focus_changed(target);
if(jwidget_has_active_focus(fs))
set_focus_chain_active(target, true, false, false);
}
jevent e;
e.source = fs;
e.type = JWIDGET_FOCUS_TARGET_CHANGED;
jwidget_event(fs, e);
}
jwidget *jwidgetctx_enclosing_focus_scope(void *w0)
{
J_CAST(w)
do w = w->parent;
while(w && w->focus_policy != J_FOCUS_POLICY_SCOPE);
return w;
}
void jwidgetctx_drop_focus(void *w0)
{
J_CAST(w)
if(!w || !jwidget_has_focus(w))
return;
jwidget *scope = jwidgetctx_enclosing_focus_scope(w);
if(scope)
jwidget_scope_clear_focus(scope);
}
void jwidgetctx_grab_focus(void *w0)
{
J_CAST(w)
if(!w || jwidget_has_focus(w))
return;
jwidget *scope = jwidgetctx_enclosing_focus_scope(w);
if(scope)
jwidget_scope_set_target(scope, w);
}
//--- //---
// Event management // Event management
//--- //---
@ -752,11 +868,3 @@ int j_register_event(void)
event_id++; event_id++;
return event_id; return event_id;
} }
__attribute__((constructor(1000)))
static void j_register_jwidget(void)
{
JWIDGET_KEY = j_register_event();
JWIDGET_FOCUS_IN = j_register_event();
JWIDGET_FOCUS_OUT = j_register_event();
}