/* focus the new window? */
if (ob_state() != OB_STATE_STARTING &&
(!self->session || self->session->focused) &&
- !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_tree_full(self)) &&
/* this checks for focus=false for the window */
(!settings || settings->focus != 0) &&
- /* note the check against type Normal/Dialog/Utility,
- not client_normal(self), which would also include other types.
- in this case we want more strict rules for focus */
- (self->type == OB_CLIENT_TYPE_NORMAL ||
- self->type == OB_CLIENT_TYPE_UTILITY ||
- self->type == OB_CLIENT_TYPE_DIALOG))
+ focus_valid_target(self, FALSE, TRUE, FALSE, FALSE))
{
activate = TRUE;
}
client_normal(self) &&
!self->session)))
{
- /* make a copy to modify */
- Rect a = *screen_area_monitor(self->desktop, client_monitor(self));
+ Rect placer;
+
+ RECT_SET(placer, placex, placey, placew, placeh);
+ frame_rect_to_frame(self->frame, &placer);
+
+ Rect *a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &placer);
/* 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;
+ 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 (placew > a.width || self->area.height > a.height) {
- placew = MIN(self->area.width, a.width);
- placeh = MIN(self->area.height, a.height);
+ if (placew > a->width || self->area.height > a->height) {
+ placew = MIN(self->area.width, a->width);
+ placeh = MIN(self->area.height, a->height);
ob_debug("setting window size to %dx%d\n",
self->area.width, self->area.height);
}
+ g_free(a);
}
gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
gboolean rude)
{
- Rect *mon_a, *all_a;
gint ox = *x, oy = *y;
gboolean rudel = rude, ruder = rude, rudet = rude, rudeb = rude;
gint fw, fh;
Rect desired;
+ guint i;
RECT_SET(desired, *x, *y, w, h);
- all_a = screen_area(self->desktop);
- mon_a = screen_area_monitor(self->desktop, screen_find_monitor(&desired));
+ frame_rect_to_frame(self->frame, &desired);
/* get where the frame would be */
frame_client_gravity(self->frame, x, y, w, h);
fw = self->frame->size.left + w + self->frame->size.right;
fh = self->frame->size.top + h + self->frame->size.bottom;
- /* This makes sure windows aren't entirely outside of the screen so you
- can't see them at all.
- It makes sure 10% of the window is on the screen at least. At don't let
- it move itself off the top of the screen, which would hide the titlebar
- on you. (The user can still do this if they want too, it's only limiting
- the application.
-
- XXX watch for xinerama dead areas...
- */
- if (client_normal(self)) {
- if (!self->strut.right && *x + fw/10 >= all_a->x + all_a->width - 1)
- *x = all_a->x + all_a->width - fw/10;
- if (!self->strut.bottom && *y + fh/10 >= all_a->y + all_a->height - 1)
- *y = all_a->y + all_a->height - fh/10;
- if (!self->strut.left && *x + fw*9/10 - 1 < all_a->x)
- *x = all_a->x - fw*9/10;
- if (!self->strut.top && *y + fh*9/10 - 1 < all_a->y)
- *y = all_a->y - fw*9/10;
- }
-
- /* If rudeness wasn't requested, then figure out of the client is currently
- entirely on the screen. If it is, and the position isn't changing by
- request, and it is enlarging, then be rude even though it wasn't
- requested */
+ /* If rudeness wasn't requested, then still be rude in a given direction
+ if the client is not moving, only resizing in that direction */
if (!rude) {
Point oldtl, oldtr, oldbl, oldbr;
Point newtl, newtr, newbl, newbr;
rudeb = TRUE;
}
- /* This here doesn't let windows even a pixel outside the struts/screen.
- * When called from client_manage, programs placing themselves are
- * forced completely onscreen, while things like
- * xterm -geometry resolution-width/2 will work fine. Trying to
- * place it completely offscreen will be handled in the above code.
- * Sorry for this confused comment, i am tired. */
- if (rudel && !self->strut.left && *x < mon_a->x) *x = mon_a->x;
- if (ruder && !self->strut.right && *x + fw > mon_a->x + mon_a->width)
- *x = mon_a->x + MAX(0, mon_a->width - fw);
+ for (i = 0; i < screen_num_monitors; ++i) {
+ Rect *a;
+
+ if (!screen_physical_area_monitor_contains(i, &desired))
+ continue;
+
+ a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &desired);
- if (rudet && !self->strut.top && *y < mon_a->y) *y = mon_a->y;
- if (rudeb && !self->strut.bottom && *y + fh > mon_a->y + mon_a->height)
- *y = mon_a->y + MAX(0, mon_a->height - fh);
+ /* This makes sure windows aren't entirely outside of the screen so you
+ can't see them at all.
+ It makes sure 10% of the window is on the screen at least. At don't
+ let it move itself off the top of the screen, which would hide the
+ titlebar on you. (The user can still do this if they want too, it's
+ only limiting the application.
+ */
+ if (client_normal(self)) {
+ if (!self->strut.right && *x + fw/10 >= a->x + a->width - 1)
+ *x = a->x + a->width - fw/10;
+ if (!self->strut.bottom && *y + fh/10 >= a->y + a->height - 1)
+ *y = a->y + a->height - fh/10;
+ if (!self->strut.left && *x + fw*9/10 - 1 < a->x)
+ *x = a->x - fw*9/10;
+ if (!self->strut.top && *y + fh*9/10 - 1 < a->y)
+ *y = a->y - fw*9/10;
+ }
+
+ /* This here doesn't let windows even a pixel outside the
+ struts/screen. When called from client_manage, programs placing
+ themselves are forced completely onscreen, while things like
+ xterm -geometry resolution-width/2 will work fine. Trying to
+ place it completely offscreen will be handled in the above code.
+ Sorry for this confused comment, i am tired. */
+ if (rudel && !self->strut.left && *x < a->x) *x = a->x;
+ if (ruder && !self->strut.right && *x + fw > a->x + a->width)
+ *x = a->x + MAX(0, a->width - fw);
+
+ if (rudet && !self->strut.top && *y < a->y) *y = a->y;
+ if (rudeb && !self->strut.bottom && *y + fh > a->y + a->height)
+ *y = a->y + MAX(0, a->height - fh);
+
+ g_free(a);
+ }
/* get where the client should be */
frame_frame_gravity(self->frame, x, y, w, h);
if (size.flags & PResizeInc && size.width_inc && size.height_inc)
SIZE_SET(self->size_inc, size.width_inc, size.height_inc);
+
+ ob_debug("Normal hints: min size (%d %d) max size (%d %d)\n "
+ "size inc (%d %d) base size (%d %d)\n",
+ self->min_size.width, self->min_size.height,
+ self->max_size.width, self->max_size.height,
+ self->size_inc.width, self->size_inc.height,
+ self->base_size.width, self->base_size.height);
}
+ else
+ ob_debug("Normal hints: not set\n");
}
void client_setup_decor_and_functions(ObClient *self, gboolean reconfig)
client_change_allowed_actions(self);
if (reconfig)
- client_reconfigure(self);
+ /* force reconfigure to make sure decorations are updated */
+ client_reconfigure(self, TRUE);
}
static void client_change_allowed_actions(ObClient *self)
}
}
-void client_reconfigure(ObClient *self)
-{
- client_configure(self, self->area.x, self->area.y,
- self->area.width, self->area.height,
- FALSE, TRUE);
-}
-
void client_update_wmhints(ObClient *self)
{
XWMHints *hints;
if (!got &&
PROP_GETA32(self->window, net_wm_strut, cardinal, &data, &num)) {
if (num == 4) {
- const Rect *a;
+ Rect *a;
got = TRUE;
/* use the screen's width/height */
- a = screen_physical_area();
+ a = screen_physical_area_all_monitors();
STRUT_PARTIAL_SET(strut,
data[0], data[2], data[1], data[3],
a->x, a->x + a->width - 1,
a->y, a->y + a->height - 1,
a->x, a->x + a->width - 1);
+ g_free(a);
}
g_free(data);
}
static ObStackingLayer calc_layer(ObClient *self)
{
ObStackingLayer l;
+ Rect *monitor;
+
+ monitor = screen_physical_area_monitor(client_monitor(self));
if (self->type == OB_CLIENT_TYPE_DESKTOP)
l = OB_STACKING_LAYER_DESKTOP;
*/
(self->decorations == 0 &&
!(self->max_horz && self->max_vert) &&
- RECT_EQUAL(self->area,
- *screen_physical_area_monitor
- (client_monitor(self))))) &&
+ RECT_EQUAL(self->area, *monitor))) &&
(client_focused(self) || client_search_focus_tree(self)))
l = OB_STACKING_LAYER_FULLSCREEN;
else if (self->above) l = OB_STACKING_LAYER_ABOVE;
else if (self->below) l = OB_STACKING_LAYER_BELOW;
else l = OB_STACKING_LAYER_NORMAL;
+ g_free(monitor);
+
return l;
}
gboolean client_hide(ObClient *self)
{
gboolean hide = FALSE;
- gulong ignore_start;
if (!client_should_show(self)) {
if (self == focus_client) {
event_cancel_all_key_grabs();
}
- if (!config_focus_under_mouse)
- ignore_start = event_start_ignore_all_enters();
+ /* We don't need to ignore enter events here.
+ The window can hide/iconify in 3 different ways:
+ 1 - through an x message. in this case we ignore all enter events
+ caused by responding to the x message (unless underMouse)
+ 2 - by a keyboard action. in this case we ignore all enter events
+ caused by the action
+ 3 - by a mouse action. in this case they are doing stuff with the
+ mouse and focus _should_ move.
+
+ Also in action_end, we simulate an enter event that can't be ignored
+ so trying to ignore them is futile in case 3 anyways
+ */
frame_hide(self->frame);
hide = TRUE;
- if (!config_focus_under_mouse)
- event_end_ignore_all_enters(ignore_start);
-
/* 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!
/* if the window hasn't been configured yet, then do so now */
if (!fullscreen && !max_vert && !max_horz) {
self->area = oldarea;
- client_configure(self, x, y, w, h, FALSE, TRUE);
+ client_configure(self, x, y, w, h, FALSE, TRUE, FALSE);
}
/* set the desktop hint, to make sure that it always exists */
gint *logicalw, gint *logicalh,
gboolean user)
{
- Rect desired_area = {*x, *y, *w, *h};
+ Rect desired = {*x, *y, *w, *h};
+ frame_rect_to_frame(self->frame, &desired);
/* make the frame recalculate its dimentions n shit without changing
anything visible for real, this way the constraints below can work with
the updated frame dimensions. */
frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+ /* gets the frame's position */
+ frame_client_gravity(self->frame, x, y, *w, *h);
+
+ /* these positions are frame positions, not client positions */
+
+ /* set the size and position if fullscreen */
+ if (self->fullscreen) {
+ Rect *a;
+ guint i;
+
+ i = screen_find_monitor(&desired);
+ a = screen_physical_area_monitor(i);
+
+ *x = a->x;
+ *y = a->y;
+ *w = a->width;
+ *h = a->height;
+
+ user = FALSE; /* ignore if the client can't be moved/resized when it
+ is fullscreening */
+
+ g_free(a);
+ } else if (self->max_horz || self->max_vert) {
+ Rect *a;
+ guint i;
+
+ /* use all possible struts when maximizing to the full screen */
+ i = screen_find_monitor(&desired);
+ a = screen_area(self->desktop, i,
+ (self->max_horz && self->max_vert ? NULL : &desired));
+
+ /* 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;
+ }
+ if (self->max_vert) {
+ *y = a->y;
+ *h = a->height - self->frame->size.top - self->frame->size.bottom;
+ }
+
+ user = FALSE; /* ignore if the client can't be moved/resized when it
+ is maximizing */
+
+ g_free(a);
+ }
+
+ /* gets the client's position */
+ frame_frame_gravity(self->frame, x, y, *w, *h);
+
/* work within the prefered sizes given by the window */
if (!(*w == self->area.width && *h == self->area.height)) {
gint basew, baseh, minw, minh;
+ gint incw, inch;
+ gfloat minratio, maxratio;
+
+ incw = self->fullscreen || self->max_horz ? 1 : self->size_inc.width;
+ inch = self->fullscreen || self->max_vert ? 1 : self->size_inc.height;
+ minratio = self->fullscreen || (self->max_horz && self->max_vert) ?
+ 0 : self->min_ratio;
+ maxratio = self->fullscreen || (self->max_horz && self->max_vert) ?
+ 0 : self->max_ratio;
/* base size is substituted with min size if not specified */
if (self->base_size.width || self->base_size.height) {
*h -= baseh;
/* keep to the increments */
- *w /= self->size_inc.width;
- *h /= self->size_inc.height;
+ *w /= incw;
+ *h /= inch;
/* you cannot resize to nothing */
if (basew + *w < 1) *w = 1 - basew;
if (baseh + *h < 1) *h = 1 - baseh;
/* save the logical size */
- *logicalw = self->size_inc.width > 1 ? *w : *w + basew;
- *logicalh = self->size_inc.height > 1 ? *h : *h + baseh;
+ *logicalw = incw > 1 ? *w : *w + basew;
+ *logicalh = inch > 1 ? *h : *h + baseh;
- *w *= self->size_inc.width;
- *h *= self->size_inc.height;
+ *w *= incw;
+ *h *= inch;
*w += basew;
*h += baseh;
*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 (minratio)
+ if (*h * minratio > *w) {
+ *h = (gint)(*w / minratio);
- /* you cannot resize to nothing */
- if (*h < 1) {
- *h = 1;
- *w = (gint)(*h * self->min_ratio);
- }
+ /* you cannot resize to nothing */
+ if (*h < 1) {
+ *h = 1;
+ *w = (gint)(*h * minratio);
}
- if (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 (maxratio)
+ if (*h * maxratio < *w) {
+ *h = (gint)(*w / maxratio);
+
+ /* you cannot resize to nothing */
+ if (*h < 1) {
+ *h = 1;
+ *w = (gint)(*h * minratio);
}
- }
+ }
*w += self->base_size.width;
*h += self->base_size.height;
}
- /* gets the frame's position */
- frame_client_gravity(self->frame, x, y, *w, *h);
-
- /* these positions are frame positions, not client positions */
-
- /* set the size and position if fullscreen */
- if (self->fullscreen) {
- Rect *a;
- guint i;
-
- i = screen_find_monitor(&desired_area);
- a = screen_physical_area_monitor(i);
-
- *x = a->x;
- *y = a->y;
- *w = a->width;
- *h = a->height;
-
- user = FALSE; /* ignore if the client can't be moved/resized when it
- is fullscreening */
- } else if (self->max_horz || self->max_vert) {
- Rect *a;
- guint i;
-
- i = screen_find_monitor(&desired_area);
- a = screen_area_monitor(self->desktop, i);
-
- /* 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;
- }
- if (self->max_vert) {
- *y = a->y;
- *h = a->height - self->frame->size.top - self->frame->size.bottom;
- }
-
- user = FALSE; /* ignore if the client can't be moved/resized when it
- is maximizing */
- }
-
- /* gets the client's position */
- frame_frame_gravity(self->frame, x, y, *w, *h);
-
/* these override the above states! if you cant move you can't move! */
if (user) {
if (!(self->functions & OB_CLIENT_FUNC_MOVE)) {
void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
- gboolean user, gboolean final)
+ gboolean user, gboolean final, gboolean force_reply)
{
gint oldw, oldh;
gboolean send_resize_client;
- gboolean moved = FALSE, resized = FALSE;
+ gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE;
gboolean fmoved, fresized;
guint fdecor = self->frame->decorations;
gboolean fhorz = self->frame->max_horz;
}
/* adjust the frame */
- if (fmoved || fresized)
+ if (fmoved || fresized) {
+ gulong ignore_start;
+ if (!user)
+ ignore_start = event_start_ignore_all_enters();
+
frame_adjust_area(self->frame, fmoved, fresized, FALSE);
+ if (!user)
+ event_end_ignore_all_enters(ignore_start);
+ }
+
+ if (!user || final) {
+ gint oldrx = self->root_pos.x;
+ gint oldry = self->root_pos.y;
+ /* 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,
+ self->frame->area.y + self->frame->size.top -
+ self->border_width);
+ if (self->root_pos.x != oldrx || self->root_pos.y != oldry)
+ rootmoved = TRUE;
+ }
+
/* This is kinda tricky and should not be changed.. let me explain!
When user = FALSE, then the request is coming from the application
itself, and we are more strict about when to send a synthetic
ConfigureNotify. We strictly follow the rules of the ICCCM sec 4.1.5
- in this case.
+ in this case (if force_reply is true)
When user = TRUE, then the request is coming from "us", like when we
- maximize a window or sometihng. In this case we are more lenient. We
+ maximize a window or something. In this case we are more lenient. We
used to follow the same rules as above, but _Java_ Swing can't handle
this. So just to appease Swing, when user = TRUE, we always send
a synthetic ConfigureNotify to give the window its root coordinates.
*/
- if ((!user && !resized) || (user && final))
+ if ((!user && !resized && (rootmoved || force_reply)) ||
+ (user && final && rootmoved))
{
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,
- self->frame->area.y + self->frame->size.top -
- self->border_width);
-
event.type = ConfigureNotify;
event.xconfigure.display = ob_display;
event.xconfigure.event = self->window;
if (curdesk && self->desktop != screen_desktop &&
self->desktop != DESKTOP_ALL)
- client_set_desktop(self, screen_desktop, FALSE);
+ client_set_desktop(self, screen_desktop, FALSE, FALSE);
/* this puts it after the current focused window */
focus_order_remove(self);
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);
+ frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
}
void client_close(ObClient *self)
void client_set_desktop_recursive(ObClient *self,
guint target,
- gboolean donthide)
+ gboolean donthide,
+ gboolean dontraise)
{
guint old;
GSList *it;
frame_adjust_state(self->frame);
/* 'move' the window to the new desktop */
if (!donthide)
- client_showhide(self);
+ client_hide(self);
+ client_show(self);
/* raise if it was not already on the desktop */
- if (old != DESKTOP_ALL)
+ if (old != DESKTOP_ALL && !dontraise)
stacking_raise(CLIENT_AS_WINDOW(self));
if (STRUT_EXISTS(self->strut))
screen_update_areas();
+ else
+ /* the new desktop's geometry may be different, so we may need to
+ resize, for example if we are maximized */
+ client_reconfigure(self, FALSE);
}
/* move all transients */
for (it = self->transients; it; it = g_slist_next(it))
if (it->data != self)
if (client_is_direct_child(self, it->data))
- client_set_desktop_recursive(it->data, target, donthide);
+ client_set_desktop_recursive(it->data, target,
+ donthide, dontraise);
}
-void client_set_desktop(ObClient *self, guint target, gboolean donthide)
+void client_set_desktop(ObClient *self, guint target,
+ gboolean donthide, gboolean dontraise)
{
self = client_search_top_direct_parent(self);
- client_set_desktop_recursive(self, target, donthide);
+ client_set_desktop_recursive(self, target, donthide, dontraise);
}
gboolean client_is_direct_child(ObClient *parent, ObClient *child)
self->desktop != screen_desktop)
{
if (here)
- client_set_desktop(self, screen_desktop, FALSE);
+ client_set_desktop(self, screen_desktop, FALSE, TRUE);
else
screen_set_desktop(self->desktop, FALSE);
} else if (!self->frame->visible)
if (iconic && self->iconic)
client_iconify(self, FALSE, TRUE, FALSE);
else
- client_set_desktop(self, desktop, FALSE);
+ client_set_desktop(self, desktop, FALSE, FALSE);
}
}
gint dest, monitor_dest;
gint my_edge_start, my_edge_end, my_offset;
GList *it;
- Rect *a, *monitor;
+ Rect *a, *mon;
if(!client_list)
return -1;
- a = screen_area(c->desktop);
- monitor = screen_area_monitor(c->desktop, client_monitor(c));
+ a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
+ mon = screen_area(c->desktop, SCREEN_AREA_ONE_MONITOR, &c->frame->area);
switch(dir) {
case OB_DIRECTION_NORTH:
/* default: top of screen */
dest = a->y + (hang ? c->frame->area.height : 0);
- monitor_dest = monitor->y + (hang ? c->frame->area.height : 0);
+ monitor_dest = mon->y + (hang ? c->frame->area.height : 0);
/* if the monitor edge comes before the screen edge, */
/* use that as the destination instead. (For xinerama) */
if (monitor_dest != dest && my_offset > monitor_dest)
/* default: bottom of screen */
dest = a->y + a->height - (hang ? c->frame->area.height : 0);
- monitor_dest = monitor->y + monitor->height -
+ monitor_dest = mon->y + mon->height -
(hang ? c->frame->area.height : 0);
/* if the monitor edge comes before the screen edge, */
/* use that as the destination instead. (For xinerama) */
/* default: leftmost egde of screen */
dest = a->x + (hang ? c->frame->area.width : 0);
- monitor_dest = monitor->x + (hang ? c->frame->area.width : 0);
+ monitor_dest = mon->x + (hang ? c->frame->area.width : 0);
/* if the monitor edge comes before the screen edge, */
/* use that as the destination instead. (For xinerama) */
if (monitor_dest != dest && my_offset > monitor_dest)
/* default: rightmost edge of screen */
dest = a->x + a->width - (hang ? c->frame->area.width : 0);
- monitor_dest = monitor->x + monitor->width -
+ monitor_dest = mon->x + mon->width -
(hang ? c->frame->area.width : 0);
/* if the monitor edge comes before the screen edge, */
/* use that as the destination instead. (For xinerama) */
g_assert_not_reached();
dest = 0; /* suppress warning */
}
+
+ g_free(a);
+ g_free(mon);
return dest;
}