commit b20fa6cc3a68def3eaab8c1df83f8db338173121 Author: 諏訪子 Date: Sat Jan 17 07:24:25 2026 +0900 最初コミット diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c1d6ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +ucalc +*.o +*.core diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c2f91f4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2 @@ +# 0.0.0 +* 標準電卓 diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..e69de29 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e8da90a --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +UNAME_S != uname -s +OS = ${UNAME_S} + +.if ${UNAME_S} == "OpenBSD" +OS = openbsd +.elif ${UNAME_S} == "FreeBSD" +OS = freebsd +.endif + +NAME != cat main.c | grep "const char \*sofname" | awk '{print $$5}' |\ + sed "s/\"//g" | sed "s/;//" +VERSION != cat main.c | grep "const char \*version" | awk '{print $$5}' |\ + sed "s/\"//g" | sed "s/;//" + +PREFIX = /usr/local + +CC = cc +FILES = main.c src/*.c +# FILES = main.c + +CFLAGS = -Wall -Wextra \ + -I./dep/include -I/usr/include -I/usr/local/include -I/usr/X11R6/include \ + -L./dep/lib/${OS} -L/usr/lib -L/usr/local/lib -L/usr/X11R6/lib \ + -I/usr/X11R6/include/freetype2 -I/usr/local/include/freetype2 + +LDFLAGS = -lc -lX11 -lXft -lsys +SLIB = -lxcb -lthr -lfontconfig -lfreetype -lXrender -lXau -lXdmcp -lexpat -lintl \ + -lbz2 -lpng16 -lbrotlidec -lz -lm -lbrotlicommon + +all: debug + +debug: + ${CC} -O0 -g ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS} + lldb -o run ${NAME} + +develop: + ${CC} -O3 -g ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS} ${SLIB} + ./${NAME} + +release: + ${CC} -O3 ${CFLAGS} -o ${NAME} ${FILES} -static ${LDFLAGS} ${SLIB} + strip ${NAME} + ./${NAME} + +clean: + rm -rf ${NAME} *.core *.o + +install: + cp ${NAME} ${PREFIX}/bin + chmod +x ${PREFIX}/bin/${NAME} + +uninstall: + rm -rf ${PREFIX}/bin/${NAME} + +dist: + +.PHONY: all debug develop release clean install uninstall dist diff --git a/README.md b/README.md new file mode 100644 index 0000000..47640db --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# Unix Calc + +XLibre向け電卓。 +Xorg以外、従属ライブラリを使いません。 + +## インストールする方法 | Installation +### BSD +```sh +make +doas make install +``` + +### Linux +```sh +make +doas bmake install +``` + +![](scrot1.png)\ +![](scrot2.png) diff --git a/main.c b/main.c new file mode 100644 index 0000000..456c304 --- /dev/null +++ b/main.c @@ -0,0 +1,171 @@ +#include + +#include +#include "src/utils.h" +#include "src/control.h" + +XftColor color, btncolor; +Colormap colormap; +XftFont *font; +XftFont *prbfont; +XftFont *disfont; +Visual *visual; + +const char *sofname = "ucalc"; +const char *version = "0.0.0"; +const char *disname = "Unix Calc"; + +int main() { + Display *display; + Window window; + XEvent event; + int screen; + GC gc = NULL; + XGCValues values; + + display = XOpenDisplay(NULL); + if (display == NULL) { + fprintf(stderr, "画面を開けられません。\n"); + exit(1); + } + + screen = DefaultScreen(display); + + int sw = DisplayWidth(display, screen); + int sh = DisplayHeight(display, screen); + int window_x = (sw - window_width) / 3; + int window_y = (sh - window_height) / 2; + + window = XCreateSimpleWindow(display, RootWindow(display, screen), + window_x, window_y, window_width, window_height, 1, BTCOL, BGCOL); + if (!window) { + cleanup(display, window, gc, &color, &btncolor, font, disfont, prbfont, colormap, visual, backbuf); + fprintf(stderr, "ウィンドウを作成に失敗。\n"); + exit(1); + } + + backbuf = XCreatePixmap(display, window, window_width, window_height, DefaultDepth(display, screen)); + + Atom net_wm_window_type = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); + Atom dialog = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + + XChangeProperty(display, window, net_wm_window_type, XA_ATOM, 32, + PropModeReplace, (unsigned char *)&dialog, 1); + + XStoreName(display, window, disname); + Atom net_wm_name = XInternAtom(display, "_NET_WM_NAME", False); + char displayname[16]; + snprintf(displayname, 16, "%s %s", disname, version); + XChangeProperty(display, window, net_wm_name, + XInternAtom(display, "UTF8_STRING", False), 8, + PropModeReplace, (unsigned char *)displayname, strlen(displayname)); + + XClassHint *classHint = XAllocClassHint(); + if (classHint) { + classHint->res_name = "unixcalc"; + classHint->res_class = "UnixCalc"; + XSetClassHint(display, window, classHint); + XFree(classHint); + } + + XSetWindowBackground(display, window, BGCOL); + + XSelectInput(display, window, + ExposureMask + | ButtonPressMask + | ButtonReleaseMask + | KeyPressMask + // | PointerMotionMask + // | ButtonMotionMask + // | StructureNotifyMask + ); + + gc = XCreateGC(display, window, 0, &values); + if (!gc) { + cleanup(display, window, gc, &color, &btncolor, font, disfont, prbfont, colormap, visual, backbuf); + fprintf(stderr, "GCを作成に失敗。\n"); + exit(1); + } + + visual = DefaultVisual(display, screen); + + colormap = XCreateColormap(display, window, visual, AllocNone); + if (colormap == None) { + cleanup(display, window, gc, &color, &btncolor, font, disfont, prbfont, colormap, visual, backbuf); + fprintf(stderr, "カラーマップを作成に失敗。\n"); + exit(1); + } + + font = XftFontOpenName(display, screen, "Noto Sans CJK-12"); + if (!font) { + cleanup(display, window, gc, &color, &btncolor, font, disfont, prbfont, colormap, visual, backbuf); + fprintf(stderr, "フォントの読み込みに失敗。\n"); + exit(1); + } + + prbfont = XftFontOpenName(display, screen, "Noto Sans CJK-24"); + if (!prbfont) { + cleanup(display, window, gc, &color, &btncolor, font, disfont, prbfont, colormap, visual, backbuf); + fprintf(stderr, "問題フォントの読み込みに失敗。\n"); + exit(1); + } + + disfont = XftFontOpenName(display, screen, "Noto Sans CJK-72"); + if (!disfont) { + cleanup(display, window, gc, &color, &btncolor, font, disfont, prbfont, colormap, visual, backbuf); + fprintf(stderr, "解決フォントの読み込みに失敗。\n"); + exit(1); + } + + if (!XftColorAllocName(display, visual, colormap, "#232020", &color)) { + cleanup(display, window, gc, &color, &btncolor, font, disfont, prbfont, colormap, visual, backbuf); + fprintf(stderr, "色の役割に失敗。\n"); + exit(1); + } + + XMapWindow(display, window); + { + XWindowAttributes attr; + XGetWindowAttributes(display, window, &attr); + XEvent fake = { .type = Expose }; + fake.xexpose.window = window; + fake.xexpose.width = attr.width; + fake.xexpose.height = attr.height; + control_expose(display, window, gc, &event, &color, font, disfont, prbfont); + } + + while (isrunning) { + XNextEvent(display, &event); + + switch (event.type) { + case Expose: + case ConfigureNotify: + XClearWindow(display, window); + control_expose(display, window, gc, &event, &color, font, disfont, prbfont); + break; + case ButtonPress: + if (event.xbutton.button == Button1) { + handle_button_press(display, gc, event.xbutton.x, event.xbutton.y, &color, font); + break; + } + case ButtonRelease: + if (event.xbutton.button == Button1) { + handle_button_release(display, window, gc, event.xbutton.x, event.xbutton.y, &color, font, disfont, prbfont); + break; + } + case KeyPress: + handle_key_press(display, window, gc, &event, &color, font, disfont, prbfont); + break; + // case MotionNotify: + // handle_mouse_hover(display, window, gc, &event, &color, font); + // break; + case ClientMessage: + // WM_DELETE_WINDOW + break; + } + } + + cleanup(display, window, gc, &color, &btncolor, font, disfont, prbfont, colormap, visual, backbuf); + + return 0; +} diff --git a/scrot1.png b/scrot1.png new file mode 100644 index 0000000..6200fd8 Binary files /dev/null and b/scrot1.png differ diff --git a/scrot2.png b/scrot2.png new file mode 100644 index 0000000..18860f7 Binary files /dev/null and b/scrot2.png differ diff --git a/src/control.c b/src/control.c new file mode 100644 index 0000000..dff9fef --- /dev/null +++ b/src/control.c @@ -0,0 +1,389 @@ +#include +#include +#include + +#include "control.h" +#include "display.h" +#include "program.h" + +static const char *btn_labels[][10] = { + { NULL }, // 数字表示 + { "C", "±", "%", "÷" }, + { "7", "8", "9", "×" }, + { "4", "5", "6", "-" }, + { "1", "2", "3", "+" }, + { "0", ".", "=", "<" }, +}; + +#define NUM_ROWS 6 +#define NUM_COLS 6 + +static SuwaButton *find_button_at(int mx, int my) { + static SuwaButton found = {0}; + + int btn_w = 93; + int btn_h = 60; + int padding = 2; + + int row = -1; + int col = -1; + + for (int r = 1; r < NUM_ROWS; ++r) { + int y_start = 224 + (r - 1) * btn_h + padding; + if (my >= y_start && my < y_start + btn_h) { + row = r; + break; + } + } + + if (row < 0) return NULL; + + for (int c = 0; c < NUM_COLS; ++c) { + int x_start = padding + c * (btn_w + padding); + if (mx >= x_start && mx < x_start + btn_w) { + col = c; + break; + } + } + + if (col < 0) return NULL; + + found.x = padding + col * (btn_w + padding); + found.y = 224 + (row - 1) * (btn_h + padding); + found.width = btn_w; + found.height = btn_h; + found.label = btn_labels[row][col]; + found.pressed = 1; + + return &found; +} + +void append_to_input(char c) { + if ((unsigned long)input_pos >= sizeof(curinput) - 2) return; + strcpy(displayprb, ""); + curinput[input_pos++] = c; + curinput[input_pos] = '\0'; + + strncpy(displaytxt, curinput, sizeof(displaytxt) - 1); + displaytxt[sizeof(displaytxt) - 1] = '\0'; +} + +void clear_calculator(void) { + strcpy(displayprb, ""); + curinput[0] = '\0'; + input_pos = 0; + strcpy(displaytxt, "0"); +} + +double evaluate_simple(const char *expr) { + double res = 0.0; + double cur = 0.0; + char op = '+'; + int i = 0; + snprintf(displayprb, sizeof(displayprb), "%s=", expr); + + while (expr[i]) { + if (expr[i] == ' ') { i++; continue; } + + if (isdigit(expr[i]) || expr[i] == '.') { + char numbuf[32]; + int j = 0; + while (isdigit(expr[i]) || expr[i] == '.') { + if (j < 31) numbuf[j++] = expr[i]; + ++i; + } + numbuf[j] = '\0'; + cur = atof(numbuf); + } else { + if (op == '+') res += cur; + else if (op == '-') res -= cur; + else if (op == '*') res *= cur; + else if (op == '/') { + if (cur == 0) return NAN; + res /= cur; + } + + op = expr[i]; + ++i; + cur = 0.0; + } + } + + if (op == '+') res += cur; + else if (op == '-') res -= cur; + else if (op == '*') res *= cur; + else if (op == '/') { + if (cur == 0) return NAN; + res /= cur; + } + + return res; +} + +void control_expose(Display *dpy, Window wnd, GC gc, XEvent *e, XftColor *color, XftFont *f, XftFont *df, XftFont *pf) { + (void)color; + if (e->type != Expose && e->type != ConfigureNotify) return; + + XWindowAttributes attr; + XGetWindowAttributes(dpy, wnd, &attr); + int w = attr.width; + int h = attr.height; + + if (backbuf != None) { + XFreePixmap(dpy, backbuf); + } + + backbuf = XCreatePixmap(dpy, wnd, w, h, DefaultDepth(dpy, DefaultScreen(dpy))); + + if (backbuf == None) { + backbuf = wnd; + } + + XftDraw *backdraw = XftDrawCreate(dpy, backbuf, + DefaultVisual(dpy, DefaultScreen(dpy)), DefaultColormap(dpy, DefaultScreen(dpy))); + if (!backdraw) { + fprintf(stderr, "Pixmap向けXftDrawの作成に失敗。\n"); + XFreePixmap(dpy, backbuf); + backbuf = None; + return; + } + + XSetForeground(dpy, gc, BGCOL); + XFillRectangle(dpy, backbuf, gc, 0, 0, w, h); + + // 出力 + if (displaytxt[0] != '\0' && df) { + const FcChar8 *text = (const FcChar8 *)displaytxt; + int len = strlen((const char *)text); + + XGlyphInfo extents; + XftTextExtentsUtf8(dpy, df, text, len, &extents); + + int tx = w - 20 - extents.xOff; + int ty = 160; + + XftColor discol; + XftColorAllocName(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), + DefaultColormap(dpy, DefaultScreen(dpy)), + "#ee4030", &discol); + + XftDrawStringUtf8(backdraw, &discol, df, tx, ty, text, len); + + XftColorFree(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), + DefaultColormap(dpy, DefaultScreen(dpy)), &discol); + } + + if (displayprb[0] != '\0' && pf) { + const FcChar8 *text = (const FcChar8 *)displayprb; + int len = strlen((const char *)text); + + XGlyphInfo extents; + XftTextExtentsUtf8(dpy, pf, text, len, &extents); + + int tx = w - 20 - extents.xOff; + int ty = 80; + + XftColor discol; + XftColorAllocName(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), + DefaultColormap(dpy, DefaultScreen(dpy)), + "#b61729", &discol); + + XftDrawStringUtf8(backdraw, &discol, pf, tx, ty, text, len); + + XftColorFree(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), + DefaultColormap(dpy, DefaultScreen(dpy)), &discol); + } + + int width = 93; + int height = 60; + int padding = 2; + printf("ウィンドウ: (%dx%d)\n", attr.width, attr.height); + + for (int row = 0; row < 6; ++row) { + int y = 162 + row * (height + padding); + if (y + height > h) break; + + int cols = 4; + + for (int col = 0; col < cols; ++col) { + const char *label = btn_labels[row][col]; + if (!label) continue; + + int x = padding + col * (width + padding); + + SuwaButton btn; + btn.x = x; + btn.y = y; + btn.width = width; + btn.height = height; + btn.label = label; + btn.pressed = 0; + + drawbuttons(dpy, backbuf, gc, &btn, backdraw, color, f); + } + } + + XCopyArea(dpy, backbuf, wnd, gc, 0, 0, w, h, 0, 0); + XftDrawDestroy(backdraw); + XFlush(dpy); +} + +void handle_button_press(Display *dpy, GC gc, int mx, int my, XftColor *col, XftFont *f) { + SuwaButton *btn = find_button_at(mx, my); + if (!btn) return; + + btn->pressed = 1; + XftDraw *backdraw = XftDrawCreate(dpy, backbuf, + DefaultVisual(dpy, DefaultScreen(dpy)), DefaultColormap(dpy, DefaultScreen(dpy))); + if (!backdraw) { + fprintf(stderr, "Pixmap向けXftDrawの作成に失敗。\n"); + XFreePixmap(dpy, backbuf); + backbuf = None; + return; + } + + drawbuttons(dpy, backbuf, gc, btn, backdraw, col, f); + XFlush(dpy); +} + +void handle_button_release(Display *dpy, Window wnd, GC gc, int mx, int my, XftColor *col, XftFont *f, XftFont *df, XftFont *pf) { + SuwaButton *btn = find_button_at(mx, my); + if (!btn) return; + + btn->pressed = 0; + + XftDraw *backdraw = XftDrawCreate(dpy, backbuf, + DefaultVisual(dpy, DefaultScreen(dpy)), DefaultColormap(dpy, DefaultScreen(dpy))); + if (!backdraw) { + fprintf(stderr, "Pixmap向けXftDrawの作成に失敗。\n"); + XFreePixmap(dpy, backbuf); + backbuf = None; + return; + } + drawbuttons(dpy, backbuf, gc, btn, backdraw, col, f); + XftDrawDestroy(backdraw); + XFlush(dpy); + + const char *label = btn->label; + if (strcmp(label, "C") == 0) { + clear_calculator(); + } else if (strcmp(label, "<") == 0) { + curinput[--input_pos] = '\0'; + strcpy(displaytxt, curinput[0] ? curinput : "0"); + } else if (strcmp(label, "=") == 0) { + double res = evaluate_simple(curinput); + if (isnan(res)) { + strncpy(displaytxt, "Error", 5); + } else { + snprintf(displaytxt, sizeof(displaytxt), "%.8g", res); + strncpy(curinput, displaytxt, strlen(displaytxt)); + input_pos = strlen(curinput); + } + } else if (strlen(label) == 1) { + append_to_input(label[0]); + } + + control_expose(dpy, wnd, gc, &(XEvent){.type = Expose}, col, f, df, pf); +} + +void handle_key_press(Display *dpy, Window wnd, GC gc, XEvent *event, XftColor *col, XftFont *f, XftFont *df, XftFont *pf) { + KeySym keysym; + char buf[32]; + int len; + (void)len; + + keysym = XLookupKeysym(&event->xkey, 0); + len = XLookupString(&event->xkey, buf, sizeof(buf), &keysym, NULL); + + if (keysym == XK_Q) { + isrunning = 0; + return; + } + + if (keysym == XK_B) { + puts("標準電卓画面"); + } + + if (keysym == XK_S) { + puts("関数電卓画面"); + } + + if (keysym == XK_P) { + puts("プログラマー電卓画面"); + } + + if (keysym == XK_H) { + puts("履歴画面"); + } + + if (keysym == XK_h) { + puts("ヘルプ画面"); + puts("-----"); + puts("Q = 終了 Exit"); + puts("X = 1文字の消し Remove 1 character"); + puts("C = クリ了 Clear"); + puts("h = ヘルプ画面 Help screen"); + puts("H = 履歴画面 History screen"); + puts("B = 標準電卓画面 Basic calculator screen"); + puts("S = 関数電卓画面 Scientific calculator screen"); + puts("P = プログラマー電卓画面 Programmer calculator screen"); + } + + if (keysym == XK_C) { + clear_calculator(); + goto redraw; + } + + if (keysym == XK_Return || keysym == XK_KP_Enter) { + double res = evaluate_simple(curinput); + if (isnan(res)) { + strncpy(displaytxt, "Error", 5); + } else { + snprintf(displaytxt, sizeof(displaytxt), "%.8g", res); + } + goto redraw; + } + + if ((keysym == XK_BackSpace && input_pos > 0) + || (keysym == XK_Delete && input_pos > 0) + || (keysym == XK_X && input_pos > 0)) { + curinput[--input_pos] = '\0'; + strcpy(displaytxt, curinput[0] ? curinput : "0"); + goto redraw; + } + + char c = 0; + if (keysym >= XK_0 && keysym <= XK_9) c = '0' + (keysym - XK_0); + else if (keysym >= XK_KP_0 && keysym <= XK_KP_9) c = '0' + (keysym - XK_0); + else if (keysym == XK_KP_Add || keysym == XK_plus) c = '+'; + else if (keysym == XK_KP_Subtract || keysym == XK_minus) c = '-'; + else if (keysym == XK_KP_Multiply || keysym == XK_asterisk) c = '*'; + else if (keysym == XK_KP_Divide || keysym == XK_slash) c = '/'; + else if (keysym == XK_KP_Decimal || keysym == XK_period) c = '.'; + + if (c) { + append_to_input(c); + goto redraw; + } + + return; + +redraw: + control_expose(dpy, wnd, gc, &(XEvent){.type = Expose}, col, f, df, pf); +} + +// void handle_mouse_hover(Display *dpy, Window wnd, GC gc, XEvent *event, XftColor *col, XftFont *f) { +// SuwaButton *hover = find_button_at(event->xmotion.x, event->xmotion.y); + +// if (hover != hovered_btn) { +// if (hovered_btn) { +// hovered_btn->pressed = 0; +// redraw_single_button(dpy, wnd, gc, col, f, hovered_btn); +// } +// hovered_btn = hover; + +// if (hovered_btn) { +// redraw_single_button(dpy, wnd, gc, col, f, hovered_btn); +// } +// } +// } diff --git a/src/control.h b/src/control.h new file mode 100644 index 0000000..e313856 --- /dev/null +++ b/src/control.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +void control_expose(Display *dpy, Window wnd, GC gc, XEvent *event, XftColor *color, XftFont *f, XftFont *df, XftFont *pf); +void handle_button_press(Display *dpy, GC gc, int mx, int my, XftColor *col, XftFont *f); +void handle_button_release(Display *dpy, Window wnd, GC gc, int mx, int my, XftColor *col, XftFont *f, XftFont *df, XftFont *pf); +void handle_key_press(Display *dpy, Window wnd, GC gc, XEvent *event, XftColor *col, XftFont *f, XftFont *df, XftFont *pf); +void handle_mouse_hover(Display *dpy, Window wnd, GC gc, XEvent *event, XftColor *col, XftFont *f); diff --git a/src/display.c b/src/display.c new file mode 100644 index 0000000..0080708 --- /dev/null +++ b/src/display.c @@ -0,0 +1,30 @@ +#include "display.h" +#include "program.h" + +#include + +void drawbuttons(Display *dpy, Drawable target, GC gc, SuwaButton *btn, + XftDraw *xftdraw, XftColor *textcolor, XftFont *font) { + unsigned long curbg = btn->pressed ? BTSEL : BTCOL; + XSetForeground(dpy, gc, curbg); + XFillRectangle(dpy, target, gc, btn->x, btn->y, btn->width, btn->height); + + // 文字の中央に + if (btn->label && font && xftdraw) { + const FcChar8 *str = (const FcChar8 *)btn->label; + int len = strlen((const char *)str); + + XGlyphInfo extents; + XftTextExtentsUtf8(dpy, font, str, len, &extents); + + int text_w = extents.xOff; + int text_h = font->ascent + font->descent; + + int tx = btn->x + (btn->width - text_w) / 2; + int ty = btn->y + (btn->height - text_h) / 2 + font->ascent; + + // tx -= extents.x; + + XftDrawStringUtf8(xftdraw, textcolor, font, tx, ty, (FcChar8 *)btn->label, len); + } +} diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..f164249 --- /dev/null +++ b/src/display.h @@ -0,0 +1,6 @@ +#pragma once + +#include "program.h" + +void drawbuttons(Display *dpy, Drawable target, GC gc, SuwaButton *btn, + XftDraw *xftdraw, XftColor *textcolor, XftFont *font); diff --git a/src/program.c b/src/program.c new file mode 100644 index 0000000..0e8805c --- /dev/null +++ b/src/program.c @@ -0,0 +1,12 @@ +#include "program.h" + +int window_width = 382; +int window_height = 534; +int isrunning = 1; +char displayprb[128] = ""; +char curinput[256] = {0}; +char displaytxt[64] = "0"; +int input_pos = 0; +Pixmap backbuf = None; +SuwaButton *hovered_btn = NULL; +SuwaButton *pressed_btn = NULL; diff --git a/src/program.h b/src/program.h new file mode 100644 index 0000000..67b0dc2 --- /dev/null +++ b/src/program.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include "ui.h" + +#define FGCOL 0xfcfcfc +#define BGCOL 0x232020 +#define BTSEL 0xb61729 +#define BTCOL 0xee4030 +#define BTHVR 0xf35869 + +extern int window_width; +extern int window_height; +extern int isrunning; +extern char displayprb[128]; +extern char curinput[256]; +extern char displaytxt[64]; +extern int input_pos; +extern Pixmap backbuf; +extern SuwaButton *hovered_btn; +extern SuwaButton *pressed_btn; diff --git a/src/ui.h b/src/ui.h new file mode 100644 index 0000000..7a3236f --- /dev/null +++ b/src/ui.h @@ -0,0 +1,7 @@ +#pragma once + +typedef struct { + int x, y, width, height; + const char *label; + int pressed; // 0 = 普通、1 = 押している +} SuwaButton; diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..db9a542 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,19 @@ +#include "utils.h" + +void cleanup(Display *display, Window window, GC gc, + XftColor *color, XftColor *btncolor, XftFont *font, + XftFont *disfont, XftFont *prbfont, Colormap colormap, Visual *visual, + Pixmap backbuf) { + if (btncolor) XftColorFree(display, visual, colormap, btncolor); + if (color) XftColorFree(display, visual, colormap, color); + if (disfont) XftFontClose(display, disfont); + if (prbfont) XftFontClose(display, prbfont); + if (font) XftFontClose(display, font); + if (gc) XFreeGC(display, gc); + if (backbuf) { + XFreePixmap(display, backbuf); + backbuf = None; + } + if (window) XDestroyWindow(display, window); + if (display) XCloseDisplay(display); +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..fdf356f --- /dev/null +++ b/src/utils.h @@ -0,0 +1,8 @@ +#pragma once + +#include "program.h" + +void cleanup(Display *display, Window window, GC gc, + XftColor *color, XftColor *btncolor, XftFont *font, + XftFont *disfont, XftFont *prbfont, Colormap colormap, Visual *visual, + Pixmap backbuf);