2012-11-28 16:17:15 -06:00
|
|
|
/*
|
|
|
|
* See LICENSE file for copyright and license details.
|
2009-09-07 06:32:58 -05:00
|
|
|
*/
|
2012-11-28 16:17:15 -06:00
|
|
|
|
2009-09-07 17:06:46 -05:00
|
|
|
#include <sys/wait.h>
|
2009-09-07 06:32:58 -05:00
|
|
|
#include <locale.h>
|
2009-09-07 17:06:46 -05:00
|
|
|
#include <signal.h>
|
2016-01-03 06:00:57 -06:00
|
|
|
#include <stdarg.h>
|
2009-09-07 06:32:58 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2016-01-03 06:00:57 -06:00
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2009-09-07 06:32:58 -05:00
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/Xlib.h>
|
2009-09-08 04:30:08 -05:00
|
|
|
#include <X11/Xproto.h>
|
|
|
|
#include <X11/Xutil.h>
|
2012-07-07 15:50:26 -05:00
|
|
|
#include <X11/XKBlib.h>
|
2016-02-13 15:42:14 -06:00
|
|
|
#include <X11/Xft/Xft.h>
|
2009-09-07 06:32:58 -05:00
|
|
|
|
2012-04-06 13:44:47 -05:00
|
|
|
#include "arg.h"
|
|
|
|
|
2009-09-23 02:53:30 -05:00
|
|
|
/* XEMBED messages */
|
2009-10-27 15:07:08 -05:00
|
|
|
#define XEMBED_EMBEDDED_NOTIFY 0
|
|
|
|
#define XEMBED_WINDOW_ACTIVATE 1
|
|
|
|
#define XEMBED_WINDOW_DEACTIVATE 2
|
|
|
|
#define XEMBED_REQUEST_FOCUS 3
|
|
|
|
#define XEMBED_FOCUS_IN 4
|
|
|
|
#define XEMBED_FOCUS_OUT 5
|
|
|
|
#define XEMBED_FOCUS_NEXT 6
|
|
|
|
#define XEMBED_FOCUS_PREV 7
|
2009-09-23 02:53:30 -05:00
|
|
|
/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
|
2009-10-27 15:07:08 -05:00
|
|
|
#define XEMBED_MODALITY_ON 10
|
|
|
|
#define XEMBED_MODALITY_OFF 11
|
2009-09-23 02:53:30 -05:00
|
|
|
#define XEMBED_REGISTER_ACCELERATOR 12
|
|
|
|
#define XEMBED_UNREGISTER_ACCELERATOR 13
|
|
|
|
#define XEMBED_ACTIVATE_ACCELERATOR 14
|
|
|
|
|
|
|
|
/* Details for XEMBED_FOCUS_IN: */
|
2009-10-27 15:07:08 -05:00
|
|
|
#define XEMBED_FOCUS_CURRENT 0
|
|
|
|
#define XEMBED_FOCUS_FIRST 1
|
|
|
|
#define XEMBED_FOCUS_LAST 2
|
2009-09-07 06:32:58 -05:00
|
|
|
|
2009-09-23 03:00:06 -05:00
|
|
|
/* Macros */
|
2016-01-03 06:00:57 -06:00
|
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
#define LENGTH(x) (sizeof((x)) / sizeof(*(x)))
|
|
|
|
#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
|
|
|
|
#define TEXTW(x) (textnw(x, strlen(x)) + dc.font.height)
|
2009-09-23 03:00:06 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
enum { ColFG, ColBG, ColLast }; /* color */
|
2012-12-03 14:28:02 -06:00
|
|
|
enum { WMProtocols, WMDelete, WMName, WMState, WMFullscreen,
|
2016-01-03 06:00:57 -06:00
|
|
|
XEmbed, WMSelectTab, WMLast }; /* default atoms */
|
2009-09-23 03:00:06 -05:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
typedef union {
|
|
|
|
int i;
|
|
|
|
const void *v;
|
|
|
|
} Arg;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
unsigned int mod;
|
|
|
|
KeySym keysym;
|
|
|
|
void (*func)(const Arg *);
|
|
|
|
const Arg arg;
|
|
|
|
} Key;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
int x, y, w, h;
|
2016-02-13 15:42:14 -06:00
|
|
|
XftColor norm[ColLast];
|
|
|
|
XftColor sel[ColLast];
|
|
|
|
XftColor urg[ColLast];
|
2009-09-07 06:32:58 -05:00
|
|
|
Drawable drawable;
|
|
|
|
GC gc;
|
|
|
|
struct {
|
|
|
|
int ascent;
|
|
|
|
int descent;
|
|
|
|
int height;
|
2016-02-13 15:42:14 -06:00
|
|
|
XftFont *xfont;
|
2009-09-07 06:32:58 -05:00
|
|
|
} font;
|
|
|
|
} DC; /* draw context */
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
typedef struct {
|
2009-09-07 06:32:58 -05:00
|
|
|
char name[256];
|
|
|
|
Window win;
|
2009-09-08 08:55:23 -05:00
|
|
|
int tabx;
|
2014-05-13 18:34:44 -05:00
|
|
|
Bool urgent;
|
2010-05-24 17:44:20 -05:00
|
|
|
Bool closed;
|
2009-09-07 07:21:26 -05:00
|
|
|
} Client;
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
/* function declarations */
|
2009-10-13 12:52:34 -05:00
|
|
|
static void buttonpress(const XEvent *e);
|
2009-09-07 06:32:58 -05:00
|
|
|
static void cleanup(void);
|
2009-10-13 12:52:34 -05:00
|
|
|
static void clientmessage(const XEvent *e);
|
|
|
|
static void configurenotify(const XEvent *e);
|
|
|
|
static void configurerequest(const XEvent *e);
|
|
|
|
static void createnotify(const XEvent *e);
|
|
|
|
static void destroynotify(const XEvent *e);
|
2009-09-07 06:32:58 -05:00
|
|
|
static void die(const char *errstr, ...);
|
2012-11-25 15:09:55 -06:00
|
|
|
static void drawbar(void);
|
2016-02-13 15:42:14 -06:00
|
|
|
static void drawtext(const char *text, XftColor col[ColLast]);
|
2014-05-24 14:09:56 -05:00
|
|
|
static void *ecalloc(size_t n, size_t size);
|
2012-11-25 15:09:55 -06:00
|
|
|
static void *erealloc(void *o, size_t size);
|
2009-10-13 12:52:34 -05:00
|
|
|
static void expose(const XEvent *e);
|
2012-11-25 15:09:55 -06:00
|
|
|
static void focus(int c);
|
2009-10-13 12:52:34 -05:00
|
|
|
static void focusin(const XEvent *e);
|
2009-12-15 02:26:01 -06:00
|
|
|
static void focusonce(const Arg *arg);
|
2016-01-03 06:00:57 -06:00
|
|
|
static void focusurgent(const Arg *arg);
|
2012-12-03 14:28:02 -06:00
|
|
|
static void fullscreen(const Arg *arg);
|
2016-01-03 06:00:57 -06:00
|
|
|
static char *getatom(int a);
|
2012-11-25 15:09:55 -06:00
|
|
|
static int getclient(Window w);
|
2016-02-13 15:42:14 -06:00
|
|
|
static XftColor getcolor(const char *colstr);
|
2012-11-25 15:09:55 -06:00
|
|
|
static int getfirsttab(void);
|
2009-09-08 04:30:08 -05:00
|
|
|
static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
2009-09-07 06:32:58 -05:00
|
|
|
static void initfont(const char *fontstr);
|
2012-11-25 15:09:55 -06:00
|
|
|
static Bool isprotodel(int c);
|
2009-10-13 12:52:34 -05:00
|
|
|
static void keypress(const XEvent *e);
|
2009-09-07 15:22:08 -05:00
|
|
|
static void killclient(const Arg *arg);
|
2009-09-08 04:30:08 -05:00
|
|
|
static void manage(Window win);
|
2009-10-28 14:09:53 -05:00
|
|
|
static void maprequest(const XEvent *e);
|
2009-09-23 03:33:10 -05:00
|
|
|
static void move(const Arg *arg);
|
2012-11-25 15:09:55 -06:00
|
|
|
static void movetab(const Arg *arg);
|
2009-10-13 12:52:34 -05:00
|
|
|
static void propertynotify(const XEvent *e);
|
2012-11-25 15:09:55 -06:00
|
|
|
static void resize(int c, int w, int h);
|
2009-09-07 06:32:58 -05:00
|
|
|
static void rotate(const Arg *arg);
|
|
|
|
static void run(void);
|
2012-11-25 15:09:55 -06:00
|
|
|
static void sendxembed(int c, long msg, long detail, long d1, long d2);
|
2012-11-08 14:48:51 -06:00
|
|
|
static void setcmd(int argc, char *argv[], int);
|
2016-01-03 06:00:57 -06:00
|
|
|
static void setup(void);
|
2009-10-15 08:40:18 -05:00
|
|
|
static void sigchld(int unused);
|
2009-09-23 03:33:10 -05:00
|
|
|
static void spawn(const Arg *arg);
|
2009-09-07 06:32:58 -05:00
|
|
|
static int textnw(const char *text, unsigned int len);
|
autofocus urgent tabs
When tabbed becomes urgent because one of it tabs becomes urgent, it
may be desireable to automatically focus that tab. As a notification may
be lost, if another notification comes in before you focused tabbed, the
switch is only done, if tabbed is not urgent already.
Moreover, it may be anoying, if you just type into one tab, another tab
gets urgent -therfore focused- and you type into the other tab, you may
switch between autofocus and nofocus using Ctrl-Shift-u.
Maybe it would also be usefull, if there would be an commandline
parameter to toggle that option, but as -u is already used for
urgent-tab-color, i did not implement that.
Signed-off-by: Jonas Rabenstein <jonas.rabenstein@studium.uni-erlangen.de>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
2015-08-19 14:11:16 -05:00
|
|
|
static void toggle(const Arg *arg);
|
2012-11-25 15:09:55 -06:00
|
|
|
static void unmanage(int c);
|
2016-01-03 06:00:57 -06:00
|
|
|
static void unmapnotify(const XEvent *e);
|
2009-09-07 06:32:58 -05:00
|
|
|
static void updatenumlockmask(void);
|
2012-11-25 15:09:55 -06:00
|
|
|
static void updatetitle(int c);
|
2009-09-08 00:34:15 -05:00
|
|
|
static int xerror(Display *dpy, XErrorEvent *ee);
|
2013-01-16 11:33:50 -06:00
|
|
|
static void xsettitle(Window w, const char *str);
|
2009-09-07 06:32:58 -05:00
|
|
|
|
|
|
|
/* variables */
|
|
|
|
static int screen;
|
2009-10-13 12:52:34 -05:00
|
|
|
static void (*handler[LASTEvent]) (const XEvent *) = {
|
2009-09-08 04:53:32 -05:00
|
|
|
[ButtonPress] = buttonpress,
|
2009-09-13 05:13:10 -05:00
|
|
|
[ClientMessage] = clientmessage,
|
2009-09-23 03:33:10 -05:00
|
|
|
[ConfigureNotify] = configurenotify,
|
2009-10-13 01:13:30 -05:00
|
|
|
[ConfigureRequest] = configurerequest,
|
2009-09-22 13:17:20 -05:00
|
|
|
[CreateNotify] = createnotify,
|
2014-09-10 12:50:34 -05:00
|
|
|
[UnmapNotify] = unmapnotify,
|
2009-09-23 03:33:10 -05:00
|
|
|
[DestroyNotify] = destroynotify,
|
|
|
|
[Expose] = expose,
|
2009-09-23 02:53:30 -05:00
|
|
|
[FocusIn] = focusin,
|
2009-09-23 03:33:10 -05:00
|
|
|
[KeyPress] = keypress,
|
2009-10-28 14:09:53 -05:00
|
|
|
[MapRequest] = maprequest,
|
2009-09-23 03:33:10 -05:00
|
|
|
[PropertyNotify] = propertynotify,
|
2009-09-07 06:32:58 -05:00
|
|
|
};
|
2020-05-12 10:09:01 -05:00
|
|
|
static int bh, obh, wx, wy, ww, wh;
|
2016-01-03 06:00:57 -06:00
|
|
|
static unsigned int numlockmask;
|
2012-12-25 09:50:32 -06:00
|
|
|
static Bool running = True, nextfocus, doinitspawn = True,
|
2016-03-20 21:16:12 -05:00
|
|
|
fillagain = False, closelastclient = False,
|
|
|
|
killclientsfirst = False;
|
2009-09-07 06:32:58 -05:00
|
|
|
static Display *dpy;
|
|
|
|
static DC dc;
|
2012-10-12 23:57:32 -05:00
|
|
|
static Atom wmatom[WMLast];
|
2009-09-07 06:32:58 -05:00
|
|
|
static Window root, win;
|
2016-01-03 06:00:57 -06:00
|
|
|
static Client **clients;
|
|
|
|
static int nclients, sel = -1, lastsel = -1;
|
2009-09-11 06:08:27 -05:00
|
|
|
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
2016-01-03 06:00:57 -06:00
|
|
|
static int cmd_append_pos;
|
2009-10-13 01:13:30 -05:00
|
|
|
static char winid[64];
|
2016-01-03 06:00:57 -06:00
|
|
|
static char **cmd;
|
2012-10-03 00:56:53 -05:00
|
|
|
static char *wmname = "tabbed";
|
2016-01-03 06:00:57 -06:00
|
|
|
static const char *geometry;
|
2012-04-06 13:44:47 -05:00
|
|
|
|
|
|
|
char *argv0;
|
2012-11-28 16:30:09 -06:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
/* configuration, allows nested code to access above variables */
|
|
|
|
#include "config.h"
|
|
|
|
|
2009-09-08 04:53:32 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
buttonpress(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XButtonPressedEvent *ev = &e->xbutton;
|
2016-01-03 06:00:57 -06:00
|
|
|
int i, fc;
|
2009-10-28 15:37:15 -05:00
|
|
|
Arg arg;
|
2009-09-08 04:53:32 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (ev->y < 0 || ev->y > bh)
|
2009-09-08 08:55:23 -05:00
|
|
|
return;
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (((fc = getfirsttab()) > 0 && ev->x < TEXTW(before)) || ev->x < 0)
|
2013-07-29 02:11:33 -05:00
|
|
|
return;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
for (i = fc; i < nclients; i++) {
|
|
|
|
if (clients[i]->tabx > ev->x) {
|
|
|
|
switch (ev->button) {
|
2009-10-28 15:37:15 -05:00
|
|
|
case Button1:
|
2012-11-25 15:09:55 -06:00
|
|
|
focus(i);
|
2009-10-28 15:37:15 -05:00
|
|
|
break;
|
|
|
|
case Button2:
|
2012-11-25 15:09:55 -06:00
|
|
|
focus(i);
|
2009-10-28 15:37:15 -05:00
|
|
|
killclient(NULL);
|
|
|
|
break;
|
2016-01-03 06:00:57 -06:00
|
|
|
case Button4: /* FALLTHROUGH */
|
2009-10-28 15:37:15 -05:00
|
|
|
case Button5:
|
|
|
|
arg.i = ev->button == Button4 ? -1 : 1;
|
|
|
|
rotate(&arg);
|
|
|
|
break;
|
|
|
|
}
|
2009-09-08 04:53:32 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
cleanup(void)
|
|
|
|
{
|
2012-11-25 15:09:55 -06:00
|
|
|
int i;
|
2009-10-26 10:50:38 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
for (i = 0; i < nclients; i++) {
|
2012-11-25 15:09:55 -06:00
|
|
|
focus(i);
|
2011-05-06 15:40:53 -05:00
|
|
|
killclient(NULL);
|
2012-11-25 15:09:55 -06:00
|
|
|
XReparentWindow(dpy, clients[i]->win, root, 0, 0);
|
|
|
|
unmanage(i);
|
2009-10-26 10:50:38 -05:00
|
|
|
}
|
2012-11-25 15:09:55 -06:00
|
|
|
free(clients);
|
|
|
|
clients = NULL;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
XFreePixmap(dpy, dc.drawable);
|
|
|
|
XFreeGC(dpy, dc.gc);
|
|
|
|
XDestroyWindow(dpy, win);
|
|
|
|
XSync(dpy, False);
|
2011-05-06 15:40:53 -05:00
|
|
|
free(cmd);
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
|
2009-09-13 05:13:10 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
clientmessage(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XClientMessageEvent *ev = &e->xclient;
|
2009-09-13 05:13:10 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (ev->message_type == wmatom[WMProtocols] &&
|
2016-03-20 21:16:12 -05:00
|
|
|
ev->data.l[0] == wmatom[WMDelete]) {
|
|
|
|
if (nclients > 1 && killclientsfirst) {
|
|
|
|
killclient(0);
|
|
|
|
return;
|
|
|
|
}
|
2009-10-26 10:50:38 -05:00
|
|
|
running = False;
|
2016-03-20 21:16:12 -05:00
|
|
|
}
|
2009-09-13 05:13:10 -05:00
|
|
|
}
|
2009-10-13 01:13:30 -05:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
configurenotify(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XConfigureEvent *ev = &e->xconfigure;
|
2009-09-07 06:32:58 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (ev->window == win && (ev->width != ww || ev->height != wh)) {
|
2009-09-07 06:32:58 -05:00
|
|
|
ww = ev->width;
|
|
|
|
wh = ev->height;
|
|
|
|
XFreePixmap(dpy, dc.drawable);
|
2012-11-08 14:40:58 -06:00
|
|
|
dc.drawable = XCreatePixmap(dpy, root, ww, wh,
|
2016-01-03 06:00:57 -06:00
|
|
|
DefaultDepth(dpy, screen));
|
2020-05-12 10:09:01 -05:00
|
|
|
|
|
|
|
if (!obh && (wh <= bh)) {
|
|
|
|
obh = bh;
|
|
|
|
bh = 0;
|
|
|
|
} else if (!bh && (wh > obh)) {
|
|
|
|
bh = obh;
|
|
|
|
obh = 0;
|
|
|
|
}
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel > -1)
|
2009-10-28 14:31:34 -05:00
|
|
|
resize(sel, ww, wh - bh);
|
2009-09-08 04:30:08 -05:00
|
|
|
XSync(dpy, False);
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-13 01:13:30 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
configurerequest(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XConfigureRequestEvent *ev = &e->xconfigurerequest;
|
2009-10-13 01:13:30 -05:00
|
|
|
XWindowChanges wc;
|
2012-11-25 15:09:55 -06:00
|
|
|
int c;
|
2009-10-13 01:13:30 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if ((c = getclient(ev->window)) > -1) {
|
2009-10-13 01:13:30 -05:00
|
|
|
wc.x = 0;
|
|
|
|
wc.y = bh;
|
|
|
|
wc.width = ww;
|
|
|
|
wc.height = wh - bh;
|
|
|
|
wc.border_width = 0;
|
|
|
|
wc.sibling = ev->above;
|
|
|
|
wc.stack_mode = ev->detail;
|
2012-11-25 15:09:55 -06:00
|
|
|
XConfigureWindow(dpy, clients[c]->win, ev->value_mask, &wc);
|
2009-10-13 01:13:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-22 13:17:20 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
createnotify(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XCreateWindowEvent *ev = &e->xcreatewindow;
|
2009-09-22 13:17:20 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (ev->window != win && getclient(ev->window) < 0)
|
2009-09-22 13:17:20 -05:00
|
|
|
manage(ev->window);
|
|
|
|
}
|
|
|
|
|
2014-09-10 12:50:34 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
destroynotify(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XDestroyWindowEvent *ev = &e->xdestroywindow;
|
2012-11-25 15:09:55 -06:00
|
|
|
int c;
|
2009-09-08 05:50:08 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if ((c = getclient(ev->window)) > -1)
|
2009-09-08 05:50:08 -05:00
|
|
|
unmanage(c);
|
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
die(const char *errstr, ...)
|
|
|
|
{
|
2009-09-07 06:32:58 -05:00
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, errstr);
|
|
|
|
vfprintf(stderr, errstr, ap);
|
|
|
|
va_end(ap);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
drawbar(void)
|
|
|
|
{
|
2016-02-13 15:42:14 -06:00
|
|
|
XftColor *col;
|
2015-01-20 20:46:38 -06:00
|
|
|
int c, cc, fc, width;
|
2009-10-13 01:13:30 -05:00
|
|
|
char *name = NULL;
|
2009-09-08 04:30:08 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (nclients == 0) {
|
2009-09-08 11:55:43 -05:00
|
|
|
dc.x = 0;
|
|
|
|
dc.w = ww;
|
2009-10-13 01:13:30 -05:00
|
|
|
XFetchName(dpy, win, &name);
|
|
|
|
drawtext(name ? name : "", dc.norm);
|
2009-09-11 06:08:27 -05:00
|
|
|
XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0, 0);
|
|
|
|
XSync(dpy, False);
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2009-09-08 11:55:43 -05:00
|
|
|
return;
|
|
|
|
}
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-08 05:17:59 -05:00
|
|
|
width = ww;
|
2015-01-20 20:46:38 -06:00
|
|
|
cc = ww / tabwidth;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (nclients > cc)
|
2015-01-20 20:46:38 -06:00
|
|
|
cc = (ww - TEXTW(before) - TEXTW(after)) / tabwidth;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if ((fc = getfirsttab()) + cc < nclients) {
|
2009-09-08 05:17:59 -05:00
|
|
|
dc.w = TEXTW(after);
|
|
|
|
dc.x = width - dc.w;
|
2009-09-08 05:50:08 -05:00
|
|
|
drawtext(after, dc.sel);
|
2009-09-08 05:17:59 -05:00
|
|
|
width -= dc.w;
|
|
|
|
}
|
2009-09-08 04:30:08 -05:00
|
|
|
dc.x = 0;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (fc > 0) {
|
2009-09-08 05:17:59 -05:00
|
|
|
dc.w = TEXTW(before);
|
2009-09-08 05:50:08 -05:00
|
|
|
drawtext(before, dc.sel);
|
2009-09-08 05:17:59 -05:00
|
|
|
dc.x += dc.w;
|
|
|
|
width -= dc.w;
|
|
|
|
}
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2015-01-20 20:46:38 -06:00
|
|
|
cc = MIN(cc, nclients);
|
2016-01-03 06:00:57 -06:00
|
|
|
for (c = fc; c < fc + cc; c++) {
|
2015-01-20 20:46:38 -06:00
|
|
|
dc.w = width / cc;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (c == sel) {
|
2009-09-08 04:30:08 -05:00
|
|
|
col = dc.sel;
|
2015-01-20 20:46:38 -06:00
|
|
|
dc.w += width % cc;
|
2012-11-08 14:40:58 -06:00
|
|
|
} else {
|
2014-05-13 18:34:44 -05:00
|
|
|
col = clients[c]->urgent ? dc.urg : dc.norm;
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
2012-11-25 15:09:55 -06:00
|
|
|
drawtext(clients[c]->name, col);
|
2009-09-08 04:30:08 -05:00
|
|
|
dc.x += dc.w;
|
2012-11-25 15:09:55 -06:00
|
|
|
clients[c]->tabx = dc.x;
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
|
|
|
XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0, 0);
|
|
|
|
XSync(dpy, False);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-02-13 15:42:14 -06:00
|
|
|
drawtext(const char *text, XftColor col[ColLast])
|
2016-01-03 06:00:57 -06:00
|
|
|
{
|
2016-01-03 19:21:04 -06:00
|
|
|
int i, j, x, y, h, len, olen;
|
2009-10-13 12:52:34 -05:00
|
|
|
char buf[256];
|
2016-02-13 15:42:14 -06:00
|
|
|
XftDraw *d;
|
2009-09-08 04:30:08 -05:00
|
|
|
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
|
|
|
|
|
2016-02-13 15:42:14 -06:00
|
|
|
XSetForeground(dpy, dc.gc, col[ColBG].pixel);
|
2009-09-08 04:30:08 -05:00
|
|
|
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!text)
|
2009-09-08 04:30:08 -05:00
|
|
|
return;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
olen = strlen(text);
|
|
|
|
h = dc.font.ascent + dc.font.descent;
|
|
|
|
y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
|
|
|
|
x = dc.x + (h / 2);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
/* shorten text if necessary */
|
2016-01-03 06:00:57 -06:00
|
|
|
for (len = MIN(olen, sizeof(buf));
|
|
|
|
len && textnw(text, len) > dc.w - h; len--);
|
|
|
|
|
|
|
|
if (!len)
|
2009-09-08 04:30:08 -05:00
|
|
|
return;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
memcpy(buf, text, len);
|
2016-01-03 19:21:04 -06:00
|
|
|
if (len < olen) {
|
|
|
|
for (i = len, j = strlen(titletrim); j && i;
|
|
|
|
buf[--i] = titletrim[--j])
|
|
|
|
;
|
|
|
|
}
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-02-13 15:42:14 -06:00
|
|
|
d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen));
|
|
|
|
XftDrawStringUtf8(d, &col[ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len);
|
|
|
|
XftDrawDestroy(d);
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
|
|
|
|
2009-09-07 17:06:46 -05:00
|
|
|
void *
|
2016-01-03 06:00:57 -06:00
|
|
|
ecalloc(size_t n, size_t size)
|
|
|
|
{
|
2009-09-07 17:06:46 -05:00
|
|
|
void *p;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!(p = calloc(n, size)))
|
2016-01-03 06:01:14 -06:00
|
|
|
die("%s: cannot calloc\n", argv0);
|
2009-09-07 17:06:46 -05:00
|
|
|
return p;
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
|
2012-11-25 15:09:55 -06:00
|
|
|
void *
|
2016-01-03 06:00:57 -06:00
|
|
|
erealloc(void *o, size_t size)
|
|
|
|
{
|
2012-11-25 15:09:55 -06:00
|
|
|
void *p;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!(p = realloc(o, size)))
|
2016-01-03 06:01:14 -06:00
|
|
|
die("%s: cannot realloc\n", argv0);
|
2012-11-25 15:09:55 -06:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
expose(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XExposeEvent *ev = &e->xexpose;
|
2009-09-08 04:30:08 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (ev->count == 0 && win == ev->window)
|
2009-09-08 04:30:08 -05:00
|
|
|
drawbar();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
focus(int c)
|
|
|
|
{
|
2012-11-08 14:40:58 -06:00
|
|
|
char buf[BUFSIZ] = "tabbed-"VERSION" ::";
|
|
|
|
size_t i, n;
|
2014-05-13 18:34:44 -05:00
|
|
|
XWMHints* wmh;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2012-11-25 15:09:55 -06:00
|
|
|
/* If c, sel and clients are -1, raise tabbed-win itself */
|
2016-01-03 06:00:57 -06:00
|
|
|
if (nclients == 0) {
|
2013-11-28 11:26:21 -06:00
|
|
|
cmd[cmd_append_pos] = NULL;
|
2012-11-08 14:40:58 -06:00
|
|
|
for(i = 0, n = strlen(buf); cmd[i] && n < sizeof(buf); i++)
|
|
|
|
n += snprintf(&buf[n], sizeof(buf) - n, " %s", cmd[i]);
|
2011-11-20 10:38:48 -06:00
|
|
|
|
2013-01-16 11:33:50 -06:00
|
|
|
xsettitle(win, buf);
|
2010-02-16 12:56:22 -06:00
|
|
|
XRaiseWindow(dpy, win);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
return;
|
2009-09-08 11:55:43 -05:00
|
|
|
}
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (c < 0 || c >= nclients)
|
2012-11-25 15:09:55 -06:00
|
|
|
return;
|
|
|
|
|
2009-10-28 14:31:34 -05:00
|
|
|
resize(c, ww, wh - bh);
|
2012-11-25 15:09:55 -06:00
|
|
|
XRaiseWindow(dpy, clients[c]->win);
|
|
|
|
XSetInputFocus(dpy, clients[c]->win, RevertToParent, CurrentTime);
|
2009-10-27 07:13:15 -05:00
|
|
|
sendxembed(c, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0);
|
|
|
|
sendxembed(c, XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
|
2013-01-16 11:33:50 -06:00
|
|
|
xsettitle(win, clients[c]->name);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel != c) {
|
2009-12-15 02:26:01 -06:00
|
|
|
lastsel = sel;
|
2012-12-25 16:48:28 -06:00
|
|
|
sel = c;
|
2014-06-21 00:46:26 -05:00
|
|
|
}
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (clients[c]->urgent && (wmh = XGetWMHints(dpy, clients[c]->win))) {
|
2014-06-21 00:46:26 -05:00
|
|
|
wmh->flags &= ~XUrgencyHint;
|
|
|
|
XSetWMHints(dpy, clients[c]->win, wmh);
|
|
|
|
clients[c]->urgent = False;
|
|
|
|
XFree(wmh);
|
2012-12-25 16:48:28 -06:00
|
|
|
}
|
2012-11-27 13:25:56 -06:00
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
drawbar();
|
2012-12-25 16:48:28 -06:00
|
|
|
XSync(dpy, False);
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
|
2009-09-23 02:53:30 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
focusin(const XEvent *e)
|
|
|
|
{
|
2011-09-26 16:39:59 -05:00
|
|
|
const XFocusChangeEvent *ev = &e->xfocus;
|
|
|
|
int dummy;
|
|
|
|
Window focused;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (ev->mode != NotifyUngrab) {
|
2011-09-26 16:39:59 -05:00
|
|
|
XGetInputFocus(dpy, &focused, &dummy);
|
2016-01-03 06:00:57 -06:00
|
|
|
if (focused == win)
|
2011-09-26 16:39:59 -05:00
|
|
|
focus(sel);
|
|
|
|
}
|
2009-09-23 02:53:30 -05:00
|
|
|
}
|
|
|
|
|
2009-12-15 02:26:01 -06:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
focusonce(const Arg *arg)
|
|
|
|
{
|
2009-12-15 02:26:01 -06:00
|
|
|
nextfocus = True;
|
|
|
|
}
|
|
|
|
|
2015-08-19 14:11:15 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
focusurgent(const Arg *arg)
|
|
|
|
{
|
2015-08-19 14:11:15 -05:00
|
|
|
int c;
|
2016-01-03 06:00:57 -06:00
|
|
|
|
2017-05-07 20:08:37 -05:00
|
|
|
if (sel < 0)
|
|
|
|
return;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
for (c = (sel + 1) % nclients; c != sel; c = (c + 1) % nclients) {
|
|
|
|
if (clients[c]->urgent) {
|
2015-08-19 14:11:15 -05:00
|
|
|
focus(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-03 14:28:02 -06:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
fullscreen(const Arg *arg)
|
|
|
|
{
|
2012-12-03 14:28:02 -06:00
|
|
|
XEvent e;
|
|
|
|
|
|
|
|
e.type = ClientMessage;
|
|
|
|
e.xclient.window = win;
|
|
|
|
e.xclient.message_type = wmatom[WMState];
|
|
|
|
e.xclient.format = 32;
|
|
|
|
e.xclient.data.l[0] = 2;
|
|
|
|
e.xclient.data.l[1] = wmatom[WMFullscreen];
|
|
|
|
e.xclient.data.l[2] = 0;
|
|
|
|
XSendEvent(dpy, root, False, SubstructureNotifyMask, &e);
|
|
|
|
}
|
|
|
|
|
2013-11-28 11:26:21 -06:00
|
|
|
char *
|
2016-01-03 06:00:57 -06:00
|
|
|
getatom(int a)
|
|
|
|
{
|
2013-11-28 11:26:21 -06:00
|
|
|
static char buf[BUFSIZ];
|
|
|
|
Atom adummy;
|
|
|
|
int idummy;
|
|
|
|
unsigned long ldummy;
|
|
|
|
unsigned char *p = NULL;
|
|
|
|
|
|
|
|
XGetWindowProperty(dpy, win, wmatom[a], 0L, BUFSIZ, False, XA_STRING,
|
2016-01-03 06:00:57 -06:00
|
|
|
&adummy, &idummy, &ldummy, &ldummy, &p);
|
|
|
|
if (p)
|
2013-11-28 11:26:21 -06:00
|
|
|
strncpy(buf, (char *)p, LENGTH(buf)-1);
|
2016-01-03 06:00:57 -06:00
|
|
|
else
|
2013-11-28 11:26:21 -06:00
|
|
|
buf[0] = '\0';
|
|
|
|
XFree(p);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2012-11-25 15:09:55 -06:00
|
|
|
int
|
2016-01-03 06:00:57 -06:00
|
|
|
getclient(Window w)
|
|
|
|
{
|
2012-11-25 15:09:55 -06:00
|
|
|
int i;
|
2009-09-08 04:30:08 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
for (i = 0; i < nclients; i++) {
|
|
|
|
if (clients[i]->win == w)
|
2012-11-25 15:09:55 -06:00
|
|
|
return i;
|
2012-11-08 14:40:58 -06:00
|
|
|
}
|
|
|
|
|
2012-11-25 15:09:55 -06:00
|
|
|
return -1;
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
|
|
|
|
2016-02-13 15:42:14 -06:00
|
|
|
XftColor
|
2016-01-03 06:00:57 -06:00
|
|
|
getcolor(const char *colstr)
|
|
|
|
{
|
2016-02-13 15:42:14 -06:00
|
|
|
XftColor color;
|
2009-09-23 03:33:10 -05:00
|
|
|
|
2016-02-13 15:42:14 -06:00
|
|
|
if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), colstr, &color))
|
2016-01-03 06:01:14 -06:00
|
|
|
die("%s: cannot allocate color '%s'\n", argv0, colstr);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-02-13 15:42:14 -06:00
|
|
|
return color;
|
2009-09-23 03:33:10 -05:00
|
|
|
}
|
|
|
|
|
2012-11-25 15:09:55 -06:00
|
|
|
int
|
2016-01-03 06:00:57 -06:00
|
|
|
getfirsttab(void)
|
|
|
|
{
|
2015-01-20 20:46:38 -06:00
|
|
|
int cc, ret;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel < 0)
|
2015-01-20 20:46:38 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
cc = ww / tabwidth;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (nclients > cc)
|
2015-01-20 20:46:38 -06:00
|
|
|
cc = (ww - TEXTW(before) - TEXTW(after)) / tabwidth;
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2015-01-20 20:46:38 -06:00
|
|
|
ret = sel - cc / 2 + (cc + 1) % 2;
|
2016-01-03 06:00:57 -06:00
|
|
|
return ret < 0 ? 0 :
|
|
|
|
ret + cc > nclients ? MAX(0, nclients - cc) :
|
|
|
|
ret;
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
2016-01-03 06:00:57 -06:00
|
|
|
gettextprop(Window w, Atom atom, char *text, unsigned int size)
|
|
|
|
{
|
2009-09-08 04:30:08 -05:00
|
|
|
char **list = NULL;
|
|
|
|
int n;
|
|
|
|
XTextProperty name;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!text || size == 0)
|
2009-09-08 04:30:08 -05:00
|
|
|
return False;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
text[0] = '\0';
|
|
|
|
XGetTextProperty(dpy, w, &name, atom);
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!name.nitems)
|
2009-09-08 04:30:08 -05:00
|
|
|
return False;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (name.encoding == XA_STRING) {
|
2009-09-08 04:30:08 -05:00
|
|
|
strncpy(text, (char *)name.value, size - 1);
|
2016-01-03 06:00:57 -06:00
|
|
|
} else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
|
|
|
|
&& n > 0 && *list) {
|
|
|
|
strncpy(text, *list, size - 1);
|
|
|
|
XFreeStringList(list);
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
|
|
|
text[size - 1] = '\0';
|
|
|
|
XFree(name.value);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
initfont(const char *fontstr)
|
|
|
|
{
|
2016-02-13 15:42:14 -06:00
|
|
|
if (!(dc.font.xfont = XftFontOpenName(dpy, screen, fontstr))
|
|
|
|
&& !(dc.font.xfont = XftFontOpenName(dpy, screen, "fixed")))
|
|
|
|
die("error, cannot load font: '%s'\n", fontstr);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-02-13 15:42:14 -06:00
|
|
|
dc.font.ascent = dc.font.xfont->ascent;
|
|
|
|
dc.font.descent = dc.font.xfont->descent;
|
2009-09-07 06:32:58 -05:00
|
|
|
dc.font.height = dc.font.ascent + dc.font.descent;
|
|
|
|
}
|
|
|
|
|
2009-09-08 05:50:08 -05:00
|
|
|
Bool
|
2016-01-03 06:00:57 -06:00
|
|
|
isprotodel(int c)
|
|
|
|
{
|
2009-09-08 05:50:08 -05:00
|
|
|
int i, n;
|
|
|
|
Atom *protocols;
|
|
|
|
Bool ret = False;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (XGetWMProtocols(dpy, clients[c]->win, &protocols, &n)) {
|
|
|
|
for (i = 0; !ret && i < n; i++) {
|
|
|
|
if (protocols[i] == wmatom[WMDelete])
|
2009-09-08 05:50:08 -05:00
|
|
|
ret = True;
|
2012-11-08 14:40:58 -06:00
|
|
|
}
|
2009-09-08 05:50:08 -05:00
|
|
|
XFree(protocols);
|
|
|
|
}
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-08 05:50:08 -05:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
keypress(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XKeyEvent *ev = &e->xkey;
|
2009-09-07 06:32:58 -05:00
|
|
|
unsigned int i;
|
|
|
|
KeySym keysym;
|
|
|
|
|
2012-07-07 15:50:26 -05:00
|
|
|
keysym = XkbKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0, 0);
|
2016-01-03 06:00:57 -06:00
|
|
|
for (i = 0; i < LENGTH(keys); i++) {
|
|
|
|
if (keysym == keys[i].keysym &&
|
|
|
|
CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) &&
|
|
|
|
keys[i].func)
|
2009-09-07 06:32:58 -05:00
|
|
|
keys[i].func(&(keys[i].arg));
|
2012-11-08 14:40:58 -06:00
|
|
|
}
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
|
2009-09-07 15:21:27 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
killclient(const Arg *arg)
|
|
|
|
{
|
2009-09-08 05:50:08 -05:00
|
|
|
XEvent ev;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel < 0)
|
2009-09-08 05:50:08 -05:00
|
|
|
return;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (isprotodel(sel) && !clients[sel]->closed) {
|
2009-09-08 05:50:08 -05:00
|
|
|
ev.type = ClientMessage;
|
2012-11-25 15:09:55 -06:00
|
|
|
ev.xclient.window = clients[sel]->win;
|
2009-09-08 05:50:08 -05:00
|
|
|
ev.xclient.message_type = wmatom[WMProtocols];
|
|
|
|
ev.xclient.format = 32;
|
|
|
|
ev.xclient.data.l[0] = wmatom[WMDelete];
|
|
|
|
ev.xclient.data.l[1] = CurrentTime;
|
2012-11-25 15:09:55 -06:00
|
|
|
XSendEvent(dpy, clients[sel]->win, False, NoEventMask, &ev);
|
|
|
|
clients[sel]->closed = True;
|
2012-11-08 14:40:58 -06:00
|
|
|
} else {
|
2012-11-25 15:09:55 -06:00
|
|
|
XKillClient(dpy, clients[sel]->win);
|
2012-11-08 14:40:58 -06:00
|
|
|
}
|
2009-09-07 15:21:27 -05:00
|
|
|
}
|
|
|
|
|
2009-09-07 23:57:19 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
manage(Window w)
|
|
|
|
{
|
2009-09-08 04:30:08 -05:00
|
|
|
updatenumlockmask();
|
|
|
|
{
|
2012-12-25 16:48:28 -06:00
|
|
|
int i, j, nextpos;
|
2012-11-25 15:09:55 -06:00
|
|
|
unsigned int modifiers[] = { 0, LockMask, numlockmask,
|
2016-01-03 06:00:57 -06:00
|
|
|
numlockmask | LockMask };
|
2009-09-08 04:30:08 -05:00
|
|
|
KeyCode code;
|
|
|
|
Client *c;
|
2009-09-13 05:13:10 -05:00
|
|
|
XEvent e;
|
2009-09-08 04:30:08 -05:00
|
|
|
|
2009-09-13 05:13:10 -05:00
|
|
|
XWithdrawWindow(dpy, w, 0);
|
2009-09-08 04:30:08 -05:00
|
|
|
XReparentWindow(dpy, w, win, 0, bh);
|
2016-01-03 06:00:57 -06:00
|
|
|
XSelectInput(dpy, w, PropertyChangeMask |
|
|
|
|
StructureNotifyMask | EnterWindowMask);
|
2009-09-13 05:13:10 -05:00
|
|
|
XSync(dpy, False);
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
for (i = 0; i < LENGTH(keys); i++) {
|
|
|
|
if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) {
|
|
|
|
for (j = 0; j < LENGTH(modifiers); j++) {
|
|
|
|
XGrabKey(dpy, code, keys[i].mod |
|
|
|
|
modifiers[j], w, True,
|
|
|
|
GrabModeAsync, GrabModeAsync);
|
2012-11-25 15:09:55 -06:00
|
|
|
}
|
2012-11-08 14:40:58 -06:00
|
|
|
}
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2014-05-24 14:09:56 -05:00
|
|
|
c = ecalloc(1, sizeof *c);
|
2009-09-08 04:30:08 -05:00
|
|
|
c->win = w;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2012-11-25 15:09:55 -06:00
|
|
|
nclients++;
|
|
|
|
clients = erealloc(clients, sizeof(Client *) * nclients);
|
2012-12-25 16:48:28 -06:00
|
|
|
|
|
|
|
if(npisrelative) {
|
|
|
|
nextpos = sel + newposition;
|
|
|
|
} else {
|
2016-01-03 06:00:57 -06:00
|
|
|
if (newposition < 0)
|
2012-12-25 16:48:28 -06:00
|
|
|
nextpos = nclients - newposition;
|
2016-01-03 06:00:57 -06:00
|
|
|
else
|
2012-12-25 16:48:28 -06:00
|
|
|
nextpos = newposition;
|
|
|
|
}
|
2016-01-03 06:00:57 -06:00
|
|
|
if (nextpos >= nclients)
|
2012-12-25 16:48:28 -06:00
|
|
|
nextpos = nclients - 1;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (nextpos < 0)
|
2012-12-25 16:48:28 -06:00
|
|
|
nextpos = 0;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (nclients > 1 && nextpos < nclients - 1)
|
2012-12-25 16:48:28 -06:00
|
|
|
memmove(&clients[nextpos + 1], &clients[nextpos],
|
2016-01-03 06:00:57 -06:00
|
|
|
sizeof(Client *) * (nclients - nextpos - 1));
|
|
|
|
|
2012-12-25 16:48:28 -06:00
|
|
|
clients[nextpos] = c;
|
|
|
|
updatetitle(nextpos);
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2012-11-08 14:51:55 -06:00
|
|
|
XLowerWindow(dpy, w);
|
|
|
|
XMapWindow(dpy, w);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-13 05:13:10 -05:00
|
|
|
e.xclient.window = w;
|
|
|
|
e.xclient.type = ClientMessage;
|
2012-10-12 23:57:32 -05:00
|
|
|
e.xclient.message_type = wmatom[XEmbed];
|
2009-09-13 05:13:10 -05:00
|
|
|
e.xclient.format = 32;
|
|
|
|
e.xclient.data.l[0] = CurrentTime;
|
|
|
|
e.xclient.data.l[1] = XEMBED_EMBEDDED_NOTIFY;
|
|
|
|
e.xclient.data.l[2] = 0;
|
|
|
|
e.xclient.data.l[3] = win;
|
|
|
|
e.xclient.data.l[4] = 0;
|
|
|
|
XSendEvent(dpy, root, False, NoEventMask, &e);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-23 02:53:30 -05:00
|
|
|
XSync(dpy, False);
|
2012-12-25 16:48:28 -06:00
|
|
|
|
|
|
|
/* Adjust sel before focus does set it to lastsel. */
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel >= nextpos)
|
2012-12-25 16:48:28 -06:00
|
|
|
sel++;
|
2016-01-03 06:00:57 -06:00
|
|
|
focus(nextfocus ? nextpos :
|
|
|
|
sel < 0 ? 0 :
|
|
|
|
sel);
|
2009-12-15 02:26:01 -06:00
|
|
|
nextfocus = foreground;
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-28 14:09:53 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
maprequest(const XEvent *e)
|
|
|
|
{
|
2009-10-28 14:09:53 -05:00
|
|
|
const XMapRequestEvent *ev = &e->xmaprequest;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (getclient(ev->window) < 0)
|
2009-10-28 14:09:53 -05:00
|
|
|
manage(ev->window);
|
|
|
|
}
|
|
|
|
|
2009-09-23 03:33:10 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
move(const Arg *arg)
|
|
|
|
{
|
|
|
|
if (arg->i >= 0 && arg->i < nclients)
|
2012-11-25 15:09:55 -06:00
|
|
|
focus(arg->i);
|
|
|
|
}
|
2009-09-23 03:33:10 -05:00
|
|
|
|
2012-11-25 15:09:55 -06:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
movetab(const Arg *arg)
|
|
|
|
{
|
2012-11-25 15:09:55 -06:00
|
|
|
int c;
|
|
|
|
Client *new;
|
|
|
|
|
2017-05-07 20:08:37 -05:00
|
|
|
if (sel < 0)
|
|
|
|
return;
|
|
|
|
|
2014-10-07 10:15:59 -05:00
|
|
|
c = (sel + arg->i) % nclients;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (c < 0)
|
2012-11-25 15:09:55 -06:00
|
|
|
c += nclients;
|
|
|
|
|
2017-05-07 20:08:37 -05:00
|
|
|
if (c == sel)
|
2014-10-07 10:15:59 -05:00
|
|
|
return;
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2014-10-07 10:15:59 -05:00
|
|
|
new = clients[sel];
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel < c)
|
|
|
|
memmove(&clients[sel], &clients[sel+1],
|
|
|
|
sizeof(Client *) * (c - sel));
|
2014-10-07 10:15:59 -05:00
|
|
|
else
|
2016-01-03 06:00:57 -06:00
|
|
|
memmove(&clients[c+1], &clients[c],
|
|
|
|
sizeof(Client *) * (sel - c));
|
2014-10-07 10:15:59 -05:00
|
|
|
clients[c] = new;
|
2012-11-25 15:09:55 -06:00
|
|
|
sel = c;
|
|
|
|
|
|
|
|
drawbar();
|
2009-09-23 03:33:10 -05:00
|
|
|
}
|
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
propertynotify(const XEvent *e)
|
|
|
|
{
|
2009-10-13 12:52:34 -05:00
|
|
|
const XPropertyEvent *ev = &e->xproperty;
|
2014-05-13 18:34:44 -05:00
|
|
|
XWMHints *wmh;
|
2012-11-25 15:09:55 -06:00
|
|
|
int c;
|
2013-11-28 11:26:21 -06:00
|
|
|
char* selection = NULL;
|
|
|
|
Arg arg;
|
2009-09-08 04:30:08 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (ev->state == PropertyNewValue && ev->atom == wmatom[WMSelectTab]) {
|
2013-11-28 11:26:21 -06:00
|
|
|
selection = getatom(WMSelectTab);
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!strncmp(selection, "0x", 2)) {
|
2013-11-28 11:26:21 -06:00
|
|
|
arg.i = getclient(strtoul(selection, NULL, 0));
|
|
|
|
move(&arg);
|
|
|
|
} else {
|
|
|
|
cmd[cmd_append_pos] = selection;
|
|
|
|
arg.v = cmd;
|
|
|
|
spawn(&arg);
|
|
|
|
}
|
2016-01-03 06:00:57 -06:00
|
|
|
} else if (ev->state == PropertyNewValue && ev->atom == XA_WM_HINTS &&
|
|
|
|
(c = getclient(ev->window)) > -1 &&
|
|
|
|
(wmh = XGetWMHints(dpy, clients[c]->win))) {
|
|
|
|
if (wmh->flags & XUrgencyHint) {
|
autofocus urgent tabs
When tabbed becomes urgent because one of it tabs becomes urgent, it
may be desireable to automatically focus that tab. As a notification may
be lost, if another notification comes in before you focused tabbed, the
switch is only done, if tabbed is not urgent already.
Moreover, it may be anoying, if you just type into one tab, another tab
gets urgent -therfore focused- and you type into the other tab, you may
switch between autofocus and nofocus using Ctrl-Shift-u.
Maybe it would also be usefull, if there would be an commandline
parameter to toggle that option, but as -u is already used for
urgent-tab-color, i did not implement that.
Signed-off-by: Jonas Rabenstein <jonas.rabenstein@studium.uni-erlangen.de>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
2015-08-19 14:11:16 -05:00
|
|
|
XFree(wmh);
|
|
|
|
wmh = XGetWMHints(dpy, win);
|
2016-01-03 06:00:57 -06:00
|
|
|
if (c != sel) {
|
|
|
|
if (urgentswitch && wmh &&
|
|
|
|
!(wmh->flags & XUrgencyHint)) {
|
|
|
|
/* only switch, if tabbed was focused
|
|
|
|
* since last urgency hint if WMHints
|
|
|
|
* could not be received,
|
|
|
|
* default to no switch */
|
autofocus urgent tabs
When tabbed becomes urgent because one of it tabs becomes urgent, it
may be desireable to automatically focus that tab. As a notification may
be lost, if another notification comes in before you focused tabbed, the
switch is only done, if tabbed is not urgent already.
Moreover, it may be anoying, if you just type into one tab, another tab
gets urgent -therfore focused- and you type into the other tab, you may
switch between autofocus and nofocus using Ctrl-Shift-u.
Maybe it would also be usefull, if there would be an commandline
parameter to toggle that option, but as -u is already used for
urgent-tab-color, i did not implement that.
Signed-off-by: Jonas Rabenstein <jonas.rabenstein@studium.uni-erlangen.de>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
2015-08-19 14:11:16 -05:00
|
|
|
focus(c);
|
|
|
|
} else {
|
2016-01-03 06:00:57 -06:00
|
|
|
/* if no switch should be performed,
|
|
|
|
* mark tab as urgent */
|
autofocus urgent tabs
When tabbed becomes urgent because one of it tabs becomes urgent, it
may be desireable to automatically focus that tab. As a notification may
be lost, if another notification comes in before you focused tabbed, the
switch is only done, if tabbed is not urgent already.
Moreover, it may be anoying, if you just type into one tab, another tab
gets urgent -therfore focused- and you type into the other tab, you may
switch between autofocus and nofocus using Ctrl-Shift-u.
Maybe it would also be usefull, if there would be an commandline
parameter to toggle that option, but as -u is already used for
urgent-tab-color, i did not implement that.
Signed-off-by: Jonas Rabenstein <jonas.rabenstein@studium.uni-erlangen.de>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
2015-08-19 14:11:16 -05:00
|
|
|
clients[c]->urgent = True;
|
|
|
|
drawbar();
|
|
|
|
}
|
2014-05-13 18:34:44 -05:00
|
|
|
}
|
2016-01-03 06:00:57 -06:00
|
|
|
if (wmh && !(wmh->flags & XUrgencyHint)) {
|
|
|
|
/* update tabbed urgency hint
|
|
|
|
* if not set already */
|
2014-05-13 18:34:44 -05:00
|
|
|
wmh->flags |= XUrgencyHint;
|
|
|
|
XSetWMHints(dpy, win, wmh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
XFree(wmh);
|
2016-01-03 06:00:57 -06:00
|
|
|
} else if (ev->state != PropertyDelete && ev->atom == XA_WM_NAME &&
|
|
|
|
(c = getclient(ev->window)) > -1) {
|
2009-09-08 04:30:08 -05:00
|
|
|
updatetitle(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
resize(int c, int w, int h)
|
|
|
|
{
|
2009-09-08 04:30:08 -05:00
|
|
|
XConfigureEvent ce;
|
|
|
|
XWindowChanges wc;
|
|
|
|
|
|
|
|
ce.x = 0;
|
2020-05-12 10:09:01 -05:00
|
|
|
ce.y = wc.y = bh;
|
2009-09-08 04:30:08 -05:00
|
|
|
ce.width = wc.width = w;
|
|
|
|
ce.height = wc.height = h;
|
|
|
|
ce.type = ConfigureNotify;
|
|
|
|
ce.display = dpy;
|
2012-11-25 15:09:55 -06:00
|
|
|
ce.event = clients[c]->win;
|
|
|
|
ce.window = clients[c]->win;
|
2009-09-08 04:30:08 -05:00
|
|
|
ce.above = None;
|
|
|
|
ce.override_redirect = False;
|
|
|
|
ce.border_width = 0;
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2020-05-12 10:09:01 -05:00
|
|
|
XConfigureWindow(dpy, clients[c]->win, CWY | CWWidth | CWHeight, &wc);
|
2012-11-25 15:09:55 -06:00
|
|
|
XSendEvent(dpy, clients[c]->win, False, StructureNotifyMask,
|
2016-01-03 06:00:57 -06:00
|
|
|
(XEvent *)&ce);
|
2009-09-07 23:57:19 -05:00
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
rotate(const Arg *arg)
|
|
|
|
{
|
2012-11-25 15:09:55 -06:00
|
|
|
int nsel = -1;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel < 0)
|
2012-11-25 15:09:55 -06:00
|
|
|
return;
|
2009-09-08 04:30:08 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (arg->i == 0) {
|
|
|
|
if (lastsel > -1)
|
2012-11-25 15:09:55 -06:00
|
|
|
focus(lastsel);
|
2016-01-03 06:00:57 -06:00
|
|
|
} else if (sel > -1) {
|
2012-11-25 15:09:55 -06:00
|
|
|
/* Rotating in an arg->i step around the clients. */
|
|
|
|
nsel = sel + arg->i;
|
2016-01-03 06:00:57 -06:00
|
|
|
while (nsel >= nclients)
|
2012-11-25 15:09:55 -06:00
|
|
|
nsel -= nclients;
|
2016-01-03 06:00:57 -06:00
|
|
|
while (nsel < 0)
|
2012-11-25 15:09:55 -06:00
|
|
|
nsel += nclients;
|
|
|
|
focus(nsel);
|
2009-09-08 04:30:08 -05:00
|
|
|
}
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
run(void)
|
|
|
|
{
|
2009-09-07 06:32:58 -05:00
|
|
|
XEvent ev;
|
|
|
|
|
2009-10-13 12:37:20 -05:00
|
|
|
/* main event loop */
|
2009-09-07 06:32:58 -05:00
|
|
|
XSync(dpy, False);
|
2009-09-08 11:55:43 -05:00
|
|
|
drawbar();
|
2016-01-03 06:00:57 -06:00
|
|
|
if (doinitspawn == True)
|
2012-02-09 10:39:33 -06:00
|
|
|
spawn(NULL);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
while (running) {
|
2009-09-11 06:08:27 -05:00
|
|
|
XNextEvent(dpy, &ev);
|
2016-01-03 06:00:57 -06:00
|
|
|
if (handler[ev.type])
|
2009-09-11 06:08:27 -05:00
|
|
|
(handler[ev.type])(&ev); /* call handler */
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-28 14:31:34 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
sendxembed(int c, long msg, long detail, long d1, long d2)
|
|
|
|
{
|
2009-10-28 14:31:34 -05:00
|
|
|
XEvent e = { 0 };
|
|
|
|
|
2012-11-25 15:09:55 -06:00
|
|
|
e.xclient.window = clients[c]->win;
|
2009-10-28 14:31:34 -05:00
|
|
|
e.xclient.type = ClientMessage;
|
2012-10-12 23:57:32 -05:00
|
|
|
e.xclient.message_type = wmatom[XEmbed];
|
2009-10-28 14:31:34 -05:00
|
|
|
e.xclient.format = 32;
|
|
|
|
e.xclient.data.l[0] = CurrentTime;
|
|
|
|
e.xclient.data.l[1] = msg;
|
|
|
|
e.xclient.data.l[2] = detail;
|
|
|
|
e.xclient.data.l[3] = d1;
|
|
|
|
e.xclient.data.l[4] = d2;
|
2012-11-25 15:09:55 -06:00
|
|
|
XSendEvent(dpy, clients[c]->win, False, NoEventMask, &e);
|
2009-10-28 14:31:34 -05:00
|
|
|
}
|
|
|
|
|
2011-05-06 15:40:53 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
setcmd(int argc, char *argv[], int replace)
|
|
|
|
{
|
2011-05-06 15:40:53 -05:00
|
|
|
int i;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
cmd = ecalloc(argc + 3, sizeof(*cmd));
|
2013-07-07 13:41:24 -05:00
|
|
|
if (argc == 0)
|
|
|
|
return;
|
2016-01-03 06:00:57 -06:00
|
|
|
for (i = 0; i < argc; i++)
|
2011-05-06 15:40:53 -05:00
|
|
|
cmd[i] = argv[i];
|
2016-01-03 06:00:57 -06:00
|
|
|
cmd[replace > 0 ? replace : argc] = winid;
|
2013-11-28 11:26:21 -06:00
|
|
|
cmd_append_pos = argc + !replace;
|
2016-01-03 06:00:57 -06:00
|
|
|
cmd[cmd_append_pos] = cmd[cmd_append_pos + 1] = NULL;
|
2011-05-06 15:40:53 -05:00
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
setup(void)
|
|
|
|
{
|
2013-08-20 11:44:00 -05:00
|
|
|
int bitm, tx, ty, tw, th, dh, dw, isfixed;
|
2014-05-13 18:34:44 -05:00
|
|
|
XWMHints *wmh;
|
2013-08-20 11:44:00 -05:00
|
|
|
XClassHint class_hint;
|
|
|
|
XSizeHints *size_hint;
|
|
|
|
|
2009-09-23 03:33:10 -05:00
|
|
|
/* clean up any zombies immediately */
|
|
|
|
sigchld(0);
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
/* init screen */
|
|
|
|
screen = DefaultScreen(dpy);
|
|
|
|
root = RootWindow(dpy, screen);
|
|
|
|
initfont(font);
|
2009-09-08 04:30:08 -05:00
|
|
|
bh = dc.h = dc.font.height + 2;
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2009-09-08 05:50:08 -05:00
|
|
|
/* init atoms */
|
|
|
|
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
2016-01-03 06:00:57 -06:00
|
|
|
wmatom[WMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN",
|
|
|
|
False);
|
2012-10-12 23:57:32 -05:00
|
|
|
wmatom[WMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
|
2016-01-03 06:00:57 -06:00
|
|
|
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
2013-11-28 11:26:21 -06:00
|
|
|
wmatom[WMSelectTab] = XInternAtom(dpy, "_TABBED_SELECT_TAB", False);
|
2016-01-03 06:00:57 -06:00
|
|
|
wmatom[WMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
|
|
|
|
wmatom[XEmbed] = XInternAtom(dpy, "_XEMBED", False);
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
/* init appearance */
|
|
|
|
wx = 0;
|
|
|
|
wy = 0;
|
|
|
|
ww = 800;
|
|
|
|
wh = 600;
|
2013-08-20 11:44:00 -05:00
|
|
|
isfixed = 0;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (geometry) {
|
2013-08-20 11:44:00 -05:00
|
|
|
tx = ty = tw = th = 0;
|
|
|
|
bitm = XParseGeometry(geometry, &tx, &ty, (unsigned *)&tw,
|
2016-01-03 06:00:57 -06:00
|
|
|
(unsigned *)&th);
|
|
|
|
if (bitm & XValue)
|
2013-08-20 11:44:00 -05:00
|
|
|
wx = tx;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (bitm & YValue)
|
2013-08-20 11:44:00 -05:00
|
|
|
wy = ty;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (bitm & WidthValue)
|
2013-08-20 11:44:00 -05:00
|
|
|
ww = tw;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (bitm & HeightValue)
|
2013-08-20 11:44:00 -05:00
|
|
|
wh = th;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (bitm & XNegative && wx == 0)
|
2013-08-20 11:44:00 -05:00
|
|
|
wx = -1;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (bitm & YNegative && wy == 0)
|
2013-08-20 11:44:00 -05:00
|
|
|
wy = -1;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (bitm & (HeightValue | WidthValue))
|
2013-08-20 11:44:00 -05:00
|
|
|
isfixed = 1;
|
|
|
|
|
|
|
|
dw = DisplayWidth(dpy, screen);
|
|
|
|
dh = DisplayHeight(dpy, screen);
|
2016-01-03 06:00:57 -06:00
|
|
|
if (wx < 0)
|
2013-08-20 11:44:00 -05:00
|
|
|
wx = dw + wx - ww - 1;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (wy < 0)
|
2013-08-20 11:44:00 -05:00
|
|
|
wy = dh + wy - wh - 1;
|
|
|
|
}
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
dc.norm[ColBG] = getcolor(normbgcolor);
|
|
|
|
dc.norm[ColFG] = getcolor(normfgcolor);
|
|
|
|
dc.sel[ColBG] = getcolor(selbgcolor);
|
|
|
|
dc.sel[ColFG] = getcolor(selfgcolor);
|
2014-05-13 18:34:44 -05:00
|
|
|
dc.urg[ColBG] = getcolor(urgbgcolor);
|
|
|
|
dc.urg[ColFG] = getcolor(urgfgcolor);
|
2012-11-08 14:40:58 -06:00
|
|
|
dc.drawable = XCreatePixmap(dpy, root, ww, wh,
|
2016-01-03 06:00:57 -06:00
|
|
|
DefaultDepth(dpy, screen));
|
2009-09-07 06:32:58 -05:00
|
|
|
dc.gc = XCreateGC(dpy, root, 0, 0);
|
|
|
|
|
2012-11-08 14:40:58 -06:00
|
|
|
win = XCreateSimpleWindow(dpy, root, wx, wy, ww, wh, 0,
|
2016-02-13 15:42:14 -06:00
|
|
|
dc.norm[ColFG].pixel, dc.norm[ColBG].pixel);
|
2009-09-07 06:32:58 -05:00
|
|
|
XMapRaised(dpy, win);
|
2016-01-03 06:00:57 -06:00
|
|
|
XSelectInput(dpy, win, SubstructureNotifyMask | FocusChangeMask |
|
|
|
|
ButtonPressMask | ExposureMask | KeyPressMask |
|
|
|
|
PropertyChangeMask | StructureNotifyMask |
|
|
|
|
SubstructureRedirectMask);
|
2009-09-11 06:08:27 -05:00
|
|
|
xerrorxlib = XSetErrorHandler(xerror);
|
2012-10-03 00:56:53 -05:00
|
|
|
|
|
|
|
class_hint.res_name = wmname;
|
|
|
|
class_hint.res_class = "tabbed";
|
2009-09-08 06:06:13 -05:00
|
|
|
XSetClassHint(dpy, win, &class_hint);
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2013-08-20 11:44:00 -05:00
|
|
|
size_hint = XAllocSizeHints();
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!isfixed) {
|
2020-05-12 10:09:01 -05:00
|
|
|
size_hint->flags = PSize | PMinSize;
|
2013-08-20 11:44:00 -05:00
|
|
|
size_hint->height = wh;
|
|
|
|
size_hint->width = ww;
|
2020-05-12 10:09:01 -05:00
|
|
|
size_hint->min_height = bh + 1;
|
2013-08-20 11:44:00 -05:00
|
|
|
} else {
|
|
|
|
size_hint->flags = PMaxSize | PMinSize;
|
|
|
|
size_hint->min_width = size_hint->max_width = ww;
|
|
|
|
size_hint->min_height = size_hint->max_height = wh;
|
|
|
|
}
|
2014-05-13 18:34:44 -05:00
|
|
|
wmh = XAllocWMHints();
|
|
|
|
XSetWMProperties(dpy, win, NULL, NULL, NULL, 0, size_hint, wmh, NULL);
|
2013-08-20 11:44:00 -05:00
|
|
|
XFree(size_hint);
|
2014-05-13 18:34:44 -05:00
|
|
|
XFree(wmh);
|
2013-08-20 11:44:00 -05:00
|
|
|
|
2009-10-26 10:50:38 -05:00
|
|
|
XSetWMProtocols(dpy, win, &wmatom[WMDelete], 1);
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2012-11-08 14:40:58 -06:00
|
|
|
snprintf(winid, sizeof(winid), "%lu", win);
|
2012-12-25 16:50:21 -06:00
|
|
|
setenv("XEMBED", winid, 1);
|
|
|
|
|
2009-12-15 02:26:01 -06:00
|
|
|
nextfocus = foreground;
|
2012-11-25 15:09:55 -06:00
|
|
|
focus(-1);
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
|
2009-09-23 03:33:10 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
sigchld(int unused)
|
|
|
|
{
|
|
|
|
if (signal(SIGCHLD, sigchld) == SIG_ERR)
|
2016-01-03 06:01:14 -06:00
|
|
|
die("%s: cannot install SIGCHLD handler", argv0);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
while (0 < waitpid(-1, NULL, WNOHANG));
|
2009-09-23 03:33:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
spawn(const Arg *arg)
|
|
|
|
{
|
|
|
|
if (fork() == 0) {
|
2009-09-23 03:33:10 -05:00
|
|
|
if(dpy)
|
|
|
|
close(ConnectionNumber(dpy));
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-23 03:33:10 -05:00
|
|
|
setsid();
|
2016-01-03 06:00:57 -06:00
|
|
|
if (arg && arg->v) {
|
2012-08-20 02:05:45 -05:00
|
|
|
execvp(((char **)arg->v)[0], (char **)arg->v);
|
2016-01-03 06:01:14 -06:00
|
|
|
fprintf(stderr, "%s: execvp %s", argv0,
|
2016-01-03 06:00:57 -06:00
|
|
|
((char **)arg->v)[0]);
|
2012-08-20 02:02:56 -05:00
|
|
|
} else {
|
2013-11-28 11:26:21 -06:00
|
|
|
cmd[cmd_append_pos] = NULL;
|
2012-08-20 02:02:56 -05:00
|
|
|
execvp(cmd[0], cmd);
|
2016-01-03 06:01:14 -06:00
|
|
|
fprintf(stderr, "%s: execvp %s", argv0, cmd[0]);
|
2012-08-20 02:02:56 -05:00
|
|
|
}
|
2009-09-23 03:33:10 -05:00
|
|
|
perror(" failed");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
int
|
2016-01-03 06:00:57 -06:00
|
|
|
textnw(const char *text, unsigned int len)
|
|
|
|
{
|
2016-02-13 15:42:14 -06:00
|
|
|
XGlyphInfo ext;
|
|
|
|
XftTextExtentsUtf8(dpy, dc.font.xfont, (XftChar8 *) text, len, &ext);
|
|
|
|
return ext.xOff;
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|
|
|
|
|
autofocus urgent tabs
When tabbed becomes urgent because one of it tabs becomes urgent, it
may be desireable to automatically focus that tab. As a notification may
be lost, if another notification comes in before you focused tabbed, the
switch is only done, if tabbed is not urgent already.
Moreover, it may be anoying, if you just type into one tab, another tab
gets urgent -therfore focused- and you type into the other tab, you may
switch between autofocus and nofocus using Ctrl-Shift-u.
Maybe it would also be usefull, if there would be an commandline
parameter to toggle that option, but as -u is already used for
urgent-tab-color, i did not implement that.
Signed-off-by: Jonas Rabenstein <jonas.rabenstein@studium.uni-erlangen.de>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
2015-08-19 14:11:16 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
toggle(const Arg *arg)
|
|
|
|
{
|
autofocus urgent tabs
When tabbed becomes urgent because one of it tabs becomes urgent, it
may be desireable to automatically focus that tab. As a notification may
be lost, if another notification comes in before you focused tabbed, the
switch is only done, if tabbed is not urgent already.
Moreover, it may be anoying, if you just type into one tab, another tab
gets urgent -therfore focused- and you type into the other tab, you may
switch between autofocus and nofocus using Ctrl-Shift-u.
Maybe it would also be usefull, if there would be an commandline
parameter to toggle that option, but as -u is already used for
urgent-tab-color, i did not implement that.
Signed-off-by: Jonas Rabenstein <jonas.rabenstein@studium.uni-erlangen.de>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
2015-08-19 14:11:16 -05:00
|
|
|
*(Bool*) arg->v = !*(Bool*) arg->v;
|
|
|
|
}
|
|
|
|
|
2009-09-08 05:50:08 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
unmanage(int c)
|
|
|
|
{
|
|
|
|
if (c < 0 || c >= nclients) {
|
2012-11-27 13:25:56 -06:00
|
|
|
drawbar();
|
2012-12-25 16:48:28 -06:00
|
|
|
XSync(dpy, False);
|
2012-11-25 15:09:55 -06:00
|
|
|
return;
|
2012-11-27 13:25:56 -06:00
|
|
|
}
|
2009-09-08 05:50:08 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!nclients)
|
2009-09-08 11:55:43 -05:00
|
|
|
return;
|
2014-01-26 13:05:40 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (c == 0) {
|
2012-11-25 15:09:55 -06:00
|
|
|
/* First client. */
|
|
|
|
nclients--;
|
|
|
|
free(clients[0]);
|
|
|
|
memmove(&clients[0], &clients[1], sizeof(Client *) * nclients);
|
2016-01-03 06:00:57 -06:00
|
|
|
} else if (c == nclients - 1) {
|
2012-11-25 15:09:55 -06:00
|
|
|
/* Last client. */
|
|
|
|
nclients--;
|
|
|
|
free(clients[c]);
|
|
|
|
clients = erealloc(clients, sizeof(Client *) * nclients);
|
2012-11-08 14:40:58 -06:00
|
|
|
} else {
|
2012-11-25 15:09:55 -06:00
|
|
|
/* Somewhere inbetween. */
|
|
|
|
free(clients[c]);
|
|
|
|
memmove(&clients[c], &clients[c+1],
|
2016-01-03 06:00:57 -06:00
|
|
|
sizeof(Client *) * (nclients - (c + 1)));
|
2012-11-25 15:09:55 -06:00
|
|
|
nclients--;
|
2009-09-08 11:55:43 -05:00
|
|
|
}
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (nclients <= 0) {
|
2014-01-26 13:05:40 -06:00
|
|
|
lastsel = sel = -1;
|
2012-11-25 15:09:55 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (closelastclient)
|
2012-12-25 09:50:32 -06:00
|
|
|
running = False;
|
2016-01-03 06:00:57 -06:00
|
|
|
else if (fillagain && running)
|
2012-12-25 09:50:32 -06:00
|
|
|
spawn(NULL);
|
2012-12-25 16:48:28 -06:00
|
|
|
} else {
|
2016-01-03 06:00:57 -06:00
|
|
|
if (lastsel >= nclients)
|
2014-01-26 11:48:52 -06:00
|
|
|
lastsel = nclients - 1;
|
2016-01-03 06:00:57 -06:00
|
|
|
else if (lastsel > c)
|
2012-12-25 16:48:28 -06:00
|
|
|
lastsel--;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (c == sel && lastsel >= 0) {
|
2014-01-26 13:05:40 -06:00
|
|
|
focus(lastsel);
|
2012-12-25 16:48:28 -06:00
|
|
|
} else {
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel > c)
|
2014-01-26 13:05:40 -06:00
|
|
|
sel--;
|
2016-01-03 06:00:57 -06:00
|
|
|
if (sel >= nclients)
|
2012-12-25 16:48:28 -06:00
|
|
|
sel = nclients - 1;
|
|
|
|
|
|
|
|
focus(sel);
|
|
|
|
}
|
2012-12-25 09:50:32 -06:00
|
|
|
}
|
2012-11-26 07:55:26 -06:00
|
|
|
|
2010-02-16 12:53:03 -06:00
|
|
|
drawbar();
|
2009-09-08 05:50:08 -05:00
|
|
|
XSync(dpy, False);
|
2009-09-07 17:06:46 -05:00
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
unmapnotify(const XEvent *e)
|
|
|
|
{
|
|
|
|
const XUnmapEvent *ev = &e->xunmap;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
if ((c = getclient(ev->window)) > -1)
|
|
|
|
unmanage(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
updatenumlockmask(void)
|
|
|
|
{
|
2009-09-07 06:32:58 -05:00
|
|
|
unsigned int i, j;
|
|
|
|
XModifierKeymap *modmap;
|
|
|
|
|
|
|
|
numlockmask = 0;
|
|
|
|
modmap = XGetModifierMapping(dpy);
|
2016-01-03 06:00:57 -06:00
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
for (j = 0; j < modmap->max_keypermod; j++) {
|
|
|
|
if (modmap->modifiermap[i * modmap->max_keypermod + j]
|
|
|
|
== XKeysymToKeycode(dpy, XK_Num_Lock))
|
2009-09-07 06:32:58 -05:00
|
|
|
numlockmask = (1 << i);
|
2012-11-08 14:40:58 -06:00
|
|
|
}
|
|
|
|
}
|
2009-09-07 06:32:58 -05:00
|
|
|
XFreeModifiermap(modmap);
|
|
|
|
}
|
|
|
|
|
2009-09-08 04:30:08 -05:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
updatetitle(int c)
|
|
|
|
{
|
|
|
|
if (!gettextprop(clients[c]->win, wmatom[WMName], clients[c]->name,
|
|
|
|
sizeof(clients[c]->name)))
|
|
|
|
gettextprop(clients[c]->win, XA_WM_NAME, clients[c]->name,
|
|
|
|
sizeof(clients[c]->name));
|
|
|
|
if (sel == c)
|
2013-01-16 11:33:50 -06:00
|
|
|
xsettitle(win, clients[c]->name);
|
2009-09-08 04:30:08 -05:00
|
|
|
drawbar();
|
|
|
|
}
|
|
|
|
|
2009-09-08 00:34:15 -05:00
|
|
|
/* There's no way to check accesses to destroyed windows, thus those cases are
|
|
|
|
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
|
|
|
|
* default error handler, which may call exit. */
|
|
|
|
int
|
2016-01-03 06:00:57 -06:00
|
|
|
xerror(Display *dpy, XErrorEvent *ee)
|
|
|
|
{
|
|
|
|
if (ee->error_code == BadWindow
|
|
|
|
|| (ee->request_code == X_SetInputFocus &&
|
|
|
|
ee->error_code == BadMatch)
|
|
|
|
|| (ee->request_code == X_PolyText8 &&
|
|
|
|
ee->error_code == BadDrawable)
|
|
|
|
|| (ee->request_code == X_PolyFillRectangle &&
|
|
|
|
ee->error_code == BadDrawable)
|
|
|
|
|| (ee->request_code == X_PolySegment &&
|
|
|
|
ee->error_code == BadDrawable)
|
|
|
|
|| (ee->request_code == X_ConfigureWindow &&
|
|
|
|
ee->error_code == BadMatch)
|
|
|
|
|| (ee->request_code == X_GrabButton &&
|
|
|
|
ee->error_code == BadAccess)
|
|
|
|
|| (ee->request_code == X_GrabKey &&
|
|
|
|
ee->error_code == BadAccess)
|
|
|
|
|| (ee->request_code == X_CopyArea &&
|
|
|
|
ee->error_code == BadDrawable))
|
2009-10-28 05:40:02 -05:00
|
|
|
return 0;
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2016-01-03 06:01:14 -06:00
|
|
|
fprintf(stderr, "%s: fatal error: request code=%d, error code=%d\n",
|
|
|
|
argv0, ee->request_code, ee->error_code);
|
2009-09-11 06:08:27 -05:00
|
|
|
return xerrorxlib(dpy, ee); /* may call exit */
|
2009-09-08 00:34:15 -05:00
|
|
|
}
|
|
|
|
|
2013-01-16 11:33:50 -06:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
xsettitle(Window w, const char *str)
|
|
|
|
{
|
2013-01-16 11:33:50 -06:00
|
|
|
XTextProperty xtp;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (XmbTextListToTextProperty(dpy, (char **)&str, 1,
|
|
|
|
XCompoundTextStyle, &xtp) == Success) {
|
2013-01-16 11:33:50 -06:00
|
|
|
XSetTextProperty(dpy, w, &xtp, wmatom[WMName]);
|
|
|
|
XSetTextProperty(dpy, w, &xtp, XA_WM_NAME);
|
|
|
|
XFree(xtp.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-09 10:39:33 -06:00
|
|
|
void
|
2016-01-03 06:00:57 -06:00
|
|
|
usage(void)
|
|
|
|
{
|
2016-03-20 21:16:12 -05:00
|
|
|
die("usage: %s [-dfksv] [-g geometry] [-n name] [-p [s+/-]pos]\n"
|
2016-01-03 06:01:14 -06:00
|
|
|
" [-r narg] [-o color] [-O color] [-t color] [-T color]\n"
|
|
|
|
" [-u color] [-U color] command...\n", argv0);
|
2012-02-09 10:39:33 -06:00
|
|
|
}
|
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
int
|
2016-01-03 06:00:57 -06:00
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
2012-12-25 09:50:32 -06:00
|
|
|
Bool detach = False;
|
|
|
|
int replace = 0;
|
2012-12-25 16:48:28 -06:00
|
|
|
char *pstr;
|
2012-04-06 13:44:47 -05:00
|
|
|
|
|
|
|
ARGBEGIN {
|
2012-12-25 09:50:32 -06:00
|
|
|
case 'c':
|
|
|
|
closelastclient = True;
|
|
|
|
fillagain = False;
|
2013-12-12 11:06:51 -06:00
|
|
|
break;
|
2012-10-03 00:56:53 -05:00
|
|
|
case 'd':
|
2012-12-25 09:50:32 -06:00
|
|
|
detach = True;
|
2012-10-03 00:56:53 -05:00
|
|
|
break;
|
2012-11-26 07:55:26 -06:00
|
|
|
case 'f':
|
2012-12-25 09:50:32 -06:00
|
|
|
fillagain = True;
|
2012-11-26 07:55:26 -06:00
|
|
|
break;
|
2013-08-20 11:44:00 -05:00
|
|
|
case 'g':
|
|
|
|
geometry = EARGF(usage());
|
|
|
|
break;
|
2016-03-20 21:16:12 -05:00
|
|
|
case 'k':
|
|
|
|
killclientsfirst = True;
|
|
|
|
break;
|
2012-10-03 00:56:53 -05:00
|
|
|
case 'n':
|
|
|
|
wmname = EARGF(usage());
|
|
|
|
break;
|
2016-01-03 06:00:57 -06:00
|
|
|
case 'O':
|
|
|
|
normfgcolor = EARGF(usage());
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
normbgcolor = EARGF(usage());
|
|
|
|
break;
|
2012-12-25 16:48:28 -06:00
|
|
|
case 'p':
|
|
|
|
pstr = EARGF(usage());
|
2016-01-03 06:00:57 -06:00
|
|
|
if (pstr[0] == 's') {
|
2012-12-25 16:48:28 -06:00
|
|
|
npisrelative = True;
|
2012-12-25 17:02:50 -06:00
|
|
|
newposition = atoi(&pstr[1]);
|
|
|
|
} else {
|
|
|
|
newposition = atoi(pstr);
|
|
|
|
}
|
2012-12-25 16:48:28 -06:00
|
|
|
break;
|
2012-11-08 14:48:51 -06:00
|
|
|
case 'r':
|
|
|
|
replace = atoi(EARGF(usage()));
|
|
|
|
break;
|
2012-10-03 00:56:53 -05:00
|
|
|
case 's':
|
|
|
|
doinitspawn = False;
|
|
|
|
break;
|
2016-01-03 06:00:57 -06:00
|
|
|
case 'T':
|
|
|
|
selfgcolor = EARGF(usage());
|
2014-05-13 18:50:10 -05:00
|
|
|
break;
|
2013-12-12 11:06:51 -06:00
|
|
|
case 't':
|
|
|
|
selbgcolor = EARGF(usage());
|
|
|
|
break;
|
2016-01-03 06:00:57 -06:00
|
|
|
case 'U':
|
|
|
|
urgfgcolor = EARGF(usage());
|
2013-12-12 11:06:51 -06:00
|
|
|
break;
|
|
|
|
case 'u':
|
2014-05-13 18:50:10 -05:00
|
|
|
urgbgcolor = EARGF(usage());
|
2013-12-12 11:06:51 -06:00
|
|
|
break;
|
2014-01-21 12:43:40 -06:00
|
|
|
case 'v':
|
2016-01-03 06:01:14 -06:00
|
|
|
die("tabbed-"VERSION", © 2009-2016 tabbed engineers, "
|
|
|
|
"see LICENSE for details.\n");
|
2014-01-21 12:43:40 -06:00
|
|
|
break;
|
2016-01-03 06:01:32 -06:00
|
|
|
default:
|
2012-04-06 13:44:47 -05:00
|
|
|
usage();
|
2016-01-03 06:01:32 -06:00
|
|
|
break;
|
2012-04-06 13:44:47 -05:00
|
|
|
} ARGEND;
|
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (argc < 1) {
|
2012-04-06 11:42:53 -05:00
|
|
|
doinitspawn = False;
|
2012-11-26 07:55:26 -06:00
|
|
|
fillagain = False;
|
|
|
|
}
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2012-11-08 14:48:51 -06:00
|
|
|
setcmd(argc, argv, replace);
|
2012-02-09 11:03:50 -06:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
|
|
|
fprintf(stderr, "%s: no locale support\n", argv0);
|
|
|
|
if (!(dpy = XOpenDisplay(NULL)))
|
|
|
|
die("%s: cannot open display\n", argv0);
|
2012-11-08 14:40:58 -06:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
setup();
|
2011-06-18 08:37:43 -05:00
|
|
|
printf("0x%lx\n", win);
|
2009-09-11 06:08:27 -05:00
|
|
|
fflush(NULL);
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2016-01-03 06:00:57 -06:00
|
|
|
if (detach) {
|
|
|
|
if (fork() == 0) {
|
2009-10-26 10:50:38 -05:00
|
|
|
fclose(stdout);
|
2012-12-25 09:50:32 -06:00
|
|
|
} else {
|
2016-01-03 06:00:57 -06:00
|
|
|
if (dpy)
|
2009-10-26 10:50:38 -05:00
|
|
|
close(ConnectionNumber(dpy));
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
2009-09-13 05:13:10 -05:00
|
|
|
}
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2009-09-07 06:32:58 -05:00
|
|
|
run();
|
|
|
|
cleanup();
|
|
|
|
XCloseDisplay(dpy);
|
2012-10-03 00:56:53 -05:00
|
|
|
|
2009-09-13 05:13:10 -05:00
|
|
|
return EXIT_SUCCESS;
|
2009-09-07 06:32:58 -05:00
|
|
|
}
|