Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(control char): add basic control char support #238

Merged
merged 14 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 45 additions & 15 deletions i3lock.1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
.fi
..

.TH i3lock-color 1 "JUN 2021" Linux "User Manuals"
.TH i3lock-color 1 "JAN 2022" Linux "User Manuals"

.SH NAME
i3lock-color \- improved screen locker
Expand Down Expand Up @@ -240,6 +240,23 @@ Sets the color of the status text while verifying and when password is wrong.
.B \-\-{layout, time, date, greeter}\-color=rrggbbaa
Sets text colors.

.TP
.B \-\-keylayout mode
Displays the keylayout. Positionable similar to date, time, and indicator.
Modes are as follows:
.RS
.IP \[bu] 2
0 - Displays the full string returned by the query, i.e. "English (US)"
.IP \[bu]
1 - Displays up until the first parenthesis, i.e. "English"
.IP \[bu]
2 - Displays just the contents of the parenthesis, i.e. "US"
.RE

.B For all following -str or -text options, some control characters
.B (i.e. \\\\n, \\\\t) are supported. See \fBCONTROL CHARACTERS\fR
.B for more details.

.TP
.B \-\-time\-str="%H:%M:%S"
Sets the format used for generating the time string.
Expand All @@ -257,19 +274,6 @@ Sets the string to be shown while verifying the password/input/key/etc.
.B \-\-wrong\-text="wrong!"
Sets the string to be shown upon entering an incorrect password.

.TP
.B \-\-keylayout mode
Displays the keylayout. Positionable similar to date, time, and indicator.
Modes are as follows:
.RS
.IP \[bu] 2
0 - Displays the full string returned by the query, i.e. "English (US)"
.IP \[bu]
1 - Displays up until the first parenthesis, i.e. "English"
.IP \[bu]
2 - Displays just the contents of the parenthesis, i.e. "US"
.RE

.TP
.B \-\-noinput\-text="no input"
Sets the string to be shown upon pressing backspace without anything to delete.
Expand Down Expand Up @@ -484,14 +488,40 @@ The interval to wait until switching to the next image.
.B \-\-slideshow\-random\-selection
Randomize the order of the images.

.SH CONTROL CHARACTERS
Control characters (\\r \\n \\b \\t) are supported in text OPTIONS. Their behavior
are almost as same as anywhere else.
.TP
.B Carriage Return(\\\\r)
Move to the start of line (left edge).
Notes: The rendered characters would still live there.
.TP
.B Line Feed(\\\\n)
Move to start of next line (left edge).
.TP
.B Backspace(\\\\b)
Overwrite last one char if exists.
Notes: The rendered character would still live there.
.TP
.B Tab(\\\\t)
Move to next tab stop position.The width of one character for moving is as same as character 'a'.
Note: The width may be strange if the font is not mono-spaced.

.SH SEE ALSO
.IR xautolock(1)
\- use i3lock as your screen saver

.IR convert(1)
\- feed a wide variety of image formats to i3lock

.SH AUTHOR
.SH HOMEPAGE
https://github.com/Raymo111/i3lock-color

Please report bugs and submit pull-requests as follows:
For i3lock (upstream): https://github.com/i3/i3lock
For i3lock-color (enhancements on top of i3lock): https://github.com/Raymo111/i3lock-color

.SH AUTHORS
Michael Stapelberg <michael+i3lock at stapelberg dot de>

Jan-Erik Rediger <badboy at archlinux.us>
Expand Down
99 changes: 97 additions & 2 deletions unlock_indicator.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ static cairo_font_face_t *font_faces[6] = {
NULL,
};

static control_char_config_t control_characters[] = {
{'\n', CC_POS_RESET, 0, CC_POS_CHANGE, 1},
{'\b', CC_POS_CHANGE, -1, CC_POS_KEEP, 0},
{'\r', CC_POS_RESET, 0, CC_POS_KEEP, 0},
{'\t', CC_POS_TAB, 4, CC_POS_KEEP, 0},
};
size_t control_char_count = sizeof control_characters / sizeof(control_char_config_t);

