X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=43a2f551f8252d2f5aec58faa2570690ecd4527c;hb=91a1b089097cb3ba66f779df80fa7a51490aa785;hp=2f8f58a90328b3d84e42365d57eb1fb06a4e555e;hpb=f9f32d9fbaae9ca415603bb61b36393994afbd16;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 2f8f58a9..43a2f551 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -24,6 +24,7 @@ #include "xerror.h" #include "screen.h" #include "moveresize.h" +#include "ping.h" #include "place.h" #include "prop.h" #include "extensions.h" @@ -79,6 +80,10 @@ static void client_get_state(ObClient *self); static void client_get_shaped(ObClient *self); static void client_get_mwm_hints(ObClient *self); static void client_get_colormap(ObClient *self); +static void client_set_desktop_recursive(ObClient *self, + guint target, + gboolean donthide, + gboolean dontraise); static void client_change_allowed_actions(ObClient *self); static void client_change_state(ObClient *self); static void client_change_wm_state(ObClient *self); @@ -196,6 +201,9 @@ void client_manage_all(void) } } + /* manage windows in reverse order from how they were originally mapped. + this is an attempt to manage children windows before their parents, so + that when the parent is mapped, it can find the child */ for (i = 0; i < nchild; ++i) { if (children[i] == None) continue; @@ -284,6 +292,11 @@ void client_manage(Window window) ob_debug("Window type: %d\n", self->type); ob_debug("Window group: 0x%x\n", self->group?self->group->leader:0); + /* now we have all of the window's information so we can set this up. + do this before creating the frame, so it can tell that we are still + mapping and doesn't go applying things right away */ + client_setup_decor_and_functions(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); @@ -304,11 +317,8 @@ void client_manage(Window window) /* the session should get the last say though */ 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, FALSE); - /* tell startup notification that this app started */ - launch_time = sn_app_started(self->startup_id, self->class); + launch_time = sn_app_started(self->startup_id, self->class, self->name); /* do this after we have a frame.. it uses the frame to help determine the WM_STATE to apply. */ @@ -604,7 +614,10 @@ void client_manage(Window window) /* watch for when the application stops responding. only do this for normal windows, i.e. windows which have titlebars and close buttons - and things like that */ + and things like that. + we don't need to stop pinging on unmanage, because it will be handled + automatically by the destroy callback! + */ if (self->ping && client_normal(self)) ping_start(self, client_ping_event); @@ -689,10 +702,6 @@ void client_unmanage(ObClient *self) /* remove the window from our save set */ XChangeSaveSet(ob_display, self->window, SetModeDelete); - /* stop pinging the window */ - if (self->ping && client_normal(self)) - ping_stop(self); - /* update the focus lists */ focus_order_remove(self); if (client_focused(self)) { @@ -794,6 +803,7 @@ void client_unmanage(ObClient *self) g_free(self->icons[j].data); if (self->nicons > 0) g_free(self->icons); + g_free(self->startup_id); g_free(self->wm_command); g_free(self->title); g_free(self->icon_title); @@ -983,6 +993,7 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, gint fw, fh; Rect desired; guint i; + gboolean found_mon; RECT_SET(desired, *x, *y, w, h); frame_rect_to_frame(self->frame, &desired); @@ -1032,18 +1043,26 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, rudeb = TRUE; } + /* we iterate through every monitor that the window is at least partially + on, to make sure it is obeying the rules on them all + + if the window does not appear on any monitors, then use the first one + */ + found_mon = FALSE; for (i = 0; i < screen_num_monitors; ++i) { Rect *a; if (!screen_physical_area_monitor_contains(i, &desired)) { - if (i < screen_num_monitors - 1) + if (i < screen_num_monitors - 1 || found_mon) continue; /* the window is not inside any monitor! so just use the first one */ a = screen_area(self->desktop, 0, NULL); - } else + } else { + found_mon = TRUE; a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &desired); + } /* This makes sure windows aren't entirely outside of the screen so you can't see them at all. @@ -1551,7 +1570,7 @@ void client_update_sync_request_counter(ObClient *self) } #endif -void client_get_colormap(ObClient *self) +static void client_get_colormap(ObClient *self) { XWindowAttributes wa; @@ -1826,16 +1845,16 @@ static void client_change_allowed_actions(ObClient *self) PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num); - /* make sure the window isn't breaking any rules now */ + /* make sure the window isn't breaking any rules now + + don't check ICONIFY here. just cuz a window can't iconify doesnt mean + it can't be iconified with its parent + */ if (!(self->functions & OB_CLIENT_FUNC_SHADE) && self->shaded) { 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, FALSE); - else self->iconic = FALSE; - } if (!(self->functions & OB_CLIENT_FUNC_FULLSCREEN) && self->fullscreen) { if (self->frame) client_fullscreen(self, FALSE); else self->fullscreen = FALSE; @@ -2062,11 +2081,17 @@ void client_update_strut(ObClient *self) } } +/* Avoid storing icons above this size if possible */ +#define AVOID_ABOVE 64 + void client_update_icons(ObClient *self) { guint num; guint32 *data; guint w, h, i, j; + guint num_seen; /* number of icons present */ + guint num_small_seen; /* number of icons small enough present */ + guint smallest, smallest_area; for (i = 0; i < self->nicons; ++i) g_free(self->icons[i].data); @@ -2077,25 +2102,54 @@ void client_update_icons(ObClient *self) 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; - } + num_seen = num_small_seen = 0; + smallest = smallest_area = 0; + if (num > 2) + while (i < num) { + w = data[i++]; + h = data[i++]; + i += w * h; + /* watch for it being too small for the specified size, or for + zero sized icons. */ + if (i > num || w == 0 || h == 0) break; + + if (!smallest_area || w*h < smallest_area) { + smallest = num_seen; + smallest_area = w*h; + } + ++num_seen; + if (w <= AVOID_ABOVE && h <= AVOID_ABOVE) + ++num_small_seen; + } + if (num_small_seen > 0) + self->nicons = num_small_seen; + else if (num_seen) + self->nicons = 1; self->icons = g_new(ObClientIcon, self->nicons); /* store the icons */ i = 0; - for (j = 0; j < self->nicons; ++j) { + for (j = 0; j < self->nicons;) { guint x, y, t; w = self->icons[j].width = data[i++]; h = self->icons[j].height = data[i++]; - if (w*h == 0) continue; + /* if there are some icons smaller than the threshold, we're + skipping all the ones above */ + if (num_small_seen > 0) { + if (w > AVOID_ABOVE || h > AVOID_ABOVE) { + i += w*h; + continue; + } + } + /* if there were no icons smaller than the threshold, then we are + only taking the smallest available one we saw */ + else if (j != smallest) { + i += w*h; + continue; + } self->icons[j].data = g_new(RrPixel32, w * h); for (x = 0, y = 0, t = 0; t < w * h; ++t, ++x, ++i) { @@ -2110,6 +2164,8 @@ void client_update_icons(ObClient *self) (((data[i] >> 0) & 0xff) << RrDefaultBlueOffset); } g_assert(i <= num); + + ++j; } g_free(data); @@ -2171,12 +2227,13 @@ void client_update_icon_geometry(ObClient *self) RECT_SET(self->icon_geometry, 0, 0, 0, 0); - if (PROP_GETA32(self->window, net_wm_icon_geometry, cardinal, &data, &num) - && num == 4) + if (PROP_GETA32(self->window, net_wm_icon_geometry, cardinal, &data, &num)) { - /* don't let them set it with an area < 0 */ - RECT_SET(self->icon_geometry, data[0], data[1], - MAX(data[2],0), MAX(data[3],0)); + if (num == 4) + /* don't let them set it with an area < 0 */ + RECT_SET(self->icon_geometry, data[0], data[1], + MAX(data[2],0), MAX(data[3],0)); + g_free(data); } } @@ -2414,7 +2471,15 @@ static ObStackingLayer calc_layer(ObClient *self) (self->decorations == 0 && !(self->max_horz && self->max_vert) && RECT_EQUAL(self->area, *monitor))) && - (client_focused(self) || client_search_focus_tree(self))) + /* you are fullscreen while you or your children are focused.. */ + (client_focused(self) || client_search_focus_tree(self) || + /* you can be fullscreen if you're on another desktop */ + (self->desktop != screen_desktop && + self->desktop != DESKTOP_ALL) || + /* and you can also be fullscreen if the focused client is on + another monitor, or nothing else is focused */ + (!focus_client || + client_monitor(focus_client) != client_monitor(self)))) l = OB_STACKING_LAYER_FULLSCREEN; else if (self->above) l = OB_STACKING_LAYER_ABOVE; else if (self->below) l = OB_STACKING_LAYER_BELOW; @@ -2440,23 +2505,54 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig, stacking_add_nonintrusive(CLIENT_AS_WINDOW(self)); } + /* we've been restacked */ + self->visited = TRUE; + for (it = self->transients; it; it = g_slist_next(it)) client_calc_layer_recursive(it->data, orig, self->layer); } +static void client_calc_layer_internal(ObClient *self) +{ + GSList *sit; + + /* transients take on the layer of their parents */ + sit = client_search_all_top_parents(self); + + for (; sit; sit = g_slist_next(sit)) + client_calc_layer_recursive(sit->data, self, 0); +} + void client_calc_layer(ObClient *self) { - ObClient *orig; - GSList *it; + GList *it; - orig = self; + /* skip over stuff above fullscreen layer */ + for (it = stacking_list; it; it = g_list_next(it)) + if (window_layer(it->data) <= OB_STACKING_LAYER_FULLSCREEN) break; - /* transients take on the layer of their parents */ - it = client_search_all_top_parents(self); + /* find the windows in the fullscreen layer, and mark them not-visited */ + for (; it; it = g_list_next(it)) { + if (window_layer(it->data) < OB_STACKING_LAYER_FULLSCREEN) break; + else if (WINDOW_IS_CLIENT(it->data)) + WINDOW_AS_CLIENT(it->data)->visited = FALSE; + } + + client_calc_layer_internal(self); - for (; it; it = g_slist_next(it)) - client_calc_layer_recursive(it->data, orig, 0); + /* skip over stuff above fullscreen layer */ + for (it = stacking_list; it; it = g_list_next(it)) + if (window_layer(it->data) <= OB_STACKING_LAYER_FULLSCREEN) break; + + /* now recalc any windows in the fullscreen layer which have not + had their layer recalced already */ + for (; it; it = g_list_next(it)) { + if (window_layer(it->data) < OB_STACKING_LAYER_FULLSCREEN) break; + else if (WINDOW_IS_CLIENT(it->data) && + !WINDOW_AS_CLIENT(it->data)->visited) + client_calc_layer_internal(it->data); + } } gboolean client_should_show(ObClient *self) @@ -2476,6 +2572,10 @@ gboolean client_show(ObClient *self) gboolean show = FALSE; if (client_should_show(self)) { + /* replay pending pointer event before showing the window, in case it + should be going to something under the window */ + mouse_replay_pointer(); + frame_show(self->frame); show = TRUE; @@ -2517,6 +2617,10 @@ gboolean client_hide(ObClient *self) so trying to ignore them is futile in case 3 anyways */ + /* replay pending pointer event before hiding the window, in case it + should be going to the window */ + mouse_replay_pointer(); + frame_hide(self->frame); hide = TRUE; @@ -2874,6 +2978,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gboolean user, gboolean final, gboolean force_reply) { + Rect oldframe; gint oldw, oldh; gboolean send_resize_client; gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE; @@ -2896,6 +3001,7 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, oldw = self->area.width; oldh = self->area.height; + oldframe = self->frame->area; RECT_SET(self->area, x, y, w, h); /* for app-requested resizes, always resize if 'resized' is true. @@ -2930,6 +3036,10 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, if (!user) ignore_start = event_start_ignore_all_enters(); + /* replay pending pointer event before move the window, in case it + would change what window gets the event */ + mouse_replay_pointer(); + frame_adjust_area(self->frame, fmoved, fresized, FALSE); if (!user) @@ -3000,6 +3110,14 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, } XFlush(ob_display); + + /* if it moved between monitors, then this can affect the stacking + layer of this window or others - for fullscreen windows */ + if (screen_find_monitor(&self->frame->area) != + screen_find_monitor(&oldframe)) + { + client_calc_layer(self); + } } void client_fullscreen(ObClient *self, gboolean fs) @@ -3230,11 +3348,11 @@ void client_close(ObClient *self) XKillClient(ob_display, self->window); else if (self->not_responding) client_kill(self); - else { + else + /* request the client to close with WM_DELETE_WINDOW */ PROP_MSG_TO(self->window, self->window, wm_protocols, prop_atoms.wm_delete_window, event_curtime, 0, 0, 0, NoEventMask); - } } void client_kill(ObClient *self) @@ -3276,10 +3394,10 @@ void client_hilite(ObClient *self, gboolean hilite) } } -void client_set_desktop_recursive(ObClient *self, - guint target, - gboolean donthide, - gboolean dontraise) +static void client_set_desktop_recursive(ObClient *self, + guint target, + gboolean donthide, + gboolean dontraise) { guint old; GSList *it;