X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=fab5328d2b712a40fd85354974d5f40db920c5e8;hb=055aa5cd7411c4563956e376523219afc6198ce1;hp=b3ea0082e3248aea83e1005f59a982f572133cff;hpb=b9d47c49d6e4272e1cda7cec2c58e925cb610776;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index b3ea0082..fab5328d 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -1,19 +1,19 @@ /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- - client.c for the Openbox window manager - Copyright (c) 2003 Ben Jansens +client.c for the Openbox window manager +Copyright (c) 2003 Ben Jansens - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. - See the COPYING file for a copy of the GNU General Public License. +See the COPYING file for a copy of the GNU General Public License. */ #include "client.h" @@ -117,51 +117,51 @@ void client_set_list() /* create an array of the window ids */ if (size > 0) { - windows = g_new(Window, size); - win_it = windows; - for (it = client_list; it != NULL; it = it->next, ++win_it) - *win_it = ((ObClient*)it->data)->window; + windows = g_new(Window, size); + win_it = windows; + for (it = client_list; it != NULL; it = it->next, ++win_it) + *win_it = ((ObClient*)it->data)->window; } else - windows = NULL; + windows = NULL; PROP_SETA32(RootWindow(ob_display, ob_screen), net_client_list, window, (guint32*)windows, size); if (windows) - g_free(windows); + g_free(windows); stacking_set_list(); } /* -void client_foreach_transient(ObClient *self, ObClientForeachFunc func, void *data) -{ - GSList *it; - - for (it = self->transients; it; it = it->next) { - if (!func(it->data, data)) return; - client_foreach_transient(it->data, func, data); - } -} - -void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, void *data) -{ - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) { - if (!func(self->transient_for, data)) return; - client_foreach_ancestor(self->transient_for, func, data); - } else { - GSList *it; - - for (it = self->group->members; it; it = it->next) - if (it->data != self && - !((ObClient*)it->data)->transient_for) { - if (!func(it->data, data)) return; - client_foreach_ancestor(it->data, func, data); - } - } - } -} + void client_foreach_transient(ObClient *self, ObClientForeachFunc func, void *data) + { + GSList *it; + + for (it = self->transients; it; it = it->next) { + if (!func(it->data, data)) return; + client_foreach_transient(it->data, func, data); + } + } + + void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, void *data) + { + if (self->transient_for) { + if (self->transient_for != OB_TRAN_GROUP) { + if (!func(self->transient_for, data)) return; + client_foreach_ancestor(self->transient_for, func, data); + } else { + GSList *it; + + for (it = self->group->members; it; it = it->next) + if (it->data != self && + !((ObClient*)it->data)->transient_for) { + if (!func(it->data, data)) return; + client_foreach_ancestor(it->data, func, data); + } + } + } + } */ void client_manage_all() @@ -176,29 +176,29 @@ void client_manage_all() /* remove all icon windows from the list */ for (i = 0; i < nchild; i++) { - if (children[i] == None) continue; - wmhints = XGetWMHints(ob_display, children[i]); - if (wmhints) { - if ((wmhints->flags & IconWindowHint) && - (wmhints->icon_window != children[i])) - for (j = 0; j < nchild; j++) - if (children[j] == wmhints->icon_window) { - children[j] = None; - break; - } - XFree(wmhints); - } + if (children[i] == None) continue; + wmhints = XGetWMHints(ob_display, children[i]); + if (wmhints) { + if ((wmhints->flags & IconWindowHint) && + (wmhints->icon_window != children[i])) + for (j = 0; j < nchild; j++) + if (children[j] == wmhints->icon_window) { + children[j] = None; + break; + } + XFree(wmhints); + } } for (i = 0; i < nchild; ++i) { - if (children[i] == None) - continue; - if (XGetWindowAttributes(ob_display, children[i], &attrib)) { - if (attrib.override_redirect) continue; + if (children[i] == None) + continue; + if (XGetWindowAttributes(ob_display, children[i], &attrib)) { + if (attrib.override_redirect) continue; - if (attrib.map_state != IsUnmapped) - client_manage(children[i]); - } + if (attrib.map_state != IsUnmapped) + client_manage(children[i]); + } } XFree(children); } @@ -217,30 +217,30 @@ void client_manage(Window window) /* check if it has already been unmapped by the time we started mapping the grab does a sync so we don't have to here */ if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) || - XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e)) { - XPutBackEvent(ob_display, &e); + XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e)) { + XPutBackEvent(ob_display, &e); grab_server(FALSE); - return; /* don't manage it */ + return; /* don't manage it */ } /* make sure it isn't an override-redirect window */ if (!XGetWindowAttributes(ob_display, window, &attrib) || - attrib.override_redirect) { + attrib.override_redirect) { grab_server(FALSE); - return; /* don't manage it */ + return; /* don't manage it */ } /* is the window a docking app */ if ((wmhint = XGetWMHints(ob_display, window))) { - if ((wmhint->flags & StateHint) && - wmhint->initial_state == WithdrawnState) { + if ((wmhint->flags & StateHint) && + wmhint->initial_state == WithdrawnState) { dock_add(window, wmhint); grab_server(FALSE); - XFree(wmhint); - return; - } - XFree(wmhint); + XFree(wmhint); + return; + } + XFree(wmhint); } ob_debug("Managing window: %lx\n", window); @@ -249,7 +249,7 @@ void client_manage(Window window) attrib_set.event_mask = CLIENT_EVENTMASK; attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK; XChangeWindowAttributes(ob_display, window, - CWEventMask|CWDontPropagate, &attrib_set); + CWEventMask|CWDontPropagate, &attrib_set); /* create the ObClient struct, and populate it from the hints on the @@ -346,7 +346,11 @@ void client_manage(Window window) client_find_onscreen(self, &x, &y, self->frame->area.width, self->frame->area.height, - client_normal(self)); + /* non-normal clients has less rules, and + windows that are being restored from a session + do also. we can assume you want it back where + you saved it */ + client_normal(self) && !self->session); if (x != ox || y != oy) client_move(self, x, y); @@ -359,7 +363,17 @@ 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); + /* since focus can change the stacking orders, if we focus the window + then the standard raise it gets is not enough, we need to queue one + for after the focus change takes place */ + client_raise(self); + } /* client_activate does this but we aret using it so we have to do it here as well */ @@ -385,7 +399,7 @@ void client_manage(Window window) void client_unmanage_all() { while (client_list != NULL) - client_unmanage(client_list->data); + client_unmanage(client_list->data); } void client_unmanage(ObClient *self) @@ -473,16 +487,16 @@ void client_unmanage(ObClient *self) self->frame = NULL; if (ob_state() != OB_STATE_EXITING) { - /* these values should not be persisted across a window - unmapping/mapping */ - PROP_ERASE(self->window, net_wm_desktop); - PROP_ERASE(self->window, net_wm_state); - PROP_ERASE(self->window, wm_state); + /* these values should not be persisted across a window + unmapping/mapping */ + PROP_ERASE(self->window, net_wm_desktop); + PROP_ERASE(self->window, net_wm_state); + PROP_ERASE(self->window, wm_state); } else { - /* if we're left in an iconic state, the client wont be mapped. this is - bad, since we will no longer be managing the window on restart */ - if (self->iconic) - XMapWindow(ob_display, self->window); + /* if we're left in an iconic state, the client wont be mapped. this is + bad, since we will no longer be managing the window on restart */ + if (self->iconic) + XMapWindow(ob_display, self->window); } @@ -523,12 +537,14 @@ static void client_restore_session_state(ObClient *self) self->session = it->data; - RECT_SET(self->area, self->session->x, self->session->y, - self->session->w, self->session->h); + RECT_SET_POINT(self->area, self->session->x, self->session->y); self->positioned = TRUE; - if (self->session->w > 0 && self->session->h > 0) - XResizeWindow(ob_display, self->window, - self->session->w, self->session->h); + if (self->session->w > 0) + self->area.width = self->session->w; + if (self->session->h > 0) + self->area.height = self->session->h; + XResizeWindow(ob_display, self->window, + self->area.width, self->area.height); self->desktop = (self->session->desktop == DESKTOP_ALL ? self->session->desktop : @@ -640,55 +656,55 @@ static void client_toggle_border(ObClient *self, gboolean show) case NorthWestGravity: case WestGravity: case SouthWestGravity: - break; + break; case NorthEastGravity: case EastGravity: case SouthEastGravity: - if (show) x -= self->border_width * 2; - else x += self->border_width * 2; - break; + 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; + if (show) x -= self->border_width; + else x += self->border_width; + break; } switch(self->gravity) { default: case NorthWestGravity: case NorthGravity: case NorthEastGravity: - break; + break; case SouthWestGravity: case SouthGravity: case SouthEastGravity: - if (show) y -= self->border_width * 2; - else y += self->border_width * 2; - break; + 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; + 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); + XSetWindowBorderWidth(ob_display, self->window, self->border_width); - /* move the client so it is back it the right spot _with_ its - border! */ - if (x != oldx || y != oldy) - XMoveWindow(ob_display, self->window, x, y); + /* move the client so it is back it the right spot _with_ its + border! */ + if (x != oldx || y != oldy) + XMoveWindow(ob_display, self->window, x, y); } else - XSetWindowBorderWidth(ob_display, self->window, 0); + XSetWindowBorderWidth(ob_display, self->window, 0); } @@ -705,11 +721,23 @@ static void client_get_all(ObClient *self) client_get_mwm_hints(self); client_get_type(self);/* this can change the mwmhints for special cases */ + { + /* a couple type-based defaults for new windows */ + + /* this makes sure that these windows appear on all desktops */ + if (self->type == OB_CLIENT_TYPE_DESKTOP) + self->desktop = DESKTOP_ALL; + + /* dock windows default to ABOVE */ + if (self->type == OB_CLIENT_TYPE_DOCK && !self->below) + self->above = TRUE; + } + client_update_protocols(self); client_get_gravity(self); /* get the attribute gravity */ client_update_normal_hints(self); /* this may override the attribute - gravity */ + gravity */ /* got the type, the mwmhints, the protocols, and the normal hints (min/max sizes), so we're ready to set up the decorations/functions */ @@ -747,15 +775,15 @@ static void client_get_desktop(ObClient *self) guint32 d = screen_num_desktops; /* an always-invalid value */ if (PROP_GET32(self->window, net_wm_desktop, cardinal, &d)) { - if (d >= screen_num_desktops && d != DESKTOP_ALL) - self->desktop = screen_num_desktops - 1; + if (d >= screen_num_desktops && d != DESKTOP_ALL) + self->desktop = screen_num_desktops - 1; else self->desktop = d; } else { gboolean trdesk = FALSE; - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) { + if (self->transient_for) { + if (self->transient_for != OB_TRAN_GROUP) { self->desktop = self->transient_for->desktop; trdesk = TRUE; } else { @@ -769,17 +797,17 @@ static void client_get_desktop(ObClient *self) break; } } - } - if (!trdesk) { - /* try get from the startup-notification protocol */ - if (sn_get_desktop(self->startup_id, &self->desktop)) { - if (self->desktop >= screen_num_desktops && - self->desktop != DESKTOP_ALL) - self->desktop = screen_num_desktops - 1; - } else - /* defaults to the current desktop */ - self->desktop = screen_desktop; - } + } + if (!trdesk) { + /* try get from the startup-notification protocol */ + if (sn_get_desktop(self->startup_id, &self->desktop)) { + if (self->desktop >= screen_num_desktops && + self->desktop != DESKTOP_ALL) + self->desktop = screen_num_desktops - 1; + } else + /* defaults to the current desktop */ + self->desktop = screen_desktop; + } } if (self->desktop != d) { /* set the desktop hint, to make sure that it always exists */ @@ -828,16 +856,16 @@ static void client_get_shaped(ObClient *self) self->shaped = FALSE; #ifdef SHAPE if (extensions_shape) { - int foo; - guint ufoo; - int s; + int foo; + guint ufoo; + int s; - XShapeSelectInput(ob_display, self->window, ShapeNotifyMask); + XShapeSelectInput(ob_display, self->window, ShapeNotifyMask); - XShapeQueryExtents(ob_display, self->window, &s, &foo, - &foo, &ufoo, &ufoo, &foo, &foo, &foo, &ufoo, - &ufoo); - self->shaped = (s != 0); + XShapeQueryExtents(ob_display, self->window, &s, &foo, + &foo, &ufoo, &ufoo, &foo, &foo, &foo, &ufoo, + &ufoo); + self->shaped = (s != 0); } #endif } @@ -876,25 +904,25 @@ void client_update_transient_for(ObClient *self) /* if anything has changed... */ if (target != self->transient_for) { - if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */ + if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */ GSList *it; - /* remove from old parents */ + /* remove from old parents */ for (it = self->group->members; it; it = g_slist_next(it)) { ObClient *c = it->data; if (c != self && !c->transient_for) c->transients = g_slist_remove(c->transients, self); } } else if (self->transient_for != NULL) { /* transient of window */ - /* remove from old parent */ - self->transient_for->transients = + /* remove from old parent */ + self->transient_for->transients = g_slist_remove(self->transient_for->transients, self); } - self->transient_for = target; - if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */ + self->transient_for = target; + if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */ GSList *it; - /* add to new parents */ + /* add to new parents */ for (it = self->group->members; it; it = g_slist_next(it)) { ObClient *c = it->data; if (c != self && !c->transient_for) @@ -913,8 +941,8 @@ void client_update_transient_for(ObClient *self) } } } else if (self->transient_for != NULL) { /* transient of window */ - /* add to new parent */ - self->transient_for->transients = + /* add to new parent */ + self->transient_for->transients = g_slist_append(self->transient_for->transients, self); } } @@ -929,12 +957,12 @@ static void client_get_mwm_hints(ObClient *self) if (PROP_GETA32(self->window, motif_wm_hints, motif_wm_hints, &hints, &num)) { - if (num >= OB_MWM_ELEMENTS) { - self->mwmhints.flags = hints[0]; - self->mwmhints.functions = hints[1]; - self->mwmhints.decorations = hints[2]; - } - g_free(hints); + if (num >= OB_MWM_ELEMENTS) { + self->mwmhints.flags = hints[0]; + self->mwmhints.functions = hints[1]; + self->mwmhints.decorations = hints[2]; + } + g_free(hints); } } @@ -946,46 +974,46 @@ void client_get_type(ObClient *self) self->type = -1; if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) { - /* use the first value that we know about in the array */ - for (i = 0; i < num; ++i) { - if (val[i] == prop_atoms.net_wm_window_type_desktop) - self->type = OB_CLIENT_TYPE_DESKTOP; - else if (val[i] == prop_atoms.net_wm_window_type_dock) - self->type = OB_CLIENT_TYPE_DOCK; - else if (val[i] == prop_atoms.net_wm_window_type_toolbar) - self->type = OB_CLIENT_TYPE_TOOLBAR; - else if (val[i] == prop_atoms.net_wm_window_type_menu) - self->type = OB_CLIENT_TYPE_MENU; - else if (val[i] == prop_atoms.net_wm_window_type_utility) - self->type = OB_CLIENT_TYPE_UTILITY; - else if (val[i] == prop_atoms.net_wm_window_type_splash) - self->type = OB_CLIENT_TYPE_SPLASH; - else if (val[i] == prop_atoms.net_wm_window_type_dialog) - self->type = OB_CLIENT_TYPE_DIALOG; - else if (val[i] == prop_atoms.net_wm_window_type_normal) - self->type = OB_CLIENT_TYPE_NORMAL; - else if (val[i] == prop_atoms.kde_net_wm_window_type_override) { - /* prevent this window from getting any decor or - functionality */ - self->mwmhints.flags &= (OB_MWM_FLAG_FUNCTIONS | - OB_MWM_FLAG_DECORATIONS); - self->mwmhints.decorations = 0; - self->mwmhints.functions = 0; - } - if (self->type != (ObClientType) -1) - break; /* grab the first legit type */ - } - g_free(val); + /* use the first value that we know about in the array */ + for (i = 0; i < num; ++i) { + if (val[i] == prop_atoms.net_wm_window_type_desktop) + self->type = OB_CLIENT_TYPE_DESKTOP; + else if (val[i] == prop_atoms.net_wm_window_type_dock) + self->type = OB_CLIENT_TYPE_DOCK; + else if (val[i] == prop_atoms.net_wm_window_type_toolbar) + self->type = OB_CLIENT_TYPE_TOOLBAR; + else if (val[i] == prop_atoms.net_wm_window_type_menu) + self->type = OB_CLIENT_TYPE_MENU; + else if (val[i] == prop_atoms.net_wm_window_type_utility) + self->type = OB_CLIENT_TYPE_UTILITY; + else if (val[i] == prop_atoms.net_wm_window_type_splash) + self->type = OB_CLIENT_TYPE_SPLASH; + else if (val[i] == prop_atoms.net_wm_window_type_dialog) + self->type = OB_CLIENT_TYPE_DIALOG; + else if (val[i] == prop_atoms.net_wm_window_type_normal) + self->type = OB_CLIENT_TYPE_NORMAL; + else if (val[i] == prop_atoms.kde_net_wm_window_type_override) { + /* prevent this window from getting any decor or + functionality */ + self->mwmhints.flags &= (OB_MWM_FLAG_FUNCTIONS | + OB_MWM_FLAG_DECORATIONS); + self->mwmhints.decorations = 0; + self->mwmhints.functions = 0; + } + if (self->type != (ObClientType) -1) + break; /* grab the first legit type */ + } + g_free(val); } if (self->type == (ObClientType) -1) { - /*the window type hint was not set, which means we either classify - ourself as a normal window or a dialog, depending on if we are a - transient. */ - if (self->transient) - self->type = OB_CLIENT_TYPE_DIALOG; - else - self->type = OB_CLIENT_TYPE_NORMAL; + /*the window type hint was not set, which means we either classify + ourself as a normal window or a dialog, depending on if we are a + transient. */ + if (self->transient) + self->type = OB_CLIENT_TYPE_DIALOG; + else + self->type = OB_CLIENT_TYPE_NORMAL; } } @@ -998,16 +1026,16 @@ void client_update_protocols(ObClient *self) self->delete_window = FALSE; if (PROP_GETA32(self->window, wm_protocols, atom, &proto, &num_return)) { - for (i = 0; i < num_return; ++i) { - if (proto[i] == prop_atoms.wm_delete_window) { - /* this means we can request the window to close */ - self->delete_window = TRUE; - } else if (proto[i] == prop_atoms.wm_take_focus) - /* if this protocol is requested, then the window will be - notified whenever we want it to receive focus */ - self->focus_notify = TRUE; - } - g_free(proto); + for (i = 0; i < num_return; ++i) { + if (proto[i] == prop_atoms.wm_delete_window) { + /* this means we can request the window to close */ + self->delete_window = TRUE; + } else if (proto[i] == prop_atoms.wm_take_focus) + /* if this protocol is requested, then the window will be + notified whenever we want it to receive focus */ + self->focus_notify = TRUE; + } + g_free(proto); } } @@ -1039,38 +1067,38 @@ void client_update_normal_hints(ObClient *self) if (XGetWMNormalHints(ob_display, self->window, &size, &ret)) { self->positioned = !!(size.flags & (PPosition|USPosition)); - if (size.flags & PWinGravity) { - self->gravity = size.win_gravity; + 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 */ - self->area.x = self->frame->area.x; - self->area.y = self->frame->area.y; - frame_frame_gravity(self->frame, &self->area.x, &self->area.y); - } - } + /* 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 */ + self->area.x = self->frame->area.x; + self->area.y = self->frame->area.y; + frame_frame_gravity(self->frame, &self->area.x, &self->area.y); + } + } - if (size.flags & PAspect) { - if (size.min_aspect.y) - self->min_ratio = (float)size.min_aspect.x / size.min_aspect.y; - if (size.max_aspect.y) - self->max_ratio = (float)size.max_aspect.x / size.max_aspect.y; - } + if (size.flags & PAspect) { + if (size.min_aspect.y) + self->min_ratio = (float)size.min_aspect.x / size.min_aspect.y; + if (size.max_aspect.y) + self->max_ratio = (float)size.max_aspect.x / size.max_aspect.y; + } - if (size.flags & PMinSize) - SIZE_SET(self->min_size, size.min_width, size.min_height); + if (size.flags & PMinSize) + SIZE_SET(self->min_size, size.min_width, size.min_height); - if (size.flags & PMaxSize) - SIZE_SET(self->max_size, size.max_width, size.max_height); + if (size.flags & PMaxSize) + SIZE_SET(self->max_size, size.max_width, size.max_height); - if (size.flags & PBaseSize) - SIZE_SET(self->base_size, size.base_width, size.base_height); + if (size.flags & PBaseSize) + SIZE_SET(self->base_size, size.base_width, size.base_height); - if (size.flags & PResizeInc) - SIZE_SET(self->size_inc, size.width_inc, size.height_inc); + if (size.flags & PResizeInc) + SIZE_SET(self->size_inc, size.width_inc, size.height_inc); } } @@ -1086,17 +1114,15 @@ void client_setup_decor_and_functions(ObClient *self) OB_FRAME_DECOR_ALLDESKTOPS | OB_FRAME_DECOR_ICONIFY | OB_FRAME_DECOR_MAXIMIZE | - OB_FRAME_DECOR_SHADE); + OB_FRAME_DECOR_SHADE | + OB_FRAME_DECOR_CLOSE); self->functions = (OB_CLIENT_FUNC_RESIZE | OB_CLIENT_FUNC_MOVE | OB_CLIENT_FUNC_ICONIFY | OB_CLIENT_FUNC_MAXIMIZE | - OB_CLIENT_FUNC_SHADE); - if (self->delete_window) { - self->functions |= OB_CLIENT_FUNC_CLOSE; - self->decorations |= OB_FRAME_DECOR_CLOSE; - } + OB_CLIENT_FUNC_SHADE | + OB_CLIENT_FUNC_CLOSE); if (!(self->min_size.width < self->max_size.width || self->min_size.height < self->max_size.height)) @@ -1171,7 +1197,7 @@ void client_setup_decor_and_functions(ObClient *self) if (!((self->functions & OB_CLIENT_FUNC_MAXIMIZE) && (self->functions & OB_CLIENT_FUNC_MOVE) && (self->functions & OB_CLIENT_FUNC_RESIZE))) { - self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE; + self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE; self->decorations &= ~OB_FRAME_DECOR_MAXIMIZE; } @@ -1180,9 +1206,9 @@ 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 */ + everything (but doesnt give it a border if it doesnt have one) */ if (self->undecorated) - self->decorations = OB_FRAME_DECOR_BORDER; + self->decorations &= OB_FRAME_DECOR_BORDER; /* if we don't have a titlebar, then we cannot shade! */ if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR)) @@ -1201,13 +1227,6 @@ void client_setup_decor_and_functions(ObClient *self) if (self->frame) { /* adjust the client's decorations, etc. */ client_reconfigure(self); - } else { - /* this makes sure that these windows appear on all desktops */ - if (self->type == OB_CLIENT_TYPE_DESKTOP && - self->desktop != DESKTOP_ALL) - { - self->desktop = DESKTOP_ALL; - } } } @@ -1221,20 +1240,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); @@ -1242,21 +1261,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,19 +1298,19 @@ void client_update_wmhints(ObClient *self) self->can_focus = TRUE; if ((hints = XGetWMHints(ob_display, self->window)) != NULL) { - if (hints->flags & InputHint) - self->can_focus = hints->input; + if (hints->flags & InputHint) + self->can_focus = hints->input; - /* only do this when first managing the window *AND* when we aren't + /* only do this when first managing the window *AND* when we aren't starting up! */ - if (ob_state() != OB_STATE_STARTING && self->frame == NULL) + if (ob_state() != OB_STATE_STARTING && self->frame == NULL) if (hints->flags & StateHint) self->iconic = hints->initial_state == IconicState; - if (hints->flags & XUrgencyHint) - ur = TRUE; + if (hints->flags & XUrgencyHint) + ur = TRUE; - if (!(hints->flags & WindowGroupHint)) + if (!(hints->flags & WindowGroupHint)) hints->window_group = None; /* did the group state change? */ @@ -1370,9 +1389,9 @@ void client_update_title(ObClient *self) /* try netwm */ if (!PROP_GETS(self->window, net_wm_name, utf8, &data)) - /* try old x stuff */ - if (!PROP_GETS(self->window, wm_name, locale, &data)) - data = g_strdup("Unnamed Window"); + /* try old x stuff */ + if (!PROP_GETS(self->window, wm_name, locale, &data)) + data = g_strdup("Unnamed Window"); /* did the title change? then reset the title_count */ if (old_title && 0 != strncmp(old_title, data, strlen(data))) @@ -1406,7 +1425,7 @@ void client_update_title(ObClient *self) self->title = data; if (self->frame) - frame_adjust_title(self->frame); + frame_adjust_title(self->frame); g_free(old_title); @@ -1417,8 +1436,8 @@ void client_update_title(ObClient *self) read_title = TRUE; /* try netwm */ if (!PROP_GETS(self->window, net_wm_icon_name, utf8, &data)) - /* try old x stuff */ - if (!PROP_GETS(self->window, wm_icon_name, locale, &data)) { + /* try old x stuff */ + if (!PROP_GETS(self->window, wm_icon_name, locale, &data)) { data = g_strdup(self->title); read_title = FALSE; } @@ -1451,7 +1470,7 @@ void client_update_class(ObClient *self) if (PROP_GETSS(self->window, wm_class, locale, &data)) { if (data[0]) { - self->name = g_strdup(data[0]); + self->name = g_strdup(data[0]); if (data[1]) self->class = g_strdup(data[1]); } @@ -1459,7 +1478,7 @@ void client_update_class(ObClient *self) } if (PROP_GETS(self->window, wm_window_role, locale, &s)) - self->role = s; + self->role = s; if (self->name == NULL) self->name = g_strdup(""); if (self->class == NULL) self->class = g_strdup(""); @@ -1653,8 +1672,8 @@ ObClient *client_search_focus_tree(ObClient *self) ObClient *ret; for (it = self->transients; it != NULL; it = it->next) { - if (client_focused(it->data)) return it->data; - if ((ret = client_search_focus_tree(it->data))) return ret; + if (client_focused(it->data)) return it->data; + if ((ret = client_search_focus_tree(it->data))) return ret; } return NULL; } @@ -1676,14 +1695,14 @@ ObClient *client_search_focus_tree_full(ObClient *self) recursed = TRUE; } if (recursed) - return NULL; + return NULL; } } /* 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 self; return client_search_focus_tree(self); } @@ -1723,8 +1742,7 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig, l, raised ? raised : l != old); if (!raised && l != old) - if (orig->frame) { /* only restack if the original window is managed */ - /* XXX add_non_intrusive ever? */ + if (orig->frame) { /* only restack if the original window is managed */ stacking_remove(CLIENT_AS_WINDOW(self)); stacking_add(CLIENT_AS_WINDOW(self)); } @@ -1767,7 +1785,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) @@ -2058,7 +2076,7 @@ void client_fullscreen(ObClient *self, gboolean fs, gboolean savearea) int x, y, w, h; if (!(self->functions & OB_CLIENT_FUNC_FULLSCREEN) || /* can't */ - self->fullscreen == fs) return; /* already done */ + self->fullscreen == fs) return; /* already done */ self->fullscreen = fs; client_change_state(self); /* change the state hints on the client, @@ -2270,7 +2288,7 @@ void client_shade(ObClient *self, gboolean shade) { if ((!(self->functions & OB_CLIENT_FUNC_SHADE) && shade) || /* can't shade */ - self->shaded == shade) return; /* already done */ + self->shaded == shade) return; /* already done */ /* when we're iconic, don't change the wmstate */ if (!self->iconic) { @@ -2295,6 +2313,11 @@ void client_close(ObClient *self) if (!(self->functions & OB_CLIENT_FUNC_CLOSE)) return; + /* in the case that the client provides no means to requesting that it + close, we just kill it */ + if (!self->delete_window) + client_kill(self); + /* XXX: itd be cool to do timeouts and shit here for killing the client's process off @@ -2374,9 +2397,9 @@ ObClient *client_search_modal_child(ObClient *self) ObClient *ret; for (it = self->transients; it != NULL; it = it->next) { - ObClient *c = it->data; - if ((ret = client_search_modal_child(c))) return ret; - if (c->modal) return c; + ObClient *c = it->data; + if ((ret = client_search_modal_child(c))) return ret; + if (c->modal) return c; } return NULL; } @@ -2388,9 +2411,9 @@ gboolean client_validate(ObClient *self) XSync(ob_display, FALSE); /* get all events on the server */ if (XCheckTypedWindowEvent(ob_display, self->window, DestroyNotify, &e) || - XCheckTypedWindowEvent(ob_display, self->window, UnmapNotify, &e)) { - XPutBackEvent(ob_display, &e); - return FALSE; + XCheckTypedWindowEvent(ob_display, self->window, UnmapNotify, &e)) { + XPutBackEvent(ob_display, &e); + return FALSE; } return TRUE; @@ -2402,11 +2425,11 @@ void client_set_wm_state(ObClient *self, long state) switch (state) { case IconicState: - client_iconify(self, TRUE, TRUE); - break; + client_iconify(self, TRUE, TRUE); + break; case NormalState: - client_iconify(self, FALSE, TRUE); - break; + client_iconify(self, FALSE, TRUE); + break; } } @@ -2417,6 +2440,7 @@ void client_set_state(ObClient *self, Atom action, long data1, long data2) gboolean undecorated = self->undecorated; gboolean max_horz = self->max_horz; gboolean max_vert = self->max_vert; + gboolean modal = self->modal; int i; if (!(action == prop_atoms.net_wm_state_add || @@ -2433,7 +2457,7 @@ void client_set_state(ObClient *self, Atom action, long data1, long data2) /* 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 : + action = 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 : @@ -2469,8 +2493,7 @@ void client_set_state(ObClient *self, Atom action, long data1, long data2) if (action == prop_atoms.net_wm_state_add) { if (state == prop_atoms.net_wm_state_modal) { - /* XXX raise here or something? */ - self->modal = TRUE; + 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) { @@ -2493,7 +2516,7 @@ void client_set_state(ObClient *self, Atom action, long data1, long data2) } else { /* action == prop_atoms.net_wm_state_remove */ if (state == prop_atoms.net_wm_state_modal) { - self->modal = FALSE; + 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) { @@ -2540,6 +2563,12 @@ void client_set_state(ObClient *self, Atom action, long data1, long data2) client_shade(self, shaded); if (undecorated != self->undecorated) client_set_undecorated(self, undecorated); + if (modal != self->modal) { + self->modal = modal; + /* when a window changes modality, then its stacking order with its + transients needs to change */ + client_raise(self); + } client_calc_layer(self); client_change_state(self); /* change the hint to reflect these changes */ } @@ -2609,23 +2638,23 @@ gboolean client_focus(ObClient *self) Update: Changing this to RevertToNone fixed a bug with mozilla (bug #799. So now it is RevertToNone again. */ - XSetInputFocus(ob_display, self->window, RevertToNone, + XSetInputFocus(ob_display, self->window, RevertToNone, event_lasttime); } if (self->focus_notify) { - XEvent ce; - ce.xclient.type = ClientMessage; - ce.xclient.message_type = prop_atoms.wm_protocols; - ce.xclient.display = ob_display; - ce.xclient.window = self->window; - ce.xclient.format = 32; - ce.xclient.data.l[0] = prop_atoms.wm_take_focus; - ce.xclient.data.l[1] = event_lasttime; - ce.xclient.data.l[2] = 0l; - ce.xclient.data.l[3] = 0l; - ce.xclient.data.l[4] = 0l; - XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce); + XEvent ce; + ce.xclient.type = ClientMessage; + ce.xclient.message_type = prop_atoms.wm_protocols; + ce.xclient.display = ob_display; + ce.xclient.window = self->window; + ce.xclient.format = 32; + ce.xclient.data.l[0] = prop_atoms.wm_take_focus; + ce.xclient.data.l[1] = event_lasttime; + ce.xclient.data.l[2] = 0l; + ce.xclient.data.l[3] = 0l; + ce.xclient.data.l[4] = 0l; + XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce); } #ifdef DEBUG_FOCUS @@ -2784,7 +2813,7 @@ ObClient *client_find_directional(ObClient *c, ObDirection dir) continue; if(cur->iconic) continue; - if(client_focus_target(cur) == cur && + if(client_focus_target(cur) == cur && !(cur->can_focus || cur->focus_notify)) continue; @@ -2815,7 +2844,7 @@ ObClient *client_find_directional(ObClient *c, ObDirection dir) case OB_DIRECTION_SOUTHWEST: offset = (his_cx < 0) ? -his_cx : his_cx; distance = ((dir == OB_DIRECTION_NORTH || - dir == OB_DIRECTION_NORTHEAST) ? + dir == OB_DIRECTION_NORTHEAST) ? -his_cy : his_cy); break; case OB_DIRECTION_EAST: @@ -2824,7 +2853,7 @@ ObClient *client_find_directional(ObClient *c, ObDirection dir) case OB_DIRECTION_NORTHWEST: offset = (his_cy < 0) ? -his_cy : his_cy; distance = ((dir == OB_DIRECTION_WEST || - dir == OB_DIRECTION_NORTHWEST) ? + dir == OB_DIRECTION_NORTHWEST) ? -his_cx : his_cx); break; } @@ -2877,15 +2906,25 @@ void client_set_undecorated(ObClient *self, gboolean undecorated) guint client_monitor(ObClient *self) { guint i; + guint most = 0; + guint mostv = 0; for (i = 0; i < screen_num_monitors; ++i) { Rect *area = screen_physical_area_monitor(i); - if (RECT_INTERSECTS_RECT(*area, self->frame->area)) - break; + if (RECT_INTERSECTS_RECT(*area, self->frame->area)) { + Rect r; + guint v; + + RECT_SET_INTERSECTION(r, *area, self->frame->area); + v = r.width * r.height; + + if (v > mostv) { + mostv = v; + most = i; + } + } } - if (i == screen_num_monitors) i = 0; - g_assert(i < screen_num_monitors); - return i; + return most; } ObClient *client_search_top_transient(ObClient *self) @@ -3006,7 +3045,8 @@ int client_directional_edge_search(ObClient *c, ObDirection dir) my_edge_end = c->frame->area.x + c->frame->area.width; my_offset = c->frame->area.y; - dest = a->y; /* default: top of screen */ + /* default: top of screen */ + dest = a->y; for(it = g_list_first(client_list); it; it = it->next) { int his_edge_start, his_edge_end, his_offset; @@ -3045,8 +3085,9 @@ int client_directional_edge_search(ObClient *c, ObDirection dir) my_edge_start = c->frame->area.x; my_edge_end = c->frame->area.x + c->frame->area.width; my_offset = c->frame->area.y + c->frame->area.height; - - dest = a->y + a->height; /* default: bottom of screen */ + + /* default: bottom of screen */ + dest = a->y + a->height; for(it = g_list_first(client_list); it; it = it->next) { int his_edge_start, his_edge_end, his_offset; @@ -3087,7 +3128,8 @@ int client_directional_edge_search(ObClient *c, ObDirection dir) my_edge_end = c->frame->area.y + c->frame->area.height; my_offset = c->frame->area.x; - dest = a->x; /* default: leftmost egde of screen */ + /* default: leftmost egde of screen */ + dest = a->x; for(it = g_list_first(client_list); it; it = it->next) { int his_edge_start, his_edge_end, his_offset; @@ -3128,7 +3170,8 @@ int client_directional_edge_search(ObClient *c, ObDirection dir) my_edge_end = c->frame->area.y + c->frame->area.height; my_offset = c->frame->area.x + c->frame->area.width; - dest = a->x + a->width; /* default: rightmost edge of screen */ + /* default: rightmost edge of screen */ + dest = a->x + a->width; for(it = g_list_first(client_list); it; it = it->next) { int his_edge_start, his_edge_end, his_offset; @@ -3194,3 +3237,8 @@ ObClient* client_under_pointer() } return ret; } + +gboolean client_has_group_siblings(ObClient *self) +{ + return self->group && self->group->members->next; +}