static cairo_font_face_t *get_font_face(int which) {
if (font_faces[which]) {
return font_faces[which];
Expand Down Expand Up @@ -314,6 +322,94 @@ static cairo_font_face_t *get_font_face(int which) {
return face;
}

/*
* Splits the given text by "control chars",
* And then draws the given text onto the cairo context.
*/
static void draw_text_with_cc(cairo_t *ctx, text_t text, double start_x) {
// get scaled_font
cairo_scaled_font_t *sft;
cairo_matrix_t fm, ctm;
cairo_matrix_init_scale(&fm, text.size, text.size);
cairo_get_matrix(ctx, &ctm);
cairo_font_options_t *opts;
opts = cairo_font_options_create();
sft = cairo_scaled_font_create(text.font, &fm, &ctm, opts);
cairo_font_options_destroy(opts);
/* use `a` to represent common character width, using in `\t` */
cairo_text_extents_t te;
cairo_text_extents(ctx, "a", &te);

// convert text to glyphs.
cairo_status_t status;
cairo_glyph_t* glyphs;
int nglyphs = 0,
len = 0,
start = 0,
lineno = 0,
x = start_x,
y = text.y;
size_t cur_cc;

while (text.str[start + len] != '\0') {
char is_cc = 0;
do {
for (cur_cc = 0; cur_cc < control_char_count; cur_cc++) {
if (text.str[start+len] == control_characters[cur_cc].character) {
is_cc = 1;
break;
}
}
} while (text.str[start+(len++)] != '\0' && !is_cc);
if (len > is_cc) {
status = cairo_scaled_font_text_to_glyphs(
sft, x, y, text.str + start, is_cc ? len - 1: len,
&glyphs, &nglyphs,
NULL, NULL, NULL
);
if (status == CAIRO_STATUS_SUCCESS) {
cairo_glyph_path(ctx, glyphs, nglyphs);
} else {
DEBUG("draw %c failed\n", text.str[start]);
}
}
if (is_cc && (cur_cc < control_char_count)) {
if (control_characters[cur_cc].x_behavior == CC_POS_CHANGE) {
char x_offset = control_characters[cur_cc].x_behavior_arg;
if (x_offset < 0 && x_offset > -nglyphs) {
x = glyphs[nglyphs+x_offset].x;
} else if (x_offset > 0) {
if (nglyphs >= 1) { // the case is some leading control chars.(although there is none now)
x = glyphs[nglyphs - 1].x + x_offset * te.x_advance;
} else { // deal the leading control chars.
x += x_offset * te.x_advance;
}
}
} else if (control_characters[cur_cc].x_behavior == CC_POS_RESET) {
x = start_x;
} else if (control_characters[cur_cc].x_behavior == CC_POS_TAB) {
if (nglyphs > 0) { // there may be leading tab, such as '\t\t' or '\n\t'
int advance = control_characters[cur_cc].x_behavior_arg - ((nglyphs - 1) % control_characters[cur_cc].x_behavior_arg);
x = glyphs[nglyphs - 1].x + advance * te.x_advance;
} else { // deal the leading tab.
x += control_characters[cur_cc].x_behavior_arg * te.x_advance;
}
}
if (control_characters[cur_cc].y_behavior == CC_POS_CHANGE) {
lineno += control_characters[cur_cc].y_behavior_arg;
} // CC_POS_KEEP is default for y
}
y = text.y + text.size * lineno;
if (len > is_cc) {
cairo_glyph_free(glyphs);
}
nglyphs = 0;
start += len;
len = 0;
}
cairo_scaled_font_destroy(sft);
}

/*
* Draws the given text onto the cairo context
*/
Expand Down Expand Up @@ -342,9 +438,8 @@ static void draw_text(cairo_t *ctx, text_t text) {
}

cairo_set_source_rgba(ctx, text.color.red, text.color.green, text.color.blue, text.color.alpha);
cairo_move_to(ctx, x, text.y);

cairo_text_path(ctx, text.str);
draw_text_with_cc(ctx, text, x);
cairo_fill_preserve(ctx);

cairo_set_source_rgba(ctx, text.outline_color.red, text.outline_color.green, text.outline_color.blue, text.outline_color.alpha);
Expand Down
16 changes: 16 additions & 0 deletions unlock_indicator.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ typedef enum {
MAX,
} background_type_t;


typedef enum {
CC_POS_RESET,
CC_POS_CHANGE,
CC_POS_KEEP,
CC_POS_TAB
} control_char_pos_t;

typedef struct {
char character;
control_char_pos_t x_behavior;
int x_behavior_arg;
control_char_pos_t y_behavior;
int y_behavior_arg;
} control_char_config_t;

void render_lock(uint32_t* resolution, xcb_drawable_t drawable);
void draw_image(uint32_t* resolution, cairo_surface_t* img, cairo_t* xcb_ctx);
void init_colors_once(void);
Expand Down