summaryrefslogtreecommitdiffstats
path: root/xlnch.c
diff options
context:
space:
mode:
authorgramanas <anastasis.gramm2@gmail.com>2020-07-20 19:30:46 +0300
committergramanas <anastasis.gramm2@gmail.com>2020-07-20 19:30:46 +0300
commit2b31f69a1a17e153adb08d9a0ad125972e957971 (patch)
tree13797fb470179e3e78a8e7b15c31db5070728902 /xlnch.c
downloadxlnch-2b31f69a1a17e153adb08d9a0ad125972e957971.tar.gz
xlnch-2b31f69a1a17e153adb08d9a0ad125972e957971.tar.bz2
xlnch-2b31f69a1a17e153adb08d9a0ad125972e957971.zip
Initial
Diffstat (limited to 'xlnch.c')
-rw-r--r--xlnch.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/xlnch.c b/xlnch.c
new file mode 100644
index 0000000..81dcf64
--- /dev/null
+++ b/xlnch.c
@@ -0,0 +1,362 @@
+/**
+ * xlnch -- D e s c r i p t i o n
+ * Copyright (C) 2019 Anastasis Grammenos
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* Basic X code from:
+ * Brian Hammond 2/9/96. http://mech.math.msu.su/~nap/2/GWindow/xintro.html
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <sys/wait.h>
+
+#include <wordexp.h>
+
+
+Display *dis;
+int screen;
+Window win;
+GC gc;
+
+Colormap cm;
+XColor red;
+
+void init_x()
+{
+ /* get the colors black and white (see section for details) */
+ unsigned long black,white;
+
+ /* use the information from the environment variable DISPLAY
+ to create the X connection:
+ */
+ dis=XOpenDisplay((char *)0);
+ screen=DefaultScreen(dis);
+ black=BlackPixel(dis,screen);
+ white=WhitePixel(dis, screen);
+
+ /* once the display is initialized, create the window.
+ This window will be have be 200 pixels across and 300 down.
+ It will have the foreground white and background black
+ */
+ win=XCreateSimpleWindow(dis,DefaultRootWindow(dis),0,0,
+ 200, 300, 1, white, black);
+
+ /* here is where some properties of the window can be set.
+ The third and fourth items indicate the name which appears
+ at the top of the window and the name of the minimized window
+ respectively.
+ */
+ XSetStandardProperties(dis,win,"xlnch","xlnch",None,NULL,0,NULL);
+
+ XClassHint *hint = XAllocClassHint();
+ if (hint) {
+ hint->res_name = "xlnch";
+ hint->res_class = "xlnch";
+ }
+ XSetClassHint(dis,win,hint);
+ XFree(hint);
+
+ /* this routine determines which types of input are allowed in
+ the input. see the appropriate section for details...
+ */
+ XSelectInput(dis, win, ExposureMask|ButtonPressMask|KeyPressMask);
+
+ /* create the Graphics Context */
+ gc=XCreateGC(dis, win, 0,0);
+
+ /* here is another routine to set the foreground and background
+ colors _currently_ in use in the window.
+ */
+ XSetBackground(dis,gc,black);
+ XSetForeground(dis,gc,white);
+
+ cm = DefaultColormap(dis, screen);
+ if (! XAllocNamedColor(dis, cm, "red", &red, &red)) {
+ fprintf(stderr, "XAllocNamedColor - failed to allocated 'red' color.\n");
+ exit(1);
+ }
+
+ /* Font font = XLoadFont(dis,"*mono*"); */
+ /* XSetFont(dis,gc,font); */
+
+ /* clear the window and bring it on top of the other windows */
+ XClearWindow(dis, win);
+ XMapRaised(dis, win);
+}
+
+void close_x()
+{
+ XFreeGC(dis, gc);
+ XDestroyWindow(dis,win);
+ XCloseDisplay(dis);
+}
+
+
+#define BUF_SIZE 2048
+char buf[BUF_SIZE] = "";
+
+struct lnch_t {
+ int exits;
+ char key;
+ char desc[512];
+ char cmd[1024];
+};
+
+struct lnch_t lnch[32];
+unsigned int idx = 0;
+
+void trim(char * str)
+{
+ int i;
+ int begin = 0;
+ int end = strlen(str) - 1;
+
+ while (isspace((unsigned char) str[begin]))
+ begin++;
+
+ while (isspace((unsigned char) str[end]) && (end >= begin))
+ end--;
+
+ /* Shift all characters back to the start of the string array. */
+ for (i = begin; i <= end; i++)
+ str[i - begin] = str[i];
+
+ str[i - begin] = '\0';
+}
+
+int parse_line(char * line)
+{
+ char *token;
+ char delim[2] = ":";
+
+ lnch[idx].exits = 1;
+
+ if (line[0] == '&') {
+ lnch[idx].exits = 0;
+ line++;
+ }
+
+ /* Get key entry */
+ token = strtok(line, delim);
+
+ if (strlen(token) != 1) {
+ printf("error on token %s", token) ;
+ return 1;
+ }
+ lnch[idx].key = token[0];
+ line+=2; // pass the key, pass the `:`
+
+ /* Get description */
+ token = strtok(NULL, delim);
+ strcpy(lnch[idx].desc, token);
+ line+=(strlen(token) + 1 ); // pass the decription, pass the `:`
+
+ /* Get command */
+ strcpy(lnch[idx].cmd, line);
+
+ /* If description is epmty command becomes the descritpion */
+ if (!strlen(lnch[idx].desc))
+ strcpy(lnch[idx].desc, line);
+
+ idx++;
+ return 0;
+}
+
+
+int run_cmd(char * cmd)
+{
+ wordexp_t p;
+ int rc = wordexp(cmd, &p, 0);
+ switch (rc) {
+ case WRDE_BADCHAR:
+ printf("Illegal occurrence of newline or one of |, &, ;, <, >, (, ), {, }.\n");
+ break;
+ case WRDE_BADVAL:
+ printf("An undefined shell variable was referenced, and the WRDE_UNDEF flag told us to consider this an error.\n");
+ break;
+ case WRDE_CMDSUB:
+ printf("Command substitution requested, but the WRDE_NOCMD flag told us to consider this an error.\n");
+ break;
+ case WRDE_NOSPACE:
+ printf("Out of memory.\n");
+ break;
+ case WRDE_SYNTAX:
+ printf("Shell syntax error, such as unbalanced parentheses or unmatched quotes.\n");
+ break;
+ default:
+ printf("Running:");
+ for (size_t i = 0; i < p.we_wordc; i++) {
+ printf(" %s", p.we_wordv[i]);
+ }
+ printf("\n");
+
+ /* double fork from i3wm's exec implementation */
+ if (fork() == 0) {
+ setsid();
+ if (fork() == 0) {
+ execvp(p.we_wordv[0], p.we_wordv);
+ /* never reached */
+ }
+ _exit(EXIT_SUCCESS);
+ }
+ wait(0);
+ }
+ wordfree(&p);
+ return rc;
+}
+
+void grabfocus()
+{
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
+ Window focuswin;
+ int i, revertwin;
+
+ for (i = 0; i < 100; ++i) {
+ XGetInputFocus(dis, &focuswin, &revertwin);
+ if (focuswin == win)
+ return;
+ XSetInputFocus(dis, win, RevertToParent, CurrentTime);
+ nanosleep(&ts, NULL);
+ }
+ printf("cannot grab focus\n");
+}
+
+void grabkeyboard()
+{
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
+ int i;
+
+ /* try to grab keyboard, we may have to wait for another process to ungrab */
+ for (i = 0; i < 1000; i++) {
+ if (XGrabKeyboard(dis, DefaultRootWindow(dis), True, GrabModeAsync,
+ GrabModeAsync, CurrentTime) == GrabSuccess)
+ return;
+ nanosleep(&ts, NULL);
+ }
+ printf("Cannot grab keyboard\n");
+}
+
+void draw_text()
+{
+ char text[2048];
+ int x = 10, y = 10;
+ for (unsigned int i = 0; i < idx; i++) {
+ if (lnch[i].exits)
+ XSetForeground(dis,gc,WhitePixel(dis,DefaultScreen(dis)));
+ else
+ XSetForeground(dis,gc,red.pixel);
+ sprintf(text, "%c: %s", lnch[i].key, lnch[i].desc);
+ XDrawString(dis,win,gc,x,y+=13, text, strlen(text));
+ }
+}
+
+void redraw()
+{
+ XClearWindow(dis, win);
+ draw_text();
+}
+
+int main (int argc, char *argv[])
+{
+ if (argc < 2) {
+ printf("Usage:\n%s xlnchrc\n", argv[0]);
+ printf("xlnchrc format:\n[&]<key>:<description>:<command>\n");
+ return -1;
+ }
+ FILE *f;
+ f = fopen(argv[1], "r");
+
+ if (!f) {
+ printf("xlnchrc required\n");
+ return -1;
+ }
+
+ while (fgets(buf, BUF_SIZE, f)) {
+ trim(buf);
+ parse_line(buf);
+ }
+
+ fclose(f);
+
+ XEvent event; /* the XEvent declaration !!! */
+ KeySym key; /* a dealie-bob to handle KeyPress Events */
+ char text[255]; /* a char buffer for KeyPress Events */
+
+ int rc;
+ init_x();
+ grabkeyboard();
+ grabfocus();
+
+ /* look for events forever... */
+ while(1) {
+ /* get the next event and stuff it into our event variable.
+ Note: only events we set the mask for are detected!
+ */
+ XNextEvent(dis, &event);
+
+ if (event.type==Expose && event.xexpose.count==0) {
+ /* the window was exposed redraw it! */
+ redraw();
+ }
+
+ if (event.type==KeyPress &&
+ XLookupString(&event.xkey,text,255,&key,0)==1) {
+ /* use the XLookupString routine to convert the invent
+ KeyPress data into regular text. Weird but necessary...
+ */
+ if (text[0]=='q') {
+ close_x();
+ exit(0);
+ }
+ printf("You pressed the %c key!\n",text[0]);
+
+ for (unsigned int i = 0; i < idx; i++) {
+ if (lnch[i].key == text[0]) {
+ rc = run_cmd(lnch[i].cmd);
+ if (lnch[i].exits) {
+ close_x();
+ exit(0);
+ }
+ }
+ }
+ }
+ if (event.type==ButtonPress) {
+ /* tell where the mouse Button was Pressed */
+ int x=event.xbutton.x,
+ y=event.xbutton.y;
+
+ strcpy(text,">>xlnch<<");
+ XSetForeground(dis,gc,rand()%255);
+ XDrawString(dis,win,gc,x,y, text, strlen(text));
+ }
+
+ if (event.type==FocusIn) {
+ if (event.xfocus.window != win) {
+ grabfocus();
+ }
+ }
+ }
+}