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);
XWMHints *wmhint;
gboolean activate = FALSE;
ObAppSettings *settings;
+ gint placex, placey;
grab_server(TRUE);
XFree(wmhint);
}
- ob_debug("Managing window: %lx\n", window);
+ ob_debug("Managing window: 0x%lx\n", window);
/* choose the events we want to receive on the CLIENT window */
attrib_set.event_mask = CLIENT_EVENTMASK;
grab_server(FALSE);
/* per-app settings override stuff from client_get_all, and return the
- settings for other uses too */
+ settings for other uses too. the returned settings is a shallow copy,
+ that needs to be freed with g_free(). */
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;
!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),
activate = TRUE;
}
- /* figure out placement for the window */
+ /* adjust the frame to the client's size before showing or placing
+ the window */
+ frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
+ frame_adjust_client_area(self->frame);
+
+ /* where the frame was placed is where the window was originally */
+ placex = self->area.x;
+ placey = self->area.y;
+
+ /* 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);
-
- transient = place_client(self, &self->area.x, &self->area.y, settings);
+ (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, &self->area.x, &self->area.y,
+ client_find_onscreen(self, &placex, &placey,
self->area.width, self->area.height,
/* non-normal clients has less rules, and
windows that are being restored from a
it is up to the placement routines to avoid
the xinerama divides) */
transient ||
- (((self->positioned & PPosition) &&
- !(self->positioned & USPosition)) &&
+ (!(self->positioned & USPosition) &&
client_normal(self) &&
!self->session));
}
ob_debug("placing window 0x%x at %d, %d with size %d x %d\n",
- self->window, self->area.x, self->area.y,
+ self->window, placex, placey,
self->area.width, self->area.height);
if (self->session)
ob_debug(" but session requested %d %d instead, overriding\n",
self->session->x, self->session->y);
- /* adjust the frame to the client's size before showing the window */
- frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
- frame_adjust_client_area(self->frame);
-
+ /* do this after the window is placed, so the premax/prefullscreen numbers
+ won't be all wacko!!
+ also, this moves the window to the position where it has been placed
+ */
+ client_apply_startup_state(self);
/* move the client to its placed position, or it it's already there,
generate a ConfigureNotify telling the client where it is.
do this after adjusting the frame. otherwise it gets all weird and
- clients don't work right */
- client_configure_full(self, self->area.x, self->area.y,
- self->area.width, self->area.height,
- FALSE, TRUE);
+ clients don't work right
- /* do this after the window is placed, so the premax/prefullscreen numbers
- won't be all wacko!!
- also, this moves the window to the position where it has been placed
+ also do this after applying the startup state so maximize and fullscreen
+ will get the right sizes and positions if the client is starting with
+ those states
*/
- client_apply_startup_state(self);
+ client_configure(self, placex, placey,
+ self->area.width, self->area.height,
+ self->border_width,
+ FALSE, TRUE);
+
if (activate) {
guint32 last_time = focus_client ?
"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) {
/* update the list hints */
client_set_list();
+ /* free the ObAppSettings shallow copy */
+ g_free(settings);
+
ob_debug("Managed window 0x%lx plate 0x%x (%s)\n",
window, self->frame->plate, self->class);
client_get_all(self, FALSE);
/* per-app settings override stuff, and return the settings for other
- uses too */
+ uses too. this returns a shallow copy that needs to be freed */
settings = client_get_settings_state(self);
client_setup_decor_and_functions(self);
/* create the decoration frame for the client window and adjust its size */
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);
+
return self;
}
/* ignore enter events from the unmap so it doesnt mess with the
focus */
- event_ignore_queued_enters();
+ event_ignore_all_queued_enters();
mouse_grab_for_client(self, FALSE);
{
Rect a;
- /* give the client its border back */
- client_toggle_border(self, TRUE);
-
a = self->area;
if (self->fullscreen)
}
self->fullscreen = self->max_horz = self->max_vert = FALSE;
+ /* let it be moved and resized no matter what */
+ self->functions = OB_CLIENT_FUNC_MOVE | OB_CLIENT_FUNC_RESIZE;
self->decorations = 0; /* unmanaged windows have no decor */
client_move_resize(self, a.x, a.y, a.width, a.height);
g_free(self);
}
+/*! Returns a new structure containing the per-app settings for this client.
+ The returned structure needs to be freed with g_free. */
static ObAppSettings *client_get_settings_state(ObClient *self)
{
- ObAppSettings *settings = NULL;
+ ObAppSettings *settings;
GSList *it;
+ settings = config_create_app_settings();
+
for (it = config_per_app_settings; it; it = g_slist_next(it)) {
ObAppSettings *app = it->data;
-
- if ((app->name && !app->class && !strcmp(app->name, self->name))
- || (app->class && !app->name && !strcmp(app->class, self->class))
- || (app->class && app->name && !strcmp(app->class, self->class)
- && !strcmp(app->name, self->name)))
- {
- /* Match if no role was specified in the per app setting, or if the
- * string matches the beginning of the role, since apps like to set
- * the role to things like browser-window-23c4b2f */
- if (!app->role
- || !strncmp(app->role, self->role, strlen(app->role)))
- {
- ob_debug("Window matching: %s\n", app->name);
- /* use this one */
- settings = app;
- break;
- }
- }
+ gboolean match = TRUE;
+
+ g_assert(app->name != NULL || app->class != NULL);
+
+ /* we know that either name or class is not NULL so it will have to
+ match to use the rule */
+ if (app->name &&
+ !g_pattern_match(app->name, strlen(self->name), self->name, NULL))
+ match = FALSE;
+ else if (app->class &&
+ !g_pattern_match(app->class,
+ strlen(self->class), self->class, NULL))
+ match = FALSE;
+ else if (app->role &&
+ !g_pattern_match(app->role,
+ strlen(self->role), self->role, NULL))
+ match = FALSE;
+
+ if (match) {
+ ob_debug("Window matching: %s\n", app->name);
+
+ /* copy the settings to our struct, overriding the existing
+ settings if they are not defaults */
+ config_app_settings_copy_non_defaults(app, settings);
+ }
+ }
+
+ if (settings->shade != -1)
+ self->shaded = !!settings->shade;
+ if (settings->decor != -1)
+ self->undecorated = !settings->decor;
+ if (settings->iconic != -1)
+ self->iconic = !!settings->iconic;
+ if (settings->skip_pager != -1)
+ self->skip_pager = !!settings->skip_pager;
+ if (settings->skip_taskbar != -1)
+ self->skip_taskbar = !!settings->skip_taskbar;
+
+ if (settings->max_vert != -1)
+ self->max_vert = !!settings->max_vert;
+ if (settings->max_horz != -1)
+ self->max_horz = !!settings->max_horz;
+
+ if (settings->fullscreen != -1)
+ self->fullscreen = !!settings->fullscreen;
+
+ if (settings->desktop) {
+ if (settings->desktop == DESKTOP_ALL)
+ self->desktop = settings->desktop;
+ else if (settings->desktop > 0 &&
+ settings->desktop <= screen_num_desktops)
+ self->desktop = settings->desktop - 1;
+ }
+
+ if (settings->layer == -1) {
+ self->below = TRUE;
+ self->above = FALSE;
}
-
- if (settings) {
- if (settings->shade != -1)
- self->shaded = !!settings->shade;
- if (settings->decor != -1)
- self->undecorated = !settings->decor;
- if (settings->iconic != -1)
- self->iconic = !!settings->iconic;
- if (settings->skip_pager != -1)
- self->skip_pager = !!settings->skip_pager;
- if (settings->skip_taskbar != -1)
- self->skip_taskbar = !!settings->skip_taskbar;
-
- if (settings->max_vert != -1)
- self->max_vert = !!settings->max_vert;
- if (settings->max_horz != -1)
- self->max_horz = !!settings->max_horz;
-
- if (settings->fullscreen != -1)
- self->fullscreen = !!settings->fullscreen;
-
- if (settings->desktop) {
- if (settings->desktop == DESKTOP_ALL)
- self->desktop = settings->desktop;
- else if (settings->desktop > 0 &&
- settings->desktop <= screen_num_desktops)
- self->desktop = settings->desktop - 1;
- }
-
- if (settings->layer == -1) {
- self->below = TRUE;
- self->above = FALSE;
- }
- else if (settings->layer == 0) {
- self->below = FALSE;
- self->above = FALSE;
- }
- else if (settings->layer == 1) {
- self->below = FALSE;
- self->above = TRUE;
- }
+ else if (settings->layer == 0) {
+ self->below = FALSE;
+ self->above = FALSE;
+ }
+ else if (settings->layer == 1) {
+ self->below = FALSE;
+ self->above = TRUE;
}
return settings;
}
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)
gint ox = *x, oy = *y;
gboolean rudel = rude, ruder = rude, rudet = rude, rudeb = rude;
gint fw, fh;
+ Rect desired;
+ RECT_SET(desired, *x, *y, w, h);
all_a = screen_area(self->desktop);
- mon_a = screen_area_monitor(self->desktop, client_monitor(self));
+ mon_a = screen_area_monitor(self->desktop, screen_find_monitor(&desired));
/* get where the frame would be */
frame_client_gravity(self->frame, x, y, w, h);
POINT_SET(newbl, newtl.x, newbr.y);
/* is it moving or just resizing from some corner? */
- stationary_l = oldtl.x == oldtl.x;
- stationary_r = oldtr.x == oldtr.x;
- stationary_t = oldtl.y == oldtl.y;
- stationary_b = oldbl.y == oldbl.y;
+ stationary_l = oldtl.x == newtl.x;
+ stationary_r = oldtr.x == newtr.x;
+ stationary_t = oldtl.y == newtl.y;
+ stationary_b = oldbl.y == newbl.y;
/* if left edge is growing and didnt move right edge */
if (stationary_r && newtl.x < oldtl.x)
* 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 (fw <= mon_a->width) {
- 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 + mon_a->width - fw;
- }
- if (fh <= mon_a->height) {
- 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 + mon_a->height - fh;
- }
+ 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);
+
+ 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);
/* get where the client should be */
frame_frame_gravity(self->frame, x, y, w, h);
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 */
POINT_SET(self->root_pos, wattrib.x, wattrib.y);
self->border_width = wattrib.border_width;
- ob_debug("client area: %d %d %d %d\n", wattrib.x, wattrib.y,
- wattrib.width, wattrib.height);
+ ob_debug("client area: %d %d %d %d bw %d\n", wattrib.x, wattrib.y,
+ wattrib.width, wattrib.height, wattrib.border_width);
}
static void client_get_desktop(ObClient *self)
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) {
void client_update_colormap(ObClient *self, Colormap colormap)
{
- self->colormap = colormap;
+ if (colormap == self->colormap) return;
+
+ ob_debug("Setting client %s colormap: 0x%x\n", self->title, colormap);
+
+ if (client_focused(self)) {
+ screen_install_colormap(self, FALSE); /* uninstall old one */
+ self->colormap = colormap;
+ screen_install_colormap(self, FALSE); /* install new one */
+ } else
+ self->colormap = colormap;
}
void client_update_normal_hints(ObClient *self)
{
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)
}
}
+/*! This needs to be followed by a call to client_configure to make
+ the changes show */
void client_setup_decor_and_functions(ObClient *self)
{
/* start with everything (cept fullscreen) */
OB_CLIENT_FUNC_SHADE |
OB_CLIENT_FUNC_CLOSE |
OB_CLIENT_FUNC_BELOW |
- OB_CLIENT_FUNC_ABOVE);
+ OB_CLIENT_FUNC_ABOVE |
+ OB_CLIENT_FUNC_UNDECORATE);
if (!(self->min_size.width < self->max_size.width ||
self->min_size.height < self->max_size.height))
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:
do with them is move them */
self->decorations = 0;
self->functions = OB_CLIENT_FUNC_MOVE;
+ break;
case OB_CLIENT_TYPE_DESKTOP:
/* these windows are not manipulated by the window manager */
self->decorations = 0;
self->functions = 0;
+ break;
case OB_CLIENT_TYPE_DOCK:
/* these windows are not manipulated by the window manager, but they
self->decorations &= ~OB_FRAME_DECOR_MAXIMIZE;
}
- /* kill the handle on fully maxed windows */
- if (self->max_vert && self->max_horz)
+ 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 */
+ if (self->decorations == 0)
+ self->functions &= ~OB_CLIENT_FUNC_UNDECORATE;
/* finally, the user can have requested no decorations, which overrides
everything (but doesnt give it a border if it doesnt have one) */
}
client_change_allowed_actions(self);
-
- if (self->frame) {
- /* adjust the client's decorations, etc. */
- client_reconfigure(self);
- }
}
static void client_change_allowed_actions(ObClient *self)
{
- gulong actions[11];
+ gulong actions[12];
gint num = 0;
/* desktop windows are kept on all desktops */
actions[num++] = prop_atoms.net_wm_action_above;
if (self->functions & OB_CLIENT_FUNC_BELOW)
actions[num++] = prop_atoms.net_wm_action_below;
+ if (self->functions & OB_CLIENT_FUNC_UNDECORATE)
+ actions[num++] = prop_atoms.ob_wm_action_undecorate;
PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num);
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)
}
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))))) &&
if (client_should_show(self)) {
frame_show(self->frame);
show = TRUE;
- }
- /* 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);
+ /* 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);
+ }
return show;
}
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);
hide = TRUE;
- }
- /* 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);
+ /* 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);
+ }
return hide;
}
{
if (!client_show(self))
client_hide(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_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,
/* 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, TRUE, TRUE, TRUE);
+ frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
/* work within the prefered sizes given by the window */
if (!(*w == self->area.width && *h == self->area.height)) {
*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_full(ObClient *self, gint x, gint y, gint w, gint h,
- gboolean user, gboolean final)
+void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
+ gboolean user, gboolean final)
{
gint oldw, oldh;
gboolean send_resize_client;
gboolean moved = FALSE, resized = FALSE;
+ gboolean fmoved, fresized;
guint fdecor = self->frame->decorations;
gboolean fhorz = self->frame->max_horz;
+ gboolean fvert = self->frame->max_vert;
gint logicalw, logicalh;
/* find the new x, y, width, and height (and logical size) */
/* 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);
}
/* find the frame's dimensions and move/resize it */
- if (self->decorations != fdecor || self->max_horz != fhorz)
- moved = resized = TRUE;
- if (moved || resized)
- frame_adjust_area(self->frame, moved, resized, FALSE);
+ fmoved = moved;
+ fresized = resized;
+
+ /* if decorations changed, then readjust everything for the frame */
+ if (self->decorations != fdecor ||
+ self->max_horz != fhorz || self->max_vert != fvert)
+ {
+ fmoved = fresized = TRUE;
+ }
+
+ /* adjust the frame */
+ if (fmoved || fresized)
+ frame_adjust_area(self->frame, fmoved, fresized, FALSE);
if ((!user || (user && final)) && !resized)
{
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.above = self->frame->plate;
+ event.xconfigure.border_width = self->border_width;
+ event.xconfigure.above = None;
event.xconfigure.override_redirect = FALSE;
XSendEvent(event.xconfigure.display, event.xconfigure.window,
FALSE, StructureNotifyMask, &event);
}
/* if the client is shrinking, then resize the frame before the client */
- if (send_resize_client && (w <= oldw || h <= oldh)) {
+ if (send_resize_client && (w <= oldw && h <= oldh)) {
/* 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;
}
guint old;
GSList *it;
- if (target != self->desktop) {
+ if (target != self->desktop && self->type != OB_CLIENT_TYPE_DESKTOP) {
ob_debug("Setting desktop %u\n", target+1);
}
}
- /* Grab pointer across these, so it is the same as actions. Enter events
- won't be generated by the windows moving around */
- grab_pointer(FALSE, FALSE, OB_CURSOR_NONE);
-
if (max_horz != self->max_horz || max_vert != self->max_vert) {
if (max_horz != self->max_horz && max_vert != self->max_vert) {
/* toggling both */
client_calc_layer(self);
}
- /* These things below can change focus so we can't grab pointer for them */
- ungrab_pointer();
-
if (modal != self->modal) {
self->modal = modal;
/* when a window changes modality, then its stacking order with its
transients needs to change */
stacking_raise(CLIENT_AS_WINDOW(self));
+
/* it also may get focused. if something is focused that shouldn't
be focused anymore, then move the focus */
if (focus_client && client_focus_target(focus_client) != focus_client)
client_focus(focus_client);
}
+
if (iconic != self->iconic)
client_iconify(self, iconic, FALSE, FALSE);
}
ob_debug_type(OB_DEBUG_FOCUS,
- "Focusing client \"%s\" at time %u\n",
- self->title, event_curtime);
+ "Focusing client \"%s\" (0x%x) at time %u\n",
+ self->title, self->window, event_curtime);
/* if there is a grab going on, then we need to cancel it. if we move
focus during the grab, applications will get NotifyWhileGrabbed events
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;
xerror_set_ignore(FALSE);
+ ob_debug_type(OB_DEBUG_FOCUS, "Error focusing? %d\n", xerror_occured);
return !xerror_occured;
}
self->window, event_curtime, last_time,
(user ? "user" : "application"), allow);
- if (allow) {
- if (event_curtime != CurrentTime)
- self->user_time = event_curtime;
-
+ if (allow)
client_present(self, here, TRUE);
- } else
+ else
/* don't focus it but tell the user it wants attention */
client_hilite(self, TRUE);
}
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;
void client_set_undecorated(ObClient *self, gboolean undecorated)
{
- if (self->undecorated != undecorated) {
+ if (self->undecorated != undecorated &&
+ /* don't let it undecorate if the function is missing, but let
+ it redecorate */
+ (self->functions & OB_CLIENT_FUNC_UNDECORATE || !undecorated))
+ {
self->undecorated = undecorated;
client_setup_decor_and_functions(self);
- /* Make sure the client knows it might have moved. Maybe there is a
- * better way of doing this so only one client_configure is sent, but
- * since 125 of these are sent per second when moving the window (with
- * user = FALSE) i doubt it matters much.
- */
- client_configure(self, self->area.x, self->area.y,
- self->area.width, self->area.height, TRUE, TRUE);
+ client_reconfigure(self); /* show the lack of decorations */
client_change_state(self); /* reflect this in the state hints */
}
}