最初コミット
This commit is contained in:
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# 076 Free License
|
||||
|
||||
Copyright (c) 2026 テクニカル諏訪子
|
||||
|
||||
Permission is hereby granted to any person obtaining a copy of the software
|
||||
SuwaUI (the "Software") to use, modify, merge, copy, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, subject to the following conditions:
|
||||
|
||||
1. **Origin Attribution**:
|
||||
- You must not misrepresent the origin of the Software; you must not claim
|
||||
you created the original Software.
|
||||
2. **Notice Preservation**:
|
||||
- This license and the above copyright notice must remain intact in all copies
|
||||
of the source code.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
367
suwaui.h
Normal file
367
suwaui.h
Normal file
@@ -0,0 +1,367 @@
|
||||
/**************************************************************************************
|
||||
# 076 Free License
|
||||
|
||||
Copyright (c) 2026 テクニカル諏訪子
|
||||
|
||||
Permission is hereby granted to any person obtaining a copy of the software
|
||||
SuwaUI (the "Software") to use, modify, merge, copy, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, subject to the following conditions:
|
||||
|
||||
1. **Origin Attribution**:
|
||||
- You must not misrepresent the origin of the Software; you must not claim
|
||||
you created the original Software.
|
||||
2. **Notice Preservation**:
|
||||
- This license and the above copyright notice must remain intact in all copies
|
||||
of the source code.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************/
|
||||
#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
|
||||
Reference in New Issue
Block a user