X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=e3a602d5abf7394dd32359a0286bad190ceb9262;hb=8ab1e9537e5aebfe48d826cbf266cf8d582d9d65;hp=c6945d231c89216bbf8ff2ae74b29504d59e180a;hpb=8f2e3f5fe16aeb0324aa5ee2b2c30a83ec724ad0;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index c6945d23..e3a602d5 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -88,7 +88,8 @@ static void client_update_transient_tree(ObClient *self, gboolean oldgtran, gboolean newgtran, ObClient* oldparent, ObClient *newparent); -static void client_present(ObClient *self, gboolean here, gboolean raise); +static void client_present(ObClient *self, gboolean here, gboolean raise, + gboolean unshade); static GSList *client_search_all_top_parents_internal(ObClient *self, gboolean bylayer, ObStackingLayer layer); @@ -394,25 +395,30 @@ void client_manage(Window window) */ if (ob_state() == OB_STATE_RUNNING && (transient || - (!(self->sized & USSize) && + (!(self->sized & USSize || self->positioned & USPosition) && client_normal(self) && !self->session))) { - /* make a copy to modify */ - Rect a = *screen_area_monitor(self->desktop, client_monitor(self)); + Rect placer; + + RECT_SET(placer, placex, placey, placew, placeh); + frame_rect_to_frame(self->frame, &placer); + + Rect *a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &placer); /* shrink by the frame's area */ - a.width -= self->frame->size.left + self->frame->size.right; - a.height -= self->frame->size.top + self->frame->size.bottom; + a->width -= self->frame->size.left + self->frame->size.right; + a->height -= self->frame->size.top + self->frame->size.bottom; /* fit the window inside the area */ - if (placew > a.width || self->area.height > a.height) { - placew = MIN(self->area.width, a.width); - placeh = MIN(self->area.height, a.height); + if (placew > a->width || self->area.height > a->height) { + placew = MIN(self->area.width, a->width); + placeh = MIN(self->area.height, a->height); ob_debug("setting window size to %dx%d\n", self->area.width, self->area.height); } + g_free(a); } @@ -539,7 +545,7 @@ void client_manage(Window window) if (activate) { gboolean stacked = client_restore_session_stacking(self); - client_present(self, FALSE, !stacked); + client_present(self, FALSE, !stacked, TRUE); } /* add to client list/map */ @@ -917,47 +923,24 @@ void client_move_onscreen(ObClient *self, gboolean rude) gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, gboolean rude) { - Rect *mon_a, *all_a; gint ox = *x, oy = *y; gboolean rudel = rude, ruder = rude, rudet = rude, rudeb = rude; gint fw, fh; Rect desired; + guint i; RECT_SET(desired, *x, *y, w, h); - all_a = screen_area(self->desktop); - mon_a = screen_area_monitor(self->desktop, screen_find_monitor(&desired)); + frame_rect_to_frame(self->frame, &desired); /* get where the frame would be */ - frame_client_gravity(self->frame, x, y, w, h); + frame_client_gravity(self->frame, x, y); /* get the requested size of the window with decorations */ fw = self->frame->size.left + w + self->frame->size.right; fh = self->frame->size.top + h + self->frame->size.bottom; - /* This makes sure windows aren't entirely outside of the screen so you - can't see them at all. - It makes sure 10% of the window is on the screen at least. At don't let - it move itself off the top of the screen, which would hide the titlebar - on you. (The user can still do this if they want too, it's only limiting - the application. - - XXX watch for xinerama dead areas... - */ - if (client_normal(self)) { - if (!self->strut.right && *x + fw/10 >= all_a->x + all_a->width - 1) - *x = all_a->x + all_a->width - fw/10; - if (!self->strut.bottom && *y + fh/10 >= all_a->y + all_a->height - 1) - *y = all_a->y + all_a->height - fh/10; - if (!self->strut.left && *x + fw*9/10 - 1 < all_a->x) - *x = all_a->x - fw*9/10; - if (!self->strut.top && *y + fh*9/10 - 1 < all_a->y) - *y = all_a->y - fw*9/10; - } - - /* If rudeness wasn't requested, then figure out of the client is currently - entirely on the screen. If it is, and the position isn't changing by - request, and it is enlarging, then be rude even though it wasn't - requested */ + /* If rudeness wasn't requested, then still be rude in a given direction + if the client is not moving, only resizing in that direction */ if (!rude) { Point oldtl, oldtr, oldbl, oldbr; Point newtl, newtr, newbl, newbr; @@ -994,22 +977,51 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, rudeb = TRUE; } - /* This here doesn't let windows even a pixel outside the struts/screen. - * When called from client_manage, programs placing themselves are - * forced completely onscreen, while things like - * xterm -geometry resolution-width/2 will work fine. Trying to - * place it completely offscreen will be handled in the above code. - * Sorry for this confused comment, i am tired. */ - if (rudel && !self->strut.left && *x < mon_a->x) *x = mon_a->x; - if (ruder && !self->strut.right && *x + fw > mon_a->x + mon_a->width) - *x = mon_a->x + MAX(0, mon_a->width - fw); + for (i = 0; i < screen_num_monitors; ++i) { + Rect *a; + + if (!screen_physical_area_monitor_contains(i, &desired)) + continue; + + a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &desired); - if (rudet && !self->strut.top && *y < mon_a->y) *y = mon_a->y; - if (rudeb && !self->strut.bottom && *y + fh > mon_a->y + mon_a->height) - *y = mon_a->y + MAX(0, mon_a->height - fh); + /* This makes sure windows aren't entirely outside of the screen so you + can't see them at all. + It makes sure 10% of the window is on the screen at least. At don't + let it move itself off the top of the screen, which would hide the + titlebar on you. (The user can still do this if they want too, it's + only limiting the application. + */ + if (client_normal(self)) { + if (!self->strut.right && *x + fw/10 >= a->x + a->width - 1) + *x = a->x + a->width - fw/10; + if (!self->strut.bottom && *y + fh/10 >= a->y + a->height - 1) + *y = a->y + a->height - fh/10; + if (!self->strut.left && *x + fw*9/10 - 1 < a->x) + *x = a->x - fw*9/10; + if (!self->strut.top && *y + fh*9/10 - 1 < a->y) + *y = a->y - fw*9/10; + } + + /* This here doesn't let windows even a pixel outside the + struts/screen. When called from client_manage, programs placing + themselves are forced completely onscreen, while things like + xterm -geometry resolution-width/2 will work fine. Trying to + place it completely offscreen will be handled in the above code. + Sorry for this confused comment, i am tired. */ + if (rudel && !self->strut.left && *x < a->x) *x = a->x; + if (ruder && !self->strut.right && *x + fw > a->x + a->width) + *x = a->x + MAX(0, a->width - fw); + + if (rudet && !self->strut.top && *y < a->y) *y = a->y; + if (rudeb && !self->strut.bottom && *y + fh > a->y + a->height) + *y = a->y + MAX(0, a->height - fh); + + g_free(a); + } /* get where the client should be */ - frame_frame_gravity(self->frame, x, y, w, h); + frame_frame_gravity(self->frame, x, y); return ox != *x || oy != *y; } @@ -1738,7 +1750,8 @@ void client_setup_decor_and_functions(ObClient *self, gboolean reconfig) client_change_allowed_actions(self); if (reconfig) - client_reconfigure(self); + /* force reconfigure to make sure decorations are updated */ + client_reconfigure(self, TRUE); } static void client_change_allowed_actions(ObClient *self) @@ -1796,13 +1809,6 @@ static void client_change_allowed_actions(ObClient *self) } } -void client_reconfigure(ObClient *self) -{ - client_configure(self, self->area.x, self->area.y, - self->area.width, self->area.height, - FALSE, TRUE); -} - void client_update_wmhints(ObClient *self) { XWMHints *hints; @@ -1968,12 +1974,12 @@ void client_update_strut(ObClient *self) if (!got && PROP_GETA32(self->window, net_wm_strut, cardinal, &data, &num)) { if (num == 4) { - const Rect *a; + Rect *a; got = TRUE; /* use the screen's width/height */ - a = screen_physical_area(); + a = screen_physical_area_all_monitors(); STRUT_PARTIAL_SET(strut, data[0], data[2], data[1], data[3], @@ -1981,6 +1987,7 @@ void client_update_strut(ObClient *self) a->x, a->x + a->width - 1, a->y, a->y + a->height - 1, a->x, a->x + a->width - 1); + g_free(a); } g_free(data); } @@ -2078,8 +2085,11 @@ void client_update_icons(ObClient *self) /* set the default icon onto the window in theory, this could be a race, but if a window doesn't set an icon or removes it entirely, it's not very likely it is going to set one - right away afterwards */ - if (self->nicons == 0) { + right away afterwards + + if it has parents, then one of them will have an icon already + */ + if (self->nicons == 0 && !self->parents) { RrPixel32 *icon = ob_rr_theme->def_win_icon; gulong *data; @@ -2381,6 +2391,9 @@ gboolean client_has_parent(ObClient *self) static ObStackingLayer calc_layer(ObClient *self) { ObStackingLayer l; + Rect *monitor; + + monitor = screen_physical_area_monitor(client_monitor(self)); if (self->type == OB_CLIENT_TYPE_DESKTOP) l = OB_STACKING_LAYER_DESKTOP; @@ -2394,15 +2407,15 @@ static ObStackingLayer calc_layer(ObClient *self) */ (self->decorations == 0 && !(self->max_horz && self->max_vert) && - RECT_EQUAL(self->area, - *screen_physical_area_monitor - (client_monitor(self))))) && + RECT_EQUAL(self->area, *monitor))) && (client_focused(self) || client_search_focus_tree(self))) l = OB_STACKING_LAYER_FULLSCREEN; else if (self->above) l = OB_STACKING_LAYER_ABOVE; else if (self->below) l = OB_STACKING_LAYER_BELOW; else l = OB_STACKING_LAYER_NORMAL; + g_free(monitor); + return l; } @@ -2603,7 +2616,7 @@ static void client_apply_startup_state(ObClient *self, /* if the window hasn't been configured yet, then do so now */ if (!fullscreen && !max_vert && !max_horz) { self->area = oldarea; - client_configure(self, x, y, w, h, FALSE, TRUE); + client_configure(self, x, y, w, h, FALSE, TRUE, FALSE); } /* set the desktop hint, to make sure that it always exists */ @@ -2680,7 +2693,8 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, gint *logicalw, gint *logicalh, gboolean user) { - Rect desired_area = {*x, *y, *w, *h}; + Rect desired = {*x, *y, *w, *h}; + frame_rect_to_frame(self->frame, &desired); /* make the frame recalculate its dimentions n shit without changing anything visible for real, this way the constraints below can work with @@ -2688,7 +2702,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, frame_adjust_area(self->frame, FALSE, TRUE, TRUE); /* gets the frame's position */ - frame_client_gravity(self->frame, x, y, *w, *h); + frame_client_gravity(self->frame, x, y); /* these positions are frame positions, not client positions */ @@ -2697,7 +2711,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, Rect *a; guint i; - i = screen_find_monitor(&desired_area); + i = screen_find_monitor(&desired); a = screen_physical_area_monitor(i); *x = a->x; @@ -2707,12 +2721,16 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, user = FALSE; /* ignore if the client can't be moved/resized when it is fullscreening */ + + g_free(a); } else if (self->max_horz || self->max_vert) { Rect *a; guint i; - i = screen_find_monitor(&desired_area); - a = screen_area_monitor(self->desktop, i); + /* use all possible struts when maximizing to the full screen */ + i = screen_find_monitor(&desired); + a = screen_area(self->desktop, i, + (self->max_horz && self->max_vert ? NULL : &desired)); /* set the size and position if maximized */ if (self->max_horz) { @@ -2726,15 +2744,18 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, user = FALSE; /* ignore if the client can't be moved/resized when it is maximizing */ + + g_free(a); } /* gets the client's position */ - frame_frame_gravity(self->frame, x, y, *w, *h); + frame_frame_gravity(self->frame, x, y); /* work within the prefered sizes given by the window */ if (!(*w == self->area.width && *h == self->area.height)) { gint basew, baseh, minw, minh; - gint incw, inch, minratio, maxratio; + gint incw, inch; + gfloat minratio, maxratio; incw = self->fullscreen || self->max_horz ? 1 : self->size_inc.width; inch = self->fullscreen || self->max_vert ? 1 : self->size_inc.height; @@ -2838,11 +2859,11 @@ 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 user, gboolean final, gboolean force_reply) { gint oldw, oldh; gboolean send_resize_client; - gboolean moved = FALSE, resized = FALSE; + gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE; gboolean fmoved, fresized; guint fdecor = self->frame->decorations; gboolean fhorz = self->frame->max_horz; @@ -2891,34 +2912,49 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, } /* adjust the frame */ - if (fmoved || fresized) + if (fmoved || fresized) { + gulong ignore_start; + if (!user) + ignore_start = event_start_ignore_all_enters(); + frame_adjust_area(self->frame, fmoved, fresized, FALSE); + if (!user) + event_end_ignore_all_enters(ignore_start); + } + + if (!user || final) { + gint oldrx = self->root_pos.x; + gint oldry = self->root_pos.y; + /* we have reset the client to 0 border width, so don't include + it in these coords */ + POINT_SET(self->root_pos, + self->frame->area.x + self->frame->size.left - + self->border_width, + self->frame->area.y + self->frame->size.top - + self->border_width); + if (self->root_pos.x != oldrx || self->root_pos.y != oldry) + rootmoved = TRUE; + } + /* This is kinda tricky and should not be changed.. let me explain! When user = FALSE, then the request is coming from the application itself, and we are more strict about when to send a synthetic ConfigureNotify. We strictly follow the rules of the ICCCM sec 4.1.5 - in this case. + in this case (if force_reply is true) When user = TRUE, then the request is coming from "us", like when we - maximize a window or sometihng. In this case we are more lenient. We + maximize a window or something. In this case we are more lenient. We used to follow the same rules as above, but _Java_ Swing can't handle this. So just to appease Swing, when user = TRUE, we always send a synthetic ConfigureNotify to give the window its root coordinates. */ - if ((!user && !resized) || (user && final)) + if ((!user && !resized && (rootmoved || force_reply)) || + (user && final && rootmoved)) { XEvent event; - /* we have reset the client to 0 border width, so don't include - it in these coords */ - POINT_SET(self->root_pos, - self->frame->area.x + self->frame->size.left - - self->border_width, - self->frame->area.y + self->frame->size.top - - self->border_width); - event.type = ConfigureNotify; event.xconfigure.display = ob_display; event.xconfigure.event = self->window; @@ -3036,7 +3072,7 @@ static void client_iconify_recursive(ObClient *self, if (curdesk && self->desktop != screen_desktop && self->desktop != DESKTOP_ALL) - client_set_desktop(self, screen_desktop, FALSE); + client_set_desktop(self, screen_desktop, FALSE, FALSE); /* this puts it after the current focused window */ focus_order_remove(self); @@ -3151,7 +3187,7 @@ void client_shade(ObClient *self, gboolean 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); + frame_adjust_area(self->frame, FALSE, TRUE, FALSE); } void client_close(ObClient *self) @@ -3209,7 +3245,8 @@ void client_hilite(ObClient *self, gboolean hilite) void client_set_desktop_recursive(ObClient *self, guint target, - gboolean donthide) + gboolean donthide, + gboolean dontraise) { guint old; GSList *it; @@ -3227,28 +3264,32 @@ void client_set_desktop_recursive(ObClient *self, frame_adjust_state(self->frame); /* 'move' the window to the new desktop */ if (!donthide) - client_showhide(self); + client_hide(self); + client_show(self); /* raise if it was not already on the desktop */ - if (old != DESKTOP_ALL) + if (old != DESKTOP_ALL && !dontraise) stacking_raise(CLIENT_AS_WINDOW(self)); - /* the new desktop's geometry may be different, so we may need to - resize, for example if we are maximized */ - client_reconfigure(self); if (STRUT_EXISTS(self->strut)) screen_update_areas(); + else + /* the new desktop's geometry may be different, so we may need to + resize, for example if we are maximized */ + client_reconfigure(self, FALSE); } /* move all transients */ for (it = self->transients; it; it = g_slist_next(it)) if (it->data != self) if (client_is_direct_child(self, it->data)) - client_set_desktop_recursive(it->data, target, donthide); + client_set_desktop_recursive(it->data, target, + donthide, dontraise); } -void client_set_desktop(ObClient *self, guint target, gboolean donthide) +void client_set_desktop(ObClient *self, guint target, + gboolean donthide, gboolean dontraise) { self = client_search_top_direct_parent(self); - client_set_desktop_recursive(self, target, donthide); + client_set_desktop_recursive(self, target, donthide, dontraise); } gboolean client_is_direct_child(ObClient *parent, ObClient *child) @@ -3521,6 +3562,10 @@ gboolean client_focus(ObClient *self) "Focusing client \"%s\" (0x%x) at time %u\n", self->title, self->window, event_curtime); + /* if using focus_delay, stop the timer now so that focus doesn't + go moving on us */ + event_halt_focus_delay(); + /* if there is a grab going on, then we need to cancel it. if we move focus during the grab, applications will get NotifyWhileGrabbed events and ignore them ! @@ -3561,17 +3606,9 @@ gboolean client_focus(ObClient *self) return !xerror_occured; } -/*! Present the client to the user. - @param raise If the client should be raised or not. You should only set - raise to false if you don't care if the window is completely - hidden. -*/ -static void client_present(ObClient *self, gboolean here, gboolean raise) +static void client_present(ObClient *self, gboolean here, gboolean raise, + gboolean unshade) { - /* if using focus_delay, stop the timer now so that focus doesn't - go moving on us */ - event_halt_focus_delay(); - if (client_normal(self) && screen_showing_desktop) screen_show_desktop(FALSE, self); if (self->iconic) @@ -3580,14 +3617,14 @@ static void client_present(ObClient *self, gboolean here, gboolean raise) self->desktop != screen_desktop) { if (here) - client_set_desktop(self, screen_desktop, FALSE); + client_set_desktop(self, screen_desktop, FALSE, TRUE); else screen_set_desktop(self->desktop, FALSE); } else if (!self->frame->visible) /* if its not visible for other reasons, then don't mess with it */ return; - if (self->shaded) + if (self->shaded && unshade) client_shade(self, FALSE); if (raise) stacking_raise(CLIENT_AS_WINDOW(self)); @@ -3595,7 +3632,8 @@ static void client_present(ObClient *self, gboolean here, gboolean raise) client_focus(self); } -void client_activate(ObClient *self, gboolean here, gboolean user) +void client_activate(ObClient *self, gboolean here, gboolean raise, + gboolean unshade, gboolean user) { guint32 last_time = focus_client ? focus_client->user_time : CurrentTime; gboolean allow = FALSE; @@ -3621,7 +3659,7 @@ void client_activate(ObClient *self, gboolean here, gboolean user) (user ? "user" : "application"), allow); if (allow) - client_present(self, here, TRUE); + client_present(self, here, raise, unshade); else /* don't focus it but tell the user it wants attention */ client_hilite(self, TRUE); @@ -3647,7 +3685,7 @@ static void client_bring_windows_recursive(ObClient *self, if (iconic && self->iconic) client_iconify(self, FALSE, TRUE, FALSE); else - client_set_desktop(self, desktop, FALSE); + client_set_desktop(self, desktop, FALSE, FALSE); } } @@ -3851,13 +3889,13 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) gint dest, monitor_dest; gint my_edge_start, my_edge_end, my_offset; GList *it; - Rect *a, *monitor; + Rect *a, *mon; if(!client_list) return -1; - a = screen_area(c->desktop); - monitor = screen_area_monitor(c->desktop, client_monitor(c)); + a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area); + mon = screen_area(c->desktop, SCREEN_AREA_ONE_MONITOR, &c->frame->area); switch(dir) { case OB_DIRECTION_NORTH: @@ -3867,7 +3905,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) /* default: top of screen */ dest = a->y + (hang ? c->frame->area.height : 0); - monitor_dest = monitor->y + (hang ? c->frame->area.height : 0); + monitor_dest = mon->y + (hang ? c->frame->area.height : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ if (monitor_dest != dest && my_offset > monitor_dest) @@ -3900,7 +3938,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) /* default: bottom of screen */ dest = a->y + a->height - (hang ? c->frame->area.height : 0); - monitor_dest = monitor->y + monitor->height - + monitor_dest = mon->y + mon->height - (hang ? c->frame->area.height : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ @@ -3935,7 +3973,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) /* default: leftmost egde of screen */ dest = a->x + (hang ? c->frame->area.width : 0); - monitor_dest = monitor->x + (hang ? c->frame->area.width : 0); + monitor_dest = mon->x + (hang ? c->frame->area.width : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ if (monitor_dest != dest && my_offset > monitor_dest) @@ -3968,7 +4006,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) /* default: rightmost edge of screen */ dest = a->x + a->width - (hang ? c->frame->area.width : 0); - monitor_dest = monitor->x + monitor->width - + monitor_dest = mon->x + mon->width - (hang ? c->frame->area.width : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ @@ -4004,6 +4042,9 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) g_assert_not_reached(); dest = 0; /* suppress warning */ } + + g_free(a); + g_free(mon); return dest; } @@ -4040,3 +4081,30 @@ gboolean client_has_group_siblings(ObClient *self) { return self->group && self->group->members->next; } + +ObClientIcon *client_thumbnail(ObClient *self, gint wantw, gint wanth) +{ + ObClientIcon *ret; + RrPixel32 *data; + gint w, h; + + if (!self->frame->pixmap) return NULL; + if (!RrPixmapToRGBA(ob_rr_inst, self->frame->pixmap, None, &w, &h, &data)) + return NULL; + + /* resize the thumbnail (within aspect ratio) to the given sizes */ + + ret = g_new(ObClientIcon, 1); + ret->data = data; + ret->width = w; + ret->height = h; + return ret; +} + +void clienticon_free(ObClientIcon *ci) +{ + if (ci) { + g_free(ci->data); + g_free(ci); + } +}