all repos — openbox @ 7f262bc2a0733a77ae5a30752aecdcf4ba35f223

openbox fork - make it a bit more like ryudo

add support for _NET_REQUEST_FRAME_EXTENTS
Dana Jansens danakj@orodu.net
commit

7f262bc2a0733a77ae5a30752aecdcf4ba35f223

parent

20eaccaba2020e8396c0c9d9ad1282bf5d2ad95d

M openbox/client.copenbox/client.c

@@ -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 @@ gint newx, newy;

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 @@ attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;

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 @@ self->layer = -1;

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 @@

/* 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 @@ /* update the list hints */

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 @@ {

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 @@ frame_hide(self->frame);

/* 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 @@ if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */

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 @@ client_move_resize(self, a.x, a.y, a.width, a.height);

} /* 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,10 +628,14 @@ PROP_ERASE(self->window, net_wm_desktop);

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);

@@ -626,9 +654,14 @@ g_free(self->role);

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 @@ XSetWindowBorderWidth(ob_display, self->window, 0);

} -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); - 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. + /* these things can change the decor and functions of the window */ - 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 */ + client_get_mwm_hints(self); + /* this can change the mwmhints for special cases */ + client_get_type_and_transientness(self); client_get_state(self); + client_update_protocols(self); + client_update_normal_hints(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); + /* 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); - client_get_layer(self); /* if layer hasn't been specified, get it from - other sources if possible */ + 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); - { - /* 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_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_update_protocols(self); + client_get_layer(self); /* if layer hasn't been specified, get it from + other sources if possible */ - client_get_gravity(self); /* get the attribute gravity */ - client_update_normal_hints(self); /* this may override the attribute - gravity */ + { + /* a couple type-based defaults for new windows */ - /* 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); + /* 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 @@ }

#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 @@ target = OB_TRAN_GROUP;

} } } - } 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 @@ g_free(hints);

} } -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 @@ break; /* grab the first legit type */

} 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 @@ self->type = OB_CLIENT_TYPE_DIALOG;

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)

@@ -1455,16 +1480,6 @@ } else

self->sync_counter = None; } #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) {
M openbox/client.hopenbox/client.h

@@ -314,12 +314,21 @@ 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 @@ This also updates the NET_WM_ALLOWED_ACTIONS hint.

*/ 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);
M openbox/event.copenbox/event.c

@@ -568,8 +568,32 @@ else if (window == RootWindow(ob_display, ob_screen))

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 @@ } else if (msgtype == XA_WM_HINTS) {

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);
M openbox/frame.copenbox/frame.c

@@ -99,6 +99,7 @@ ObFrame *self;

Visual *visual; self = g_new0(ObFrame, 1); + self->client = client; visual = check_32bit_client(client);

@@ -245,7 +246,7 @@ RrAppearanceFree(self->a_focused_handle);

RrAppearanceFree(self->a_icon); } -static void frame_free(ObFrame *self) +void frame_free(ObFrame *self) { free_theme_statics(self);

@@ -553,12 +554,10 @@ {

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 @@ member set the root window, and one set to the client, but both get

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 @@

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 @@ g_hash_table_remove(window_map, &self->trtresize);

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? */
M openbox/frame.hopenbox/frame.h

@@ -162,6 +162,8 @@ GTimeVal iconify_animation_end;

}; 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);
M openbox/prop.hopenbox/prop.h

@@ -132,6 +132,7 @@ Atom net_wm_allowed_actions;

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; */
M openbox/screen.copenbox/screen.c

@@ -275,6 +275,7 @@ supported[i++] = prop_atoms.net_wm_moveresize;

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;