SVNからのミラー

This commit is contained in:
2026-01-06 21:47:05 +09:00
commit 7603358afe
20 changed files with 816 additions and 0 deletions

7
CHANGELOG.md Normal file
View File

@@ -0,0 +1,7 @@
# 0.2.0 (2025/07/07)
* .desktopファイルがなければ、$PATHから実効してみる様に
* um.desktopファイルの追加
* CLI用プログラムの場合は端末にラウンチする様に
# 0.1.0 (2024/09/16)
* 開始

13
LICENSE.txt Normal file
View File

@@ -0,0 +1,13 @@
Copyright © 2018-2024 by 076.moe
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

97
Makefile Normal file
View File

@@ -0,0 +1,97 @@
UNAME_S != uname -s
UNAME_M != uname -m
OS = ${UNAME_S}
ARCH = ${UNAME_M}
.if ${UNAME_S} == "OpenBSD"
OS = openbsd
.elif ${UNAME_S} == "NetBSD"
OS = netbsd
.elif ${UNAME_S} == "FreeBSD"
OS = freebsd
.elif ${UNAME_S} == "Dragonfly"
OS = dragonfly
.elif ${UNAME_S} == "Linux"
OS = linux
.endif
.if ${UNAME_M} == "x86_64"
ARCH = amd64
.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
.if ${OS} == "linux"
PREFIX = /usr
.endif
CC = cc
FILES = main.c src/*.c
CFLAGS = -Wall -Wextra -I/usr/include -L/usr/lib
.if ${OS} == "netbsd"
CFLAGS += -I/usr/X11R7/include -I/usr/X11R7/include/freetype2 -L/usr/X11R7/lib
.elif ${OS} == "openbsd"
CFLAGS += -I/usr/X11R6/include -I/usr/X11R6/include/freetype2 -L/usr/X11R6/lib
.elif ${OS} == "freebsd"
CFLAGS += -I/usr/local/include -I/usr/local/include/X11\
-I /usr/local/include/freetype2\
-L/usr/local/lib
.elif ${OS} == "linux"
CFLAGS += -I/usr/include/freetype2
.endif
LDFLAGS = -lc -lX11 -lXft
SLIB = -lxcb
.if ${OS} == "openbsd"
SLIB += -lfontconfig -lz -lexpat -lfreetype -lXrender -lXau -lXdmcp
.elif ${OS} == "freebsd"
SLIB += -lthr -lfontconfig -lfreetype -lXrender -lXau -lXdmcp -lexpat -lz -lbz2\
-lpng16 -lbrotlidec -lm -lbrotlicommon
.elif ${OS} == "netbsd"
SLIB += -lfontconfig -lfreetype -lXau -lXdmcp -lgcc -lexpat -lz -lbz2 -lXrandr\
-lXrender -lXext -lX11
.elif ${OS} == "linux"
SLIB += -lfontconfig -lfreetype -lXrender -lXau -lXdmcp -lX11\
-lexpat -lpng16 -lbz2 -lz\
-lbrotlidec -lbrotlicommon
.endif
all:
${CC} -O3 ${CFLAGS} -o ${NAME} ${FILES} -static ${LDFLAGS} ${SLIB}
strip ${NAME}
debug:
${CC} -g ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS}
clean:
rm -rf ${NAME}
dist:
mkdir -p ${NAME}-${VERSION} release/src
cp -R LICENSE.txt Makefile README.md CHANGELOG.md\
main.c ${NAME}.desktop ${NAME}-${VERSION}
tar zcfv release/src/${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION}
rm -rf ${NAME}-${VERSION}
release:
mkdir -p release/bin/${VERSION}/${OS}/${ARCH}
${CC} -O3 ${CFLAGS} -o release/bin/${VERSION}/${OS}/${ARCH}/${NAME} ${FILES}\
-static ${LDFLAGS} ${SLIB}
strip release/bin/${VERSION}/${OS}/${ARCH}/${NAME}
install:
mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${PREFIX}/share/applications
cp -f ${NAME} ${DESTDIR}${PREFIX}/bin
cp -f ${NAME}.desktop ${DESTDIR}${PREFIX}/share/applications
chmod 644 ${DESTDIR}${PREFIX}/share/applications/${NAME}.desktop
chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME}
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/${NAME}
.PHONY: all debug clean dist release install uninstall

21
README.md Normal file
View File

@@ -0,0 +1,21 @@
# um
只のランチャー。
Xorg以外、従属ライブラリを使いません。
## インストールする方法 | Installation
### BSD
```sh
make
doas make install
```
### Linux
```sh
bmake
doas bmake install
```
![](scrot1.png)
![](scrot2.png)

1
fonts.dir Normal file
View File

@@ -0,0 +1 @@
0

1
fonts.scale Normal file
View File

@@ -0,0 +1 @@
0

114
main.c Normal file
View File

@@ -0,0 +1,114 @@
#include <stdio.h>
#include <stdlib.h>
#include "src/control.h"
#include "src/program.h"
#include "src/display.h"
#include "src/parser.h"
#include "src/utils.h"
XftColor color, selcolor;
Colormap colormap;
XftDraw *draw;
XftFont *font;
Visual *visual;
const char *sofname = "um";
const char *version = "0.2.0";
int main() {
Display *display;
Window window;
XEvent event;
int screen;
GC gc = NULL;
XGCValues values;
char input[MAX_NAME_LEN] = {0};
int sel = 0;
fetch_programs();
display = XOpenDisplay(NULL);
if (display == NULL) {
fprintf(stderr, "画面を開けられません。\n");
exit(1);
}
screen = DefaultScreen(display);
int screen_width = DisplayWidth(display, screen);
int screen_height = DisplayHeight(display, screen);
window_width = screen_width / 4;
window_height = screen_height / 4;
int window_x = (screen_width - window_width) / 2;
int window_y = (screen_height - window_height) / 2;
window = XCreateSimpleWindow(display, RootWindow(display, screen),
window_x, window_y, window_width, window_height, 1, BLACK, BLACK);
if (!window) {
cleanup(display, window, gc, &color, &selcolor, draw, font, colormap, visual);
}
XSetWindowBackground(display, window, BGCOL);
XSelectInput(display, window,
ExposureMask | KeyPressMask | StructureNotifyMask | ButtonPressMask);
gc = XCreateGC(display, window, 0, &values);
if (!gc) {
cleanup(display, window, gc, &color, &selcolor, draw, font, colormap, visual);
fprintf(stderr, "GCを作れません。\n");
exit(1);
}
visual = DefaultVisual(display, screen);
colormap = XCreateColormap(display, window, visual, AllocNone);
if (colormap == None) {
cleanup(display, window, gc, &color, &selcolor, draw, font, colormap, visual);
fprintf(stderr, "カラーマップを作れません。\n");
exit(1);
}
draw = XftDrawCreate(display, window, visual, colormap);
if (!draw) {
cleanup(display, window, gc, &color, &selcolor, draw, font, colormap, visual);
fprintf(stderr, "ドローを作れません。\n");
exit(1);
}
font = XftFontOpenName(display, screen, "Noto Sans CJK-12");
if (!font) {
cleanup(display, window, gc, &color, &selcolor, draw, font, colormap, visual);
fprintf(stderr, "フォントの読み込みに失敗。\n");
exit(1);
}
if (!XftColorAllocName(display, visual, colormap, "white", &color)) {
cleanup(display, window, gc, &color, &selcolor, draw, font, colormap, visual);
fprintf(stderr, "色の役割に失敗。\n");
}
if (!XftColorAllocName(display, visual, colormap, "black", &selcolor)) {
cleanup(display, window, gc, &color, &selcolor, draw, font, colormap, visual);
fprintf(stderr, "選択色の役割に失敗。\n");
}
XMapWindow(display, window);
while (1) {
XNextEvent(display, &event);
if (event.type == Expose || event.type == ConfigureNotify) {
control_expose(display, window, gc, &event, input, &sel);
} else if (event.type == KeyPress) {
control_keypress(display, window, gc, &event, input, &sel);
} else if (event.type == ButtonPress) {
control_buttonpress(&event, programs, item_height);
}
}
cleanup(display, window, gc, &color, &selcolor, draw, font, colormap, visual);
return 0;
}

BIN
scrot1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

BIN
scrot2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

91
src/control.c Normal file
View File

@@ -0,0 +1,91 @@
#include "control.h"
#include "display.h"
#include "utils.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void control_expose(
Display *display, Window window, GC gc, XEvent *event, char *input, int *sel) {
if (event->type == ConfigureNotify)
calculate_dimensions(event->xconfigure.width, event->xconfigure.height);
filterdisplay(display, window, gc, input, *sel);
}
void control_keypress(
Display *display, Window window, GC gc, XEvent *event, char *input, int *sel) {
char buf[32];
KeySym keysym;
int len = XLookupString(&event->xkey, buf, sizeof(buf) - 1, &keysym, NULL);
if (keysym == XK_Up) {
if (*sel > 0) {
(*sel)--;
if (*sel < topidx) topidx--;
}
} else if (keysym == XK_Down) {
int filteredcount = filtercount(input);
if (*sel < filteredcount - 1) {
(*sel)++;
if (*sel >= topidx + display_items) topidx++;
}
} else if (keysym == XK_Page_Up) {
if (*sel > 0) {
*sel -= display_items;
if (*sel < topidx) topidx -= display_items;
}
} else if (keysym == XK_Page_Down) {
int filteredcount = filtercount(input);
if (*sel < filteredcount - 1) {
*sel += display_items;
if (*sel >= topidx + display_items) topidx += display_items;
}
} else if (keysym == XK_BackSpace && strlen(input) > 0) {
input[strlen(input) - 1] = '\0';
*sel = 0;
topidx = 0;
} else if (keysym == XK_Return) {
int visible_index = 0;
int found = 0;
for (int i = 0; i < programcount; i++) {
if (!strcasestr(programs[i].name, input)) continue;
if (visible_index == *sel) {
launch_program(programs[i].exec, programs[i].term);
found = 1;
break;
}
visible_index++;
}
if (found == 0 && launch_path(input)) {
launch_program(input, "false");
}
exit(0);
} else if (keysym == XK_Escape) {
exit(0);
} else if (len > 0 && len < MAX_NAME_LEN - 1) {
strncat(input, buf, len);
*sel = 0;
topidx = 0;
}
filterdisplay(display, window, gc, input, *sel);
}
void control_buttonpress(XEvent *event, Program *programs, int item_height) {
int x = event->xbutton.x;
int y = event->xbutton.y;
for (int i = 0; i < programcount; i++) {
if (
x >= programs[i].x &&
x <= programs[i].x + programs[i].width &&
y >= programs[i].y - item_height &&
y <= programs[i].y
) {
launch_program(programs[i].exec, programs[i].term);
break;
}
}
}

12
src/control.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef CONTROL_H
#define CONTROL_H
#include "program.h"
void control_expose(
Display *display, Window window, GC gc, XEvent *event, char *input, int *sel);
void control_keypress(
Display *display, Window window, GC gc, XEvent *event, char *input, int *sel);
void control_buttonpress(XEvent *event, Program *programs, int item_height);
#endif

46
src/display.c Normal file
View File

@@ -0,0 +1,46 @@
#include "display.h"
#include <string.h>
int topidx = 0;
void drawtext(
Display *display, Window window, GC gc, int x, int y, const char *text, int sel) {
if (sel) {
XSetForeground(display, gc, BLACK);
XFillRectangle(
display, window, gc, 0, y - item_height + 5, window_width, item_height);
XSetForeground(display, gc, BLACK);
} else {
XSetForeground(display, gc, WHITE);
}
XftDrawStringUtf8(draw, &color, font, x, y, (const FcChar8 *)text, strlen(text));
}
void filterdisplay(
Display *display,
Window window,
GC gc,
const char *input,
int sel
) {
XClearWindow(display, window);
// 検索ボックス
drawtext(display, window, gc, 10, item_height, input, 0);
int y = item_height * 2;
int idx = 0;
for (int i = 0; i < programcount; i++) {
if (!strcasestr(programs[i].name, input) && !strcasestr(programs[i].keys, input))
continue;
if (idx >= topidx && idx < topidx + display_items) {
drawtext(display, window, gc, 10, y, programs[i].name, idx == sel);
y += item_height;
}
idx++;
}
}

21
src/display.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef DISPLAY_H
#define DISPLAY_H
#include "program.h"
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
void drawtext(
Display *display, Window window, GC gc, int x, int y, const char *text, int sel);
void filterdisplay(
Display *display, Window window, GC gc, const char *input, int sel);
extern XftColor color, selcolor;
extern Colormap colormap;
extern XftDraw *draw;
extern XftFont *font;
extern Visual *visual;
extern int topidx;
#endif

138
src/parser.c Normal file
View File

@@ -0,0 +1,138 @@
#include "parser.h"
#include "utils.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
bool foundName = false;
bool foundKey = false;
bool foundExec = false;
bool isDesktopEntry = false;
void parse_name(char *line, Program *program) {
if (foundName) return;
if (strncmp(line, "Name[", 5) == 0) {
char *locale = line + 5;
char *end = strchr(locale, ']');
if (!end) return;
*end = '\0';
if (strncmp(locale, getenv("LANG"), 2) != 0) return;
if (!isdup(end + 2)) {
strncpy(program->name, end + 2, MAX_NAME_LEN - 1);
program->name[strcspn(program->name, "\n")] = '\0';
}
add_to_dup(end + 2);
foundName = true;
} else {
if (!isdup(line + 5)) {
strncpy(program->name, line + 5, MAX_NAME_LEN - 1);
program->name[strcspn(program->name, "\n")] = '\0';
}
add_to_dup(line + 5);
foundName = true;
}
}
void parse_keywords(char *line, Program *program) {
if (foundKey) return;
size_t len = strnlen(line + 9, MAX_NAME_LEN - 1);
strncpy(program->keys, line + 9, len);
program->keys[len] = '\0';
program->keys[strcspn(program->keys, "\n")] = '\0';
foundKey = true;
}
void parse_exec(char *line, Program *program) {
if (foundExec) return;
size_t len = strnlen(line + 5, MAX_NAME_LEN - 1);
strncpy(program->exec, line + 5, len);
program->exec[strcspn(program->exec, "\n")] = '\0';
char *p = program->exec;
while ((p = strpbrk(p, "%")) != NULL) {
*p = '\0';
size_t rspace = MAX_NAME_LEN - strlen(program->exec) - 1;
if (rspace > 0) {
strncat(program->exec, p + 2, rspace);
}
}
foundExec = true;
}
void parse_term(char *line, Program *program) {
size_t len = strnlen(line + 9, MAX_NAME_LEN - 1);
strncpy(program->term, line + 9, len);
program->term[strcspn(program->term, "\n")] = '\0';
char *p = program->term;
while ((p = strpbrk(p, "%")) != NULL) {
*p = '\0';
size_t rspace = MAX_NAME_LEN - strlen(program->term) - 1;
if (rspace > 0) {
strncat(program->term, p + 2, rspace);
}
}
}
void parse_desktop_file(const char *filepath) {
FILE *file = fopen(filepath, "r");
if (!file) return;
char line[MAX_NAME_LEN * 2];
Program program = {0};
while (fgets(line, sizeof(line), file)) {
if (strncmp(line, "Name=", 5) == 0 || strncmp(line, "Name[", 5) == 0) {
parse_name(line, &program);
} else if (strncmp(line, "Keywords=", 9) == 0) {
parse_keywords(line, &program);
} else if (strncmp(line, "Exec=", 5) == 0) {
parse_exec(line, &program);
} else if (strncmp(line, "Terminal=", 9) == 0) {
parse_term(line, &program);
}
}
fclose(file);
if (program.name[0] && program.exec[0]) {
programs[programcount++] = program;
}
}
void scan_desktop_files(const char *directory) {
DIR *dir = opendir(directory);
if (!dir) return;
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcasestr(entry->d_name, ".desktop")) {
size_t filepath_len = strlen(directory) + strlen(entry->d_name) + 2;
char *filepath = malloc(filepath_len);
if (!filepath) {
closedir(dir);
return;
}
snprintf(filepath, filepath_len, "%s/%s", directory, entry->d_name);
if (isdis(filepath)) parse_desktop_file(filepath);
isDesktopEntry = false;
foundName = false;
foundKey = false;
foundExec = false;
free(filepath);
}
}
closedir(dir);
}

13
src/parser.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef PARSER_H
#define PARSER_H
#include "program.h"
void parse_name(char *line, Program *program);
void parse_keywords(char *line, Program *program);
void parse_exec(char *line, Program *program);
void parse_term(char *line, Program *program);
void parse_desktop_file(const char *filepath);
void scan_desktop_files(const char *directory);
#endif

70
src/program.c Normal file
View File

@@ -0,0 +1,70 @@
#include "program.h"
#include "parser.h"
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
Program programs[MAX_ITEMS];
int programcount = 0;
int window_width = 300;
int window_height = 240;
int item_height = 20;
int display_items = 10;
void fetch_programs() {
char *xdg_data_home = getenv("XDG_DATA_HOME");
if (!xdg_data_home) {
xdg_data_home = getenv("HOME");
if (xdg_data_home) {
char path[MAX_NAME_LEN];
snprintf(path, sizeof(path), "%s/.local/share/applications", xdg_data_home);
scan_desktop_files(path);
}
} else {
char path[MAX_NAME_LEN];
snprintf(path, sizeof(path), "%s/applications", xdg_data_home);
scan_desktop_files(path);
}
scan_desktop_files("/usr/share/applications");
scan_desktop_files("/usr/local/share/applications");
#if defined(__NetBSD__)
scan_desktop_files("/usr/pkg/share/applications");
#endif
}
void launch_program(const char *exec, const char *term) {
if (fork() == 0) {
setsid();
if (strncmp(term, "true", 4) == 0) {
char *terminal = getenv("TERMINAL");
if (!terminal) terminal = "xterm";
execlp(terminal, terminal, "-e", exec, NULL);
} else {
execl("/bin/sh", "sh", "-c", exec, NULL);
}
exit(0);
}
}
int filtercount(const char *input) {
int count = 0;
for (int i = 0; i < programcount; i++) {
if (strcasestr(programs[i].name, input) || strcasestr(programs[i].keys, input))
count++;
}
return count;
}
void calculate_dimensions(int win_width, int win_height) {
window_width = win_width;
window_height = win_height;
item_height = win_height / (display_items + 2);
}

35
src/program.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef PROGRAM_H
#define PROGRAM_H
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#define MAX_ITEMS 512
#define MAX_NAME_LEN 256
#define MAX_LINE_LENGTH 256
#define WHITE 0xfcfcfc
#define BLACK 0x120f12
#define BGCOL 0x550f75
typedef struct {
char name[MAX_NAME_LEN];
char keys[MAX_NAME_LEN];
char exec[MAX_NAME_LEN];
char term[MAX_NAME_LEN];
int x, y, width, height;
} Program;
void fetch_programs();
void launch_program(const char *exec, const char *term);
int filtercount(const char *input);
void calculate_dimensions(int win_width, int win_height);
extern Program programs[MAX_ITEMS];
extern int programcount;
extern int window_width;
extern int window_height;
extern int item_height;
extern int display_items;
#endif

98
src/utils.c Normal file
View File

@@ -0,0 +1,98 @@
#include "utils.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#if defined(__linux__)
#include <string.h>
#include <ctype.h>
#endif
Dup dupn[MAX_NAME_LEN * 2];
int dupcnt = 0;
#if defined(__linux__)
#include <string.h>
char *strcasestr(const char *haystack, const char *needle) {
size_t needle_len = strlen(needle);
if (needle_len == 0) {
return (char *)haystack;
}
while (*haystack) {
if (strncasecmp(haystack, needle, needle_len) == 0) {
return (char *)haystack;
}
haystack++;
}
return NULL;
}
#endif
int isdup(const char *name) {
for (int i = 0; i < dupcnt; i++) {
if (strncmp(dupn[i].name, name, strlen(name)) == 0) return 1;
}
return 0;
}
int isdis(const char *filepath) {
FILE *file = fopen(filepath, "r");
if (!file) return 0;
char line[MAX_LINE_LENGTH];
while (fgets(line, sizeof(line), file)) {
if (strstr(line, "NoDisplay=true")) {
fclose(file);
return 0;
}
}
fclose(file);
return 1;
}
void add_to_dup(const char *name) {
if (dupcnt < (MAX_NAME_LEN * 2)) {
strncpy(dupn[dupcnt].name, name, MAX_NAME_LEN - 1);
dupn[dupcnt].name[MAX_NAME_LEN - 1] = '\0';
dupcnt++;
}
}
int launch_path(const char *exec) {
char *path = getenv("PATH");
if (!path) return 1;
char *pdup = strdup(path);
char *dir = strtok(pdup, ":");
while (dir != NULL) {
char fp[1024];
snprintf(fp, sizeof(fp), "%s/%s", dir, exec);
if (access(fp, X_OK) == 0) {
free(pdup);
return 1;
}
dir = strtok(NULL, ":");
}
free(pdup);
return 0;
}
void cleanup(Display *display, Window window, GC gc, XftColor *color,
XftColor *selcolor, XftDraw *draw, XftFont *font,
Colormap colormap, Visual *visual) {
if (color) XftColorFree(display, visual, colormap, color);
if (selcolor) XftColorFree(display, visual, colormap, selcolor);
if (font) XftFontClose(display, font);
if (draw) XftDrawDestroy(draw);
if (gc) XFreeGC(display, gc);
if (window) XDestroyWindow(display, window);
if (display) XCloseDisplay(display);
}

28
src/utils.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef UTILS_H
#define UTILS_H
#include "program.h"
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
typedef struct {
char name[MAX_NAME_LEN];
} Dup;
extern Dup dupn[MAX_NAME_LEN * 2];
extern int dupcnt;
#if defined(__linux__)
char *strcasestr(const char *haystack, const char *needle);
#endif
int isdup(const char *name);
int isdis(const char *filepath);
void add_to_dup(const char *name);
int launch_path(const char *exec);
void cleanup(Display *display, Window window, GC gc,
XftColor *color, XftColor *selcolor, XftDraw *draw, XftFont *font,
Colormap colormap, Visual *visual);
#endif

10
um.desktop Normal file
View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Application
Name=um
GenericName=Just launcher
GenericName[ja]=只のラウンチャー
Exec=um %F
StartupNotify=true
Terminal=false
Type=Application
Categories=Application;Utility;System;DeskopUtility;