SVNからのミラー
This commit is contained in:
7
CHANGELOG.md
Normal file
7
CHANGELOG.md
Normal 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
13
LICENSE.txt
Normal 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
97
Makefile
Normal 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
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# um
|
||||
只のランチャー。
|
||||
|
||||
Xorg以外、従属ライブラリを使いません。
|
||||
|
||||
## インストールする方法 | Installation
|
||||
### BSD
|
||||
```sh
|
||||
make
|
||||
doas make install
|
||||
```
|
||||
|
||||
### Linux
|
||||
```sh
|
||||
bmake
|
||||
doas bmake install
|
||||
```
|
||||
|
||||

|
||||
|
||||

|
||||
1
fonts.scale
Normal file
1
fonts.scale
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
114
main.c
Normal file
114
main.c
Normal 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
BIN
scrot1.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 401 KiB |
BIN
scrot2.png
Executable file
BIN
scrot2.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 402 KiB |
91
src/control.c
Normal file
91
src/control.c
Normal 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
12
src/control.h
Normal 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
46
src/display.c
Normal 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
21
src/display.h
Normal 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
138
src/parser.c
Normal 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
13
src/parser.h
Normal 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
70
src/program.c
Normal 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
35
src/program.h
Normal 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
98
src/utils.c
Normal 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
28
src/utils.h
Normal 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
10
um.desktop
Normal 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;
|
||||
Reference in New Issue
Block a user