mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-27 05:34:00 +00:00
682 lines
21 KiB
C
682 lines
21 KiB
C
#include "cmd_runtime.h"
|
|
#include "qrcode/qrcodegen.h"
|
|
|
|
#define USH_QRCODE_MAX_TEXT 640U
|
|
#define USH_QRCODE_MAX_VERSION 15
|
|
#define USH_QRCODE_BORDER 4U
|
|
#define USH_QRCODE_MAX_MODULES ((USH_QRCODE_MAX_VERSION * 4U) + 17U + (USH_QRCODE_BORDER * 2U))
|
|
#define USH_QRCODE_CANVAS_MAX 640U
|
|
#define USH_QRCODE_TTY_DISPLAY 1ULL
|
|
#define USH_QRCODE_TITLE_H 34
|
|
#define USH_QRCODE_FOOTER_H 34
|
|
#define USH_QRCODE_PAD 24
|
|
#define USH_QRCODE_CLOSE_W 44
|
|
#define USH_QRCODE_WINDOW_DEFAULT_W 520
|
|
#define USH_QRCODE_WINDOW_DEFAULT_H 600
|
|
#define USH_QRCODE_WINDOW_MIN_W 320
|
|
#define USH_QRCODE_WINDOW_MIN_H 380
|
|
|
|
#define USH_QRCODE_COLOR_DARK 0x00000000U
|
|
#define USH_QRCODE_COLOR_LIGHT 0x00FFFFFFU
|
|
#define USH_QRCODE_COLOR_DESKTOP 0x00F3F3F3U
|
|
#define USH_QRCODE_COLOR_TITLE 0x000078D7U
|
|
#define USH_QRCODE_COLOR_CLOSE 0x00E81123U
|
|
#define USH_QRCODE_COLOR_TEXT 0x00232323U
|
|
#define USH_QRCODE_COLOR_MUTED 0x00666666U
|
|
#define USH_QRCODE_COLOR_BORDER 0x00D0D0D0U
|
|
#define USH_QRCODE_COLOR_PANEL 0x00FFFFFFU
|
|
|
|
#define USH_QRCODE_GLYPH7(r0, r1, r2, r3, r4, r5, r6) \
|
|
(((u64)(r0) << 30U) | ((u64)(r1) << 25U) | ((u64)(r2) << 20U) | ((u64)(r3) << 15U) | ((u64)(r4) << 10U) | \
|
|
((u64)(r5) << 5U) | (u64)(r6))
|
|
|
|
static unsigned int ush_qrcode_canvas[USH_QRCODE_CANVAS_MAX][USH_QRCODE_CANVAS_MAX];
|
|
|
|
static int ush_qrcode_clampi(int value, int min_value, int max_value) {
|
|
if (value < min_value) {
|
|
return min_value;
|
|
}
|
|
|
|
if (value > max_value) {
|
|
return max_value;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static int ush_qrcode_u64_as_i32(u64 raw) {
|
|
return (int)(i64)raw;
|
|
}
|
|
|
|
static char ush_qrcode_upper_char(char ch) {
|
|
if (ch >= 'a' && ch <= 'z') {
|
|
return (char)(ch - ('a' - 'A'));
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
static u64 ush_qrcode_glyph_mask(char ch) {
|
|
switch (ush_qrcode_upper_char(ch)) {
|
|
case 'C':
|
|
return USH_QRCODE_GLYPH7(14U, 17U, 16U, 16U, 16U, 17U, 14U);
|
|
case 'D':
|
|
return USH_QRCODE_GLYPH7(30U, 17U, 17U, 17U, 17U, 17U, 30U);
|
|
case 'E':
|
|
return USH_QRCODE_GLYPH7(31U, 16U, 16U, 30U, 16U, 16U, 31U);
|
|
case 'L':
|
|
return USH_QRCODE_GLYPH7(16U, 16U, 16U, 16U, 16U, 16U, 31U);
|
|
case 'O':
|
|
return USH_QRCODE_GLYPH7(14U, 17U, 17U, 17U, 17U, 17U, 14U);
|
|
case 'P':
|
|
return USH_QRCODE_GLYPH7(30U, 17U, 17U, 30U, 16U, 16U, 16U);
|
|
case 'Q':
|
|
return USH_QRCODE_GLYPH7(14U, 17U, 17U, 17U, 21U, 18U, 13U);
|
|
case 'R':
|
|
return USH_QRCODE_GLYPH7(30U, 17U, 17U, 30U, 20U, 18U, 17U);
|
|
case 'S':
|
|
return USH_QRCODE_GLYPH7(15U, 16U, 16U, 14U, 1U, 1U, 30U);
|
|
case 'T':
|
|
return USH_QRCODE_GLYPH7(31U, 4U, 4U, 4U, 4U, 4U, 4U);
|
|
default:
|
|
return 0ULL;
|
|
}
|
|
}
|
|
|
|
static void ush_qrcode_fill_rect(int canvas_w, int canvas_h, int x, int y, int w, int h, unsigned int color) {
|
|
int left;
|
|
int top;
|
|
int right;
|
|
int bottom;
|
|
int row;
|
|
|
|
if (canvas_w <= 0 || canvas_h <= 0 || canvas_w > (int)USH_QRCODE_CANVAS_MAX ||
|
|
canvas_h > (int)USH_QRCODE_CANVAS_MAX || w <= 0 || h <= 0) {
|
|
return;
|
|
}
|
|
|
|
left = ush_qrcode_clampi(x, 0, canvas_w);
|
|
top = ush_qrcode_clampi(y, 0, canvas_h);
|
|
right = ush_qrcode_clampi(x + w, 0, canvas_w);
|
|
bottom = ush_qrcode_clampi(y + h, 0, canvas_h);
|
|
if (left >= right || top >= bottom) {
|
|
return;
|
|
}
|
|
|
|
for (row = top; row < bottom; row++) {
|
|
int col;
|
|
for (col = left; col < right; col++) {
|
|
ush_qrcode_canvas[row][col] = color;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ush_qrcode_stroke_rect(int canvas_w, int canvas_h, int x, int y, int w, int h, unsigned int color) {
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, x, y, w, 1, color);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, x, y + h - 1, w, 1, color);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, x, y, 1, h, color);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, x + w - 1, y, 1, h, color);
|
|
}
|
|
|
|
static void ush_qrcode_draw_char(int canvas_w, int canvas_h, int x, int y, char ch, int scale, unsigned int color) {
|
|
u64 mask = ush_qrcode_glyph_mask(ch);
|
|
int row;
|
|
|
|
if (mask == 0ULL || scale <= 0) {
|
|
return;
|
|
}
|
|
|
|
for (row = 0; row < 7; row++) {
|
|
int col;
|
|
for (col = 0; col < 5; col++) {
|
|
unsigned int bit_index = (unsigned int)((6 - row) * 5 + (4 - col));
|
|
if ((mask & (1ULL << bit_index)) != 0ULL) {
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, x + (col * scale), y + (row * scale), scale, scale, color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ush_qrcode_draw_text(int canvas_w, int canvas_h, int x, int y, const char *text, int scale,
|
|
unsigned int color) {
|
|
int cursor_x = x;
|
|
|
|
if (text == (const char *)0 || scale <= 0) {
|
|
return;
|
|
}
|
|
|
|
while (*text != '\0' && cursor_x + (5 * scale) < canvas_w) {
|
|
if (*text != ' ') {
|
|
ush_qrcode_draw_char(canvas_w, canvas_h, cursor_x, y, *text, scale, color);
|
|
}
|
|
cursor_x += 6 * scale;
|
|
text++;
|
|
}
|
|
}
|
|
|
|
static int ush_qrcode_streq_ignore_case(const char *left, const char *right) {
|
|
u64 i = 0ULL;
|
|
|
|
if (left == (const char *)0 || right == (const char *)0) {
|
|
return 0;
|
|
}
|
|
|
|
while (left[i] != '\0' && right[i] != '\0') {
|
|
char lc = left[i];
|
|
char rc = right[i];
|
|
|
|
if (lc >= 'a' && lc <= 'z') {
|
|
lc = (char)(lc - ('a' - 'A'));
|
|
}
|
|
|
|
if (rc >= 'a' && rc <= 'z') {
|
|
rc = (char)(rc - ('a' - 'A'));
|
|
}
|
|
|
|
if (lc != rc) {
|
|
return 0;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return (left[i] == '\0' && right[i] == '\0') ? 1 : 0;
|
|
}
|
|
|
|
static int ush_qrcode_parse_ecc(const char *text, enum qrcodegen_Ecc *out_ecc) {
|
|
if (text == (const char *)0 || out_ecc == (enum qrcodegen_Ecc *)0) {
|
|
return 0;
|
|
}
|
|
|
|
if (ush_qrcode_streq_ignore_case(text, "L") != 0 || ush_qrcode_streq_ignore_case(text, "LOW") != 0) {
|
|
*out_ecc = qrcodegen_Ecc_LOW;
|
|
return 1;
|
|
}
|
|
|
|
if (ush_qrcode_streq_ignore_case(text, "M") != 0 || ush_qrcode_streq_ignore_case(text, "MEDIUM") != 0) {
|
|
*out_ecc = qrcodegen_Ecc_MEDIUM;
|
|
return 1;
|
|
}
|
|
|
|
if (ush_qrcode_streq_ignore_case(text, "Q") != 0 || ush_qrcode_streq_ignore_case(text, "QUARTILE") != 0) {
|
|
*out_ecc = qrcodegen_Ecc_QUARTILE;
|
|
return 1;
|
|
}
|
|
|
|
if (ush_qrcode_streq_ignore_case(text, "H") != 0 || ush_qrcode_streq_ignore_case(text, "HIGH") != 0) {
|
|
*out_ecc = qrcodegen_Ecc_HIGH;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ush_qrcode_usage(void) {
|
|
ush_writeln("usage: qrcode [--ecc <L|M|Q|H>] <text>");
|
|
ush_writeln(" qrcode --help");
|
|
ush_writeln("note: pipeline input supported when <text> omitted");
|
|
}
|
|
|
|
/* return: 0 fail, 1 ok, 2 help */
|
|
static int ush_qrcode_parse_args(const char *arg, char *out_text, u64 out_text_size, enum qrcodegen_Ecc *out_ecc) {
|
|
char first[USH_PATH_MAX];
|
|
char second[USH_PATH_MAX];
|
|
const char *rest = "";
|
|
const char *rest2 = "";
|
|
|
|
if (out_text == (char *)0 || out_text_size == 0ULL || out_ecc == (enum qrcodegen_Ecc *)0) {
|
|
return 0;
|
|
}
|
|
|
|
*out_ecc = qrcodegen_Ecc_LOW;
|
|
out_text[0] = '\0';
|
|
|
|
if (arg == (const char *)0 || arg[0] == '\0') {
|
|
if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_text[0] != '\0') {
|
|
if (ush_pipeline_stdin_len + 1ULL > out_text_size) {
|
|
return 0;
|
|
}
|
|
|
|
ush_copy(out_text, out_text_size, ush_pipeline_stdin_text);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (ush_split_first_and_rest(arg, first, (u64)sizeof(first), &rest) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (ush_streq(first, "--help") != 0 || ush_streq(first, "-h") != 0) {
|
|
return 2;
|
|
}
|
|
|
|
if (ush_streq(first, "--ecc") != 0) {
|
|
if (ush_split_first_and_rest(rest, second, (u64)sizeof(second), &rest2) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (ush_qrcode_parse_ecc(second, out_ecc) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (rest2 == (const char *)0 || rest2[0] == '\0') {
|
|
if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_text[0] != '\0') {
|
|
if (ush_pipeline_stdin_len + 1ULL > out_text_size) {
|
|
return 0;
|
|
}
|
|
|
|
ush_copy(out_text, out_text_size, ush_pipeline_stdin_text);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ush_copy(out_text, out_text_size, rest2);
|
|
return 1;
|
|
}
|
|
|
|
if (first[0] == '-' && first[1] == '-') {
|
|
const char *prefix = "--ecc=";
|
|
u64 i = 0ULL;
|
|
int match = 1;
|
|
|
|
while (prefix[i] != '\0') {
|
|
if (first[i] != prefix[i]) {
|
|
match = 0;
|
|
break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
if (match != 0) {
|
|
if (first[i] == '\0') {
|
|
return 0;
|
|
}
|
|
|
|
if (ush_qrcode_parse_ecc(&first[i], out_ecc) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (rest == (const char *)0 || rest[0] == '\0') {
|
|
if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_text[0] != '\0') {
|
|
if (ush_pipeline_stdin_len + 1ULL > out_text_size) {
|
|
return 0;
|
|
}
|
|
|
|
ush_copy(out_text, out_text_size, ush_pipeline_stdin_text);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ush_copy(out_text, out_text_size, rest);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
ush_copy(out_text, out_text_size, arg);
|
|
return 1;
|
|
}
|
|
|
|
static void ush_qrcode_emit_ascii(const uint8_t qrcode[]) {
|
|
int size = qrcodegen_getSize(qrcode);
|
|
int border = (int)USH_QRCODE_BORDER;
|
|
int limit;
|
|
int y;
|
|
int x;
|
|
|
|
limit = size + border;
|
|
|
|
for (y = -border; y < limit; y++) {
|
|
for (x = -border; x < limit; x++) {
|
|
int dark = (x >= 0 && y >= 0 && x < size && y < size && qrcodegen_getModule(qrcode, x, y)) ? 1 : 0;
|
|
ush_write(dark != 0 ? "##" : " ");
|
|
}
|
|
|
|
ush_write_char('\n');
|
|
}
|
|
}
|
|
|
|
static void ush_qrcode_choose_window_geometry(const cleonos_fb_info *fb_info, int *out_x, int *out_y, int *out_w,
|
|
int *out_h) {
|
|
int screen_w = 800;
|
|
int screen_h = 600;
|
|
int max_w;
|
|
int max_h;
|
|
int win_w;
|
|
int win_h;
|
|
|
|
if (fb_info != (const cleonos_fb_info *)0 && fb_info->width > 0ULL && fb_info->height > 0ULL &&
|
|
fb_info->width <= 4096ULL && fb_info->height <= 4096ULL) {
|
|
screen_w = (int)fb_info->width;
|
|
screen_h = (int)fb_info->height;
|
|
}
|
|
|
|
max_w = screen_w - 80;
|
|
max_h = screen_h - 96;
|
|
if (max_w < USH_QRCODE_WINDOW_MIN_W) {
|
|
max_w = screen_w;
|
|
}
|
|
if (max_h < USH_QRCODE_WINDOW_MIN_H) {
|
|
max_h = screen_h;
|
|
}
|
|
|
|
win_w = ush_qrcode_clampi(USH_QRCODE_WINDOW_DEFAULT_W, USH_QRCODE_WINDOW_MIN_W, max_w);
|
|
win_h = ush_qrcode_clampi(USH_QRCODE_WINDOW_DEFAULT_H, USH_QRCODE_WINDOW_MIN_H, max_h);
|
|
if (win_w > (int)USH_QRCODE_CANVAS_MAX) {
|
|
win_w = (int)USH_QRCODE_CANVAS_MAX;
|
|
}
|
|
if (win_h > (int)USH_QRCODE_CANVAS_MAX) {
|
|
win_h = (int)USH_QRCODE_CANVAS_MAX;
|
|
}
|
|
|
|
*out_w = win_w;
|
|
*out_h = win_h;
|
|
*out_x = (screen_w > win_w) ? ((screen_w - win_w) / 2) : 0;
|
|
*out_y = (screen_h > win_h) ? ((screen_h - win_h) / 2) : 0;
|
|
}
|
|
|
|
static int ush_qrcode_draw_window_canvas(const uint8_t qrcode[], int canvas_w, int canvas_h) {
|
|
int qr_size = qrcodegen_getSize(qrcode);
|
|
int border = (int)USH_QRCODE_BORDER;
|
|
int side_modules;
|
|
int content_w;
|
|
int content_h;
|
|
int qr_area;
|
|
int module_pixels;
|
|
int side_pixels;
|
|
int qr_x;
|
|
int qr_y;
|
|
int y;
|
|
|
|
if (qrcode == (const uint8_t *)0 || qr_size <= 0 || canvas_w <= 0 || canvas_h <= 0 ||
|
|
canvas_w > (int)USH_QRCODE_CANVAS_MAX || canvas_h > (int)USH_QRCODE_CANVAS_MAX) {
|
|
return 0;
|
|
}
|
|
|
|
side_modules = qr_size + (border * 2);
|
|
if (side_modules <= 0 || side_modules > (int)USH_QRCODE_MAX_MODULES) {
|
|
return 0;
|
|
}
|
|
|
|
content_w = canvas_w - (USH_QRCODE_PAD * 2);
|
|
content_h = canvas_h - USH_QRCODE_TITLE_H - USH_QRCODE_FOOTER_H - (USH_QRCODE_PAD * 2);
|
|
qr_area = (content_w < content_h) ? content_w : content_h;
|
|
module_pixels = qr_area / side_modules;
|
|
if (module_pixels <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
side_pixels = side_modules * module_pixels;
|
|
qr_x = (canvas_w - side_pixels) / 2;
|
|
qr_y = USH_QRCODE_TITLE_H + USH_QRCODE_PAD + ((content_h - side_pixels) / 2);
|
|
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, 0, 0, canvas_w, canvas_h, USH_QRCODE_COLOR_DESKTOP);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, 0, 0, canvas_w, USH_QRCODE_TITLE_H, USH_QRCODE_COLOR_TITLE);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, canvas_w - USH_QRCODE_CLOSE_W, 0, USH_QRCODE_CLOSE_W, USH_QRCODE_TITLE_H,
|
|
USH_QRCODE_COLOR_CLOSE);
|
|
ush_qrcode_draw_text(canvas_w, canvas_h, 14, 10, "QRCODE", 1, USH_QRCODE_COLOR_LIGHT);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, canvas_w - 28, 11, 14, 2, USH_QRCODE_COLOR_LIGHT);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, canvas_w - 28, 22, 14, 2, USH_QRCODE_COLOR_LIGHT);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, canvas_w - 22, 15, 2, 6, USH_QRCODE_COLOR_LIGHT);
|
|
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, qr_x - 10, qr_y - 10, side_pixels + 20, side_pixels + 20,
|
|
USH_QRCODE_COLOR_PANEL);
|
|
ush_qrcode_stroke_rect(canvas_w, canvas_h, qr_x - 10, qr_y - 10, side_pixels + 20, side_pixels + 20,
|
|
USH_QRCODE_COLOR_BORDER);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, qr_x, qr_y, side_pixels, side_pixels, USH_QRCODE_COLOR_LIGHT);
|
|
|
|
for (y = -border; y < qr_size + border; y++) {
|
|
int x;
|
|
for (x = -border; x < qr_size + border; x++) {
|
|
int dark = (x >= 0 && y >= 0 && x < qr_size && y < qr_size && qrcodegen_getModule(qrcode, x, y)) ? 1 : 0;
|
|
if (dark != 0) {
|
|
int px = qr_x + ((x + border) * module_pixels);
|
|
int py = qr_y + ((y + border) * module_pixels);
|
|
ush_qrcode_fill_rect(canvas_w, canvas_h, px, py, module_pixels, module_pixels, USH_QRCODE_COLOR_DARK);
|
|
}
|
|
}
|
|
}
|
|
|
|
ush_qrcode_draw_text(canvas_w, canvas_h, 22, canvas_h - 24, "PRESS Q TO CLOSE", 1, USH_QRCODE_COLOR_MUTED);
|
|
return 1;
|
|
}
|
|
|
|
static int ush_qrcode_present_window(u64 window_id, int width, int height) {
|
|
cleonos_wm_present_req req;
|
|
|
|
if (window_id == 0ULL || width <= 0 || height <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
req.window_id = window_id;
|
|
req.pixels_ptr = (u64)(usize)&ush_qrcode_canvas[0][0];
|
|
req.src_width = (u64)(unsigned int)width;
|
|
req.src_height = (u64)(unsigned int)height;
|
|
req.src_pitch_bytes = (u64)USH_QRCODE_CANVAS_MAX * 4ULL;
|
|
return (cleonos_sys_wm_present(&req) != 0ULL) ? 1 : 0;
|
|
}
|
|
|
|
static int ush_qrcode_close_hit(int width, int local_x, int local_y) {
|
|
return (local_x >= width - USH_QRCODE_CLOSE_W && local_x < width && local_y >= 0 && local_y < USH_QRCODE_TITLE_H)
|
|
? 1
|
|
: 0;
|
|
}
|
|
|
|
static void ush_qrcode_window_loop(u64 window_id, int width, int height, int x, int y) {
|
|
int running = 1;
|
|
int dragging = 0;
|
|
int drag_offset_x = 0;
|
|
int drag_offset_y = 0;
|
|
|
|
(void)height;
|
|
|
|
while (running != 0) {
|
|
u64 budget = 0ULL;
|
|
int handled = 0;
|
|
|
|
while (budget < 64ULL) {
|
|
cleonos_wm_event event;
|
|
ush_zero(&event, (u64)sizeof(event));
|
|
if (cleonos_sys_wm_poll_event(window_id, &event) == 0ULL) {
|
|
break;
|
|
}
|
|
|
|
handled = 1;
|
|
if (event.type == CLEONOS_WM_EVENT_KEY) {
|
|
if (event.arg0 == (u64)'q' || event.arg0 == (u64)'Q' || event.arg0 == 27ULL || event.arg0 == 13ULL) {
|
|
running = 0;
|
|
break;
|
|
}
|
|
} else if (event.type == CLEONOS_WM_EVENT_MOUSE_BUTTON) {
|
|
u64 buttons = event.arg0;
|
|
u64 changed = event.arg1;
|
|
int local_x = ush_qrcode_u64_as_i32(event.arg2);
|
|
int local_y = ush_qrcode_u64_as_i32(event.arg3);
|
|
int left_changed = ((changed & 0x1ULL) != 0ULL) ? 1 : 0;
|
|
int left_down = ((buttons & 0x1ULL) != 0ULL) ? 1 : 0;
|
|
|
|
if (left_changed != 0) {
|
|
if (left_down == 0) {
|
|
dragging = 0;
|
|
} else if (ush_qrcode_close_hit(width, local_x, local_y) != 0) {
|
|
running = 0;
|
|
break;
|
|
} else if (local_y >= 0 && local_y < USH_QRCODE_TITLE_H) {
|
|
dragging = 1;
|
|
drag_offset_x = local_x;
|
|
drag_offset_y = local_y;
|
|
}
|
|
}
|
|
} else if (event.type == CLEONOS_WM_EVENT_MOUSE_MOVE && dragging != 0) {
|
|
cleonos_wm_move_req move_req;
|
|
x = ush_qrcode_u64_as_i32(event.arg0) - drag_offset_x;
|
|
y = ush_qrcode_u64_as_i32(event.arg1) - drag_offset_y;
|
|
move_req.window_id = window_id;
|
|
move_req.x = (u64)(i64)x;
|
|
move_req.y = (u64)(i64)y;
|
|
(void)cleonos_sys_wm_move(&move_req);
|
|
}
|
|
|
|
budget++;
|
|
}
|
|
|
|
if (running == 0) {
|
|
break;
|
|
}
|
|
|
|
if (handled != 0) {
|
|
(void)cleonos_sys_yield();
|
|
} else {
|
|
(void)cleonos_sys_sleep_ticks(1ULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int ush_qrcode_emit_window(const uint8_t qrcode[]) {
|
|
int qr_size = qrcodegen_getSize(qrcode);
|
|
cleonos_fb_info fb_info;
|
|
cleonos_wm_create_req create_req;
|
|
u64 old_tty;
|
|
u64 window_id;
|
|
int win_x;
|
|
int win_y;
|
|
int win_w;
|
|
int win_h;
|
|
|
|
if (qr_size <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
ush_zero(&fb_info, (u64)sizeof(fb_info));
|
|
if (cleonos_sys_fb_info(&fb_info) == 0ULL || fb_info.width == 0ULL || fb_info.height == 0ULL ||
|
|
fb_info.bpp != 32ULL) {
|
|
ush_writeln("qrcode: desktop unavailable, fallback to ascii");
|
|
ush_qrcode_emit_ascii(qrcode);
|
|
return 1;
|
|
}
|
|
|
|
ush_qrcode_choose_window_geometry(&fb_info, &win_x, &win_y, &win_w, &win_h);
|
|
if (ush_qrcode_draw_window_canvas(qrcode, win_w, win_h) == 0) {
|
|
ush_writeln("qrcode: desktop window too small");
|
|
return 0;
|
|
}
|
|
|
|
old_tty = cleonos_sys_tty_active();
|
|
if (old_tty != USH_QRCODE_TTY_DISPLAY) {
|
|
(void)cleonos_sys_tty_switch(USH_QRCODE_TTY_DISPLAY);
|
|
}
|
|
|
|
create_req.x = (u64)(i64)win_x;
|
|
create_req.y = (u64)(i64)win_y;
|
|
create_req.width = (u64)(unsigned int)win_w;
|
|
create_req.height = (u64)(unsigned int)win_h;
|
|
create_req.flags = CLEONOS_WM_FLAG_TOPMOST;
|
|
window_id = cleonos_sys_wm_create(&create_req);
|
|
if (window_id == 0ULL) {
|
|
if (old_tty != USH_QRCODE_TTY_DISPLAY) {
|
|
(void)cleonos_sys_tty_switch(old_tty);
|
|
}
|
|
ush_writeln("qrcode: wm window create failed, fallback to ascii");
|
|
ush_qrcode_emit_ascii(qrcode);
|
|
return 1;
|
|
}
|
|
|
|
if (ush_qrcode_present_window(window_id, win_w, win_h) == 0) {
|
|
(void)cleonos_sys_wm_destroy(window_id);
|
|
if (old_tty != USH_QRCODE_TTY_DISPLAY) {
|
|
(void)cleonos_sys_tty_switch(old_tty);
|
|
}
|
|
ush_writeln("qrcode: wm present failed");
|
|
return 0;
|
|
}
|
|
|
|
(void)cleonos_sys_wm_set_focus(window_id);
|
|
ush_qrcode_window_loop(window_id, win_w, win_h, win_x, win_y);
|
|
(void)cleonos_sys_wm_destroy(window_id);
|
|
if (old_tty != USH_QRCODE_TTY_DISPLAY) {
|
|
(void)cleonos_sys_tty_switch(old_tty);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int ush_cmd_qrcode(const char *arg) {
|
|
char text[USH_QRCODE_MAX_TEXT];
|
|
enum qrcodegen_Ecc ecc;
|
|
uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(USH_QRCODE_MAX_VERSION)];
|
|
uint8_t temp[qrcodegen_BUFFER_LEN_FOR_VERSION(USH_QRCODE_MAX_VERSION)];
|
|
int parse_ret;
|
|
int ok;
|
|
|
|
parse_ret = ush_qrcode_parse_args(arg, text, (u64)sizeof(text), &ecc);
|
|
if (parse_ret == 2) {
|
|
ush_qrcode_usage();
|
|
return 1;
|
|
}
|
|
|
|
if (parse_ret == 0 || text[0] == '\0') {
|
|
ush_qrcode_usage();
|
|
return 0;
|
|
}
|
|
|
|
ok = qrcodegen_encodeText(text, temp, qrcode, ecc, qrcodegen_VERSION_MIN, USH_QRCODE_MAX_VERSION,
|
|
qrcodegen_Mask_AUTO, true);
|
|
|
|
if (ok == 0) {
|
|
ush_writeln("qrcode: encode failed (input too long or invalid)");
|
|
return 0;
|
|
}
|
|
|
|
return ush_qrcode_emit_window(qrcode);
|
|
}
|
|
|
|
int cleonos_app_main(void) {
|
|
ush_cmd_ctx ctx;
|
|
ush_cmd_ret ret;
|
|
ush_state sh;
|
|
char initial_cwd[USH_PATH_MAX];
|
|
int has_context = 0;
|
|
int success = 0;
|
|
const char *arg = "";
|
|
|
|
ush_zero(&ctx, (u64)sizeof(ctx));
|
|
ush_zero(&ret, (u64)sizeof(ret));
|
|
ush_init_state(&sh);
|
|
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
|
|
|
|
if (ush_command_ctx_read(&ctx) != 0) {
|
|
if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "qrcode") != 0) {
|
|
has_context = 1;
|
|
arg = ctx.arg;
|
|
if (ctx.cwd[0] == '/') {
|
|
ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd);
|
|
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
|
|
}
|
|
}
|
|
}
|
|
|
|
success = ush_cmd_qrcode(arg);
|
|
|
|
if (has_context != 0) {
|
|
if (ush_streq(sh.cwd, initial_cwd) == 0) {
|
|
ret.flags |= USH_CMD_RET_FLAG_CWD;
|
|
ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd);
|
|
}
|
|
|
|
if (sh.exit_requested != 0) {
|
|
ret.flags |= USH_CMD_RET_FLAG_EXIT;
|
|
ret.exit_code = sh.exit_code;
|
|
}
|
|
|
|
(void)ush_command_ret_write(&ret);
|
|
}
|
|
|
|
return (success != 0) ? 0 : 1;
|
|
}
|