Skip to content

Commit 2910f17

Browse files
eddyeddy
eddy
authored and
eddy
committed
Initial
1 parent f09fb35 commit 2910f17

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

makefile

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
LDFLAGS += -lX11
2+
CXXFLAGS += -Wall
3+
4+
SRC=wintag.cpp
5+
OBJS=$(patsubst %.cpp,%.o,$(SRC))
6+
BINARY=wintag
7+
8+
%.o: %.cpp
9+
g++ $(CXXFLAGS) -c -o $@ $<
10+
11+
$(BINARY): $(OBJS)
12+
g++ $(LDFLAGS) -o $@ $^
13+
14+
clean:
15+
rm -rf $(OBJS) $(BINARY)
16+
17+
.PHONY: clean

wintag.cpp

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/* TODO:
2+
* per screen context
3+
* root window change event handling (regrab keys)
4+
* systray icon
5+
*/
6+
7+
#include <map>
8+
#include <stdio.h>
9+
#include <X11/Xlib.h>
10+
#include <X11/Xatom.h>
11+
12+
Atom active_window_atom(Display *display) {
13+
return XInternAtom(display, "_NET_ACTIVE_WINDOW", True);
14+
}
15+
16+
struct XBuffer {
17+
unsigned char* mem;
18+
int format;
19+
unsigned long items;
20+
21+
XBuffer(): mem(0), format(0), items(0) {}
22+
23+
~XBuffer() {
24+
if (mem) { XFree(mem); }
25+
}
26+
};
27+
28+
struct XDisplay {
29+
Display *display;
30+
XDisplay(const char *name) {
31+
display = XOpenDisplay(name);
32+
}
33+
~XDisplay() {
34+
XCloseDisplay(display);
35+
}
36+
operator Display* () {
37+
return display;
38+
}
39+
};
40+
41+
int get_window_property(Display *display, Window window, Atom property, Atom type, int format, unsigned size, XBuffer& buffer/* result */) {
42+
Atom ret_type;
43+
unsigned long bytes_after;
44+
45+
int r = XGetWindowProperty(display, window, property, 0, size, False, XA_WINDOW,
46+
&ret_type, &buffer.format, &buffer.items, &bytes_after, &buffer.mem);
47+
48+
if (r != Success) { printf("XGetWindowProperty failed"); return 1; }
49+
if (ret_type != type) { printf("XGetWindowProperty: ret type mismatch: %lu\n", ret_type); return 1; }
50+
if (format != buffer.format) { printf("XGetWindowProperty: format mismatch: %d\n", format); return 1; }
51+
if (buffer.items < size) { printf("XGetWindowProperty: bad item size: %d\n", format); return 1; }
52+
53+
return 0;
54+
}
55+
56+
Window get_active_window(Display *display, Window root) {
57+
XBuffer result;
58+
if (get_window_property(display, root, active_window_atom(display), XA_WINDOW, 32, 1, result) != 0) { return 0; }
59+
60+
return *(Window*) result.mem;
61+
}
62+
63+
typedef std::map<unsigned int, Window> KeyToWindowMap;
64+
65+
void map_hotkeys(Display *display, Window root, KeyToWindowMap& map, unsigned int modifiers, const char* keys[]) {
66+
for (int i = 0; keys[i] != 0; ++i) {
67+
KeyCode key = XKeysymToKeycode(display, XStringToKeysym(keys[i]));
68+
XGrabKey(display, key, modifiers, root, True, GrabModeSync, GrabModeSync);
69+
map[key] = 0;
70+
}
71+
}
72+
73+
void activate_window(Display *display, Window root, Window active_window) {
74+
XEvent ev;
75+
ev.type = ClientMessage;
76+
ev.xclient.display = display;
77+
ev.xclient.window = active_window;
78+
ev.xclient.message_type = active_window_atom(display);
79+
ev.xclient.format = 32;
80+
ev.xclient.data.l[0] = 2; // pager message source
81+
ev.xclient.data.l[1] = CurrentTime;
82+
XSendEvent(display, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &ev);
83+
}
84+
85+
#define AltKeyMask Mod1Mask
86+
#define WinKeyMask Mod4Mask
87+
88+
#define SelectKeyMask WinKeyMask
89+
#define SetKeyMask (WinKeyMask | AltKeyMask)
90+
91+
int main() {
92+
XDisplay display = XDisplay("");
93+
Window root = XDefaultRootWindow(display);
94+
95+
KeyToWindowMap hotkeys;
96+
const char* keys[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", 0 };
97+
map_hotkeys(display, root, hotkeys, SelectKeyMask, keys);
98+
map_hotkeys(display, root, hotkeys, SetKeyMask, keys);
99+
100+
XEvent ev;
101+
for(;;) {
102+
XNextEvent(display, &ev);
103+
if (ev.type == KeyPress || ev.type == KeyRelease) {
104+
//printf("Key event: code=%p mod=%p set=%p select=%p\n", ev.xkey.keycode, ev.xkey.state, SetKeyMask, SelectKeyMask);
105+
KeyToWindowMap::iterator it = hotkeys.find(ev.xkey.keycode);
106+
if (it != hotkeys.end() && ((ev.xkey.state == SetKeyMask) || (ev.xkey.state == SelectKeyMask))) {
107+
// do job
108+
if(ev.type == KeyPress) {
109+
if (ev.xkey.state == SelectKeyMask) {
110+
if (it->second != 0) {
111+
printf("Bringing up active window: %lu\n", it->second);
112+
activate_window(display, root, it->second);
113+
} else {
114+
printf("No active window\n");
115+
}
116+
} else if (ev.xkey.state == SetKeyMask) {
117+
it->second = get_active_window(display, root);
118+
printf("Remembering active window: %lu\n", it->second);
119+
}
120+
}
121+
XAllowEvents(display, AsyncKeyboard, ev.xkey.time);
122+
} else {
123+
//let key go
124+
XAllowEvents(display, ReplayKeyboard, ev.xkey.time);
125+
}
126+
XFlush(display);
127+
}
128+
}
129+
130+
return 0;
131+
}

0 commit comments

Comments
 (0)