#define CLIENT_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \
ButtonMotionMask)
+typedef struct
+{
+ ObClientDestructor func;
+ gpointer data;
+} Destructor;
+
GList *client_list = NULL;
GSList *client_destructors = NULL;
{
}
-void client_add_destructor(GDestroyNotify func)
+void client_add_destructor(ObClientDestructor func, gpointer data)
{
- client_destructors = g_slist_prepend(client_destructors, (gpointer)func);
+ Destructor *d = g_new(Destructor, 1);
+ d->func = func;
+ d->data = data;
+ client_destructors = g_slist_prepend(client_destructors, d);
}
-void client_remove_destructor(GDestroyNotify func)
+void client_remove_destructor(ObClientDestructor func)
{
- client_destructors = g_slist_remove(client_destructors, (gpointer)func);
+ GSList *it;
+
+ for (it = client_destructors; it; it = g_slist_next(it)) {
+ Destructor *d = it->data;
+ if (d->func == func) {
+ g_free(d);
+ client_destructors = g_slist_delete_link(client_destructors, it);
+ break;
+ }
+ }
}
void client_set_list()
influence */
screen_update_areas();
+ for (it = client_destructors; it; it = g_slist_next(it)) {
+ 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;
((ObClient*)it->data)->transients =
g_slist_remove(((ObClient*)it->data)->transients, self);
} else if (self->transient_for) { /* transient of window */
- self->transient_for->transients =
- g_slist_remove(self->transient_for->transients, self);
+ self->transient_for->transients =
+ g_slist_remove(self->transient_for->transients, self);
}
/* tell our transients that we're gone */
}
}
- for (it = client_destructors; it; it = g_slist_next(it)) {
- GDestroyNotify func = (GDestroyNotify) it->data;
- func(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));
- client_unfocus(self);
- }
-
/* remove from its group */
if (self->group) {
group_remove(self->group, self);
/* free all data allocated in the client struct */
g_slist_free(self->transients);
for (j = 0; j < self->nicons; ++j)
- g_free(self->icons[j].data);
+ g_free(self->icons[j].data);
if (self->nicons > 0)
- g_free(self->icons);
+ g_free(self->icons);
g_free(self->title);
g_free(self->icon_title);
g_free(self->name);
ObClient *target = NULL;
if (XGetTransientForHint(ob_display, self->window, &t)) {
- self->transient = TRUE;
+ self->transient = TRUE;
if (t != self->window) { /* cant be transient to itself! */
target = g_hash_table_lookup(window_map, &t);
/* if this happens then we need to check for it*/
group */
if (t == self->group->leader ||
t == None ||
- t == RootWindow(ob_display, ob_screen)) {
+ t == RootWindow(ob_display, ob_screen))
+ {
/* window is a transient for its group! */
target = OB_TRAN_GROUP;
}
}
}
} else
- self->transient = FALSE;
+ self->transient = FALSE;
/* if anything has changed... */
if (target != self->transient_for) {
for (it = self->group->members; it; it = it->next)
self->transients = g_slist_remove(self->transients,
it->data);
+
+ /* remove myself from parents in the group */
+ if (self->transient_for == OB_TRAN_GROUP) {
+ for (it = self->group->members; it; it = it->next) {
+ ObClient *c = it->data;
+
+ if (c != self && !c->transient_for)
+ c->transients = g_slist_remove(c->transients,
+ self);
+ }
+ }
+
group_remove(self->group, self);
self->group = NULL;
}
guint w, h, i, j;
for (i = 0; i < self->nicons; ++i)
- g_free(self->icons[i].data);
+ g_free(self->icons[i].data);
if (self->nicons > 0)
- g_free(self->icons);
+ g_free(self->icons);
self->nicons = 0;
if (PROP_GETA32(self->window, net_wm_icon, cardinal, &data, &num)) {
- /* figure out how many valid icons are in here */
- i = 0;
- while (num - i > 2) {
- w = data[i++];
- h = data[i++];
- i += w * h;
- if (i > num || w*h == 0) break;
- ++self->nicons;
- }
+ /* figure out how many valid icons are in here */
+ i = 0;
+ while (num - i > 2) {
+ w = data[i++];
+ h = data[i++];
+ i += w * h;
+ if (i > num || w*h == 0) break;
+ ++self->nicons;
+ }
- self->icons = g_new(ObClientIcon, self->nicons);
+ self->icons = g_new(ObClientIcon, self->nicons);
- /* store the icons */
- i = 0;
- for (j = 0; j < self->nicons; ++j) {
+ /* store the icons */
+ i = 0;
+ for (j = 0; j < self->nicons; ++j) {
guint x, y, t;
- w = self->icons[j].width = data[i++];
- h = self->icons[j].height = data[i++];
+ w = self->icons[j].width = data[i++];
+ h = self->icons[j].height = data[i++];
if (w*h == 0) continue;
- self->icons[j].data = g_new(RrPixel32, w * h);
+ self->icons[j].data = g_new(RrPixel32, w * h);
for (x = 0, y = 0, t = 0; t < w * h; ++t, ++x, ++i) {
if (x >= w) {
x = 0;
(((data[i] >> 8) & 0xff) << RrDefaultGreenOffset) +
(((data[i] >> 0) & 0xff) << RrDefaultBlueOffset);
}
- g_assert(i <= num);
- }
+ g_assert(i <= num);
+ }
- g_free(data);
+ g_free(data);
} else if (PROP_GETA32(self->window, kwm_win_icon,
kwm_win_icon, &data, &num)) {
if (num == 2) {
}
}
- if (!self->nicons) {
- self->nicons++;
- self->icons = g_new(ObClientIcon, self->nicons);
- self->icons[self->nicons-1].width = 48;
- self->icons[self->nicons-1].height = 48;
- self->icons[self->nicons-1].data = g_memdup(ob_rr_theme->def_win_icon,
- sizeof(RrPixel32)
- * 48 * 48);
- }
-
if (self->frame)
- frame_adjust_icon(self->frame);
+ frame_adjust_icon(self->frame);
}
static void client_change_state(ObClient *self)
h -= self->base_size.height;
if (self->min_ratio)
- if (h * self->min_ratio > w) h = (int)(w / self->min_ratio);
+ if (h * self->min_ratio > w) {
+ h = (int)(w / self->min_ratio);
+
+ /* you cannot resize to nothing */
+ if (h < 1) {
+ h = 1;
+ w = (int)(h * self->min_ratio);
+ }
+ }
if (self->max_ratio)
- if (h * self->max_ratio < w) h = (int)(w / self->max_ratio);
+ if (h * self->max_ratio < w) {
+ h = (int)(w / self->max_ratio);
+
+ /* you cannot resize to nothing */
+ if (h < 1) {
+ h = 1;
+ w = (int)(h * self->min_ratio);
+ }
+ }
w += self->base_size.width;
h += self->base_size.height;
}
+ g_assert(w > 0);
+ g_assert(h > 0);
+
switch (anchor) {
case OB_CORNER_TOPLEFT:
- break;
+ break;
case OB_CORNER_TOPRIGHT:
- x -= w - self->area.width;
- break;
+ x -= w - self->area.width;
+ break;
case OB_CORNER_BOTTOMLEFT:
- y -= h - self->area.height;
- break;
+ y -= h - self->area.height;
+ break;
case OB_CORNER_BOTTOMRIGHT:
- x -= w - self->area.width;
- y -= h - self->area.height;
- break;
+ x -= w - self->area.width;
+ y -= h - self->area.height;
+ break;
}
moved = x != self->area.x || y != self->area.y;
client_showhide(self);
/* raise if it was not already on the desktop */
if (old != DESKTOP_ALL)
- stacking_raise(CLIENT_AS_WINDOW(self));
+ client_raise(self);
screen_update_areas();
/* add to the new desktop(s) */
ObClient *child;
/* if we have a modal child, then focus it, not us */
- child = client_search_modal_child(self);
+ child = client_search_modal_child(client_search_top_transient(self));
if (child) return child;
return self;
}
(self->desktop == screen_desktop ||
self->desktop == DESKTOP_ALL) &&
!self->iconic))
- return FALSE;
+ return FALSE;
/* do a check to see if the window has already been unmapped or destroyed
do this intelligently while watching out for unmaps we've generated
(ignore_unmaps > 0) */
if (XCheckTypedWindowEvent(ob_display, self->window,
- DestroyNotify, &ev)) {
- XPutBackEvent(ob_display, &ev);
- return FALSE;
+ DestroyNotify, &ev)) {
+ XPutBackEvent(ob_display, &ev);
+ return FALSE;
}
while (XCheckTypedWindowEvent(ob_display, self->window,
- UnmapNotify, &ev)) {
- if (self->ignore_unmaps) {
- self->ignore_unmaps--;
- } else {
- XPutBackEvent(ob_display, &ev);
- return FALSE;
- }
+ UnmapNotify, &ev)) {
+ if (self->ignore_unmaps) {
+ self->ignore_unmaps--;
+ } else {
+ XPutBackEvent(ob_display, &ev);
+ return FALSE;
+ }
}
return TRUE;
if (client_normal(self) && screen_showing_desktop)
screen_show_desktop(FALSE);
if (self->iconic)
- client_iconify(self, FALSE, FALSE);
+ client_iconify(self, FALSE, here);
if (self->desktop != DESKTOP_ALL &&
self->desktop != screen_desktop) {
if (here)
return;
if (self->shaded)
client_shade(self, FALSE);
- action_run_string("Focus", self);
+
+ client_focus(self);
+
+ /* we do this an action here. this is rather important. this is because
+ we want the results from the focus change to take place BEFORE we go
+ about raising the window. when a fullscreen window loses focus, we need
+ this or else the raise wont be able to raise above the to-lose-focus
+ fullscreen window. */
+ client_raise(self);
+}
+
+void client_raise(ObClient *self)
+{
+ action_run_string("Raise", self);
+}
+
+void client_lower(ObClient *self)
+{
action_run_string("Raise", self);
}
return self == focus_client;
}
-ObClientIcon *client_icon(ObClient *self, int w, int h)
+static ObClientIcon* client_icon_recursive(ObClient *self, int w, int h)
{
guint i;
/* si is the smallest image >= req */
/* li is the largest image < req */
unsigned long size, smallest = 0xffffffff, largest = 0, si = 0, li = 0;
+ if (!self->nicons) {
+ ObClientIcon *parent = NULL;
+
+ if (self->transient_for) {
+ if (self->transient_for != OB_TRAN_GROUP)
+ parent = client_icon_recursive(self->transient_for, w, h);
+ else {
+ GSList *it;
+ for (it = self->group->members; it; it = g_slist_next(it)) {
+ ObClient *c = it->data;
+ if (c != self && !c->transient_for) {
+ if ((parent = client_icon_recursive(c, w, h)))
+ break;
+ }
+ }
+ }
+ }
+
+ return parent;
+ }
+
for (i = 0; i < self->nicons; ++i) {
size = self->icons[i].width * self->icons[i].height;
if (size < smallest && size >= (unsigned)(w * h)) {
return &self->icons[li];
}
+const ObClientIcon* client_icon(ObClient *self, int w, int h)
+{
+ ObClientIcon *ret;
+ static ObClientIcon deficon;
+
+ if (!(ret = client_icon_recursive(self, w, h))) {
+ deficon.width = deficon.height = 48;
+ deficon.data = ob_rr_theme->def_win_icon;
+ ret = &deficon;
+ }
+ return ret;
+}
+
/* this be mostly ripped from fvwm */
ObClient *client_find_directional(ObClient *c, ObDirection dir)
{
} else {
GSList *it;
+ g_assert(self->group);
+
for (it = self->group->members; it; it = it->next) {
ObClient *c = it->data;
for (it = stacking_list; it != NULL; it = it->next) {
if (WINDOW_IS_CLIENT(it->data)) {
ObClient *c = WINDOW_AS_CLIENT(it->data);
- if (c->desktop == screen_desktop &&
+ if (c->frame->visible &&
RECT_CONTAINS(c->frame->area, x, y)) {
ret = c;
break;