X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=a51ecfd7c7ed54ce2ba0e094d394b9969cb6f885;hb=eb2a0feb0154e86a1c6c117fd0f6d1a18959b694;hp=569718c333287925aaf6dccf0637de378bc5e082;hpb=270a5b25df8db500f94a7c29430ebc224ddf18b2;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 569718c3..a51ecfd7 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -78,6 +78,7 @@ static void client_apply_startup_state(ObClient *self, gint x, gint y); static void client_restore_session_state(ObClient *self); static void client_restore_session_stacking(ObClient *self); static ObAppSettings *client_get_settings_state(ObClient *self); +static void client_unfocus(ObClient *self); void client_startup(gboolean reconfig) { @@ -219,13 +220,14 @@ void client_manage(Window window) grab_server(TRUE); - /* check if it has already been unmapped by the time we started mapping + /* 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); + ob_debug("Trying to manage unmapped window. Aborting that.\n"); grab_server(FALSE); return; /* don't manage it */ } @@ -267,8 +269,7 @@ void client_manage(Window window) self->window = window; /* non-zero defaults */ - self->title_count = 1; - self->wmstate = NormalState; + self->wmstate = WithdrawnState; /* make sure it gets updated first time */ self->layer = -1; self->desktop = screen_num_desktops; /* always an invalid value */ self->user_time = ~0; /* maximum value, always newer than the real time */ @@ -393,6 +394,8 @@ void client_manage(Window window) won't be all wacko!! also, this moves the window to the position where it has been placed */ + ob_debug("placing window 0x%x at %d, %d with size %d x %d\n", + self->window, newx, newy, self->area.width, self->area.height); client_apply_startup_state(self, newx, newy); keyboard_grab_for_client(self, TRUE); @@ -416,7 +419,7 @@ void client_manage(Window window) /* Don't steal focus from globally active clients. I stole this idea from KWin. It seems nice. */ - if (!focus_client->can_focus && focus_client->focus_notify) + if (!(focus_client->can_focus || focus_client->focus_notify)) activate = FALSE; } @@ -498,29 +501,44 @@ void client_unmanage(ObClient *self) g_assert(self != NULL); - keyboard_grab_for_client(self, FALSE); - mouse_grab_for_client(self, FALSE); + /* update the focus lists */ + focus_order_remove(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)); + /* 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); + } /* potentially fix focusLast */ if (config_focus_last) grab_pointer(TRUE, OB_CURSOR_NONE); + frame_hide(self->frame); + XFlush(ob_display); + + keyboard_grab_for_client(self, FALSE); + mouse_grab_for_client(self, FALSE); + /* remove the window from our save set */ XChangeSaveSet(ob_display, self->window, SetModeDelete); /* we dont want events no more */ XSelectInput(ob_display, self->window, NoEventMask); - frame_hide(self->frame); - client_list = g_list_remove(client_list, self); stacking_remove(self); g_hash_table_remove(window_map, &self->window); - /* update the focus lists */ - focus_order_remove(self); - - /* once the client is out of the list, update the struts to remove it's + /* once the client is out of the list, update the struts to remove its influence */ if (STRUT_EXISTS(self->strut)) screen_update_areas(); @@ -529,20 +547,6 @@ void client_unmanage(ObClient *self) 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 */ @@ -639,7 +643,7 @@ static ObAppSettings *client_get_settings_state(ObClient *self) GSList *it; for (it = config_per_app_settings; it; it = g_slist_next(it)) { - ObAppSettings *app; + ObAppSettings *app = it->data; if ((app->name && !app->class && !strcmp(app->name, self->name)) || (app->class && !app->name && !strcmp(app->class, self->class)) @@ -1642,108 +1646,44 @@ void client_update_wmhints(ObClient *self) void client_update_title(ObClient *self) { - GList *it; - guint32 nums; - guint i; gchar *data = NULL; - gboolean read_title; - gchar *old_title; - old_title = self->title; + g_free(self->title); /* 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) || PROP_GETS(self->window, wm_name, utf8, &data))) { - // http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html if (self->transient) { + /* + GNOME alert windows are not given titles: + http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html + */ data = g_strdup(""); - goto no_number; } else data = g_strdup("Unnamed Window"); } } - if (config_title_number) { - - /* did the title change? then reset the title_count */ - if (old_title && 0 != strncmp(old_title, data, strlen(data))) - self->title_count = 1; - - /* look for duplicates and append a number */ - nums = 0; - for (it = client_list; it; it = g_list_next(it)) - if (it->data != self) { - ObClient *c = it->data; - - if (c->title_count == 1) { - if (!strcmp(c->title, data)) - nums |= 1 << c->title_count; - } else { - size_t len; - gchar *end; - - /* find the beginning of our " - [%u]", this relies on - that syntax being used */ - end = strrchr(c->title, '-') - 1; - len = end - c->title; - if (!strncmp(c->title, data, len)) - nums |= 1 << c->title_count; - } - } - /* find first free number */ - for (i = 1; i <= 32; ++i) - if (!(nums & (1 << i))) { - if (self->title_count == 1 || i == 1) - self->title_count = i; - break; - } - /* dont display the number for the first window */ - if (self->title_count > 1) { - gchar *ndata; - ndata = g_strdup_printf("%s - [%u]", data, self->title_count); - g_free(data); - data = ndata; - } - } else - self->title_count = 1; - -no_number: PROP_SETS(self->window, net_wm_visible_name, data); self->title = data; if (self->frame) frame_adjust_title(self->frame); - g_free(old_title); - /* update the icon title */ data = NULL; g_free(self->icon_title); - 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) - || PROP_GETS(self->window, wm_icon_name, utf8, &data))) { + if (!(PROP_GETS(self->window, wm_icon_name, locale, &data) || + PROP_GETS(self->window, wm_icon_name, utf8, &data))) data = g_strdup(self->title); - read_title = FALSE; - } - - /* append the title count, dont display the number for the first window. - * We don't need to check for config_title_number here since title_count - * is not set above 1 then. */ - if (read_title && self->title_count > 1) { - gchar *newdata; - newdata = g_strdup_printf("%s - [%u]", data, self->title_count); - g_free(data); - data = newdata; - } PROP_SETS(self->window, net_wm_visible_icon_name, data); - self->icon_title = data; } @@ -1925,7 +1865,10 @@ void client_update_user_time(ObClient *self, gboolean new_event) if (new_event) client_last_user_time = time; - /*ob_debug("window 0x%x user time %u\n", self->window, time);*/ + /* + ob_debug("window %s user time %u\n", self->title, time); + ob_debug("last user time %u\n", client_last_user_time); + */ } } @@ -1956,8 +1899,6 @@ static void client_change_state(ObClient *self) gulong netstate[11]; guint num; - client_change_wm_state(self); - num = 0; if (self->modal) netstate[num++] = prop_atoms.net_wm_state_modal; @@ -2118,12 +2059,16 @@ void client_showhide(ObClient *self) { if (client_should_show(self)) { - if (!self->frame->visible) - frame_show(self->frame); + frame_show(self->frame); } - else if (self->frame->visible) + else { frame_hide(self->frame); + /* Fall back focus since we're disappearing */ + if (focus_client == self) + client_unfocus(self); + } + /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it needs to be in IconicState. This includes when it is on another desktop! @@ -2203,17 +2148,12 @@ static void client_apply_startup_state(ObClient *self, gint x, gint y) */ } -void client_configure_full(ObClient *self, ObCorner anchor, - gint x, gint y, gint w, gint h, - gboolean user, gboolean final, - gboolean force_reply) +void client_try_configure(ObClient *self, ObCorner anchor, + gint *x, gint *y, gint *w, gint *h, + gint *logicalw, gint *logicalh, + gboolean user) { - gint oldw, oldh; - gboolean send_resize_client; - gboolean moved = FALSE, resized = FALSE; - guint fdecor = self->frame->decorations; - gboolean fhorz = self->frame->max_horz; - Rect desired_area = {x, y, w, h}; + Rect desired_area = {*x, *y, *w, *h}; /* make the frame recalculate its dimentions n shit without changing anything visible for real, this way the constraints below can work with @@ -2221,7 +2161,7 @@ void client_configure_full(ObClient *self, ObCorner anchor, frame_adjust_area(self->frame, TRUE, TRUE, TRUE); /* gets the frame's position */ - frame_client_gravity(self->frame, &x, &y); + frame_client_gravity(self->frame, x, y); /* these positions are frame positions, not client positions */ @@ -2233,10 +2173,10 @@ void client_configure_full(ObClient *self, ObCorner anchor, i = screen_find_monitor(&desired_area); a = screen_physical_area_monitor(i); - x = a->x; - y = a->y; - w = a->width; - h = a->height; + *x = a->x; + *y = a->y; + *w = a->width; + *h = a->height; user = FALSE; /* ignore that increment etc shit when in fullscreen */ } else { @@ -2248,31 +2188,31 @@ void client_configure_full(ObClient *self, ObCorner anchor, /* set the size and position if maximized */ if (self->max_horz) { - x = a->x; - w = a->width - self->frame->size.left - self->frame->size.right; + *x = a->x; + *w = a->width - self->frame->size.left - self->frame->size.right; } if (self->max_vert) { - y = a->y; - h = a->height - self->frame->size.top - self->frame->size.bottom; + *y = a->y; + *h = a->height - self->frame->size.top - self->frame->size.bottom; } } /* gets the client's position */ - frame_frame_gravity(self->frame, &x, &y); + frame_frame_gravity(self->frame, x, y); /* these override the above states! if you cant move you can't move! */ if (user) { if (!(self->functions & OB_CLIENT_FUNC_MOVE)) { - x = self->area.x; - y = self->area.y; + *x = self->area.x; + *y = self->area.y; } if (!(self->functions & OB_CLIENT_FUNC_RESIZE)) { - w = self->area.width; - h = self->area.height; + *w = self->area.width; + *h = self->area.height; } } - if (!(w == self->area.width && h == self->area.height)) { + if (!(*w == self->area.width && *h == self->area.height)) { gint basew, baseh, minw, minh; /* base size is substituted with min size if not specified */ @@ -2296,83 +2236,105 @@ void client_configure_full(ObClient *self, ObCorner anchor, sizes */ /* smaller than min size or bigger than max size? */ - if (w > self->max_size.width) w = self->max_size.width; - if (w < minw) w = minw; - if (h > self->max_size.height) h = self->max_size.height; - if (h < minh) h = minh; + if (*w > self->max_size.width) *w = self->max_size.width; + if (*w < minw) *w = minw; + if (*h > self->max_size.height) *h = self->max_size.height; + if (*h < minh) *h = minh; - w -= basew; - h -= baseh; + *w -= basew; + *h -= baseh; /* keep to the increments */ - w /= self->size_inc.width; - h /= self->size_inc.height; + *w /= self->size_inc.width; + *h /= self->size_inc.height; /* you cannot resize to nothing */ - if (basew + w < 1) w = 1 - basew; - if (baseh + h < 1) h = 1 - baseh; + if (basew + *w < 1) *w = 1 - basew; + if (baseh + *h < 1) *h = 1 - baseh; - /* store the logical size */ - SIZE_SET(self->logical_size, - self->size_inc.width > 1 ? w : w + basew, - self->size_inc.height > 1 ? h : h + baseh); + /* save the logical size */ + *logicalw = self->size_inc.width > 1 ? *w : *w + basew; + *logicalh = self->size_inc.height > 1 ? *h : *h + baseh; - w *= self->size_inc.width; - h *= self->size_inc.height; + *w *= self->size_inc.width; + *h *= self->size_inc.height; - w += basew; - h += baseh; + *w += basew; + *h += baseh; /* adjust the height to match the width for the aspect ratios. for this, min size is not substituted for base size ever. */ - w -= self->base_size.width; - h -= self->base_size.height; + *w -= self->base_size.width; + *h -= self->base_size.height; if (!self->fullscreen) { if (self->min_ratio) - if (h * self->min_ratio > w) { - h = (gint)(w / self->min_ratio); + if (*h * self->min_ratio > *w) { + *h = (gint)(*w / self->min_ratio); /* you cannot resize to nothing */ - if (h < 1) { - h = 1; - w = (gint)(h * self->min_ratio); + if (*h < 1) { + *h = 1; + *w = (gint)(*h * self->min_ratio); } } if (self->max_ratio) - if (h * self->max_ratio < w) { - h = (gint)(w / self->max_ratio); + if (*h * self->max_ratio < *w) { + *h = (gint)(*w / self->max_ratio); /* you cannot resize to nothing */ - if (h < 1) { - h = 1; - w = (gint)(h * self->min_ratio); + if (*h < 1) { + *h = 1; + *w = (gint)(*h * self->min_ratio); } } } - w += self->base_size.width; - h += self->base_size.height; + *w += self->base_size.width; + *h += self->base_size.height; } - g_assert(w > 0); - g_assert(h > 0); + g_assert(*w > 0); + g_assert(*h > 0); switch (anchor) { case OB_CORNER_TOPLEFT: break; case OB_CORNER_TOPRIGHT: - x -= w - self->area.width; + *x -= *w - self->area.width; break; case OB_CORNER_BOTTOMLEFT: - y -= h - self->area.height; + *y -= *h - self->area.height; break; case OB_CORNER_BOTTOMRIGHT: - x -= w - self->area.width; - y -= h - self->area.height; + *x -= *w - self->area.width; + *y -= *h - self->area.height; break; } +} + + +void client_configure_full(ObClient *self, ObCorner anchor, + gint x, gint y, gint w, gint h, + gboolean user, gboolean final, + gboolean force_reply) +{ + gint oldw, oldh; + gboolean send_resize_client; + gboolean moved = FALSE, resized = FALSE; + guint fdecor = self->frame->decorations; + gboolean fhorz = self->frame->max_horz; + gint logicalw, logicalh; + + /* find the new x, y, width, and height (and logical size) */ + client_try_configure(self, anchor, &x, &y, &w, &h, + &logicalw, &logicalh, user); + /* set the logical size if things changed */ + if (!(w == self->area.width && h == self->area.height)) + SIZE_SET(self->logical_size, logicalw, logicalh); + + /* figure out if we moved or resized or what */ moved = x != self->area.x || y != self->area.y; resized = w != self->area.width || h != self->area.height; @@ -2496,22 +2458,20 @@ static void client_iconify_recursive(ObClient *self, ob_debug("%sconifying window: 0x%lx\n", (iconic ? "I" : "Uni"), self->window); - self->iconic = iconic; - if (iconic) { if (self->functions & OB_CLIENT_FUNC_ICONIFY) { + self->iconic = iconic; + /* update the focus lists.. iconic windows go to the bottom of the list, put the new iconic window at the 'top of the bottom'. */ focus_order_to_top(self); - /* Fall back focus since we're disappearing */ - if (focus_client == self) - client_unfocus(self); - changed = TRUE; } } else { + self->iconic = iconic; + if (curdesk) client_set_desktop(self, screen_desktop, FALSE); @@ -2632,6 +2592,7 @@ void client_shade(ObClient *self, gboolean shade) self->shaded = shade; client_change_state(self); + client_change_wm_state(self); /* the window is being hidden/shown */ /* resize the frame to just the titlebar */ frame_adjust_area(self->frame, FALSE, FALSE, FALSE); } @@ -3015,14 +2976,7 @@ gboolean client_focus(ObClient *self) ob_debug("Focusing client \"%s\" at time %u\n", self->title, event_curtime); 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 - are left. (I hate X. I hate focus events.) - - 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, RevertToPointerRoot, event_curtime); } @@ -3057,17 +3011,17 @@ gboolean client_focus(ObClient *self) /* Used when the current client is closed or otherwise hidden, focus_last will then prevent focus from going to the mouse pointer */ -void client_unfocus(ObClient *self) +static void client_unfocus(ObClient *self) { if (focus_client == self) { #ifdef DEBUG_FOCUS ob_debug("client_unfocus for %lx\n", self->window); #endif - focus_fallback(OB_FOCUS_FALLBACK_CLOSED); + focus_fallback(FALSE); } } -void client_activate(ObClient *self, gboolean here, gboolean user, Time time) +void client_activate(ObClient *self, gboolean here, gboolean user) { /* XXX do some stuff here if user is false to determine if we really want to activate it or not (a parent or group member is currently @@ -3075,9 +3029,9 @@ void client_activate(ObClient *self, gboolean here, gboolean user, Time time) */ ob_debug("Want to activate window 0x%x with time %u (last time %u), " "source=%s\n", - self->window, time, client_last_user_time, + self->window, event_curtime, client_last_user_time, (user ? "user" : "application")); - if (!user && time && time < client_last_user_time) + if (!user && event_curtime && event_curtime < client_last_user_time) client_hilite(self, TRUE); else { if (client_normal(self) && screen_showing_desktop)