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_showhide(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);
static void client_apply_startup_state(ObClient *self, gint x, gint y);
static void client_restore_session_state(ObClient *self);
static void client_restore_session_stacking(ObClient *self);
static ObAppSettings *client_get_settings_state(ObClient *self);
+static void client_unfocus(ObClient *self);
void client_startup(gboolean reconfig)
{
/* non-zero defaults */
self->title_count = 1;
- self->wmstate = NormalState;
+ self->wmstate = WithdrawnState; /* make sure it gets updated first time */
self->layer = -1;
self->desktop = screen_num_desktops; /* always an invalid value */
self->user_time = ~0; /* maximum value, always newer than the real time */
it can end up in the list twice! */
focus_order_add_new(self);
- client_change_state(self);
-
/* remove the client's border (and adjust re gravity) */
client_toggle_border(self, FALSE);
frame_grab_client(self->frame, self);
+ /* 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);
stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
g_assert(self != NULL);
- keyboard_grab_for_client(self, FALSE);
- mouse_grab_for_client(self, FALSE);
+ /* update the focus lists */
+ focus_order_remove(self);
+
+ if (focus_client == self) {
+ XEvent e;
+
+ /* focus the last focused window on the desktop, and ignore enter
+ events from the unmap so it doesnt mess with the focus */
+ while (XCheckTypedEvent(ob_display, EnterNotify, &e));
+ /* remove these flags so we don't end up getting focused in the
+ fallback! */
+ self->can_focus = FALSE;
+ self->focus_notify = FALSE;
+ self->modal = FALSE;
+ client_unfocus(self);
+ }
/* potentially fix focusLast */
if (config_focus_last)
grab_pointer(TRUE, OB_CURSOR_NONE);
+ frame_hide(self->frame);
+ XFlush(ob_display);
+
+ keyboard_grab_for_client(self, FALSE);
+ mouse_grab_for_client(self, FALSE);
+
/* remove the window from our save set */
XChangeSaveSet(ob_display, self->window, SetModeDelete);
/* we dont want events no more */
XSelectInput(ob_display, self->window, NoEventMask);
- frame_hide(self->frame);
-
client_list = g_list_remove(client_list, self);
stacking_remove(self);
g_hash_table_remove(window_map, &self->window);
- /* update the focus lists */
- focus_order_remove(self);
-
- /* once the client is out of the list, update the struts to remove it's
+ /* once the client is out of the list, update the struts to remove its
influence */
if (STRUT_EXISTS(self->strut))
screen_update_areas();
Destructor *d = it->data;
d->func(self, d->data);
}
-
- if (focus_client == self) {
- XEvent e;
-
- /* focus the last focused window on the desktop, and ignore enter
- events from the unmap so it doesnt mess with the focus */
- while (XCheckTypedEvent(ob_display, EnterNotify, &e));
- /* remove these flags so we don't end up getting focused in the
- fallback! */
- self->can_focus = FALSE;
- self->focus_notify = FALSE;
- self->modal = FALSE;
- client_unfocus(self);
- }
/* tell our parent(s) that we're gone */
if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
GSList *it;
for (it = config_per_app_settings; it; it = g_slist_next(it)) {
- ObAppSettings *app;
+ ObAppSettings *app = it->data;
if ((app->name && !app->class && !strcmp(app->name, self->name))
|| (app->class && !app->name && !strcmp(app->class, self->class))
}
}
-static void client_change_state(ObClient *self)
+static void client_change_wm_state(ObClient *self)
{
gulong state[2];
+ glong old;
+
+ old = self->wmstate;
+
+ if (self->shaded || self->iconic || !self->frame->visible)
+ self->wmstate = IconicState;
+ else
+ self->wmstate = NormalState;
+
+ if (old != self->wmstate) {
+ PROP_MSG(self->window, kde_wm_change_state,
+ self->wmstate, 1, 0, 0);
+
+ state[0] = self->wmstate;
+ state[1] = None;
+ PROP_SETA32(self->window, wm_state, wm_state, state, 2);
+ }
+}
+
+static void client_change_state(ObClient *self)
+{
gulong netstate[11];
guint num;
- state[0] = self->wmstate;
- state[1] = None;
- PROP_SETA32(self->window, wm_state, wm_state, state, 2);
-
num = 0;
if (self->modal)
netstate[num++] = prop_atoms.net_wm_state_modal;
return FALSE;
}
-static void client_showhide(ObClient *self)
+void client_showhide(ObClient *self)
{
- if (client_should_show(self))
+ if (client_should_show(self)) {
frame_show(self->frame);
- else
+ }
+ else {
frame_hide(self->frame);
+
+ /* Fall back focus since we're disappearing */
+ if (focus_client == self)
+ client_unfocus(self);
+ }
+
+ /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
+ needs to be in IconicState. This includes when it is on another
+ desktop!
+ */
+ client_change_wm_state(self);
}
gboolean client_normal(ObClient *self) {
*/
}
-void client_configure_full(ObClient *self, ObCorner anchor,
- gint x, gint y, gint w, gint h,
- gboolean user, gboolean final,
- gboolean force_reply)
+void client_try_configure(ObClient *self, ObCorner anchor,
+ gint *x, gint *y, gint *w, gint *h,
+ gint *logicalw, gint *logicalh,
+ gboolean user)
{
- gint oldw, oldh;
- gboolean send_resize_client;
- gboolean moved = FALSE, resized = FALSE;
- guint fdecor = self->frame->decorations;
- gboolean fhorz = self->frame->max_horz;
- Rect desired_area = {x, y, w, h};
+ Rect desired_area = {*x, *y, *w, *h};
/* make the frame recalculate its dimentions n shit without changing
anything visible for real, this way the constraints below can work with
frame_adjust_area(self->frame, TRUE, TRUE, TRUE);
/* gets the frame's position */
- frame_client_gravity(self->frame, &x, &y);
+ frame_client_gravity(self->frame, x, y);
/* these positions are frame positions, not client positions */
i = screen_find_monitor(&desired_area);
a = screen_physical_area_monitor(i);
- x = a->x;
- y = a->y;
- w = a->width;
- h = a->height;
+ *x = a->x;
+ *y = a->y;
+ *w = a->width;
+ *h = a->height;
user = FALSE; /* ignore that increment etc shit when in fullscreen */
} else {
/* set the size and position if maximized */
if (self->max_horz) {
- x = a->x;
- w = a->width - self->frame->size.left - self->frame->size.right;
+ *x = a->x;
+ *w = a->width - self->frame->size.left - self->frame->size.right;
}
if (self->max_vert) {
- y = a->y;
- h = a->height - self->frame->size.top - self->frame->size.bottom;
+ *y = a->y;
+ *h = a->height - self->frame->size.top - self->frame->size.bottom;
}
}
/* gets the client's position */
- frame_frame_gravity(self->frame, &x, &y);
+ frame_frame_gravity(self->frame, x, y);
/* these override the above states! if you cant move you can't move! */
if (user) {
if (!(self->functions & OB_CLIENT_FUNC_MOVE)) {
- x = self->area.x;
- y = self->area.y;
+ *x = self->area.x;
+ *y = self->area.y;
}
if (!(self->functions & OB_CLIENT_FUNC_RESIZE)) {
- w = self->area.width;
- h = self->area.height;
+ *w = self->area.width;
+ *h = self->area.height;
}
}
- if (!(w == self->area.width && h == self->area.height)) {
+ if (!(*w == self->area.width && *h == self->area.height)) {
gint basew, baseh, minw, minh;
/* base size is substituted with min size if not specified */
sizes */
/* smaller than min size or bigger than max size? */
- if (w > self->max_size.width) w = self->max_size.width;
- if (w < minw) w = minw;
- if (h > self->max_size.height) h = self->max_size.height;
- if (h < minh) h = minh;
+ if (*w > self->max_size.width) *w = self->max_size.width;
+ if (*w < minw) *w = minw;
+ if (*h > self->max_size.height) *h = self->max_size.height;
+ if (*h < minh) *h = minh;
- w -= basew;
- h -= baseh;
+ *w -= basew;
+ *h -= baseh;
/* keep to the increments */
- w /= self->size_inc.width;
- h /= self->size_inc.height;
+ *w /= self->size_inc.width;
+ *h /= self->size_inc.height;
/* you cannot resize to nothing */
- if (basew + w < 1) w = 1 - basew;
- if (baseh + h < 1) h = 1 - baseh;
+ if (basew + *w < 1) *w = 1 - basew;
+ if (baseh + *h < 1) *h = 1 - baseh;
- /* store the logical size */
- SIZE_SET(self->logical_size,
- self->size_inc.width > 1 ? w : w + basew,
- self->size_inc.height > 1 ? h : h + baseh);
+ /* save the logical size */
+ *logicalw = self->size_inc.width > 1 ? *w : *w + basew;
+ *logicalh = self->size_inc.height > 1 ? *h : *h + baseh;
- w *= self->size_inc.width;
- h *= self->size_inc.height;
+ *w *= self->size_inc.width;
+ *h *= self->size_inc.height;
- w += basew;
- h += baseh;
+ *w += basew;
+ *h += baseh;
/* adjust the height to match the width for the aspect ratios.
for this, min size is not substituted for base size ever. */
- w -= self->base_size.width;
- h -= self->base_size.height;
+ *w -= self->base_size.width;
+ *h -= self->base_size.height;
if (!self->fullscreen) {
if (self->min_ratio)
- if (h * self->min_ratio > w) {
- h = (gint)(w / self->min_ratio);
+ if (*h * self->min_ratio > *w) {
+ *h = (gint)(*w / self->min_ratio);
/* you cannot resize to nothing */
- if (h < 1) {
- h = 1;
- w = (gint)(h * self->min_ratio);
+ if (*h < 1) {
+ *h = 1;
+ *w = (gint)(*h * self->min_ratio);
}
}
if (self->max_ratio)
- if (h * self->max_ratio < w) {
- h = (gint)(w / self->max_ratio);
+ if (*h * self->max_ratio < *w) {
+ *h = (gint)(*w / self->max_ratio);
/* you cannot resize to nothing */
- if (h < 1) {
- h = 1;
- w = (gint)(h * self->min_ratio);
+ if (*h < 1) {
+ *h = 1;
+ *w = (gint)(*h * self->min_ratio);
}
}
}
- w += self->base_size.width;
- h += self->base_size.height;
+ *w += self->base_size.width;
+ *h += self->base_size.height;
}
- g_assert(w > 0);
- g_assert(h > 0);
+ g_assert(*w > 0);
+ g_assert(*h > 0);
switch (anchor) {
case OB_CORNER_TOPLEFT:
break;
case OB_CORNER_TOPRIGHT:
- x -= w - self->area.width;
+ *x -= *w - self->area.width;
break;
case OB_CORNER_BOTTOMLEFT:
- y -= h - self->area.height;
+ *y -= *h - self->area.height;
break;
case OB_CORNER_BOTTOMRIGHT:
- x -= w - self->area.width;
- y -= h - self->area.height;
+ *x -= *w - self->area.width;
+ *y -= *h - self->area.height;
break;
}
+}
+
+
+void client_configure_full(ObClient *self, ObCorner anchor,
+ gint x, gint y, gint w, gint h,
+ gboolean user, gboolean final,
+ gboolean force_reply)
+{
+ gint oldw, oldh;
+ gboolean send_resize_client;
+ gboolean moved = FALSE, resized = FALSE;
+ guint fdecor = self->frame->decorations;
+ gboolean fhorz = self->frame->max_horz;
+ gint logicalw, logicalh;
+
+ /* find the new x, y, width, and height (and logical size) */
+ client_try_configure(self, anchor, &x, &y, &w, &h,
+ &logicalw, &logicalh, user);
+ /* set the logical size */
+ SIZE_SET(self->logical_size, logicalw, logicalh);
+
+ /* figure out if we moved or resized or what */
moved = x != self->area.x || y != self->area.y;
resized = w != self->area.width || h != self->area.height;
ob_debug("%sconifying window: 0x%lx\n", (iconic ? "I" : "Uni"),
self->window);
- self->iconic = iconic;
-
if (iconic) {
if (self->functions & OB_CLIENT_FUNC_ICONIFY) {
- glong old;
-
- old = self->wmstate;
- self->wmstate = IconicState;
- if (old != self->wmstate)
- PROP_MSG(self->window, kde_wm_change_state,
- self->wmstate, 1, 0, 0);
+ self->iconic = iconic;
/* update the focus lists.. iconic windows go to the bottom of
the list, put the new iconic window at the 'top of the
bottom'. */
focus_order_to_top(self);
- /* Fall back focus since we're disappearing */
- if (focus_client == self)
- client_unfocus(self);
-
changed = TRUE;
}
} else {
- glong old;
+ self->iconic = iconic;
if (curdesk)
client_set_desktop(self, screen_desktop, FALSE);
- old = self->wmstate;
- self->wmstate = self->shaded ? IconicState : NormalState;
- if (old != self->wmstate)
- PROP_MSG(self->window, kde_wm_change_state,
- self->wmstate, 1, 0, 0);
-
/* this puts it after the current focused window */
focus_order_remove(self);
focus_order_add_new(self);
shade) || /* can't shade */
self->shaded == shade) return; /* already done */
- /* when we're iconic, don't change the wmstate */
- if (!self->iconic) {
- glong old;
-
- old = self->wmstate;
- self->wmstate = shade ? IconicState : NormalState;
- if (old != self->wmstate)
- PROP_MSG(self->window, kde_wm_change_state,
- self->wmstate, 1, 0, 0);
- }
-
self->shaded = shade;
client_change_state(self);
+ client_change_wm_state(self); /* the window is being hidden/shown */
/* resize the frame to just the titlebar */
frame_adjust_area(self->frame, FALSE, FALSE, FALSE);
}
ob_debug("Focusing client \"%s\" at time %u\n", self->title, event_curtime);
if (self->can_focus) {
- /* RevertToPointerRoot causes much more headache than RevertToNone, so
- I choose to use it always, hopefully to find errors quicker, if any
- are left. (I hate X. I hate focus events.)
-
- Update: Changing this to RevertToNone fixed a bug with mozilla (bug
- #799. So now it is RevertToNone again.
- */
- XSetInputFocus(ob_display, self->window, RevertToNone,
+ XSetInputFocus(ob_display, self->window, RevertToPointerRoot,
event_curtime);
}
/* Used when the current client is closed or otherwise hidden, focus_last will
then prevent focus from going to the mouse pointer
*/
-void client_unfocus(ObClient *self)
+static void client_unfocus(ObClient *self)
{
if (focus_client == self) {
#ifdef DEBUG_FOCUS
ob_debug("client_unfocus for %lx\n", self->window);
#endif
- focus_fallback(OB_FOCUS_FALLBACK_CLOSED);
+ focus_fallback(FALSE);
}
}