add support for _NET_REQUEST_FRAME_EXTENTS

This commit is contained in:
Dana Jansens 2007-05-09 20:13:20 +00:00
parent 20eaccaba2
commit 7f262bc2a0
7 changed files with 188 additions and 141 deletions

View file

@ -66,7 +66,7 @@ GList *client_list = NULL;
static GSList *client_destructors = NULL;
static void client_get_all(ObClient *self);
static void client_get_all(ObClient *self, gboolean real);
static void client_toggle_border(ObClient *self, gboolean show);
static void client_get_startup_id(ObClient *self);
static void client_get_session_ids(ObClient *self);
@ -76,9 +76,7 @@ static void client_get_state(ObClient *self);
static void client_get_layer(ObClient *self);
static void client_get_shaped(ObClient *self);
static void client_get_mwm_hints(ObClient *self);
static void client_get_gravity(ObClient *self);
static void client_get_colormap(ObClient *self);
static void client_get_transientness(ObClient *self);
static void client_change_allowed_actions(ObClient *self);
static void client_change_state(ObClient *self);
static void client_change_wm_state(ObClient *self);
@ -236,8 +234,8 @@ void client_manage(Window window)
grab_server(TRUE);
/* check if it has already been unmapped by the time we started mapping.
the grab does a sync so we don't have to here */
/* check if it has already been unmapped by the time we started
mapping. the grab does a sync so we don't have to here */
if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) ||
XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e))
{
@ -277,7 +275,6 @@ void client_manage(Window window)
XChangeWindowAttributes(ob_display, window,
CWEventMask|CWDontPropagate, &attrib_set);
/* create the ObClient struct, and populate it from the hints on the
window */
self = g_new0(ObClient, 1);
@ -290,7 +287,7 @@ void client_manage(Window window)
self->desktop = screen_num_desktops; /* always an invalid value */
self->user_time = focus_client ? focus_client->user_time : CurrentTime;
client_get_all(self);
client_get_all(self, TRUE);
/* per-app settings override stuff, and return the settings for other
uses too */
settings = client_get_settings_state(self);
@ -311,14 +308,14 @@ void client_manage(Window window)
/* remove the client's border (and adjust re gravity) */
client_toggle_border(self, FALSE);
/* specify that if we exit, the window should not be destroyed and should
be reparented back to root automatically */
/* specify that if we exit, the window should not be destroyed and
should be reparented back to root automatically */
XChangeSaveSet(ob_display, window, SetModeInsert);
/* create the decoration frame for the client window */
self->frame = frame_new(self);
frame_grab_client(self->frame, self);
frame_grab_client(self->frame);
/* do this after we have a frame.. it uses the frame to help determine the
WM_STATE to apply. */
@ -484,6 +481,31 @@ void client_manage(Window window)
client_set_list();
ob_debug("Managed window 0x%lx (%s)\n", window, self->class);
return;
}
ObClient *client_fake_manage(Window window)
{
ObClient *self;
ObAppSettings *settings;
ob_debug("Pretend-managing window: %lx\n", window);
/* do this minimal stuff to figure out the client's decorations */
self = g_new0(ObClient, 1);
self->window = window;
client_get_all(self, FALSE);
/* per-app settings override stuff, and return the settings for other
uses too */
settings = client_get_settings_state(self);
/* create the decoration frame for the client window */
self->frame = frame_new(self);
return self;
}
void client_unmanage_all()
@ -497,8 +519,8 @@ void client_unmanage(ObClient *self)
guint j;
GSList *it;
ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window, self->class,
self->title ? self->title : "");
ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window,
self->class, self->title ? self->title : "");
g_assert(self != NULL);
@ -510,7 +532,8 @@ void client_unmanage(ObClient *self)
/* flush to send the hide to the server quickly */
XFlush(ob_display);
/* ignore enter events from the unmap so it doesnt mess with the focus */
/* ignore enter events from the unmap so it doesnt mess with the
focus */
event_ignore_queued_enters();
mouse_grab_for_client(self, FALSE);
@ -547,7 +570,7 @@ void client_unmanage(ObClient *self)
for (it = self->group->members; it; it = g_slist_next(it))
if (it->data != self)
((ObClient*)it->data)->transients =
g_slist_remove(((ObClient*)it->data)->transients, self);
g_slist_remove(((ObClient*)it->data)->transients,self);
} else if (self->transient_for) { /* transient of window */
self->transient_for->transients =
g_slist_remove(self->transient_for->transients, self);
@ -594,7 +617,8 @@ void client_unmanage(ObClient *self)
}
/* reparent the window out of the frame, and free the frame */
frame_release_client(self->frame, self);
frame_release_client(self->frame);
frame_free(self->frame);
self->frame = NULL;
if (ob_state() != OB_STATE_EXITING) {
@ -604,11 +628,15 @@ void client_unmanage(ObClient *self)
PROP_ERASE(self->window, net_wm_state);
PROP_ERASE(self->window, wm_state);
} else {
/* if we're left in an unmapped state, the client wont be mapped. this
is bad, since we will no longer be managing the window on restart */
/* if we're left in an unmapped state, the client wont be mapped.
this is bad, since we will no longer be managing the window on
restart */
XMapWindow(ob_display, self->window);
}
/* update the list hints */
client_set_list();
ob_debug("Unmanaged window 0x%lx\n", self->window);
/* free all data allocated in the client struct */
@ -626,9 +654,14 @@ void client_unmanage(ObClient *self)
g_free(self->client_machine);
g_free(self->sm_client_id);
g_free(self);
/* update the list hints */
client_set_list();
}
void client_fake_unmanage(ObClient *self)
{
/* this is all that got allocated to get the decorations */
frame_free(self->frame);
g_free(self);
}
static ObAppSettings *client_get_settings_state(ObClient *self)
@ -949,68 +982,62 @@ static void client_toggle_border(ObClient *self, gboolean show)
}
static void client_get_all(ObClient *self)
static void client_get_all(ObClient *self, gboolean real)
{
/* this is needed for the frame to set itself up */
client_get_area(self);
/* these things can change the decor and functions of the window */
client_get_mwm_hints(self);
/* The transient-ness of a window is used to pick a type, but the type can
also affect transiency.
Dialogs are always made transients for their group if they have one.
I also have made non-application type windows be transients for their
group (eg utility windows).
*/
client_get_transientness(self);
client_get_type(self);/* this can change the mwmhints for special cases */
/* this can change the mwmhints for special cases */
client_get_type_and_transientness(self);
client_get_state(self);
client_update_wmhints(self);
/* this may have already been called from client_update_wmhints */
if (self->transient_for == NULL)
client_update_transient_for(self);
client_get_startup_id(self);
client_get_desktop(self);/* uses transient data/group/startup id if a
desktop is not specified */
client_get_shaped(self);
client_get_layer(self); /* if layer hasn't been specified, get it from
other sources if possible */
{
/* a couple type-based defaults for new windows */
/* this makes sure that these windows appear on all desktops */
if (self->type == OB_CLIENT_TYPE_DESKTOP)
self->desktop = DESKTOP_ALL;
}
client_update_protocols(self);
client_get_gravity(self); /* get the attribute gravity */
client_update_normal_hints(self); /* this may override the attribute
gravity */
client_update_normal_hints(self);
/* got the type, the mwmhints, the protocols, and the normal hints
(min/max sizes), so we're ready to set up the decorations/functions */
client_setup_decor_and_functions(self);
if (real) {
client_update_wmhints(self);
/* this may have already been called from client_update_wmhints */
if (self->transient_for == NULL)
client_update_transient_for(self);
client_get_startup_id(self);
client_get_desktop(self);/* uses transient data/group/startup id if a
desktop is not specified */
client_get_shaped(self);
client_get_layer(self); /* if layer hasn't been specified, get it from
other sources if possible */
{
/* a couple type-based defaults for new windows */
/* this makes sure that these windows appear on all desktops */
if (self->type == OB_CLIENT_TYPE_DESKTOP)
self->desktop = DESKTOP_ALL;
}
#ifdef SYNC
client_update_sync_request_counter(self);
client_update_sync_request_counter(self);
#endif
/* get the session related properties */
client_get_session_ids(self);
/* get the session related properties */
client_get_session_ids(self);
client_get_colormap(self);
client_update_title(self);
client_update_strut(self);
client_update_icons(self);
client_update_user_time_window(self);
if (!self->user_time_window) /* check if this would have been called */
client_update_user_time(self);
client_update_icon_geometry(self);
client_get_colormap(self);
client_update_title(self);
client_update_strut(self);
client_update_icons(self);
client_update_user_time_window(self);
if (!self->user_time_window) /* check if this would have been called */
client_update_user_time(self);
client_update_icon_geometry(self);
}
}
static void client_get_startup_id(ObClient *self)
@ -1170,20 +1197,12 @@ static void client_get_shaped(ObClient *self)
#endif
}
void client_get_transientness(ObClient *self)
{
Window t;
if (XGetTransientForHint(ob_display, self->window, &t))
self->transient = TRUE;
}
void client_update_transient_for(ObClient *self)
{
Window t = None;
ObClient *target = NULL;
if (XGetTransientForHint(ob_display, self->window, &t)) {
self->transient = TRUE;
if (t != self->window) { /* cant be transient to itself! */
target = g_hash_table_lookup(window_map, &t);
/* if this happens then we need to check for it*/
@ -1220,16 +1239,8 @@ void client_update_transient_for(ObClient *self)
}
}
}
} else if (self->type == OB_CLIENT_TYPE_DIALOG ||
self->type == OB_CLIENT_TYPE_TOOLBAR ||
self->type == OB_CLIENT_TYPE_MENU ||
self->type == OB_CLIENT_TYPE_UTILITY)
{
self->transient = TRUE;
if (self->group)
target = OB_TRAN_GROUP;
} else
self->transient = FALSE;
} else if (self->transient && self->group)
target = OB_TRAN_GROUP;
client_update_transient_tree(self, self->group, self->group,
self->transient_for, target);
@ -1364,12 +1375,14 @@ static void client_get_mwm_hints(ObClient *self)
}
}
void client_get_type(ObClient *self)
void client_get_type_and_transientness(ObClient *self)
{
guint num, i;
guint32 *val;
Window t;
self->type = -1;
self->transient = FALSE;
if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
/* use the first value that we know about in the array */
@ -1403,7 +1416,10 @@ void client_get_type(ObClient *self)
}
g_free(val);
}
if (XGetTransientForHint(ob_display, self->window, &t))
self->transient = TRUE;
if (self->type == (ObClientType) -1) {
/*the window type hint was not set, which means we either classify
ourself as a normal window or a dialog, depending on if we are a
@ -1413,6 +1429,15 @@ void client_get_type(ObClient *self)
else
self->type = OB_CLIENT_TYPE_NORMAL;
}
/* then, based on our type, we can update our transientness.. */
if (self->type == OB_CLIENT_TYPE_DIALOG ||
self->type == OB_CLIENT_TYPE_TOOLBAR ||
self->type == OB_CLIENT_TYPE_MENU ||
self->type == OB_CLIENT_TYPE_UTILITY)
{
self->transient = TRUE;
}
}
void client_update_protocols(ObClient *self)
@ -1456,16 +1481,6 @@ void client_update_sync_request_counter(ObClient *self)
}
#endif
static void client_get_gravity(ObClient *self)
{
XWindowAttributes wattrib;
Status ret;
ret = XGetWindowAttributes(ob_display, self->window, &wattrib);
g_assert(ret != BadWindow);
self->gravity = wattrib.win_gravity;
}
void client_get_colormap(ObClient *self)
{
XWindowAttributes wa;

View file

@ -314,13 +314,22 @@ void client_remove_destructor(ObClientCallback func);
/*! Manages all existing windows */
void client_manage_all();
/*! Manages a given window */
/*! Manages a given window
*/
void client_manage(Window win);
/*! Unmanages all managed windows */
void client_unmanage_all();
/*! Unmanages a given client */
void client_unmanage(ObClient *client);
/*! This manages a window only so far as is needed to get it's decorations.
This is used when you want to determine a window's decorations before it
is mapped. Call client_fake_unmanage() with the returned client when you
are done with it. */
ObClient *client_fake_manage(Window win);
/*! Free the stuff created by client_fake_manage() */
void client_fake_unmanage(ObClient *self);
/*! Sets the client list on the root window from the client_list */
void client_set_list();
@ -354,7 +363,7 @@ gboolean client_focused(ObClient *self);
/*! Convery a position/size from a given gravity to the client's true gravity
*/
void client_convert_gravity(ObClient *client, gint gravity, gint *x, gint *y,
void client_convert_gravity(ObClient *self, gint gravity, gint *x, gint *y,
gint w, gint h);
#define client_move(self, x, y) \
@ -536,7 +545,7 @@ void client_activate(ObClient *self, gboolean here, gboolean user);
/*! Bring all of its helper windows to its desktop. These are the utility and
stuff windows. */
void client_bring_helper_windows(ObClient *client);
void client_bring_helper_windows(ObClient *self);
/*! Calculates the stacking layer for the client window */
void client_calc_layer(ObClient *self);
@ -600,8 +609,8 @@ void client_update_icon_geometry(ObClient *self);
*/
void client_setup_decor_and_functions(ObClient *self);
/*! Retrieves the window's type and sets ObClient->type */
void client_get_type(ObClient *self);
/*! Sets the window's type and transient flag */
void client_get_type_and_transientness(ObClient *self);
const ObClientIcon *client_icon(ObClient *self, gint w, gint h);

View file

@ -568,8 +568,32 @@ static void event_process(const XEvent *ec, gpointer data)
event_handle_root(e);
else if (e->type == MapRequest)
client_manage(window);
else if (e->type == ClientMessage) {
/* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for
windows that are not managed yet. */
if (e->xclient.message_type == prop_atoms.net_request_frame_extents) {
/* Pretend to manage the client, getting information used to
determine its decorations */
ObClient *c = client_fake_manage(e->xclient.window);
gulong vals[4];
/* adjust the decorations so we know the sizes */
frame_adjust_area(c->frame, FALSE, TRUE, TRUE);
/* set the frame extents on the window */
vals[0] = c->frame->size.left;
vals[1] = c->frame->size.right;
vals[2] = c->frame->size.top;
vals[3] = c->frame->size.bottom;
PROP_SETA32(e->xclient.window, net_frame_extents,
cardinal, vals, 4);
/* Free the pretend client */
client_fake_unmanage(c);
}
}
else if (e->type == ConfigureRequest) {
/* unhandled configure requests must be used to configure the
/* unhandled config5Aure requests must be used to configure the
window directly */
XWindowChanges xwc;
@ -1167,7 +1191,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
client_update_wmhints(client);
} else if (msgtype == XA_WM_TRANSIENT_FOR) {
client_update_transient_for(client);
client_get_type(client);
client_get_type_and_transientness(client);
/* type may have changed, so update the layer */
client_calc_layer(client);
client_setup_decor_and_functions(client);

View file

@ -99,6 +99,7 @@ ObFrame *frame_new(ObClient *client)
Visual *visual;
self = g_new0(ObFrame, 1);
self->client = client;
visual = check_32bit_client(client);
@ -245,7 +246,7 @@ static void free_theme_statics(ObFrame *self)
RrAppearanceFree(self->a_icon);
}
static void frame_free(ObFrame *self)
void frame_free(ObFrame *self)
{
free_theme_statics(self);
@ -553,12 +554,10 @@ void frame_adjust_icon(ObFrame *self)
framerender_frame(self);
}
void frame_grab_client(ObFrame *self, ObClient *client)
void frame_grab_client(ObFrame *self)
{
self->client = client;
/* reparent the client to the frame */
XReparentWindow(ob_display, client->window, self->plate, 0, 0);
XReparentWindow(ob_display, self->client->window, self->plate, 0, 0);
/*
When reparenting the client window, it is usually not mapped yet, since
this occurs from a MapRequest. However, in the case where Openbox is
@ -568,52 +567,50 @@ void frame_grab_client(ObFrame *self, ObClient *client)
handled and need to be ignored.
*/
if (ob_state() == OB_STATE_STARTING)
client->ignore_unmaps += 2;
self->client->ignore_unmaps += 2;
/* select the event mask on the client's parent (to receive config/map
req's) the ButtonPress is to catch clicks on the client border */
XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
/* map the client so it maps when the frame does */
XMapWindow(ob_display, client->window);
XMapWindow(ob_display, self->client->window);
/* adjust the frame to the client's size */
frame_adjust_area(self, FALSE, TRUE, FALSE);
/* set all the windows for the frame in the window_map */
g_hash_table_insert(window_map, &self->window, client);
g_hash_table_insert(window_map, &self->plate, client);
g_hash_table_insert(window_map, &self->inner, client);
g_hash_table_insert(window_map, &self->title, client);
g_hash_table_insert(window_map, &self->label, client);
g_hash_table_insert(window_map, &self->max, client);
g_hash_table_insert(window_map, &self->close, client);
g_hash_table_insert(window_map, &self->desk, client);
g_hash_table_insert(window_map, &self->shade, client);
g_hash_table_insert(window_map, &self->icon, client);
g_hash_table_insert(window_map, &self->iconify, client);
g_hash_table_insert(window_map, &self->handle, client);
g_hash_table_insert(window_map, &self->lgrip, client);
g_hash_table_insert(window_map, &self->rgrip, client);
g_hash_table_insert(window_map, &self->tltresize, client);
g_hash_table_insert(window_map, &self->tllresize, client);
g_hash_table_insert(window_map, &self->trtresize, client);
g_hash_table_insert(window_map, &self->trrresize, client);
g_hash_table_insert(window_map, &self->window, self->client);
g_hash_table_insert(window_map, &self->plate, self->client);
g_hash_table_insert(window_map, &self->inner, self->client);
g_hash_table_insert(window_map, &self->title, self->client);
g_hash_table_insert(window_map, &self->label, self->client);
g_hash_table_insert(window_map, &self->max, self->client);
g_hash_table_insert(window_map, &self->close, self->client);
g_hash_table_insert(window_map, &self->desk, self->client);
g_hash_table_insert(window_map, &self->shade, self->client);
g_hash_table_insert(window_map, &self->icon, self->client);
g_hash_table_insert(window_map, &self->iconify, self->client);
g_hash_table_insert(window_map, &self->handle, self->client);
g_hash_table_insert(window_map, &self->lgrip, self->client);
g_hash_table_insert(window_map, &self->rgrip, self->client);
g_hash_table_insert(window_map, &self->tltresize, self->client);
g_hash_table_insert(window_map, &self->tllresize, self->client);
g_hash_table_insert(window_map, &self->trtresize, self->client);
g_hash_table_insert(window_map, &self->trrresize, self->client);
}
void frame_release_client(ObFrame *self, ObClient *client)
void frame_release_client(ObFrame *self)
{
XEvent ev;
gboolean reparent = TRUE;
g_assert(self->client == client);
/* if there was any animation going on, kill it */
ob_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
self, FALSE);
/* check if the app has already reparented its window away */
while (XCheckTypedWindowEvent(ob_display, client->window,
while (XCheckTypedWindowEvent(ob_display, self->client->window,
ReparentNotify, &ev))
{
/* This check makes sure we don't catch our own reparent action to
@ -633,10 +630,10 @@ void frame_release_client(ObFrame *self, ObClient *client)
if (reparent) {
/* according to the ICCCM - if the client doesn't reparent itself,
then we will reparent the window to root for them */
XReparentWindow(ob_display, client->window,
XReparentWindow(ob_display, self->client->window,
RootWindow(ob_display, ob_screen),
client->area.x,
client->area.y);
self->client->area.x,
self->client->area.y);
}
/* remove all the windows for the frame from the window_map */
@ -660,8 +657,6 @@ void frame_release_client(ObFrame *self, ObClient *client)
g_hash_table_remove(window_map, &self->trrresize);
ob_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE);
frame_free(self);
}
/* is there anything present between us and the label? */

View file

@ -162,6 +162,8 @@ struct _ObFrame
};
ObFrame *frame_new(struct _ObClient *c);
void frame_free(ObFrame *self);
void frame_show(ObFrame *self);
void frame_hide(ObFrame *self);
void frame_adjust_theme(ObFrame *self);
@ -173,8 +175,8 @@ void frame_adjust_state(ObFrame *self);
void frame_adjust_focus(ObFrame *self, gboolean hilite);
void frame_adjust_title(ObFrame *self);
void frame_adjust_icon(ObFrame *self);
void frame_grab_client(ObFrame *self, struct _ObClient *client);
void frame_release_client(ObFrame *self, struct _ObClient *client);
void frame_grab_client(ObFrame *self);
void frame_release_client(ObFrame *self);
ObFrameContext frame_context_from_string(const gchar *name);

View file

@ -132,6 +132,7 @@ typedef struct Atoms {
Atom net_wm_user_time;
Atom net_wm_user_time_window;
Atom net_frame_extents;
Atom net_request_frame_extents;
/* application protocols */
/* Atom net_wm_ping; */

View file

@ -275,6 +275,7 @@ gboolean screen_annex(const gchar *program_name)
supported[i++] = prop_atoms.net_wm_user_time;
supported[i++] = prop_atoms.net_wm_user_time_window;
supported[i++] = prop_atoms.net_frame_extents;
supported[i++] = prop_atoms.net_request_frame_extents;
supported[i++] = prop_atoms.net_startup_id;
#ifdef SYNC
supported[i++] = prop_atoms.net_wm_sync_request;