/* -*-c-*- */
#include "config.h"
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Intrinsic.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include "libs/FEvent.h"
Display *dpy;
Window Root, win;
int screen;
int has_focus_proto = 0;
int has_delete_proto = 1;
int input_mode = -1;
Atom ATOM_NET_WM_WINDOW_TYPE = None;
Atom ATOM_NET_WM_WINDOW_TYPE_DESKTOP = None;
Atom ATOM_NET_WM_WINDOW_TYPE_DOCK = None;
Atom ATOM_NET_WM_WINDOW_TYPE_TOOLBAR = None;
Atom ATOM_NET_WM_WINDOW_TYPE_MENU = None;
Atom ATOM_NET_WM_WINDOW_TYPE_DIALOG = None;
Atom ATOM_NET_WM_WINDOW_TYPE_NORMAL = None;
Atom ATOM_NET_WM_WINDOW_TYPE_SPLASH = None;
Atom ATOM_NET_WM_WINDOW_TYPE_UTILITY = None;
Atom ATOM_KDE_NET_WM_WINDOW_TYPE_OVERRIDE = None;
Atom ATOM_NET_WM_STATE = None;
Atom ATOM_NET_WM_STATE_MODAL = None;
Atom ATOM_NET_WM_STATE_STICKY = None;
Atom ATOM_NET_WM_STATE_MAXIMIZED_VERT = None;
Atom ATOM_NET_WM_STATE_MAXIMIZED_HORIZ = None;
Atom ATOM_NET_WM_STATE_SHADED = None;
Atom ATOM_NET_WM_STATE_SKIP_TASKBAR = None;
Atom ATOM_NET_WM_STATE_SKIP_PAGER = None;
Atom ATOM_NET_WM_STATE_HIDDEN = None;
Atom ATOM_NET_WM_STATE_STAYS_ON_TOP = None;
Atom ATOM_NET_WM_STATE_FULLSCREEN = None;
Atom ATOM_NET_WM_DESKTOP = None;
/* wm protocol */
Atom ATOM_WM_DELETE_WINDOW = None;
Atom ATOM_WM_TAKE_FOCUS = None;
/* Motif window hints */
Atom ATOM_MOTIF_WM_HINTS = None;
#define MWM_HINTS_FUNCTIONS (1L << 0)
#define MWM_HINTS_DECORATIONS (1L << 1)
#define MWM_HINTS_INPUT_MODE (1L << 2)
#define MWM_HINTS_STATUS (1L << 3) /* ? */
/* bit definitions for MwmHints.functions */
#define MWM_FUNC_ALL (1L << 0)
#define MWM_FUNC_RESIZE (1L << 1)
#define MWM_FUNC_MOVE (1L << 2)
#define MWM_FUNC_MINIMIZE (1L << 3)
#define MWM_FUNC_MAXIMIZE (1L << 4)
#define MWM_FUNC_CLOSE (1L << 5)
/* values for MwmHints.input_mode */
#define MWM_INPUT_MODELESS 0
#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
#define MWM_INPUT_SYSTEM_MODAL 2
#define MWM_INPUT_FULL_APPLICATION_MODAL 3
/* bit definitions for MwmHints.decorations */
#define MWM_DECOR_ALL (1L << 0)
#define MWM_DECOR_BORDER (1L << 1)
#define MWM_DECOR_RESIZEH (1L << 2)
#define MWM_DECOR_TITLE (1L << 3)
#define MWM_DECOR_MENU (1L << 4)
#define MWM_DECOR_MINIMIZE (1L << 5)
#define MWM_DECOR_MAXIMIZE (1L << 6)
/*
* _MWM_HINTS property
*/
typedef struct
{
long props[4];
/* props[0]: flags */
/* props[1]: functions */
/* props[2]: decorations */
/* props[3]: inputMode */
} PropMotifWmHints;
typedef PropMotifWmHints PropMwmHints;
#define PROP_MOTIF_WM_HINTS_ELEMENTS 4
#define PROP_MWM_HINTS_ELEMENTS PROP_MOTIF_WM_HINTS_ELEMENTS
void
Xloop(void)
{
while (1)
{
XEvent ev;
XWindowAttributes xatt;
/* Sit and wait for an event to happen */
FNextEvent(dpy,&ev);
switch(ev.type)
{
case ConfigureNotify:
break;
case ClientMessage:
if (has_delete_proto && ev.xclient.format == 32 &&
ev.xclient.data.l[0] == ATOM_WM_DELETE_WINDOW)
{
exit(0);
}
else if (has_focus_proto &&
ev.xclient.data.l[0] == ATOM_WM_TAKE_FOCUS)
{
printf("WM_TAKE_FOCUS message\n");
if (input_mode == 1)
{
printf ("\t...do nothing\n");
}
else if (input_mode == 0)
{
if (XGetWindowAttributes(dpy, win, &xatt)
&& xatt.map_state == IsViewable)
{
printf ("\t...setting focus on our own: %lu\n",
ev.xclient.data.l[1]);
XSetInputFocus(
dpy, win, RevertToParent,
ev.xclient.data.l[1]);
}
else
{
printf ("\t...but we are not viewable\n");
}
}
}
break;
default:
break;
}
}
}
#define XIA(a) XInternAtom(dpy,a,False);
void InitAtom(void)
{
ATOM_NET_WM_WINDOW_TYPE = XIA("_NET_WM_WINDOW_TYPE");
ATOM_NET_WM_WINDOW_TYPE_DESKTOP = XIA("_NET_WM_WINDOW_TYPE_DESKTOP");
ATOM_NET_WM_WINDOW_TYPE_DOCK = XIA("_NET_WM_WINDOW_TYPE_DOCK");
ATOM_NET_WM_WINDOW_TYPE_TOOLBAR = XIA("_NET_WM_WINDOW_TYPE_TOOLBAR");
ATOM_NET_WM_WINDOW_TYPE_MENU = XIA("_NET_WM_WINDOW_TYPE_MENU");
ATOM_NET_WM_WINDOW_TYPE_DIALOG = XIA("_NET_WM_WINDOW_TYPE_DIALOG");
ATOM_NET_WM_WINDOW_TYPE_NORMAL = XIA("_NET_WM_WINDOW_TYPE_NORMAL");
ATOM_NET_WM_WINDOW_TYPE_SPLASH = XIA("_NET_WM_WINDOW_TYPE_SPLASH");
ATOM_NET_WM_WINDOW_TYPE_UTILITY = XIA("_NET_WM_WINDOW_TYPE_UTILITY");
ATOM_KDE_NET_WM_WINDOW_TYPE_OVERRIDE = XIA("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
ATOM_NET_WM_STATE = XIA("_NET_WM_STATE");
ATOM_NET_WM_STATE_MODAL = XIA("_NET_WM_STATE_MODAL");
ATOM_NET_WM_STATE_STICKY = XIA("_NET_WM_STATE_STICKY");
ATOM_NET_WM_STATE_MAXIMIZED_VERT = XIA("_NET_WM_STATE_MAXIMIZED_VERT");
ATOM_NET_WM_STATE_MAXIMIZED_HORIZ = XIA("_NET_WM_STATE_MAXIMIZED_HORIZ");
ATOM_NET_WM_STATE_SHADED = XIA("_NET_WM_STATE_SHADED");
ATOM_NET_WM_STATE_SKIP_TASKBAR = XIA("_NET_WM_STATE_SKIP_TASKBAR");
ATOM_NET_WM_STATE_SKIP_PAGER = XIA("_NET_WM_STATE_SKIP_PAGER");
ATOM_NET_WM_STATE_HIDDEN = XIA("_NET_WM_STATE_HIDDEN");
ATOM_NET_WM_STATE_FULLSCREEN = XIA("_NET_WM_STATE_FULLSCREEN");
ATOM_NET_WM_STATE_STAYS_ON_TOP = XIA("_NET_WM_STATE_STAYS_ON_TOP");
ATOM_NET_WM_DESKTOP = XIA("_NET_WM_DESKTOP");
ATOM_WM_DELETE_WINDOW = XIA("WM_DELETE_WINDOW");
ATOM_WM_TAKE_FOCUS = XIA("WM_TAKE_FOCUS");
ATOM_MOTIF_WM_HINTS = XIA("_MOTIF_WM_HINTS");
}
void show_usage(void)
{
printf("Usage: hints_test OPTIONS\n");
printf("Options:\n");
printf(" --mwm-func <names>\n");
printf(" all, resize, move, minimize, maximize, close\n");
printf(" --mwm-decor <names>\n");
printf(" all, border, resizeh, title, menu, minimize, maximize\n");
printf(" --ewmh-state <names>\n");
printf(" hidden, shaded, sticky, skippager, skiptaskbar,\n");
printf(" maxhoriz, maxvert, modal, staysontop, fullscreen\n");
printf(" --ewmh-type <names>\n");
printf(" normal, dock, toolbar, desktop, menu, dialog, splash, utility\n");
printf(" --mwm-input { modless, app_modal, sys_modal, full_app_modal}\n");
printf(" --ewmh-desktop\n");
printf(" --wm-state { withdrawn, normal, iconic }\n");
printf(" --wm-urgency\n");
printf(" --wm-group { window, root, <win_id> }\n");
printf(" --min-size <width> <height>\n");
printf(" --max-size <width> <height>\n");
printf(" --inc-size <width> <height>\n");
printf(" --p-geometry <geometry>\n");
printf(" --us-geometry <geometry>\n");
printf(" --input { true, false }\n");
printf(" --delete-proto\n");
printf(" --no-delete-proto\n");
printf(" --transient\n");
}
int main(int argc, char **argv)
{
int state_count = 0;
Atom states[10];
Atom type = 0;
int i,x_r,y_r;
unsigned int h_r,w_r;
int ret;
int ewmh_state_arg = 0;
int ewmh_type_arg = 0;
int mwm_func_arg = 0;
int mwm_decor_arg = 0;
int has_ewmh_desktop = 0;
Atom ewmh_desktop = 0;
XSizeHints hints;
XClassHint classhints;
XWMHints wm_hints;
PropMwmHints mwm_hints;
Window trans_win = 0;
if (!(dpy = XOpenDisplay("")))
{
fprintf(stderr, "can't open display\n");
exit(1);
}
screen = DefaultScreen(dpy);
Root = RootWindow(dpy, screen);
InitAtom();
hints.width = 170;
hints.height = 100;
hints.x = 0;
hints.y = 0;
hints.flags = 0;
wm_hints.flags = 0;
mwm_hints.props[0] = 0;
mwm_hints.props[1] = 0;
mwm_hints.props[2] = 0;
mwm_hints.props[3] = 0;
win = XCreateSimpleWindow(
dpy, Root, 0, 0, hints.width, hints.height, 0, 0, 0);
for (i = 1; i < argc; i++)
{
char *error_arg = NULL;
if (strcasecmp(argv[i], "--help") == 0)
{
show_usage();
exit(0);
}
else if (strcasecmp(argv[i], "--ewmh-state") == 0)
{
ewmh_state_arg = 1;
ewmh_type_arg = 0;
mwm_func_arg = 0;
mwm_decor_arg = 0;
}
else if (strcasecmp(argv[i], "--ewmh-type") == 0)
{
ewmh_state_arg = 0;
ewmh_type_arg = 1;
mwm_func_arg = 0;
mwm_decor_arg = 0;
}
else if (strcasecmp(argv[i], "--mwm-func") == 0)
{
ewmh_state_arg = 0;
ewmh_type_arg = 0;
mwm_func_arg = 1;
mwm_decor_arg = 0;
}
else if (strcasecmp(argv[i], "--mwm-decor") == 0)
{
ewmh_state_arg = 0;
ewmh_type_arg = 0;
mwm_func_arg = 0;
mwm_decor_arg = 1;
}
else if (strcasecmp(argv[i], "--min-size") == 0)
{
i++;
hints.min_width = atoi(argv[i]);
i++;
hints.min_height = atoi(argv[i]);
hints.flags |= PMinSize;
}
else if (strcasecmp(argv[i], "--max-size") == 0)
{
i++;
hints.max_width = atoi(argv[i]);
i++;
hints.max_height = atoi(argv[i]);
hints.flags |= PMaxSize;
}
else if (strcasecmp(argv[i], "--inc-size") == 0)
{
i++;
hints.width_inc = atoi(argv[i]);
i++;
hints.height_inc = atoi(argv[i]);
hints.flags |= PResizeInc;
}
else if (strcasecmp(argv[i], "--p-geometry") == 0)
{
i++;
ret = XParseGeometry(argv[i], &x_r, &y_r, &w_r, &h_r);
if ((ret & WidthValue) && (ret & HeightValue))
{
hints.width = w_r;
hints.height = h_r;
hints.flags |= PSize;
}
if ((ret & XValue) && (ret & YValue))
{
hints.x = x_r;
hints.y = y_r;
hints.win_gravity = NorthWestGravity;
if (ret & XNegative)
{
hints.x += XDisplayWidth(dpy, screen) -
hints.width;
hints.win_gravity = NorthEastGravity;
}
if (ret & YNegative)
{
hints.y += XDisplayHeight(dpy, screen) -
hints.height;
if (ret & XNegative)
{
hints.win_gravity =
SouthEastGravity;
}
else
{
hints.win_gravity =
SouthWestGravity;
}
hints.flags |= PWinGravity;
}
hints.flags |= PPosition;
}
}
else if (strcasecmp(argv[i], "--us-geometry") == 0)
{
i++;
ret = XParseGeometry(argv[i], &x_r, &y_r, &w_r, &h_r);
if ((ret & WidthValue) && (ret & HeightValue))
{
hints.width = w_r;
hints.height = h_r;
hints.flags |= USSize;
}
if ((ret & XValue) && (ret & YValue))
{
hints.x = x_r;
hints.y = y_r;
hints.win_gravity=NorthWestGravity;
if (ret & XNegative)
{
hints.x += XDisplayWidth(dpy,screen) -
hints.width;
hints.win_gravity=NorthEastGravity;
}
if (ret & YNegative)
{
hints.y += XDisplayHeight(dpy,screen) -
hints.height;
if (ret & XNegative)
{
hints.win_gravity =
SouthEastGravity;
}
else
{
hints.win_gravity =
SouthWestGravity;
}
}
hints.flags |= USPosition | PWinGravity;
}
}
else if (strcasecmp(argv[i], "--input") == 0)
{
i++;
if (strcasecmp(argv[i], "true") == 0)
{
wm_hints.input = input_mode = True;
wm_hints.flags |= InputHint;
}
else if (strcasecmp(argv[i], "false") == 0)
{
wm_hints.input = input_mode = False;
wm_hints.flags |= InputHint;
}
else
{
error_arg = "--input";
}
}
else if (strcasecmp(argv[i], "--focus-proto") == 0)
{
has_focus_proto = 1;
}
else if (strcasecmp(argv[i], "--no-delete-proto") == 0)
{
has_delete_proto = 0;
}
else if (strcasecmp(argv[i], "--wm-state") == 0)
{
wm_hints.flags |= StateHint;
i++;
if (strcasecmp(argv[i], "withdrawn") == 0)
{
wm_hints.initial_state = WithdrawnState;
}
else if (strcasecmp(argv[i], "normal") == 0)
{
wm_hints.initial_state = NormalState;
}
else if (strcasecmp(argv[i], "iconic") == 0)
{
wm_hints.initial_state = IconicState;
}
else
{
error_arg = "--wm-state";
}
}
else if (strcasecmp(argv[i], "--wm-urgency") == 0)
{
wm_hints.flags |= XUrgencyHint;
}
else if (strcasecmp(argv[i], "--wm-group") == 0)
{
wm_hints.flags |= WindowGroupHint;
i++;
if (strcasecmp(argv[i], "window") == 0)
{
wm_hints.window_group = win;
}
else if (strcasecmp(argv[i], "root") == 0)
{
wm_hints.window_group = Root;
}
else
{
wm_hints.window_group =
strtoul(argv[i], NULL, 0);
}
}
else if (strcasecmp(argv[i], "--transient") == 0)
{
i++;
if (strcasecmp(argv[i],"root") == 0)
{
trans_win = Root;
}
else
{
trans_win = strtoul(argv[i], NULL, 0);
}
}
else if (strcasecmp(argv[i], "--mwm-input") == 0)
{
mwm_hints.props[0] |= MWM_HINTS_INPUT_MODE;
i++;
if (strcasecmp(argv[i], "modless") == 0)
{
mwm_hints.props[3] = MWM_INPUT_MODELESS;
}
else if (strcasecmp(argv[i], "app_modal") == 0)
{
mwm_hints.props[3] =
MWM_INPUT_PRIMARY_APPLICATION_MODAL;
}
else if (strcasecmp(argv[i], "sys_modal") == 0)
{
mwm_hints.props[3] =
MWM_INPUT_SYSTEM_MODAL;
}
else if (strcasecmp(argv[i], "full_app_modal") == 0)
{
mwm_hints.props[3] =
MWM_INPUT_FULL_APPLICATION_MODAL;
}
else
{
error_arg = "--mwm-input";
}
}
else if (strcasecmp(argv[i], "--ewmh-desktop") == 0)
{
has_ewmh_desktop = 1;
i++;
ewmh_desktop = atol(argv[i]);
}
else if (ewmh_state_arg && state_count < 10)
{
if (strcasecmp(argv[i], "hidden") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_HIDDEN;
}
else if (strcasecmp(argv[i], "shaded") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_SHADED;
}
else if (strcasecmp(argv[i], "sticky") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_STICKY;
}
else if (strcasecmp(argv[i], "skippager") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_SKIP_PAGER;
}
else if (strcasecmp(argv[i], "skiptaskbar") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_SKIP_TASKBAR;
}
else if (strcasecmp(argv[i], "maxhoriz") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_MAXIMIZED_HORIZ;
}
else if (strcasecmp(argv[i], "maxvert") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_MAXIMIZED_VERT;
}
else if (strcasecmp(argv[i], "modal") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_MODAL;
}
else if (strcasecmp(argv[i], "staysontop") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_STAYS_ON_TOP;
}
else if (strcasecmp(argv[i], "fullscreen") == 0)
{
states[state_count++] =
ATOM_NET_WM_STATE_FULLSCREEN;
}
else
{
error_arg = "--ewmh-state";
}
}
else if (ewmh_type_arg)
{
if (strcasecmp(argv[i], "normal") == 0)
{
type = ATOM_NET_WM_WINDOW_TYPE_NORMAL;
}
else if (strcasecmp(argv[i], "dock") == 0)
{
type = ATOM_NET_WM_WINDOW_TYPE_DOCK;
}
else if (strcasecmp(argv[i], "toolbar") == 0)
{
type = ATOM_NET_WM_WINDOW_TYPE_TOOLBAR;
}
else if (strcasecmp(argv[i], "desktop") == 0)
{
type = ATOM_NET_WM_WINDOW_TYPE_DESKTOP;
}
else if (strcasecmp(argv[i], "menu") == 0)
{
type = ATOM_NET_WM_WINDOW_TYPE_MENU;
}
else if (strcasecmp(argv[i], "dialog") == 0)
{
type = ATOM_NET_WM_WINDOW_TYPE_DIALOG;
}
else if (strcasecmp(argv[i], "splash") == 0)
{
type = ATOM_NET_WM_WINDOW_TYPE_SPLASH;
}
else if (strcasecmp(argv[i], "utility") == 0)
{
type = ATOM_NET_WM_WINDOW_TYPE_UTILITY;
}
else
{
error_arg = "--ewmh-type";
}
}
else if (mwm_func_arg)
{
mwm_hints.props[0] |= MWM_HINTS_FUNCTIONS;
if (strcasecmp(argv[i], "all") == 0)
{
mwm_hints.props[1] |= MWM_FUNC_ALL;
}
else if (strcasecmp(argv[i], "resize") == 0)
{
mwm_hints.props[1] |= MWM_FUNC_RESIZE;
}
else if (strcasecmp(argv[i], "move") == 0)
{
mwm_hints.props[1] |= MWM_FUNC_MOVE;
}
else if (strcasecmp(argv[i], "minimize") == 0)
{
mwm_hints.props[1] |= MWM_FUNC_MINIMIZE;
}
else if (strcasecmp(argv[i], "maximize") == 0)
{
mwm_hints.props[1] |= MWM_FUNC_MAXIMIZE;
}
else if (strcasecmp(argv[i], "close") == 0)
{
mwm_hints.props[1] |= MWM_FUNC_CLOSE;
}
else
{
error_arg = "--mwm-func";
}
}
else if (mwm_decor_arg)
{
mwm_hints.props[0] |= MWM_HINTS_DECORATIONS;
if (strcasecmp(argv[i], "all") == 0)
{
mwm_hints.props[2] |= MWM_DECOR_ALL;
}
else if (strcasecmp(argv[i], "border") == 0)
{
mwm_hints.props[2] |= MWM_DECOR_BORDER;
}
else if (strcasecmp(argv[i], "resizeh") == 0)
{
mwm_hints.props[2] |= MWM_DECOR_RESIZEH;
}
else if (strcasecmp(argv[i], "title") == 0)
{
mwm_hints.props[2] |= MWM_DECOR_TITLE;
}
else if (strcasecmp(argv[i], "menu") == 0)
{
mwm_hints.props[2] |= MWM_DECOR_MENU;
}
else if (strcasecmp(argv[i], "minimize") == 0)
{
mwm_hints.props[2] |= MWM_DECOR_MINIMIZE;
}
else if (strcasecmp(argv[i], "maximize") == 0)
{
mwm_hints.props[2] |= MWM_DECOR_MAXIMIZE;
}
else
{
error_arg = "--mwm-decor";
}
}
else
{
error_arg = "regular";
}
if (error_arg)
{
show_usage();
printf("Invalid %s argument: %s\n", error_arg, argv[i]);
exit(1);
}
}
XSelectInput(dpy, win, StructureNotifyMask);
if (wm_hints.flags)
{
XSetWMHints(dpy, win, &wm_hints);
}
if (state_count != 0)
{
XChangeProperty(
dpy, win, ATOM_NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char *)states, state_count);
}
if (type != 0)
{
XChangeProperty(
dpy, win, ATOM_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&type, 1);
}
if (has_ewmh_desktop)
{
XChangeProperty(
dpy, win, ATOM_NET_WM_DESKTOP, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&ewmh_desktop, 1);
}
if (has_delete_proto || has_focus_proto)
{
Atom proto[2];
int j = 0;
if (has_delete_proto)
proto[j++] = ATOM_WM_DELETE_WINDOW;
if (has_focus_proto)
proto[j++] = ATOM_WM_TAKE_FOCUS;
XSetWMProtocols(dpy, win, proto, j);
}
{
XTextProperty nametext;
char *list[] = { NULL, NULL };
list[0] = "Hints Test";
classhints.res_name = strdup("hints_test");
classhints.res_class = strdup("HintsTest");
if (!XStringListToTextProperty(list, 1, &nametext))
{
fprintf(stderr, "Failed to convert name to XText\n");
exit(1);
}
XSetWMProperties(
dpy, win, &nametext, &nametext, NULL, 0, &hints, NULL,
&classhints);
XFree(nametext.value);
}
if (mwm_hints.props[0] != 0)
{
XChangeProperty(
dpy, win, ATOM_MOTIF_WM_HINTS, ATOM_MOTIF_WM_HINTS, 32,
PropModeReplace,(unsigned char *)&mwm_hints,
PROP_MWM_HINTS_ELEMENTS);
}
if (trans_win !=0)
XSetTransientForHint(dpy, win, trans_win);
XMapWindow(dpy, win);
XSetWindowBackground(dpy, win, 0);
Xloop();
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1