X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=3fac34f79ef555ed82dfa93ada2d30d72c0f590d;hb=e9115802d51795646d9c19015d77d74380e471a7;hp=bca2261c6eb393248f202650d4630de8782bf6ab;hpb=281c1edb4206b7e7874990b1bd5f66e1e7e43ede;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index bca2261c..3fac34f7 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -241,6 +241,7 @@ void client_manage(Window window) XWMHints *wmhint; gboolean activate = FALSE; ObAppSettings *settings; + gint placex, placey; grab_server(TRUE); @@ -314,7 +315,8 @@ void client_manage(Window window) grab_server(FALSE); /* per-app settings override stuff from client_get_all, and return the - settings for other uses too */ + settings for other uses too. the returned settings is a shallow copy, + that needs to be freed with g_free(). */ settings = client_get_settings_state(self); /* the session should get the last say thought */ client_restore_session_state(self); @@ -358,6 +360,15 @@ void client_manage(Window window) activate = TRUE; } + /* adjust the frame to the client's size before showing or placing + the window */ + frame_adjust_area(self->frame, FALSE, TRUE, FALSE); + frame_adjust_client_area(self->frame); + + /* where the frame was placed is where the window was originally */ + placex = self->area.x; + placey = self->area.y; + /* figure out placement for the window */ if (ob_state() == OB_STATE_RUNNING) { gboolean transient; @@ -368,10 +379,10 @@ void client_manage(Window window) (self->positioned == USPosition ? "user specified" : "BADNESS !?"))), self->area.x, self->area.y); - transient = place_client(self, &self->area.x, &self->area.y, settings); + transient = place_client(self, &placex, &placey, settings); /* make sure the window is visible. */ - client_find_onscreen(self, &self->area.x, &self->area.y, + client_find_onscreen(self, &placex, &placey, self->area.width, self->area.height, /* non-normal clients has less rules, and windows that are being restored from a @@ -391,31 +402,32 @@ void client_manage(Window window) } ob_debug("placing window 0x%x at %d, %d with size %d x %d\n", - self->window, self->area.x, self->area.y, + self->window, placex, placey, self->area.width, self->area.height); if (self->session) ob_debug(" but session requested %d %d instead, overriding\n", self->session->x, self->session->y); - /* adjust the frame to the client's size before showing the window */ - frame_adjust_area(self->frame, FALSE, TRUE, FALSE); - frame_adjust_client_area(self->frame); - + /* do this after the window is placed, so the premax/prefullscreen numbers + won't be all wacko!! + also, this moves the window to the position where it has been placed + */ + client_apply_startup_state(self); /* move the client to its placed position, or it it's already there, generate a ConfigureNotify telling the client where it is. do this after adjusting the frame. otherwise it gets all weird and - clients don't work right */ - client_configure(self, self->area.x, self->area.y, + clients don't work right + + also do this after applying the startup state so maximize and fullscreen + will get the right sizes and positions if the client is starting with + those states + */ + client_configure(self, placex, placey, self->area.width, self->area.height, FALSE, TRUE); - /* do this after the window is placed, so the premax/prefullscreen numbers - won't be all wacko!! - also, this moves the window to the position where it has been placed - */ - client_apply_startup_state(self); if (activate) { guint32 last_time = focus_client ? @@ -506,6 +518,9 @@ void client_manage(Window window) /* update the list hints */ client_set_list(); + /* free the ObAppSettings shallow copy */ + g_free(settings); + ob_debug("Managed window 0x%lx plate 0x%x (%s)\n", window, self->frame->plate, self->class); @@ -527,7 +542,7 @@ ObClient *client_fake_manage(Window window) client_get_all(self, FALSE); /* per-app settings override stuff, and return the settings for other - uses too */ + uses too. this returns a shallow copy that needs to be freed */ settings = client_get_settings_state(self); client_setup_decor_and_functions(self); @@ -535,6 +550,10 @@ ObClient *client_fake_manage(Window window) /* create the decoration frame for the client window and adjust its size */ self->frame = frame_new(self); frame_adjust_area(self->frame, FALSE, TRUE, TRUE); + + /* free the ObAppSettings shallow copy */ + g_free(settings); + return self; } @@ -565,7 +584,7 @@ void client_unmanage(ObClient *self) /* ignore enter events from the unmap so it doesnt mess with the focus */ - event_ignore_queued_enters(); + event_ignore_all_queued_enters(); mouse_grab_for_client(self, FALSE); @@ -641,6 +660,8 @@ void client_unmanage(ObClient *self) } self->fullscreen = self->max_horz = self->max_vert = FALSE; + /* let it be moved and resized no matter what */ + self->functions = OB_CLIENT_FUNC_MOVE | OB_CLIENT_FUNC_RESIZE; self->decorations = 0; /* unmanaged windows have no decor */ client_move_resize(self, a.x, a.y, a.width, a.height); @@ -694,73 +715,82 @@ void client_fake_unmanage(ObClient *self) g_free(self); } +/*! Returns a new structure containing the per-app settings for this client. + The returned structure needs to be freed with g_free. */ static ObAppSettings *client_get_settings_state(ObClient *self) { - ObAppSettings *settings = NULL; + ObAppSettings *settings; GSList *it; + settings = config_create_app_settings(); + for (it = config_per_app_settings; it; it = g_slist_next(it)) { ObAppSettings *app = it->data; - - if ((app->name && !app->class && !strcmp(app->name, self->name)) - || (app->class && !app->name && !strcmp(app->class, self->class)) - || (app->class && app->name && !strcmp(app->class, self->class) - && !strcmp(app->name, self->name))) - { - /* Match if no role was specified in the per app setting, or if the - * string matches the beginning of the role, since apps like to set - * the role to things like browser-window-23c4b2f */ - if (!app->role - || !strncmp(app->role, self->role, strlen(app->role))) - { - ob_debug("Window matching: %s\n", app->name); - /* use this one */ - settings = app; - break; - } - } + gboolean match = TRUE; + + g_assert(app->name != NULL || app->class != NULL); + + /* we know that either name or class is not NULL so it will have to + match to use the rule */ + if (app->name && + !g_pattern_match(app->name, strlen(self->name), self->name, NULL)) + match = FALSE; + else if (app->class && + !g_pattern_match(app->class, + strlen(self->class), self->class, NULL)) + match = FALSE; + else if (app->role && + !g_pattern_match(app->role, + strlen(self->role), self->role, NULL)) + match = FALSE; + + if (match) { + ob_debug("Window matching: %s\n", app->name); + + /* copy the settings to our struct, overriding the existing + settings if they are not defaults */ + config_app_settings_copy_non_defaults(app, settings); + } + } + + if (settings->shade != -1) + self->shaded = !!settings->shade; + if (settings->decor != -1) + self->undecorated = !settings->decor; + if (settings->iconic != -1) + self->iconic = !!settings->iconic; + if (settings->skip_pager != -1) + self->skip_pager = !!settings->skip_pager; + if (settings->skip_taskbar != -1) + self->skip_taskbar = !!settings->skip_taskbar; + + if (settings->max_vert != -1) + self->max_vert = !!settings->max_vert; + if (settings->max_horz != -1) + self->max_horz = !!settings->max_horz; + + if (settings->fullscreen != -1) + self->fullscreen = !!settings->fullscreen; + + if (settings->desktop) { + if (settings->desktop == DESKTOP_ALL) + self->desktop = settings->desktop; + else if (settings->desktop > 0 && + settings->desktop <= screen_num_desktops) + self->desktop = settings->desktop - 1; + } + + if (settings->layer == -1) { + self->below = TRUE; + self->above = FALSE; } - - if (settings) { - if (settings->shade != -1) - self->shaded = !!settings->shade; - if (settings->decor != -1) - self->undecorated = !settings->decor; - if (settings->iconic != -1) - self->iconic = !!settings->iconic; - if (settings->skip_pager != -1) - self->skip_pager = !!settings->skip_pager; - if (settings->skip_taskbar != -1) - self->skip_taskbar = !!settings->skip_taskbar; - - if (settings->max_vert != -1) - self->max_vert = !!settings->max_vert; - if (settings->max_horz != -1) - self->max_horz = !!settings->max_horz; - - if (settings->fullscreen != -1) - self->fullscreen = !!settings->fullscreen; - - if (settings->desktop) { - if (settings->desktop == DESKTOP_ALL) - self->desktop = settings->desktop; - else if (settings->desktop > 0 && - settings->desktop <= screen_num_desktops) - self->desktop = settings->desktop - 1; - } - - if (settings->layer == -1) { - self->below = TRUE; - self->above = FALSE; - } - else if (settings->layer == 0) { - self->below = FALSE; - self->above = FALSE; - } - else if (settings->layer == 1) { - self->below = FALSE; - self->above = TRUE; - } + else if (settings->layer == 0) { + self->below = FALSE; + self->above = FALSE; + } + else if (settings->layer == 1) { + self->below = FALSE; + self->above = TRUE; } return settings; } @@ -853,9 +883,11 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, gint ox = *x, oy = *y; gboolean rudel = rude, ruder = rude, rudet = rude, rudeb = rude; gint fw, fh; + Rect desired; + RECT_SET(desired, *x, *y, w, h); all_a = screen_area(self->desktop); - mon_a = screen_area_monitor(self->desktop, client_monitor(self)); + mon_a = screen_area_monitor(self->desktop, screen_find_monitor(&desired)); /* get where the frame would be */ frame_client_gravity(self->frame, x, y, w, h); @@ -905,10 +937,10 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, POINT_SET(newbl, newtl.x, newbr.y); /* is it moving or just resizing from some corner? */ - stationary_l = oldtl.x == oldtl.x; - stationary_r = oldtr.x == oldtr.x; - stationary_t = oldtl.y == oldtl.y; - stationary_b = oldbl.y == oldbl.y; + stationary_l = oldtl.x == newtl.x; + stationary_r = oldtr.x == newtr.x; + stationary_t = oldtl.y == newtl.y; + stationary_b = oldbl.y == newbl.y; /* if left edge is growing and didnt move right edge */ if (stationary_r && newtl.x < oldtl.x) @@ -930,16 +962,13 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, * 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 (fw <= mon_a->width) { - 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 + mon_a->width - fw; - } - if (fh <= mon_a->height) { - 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 + mon_a->height - fh; - } + 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); + + 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); /* get where the client should be */ frame_frame_gravity(self->frame, x, y, w, h); @@ -1563,6 +1592,8 @@ void client_update_normal_hints(ObClient *self) } } +/*! This needs to be followed by a call to client_configure to make + the changes show */ void client_setup_decor_and_functions(ObClient *self) { /* start with everything (cept fullscreen) */ @@ -1585,7 +1616,8 @@ void client_setup_decor_and_functions(ObClient *self) OB_CLIENT_FUNC_SHADE | OB_CLIENT_FUNC_CLOSE | OB_CLIENT_FUNC_BELOW | - OB_CLIENT_FUNC_ABOVE); + OB_CLIENT_FUNC_ABOVE | + OB_CLIENT_FUNC_UNDECORATE); if (!(self->min_size.width < self->max_size.width || self->min_size.height < self->max_size.height)) @@ -1615,11 +1647,13 @@ void client_setup_decor_and_functions(ObClient *self) do with them is move them */ self->decorations = 0; self->functions = OB_CLIENT_FUNC_MOVE; + break; case OB_CLIENT_TYPE_DESKTOP: /* these windows are not manipulated by the window manager */ self->decorations = 0; self->functions = 0; + break; case OB_CLIENT_TYPE_DOCK: /* these windows are not manipulated by the window manager, but they @@ -1680,10 +1714,15 @@ void client_setup_decor_and_functions(ObClient *self) self->decorations &= ~OB_FRAME_DECOR_MAXIMIZE; } - /* kill the handle on fully maxed windows */ - if (self->max_vert && self->max_horz) + if (self->max_horz && self->max_vert) + /* kill the handle on fully maxed windows */ self->decorations &= ~(OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS); + /* If there are no decorations to remove, don't allow the user to try + toggle the state */ + if (self->decorations == 0) + self->functions &= ~OB_CLIENT_FUNC_UNDECORATE; + /* finally, the user can have requested no decorations, which overrides everything (but doesnt give it a border if it doesnt have one) */ if (self->undecorated) { @@ -1706,16 +1745,11 @@ void client_setup_decor_and_functions(ObClient *self) } client_change_allowed_actions(self); - - if (self->frame) { - /* adjust the client's decorations, etc. */ - client_reconfigure(self); - } } static void client_change_allowed_actions(ObClient *self) { - gulong actions[11]; + gulong actions[12]; gint num = 0; /* desktop windows are kept on all desktops */ @@ -1742,6 +1776,8 @@ static void client_change_allowed_actions(ObClient *self) actions[num++] = prop_atoms.net_wm_action_above; if (self->functions & OB_CLIENT_FUNC_BELOW) actions[num++] = prop_atoms.net_wm_action_below; + if (self->functions & OB_CLIENT_FUNC_UNDECORATE) + actions[num++] = prop_atoms.ob_wm_action_undecorate; PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num); @@ -2247,6 +2283,7 @@ static void client_change_wm_state(ObClient *self) state[0] = self->wmstate; state[1] = None; PROP_SETA32(self->window, wm_state, wm_state, state, 2); + ob_debug("setting wm_state %d\n", self->wmstate); } } @@ -2407,13 +2444,13 @@ gboolean client_show(ObClient *self) if (client_should_show(self)) { frame_show(self->frame); show = TRUE; - } - /* 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! - */ - client_change_wm_state(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! + */ + client_change_wm_state(self); + } return show; } @@ -2436,13 +2473,13 @@ gboolean client_hide(ObClient *self) frame_hide(self->frame); hide = TRUE; - } - /* 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! - */ - client_change_wm_state(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! + */ + client_change_wm_state(self); + } return hide; } @@ -2450,12 +2487,6 @@ void client_showhide(ObClient *self) { if (!client_show(self)) client_hide(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! - */ - client_change_wm_state(self); } gboolean client_normal(ObClient *self) { @@ -2558,7 +2589,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, /* make the frame recalculate its dimentions n shit without changing anything visible for real, this way the constraints below can work with the updated frame dimensions. */ - frame_adjust_area(self->frame, TRUE, TRUE, TRUE); + frame_adjust_area(self->frame, FALSE, TRUE, TRUE); /* work within the prefered sizes given by the window */ if (!(*w == self->area.width && *h == self->area.height)) { @@ -2713,6 +2744,7 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gboolean fmoved, fresized; guint fdecor = self->frame->decorations; gboolean fhorz = self->frame->max_horz; + gboolean fvert = self->frame->max_vert; gint logicalw, logicalh; /* find the new x, y, width, and height (and logical size) */ @@ -2748,8 +2780,15 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, /* find the frame's dimensions and move/resize it */ fmoved = moved; fresized = resized; - if (self->decorations != fdecor || self->max_horz != fhorz) + + /* if decorations changed, then readjust everything for the frame */ + if (self->decorations != fdecor || + self->max_horz != fhorz || self->max_vert != fvert) + { fmoved = fresized = TRUE; + } + + /* adjust the frame */ if (fmoved || fresized) frame_adjust_area(self->frame, fmoved, fresized, FALSE); @@ -3059,7 +3098,7 @@ void client_set_desktop_recursive(ObClient *self, guint old; GSList *it; - if (target != self->desktop) { + if (target != self->desktop && self->type != OB_CLIENT_TYPE_DESKTOP) { ob_debug("Setting desktop %u\n", target+1); @@ -3461,12 +3500,9 @@ void client_activate(ObClient *self, gboolean here, gboolean user) self->window, event_curtime, last_time, (user ? "user" : "application"), allow); - if (allow) { - if (event_curtime != CurrentTime) - self->user_time = event_curtime; - + if (allow) client_present(self, here, TRUE); - } else + else /* don't focus it but tell the user it wants attention */ client_hilite(self, TRUE); } @@ -3571,9 +3607,14 @@ void client_set_layer(ObClient *self, gint layer) void client_set_undecorated(ObClient *self, gboolean undecorated) { - if (self->undecorated != undecorated) { + if (self->undecorated != undecorated && + /* don't let it undecorate if the function is missing, but let + it redecorate */ + (self->functions & OB_CLIENT_FUNC_UNDECORATE || !undecorated)) + { self->undecorated = undecorated; client_setup_decor_and_functions(self); + client_reconfigure(self); /* show the lack of decorations */ client_change_state(self); /* reflect this in the state hints */ } }