master xtr.c
  1#include <X11/Xlib.h>
  2#include <X11/keysym.h>
  3#include <xkbcommon/xkbcommon.h>
  4
  5#include <stdbool.h>
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <string.h>
  9
 10#include <getopt.h>
 11
 12#include "config.h"
 13
 14int main(int ac, char **av) {
 15  int wi = 350, hi = 75, x = 0, y = 0;
 16
 17  char path[128];
 18  snprintf(path, sizeof path, "%s/%s", getenv("HOME"), ".xlrc");
 19
 20  char *fnt = NULL;
 21
 22  int opt;
 23  while ((opt = getopt(ac, av, "f:h ")) != -1) {
 24    switch (opt) {
 25    case 'f':
 26      fnt = optarg;
 27      break;
 28    case 'h':
 29      fprintf(stderr, "usage: %s [-f fontname]\nusage: %s [-h]\nusage: %s\n",
 30              av[0], av[0], av[0]);
 31      return 0;
 32      break;
 33    case ':':
 34      fprintf(stderr, "-%c needs a argument!\n", optopt);
 35      return 1;
 36      break;
 37    case '?':
 38      fprintf(stderr, "unknown flag: -%c\n", optopt);
 39      return 1;
 40      break;
 41    }
 42  }
 43
 44  Display *d = XOpenDisplay(NULL);
 45  if (!d) {
 46    fprintf(stderr, "couldnt open display\n");
 47    return 1;
 48  }
 49
 50  int s = DefaultScreen(d);
 51  int swi = DisplayWidth(d, s);
 52  int shi = DisplayHeight(d, s);
 53
 54  Window r = DefaultRootWindow(d);
 55  Window w_r;
 56  unsigned int m_r;
 57  int d1, d2;
 58
 59  if (XQueryPointer(d, r, &w_r, &w_r, &x, &y, &d1, &d2, &m_r)) {
 60  }
 61
 62  XColor col[6];
 63  for (size_t c = 0; cols[c] != NULL; c++) {
 64    XParseColor(d, DefaultColormap(d, s), cols[c], &col[c]);
 65    XAllocColor(d, DefaultColormap(d, s), &col[c]);
 66  }
 67
 68  Window w = XCreateSimpleWindow(d, RootWindow(d, s), (swi / 2) - (wi / 2),
 69                                 (shi / 2) - (hi / 2), wi, hi, 1, col[0].pixel,
 70                                 WhitePixel(d, s));
 71  XStoreName(d, w, "xlnd");
 72  XSelectInput(d, w, ExposureMask | KeyPressMask | KeyReleaseMask);
 73  /*
 74   * dont make it a regular window
 75   * kinda like rofi or layer-shell
 76   */
 77  XSetWindowAttributes at;
 78  at.override_redirect = True;
 79  XChangeWindowAttributes(d, w, CWOverrideRedirect, &at);
 80
 81  XMapWindow(d, w);
 82  XMapRaised(d, w);
 83  XSetInputFocus(d, w, RevertToPointerRoot, CurrentTime);
 84  XGrabKeyboard(d, w, True, GrabModeAsync, GrabModeAsync, CurrentTime);
 85  XGrabPointer(d, w, True, ButtonPressMask | PointerMotionMask, GrabModeAsync,
 86               GrabModeAsync, None, None, CurrentTime);
 87
 88  GC gc = XCreateGC(d, w, 0, NULL);
 89  XSetForeground(d, gc, WhitePixel(d, s));
 90  XFillRectangle(d, w, gc, 0, 0, wi, hi);
 91  XSetForeground(d, gc, BlackPixel(d, s));
 92
 93  XFontStruct *font = XLoadQueryFont(d, fnt ? fnt : "fixed");
 94  if (!font)
 95    font = XLoadQueryFont(d, "fixed");
 96  XSetFont(d, gc, font->fid);
 97
 98  bool end = false;
 99  bool Nend = false;
100  int cmd_end = 0;
101  char cmd[512];
102  size_t idx = 0;
103  for (int c = 0; c < 1023; c++) {
104    cmd[c] = '\0';
105  }
106
107  struct xkb_context *ctx;
108  struct xkb_keymap *keymap;
109  struct xkb_state *state;
110
111  ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
112
113  keymap = xkb_keymap_new_from_names(ctx, &(struct xkb_rule_names){0},
114                                     XKB_KEYMAP_COMPILE_NO_FLAGS);
115
116  state = xkb_state_new(keymap);
117
118  while (1) {
119    XEvent ev;
120    XNextEvent(d, &ev);
121
122    switch (ev.type) {
123    case Expose:
124      if (ev.xexpose.count != 0)
125        break;
126
127      int direction, as, des;
128      XCharStruct ov;
129      XTextExtents(font, cmd, strlen(cmd), &direction, &as, &des, &ov);
130
131      int Ndirection, Nas, Ndes;
132      XCharStruct Nov;
133      XTextExtents(font, cmd + cmd_end, strlen(cmd + cmd_end), &Ndirection,
134                   &Nas, &Ndes, &Nov);
135
136      XSetForeground(d, gc, col[1].pixel);
137      XFillRectangle(d, w, gc, 0, 0, wi, hi);
138      XSetForeground(d, gc, col[2].pixel);
139      XFillRectangle(d, w, gc, 10, 30, wi - 20, hi - 30 - 10);
140
141      XSetForeground(d, gc, col[1].pixel);
142      XFillRectangle(d, w, gc, 10 + 1, 30 + 1, wi - 20 - (1 * 2),
143                     hi - 30 - 10 - (1 * 2));
144      XSetForeground(d, gc, col[0].pixel);
145
146      char cmd_str[512 + 1];
147      strncpy(cmd_str, cmd, end ? cmd_end : strlen(cmd));
148      cmd_str[512] = '\0';
149      XDrawString(d, w, gc, 15 - 2, 30 + (as + des) + 2, cmd, strlen(cmd_str));
150
151      if (end) {
152        XDrawString(d, w, gc, 15 - 2, 30 + ((as + des) * 2), cmd + cmd_end,
153                    strlen(cmd + cmd_end));
154      }
155
156      if (ov.width - 15 > (wi - 30 - 20) && !end) {
157        cmd_end = strlen(cmd);
158        printf("%d\n", cmd_end);
159        end = true;
160      }
161      if (Nov.width - 15 > (wi - 30 - 10) && end) {
162        Nend = true;
163      }
164
165      break;
166    case KeyPress: {
167      xkb_keycode_t xkb = ev.xkey.keycode;
168      xkb_state_update_key(state, xkb, XKB_KEY_DOWN);
169      KeySym k = XLookupKeysym(&ev.xkey, 0);
170
171      if (k == XK_Escape) {
172        goto q;
173      }
174      if (k == XK_Return) {
175        puts(cmd);
176        goto q;
177      }
178      if (k == XK_BackSpace) {
179        if (idx > 0) {
180          cmd[idx--] = ' ';
181          XClearArea(d, w, 0, 0, 0, 0, True);
182        }
183        break;
184      }
185
186      if (Nend) {
187        xkb_state_update_key(state, xkb, XKB_KEY_UP);
188        break;
189      }
190
191      char buf[32];
192
193      int l = xkb_state_key_get_utf8(state, xkb, buf, sizeof(buf));
194
195      if (l > 0) {
196        if (idx + l < sizeof(cmd)) {
197          cmd[idx++] = buf[0];
198          XClearArea(d, w, 0, 0, 0, 0, True);
199        }
200      }
201
202      break;
203    }
204    case KeyRelease: {
205      xkb_keycode_t xkb = ev.xkey.keycode;
206      xkb_state_update_key(state, xkb, XKB_KEY_UP);
207      break;
208    }
209    }
210  }
211
212q:
213  xkb_state_unref(state);
214  xkb_keymap_unref(keymap);
215  xkb_context_unref(ctx);
216  XFreeFont(d, font);
217  XUngrabKeyboard(d, CurrentTime);
218  XUngrabPointer(d, CurrentTime);
219  XFreeGC(d, gc);
220  XDestroyWindow(d, w);
221  XCloseDisplay(d);
222  return 0;
223}