sample x11 popup window
This commit is contained in:
+361
@@ -0,0 +1,361 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int get_active_window(Display *dpy, Window root, Window *active)
|
||||
{
|
||||
Atom prop = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", True);
|
||||
|
||||
if (!prop)
|
||||
return 0;
|
||||
|
||||
Atom actual;
|
||||
int format;
|
||||
unsigned long nitems;
|
||||
unsigned long bytes_after;
|
||||
unsigned char *data = NULL;
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
dpy,
|
||||
root,
|
||||
prop,
|
||||
0,
|
||||
1,
|
||||
False,
|
||||
XA_WINDOW,
|
||||
&actual,
|
||||
&format,
|
||||
&nitems,
|
||||
&bytes_after,
|
||||
&data
|
||||
);
|
||||
|
||||
if (status != Success || !data || nitems == 0) {
|
||||
if (data)
|
||||
XFree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*active = *(Window *)data;
|
||||
|
||||
XFree(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_window_center(
|
||||
Display *dpy,
|
||||
Window window,
|
||||
int *cx,
|
||||
int *cy
|
||||
)
|
||||
{
|
||||
Window root;
|
||||
Window child;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int border;
|
||||
unsigned int depth;
|
||||
|
||||
if (!XGetGeometry(
|
||||
dpy,
|
||||
window,
|
||||
&root,
|
||||
&x,
|
||||
&y,
|
||||
&width,
|
||||
&height,
|
||||
&border,
|
||||
&depth))
|
||||
return 0;
|
||||
|
||||
int root_x;
|
||||
int root_y;
|
||||
|
||||
if (!XTranslateCoordinates(
|
||||
dpy,
|
||||
window,
|
||||
root,
|
||||
0,
|
||||
0,
|
||||
&root_x,
|
||||
&root_y,
|
||||
&child))
|
||||
return 0;
|
||||
|
||||
*cx = root_x + (int)width / 2;
|
||||
*cy = root_y + (int)height / 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
|
||||
if (!dpy) {
|
||||
fprintf(stderr, "popup: cannot open X display\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int screen = DefaultScreen(dpy);
|
||||
Window root = RootWindow(dpy, screen);
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* Find the currently focused window.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Window active = None;
|
||||
|
||||
int cursor_x = DisplayWidth(dpy, screen) / 2;
|
||||
int cursor_y = DisplayHeight(dpy, screen) / 2;
|
||||
|
||||
if (get_active_window(dpy, root, &active)) {
|
||||
get_window_center(
|
||||
dpy,
|
||||
active,
|
||||
&cursor_x,
|
||||
&cursor_y
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* Find the monitor containing the active window.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int monitor_x = 0;
|
||||
int monitor_y = 0;
|
||||
|
||||
int monitor_width = DisplayWidth(dpy, screen);
|
||||
int monitor_height = DisplayHeight(dpy, screen);
|
||||
|
||||
int monitor_count = 0;
|
||||
|
||||
XRRMonitorInfo *monitors =
|
||||
XRRGetMonitors(
|
||||
dpy,
|
||||
root,
|
||||
True,
|
||||
&monitor_count
|
||||
);
|
||||
|
||||
if (monitors) {
|
||||
|
||||
for (int i = 0; i < monitor_count; i++) {
|
||||
|
||||
XRRMonitorInfo *m = &monitors[i];
|
||||
|
||||
if (cursor_x >= m->x &&
|
||||
cursor_x < m->x + (int)m->width &&
|
||||
cursor_y >= m->y &&
|
||||
cursor_y < m->y + (int)m->height) {
|
||||
|
||||
monitor_x = m->x;
|
||||
monitor_y = m->y;
|
||||
|
||||
monitor_width = m->width;
|
||||
monitor_height = m->height;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XRRFreeMonitors(monitors);
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* Desired geometry.
|
||||
*
|
||||
* Half the monitor width and half the monitor height,
|
||||
* centered on that monitor.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int width = monitor_width / 2;
|
||||
int height = monitor_height / 2;
|
||||
|
||||
int x = monitor_x + (monitor_width - width) / 2;
|
||||
int y = monitor_y + (monitor_height - height) / 2;
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* Create the window.
|
||||
*
|
||||
* override_redirect means the window manager does not manage
|
||||
* this window. This prevents it from moving/resizing it.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
|
||||
XSetWindowAttributes attributes;
|
||||
|
||||
attributes.override_redirect = True;
|
||||
attributes.background_pixel =
|
||||
BlackPixel(dpy, screen);
|
||||
|
||||
attributes.event_mask =
|
||||
KeyPressMask |
|
||||
FocusChangeMask |
|
||||
StructureNotifyMask;
|
||||
|
||||
Window window = XCreateWindow(
|
||||
dpy,
|
||||
root,
|
||||
|
||||
x,
|
||||
y,
|
||||
|
||||
width,
|
||||
height,
|
||||
|
||||
0,
|
||||
|
||||
CopyFromParent,
|
||||
InputOutput,
|
||||
CopyFromParent,
|
||||
|
||||
CWOverrideRedirect |
|
||||
CWBackPixel |
|
||||
CWEventMask,
|
||||
|
||||
&attributes
|
||||
);
|
||||
|
||||
if (!window) {
|
||||
fprintf(stderr, "popup: XCreateWindow failed\n");
|
||||
XCloseDisplay(dpy);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* Map the window.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
|
||||
XMapRaised(dpy, window);
|
||||
XFlush(dpy);
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* Wait until the X server has actually mapped the window.
|
||||
*
|
||||
* Calling XSetInputFocus() before this can result in:
|
||||
*
|
||||
* BadMatch (invalid parameter attributes)
|
||||
*
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
|
||||
XEvent event;
|
||||
|
||||
XNextEvent(dpy, &event);
|
||||
|
||||
if (event.type == MapNotify &&
|
||||
event.xmap.window == window) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* Now that the window is viewable, take keyboard focus.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
|
||||
XSetInputFocus(
|
||||
dpy,
|
||||
window,
|
||||
RevertToParent,
|
||||
CurrentTime
|
||||
);
|
||||
|
||||
XRaiseWindow(dpy, window);
|
||||
|
||||
XFlush(dpy);
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* Event loop.
|
||||
*
|
||||
* Escape:
|
||||
* exit
|
||||
*
|
||||
* FocusOut:
|
||||
* exit
|
||||
*
|
||||
* The window is override-redirect, so the WM won't resize or
|
||||
* reposition it.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
|
||||
XEvent event;
|
||||
|
||||
XNextEvent(dpy, &event);
|
||||
|
||||
switch (event.type) {
|
||||
|
||||
case KeyPress:
|
||||
{
|
||||
KeySym key =
|
||||
XLookupKeysym(
|
||||
&event.xkey,
|
||||
0
|
||||
);
|
||||
|
||||
if (key == XK_Escape) {
|
||||
|
||||
XDestroyWindow(
|
||||
dpy,
|
||||
window
|
||||
);
|
||||
|
||||
XCloseDisplay(dpy);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FocusOut:
|
||||
{
|
||||
/*
|
||||
* Any loss of keyboard focus causes the popup
|
||||
* to immediately terminate.
|
||||
*/
|
||||
|
||||
XDestroyWindow(
|
||||
dpy,
|
||||
window
|
||||
);
|
||||
|
||||
XCloseDisplay(dpy);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user