X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;ds=sidebyside;f=openbox%2Fclient.c;h=1aaa0267c6cc0ba883f7a59b1d1e2123d1224520;hb=b84a934ab7b3ebd68b8b90961146463ac17d396e;hp=ab37bb65349b2dd61a8e3e8314add5211b84a92a;hpb=abde4bc153b0b79b770506e2e35e36fcb1e32dc3;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index ab37bb65..1aaa0267 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -50,6 +50,12 @@ #define CLIENT_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \ ButtonMotionMask) +typedef struct +{ + ObClientDestructor func; + gpointer data; +} Destructor; + GList *client_list = NULL; GSList *client_destructors = NULL; @@ -81,14 +87,26 @@ void client_shutdown(gboolean reconfig) { } -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() @@ -183,9 +201,6 @@ void client_manage_all() } } XFree(children); - - if (config_focus_new) - focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); } void client_manage(Window window) @@ -247,7 +262,6 @@ void client_manage(Window window) self->title_count = 1; self->wmstate = NormalState; self->layer = -1; - self->decorate = TRUE; self->desktop = screen_num_desktops; /* always an invalid value */ client_get_all(self); @@ -280,7 +294,8 @@ void client_manage(Window window) client_restore_session_stacking(self); /* focus the new window? */ - if (ob_state() != OB_STATE_STARTING && config_focus_new && + if (ob_state() != OB_STATE_STARTING && + (config_focus_new || client_search_focus_parent(self)) && /* 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 */ @@ -344,7 +359,13 @@ void client_manage(Window window) a window maps since its not based on an action from the user like clicking a window to activate is. so keep the new window out of the way but do focus it. */ - if (activate) client_focus(self); + if (activate) { + /* if using focus_delay, stop the timer now so that focus doesn't go + moving on us */ + event_halt_focus_delay(); + + client_focus(self); + } /* client_activate does this but we aret using it so we have to do it here as well */ @@ -404,6 +425,25 @@ void client_unmanage(ObClient *self) 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; @@ -413,8 +453,8 @@ void client_unmanage(ObClient *self) ((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 */ @@ -425,20 +465,6 @@ void client_unmanage(ObClient *self) } } - 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); @@ -471,9 +497,9 @@ void client_unmanage(ObClient *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); @@ -506,8 +532,9 @@ static void client_restore_session_state(ObClient *self) RECT_SET(self->area, self->session->x, self->session->y, self->session->w, self->session->h); self->positioned = TRUE; - XResizeWindow(ob_display, self->window, - self->session->w, self->session->h); + if (self->session->w > 0 && self->session->h > 0) + XResizeWindow(ob_display, self->window, + self->session->w, self->session->h); self->desktop = (self->session->desktop == DESKTOP_ALL ? self->session->desktop : @@ -772,31 +799,33 @@ static void client_get_state(ObClient *self) guint num; if (PROP_GETA32(self->window, net_wm_state, atom, &state, &num)) { - gulong i; - for (i = 0; i < num; ++i) { - if (state[i] == prop_atoms.net_wm_state_modal) - self->modal = TRUE; - else if (state[i] == prop_atoms.net_wm_state_shaded) - self->shaded = TRUE; - else if (state[i] == prop_atoms.net_wm_state_hidden) - self->iconic = TRUE; - else if (state[i] == prop_atoms.net_wm_state_skip_taskbar) - self->skip_taskbar = TRUE; - else if (state[i] == prop_atoms.net_wm_state_skip_pager) - self->skip_pager = TRUE; - else if (state[i] == prop_atoms.net_wm_state_fullscreen) - self->fullscreen = TRUE; - else if (state[i] == prop_atoms.net_wm_state_maximized_vert) - self->max_vert = TRUE; - else if (state[i] == prop_atoms.net_wm_state_maximized_horz) - self->max_horz = TRUE; - else if (state[i] == prop_atoms.net_wm_state_above) - self->above = TRUE; - else if (state[i] == prop_atoms.net_wm_state_below) - self->below = TRUE; - } + gulong i; + for (i = 0; i < num; ++i) { + if (state[i] == prop_atoms.net_wm_state_modal) + self->modal = TRUE; + else if (state[i] == prop_atoms.net_wm_state_shaded) + self->shaded = TRUE; + else if (state[i] == prop_atoms.net_wm_state_hidden) + self->iconic = TRUE; + else if (state[i] == prop_atoms.net_wm_state_skip_taskbar) + self->skip_taskbar = TRUE; + else if (state[i] == prop_atoms.net_wm_state_skip_pager) + self->skip_pager = TRUE; + else if (state[i] == prop_atoms.net_wm_state_fullscreen) + self->fullscreen = TRUE; + else if (state[i] == prop_atoms.net_wm_state_maximized_vert) + self->max_vert = TRUE; + else if (state[i] == prop_atoms.net_wm_state_maximized_horz) + self->max_horz = TRUE; + else if (state[i] == prop_atoms.net_wm_state_above) + self->above = TRUE; + else if (state[i] == prop_atoms.net_wm_state_below) + self->below = TRUE; + else if (state[i] == prop_atoms.ob_wm_state_undecorated) + self->undecorated = TRUE; + } - g_free(state); + g_free(state); } } @@ -825,7 +854,7 @@ void client_update_transient_for(ObClient *self) 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*/ @@ -841,14 +870,15 @@ void client_update_transient_for(ObClient *self) 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) { @@ -1070,70 +1100,70 @@ void client_setup_decor_and_functions(ObClient *self) OB_CLIENT_FUNC_MAXIMIZE | OB_CLIENT_FUNC_SHADE); if (self->delete_window) { - self->functions |= OB_CLIENT_FUNC_CLOSE; + self->functions |= OB_CLIENT_FUNC_CLOSE; self->decorations |= OB_FRAME_DECOR_CLOSE; } if (!(self->min_size.width < self->max_size.width || - self->min_size.height < self->max_size.height)) - self->functions &= ~OB_CLIENT_FUNC_RESIZE; + self->min_size.height < self->max_size.height)) + self->functions &= ~OB_CLIENT_FUNC_RESIZE; switch (self->type) { case OB_CLIENT_TYPE_NORMAL: - /* normal windows retain all of the possible decorations and - functionality, and are the only windows that you can fullscreen */ - self->functions |= OB_CLIENT_FUNC_FULLSCREEN; - break; + /* normal windows retain all of the possible decorations and + functionality, and are the only windows that you can fullscreen */ + self->functions |= OB_CLIENT_FUNC_FULLSCREEN; + break; case OB_CLIENT_TYPE_DIALOG: case OB_CLIENT_TYPE_UTILITY: - /* these windows cannot be maximized */ - self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE; - break; + /* these windows cannot be maximized */ + self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE; + 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); - break; + /* these windows get less functionality */ + self->functions &= ~(OB_CLIENT_FUNC_ICONIFY | OB_CLIENT_FUNC_RESIZE); + break; case OB_CLIENT_TYPE_DESKTOP: case OB_CLIENT_TYPE_DOCK: case OB_CLIENT_TYPE_SPLASH: - /* none of these windows are manipulated by the window manager */ - self->decorations = 0; - self->functions = 0; - break; + /* none of these windows are manipulated by the window manager */ + self->decorations = 0; + self->functions = 0; + break; } /* Mwm Hints are applied subtractively to what has already been chosen for decor and functionality */ if (self->mwmhints.flags & OB_MWM_FLAG_DECORATIONS) { - if (! (self->mwmhints.decorations & OB_MWM_DECOR_ALL)) { - if (! ((self->mwmhints.decorations & OB_MWM_DECOR_HANDLE) || + if (! (self->mwmhints.decorations & OB_MWM_DECOR_ALL)) { + if (! ((self->mwmhints.decorations & OB_MWM_DECOR_HANDLE) || (self->mwmhints.decorations & OB_MWM_DECOR_TITLE))) /* if the mwm hints request no handle or title, then all decorations are disabled */ - self->decorations = 0; - } + self->decorations = 0; + } } if (self->mwmhints.flags & OB_MWM_FLAG_FUNCTIONS) { - if (! (self->mwmhints.functions & OB_MWM_FUNC_ALL)) { - if (! (self->mwmhints.functions & OB_MWM_FUNC_RESIZE)) - self->functions &= ~OB_CLIENT_FUNC_RESIZE; - if (! (self->mwmhints.functions & OB_MWM_FUNC_MOVE)) - self->functions &= ~OB_CLIENT_FUNC_MOVE; + if (! (self->mwmhints.functions & OB_MWM_FUNC_ALL)) { + if (! (self->mwmhints.functions & OB_MWM_FUNC_RESIZE)) + self->functions &= ~OB_CLIENT_FUNC_RESIZE; + if (! (self->mwmhints.functions & OB_MWM_FUNC_MOVE)) + self->functions &= ~OB_CLIENT_FUNC_MOVE; /* dont let mwm hints kill any buttons - if (! (self->mwmhints.functions & OB_MWM_FUNC_ICONIFY)) - self->functions &= ~OB_CLIENT_FUNC_ICONIFY; - if (! (self->mwmhints.functions & OB_MWM_FUNC_MAXIMIZE)) - self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE; + if (! (self->mwmhints.functions & OB_MWM_FUNC_ICONIFY)) + self->functions &= ~OB_CLIENT_FUNC_ICONIFY; + if (! (self->mwmhints.functions & OB_MWM_FUNC_MAXIMIZE)) + self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE; */ - /* dont let mwm hints kill the close button - if (! (self->mwmhints.functions & MwmFunc_Close)) - self->functions &= ~OB_CLIENT_FUNC_CLOSE; */ - } + /* dont let mwm hints kill the close button + if (! (self->mwmhints.functions & MwmFunc_Close)) + self->functions &= ~OB_CLIENT_FUNC_CLOSE; */ + } } if (!(self->functions & OB_CLIENT_FUNC_SHADE)) @@ -1156,20 +1186,20 @@ void client_setup_decor_and_functions(ObClient *self) self->decorations &= ~OB_FRAME_DECOR_HANDLE; /* finally, the user can have requested no decorations, which overrides - everything */ - if (!self->decorate) - self->decorations = OB_FRAME_DECOR_BORDER; + everything (but doesnt give it a border if it doesnt have one) */ + if (self->undecorated) + self->decorations &= OB_FRAME_DECOR_BORDER; /* if we don't have a titlebar, then we cannot shade! */ if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR)) - self->functions &= ~OB_CLIENT_FUNC_SHADE; + self->functions &= ~OB_CLIENT_FUNC_SHADE; /* now we need to check against rules for the client's current state */ if (self->fullscreen) { - self->functions &= (OB_CLIENT_FUNC_CLOSE | + self->functions &= (OB_CLIENT_FUNC_CLOSE | OB_CLIENT_FUNC_FULLSCREEN | OB_CLIENT_FUNC_ICONIFY); - self->decorations = 0; + self->decorations = 0; } client_change_allowed_actions(self); @@ -1197,20 +1227,20 @@ static void client_change_allowed_actions(ObClient *self) actions[num++] = prop_atoms.net_wm_action_change_desktop; if (self->functions & OB_CLIENT_FUNC_SHADE) - actions[num++] = prop_atoms.net_wm_action_shade; + actions[num++] = prop_atoms.net_wm_action_shade; if (self->functions & OB_CLIENT_FUNC_CLOSE) - actions[num++] = prop_atoms.net_wm_action_close; + actions[num++] = prop_atoms.net_wm_action_close; if (self->functions & OB_CLIENT_FUNC_MOVE) - actions[num++] = prop_atoms.net_wm_action_move; + actions[num++] = prop_atoms.net_wm_action_move; if (self->functions & OB_CLIENT_FUNC_ICONIFY) - actions[num++] = prop_atoms.net_wm_action_minimize; + actions[num++] = prop_atoms.net_wm_action_minimize; if (self->functions & OB_CLIENT_FUNC_RESIZE) - actions[num++] = prop_atoms.net_wm_action_resize; + actions[num++] = prop_atoms.net_wm_action_resize; if (self->functions & OB_CLIENT_FUNC_FULLSCREEN) - actions[num++] = prop_atoms.net_wm_action_fullscreen; + actions[num++] = prop_atoms.net_wm_action_fullscreen; if (self->functions & OB_CLIENT_FUNC_MAXIMIZE) { - actions[num++] = prop_atoms.net_wm_action_maximize_horz; - actions[num++] = prop_atoms.net_wm_action_maximize_vert; + actions[num++] = prop_atoms.net_wm_action_maximize_horz; + actions[num++] = prop_atoms.net_wm_action_maximize_vert; } PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num); @@ -1218,21 +1248,21 @@ static void client_change_allowed_actions(ObClient *self) /* make sure the window isn't breaking any rules now */ if (!(self->functions & OB_CLIENT_FUNC_SHADE) && self->shaded) { - if (self->frame) client_shade(self, FALSE); - else self->shaded = FALSE; + if (self->frame) client_shade(self, FALSE); + else self->shaded = FALSE; } if (!(self->functions & OB_CLIENT_FUNC_ICONIFY) && self->iconic) { - if (self->frame) client_iconify(self, FALSE, TRUE); - else self->iconic = FALSE; + if (self->frame) client_iconify(self, FALSE, TRUE); + else self->iconic = FALSE; } if (!(self->functions & OB_CLIENT_FUNC_FULLSCREEN) && self->fullscreen) { - if (self->frame) client_fullscreen(self, FALSE, TRUE); - else self->fullscreen = FALSE; + if (self->frame) client_fullscreen(self, FALSE, TRUE); + else self->fullscreen = FALSE; } if (!(self->functions & OB_CLIENT_FUNC_MAXIMIZE) && (self->max_horz || self->max_vert)) { - if (self->frame) client_maximize(self, FALSE, 0, TRUE); - else self->max_vert = self->max_horz = FALSE; + if (self->frame) client_maximize(self, FALSE, 0, TRUE); + else self->max_vert = self->max_horz = FALSE; } } @@ -1279,6 +1309,18 @@ void client_update_wmhints(ObClient *self) 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; } @@ -1309,16 +1351,14 @@ void client_update_wmhints(ObClient *self) /* the WM_HINTS can contain an icon */ client_update_icons(self); - XFree(hints); + XFree(hints); } if (ur != self->urgent) { - self->urgent = ur; - ob_debug("Urgent Hint for 0x%lx: %s\n", self->window, - ur ? "ON" : "OFF"); - /* fire the urgent callback if we're mapped, otherwise, wait until - after we're mapped */ - if (self->frame) + self->urgent = ur; + /* fire the urgent callback if we're mapped, otherwise, wait until + after we're mapped */ + if (self->frame) client_urgent_notify(self); } } @@ -1483,35 +1523,35 @@ void client_update_icons(ObClient *self) 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; @@ -1523,10 +1563,10 @@ void client_update_icons(ObClient *self) (((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) { @@ -1568,24 +1608,14 @@ void client_update_icons(ObClient *self) } } - 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) { guint32 state[2]; - guint32 netstate[10]; + guint32 netstate[11]; guint num; state[0] = self->wmstate; @@ -1594,31 +1624,33 @@ static void client_change_state(ObClient *self) num = 0; if (self->modal) - netstate[num++] = prop_atoms.net_wm_state_modal; + netstate[num++] = prop_atoms.net_wm_state_modal; if (self->shaded) - netstate[num++] = prop_atoms.net_wm_state_shaded; + netstate[num++] = prop_atoms.net_wm_state_shaded; if (self->iconic) - netstate[num++] = prop_atoms.net_wm_state_hidden; + netstate[num++] = prop_atoms.net_wm_state_hidden; if (self->skip_taskbar) - netstate[num++] = prop_atoms.net_wm_state_skip_taskbar; + netstate[num++] = prop_atoms.net_wm_state_skip_taskbar; if (self->skip_pager) - netstate[num++] = prop_atoms.net_wm_state_skip_pager; + netstate[num++] = prop_atoms.net_wm_state_skip_pager; if (self->fullscreen) - netstate[num++] = prop_atoms.net_wm_state_fullscreen; + netstate[num++] = prop_atoms.net_wm_state_fullscreen; if (self->max_vert) - netstate[num++] = prop_atoms.net_wm_state_maximized_vert; + netstate[num++] = prop_atoms.net_wm_state_maximized_vert; if (self->max_horz) - netstate[num++] = prop_atoms.net_wm_state_maximized_horz; + netstate[num++] = prop_atoms.net_wm_state_maximized_horz; if (self->above) - netstate[num++] = prop_atoms.net_wm_state_above; + netstate[num++] = prop_atoms.net_wm_state_above; if (self->below) - netstate[num++] = prop_atoms.net_wm_state_below; + netstate[num++] = prop_atoms.net_wm_state_below; + if (self->undecorated) + netstate[num++] = prop_atoms.ob_wm_state_undecorated; PROP_SETA32(self->window, net_wm_state, atom, netstate, num); client_calc_layer(self); if (self->frame) - frame_adjust_state(self->frame); + frame_adjust_state(self->frame); } ObClient *client_search_focus_tree(ObClient *self) @@ -1665,11 +1697,14 @@ static ObStackingLayer calc_layer(ObClient *self) { ObStackingLayer l; - if (self->fullscreen) l = OB_STACKING_LAYER_FULLSCREEN; + if (self->fullscreen && + (client_focused(self) || client_search_focus_tree(self))) + l = OB_STACKING_LAYER_FULLSCREEN; else if (self->type == OB_CLIENT_TYPE_DESKTOP) l = OB_STACKING_LAYER_DESKTOP; else if (self->type == OB_CLIENT_TYPE_DOCK) { - if (!self->below) l = OB_STACKING_LAYER_TOP; + if (self->above) l = OB_STACKING_LAYER_DOCK_ABOVE; + else if (self->below) l = OB_STACKING_LAYER_DOCK_BELOW; else l = OB_STACKING_LAYER_NORMAL; } else if (self->above) l = OB_STACKING_LAYER_ABOVE; @@ -1720,7 +1755,7 @@ gboolean client_should_show(ObClient *self) { if (self->iconic) return FALSE; else if (!(self->desktop == screen_desktop || - self->desktop == DESKTOP_ALL)) return FALSE; + self->desktop == DESKTOP_ALL)) return FALSE; else if (client_normal(self) && screen_showing_desktop) return FALSE; return TRUE; @@ -1738,7 +1773,7 @@ static void client_showhide(ObClient *self) gboolean client_normal(ObClient *self) { return ! (self->type == OB_CLIENT_TYPE_DESKTOP || self->type == OB_CLIENT_TYPE_DOCK || - self->type == OB_CLIENT_TYPE_SPLASH); + self->type == OB_CLIENT_TYPE_SPLASH); } static void client_apply_startup_state(ObClient *self) @@ -1746,29 +1781,33 @@ static void client_apply_startup_state(ObClient *self) /* these are in a carefully crafted order.. */ if (self->iconic) { - self->iconic = FALSE; - client_iconify(self, TRUE, FALSE); + self->iconic = FALSE; + client_iconify(self, TRUE, FALSE); } if (self->fullscreen) { - self->fullscreen = FALSE; - client_fullscreen(self, TRUE, FALSE); + self->fullscreen = FALSE; + client_fullscreen(self, TRUE, FALSE); + } + if (self->undecorated) { + self->undecorated = FALSE; + client_set_undecorated(self, TRUE); } if (self->shaded) { - self->shaded = FALSE; - client_shade(self, TRUE); + self->shaded = FALSE; + client_shade(self, TRUE); } if (self->urgent) client_urgent_notify(self); if (self->max_vert && self->max_horz) { - self->max_vert = self->max_horz = FALSE; - client_maximize(self, TRUE, 0, FALSE); + self->max_vert = self->max_horz = FALSE; + client_maximize(self, TRUE, 0, FALSE); } else if (self->max_vert) { - self->max_vert = FALSE; - client_maximize(self, TRUE, 2, FALSE); + self->max_vert = FALSE; + client_maximize(self, TRUE, 2, FALSE); } else if (self->max_horz) { - self->max_horz = FALSE; - client_maximize(self, TRUE, 1, FALSE); + self->max_horz = FALSE; + client_maximize(self, TRUE, 1, FALSE); } /* nothing to do for the other states: @@ -1922,27 +1961,46 @@ void client_configure_full(ObClient *self, ObCorner anchor, 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; @@ -1960,7 +2018,7 @@ void client_configure_full(ObClient *self, ObCorner anchor, (resized && config_redraw_resize)))); /* if the client is enlarging, the resize the client before the frame */ - if (!user || (send_resize_client && (w > oldw || h > oldh))) + if (send_resize_client && user && (w > oldw || h > oldh)) XResizeWindow(ob_display, self->window, MAX(w, oldw), MAX(h, oldh)); /* move/resize the frame to match the request */ @@ -1995,7 +2053,7 @@ void client_configure_full(ObClient *self, ObCorner anchor, } /* if the client is shrinking, then resize the frame before the client */ - if (user && (send_resize_client && (w <= oldw || h <= oldh))) + if (send_resize_client && (!user || (w <= oldw || h <= oldh))) XResizeWindow(ob_display, self->window, w, h); XFlush(ob_display); @@ -2013,42 +2071,31 @@ void client_fullscreen(ObClient *self, gboolean fs, gboolean savearea) and adjust out layer/stacking */ if (fs) { - if (savearea) { - guint32 dimensions[4]; - dimensions[0] = self->area.x; - dimensions[1] = self->area.y; - dimensions[2] = self->area.width; - dimensions[3] = self->area.height; - - PROP_SETA32(self->window, openbox_premax, cardinal, - dimensions, 4); - } + if (savearea) + self->pre_fullscreen_area = self->area; /* these are not actually used cuz client_configure will set them as appropriate when the window is fullscreened */ x = y = w = h = 0; } else { - guint num; - gint32 *dimensions; Rect *a; - /* pick some fallbacks... */ - a = screen_area_monitor(self->desktop, 0); - x = a->x + a->width / 4; - y = a->y + a->height / 4; - w = a->width / 2; - h = a->height / 2; - - if (PROP_GETA32(self->window, openbox_premax, cardinal, - (guint32**)&dimensions, &num)) { - if (num == 4) { - x = dimensions[0]; - y = dimensions[1]; - w = dimensions[2]; - h = dimensions[3]; - } - g_free(dimensions); - } + if (self->pre_fullscreen_area.width > 0 && + self->pre_fullscreen_area.height > 0) + { + x = self->pre_fullscreen_area.x; + y = self->pre_fullscreen_area.y; + w = self->pre_fullscreen_area.width; + h = self->pre_fullscreen_area.height; + RECT_SET(self->pre_fullscreen_area, 0, 0, 0, 0); + } else { + /* pick some fallbacks... */ + a = screen_area_monitor(self->desktop, 0); + x = a->x + a->width / 4; + y = a->y + a->height / 4; + w = a->width / 2; + h = a->height / 2; + } } client_setup_decor_and_functions(self); @@ -2074,7 +2121,14 @@ static void client_iconify_recursive(ObClient *self, if (iconic) { if (self->functions & OB_CLIENT_FUNC_ICONIFY) { + long old; + + old = self->wmstate; self->wmstate = IconicState; + if (old != self->wmstate) + PROP_MSG(self->window, kde_wm_change_state, + self->wmstate, 1, 0, 0); + self->ignore_unmaps++; /* we unmap the client itself so that we can get MapRequest events, and because the ICCCM tells us to! */ @@ -2088,9 +2142,17 @@ static void client_iconify_recursive(ObClient *self, changed = TRUE; } } else { + long old; + if (curdesk) client_set_desktop(self, screen_desktop, FALSE); + + old = self->wmstate; self->wmstate = self->shaded ? IconicState : NormalState; + if (old != self->wmstate) + PROP_MSG(self->window, kde_wm_change_state, + self->wmstate, 1, 0, 0); + XMapWindow(ob_display, self->window); /* this puts it after the current focused window */ @@ -2137,98 +2199,76 @@ void client_maximize(ObClient *self, gboolean max, int dir, gboolean savearea) /* check if already done */ if (max) { - if (dir == 0 && self->max_horz && self->max_vert) return; - if (dir == 1 && self->max_horz) return; - if (dir == 2 && self->max_vert) return; + if (dir == 0 && self->max_horz && self->max_vert) return; + if (dir == 1 && self->max_horz) return; + if (dir == 2 && self->max_vert) return; } else { - if (dir == 0 && !self->max_horz && !self->max_vert) return; - if (dir == 1 && !self->max_horz) return; - if (dir == 2 && !self->max_vert) return; + if (dir == 0 && !self->max_horz && !self->max_vert) return; + if (dir == 1 && !self->max_horz) return; + if (dir == 2 && !self->max_vert) return; } - /* work with the frame's coords */ - x = self->frame->area.x; - y = self->frame->area.y; + /* we just tell it to configure in the same place and client_configure + worries about filling the screen with the window */ + x = self->area.x; + y = self->area.y; w = self->area.width; h = self->area.height; if (max) { - if (savearea) { - gint32 dimensions[4]; - gint32 *readdim; - guint num; - - dimensions[0] = x; - dimensions[1] = y; - dimensions[2] = w; - dimensions[3] = h; - - /* get the property off the window and use it for the dimensions - we are already maxed on */ - if (PROP_GETA32(self->window, openbox_premax, cardinal, - (guint32**)&readdim, &num)) { - if (num == 4) { - if (self->max_horz) { - dimensions[0] = readdim[0]; - dimensions[2] = readdim[2]; - } - if (self->max_vert) { - dimensions[1] = readdim[1]; - dimensions[3] = readdim[3]; - } - } - g_free(readdim); - } - - PROP_SETA32(self->window, openbox_premax, cardinal, - (guint32*)dimensions, 4); - } + if (savearea) { + if ((dir == 0 || dir == 1) && !self->max_horz) { /* horz */ + RECT_SET(self->pre_max_area, + self->area.x, self->pre_max_area.y, + self->area.width, self->pre_max_area.height); + } + if ((dir == 0 || dir == 2) && !self->max_vert) { /* vert */ + RECT_SET(self->pre_max_area, + self->pre_max_area.x, self->area.y, + self->pre_max_area.width, self->area.height); + } + } } else { - guint num; - gint32 *dimensions; Rect *a; - /* pick some fallbacks... */ a = screen_area_monitor(self->desktop, 0); - if (dir == 0 || dir == 1) { /* horz */ - x = a->x + a->width / 4; - w = a->width / 2; - } - if (dir == 0 || dir == 2) { /* vert */ - y = a->y + a->height / 4; - h = a->height / 2; + if ((dir == 0 || dir == 1) && self->max_horz) { /* horz */ + if (self->pre_max_area.width > 0) { + x = self->pre_max_area.x; + w = self->pre_max_area.width; + + RECT_SET(self->pre_max_area, 0, self->pre_max_area.y, + 0, self->pre_max_area.height); + } else { + /* pick some fallbacks... */ + x = a->x + a->width / 4; + w = a->width / 2; + } } + if ((dir == 0 || dir == 2) && self->max_vert) { /* vert */ + if (self->pre_max_area.height > 0) { + y = self->pre_max_area.y; + h = self->pre_max_area.height; - if (PROP_GETA32(self->window, openbox_premax, cardinal, - (guint32**)&dimensions, &num)) { - if (num == 4) { - if (dir == 0 || dir == 1) { /* horz */ - x = dimensions[0]; - w = dimensions[2]; - } - if (dir == 0 || dir == 2) { /* vert */ - y = dimensions[1]; - h = dimensions[3]; - } + RECT_SET(self->pre_max_area, self->pre_max_area.x, 0, + self->pre_max_area.width, 0); + } else { + /* pick some fallbacks... */ + y = a->y + a->height / 4; + h = a->height / 2; } - g_free(dimensions); - } + } } if (dir == 0 || dir == 1) /* horz */ - self->max_horz = max; + self->max_horz = max; if (dir == 0 || dir == 2) /* vert */ - self->max_vert = max; - - if (!self->max_horz && !self->max_vert) - PROP_ERASE(self->window, openbox_premax); + self->max_vert = max; client_change_state(self); /* change the state hints on the client */ client_setup_decor_and_functions(self); - /* figure out where the client should be going */ - frame_frame_gravity(self->frame, &x, &y); client_move_resize(self, x, y, w, h); } @@ -2239,8 +2279,16 @@ void client_shade(ObClient *self, gboolean shade) self->shaded == shade) return; /* already done */ /* when we're iconic, don't change the wmstate */ - if (!self->iconic) - self->wmstate = shade ? IconicState : NormalState; + if (!self->iconic) { + long old; + + old = self->wmstate; + self->wmstate = shade ? IconicState : NormalState; + if (old != self->wmstate) + PROP_MSG(self->window, kde_wm_change_state, + self->wmstate, 1, 0, 0); + } + self->shaded = shade; client_change_state(self); /* resize the frame to just the titlebar */ @@ -2304,7 +2352,7 @@ void client_set_desktop_recursive(ObClient *self, 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) */ @@ -2372,122 +2420,132 @@ void client_set_state(ObClient *self, Atom action, long data1, long data2) { gboolean shaded = self->shaded; gboolean fullscreen = self->fullscreen; + gboolean undecorated = self->undecorated; gboolean max_horz = self->max_horz; gboolean max_vert = self->max_vert; int i; if (!(action == prop_atoms.net_wm_state_add || - action == prop_atoms.net_wm_state_remove || - action == prop_atoms.net_wm_state_toggle)) - /* an invalid action was passed to the client message, ignore it */ - return; + action == prop_atoms.net_wm_state_remove || + action == prop_atoms.net_wm_state_toggle)) + /* an invalid action was passed to the client message, ignore it */ + return; for (i = 0; i < 2; ++i) { - Atom state = i == 0 ? data1 : data2; + Atom state = i == 0 ? data1 : data2; - if (!state) continue; - - /* if toggling, then pick whether we're adding or removing */ - if (action == prop_atoms.net_wm_state_toggle) { - if (state == prop_atoms.net_wm_state_modal) - action = self->modal ? prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - else if (state == prop_atoms.net_wm_state_maximized_vert) - action = self->max_vert ? prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - else if (state == prop_atoms.net_wm_state_maximized_horz) - action = self->max_horz ? prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - else if (state == prop_atoms.net_wm_state_shaded) - action = self->shaded ? prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - else if (state == prop_atoms.net_wm_state_skip_taskbar) - action = self->skip_taskbar ? - prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - else if (state == prop_atoms.net_wm_state_skip_pager) - action = self->skip_pager ? - prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - else if (state == prop_atoms.net_wm_state_fullscreen) - action = self->fullscreen ? - prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - else if (state == prop_atoms.net_wm_state_above) - action = self->above ? prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - else if (state == prop_atoms.net_wm_state_below) - action = self->below ? prop_atoms.net_wm_state_remove : - prop_atoms.net_wm_state_add; - } + if (!state) continue; + + /* if toggling, then pick whether we're adding or removing */ + if (action == prop_atoms.net_wm_state_toggle) { + if (state == prop_atoms.net_wm_state_modal) + action = self->modal ? prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.net_wm_state_maximized_vert) + action = self->max_vert ? prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.net_wm_state_maximized_horz) + action = self->max_horz ? prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.net_wm_state_shaded) + action = shaded ? prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.net_wm_state_skip_taskbar) + action = self->skip_taskbar ? + prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.net_wm_state_skip_pager) + action = self->skip_pager ? + prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.net_wm_state_fullscreen) + action = fullscreen ? + prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.net_wm_state_above) + action = self->above ? prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.net_wm_state_below) + action = self->below ? prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + else if (state == prop_atoms.ob_wm_state_undecorated) + action = undecorated ? prop_atoms.net_wm_state_remove : + prop_atoms.net_wm_state_add; + } - if (action == prop_atoms.net_wm_state_add) { - if (state == prop_atoms.net_wm_state_modal) { - /* XXX raise here or something? */ - self->modal = TRUE; - } else if (state == prop_atoms.net_wm_state_maximized_vert) { - max_vert = TRUE; - } else if (state == prop_atoms.net_wm_state_maximized_horz) { - max_horz = TRUE; - } else if (state == prop_atoms.net_wm_state_shaded) { - shaded = TRUE; - } else if (state == prop_atoms.net_wm_state_skip_taskbar) { - self->skip_taskbar = TRUE; - } else if (state == prop_atoms.net_wm_state_skip_pager) { - self->skip_pager = TRUE; - } else if (state == prop_atoms.net_wm_state_fullscreen) { - fullscreen = TRUE; - } else if (state == prop_atoms.net_wm_state_above) { - self->above = TRUE; - } else if (state == prop_atoms.net_wm_state_below) { - self->below = TRUE; - } + if (action == prop_atoms.net_wm_state_add) { + if (state == prop_atoms.net_wm_state_modal) { + /* XXX raise here or something? */ + self->modal = TRUE; + } else if (state == prop_atoms.net_wm_state_maximized_vert) { + max_vert = TRUE; + } else if (state == prop_atoms.net_wm_state_maximized_horz) { + max_horz = TRUE; + } else if (state == prop_atoms.net_wm_state_shaded) { + shaded = TRUE; + } else if (state == prop_atoms.net_wm_state_skip_taskbar) { + self->skip_taskbar = TRUE; + } else if (state == prop_atoms.net_wm_state_skip_pager) { + self->skip_pager = TRUE; + } else if (state == prop_atoms.net_wm_state_fullscreen) { + fullscreen = TRUE; + } else if (state == prop_atoms.net_wm_state_above) { + self->above = TRUE; + } else if (state == prop_atoms.net_wm_state_below) { + self->below = TRUE; + } else if (state == prop_atoms.ob_wm_state_undecorated) { + undecorated = TRUE; + } - } else { /* action == prop_atoms.net_wm_state_remove */ - if (state == prop_atoms.net_wm_state_modal) { - self->modal = FALSE; - } else if (state == prop_atoms.net_wm_state_maximized_vert) { - max_vert = FALSE; - } else if (state == prop_atoms.net_wm_state_maximized_horz) { - max_horz = FALSE; - } else if (state == prop_atoms.net_wm_state_shaded) { - shaded = FALSE; - } else if (state == prop_atoms.net_wm_state_skip_taskbar) { - self->skip_taskbar = FALSE; - } else if (state == prop_atoms.net_wm_state_skip_pager) { - self->skip_pager = FALSE; - } else if (state == prop_atoms.net_wm_state_fullscreen) { - fullscreen = FALSE; - } else if (state == prop_atoms.net_wm_state_above) { - self->above = FALSE; - } else if (state == prop_atoms.net_wm_state_below) { - self->below = FALSE; - } - } + } else { /* action == prop_atoms.net_wm_state_remove */ + if (state == prop_atoms.net_wm_state_modal) { + self->modal = FALSE; + } else if (state == prop_atoms.net_wm_state_maximized_vert) { + max_vert = FALSE; + } else if (state == prop_atoms.net_wm_state_maximized_horz) { + max_horz = FALSE; + } else if (state == prop_atoms.net_wm_state_shaded) { + shaded = FALSE; + } else if (state == prop_atoms.net_wm_state_skip_taskbar) { + self->skip_taskbar = FALSE; + } else if (state == prop_atoms.net_wm_state_skip_pager) { + self->skip_pager = FALSE; + } else if (state == prop_atoms.net_wm_state_fullscreen) { + fullscreen = FALSE; + } else if (state == prop_atoms.net_wm_state_above) { + self->above = FALSE; + } else if (state == prop_atoms.net_wm_state_below) { + self->below = FALSE; + } else if (state == prop_atoms.ob_wm_state_undecorated) { + undecorated = FALSE; + } + } } if (max_horz != self->max_horz || max_vert != self->max_vert) { - if (max_horz != self->max_horz && max_vert != self->max_vert) { - /* toggling both */ - if (max_horz == max_vert) { /* both going the same way */ - client_maximize(self, max_horz, 0, TRUE); - } else { - client_maximize(self, max_horz, 1, TRUE); - client_maximize(self, max_vert, 2, TRUE); - } - } else { - /* toggling one */ - if (max_horz != self->max_horz) - client_maximize(self, max_horz, 1, TRUE); - else - client_maximize(self, max_vert, 2, TRUE); - } + if (max_horz != self->max_horz && max_vert != self->max_vert) { + /* toggling both */ + if (max_horz == max_vert) { /* both going the same way */ + client_maximize(self, max_horz, 0, TRUE); + } else { + client_maximize(self, max_horz, 1, TRUE); + client_maximize(self, max_vert, 2, TRUE); + } + } else { + /* toggling one */ + if (max_horz != self->max_horz) + client_maximize(self, max_horz, 1, TRUE); + else + client_maximize(self, max_vert, 2, TRUE); + } } /* change fullscreen state before shading, as it will affect if the window can shade or not */ if (fullscreen != self->fullscreen) - client_fullscreen(self, fullscreen, TRUE); + client_fullscreen(self, fullscreen, TRUE); if (shaded != self->shaded) - client_shade(self, shaded); + client_shade(self, shaded); + if (undecorated != self->undecorated) + client_set_undecorated(self, undecorated); client_calc_layer(self); client_change_state(self); /* change the hint to reflect these changes */ } @@ -2497,7 +2555,7 @@ ObClient *client_focus_target(ObClient *self) 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; } @@ -2512,28 +2570,25 @@ gboolean client_can_focus(ObClient *self) if (!self->frame->visible) return FALSE; - if (!((self->can_focus || self->focus_notify) && - (self->desktop == screen_desktop || - self->desktop == DESKTOP_ALL) && - !self->iconic)) - return FALSE; + if (!(self->can_focus || self->focus_notify)) + 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; @@ -2594,11 +2649,12 @@ gboolean client_focus(ObClient *self) void client_unfocus(ObClient *self) { - g_assert(focus_client == self); + if (focus_client == self) { #ifdef DEBUG_FOCUS - ob_debug("client_unfocus for %lx\n", self->window); + ob_debug("client_unfocus for %lx\n", self->window); #endif - focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING); + focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING); + } } void client_activate(ObClient *self, gboolean here) @@ -2606,7 +2662,7 @@ void client_activate(ObClient *self, gboolean here) 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) @@ -2619,8 +2675,25 @@ void client_activate(ObClient *self, gboolean here) return; if (self->shaded) client_shade(self, FALSE); + client_focus(self); - stacking_raise(CLIENT_AS_WINDOW(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); } gboolean client_focused(ObClient *self) @@ -2628,13 +2701,34 @@ gboolean client_focused(ObClient *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)) { @@ -2651,6 +2745,19 @@ ObClientIcon *client_icon(ObClient *self, int w, int 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) { @@ -2764,6 +2871,15 @@ void client_set_layer(ObClient *self, int layer) client_change_state(self); /* reflect this in the state hints */ } +void client_set_undecorated(ObClient *self, gboolean undecorated) +{ + if (self->undecorated != undecorated) { + self->undecorated = undecorated; + client_setup_decor_and_functions(self); + client_change_state(self); /* reflect this in the state hints */ + } +} + guint client_monitor(ObClient *self) { guint i; @@ -2787,6 +2903,8 @@ ObClient *client_search_top_transient(ObClient *self) } else { GSList *it; + g_assert(self->group); + for (it = self->group->members; it; it = it->next) { ObClient *c = it->data; @@ -2802,6 +2920,52 @@ ObClient *client_search_top_transient(ObClient *self) return self; } +ObClient *client_search_focus_parent(ObClient *self) +{ + if (self->transient_for) { + if (self->transient_for != OB_TRAN_GROUP) { + if (client_focused(self->transient_for)) + return self->transient_for; + } else { + GSList *it; + + for (it = self->group->members; it; it = it->next) { + ObClient *c = it->data; + + /* checking transient_for prevents infinate loops! */ + if (c != self && !c->transient_for) + if (client_focused(c)) + return c; + } + } + } + + return NULL; +} + +ObClient *client_search_parent(ObClient *self, ObClient *search) +{ + if (self->transient_for) { + if (self->transient_for != OB_TRAN_GROUP) { + if (self->transient_for == search) + return search; + } else { + GSList *it; + + for (it = self->group->members; it; it = it->next) { + ObClient *c = it->data; + + /* checking transient_for prevents infinate loops! */ + if (c != self && !c->transient_for) + if (c == search) + return search; + } + } + } + + return NULL; +} + ObClient *client_search_transient(ObClient *self, ObClient *search) { GSList *sit; @@ -3010,9 +3174,34 @@ int client_directional_edge_search(ObClient *c, ObDirection dir) case OB_DIRECTION_NORTHWEST: case OB_DIRECTION_SOUTHWEST: /* not implemented */ - break; default: - g_assert_not_reached(); + g_assert_not_reached(); } return dest; } + +ObClient* client_under_pointer() +{ + int x, y; + GList *it; + ObClient *ret = NULL; + + if (screen_pointer_pos(&x, &y)) { + for (it = stacking_list; it != NULL; it = it->next) { + if (WINDOW_IS_CLIENT(it->data)) { + ObClient *c = WINDOW_AS_CLIENT(it->data); + if (c->frame->visible && + RECT_CONTAINS(c->frame->area, x, y)) { + ret = c; + break; + } + } + } + } + return ret; +} + +gboolean client_has_group_siblings(ObClient *self) +{ + return self->group && self->group->members->next; +}