Time launch_time;
guint32 user_time;
gboolean obplaced;
- gulong ignore_start;
+ gulong ignore_start = FALSE;
ob_debug("Managing window: 0x%lx", window);
ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
ob_debug("Window name: %s class: %s role: %s title: %s",
self->name, self->class, self->role, self->title);
+ ob_debug("Window group name: %s group class: %s",
+ self->group_name, self->group_class);
/* per-app settings override stuff from client_get_all, and return the
settings for other uses too. the returned settings is a shallow copy,
"program + user specified" :
"BADNESS !?")))), place.width, place.height);
- obplaced = place_client(self, do_activate, &place.x, &place.y,
- settings);
+ obplaced = place_client(self, do_activate, &place, settings);
/* watch for buggy apps that ask to be placed at (0,0) when there is
a strut there */
g_free(self->name);
g_free(self->class);
g_free(self->role);
+ g_free(self->group_name);
+ g_free(self->group_class);
g_free(self->client_machine);
g_free(self->sm_client_id);
g_slice_free(ObClient, self);
g_assert(app->name != NULL || app->class != NULL ||
app->role != NULL || app->title != NULL ||
+ app->group_name != NULL || app->group_class != NULL ||
(signed)app->type >= 0);
if (app->name &&
!g_pattern_match(app->name, strlen(self->name), self->name, NULL))
match = FALSE;
+ else if (app->group_name &&
+ !g_pattern_match(app->group_name,
+ strlen(self->group_name), self->group_name, NULL))
+ match = FALSE;
else if (app->class &&
!g_pattern_match(app->class,
strlen(self->class), self->class, NULL))
match = FALSE;
+ else if (app->group_class &&
+ !g_pattern_match(app->group_class,
+ strlen(self->group_class), self->group_class,
+ NULL))
+ match = FALSE;
else if (app->role &&
!g_pattern_match(app->role,
strlen(self->role), self->role, NULL))
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 - fh*9/10;
+ if (!self->strut.right && *x + fw/100 >= a->x + a->width - 1)
+ *x = a->x + a->width - fw/100;
+ if (!self->strut.bottom && *y + fh/100 >= a->y + a->height - 1)
+ *y = a->y + a->height - fh/100;
+ if (!self->strut.left && *x + fw*99/100 - 1 < a->x)
+ *x = a->x - fw*99/100;
+ if (!self->strut.top && *y + fh*99/100 - 1 < a->y)
+ *y = a->y - fh*99/100;
}
/* This here doesn't let windows even a pixel outside the
from per-app settings */
client_get_session_ids(self);
- /* now we got everything that can affect the decorations */
+ /* get this early so we have it for debugging, also this can be used
+ by app rule matching */
+ client_update_title(self);
+
+ /* now we got everything that can affect the decorations or app rule
+ matching */
if (!real)
return;
- /* get this early so we have it for debugging */
- client_update_title(self);
-
/* save the values of the variables used for app rule matching */
client_save_app_rule_values(self);
self->demands_attention = TRUE;
else if (state[i] == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED))
self->undecorated = TRUE;
+ else if (state[i] == OBT_PROP_ATOM(OB_WM_STATE_LOCKED))
+ self->locked = TRUE;
}
g_free(state);
gchar *data = NULL;
gchar *visible = NULL;
- g_free(self->title);
g_free(self->original_title);
/* try netwm */
g_free(data);
}
- OBT_PROP_SETS(self->window, NET_WM_VISIBLE_NAME, visible);
- self->title = visible;
+ if (!self->title || strcmp(self->title, visible)) {
+ OBT_PROP_SETS(self->window, NET_WM_VISIBLE_NAME, visible);
+ g_free(self->title);
+ self->title = visible;
+ } else
+ g_free(visible);
if (self->frame)
frame_adjust_title(self->frame);
/* update the icon title */
data = NULL;
- g_free(self->icon_title);
/* try netwm */
if (!OBT_PROP_GETS_UTF8(self->window, NET_WM_ICON_NAME, &data))
g_free(data);
}
- OBT_PROP_SETS(self->window, NET_WM_VISIBLE_ICON_NAME, visible);
- self->icon_title = visible;
+ if (!self->icon_title || strcmp(self->icon_title, visible)) {
+ OBT_PROP_SETS(self->window, NET_WM_VISIBLE_ICON_NAME, visible);
+ g_free(self->icon_title);
+ self->icon_title = visible;
+ } else
+ g_free(visible);
}
void client_update_strut(ObClient *self)
if (!self->icon_set && !self->parents) {
RrPixel32 *icon = ob_rr_theme->def_win_icon;
gulong *ldata; /* use a long here to satisfy OBT_PROP_SETA32 */
+ gint32 r,g,b;
+ r = g_random_int_range(0,255);
+ g = g_random_int_range(0,255);
+ b = g_random_int_range(0,255);
w = ob_rr_theme->def_win_icon_w;
h = ob_rr_theme->def_win_icon_h;
ldata[1] = h;
for (i = 0; i < w*h; ++i)
ldata[i+2] = (((icon[i] >> RrDefaultAlphaOffset) & 0xff) << 24) +
- (((icon[i] >> RrDefaultRedOffset) & 0xff) << 16) +
- (((icon[i] >> RrDefaultGreenOffset) & 0xff) << 8) +
- (((icon[i] >> RrDefaultBlueOffset) & 0xff) << 0);
+ ((((icon[i] >> RrDefaultRedOffset) & 0xff)*r/255) << 16) +
+ ((((icon[i] >> RrDefaultGreenOffset) & 0xff)*g/255) << 8) +
+ ((((icon[i] >> RrDefaultBlueOffset) & 0xff)*b/255) << 0);
OBT_PROP_SETA32(self->window, NET_WM_ICON, CARDINAL, ldata, w*h+2);
g_free(ldata);
} else if (self->frame)
if (self->name == NULL) self->name = g_strdup("");
if (self->class == NULL) self->class = g_strdup("");
+ /* get the WM_CLASS (name and class) from the group leader. make them "" if
+ they are not provided */
+ if (leader)
+ got = OBT_PROP_GETSS_TYPE(leader, WM_CLASS, STRING_NO_CC, &ss);
+ else
+ got = FALSE;
+
+ if (got) {
+ if (ss[0]) {
+ self->group_name = g_strdup(ss[0]);
+ if (ss[1])
+ self->group_class = g_strdup(ss[1]);
+ }
+ g_strfreev(ss);
+ }
+
+ if (self->group_name == NULL) self->group_name = g_strdup("");
+ if (self->group_class == NULL) self->group_class = g_strdup("");
+
/* get the WM_WINDOW_ROLE. make it "" if it is not provided */
got = OBT_PROP_GETS_XPCS(self->window, WM_WINDOW_ROLE, &s);
}
}
-/*! Save the properties used for app matching rules, as seen by Openbox when
- the window mapped, so that users can still access them later if the app
- changes them */
-static void client_save_app_rule_values(ObClient *self)
+const gchar *client_type_to_string(ObClient *self)
{
const gchar *type;
- OBT_PROP_SETS(self->window, OB_APP_ROLE, self->role);
- OBT_PROP_SETS(self->window, OB_APP_NAME, self->name);
- OBT_PROP_SETS(self->window, OB_APP_CLASS, self->class);
- OBT_PROP_SETS(self->window, OB_APP_TITLE, self->original_title);
-
switch (self->type) {
case OB_CLIENT_TYPE_NORMAL:
type = "normal"; break;
case OB_CLIENT_TYPE_DOCK:
type = "dock"; break;
}
- OBT_PROP_SETS(self->window, OB_APP_TYPE, type);
+
+ return type;
+}
+
+/*! Save the properties used for app matching rules, as seen by Openbox when
+ the window mapped, so that users can still access them later if the app
+ changes them */
+static void client_save_app_rule_values(ObClient *self)
+{
+ OBT_PROP_SETS(self->window, OB_APP_ROLE, self->role);
+ OBT_PROP_SETS(self->window, OB_APP_NAME, self->name);
+ OBT_PROP_SETS(self->window, OB_APP_CLASS, self->class);
+ OBT_PROP_SETS(self->window, OB_APP_GROUP_NAME, self->group_name);
+ OBT_PROP_SETS(self->window, OB_APP_GROUP_CLASS, self->group_class);
+ OBT_PROP_SETS(self->window, OB_APP_TITLE, self->original_title);
+
+ OBT_PROP_SETS(self->window, OB_APP_TYPE, client_type_to_string(self));
}
static void client_change_wm_state(ObClient *self)
static void client_change_state(ObClient *self)
{
- gulong netstate[12];
+ gulong netstate[13];
guint num;
num = 0;
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION);
if (self->undecorated)
netstate[num++] = OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED);
+ if (self->locked)
+ netstate[num++] = OBT_PROP_ATOM(OB_WM_STATE_LOCKED);
OBT_PROP_SETA32(self->window, NET_WM_STATE, ATOM, netstate, num);
if (self->frame)
{
if (self->iconic)
return FALSE;
- if (client_normal(self) && screen_showing_desktop)
+ if (client_normal(self) && screen_showing_desktop())
return FALSE;
if (self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
return TRUE;
self->type == OB_CLIENT_TYPE_TOOLBAR);
}
+gboolean client_occupies_space(ObClient *self)
+{
+ return !(self->type == OB_CLIENT_TYPE_DESKTOP ||
+ self->type == OB_CLIENT_TYPE_SPLASH);
+}
+
gboolean client_mouse_focusable(ObClient *self)
{
- return !(self->type == OB_CLIENT_TYPE_MENU ||
+ return !(/*self->type == OB_CLIENT_TYPE_MENU ||*/
self->type == OB_CLIENT_TYPE_TOOLBAR ||
self->type == OB_CLIENT_TYPE_SPLASH ||
self->type == OB_CLIENT_TYPE_DOCK);
maxratio = self->fullscreen || (self->max_horz && self->max_vert) ?
0 : self->max_ratio;
+ /* XXX TODO FIXME these two fallbacks don't check that the fallback
+ * value itself is specified before using it */
/* base size is substituted with min size if not specified */
if (self->base_size.width >= 0 || self->base_size.height >= 0) {
basew = self->base_size.width;
gboolean shaded = self->shaded;
gboolean fullscreen = self->fullscreen;
gboolean undecorated = self->undecorated;
+ gboolean locked = self->locked;
gboolean max_horz = self->max_horz;
gboolean max_vert = self->max_vert;
gboolean modal = self->modal;
value = self->demands_attention;
else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED))
value = undecorated;
+ else if (state == OBT_PROP_ATOM(OB_WM_STATE_LOCKED))
+ value = locked;
else
g_assert_not_reached();
action = value ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) :
demands_attention = value;
} else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED)) {
undecorated = value;
+ } else if (state == OBT_PROP_ATOM(OB_WM_STATE_LOCKED)) {
+ locked = value;
}
}
client_shade(self, shaded);
if (undecorated != self->undecorated)
client_set_undecorated(self, undecorated);
+ if (locked != self->locked)
+ client_set_locked(self, locked);
if (above != self->above || below != self->below) {
self->above = above;
self->below = below;
{
if (!client_validate(self)) return FALSE;
+ {
+ XkbStateRec state;
+ XkbGetState(obt_display, XkbUseCoreKbd, &state);
+ if (state.locked_mods & 128)
+ return FALSE;
+ }
+
/* we might not focus this window, so if we have modal children which would
be focused instead, bring them to this desktop */
client_bring_modal_windows(self);
static void client_present(ObClient *self, gboolean here, gboolean raise,
gboolean unshade)
{
- if (client_normal(self) && screen_showing_desktop)
+ if (client_normal(self) && screen_showing_desktop())
screen_show_desktop(FALSE, self);
if (self->iconic)
client_iconify(self, FALSE, here, FALSE);
client_change_state(self); /* reflect this in the state hints */
}
+void client_set_locked(ObClient *self, gboolean locked)
+{
+ if (self->locked != locked) {
+ self->locked = locked;
+ client_change_state(self);
+ }
+}
+
void client_set_undecorated(ObClient *self, gboolean undecorated)
{
if (self->undecorated != undecorated &&
frame_frame_gravity(self->frame, x, y);
}
-void client_find_resize_directional(ObClient *self, ObDirection side,
- gboolean grow,
+void client_find_resize_directional(ObClient *self,
+ ObDirection side,
+ ObClientDirectionalResizeType resize_type,
gint *x, gint *y, gint *w, gint *h)
{
gint head;
gboolean near;
ObDirection dir;
+ gboolean grow;
+ switch (resize_type) {
+ case CLIENT_RESIZE_GROW:
+ grow = TRUE;
+ break;
+ case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE:
+ grow = TRUE;
+ break;
+ case CLIENT_RESIZE_SHRINK:
+ grow = FALSE;
+ break;
+ }
+
switch (side) {
case OB_DIRECTION_EAST:
- head = RECT_RIGHT(self->frame->area) +
- (self->size_inc.width - 1) * (grow ? 1 : 0);
+ head = RECT_RIGHT(self->frame->area);
+ switch (resize_type) {
+ case CLIENT_RESIZE_GROW:
+ head += self->size_inc.width - 1;
+ break;
+ case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE:
+ head -= 1;
+ break;
+ case CLIENT_RESIZE_SHRINK:
+ break;
+ }
+
e_start = RECT_TOP(self->frame->area);
e_size = self->frame->area.height;
dir = grow ? OB_DIRECTION_EAST : OB_DIRECTION_WEST;
break;
case OB_DIRECTION_WEST:
- head = RECT_LEFT(self->frame->area) -
- (self->size_inc.width - 1) * (grow ? 1 : 0);
+ head = RECT_LEFT(self->frame->area);
+ switch (resize_type) {
+ case CLIENT_RESIZE_GROW:
+ head -= self->size_inc.width - 1;
+ break;
+ case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE:
+ head += 1;
+ break;
+ case CLIENT_RESIZE_SHRINK:
+ break;
+ }
+
e_start = RECT_TOP(self->frame->area);
e_size = self->frame->area.height;
dir = grow ? OB_DIRECTION_WEST : OB_DIRECTION_EAST;
break;
case OB_DIRECTION_NORTH:
- head = RECT_TOP(self->frame->area) -
- (self->size_inc.height - 1) * (grow ? 1 : 0);
+ head = RECT_TOP(self->frame->area);
+ switch (resize_type) {
+ case CLIENT_RESIZE_GROW:
+ head -= self->size_inc.height - 1;
+ break;
+ case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE:
+ head += 1;
+ break;
+ case CLIENT_RESIZE_SHRINK:
+ break;
+ }
+
e_start = RECT_LEFT(self->frame->area);
e_size = self->frame->area.width;
dir = grow ? OB_DIRECTION_NORTH : OB_DIRECTION_SOUTH;
break;
case OB_DIRECTION_SOUTH:
- head = RECT_BOTTOM(self->frame->area) +
- (self->size_inc.height - 1) * (grow ? 1 : 0);
+ head = RECT_BOTTOM(self->frame->area);
+ switch (resize_type) {
+ case CLIENT_RESIZE_GROW:
+ head += self->size_inc.height - 1;
+ break;
+ case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE:
+ head -= 1;
+ break;
+ case CLIENT_RESIZE_SHRINK:
+ break;
+ }
+
e_start = RECT_LEFT(self->frame->area);
e_size = self->frame->area.width;
dir = grow ? OB_DIRECTION_SOUTH : OB_DIRECTION_NORTH;
if (grow == near) --e;
delta = e - RECT_BOTTOM(self->frame->area);
*h += delta;
- break;
+ break;
default:
g_assert_not_reached();
}