#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
-/* dlopened xlib so we can find the symbols in the real xlib to call them */
-static void *lib_xlib = NULL;
+/* dlopened libs so we can find the symbols in the real one to call them */
+static void *lib_xlib = NULL;
+static void *lib_xtlib = NULL;
-static Window root = None;
+static Window root = None;
+static int xterm = 0;
+static Display *dpy = NULL;
/* Find our root window */
static Window
/* find the real Xlib and the real X function */
if (!lib_xlib)
lib_xlib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY);
- if (!func)
+ if (!func) {
func = (CWF *) dlsym(lib_xlib, "XCreateWindow");
+ dpy = display;
+ }
if (parent == DefaultRootWindow(display))
parent = MyRoot(display);
set_property(display, id, "_SWM_WS", env);
if ((env = getenv("_SWM_PID")) != NULL)
set_property(display, id, "_SWM_PID", env);
+ if ((env = getenv("_SWM_XTERM_FONTADJ")) != NULL) {
+ unsetenv("_SWM_XTERM_FONTADJ");
+ xterm = 1;
+ }
}
return (id);
}
set_property(display, id, "_SWM_WS", env);
if ((env = getenv("_SWM_PID")) != NULL)
set_property(display, id, "_SWM_PID", env);
+ if ((env = getenv("_SWM_XTERM_FONTADJ")) != NULL) {
+ unsetenv("_SWM_XTERM_FONTADJ");
+ xterm = 1;
+ }
}
return (id);
}
return (*func) (display, window, parent, x, y);
}
+
+typedef void (ANEF) (XtAppContext app_context, XEvent *event_return);
+int evcount = 0;
+
+/*
+ * XtAppNextEvent Intercept Hack
+ * Normally xterm rejects "synthetic" (XSendEvent) events to prevent spoofing.
+ * We don't want to disable this completely, it's insecure. But hook here
+ * and allow these mostly harmless ones that we use to adjust fonts.
+ */
+void
+XtAppNextEvent(XtAppContext app_context, XEvent *event_return)
+{
+ static ANEF *func = NULL;
+ static int kp_add = 0, kp_subtract = 0;
+
+ /* find the real Xlib and the real X function */
+ if (!lib_xtlib)
+ lib_xtlib = dlopen("libXt.so", RTLD_GLOBAL | RTLD_LAZY);
+ if (!func) {
+ func = (ANEF *) dlsym(lib_xtlib, "XtAppNextEvent");
+ if (dpy != NULL) {
+ kp_add = XKeysymToKeycode(dpy, XK_KP_Add);
+ kp_subtract = XKeysymToKeycode(dpy, XK_KP_Subtract);
+ }
+ }
+
+ (*func) (app_context, event_return);
+
+ /* Return here if it's not an Xterm. */
+ if (!xterm)
+ return;
+
+ /* Allow spoofing of font change keystrokes. */
+ if ((event_return->type == KeyPress ||
+ event_return->type == KeyRelease) &&
+ event_return->xkey.state == ShiftMask &&
+ (event_return->xkey.keycode == kp_add ||
+ event_return->xkey.keycode == kp_subtract))
+ event_return->xkey.send_event = 0;
+}
#define Y(r) (r)->g.y
#define WIDTH(r) (r)->g.w
#define HEIGHT(r) (r)->g.h
+#define SWM_MAX_FONT_STEPS (3)
#ifndef SWM_LIB
#define SWM_LIB "/usr/X11R6/lib/swmhack.so"
int cycle_empty = 0;
int cycle_visible = 0;
+int term_width = 0;
+int font_adjusted = 0;
/* dialog windows */
double dialog_ratio = .6;
int floating;
int transient;
int manual;
+ int font_size_boundary[SWM_MAX_FONT_STEPS];
+ int font_steps;
+ int last_inc;
unsigned long quirks;
struct workspace *ws; /* always valid */
struct swm_screen *s; /* always valid, never changes */
#define SWM_Q_FLOAT (1<<0) /* float this window */
#define SWM_Q_TRANSSZ (1<<1) /* transiend window size too small */
#define SWM_Q_ANYWHERE (1<<2) /* don't position this window */
+#define SWM_Q_XTERM_FONTADJ (1<<3) /* adjust xterm fonts when resizing */
} quirks[] = {
{ "MPlayer", "xv", SWM_Q_FLOAT },
{ "OpenOffice.org 2.4", "VCLSalFrame", SWM_Q_FLOAT },
{ "OpenOffice.org 3.0", "VCLSalFrame", SWM_Q_FLOAT },
{ "Firefox-bin", "firefox-bin", SWM_Q_TRANSSZ},
{ "Gimp", "gimp", SWM_Q_FLOAT | SWM_Q_ANYWHERE},
+ { "XTerm", "xterm", SWM_Q_XTERM_FONTADJ},
{ NULL, NULL, 0},
};
case 's':
if (!strncmp(var, "spawn_term", strlen("spawn_term")))
asprintf(&spawn_term[0], "%s", val);
- if (!strncmp(var, "screenshot_enabled",
+ else if (!strncmp(var, "screenshot_enabled",
strlen("screenshot_enabled")))
ss_enabled = atoi(val);
- if (!strncmp(var, "screenshot_app",
+ else if (!strncmp(var, "screenshot_app",
strlen("screenshot_app")))
asprintf(&spawn_screenshot[0], "%s", val);
+ else
+ goto bad;
break;
+
+ case 't':
+ if (!strncmp(var, "term_width", strlen("term_width")))
+ term_width = atoi(val);
+ else
+ goto bad;
+ break;
+
default:
goto bad;
}
XUnmapWindow(display, win->id);
}
+void
+fake_keypress(struct ws_win *win, int keysym, int modifiers)
+{
+ XKeyEvent event;
+
+ event.display = display; /* Ignored, but what the hell */
+ event.window = win->id;
+ event.root = win->s->root;
+ event.subwindow = None;
+ event.time = CurrentTime;
+ event.x = win->g.x;
+ event.y = win->g.y;
+ event.x_root = 1;
+ event.y_root = 1;
+ event.same_screen = True;
+ event.keycode = XKeysymToKeycode(display, keysym);
+ event.state = modifiers;
+
+ event.type = KeyPress;
+ XSendEvent(event.display, event.window, True,
+ KeyPressMask, (XEvent *)&event);
+
+ event.type = KeyRelease;
+ XSendEvent(event.display, event.window, True,
+ KeyPressMask, (XEvent *)&event);
+
+}
+
void
restart(struct swm_region *r, union arg *args)
{
wait(0);
}
+void
+spawnterm(struct swm_region *r, union arg *args)
+{
+ DNPRINTF(SWM_D_MISC, "spawnterm\n");
+
+ if (term_width)
+ setenv("_SWM_XTERM_FONTADJ", "", 1);
+ spawn(r, args);
+}
+
void
spawnmenu(struct swm_region *r, union arg *args)
{
r->ws->cur_layout->l_stack(r->ws, &g);
}
}
+ if (font_adjusted)
+ font_adjusted--;
XSync(display, False);
}
XConfigureWindow(display, win->id, mask, &wc);
}
+/*
+ * Send keystrokes to terminal to decrease/increase the font size as the
+ * window size changes.
+ */
+void
+adjust_font(struct ws_win *win)
+{
+ if (!(win->quirks & SWM_Q_XTERM_FONTADJ) ||
+ win->floating || win->transient)
+ return;
+
+ if (win->sh.width_inc && win->last_inc != win->sh.width_inc &&
+ win->g.w / win->sh.width_inc < term_width &&
+ win->font_steps < SWM_MAX_FONT_STEPS) {
+ win->font_size_boundary[win->font_steps] =
+ (win->sh.width_inc * term_width) + win->sh.base_width;
+ win->font_steps++;
+ font_adjusted++;
+ win->last_inc = win->sh.width_inc;
+ fake_keypress(win, XK_KP_Subtract, ShiftMask);
+ } else if (win->font_steps && win->last_inc != win->sh.width_inc &&
+ win->g.w > win->font_size_boundary[win->font_steps - 1]) {
+ win->font_steps--;
+ font_adjusted++;
+ win->last_inc = win->sh.width_inc;
+ fake_keypress(win, XK_KP_Add, ShiftMask);
+ }
+}
+
#define SWAPXY(g) do { \
int tmp; \
tmp = (g)->y; (g)->y = (g)->x; (g)->x = tmp; \
win->g.w = wc.width = win_g.w;
win->g.h = wc.height = win_g.h;
}
+ adjust_font(win);
mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
XConfigureWindow(display, win->id, mask, &wc);
XMapRaised(display, win->id);
{ MODKEY, XK_k, focus, {.id = SWM_ARG_ID_FOCUSPREV} },
{ MODKEY | ShiftMask, XK_j, swapwin, {.id = SWM_ARG_ID_SWAPNEXT} },
{ MODKEY | ShiftMask, XK_k, swapwin, {.id = SWM_ARG_ID_SWAPPREV} },
- { MODKEY | ShiftMask, XK_Return, spawn, {.argv = spawn_term} },
+ { MODKEY | ShiftMask, XK_Return, spawnterm, {.argv = spawn_term} },
{ MODKEY, XK_p, spawnmenu, {.argv = spawn_menu} },
{ MODKEY | ShiftMask, XK_q, quit, {0} },
{ MODKEY, XK_q, restart, {0} },
void
configurenotify(XEvent *e)
{
+ struct ws_win *win;
+ long mask;
+
DNPRINTF(SWM_D_EVENT, "configurenotify: window: %lu\n",
e->xconfigure.window);
+
+ win = find_window(e->xconfigure.window);
+ XMapWindow(display, win->id);
+ XGetWMNormalHints(display, win->id, &win->sh, &mask);
+ adjust_font(win);
+ XMapWindow(display, win->id);
+ if (font_adjusted)
+ stack();
}
void