static GSList *client_destroy_notifies = NULL;
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);
static void client_get_area(ObClient *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;
!self->iconic &&
/* this means focus=true for window is same as config_focus_new=true */
((config_focus_new || (settings && settings->focus == 1)) ||
- client_search_focus_parent(self)) &&
+ client_search_focus_tree_full(self)) &&
/* this checks for focus=false for the window */
(!settings || settings->focus != 0) &&
/* note the check against Type_Normal/Dialog, not client_normal(self),
placex = self->area.x;
placey = self->area.y;
- /* figure out placement for the window */
+ /* figure out placement for the window if the window is new */
if (ob_state() == OB_STATE_RUNNING) {
gboolean transient;
(!self->positioned ? "no" :
(self->positioned == PPosition ? "program specified" :
(self->positioned == USPosition ? "user specified" :
- "BADNESS !?"))), self->area.x, self->area.y);
+ (self->positioned == (PPosition | USPosition) ?
+ "program + user specified" :
+ "BADNESS !?")))), self->area.x, self->area.y);
+
+ ob_debug("Sized: %s @ %d %d\n",
+ (!self->sized ? "no" :
+ (self->sized == PSize ? "program specified" :
+ (self->sized == USSize ? "user specified" :
+ (self->sized == (PSize | USSize) ?
+ "program + user specified" :
+ "BADNESS !?")))), self->area.width, self->area.height);
transient = place_client(self, &placex, &placey, settings);
+ /* if the window isn't user-positioned, then make it fit inside
+ the visible screen area on its monitor.
+
+ the monitor is chosen by place_client! */
+ if (!(self->sized & USSize)) {
+ /* make a copy to modify */
+ Rect a = *screen_area_monitor(self->desktop, client_monitor(self));
+
+ /* shrink by the frame's area */
+ a.width -= self->frame->size.left + self->frame->size.right;
+ a.height -= self->frame->size.top + self->frame->size.bottom;
+
+ /* fit the window inside the area */
+ if (self->area.width > a.width || self->area.height > a.height) {
+ self->area.width = MIN(self->area.width, a.width);
+ self->area.height = MIN(self->area.height, a.height);
+
+ ob_debug("setting window size to %dx%d\n",
+ self->area.width, self->area.height);
+
+ /* adjust the frame to the client's new size */
+ frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
+ frame_adjust_client_area(self->frame);
+ }
+ }
+
/* make sure the window is visible. */
client_find_onscreen(self, &placex, &placey,
self->area.width, self->area.height,
*/
client_configure(self, placex, placey,
self->area.width, self->area.height,
+ self->border_width,
FALSE, TRUE);
"Not focusing the window because its on another "
"desktop\n");
}
- /* If something is focused, and it's not our parent... */
- else if (focus_client && client_search_focus_parent(self) == NULL)
+ /* If something is focused, and it's not our relative... */
+ else if (focus_client && client_search_focus_tree_full(self) == NULL)
{
/* If time stamp is old, don't steal focus */
if (self->user_time && last_time &&
"Not focusing the window because the time is "
"too old\n");
}
+ /* If its a transient (and parents aren't focused) and the time
+ is ambiguous (either the current focus target doesn't have
+ a timestamp, or they are the same (we probably inherited it
+ from them) */
+ else if (self->transient_for != NULL &&
+ (!last_time || self->user_time == last_time))
+ {
+ activate = FALSE;
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Not focusing the window because it is a "
+ "transient, and the time is very ambiguous\n");
+ }
/* Don't steal focus from globally active clients.
I stole this idea from KWin. It seems nice.
*/
- if (!(focus_client->can_focus || focus_client->focus_notify)) {
+ else if (!(focus_client->can_focus ||
+ focus_client->focus_notify))
+ {
activate = FALSE;
ob_debug_type(OB_DEBUG_FOCUS,
"Not focusing the window because a globally "
"active client has focus\n");
}
+ /* Don't move focus if it's not going to go to this window
+ anyway */
+ else if (client_focus_target(self) != self) {
+ activate = FALSE;
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Not focusing the window because another window "
+ "would get the focus anyway\n");
+ }
}
if (!activate) {
self->frame = frame_new(self);
frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+ ob_debug("gave extents left %d right %d top %d bottom %d\n",
+ self->frame->size.left, self->frame->size.right,
+ self->frame->size.top, self->frame->size.bottom);
+
/* free the ObAppSettings shallow copy */
g_free(settings);
{
Rect a;
- /* give the client its border back */
- client_toggle_border(self, TRUE);
-
a = self->area;
if (self->fullscreen)
RECT_SET_POINT(self->area, self->session->x, self->session->y);
self->positioned = USPosition;
+ self->sized = USSize;
if (self->session->w > 0)
self->area.width = self->session->w;
if (self->session->h > 0)
return ox != *x || oy != *y;
}
-static void client_toggle_border(ObClient *self, gboolean show)
-{
- /* adjust our idea of where the client is, based on its border. When the
- border is removed, the client should now be considered to be in a
- different position.
- when re-adding the border to the client, the same operation needs to be
- reversed. */
- gint oldx = self->area.x, oldy = self->area.y;
- gint x = oldx, y = oldy;
- switch(self->gravity) {
- default:
- case NorthWestGravity:
- case WestGravity:
- case SouthWestGravity:
- break;
- case NorthEastGravity:
- case EastGravity:
- case SouthEastGravity:
- if (show) x -= self->border_width * 2;
- else x += self->border_width * 2;
- break;
- case NorthGravity:
- case SouthGravity:
- case CenterGravity:
- case ForgetGravity:
- case StaticGravity:
- if (show) x -= self->border_width;
- else x += self->border_width;
- break;
- }
- switch(self->gravity) {
- default:
- case NorthWestGravity:
- case NorthGravity:
- case NorthEastGravity:
- break;
- case SouthWestGravity:
- case SouthGravity:
- case SouthEastGravity:
- if (show) y -= self->border_width * 2;
- else y += self->border_width * 2;
- break;
- case WestGravity:
- case EastGravity:
- case CenterGravity:
- case ForgetGravity:
- case StaticGravity:
- if (show) y -= self->border_width;
- else y += self->border_width;
- break;
- }
- self->area.x = x;
- self->area.y = y;
-
- if (show) {
- XSetWindowBorderWidth(ob_display, self->window, self->border_width);
-
- /* set border_width to 0 because there is no border to add into
- calculations anymore */
- self->border_width = 0;
- } else
- XSetWindowBorderWidth(ob_display, self->window, 0);
-}
-
-
static void client_get_all(ObClient *self, gboolean real)
{
/* this is needed for the frame to set itself up */
self->desktop = self->transient_for->desktop;
trdesk = TRUE;
} else {
+ /* if all the group is on one desktop, then open it on the
+ same desktop */
GSList *it;
+ gboolean first = TRUE;
+ guint all = screen_num_desktops; /* not a valid value */
- for (it = self->group->members; it; it = g_slist_next(it))
- if (it->data != self &&
- !((ObClient*)it->data)->transient_for) {
- self->desktop = ((ObClient*)it->data)->desktop;
- trdesk = TRUE;
- break;
+ for (it = self->group->members; it; it = g_slist_next(it)) {
+ ObClient *c = it->data;
+ if (c != self) {
+ if (first) {
+ all = c->desktop;
+ first = FALSE;
+ }
+ else if (all != c->desktop)
+ all = screen_num_desktops; /* make it invalid */
}
+ }
+ if (all != screen_num_desktops) {
+ self->desktop = all;
+ trdesk = TRUE;
+ }
}
}
if (!trdesk) {
{
XSizeHints size;
glong ret;
- gint oldgravity = self->gravity;
/* defaults */
self->min_ratio = 0.0f;
if (!client_normal(self))
*/
self->positioned = (size.flags & (PPosition|USPosition));
+ self->sized = (size.flags & (PSize|USSize));
- if (size.flags & PWinGravity) {
+ if (size.flags & PWinGravity)
self->gravity = size.win_gravity;
-
- /* if the client has a frame, i.e. has already been mapped and
- is changing its gravity */
- if (self->frame && self->gravity != oldgravity) {
- /* move our idea of the client's position based on its new
- gravity */
- client_convert_gravity(self, oldgravity,
- &self->area.x, &self->area.y,
- self->area.width, self->area.height);
- }
- }
if (size.flags & PAspect) {
if (size.min_aspect.y)
case OB_CLIENT_TYPE_DIALOG:
case OB_CLIENT_TYPE_UTILITY:
- /* these windows cannot be maximized */
- self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE;
+ /* these windows don't have anything added or removed by default */
break;
case OB_CLIENT_TYPE_MENU:
case OB_CLIENT_TYPE_TOOLBAR:
- /* these windows get less functionality */
- self->functions &= ~(OB_CLIENT_FUNC_ICONIFY | OB_CLIENT_FUNC_RESIZE);
+ /* these windows can't iconify or maximize */
+ self->decorations &= ~(OB_FRAME_DECOR_ICONIFY |
+ OB_FRAME_DECOR_MAXIMIZE);
+ self->functions &= ~(OB_CLIENT_FUNC_ICONIFY |
+ OB_CLIENT_FUNC_MAXIMIZE);
break;
case OB_CLIENT_TYPE_SPLASH:
self->decorations &= ~OB_FRAME_DECOR_MAXIMIZE;
}
- if (self->max_horz && self->max_vert)
+ if (self->max_horz && self->max_vert) {
+ /* you can't resize fully maximized windows */
+ self->functions &= ~OB_CLIENT_FUNC_RESIZE;
/* kill the handle on fully maxed windows */
self->decorations &= ~(OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS);
+ }
/* If there are no decorations to remove, don't allow the user to try
toggle the state */
void client_reconfigure(ObClient *self)
{
- /* by making this pass FALSE for user, we avoid the emacs event storm where
- every configurenotify causes an update in its normal hints, i think this
- is generally what we want anyways... */
client_configure(self, self->area.x, self->area.y,
- self->area.width, self->area.height, FALSE, TRUE);
+ self->area.width, self->area.height,
+ self->border_width, FALSE, TRUE);
}
void client_update_wmhints(ObClient *self)
}
/* the WM_HINTS can contain an icon */
- client_update_icons(self);
+ if (hints->flags & IconPixmapHint)
+ client_update_icons(self);
XFree(hints);
}
PROP_GETS(self->window, wm_icon_name, utf8, &data)))
data = g_strdup(self->title);
- PROP_SETS(self->window, net_wm_visible_icon_name, data);
- self->icon_title = data;
+ if (self->client_machine) {
+ visible = g_strdup_printf("%s (%s)", data, self->client_machine);
+ g_free(data);
+ } else
+ visible = data;
+
+ PROP_SETS(self->window, net_wm_visible_icon_name, visible);
+ self->icon_title = visible;
}
void client_update_strut(ObClient *self)
state[0] = self->wmstate;
state[1] = None;
PROP_SETA32(self->window, wm_state, wm_state, state, 2);
- ob_debug("setting wm_state %d\n", self->wmstate);
}
}
}
else if ((self->fullscreen ||
/* No decorations and fills the monitor = oldskool fullscreen.
- But not for undecorated windows, because the user can do that
+ But not for maximized windows.
*/
(self->decorations == 0 &&
- !self->undecorated &&
+ !(self->max_horz && self->max_vert) &&
RECT_EQUAL(self->area,
*screen_physical_area_monitor
(client_monitor(self))))) &&
actions should not rely on being able to move focus during an
interactive grab.
*/
- if (keyboard_interactively_grabbed())
- keyboard_interactive_cancel();
+ event_cancel_all_key_grabs();
}
frame_hide(self->frame);
*/
}
-void client_convert_gravity(ObClient *self, gint gravity, gint *x, gint *y,
- gint w, gint h)
+void client_gravity_resize_w(ObClient *self, gint *x, gint oldw, gint neww)
{
- gint oldg = self->gravity;
+ /* these should be the current values. this is for when you're not moving,
+ just resizing */
+ g_assert(*x == self->area.x);
+ g_assert(oldw == self->area.width);
- /* get the frame's position from the requested stuff */
- self->gravity = gravity;
- frame_client_gravity(self->frame, x, y, w, h);
- self->gravity = oldg;
+ /* horizontal */
+ switch (self->gravity) {
+ default:
+ case NorthWestGravity:
+ case WestGravity:
+ case SouthWestGravity:
+ case StaticGravity:
+ case ForgetGravity:
+ break;
+ case NorthGravity:
+ case CenterGravity:
+ case SouthGravity:
+ *x -= (neww - oldw) / 2;
+ break;
+ case NorthEastGravity:
+ case EastGravity:
+ case SouthEastGravity:
+ *x -= neww - oldw;
+ break;
+ }
+}
- /* get the client's position in its true gravity from that */
- frame_frame_gravity(self->frame, x, y, w, h);
+void client_gravity_resize_h(ObClient *self, gint *y, gint oldh, gint newh)
+{
+ /* these should be the current values. this is for when you're not moving,
+ just resizing */
+ g_assert(*y == self->area.y);
+ g_assert(oldh == self->area.height);
+
+ /* vertical */
+ switch (self->gravity) {
+ default:
+ case NorthWestGravity:
+ case NorthGravity:
+ case NorthEastGravity:
+ case StaticGravity:
+ case ForgetGravity:
+ break;
+ case WestGravity:
+ case CenterGravity:
+ case EastGravity:
+ *y -= (newh - oldh) / 2;
+ break;
+ case SouthWestGravity:
+ case SouthGravity:
+ case SouthEastGravity:
+ *y -= newh - oldh;
+ break;
+ }
}
void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
*h = a->height;
user = FALSE; /* ignore if the client can't be moved/resized when it
- is entering fullscreen */
+ is fullscreening */
} else if (self->max_horz || self->max_vert) {
Rect *a;
guint i;
*h = a->height - self->frame->size.top - self->frame->size.bottom;
}
- /* maximizing is not allowed if the user can't move+resize the window
- */
+ user = FALSE; /* ignore if the client can't be moved/resized when it
+ is maximizing */
}
/* gets the client's position */
}
-void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
+void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
gboolean user, gboolean final)
{
gint oldw, oldh;
/* 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;
+ resized = w != self->area.width || h != self->area.height ||
+ b != self->border_width;
oldw = self->area.width;
oldh = self->area.height;
RECT_SET(self->area, x, y, w, h);
+ self->border_width = b;
/* for app-requested resizes, always resize if 'resized' is true.
for user-requested ones, only resize if final is true, or when
/* if the client is enlarging, then resize the client before the frame */
if (send_resize_client && (w > oldw || h > oldh)) {
- XResizeWindow(ob_display, self->window,
- MAX(w, oldw), MAX(h, oldh));
+ XWindowChanges changes;
+ changes.x = -self->border_width;
+ changes.y = -self->border_width;
+ changes.width = MAX(w, oldw);
+ changes.height = MAX(h, oldh);
+ changes.border_width = self->border_width;
+ XConfigureWindow(ob_display, self->window,
+ CWX|CWY|CWWidth|CWHeight|CWBorderWidth,
+ &changes);
/* resize the plate to show the client padding color underneath */
frame_adjust_client_area(self->frame);
}
{
XEvent event;
+ /* we have reset the client to 0 border width, so don't include
+ it in these coords */
POINT_SET(self->root_pos,
self->frame->area.x + self->frame->size.left -
self->border_width,
event.xconfigure.y = self->root_pos.y;
event.xconfigure.width = w;
event.xconfigure.height = h;
- event.xconfigure.border_width = 0;
+ event.xconfigure.border_width = self->border_width;
event.xconfigure.above = self->frame->plate;
event.xconfigure.override_redirect = FALSE;
XSendEvent(event.xconfigure.display, event.xconfigure.window,
/* resize the plate to show the client padding color underneath */
frame_adjust_client_area(self->frame);
- if (send_resize_client)
- XResizeWindow(ob_display, self->window, w, h);
+ if (send_resize_client) {
+ XWindowChanges changes;
+ changes.x = -self->border_width;
+ changes.y = -self->border_width;
+ changes.width = w;
+ changes.height = h;
+ changes.border_width = self->border_width;
+ XConfigureWindow(ob_display, self->window,
+ CWX|CWY|CWWidth|CWHeight|CWBorderWidth,
+ &changes);
+ }
}
XFlush(ob_display);
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);
+ the list */
+ focus_order_to_bottom(self);
changed = TRUE;
}
actions should not rely on being able to move focus during an
interactive grab.
*/
- if (keyboard_interactively_grabbed())
- keyboard_interactive_cancel();
+ event_cancel_all_key_grabs();
xerror_set_ignore(TRUE);
xerror_occured = FALSE;
for (i = 1; i < self->nicons; ++i) {
gulong diff;
- diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h);
+ diff = ABS(self->icons[i].width - w) + ABS(self->icons[i].height - h);
if (diff < min_diff) {
min_diff = diff;
min_i = i;