X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=a9a9eb5fa1c88e9370ecca098fce4f372b22f10a;hb=795d90c3bc57eaf2c98c447f3af5c1c9e7a52fa3;hp=77bf98fd0f126a4ebd5cdbb740c4a660cac96bc3;hpb=f17b225daadb483b8736dc0e57a9def68e770ae9;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 77bf98fd..a9a9eb5f 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -1,5 +1,6 @@ #include "client.h" #include "dock.h" +#include "xerror.h" #include "startup.h" #include "screen.h" #include "moveresize.h" @@ -14,6 +15,8 @@ #include "openbox.h" #include "group.h" #include "config.h" +#include "menu.h" +#include "render/render.h" #include #include @@ -94,7 +97,7 @@ void client_foreach_ancestor(Client *self, ClientForeachFunc func, void *data) for (it = self->group->members; it; it = it->next) if (it->data != self && - ((Client*)it->data)->transient_for != TRAN_GROUP) { + !((Client*)it->data)->transient_for) { if (!func(it->data, data)) return; client_foreach_ancestor(it->data, func, data); } @@ -251,26 +254,26 @@ void client_manage(Window window) focus_order_add_new(self); /* focus the new window? */ - if (ob_state != State_Starting && config_focus_new) { + if (ob_state != State_Starting && config_focus_new && + (self->type == Type_Normal || self->type == Type_Dialog)) { gboolean group_foc = FALSE; if (self->group) { GSList *it; - for (it = self->group->members; it; it = it->next) + for (it = self->group->members; it; it = it->next) { if (client_focused(it->data)) { group_foc = TRUE; break; } + } } /* note the check against Type_Normal/Dialog, not client_normal(self), which would also include other types. in this case we want more strict rules for focus */ - if (((self->type == Type_Normal || - (self->type == Type_Dialog && - (group_foc || - (!self->transient_for && (!self->group || - !self->group->members->next)))))) || + if ((group_foc || + (!self->transient_for && (!self->group || + !self->group->members->next))) || client_search_focus_tree_full(self) || !focus_client || !client_normal(focus_client)) { @@ -301,7 +304,7 @@ void client_manage(Window window) dispatch_client(Event_Client_Mapped, self, 0, 0); - g_message("Managed window 0x%lx (%s)", window, self->name); + g_message("Managed window 0x%lx (%s)", window, self->class); } void client_unmanage_all() @@ -310,12 +313,19 @@ void client_unmanage_all() client_unmanage(client_list->data); } +/* called by client_unmanage() to close any menus referencing this client */ +void client_close_menus(gpointer key, gpointer value, gpointer self) +{ + if (((Menu *)value)->client == (Client *)self) + menu_hide((Menu *)value); +} + void client_unmanage(Client *self) { int j; GSList *it; - g_message("Unmanaging window: %lx (%s)", self->window, self->name); + g_message("Unmanaging window: %lx (%s)", self->window, self->class); dispatch_client(Event_Client_Destroy, self, 0, 0); g_assert(self != NULL); @@ -363,6 +373,10 @@ void client_unmanage(Client *self) if (moveresize_client == self) moveresize_end(TRUE); + /* close any windows that are attached to this window */ + g_hash_table_foreach(menu_hash, client_close_menus, self); + + if (focus_client == self) { XEvent e; @@ -555,7 +569,6 @@ static void client_get_all(Client *self) client_update_class(self); client_update_strut(self); client_update_icons(self); - client_update_kwm_icon(self); client_change_state(self); } @@ -592,7 +605,7 @@ static void client_get_desktop(Client *self) for (it = self->group->members; it; it = it->next) if (it->data != self && - ((Client*)it->data)->transient_for != TRAN_GROUP) { + !((Client*)it->data)->transient_for) { self->desktop = ((Client*)it->data)->desktop; trdesk = TRUE; break; @@ -700,7 +713,7 @@ void client_update_transient_for(Client *self) /* remove from old parents */ for (it = self->group->members; it; it = it->next) if (it->data != self && - (((Client*)it->data)->transient_for != TRAN_GROUP)) + !((Client*)it->data)->transient_for) ((Client*)it->data)->transients = g_slist_remove(((Client*)it->data)->transients, self); } else if (self->transient_for != NULL) { /* transient of window */ @@ -715,7 +728,7 @@ void client_update_transient_for(Client *self) /* add to new parents */ for (it = self->group->members; it; it = it->next) if (it->data != self && - (((Client*)it->data)->transient_for != TRAN_GROUP)) + !((Client*)it->data)->transient_for) ((Client*)it->data)->transients = g_slist_append(((Client*)it->data)->transients, self); @@ -1123,26 +1136,30 @@ void client_update_wmhints(Client *self) if (self->group != NULL) { /* remove transients of the group */ for (it = self->group->members; it; it = it->next) - if (it->data != self && - ((Client*)it->data)->transient_for == TRAN_GROUP) { - self->transients = g_slist_remove(self->transients, - it->data); - } + self->transients = g_slist_remove(self->transients, + it->data); group_remove(self->group, self); self->group = NULL; } if (hints->window_group != None) { self->group = group_add(hints->window_group, self); - /* add other transients of the group that are already - set up */ - for (it = self->group->members; it; it = it->next) - if (it->data != self && - ((Client*)it->data)->transient_for == TRAN_GROUP) - self->transients = g_slist_append(self->transients, - it->data); + /* i can only have transients from the group if i am not + transient myself */ + if (!self->transient_for) { + /* add other transients of the group that are already + set up */ + for (it = self->group->members; it; it = it->next) + if (it->data != self && + ((Client*)it->data)->transient_for == TRAN_GROUP) + self->transients = g_slist_append(self->transients, + it->data); + } } + /* the WM_HINTS can contain an icon */ + client_update_icons(self); + /* because the self->transient flag wont change from this call, we don't need to update the window's type and such, only its transient_for, and the transients lists of other windows in @@ -1150,23 +1167,6 @@ void client_update_wmhints(Client *self) client_update_transient_for(self); } - client_update_kwm_icon(self); - /* try get the kwm icon first, this is a fallback only */ - if (self->pixmap_icon == None) { - if (hints->flags & IconPixmapHint) { - if (self->pixmap_icon == None) { - self->pixmap_icon = hints->icon_pixmap; - if (hints->flags & IconMaskHint) - self->pixmap_icon_mask = hints->icon_mask; - else - self->pixmap_icon_mask = None; - - if (self->frame) - frame_adjust_icon(self->frame); - } - } - } - XFree(hints); } @@ -1326,7 +1326,7 @@ void client_update_icons(Client *self) w = data[i++]; h = data[i++]; i += w * h; - if (i > num) break; + if (i > num || w*h == 0) break; ++self->nicons; } @@ -1335,36 +1335,68 @@ void client_update_icons(Client *self) /* 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++]; - self->icons[j].data = - g_memdup(&data[i], w * h * sizeof(gulong)); - i += w * h; + + if (w*h == 0) continue; + + self->icons[j].data = g_new(pixel32, w * h); + for (x = 0, y = 0, t = 0; t < w * h; ++t, ++x, ++i) { + if (x >= w) { + x = 0; + ++y; + } + self->icons[j].data[t] = + (((data[i] >> 24) & 0xff) << default_alpha_offset) + + (((data[i] >> 16) & 0xff) << default_red_offset) + + (((data[i] >> 8) & 0xff) << default_green_offset) + + (((data[i] >> 0) & 0xff) << default_blue_offset); + } g_assert(i <= num); } g_free(data); - } - - if (self->frame) - frame_adjust_icon(self->frame); -} - -void client_update_kwm_icon(Client *self) -{ - guint num; - guint32 *data; - - if (!PROP_GETA32(self->window, kwm_win_icon, kwm_win_icon, &data, &num)) { - self->pixmap_icon = self->pixmap_icon_mask = None; - } else { + } else if (PROP_GETA32(self->window, kwm_win_icon, + kwm_win_icon, &data, &num)) { if (num == 2) { - self->pixmap_icon = data[0]; - self->pixmap_icon_mask = data[1]; - } else - self->pixmap_icon = self->pixmap_icon_mask = None; - g_free(data); + self->nicons++; + self->icons = g_new(Icon, self->nicons); + xerror_set_ignore(TRUE); + if (!render_pixmap_to_rgba(data[0], data[1], + &self->icons[self->nicons-1].width, + &self->icons[self->nicons-1].height, + &self->icons[self->nicons-1].data)) { + g_free(&self->icons[self->nicons-1]); + self->nicons--; + } + xerror_set_ignore(FALSE); + } + g_free(data); + } else { + XWMHints *hints; + + if ((hints = XGetWMHints(ob_display, self->window))) { + if (hints->flags & IconPixmapHint) { + self->nicons++; + self->icons = g_new(Icon, self->nicons); + xerror_set_ignore(TRUE); + if (!render_pixmap_to_rgba(hints->icon_pixmap, + (hints->flags & IconMaskHint ? + hints->icon_mask : None), + &self->icons[self->nicons-1].width, + &self->icons[self->nicons-1].height, + &self->icons[self->nicons-1].data)){ + g_free(&self->icons[self->nicons-1]); + self->nicons--; + } + xerror_set_ignore(FALSE); + } + XFree(hints); + } } + if (self->frame) frame_adjust_icon(self->frame); } @@ -1427,22 +1459,25 @@ Client *client_search_focus_tree_full(Client *self) return client_search_focus_tree_full(self->transient_for); } else { GSList *it; + gboolean recursed = FALSE; for (it = self->group->members; it; it = it->next) - if (((Client*)it->data)->transient_for != TRAN_GROUP) { + if (!((Client*)it->data)->transient_for) { Client *c; if ((c = client_search_focus_tree_full(it->data))) return c; + recursed = TRUE; } - return NULL; + if (recursed) + return NULL; } - } else { - /* this function checks the whole tree, the client_search_focus_tree - does not, so we need to check this window */ - if (client_focused(self)) - return self; - return client_search_focus_tree(self); } + + /* this function checks the whole tree, the client_search_focus_tree~ + does not, so we need to check this window */ + if (client_focused(self)) + return self; + return client_search_focus_tree(self); } static StackLayer calc_layer(Client *self) @@ -1496,7 +1531,7 @@ void client_calc_layer(Client *self) for (it = self->group->members; it; it = it->next) if (it->data != self && - ((Client*)it->data)->transient_for != TRAN_GROUP) { + !((Client*)it->data)->transient_for) { self = it->data; break; } @@ -1794,13 +1829,10 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk) } else { GSList *it; - /* the check for TRAN_GROUP is to prevent an infinate loop with - 2 transients of the same group at the head of the group's - members list */ for (it = self->group->members; it; it = it->next) { Client *c = it->data; if (c != self && c->iconic != iconic && - c->transient_for != TRAN_GROUP) { + !c->transient_for) { client_iconify(it->data, iconic, curdesk); break; } @@ -2002,7 +2034,7 @@ void client_set_desktop(Client *self, guint target, gboolean donthide) if (target == self->desktop) return; - g_message("Setting desktop %u", target); + g_message("Setting desktop %u", target+1); g_assert(target < screen_num_desktops || target == DESKTOP_ALL); @@ -2194,7 +2226,7 @@ void client_set_state(Client *self, Atom action, long data1, long data2) if (shaded != self->shaded) client_shade(self, shaded); client_calc_layer(self); - client_change_state(self); /* change the hint to relect these changes */ + client_change_state(self); /* change the hint to reflect these changes */ } Client *client_focus_target(Client *self) @@ -2207,18 +2239,15 @@ Client *client_focus_target(Client *self) return self; } -gboolean client_focus(Client *self) +gboolean client_can_focus(Client *self) { XEvent ev; /* choose the correct target */ self = client_focus_target(self); - if (self->desktop != DESKTOP_ALL && self->desktop != screen_desktop) { - /* update the focus lists */ - focus_order_to_top(self); + if (!self->frame->visible) return FALSE; - } if (!((self->can_focus || self->focus_notify) && (self->desktop == screen_desktop || @@ -2244,6 +2273,22 @@ gboolean client_focus(Client *self) } } + return TRUE; +} + +gboolean client_focus(Client *self) +{ + /* choose the correct target */ + self = client_focus_target(self); + + if (!client_can_focus(self)) { + if (!self->frame->visible) { + /* update the focus lists */ + focus_order_to_top(self); + } + return FALSE; + } + if (self->can_focus) /* RevertToPointerRoot causes much more headache than RevertToNone, so I choose to use it always, hopefully to find errors quicker, if any @@ -2333,3 +2378,113 @@ Icon *client_icon(Client *self, int w, int h) return &self->icons[si]; return &self->icons[li]; } + +/* this be mostly ripped from fvwm */ +Client *client_find_directional(Client *c, Direction dir) +{ + int my_cx, my_cy, his_cx, his_cy; + int offset = 0; + int distance = 0; + int score, best_score; + Client *best_client, *cur; + GList *it; + + if(!client_list) + return NULL; + + /* first, find the centre coords of the currently focused window */ + my_cx = c->frame->area.x + c->frame->area.width / 2; + my_cy = c->frame->area.y + c->frame->area.height / 2; + + best_score = -1; + best_client = NULL; + + for(it = g_list_first(client_list); it; it = it->next) { + cur = it->data; + + /* the currently selected window isn't interesting */ + if(cur == c) + continue; + if (!client_normal(cur)) + continue; + if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL) + continue; + if(cur->iconic) + continue; + if(client_focus_target(cur) == cur && + !(cur->can_focus || cur->focus_notify)) + continue; + + /* find the centre coords of this window, from the + * currently focused window's point of view */ + his_cx = (cur->frame->area.x - my_cx) + + cur->frame->area.width / 2; + his_cy = (cur->frame->area.y - my_cy) + + cur->frame->area.height / 2; + + if(dir > 3) { + int tx; + /* Rotate the diagonals 45 degrees counterclockwise. + * To do this, multiply the matrix /+h +h\ with the + * vector (x y). \-h +h/ + * h = sqrt(0.5). We can set h := 1 since absolute + * distance doesn't matter here. */ + tx = his_cx + his_cy; + his_cy = -his_cx + his_cy; + his_cx = tx; + } + + switch(dir) { + case Direction_North : + case Direction_South : + case Direction_NorthEast : + case Direction_SouthWest : + offset = (his_cx < 0) ? -his_cx : his_cx; + distance = (dir == Direction_North || dir == Direction_NorthEast) ? + -his_cy : his_cy; + break; + case Direction_East : + case Direction_West : + case Direction_SouthEast : + case Direction_NorthWest : + offset = (his_cy < 0) ? -his_cy : his_cy; + distance = (dir == Direction_West || dir == Direction_NorthWest) ? + -his_cx : his_cx; + break; + } + + /* the target must be in the requested direction */ + if(distance <= 0) + continue; + + /* Calculate score for this window. The smaller the better. */ + score = distance + offset; + + /* windows more than 45 degrees off the direction are + * heavily penalized and will only be chosen if nothing + * else within a million pixels */ + if(offset > distance) + score += 1000000; + + if(best_score == -1 || score < best_score) + best_client = cur, + best_score = score; + } + + return best_client; +} + +void client_set_layer(Client *self, int layer) +{ + if (layer < 0) { + self->below = TRUE; + self->above = FALSE; + } else if (layer == 0) { + self->below = self->above = FALSE; + } else { + self->below = FALSE; + self->above = TRUE; + } + client_calc_layer(self); + client_change_state(self); /* reflect this in the state hints */ +}