/* non-zero defaults */
self->wmstate = WithdrawnState; /* make sure it gets updated first time */
- self->layer = -1;
+ self->gravity = NorthWestGravity;
self->desktop = screen_num_desktops; /* always an invalid value */
self->user_time = focus_client ? focus_client->user_time : CurrentTime;
+ /* get all the stuff off the window */
client_get_all(self, TRUE);
- /* per-app settings override stuff, and return the settings for other
- uses too */
- settings = client_get_settings_state(self);
- /* the session should get the last say */
- client_restore_session_state(self);
-
- client_setup_decor_and_functions(self);
-
- client_calc_layer(self);
- {
- Time t = sn_app_started(self->startup_id, self->class);
- if (t) self->user_time = t;
- }
-
- /* update the focus lists, do this before the call to change_state or
- it can end up in the list twice! */
- focus_order_add_new(self);
-
- /* 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 */
XChangeSaveSet(ob_display, window, SetModeInsert);
frame_grab_client(self->frame);
+ /* we've grabbed everything and set everything that we need to at mapping
+ time now */
+ grab_server(FALSE);
+
+ /* per-app settings override stuff from client_get_all, and return the
+ settings for other uses too */
+ settings = client_get_settings_state(self);
+ /* the session should get the last say thought */
+ client_restore_session_state(self);
+
+ /* now we have all of the window's information so we can set this up */
+ client_setup_decor_and_functions(self);
+
+ /* remove the client's border (and adjust re gravity) */
+ client_toggle_border(self, FALSE);
+
+ {
+ Time t = sn_app_started(self->startup_id, self->class);
+ if (t) self->user_time = t;
+ }
+
/* do this after we have a frame.. it uses the frame to help determine the
WM_STATE to apply. */
client_change_state(self);
- grab_server(FALSE);
+ /* add ourselves to the focus order */
+ focus_order_add_new(self);
- stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
+ /* do this to add ourselves to the stacking list in a non-intrusive way */
+ client_calc_layer(self);
/* focus the new window? */
if (ob_state() != OB_STATE_STARTING &&
stacking_raise(CLIENT_AS_WINDOW(self));
}
+ /* adjust the frame to the client's size before showing the window */
+ frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
+
/* this has to happen before we try focus the window, but we want it to
happen after the client's stacking has been determined or it looks bad
*/
/* restore the window's original geometry so it is not lost */
{
- Rect a = self->area;
+ Rect a;
+
+ /* give the client its border back */
+ client_toggle_border(self, TRUE);
+
+ a = self->area;
if (self->fullscreen)
a = self->pre_fullscreen_area;
}
}
- /* give the client its border back */
- client_toggle_border(self, TRUE);
-
self->fullscreen = self->max_horz = self->max_vert = FALSE;
self->decorations = 0; /* unmanaged windows have no decor */
if (!real)
return;
+ /* get this early so we have it for debugging */
+ client_update_title(self);
+
client_update_protocols(self);
client_update_wmhints(self);
#endif
client_get_colormap(self);
- client_update_title(self);
client_update_strut(self);
client_update_icons(self);
client_update_user_time_window(self);
GSList *it, *next;
ObClient *c;
+ /* * *
+ Group transient windows are not allowed to have other group
+ transient windows as their children.
+ * * */
+
+
/* No change has occured */
if (oldgroup == newgroup && oldparent == newparent) return;
/** Remove the client from the transient tree wherever it has changed **/
/* If the window is becoming a direct transient for a window in its group
- then that window can't be a child of this window anymore */
+ then any group transients which were our children and are now becoming
+ our parents need to stop being our children.
+
+ Group transients can't be children of group transients already, but
+ we could have any number of direct parents above up, any of which could
+ be transient for the group, and we need to remove it from our children.
+ */
if (oldparent != newparent &&
newparent != NULL && newparent != OB_TRAN_GROUP &&
- newparent->transient_for == OB_TRAN_GROUP &&
newgroup != NULL && newgroup == oldgroup)
{
- self->transients = g_slist_remove(self->transients, newparent);
+ ObClient *look = newparent;
+ do {
+ self->transients = g_slist_remove(self->transients, look);
+ look = look->transient_for;
+ } while (look != NULL && look != OB_TRAN_GROUP);
}
WARNING: Cyclical transient-ness is possible. For e.g. if:
A is transient for the group
- B is a member of the group and transient for A
+ B is transient for A
+ C is transient for B
+ A can't be transient for C or we have a cycle
*/
if (oldgroup != newgroup && newgroup != NULL &&
newparent != OB_TRAN_GROUP)
if (!(self->functions & OB_CLIENT_FUNC_ICONIFY))
self->decorations &= ~OB_FRAME_DECOR_ICONIFY;
if (!(self->functions & OB_CLIENT_FUNC_RESIZE))
- self->decorations &= ~OB_FRAME_DECOR_GRIPS;
+ self->decorations &= ~(OB_FRAME_DECOR_GRIPS | OB_FRAME_DECOR_HANDLE);
/* can't maximize without moving/resizing */
if (!((self->functions & OB_CLIENT_FUNC_MAXIMIZE) &&
else self->shaded = FALSE;
}
if (!(self->functions & OB_CLIENT_FUNC_ICONIFY) && self->iconic) {
- if (self->frame) client_iconify(self, FALSE, TRUE);
+ if (self->frame) client_iconify(self, FALSE, TRUE, FALSE);
else self->iconic = FALSE;
}
if (!(self->functions & OB_CLIENT_FUNC_FULLSCREEN) && self->fullscreen) {
}
static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
- ObStackingLayer min, gboolean raised)
+ ObStackingLayer min)
{
ObStackingLayer old, own;
GSList *it;
own = calc_layer(self);
self->layer = MAX(own, min);
+ if (self->layer != old) {
+ stacking_remove(CLIENT_AS_WINDOW(self));
+ stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
+ }
+
for (it = self->transients; it; it = g_slist_next(it))
client_calc_layer_recursive(it->data, orig,
- self->layer,
- raised ? raised : self->layer > old);
-
- /* restack. but only if the original window is managed.
-
- raised is used so that only the bottom-most window in the stacking
- order is raised, the others will automatically come with it.
-
- also only the highest windows in the stacking order (no transients)
- are lowered, cuz the rest come for free
- */
- if (!raised && orig->frame) {
- if (self->layer > old) {
- stacking_remove(CLIENT_AS_WINDOW(self));
- stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
- } else if (self->layer < old && self->transients == NULL) {
- stacking_remove(CLIENT_AS_WINDOW(self));
- stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
- }
- }
+ self->layer);
}
void client_calc_layer(ObClient *self)
it = client_search_all_top_parents(self);
for (; it; it = g_slist_next(it))
- client_calc_layer_recursive(it->data, orig, 0, FALSE);
+ client_calc_layer_recursive(it->data, orig, 0);
}
gboolean client_should_show(ObClient *self)
if (self->iconic) {
self->iconic = FALSE;
- client_iconify(self, TRUE, FALSE);
+ client_iconify(self, TRUE, FALSE, TRUE);
}
if (self->fullscreen) {
self->fullscreen = FALSE;
void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h,
- gboolean user, gboolean final,
- gboolean force_reply)
+ gboolean user, gboolean final)
{
- gint oldw, oldh, oldrx, oldry;
+ gint oldw, oldh;
gboolean send_resize_client;
- gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE;
+ gboolean moved = FALSE, resized = FALSE;
guint fdecor = self->frame->decorations;
gboolean fhorz = self->frame->max_horz;
gint logicalw, logicalh;
if (moved || resized)
frame_adjust_area(self->frame, moved, resized, FALSE);
- /* find the client's position relative to the root window */
- oldrx = self->root_pos.x;
- oldry = self->root_pos.y;
- rootmoved = (oldrx != (signed)(self->frame->area.x +
- self->frame->size.left -
- self->border_width) ||
- oldry != (signed)(self->frame->area.y +
- self->frame->size.top -
- self->border_width));
-
- if (force_reply || ((!user || (user && final)) && rootmoved))
+ if ((!user || (user && final)) && !resized)
{
XEvent event;
event.xconfigure.event = self->window;
event.xconfigure.window = self->window;
+ ob_debug("Sending ConfigureNotify to %s for %d,%d %dx%d\n",
+ self->title, self->root_pos.x, self->root_pos.y, w, h);
+
/* root window real coords */
event.xconfigure.x = self->root_pos.x;
event.xconfigure.y = self->root_pos.y;
}
static void client_iconify_recursive(ObClient *self,
- gboolean iconic, gboolean curdesk)
+ gboolean iconic, gboolean curdesk,
+ gboolean hide_animation)
{
GSList *it;
gboolean changed = FALSE;
if (changed) {
client_change_state(self);
- if (ob_state() != OB_STATE_STARTING && config_animate_iconify)
+ if (config_animate_iconify && !hide_animation)
frame_begin_iconify_animation(self->frame, iconic);
/* do this after starting the animation so it doesn't flash */
client_showhide(self);
for (it = self->transients; it; it = g_slist_next(it))
if (it->data != self)
if (client_is_direct_child(self, it->data) || !iconic)
- client_iconify_recursive(it->data, iconic, curdesk);
+ client_iconify_recursive(it->data, iconic, curdesk,
+ hide_animation);
}
-void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk)
+void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk,
+ gboolean hide_animation)
{
if (self->functions & OB_CLIENT_FUNC_ICONIFY || !iconic) {
/* move up the transient chain as far as possible first */
self = client_search_top_normal_parent(self);
- client_iconify_recursive(self, iconic, curdesk);
+ client_iconify_recursive(self, iconic, curdesk, hide_animation);
}
}
switch (state) {
case IconicState:
- client_iconify(self, TRUE, TRUE);
+ client_iconify(self, TRUE, TRUE, FALSE);
break;
case NormalState:
- client_iconify(self, FALSE, TRUE);
+ client_iconify(self, FALSE, TRUE, FALSE);
break;
}
}
stacking_raise(CLIENT_AS_WINDOW(self));
}
if (iconic != self->iconic)
- client_iconify(self, iconic, FALSE);
+ client_iconify(self, iconic, FALSE, FALSE);
if (demands_attention != self->demands_attention)
client_hilite(self, demands_attention);
event_halt_focus_delay();
if (client_normal(self) && screen_showing_desktop)
- screen_show_desktop(FALSE, FALSE);
+ screen_show_desktop(FALSE, self);
if (self->iconic)
- client_iconify(self, FALSE, here);
+ client_iconify(self, FALSE, here, FALSE);
if (self->desktop != DESKTOP_ALL &&
self->desktop != screen_desktop)
{
static ObClientIcon* client_icon_recursive(ObClient *self, gint w, gint h)
{
guint i;
- /* si is the smallest image >= req */
- /* li is the largest image < req */
- gulong size, smallest = 0xffffffff, largest = 0, si = 0, li = 0;
+ gulong min_diff, min_i;
if (!self->nicons) {
ObClientIcon *parent = NULL;
return parent;
}
- for (i = 0; i < self->nicons; ++i) {
- size = self->icons[i].width * self->icons[i].height;
- if (size < smallest && size >= (unsigned)(w * h)) {
- smallest = size;
- si = i;
- }
- if (size > largest && size <= (unsigned)(w * h)) {
- largest = size;
- li = i;
+ /* some kind of crappy approximation to find the icon closest in size to
+ what we requested, but icons are generally all the same ratio as
+ eachother so it's good enough. */
+
+ min_diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h);
+ min_i = 0;
+
+ for (i = 1; i < self->nicons; ++i) {
+ gulong diff;
+
+ diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h);
+ if (diff < min_diff) {
+ min_diff = diff;
+ min_i = i;
}
}
- if (largest == 0) /* didnt find one smaller than the requested size */
- return &self->icons[si];
- return &self->icons[li];
+ return &self->icons[min_i];
}
const ObClientIcon* client_icon(ObClient *self, gint w, gint h)
continue; \
if(cur->iconic) \
continue; \
- if(cur->layer < c->layer && !config_resist_layers_below) \
+ if(cur->layer == c->layer) \
continue;
#define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \