X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=112b8d8b900623ed1dcf53772a1d801e9909a446;hb=9f22554b6a1e7113b4ff86061327d9d0b0d87760;hp=f41c7558140062b53dee565ebaffb9b69a1283a1;hpb=65d50861ada11f5409680de285f461f16e78c090;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index f41c7558..112b8d8b 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -65,6 +65,7 @@ typedef struct GList *client_list = NULL; static GSList *client_destructors = NULL; +static GSList *client_hide_notifies = NULL; static void client_get_all(ObClient *self, gboolean real); static void client_toggle_border(ObClient *self, gboolean show); @@ -91,6 +92,7 @@ static void client_present(ObClient *self, gboolean here, gboolean raise); static GSList *client_search_all_top_parents_internal(ObClient *self, gboolean bylayer, ObStackingLayer layer); +static void client_call_callbacks(ObClient *self, GSList *list); void client_startup(gboolean reconfig) { @@ -104,6 +106,16 @@ void client_shutdown(gboolean reconfig) if (reconfig) return; } +static void client_call_callbacks(ObClient *self, GSList *list) +{ + GSList *it; + + for (it = list; it; it = g_slist_next(it)) { + ClientCallback *d = it->data; + d->func(self, d->data); + } +} + void client_add_destructor(ObClientCallback func, gpointer data) { ClientCallback *d = g_new(ClientCallback, 1); @@ -126,6 +138,29 @@ void client_remove_destructor(ObClientCallback func) } } +void client_add_hide_notify(ObClientCallback func, gpointer data) +{ + ClientCallback *d = g_new(ClientCallback, 1); + d->func = func; + d->data = data; + client_hide_notifies = g_slist_prepend(client_destructors, d); +} + +void client_remove_hide_notify(ObClientCallback func) +{ + GSList *it; + + for (it = client_hide_notifies; it; it = g_slist_next(it)) { + ClientCallback *d = it->data; + if (d->func == func) { + g_free(d); + client_hide_notifies = + g_slist_delete_link(client_hide_notifies, it); + break; + } + } +} + void client_set_list() { Window *windows, *win_it; @@ -282,30 +317,13 @@ void client_manage(Window window) /* non-zero defaults */ self->wmstate = WithdrawnState; /* make sure it gets updated first time */ + self->gravity = NorthWestGravity; self->desktop = screen_num_desktops; /* always an invalid value */ self->user_time = focus_client ? focus_client->user_time : CurrentTime; + /* get all the stuff off the window */ client_get_all(self, TRUE); - /* per-app settings override stuff, and return the settings for other - uses too */ - settings = client_get_settings_state(self); - /* the session should get the last say */ - client_restore_session_state(self); - client_setup_decor_and_functions(self); - - { - Time t = sn_app_started(self->startup_id, self->class); - if (t) self->user_time = t; - } - - /* update the focus lists, do this before the call to change_state or - it can end up in the list twice! */ - focus_order_add_new(self); - - /* remove the client's border (and adjust re gravity) */ - client_toggle_border(self, FALSE); - /* specify that if we exit, the window should not be destroyed and should be reparented back to root automatically */ XChangeSaveSet(ob_display, window, SetModeInsert); @@ -315,11 +333,33 @@ void client_manage(Window window) frame_grab_client(self->frame); + /* we've grabbed everything and set everything that we need to at mapping + time now */ + grab_server(FALSE); + + /* per-app settings override stuff from client_get_all, and return the + settings for other uses too */ + settings = client_get_settings_state(self); + /* the session should get the last say thought */ + client_restore_session_state(self); + + /* now we have all of the window's information so we can set this up */ + client_setup_decor_and_functions(self); + + /* remove the client's border (and adjust re gravity) */ + client_toggle_border(self, FALSE); + + { + Time t = sn_app_started(self->startup_id, self->class); + if (t) self->user_time = t; + } + /* do this after we have a frame.. it uses the frame to help determine the WM_STATE to apply. */ client_change_state(self); - grab_server(FALSE); + /* add ourselves to the focus order */ + focus_order_add_new(self); /* do this to add ourselves to the stacking list in a non-intrusive way */ client_calc_layer(self); @@ -453,16 +493,14 @@ void client_manage(Window window) stacking_raise(CLIENT_AS_WINDOW(self)); } + /* adjust the frame to the client's size before showing the window */ + frame_adjust_area(self->frame, FALSE, TRUE, FALSE); + /* this has to happen before we try focus the window, but we want it to happen after the client's stacking has been determined or it looks bad */ client_show(self); - /* use client_focus instead of client_activate cuz client_activate does - stuff like switch desktops etc and I'm not interested in all that when - a window maps since its not based on an action from the user like - clicking a window to activate it. so keep the new window out of the way - but do focus it. */ if (activate) { gboolean stacked = client_restore_session_stacking(self); client_present(self, FALSE, !stacked); @@ -562,10 +600,7 @@ void client_unmanage(ObClient *self) if (STRUT_EXISTS(self->strut)) screen_update_areas(); - for (it = client_destructors; it; it = g_slist_next(it)) { - ClientCallback *d = it->data; - d->func(self, d->data); - } + client_call_callbacks(self, client_destructors); /* tell our parent(s) that we're gone */ if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */ @@ -594,7 +629,12 @@ void client_unmanage(ObClient *self) /* restore the window's original geometry so it is not lost */ { - Rect a = self->area; + Rect a; + + /* give the client its border back */ + client_toggle_border(self, TRUE); + + a = self->area; if (self->fullscreen) a = self->pre_fullscreen_area; @@ -609,9 +649,6 @@ void client_unmanage(ObClient *self) } } - /* give the client its border back */ - client_toggle_border(self, TRUE); - self->fullscreen = self->max_horz = self->max_vert = FALSE; self->decorations = 0; /* unmanaged windows have no decor */ @@ -1005,6 +1042,9 @@ static void client_get_all(ObClient *self, gboolean real) if (!real) return; + /* get this early so we have it for debugging */ + client_update_title(self); + client_update_protocols(self); client_update_wmhints(self); @@ -1030,7 +1070,6 @@ static void client_get_all(ObClient *self, gboolean real) #endif client_get_colormap(self); - client_update_title(self); client_update_strut(self); client_update_icons(self); client_update_user_time_window(self); @@ -1220,19 +1259,34 @@ static void client_update_transient_tree(ObClient *self, GSList *it, *next; ObClient *c; + /* * * + Group transient windows are not allowed to have other group + transient windows as their children. + * * */ + + /* No change has occured */ if (oldgroup == newgroup && oldparent == newparent) return; /** Remove the client from the transient tree wherever it has changed **/ /* If the window is becoming a direct transient for a window in its group - then that window can't be a child of this window anymore */ + then any group transients which were our children and are now becoming + our parents need to stop being our children. + + Group transients can't be children of group transients already, but + we could have any number of direct parents above up, any of which could + be transient for the group, and we need to remove it from our children. + */ if (oldparent != newparent && newparent != NULL && newparent != OB_TRAN_GROUP && - newparent->transient_for == OB_TRAN_GROUP && newgroup != NULL && newgroup == oldgroup) { - self->transients = g_slist_remove(self->transients, newparent); + ObClient *look = newparent; + do { + self->transients = g_slist_remove(self->transients, look); + look = look->transient_for; + } while (look != NULL && look != OB_TRAN_GROUP); } @@ -1304,7 +1358,9 @@ static void client_update_transient_tree(ObClient *self, WARNING: Cyclical transient-ness is possible. For e.g. if: A is transient for the group - B is a member of the group and transient for A + B is transient for A + C is transient for B + A can't be transient for C or we have a cycle */ if (oldgroup != newgroup && newgroup != NULL && newparent != OB_TRAN_GROUP) @@ -1616,7 +1672,7 @@ void client_setup_decor_and_functions(ObClient *self) if (!(self->functions & OB_CLIENT_FUNC_ICONIFY)) self->decorations &= ~OB_FRAME_DECOR_ICONIFY; if (!(self->functions & OB_CLIENT_FUNC_RESIZE)) - self->decorations &= ~OB_FRAME_DECOR_GRIPS; + self->decorations &= ~(OB_FRAME_DECOR_GRIPS | OB_FRAME_DECOR_HANDLE); /* can't maximize without moving/resizing */ if (!((self->functions & OB_CLIENT_FUNC_MAXIMIZE) && @@ -2359,6 +2415,8 @@ void client_hide(ObClient *self) { if (!client_should_show(self)) { frame_hide(self->frame); + + client_call_callbacks(self, client_hide_notifies); } /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it @@ -2376,6 +2434,8 @@ void client_showhide(ObClient *self) } else { frame_hide(self->frame); + + client_call_callbacks(self, client_hide_notifies); } /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it @@ -2657,12 +2717,11 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h, - gboolean user, gboolean final, - gboolean force_reply) + gboolean user, gboolean final) { - gint oldw, oldh, oldrx, oldry; + gint oldw, oldh; gboolean send_resize_client; - gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE; + gboolean moved = FALSE, resized = FALSE; guint fdecor = self->frame->decorations; gboolean fhorz = self->frame->max_horz; gint logicalw, logicalh; @@ -2702,17 +2761,7 @@ void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h, if (moved || resized) frame_adjust_area(self->frame, moved, resized, FALSE); - /* find the client's position relative to the root window */ - oldrx = self->root_pos.x; - oldry = self->root_pos.y; - rootmoved = (oldrx != (signed)(self->frame->area.x + - self->frame->size.left - - self->border_width) || - oldry != (signed)(self->frame->area.y + - self->frame->size.top - - self->border_width)); - - if (force_reply || ((!user || (user && final)) && rootmoved)) + if ((!user || (user && final)) && !resized) { XEvent event; @@ -2727,6 +2776,9 @@ void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h, event.xconfigure.event = self->window; event.xconfigure.window = self->window; + ob_debug("Sending ConfigureNotify to %s for %d,%d %dx%d\n", + self->title, self->root_pos.x, self->root_pos.y, w, h); + /* root window real coords */ event.xconfigure.x = self->root_pos.x; event.xconfigure.y = self->root_pos.y; @@ -3476,9 +3528,7 @@ gboolean client_focused(ObClient *self) static ObClientIcon* client_icon_recursive(ObClient *self, gint w, gint h) { guint i; - /* si is the smallest image >= req */ - /* li is the largest image < req */ - gulong size, smallest = 0xffffffff, largest = 0, si = 0, li = 0; + gulong min_diff, min_i; if (!self->nicons) { ObClientIcon *parent = NULL; @@ -3501,20 +3551,23 @@ static ObClientIcon* client_icon_recursive(ObClient *self, gint w, gint h) 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)) { - smallest = size; - si = i; - } - if (size > largest && size <= (unsigned)(w * h)) { - largest = size; - li = i; + /* some kind of crappy approximation to find the icon closest in size to + what we requested, but icons are generally all the same ratio as + eachother so it's good enough. */ + + min_diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h); + min_i = 0; + + for (i = 1; i < self->nicons; ++i) { + gulong diff; + + diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h); + if (diff < min_diff) { + min_diff = diff; + min_i = i; } } - if (largest == 0) /* didnt find one smaller than the requested size */ - return &self->icons[si]; - return &self->icons[li]; + return &self->icons[min_i]; } const ObClientIcon* client_icon(ObClient *self, gint w, gint h) @@ -3688,7 +3741,7 @@ ObClient *client_search_transient(ObClient *self, ObClient *search) continue; \ if(cur->iconic) \ continue; \ - if(cur->layer < c->layer && !config_resist_layers_below) \ + if(cur->layer == c->layer) \ continue; #define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \