シンプル化

This commit is contained in:
2026-01-19 00:20:27 +09:00
parent 4a9266fe9a
commit ffa9c69270
11 changed files with 510 additions and 452 deletions

344
include/suwaui.h Normal file
View File

@@ -0,0 +1,344 @@
#pragma once
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include <X11/Xatom.h>
#include <stdio.h>
#define FGCOL 0xfcfcfc
#if defined(__OpenBSD__)
#define BGCOL 0x232320
#define BTSEL 0xb8b515
#define BTCOL 0xf1ed25
#define BTHVR 0xecea71
#elif defined(__FreeBSD__)
#define BGCOL 0x232020
#define BTSEL 0xb61729
#define BTCOL 0xee4030
#define BTHVR 0xf35869
#endif
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(SUWAUI_IMPLEMENTS_SUWAWINDOW)
#include <string.h>
typedef struct {
int x, y, width, height;
int start_width, start_height;
int isrunning;
const char *name;
const char *version;
const char *res_name;
const char *class_name;
Display *display;
Window xwindow;
int screen;
Drawable target;
GC gc;
Visual visual;
XftColor color;
XftFont *font;
Colormap colormap;
Pixmap backbuf;
XEvent event;
} SuwaWindow;
__attribute__((unused)) static void suwaui_destroy_window(SuwaWindow *w);
__attribute__((unused)) static inline float get_scale(SuwaWindow *w) {
XWindowAttributes attr;
XGetWindowAttributes(w->display, w->xwindow, &attr);
float sx = (float)attr.width / w->start_width;
float sy = (float)attr.height / w->start_height;
return sx < sy ? sx : sy;
}
__attribute__((unused)) static SuwaWindow suwaui_create_window(int x, int y, int width, int height,
const char *software_name, const char *software_version,
const char *res_name, const char *class_name,
const char *font, const char *fg_color,
int is_centered, int cannot_shrink, int cannot_grow) {
(void)cannot_grow;
SuwaWindow w = {0};
w.width = width;
w.height = height;
w.start_width = width;
w.start_height = height;
w.name = software_name;
w.version = software_version;
w.res_name = res_name;
w.class_name = class_name;
w.isrunning = 1;
XGCValues values;
w.display = XOpenDisplay(NULL);
if (w.display == NULL) {
fprintf(stderr, "screen open fail\n");
return (SuwaWindow){0};
}
w.screen = DefaultScreen(w.display);
if (is_centered > 0) {
int sw = DisplayWidth(w.display, w.screen);
int sh = DisplayHeight(w.display, w.screen);
w.x = (sw - w.width) / 2;
w.y = (sh - w.height) / 2;
} else {
w.x = x;
w.y = y;
}
w.xwindow = XCreateSimpleWindow(w.display,
RootWindow(w.display, w.screen),
w.x, w.y,
w.width, w.height,
1, BTCOL, BGCOL);
if (!w.xwindow) {
suwaui_destroy_window(&w);
fprintf(stderr, "window create fail\n");
return (SuwaWindow){0};
}
if (cannot_shrink) {
XSizeHints *sizeHint = XAllocSizeHints();
if (sizeHint) {
sizeHint->flags = PMinSize;
sizeHint->min_width = width;
sizeHint->min_height = height;
XSetWMNormalHints(w.display, w.xwindow, sizeHint);
XFree(sizeHint);
}
}
w.backbuf = XCreatePixmap(w.display, w.xwindow,
w.width, w.height,
DefaultDepth(w.display, w.screen));
w.target = w.backbuf;
Atom net_wm_window_type = XInternAtom(w.display, "_NET_WM_WINDOW_TYPE", False);
Atom dialog = XInternAtom(w.display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
XChangeProperty(w.display, w.xwindow, net_wm_window_type, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&dialog, 1);
XStoreName(w.display, w.xwindow, w.name);
Atom net_wm_name = XInternAtom(w.display, "_NET_WM_NAME", False);
char displayname[16];
snprintf(displayname, 16, "%s %s", w.name, w.version);
XChangeProperty(w.display, w.xwindow, net_wm_name,
XInternAtom(w.display, "UTF8_STRING", False), 8,
PropModeReplace, (unsigned char *)displayname, strlen(displayname));
XClassHint *classHint = XAllocClassHint();
if (classHint) {
classHint->res_name = strdup(w.res_name);
classHint->res_class = strdup(w.class_name);
XSetClassHint(w.display, w.xwindow, classHint);
XFree(classHint);
}
XSetWindowBackground(w.display, w.xwindow, BGCOL);
XSelectInput(w.display, w.xwindow,
ExposureMask
| ButtonPressMask
| ButtonReleaseMask
| KeyPressMask
// | PointerMotionMask
// | ButtonMotionMask
// | StructureNotifyMask
);
w.gc = XCreateGC(w.display, w.xwindow, 0, &values);
if (!w.gc) {
suwaui_destroy_window(&w);
fprintf(stderr, "gc create fail\n");
return (SuwaWindow){0};
}
w.visual = *DefaultVisual(w.display, w.screen);
w.colormap = XCreateColormap(w.display, w.xwindow,
&w.visual, AllocNone);
if (w.colormap == None) {
suwaui_destroy_window(&w);
fprintf(stderr, "calor map create fail\n");
return (SuwaWindow){0};
}
w.font = XftFontOpenName(w.display, w.screen, font);
if (!w.font) {
suwaui_destroy_window(&w);
fprintf(stderr, "font create fail\n");
return (SuwaWindow){0};
}
if (!XftColorAllocName(w.display, &w.visual,
w.colormap, fg_color, &w.color)) {
suwaui_destroy_window(&w);
fprintf(stderr, "color estimate fail\n");
return (SuwaWindow){0};
}
return w;
}
__attribute__((unused)) static void suwaui_destroy_window(SuwaWindow *w) {
if (w->font) XftFontClose(w->display, w->font);
if (w->gc) XFreeGC(w->display, w->gc);
if (w->backbuf) {
XFreePixmap(w->display, w->backbuf);
w->backbuf = None;
}
if (w->xwindow) XDestroyWindow(w->display, w->xwindow);
if (w->display) XCloseDisplay(w->display);
}
#endif // SUWAUI_IMPLEMENTS_SUWAWINDOW
#if defined(SUWAUI_IMPLEMENTS_SUWATABS)
typedef struct {
int x, y, width, height;
} SuwaTab;
typedef struct {
int x, y, width, height;
} SuwaTabs;
#endif // SUWAUI_IMPLEMENTS_SUWATABS
#if defined(SUWAUI_IMPLEMENTS_SUWABUTTON)
typedef struct {
int x, y, width, height;
const char *text;
XftFont *font;
int bg_color;
XftColor fg_color;
int pressed; // 0 = 普通、1 = 押している
} SuwaButton;
// __attribute__((unused)) static void suwaui_del_button(SuwaWindow *window, SuwaButton *button);
__attribute__((unused)) static XftColor suwaui_set_button_fgcolor(SuwaWindow *window, const char *color) {
XftColor xcolor;
XftColorAllocName(window->display,
DefaultVisual(window->display, DefaultScreen(window->display)),
DefaultColormap(window->display, DefaultScreen(window->display)),
color, &xcolor);
return xcolor;
}
__attribute__((unused)) static void suwaui_draw_button(SuwaWindow *window, SuwaButton *btn, XftDraw *xftdraw) {
unsigned long curbg = btn->pressed ? BTSEL : btn->bg_color;
XSetForeground(window->display, window->gc, curbg);
XFillRectangle(window->display, window->target, window->gc, btn->x, btn->y,
btn->width, btn->height);
// 文字の中央に
if (btn->text && window->font && xftdraw) {
const FcChar8 *str = (const FcChar8 *)btn->text;
int len = strlen((const char *)str);
XGlyphInfo extents;
XftTextExtentsUtf8(window->display, window->font, str, len, &extents);
int text_w = extents.xOff;
int text_h = window->font->ascent + window->font->descent;
int tx = btn->x + (btn->width - text_w) / 2;
int ty = btn->y + (btn->height - text_h) / 2 + window->font->ascent;
XftDrawStringUtf8(xftdraw, &btn->fg_color, window->font, tx, ty,
(FcChar8 *)btn->text, len);
}
}
__attribute__((unused)) static SuwaButton suwaui_add_button(int x, int y, int width, int height,
const char *text, XftFont *font, int bg_color, XftColor fg_color) {
SuwaButton button = {
.x = x,
.y = y,
.width = width,
.height = height,
.text = text,
.font = font,
.bg_color = bg_color,
.fg_color = fg_color,
.pressed = 0
};
return button;
}
#endif // SUWAUI_IMPLEMENTS_SUWABUTTON
#if defined(SUWAUI_IMPLEMENTS_SUWALABEL)
typedef struct {
int x, y, width, height;
char text[64];
XftFont *font;
XftColor fg_color;
} SuwaLabel;
__attribute__((unused)) static void suwaui_del_label(SuwaWindow *window, SuwaLabel *label);
__attribute__((unused)) static SuwaLabel suwaui_add_label(SuwaWindow *window,
int x, int y, int width, int height, char text[64], const char *font,
const char *fg_color, int rtl) {
(void)width;
(void)height;
SuwaLabel label = {
.x = x,
.y = y,
.width = width,
.height = height
};
label.font = XftFontOpenName(window->display, window->screen, font);
if (!label.font) {
fprintf(stderr, "font create fail\n");
return (SuwaLabel){0};
}
strncpy(label.text, text ? text : "", sizeof(label.text) - 1);
label.text[sizeof(label.text)-1] = '\0';
const FcChar8 *txt = (const FcChar8 *)label.text;
int len = strlen((const char *)txt);
XGlyphInfo extents;
XftTextExtentsUtf8(window->display, label.font, txt, len, &extents);
if (rtl > 0) {
XWindowAttributes attr;
XGetWindowAttributes(window->display, window->xwindow, &attr);
int w = attr.width;
label.x = w - label.x - extents.xOff;
}
if (!XftColorAllocName(window->display,
DefaultVisual(window->display, DefaultScreen(window->display)),
DefaultColormap(window->display, DefaultScreen(window->display)),
fg_color, &label.fg_color)) {
suwaui_del_label(window, &label);
fprintf(stderr, "color estimate fail\n");
return (SuwaLabel){0};
}
return label;
}
__attribute__((unused)) static void suwaui_del_label(SuwaWindow *window, SuwaLabel *label) {
if (label->font) XftFontClose(window->display, label->font);
}
#endif // SUWAUI_IMPLEMENTS_SUWALABEL
#if defined(__cplusplus)
}
#endif